diff options
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; \ |