Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClément Foucault <foucault.clem@gmail.com>2017-07-23 01:03:45 +0300
committerClément Foucault <foucault.clem@gmail.com>2017-07-23 01:03:45 +0300
commit455aeb14954f59c0a0a67419dbe21ec3607f5541 (patch)
tree718516c87a77392ffbf9ce12769e4d0ede39821f
parentf359db19771102c85eac8e7c8494f667bd6e1315 (diff)
Eevee: SSR: Add two hit option.
This option add another raytrace per pixel, clearing some noise. But multiplying the raytrace cost.
-rw-r--r--release/scripts/startup/bl_ui/properties_render.py1
-rw-r--r--release/scripts/startup/bl_ui/properties_render_layer.py1
-rw-r--r--source/blender/draw/engines/eevee/eevee_effects.c119
-rw-r--r--source/blender/draw/engines/eevee/eevee_engine.c1
-rw-r--r--source/blender/draw/engines/eevee/eevee_private.h2
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl115
-rw-r--r--source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl2
-rw-r--r--source/blender/makesrna/intern/rna_scene.c8
8 files changed, 165 insertions, 84 deletions
diff --git a/release/scripts/startup/bl_ui/properties_render.py b/release/scripts/startup/bl_ui/properties_render.py
index 2ab67e5651d..136ee3732ff 100644
--- a/release/scripts/startup/bl_ui/properties_render.py
+++ b/release/scripts/startup/bl_ui/properties_render.py
@@ -727,6 +727,7 @@ class RENDER_PT_eevee_shading(RenderButtonsPanel, Panel):
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_stride")
col.prop(props, "ssr_thickness")
diff --git a/release/scripts/startup/bl_ui/properties_render_layer.py b/release/scripts/startup/bl_ui/properties_render_layer.py
index e8bbf69f947..d5a56fbf84e 100644
--- a/release/scripts/startup/bl_ui/properties_render_layer.py
+++ b/release/scripts/startup/bl_ui/properties_render_layer.py
@@ -269,6 +269,7 @@ 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_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_stride")
col.template_override_property(layer_props, scene_props, "ssr_thickness")
diff --git a/source/blender/draw/engines/eevee/eevee_effects.c b/source/blender/draw/engines/eevee/eevee_effects.c
index da8c569089f..1ac546a0a0b 100644
--- a/source/blender/draw/engines/eevee/eevee_effects.c
+++ b/source/blender/draw/engines/eevee/eevee_effects.c
@@ -56,6 +56,15 @@ typedef struct EEVEE_LightProbeData {
short probe_id, shadow_id;
} 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),
+};
+
static struct {
/* Downsample Depth */
struct GPUShader *minz_downlevel_sh;
@@ -83,12 +92,7 @@ static struct {
struct GPUShader *volumetric_upsample_sh;
/* Screen Space Reflection */
- struct GPUShader *ssr_raytrace_sh;
- struct GPUShader *ssr_raytrace_full_sh;
- struct GPUShader *ssr_resolve_sh;
- struct GPUShader *ssr_resolve_full_sh;
- struct GPUShader *ssr_resolve_norm_sh;
- struct GPUShader *ssr_resolve_full_norm_sh;
+ struct GPUShader *ssr_sh[SSR_MAX_SHADER];
/* Simple Downsample */
struct GPUShader *downsample_sh;
@@ -166,6 +170,48 @@ static void eevee_motion_blur_camera_get_matrix_at_time(
mul_m4_m4m4(r_mat, params.winmat, obmat);
}
+static struct GPUShader *eevee_effects_ssr_shader_get(int options)
+{
+ if (e_data.ssr_sh[options] == NULL) {
+ DynStr *ds_frag = BLI_dynstr_new();
+ BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl);
+ BLI_dynstr_append(ds_frag, datatoc_bsdf_sampling_lib_glsl);
+ BLI_dynstr_append(ds_frag, datatoc_octahedron_lib_glsl);
+ BLI_dynstr_append(ds_frag, datatoc_lightprobe_lib_glsl);
+ BLI_dynstr_append(ds_frag, datatoc_raytrace_lib_glsl);
+ BLI_dynstr_append(ds_frag, datatoc_effect_ssr_frag_glsl);
+ char *ssr_shader_str = BLI_dynstr_get_cstring(ds_frag);
+ BLI_dynstr_free(ds_frag);
+
+ DynStr *ds_defines = BLI_dynstr_new();
+ BLI_dynstr_appendf(ds_defines, SHADER_DEFINES);
+ if (options & SSR_RESOLVE) {
+ BLI_dynstr_appendf(ds_defines, "#define STEP_RESOLVE\n");
+ }
+ 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);
+
+ e_data.ssr_sh[options] = DRW_shader_create_fullscreen(ssr_shader_str, ssr_define_str);
+
+ MEM_freeN(ssr_shader_str);
+ MEM_freeN(ssr_define_str);
+ }
+
+ return e_data.ssr_sh[options];
+}
+
void EEVEE_effects_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata)
{
EEVEE_StorageList *stl = vedata->stl;
@@ -185,30 +231,6 @@ void EEVEE_effects_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata)
/* Shaders */
if (!e_data.motion_blur_sh) {
- DynStr *ds_frag = BLI_dynstr_new();
- BLI_dynstr_append(ds_frag, datatoc_bsdf_common_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_bsdf_sampling_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_octahedron_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_lightprobe_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_raytrace_lib_glsl);
- BLI_dynstr_append(ds_frag, datatoc_effect_ssr_frag_glsl);
- char *ssr_shader_str = BLI_dynstr_get_cstring(ds_frag);
- BLI_dynstr_free(ds_frag);
-
- e_data.ssr_raytrace_sh = DRW_shader_create_fullscreen(ssr_shader_str, SHADER_DEFINES "#define STEP_RAYTRACE\n");
- e_data.ssr_raytrace_full_sh = DRW_shader_create_fullscreen(ssr_shader_str, SHADER_DEFINES "#define STEP_RAYTRACE\n"
- "#define FULLRES\n");
- e_data.ssr_resolve_sh = DRW_shader_create_fullscreen(ssr_shader_str, SHADER_DEFINES "#define STEP_RESOLVE\n");
- e_data.ssr_resolve_norm_sh = DRW_shader_create_fullscreen(ssr_shader_str, SHADER_DEFINES "#define STEP_RESOLVE\n"
- "#define USE_NORMALIZATION\n");
- e_data.ssr_resolve_full_sh = DRW_shader_create_fullscreen(ssr_shader_str, SHADER_DEFINES "#define STEP_RESOLVE\n"
- "#define FULLRES\n");
- e_data.ssr_resolve_full_norm_sh = DRW_shader_create_fullscreen(ssr_shader_str, SHADER_DEFINES "#define STEP_RESOLVE\n"
- "#define USE_NORMALIZATION\n"
- "#define FULLRES\n");
-
- MEM_freeN(ssr_shader_str);
-
e_data.downsample_sh = DRW_shader_create_fullscreen(datatoc_effect_downsample_frag_glsl, NULL);
e_data.volumetric_upsample_sh = DRW_shader_create_fullscreen(datatoc_volumetric_frag_glsl, "#define STEP_UPSAMPLE\n");
@@ -550,6 +572,7 @@ 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->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");
@@ -558,7 +581,6 @@ void EEVEE_effects_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata)
const int divisor = (effects->reflection_trace_full) ? 1 : 2;
int tracing_res[2] = {(int)viewport_size[0] / divisor, (int)viewport_size[1] / divisor};
- const bool record_two_hit = false;
const bool high_qual_input = true; /* TODO dither low quality input */
/* MRT for the shading pass in order to output needed data for the SSR pass. */
@@ -582,8 +604,8 @@ 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, (record_two_hit) ? DRW_TEX_RGBA_16 : DRW_TEX_RG_16, DRW_TEX_TEMP},
- {&stl->g_data->ssr_pdf_output, (record_two_hit) ? DRW_TEX_RG_16 : DRW_TEX_R_16, DRW_TEX_TEMP}};
+ 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}};
DRW_framebuffer_init(&fbl->screen_tracing_fb, &draw_engine_eevee_type, tracing_res[0], tracing_res[1], tex_output, 2);
@@ -621,9 +643,6 @@ void EEVEE_effects_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata)
DRW_framebuffer_init(&fbl->double_buffer, &draw_engine_eevee_type,
(int)viewport_size[0], (int)viewport_size[1],
&tex_double_buffer, 1);
-
- copy_m4_m4(stl->g_data->prev_persmat, stl->g_data->next_persmat);
- DRW_viewport_matrix_get(stl->g_data->next_persmat, DRW_MAT_PERS);
}
else {
/* Cleanup to release memory */
@@ -719,14 +738,13 @@ void EEVEE_effects_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata)
}
if ((effects->enabled_effects & EFFECT_SSR) != 0) {
- struct GPUShader *trace_shader = (effects->reflection_trace_full) ? e_data.ssr_raytrace_full_sh : e_data.ssr_raytrace_sh;
- struct GPUShader *resolve_shader = NULL;
- if (effects->ssr_use_normalization) {
- resolve_shader = (effects->reflection_trace_full) ? e_data.ssr_resolve_full_norm_sh : e_data.ssr_resolve_norm_sh;
- }
- else {
- resolve_shader = (effects->reflection_trace_full) ? e_data.ssr_resolve_full_sh : e_data.ssr_resolve_sh;
- }
+ 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;
+
+ struct GPUShader *trace_shader = eevee_effects_ssr_shader_get(options);
+ struct GPUShader *resolve_shader = eevee_effects_ssr_shader_get(SSR_RESOLVE | options);
psl->ssr_raytrace = DRW_pass_create("SSR Raytrace", DRW_STATE_WRITE_COLOR);
DRWShadingGroup *grp = DRW_shgroup_create(trace_shader, psl->ssr_raytrace);
@@ -1225,22 +1243,21 @@ void EEVEE_draw_effects(EEVEE_Data *vedata)
DRW_viewport_request_redraw();
}
+ /* Record pers matrix for the next frame. */
+ DRW_viewport_matrix_get(stl->g_data->prev_persmat, DRW_MAT_PERS);
+
/* Update double buffer status if render mode. */
if (DRW_state_is_image_render()) {
stl->g_data->valid_double_buffer = (txl->color_double_buffer != NULL);
- DRW_viewport_matrix_get(stl->g_data->prev_persmat, DRW_MAT_PERS);
}
}
void EEVEE_effects_free(void)
{
+ for (int i = 0; i < SSR_MAX_SHADER; ++i) {
+ DRW_SHADER_FREE_SAFE(e_data.ssr_sh[i]);
+ }
DRW_SHADER_FREE_SAFE(e_data.downsample_sh);
- DRW_SHADER_FREE_SAFE(e_data.ssr_raytrace_sh);
- DRW_SHADER_FREE_SAFE(e_data.ssr_raytrace_full_sh);
- DRW_SHADER_FREE_SAFE(e_data.ssr_resolve_sh);
- DRW_SHADER_FREE_SAFE(e_data.ssr_resolve_full_sh);
- DRW_SHADER_FREE_SAFE(e_data.ssr_resolve_norm_sh);
- DRW_SHADER_FREE_SAFE(e_data.ssr_resolve_full_norm_sh);
DRW_SHADER_FREE_SAFE(e_data.volumetric_upsample_sh);
diff --git a/source/blender/draw/engines/eevee/eevee_engine.c b/source/blender/draw/engines/eevee/eevee_engine.c
index 07b084a95b9..5012e098124 100644
--- a/source/blender/draw/engines/eevee/eevee_engine.c
+++ b/source/blender/draw/engines/eevee/eevee_engine.c
@@ -208,6 +208,7 @@ 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_stride", 16);
diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h
index 824c338b927..5dda9b088e3 100644
--- a/source/blender/draw/engines/eevee/eevee_private.h
+++ b/source/blender/draw/engines/eevee/eevee_private.h
@@ -319,6 +319,7 @@ typedef struct EEVEE_EffectsInfo {
/* SSR */
bool use_ssr;
bool reflection_trace_full;
+ bool ssr_use_two_hit;
bool ssr_use_normalization;
float ssr_border_fac;
float ssr_stride;
@@ -466,7 +467,6 @@ typedef struct EEVEE_PrivateData {
/* For double buffering */
bool valid_double_buffer;
float prev_persmat[4][4];
- float next_persmat[4][4];
} EEVEE_PrivateData; /* Transient data */
/* eevee_data.c */
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 b61b191c2d1..268afa1e373 100644
--- a/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl
@@ -72,6 +72,10 @@ void main()
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 */
@@ -89,19 +93,35 @@ void main()
/* 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;
@@ -109,8 +129,20 @@ void main()
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
}
#else /* STEP_RESOLVE */
@@ -222,6 +254,45 @@ float view_facing_mask(vec3 V, vec3 R)
return smoothstep(0.95, 0.80, dot(V, R));
}
+vec4 get_ssr_sample(
+ vec2 hit_co, vec3 worldPosition, vec3 N, vec3 V, float roughnessSquared,
+ float cone_tan, vec2 source_uvs, vec2 texture_size, ivec2 target_texel,
+ out float weight)
+{
+ /* Reconstruct ray */
+ float hit_depth = textureLod(depthBuffer, hit_co, 0.0).r;
+ vec3 hit_pos = get_world_space_from_depth(hit_co, hit_depth);
+
+ /* 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 */
+ 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);
+
+ 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;
+
+ weight = step(0.001, pdf) * bsdf / pdf;
+#else
+ weight = 1.0;
+#endif
+
+ vec3 sample = textureLod(colorBuffer, ref_uvs, mip).rgb ;
+
+ /* Firefly removal */
+ sample /= 1.0 + brightness(sample);
+
+ float mask = screen_border_mask(ref_uvs, hit_pos);
+ mask *= view_facing_mask(V, N);
+
+ /* Check if there was a hit */
+ return vec4(sample, mask) * weight * step(0.0, hit_co.x);
+}
#define NUM_NEIGHBORS 9
@@ -280,42 +351,24 @@ void main()
for (int i = 0; i < NUM_NEIGHBORS; i++) {
ivec2 target_texel = halfres_texel + neighbors[i] * invert_neighbor;
- vec2 hit_co = texelFetch(hitBuffer, target_texel, 0).rg;
-
- /* Reconstruct ray */
- float hit_depth = textureLod(depthBuffer, hit_co, 0.0).r;
- vec3 hit_pos = get_world_space_from_depth(hit_co, hit_depth);
-
- /* 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 */
- 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);
-
- 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, pdf) * bsdf / pdf;
+#ifdef TWO_HIT
+ vec4 hit_co = texelFetch(hitBuffer, target_texel, 0).rgba;
#else
- float weight = 1.0;
+ vec2 hit_co = texelFetch(hitBuffer, target_texel, 0).rg;
#endif
- vec3 sample = textureLod(colorBuffer, ref_uvs, mip).rgb ;
-
- /* Firefly removal */
- sample /= 1.0 + brightness(sample);
-
- float mask = screen_border_mask(ref_uvs, hit_pos);
- mask *= view_facing_mask(V, N);
+ 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;
- /* Check if there was a hit */
- ssr_accum += vec4(sample, mask) * weight * step(0.0, hit_co.x);
+#ifdef TWO_HIT
+ ssr_accum += get_ssr_sample(hit_co.zw, worldPosition, N, V,
+ roughnessSquared, cone_tan, source_uvs,
+ texture_size, target_texel, weight);
weight_acc += weight;
+#endif
}
/* Compute SSR contribution */
diff --git a/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl b/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl
index d0c60310a00..f017453bad0 100644
--- a/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl
@@ -113,7 +113,7 @@ float raycast(sampler2D depth_texture, vec3 ray_origin, vec3 ray_dir, float ray_
float zmin = prev_zmax;
zmax = (dPQK.z * 0.5 + pqk.z) / (dPQK.w * 0.5 + pqk.w);
prev_zmax = zmax;
- swapIfBigger(zmin, zmax); /* ??? why don't we need this ??? */
+ swapIfBigger(zmin, zmax);
float vmax = get_view_z_from_depth(raw_depth);
float vmin = vmax - ssrThickness;
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index 90dab17069e..a3983290236 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -2623,6 +2623,7 @@ 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_stride)
@@ -6197,6 +6198,13 @@ 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");