diff options
author | Clément Foucault <foucault.clem@gmail.com> | 2021-03-09 13:24:16 +0300 |
---|---|---|
committer | Clément Foucault <foucault.clem@gmail.com> | 2021-03-10 19:57:09 +0300 |
commit | 9957096f35fcb9d63ae611464667638dcbfb6dd6 (patch) | |
tree | 040ac288e69047e57b190f3e01b224feb18a8d12 /source/blender | |
parent | 79bc4962d376a37356752334d43021a18fbdba5b (diff) |
EEVEE: ScreenSpaceReflections: Improve hit quality
This changes the hitBuffer to store `ReflectionDir * HitTime, invPdf`
just as the reference presentation.
This avoids issues when the hit refinement produce a coordinate that
does not land on the correct surface.
We now store the pdf in the same texture and store it inversed so we can
remove some ALU from the resolve shader.
This also rewrite the resolve shader to not be vectorized to improve
readability and scalability.
Diffstat (limited to 'source/blender')
10 files changed, 190 insertions, 389 deletions
diff --git a/source/blender/draw/engines/eevee/eevee_effects.c b/source/blender/draw/engines/eevee/eevee_effects.c index d1d7c67d16c..f4f7acb8862 100644 --- a/source/blender/draw/engines/eevee/eevee_effects.c +++ b/source/blender/draw/engines/eevee/eevee_effects.c @@ -149,8 +149,6 @@ void EEVEE_effects_init(EEVEE_ViewLayerData *sldata, */ common_data->hiz_uv_scale[0] = viewport_size[0] / effects->hiz_size[0]; common_data->hiz_uv_scale[1] = viewport_size[1] / effects->hiz_size[1]; - common_data->hiz_uv_scale[2] = 1.0f / effects->hiz_size[0]; - common_data->hiz_uv_scale[3] = 1.0f / effects->hiz_size[1]; /* Compute pixel size. Size is multiplied by 2 because it is applied in NDC [-1..1] range. */ sldata->common_data.ssr_pixelsize[0] = 2.0f / size_fs[0]; diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c index bc7db4b5df6..042fa621117 100644 --- a/source/blender/draw/engines/eevee/eevee_materials.c +++ b/source/blender/draw/engines/eevee/eevee_materials.c @@ -128,7 +128,8 @@ void EEVEE_material_bind_resources(DRWShadingGroup *shgrp, DRW_shgroup_uniform_float_copy( shgrp, "refractionDepth", (refract_depth) ? *refract_depth : 0.0); if (use_ssrefraction) { - DRW_shgroup_uniform_texture_ref(shgrp, "colorBuffer", &vedata->txl->filtered_radiance); + DRW_shgroup_uniform_texture_ref( + shgrp, "refractColorBuffer", &vedata->txl->filtered_radiance); } } if (use_alpha_blend) { diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h index 45afee31591..eb1c51f49dd 100644 --- a/source/blender/draw/engines/eevee/eevee_private.h +++ b/source/blender/draw/engines/eevee/eevee_private.h @@ -737,7 +737,6 @@ typedef struct EEVEE_EffectsInfo { struct GPUTexture *ssr_normal_input; /* Textures from pool */ struct GPUTexture *ssr_specrough_input; struct GPUTexture *ssr_hit_output; - struct GPUTexture *ssr_pdf_output; /* Temporal Anti Aliasing */ int taa_reproject_sample; int taa_current_sample; @@ -854,8 +853,8 @@ typedef struct EEVEE_EffectsInfo { * - Arrays of vec2/vec3 are padded as arrays of vec4. * - sizeof(bool) == sizeof(int) in GLSL so use int in C */ typedef struct EEVEE_CommonUniformBuffer { - float prev_persmat[4][4]; /* mat4 */ - float hiz_uv_scale[4]; /* vec4 */ + float prev_persmat[4][4]; /* mat4 */ + float hiz_uv_scale[2], ssr_uv_scale[2]; /* vec4 */ /* Ambient Occlusion */ /* -- 16 byte aligned -- */ float ao_dist, pad1, ao_factor, pad2; /* vec4 */ diff --git a/source/blender/draw/engines/eevee/eevee_renderpasses.c b/source/blender/draw/engines/eevee/eevee_renderpasses.c index 0e16037f42d..5739024993e 100644 --- a/source/blender/draw/engines/eevee/eevee_renderpasses.c +++ b/source/blender/draw/engines/eevee/eevee_renderpasses.c @@ -490,7 +490,7 @@ void EEVEE_renderpasses_draw_debug(EEVEE_Data *vedata) tx = txl->maxzbuffer; break; case 2: - tx = effects->ssr_pdf_output; + /* UNUSED */ break; case 3: tx = effects->ssr_normal_input; diff --git a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c index 80a1c9fcbe5..00004b28ef3 100644 --- a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c +++ b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c @@ -77,6 +77,7 @@ int EEVEE_screen_raytrace_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) common_data->ssr_firefly_fac = FLT_MAX; } + void *owner = (void *)EEVEE_screen_raytrace_init; const int divisor = (effects->reflection_trace_full) ? 1 : 2; int tracing_res[2] = {(int)viewport_size[0] / divisor, (int)viewport_size[1] / divisor}; const int size_fs[2] = {(int)viewport_size[0], (int)viewport_size[1]}; @@ -86,22 +87,22 @@ int EEVEE_screen_raytrace_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) tracing_res[0] = max_ii(1, tracing_res[0]); tracing_res[1] = max_ii(1, tracing_res[1]); + common_data->ssr_uv_scale[0] = size_fs[0] / ((float)tracing_res[0] * divisor); + common_data->ssr_uv_scale[1] = size_fs[1] / ((float)tracing_res[1] * divisor); + /* MRT for the shading pass in order to output needed data for the SSR pass. */ - effects->ssr_specrough_input = DRW_texture_pool_query_2d( - size_fs[0], size_fs[1], format, &draw_engine_eevee_type); + effects->ssr_specrough_input = DRW_texture_pool_query_2d(UNPACK2(size_fs), format, owner); GPU_framebuffer_texture_attach(fbl->main_fb, effects->ssr_specrough_input, 2, 0); /* Ray-tracing output. */ - effects->ssr_hit_output = DRW_texture_pool_query_2d( - tracing_res[0], tracing_res[1], GPU_RG16I, &draw_engine_eevee_type); - effects->ssr_pdf_output = DRW_texture_pool_query_2d( - tracing_res[0], tracing_res[1], GPU_R16F, &draw_engine_eevee_type); + effects->ssr_hit_output = DRW_texture_pool_query_2d(UNPACK2(tracing_res), GPU_RGBA16F, owner); GPU_framebuffer_ensure_config(&fbl->screen_tracing_fb, - {GPU_ATTACHMENT_NONE, - GPU_ATTACHMENT_TEXTURE(effects->ssr_hit_output), - GPU_ATTACHMENT_TEXTURE(effects->ssr_pdf_output)}); + { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(effects->ssr_hit_output), + }); return EFFECT_SSR | EFFECT_NORMAL_BUFFER | EFFECT_RADIANCE_BUFFER | EFFECT_DOUBLE_BUFFER | ((use_refraction) ? EFFECT_REFRACT : 0); @@ -111,7 +112,6 @@ int EEVEE_screen_raytrace_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) GPU_FRAMEBUFFER_FREE_SAFE(fbl->screen_tracing_fb); effects->ssr_specrough_input = NULL; effects->ssr_hit_output = NULL; - effects->ssr_pdf_output = NULL; return 0; } @@ -148,7 +148,6 @@ void EEVEE_screen_raytrace_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *v */ DRW_PASS_CREATE(psl->ssr_raytrace, DRW_STATE_WRITE_COLOR); DRWShadingGroup *grp = DRW_shgroup_create(trace_shader, psl->ssr_raytrace); - DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &e_data.depth_src); DRW_shgroup_uniform_texture_ref(grp, "normalBuffer", &effects->ssr_normal_input); DRW_shgroup_uniform_texture_ref(grp, "specroughBuffer", &effects->ssr_specrough_input); DRW_shgroup_uniform_texture_ref(grp, "maxzBuffer", &txl->maxzbuffer); @@ -164,17 +163,17 @@ void EEVEE_screen_raytrace_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *v } DRW_shgroup_call(grp, quad, NULL); + eGPUSamplerState no_filter = GPU_SAMPLER_DEFAULT; + DRW_PASS_CREATE(psl->ssr_resolve, DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ADD); grp = DRW_shgroup_create(resolve_shader, psl->ssr_resolve); - DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &e_data.depth_src); DRW_shgroup_uniform_texture_ref(grp, "normalBuffer", &effects->ssr_normal_input); DRW_shgroup_uniform_texture_ref(grp, "specroughBuffer", &effects->ssr_specrough_input); DRW_shgroup_uniform_texture_ref(grp, "probeCubes", &lcache->cube_tx.tex); DRW_shgroup_uniform_texture_ref(grp, "probePlanars", &vedata->txl->planar_pool); DRW_shgroup_uniform_texture_ref(grp, "planarDepth", &vedata->txl->planar_depth); - DRW_shgroup_uniform_texture_ref(grp, "hitBuffer", &effects->ssr_hit_output); - DRW_shgroup_uniform_texture_ref(grp, "pdfBuffer", &effects->ssr_pdf_output); - DRW_shgroup_uniform_texture_ref(grp, "prevColorBuffer", &txl->filtered_radiance); + DRW_shgroup_uniform_texture_ref_ex(grp, "hitBuffer", &effects->ssr_hit_output, no_filter); + DRW_shgroup_uniform_texture_ref(grp, "colorBuffer", &txl->filtered_radiance); DRW_shgroup_uniform_texture_ref(grp, "maxzBuffer", &txl->maxzbuffer); DRW_shgroup_uniform_texture_ref(grp, "shadowCubeTexture", &sldata->shadow_cube_pool); DRW_shgroup_uniform_texture_ref(grp, "shadowCascadeTexture", &sldata->shadow_cascade_pool); diff --git a/source/blender/draw/engines/eevee/shaders/common_uniforms_lib.glsl b/source/blender/draw/engines/eevee/shaders/common_uniforms_lib.glsl index 24de4520207..b3174afc799 100644 --- a/source/blender/draw/engines/eevee/shaders/common_uniforms_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/common_uniforms_lib.glsl @@ -69,3 +69,5 @@ layout(std140) uniform common_block #define ssrQuality ssrParameters.x #define ssrThickness ssrParameters.y #define ssrPixelSize ssrParameters.zw + +#define ssrUvScale hizUvScale.zw 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 66183e1bc02..a9139b7a146 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl @@ -6,32 +6,55 @@ #pragma BLENDER_REQUIRE(closure_eval_lib.glsl) #pragma BLENDER_REQUIRE(raytrace_lib.glsl) #pragma BLENDER_REQUIRE(lightprobe_lib.glsl) -#pragma BLENDER_REQUIRE(ssr_lib.glsl) - -/* Based on Stochastic Screen Space Reflections - * https://www.ea.com/frostbite/news/stochastic-screen-space-reflections */ - -#define MAX_MIP 9.0 +#pragma BLENDER_REQUIRE(bsdf_common_lib.glsl) +#pragma BLENDER_REQUIRE(bsdf_sampling_lib.glsl) +#pragma BLENDER_REQUIRE(surface_lib.glsl) + +/* Based on: + * "Stochastic Screen Space Reflections" + * by Tomasz Stachowiak. + * https://www.ea.com/frostbite/news/stochastic-screen-space-reflections + * and + * "Stochastic all the things: raytracing in hybrid real-time rendering" + * by Tomasz Stachowiak. + * https://media.contentapi.ea.com/content/dam/ea/seed/presentations/dd18-seed-raytracing-in-hybrid-real-time-rendering.pdf + */ uniform ivec2 halfresOffset; -ivec2 encode_hit_data(vec2 hit_pos, bool has_hit, bool is_planar) +struct HitData { + /** Hit direction scaled by intersection time. */ + vec3 hit_dir; + /** Inverse probability of ray spawning in this direction. */ + float ray_pdf_inv; + /** True if ray has hit valid geometry. */ + bool is_hit; + /** True if ray was generated from a planar reflection probe. */ + bool is_planar; +}; + +vec4 encode_hit_data(HitData data) { - ivec2 hit_data = ivec2(saturate(hit_pos) * 32767.0); /* 16bit signed int limit */ - hit_data.x *= (is_planar) ? -1 : 1; - hit_data.y *= (has_hit) ? 1 : -1; - return hit_data; + vec4 encoded_data; + encoded_data.xyz = data.hit_dir; + /* Encode planar in Z sign. */ + /* TODO fixme */ + // encoded_data.z = data.is_planar ? -encoded_data.z : encoded_data.z; + /* Record 1.0 / pdf to reduce the computation in the resolve phase. */ + /* Encode hit validity in sign. */ + encoded_data.w = data.ray_pdf_inv * ((data.is_hit) ? 1.0 : -1.0); + return encoded_data; } -vec2 decode_hit_data(vec2 hit_data, out bool has_hit, out bool is_planar) +HitData decode_hit_data(vec4 encoded_data) { - is_planar = (hit_data.x < 0); - has_hit = (hit_data.y > 0); - vec2 hit_co = vec2(abs(hit_data)) / 32767.0; /* 16bit signed int limit */ - if (is_planar) { - hit_co.x = 1.0 - hit_co.x; - } - return hit_co; + HitData data; + data.hit_dir.xyz = encoded_data.xyz; + /* TODO fixme */ + data.is_planar = false; + data.ray_pdf_inv = abs(encoded_data.w); + data.is_hit = (encoded_data.w > 0.0); + return data; } #ifdef STEP_RAYTRACE @@ -39,30 +62,29 @@ vec2 decode_hit_data(vec2 hit_data, out bool has_hit, out bool is_planar) uniform sampler2D normalBuffer; uniform sampler2D specroughBuffer; -layout(location = 0) out ivec2 hitData; -layout(location = 1) out float pdfData; +layout(location = 0) out vec4 hitData; void do_planar_ssr( - int index, vec3 V, vec3 N, vec3 T, vec3 B, vec3 planeNormal, vec3 vP, float a2, vec4 rand) + int index, vec3 V, vec3 N, vec3 T, vec3 B, vec3 viewPlaneNormal, vec3 vP, float a2, vec4 rand) { float NH; - vec3 H = sample_ggx(rand.xzw, a2, N, T, B, NH); /* Microfacet normal */ + /* Microfacet normal */ + vec3 H = sample_ggx(rand.xzw, a2, N, T, B, NH); float pdf = pdf_ggx_reflect(NH, a2); vec3 R = reflect(-V, H); - R = reflect(R, planeNormal); + R = reflect(R, viewPlaneNormal); /* If ray is bad (i.e. going below the plane) regenerate. */ - if (dot(R, planeNormal) > 0.0) { - vec3 H = sample_ggx(rand.xzw * vec3(1.0, -1.0, -1.0), a2, N, T, B, NH); /* Microfacet normal */ + if (dot(R, viewPlaneNormal) > 0.0) { + /* Microfacet normal */ + vec3 H = sample_ggx(rand.xzw * vec3(1.0, -1.0, -1.0), a2, N, T, B, NH); pdf = pdf_ggx_reflect(NH, a2); R = reflect(-V, H); - R = reflect(R, planeNormal); + R = reflect(R, viewPlaneNormal); } - pdfData = min(1024e32, pdf); /* Theoretical limit of 16bit float */ - Ray ray; ray.origin = vP; ray.direction = R * 1e16; @@ -72,10 +94,14 @@ void do_planar_ssr( params.trace_quality = ssrQuality; params.roughness = a2; - vec3 hit_pos; - bool hit = raytrace_planar(ray, params, index, hit_pos); + HitData data; + data.is_planar = true; + data.ray_pdf_inv = safe_rcp(pdf); + data.is_hit = raytrace_planar(ray, params, index, data.hit_dir); + data.hit_dir = get_view_space_from_depth(data.hit_dir.xy, data.hit_dir.z); + data.hit_dir -= ray.origin; - hitData = encode_hit_data(hit_pos.xy, hit, true); + hitData = encode_hit_data(data); } void do_ssr(vec3 V, vec3 N, vec3 T, vec3 B, vec3 vP, float a2, vec4 rand) @@ -85,32 +111,6 @@ void do_ssr(vec3 V, vec3 N, vec3 T, vec3 B, vec3 vP, float a2, vec4 rand) vec3 H = sample_ggx(rand.xzw, a2, N, T, B, NH); vec3 R = reflect(-V, H); - const float bad_ray_threshold = 0.01; - - vec3 vNg = safe_normalize(cross(dFdx(vP), dFdy(vP))); - - /* If ray is bad (i.e. going below the surface) regenerate. */ - if (dot(R, vNg) < bad_ray_threshold) { - H = sample_ggx(rand.xzw * vec3(1.0, -1.0, -1.0), a2, N, T, B, NH); - R = reflect(-V, H); - } - if (dot(R, vNg) < bad_ray_threshold) { - H = sample_ggx(rand.xzw * vec3(1.0, 1.0, -1.0), a2, N, T, B, NH); - R = reflect(-V, H); - } - if (dot(R, vNg) < bad_ray_threshold) { - H = sample_ggx(rand.xzw * vec3(1.0, -1.0, 1.0), a2, N, T, B, NH); - R = reflect(-V, H); - } - if (dot(R, vNg) < bad_ray_threshold) { - /* Not worth tracing. */ - return; - } - - pdfData = min(1024e32, pdf_ggx_reflect(NH, a2)); /* Theoretical limit of 16bit float */ - - vP = raytrace_offset(vP, vNg); - Ray ray; ray.origin = vP; ray.direction = R * 1e16; @@ -121,10 +121,14 @@ void do_ssr(vec3 V, vec3 N, vec3 T, vec3 B, vec3 vP, float a2, vec4 rand) params.trace_quality = ssrQuality; params.roughness = a2; - vec3 hit_pos; - bool hit = raytrace(ray, params, true, hit_pos); + HitData data; + data.is_planar = true; + data.ray_pdf_inv = safe_rcp(pdf_ggx_reflect(NH, a2)); + data.is_hit = raytrace(ray, params, true, data.hit_dir); + data.hit_dir = get_view_space_from_depth(data.hit_dir.xy, data.hit_dir.z); + data.hit_dir -= ray.origin; - hitData = encode_hit_data(hit_pos.xy, hit, false); + hitData = encode_hit_data(data); } in vec4 uvcoordsvar; @@ -132,11 +136,16 @@ in vec4 uvcoordsvar; void main() { vec2 uvs = uvcoordsvar.xy; - float depth = textureLod(depthBuffer, uvs, 0.0).r; + float depth = textureLod(maxzBuffer, uvs * hizUvScale.xy, 0.0).r; + + HitData data; + data.is_planar = false; + data.ray_pdf_inv = safe_rcp(0.0); + data.is_hit = false; + data.hit_dir = vec3(0.0, 0.0, 0.0); /* Default: not hits. */ - hitData = encode_hit_data(vec2(0.5), false, false); - pdfData = 0.0; + hitData = encode_hit_data(data); /* Early out */ /* We can't do discard because we don't clear the render target. */ @@ -193,9 +202,9 @@ void main() /* TODO optimize, use view space for all. */ vec3 tracePosition = line_plane_intersect(P, V, pd.pl_plane_eq); tracePosition = transform_point(ViewMatrix, tracePosition); - vec3 planeNormal = transform_direction(ViewMatrix, pd.pl_normal); + vec3 viewPlaneNormal = transform_direction(ViewMatrix, pd.pl_normal); - do_planar_ssr(i, vV, vN, vT, vB, planeNormal, tracePosition, a2, rand); + do_planar_ssr(i, vV, vN, vT, vB, viewPlaneNormal, tracePosition, a2, rand); return; } } @@ -205,270 +214,92 @@ void main() #else /* STEP_RESOLVE */ -uniform sampler2D prevColorBuffer; /* previous frame */ +uniform sampler2D colorBuffer; /* previous frame */ uniform sampler2D normalBuffer; uniform sampler2D specroughBuffer; - -uniform isampler2D hitBuffer; -uniform sampler2D pdfBuffer; - -uniform int neighborOffset; +uniform sampler2D hitBuffer; in vec4 uvcoordsvar; -const ivec2 neighbors[32] = ivec2[32](ivec2(0, 0), - ivec2(1, 1), - ivec2(-2, 0), - ivec2(0, -2), - ivec2(0, 0), - ivec2(1, -1), - ivec2(-2, 0), - ivec2(0, 2), - ivec2(0, 0), - ivec2(-1, -1), - ivec2(2, 0), - ivec2(0, 2), - ivec2(0, 0), - ivec2(-1, 1), - ivec2(2, 0), - ivec2(0, -2), - - ivec2(0, 0), - ivec2(2, 2), - ivec2(-2, 2), - ivec2(0, -1), - ivec2(0, 0), - ivec2(2, -2), - ivec2(-2, -2), - ivec2(0, 1), - ivec2(0, 0), - ivec2(-2, -2), - ivec2(-2, 2), - ivec2(1, 0), - ivec2(0, 0), - ivec2(2, 2), - ivec2(2, -2), - ivec2(-1, 0)); - out vec4 fragColor; -# if 0 /* Finish reprojection with motion vectors */ -vec3 get_motion_vector(vec3 pos) -{ -} - -/* http://bitsquid.blogspot.fr/2017/06/reprojecting-reflections_22.html */ -vec3 find_reflection_incident_point(vec3 cam, vec3 hit, vec3 pos, vec3 N) -{ - float d_cam = point_plane_projection_dist(cam, pos, N); - float d_hit = point_plane_projection_dist(hit, pos, N); - - if (d_hit < d_cam) { - /* Swap */ - float tmp = d_cam; - d_cam = d_hit; - d_hit = tmp; - } - - vec3 proj_cam = cam - (N * d_cam); - vec3 proj_hit = hit - (N * d_hit); - - return (proj_hit - proj_cam) * d_cam / (d_cam + d_hit) + proj_cam; -} -# endif - float brightness(vec3 c) { return max(max(c.r, c.g), c.b); } -vec2 get_reprojected_reflection(vec3 hit, vec3 pos, vec3 N) +vec4 ssr_get_scene_color_and_mask(vec3 hit_vP, int planar_index, float mip) { - /* TODO real reprojection with motion vectors, etc... */ - return project_point(pastViewProjectionMatrix, hit).xy * 0.5 + 0.5; -} - -float get_sample_depth(vec2 hit_co, bool is_planar, float planar_index) -{ - if (is_planar) { - hit_co.x = 1.0 - hit_co.x; - return textureLod(planarDepth, vec3(hit_co, planar_index), 0.0).r; + vec2 uv; + if (planar_index != -1) { + uv = get_uvs_from_view(hit_vP); + /* Planar X axis is flipped. */ + uv.x = 1.0 - uv.x; } else { - return textureLod(depthBuffer, hit_co, 0.0).r; + /* Find hit position in previous frame. */ + /* TODO Combine matrices. */ + vec3 hit_P = transform_point(ViewMatrixInverse, hit_vP); + /* TODO real reprojection with motion vectors, etc... */ + uv = project_point(pastViewProjectionMatrix, hit_P).xy * 0.5 + 0.5; } -} -vec3 get_hit_vector(vec3 hit_pos, - PlanarData pd, - vec3 P, - vec3 N, - vec3 V, - bool is_planar, - inout vec2 hit_co, - inout float mask) -{ - vec3 hit_vec; - - if (is_planar) { - /* Reflect back the hit position to have it in non-reflected world space */ - vec3 trace_pos = line_plane_intersect(P, V, pd.pl_plane_eq); - hit_vec = hit_pos - trace_pos; - hit_vec = reflect(hit_vec, pd.pl_normal); - /* Modify here so mip texel alignment is correct. */ - hit_co.x = 1.0 - hit_co.x; + vec3 color; + if (planar_index != -1) { + color = textureLod(probePlanars, vec3(uv, planar_index), mip).rgb; } else { - /* Find hit position in previous frame. */ - hit_co = get_reprojected_reflection(hit_pos, P, N); - hit_vec = hit_pos - P; + color = textureLod(colorBuffer, uv * hizUvScale.xy, mip).rgb; } - mask = screen_border_mask(hit_co); - return hit_vec; -} + /* Clamped brightness. */ + float luma = brightness(color); + color *= 1.0 - max(0.0, luma - ssrFireflyFac) * safe_rcp(luma); -vec3 get_scene_color(vec2 ref_uvs, float mip, float planar_index, bool is_planar) -{ - if (is_planar) { - return textureLod(probePlanars, vec3(ref_uvs, planar_index), mip).rgb; - } - else { - return textureLod(prevColorBuffer, ref_uvs * hizUvScale.xy, mip).rgb; - } + float mask = screen_border_mask(uv); + return vec4(color, mask); } -vec4 get_ssr_samples(vec4 hit_pdf, - ivec4 hit_data[2], - PlanarData pd, - float planar_index, - vec3 P, - vec3 N, - vec3 V, - float roughnessSquared, - float cone_tan, - vec2 source_uvs, - inout float weight_acc) +void resolve_reflection_sample(int planar_index, + vec2 sample_uv, + vec3 vP, + vec3 vN, + vec3 vV, + float roughness_squared, + float cone_tan, + inout float weight_accum, + inout vec4 ssr_accum) { - bvec4 is_planar, has_hit; - vec4 hit_co[2]; - hit_co[0].xy = decode_hit_data(hit_data[0].xy, has_hit.x, is_planar.x); - hit_co[0].zw = decode_hit_data(hit_data[0].zw, has_hit.y, is_planar.y); - hit_co[1].xy = decode_hit_data(hit_data[1].xy, has_hit.z, is_planar.z); - hit_co[1].zw = decode_hit_data(hit_data[1].zw, has_hit.w, is_planar.w); - - /* TODO/FIXME(fclem) This is giving precision issues due to refined intersection. This is most - * noticeable on rough surfaces. */ - vec4 hit_depth; - hit_depth.x = get_sample_depth(hit_co[0].xy, is_planar.x, planar_index); - hit_depth.y = get_sample_depth(hit_co[0].zw, is_planar.y, planar_index); - hit_depth.z = get_sample_depth(hit_co[1].xy, is_planar.z, planar_index); - hit_depth.w = get_sample_depth(hit_co[1].zw, is_planar.w, planar_index); - - /* Hit position in view space. */ - vec3 hit_view[4]; - hit_view[0] = get_view_space_from_depth(hit_co[0].xy, hit_depth.x); - hit_view[1] = get_view_space_from_depth(hit_co[0].zw, hit_depth.y); - hit_view[2] = get_view_space_from_depth(hit_co[1].xy, hit_depth.z); - hit_view[3] = get_view_space_from_depth(hit_co[1].zw, hit_depth.w); - - vec4 homcoord = vec4(hit_view[0].z, hit_view[1].z, hit_view[2].z, hit_view[3].z); - homcoord = ProjectionMatrix[2][3] * homcoord + ProjectionMatrix[3][3]; - - /* Hit position in world space. */ - vec3 hit_pos[4]; - hit_pos[0] = transform_point(ViewMatrixInverse, hit_view[0]); - hit_pos[1] = transform_point(ViewMatrixInverse, hit_view[1]); - hit_pos[2] = transform_point(ViewMatrixInverse, hit_view[2]); - hit_pos[3] = transform_point(ViewMatrixInverse, hit_view[3]); - - /* Get actual hit vector and hit coordinate (from last frame). */ - vec4 mask = vec4(1.0); - hit_pos[0] = get_hit_vector(hit_pos[0], pd, P, N, V, is_planar.x, hit_co[0].xy, mask.x); - hit_pos[1] = get_hit_vector(hit_pos[1], pd, P, N, V, is_planar.y, hit_co[0].zw, mask.y); - hit_pos[2] = get_hit_vector(hit_pos[2], pd, P, N, V, is_planar.z, hit_co[1].xy, mask.z); - hit_pos[3] = get_hit_vector(hit_pos[3], pd, P, N, V, is_planar.w, hit_co[1].zw, mask.w); - - vec4 hit_dist; - hit_dist.x = length(hit_pos[0]); - hit_dist.y = length(hit_pos[1]); - hit_dist.z = length(hit_pos[2]); - hit_dist.w = length(hit_pos[3]); - hit_dist = max(vec4(1e-8), hit_dist); - - /* Normalize */ - hit_pos[0] /= hit_dist.x; - hit_pos[1] /= hit_dist.y; - hit_pos[2] /= hit_dist.z; - hit_pos[3] /= hit_dist.w; + HitData data = decode_hit_data(texture(hitBuffer, sample_uv * ssrUvScale)); - /* Compute cone footprint in screen space. */ - vec4 cone_footprint = hit_dist * cone_tan; - cone_footprint = ssrBrdfBias * 0.5 * cone_footprint * - max(ProjectionMatrix[0][0], ProjectionMatrix[1][1]) / homcoord; + float hit_dist = length(data.hit_dir); - /* Estimate a cone footprint to sample a corresponding mipmap level. */ - vec4 mip = log2(cone_footprint * max_v2(vec2(textureSize(depthBuffer, 0)))); - mip = clamp(mip, 0.0, MAX_MIP); + /* Slide 54. */ + float bsdf = bsdf_ggx(vN, data.hit_dir / hit_dist, vV, roughness_squared); - /* Slide 54 */ - vec4 bsdf; - bsdf.x = bsdf_ggx(N, hit_pos[0], V, roughnessSquared); - bsdf.y = bsdf_ggx(N, hit_pos[1], V, roughnessSquared); - bsdf.z = bsdf_ggx(N, hit_pos[2], V, roughnessSquared); - bsdf.w = bsdf_ggx(N, hit_pos[3], V, roughnessSquared); + float weight = bsdf * data.ray_pdf_inv; - vec4 weight = step(1e-8, hit_pdf) * bsdf / max(vec4(1e-8), hit_pdf); + /* Do not add light if ray has failed but still weight it. */ + if (!data.is_hit || (planar_index == -1 && data.is_planar) || + (planar_index != -1 && !data.is_planar)) { + weight_accum += weight; + return; + } - vec3 sample[4]; - sample[0] = get_scene_color(hit_co[0].xy, mip.x, planar_index, is_planar.x); - sample[1] = get_scene_color(hit_co[0].zw, mip.y, planar_index, is_planar.y); - sample[2] = get_scene_color(hit_co[1].xy, mip.z, planar_index, is_planar.z); - sample[3] = get_scene_color(hit_co[1].zw, mip.w, planar_index, is_planar.w); + vec3 hit_vP = vP + data.hit_dir; - /* Clamped brightness. */ - vec4 luma; - luma.x = brightness(sample[0]); - luma.y = brightness(sample[1]); - luma.z = brightness(sample[2]); - luma.w = brightness(sample[3]); - luma = max(vec4(1e-8), luma); - luma = 1.0 - max(vec4(0.0), luma - ssrFireflyFac) / luma; - - sample[0] *= luma.x; - sample[1] *= luma.y; - sample[2] *= luma.z; - sample[3] *= luma.w; - - /* Protection against NaNs in the history buffer. - * This could be removed if some previous pass has already - * sanitized the input. */ - if (any(isnan(sample[0]))) { - sample[0] = vec3(0.0); - weight.x = 0.0; - } - if (any(isnan(sample[1]))) { - sample[1] = vec3(0.0); - weight.y = 0.0; - } - if (any(isnan(sample[2]))) { - sample[2] = vec3(0.0); - weight.z = 0.0; - } - if (any(isnan(sample[3]))) { - sample[3] = vec3(0.0); - weight.w = 0.0; - } + /* Compute cone footprint in screen space. */ + float cone_footprint = hit_dist * cone_tan; + float homcoord = ProjectionMatrix[2][3] * hit_vP.z + ProjectionMatrix[3][3]; + cone_footprint *= max(ProjectionMatrix[0][0], ProjectionMatrix[1][1]) / homcoord; + cone_footprint *= ssrBrdfBias * 0.5; + /* Estimate a cone footprint to sample a corresponding mipmap level. */ + float mip = log2(cone_footprint * max_v2(vec2(textureSize(specroughBuffer, 0)))); - weight_acc += sum(weight); + vec4 radiance_mask = ssr_get_scene_color_and_mask(hit_vP, planar_index, mip); - /* Do not add light if ray has failed. */ - vec4 accum; - accum = vec4(sample[0], mask.x) * weight.x * float(has_hit.x); - accum += vec4(sample[1], mask.y) * weight.y * float(has_hit.y); - accum += vec4(sample[2], mask.z) * weight.z * float(has_hit.z); - accum += vec4(sample[3], mask.w) * weight.w * float(has_hit.w); - return accum; + ssr_accum += radiance_mask * weight; + weight_accum += weight; } void raytrace_resolve(ClosureInputGlossy cl_in, @@ -476,74 +307,55 @@ void raytrace_resolve(ClosureInputGlossy cl_in, inout ClosureEvalCommon cl_common, inout ClosureOutputGlossy cl_out) { -# ifdef FULLRES - ivec2 texel = ivec2(gl_FragCoord.xy); -# else - ivec2 texel = ivec2(gl_FragCoord.xy / 2.0); -# endif - /* Using world space */ - vec3 V = cl_common.V; - vec3 N = cl_in.N; - vec3 P = cl_common.P; - float roughness = cl_in.roughness; - float roughnessSquared = max(1e-3, sqr(roughness)); - - /* Resolve SSR */ - float cone_cos = cone_cosine(roughnessSquared); - float cone_tan = sqrt(1 - cone_cos * cone_cos) / cone_cos; - cone_tan *= mix(saturate(dot(N, -V) * 2.0), 1.0, roughness); /* Elongation fit */ - - vec2 source_uvs = project_point(pastViewProjectionMatrix, P).xy * 0.5 + 0.5; vec4 ssr_accum = vec4(0.0); float weight_acc = 0.0; if (roughness < ssrMaxRoughness + 0.2) { - /* TODO optimize with textureGather */ - /* Doing these fetches early to hide latency. */ - vec4 hit_pdf; - hit_pdf.x = texelFetch(pdfBuffer, texel + neighbors[0 + neighborOffset], 0).r; - hit_pdf.y = texelFetch(pdfBuffer, texel + neighbors[1 + neighborOffset], 0).r; - hit_pdf.z = texelFetch(pdfBuffer, texel + neighbors[2 + neighborOffset], 0).r; - hit_pdf.w = texelFetch(pdfBuffer, texel + neighbors[3 + neighborOffset], 0).r; - - ivec4 hit_data[2]; - hit_data[0].xy = texelFetch(hitBuffer, texel + neighbors[0 + neighborOffset], 0).rg; - hit_data[0].zw = texelFetch(hitBuffer, texel + neighbors[1 + neighborOffset], 0).rg; - hit_data[1].xy = texelFetch(hitBuffer, texel + neighbors[2 + neighborOffset], 0).rg; - hit_data[1].zw = texelFetch(hitBuffer, texel + neighbors[3 + neighborOffset], 0).rg; - /* Find Planar Reflections affecting this pixel */ - PlanarData pd; - float planar_index; + int planar_index = -1; for (int i = 0; i < MAX_PLANAR && i < prbNumPlanar; i++) { - pd = planars_data[i]; - - float fade = probe_attenuation_planar(pd, P); - fade *= probe_attenuation_planar_normal_roughness(pd, N, 0.0); - + float fade = probe_attenuation_planar(planars_data[i], cl_common.P); + fade *= probe_attenuation_planar_normal_roughness(planars_data[i], cl_in.N, 0.0); if (fade > 0.5) { - planar_index = float(i); + planar_index = i; break; } } - ssr_accum += get_ssr_samples(hit_pdf, - hit_data, - pd, - planar_index, - P, - N, - V, - roughnessSquared, - cone_tan, - source_uvs, - weight_acc); + vec3 V, P, N; + if (planar_index != -1) { + PlanarData pd = planars_data[planar_index]; + /* Evaluate everything in refected space. */ + P = line_plane_intersect(cl_common.P, cl_common.V, pd.pl_plane_eq); + V = reflect(cl_common.V, pd.pl_normal); + N = reflect(cl_in.N, pd.pl_normal); + } + else { + V = cl_common.V; + P = cl_common.P; + N = cl_in.N; + } + + /* Using view space */ + vec3 vV = transform_direction(ViewMatrix, cl_common.V); + vec3 vP = transform_point(ViewMatrix, cl_common.P); + vec3 vN = transform_direction(ViewMatrix, cl_in.N); + + float roughness_squared = max(1e-3, sqr(roughness)); + float cone_cos = cone_cosine(roughness_squared); + float cone_tan = sqrt(1.0 - cone_cos * cone_cos) / cone_cos; + cone_tan *= mix(saturate(dot(vN, -vV) * 2.0), 1.0, roughness); /* Elongation fit */ + + vec2 sample_uv = uvcoordsvar.xy; + + resolve_reflection_sample( + planar_index, sample_uv, vP, vN, vV, roughness_squared, cone_tan, weight_acc, ssr_accum); } /* Compute SSR contribution */ - ssr_accum *= (weight_acc == 0.0) ? 0.0 : (1.0 / weight_acc); + ssr_accum *= safe_rcp(weight_acc); /* fade between 0.5 and 1.0 roughness */ ssr_accum.a *= smoothstep(ssrMaxRoughness + 0.2, ssrMaxRoughness, roughness); @@ -555,13 +367,13 @@ CLOSURE_EVAL_FUNCTION_DECLARE_1(ssr_resolve, Glossy) void main() { - ivec2 texel = ivec2(gl_FragCoord.xy); - float depth = texelFetch(depthBuffer, texel, 0).r; + float depth = textureLod(maxzBuffer, uvcoordsvar.xy * hizUvScale.xy, 0.0).r; if (depth == 1.0) { discard; } + ivec2 texel = ivec2(gl_FragCoord.xy); vec4 speccol_roughness = texelFetch(specroughBuffer, texel, 0).rgba; vec3 brdf = speccol_roughness.rgb; float roughness = speccol_roughness.a; diff --git a/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl b/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl index 7c375aabb62..dce50a7051e 100644 --- a/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl @@ -15,13 +15,6 @@ struct Ray { vec3 direction; }; -vec3 raytrace_offset(vec3 P, vec3 Ng) -{ - /* TODO(fclem) better offset */ - const float epsilon_f = 1e-4; - return P + epsilon_f * Ng; -} - /* Inputs expected to be in viewspace. */ void raytrace_clip_ray_to_near_plane(inout Ray ray) { diff --git a/source/blender/draw/engines/eevee/shaders/ssr_lib.glsl b/source/blender/draw/engines/eevee/shaders/ssr_lib.glsl index 5a09120916a..37624fc31ea 100644 --- a/source/blender/draw/engines/eevee/shaders/ssr_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/ssr_lib.glsl @@ -9,6 +9,10 @@ #define BTDF_BIAS 0.85 +uniform sampler2D refractColorBuffer; + +uniform float refractionDepth; + vec4 screen_space_refraction(vec3 vP, vec3 N, vec3 V, float ior, float roughnessSquared, vec4 rand) { float a2 = max(5e-6, roughnessSquared * roughnessSquared); @@ -75,10 +79,10 @@ vec4 screen_space_refraction(vec3 vP, vec3 N, vec3 V, float ior, float roughness vec2 hit_uvs = project_point(ProjectionMatrix, hit_pos).xy * 0.5 + 0.5; /* Texel footprint */ - vec2 texture_size = vec2(textureSize(colorBuffer, 0).xy); + vec2 texture_size = vec2(textureSize(refractColorBuffer, 0).xy) / hizUvScale.xy; float mip = clamp(log2(cone_footprint * max(texture_size.x, texture_size.y)), 0.0, 9.0); - vec3 spec = textureLod(colorBuffer, hit_uvs * hizUvScale.xy, mip).xyz; + vec3 spec = textureLod(refractColorBuffer, hit_uvs * hizUvScale.xy, mip).xyz; float mask = screen_border_mask(hit_uvs); return vec4(spec, mask); diff --git a/source/blender/draw/engines/eevee/shaders/surface_lib.glsl b/source/blender/draw/engines/eevee/shaders/surface_lib.glsl index e80dc1761f0..0acb35b2399 100644 --- a/source/blender/draw/engines/eevee/shaders/surface_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/surface_lib.glsl @@ -1,12 +1,5 @@ /** This describe the entire interface of the shader. */ -/* Samplers */ -uniform sampler2D colorBuffer; -uniform sampler2D depthBuffer; - -/* Uniforms */ -uniform float refractionDepth; - #define SURFACE_INTERFACE \ vec3 worldPosition; \ vec3 viewPosition; \ |