Skip to content

Commit

Permalink
Change Disocclusion handling
Browse files Browse the repository at this point in the history
Greatly Improves Image Stability especially in variable Motion, Adds logic to Reduce Lighting Related Ghosting, Disables Variance Clipping as I've been unsuccessful with integrating it into the new logic to improve image quality in any way.
  • Loading branch information
mrjustaguy committed Nov 30, 2023
1 parent a2037a0 commit bc64760
Showing 1 changed file with 50 additions and 61 deletions.
111 changes: 50 additions & 61 deletions servers/rendering/renderer_rd/shaders/effects/taa_resolve.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,12 @@ vec3 reinhard_inverse(vec3 sdr) {
return sdr / (1.0 - sdr);
}

const vec3 lumCoeff = vec3(0.299f, 0.587f, 0.114f);

float luminance(vec3 color) {
return max(dot(reinhard(color), lumCoeff), 0.0001f);
}

float get_depth(ivec2 thread_id) {
return texelFetch(depth_buffer, thread_id, 0).r;
}
Expand Down Expand Up @@ -268,44 +274,35 @@ vec3 clip_aabb(vec3 aabb_min, vec3 aabb_max, vec3 p, vec3 q) {
}

// Clip history to the neighbourhood of the current sample
vec3 clip_history_3x3(uvec2 group_pos, vec3 color_history) {
float luminance_clip_history_3x3(vec3 color_history, vec3 s1, vec3 s2, vec3 s3, vec3 s4, vec3 s5, vec3 s6, vec3 s7, vec3 s8, vec3 s9) {
// Sample a 3x3 neighbourhood
vec3 s1 = load_color(group_pos + kOffsets3x3[0]);
vec3 s2 = load_color(group_pos + kOffsets3x3[1]);
vec3 s3 = load_color(group_pos + kOffsets3x3[2]);
vec3 s4 = load_color(group_pos + kOffsets3x3[3]);
vec3 s5 = load_color(group_pos + kOffsets3x3[4]);
vec3 s6 = load_color(group_pos + kOffsets3x3[5]);
vec3 s7 = load_color(group_pos + kOffsets3x3[6]);
vec3 s8 = load_color(group_pos + kOffsets3x3[7]);
vec3 s9 = load_color(group_pos + kOffsets3x3[8]);

// Compute min and max
vec3 color_avg = (s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9) * RPC_9;
vec3 color_avg2 = ((s1 * s1) + (s2 * s2) + (s3 * s3) + (s4 * s4) + (s5 * s5) + (s6 * s6) + (s7 * s7) + (s8 * s8) + (s9 * s9)) * RPC_9;
vec3 dev = sqrt(abs(color_avg2 - (color_avg * color_avg)));
vec3 color_min = color_avg - dev;
vec3 color_max = color_avg + dev;

// Variance clipping
vec3 color = clip_aabb(color_min, color_max, clamp(color_avg, color_min, color_max), color_history);

// Clamp to prevent NaNs
color = clamp(color, FLT_MIN, FLT_MAX);

return color;
float ls1 = luminance(s1);
float ls2 = luminance(s2);
float ls3 = luminance(s3);
float ls4 = luminance(s4);
float ls5 = luminance(s5);
float ls6 = luminance(s6);
float ls7 = luminance(s7);
float ls8 = luminance(s8);
float ls9 = luminance(s9);

// Compute min and max luminance
float min = min(ls1, min(ls2, min(ls3, min(ls4, min(ls5, min(ls6, min(ls7, min(ls8, ls9))))))));
float max = max(ls1, max(ls2, max(ls3, max(ls4, max(ls5, max(ls6, max(ls7, max(ls8, ls9))))))));
float history = luminance(color_history);

// Take current sample if old sample isn't within the brightness range of current 3x3 grid
if (min < history && history < max) {
return 0.0;
} else {
return 1.0;
}
}

/*------------------------------------------------------------------------------
TAA
------------------------------------------------------------------------------*/

const vec3 lumCoeff = vec3(0.299f, 0.587f, 0.114f);

float luminance(vec3 color) {
return max(dot(color, lumCoeff), 0.0001f);
}

float get_factor_disocclusion(vec2 uv_reprojected, vec2 velocity) {
vec2 velocity_previous = imageLoad(last_velocity_buffer, ivec2(uv_reprojected * params.resolution)).xy;
vec2 velocity_texels = velocity * params.resolution;
Expand All @@ -321,45 +318,37 @@ vec3 temporal_antialiasing(uvec2 pos_group_top_left, uvec2 pos_group, uvec2 pos_
// Get reprojected uv
vec2 uv_reprojected = uv + velocity;

// Sample a 3x3 neighbourhood
vec3 s1 = load_color(pos_group + kOffsets3x3[0]);
vec3 s2 = load_color(pos_group + kOffsets3x3[1]);
vec3 s3 = load_color(pos_group + kOffsets3x3[2]);
vec3 s4 = load_color(pos_group + kOffsets3x3[3]);
vec3 s5 = load_color(pos_group + kOffsets3x3[4]);
vec3 s6 = load_color(pos_group + kOffsets3x3[5]);
vec3 s7 = load_color(pos_group + kOffsets3x3[6]);
vec3 s8 = load_color(pos_group + kOffsets3x3[7]);
vec3 s9 = load_color(pos_group + kOffsets3x3[8]);

// Get input color
vec3 color_input = load_color(pos_group);
vec3 color_input = (s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9) * RPC_9;

// Get history color (catmull-rom reduces a lot of the blurring that you get under motion)
vec3 color_history = sample_catmull_rom_9(tex_history, uv_reprojected, params.resolution).rgb;

// Clip history to the neighbourhood of the current sample (fixes a lot of the ghosting).
color_history = clip_history_3x3(pos_group, color_history);
// Compute disoccusion
float disocclusion = get_factor_disocclusion(uv_reprojected, velocity);

// If re-projected UV is out of screen, converge to current color immediately
float off_screen = any(lessThan(uv_reprojected, vec2(0.0))) || any(greaterThan(uv_reprojected, vec2(1.0))) ? 1.0 : 0.0;

// This greatly reduces Shadow and Specular Ghosting
float luminance_check = luminance_clip_history_3x3(color_history, s1, s2, s3, s4, s5, s6, s7, s8, s9);

// Compute blend factor
float blend_factor = clamp(RPC_16 + get_factor_disocclusion(uv_reprojected, velocity), 0.0, 1.0); // We want to be able to accumulate as many jitter samples as we generated, that is, 16. We also increase the blend factor when there is disocclusion to reduce ghosting
float blend_factor = clamp(1.0 - RPC_16 - disocclusion - off_screen - luminance_check, 0.0, 1.0);

// Resolve
vec3 color_resolved = vec3(0.0);
{
// Tonemap
color_history = reinhard(color_history);
color_input = reinhard(color_input);

// Reduce flickering
float lum_color = luminance(color_input);
float lum_history = luminance(color_history);
float diff = abs(lum_color - lum_history) / max(lum_color, max(lum_history, 1.001));
diff = 1.0 - diff;
diff = diff * diff;
blend_factor = mix(0.0, blend_factor, diff);

// If re-projected UV is out of screen, converge to current color immediately
float factor_screen = any(lessThan(uv_reprojected, vec2(0.0))) || any(greaterThan(uv_reprojected, vec2(1.0))) ? 1.0 : 0.0;
blend_factor = clamp(blend_factor + factor_screen, 0.0, 1.0);

// Lerp/blend
color_resolved = mix(color_history, color_input, blend_factor);

// Inverse tonemap
color_resolved = reinhard_inverse(color_resolved);
}

return color_resolved;
return mix(color_input, color_history, blend_factor);
}

void main() {
Expand Down

0 comments on commit bc64760

Please sign in to comment.