From 58c60bcfec30db61b0175e38b59a5fb925609549 Mon Sep 17 00:00:00 2001 From: Alexey Panteleev Date: Thu, 29 Aug 2019 15:31:48 -0700 Subject: [PATCH] Replaced the primary surface depth and slope with those of the reflected or refracted surface. Also disabled gradients on reflections and refractions because forward projection doesn't work correctly there, and light lagging looks better than noise. --- src/refresh/vkpt/shader/asvgf_atrous.comp | 4 +- .../vkpt/shader/asvgf_fwd_project.comp | 4 ++ src/refresh/vkpt/shader/asvgf_temporal.comp | 2 +- .../vkpt/shader/checkerboard_interleave.comp | 4 +- src/refresh/vkpt/shader/direct_lighting.rgen | 59 +++++++++++++++++-- 5 files changed, 64 insertions(+), 9 deletions(-) diff --git a/src/refresh/vkpt/shader/asvgf_atrous.comp b/src/refresh/vkpt/shader/asvgf_atrous.comp index f2312cf47..b225a4ba3 100644 --- a/src/refresh/vkpt/shader/asvgf_atrous.comp +++ b/src/refresh/vkpt/shader/asvgf_atrous.comp @@ -309,7 +309,7 @@ main() vec3 normal = decode_normal(texelFetch(TEX_PT_NORMAL_A, ipos, 0).x); vec2 metallic_roughness = texelFetch(TEX_PT_METALLIC, ipos, 0).rg; - bool is_checkerboard_material = texelFetch(TEX_PT_VIEW_DIRECTION, ipos, 0).a == 2.0; + float is_reflected_or_refracted = texelFetch(TEX_PT_VIEW_DIRECTION, ipos, 0).a; float metallic = metallic_roughness.x; float roughness = metallic_roughness.y; @@ -377,7 +377,7 @@ main() final_color.b += gradient_hf_spec.y * global_ubo.flt_scale_spec; } - imageStore(IMG_ASVGF_COLOR, ipos, vec4(final_color, is_checkerboard_material ? 1 : 0)); + imageStore(IMG_ASVGF_COLOR, ipos, vec4(final_color, is_reflected_or_refracted)); } } diff --git a/src/refresh/vkpt/shader/asvgf_fwd_project.comp b/src/refresh/vkpt/shader/asvgf_fwd_project.comp index 568bf1179..1b3b11a7d 100644 --- a/src/refresh/vkpt/shader/asvgf_fwd_project.comp +++ b/src/refresh/vkpt/shader/asvgf_fwd_project.comp @@ -154,6 +154,10 @@ main() if(any(lessThan(vis_buf.xy, vec2(0)))) return; + float is_reflected_or_refracted = texelFetch(TEX_PT_VIEW_DIRECTION, ipos, 0).w; + if(is_reflected_or_refracted != 0) + return; + int checkerboard_offset = (ipos.x > global_ubo.width / 2) ? global_ubo.width / 2 : 0; uint visbuf_instance_info = floatBitsToUint(vis_buf.z); diff --git a/src/refresh/vkpt/shader/asvgf_temporal.comp b/src/refresh/vkpt/shader/asvgf_temporal.comp index 8be7f7e11..ca9033e9b 100644 --- a/src/refresh/vkpt/shader/asvgf_temporal.comp +++ b/src/refresh/vkpt/shader/asvgf_temporal.comp @@ -156,7 +156,7 @@ main() float dist_depth = abs(depth_curr - depth_prev + motion.z) * motion.a; float dot_normals = dot(normal_curr, normal_prev); - if(dist_depth < 2.0 && depth_prev > 0.0 && depth_curr > 0.0 && dot_normals > 0.5) + if(dist_depth < 2.0 && dot_normals > 0.5) { float w_diff = w[i]; float w_spec = w_diff * pow(max(dot_normals, 0), 128); diff --git a/src/refresh/vkpt/shader/checkerboard_interleave.comp b/src/refresh/vkpt/shader/checkerboard_interleave.comp index 9f6b72985..eba2c8a0e 100644 --- a/src/refresh/vkpt/shader/checkerboard_interleave.comp +++ b/src/refresh/vkpt/shader/checkerboard_interleave.comp @@ -135,10 +135,12 @@ void main() vec4 center = imageLoad(IMG_ASVGF_COLOR, ipos); vec4 color; bool use_center_mv = true; + float is_reflected_or_refracted = center.a; + bool is_checkerboarded_surface = global_ubo.flt_enable != 0 && is_reflected_or_refracted == 2; // The alpha channel encodes whether the material uses checkerboard reflections and refractions. // Don't do the filter if there is no checkerboarding - which improves sharpness and reduces sparkles. - if(global_ubo.flt_enable != 0 && center.a != 0) + if(is_checkerboarded_surface) { vec4 a = imageLoad(IMG_ASVGF_COLOR, ipos + ivec2(other_side_offset, 1)); vec4 b = imageLoad(IMG_ASVGF_COLOR, ipos + ivec2(other_side_offset, -1)); diff --git a/src/refresh/vkpt/shader/direct_lighting.rgen b/src/refresh/vkpt/shader/direct_lighting.rgen index baa4c4ee0..cc1ba985c 100644 --- a/src/refresh/vkpt/shader/direct_lighting.rgen +++ b/src/refresh/vkpt/shader/direct_lighting.rgen @@ -147,6 +147,25 @@ vec3 reflect_point_vs_plane(vec3 plane_pt, vec3 plane_normal, vec3 point) return point - 2 * plane_normal * dot(plane_normal, point - plane_pt); } +float ray_distance_to_plane(vec3 plane_pt, vec3 plane_normal, vec3 ray_origin, vec3 ray_direction) +{ + return dot(plane_pt - ray_origin, plane_normal) / dot(ray_direction, plane_normal); +} + +Ray +get_primary_ray(vec2 screen_pos) +{ + vec3 view_dir = projection_screen_to_view(screen_pos, 1, false); + view_dir = normalize((global_ubo.invV * vec4(view_dir, 0)).xyz); + + Ray ray; + ray.origin = global_ubo.cam_pos.xyz; + ray.direction = view_dir; + ray.t_min = 0; + ray.t_max = 10000; + return ray; +} + void direct_lighting(ivec2 ipos, bool is_odd_checkerboard, out vec3 high_freq, out vec3 o_specular) { @@ -307,6 +326,7 @@ direct_lighting(ivec2 ipos, bool is_odd_checkerboard, out vec3 high_freq, out ve direction = reflected_direction; refraction_medium = global_ubo.medium; is_reflected_or_refracted = 1; + correct_motion_vector = 1; } else { @@ -320,12 +340,14 @@ direct_lighting(ivec2 ipos, bool is_odd_checkerboard, out vec3 high_freq, out ve direction = refracted_direction; correction_factor = (1 - F) * 2; primary_medium = MEDIUM_NONE; + correct_motion_vector = 2; } else { direction = reflected_direction; refraction_medium = global_ubo.medium; correction_factor = F * 2; + correct_motion_vector = 1; } throughput *= correction_factor; @@ -355,12 +377,14 @@ direct_lighting(ivec2 ipos, bool is_odd_checkerboard, out vec3 high_freq, out ve correction_factor = (1 - F) * 2; primary_medium = refraction_medium; primary_is_weapon = true; // hide the player model from refractions + correct_motion_vector = 2; } else { // Reflection direction = reflect(direction, normal); correction_factor = F * 2; + correct_motion_vector = 1; } throughput *= correction_factor; @@ -423,7 +447,6 @@ direct_lighting(ivec2 ipos, bool is_odd_checkerboard, out vec3 high_freq, out ve F = 0; float correction_factor = 1; - bool is_flat = (dot(normal, geo_normal) > 0.999); if(is_odd_checkerboard || F == 0) { @@ -446,14 +469,14 @@ direct_lighting(ivec2 ipos, bool is_odd_checkerboard, out vec3 high_freq, out ve correction_factor *= 2; throughput *= clamp(primary_albedo * 3, vec3(0), vec3(1)); - correct_motion_vector = is_flat ? 2 : 0; + correct_motion_vector = 2; } else { // Reflection direction = reflected_direction; correction_factor = F * 2; - correct_motion_vector = is_flat ? 1 : 0; + correct_motion_vector = 1; } throughput *= correction_factor; @@ -541,17 +564,24 @@ direct_lighting(ivec2 ipos, bool is_odd_checkerboard, out vec3 high_freq, out ve if(correct_motion_vector > 0 && !primary_is_moving) { vec3 ref_pos_curr, ref_pos_prev; + vec3 ref_geo_normal; + + // compute the apparent position of the reflected or refracted object if(correct_motion_vector == 1) { ref_pos_curr = reflect_point_vs_plane(position, geo_normal, new_position); ref_pos_prev = reflect_point_vs_plane(position, geo_normal, new_pos_prev); + ref_geo_normal = reflect(new_geo_normal, geo_normal); } else { ref_pos_curr = new_position; ref_pos_prev = new_pos_prev; + ref_geo_normal = new_geo_normal; } + + // compute the motion vector assuming that the primary surface is a static plane vec2 screen_pos_curr, screen_pos_prev; float distance_curr, distance_prev; projection_view_to_screen((global_ubo.V * vec4(ref_pos_curr, 1)).xyz, screen_pos_curr, distance_curr, false); @@ -561,8 +591,27 @@ direct_lighting(ivec2 ipos, bool is_odd_checkerboard, out vec3 high_freq, out ve motion.xy = screen_pos_prev - screen_pos_curr; motion.z = distance_prev - distance_curr; - float fwidth_depth = imageLoad(IMG_PT_MOTION, ipos).w; - //imageStore(IMG_PT_VIEW_DEPTH_A, ipos, vec4(distance_curr)); + + // compute the depth slope using ray differentials + const ivec2 image_position = get_image_position(); + const vec2 pixel_center = vec2(image_position) + vec2(0.5); + const vec2 inUV = pixel_center / vec2(get_image_size()); + + Ray ray_0 = get_primary_ray(inUV); + Ray ray_x = get_primary_ray(inUV + vec2(1.0 / float(global_ubo.width), 0)); + Ray ray_y = get_primary_ray(inUV + vec2(0, 1.0 / float(global_ubo.height))); + + float depth_vs_0 = ray_distance_to_plane(ref_pos_curr, ref_geo_normal, global_ubo.cam_pos.xyz, ray_0.direction); + float depth_vs_x = ray_distance_to_plane(ref_pos_curr, ref_geo_normal, global_ubo.cam_pos.xyz, ray_x.direction); + float depth_vs_y = ray_distance_to_plane(ref_pos_curr, ref_geo_normal, global_ubo.cam_pos.xyz, ray_y.direction); + float fwidth_depth = 1.0 / max(0.1, (abs(depth_vs_x - depth_vs_0) * 2 + abs(depth_vs_y - depth_vs_0))); + + // Use negative depth for reflections and refractions to prevent various filters from + // filtering across reflection boundaries. + motion.z = -motion.z; + distance_curr = -distance_curr; + + imageStore(IMG_PT_VIEW_DEPTH_A, ipos, vec4(distance_curr)); imageStore(IMG_PT_MOTION, ipos, vec4(motion, fwidth_depth)); }