diff options
author | Clément Foucault <foucault.clem@gmail.com> | 2021-05-05 19:13:24 +0300 |
---|---|---|
committer | Clément Foucault <foucault.clem@gmail.com> | 2021-05-05 19:40:20 +0300 |
commit | a1a9f8e6c3f341061777bc2d985b35e9d7a20ad1 (patch) | |
tree | 36f2a3f8cc329c45d8c7e2872cfbd40134ff13f7 /source/blender | |
parent | 95889fe071e179a9a7d7e6a27aaf7a4a42fc49b8 (diff) |
Fix T87068 EEVEE: Moire effect with particle hair and subsurface
This artifact was already present in previous version but was hidden
by the faulty SSS scale.
The issue comes from the translucence using the geometric normal
(computed using fragment shader derivative) leading to poor precision at
depth discontinuity.
Replacing using the same geometric normal reconstruction as the ambient
occlusion pass removes most of the issue.
Diffstat (limited to 'source/blender')
-rw-r--r-- | source/blender/draw/engines/eevee/shaders/effect_translucency_frag.glsl | 60 |
1 files changed, 57 insertions, 3 deletions
diff --git a/source/blender/draw/engines/eevee/shaders/effect_translucency_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_translucency_frag.glsl index 737ef7dc509..356ed102928 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_translucency_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_translucency_frag.glsl @@ -183,16 +183,70 @@ vec3 light_translucent(LightData ld, vec3 P, vec3 N, vec4 l_vector, vec2 rand, f #undef scube #undef scsmd +/* Similar to https://atyuwen.github.io/posts/normal-reconstruction/. + * This samples the depth buffer 4 time for each direction to get the most correct + * implicit normal reconstruction out of the depth buffer. */ +vec3 view_position_derivative_from_depth(vec2 uvs, vec2 ofs, vec3 vP, float depth_center) +{ + vec2 uv1 = uvs - ofs * 2.0; + vec2 uv2 = uvs - ofs; + vec2 uv3 = uvs + ofs; + vec2 uv4 = uvs + ofs * 2.0; + vec4 H; + H.x = textureLod(depthBuffer, uv1, 0.0).r; + H.y = textureLod(depthBuffer, uv2, 0.0).r; + H.z = textureLod(depthBuffer, uv3, 0.0).r; + H.w = textureLod(depthBuffer, uv4, 0.0).r; + /* Fix issue with depth precision. Take even larger diff. */ + vec4 diff = abs(vec4(depth_center, H.yzw) - H.x); + if (max_v4(diff) < 2.4e-7 && all(lessThan(diff.xyz, diff.www))) { + return 0.25 * (get_view_space_from_depth(uv3, H.w) - get_view_space_from_depth(uv1, H.x)); + } + /* Simplified (H.xw + 2.0 * (H.yz - H.xw)) - depth_center */ + vec2 deltas = abs((2.0 * H.yz - H.xw) - depth_center); + if (deltas.x < deltas.y) { + return vP - get_view_space_from_depth(uv2, H.y); + } + else { + return get_view_space_from_depth(uv3, H.z) - vP; + } +} + +/* TODO(fclem) port to a common place for other effects to use. */ +bool reconstruct_view_position_and_normal_from_depth(vec2 uvs, out vec3 vP, out vec3 vNg) +{ + vec2 texel_size = vec2(abs(dFdx(uvs.x)), abs(dFdy(uvs.y))); + float depth_center = textureLod(depthBuffer, uvs, 0.0).r; + + vP = get_view_space_from_depth(uvs, depth_center); + + vec3 dPdx = view_position_derivative_from_depth(uvs, texel_size * vec2(1, 0), vP, depth_center); + vec3 dPdy = view_position_derivative_from_depth(uvs, texel_size * vec2(0, 1), vP, depth_center); + + vNg = safe_normalize(cross(dPdx, dPdy)); + + /* Background case. */ + if (depth_center == 1.0) { + return false; + } + + return true; +} + void main(void) { vec2 uvs = uvcoordsvar.xy; float sss_scale = texture(sssRadius, uvs).r; - vec3 P = get_world_space_from_depth(uvs, texture(depthBuffer, uvs).r); - vec3 N = normalize(cross(dFdx(P), dFdy(P))); vec3 rand = texelfetch_noise_tex(gl_FragCoord.xy).zwy; rand.xy *= fast_sqrt(rand.z); + vec3 vP, vNg; + reconstruct_view_position_and_normal_from_depth(uvs, vP, vNg); + + vec3 P = point_view_to_world(vP); + vec3 Ng = normal_view_to_world(vNg); + vec3 accum = vec3(0.0); for (int i = 0; i < MAX_LIGHT && i < laNumLight; i++) { LightData ld = lights_data[i]; @@ -211,7 +265,7 @@ void main(void) continue; } - accum += att * ld.l_color * light_translucent(ld, P, -N, l_vector, rand.xy, sss_scale); + accum += att * ld.l_color * light_translucent(ld, P, -Ng, l_vector, rand.xy, sss_scale); } FragColor = vec4(accum, 1.0); |