From a7b7f67fc4ad0a5bf4ffc2a64467b55479f4fd95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Wed, 5 May 2021 16:10:43 +0200 Subject: [PATCH 1/3] Fix T86037 EEVEE: SSR option changes render passes result This was caused by the SSR option resetting the accumulation. But the render passes were only cleared in the init phase. This means that when SSR was resetting the taa_render_sample the actual renderpasses would still contains 1 sample. This means the renderpasses were always divided by the wrong number of samples. The fix is to clear just before accumulation if the sample is 1. The fact that it works for motion blur is kind of a blessing. This is because we check stl->effects->ssr_was_valid_double_buffer before resetting the sampling. So this only happens on the first motion step and does not affect the rest of the rendering. Reviewed by: jbakker Differential Revision: https://developer.blender.org/D11033 --- .../draw/engines/eevee/eevee_materials.c | 64 ++++++++++--------- .../blender/draw/engines/eevee/eevee_mist.c | 17 +++-- .../draw/engines/eevee/eevee_occlusion.c | 15 +++-- .../engines/eevee/eevee_screen_raytrace.c | 18 +++--- .../draw/engines/eevee/eevee_shadows.c | 18 +++--- .../draw/engines/eevee/eevee_volumes.c | 23 ++++--- 6 files changed, 76 insertions(+), 79 deletions(-) diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c index 131f9a954cf..45c6900fc0f 100644 --- a/source/blender/draw/engines/eevee/eevee_materials.c +++ b/source/blender/draw/engines/eevee/eevee_materials.c @@ -961,22 +961,9 @@ void EEVEE_material_renderpasses_init(EEVEE_Data *vedata) } } -static void material_renderpass_init(EEVEE_FramebufferList *fbl, - GPUTexture **output_tx, - const eGPUTextureFormat format, - const bool do_clear) +static void material_renderpass_init(GPUTexture **output_tx, const eGPUTextureFormat format) { DRW_texture_ensure_fullscreen_2d(output_tx, format, 0); - /* Clear texture. */ - if (do_clear) { - const float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f}; - /* TODO(fclem): replace by GPU_texture_clear once it is fast. */ - GPU_framebuffer_texture_attach(fbl->material_accum_fb, *output_tx, 0, 0); - GPU_framebuffer_bind(fbl->material_accum_fb); - GPU_framebuffer_clear_color(fbl->material_accum_fb, clear); - GPU_framebuffer_bind(fbl->main_fb); - GPU_framebuffer_texture_detach(fbl->material_accum_fb, *output_tx); - } } void EEVEE_material_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, uint tot_samples) @@ -991,33 +978,32 @@ void EEVEE_material_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, /* Should be enough precision for many samples. */ const eGPUTextureFormat texture_format = (tot_samples > 128) ? GPU_RGBA32F : GPU_RGBA16F; - const bool do_clear = (effects->taa_current_sample == 1); /* Create FrameBuffer. */ GPU_framebuffer_ensure_config(&fbl->material_accum_fb, {GPU_ATTACHMENT_TEXTURE(dtxl->depth), GPU_ATTACHMENT_LEAVE}); if (pd->render_passes & EEVEE_RENDER_PASS_ENVIRONMENT) { - material_renderpass_init(fbl, &txl->env_accum, texture_format, do_clear); + material_renderpass_init(&txl->env_accum, texture_format); } if (pd->render_passes & EEVEE_RENDER_PASS_EMIT) { - material_renderpass_init(fbl, &txl->emit_accum, texture_format, do_clear); + material_renderpass_init(&txl->emit_accum, texture_format); } if (pd->render_passes & EEVEE_RENDER_PASS_DIFFUSE_COLOR) { - material_renderpass_init(fbl, &txl->diff_color_accum, texture_format, do_clear); + material_renderpass_init(&txl->diff_color_accum, texture_format); } if (pd->render_passes & EEVEE_RENDER_PASS_DIFFUSE_LIGHT) { - material_renderpass_init(fbl, &txl->diff_light_accum, texture_format, do_clear); + material_renderpass_init(&txl->diff_light_accum, texture_format); } if (pd->render_passes & EEVEE_RENDER_PASS_SPECULAR_COLOR) { - material_renderpass_init(fbl, &txl->spec_color_accum, texture_format, do_clear); + material_renderpass_init(&txl->spec_color_accum, texture_format); } if (pd->render_passes & EEVEE_RENDER_PASS_AOV) { for (int aov_index = 0; aov_index < pd->num_aovs_used; aov_index++) { - material_renderpass_init(fbl, &txl->aov_surface_accum[aov_index], texture_format, do_clear); + material_renderpass_init(&txl->aov_surface_accum[aov_index], texture_format); } } if (pd->render_passes & EEVEE_RENDER_PASS_SPECULAR_LIGHT) { - material_renderpass_init(fbl, &txl->spec_light_accum, texture_format, do_clear); + material_renderpass_init(&txl->spec_light_accum, texture_format); if (effects->enabled_effects & EFFECT_SSR) { EEVEE_reflection_output_init(sldata, vedata, tot_samples); @@ -1025,7 +1011,8 @@ void EEVEE_material_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, } } -static void material_renderpass_accumulate(EEVEE_FramebufferList *fbl, +static void material_renderpass_accumulate(EEVEE_EffectsInfo *effects, + EEVEE_FramebufferList *fbl, DRWPass *renderpass, DRWPass *renderpass2, EEVEE_PrivateData *pd, @@ -1035,6 +1022,11 @@ static void material_renderpass_accumulate(EEVEE_FramebufferList *fbl, GPU_framebuffer_texture_attach(fbl->material_accum_fb, output_tx, 0, 0); GPU_framebuffer_bind(fbl->material_accum_fb); + if (effects->taa_current_sample == 1) { + const float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + GPU_framebuffer_clear_color(fbl->material_accum_fb, clear); + } + pd->renderpass_ubo = renderpass_option_ubo; DRW_draw_pass(renderpass); if (renderpass2) { @@ -1056,15 +1048,21 @@ void EEVEE_material_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *v DRWPass *material_accum_ps = psl->material_accum_ps; DRWPass *background_accum_ps = psl->background_accum_ps; if (pd->render_passes & EEVEE_RENDER_PASS_ENVIRONMENT) { - material_renderpass_accumulate( - fbl, background_accum_ps, NULL, pd, txl->env_accum, sldata->renderpass_ubo.environment); + material_renderpass_accumulate(effects, + fbl, + background_accum_ps, + NULL, + pd, + txl->env_accum, + sldata->renderpass_ubo.environment); } if (pd->render_passes & EEVEE_RENDER_PASS_EMIT) { material_renderpass_accumulate( - fbl, material_accum_ps, NULL, pd, txl->emit_accum, sldata->renderpass_ubo.emit); + effects, fbl, material_accum_ps, NULL, pd, txl->emit_accum, sldata->renderpass_ubo.emit); } if (pd->render_passes & EEVEE_RENDER_PASS_DIFFUSE_COLOR) { - material_renderpass_accumulate(fbl, + material_renderpass_accumulate(effects, + fbl, material_accum_ps, NULL, pd, @@ -1072,7 +1070,8 @@ void EEVEE_material_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *v sldata->renderpass_ubo.diff_color); } if (pd->render_passes & EEVEE_RENDER_PASS_DIFFUSE_LIGHT) { - material_renderpass_accumulate(fbl, + material_renderpass_accumulate(effects, + fbl, material_accum_ps, NULL, pd, @@ -1090,7 +1089,8 @@ void EEVEE_material_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *v sldata->common_data.ssr_toggle = false; GPU_uniformbuf_update(sldata->common_ubo, &sldata->common_data); } - material_renderpass_accumulate(fbl, + material_renderpass_accumulate(effects, + fbl, material_accum_ps, NULL, pd, @@ -1102,7 +1102,8 @@ void EEVEE_material_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *v } } if (pd->render_passes & EEVEE_RENDER_PASS_SPECULAR_LIGHT) { - material_renderpass_accumulate(fbl, + material_renderpass_accumulate(effects, + fbl, material_accum_ps, NULL, pd, @@ -1115,7 +1116,8 @@ void EEVEE_material_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *v } if (pd->render_passes & EEVEE_RENDER_PASS_AOV) { for (int aov_index = 0; aov_index < pd->num_aovs_used; aov_index++) { - material_renderpass_accumulate(fbl, + material_renderpass_accumulate(effects, + fbl, material_accum_ps, background_accum_ps, pd, diff --git a/source/blender/draw/engines/eevee/eevee_mist.c b/source/blender/draw/engines/eevee/eevee_mist.c index 2b448695528..d4490d6fd4c 100644 --- a/source/blender/draw/engines/eevee/eevee_mist.c +++ b/source/blender/draw/engines/eevee/eevee_mist.c @@ -40,12 +40,9 @@ void EEVEE_mist_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) EEVEE_TextureList *txl = vedata->txl; EEVEE_StorageList *stl = vedata->stl; EEVEE_PassList *psl = vedata->psl; - EEVEE_EffectsInfo *effects = stl->effects; EEVEE_PrivateData *g_data = stl->g_data; Scene *scene = draw_ctx->scene; - const float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f}; - /* Create FrameBuffer. */ /* Should be enough precision for many samples. */ DRW_texture_ensure_fullscreen_2d(&txl->mist_accum, GPU_R32F, 0); @@ -53,12 +50,6 @@ void EEVEE_mist_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) GPU_framebuffer_ensure_config(&fbl->mist_accum_fb, {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(txl->mist_accum)}); - /* Clear texture. */ - if (effects->taa_current_sample == 1) { - GPU_framebuffer_bind(fbl->mist_accum_fb); - GPU_framebuffer_clear_color(fbl->mist_accum_fb, clear); - } - /* Mist settings. */ if (scene && scene->world) { g_data->mist_start = scene->world->miststa; @@ -103,9 +94,17 @@ void EEVEE_mist_output_accumulate(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Dat { EEVEE_FramebufferList *fbl = vedata->fbl; EEVEE_PassList *psl = vedata->psl; + EEVEE_EffectsInfo *effects = vedata->stl->effects; if (fbl->mist_accum_fb != NULL) { GPU_framebuffer_bind(fbl->mist_accum_fb); + + /* Clear texture. */ + if (effects->taa_current_sample == 1) { + const float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + GPU_framebuffer_clear_color(fbl->mist_accum_fb, clear); + } + DRW_draw_pass(psl->mist_accum_ps); /* Restore */ diff --git a/source/blender/draw/engines/eevee/eevee_occlusion.c b/source/blender/draw/engines/eevee/eevee_occlusion.c index 19f34fa6108..4c2024a6f65 100644 --- a/source/blender/draw/engines/eevee/eevee_occlusion.c +++ b/source/blender/draw/engines/eevee/eevee_occlusion.c @@ -120,7 +120,6 @@ void EEVEE_occlusion_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata const eGPUTextureFormat texture_format = (tot_samples > 128) ? GPU_R32F : GPU_R16F; DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); - const float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f}; /* Should be enough precision for many samples. */ DRW_texture_ensure_fullscreen_2d(&txl->ao_accum, texture_format, 0); @@ -128,12 +127,6 @@ void EEVEE_occlusion_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata GPU_framebuffer_ensure_config(&fbl->ao_accum_fb, {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(txl->ao_accum)}); - /* Clear texture. */ - if (effects->taa_current_sample == 1) { - GPU_framebuffer_bind(fbl->ao_accum_fb); - GPU_framebuffer_clear_color(fbl->ao_accum_fb, clear); - } - /* Accumulation pass */ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ADD; DRW_PASS_CREATE(psl->ao_accum_ps, state); @@ -246,6 +239,7 @@ void EEVEE_occlusion_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data * { EEVEE_FramebufferList *fbl = vedata->fbl; EEVEE_PassList *psl = vedata->psl; + EEVEE_EffectsInfo *effects = vedata->stl->effects; if (fbl->ao_accum_fb != NULL) { DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); @@ -255,6 +249,13 @@ void EEVEE_occlusion_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data * EEVEE_occlusion_compute(sldata, vedata); GPU_framebuffer_bind(fbl->ao_accum_fb); + + /* Clear texture. */ + if (effects->taa_current_sample == 1) { + const float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + GPU_framebuffer_clear_color(fbl->ao_accum_fb, clear); + } + DRW_draw_pass(psl->ao_accum_ps); /* Restore */ diff --git a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c index 54f23073bd0..7af0f60748b 100644 --- a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c +++ b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c @@ -234,10 +234,6 @@ void EEVEE_reflection_output_init(EEVEE_ViewLayerData *UNUSED(sldata), { EEVEE_FramebufferList *fbl = vedata->fbl; EEVEE_TextureList *txl = vedata->txl; - EEVEE_StorageList *stl = vedata->stl; - EEVEE_EffectsInfo *effects = stl->effects; - - const float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f}; /* Create FrameBuffer. */ const eGPUTextureFormat texture_format = (tot_samples > 256) ? GPU_RGBA32F : GPU_RGBA16F; @@ -245,12 +241,6 @@ void EEVEE_reflection_output_init(EEVEE_ViewLayerData *UNUSED(sldata), GPU_framebuffer_ensure_config(&fbl->ssr_accum_fb, {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(txl->ssr_accum)}); - - /* Clear texture. */ - if (effects->taa_current_sample == 1) { - GPU_framebuffer_bind(fbl->ssr_accum_fb); - GPU_framebuffer_clear_color(fbl->ssr_accum_fb, clear); - } } void EEVEE_reflection_output_accumulate(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) @@ -258,9 +248,17 @@ void EEVEE_reflection_output_accumulate(EEVEE_ViewLayerData *UNUSED(sldata), EEV EEVEE_FramebufferList *fbl = vedata->fbl; EEVEE_PassList *psl = vedata->psl; EEVEE_StorageList *stl = vedata->stl; + EEVEE_EffectsInfo *effects = vedata->stl->effects; if (stl->g_data->valid_double_buffer) { GPU_framebuffer_bind(fbl->ssr_accum_fb); + + /* Clear texture. */ + if (effects->taa_current_sample == 1) { + const float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + GPU_framebuffer_clear_color(fbl->ssr_accum_fb, clear); + } + DRW_draw_pass(psl->ssr_resolve); } } diff --git a/source/blender/draw/engines/eevee/eevee_shadows.c b/source/blender/draw/engines/eevee/eevee_shadows.c index 51fd1cad41e..6a98c3316f3 100644 --- a/source/blender/draw/engines/eevee/eevee_shadows.c +++ b/source/blender/draw/engines/eevee/eevee_shadows.c @@ -361,12 +361,8 @@ void EEVEE_shadow_output_init(EEVEE_ViewLayerData *sldata, EEVEE_FramebufferList *fbl = vedata->fbl; EEVEE_TextureList *txl = vedata->txl; EEVEE_PassList *psl = vedata->psl; - EEVEE_StorageList *stl = vedata->stl; - EEVEE_EffectsInfo *effects = stl->effects; DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); - const float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f}; - /* Create FrameBuffer. */ const eGPUTextureFormat texture_format = GPU_R32F; DRW_texture_ensure_fullscreen_2d(&txl->shadow_accum, texture_format, 0); @@ -374,12 +370,6 @@ void EEVEE_shadow_output_init(EEVEE_ViewLayerData *sldata, GPU_framebuffer_ensure_config(&fbl->shadow_accum_fb, {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(txl->shadow_accum)}); - /* Clear texture. */ - if (effects->taa_current_sample == 1) { - GPU_framebuffer_bind(fbl->shadow_accum_fb); - GPU_framebuffer_clear_color(fbl->shadow_accum_fb, clear); - } - /* Create Pass and shgroup. */ DRW_PASS_CREATE(psl->shadow_accum_pass, DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_ALWAYS | DRW_STATE_BLEND_ADD_FULL); @@ -404,9 +394,17 @@ void EEVEE_shadow_output_accumulate(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_D { EEVEE_FramebufferList *fbl = vedata->fbl; EEVEE_PassList *psl = vedata->psl; + EEVEE_EffectsInfo *effects = vedata->stl->effects; if (fbl->shadow_accum_fb != NULL) { GPU_framebuffer_bind(fbl->shadow_accum_fb); + + /* Clear texture. */ + if (effects->taa_current_sample == 1) { + const float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + GPU_framebuffer_clear_color(fbl->shadow_accum_fb, clear); + } + DRW_draw_pass(psl->shadow_accum_pass); /* Restore */ diff --git a/source/blender/draw/engines/eevee/eevee_volumes.c b/source/blender/draw/engines/eevee/eevee_volumes.c index d228d26cd52..3d24cd6fab5 100644 --- a/source/blender/draw/engines/eevee/eevee_volumes.c +++ b/source/blender/draw/engines/eevee/eevee_volumes.c @@ -394,10 +394,9 @@ static bool eevee_volume_object_grids_init(Object *ob, ListBase *gpu_grids, DRWS * - Grid exists and texture was loaded -> use texture. * - Grid exists but has zero size or failed to load -> use zero. * - Grid does not exist -> use default value. */ - GPUTexture *grid_tex = (drw_grid) ? drw_grid->texture : - (volume_grid) ? - e_data.dummy_zero : - eevee_volume_default_texture(gpu_grid->default_value); + GPUTexture *grid_tex = (drw_grid) ? drw_grid->texture : + (volume_grid) ? e_data.dummy_zero : + eevee_volume_default_texture(gpu_grid->default_value); DRW_shgroup_uniform_texture(grp, gpu_grid->sampler_name, grid_tex); @@ -800,8 +799,6 @@ void EEVEE_volumes_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, EEVEE_PassList *psl = vedata->psl; EEVEE_EffectsInfo *effects = stl->effects; - const float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f}; - /* Create FrameBuffer. */ /* Should be enough precision for many samples. */ @@ -814,12 +811,6 @@ void EEVEE_volumes_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, GPU_ATTACHMENT_TEXTURE(txl->volume_scatter_accum), GPU_ATTACHMENT_TEXTURE(txl->volume_transmittance_accum)}); - /* Clear texture. */ - if (effects->taa_current_sample == 1) { - GPU_framebuffer_bind(fbl->volumetric_accum_fb); - GPU_framebuffer_clear_color(fbl->volumetric_accum_fb, clear); - } - /* Create Pass and shgroup. */ DRW_PASS_CREATE(psl->volumetric_accum_ps, DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ADD_FULL); DRWShadingGroup *grp = NULL; @@ -843,10 +834,18 @@ void EEVEE_volumes_output_accumulate(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_ { EEVEE_FramebufferList *fbl = vedata->fbl; EEVEE_PassList *psl = vedata->psl; + EEVEE_EffectsInfo *effects = vedata->stl->effects; if (fbl->volumetric_accum_fb != NULL) { /* Accum pass */ GPU_framebuffer_bind(fbl->volumetric_accum_fb); + + /* Clear texture. */ + if (effects->taa_current_sample == 1) { + const float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + GPU_framebuffer_clear_color(fbl->volumetric_accum_fb, clear); + } + DRW_draw_pass(psl->volumetric_accum_ps); /* Restore */ From 95889fe071e179a9a7d7e6a27aaf7a4a42fc49b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Wed, 5 May 2021 16:30:34 +0200 Subject: [PATCH 2/3] Fix T86823 Eevee: refraction depth shared between different materials This was caused by the material grouping system which was missing a per material uniform update in the opaque case. --- source/blender/draw/engines/eevee/eevee_materials.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c index 45c6900fc0f..a4325675ea9 100644 --- a/source/blender/draw/engines/eevee/eevee_materials.c +++ b/source/blender/draw/engines/eevee/eevee_materials.c @@ -623,6 +623,11 @@ static EeveeMaterialCache material_opaque(EEVEE_Data *vedata, /* This GPUShader has already been used by another material. * Add new shading group just after to avoid shader switching cost. */ grp = DRW_shgroup_create_sub(*grp_p); + + /* Per material uniforms. */ + if (use_ssrefract) { + DRW_shgroup_uniform_float_copy(grp, "refractionDepth", ma->refract_depth); + } } else { *grp_p = grp = DRW_shgroup_create(sh, shading_pass); From a1a9f8e6c3f341061777bc2d985b35e9d7a20ad1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Wed, 5 May 2021 18:13:24 +0200 Subject: [PATCH 3/3] 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. --- .../shaders/effect_translucency_frag.glsl | 60 ++++++++++++++++++- 1 file 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);