From a3732412ad5b2adda8e820088fba76d3c8f6ea00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Fri, 21 Jul 2017 23:48:48 +0200 Subject: Eevee: SSR: Add stride and thickness parameters. Also polished the raytracing algorithm. --- release/scripts/startup/bl_ui/properties_render.py | 3 + .../startup/bl_ui/properties_render_layer.py | 2 + source/blender/draw/engines/eevee/eevee_effects.c | 3 + source/blender/draw/engines/eevee/eevee_engine.c | 2 + source/blender/draw/engines/eevee/eevee_private.h | 2 + .../draw/engines/eevee/shaders/raytrace_lib.glsl | 69 +++++++++++----------- source/blender/makesrna/intern/rna_scene.c | 19 ++++++ 7 files changed, 67 insertions(+), 33 deletions(-) diff --git a/release/scripts/startup/bl_ui/properties_render.py b/release/scripts/startup/bl_ui/properties_render.py index 5dcedc152ef..4cd69714e3b 100644 --- a/release/scripts/startup/bl_ui/properties_render.py +++ b/release/scripts/startup/bl_ui/properties_render.py @@ -726,6 +726,9 @@ class RENDER_PT_eevee_shading(RenderButtonsPanel, Panel): col = layout.column() col.prop(props, "ssr_enable") + col.prop(props, "ssr_stride") + col.prop(props, "ssr_thickness") + col.prop(props, "ssr_border_fade") classes = ( diff --git a/release/scripts/startup/bl_ui/properties_render_layer.py b/release/scripts/startup/bl_ui/properties_render_layer.py index be39de65964..f6bc0698cbe 100644 --- a/release/scripts/startup/bl_ui/properties_render_layer.py +++ b/release/scripts/startup/bl_ui/properties_render_layer.py @@ -268,6 +268,8 @@ class RENDERLAYER_PT_eevee_shading(RenderLayerButtonsPanel, Panel): col = layout.column() col.template_override_property(layer_props, scene_props, "ssr_enable") + col.template_override_property(layer_props, scene_props, "ssr_stride") + col.template_override_property(layer_props, scene_props, "ssr_thickness") classes = ( diff --git a/source/blender/draw/engines/eevee/eevee_effects.c b/source/blender/draw/engines/eevee/eevee_effects.c index 13c6bf4ee44..245dc19ab85 100644 --- a/source/blender/draw/engines/eevee/eevee_effects.c +++ b/source/blender/draw/engines/eevee/eevee_effects.c @@ -549,6 +549,8 @@ void EEVEE_effects_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata) effects->enabled_effects |= EFFECT_DOUBLE_BUFFER; effects->reflection_trace_full = true; + 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"); const int divisor = (effects->reflection_trace_full) ? 1 : 2; int tracing_res[2] = {(int)viewport_size[0] / divisor, (int)viewport_size[1] / divisor}; @@ -723,6 +725,7 @@ 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_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_call_add(grp, quad, NULL); diff --git a/source/blender/draw/engines/eevee/eevee_engine.c b/source/blender/draw/engines/eevee/eevee_engine.c index 4ee3dee655f..6ca120a7a9b 100644 --- a/source/blender/draw/engines/eevee/eevee_engine.c +++ b/source/blender/draw/engines/eevee/eevee_engine.c @@ -212,6 +212,8 @@ 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_int(props, "ssr_stride", 16); + BKE_collection_engine_property_add_float(props, "ssr_thickness", 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_private.h b/source/blender/draw/engines/eevee/eevee_private.h index 22d100ba13e..50db5365d2b 100644 --- a/source/blender/draw/engines/eevee/eevee_private.h +++ b/source/blender/draw/engines/eevee/eevee_private.h @@ -321,6 +321,8 @@ typedef struct EEVEE_EffectsInfo { /* SSR */ bool use_ssr; bool reflection_trace_full; + float ssr_stride; + float ssr_thickness; /* Ambient Occlusion */ bool use_ao, use_bent_normals; diff --git a/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl b/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl index 1e10311bf35..36787153afc 100644 --- a/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl @@ -4,8 +4,13 @@ * http://casual-effects.blogspot.fr/2014/08/screen-space-ray-tracing.html */ #define MAX_STEP 256 +#define MAX_REFINE_STEP 32 /* Should be max allowed stride */ uniform mat4 PixelProjMatrix; /* View > NDC > Texel : maps view coords to texel coord */ +uniform vec2 ssrParameters; + +#define ssrStride ssrParameters.x +#define ssrThickness ssrParameters.y void swapIfBigger(inout float a, inout float b) { @@ -48,9 +53,6 @@ float raycast(sampler2D depth_texture, vec3 ray_origin, vec3 ray_dir) /* [Optional clipping to frustum sides here] */ - /* Initialize to off screen */ - vec2 hitpixel = vec2(-1.0, -1.0); - /* If the line is degenerate, make it cover at least one pixel * to not have to handle zero-pixel extent as a special case later */ P1 += vec2((distance_squared(P0, P1) < 0.0001) ? 0.01 : 0.0); @@ -80,82 +82,83 @@ float raycast(sampler2D depth_texture, vec3 ray_origin, vec3 ray_dir) vec4 pqk = vec4(P0, Q0.z, k0); /* Scale derivatives by the desired pixel stride */ - vec4 dPQK = vec4(dP, dQ.z, dk) * 8.0; + vec4 dPQK = vec4(dP, dQ.z, dk) * ssrStride; /* We track the ray depth at +/- 1/2 pixel to treat pixels as clip-space solid * voxels. Because the depth at -1/2 for a given pixel will be the same as at * +1/2 for the previous iteration, we actually only have to compute one value * per iteration. */ float prev_zmax = ray_origin.z; - float zmax, zmin; + float zmax; /* P1.x is never modified after this point, so pre-scale it by * the step direction for a signed comparison */ float end = P1.x * step_sign; bool hit = false; - float hitstep, raw_depth, view_depth; - for (hitstep = 0.0; hitstep < MAX_STEP && !hit; hitstep++) { + float raw_depth; + for (float hitstep = 0.0; hitstep < MAX_STEP && !hit; hitstep++) { /* Ray finished & no hit*/ if ((pqk.x * step_sign) > end) break; /* step through current cell */ pqk += dPQK; - hitpixel = permute ? pqk.yx : pqk.xy; - zmin = prev_zmax; + ivec2 hitpixel = ivec2(permute ? pqk.yx : pqk.xy); + raw_depth = texelFetch(depth_texture, ivec2(hitpixel), 0).r; + + float zmin = prev_zmax; zmax = (dPQK.z * 0.5 + pqk.z) / (dPQK.w * 0.5 + pqk.w); prev_zmax = zmax; - swapIfBigger(zmin, zmax); + swapIfBigger(zmin, zmax); /* ??? why don't we need this ??? */ - raw_depth = texelFetch(depth_texture, ivec2(hitpixel), 0).r; - view_depth = get_view_z_from_depth(raw_depth); + float vmax = get_view_z_from_depth(raw_depth); + float vmin = vmax - ssrThickness; - /* TODO user threshold */ - const float threshold = 0.5; /* In view space */ /* Check if we are somewhere near the surface. */ - if ((zmax < view_depth) && (zmax > view_depth - threshold)) { + /* Note: we consider hitting the screen borders (raw_depth == 0.0) + * as valid to check for occluder in the refine pass */ + if (!((zmin > vmax) || (zmax < vmin)) || (raw_depth == 0.0)) { /* Below surface, cannot trace further */ hit = true; } } if (hit) { - /* Rewind back a step */ + /* Rewind back a step. */ pqk -= dPQK; - /* And do a finer trace over this segment */ - dPQK /= 16.0; + /* And do a finer trace over this segment. */ + dPQK /= ssrStride; + + prev_zmax = (dPQK.z * -0.5 + pqk.z) / (dPQK.w * -0.5 + pqk.w); - for (float refinestep = 0.0; refinestep < 16.0; refinestep++) { + for (float refinestep = 0.0; refinestep < ssrStride * 2.0 && refinestep < MAX_REFINE_STEP * 2.0; refinestep++) { /* step through current cell */ pqk += dPQK; - hitpixel = permute ? pqk.yx : pqk.xy; - zmin = prev_zmax; + ivec2 hitpixel = ivec2(permute ? pqk.yx : pqk.xy); + raw_depth = texelFetch(depth_texture, hitpixel, 0).r; + + float zmin = prev_zmax; zmax = (dPQK.z * 0.5 + pqk.z) / (dPQK.w * 0.5 + pqk.w); prev_zmax = zmax; swapIfBigger(zmin, zmax); - raw_depth = texelFetch(depth_texture, ivec2(hitpixel), 0).r; - view_depth = get_view_z_from_depth(raw_depth); + float vmax = get_view_z_from_depth(raw_depth); + float vmin = vmax - ssrThickness; - /* TODO user threshold */ - const float threshold = 0.5; /* In view space */ /* Check if we are somewhere near the surface. */ - if ((zmax < view_depth) && (zmax > view_depth - threshold)) { + if (!((zmin > vmax) || (zmax < vmin)) || (raw_depth == 0.0)) { /* Below surface, cannot trace further */ break; } } } - /* Check failure cases (out of screen, hit background) */ - if (hit && (raw_depth != 1.0) && (raw_depth != 0.0)) { - /* Return length */ - return (zmax - ray_origin.z) / ray_dir.z; - } + /* Background case. */ + hit = hit && (raw_depth != 1.0); - /* Failure, return no hit */ - return -1.0; + /* Return length */ + return (hit) ? (zmax - ray_origin.z) / ray_dir.z : -1.0; } diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index a0f8f500d26..314d0b18f5f 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -2623,6 +2623,8 @@ 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_INT(ssr_stride) +RNA_LAYER_ENGINE_EEVEE_GET_SET_FLOAT(ssr_thickness) /* object engine */ RNA_LAYER_MODE_OBJECT_GET_SET_BOOL(show_wire) @@ -6185,6 +6187,23 @@ 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_stride", PROP_INT, PROP_PIXEL); + RNA_def_property_int_funcs(prop, "rna_LayerEngineSettings_Eevee_ssr_stride_get", + "rna_LayerEngineSettings_Eevee_ssr_stride_set", NULL); + RNA_def_property_ui_text(prop, "Stride", "Step size between two raymarching samples"); + RNA_def_property_range(prop, 1, 32); + 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); + RNA_def_property_ui_text(prop, "Thickness", "Pixel thickness used to detect intersection"); + RNA_def_property_range(prop, 1e-6f, FLT_MAX); + RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 5, 3); + 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", -- cgit v1.2.3