diff options
9 files changed, 194 insertions, 207 deletions
diff --git a/release/scripts/startup/bl_ui/properties_render.py b/release/scripts/startup/bl_ui/properties_render.py index 136ee3732ff..f35b3a5f47d 100644 --- a/release/scripts/startup/bl_ui/properties_render.py +++ b/release/scripts/startup/bl_ui/properties_render.py @@ -710,8 +710,8 @@ class RENDER_PT_eevee_volumetric(RenderButtonsPanel, Panel): col.prop(props, "volumetric_colored_transmittance") -class RENDER_PT_eevee_shading(RenderButtonsPanel, Panel): - bl_label = "Shading" +class RENDER_PT_eevee_screen_space_reflections(RenderButtonsPanel, Panel): + bl_label = "Screen Space Reflections" COMPAT_ENGINES = {'BLENDER_EEVEE'} @classmethod @@ -719,19 +719,23 @@ class RENDER_PT_eevee_shading(RenderButtonsPanel, Panel): scene = context.scene return scene and (scene.render.engine in cls.COMPAT_ENGINES) + def draw_header(self, context): + scene = context.scene + props = scene.layer_properties['BLENDER_EEVEE'] + self.layout.prop(props, "ssr_enable", text="") + def draw(self, context): layout = self.layout scene = context.scene props = scene.layer_properties['BLENDER_EEVEE'] col = layout.column() - col.prop(props, "ssr_enable") col.prop(props, "ssr_halfres") - col.prop(props, "ssr_two_rays") - col.prop(props, "ssr_normalize_weight") + col.prop(props, "ssr_ray_count") col.prop(props, "ssr_stride") col.prop(props, "ssr_thickness") col.prop(props, "ssr_border_fade") + col.prop(props, "ssr_firefly_fac") classes = ( @@ -751,10 +755,10 @@ classes = ( RENDER_PT_bake, RENDER_PT_clay_layer_settings, RENDER_PT_clay_collection_settings, + RENDER_PT_eevee_volumetric, + RENDER_PT_eevee_screen_space_reflections, RENDER_PT_eevee_poststack_settings, RENDER_PT_eevee_postprocess_settings, - RENDER_PT_eevee_volumetric, - RENDER_PT_eevee_shading, ) if __name__ == "__main__": # only for live edit. diff --git a/release/scripts/startup/bl_ui/properties_render_layer.py b/release/scripts/startup/bl_ui/properties_render_layer.py index d5a56fbf84e..5aeb117c071 100644 --- a/release/scripts/startup/bl_ui/properties_render_layer.py +++ b/release/scripts/startup/bl_ui/properties_render_layer.py @@ -250,8 +250,8 @@ class RENDERLAYER_PT_eevee_volumetric(RenderLayerButtonsPanel, Panel): col.template_override_property(layer_props, scene_props, "volumetric_colored_transmittance") -class RENDERLAYER_PT_eevee_shading(RenderLayerButtonsPanel, Panel): - bl_label = "Shading" +class RENDERLAYER_PT_eevee_screen_space_reflections(RenderLayerButtonsPanel, Panel): + bl_label = "Screen Space Reflections" COMPAT_ENGINES = {'BLENDER_EEVEE'} @classmethod @@ -259,6 +259,14 @@ class RENDERLAYER_PT_eevee_shading(RenderLayerButtonsPanel, Panel): scene = context.scene return scene and (scene.render.engine in cls.COMPAT_ENGINES) + def draw_header(self, context): + scene = context.scene + scene_props = scene.layer_properties['BLENDER_EEVEE'] + layer = bpy.context.render_layer + layer_props = layer.engine_overrides['BLENDER_EEVEE'] + + self.layout.template_override_property(layer_props, scene_props, "ssr_enable", text="") + def draw(self, context): layout = self.layout scene = context.scene @@ -267,13 +275,12 @@ class RENDERLAYER_PT_eevee_shading(RenderLayerButtonsPanel, Panel): layer_props = layer.engine_overrides['BLENDER_EEVEE'] col = layout.column() - col.template_override_property(layer_props, scene_props, "ssr_enable") col.template_override_property(layer_props, scene_props, "ssr_halfres") - col.template_override_property(layer_props, scene_props, "ssr_two_rays") - col.template_override_property(layer_props, scene_props, "ssr_normalize_weight") + col.template_override_property(layer_props, scene_props, "ssr_ray_count") col.template_override_property(layer_props, scene_props, "ssr_stride") col.template_override_property(layer_props, scene_props, "ssr_thickness") col.template_override_property(layer_props, scene_props, "ssr_border_fade") + col.template_override_property(layer_props, scene_props, "ssr_firefly_fac") classes = ( @@ -284,7 +291,7 @@ classes = ( RENDERLAYER_PT_clay_settings, RENDERLAYER_PT_eevee_poststack_settings, RENDERLAYER_PT_eevee_postprocess_settings, - RENDERLAYER_PT_eevee_shading, + RENDERLAYER_PT_eevee_screen_space_reflections, RENDERLAYER_PT_eevee_volumetric, ) diff --git a/source/blender/draw/engines/eevee/eevee_effects.c b/source/blender/draw/engines/eevee/eevee_effects.c index 34b33598a56..6a7983b71a6 100644 --- a/source/blender/draw/engines/eevee/eevee_effects.c +++ b/source/blender/draw/engines/eevee/eevee_effects.c @@ -59,10 +59,8 @@ typedef struct EEVEE_LightProbeData { /* SSR shader variations */ enum { SSR_RESOLVE = (1 << 0), - SSR_TWO_HIT = (1 << 1), - SSR_FULL_TRACE = (1 << 2), - SSR_NORMALIZE = (1 << 3), - SSR_MAX_SHADER = (1 << 4), + SSR_FULL_TRACE = (1 << 1), + SSR_MAX_SHADER = (1 << 2), }; static struct { @@ -194,15 +192,9 @@ static struct GPUShader *eevee_effects_ssr_shader_get(int options) else { BLI_dynstr_appendf(ds_defines, "#define STEP_RAYTRACE\n"); } - if (options & SSR_TWO_HIT) { - BLI_dynstr_appendf(ds_defines, "#define TWO_HIT\n"); - } if (options & SSR_FULL_TRACE) { BLI_dynstr_appendf(ds_defines, "#define FULLRES\n"); } - if (options & SSR_NORMALIZE) { - BLI_dynstr_appendf(ds_defines, "#define USE_NORMALIZATION\n"); - } char *ssr_define_str = BLI_dynstr_get_cstring(ds_defines); BLI_dynstr_free(ds_defines); @@ -581,12 +573,16 @@ void EEVEE_effects_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata) /* Enable double buffering to be able to read previous frame color */ effects->enabled_effects |= EFFECT_DOUBLE_BUFFER; - effects->ssr_use_two_hit = BKE_collection_engine_property_value_get_bool(props, "ssr_two_rays"); + effects->ssr_ray_count = BKE_collection_engine_property_value_get_int(props, "ssr_ray_count"); effects->reflection_trace_full = !BKE_collection_engine_property_value_get_bool(props, "ssr_halfres"); effects->ssr_use_normalization = BKE_collection_engine_property_value_get_bool(props, "ssr_normalize_weight"); effects->ssr_stride = (float)BKE_collection_engine_property_value_get_int(props, "ssr_stride"); effects->ssr_thickness = BKE_collection_engine_property_value_get_float(props, "ssr_thickness"); effects->ssr_border_fac = BKE_collection_engine_property_value_get_float(props, "ssr_border_fade"); + effects->ssr_firefly_fac = BKE_collection_engine_property_value_get_float(props, "ssr_firefly_fac"); + + /* Important, can lead to breakage otherwise. */ + CLAMP(effects->ssr_ray_count, 1, 4); const int divisor = (effects->reflection_trace_full) ? 1 : 2; int tracing_res[2] = {(int)viewport_size[0] / divisor, (int)viewport_size[1] / divisor}; @@ -613,10 +609,12 @@ void EEVEE_effects_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata) /* Raytracing output */ /* TODO try integer format for hit coord to increase precision */ - DRWFboTexture tex_output[2] = {{&stl->g_data->ssr_hit_output, (effects->ssr_use_two_hit) ? DRW_TEX_RGBA_16 : DRW_TEX_RG_16, DRW_TEX_TEMP}, - {&stl->g_data->ssr_pdf_output, (effects->ssr_use_two_hit) ? DRW_TEX_RG_16 : DRW_TEX_R_16, DRW_TEX_TEMP}}; + DRWFboTexture tex_output[4] = {{&stl->g_data->ssr_hit_output[0], DRW_TEX_RGBA_16, DRW_TEX_TEMP}, + {&stl->g_data->ssr_hit_output[1], DRW_TEX_RGBA_16, DRW_TEX_TEMP}, + {&stl->g_data->ssr_hit_output[2], DRW_TEX_RGBA_16, DRW_TEX_TEMP}, + {&stl->g_data->ssr_hit_output[3], DRW_TEX_RGBA_16, DRW_TEX_TEMP}}; - DRW_framebuffer_init(&fbl->screen_tracing_fb, &draw_engine_eevee_type, tracing_res[0], tracing_res[1], tex_output, 2); + DRW_framebuffer_init(&fbl->screen_tracing_fb, &draw_engine_eevee_type, tracing_res[0], tracing_res[1], tex_output, effects->ssr_ray_count); /* Compute pixel projection matrix */ { @@ -641,8 +639,9 @@ void EEVEE_effects_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata) DRW_TEXTURE_FREE_SAFE(txl->ssr_normal_input); DRW_TEXTURE_FREE_SAFE(txl->ssr_specrough_input); DRW_FRAMEBUFFER_FREE_SAFE(fbl->screen_tracing_fb); - stl->g_data->ssr_hit_output = NULL; - stl->g_data->ssr_pdf_output = NULL; + for (int i = 0; i < 4; ++i) { + stl->g_data->ssr_hit_output[i] = NULL; + } } /* Setup double buffer so we can access last frame as it was before post processes */ @@ -747,10 +746,7 @@ void EEVEE_effects_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata) } if ((effects->enabled_effects & EFFECT_SSR) != 0) { - int options = 0; - options |= (effects->ssr_use_two_hit) ? SSR_TWO_HIT : 0; - options |= (effects->reflection_trace_full) ? SSR_FULL_TRACE : 0; - options |= (effects->ssr_use_normalization) ? SSR_NORMALIZE : 0; + int options = (effects->reflection_trace_full) ? SSR_FULL_TRACE : 0; struct GPUShader *trace_shader = eevee_effects_ssr_shader_get(options); struct GPUShader *resolve_shader = eevee_effects_ssr_shader_get(SSR_RESOLVE | options); @@ -764,6 +760,7 @@ void EEVEE_effects_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata) DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)stl->g_data->viewvecs, 2); DRW_shgroup_uniform_vec2(grp, "ssrParameters", &effects->ssr_stride, 1); DRW_shgroup_uniform_mat4(grp, "PixelProjMatrix", (float *)&e_data.pixelprojmat); + DRW_shgroup_uniform_int(grp, "rayCount", &effects->ssr_ray_count, 1); DRW_shgroup_call_add(grp, quad, NULL); psl->ssr_resolve = DRW_pass_create("SSR Resolve", DRW_STATE_WRITE_COLOR | DRW_STATE_ADDITIVE); @@ -773,18 +770,22 @@ void EEVEE_effects_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata) 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, "hitBuffer", &stl->g_data->ssr_hit_output); - DRW_shgroup_uniform_buffer(grp, "pdfBuffer", &stl->g_data->ssr_pdf_output); 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, "probe_count", &sldata->probes->num_render_cube, 1); DRW_shgroup_uniform_float(grp, "borderFadeFactor", &effects->ssr_border_fac, 1); DRW_shgroup_uniform_float(grp, "lodCubeMax", &sldata->probes->lod_cube_max, 1); DRW_shgroup_uniform_float(grp, "lodPlanarMax", &sldata->probes->lod_planar_max, 1); + DRW_shgroup_uniform_float(grp, "fireflyFactor", &effects->ssr_firefly_fac, 1); DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo); DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo); DRW_shgroup_uniform_buffer(grp, "probeCubes", &sldata->probe_pool); DRW_shgroup_uniform_buffer(grp, "probePlanars", &vedata->txl->planar_pool); + DRW_shgroup_uniform_buffer(grp, "hitBuffer0", &stl->g_data->ssr_hit_output[0]); + DRW_shgroup_uniform_buffer(grp, "hitBuffer1", (effects->ssr_ray_count < 2) ? &stl->g_data->ssr_hit_output[0] : &stl->g_data->ssr_hit_output[1]); + DRW_shgroup_uniform_buffer(grp, "hitBuffer2", (effects->ssr_ray_count < 3) ? &stl->g_data->ssr_hit_output[0] : &stl->g_data->ssr_hit_output[2]); + DRW_shgroup_uniform_buffer(grp, "hitBuffer3", (effects->ssr_ray_count < 4) ? &stl->g_data->ssr_hit_output[0] : &stl->g_data->ssr_hit_output[3]); + DRW_shgroup_uniform_int(grp, "rayCount", &effects->ssr_ray_count, 1); DRW_shgroup_call_add(grp, quad, NULL); } @@ -1063,8 +1064,9 @@ void EEVEE_effects_do_ssr(EEVEE_SceneLayerData *UNUSED(sldata), EEVEE_Data *veda DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); e_data.depth_src = dtxl->depth; - DRW_framebuffer_texture_attach(fbl->screen_tracing_fb, stl->g_data->ssr_hit_output, 0, 0); - DRW_framebuffer_texture_attach(fbl->screen_tracing_fb, stl->g_data->ssr_pdf_output, 1, 0); + for (int i = 0; i < effects->ssr_ray_count; ++i) { + DRW_framebuffer_texture_attach(fbl->screen_tracing_fb, stl->g_data->ssr_hit_output[i], i, 0); + } DRW_framebuffer_bind(fbl->screen_tracing_fb); if (stl->g_data->valid_double_buffer) { @@ -1072,12 +1074,13 @@ void EEVEE_effects_do_ssr(EEVEE_SceneLayerData *UNUSED(sldata), EEVEE_Data *veda DRW_draw_pass(psl->ssr_raytrace); } else { - float clear_col[4] = {-1.0f, -1.0f, -1.0f, -1.0f}; + float clear_col[4] = {0.0f, 0.0f, -1.0f, 0.001f}; DRW_framebuffer_clear(true, false, false, clear_col, 0.0f); } - DRW_framebuffer_texture_detach(stl->g_data->ssr_hit_output); - DRW_framebuffer_texture_detach(stl->g_data->ssr_pdf_output); + for (int i = 0; i < effects->ssr_ray_count; ++i) { + DRW_framebuffer_texture_detach(stl->g_data->ssr_hit_output[i]); + } EEVEE_downsample_buffer(vedata, fbl->downsample_fb, txl->color_double_buffer, 9); @@ -1239,24 +1242,21 @@ void EEVEE_draw_effects(EEVEE_Data *vedata) DRW_transform_to_display(effects->source_buffer); /* Debug : Ouput buffer to view. */ - if ((G.debug_value > 0) && (G.debug_value <= 6)) { + if ((G.debug_value > 0) && (G.debug_value <= 5)) { switch (G.debug_value) { case 1: if (stl->g_data->minzbuffer) DRW_transform_to_display(stl->g_data->minzbuffer); break; case 2: - if (stl->g_data->ssr_hit_output) DRW_transform_to_display(stl->g_data->ssr_hit_output); + if (stl->g_data->ssr_hit_output[0]) DRW_transform_to_display(stl->g_data->ssr_hit_output[0]); break; case 3: - if (stl->g_data->ssr_pdf_output) DRW_transform_to_display(stl->g_data->ssr_pdf_output); - break; - case 4: if (txl->ssr_normal_input) DRW_transform_to_display(txl->ssr_normal_input); break; - case 5: + case 4: if (txl->ssr_specrough_input) DRW_transform_to_display(txl->ssr_specrough_input); break; - case 6: + case 5: if (txl->color_double_buffer) DRW_transform_to_display(txl->color_double_buffer); break; default: diff --git a/source/blender/draw/engines/eevee/eevee_engine.c b/source/blender/draw/engines/eevee/eevee_engine.c index 74b1280ff56..3e2408034d7 100644 --- a/source/blender/draw/engines/eevee/eevee_engine.c +++ b/source/blender/draw/engines/eevee/eevee_engine.c @@ -208,12 +208,12 @@ static void EEVEE_scene_layer_settings_create(RenderEngine *UNUSED(engine), IDPr props->subtype == IDP_GROUP_SUB_ENGINE_RENDER); BKE_collection_engine_property_add_bool(props, "ssr_enable", false); - BKE_collection_engine_property_add_bool(props, "ssr_two_rays", false); - BKE_collection_engine_property_add_bool(props, "ssr_normalize_weight", false); BKE_collection_engine_property_add_bool(props, "ssr_halfres", true); + BKE_collection_engine_property_add_int(props, "ssr_ray_count", 1); BKE_collection_engine_property_add_int(props, "ssr_stride", 16); BKE_collection_engine_property_add_float(props, "ssr_thickness", 0.2f); BKE_collection_engine_property_add_float(props, "ssr_border_fade", 0.075f); + BKE_collection_engine_property_add_float(props, "ssr_firefly_fac", 0.5f); BKE_collection_engine_property_add_bool(props, "volumetric_enable", false); BKE_collection_engine_property_add_float(props, "volumetric_start", 0.1f); diff --git a/source/blender/draw/engines/eevee/eevee_lightprobes.c b/source/blender/draw/engines/eevee/eevee_lightprobes.c index d5986cb7e03..c5b1966f9da 100644 --- a/source/blender/draw/engines/eevee/eevee_lightprobes.c +++ b/source/blender/draw/engines/eevee/eevee_lightprobes.c @@ -1052,7 +1052,6 @@ static void render_scene_to_planar( EEVEE_FramebufferList *fbl = vedata->fbl; EEVEE_TextureList *txl = vedata->txl; EEVEE_PassList *psl = vedata->psl; - EEVEE_StorageList *stl = vedata->stl; float viewinv[4][4]; float persinv[4][4]; diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h index ae928cf0dbb..55fb550d940 100644 --- a/source/blender/draw/engines/eevee/eevee_private.h +++ b/source/blender/draw/engines/eevee/eevee_private.h @@ -322,8 +322,9 @@ typedef struct EEVEE_EffectsInfo { /* SSR */ bool use_ssr; bool reflection_trace_full; - bool ssr_use_two_hit; bool ssr_use_normalization; + int ssr_ray_count; + float ssr_firefly_fac; float ssr_border_fac; float ssr_stride; float ssr_thickness; @@ -459,8 +460,7 @@ typedef struct EEVEE_PrivateData { struct GHash *material_hash; struct GHash *hair_material_hash; struct GPUTexture *minzbuffer; - struct GPUTexture *ssr_hit_output; - struct GPUTexture *ssr_pdf_output; + struct GPUTexture *ssr_hit_output[4]; struct GPUTexture *volumetric; struct GPUTexture *volumetric_transmit; float background_alpha; /* TODO find a better place for this. */ 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 268afa1e373..7b516f27ec9 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl @@ -1,9 +1,14 @@ +/* Based on Stochastic Screen Space Reflections + * https://www.ea.com/frostbite/news/stochastic-screen-space-reflections */ + #ifndef UTIL_TEX #define UTIL_TEX uniform sampler2DArray utilTex; #endif /* UTIL_TEX */ +uniform int rayCount; + #define BRDF_BIAS 0.7 vec3 generate_ray(vec3 V, vec3 N, float a2, vec3 rand, out float pdf) @@ -15,6 +20,7 @@ vec3 generate_ray(vec3 V, vec3 N, float a2, vec3 rand, out float pdf) /* 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); @@ -28,8 +34,34 @@ uniform sampler2D depthBuffer; uniform sampler2D normalBuffer; uniform sampler2D specroughBuffer; -layout(location = 0) out vec4 hitData; -layout(location = 1) out vec4 pdfData; +uniform mat4 ViewProjectionMatrix; + +layout(location = 0) out vec4 hitData0; +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) +{ + 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); +} + +vec4 do_ssr(sampler2D depthBuffer, vec3 V, vec3 N, vec3 viewPosition, float a2, vec3 rand) +{ + float pdf; + vec3 R = generate_ray(V, N, a2, rand, pdf); + + float hit_dist = raycast(depthBuffer, viewPosition, R, rand.x); + vec3 hit_pos = viewPosition + R * abs(hit_dist); + + if (has_hit_backface(hit_pos, R, V) || (hit_dist <= 0.0)) { + hit_pos.z *= -1.0; + } + + return vec4(hit_pos, pdf); +} void main() { @@ -68,81 +100,13 @@ void main() float roughnessSquared = max(1e-3, roughness * roughness); float a2 = roughnessSquared * roughnessSquared; - /* Generate Ray */ - float pdf; vec3 rand = texelFetch(utilTex, ivec3(halfres_texel % LUT_SIZE, 2), 0).rba; - vec3 R = generate_ray(V, N, a2, rand, pdf); -#ifdef TWO_HIT - float pdf2; - vec3 R2 = generate_ray(V, N, a2, rand * vec3(1.0, -1.0, -1.0), pdf2); -#endif - - /* Search for the planar reflection affecting this pixel */ - /* If no planar is found, fallback to screen space */ - - /* Raycast over planar reflection */ - /* Potentially lots of time waisted here for pixels - * that does not have planar reflections. TODO Profile it. */ - /* TODO: Idea, rasterize boxes around planar - * reflection volumes (frontface culling to avoid overdraw) - * and do the raycasting, discard pixel that are not in influence. - * Add stencil test to discard the main SSR. - * Cons: - Potentially raytrace multiple times - * if Planar Influence overlaps. */ - //float hit_dist = raycast(depthBuffer, W, R); - - /* Raycast over screen */ - float hit_dist = -1.0; -#ifdef TWO_HIT - float hit_dist2 = -1.0; -#endif - /* Only raytrace if ray is above the surface normal */ - /* Note : this still fails in some cases like with normal map. - * We should check against the geometric normal but we don't have it at this stage. */ - if (dot(R, N) > 0.0001) { - hit_dist = raycast(depthBuffer, viewPosition, R, rand.x); - } -#ifdef TWO_HIT - /* TODO do double raytrace at the same time */ - if (dot(R2, N) > 0.0001) { - hit_dist2 = raycast(depthBuffer, viewPosition, R2, rand.x); - } -#endif - - /* TODO Do reprojection here */ - vec2 hit_co = project_point(ProjectionMatrix, viewPosition + R * hit_dist).xy * 0.5 + 0.5; -#ifdef TWO_HIT - vec2 hit_co2 = project_point(ProjectionMatrix, viewPosition + R2 * hit_dist2).xy * 0.5 + 0.5; -#endif - - /* Check if has hit a backface */ - vec3 hit_N = normal_decode(textureLod(normalBuffer, hit_co, 0.0).rg, V); - hit_dist *= step(0.0, dot(-R, hit_N)); -#ifdef TWO_HIT - hit_N = normal_decode(textureLod(normalBuffer, hit_co2, 0.0).rg, V); - hit_dist2 *= step(0.0, dot(-R2, hit_N)); -#endif - - if (hit_dist > 0.0) { - hitData = hit_co.xyxy; - } - else { - hitData = vec4(-1.0); - } -#ifdef TWO_HIT - if (hit_dist2 > 0.0) { - hitData.zw = hit_co2; - } - else { - hitData.zw = vec2(-1.0); - } -#endif -#ifdef TWO_HIT - pdfData = vec4(pdf, pdf2, 0.0, 0.0); -#else - pdfData = vec4(pdf); -#endif + /* TODO : Raytrace together if textureGather is supported. */ + hitData0 = do_ssr(depthBuffer, V, N, viewPosition, a2, rand); + if (rayCount > 1) hitData1 = do_ssr(depthBuffer, V, N, viewPosition, a2, rand.xyz * vec3(1.0, -1.0, -1.0)); + if (rayCount > 2) hitData2 = do_ssr(depthBuffer, V, N, viewPosition, a2, rand.xzy * vec3(1.0, 1.0, -1.0)); + if (rayCount > 3) hitData3 = do_ssr(depthBuffer, V, N, viewPosition, a2, rand.xzy * vec3(1.0, -1.0, 1.0)); } #else /* STEP_RESOLVE */ @@ -152,12 +116,15 @@ uniform sampler2D depthBuffer; uniform sampler2D normalBuffer; uniform sampler2D specroughBuffer; -uniform sampler2D hitBuffer; -uniform sampler2D pdfBuffer; +uniform sampler2D hitBuffer0; +uniform sampler2D hitBuffer1; +uniform sampler2D hitBuffer2; +uniform sampler2D hitBuffer3; uniform int probe_count; uniform float borderFadeFactor; +uniform float fireflyFactor; uniform mat4 ViewProjectionMatrix; uniform mat4 PastViewProjectionMatrix; @@ -218,19 +185,6 @@ float brightness(vec3 c) return max(max(c.r, c.g), c.b); } -vec2 get_reprojected_reflection(vec3 hit, vec3 pos, vec3 N) -{ - /* TODO real motion vectors */ - /* Transform to viewspace */ - // vec4(get_view_space_from_depth(uvcoords, depth), 1.0); - // vec4(get_view_space_from_depth(uvcoords, depth), 1.0); - - /* Reproject */ - // vec3 hit_reprojected = find_reflection_incident_point(cameraPos, hit, pos, N); - - return project_point(PastViewProjectionMatrix, hit).xy * 0.5 + 0.5; -} - float screen_border_mask(vec2 past_hit_co, vec3 hit) { /* Fade on current and past screen edges */ @@ -254,44 +208,51 @@ float view_facing_mask(vec3 V, vec3 R) return smoothstep(0.95, 0.80, dot(V, R)); } +vec2 get_reprojected_reflection(vec3 hit, vec3 pos, vec3 N) +{ + /* TODO real reprojection with motion vectors, etc... */ + return project_point(PastViewProjectionMatrix, hit).xy * 0.5 + 0.5; +} + vec4 get_ssr_sample( - vec2 hit_co, vec3 worldPosition, vec3 N, vec3 V, float roughnessSquared, + sampler2D hitBuffer, vec3 worldPosition, vec3 N, vec3 V, float roughnessSquared, float cone_tan, vec2 source_uvs, vec2 texture_size, ivec2 target_texel, - out float weight) + inout float weight_acc) { - /* Reconstruct ray */ - float hit_depth = textureLod(depthBuffer, hit_co, 0.0).r; - vec3 hit_pos = get_world_space_from_depth(hit_co, hit_depth); + vec4 hit_co_pdf = texelFetch(hitBuffer, target_texel, 0).rgba; + bool has_hit = (hit_co_pdf.z < 0.0); + hit_co_pdf.z = -abs(hit_co_pdf.z); - /* Find hit position in previous frame */ + /* Hit position in world space. */ + vec3 hit_pos = (ViewMatrixInverse * vec4(hit_co_pdf.xyz, 1.0)).xyz; + + /* Find hit position in previous frame. */ vec2 ref_uvs = get_reprojected_reflection(hit_pos, worldPosition, N); - /* Estimate a cone footprint to sample a corresponding mipmap level */ - /* compute cone footprint Using UV distance because we are using screen space filtering */ + /* Estimate a cone footprint to sample a corresponding mipmap level. */ + /* Compute cone footprint Using UV distance because we are using screen space filtering. */ float cone_footprint = 1.5 * cone_tan * distance(ref_uvs, source_uvs); float mip = BRDF_BIAS * clamp(log2(cone_footprint * max(texture_size.x, texture_size.y)), 0.0, MAX_MIP); + /* Slide 54 */ vec3 L = normalize(hit_pos - worldPosition); -#ifdef USE_NORMALIZATION - /* Evaluate BSDF */ float bsdf = bsdf_ggx(N, L, V, roughnessSquared); - float pdf = texelFetch(pdfBuffer, target_texel, 0).r; + float weight = step(0.001, hit_co_pdf.w) * bsdf / hit_co_pdf.w; + weight_acc += weight; - weight = step(0.001, pdf) * bsdf / pdf; -#else - weight = 1.0; -#endif + vec3 sample = textureLod(colorBuffer, ref_uvs, mip).rgb; - vec3 sample = textureLod(colorBuffer, ref_uvs, mip).rgb ; + /* Do not add light if ray has failed. */ + sample *= float(has_hit); /* Firefly removal */ - sample /= 1.0 + brightness(sample); + sample /= 1.0 + fireflyFactor * brightness(sample); float mask = screen_border_mask(ref_uvs, hit_pos); mask *= view_facing_mask(V, N); + mask *= float(has_hit); - /* Check if there was a hit */ - return vec4(sample, mask) * weight * step(0.0, hit_co.x); + return vec4(sample, mask) * weight; } #define NUM_NEIGHBORS 9 @@ -341,34 +302,40 @@ void main() float weight_acc = 0.0; const ivec2 neighbors[9] = ivec2[9]( ivec2(0, 0), - ivec2(-1, 1), ivec2(0, 1), ivec2(1, 1), - ivec2(-1, 0), ivec2(1, 0), - ivec2(-1, -1), ivec2(0, -1), ivec2(1, -1) + + ivec2(0, 1), + ivec2(-1, -1), ivec2(1, -1), + + ivec2(-1, 1), ivec2(1, 1), + ivec2(0, -1), + + ivec2(-1, 0), ivec2(1, 0) ); ivec2 invert_neighbor; invert_neighbor.x = ((fullres_texel.x & 0x1) == 0) ? 1 : -1; invert_neighbor.y = ((fullres_texel.y & 0x1) == 0) ? 1 : -1; + for (int i = 0; i < NUM_NEIGHBORS; i++) { ivec2 target_texel = halfres_texel + neighbors[i] * invert_neighbor; -#ifdef TWO_HIT - vec4 hit_co = texelFetch(hitBuffer, target_texel, 0).rgba; -#else - vec2 hit_co = texelFetch(hitBuffer, target_texel, 0).rg; -#endif - - float weight; - ssr_accum += get_ssr_sample(hit_co.xy, worldPosition, N, V, - roughnessSquared, cone_tan, source_uvs, - texture_size, target_texel, weight); - weight_acc += weight; - -#ifdef TWO_HIT - ssr_accum += get_ssr_sample(hit_co.zw, worldPosition, N, V, + ssr_accum += get_ssr_sample(hitBuffer0, worldPosition, N, V, roughnessSquared, cone_tan, source_uvs, - texture_size, target_texel, weight); - weight_acc += weight; -#endif + texture_size, target_texel, weight_acc); + if (rayCount > 1) { + ssr_accum += get_ssr_sample(hitBuffer1, worldPosition, N, V, + roughnessSquared, cone_tan, source_uvs, + texture_size, target_texel, weight_acc); + } + if (rayCount > 2) { + ssr_accum += get_ssr_sample(hitBuffer2, worldPosition, N, V, + roughnessSquared, cone_tan, source_uvs, + texture_size, target_texel, weight_acc); + } + if (rayCount > 3) { + ssr_accum += get_ssr_sample(hitBuffer3, worldPosition, N, V, + roughnessSquared, cone_tan, source_uvs, + texture_size, target_texel, weight_acc); + } } /* Compute SSR contribution */ @@ -385,8 +352,6 @@ void main() } fragColor = vec4(spec_accum.rgb * speccol_roughness.rgb, 1.0); - // vec2 _uvs = project_point(PastViewProjectionMatrix, worldPosition).xy * 0.5 + 0.5; - // fragColor = vec4(textureLod(colorBuffer, _uvs, roughness * MAX_MIP).rgb, 1.0); } #endif diff --git a/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl b/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl index f017453bad0..421079c0bfa 100644 --- a/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl @@ -21,15 +21,20 @@ void swapIfBigger(inout float a, inout float b) } } -/* Return the length of the ray if there is a hit, and -1.0 if not hit occured */ +/* Return the length of the ray if there is a hit, and negate it if not hit occured */ float raycast(sampler2D depth_texture, vec3 ray_origin, vec3 ray_dir, float ray_jitter) { float near = get_view_z_from_depth(0.0); /* TODO optimize */ + float far = get_view_z_from_depth(1.0); /* TODO optimize */ - /* Clip ray to a near plane in 3D */ + /* Clip ray to a near/far plane in 3D */ float ray_length = 1e16; - if ((ray_origin.z + ray_dir.z * ray_length) > near) + if ((ray_origin.z + ray_dir.z * ray_length) > near) { ray_length = (near - ray_origin.z) / ray_dir.z; + } + else { + ray_length = (ray_origin.z - far) / -ray_dir.z; + } vec3 ray_end = ray_dir * ray_length + ray_origin; @@ -136,7 +141,7 @@ float raycast(sampler2D depth_texture, vec3 ray_origin, vec3 ray_dir, float ray_ prev_zmax = (dPQK.z * -0.5 + pqk.z) / (dPQK.w * -0.5 + pqk.w); - for (float refinestep = 0.0; refinestep < ssrStride * 2.0 && refinestep < MAX_REFINE_STEP * 2.0; refinestep++) { + for (float refinestep = 0.0; refinestep < (ssrStride * 2.0) && refinestep < (MAX_REFINE_STEP * 2.0); refinestep++) { /* step through current cell */ pqk += dPQK; @@ -159,9 +164,14 @@ float raycast(sampler2D depth_texture, vec3 ray_origin, vec3 ray_dir, float ray_ } } - /* Background case. */ - hit = hit && (raw_depth != 1.0); + /* If we did hit the background, get exact ray. */ + if (raw_depth == 1.0) { + zmax = get_view_z_from_depth(1.0); /* TODO optimize */ + } + + hit = hit && (raw_depth != 0.0); /* Return length */ - return (hit) ? (zmax - ray_origin.z) / ray_dir.z : -1.0; + float result = (zmax - ray_origin.z) / ray_dir.z; + return (hit) ? result : -result; } diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index a3983290236..b2c1ea73f8a 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -2623,12 +2623,12 @@ RNA_LAYER_ENGINE_EEVEE_GET_SET_BOOL(volumetric_shadows) RNA_LAYER_ENGINE_EEVEE_GET_SET_INT(volumetric_shadow_samples) RNA_LAYER_ENGINE_EEVEE_GET_SET_BOOL(volumetric_colored_transmittance) RNA_LAYER_ENGINE_EEVEE_GET_SET_BOOL(ssr_enable) -RNA_LAYER_ENGINE_EEVEE_GET_SET_BOOL(ssr_two_rays) RNA_LAYER_ENGINE_EEVEE_GET_SET_BOOL(ssr_halfres) -RNA_LAYER_ENGINE_EEVEE_GET_SET_BOOL(ssr_normalize_weight) +RNA_LAYER_ENGINE_EEVEE_GET_SET_INT(ssr_ray_count) RNA_LAYER_ENGINE_EEVEE_GET_SET_INT(ssr_stride) RNA_LAYER_ENGINE_EEVEE_GET_SET_FLOAT(ssr_thickness) RNA_LAYER_ENGINE_EEVEE_GET_SET_FLOAT(ssr_border_fade) +RNA_LAYER_ENGINE_EEVEE_GET_SET_FLOAT(ssr_firefly_fac) /* object engine */ RNA_LAYER_MODE_OBJECT_GET_SET_BOOL(show_wire) @@ -6198,20 +6198,6 @@ static void rna_def_scene_layer_engine_settings_eevee(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_SceneLayerEngineSettings_update"); - prop = RNA_def_property(srna, "ssr_two_rays", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_funcs(prop, "rna_LayerEngineSettings_Eevee_ssr_two_rays_get", - "rna_LayerEngineSettings_Eevee_ssr_two_rays_set"); - RNA_def_property_ui_text(prop, "Double Trace", "Raytrace two rays instead of just one"); - RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); - RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_SceneLayerEngineSettings_update"); - - prop = RNA_def_property(srna, "ssr_normalize_weight", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_funcs(prop, "rna_LayerEngineSettings_Eevee_ssr_normalize_weight_get", - "rna_LayerEngineSettings_Eevee_ssr_normalize_weight_set"); - RNA_def_property_ui_text(prop, "Weight Normalize", "Fills low resolution in reflection but exhibit harsh transition"); - RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); - RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_SceneLayerEngineSettings_update"); - prop = RNA_def_property(srna, "ssr_stride", PROP_INT, PROP_PIXEL); RNA_def_property_int_funcs(prop, "rna_LayerEngineSettings_Eevee_ssr_stride_get", "rna_LayerEngineSettings_Eevee_ssr_stride_set", NULL); @@ -6220,6 +6206,14 @@ static void rna_def_scene_layer_engine_settings_eevee(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_SceneLayerEngineSettings_update"); + prop = RNA_def_property(srna, "ssr_ray_count", PROP_INT, PROP_NONE); + RNA_def_property_int_funcs(prop, "rna_LayerEngineSettings_Eevee_ssr_ray_count_get", + "rna_LayerEngineSettings_Eevee_ssr_ray_count_set", NULL); + RNA_def_property_ui_text(prop, "Samples", "Number of rays to trace per pixels"); + RNA_def_property_range(prop, 1, 4); + RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); + RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_SceneLayerEngineSettings_update"); + prop = RNA_def_property(srna, "ssr_thickness", PROP_FLOAT, PROP_DISTANCE); RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Eevee_ssr_thickness_get", "rna_LayerEngineSettings_Eevee_ssr_thickness_set", NULL); @@ -6237,6 +6231,14 @@ static void rna_def_scene_layer_engine_settings_eevee(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_SceneLayerEngineSettings_update"); + prop = RNA_def_property(srna, "ssr_firefly_fac", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_funcs(prop, "rna_LayerEngineSettings_Eevee_ssr_firefly_fac_get", + "rna_LayerEngineSettings_Eevee_ssr_firefly_fac_set", NULL); + RNA_def_property_ui_text(prop, "Clamp", "Smoothly clamp pixel intensity to remove noise"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); + RNA_def_property_update(prop, NC_SCENE | ND_LAYER_CONTENT, "rna_SceneLayerEngineSettings_update"); + /* Volumetrics */ prop = RNA_def_property(srna, "volumetric_enable", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_funcs(prop, "rna_LayerEngineSettings_Eevee_volumetric_enable_get", |