Fixing artifacts in SSR

This commit is contained in:
Bastiaan Olij 2022-10-02 20:08:07 +11:00
parent e5aa5eb806
commit d09ad714bf
4 changed files with 61 additions and 19 deletions

View file

@ -1457,6 +1457,17 @@ void SSEffects::ssr_set_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_q
void SSEffects::ssr_allocate_buffers(SSRRenderBuffers &p_ssr_buffers, const RenderingDevice::DataFormat p_color_format, const Size2i &p_screen_size, const uint32_t p_view_count) {
// As we are processing one view at a time, we can reuse buffers, only our output needs to have layers for each view.
if (p_ssr_buffers.size != p_screen_size || p_ssr_buffers.roughness_quality != ssr_roughness_quality) {
ssr_free(p_ssr_buffers);
}
if (p_ssr_buffers.output.is_valid()) {
// already allocated
return;
}
p_ssr_buffers.size = p_screen_size;
p_ssr_buffers.roughness_quality = ssr_roughness_quality;
if (p_ssr_buffers.depth_scaled.is_null()) {
RD::TextureFormat tf;
@ -1581,8 +1592,13 @@ void SSEffects::screen_space_reflection(SSRRenderBuffers &p_ssr_buffers, const R
RD::Uniform u_normal_roughness(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 1, Vector<RID>({ default_sampler, p_normal_roughness_slices[v] }));
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_depth, u_normal_roughness), 1);
RD::Uniform u_output_blur(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_ssr_buffers.output_slices[v] }));
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 2, u_output_blur), 2);
if (ssr_roughness_quality != RS::ENV_SSR_ROUGHNESS_QUALITY_DISABLED) {
RD::Uniform u_output(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_ssr_buffers.output_slices[v] }));
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 2, u_output), 2);
} else {
RD::Uniform u_intermediate(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_ssr_buffers.intermediate }));
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 2, u_intermediate), 2);
}
RD::Uniform u_scale_depth(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_ssr_buffers.depth_scaled }));
RD::Uniform u_scale_normal(RD::UNIFORM_TYPE_IMAGE, 1, Vector<RID>({ p_ssr_buffers.normal_scaled }));
@ -1624,17 +1640,25 @@ void SSEffects::screen_space_reflection(SSRRenderBuffers &p_ssr_buffers, const R
RD::Uniform u_scene_data(RD::UNIFORM_TYPE_UNIFORM_BUFFER, 0, ssr.ubo);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 4, u_scene_data), 4);
RD::Uniform u_output_blur(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_ssr_buffers.output_slices[v] }));
RD::Uniform u_scale_depth(RD::UNIFORM_TYPE_IMAGE, 1, Vector<RID>({ p_ssr_buffers.depth_scaled }));
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_output_blur, u_scale_depth), 0);
if (ssr_roughness_quality != RS::ENV_SSR_ROUGHNESS_QUALITY_DISABLED) {
// read from output slices (our scale wrote into these)
RD::Uniform u_output(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_ssr_buffers.output_slices[v] }));
RD::Uniform u_scale_depth(RD::UNIFORM_TYPE_IMAGE, 1, Vector<RID>({ p_ssr_buffers.depth_scaled }));
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_output, u_scale_depth), 0);
// write to intermediate (our roughness pass will output into output slices)
RD::Uniform u_intermediate(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_ssr_buffers.intermediate }));
RD::Uniform u_blur_radius(RD::UNIFORM_TYPE_IMAGE, 1, Vector<RID>({ p_ssr_buffers.blur_radius[0] }));
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_intermediate, u_blur_radius), 1);
} else {
// read from intermediate (our scale wrote into these)
RD::Uniform u_intermediate(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_ssr_buffers.intermediate }));
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_intermediate), 1);
RD::Uniform u_scale_depth(RD::UNIFORM_TYPE_IMAGE, 1, Vector<RID>({ p_ssr_buffers.depth_scaled }));
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_intermediate, u_scale_depth), 0);
// We are not performing our blur so go directly to output.
RD::Uniform u_output(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_ssr_buffers.output_slices[v] }));
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_output), 1);
}
RD::Uniform u_scale_normal(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_ssr_buffers.normal_scaled }));

View file

@ -148,6 +148,9 @@ public:
void ssr_set_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality);
struct SSRRenderBuffers {
Size2i size;
RenderingServer::EnvironmentSSRRoughnessQuality roughness_quality = RenderingServer::ENV_SSR_ROUGHNESS_QUALITY_DISABLED;
RID normal_scaled;
RID depth_scaled;
RID blur_radius[2];

View file

@ -1500,9 +1500,8 @@ void RenderForwardClustered::_process_ssr(Ref<RenderSceneBuffersRD> p_render_buf
ERR_FAIL_COND(!environment_get_ssr_enabled(p_environment));
Size2i half_size = Size2i(internal_size.x / 2, internal_size.y / 2);
if (rb_data->ss_effects_data.ssr.output.is_null()) {
ss_effects->ssr_allocate_buffers(rb_data->ss_effects_data.ssr, _render_buffers_get_color_format(), half_size, view_count);
}
ss_effects->ssr_allocate_buffers(rb_data->ss_effects_data.ssr, _render_buffers_get_color_format(), half_size, view_count);
RID texture_slices[RendererSceneRender::MAX_RENDER_VIEWS];
RID depth_slices[RendererSceneRender::MAX_RENDER_VIEWS];
for (uint32_t v = 0; v < view_count; v++) {

View file

@ -121,7 +121,7 @@ void main() {
// clip z and w advance to line advance
vec2 line_advance = normalize(line_dir); // down to pixel
float step_size = length(line_advance) / length(line_dir);
float step_size = 1.0 / length(line_dir);
float z_advance = z_dir * step_size; // adapt z advance to line advance
float w_advance = w_dir * step_size; // adapt w advance to line advance
@ -139,6 +139,14 @@ void main() {
float depth;
vec2 prev_pos = pos;
if (ivec2(pos + line_advance - 0.5) == ssC) {
// It is possible for rounding to cause our first pixel to check to be the pixel we're reflecting.
// Make sure we skip it
pos += line_advance;
z += z_advance;
w += w_advance;
}
bool found = false;
float steps_taken = 0.0;
@ -149,8 +157,8 @@ void main() {
w += w_advance;
// convert to linear depth
depth = imageLoad(source_depth, ivec2(pos - 0.5)).r;
ivec2 test_pos = ivec2(pos - 0.5);
depth = imageLoad(source_depth, test_pos).r;
if (sc_multiview) {
depth = depth * 2.0 - 1.0;
depth = 2.0 * params.camera_z_near * params.camera_z_far / (params.camera_z_far + params.camera_z_near - depth * (params.camera_z_far - params.camera_z_near));
@ -161,13 +169,21 @@ void main() {
z_to = z / w;
if (depth > z_to) {
// if depth was surpassed
if (depth <= max(z_to, z_from) + params.depth_tolerance && -depth < params.camera_z_far * 0.95) {
// check the depth tolerance and far clip
// check that normal is valid
found = true;
// Test if our ray is hitting the "right" side of the surface, if not we're likely self reflecting and should skip.
vec4 test_normal_roughness = imageLoad(source_normal_roughness, test_pos);
vec3 test_normal = test_normal_roughness.xyz * 2.0 - 1.0;
test_normal = normalize(test_normal);
test_normal.y = -test_normal.y; //because this code reads flipped
if (dot(ray_dir, test_normal) < 0.001) {
// if depth was surpassed
if (depth <= max(z_to, z_from) + params.depth_tolerance && -depth < params.camera_z_far * 0.95) {
// check the depth tolerance and far clip
// check that normal is valid
found = true;
}
break;
}
break;
}
steps_taken += 1.0;