EEVEE: ScreenSpaceReflections: Add back support for planar reflections

We now have a new buffer to output reflection depth. This buffer is
only usefull for non planar SSR but we use it to tag the planar rays.

This also touch the raytrace algo for planars to avoid degenerate
lines on vert sharp reflections.
This commit is contained in:
Clément Foucault 2021-03-10 17:31:37 +01:00
parent 793335f3e2
commit 56bf4f3fb3
4 changed files with 40 additions and 34 deletions

View File

@ -737,6 +737,7 @@ typedef struct EEVEE_EffectsInfo {
struct GPUTexture *ssr_normal_input; /* Textures from pool */
struct GPUTexture *ssr_specrough_input;
struct GPUTexture *ssr_hit_output;
struct GPUTexture *ssr_hit_depth;
/* Temporal Anti Aliasing */
int taa_reproject_sample;
int taa_current_sample;

View File

@ -97,11 +97,13 @@ int EEVEE_screen_raytrace_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata)
/* Ray-tracing output. */
effects->ssr_hit_output = DRW_texture_pool_query_2d(UNPACK2(tracing_res), GPU_RGBA16F, owner);
effects->ssr_hit_depth = DRW_texture_pool_query_2d(UNPACK2(tracing_res), GPU_R16F, owner);
GPU_framebuffer_ensure_config(&fbl->screen_tracing_fb,
{
GPU_ATTACHMENT_NONE,
GPU_ATTACHMENT_TEXTURE(effects->ssr_hit_output),
GPU_ATTACHMENT_TEXTURE(effects->ssr_hit_depth),
});
return EFFECT_SSR | EFFECT_NORMAL_BUFFER | EFFECT_RADIANCE_BUFFER | EFFECT_DOUBLE_BUFFER |
@ -173,6 +175,7 @@ void EEVEE_screen_raytrace_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *v
DRW_shgroup_uniform_texture_ref(grp, "probePlanars", &vedata->txl->planar_pool);
DRW_shgroup_uniform_texture_ref(grp, "planarDepth", &vedata->txl->planar_depth);
DRW_shgroup_uniform_texture_ref_ex(grp, "hitBuffer", &effects->ssr_hit_output, no_filter);
DRW_shgroup_uniform_texture_ref_ex(grp, "hitDepth", &effects->ssr_hit_depth, no_filter);
DRW_shgroup_uniform_texture_ref(grp, "colorBuffer", &txl->filtered_radiance);
DRW_shgroup_uniform_texture_ref(grp, "maxzBuffer", &txl->maxzbuffer);
DRW_shgroup_uniform_texture_ref(grp, "shadowCubeTexture", &sldata->shadow_cube_pool);

View File

@ -25,6 +25,8 @@ uniform ivec2 halfresOffset;
struct HitData {
/** Hit direction scaled by intersection time. */
vec3 hit_dir;
/** Screen space [0..1] depth of the reflection hit position, or -1.0 for planar reflections. */
float hit_depth;
/** Inverse probability of ray spawning in this direction. */
float ray_pdf_inv;
/** True if ray has hit valid geometry. */
@ -33,27 +35,24 @@ struct HitData {
bool is_planar;
};
vec4 encode_hit_data(HitData data)
void encode_hit_data(HitData data, vec3 hit_sP, vec3 vP, out vec4 hit_data, out float hit_depth)
{
vec4 encoded_data;
encoded_data.xyz = data.hit_dir;
/* Encode planar in Z sign. */
/* TODO fixme */
// encoded_data.z = data.is_planar ? -encoded_data.z : encoded_data.z;
vec3 hit_vP = get_view_space_from_depth(hit_sP.xy, hit_sP.z);
hit_data.xyz = hit_vP - vP;
hit_depth = data.is_planar ? -1.0 : hit_sP.z;
/* Record 1.0 / pdf to reduce the computation in the resolve phase. */
/* Encode hit validity in sign. */
encoded_data.w = data.ray_pdf_inv * ((data.is_hit) ? 1.0 : -1.0);
return encoded_data;
hit_data.w = data.ray_pdf_inv * ((data.is_hit) ? 1.0 : -1.0);
}
HitData decode_hit_data(vec4 encoded_data)
HitData decode_hit_data(vec4 hit_data, float hit_depth)
{
HitData data;
data.hit_dir.xyz = encoded_data.xyz;
/* TODO fixme */
data.is_planar = false;
data.ray_pdf_inv = abs(encoded_data.w);
data.is_hit = (encoded_data.w > 0.0);
data.hit_dir.xyz = hit_data.xyz;
data.hit_depth = hit_depth;
data.is_planar = (hit_depth == -1.0);
data.ray_pdf_inv = abs(hit_data.w);
data.is_hit = (hit_data.w > 0.0);
return data;
}
@ -63,6 +62,7 @@ uniform sampler2D normalBuffer;
uniform sampler2D specroughBuffer;
layout(location = 0) out vec4 hitData;
layout(location = 1) out float hitDepth;
void do_planar_ssr(int index,
vec3 vV,
@ -89,14 +89,13 @@ void do_planar_ssr(int index,
params.trace_quality = ssrQuality;
params.roughness = alpha * alpha;
vec3 hit_sP;
HitData data;
data.is_planar = true;
data.ray_pdf_inv = safe_rcp(pdf);
data.is_hit = raytrace_planar(ray, params, index, data.hit_dir);
data.hit_dir = get_view_space_from_depth(data.hit_dir.xy, data.hit_dir.z);
data.hit_dir -= ray.origin;
data.is_hit = raytrace_planar(ray, params, index, hit_sP);
hitData = encode_hit_data(data);
encode_hit_data(data, hit_sP, ray.origin, hitData, hitDepth);
}
void do_ssr(vec3 vV, vec3 vN, vec3 vT, vec3 vB, vec3 vP, float alpha, vec4 rand)
@ -116,14 +115,13 @@ void do_ssr(vec3 vV, vec3 vN, vec3 vT, vec3 vB, vec3 vP, float alpha, vec4 rand)
params.trace_quality = ssrQuality;
params.roughness = alpha * alpha;
vec3 hit_sP;
HitData data;
data.is_planar = true;
data.is_planar = false;
data.ray_pdf_inv = safe_rcp(pdf);
data.is_hit = raytrace(ray, params, true, data.hit_dir);
data.hit_dir = get_view_space_from_depth(data.hit_dir.xy, data.hit_dir.z);
data.hit_dir -= ray.origin;
data.is_hit = raytrace(ray, params, true, hit_sP);
hitData = encode_hit_data(data);
encode_hit_data(data, hit_sP, ray.origin, hitData, hitDepth);
}
in vec4 uvcoordsvar;
@ -135,12 +133,12 @@ void main()
HitData data;
data.is_planar = false;
data.ray_pdf_inv = safe_rcp(0.0);
data.ray_pdf_inv = 0.0;
data.is_hit = false;
data.hit_dir = vec3(0.0, 0.0, 0.0);
/* Default: not hits. */
hitData = encode_hit_data(data);
encode_hit_data(data, data.hit_dir, data.hit_dir, hitData, hitDepth);
/* Early out */
/* We can't do discard because we don't clear the render target. */
@ -212,6 +210,7 @@ uniform sampler2D colorBuffer; /* previous frame */
uniform sampler2D normalBuffer;
uniform sampler2D specroughBuffer;
uniform sampler2D hitBuffer;
uniform sampler2D hitDepth;
in vec4 uvcoordsvar;
@ -264,7 +263,9 @@ void resolve_reflection_sample(int planar_index,
inout float weight_accum,
inout vec4 ssr_accum)
{
HitData data = decode_hit_data(texture(hitBuffer, sample_uv * ssrUvScale));
vec4 hit_data = texture(hitBuffer, sample_uv * ssrUvScale);
float hit_depth = texture(hitDepth, sample_uv * ssrUvScale).r;
HitData data = decode_hit_data(hit_data, hit_depth);
float hit_dist = length(data.hit_dir);

View File

@ -43,12 +43,12 @@ void raytrace_screenspace_ray_finalize(inout ScreenSpaceRay ray)
ray.direction.zw += bias;
ray.direction -= ray.origin;
float ray_len_sqr = len_squared(ray.direction.xyz);
/* 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 */
if (ray_len_sqr < 0.00001) {
ray.direction.xy = vec2(0.0, 0.0001);
if (len_squared(ray.direction.xy) < 0.00001) {
ray.direction.xy = vec2(0.0, 0.01);
}
float ray_len_sqr = len_squared(ray.direction.xyz);
/* Make ray.direction cover one pixel. */
bool is_more_vertical = abs(ray.direction.x) < abs(ray.direction.y);
ray.direction /= (is_more_vertical) ? abs(ray.direction.y) : abs(ray.direction.x);
@ -166,8 +166,6 @@ bool raytrace_planar(Ray ray, RayTraceParameters params, int planar_ref_id, out
}
ScreenSpaceRay ssray = raytrace_screenspace_ray_create(ray);
/* Avoid no iteration. */
ssray.max_time = max(ssray.max_time, 1.1);
/* Planar Reflections have X mirrored. */
ssray.origin.x = 1.0 - ssray.origin.x;
@ -177,9 +175,10 @@ bool raytrace_planar(Ray ray, RayTraceParameters params, int planar_ref_id, out
float depth_sample = get_depth_from_view_z(ray.origin.z);
float delta = depth_sample - ssray.origin.z;
/* Cross at least one pixel. */
float t = 1.001, time = 1.001;
bool hit = false;
float t = 0.0, time = 0.0;
/* On very sharp reflections, the ray can be perfectly aligned with the view direction
* making the tracing useless. Bypass tracing in this case. */
bool hit = (ssray.max_time < 1.0);
const float max_steps = 255.0;
for (float iter = 1.0; !hit && (time < ssray.max_time) && (iter < max_steps); iter++) {
float stride = 1.0 + iter * params.trace_quality;
@ -205,6 +204,8 @@ bool raytrace_planar(Ray ray, RayTraceParameters params, int planar_ref_id, out
time = mix(prev_time, time, saturate(prev_delta / (prev_delta - delta)));
hit_position = ssray.origin.xyz + ssray.direction.xyz * time;
/* Planar Reflections have X mirrored. */
hit_position.x = 1.0 - hit_position.x;
return hit;
}