Skip to content

Commit 8724995

Browse files
committed
TAA fixes and improvements
- use a lanczos filter for sampling the color buffer, instead of a blackman-Harris window. This improves sharpness quite a bit. - some cleanups of the shader code - never use YCoCg when rectification is not enabled. - fix the calculation of the confidence paramter when upscaling is used. Upscaling works a lot better now, but it is still work in progress.
1 parent e75bf2f commit 8724995

File tree

4 files changed

+65
-52
lines changed

4 files changed

+65
-52
lines changed

filament/include/filament/Options.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -438,7 +438,7 @@ struct MultiSampleAntiAliasingOptions {
438438
* @see setTemporalAntiAliasingOptions()
439439
*/
440440
struct TemporalAntiAliasingOptions {
441-
float filterWidth = 1.0f; //!< reconstruction filter width typically between 0.2 (sharper, aliased) and 1.5 (smoother)
441+
float filterWidth = 1.0f; //!< reconstruction filter width typically between 1 (sharper) and 2 (smoother)
442442
float feedback = 0.12f; //!< history feedback, between 0 (maximum temporal AA) and 1 (no temporal AA).
443443
float lodBias = -1.0f; //!< texturing lod bias (typically -1 or -2)
444444
float sharpness = 0.0f; //!< post-TAA sharpen, especially useful when upscaling is true.

filament/src/PostProcessManager.cpp

+25-10
Original file line numberDiff line numberDiff line change
@@ -2622,7 +2622,7 @@ void PostProcessManager::TaaJitterCamera(
26222622
current.projection = inoutCameraInfo->projection * inoutCameraInfo->getUserViewMatrix();
26232623
current.frameId = previous.frameId + 1;
26242624

2625-
auto jitterPosition = [pattern = taaOptions.jitterPattern](size_t frameIndex){
2625+
auto jitterPosition = [pattern = taaOptions.jitterPattern](size_t frameIndex) -> float2 {
26262626
using JitterPattern = TemporalAntiAliasingOptions::JitterPattern;
26272627
switch (pattern) {
26282628
case JitterPattern::RGSS_X4:
@@ -2636,6 +2636,7 @@ void PostProcessManager::TaaJitterCamera(
26362636
case JitterPattern::HALTON_23_X32:
26372637
return sHaltonSamples(frameIndex);
26382638
}
2639+
return { 0.0f, 0.0f };
26392640
};
26402641

26412642
// sample position within a pixel [-0.5, 0.5]
@@ -2759,15 +2760,31 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::taa(FrameGraph& fg,
27592760
}};
27602761

27612762
constexpr float2 sampleOffsets[9] = {
2762-
{ -1.0f, -1.0f }, { 0.0f, -1.0f }, { 1.0f, -1.0f },
2763-
{ -1.0f, 0.0f }, { 0.0f, 0.0f }, { 1.0f, 0.0f },
2764-
{ -1.0f, 1.0f }, { 0.0f, 1.0f }, { 1.0f, 1.0f },
2763+
{ -1.0f, -1.0f }, { 0.0f, -1.0f }, { 1.0f, -1.0f }, { -1.0f, 0.0f },
2764+
{ 0.0f, 0.0f },
2765+
{ 1.0f, 0.0f }, { -1.0f, 1.0f }, { 0.0f, 1.0f }, { 1.0f, 1.0f },
27652766
};
27662767

27672768
constexpr float2 subSampleOffsets[4] = {
2768-
{ -0.25f, 0.25f }, { 0.25f, 0.25f }, { 0.25f, -0.25f }, { -0.25f, -0.25f }
2769+
{ -0.25f, 0.25f },
2770+
{ 0.25f, 0.25f },
2771+
{ 0.25f, -0.25f },
2772+
{ -0.25f, -0.25f }
27692773
};
27702774

2775+
UTILS_UNUSED
2776+
auto const lanczos = [](float x, float a) -> float {
2777+
if (x <= std::numeric_limits<float>::epsilon()) {
2778+
return 1.0f;
2779+
}
2780+
if (std::abs(x) <= a) {
2781+
return (a * std::sin(f::PI * x) * std::sin(f::PI * x / a))
2782+
/ ((f::PI * f::PI) * (x * x));
2783+
}
2784+
return 0.0f;
2785+
};
2786+
2787+
float const filterWidth = std::clamp(taaOptions.filterWidth, 1.0f, 2.0f);
27712788
float4 sum = 0.0;
27722789
float4 weights[9];
27732790

@@ -2777,11 +2794,9 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::taa(FrameGraph& fg,
27772794
for (size_t i = 0; i < 9; i++) {
27782795
float2 const o = sampleOffsets[i];
27792796
for (size_t j = 0; j < 4; j++) {
2780-
float2 const s = taaOptions.upscaling ? subSampleOffsets[j] : float2{ 0 };
2781-
float2 const d = (o - current.jitter - s) / taaOptions.filterWidth;
2782-
// This is a gaussian fit of a 3.3-wide Blackman-Harris window
2783-
// see: "High Quality Temporal Supersampling" by Brian Karis
2784-
weights[i][j] = std::exp(-2.29f * (d.x * d.x + d.y * d.y));
2797+
float2 const subPixelOffset = taaOptions.upscaling ? subSampleOffsets[j] : float2{ 0 };
2798+
float2 const d = (o - (current.jitter - subPixelOffset)) / filterWidth;
2799+
weights[i][j] = lanczos(length(d), filterWidth);
27852800
}
27862801
sum += weights[i];
27872802
}

filament/src/PostProcessManager.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -428,7 +428,7 @@ class PostProcessManager {
428428

429429
template<size_t SIZE>
430430
struct JitterSequence {
431-
auto operator()(size_t i) const noexcept { return positions[i % SIZE] - 0.5f; }
431+
math::float2 operator()(size_t i) const noexcept { return positions[i % SIZE] - 0.5f; }
432432
const std::array<math::float2, SIZE> positions;
433433
};
434434

filament/src/materials/antiAliasing/taa.mat

+38-40
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,8 @@ float lumaYCoCg(const vec3 c) {
127127
}
128128

129129
float luma(const vec3 c) {
130-
return materialConstants_useYCoCg ? lumaYCoCg(c) : lumaRGB(c);
130+
return (materialConstants_useYCoCg && materialConstants_boxClipping != BOX_CLIPPING_NONE) ?
131+
lumaYCoCg(c) : lumaRGB(c);
131132
}
132133

133134
vec3 tonemap(const vec3 c) {
@@ -278,10 +279,6 @@ void postProcess(inout PostProcessInputs postProcess) {
278279
history = textureLod(materialParams_history, uv.zw, 0.0);
279280
}
280281

281-
if (materialConstants_useYCoCg) {
282-
history.rgb = RGB_YCoCg(history.rgb);
283-
}
284-
285282
highp vec2 size = vec2(textureSize(materialParams_color, 0));
286283
highp vec2 p = (floor(uv.xy * size) + 0.5) / size;
287284
vec4 filtered = textureLod(materialParams_color, p, 0.0);
@@ -297,47 +294,46 @@ void postProcess(inout PostProcessInputs postProcess) {
297294
s[6] = textureLodOffset(materialParams_color, p, 0.0, ivec2(-1, 1)).rgb;
298295
s[7] = textureLodOffset(materialParams_color, p, 0.0, ivec2( 0, 1)).rgb;
299296
s[8] = textureLodOffset(materialParams_color, p, 0.0, ivec2( 1, 1)).rgb;
300-
if (materialConstants_useYCoCg) {
301-
for (int i = 0; i < 9; i++) {
302-
s[i] = RGB_YCoCg(s[i]);
303-
}
304-
}
305297
}
306298

307-
vec2 subPixelOffset = p - uv.xy; // +/- [0.25, 0.25]
308-
float confidence = materialConstants_upscaling ? 0.0 : 1.0;
299+
int j = 0;
300+
float confidence = 1.0;
301+
if (materialConstants_upscaling) {
302+
highp vec2 subPixelOffset = (p - uv.xy) * size; // +/- [0.25, 0.25]
303+
304+
// we reduce the contribution of a sample based on the distance
305+
// to the high resolution pixel center
306+
const float cutoff = 0.5;
307+
highp float l = length(materialParams.jitter - subPixelOffset) / cutoff;
308+
confidence = saturate(1.0 - l * l);
309+
310+
if (materialConstants_filterInput) {
311+
int jxp = subPixelOffset.y > 0.0 ? 1 : 2;
312+
int jxn = subPixelOffset.y > 0.0 ? 0 : 3;
313+
j = subPixelOffset.x > 0.0 ? jxp : jxn;
314+
}
315+
}
309316

310317
if (materialConstants_filterInput) {
311318
// unjitter/filter input
312-
// figure out which set of coeficients to use
313-
filtered = vec4(0, 0, 0, filtered.a);
314-
if (materialConstants_upscaling) {
315-
int jxp = subPixelOffset.y > 0.0 ? 3 : 0;
316-
int jxn = subPixelOffset.y > 0.0 ? 2 : 1;
317-
int j = subPixelOffset.x > 0.0 ? jxp : jxn;
318-
for (int i = 0; i < 9; i++) {
319-
float w = materialParams.filterWeights[i][j];
320-
filtered.rgb += s[i] * w;
321-
confidence = max(confidence, w);
322-
}
323-
} else {
324-
for (int i = 0; i < 9; i++) {
325-
float w = materialParams.filterWeights[i][0];
326-
filtered.rgb += s[i] * w;
327-
}
328-
}
329-
} else {
330-
if (materialConstants_useYCoCg) {
331-
filtered.rgb = RGB_YCoCg(filtered.rgb);
332-
}
333-
if (materialConstants_upscaling) {
334-
confidence = float(materialParams.jitter.x * subPixelOffset.x > 0.0 &&
335-
materialParams.jitter.y * subPixelOffset.y > 0.0);
319+
filtered = vec4(vec3(0), filtered.a);
320+
for (int i = 0; i < 9; i++) {
321+
float w = materialParams.filterWeights[i][j];
322+
filtered.rgb += s[i] * w;
336323
}
324+
filtered.rgb = max(filtered.rgb, vec3(0));
337325
}
338326

339327
// build the history clamping box
340328
if (materialConstants_boxClipping != BOX_CLIPPING_NONE) {
329+
if (materialConstants_useYCoCg) {
330+
history.rgb = RGB_YCoCg(history.rgb);
331+
filtered.rgb = RGB_YCoCg(filtered.rgb);
332+
for (int i = 0; i < 9; i++) {
333+
s[i] = RGB_YCoCg(s[i]);
334+
}
335+
}
336+
341337
vec3 boxmin;
342338
vec3 boxmax;
343339
if (materialConstants_boxType == BOX_TYPE_AABB ||
@@ -346,7 +342,7 @@ void postProcess(inout PostProcessInputs postProcess) {
346342
boxmax = max(s[4], max(max(s[1], s[3]), max(s[5], s[7])));
347343
vec3 box9min = min(boxmin, min(min(s[0], s[2]), min(s[6], s[8])));
348344
vec3 box9max = max(boxmax, max(max(s[0], s[2]), max(s[6], s[8])));
349-
// round the corners of the 3x3 box
345+
// round the corners of the 3x3 box, giving less importance to the corner samples
350346
boxmin = (boxmin + box9min) * 0.5;
351347
boxmax = (boxmax + box9max) * 0.5;
352348
}
@@ -388,9 +384,11 @@ void postProcess(inout PostProcessInputs postProcess) {
388384
}
389385

390386
// go back to RGB space before tonemapping
391-
if (materialConstants_useYCoCg) {
392-
filtered.rgb = YCoCg_RGB(filtered.rgb);
393-
history.rgb = YCoCg_RGB(history.rgb);
387+
if (materialConstants_boxClipping != BOX_CLIPPING_NONE) {
388+
if (materialConstants_useYCoCg) {
389+
filtered.rgb = YCoCg_RGB(filtered.rgb);
390+
history.rgb = YCoCg_RGB(history.rgb);
391+
}
394392
}
395393

396394
// tonemap before mixing

0 commit comments

Comments
 (0)