Eevee: SSR: Remove ray count and use integer texture for hit coord.

Using GL_RG16I texture for the hit coordinates increase tremendously the precision of the hit.
The sign of the integer is used to 2 flags (has_hit and is_planar).
We do not store the depth and retrieve it from the depth buffer (increasing bandwith by +8bit/px).
The PDF is stored into another GL_R16F texture.

We remove the raycount for simplicity and to reduce compilation time (less branching in refraction shader).
This commit is contained in:
Clément Foucault 2018-01-15 17:23:17 +01:00
parent 84c91be0a4
commit 3cb2b2956b
11 changed files with 104 additions and 148 deletions

View File

@ -807,7 +807,6 @@ class RENDER_PT_eevee_screen_space_reflections(RenderButtonsPanel, Panel):
col.active = props.ssr_enable
col.prop(props, "ssr_refraction")
col.prop(props, "ssr_halfres")
col.prop(props, "ssr_ray_count")
col.prop(props, "ssr_quality")
col.prop(props, "ssr_max_roughness")
col.prop(props, "ssr_thickness")

View File

@ -377,7 +377,6 @@ class VIEWLAYER_PT_eevee_screen_space_reflections(ViewLayerButtonsPanel, Panel):
col = layout.column()
col.template_override_property(layer_props, scene_props, "ssr_halfres")
col.template_override_property(layer_props, scene_props, "ssr_refraction")
col.template_override_property(layer_props, scene_props, "ssr_ray_count")
col.template_override_property(layer_props, scene_props, "ssr_quality")
col.template_override_property(layer_props, scene_props, "ssr_max_roughness")
col.template_override_property(layer_props, scene_props, "ssr_thickness")

View File

@ -441,7 +441,7 @@ void EEVEE_draw_effects(EEVEE_Data *vedata)
if (txl->maxzbuffer) DRW_transform_to_display(txl->maxzbuffer);
break;
case 2:
if (stl->g_data->ssr_hit_output[0]) DRW_transform_to_display(stl->g_data->ssr_hit_output[0]);
if (stl->g_data->ssr_pdf_output) DRW_transform_to_display(stl->g_data->ssr_pdf_output);
break;
case 3:
if (txl->ssr_normal_input) DRW_transform_to_display(txl->ssr_normal_input);

View File

@ -361,7 +361,6 @@ static void eevee_view_layer_settings_create(RenderEngine *UNUSED(engine), IDPro
BKE_collection_engine_property_add_bool(props, "ssr_enable", false);
BKE_collection_engine_property_add_bool(props, "ssr_refraction", 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_float(props, "ssr_quality", 0.25f);
BKE_collection_engine_property_add_float(props, "ssr_max_roughness", 0.5f);
BKE_collection_engine_property_add_float(props, "ssr_thickness", 0.2f);

View File

@ -391,7 +391,6 @@ static void add_standard_uniforms(
DRW_shgroup_uniform_buffer(shgrp, "colorBuffer", &vedata->txl->refract_color);
DRW_shgroup_uniform_float(shgrp, "borderFadeFactor", &vedata->stl->effects->ssr_border_fac, 1);
DRW_shgroup_uniform_float(shgrp, "maxRoughness", &vedata->stl->effects->ssr_max_roughness, 1);
DRW_shgroup_uniform_int(shgrp, "rayCount", &vedata->stl->effects->ssr_ray_count, 1);
}
if (vedata->stl->effects->use_ao) {

View File

@ -248,6 +248,7 @@ typedef struct EEVEE_TextureList {
struct GPUTexture *bloom_upsample[MAX_BLOOM_STEP - 1]; /* R16_G16_B16 */
struct GPUTexture *ssr_normal_input;
struct GPUTexture *ssr_specrough_input;
struct GPUTexture *ssr_hit_output;
struct GPUTexture *refract_color;
struct GPUTexture *volume_prop_scattering;
@ -496,7 +497,6 @@ typedef struct EEVEE_EffectsInfo {
bool use_ssr;
bool reflection_trace_full;
bool ssr_use_normalization;
int ssr_ray_count;
float ssr_firefly_fac;
float ssr_border_fac;
float ssr_max_roughness;
@ -702,7 +702,7 @@ typedef struct EEVEE_PrivateData {
struct GHash *material_hash;
struct GHash *hair_material_hash;
struct GPUTexture *minzbuffer;
struct GPUTexture *ssr_hit_output[4];
struct GPUTexture *ssr_pdf_output;
struct GPUTexture *gtao_horizons_debug;
float background_alpha; /* TODO find a better place for this. */
float viewvecs[2][4];

View File

@ -34,10 +34,9 @@
/* SSR shader variations */
enum {
SSR_SAMPLES = (1 << 0) | (1 << 1),
SSR_RESOLVE = (1 << 2),
SSR_FULL_TRACE = (1 << 3),
SSR_MAX_SHADER = (1 << 4),
SSR_RESOLVE = (1 << 0),
SSR_FULL_TRACE = (1 << 1),
SSR_MAX_SHADER = (1 << 2),
};
static struct {
@ -71,11 +70,8 @@ static struct GPUShader *eevee_effects_screen_raytrace_shader_get(int options)
char *ssr_shader_str = BLI_dynstr_get_cstring(ds_frag);
BLI_dynstr_free(ds_frag);
int samples = (SSR_SAMPLES & options) + 1;
DynStr *ds_defines = BLI_dynstr_new();
BLI_dynstr_appendf(ds_defines, SHADER_DEFINES);
BLI_dynstr_appendf(ds_defines, "#define RAY_COUNT %d\n", samples);
if (options & SSR_RESOLVE) {
BLI_dynstr_appendf(ds_defines, "#define STEP_RESOLVE\n");
}
@ -108,7 +104,9 @@ int EEVEE_screen_raytrace_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *
const DRWContextState *draw_ctx = DRW_context_state_get();
ViewLayer *view_layer = draw_ctx->view_layer;
IDProperty *props = BKE_view_layer_engine_evaluated_get(view_layer, COLLECTION_MODE_NONE, RE_engine_id_BLENDER_EEVEE);
IDProperty *props = BKE_view_layer_engine_evaluated_get(view_layer,
COLLECTION_MODE_NONE,
RE_engine_id_BLENDER_EEVEE);
/* Compute pixel size, (shared with contact shadows) */
copy_v2_v2(effects->ssr_pixelsize, viewport_size);
@ -120,10 +118,12 @@ int EEVEE_screen_raytrace_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *
if (use_refraction) {
DRWFboTexture tex = {&txl->refract_color, DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER | DRW_TEX_MIPMAP};
DRW_framebuffer_init(&fbl->refract_fb, &draw_engine_eevee_type, (int)viewport_size[0], (int)viewport_size[1], &tex, 1);
DRW_framebuffer_init(&fbl->refract_fb, &draw_engine_eevee_type,
(int)viewport_size[0], (int)viewport_size[1],
&tex, 1);
}
effects->ssr_ray_count = BKE_collection_engine_property_value_get_int(props, "ssr_ray_count");
bool prev_trace_full = effects->reflection_trace_full;
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_quality = 1.0f - BKE_collection_engine_property_value_get_float(props, "ssr_quality");
@ -136,8 +136,9 @@ int EEVEE_screen_raytrace_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *
effects->ssr_firefly_fac = FLT_MAX;
}
/* Important, can lead to breakage otherwise. */
CLAMP(effects->ssr_ray_count, 1, 4);
if (prev_trace_full != effects->reflection_trace_full) {
DRW_TEXTURE_FREE_SAFE(txl->ssr_hit_output);
}
const int divisor = (effects->reflection_trace_full) ? 1 : 2;
int tracing_res[2] = {(int)viewport_size[0] / divisor, (int)viewport_size[1] / divisor};
@ -147,7 +148,8 @@ int EEVEE_screen_raytrace_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *
/* TODO create one texture layer per lobe */
if (txl->ssr_specrough_input == NULL) {
DRWTextureFormat specrough_format = (high_qual_input) ? DRW_TEX_RGBA_16 : DRW_TEX_RGBA_8;
txl->ssr_specrough_input = DRW_texture_create_2D((int)viewport_size[0], (int)viewport_size[1], specrough_format, 0, NULL);
txl->ssr_specrough_input = DRW_texture_create_2D((int)viewport_size[0], (int)viewport_size[1],
specrough_format, 0, NULL);
}
/* Reattach textures to the right buffer (because we are alternating between buffers) */
@ -156,15 +158,15 @@ int EEVEE_screen_raytrace_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *
DRW_framebuffer_texture_attach(fbl->main, txl->ssr_specrough_input, 2, 0);
/* Raytracing output */
/* TODO try integer format for hit coord to increase precision */
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},
};
/* (AMD or Intel) For some reason DRW_TEX_TEMP with DRW_TEX_RG_16I
* creates problems when toggling ssr_halfres. Texture is not read correctly (black output).
* So using a persistent buffer instead. */
DRWFboTexture tex_output[2] = {{&txl->ssr_hit_output, DRW_TEX_RG_16I, 0},
{&stl->g_data->ssr_pdf_output, 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, effects->ssr_ray_count);
DRW_framebuffer_init(&fbl->screen_tracing_fb, &draw_engine_eevee_type,
tracing_res[0], tracing_res[1],
tex_output, 2);
/* Enable double buffering to be able to read previous frame color */
return EFFECT_SSR | EFFECT_NORMAL_BUFFER | EFFECT_DOUBLE_BUFFER | ((use_refraction) ? EFFECT_REFRACT : 0);
@ -172,10 +174,9 @@ int EEVEE_screen_raytrace_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *
/* Cleanup to release memory */
DRW_TEXTURE_FREE_SAFE(txl->ssr_specrough_input);
DRW_TEXTURE_FREE_SAFE(txl->ssr_hit_output);
DRW_FRAMEBUFFER_FREE_SAFE(fbl->screen_tracing_fb);
for (int i = 0; i < 4; ++i) {
stl->g_data->ssr_hit_output[i] = NULL;
}
stl->g_data->ssr_pdf_output = NULL;
return 0;
}
@ -191,7 +192,6 @@ void EEVEE_screen_raytrace_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *v
if ((effects->enabled_effects & EFFECT_SSR) != 0) {
int options = (effects->reflection_trace_full) ? SSR_FULL_TRACE : 0;
options |= (effects->ssr_ray_count - 1);
struct GPUShader *trace_shader = eevee_effects_screen_raytrace_shader_get(options);
struct GPUShader *resolve_shader = eevee_effects_screen_raytrace_shader_get(SSR_RESOLVE | options);
@ -246,16 +246,9 @@ void EEVEE_screen_raytrace_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *v
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]);
if (effects->ssr_ray_count > 1) {
DRW_shgroup_uniform_buffer(grp, "hitBuffer1", &stl->g_data->ssr_hit_output[1]);
}
if (effects->ssr_ray_count > 2) {
DRW_shgroup_uniform_buffer(grp, "hitBuffer2", &stl->g_data->ssr_hit_output[2]);
}
if (effects->ssr_ray_count > 3) {
DRW_shgroup_uniform_buffer(grp, "hitBuffer3", &stl->g_data->ssr_hit_output[3]);
}
DRW_shgroup_uniform_buffer(grp, "planarDepth", &vedata->txl->planar_depth);
DRW_shgroup_uniform_buffer(grp, "hitBuffer", &vedata->txl->ssr_hit_output);
DRW_shgroup_uniform_buffer(grp, "pdfBuffer", &stl->g_data->ssr_pdf_output);
DRW_shgroup_uniform_vec4(grp, "aoParameters[0]", &effects->ao_dist, 2);
if (effects->use_ao) {
@ -301,18 +294,13 @@ void EEVEE_reflection_compute(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *v
e_data.depth_src = dtxl->depth;
DRW_stats_group_start("SSR");
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_texture_attach(fbl->screen_tracing_fb, stl->g_data->ssr_pdf_output, 1, 0);
DRW_framebuffer_bind(fbl->screen_tracing_fb);
/* Raytrace. */
DRW_draw_pass(psl->ssr_raytrace);
for (int i = 0; i < effects->ssr_ray_count; ++i) {
DRW_framebuffer_texture_detach(stl->g_data->ssr_hit_output[i]);
}
DRW_framebuffer_texture_detach(stl->g_data->ssr_pdf_output);
EEVEE_downsample_buffer(vedata, fbl->downsample_fb, txl->color_double_buffer, 9);

View File

@ -13,6 +13,21 @@ uniform sampler2DArray utilTex;
uniform float fireflyFactor;
uniform float maxRoughness;
ivec2 encode_hit_data(vec2 hit_pos, bool has_hit, bool is_planar)
{
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;
}
vec2 decode_hit_data(vec2 hit_data, out bool has_hit, out bool is_planar)
{
is_planar = (hit_data.x < 0);
has_hit = (hit_data.y > 0);
return vec2(abs(hit_data)) / 32767.0; /* 16bit signed int limit */
}
#ifdef STEP_RAYTRACE
uniform sampler2D normalBuffer;
@ -21,20 +36,17 @@ uniform sampler2D specroughBuffer;
uniform int planar_count;
uniform float noiseOffset;
layout(location = 0) out vec4 hitData0;
layout(location = 1) out vec4 hitData1;
layout(location = 2) out vec4 hitData2;
layout(location = 3) out vec4 hitData3;
layout(location = 0) out ivec2 hitData;
layout(location = 1) out float pdfData;
vec4 do_planar_ssr(int index, vec3 V, vec3 N, vec3 T, vec3 B, vec3 planeNormal, vec3 viewPosition, float a2, vec3 rand, float ofs)
void do_planar_ssr(int index, vec3 V, vec3 N, vec3 T, vec3 B, vec3 planeNormal, vec3 viewPosition, float a2, vec4 rand)
{
float pdf, NH;
float jitter = fract(rand.x + ofs);
/* Importance sampling bias */
rand.x = mix(rand.x, 0.0, BRDF_BIAS);
vec3 H = sample_ggx(rand, a2, N, T, B, NH); /* Microfacet normal */
vec3 H = sample_ggx(rand.xzw, a2, N, T, B, NH); /* Microfacet normal */
pdf = pdf_ggx_reflect(NH, a2);
vec3 R = reflect(-V, H);
@ -42,43 +54,41 @@ vec4 do_planar_ssr(int index, vec3 V, vec3 N, vec3 T, vec3 B, vec3 planeNormal,
/* If ray is bad (i.e. going below the plane) regenerate. */
if (dot(R, planeNormal) > 0.0) {
vec3 H = sample_ggx(rand * vec3(1.0, -1.0, -1.0), a2, N, T, B, NH); /* Microfacet normal */
vec3 H = sample_ggx(rand.xzw * vec3(1.0, -1.0, -1.0), a2, N, T, B, NH); /* Microfacet normal */
pdf = pdf_ggx_reflect(NH, a2);
R = reflect(-V, H);
R = reflect(R, planeNormal);
}
pdf = min(1024e32, pdf); /* Theoretical limit of 16bit float */
pdf *= -1.0; /* Tag as planar ray. */
pdfData = min(1024e32, pdf); /* Theoretical limit of 16bit float */
/* Since viewspace hit position can land behind the camera in this case,
* we save the reflected view position (visualize it as the hit position
* below the reflection plane). This way it's garanted that the hit will
* be in front of the camera. That let us tag the bad rays with a negative
* sign in the Z component. */
vec3 hit_pos = raycast(index, viewPosition, R * 1e16, 1e16, jitter, ssrQuality, a2, false);
vec3 hit_pos = raycast(index, viewPosition, R * 1e16, 1e16, rand.y, ssrQuality, a2, false);
return vec4(hit_pos, pdf);
hitData = encode_hit_data(hit_pos.xy, (hit_pos.z > 0.0), true);
}
vec4 do_ssr(vec3 V, vec3 N, vec3 T, vec3 B, vec3 viewPosition, float a2, vec3 rand, float ofs)
void do_ssr(vec3 V, vec3 N, vec3 T, vec3 B, vec3 viewPosition, float a2, vec4 rand)
{
float pdf, NH;
float jitter = fract(rand.x + ofs);
/* Importance sampling bias */
rand.x = mix(rand.x, 0.0, BRDF_BIAS);
vec3 H = sample_ggx(rand, a2, N, T, B, NH); /* Microfacet normal */
vec3 H = sample_ggx(rand.xzw, a2, N, T, B, NH); /* Microfacet normal */
pdf = pdf_ggx_reflect(NH, a2);
vec3 R = reflect(-V, H);
pdf = min(1024e32, pdf); /* Theoretical limit of 16bit float */
pdfData = min(1024e32, pdf); /* Theoretical limit of 16bit float */
vec3 hit_pos = raycast(-1, viewPosition, R * 1e16, ssrThickness, jitter, ssrQuality, a2, true);
vec3 hit_pos = raycast(-1, viewPosition, R * 1e16, ssrThickness, rand.y, ssrQuality, a2, true);
return vec4(hit_pos, pdf);
hitData = encode_hit_data(hit_pos.xy, (hit_pos.z > 0.0), false);
}
void main()
@ -119,11 +129,17 @@ void main()
float a2 = roughnessSquared * roughnessSquared;
if (roughness > maxRoughness + 0.2) {
hitData0 = hitData1 = hitData2 = hitData3 = vec4(0.0);
hitData = ivec2(0);
pdfData = 0.0;
return;
}
vec3 rand = texelFetch(utilTex, ivec3(halfres_texel % LUT_SIZE, 2), 0).rba;
vec4 rand = texelFetch(utilTex, ivec3(halfres_texel % LUT_SIZE, 2), 0);
/* Gives *perfect* reflection for very small roughness */
if (roughness < 0.04) {
rand *= vec4(0.0, 1.0, 0.0, 0.0);
}
vec3 worldPosition = transform_point(ViewMatrixInverse, viewPosition);
vec3 wN = transform_direction(ViewMatrixInverse, N);
@ -144,31 +160,12 @@ void main()
tracePosition = transform_point(ViewMatrix, tracePosition);
vec3 planeNormal = transform_direction(ViewMatrix, pd.pl_normal);
hitData0 = do_planar_ssr(i, V, N, T, B, planeNormal, tracePosition, a2, rand, 0.0);
#if (RAY_COUNT > 1)
hitData1 = do_planar_ssr(i, V, N, T, B, planeNormal, tracePosition, a2, rand.xyz * vec3(1.0, -1.0, -1.0), 1.0 / float(RAY_COUNT));
#endif
#if (RAY_COUNT > 2)
hitData2 = do_planar_ssr(i, V, N, T, B, planeNormal, tracePosition, a2, rand.xzy * vec3(1.0, 1.0, -1.0), 2.0 / float(RAY_COUNT));
#endif
#if (RAY_COUNT > 3)
hitData3 = do_planar_ssr(i, V, N, T, B, planeNormal, tracePosition, a2, rand.xzy * vec3(1.0, -1.0, 1.0), 3.0 / float(RAY_COUNT));
#endif
do_planar_ssr(i, V, N, T, B, planeNormal, tracePosition, a2, rand);
return;
}
}
/* TODO : Raytrace together if textureGather is supported. */
hitData0 = do_ssr(V, N, T, B, viewPosition, a2, rand, 0.0);
#if (RAY_COUNT > 1)
hitData1 = do_ssr(V, N, T, B, viewPosition, a2, rand.xyz * vec3(1.0, -1.0, -1.0), 1.0 / float(RAY_COUNT));
#endif
#if (RAY_COUNT > 2)
hitData2 = do_ssr(V, N, T, B, viewPosition, a2, rand.xzy * vec3(1.0, 1.0, -1.0), 2.0 / float(RAY_COUNT));
#endif
#if (RAY_COUNT > 3)
hitData3 = do_ssr(V, N, T, B, viewPosition, a2, rand.xzy * vec3(1.0, -1.0, 1.0), 3.0 / float(RAY_COUNT));
#endif
do_ssr(V, N, T, B, viewPosition, a2, rand);
}
#else /* STEP_RESOLVE */
@ -177,10 +174,8 @@ uniform sampler2D prevColorBuffer; /* previous frame */
uniform sampler2D normalBuffer;
uniform sampler2D specroughBuffer;
uniform sampler2D hitBuffer0;
uniform sampler2D hitBuffer1;
uniform sampler2D hitBuffer2;
uniform sampler2D hitBuffer3;
uniform isampler2D hitBuffer;
uniform sampler2D pdfBuffer;
uniform int probe_count;
uniform int planar_count;
@ -189,7 +184,8 @@ uniform mat4 PastViewProjectionMatrix;
out vec4 fragColor;
void fallback_cubemap(vec3 N, vec3 V, vec3 W, vec3 viewPosition, float roughness, float roughnessSquared, inout vec4 spec_accum)
void fallback_cubemap(
vec3 N, vec3 V, vec3 W, vec3 viewPosition, float roughness, float roughnessSquared, inout vec4 spec_accum)
{
/* Specular probes */
vec3 spec_dir = get_specular_reflection_dominant_dir(N, V, roughnessSquared);
@ -255,19 +251,31 @@ vec2 get_reprojected_reflection(vec3 hit, vec3 pos, vec3 N)
}
vec4 get_ssr_sample(
sampler2D hitBuffer, PlanarData pd, float planar_index, vec3 worldPosition, vec3 N, vec3 V, float roughnessSquared,
float cone_tan, vec2 source_uvs, vec2 texture_size, ivec2 target_texel,
PlanarData pd, float planar_index, vec3 worldPosition, vec3 N, vec3 V,
float roughnessSquared, float cone_tan, vec2 source_uvs, vec2 texture_size, ivec2 target_texel,
inout float weight_acc)
{
vec4 hit_co_pdf = texelFetch(hitBuffer, target_texel, 0).rgba;
bool has_hit = (hit_co_pdf.z > 0.0);
bool is_planar = (hit_co_pdf.w < 0.0);
hit_co_pdf.z = abs(hit_co_pdf.z);
hit_co_pdf.w = abs(hit_co_pdf.w);
float hit_pdf = texelFetch(pdfBuffer, target_texel, 0).r;
ivec2 hit_data = texelFetch(hitBuffer, target_texel, 0).rg;
bool is_planar, has_hit;
vec2 hit_co = decode_hit_data(hit_data, has_hit, is_planar);
/* Get precise depth of the hit. */
float hit_depth;
if (is_planar) {
hit_depth = textureLod(planarDepth, vec3(hit_co, planar_index), 0.0).r;
}
else {
hit_depth = textureLod(depthBuffer, hit_co, 0.0).r;
}
/* Hit position in view space. */
vec3 hit_view = get_view_space_from_depth(hit_co, hit_depth);
float homcoord = ProjectionMatrix[2][3] * hit_view.z + ProjectionMatrix[3][3];
/* Hit position in world space. */
hit_co_pdf.xyz = get_view_space_from_depth(hit_co_pdf.xy, hit_co_pdf.z);
vec3 hit_pos = transform_point(ViewMatrixInverse, hit_co_pdf.xyz);
vec3 hit_pos = transform_point(ViewMatrixInverse, hit_view.xyz);
vec2 ref_uvs;
vec3 hit_vec;
@ -277,7 +285,7 @@ vec4 get_ssr_sample(
vec3 trace_pos = line_plane_intersect(worldPosition, V, pd.pl_plane_eq);
hit_vec = hit_pos - trace_pos;
hit_vec = reflect(hit_vec, pd.pl_normal);
ref_uvs = project_point(ProjectionMatrix, hit_co_pdf.xyz).xy * 0.5 + 0.5;
ref_uvs = hit_co;
}
else {
/* Find hit position in previous frame. */
@ -286,7 +294,6 @@ vec4 get_ssr_sample(
mask = screen_border_mask(gl_FragCoord.xy / texture_size);
}
mask = min(mask, screen_border_mask(ref_uvs));
mask *= float(has_hit);
float hit_dist = max(1e-8, length(hit_vec));
vec3 L = hit_vec / hit_dist;
@ -294,7 +301,6 @@ vec4 get_ssr_sample(
float cone_footprint = hit_dist * cone_tan;
/* Compute cone footprint in screen space. */
float homcoord = ProjectionMatrix[2][3] * hit_co_pdf.z + ProjectionMatrix[3][3];
cone_footprint = BRDF_BIAS * 0.5 * cone_footprint * max(ProjectionMatrix[0][0], ProjectionMatrix[1][1]) / homcoord;
/* Estimate a cone footprint to sample a corresponding mipmap level. */
@ -305,7 +311,7 @@ vec4 get_ssr_sample(
/* Slide 54 */
float bsdf = bsdf_ggx(N, L, V, roughnessSquared);
float weight = step(1e-8, hit_co_pdf.w) * bsdf / max(1e-8, hit_co_pdf.w);
float weight = step(1e-8, hit_pdf) * bsdf / max(1e-8, hit_pdf);
weight_acc += weight;
vec3 sample;
@ -320,9 +326,6 @@ vec4 get_ssr_sample(
float luma = max(1e-8, brightness(sample));
sample *= 1.0 - max(0.0, luma - fireflyFactor) / luma;
/* Do not add light if ray has failed. */
sample *= float(has_hit);
/* Protection against NaNs in the history buffer.
* This could be removed if some previous pass has already
* sanitized the input. */
@ -331,7 +334,8 @@ vec4 get_ssr_sample(
weight = 0.0;
}
return vec4(sample, mask) * weight;
/* Do not add light if ray has failed. */
return vec4(sample, mask) * weight * float(has_hit);
}
#define NUM_NEIGHBORS 4
@ -346,7 +350,6 @@ void main()
#endif
vec2 texture_size = vec2(textureSize(depthBuffer, 0));
vec2 uvs = gl_FragCoord.xy / texture_size;
vec3 rand = texelFetch(utilTex, ivec3(fullres_texel % LUT_SIZE, 2), 0).rba;
float depth = textureLod(depthBuffer, uvs, 0.0).r;
@ -413,24 +416,9 @@ void main()
for (int i = 0; i < NUM_NEIGHBORS; i++) {
ivec2 target_texel = halfres_texel + neighbors[i] * invert_neighbor;
ssr_accum += get_ssr_sample(hitBuffer0, pd, planar_index, worldPosition, N, V,
ssr_accum += get_ssr_sample(pd, planar_index, worldPosition, N, V,
roughnessSquared, cone_tan, source_uvs,
texture_size, target_texel, weight_acc);
#if (RAY_COUNT > 1)
ssr_accum += get_ssr_sample(hitBuffer1, pd, planar_index, worldPosition, N, V,
roughnessSquared, cone_tan, source_uvs,
texture_size, target_texel, weight_acc);
#endif
#if (RAY_COUNT > 2)
ssr_accum += get_ssr_sample(hitBuffer2, pd, planar_index, worldPosition, N, V,
roughnessSquared, cone_tan, source_uvs,
texture_size, target_texel, weight_acc);
#endif
#if (RAY_COUNT > 3)
ssr_accum += get_ssr_sample(hitBuffer3, pd, planar_index, worldPosition, N, V,
roughnessSquared, cone_tan, source_uvs,
texture_size, target_texel, weight_acc);
#endif
}
}

View File

@ -29,7 +29,6 @@ in vec3 viewNormal;
#endif
uniform float maxRoughness;
uniform int rayCount;
#endif /* LIT_SURFACE_UNIFORM */
@ -315,13 +314,7 @@ void CLOSURE_NAME(
if (ssrToggle && roughness < maxRoughness + 0.2) {
/* Find approximated position of the 2nd refraction event. */
vec3 refr_vpos = (refractionDepth > 0.0) ? transform_point(ViewMatrix, refr_pos) : viewPosition;
float ray_ofs = 1.0 / float(rayCount);
vec4 trans = screen_space_refraction(refr_vpos, N, refr_V, final_ior, roughnessSquared, rand.xzw, 0.0);
if (rayCount > 1) trans += screen_space_refraction(refr_vpos, N, refr_V, final_ior, roughnessSquared, rand.xzw * vec3(1.0, -1.0, -1.0), 1.0 * ray_ofs);
if (rayCount > 2) trans += screen_space_refraction(refr_vpos, N, refr_V, final_ior, roughnessSquared, rand.xwz * vec3(1.0, 1.0, -1.0), 2.0 * ray_ofs);
if (rayCount > 3) trans += screen_space_refraction(refr_vpos, N, refr_V, final_ior, roughnessSquared, rand.xwz * vec3(1.0, -1.0, 1.0), 3.0 * ray_ofs);
trans /= float(rayCount);
vec4 trans = screen_space_refraction(refr_vpos, N, refr_V, final_ior, roughnessSquared, rand.xzw);
trans.a *= smoothstep(maxRoughness + 0.2, maxRoughness, roughness);
accumulate_light(trans.rgb, trans.a, refr_accum);
}

View File

@ -2,10 +2,10 @@
#define BTDF_BIAS 0.85
vec4 screen_space_refraction(vec3 viewPosition, vec3 N, vec3 V, float ior, float roughnessSquared, vec3 rand, float ofs)
vec4 screen_space_refraction(vec3 viewPosition, vec3 N, vec3 V, float ior, float roughnessSquared, vec3 rand)
{
float a2 = max(5e-6, roughnessSquared * roughnessSquared);
float jitter = fract(rand.x + ofs);
float jitter = rand.x;
/* Importance sampling bias */
rand.x = mix(rand.x, 0.0, BTDF_BIAS);

View File

@ -387,7 +387,6 @@ RNA_LAYER_ENGINE_EEVEE_GET_SET_BOOL(sss_separate_albedo)
RNA_LAYER_ENGINE_EEVEE_GET_SET_BOOL(ssr_refraction)
RNA_LAYER_ENGINE_EEVEE_GET_SET_BOOL(ssr_enable)
RNA_LAYER_ENGINE_EEVEE_GET_SET_BOOL(ssr_halfres)
RNA_LAYER_ENGINE_EEVEE_GET_SET_INT(ssr_ray_count)
RNA_LAYER_ENGINE_EEVEE_GET_SET_FLOAT(ssr_quality)
RNA_LAYER_ENGINE_EEVEE_GET_SET_FLOAT(ssr_max_roughness)
RNA_LAYER_ENGINE_EEVEE_GET_SET_FLOAT(ssr_thickness)
@ -1299,14 +1298,6 @@ static void rna_def_view_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_ViewLayerEngineSettings_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_ViewLayerEngineSettings_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);