diff options
author | Clément Foucault <foucault.clem@gmail.com> | 2017-08-09 16:29:44 +0300 |
---|---|---|
committer | Clément Foucault <foucault.clem@gmail.com> | 2017-08-10 16:43:48 +0300 |
commit | 99f37bf2a2ad452ee995cd8ce9ce60d010b1f7f9 (patch) | |
tree | 7b8c88a5032b26931245fc9ac1b36a049ada4524 /source/blender/draw | |
parent | 292f5ab7584d6e9ba54893eaafd70d9ee8d1c3ce (diff) |
Eevee: SSR: Refine Raytrace Algorithm.
We track the previous ray position offseted by the thickness. If the sampled depth is between this value and the current ray position then we have a hit.
This fixes rays that are almost colinear with the view vector. Thickness is now only important for rays that are comming back to the camera.
As a consequence, this simplify a lot of things.
Also include some refactor.
Diffstat (limited to 'source/blender/draw')
4 files changed, 133 insertions, 149 deletions
diff --git a/source/blender/draw/engines/eevee/eevee_effects.c b/source/blender/draw/engines/eevee/eevee_effects.c index 8475e280a32..b01f46b1651 100644 --- a/source/blender/draw/engines/eevee/eevee_effects.c +++ b/source/blender/draw/engines/eevee/eevee_effects.c @@ -780,7 +780,7 @@ void EEVEE_effects_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata) DRW_shgroup_uniform_buffer(grp, "normalBuffer", &txl->ssr_normal_input); DRW_shgroup_uniform_buffer(grp, "specroughBuffer", &txl->ssr_specrough_input); DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); - DRW_shgroup_uniform_buffer(grp, "colorBuffer", &txl->color_double_buffer); + DRW_shgroup_uniform_buffer(grp, "prevColorBuffer", &txl->color_double_buffer); DRW_shgroup_uniform_mat4(grp, "PastViewProjectionMatrix", (float *)stl->g_data->prev_persmat); DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)stl->g_data->viewvecs, 2); DRW_shgroup_uniform_int(grp, "planar_count", &sldata->probes->num_planar, 1); diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl index 27a08a98b4a..a766a16968d 100644 --- a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl @@ -29,6 +29,13 @@ flat in int shFace; /* Shadow layer we are rendering to. */ uniform vec2 mipRatio[10]; +/* Buffers */ +uniform sampler2D colorBuffer; +uniform sampler2D depthBuffer; +uniform sampler2D maxzBuffer; +uniform sampler2D minzBuffer; +uniform sampler2DArray planarDepth; + #define cameraForward normalize(ViewMatrixInverse[2].xyz) #define cameraPos ViewMatrixInverse[3].xyz #define cameraVec ((ProjectionMatrix[3][3] == 0.0) ? normalize(cameraPos - worldPosition) : cameraForward) diff --git a/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl index fb59c522deb..b1286fd15f0 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl @@ -7,26 +7,6 @@ uniform sampler2DArray utilTex; #endif /* UTIL_TEX */ -uniform int rayCount; -uniform float maxRoughness; - -#define BRDF_BIAS 0.7 - -vec3 generate_ray(vec3 V, vec3 N, float a2, vec3 rand, out float pdf) -{ - float NH; - vec3 T, B; - make_orthonormal_basis(N, T, B); /* Generate tangent space */ - - /* Importance sampling bias */ - rand.x = mix(rand.x, 0.0, BRDF_BIAS); - - /* TODO distribution of visible normals */ - vec3 H = sample_ggx(rand, a2, N, T, B, NH); /* Microfacet normal */ - pdf = min(1024e32, pdf_ggx_reflect(NH, a2)); /* Theoretical limit of 16bit float */ - return reflect(-V, H); -} - #define MAX_MIP 9.0 #ifdef STEP_RAYTRACE @@ -41,51 +21,57 @@ layout(location = 1) out vec4 hitData1; layout(location = 2) out vec4 hitData2; layout(location = 3) out vec4 hitData3; -bool has_hit_backface(vec3 hit_pos, vec3 R, vec3 V) +vec4 do_planar_ssr(int index, vec3 V, vec3 N, vec3 T, vec3 B, vec3 planeNormal, vec3 viewPosition, float a2, vec3 rand, float ofs) { - vec2 hit_co = project_point(ProjectionMatrix, hit_pos).xy * 0.5 + 0.5; - vec3 hit_N = normal_decode(textureLod(normalBuffer, hit_co, 0.0).rg, V); - return (dot(-R, hit_N) < 0.0); -} + float pdf, NH; + float jitter = fract(rand.x + ofs); -vec4 do_planar_ssr(int index, vec3 V, vec3 N, vec3 planeNormal, vec3 viewPosition, float a2, vec3 rand, float ray_nbr) -{ - float pdf; - vec3 R = generate_ray(V, N, a2, rand, pdf); + /* Importance sampling bias */ + rand.x = mix(rand.x, 0.0, BRDF_BIAS); + vec3 H = sample_ggx(rand, a2, N, T, B, NH); /* Microfacet normal */ + pdf = pdf_ggx_reflect(NH, a2); + + vec3 R = reflect(-V, H); R = reflect(R, planeNormal); - pdf *= -1.0; /* Tag as planar ray. */ - /* If ray is bad (i.e. going below the plane) do not trace. */ + /* If ray is bad (i.e. going below the plane) regenerate. */ if (dot(R, planeNormal) > 0.0) { - vec3 R = generate_ray(V, N, a2, rand * vec3(1.0, -1.0, -1.0), pdf); - } + vec3 H = sample_ggx(rand * vec3(1.0, -1.0, -1.0), a2, N, T, B, NH); /* Microfacet normal */ + pdf = pdf_ggx_reflect(NH, a2); - vec3 hit_pos; - if (abs(dot(-R, V)) < 0.9999) { - /* Since viewspace hit position can land behind the camera in this case, - * we save the reflected view position (visualize it as the hit position - * below the reflection plane). This way it's garanted that the hit will - * be in front of the camera. That let us tag the bad rays with a negative - * sign in the Z component. */ - hit_pos = raycast(index, viewPosition, R, fract(rand.x + (ray_nbr / float(rayCount))), a2); - } - else { - vec2 uvs = project_point(ProjectionMatrix, viewPosition).xy * 0.5 + 0.5; - float raw_depth = textureLod(planarDepth, vec3(uvs, float(index)), 0.0).r; - hit_pos = get_view_space_from_depth(uvs, raw_depth); - hit_pos.z *= (raw_depth < 1.0) ? 1.0 : -1.0; + R = reflect(-V, H); + R = reflect(R, planeNormal); } + pdf = min(1024e32, pdf); /* Theoretical limit of 16bit float */ + pdf *= -1.0; /* Tag as planar ray. */ + + /* Since viewspace hit position can land behind the camera in this case, + * we save the reflected view position (visualize it as the hit position + * below the reflection plane). This way it's garanted that the hit will + * be in front of the camera. That let us tag the bad rays with a negative + * sign in the Z component. */ + vec3 hit_pos = raycast(index, viewPosition, R, 1e16, jitter, a2); + return vec4(hit_pos, pdf); } -vec4 do_ssr(vec3 V, vec3 N, vec3 viewPosition, float a2, vec3 rand, float ray_nbr) +vec4 do_ssr(vec3 V, vec3 N, vec3 T, vec3 B, vec3 viewPosition, float a2, vec3 rand, float ofs) { - float pdf; - vec3 R = generate_ray(V, N, a2, rand, pdf); + float pdf, NH; + float jitter = fract(rand.x + ofs); + + /* Importance sampling bias */ + rand.x = mix(rand.x, 0.0, BRDF_BIAS); + + vec3 H = sample_ggx(rand, a2, N, T, B, NH); /* Microfacet normal */ + pdf = pdf_ggx_reflect(NH, a2); + + vec3 R = reflect(-V, H); + pdf = min(1024e32, pdf); /* Theoretical limit of 16bit float */ - vec3 hit_pos = raycast(-1, viewPosition, R, fract(rand.x + (ray_nbr / float(rayCount))), a2); + vec3 hit_pos = raycast(-1, viewPosition, R, ssrThickness, jitter, a2); return vec4(hit_pos, pdf); } @@ -138,6 +124,11 @@ void main() vec3 worldPosition = transform_point(ViewMatrixInverse, viewPosition); vec3 wN = transform_direction(ViewMatrixInverse, N); + vec3 T, B; + make_orthonormal_basis(N, T, B); /* Generate tangent space */ + + float ray_ofs = 1.0 / float(rayCount); + /* Planar Reflections */ for (int i = 0; i < MAX_PLANAR && i < planar_count; ++i) { PlanarData pd = planars_data[i]; @@ -152,24 +143,24 @@ void main() vec3 planeNormal = transform_direction(ViewMatrix, pd.pl_normal); /* TODO : Raytrace together if textureGather is supported. */ - hitData0 = do_planar_ssr(i, V, N, planeNormal, tracePosition, a2, rand, 0.0); - if (rayCount > 1) hitData1 = do_planar_ssr(i, V, N, planeNormal, tracePosition, a2, rand.xyz * vec3(1.0, -1.0, -1.0), 1.0); - if (rayCount > 2) hitData2 = do_planar_ssr(i, V, N, planeNormal, tracePosition, a2, rand.xzy * vec3(1.0, 1.0, -1.0), 2.0); - if (rayCount > 3) hitData3 = do_planar_ssr(i, V, N, planeNormal, tracePosition, a2, rand.xzy * vec3(1.0, -1.0, 1.0), 3.0); + hitData0 = do_planar_ssr(i, V, N, T, B, planeNormal, tracePosition, a2, rand, 0.0); + if (rayCount > 1) hitData1 = do_planar_ssr(i, V, N, T, B, planeNormal, tracePosition, a2, rand.xyz * vec3(1.0, -1.0, -1.0), 1.0 * ray_ofs); + if (rayCount > 2) hitData2 = do_planar_ssr(i, V, N, T, B, planeNormal, tracePosition, a2, rand.xzy * vec3(1.0, 1.0, -1.0), 2.0 * ray_ofs); + if (rayCount > 3) hitData3 = do_planar_ssr(i, V, N, T, B, planeNormal, tracePosition, a2, rand.xzy * vec3(1.0, -1.0, 1.0), 3.0 * ray_ofs); return; } } /* TODO : Raytrace together if textureGather is supported. */ - hitData0 = do_ssr(V, N, viewPosition, a2, rand, 0.0); - if (rayCount > 1) hitData1 = do_ssr(V, N, viewPosition, a2, rand.xyz * vec3(1.0, -1.0, -1.0), 1.0); - if (rayCount > 2) hitData2 = do_ssr(V, N, viewPosition, a2, rand.xzy * vec3(1.0, 1.0, -1.0), 2.0); - if (rayCount > 3) hitData3 = do_ssr(V, N, viewPosition, a2, rand.xzy * vec3(1.0, -1.0, 1.0), 3.0); + hitData0 = do_ssr(V, N, T, B, viewPosition, a2, rand, 0.0); + if (rayCount > 1) hitData1 = do_ssr(V, N, T, B, viewPosition, a2, rand.xyz * vec3(1.0, -1.0, -1.0), 1.0 * ray_ofs); + if (rayCount > 2) hitData2 = do_ssr(V, N, T, B, viewPosition, a2, rand.xzy * vec3(1.0, 1.0, -1.0), 2.0 * ray_ofs); + if (rayCount > 3) hitData3 = do_ssr(V, N, T, B, viewPosition, a2, rand.xzy * vec3(1.0, -1.0, 1.0), 3.0 * ray_ofs); } #else /* STEP_RESOLVE */ -uniform sampler2D colorBuffer; /* previous frame */ +uniform sampler2D prevColorBuffer; /* previous frame */ uniform sampler2D normalBuffer; uniform sampler2D specroughBuffer; @@ -181,9 +172,6 @@ uniform sampler2D hitBuffer3; uniform int probe_count; uniform int planar_count; -uniform float borderFadeFactor; -uniform float fireflyFactor; - uniform mat4 PastViewProjectionMatrix; out vec4 fragColor; @@ -242,17 +230,6 @@ float brightness(vec3 c) return max(max(c.r, c.g), c.b); } -float screen_border_mask(vec2 hit_co) -{ - const float margin = 0.003; - float atten = borderFadeFactor + margin; /* Screen percentage */ - hit_co = smoothstep(margin, atten, hit_co) * (1 - smoothstep(1.0 - atten, 1.0 - margin, hit_co)); - - float screenfade = hit_co.x * hit_co.y; - - return screenfade; -} - vec2 get_reprojected_reflection(vec3 hit, vec3 pos, vec3 N) { /* TODO real reprojection with motion vectors, etc... */ @@ -321,7 +298,7 @@ vec4 get_ssr_sample( sample = textureLod(probePlanars, vec3(ref_uvs, planar_index), mip).rgb; } else { - sample = textureLod(colorBuffer, ref_uvs, mip).rgb; + sample = textureLod(prevColorBuffer, ref_uvs, mip).rgb; } /* Clamped brightness. */ diff --git a/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl b/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl index 7afabfc5c3d..d0fc14f8a29 100644 --- a/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl @@ -2,16 +2,16 @@ #define MAX_REFINE_STEP 32 /* Should be max allowed stride */ uniform vec4 ssrParameters; - -uniform sampler2D depthBuffer; -uniform sampler2D maxzBuffer; -uniform sampler2D minzBuffer; -uniform sampler2DArray planarDepth; +uniform int rayCount; #define ssrQuality ssrParameters.x #define ssrThickness ssrParameters.y #define ssrPixelSize ssrParameters.zw +uniform float maxRoughness; +uniform float borderFadeFactor; +uniform float fireflyFactor; + float sample_depth(vec2 uv, int index, float lod) { if (index > -1) { @@ -24,26 +24,6 @@ float sample_depth(vec2 uv, int index, float lod) } } -float sample_minz_depth(vec2 uv, int index) -{ - if (index > -1) { - return textureLod(planarDepth, vec3(uv, index), 0.0).r; - } - else { - return textureLod(minzBuffer, uv, 0.0).r; - } -} - -float sample_maxz_depth(vec2 uv, int index) -{ - if (index > -1) { - return textureLod(planarDepth, vec3(uv, index), 0.0).r; - } - else { - return textureLod(maxzBuffer, uv, 0.0).r; - } -} - vec4 sample_depth_grouped(vec4 uv1, vec4 uv2, int index, float lod) { vec4 depths; @@ -82,7 +62,7 @@ float refine_isect(float prev_delta, float curr_delta) return saturate(prev_delta / (prev_delta - curr_delta)); } -void prepare_raycast(vec3 ray_origin, vec3 ray_dir, out vec4 ss_step, out vec4 ss_ray, out float max_time) +void prepare_raycast(vec3 ray_origin, vec3 ray_dir, float thickness, out vec4 ss_step, out vec4 ss_ray, out float max_time) { /* Negate the ray direction if it goes towards the camera. * This way we don't need to care if the projected point @@ -91,27 +71,42 @@ void prepare_raycast(vec3 ray_origin, vec3 ray_dir, out vec4 ss_step, out vec4 s vec3 ray_end = z_sign * ray_dir * 1e16 + ray_origin; /* Project into screen space. */ - vec3 ss_start = project_point(ProjectionMatrix, ray_origin); - vec3 ss_end = project_point(ProjectionMatrix, ray_end); - /* 4th component is current stride */ - ss_step = vec4(z_sign * normalize(ss_end - ss_start), 1.0); + vec4 ss_start, ss_end; + ss_start.xyz = project_point(ProjectionMatrix, ray_origin); + ss_end.xyz = project_point(ProjectionMatrix, ray_end); + + /* We interpolate the ray Z + thickness values to check if depth is within threshold. */ + ray_origin.z -= thickness; + ray_end.z -= thickness; + ss_start.w = project_point(ProjectionMatrix, ray_origin).z; + ss_end.w = project_point(ProjectionMatrix, ray_end).z; + + /* XXX This is a hack a better method is welcome ! */ + /* We take the delta between the offseted depth and the depth and substract it from the ray depth. + * This will change the world space thickness appearance a bit but we can have negative + * values without worries. We cannot do this in viewspace because of the perspective division. */ + ss_start.w = 2.0 * ss_start.z - ss_start.w; + ss_end.w = 2.0 * ss_end.z - ss_end.w; + + ss_step = ss_end - ss_start; + ss_step = z_sign * ss_step / length(ss_step.xyz); /* If the line is degenerate, make it cover at least one pixel * to not have to handle zero-pixel extent as a special case later */ - ss_step.xy += vec2((dot(ss_step.xy, ss_step.xy) < 0.00001) ? 0.001 : 0.0); + ss_step.xy += vec2((dot(ss_step.xy, ss_step.xy) < 0.000001) ? 0.001 : 0.0); /* Make ss_step cover one pixel. */ - ss_step.xyz /= max(abs(ss_step.x), abs(ss_step.y)); - ss_step.xyz *= ((abs(ss_step.x) > abs(ss_step.y)) ? ssrPixelSize.x : ssrPixelSize.y); + ss_step /= max(abs(ss_step.x), abs(ss_step.y)); + ss_step *= ((abs(ss_step.x) > abs(ss_step.y)) ? ssrPixelSize.x : ssrPixelSize.y); /* Clipping to frustum sides. */ - max_time = line_unit_box_intersect_dist(ss_start, ss_step.xyz) - 1.0; + max_time = line_unit_box_intersect_dist(ss_start.xyz, ss_step.xyz); /* Convert to texture coords. Z component included * since this is how it's stored in the depth buffer. * 4th component how far we are on the ray */ - ss_ray = vec4(ss_start * 0.5 + 0.5, 0.0); - ss_step.xyz *= 0.5; + ss_ray = ss_start * 0.5 + 0.5; + ss_step *= 0.5; } /* See times_and_deltas. */ @@ -120,30 +115,35 @@ void prepare_raycast(vec3 ray_origin, vec3 ray_dir, out vec4 ss_step, out vec4 s #define curr_delta times_and_deltas.z #define prev_delta times_and_deltas.w -// #define GROUPED_FETCHES +// #define GROUPED_FETCHES /* is still slower, need to see where is the bottleneck. */ /* Return the hit position, and negate the z component (making it positive) if not hit occured. */ -vec3 raycast(int index, vec3 ray_origin, vec3 ray_dir, float ray_jitter, float roughness) +vec3 raycast(int index, vec3 ray_origin, vec3 ray_dir, float thickness, float ray_jitter, float roughness) { vec4 ss_step, ss_start; float max_time; - prepare_raycast(ray_origin, ray_dir, ss_step, ss_start, max_time); + prepare_raycast(ray_origin, ray_dir, thickness, ss_step, ss_start, max_time); + + float max_trace_time = max(0.001, max_time - 0.01); #ifdef GROUPED_FETCHES ray_jitter *= 0.25; #endif - /* x : current_time, y: previous_time, z: previous_delta, w: current_delta */ - vec4 times_and_deltas = vec4(0.0, 0.0, 0.001, 0.001); + + /* x : current_time, y: previous_time, z: current_delta, w: previous_delta */ + vec4 times_and_deltas = vec4(0.0); float ray_time = 0.0; - float depth_sample; + float depth_sample = sample_depth(ss_start.xy, index, 0.0); + curr_delta = depth_sample - ss_start.z; float lod_fac = saturate(fast_sqrt(roughness) * 2.0 - 0.4); bool hit = false; float iter; - for (iter = 1.0; !hit && (ray_time <= max_time) && (iter < MAX_STEP); iter++) { + for (iter = 1.0; !hit && (ray_time < max_time) && (iter < MAX_STEP); iter++) { /* Minimum stride of 2 because we are using half res minmax zbuffer. */ float stride = max(1.0, iter * ssrQuality) * 2.0; float lod = log2(stride * 0.5 * ssrQuality) * lod_fac; + ray_time += stride; /* Save previous values. */ times_and_deltas.xyzw = times_and_deltas.yxwz; @@ -152,7 +152,7 @@ vec3 raycast(int index, vec3 ray_origin, vec3 ray_dir, float ray_jitter, float r stride *= 4.0; vec4 jit_stride = mix(vec4(2.0), vec4(stride), vec4(0.0, 0.25, 0.5, 0.75) + ray_jitter); - vec4 times = vec4(ray_time) + jit_stride; + vec4 times = min(vec4(ray_time) + jit_stride, vec4(max_trace_time)); vec4 uv1 = ss_start.xyxy + ss_step.xyxy * times.xxyy; vec4 uv2 = ss_start.xyxy + ss_step.xyxy * times.zzww; @@ -160,11 +160,13 @@ vec3 raycast(int index, vec3 ray_origin, vec3 ray_dir, float ray_jitter, float r vec4 depth_samples = sample_depth_grouped(uv1, uv2, index, lod); vec4 ray_z = ss_start.zzzz + ss_step.zzzz * times.xyzw; + vec4 ray_w = ss_start.wwww + ss_step.wwww * vec4(prev_time, times.xyz); vec4 deltas = depth_samples - ray_z; - /* Same as component wise (depth_samples <= ray_z) && (ray_time <= max_time). */ - bvec4 test = equal(step(deltas, vec4(0.0)) * step(times, vec4(max_time)), vec4(1.0)); + /* Same as component wise (curr_delta <= 0.0) && (prev_w <= depth_sample). */ + bvec4 test = equal(step(deltas, vec4(0.0)) * step(ray_w, depth_samples), vec4(1.0)); hit = any(test); + if (hit) { vec2 m = vec2(1.0, 0.0); /* Mask */ @@ -177,54 +179,52 @@ vec3 raycast(int index, vec3 ray_origin, vec3 ray_dir, float ray_jitter, float r depth_sample = (test.z) ? depth_samples.z : depth_sample; depth_sample = (test.y) ? depth_samples.y : depth_sample; depth_sample = (test.x) ? depth_samples.x : depth_sample; - break; } - curr_time = times.w; - curr_delta = deltas.w; - ray_time += stride; + else { + curr_time = times.w; + curr_delta = deltas.w; + } #else float jit_stride = mix(2.0, stride, ray_jitter); - curr_time = ray_time + jit_stride; + curr_time = min(ray_time + jit_stride, max_trace_time); vec4 ss_ray = ss_start + ss_step * curr_time; depth_sample = sample_depth(ss_ray.xy, index, lod); + float prev_w = ss_start.w + ss_step.w * prev_time; curr_delta = depth_sample - ss_ray.z; - hit = (curr_delta <= 0.0) && (curr_time <= max_time); - - ray_time += stride; + hit = (curr_delta <= 0.0) && (prev_w <= depth_sample); #endif } + /* Discard backface hits */ + hit = hit && (prev_delta > 0.0); + + /* Reject hit if background. */ + hit = hit && (depth_sample != 1.0); + curr_time = (hit) ? mix(prev_time, curr_time, refine_isect(prev_delta, curr_delta)) : curr_time; ray_time = (hit) ? curr_time : ray_time; -#if 0 /* Not needed if using refine_isect() */ - /* Binary search */ - for (float time_step = (curr_time - prev_time) * 0.5; time_step > 1.0; time_step /= 2.0) { - ray_time -= time_step; - vec4 ss_ray = ss_start + ss_step * ray_time; - float depth_sample = sample_maxz_depth(ss_ray.xy, index); - bool is_hit = (depth_sample - ss_ray.z <= 0.0); - ray_time = (is_hit) ? ray_time : ray_time + time_step; - } -#endif - /* Clip to frustum. */ - ray_time = min(ray_time, max_time - 0.5); + ray_time = max(0.001, min(ray_time, max_time - 1.5)); vec4 ss_ray = ss_start + ss_step * ray_time; vec3 hit_pos = get_view_space_from_depth(ss_ray.xy, ss_ray.z); - /* Reject hit if not within threshold. */ - /* TODO do this check while tracing. Potentially higher quality */ - if (hit && (index == -1)) { - float z = get_view_z_from_depth(depth_sample); - hit = hit && ((z - hit_pos.z - ssrThickness) <= ssrThickness); - } - /* Tag Z if ray failed. */ hit_pos.z *= (hit) ? 1.0 : -1.0; return hit_pos; } + +float screen_border_mask(vec2 hit_co) +{ + const float margin = 0.003; + float atten = borderFadeFactor + margin; /* Screen percentage */ + hit_co = smoothstep(margin, atten, hit_co) * (1 - smoothstep(1.0 - atten, 1.0 - margin, hit_co)); + + float screenfade = hit_co.x * hit_co.y; + + return screenfade; +} |