Merge pull request #111210 from blueskythlikesclouds/ssr-overhaul

Overhaul screen space reflections.
This commit is contained in:
Thaddeus Crews
2025-10-21 15:11:08 -05:00
31 changed files with 1185 additions and 934 deletions
+1 -1
View File
@@ -298,7 +298,7 @@
<member name="ssil_sharpness" type="float" setter="set_ssil_sharpness" getter="get_ssil_sharpness" default="0.98">
The amount that the screen-space indirect lighting effect is allowed to blur over the edges of objects. Setting too high will result in aliasing around the edges of objects. Setting too low will make object edges appear blurry.
</member>
<member name="ssr_depth_tolerance" type="float" setter="set_ssr_depth_tolerance" getter="get_ssr_depth_tolerance" default="0.2">
<member name="ssr_depth_tolerance" type="float" setter="set_ssr_depth_tolerance" getter="get_ssr_depth_tolerance" default="0.5">
The depth tolerance for screen-space reflections.
</member>
<member name="ssr_enabled" type="bool" setter="set_ssr_enabled" getter="is_ssr_enabled" default="false">
+2 -2
View File
@@ -2838,8 +2838,8 @@
<member name="rendering/environment/glow/upscale_mode.mobile" type="int" setter="" getter="" default="0">
Lower-end override for [member rendering/environment/glow/upscale_mode] on mobile devices, due to performance concerns or driver support.
</member>
<member name="rendering/environment/screen_space_reflection/roughness_quality" type="int" setter="" getter="" default="1">
Sets the quality for rough screen-space reflections. Turning off will make all screen space reflections sharp, while higher values make rough reflections look better.
<member name="rendering/environment/screen_space_reflection/half_size" type="bool" setter="" getter="" default="true">
If [code]true[/code], screen-space reflections will be rendered at half size and then upscaled before being added to the scene. This is faster but may look pixelated or cause flickering. If [code]false[/code], screen-space reflections will be rendered at full size.
</member>
<member name="rendering/environment/ssao/adaptive_target" type="float" setter="" getter="" default="0.5">
Quality target to use when [member rendering/environment/ssao/quality] is set to [code]Ultra[/code]. A value of [code]0.0[/code] provides a quality and speed similar to [code]Medium[/code] while a value of [code]1.0[/code] provides much higher quality than any of the other settings at the cost of performance.
+8 -1
View File
@@ -1500,7 +1500,14 @@
Sets the variables to be used with the screen-space reflections (SSR) post-process effect. See [Environment] for more details.
</description>
</method>
<method name="environment_set_ssr_roughness_quality">
<method name="environment_set_ssr_half_size">
<return type="void" />
<param index="0" name="half_size" type="bool" />
<description>
Sets whether screen-space reflections will be rendered at full or half size. Half size is faster, but may look pixelated or cause flickering.
</description>
</method>
<method name="environment_set_ssr_roughness_quality" deprecated="This option no longer does anything.">
<return type="void" />
<param index="0" name="quality" type="int" enum="RenderingServer.EnvironmentSSRRoughnessQuality" />
<description>
+3
View File
@@ -1107,6 +1107,9 @@ void RasterizerSceneGLES3::environment_glow_set_use_bicubic_upscale(bool p_enabl
glow_bicubic_upscale = p_enable;
}
void RasterizerSceneGLES3::environment_set_ssr_half_size(bool p_half_size) {
}
void RasterizerSceneGLES3::environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) {
}
+1 -1
View File
@@ -757,7 +757,6 @@ protected:
float ssao_fadeout_to = 300.0;
bool glow_bicubic_upscale = false;
RS::EnvironmentSSRRoughnessQuality ssr_roughness_quality = RS::ENV_SSR_ROUGHNESS_QUALITY_LOW;
bool lightmap_bicubic_upscale = false;
@@ -878,6 +877,7 @@ public:
void environment_glow_set_use_bicubic_upscale(bool p_enable) override;
void environment_set_ssr_half_size(bool p_half_size) override;
void environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) override;
void environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) override;
+1 -2
View File
@@ -472,8 +472,7 @@ void EditorNode::_update_from_settings() {
bool glow_bicubic = int(GLOBAL_GET("rendering/environment/glow/upscale_mode")) > 0;
RS::get_singleton()->environment_set_ssil_quality(RS::EnvironmentSSILQuality(int(GLOBAL_GET("rendering/environment/ssil/quality"))), GLOBAL_GET("rendering/environment/ssil/half_size"), GLOBAL_GET("rendering/environment/ssil/adaptive_target"), GLOBAL_GET("rendering/environment/ssil/blur_passes"), GLOBAL_GET("rendering/environment/ssil/fadeout_from"), GLOBAL_GET("rendering/environment/ssil/fadeout_to"));
RS::get_singleton()->environment_glow_set_use_bicubic_upscale(glow_bicubic);
RS::EnvironmentSSRRoughnessQuality ssr_roughness_quality = RS::EnvironmentSSRRoughnessQuality(int(GLOBAL_GET("rendering/environment/screen_space_reflection/roughness_quality")));
RS::get_singleton()->environment_set_ssr_roughness_quality(ssr_roughness_quality);
RS::get_singleton()->environment_set_ssr_half_size(GLOBAL_GET("rendering/environment/screen_space_reflection/half_size"));
RS::SubSurfaceScatteringQuality sss_quality = RS::SubSurfaceScatteringQuality(int(GLOBAL_GET("rendering/environment/subsurface_scattering/subsurface_scattering_quality")));
RS::get_singleton()->sub_surface_scattering_set_quality(sss_quality);
float sss_scale = GLOBAL_GET("rendering/environment/subsurface_scattering/subsurface_scattering_scale");
+1 -1
View File
@@ -1264,7 +1264,7 @@ void Environment::_bind_methods() {
ADD_GROUP("SSR", "ssr_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ssr_enabled", PROPERTY_HINT_GROUP_ENABLE), "set_ssr_enabled", "is_ssr_enabled");
ADD_PROPERTY(PropertyInfo(Variant::INT, "ssr_max_steps", PROPERTY_HINT_RANGE, "1,512,1"), "set_ssr_max_steps", "get_ssr_max_steps");
ADD_PROPERTY(PropertyInfo(Variant::INT, "ssr_max_steps", PROPERTY_HINT_RANGE, "32,512,1"), "set_ssr_max_steps", "get_ssr_max_steps");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssr_fade_in", PROPERTY_HINT_EXP_EASING, "positive_only"), "set_ssr_fade_in", "get_ssr_fade_in");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssr_fade_out", PROPERTY_HINT_EXP_EASING, "positive_only"), "set_ssr_fade_out", "get_ssr_fade_out");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssr_depth_tolerance", PROPERTY_HINT_RANGE, "0.01,128,0.1"), "set_ssr_depth_tolerance", "get_ssr_depth_tolerance");
+1 -1
View File
@@ -122,7 +122,7 @@ private:
int ssr_max_steps = 64;
float ssr_fade_in = 0.15;
float ssr_fade_out = 2.0;
float ssr_depth_tolerance = 0.2;
float ssr_depth_tolerance = 0.5;
void _update_ssr();
// SSAO
@@ -120,6 +120,7 @@ public:
void environment_glow_set_use_bicubic_upscale(bool p_enable) override {}
void environment_set_ssr_half_size(bool p_half_size) override {}
void environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) override {}
void environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) override {}
File diff suppressed because it is too large Load Diff
@@ -32,8 +32,10 @@
#include "servers/rendering/renderer_rd/pipeline_deferred_rd.h"
#include "servers/rendering/renderer_rd/shaders/effects/screen_space_reflection.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/effects/screen_space_reflection_downsample.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/effects/screen_space_reflection_filter.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/effects/screen_space_reflection_scale.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/effects/screen_space_reflection_hiz.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/effects/screen_space_reflection_resolve.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/effects/ss_effects_downsample.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/effects/ssao.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/effects/ssao_blur.glsl.gen.h"
@@ -46,6 +48,7 @@
#include "servers/rendering/renderer_rd/shaders/effects/subsurface_scattering.glsl.gen.h"
#include "servers/rendering/rendering_server.h"
#define RB_SCOPE_SSLF SNAME("rb_sslf")
#define RB_SCOPE_SSDS SNAME("rb_ssds")
#define RB_SCOPE_SSIL SNAME("rb_ssil")
#define RB_SCOPE_SSAO SNAME("rb_ssao")
@@ -60,16 +63,17 @@
#define RB_IMPORTANCE_MAP SNAME("importance_map")
#define RB_IMPORTANCE_PONG SNAME("importance_pong")
#define RB_DEPTH_SCALED SNAME("depth_scaled")
#define RB_NORMAL_SCALED SNAME("normal_scaled")
#define RB_BLUR_RADIUS SNAME("blur_radius")
#define RB_INTERMEDIATE SNAME("intermediate")
#define RB_OUTPUT SNAME("output")
#define RB_NORMAL_ROUGHNESS SNAME("normal_roughness")
#define RB_HIZ SNAME("hiz")
#define RB_SSR SNAME("ssr")
#define RB_MIP_LEVEL SNAME("mip_level")
class RenderSceneBuffersRD;
namespace RendererRD {
class CopyEffects;
class SSEffects {
private:
static SSEffects *singleton;
@@ -80,6 +84,11 @@ public:
SSEffects();
~SSEffects();
/* Last Frame */
void allocate_last_frame_buffer(Ref<RenderSceneBuffersRD> p_render_buffers, bool p_use_ssil, bool p_use_ssr);
void copy_internal_texture_to_last_frame(Ref<RenderSceneBuffersRD> p_render_buffers, CopyEffects &p_copy_effects);
/* SS Downsampler */
void downsample_depth(Ref<RenderSceneBuffersRD> p_render_buffers, uint32_t p_view, const Projection &p_projection);
@@ -133,15 +142,16 @@ public:
void generate_ssao(Ref<RenderSceneBuffersRD> p_render_buffers, SSAORenderBuffers &p_ssao_buffers, uint32_t p_view, RID p_normal_buffer, const Projection &p_projection, const SSAOSettings &p_settings);
/* Screen Space Reflection */
void ssr_set_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality);
void ssr_set_half_size(bool p_half_size);
struct SSRRenderBuffers {
Size2i size;
RenderingServer::EnvironmentSSRRoughnessQuality roughness_quality = RenderingServer::ENV_SSR_ROUGHNESS_QUALITY_DISABLED;
uint32_t mipmaps = 1;
bool half_size = false;
};
void ssr_allocate_buffers(Ref<RenderSceneBuffersRD> p_render_buffers, SSRRenderBuffers &p_ssr_buffers, const RenderingDevice::DataFormat p_color_format);
void screen_space_reflection(Ref<RenderSceneBuffersRD> p_render_buffers, SSRRenderBuffers &p_ssr_buffers, const RID *p_normal_roughness_slices, const RID *p_metallic_slices, int p_max_steps, float p_fade_in, float p_fade_out, float p_tolerance, const Projection *p_projections, const Vector3 *p_eye_offsets);
void ssr_allocate_buffers(Ref<RenderSceneBuffersRD> p_render_buffers, SSRRenderBuffers &p_ssr_buffers, const RD::DataFormat p_color_format);
void screen_space_reflection(Ref<RenderSceneBuffersRD> p_render_buffers, SSRRenderBuffers &p_ssr_buffers, const RID *p_normal_roughness_slices, int p_max_steps, float p_fade_in, float p_fade_out, float p_tolerance, const Projection *p_projections, const Projection *p_reprojections, const Vector3 *p_eye_offsets, RendererRD::CopyEffects &p_copy_effects);
/* subsurface scattering */
void sss_set_quality(RS::SubSurfaceScatteringQuality p_quality);
@@ -167,7 +177,7 @@ private:
float ssil_fadeout_from = 50.0;
float ssil_fadeout_to = 300.0;
RS::EnvironmentSSRRoughnessQuality ssr_roughness_quality = RS::ENV_SSR_ROUGHNESS_QUALITY_LOW;
bool ssr_half_size = false;
RS::SubSurfaceScatteringQuality sss_quality = RS::SUB_SURFACE_SCATTERING_QUALITY_MEDIUM;
float sss_scale = 0.05;
@@ -409,99 +419,85 @@ private:
/* Screen Space Reflection */
enum SSRShaderSpecializations {
SSR_MULTIVIEW = 1 << 0,
SSR_VARIATIONS = 2,
enum ScreenSpaceReflectionDownsampleMode {
SCREEN_SPACE_REFLECTION_DOWNSAMPLE_DEFAULT,
SCREEN_SPACE_REFLECTION_DOWNSAMPLE_ODD_WIDTH,
SCREEN_SPACE_REFLECTION_DOWNSAMPLE_ODD_HEIGHT,
SCREEN_SPACE_REFLECTION_DOWNSAMPLE_ODD_WIDTH_AND_HEIGHT,
SCREEN_SPACE_REFLECTION_DOWNSAMPLE_MAX
};
struct ScreenSpaceReflectionDownsamplePushConstant {
int32_t screen_size[2];
int32_t pad[2];
};
enum ScreenSpaceReflectionHizMode {
SCREEN_SPACE_REFLECTION_HIZ_DEFAULT,
SCREEN_SPACE_REFLECTION_HIZ_ODD_WIDTH,
SCREEN_SPACE_REFLECTION_HIZ_ODD_HEIGHT,
SCREEN_SPACE_REFLECTION_HIZ_ODD_WIDTH_AND_HEIGHT,
SCREEN_SPACE_REFLECTION_HIZ_MAX
};
struct ScreenSpaceReflectionHizPushConstant {
int32_t screen_size[2];
int32_t pad[2];
};
struct ScreenSpaceReflectionSceneData {
float projection[2][16];
float inv_projection[2][16];
float reprojection[2][16];
float eye_offset[2][4];
};
// SSR Scale
struct ScreenSpaceReflectionScalePushConstant {
int32_t screen_size[2];
float camera_z_near;
float camera_z_far;
uint32_t orthogonal;
uint32_t filter;
uint32_t view_index;
uint32_t pad1;
};
struct ScreenSpaceReflectionScale {
ScreenSpaceReflectionScaleShaderRD shader;
RID shader_version;
PipelineDeferredRD pipelines[SSR_VARIATIONS];
} ssr_scale;
// SSR main
enum ScreenSpaceReflectionMode {
SCREEN_SPACE_REFLECTION_NORMAL,
SCREEN_SPACE_REFLECTION_ROUGH,
SCREEN_SPACE_REFLECTION_MAX,
};
struct ScreenSpaceReflectionPushConstant {
float proj_info[4]; // 16 - 16
int32_t screen_size[2];
int32_t mipmaps;
int32_t num_steps;
float distance_fade;
float curve_fade_in;
float depth_tolerance;
int32_t orthogonal;
uint32_t view_index;
int32_t pad[3];
};
int32_t screen_size[2]; // 8 - 24
float camera_z_near; // 4 - 28
float camera_z_far; // 4 - 32
struct ScreenSpaceReflectionFilterPushConstant {
int32_t screen_size[2];
uint32_t mip_level;
int32_t pad;
};
int32_t num_steps; // 4 - 36
float depth_tolerance; // 4 - 40
float distance_fade; // 4 - 44
float curve_fade_in; // 4 - 48
uint32_t orthogonal; // 4 - 52
float filter_mipmap_levels; // 4 - 56
uint32_t use_half_res; // 4 - 60
uint32_t view_index; // 4 - 64
// float projection[16]; // this is in our ScreenSpaceReflectionSceneData now
struct ScreenSpaceReflectionResolvePushConstant {
int32_t screen_size[2];
int32_t pad[2];
};
struct ScreenSpaceReflection {
ScreenSpaceReflectionShaderRD shader;
RID shader_version;
PipelineDeferredRD pipelines[SSR_VARIATIONS][SCREEN_SPACE_REFLECTION_MAX];
ScreenSpaceReflectionDownsampleShaderRD downsample_shader;
RID downsample_shader_version;
PipelineDeferredRD downsample_pipelines[SCREEN_SPACE_REFLECTION_DOWNSAMPLE_MAX];
ScreenSpaceReflectionHizShaderRD hiz_shader;
RID hiz_shader_version;
PipelineDeferredRD hiz_pipelines[SCREEN_SPACE_REFLECTION_HIZ_MAX];
ScreenSpaceReflectionShaderRD ssr_shader;
RID ssr_shader_version;
PipelineDeferredRD ssr_pipeline;
RID ubo;
ScreenSpaceReflectionFilterShaderRD filter_shader;
RID filter_shader_version;
PipelineDeferredRD filter_pipeline;
ScreenSpaceReflectionResolveShaderRD resolve_shader;
RID resolve_shader_version;
PipelineDeferredRD resolve_pipeline;
} ssr;
// SSR Filter
struct ScreenSpaceReflectionFilterPushConstant {
float proj_info[4]; // 16 - 16
uint32_t orthogonal; // 4 - 20
float edge_tolerance; // 4 - 24
int32_t increment; // 4 - 28
uint32_t view_index; // 4 - 32
int32_t screen_size[2]; // 8 - 40
uint32_t vertical; // 4 - 44
uint32_t steps; // 4 - 48
};
enum SSRReflectionMode {
SCREEN_SPACE_REFLECTION_FILTER_HORIZONTAL,
SCREEN_SPACE_REFLECTION_FILTER_VERTICAL,
SCREEN_SPACE_REFLECTION_FILTER_MAX,
};
struct ScreenSpaceReflectionFilter {
ScreenSpaceReflectionFilterShaderRD shader;
RID shader_version;
PipelineDeferredRD pipelines[SSR_VARIATIONS][SCREEN_SPACE_REFLECTION_FILTER_MAX];
} ssr_filter;
/* Subsurface scattering */
enum SSSMode {
@@ -737,8 +737,17 @@ void RenderForwardClustered::_setup_environment(const RenderDataRD *p_render_dat
scene_state.ubo.ssao_light_affect = environment_get_ssao_direct_light_affect(p_render_data->environment);
uint32_t ss_flags = 0;
if (p_opaque_render_buffers) {
ss_flags |= environment_get_ssao_enabled(p_render_data->environment) ? 1 : 0;
ss_flags |= environment_get_ssil_enabled(p_render_data->environment) ? 2 : 0;
ss_flags |= environment_get_ssao_enabled(p_render_data->environment) ? (1 << 0) : 0;
ss_flags |= environment_get_ssil_enabled(p_render_data->environment) ? (1 << 1) : 0;
ss_flags |= environment_get_ssr_enabled(p_render_data->environment) ? (1 << 2) : 0;
if (rd.is_valid()) {
Ref<RenderBufferDataForwardClustered> rb_data;
if (rd->has_custom_data(RB_SCOPE_FORWARD_CLUSTERED)) {
rb_data = rd->get_custom_data(RB_SCOPE_FORWARD_CLUSTERED);
ss_flags |= (rb_data.is_valid() && !rb_data->ss_effects_data.ssr.half_size) ? (1 << 3) : 0;
}
}
}
scene_state.ubo.ss_effects_flags = ss_flags;
} else {
@@ -1407,42 +1416,50 @@ void RenderForwardClustered::_process_ssil(Ref<RenderSceneBuffersRD> p_render_bu
Projection correction;
correction.set_depth_correction(true);
Projection projection = correction * p_projections[v];
Projection last_frame_projection = rb_data->ss_effects_data.last_frame_projections[v] * Projection(rb_data->ss_effects_data.last_frame_transform.affine_inverse()) * Projection(transform) * projection.inverse();
Projection last_frame_projection = rb_data->ss_effects_data.ssil_last_frame_projections[v] * Projection(rb_data->ss_effects_data.ssil_last_frame_transform.affine_inverse()) * Projection(transform) * projection.inverse();
ss_effects->screen_space_indirect_lighting(p_render_buffers, rb_data->ss_effects_data.ssil, v, p_normal_buffers[v], p_projections[v], last_frame_projection, settings);
rb_data->ss_effects_data.last_frame_projections[v] = projection;
rb_data->ss_effects_data.ssil_last_frame_projections[v] = projection;
}
rb_data->ss_effects_data.last_frame_transform = transform;
rb_data->ss_effects_data.ssil_last_frame_transform = transform;
}
void RenderForwardClustered::_copy_framebuffer_to_ssil(Ref<RenderSceneBuffersRD> p_render_buffers) {
void RenderForwardClustered::_process_ssr(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_environment, const RID *p_normal_slices, const Projection *p_projections, const Vector3 *p_eye_offsets, const Transform3D &p_transform) {
ERR_FAIL_NULL(ss_effects);
ERR_FAIL_COND(p_render_buffers.is_null());
if (p_render_buffers->has_texture(RB_SCOPE_SSIL, RB_LAST_FRAME)) {
Size2i size = p_render_buffers->get_internal_size();
uint32_t mipmaps = p_render_buffers->get_texture_format(RB_SCOPE_SSIL, RB_LAST_FRAME).mipmaps;
for (uint32_t v = 0; v < p_render_buffers->get_view_count(); v++) {
RID source = p_render_buffers->get_internal_texture(v);
RID dest = p_render_buffers->get_texture_slice(RB_SCOPE_SSIL, RB_LAST_FRAME, v, 0);
copy_effects->copy_to_rect(source, dest, Rect2i(0, 0, size.x, size.y));
Ref<RenderBufferDataForwardClustered> rb_data = p_render_buffers->get_custom_data(RB_SCOPE_FORWARD_CLUSTERED);
ERR_FAIL_COND(rb_data.is_null());
int width = size.x;
int height = size.y;
for (uint32_t m = 1; m < mipmaps; m++) {
width = MAX(1, width >> 1);
height = MAX(1, height >> 1);
RENDER_TIMESTAMP("Process SSR");
source = dest;
dest = p_render_buffers->get_texture_slice(RB_SCOPE_SSIL, RB_LAST_FRAME, v, m);
ss_effects->ssr_allocate_buffers(p_render_buffers, rb_data->ss_effects_data.ssr, _render_buffers_get_color_format());
copy_effects->make_mipmap(source, dest, Size2i(width, height));
}
}
Projection reprojections[RendererSceneRender::MAX_RENDER_VIEWS];
for (uint32_t v = 0; v < p_render_buffers->get_view_count(); v++) {
Projection correction;
correction.set_depth_correction(true);
Projection projection = correction * p_projections[v];
reprojections[v] = rb_data->ss_effects_data.ssr_last_frame_projections[v] * Projection(rb_data->ss_effects_data.ssr_last_frame_transform.affine_inverse()) * Projection(p_transform) * projection.inverse();
rb_data->ss_effects_data.ssr_last_frame_projections[v] = projection;
}
rb_data->ss_effects_data.ssr_last_frame_transform = p_transform;
ss_effects->screen_space_reflection(p_render_buffers, rb_data->ss_effects_data.ssr, p_normal_slices, environment_get_ssr_max_steps(p_environment), environment_get_ssr_fade_in(p_environment), environment_get_ssr_fade_out(p_environment), environment_get_ssr_depth_tolerance(p_environment), p_projections, reprojections, p_eye_offsets, *copy_effects);
}
void RenderForwardClustered::_pre_opaque_render(RenderDataRD *p_render_data, bool p_use_ssao, bool p_use_ssil, bool p_use_gi, const RID *p_normal_roughness_slices, RID p_voxel_gi_buffer) {
void RenderForwardClustered::_copy_framebuffer_to_ss_effects(Ref<RenderSceneBuffersRD> p_render_buffers, bool p_use_ssil, bool p_use_ssr) {
ERR_FAIL_NULL(ss_effects);
ERR_FAIL_COND(p_render_buffers.is_null());
ss_effects->copy_internal_texture_to_last_frame(p_render_buffers, *copy_effects);
}
void RenderForwardClustered::_pre_opaque_render(RenderDataRD *p_render_data, bool p_use_ssao, bool p_use_ssil, bool p_use_ssr, bool p_use_gi, const RID *p_normal_roughness_slices, RID p_voxel_gi_buffer) {
// Render shadows while GI is rendering, due to how barriers are handled, this should happen at the same time
RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton();
RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
@@ -1540,6 +1557,10 @@ void RenderForwardClustered::_pre_opaque_render(RenderDataRD *p_render_data, boo
// This should allow most of the processing to happen in parallel even if we're doing
// drawcalls per eye/view. It will all sync up at the barrier.
if (p_use_ssil || p_use_ssr) {
ss_effects->allocate_last_frame_buffer(rb, p_use_ssil, p_use_ssr);
}
if (p_use_ssao || p_use_ssil) {
RENDER_TIMESTAMP("Prepare Depth for SSAO/SSIL");
// Convert our depth buffer data to linear data in
@@ -1555,6 +1576,10 @@ void RenderForwardClustered::_pre_opaque_render(RenderDataRD *p_render_data, boo
_process_ssil(rb, p_render_data->environment, p_normal_roughness_slices, p_render_data->scene_data->view_projection, p_render_data->scene_data->cam_transform);
}
}
if (p_use_ssr) {
_process_ssr(rb, p_render_data->environment, p_normal_roughness_slices, p_render_data->scene_data->view_projection, p_render_data->scene_data->view_eye_offset, p_render_data->scene_data->cam_transform);
}
}
RENDER_TIMESTAMP("Pre Opaque Render");
@@ -1597,33 +1622,6 @@ void RenderForwardClustered::_pre_opaque_render(RenderDataRD *p_render_data, boo
}
}
void RenderForwardClustered::_process_ssr(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_dest_framebuffer, const RID *p_normal_slices, RID p_specular_buffer, const RID *p_metallic_slices, RID p_environment, const Projection *p_projections, const Vector3 *p_eye_offsets, bool p_use_additive) {
ERR_FAIL_NULL(ss_effects);
ERR_FAIL_COND(p_render_buffers.is_null());
Ref<RenderBufferDataForwardClustered> rb_data = p_render_buffers->get_custom_data(RB_SCOPE_FORWARD_CLUSTERED);
ERR_FAIL_COND(rb_data.is_null());
Size2i internal_size = p_render_buffers->get_internal_size();
bool can_use_effects = internal_size.x >= 8 && internal_size.y >= 8;
uint32_t view_count = p_render_buffers->get_view_count();
if (!can_use_effects) {
//just copy
copy_effects->merge_specular(p_dest_framebuffer, p_specular_buffer, p_use_additive ? RID() : p_render_buffers->get_internal_texture(), RID(), view_count);
return;
}
ERR_FAIL_COND(p_environment.is_null());
ERR_FAIL_COND(!environment_get_ssr_enabled(p_environment));
ss_effects->ssr_allocate_buffers(p_render_buffers, rb_data->ss_effects_data.ssr, _render_buffers_get_color_format());
ss_effects->screen_space_reflection(p_render_buffers, rb_data->ss_effects_data.ssr, p_normal_slices, p_metallic_slices, environment_get_ssr_max_steps(p_environment), environment_get_ssr_fade_in(p_environment), environment_get_ssr_fade_out(p_environment), environment_get_ssr_depth_tolerance(p_environment), p_projections, p_eye_offsets);
RID output = p_render_buffers->get_texture(RB_SCOPE_SSR, RB_OUTPUT);
copy_effects->merge_specular(p_dest_framebuffer, p_specular_buffer, p_use_additive ? RID() : p_render_buffers->get_internal_texture(), output, view_count);
}
void RenderForwardClustered::_process_sss(Ref<RenderSceneBuffersRD> p_render_buffers, const Projection &p_camera) {
ERR_FAIL_COND(p_render_buffers.is_null());
@@ -1819,9 +1817,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
}
if (environment_get_ssr_enabled(p_render_data->environment)) {
if (!p_render_data->transparent_bg) {
using_separate_specular = true;
using_ssr = true;
color_pass_flags |= COLOR_PASS_FLAG_SEPARATE_SPECULAR;
} else {
WARN_PRINT_ONCE("Screen-space reflections are not supported in viewports with a transparent background. Disabling SSR in transparent viewport.");
}
@@ -2122,7 +2118,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
normal_roughness_views[v] = rb_data->get_normal_roughness(v);
}
}
_pre_opaque_render(p_render_data, using_ssao, using_ssil, using_sdfgi || using_voxelgi, normal_roughness_views, rb_data.is_valid() && rb_data->has_voxelgi() ? rb_data->get_voxelgi() : RID());
_pre_opaque_render(p_render_data, using_ssao, using_ssil, using_ssr, using_sdfgi || using_voxelgi, normal_roughness_views, rb_data.is_valid() && rb_data->has_voxelgi() ? rb_data->get_voxelgi() : RID());
RENDER_TIMESTAMP("Render Opaque Pass");
@@ -2279,16 +2275,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
RD::get_singleton()->draw_command_end_label();
}
if (using_ssr) {
RENDER_TIMESTAMP("Screen-Space Reflections");
RD::get_singleton()->draw_command_begin_label("Process Screen-Space Reflections");
RID specular_views[RendererSceneRender::MAX_RENDER_VIEWS];
for (uint32_t v = 0; v < p_render_data->scene_data->view_count; v++) {
specular_views[v] = rb_data->get_specular(v);
}
_process_ssr(rb, color_only_framebuffer, normal_roughness_views, rb_data->get_specular(), specular_views, p_render_data->environment, p_render_data->scene_data->view_projection, p_render_data->scene_data->view_eye_offset, !use_msaa);
RD::get_singleton()->draw_command_end_label();
} else {
{
//just mix specular back
RENDER_TIMESTAMP("Merge Specular");
copy_effects->merge_specular(color_only_framebuffer, rb_data->get_specular(), !use_msaa ? RID() : rb->get_internal_texture(), RID(), p_render_data->scene_data->view_count);
@@ -2394,18 +2381,18 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
RD::get_singleton()->draw_command_end_label();
RD::get_singleton()->draw_command_begin_label("Copy Framebuffer for SSIL/SSR");
if (using_ssil || using_ssr) {
RENDER_TIMESTAMP("Copy Final Framebuffer (SSIL/SSR)");
_copy_framebuffer_to_ss_effects(rb, using_ssil, using_ssr);
}
RD::get_singleton()->draw_command_end_label();
{
RENDER_TIMESTAMP("Process Post Transparent Compositor Effects");
_process_compositor_effects(RS::COMPOSITOR_EFFECT_CALLBACK_TYPE_POST_TRANSPARENT, p_render_data);
}
RD::get_singleton()->draw_command_begin_label("Copy Framebuffer for SSIL");
if (using_ssil) {
RENDER_TIMESTAMP("Copy Final Framebuffer (SSIL)");
_copy_framebuffer_to_ssil(rb);
}
RD::get_singleton()->draw_command_end_label();
if (rb_data.is_valid() && (using_upscaling || using_taa)) {
if (scale_type == SCALE_FSR2) {
rb_data->ensure_fsr2(fsr2_effect);
@@ -3577,6 +3564,38 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
u.append_id(texture);
uniforms.push_back(u);
}
{
RD::Uniform u;
u.binding = 35;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
RID ssr;
if (rb_data.is_valid()) {
if (rb_data->ss_effects_data.ssr.half_size) {
if (rb->has_texture(RB_SCOPE_SSR, RB_FINAL)) {
ssr = rb->get_texture(RB_SCOPE_SSR, RB_FINAL);
}
} else {
if (rb->has_texture(RB_SCOPE_SSR, RB_SSR)) {
ssr = rb->get_texture(RB_SCOPE_SSR, RB_SSR);
}
}
}
RID texture = ssr.is_valid() ? ssr : texture_storage->texture_rd_get_default(is_multiview ? RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_BLACK : RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK);
u.append_id(texture);
uniforms.push_back(u);
}
{
RD::Uniform u;
u.binding = 36;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
RID ssr_mip_level = (rb_data.is_valid() && !rb_data->ss_effects_data.ssr.half_size && rb->has_texture(RB_SCOPE_SSR, RB_MIP_LEVEL)) ? rb->get_texture(RB_SCOPE_SSR, RB_MIP_LEVEL) : RID();
RID texture = ssr_mip_level.is_valid() ? ssr_mip_level : texture_storage->texture_rd_get_default(is_multiview ? RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_BLACK : RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK);
u.append_id(texture);
uniforms.push_back(u);
}
return UniformSetCacheRD::get_singleton()->get_cache_vec(scene_shader.default_shader_rd, RENDER_PASS_UNIFORM_SET, uniforms);
}
@@ -3814,10 +3833,13 @@ void RenderForwardClustered::environment_set_ssil_quality(RS::EnvironmentSSILQua
ss_effects->ssil_set_quality(p_quality, p_half_size, p_adaptive_target, p_blur_passes, p_fadeout_from, p_fadeout_to);
}
void RenderForwardClustered::environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) {
void RenderForwardClustered::environment_set_ssr_half_size(bool p_half_size) {
ERR_FAIL_NULL(ss_effects);
ERR_FAIL_COND(p_quality < RS::EnvironmentSSRRoughnessQuality::ENV_SSR_ROUGHNESS_QUALITY_DISABLED || p_quality > RS::EnvironmentSSRRoughnessQuality::ENV_SSR_ROUGHNESS_QUALITY_HIGH);
ss_effects->ssr_set_roughness_quality(p_quality);
ss_effects->ssr_set_half_size(p_half_size);
}
void RenderForwardClustered::environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) {
WARN_PRINT_ONCE("environment_set_ssr_roughness_quality has been deprecated and no longer does anything.");
}
void RenderForwardClustered::sub_surface_scattering_set_quality(RS::SubSurfaceScatteringQuality p_quality) {
@@ -102,8 +102,11 @@ public:
ClusterBuilderRD *cluster_builder = nullptr;
struct SSEffectsData {
Projection last_frame_projections[RendererSceneRender::MAX_RENDER_VIEWS];
Transform3D last_frame_transform;
Projection ssil_last_frame_projections[RendererSceneRender::MAX_RENDER_VIEWS];
Transform3D ssil_last_frame_transform;
Projection ssr_last_frame_projections[RendererSceneRender::MAX_RENDER_VIEWS];
Transform3D ssr_last_frame_transform;
RendererRD::SSEffects::SSILRenderBuffers ssil;
RendererRD::SSEffects::SSAORenderBuffers ssao;
@@ -758,9 +761,9 @@ private:
/* Render Scene */
void _process_ssao(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_environment, const RID *p_normal_buffers, const Projection *p_projections);
void _process_ssil(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_environment, const RID *p_normal_buffers, const Projection *p_projections, const Transform3D &p_transform);
void _copy_framebuffer_to_ssil(Ref<RenderSceneBuffersRD> p_render_buffers);
void _pre_opaque_render(RenderDataRD *p_render_data, bool p_use_ssao, bool p_use_ssil, bool p_use_gi, const RID *p_normal_roughness_slices, RID p_voxel_gi_buffer);
void _process_ssr(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_dest_framebuffer, const RID *p_normal_buffer_slices, RID p_specular_buffer, const RID *p_metallic_slices, RID p_environment, const Projection *p_projections, const Vector3 *p_eye_offsets, bool p_use_additive);
void _process_ssr(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_environment, const RID *p_normal_slices, const Projection *p_projections, const Vector3 *p_eye_offsets, const Transform3D &p_transform);
void _copy_framebuffer_to_ss_effects(Ref<RenderSceneBuffersRD> p_render_buffers, bool p_use_ssil, bool p_use_ssr);
void _pre_opaque_render(RenderDataRD *p_render_data, bool p_use_ssao, bool p_use_ssil, bool p_use_ssr, bool p_use_gi, const RID *p_normal_roughness_slices, RID p_voxel_gi_buffer);
void _process_sss(Ref<RenderSceneBuffersRD> p_render_buffers, const Projection &p_camera);
/* Debug */
@@ -774,6 +777,7 @@ protected:
virtual void environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) override;
virtual void environment_set_ssil_quality(RS::EnvironmentSSILQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) override;
virtual void environment_set_ssr_half_size(bool p_half_size) override;
virtual void environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) override;
virtual void sub_surface_scattering_set_quality(RS::SubSurfaceScatteringQuality p_quality) override;
@@ -422,6 +422,7 @@ protected:
virtual void environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) override {}
virtual void environment_set_ssil_quality(RS::EnvironmentSSILQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) override {}
virtual void environment_set_ssr_half_size(bool p_half_size) override {}
virtual void environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) override {}
virtual void sub_surface_scattering_set_quality(RS::SubSurfaceScatteringQuality p_quality) override {}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,58 @@
#[compute]
#version 450
#VERSION_DEFINES
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
layout(set = 0, binding = 0) uniform sampler2D source_depth;
layout(set = 0, binding = 1) uniform sampler2D source_normal_roughness;
layout(r32f, set = 0, binding = 2) uniform restrict writeonly image2D dest_depth;
layout(rgba8, set = 0, binding = 3) uniform restrict writeonly image2D dest_normal_roughness;
layout(push_constant, std430) uniform Params {
ivec2 screen_size;
}
params;
void get_sample(ivec2 sample_pos, inout float depth, inout ivec2 winner_sample_pos) {
float sample_depth = texelFetch(source_depth, sample_pos, 0).x;
if (depth < sample_depth) {
depth = sample_depth;
winner_sample_pos = sample_pos;
}
}
void main() {
ivec2 pixel_pos = ivec2(gl_GlobalInvocationID.xy);
if (any(greaterThanEqual(pixel_pos, params.screen_size))) {
return;
}
ivec2 sample_pos = pixel_pos * 2 + ivec2(0, 0);
float depth = texelFetch(source_depth, sample_pos, 0).x;
get_sample(pixel_pos * 2 + ivec2(1, 0), depth, sample_pos);
get_sample(pixel_pos * 2 + ivec2(0, 1), depth, sample_pos);
get_sample(pixel_pos * 2 + ivec2(1, 1), depth, sample_pos);
#ifdef MODE_ODD_WIDTH
get_sample(pixel_pos * 2 + ivec2(2, 0), depth, sample_pos);
get_sample(pixel_pos * 2 + ivec2(2, 1), depth, sample_pos);
#endif
#ifdef MODE_ODD_HEIGHT
get_sample(pixel_pos * 2 + ivec2(0, 2), depth, sample_pos);
get_sample(pixel_pos * 2 + ivec2(1, 2), depth, sample_pos);
#endif
#if defined(MODE_ODD_WIDTH) && defined(MODE_ODD_HEIGHT)
get_sample(pixel_pos * 2 + ivec2(2, 2), depth, sample_pos);
#endif
imageStore(dest_depth, pixel_pos, vec4(depth, 0.0, 0.0, 0.0));
imageStore(dest_normal_roughness, pixel_pos, texelFetch(source_normal_roughness, sample_pos, 0));
}
@@ -6,143 +6,125 @@
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
layout(rgba16f, set = 0, binding = 0) uniform restrict readonly image2D source_ssr;
layout(r8, set = 0, binding = 1) uniform restrict readonly image2D source_radius;
layout(rgba8, set = 1, binding = 0) uniform restrict readonly image2D source_normal;
layout(rgba16f, set = 2, binding = 0) uniform restrict writeonly image2D dest_ssr;
#ifndef VERTICAL_PASS
layout(r8, set = 2, binding = 1) uniform restrict writeonly image2D dest_radius;
#endif
layout(r32f, set = 3, binding = 0) uniform restrict readonly image2D source_depth;
layout(set = 0, binding = 0) uniform sampler2D source;
layout(set = 0, binding = 1) uniform restrict writeonly image2D dest;
layout(push_constant, std430) uniform Params {
vec4 proj_info;
bool orthogonal;
float edge_tolerance;
int increment;
uint view_index;
ivec2 screen_size;
bool vertical;
uint steps;
uint mip_level;
}
params;
#include "screen_space_reflection_inc.glsl"
shared vec4 cache[16][16];
#define GAUSS_TABLE_SIZE 15
const float WEIGHTS[7] = float[7](
0.07130343198685299,
0.1315141208431224,
0.18987923288883812,
0.21460642856237303,
0.18987923288883812,
0.1315141208431224,
0.07130343198685299);
const float gauss_table[GAUSS_TABLE_SIZE + 1] = float[](
0.1847392078702266,
0.16595854345772326,
0.12031364177766891,
0.07038755277896766,
0.03322925565155569,
0.012657819729901945,
0.0038903040680094217,
0.0009646503390864025,
0.00019297087402915717,
0.000031139936308099136,
0.000004053309048174758,
4.255228059965837e-7,
3.602517634249573e-8,
2.4592560765896795e-9,
1.3534945386863618e-10,
0.0 //one more for interpolation
);
float gauss_weight(float p_val) {
float idxf;
float c = modf(max(0.0, p_val * float(GAUSS_TABLE_SIZE)), idxf);
int idx = int(idxf);
if (idx >= GAUSS_TABLE_SIZE + 1) {
return 0.0;
}
return mix(gauss_table[idx], gauss_table[idx + 1], c);
float get_weight(vec4 c) {
return mix(clamp(params.mip_level * 0.2, 0.0, 1.0), 1.0, c.a);
}
#define M_PI 3.14159265359
vec4 apply_gaus_horz(ivec2 local) {
vec4 c0 = cache[local.x - 3][local.y];
float w0 = WEIGHTS[0] * get_weight(c0);
void do_filter(inout vec4 accum, inout float accum_radius, inout float divisor, ivec2 texcoord, ivec2 increment, vec3 p_pos, vec3 normal, float p_limit_radius) {
for (int i = 1; i < params.steps; i++) {
float d = float(i * params.increment);
ivec2 tc = texcoord + increment * i;
float depth = imageLoad(source_depth, tc).r;
vec3 view_pos = reconstructCSPosition(vec2(tc) + 0.5, depth);
vec3 view_normal = normalize(imageLoad(source_normal, tc).rgb * 2.0 - 1.0);
view_normal.y = -view_normal.y;
vec4 c1 = cache[local.x - 2][local.y];
float w1 = WEIGHTS[1] * get_weight(c1);
float r = imageLoad(source_radius, tc).r;
float radius = round(r * 255.0);
vec4 c2 = cache[local.x - 1][local.y];
float w2 = WEIGHTS[2] * get_weight(c2);
float angle_n = 1.0 - abs(dot(normal, view_normal));
if (angle_n > params.edge_tolerance) {
break;
}
vec4 c3 = cache[local.x][local.y];
float w3 = WEIGHTS[3] * get_weight(c3);
float angle = abs(dot(normal, normalize(view_pos - p_pos)));
vec4 c4 = cache[local.x + 1][local.y];
float w4 = WEIGHTS[4] * get_weight(c4);
if (angle > params.edge_tolerance) {
break;
}
vec4 c5 = cache[local.x + 2][local.y];
float w5 = WEIGHTS[5] * get_weight(c5);
if (d < radius) {
float w = gauss_weight(d / radius);
accum += imageLoad(source_ssr, tc) * w;
#ifndef VERTICAL_PASS
accum_radius += r * w;
#endif
divisor += w;
}
vec4 c6 = cache[local.x + 3][local.y];
float w6 = WEIGHTS[6] * get_weight(c6);
vec4 c = c0 * w0 + c1 * w1 + c2 * w2 + c3 * w3 + c4 * w4 + c5 * w5 + c6 * w6;
float w = w0 + w1 + w2 + w3 + w4 + w5 + w6;
if (w > 0.0) {
c /= w;
} else {
c = vec4(0.0);
}
return c;
}
shared vec4 temp_cache[8][16];
vec4 apply_gaus_vert(ivec2 local) {
vec4 c0 = temp_cache[local.x][local.y - 3];
float w0 = WEIGHTS[0] * get_weight(c0);
vec4 c1 = temp_cache[local.x][local.y - 2];
float w1 = WEIGHTS[1] * get_weight(c1);
vec4 c2 = temp_cache[local.x][local.y - 1];
float w2 = WEIGHTS[2] * get_weight(c2);
vec4 c3 = temp_cache[local.x][local.y];
float w3 = WEIGHTS[3] * get_weight(c3);
vec4 c4 = temp_cache[local.x][local.y + 1];
float w4 = WEIGHTS[4] * get_weight(c4);
vec4 c5 = temp_cache[local.x][local.y + 2];
float w5 = WEIGHTS[5] * get_weight(c5);
vec4 c6 = temp_cache[local.x][local.y + 3];
float w6 = WEIGHTS[6] * get_weight(c6);
vec4 c = c0 * w0 + c1 * w1 + c2 * w2 + c3 * w3 + c4 * w4 + c5 * w5 + c6 * w6;
float w = w0 + w1 + w2 + w3 + w4 + w5 + w6;
if (w > 0.0) {
c /= w;
} else {
c = vec4(0.0);
}
return c;
}
vec4 get_sample(ivec2 pixel_pos) {
return textureLod(source, (vec2(pixel_pos) + 0.5) / params.screen_size, 0);
}
void main() {
// Pixel being shaded
ivec2 ssC = ivec2(gl_GlobalInvocationID.xy);
ivec2 global = ivec2(gl_GlobalInvocationID.xy);
ivec2 local = ivec2(gl_LocalInvocationID.xy);
if (any(greaterThanEqual(ssC.xy, params.screen_size))) { //too large, do nothing
cache[local.x * 2 + 0][local.y * 2 + 0] = get_sample(global + local - 4 + ivec2(0, 0));
cache[local.x * 2 + 1][local.y * 2 + 0] = get_sample(global + local - 4 + ivec2(1, 0));
cache[local.x * 2 + 0][local.y * 2 + 1] = get_sample(global + local - 4 + ivec2(0, 1));
cache[local.x * 2 + 1][local.y * 2 + 1] = get_sample(global + local - 4 + ivec2(1, 1));
memoryBarrierShared();
barrier();
temp_cache[local.x][local.y * 2 + 0] = apply_gaus_horz(ivec2(local.x + 4, local.y * 2 + 0));
temp_cache[local.x][local.y * 2 + 1] = apply_gaus_horz(ivec2(local.x + 4, local.y * 2 + 1));
memoryBarrierShared();
barrier();
if (any(greaterThanEqual(global, params.screen_size))) {
return;
}
float base_contrib = gauss_table[0];
vec4 accum = imageLoad(source_ssr, ssC);
float accum_radius = imageLoad(source_radius, ssC).r;
float radius = accum_radius * 255.0;
float divisor = gauss_table[0];
accum *= divisor;
accum_radius *= divisor;
#ifdef VERTICAL_PASS
ivec2 direction = ivec2(0, params.increment);
#else
ivec2 direction = ivec2(params.increment, 0);
#endif
float depth = imageLoad(source_depth, ssC).r;
vec3 pos = reconstructCSPosition(vec2(ssC.xy) + 0.5, depth);
vec3 normal = imageLoad(source_normal, ssC).xyz * 2.0 - 1.0;
normal = normalize(normal);
normal.y = -normal.y;
do_filter(accum, accum_radius, divisor, ssC.xy, direction, pos, normal, radius);
do_filter(accum, accum_radius, divisor, ssC.xy, -direction, pos, normal, radius);
if (divisor > 0.0) {
accum /= divisor;
accum_radius /= divisor;
} else {
accum = vec4(0.0);
accum_radius = 0.0;
}
imageStore(dest_ssr, ssC, accum);
#ifndef VERTICAL_PASS
imageStore(dest_radius, ssC, vec4(accum_radius));
#endif
imageStore(dest, global, apply_gaus_vert(local + ivec2(0, 4)));
}
@@ -0,0 +1,44 @@
#[compute]
#version 450
#VERSION_DEFINES
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
layout(set = 0, binding = 0) uniform sampler2D source;
layout(r32f, set = 0, binding = 1) uniform restrict writeonly image2D dest;
layout(push_constant, std430) uniform Params {
ivec2 screen_size;
}
params;
void main() {
ivec2 pixel_pos = ivec2(gl_GlobalInvocationID.xy);
if (any(greaterThanEqual(pixel_pos, params.screen_size))) {
return;
}
float depth = texelFetch(source, pixel_pos * 2 + ivec2(0, 0), 0).x;
depth = max(depth, texelFetch(source, pixel_pos * 2 + ivec2(1, 0), 0).x);
depth = max(depth, texelFetch(source, pixel_pos * 2 + ivec2(0, 1), 0).x);
depth = max(depth, texelFetch(source, pixel_pos * 2 + ivec2(1, 1), 0).x);
#ifdef MODE_ODD_WIDTH
depth = max(depth, texelFetch(source, pixel_pos * 2 + ivec2(2, 0), 0).x);
depth = max(depth, texelFetch(source, pixel_pos * 2 + ivec2(2, 1), 0).x);
#endif
#ifdef MODE_ODD_HEIGHT
depth = max(depth, texelFetch(source, pixel_pos * 2 + ivec2(0, 2), 0).x);
depth = max(depth, texelFetch(source, pixel_pos * 2 + ivec2(1, 2), 0).x);
#endif
#if defined(MODE_ODD_WIDTH) && defined(MODE_ODD_HEIGHT)
depth = max(depth, texelFetch(source, pixel_pos * 2 + ivec2(2, 2), 0).x);
#endif
imageStore(dest, pixel_pos, vec4(depth, 0.0, 0.0, 0.0));
}
@@ -1,28 +0,0 @@
layout(constant_id = 0) const bool sc_multiview = false;
layout(set = 4, binding = 0, std140) uniform SceneData {
mat4x4 projection[2];
mat4x4 inv_projection[2];
vec4 eye_offset[2];
}
scene_data;
vec3 reconstructCSPosition(vec2 screen_pos, float z) {
if (sc_multiview) {
vec4 pos;
pos.xy = (2.0 * vec2(screen_pos) / vec2(params.screen_size)) - 1.0;
pos.z = z * 2.0 - 1.0;
pos.w = 1.0;
pos = scene_data.inv_projection[params.view_index] * pos;
pos.xyz /= pos.w;
return pos.xyz;
} else {
if (params.orthogonal) {
return vec3(-(screen_pos.xy * params.proj_info.xy + params.proj_info.zw), z);
} else {
return vec3((screen_pos.xy * params.proj_info.xy + params.proj_info.zw) * z, z);
}
}
}
@@ -0,0 +1,98 @@
#[compute]
#version 450
#VERSION_DEFINES
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
layout(set = 0, binding = 0) uniform sampler2D source_depth;
layout(set = 0, binding = 1) uniform sampler2D source_normal_roughness;
layout(set = 0, binding = 2) uniform sampler2D source_depth_half;
layout(set = 0, binding = 3) uniform sampler2D source_normal_roughness_half;
layout(set = 0, binding = 4) uniform sampler2D source_color;
layout(set = 0, binding = 5) uniform sampler2D source_mip_level;
layout(rgba16f, set = 0, binding = 6) uniform restrict writeonly image2D output_color;
layout(push_constant, std430) uniform Params {
ivec2 screen_size;
}
params;
void get_sample(float depth, vec3 normal, float roughness, ivec2 pixel_pos, out vec4 color, out float weight) {
float sample_depth = texelFetch(source_depth_half, pixel_pos, 0).x;
vec4 sample_normal_roughness = texelFetch(source_normal_roughness_half, pixel_pos, 0);
vec3 sample_normal = normalize(sample_normal_roughness.xyz * 2.0 - 1.0);
float sample_roughness = sample_normal_roughness.w;
if (sample_roughness > 0.5) {
sample_roughness = 1.0 - sample_roughness;
}
sample_roughness /= (127.0 / 255.0);
vec2 uv = (pixel_pos + 0.5) / (params.screen_size * 0.5);
float mip_level = texelFetch(source_mip_level, pixel_pos, 0).x * 14.0;
color = textureLod(source_color, uv, mip_level);
// Invert the tone mapping we applied in the main trace pass.
const vec3 rec709_luminance_weights = vec3(0.2126, 0.7152, 0.0722);
color.rgb /= 1.0 - dot(color.rgb, rec709_luminance_weights);
const float DEPTH_FACTOR = 2048.0;
const float NORMAL_FACTOR = 32.0;
const float ROUGHNESS_FACTOR = 16.0;
float depth_diff = abs(depth - sample_depth);
float weight_depth = exp(-depth_diff * DEPTH_FACTOR);
float normal_diff = clamp(1.0 - dot(normal, sample_normal), 0.0, 1.0);
float weight_normal = exp(-normal_diff * NORMAL_FACTOR);
float roughness_diff = abs(roughness - sample_roughness);
float weight_roughness = exp(-roughness_diff * ROUGHNESS_FACTOR);
weight = weight_depth * weight_normal * weight_roughness;
}
void main() {
ivec2 pixel_pos = ivec2(gl_GlobalInvocationID.xy);
if (any(greaterThanEqual(pixel_pos, params.screen_size))) {
return;
}
float depth = texelFetch(source_depth, pixel_pos, 0).x;
vec4 normal_roughness = texelFetch(source_normal_roughness, pixel_pos, 0);
vec3 normal = normalize(normal_roughness.xyz * 2.0 - 1.0);
float roughness = normal_roughness.w;
if (roughness > 0.5) {
roughness = 1.0 - roughness;
}
roughness /= (127.0 / 255.0);
vec2 half_tex_coord = (pixel_pos + 0.5) * 0.5;
vec2 bilinear_weights = fract(half_tex_coord);
vec4 color0, color1, color2, color3;
float weight0, weight1, weight2, weight3;
get_sample(depth, normal, roughness, ((pixel_pos - 1) / 2) + ivec2(0, 0), color0, weight0);
get_sample(depth, normal, roughness, ((pixel_pos - 1) / 2) + ivec2(1, 0), color1, weight1);
get_sample(depth, normal, roughness, ((pixel_pos - 1) / 2) + ivec2(0, 1), color2, weight2);
get_sample(depth, normal, roughness, ((pixel_pos - 1) / 2) + ivec2(1, 1), color3, weight3);
weight0 *= bilinear_weights.x * bilinear_weights.y;
weight1 *= (1.0 - bilinear_weights.x) * bilinear_weights.y;
weight2 *= bilinear_weights.x * (1.0 - bilinear_weights.y);
weight3 *= (1.0 - bilinear_weights.x) * (1.0 - bilinear_weights.y);
vec4 result_color = color0 * weight0 + color1 * weight1 + color2 * weight2 + color3 * weight3;
float result_weight = weight0 + weight1 + weight2 + weight3;
if (result_weight > 0.0) {
result_color /= result_weight;
} else {
result_color = vec4(0.0);
}
imageStore(output_color, pixel_pos, result_color);
}
@@ -1,112 +0,0 @@
#[compute]
#version 450
#VERSION_DEFINES
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
/* Specialization Constants (Toggles) */
layout(constant_id = 0) const bool sc_multiview = false;
/* inputs */
layout(set = 0, binding = 0) uniform sampler2D source_ssr;
layout(set = 1, binding = 0) uniform sampler2D source_depth;
layout(set = 1, binding = 1) uniform sampler2D source_normal;
layout(rgba16f, set = 2, binding = 0) uniform restrict writeonly image2D dest_ssr;
layout(r32f, set = 3, binding = 0) uniform restrict writeonly image2D dest_depth;
layout(rgba8, set = 3, binding = 1) uniform restrict writeonly image2D dest_normal;
layout(push_constant, std430) uniform Params {
ivec2 screen_size;
float camera_z_near;
float camera_z_far;
bool orthogonal;
bool filtered;
uint pad[2];
}
params;
void main() {
// Pixel being shaded
ivec2 ssC = ivec2(gl_GlobalInvocationID.xy);
if (any(greaterThanEqual(ssC.xy, params.screen_size))) { //too large, do nothing
return;
}
//do not filter, SSR will generate artifacts if this is done
float divisor = 0.0;
vec4 color;
float depth;
vec4 normal;
if (params.filtered) {
color = vec4(0.0);
depth = 0.0;
normal = vec4(0.0);
for (int i = 0; i < 4; i++) {
ivec2 ofs = ssC << 1;
if (bool(i & 1)) {
ofs.x += 1;
}
if (bool(i & 2)) {
ofs.y += 1;
}
color += texelFetch(source_ssr, ofs, 0);
float d = texelFetch(source_depth, ofs, 0).r;
vec4 nr = texelFetch(source_normal, ofs, 0);
normal.xyz += normalize(nr.xyz * 2.0 - 1.0);
float roughness = normal.w;
if (roughness > 0.5) {
roughness = 1.0 - roughness;
}
roughness /= (127.0 / 255.0);
normal.w += roughness;
if (sc_multiview) {
// we're doing a full unproject so we need the value as is.
depth += d;
} else {
// unproject our Z value so we can use it directly.
d = d * 2.0 - 1.0;
if (params.orthogonal) {
d = ((d + (params.camera_z_far + params.camera_z_near) / (params.camera_z_far - params.camera_z_near)) * (params.camera_z_far - params.camera_z_near)) / 2.0;
} else {
d = 2.0 * params.camera_z_near * params.camera_z_far / (params.camera_z_far + params.camera_z_near - d * (params.camera_z_far - params.camera_z_near));
}
depth += -d;
}
}
color /= 4.0;
depth /= 4.0;
normal.xyz = normalize(normal.xyz / 4.0) * 0.5 + 0.5;
normal.w /= 4.0;
normal.w = normal.w * (127.0 / 255.0);
} else {
ivec2 ofs = ssC << 1;
color = texelFetch(source_ssr, ofs, 0);
depth = texelFetch(source_depth, ofs, 0).r;
normal = texelFetch(source_normal, ofs, 0);
if (!sc_multiview) {
// unproject our Z value so we can use it directly.
depth = depth * 2.0 - 1.0;
if (params.orthogonal) {
depth = -(depth * (params.camera_z_far - params.camera_z_near) - (params.camera_z_far + params.camera_z_near)) / 2.0;
} else {
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));
}
depth = -depth;
}
}
imageStore(dest_ssr, ssC, color);
imageStore(dest_depth, ssC, vec4(depth));
imageStore(dest_normal, ssC, normal);
}
@@ -1597,6 +1597,12 @@ void fragment_shader(in SceneData scene_data) {
float kernelRoughness2 = min(2.0 * variance, scene_data.roughness_limiter_limit); //limit effect
float filteredRoughness2 = min(1.0, roughness2 + kernelRoughness2);
roughness = sqrt(filteredRoughness2);
// Reject very small roughness values. Lack of precision can collapse
// roughness^4 to 0 in GGX specular equations and cause divisions by zero.
if (roughness < 0.00000001) {
roughness = 0.0;
}
}
#endif
//apply energy conservation
@@ -2029,6 +2035,39 @@ void fragment_shader(in SceneData scene_data) {
#endif
}
//process ssr
if (bool(implementation_data.ss_effects_flags & SCREEN_SPACE_EFFECTS_FLAGS_USE_SSR)) {
bool resolve_ssr = bool(implementation_data.ss_effects_flags & SCREEN_SPACE_EFFECTS_FLAGS_RESOLVE_SSR);
float ssr_mip_level = 0.0;
if (resolve_ssr) {
#ifdef USE_MULTIVIEW
ssr_mip_level = textureLod(sampler2DArray(ssr_mip_level_buffer, SAMPLER_NEAREST_CLAMP), vec3(screen_uv, ViewIndex), 0.0).x;
#else
ssr_mip_level = textureLod(sampler2D(ssr_mip_level_buffer, SAMPLER_NEAREST_CLAMP), screen_uv, 0.0).x;
#endif // USE_MULTIVIEW
ssr_mip_level *= 14.0;
}
#ifdef USE_MULTIVIEW
vec4 ssr = textureLod(sampler2DArray(ssr_buffer, SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), vec3(screen_uv, ViewIndex), ssr_mip_level);
#else
vec4 ssr = textureLod(sampler2D(ssr_buffer, SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP), screen_uv, ssr_mip_level);
#endif // USE_MULTIVIEW
if (resolve_ssr) {
const vec3 rec709_luminance_weights = vec3(0.2126, 0.7152, 0.0722);
ssr.rgb /= 1.0 - dot(ssr.rgb, rec709_luminance_weights);
}
// Apply fade when approaching 0.7 roughness to smoothen the harsh cutoff in the main SSR trace pass.
ssr *= smoothstep(0.0, 1.0, 1.0 - clamp((roughness - 0.6) / (0.7 - 0.6), 0.0, 1.0));
// Alpha is premultiplied.
indirect_specular_light = indirect_specular_light * (1.0 - ssr.a) + ssr.rgb;
}
//finalize ambient light here
{
ambient_light *= ao;
@@ -164,8 +164,10 @@ layout(set = 0, binding = 2) uniform sampler shadow_sampler;
//3 bits of stride
#define INSTANCE_FLAGS_PARTICLE_TRAIL_MASK 0xFF
#define SCREEN_SPACE_EFFECTS_FLAGS_USE_SSAO 1
#define SCREEN_SPACE_EFFECTS_FLAGS_USE_SSIL 2
#define SCREEN_SPACE_EFFECTS_FLAGS_USE_SSAO (1 << 0)
#define SCREEN_SPACE_EFFECTS_FLAGS_USE_SSIL (1 << 1)
#define SCREEN_SPACE_EFFECTS_FLAGS_USE_SSR (1 << 2)
#define SCREEN_SPACE_EFFECTS_FLAGS_RESOLVE_SSR (1 << 3)
layout(set = 0, binding = 3, std430) restrict readonly buffer OmniLights {
LightData data[];
@@ -435,8 +437,12 @@ layout(set = 1, binding = 33) uniform texture3D volumetric_fog_texture;
#ifdef USE_MULTIVIEW
layout(set = 1, binding = 34) uniform texture2DArray ssil_buffer;
layout(set = 1, binding = 35) uniform texture2DArray ssr_buffer;
layout(set = 1, binding = 36) uniform texture2DArray ssr_mip_level_buffer;
#else
layout(set = 1, binding = 34) uniform texture2D ssil_buffer;
layout(set = 1, binding = 35) uniform texture2D ssr_buffer;
layout(set = 1, binding = 36) uniform texture2D ssr_mip_level_buffer;
#endif // USE_MULTIVIEW
#endif
+1
View File
@@ -1311,6 +1311,7 @@ public:
PASS1RC(float, environment_get_ssr_fade_out, RID)
PASS1RC(float, environment_get_ssr_depth_tolerance, RID)
PASS1(environment_set_ssr_half_size, bool)
PASS1(environment_set_ssr_roughness_quality, RS::EnvironmentSSRRoughnessQuality)
// SSAO
@@ -202,6 +202,7 @@ public:
float environment_get_ssr_fade_out(RID p_env) const;
float environment_get_ssr_depth_tolerance(RID p_env) const;
virtual void environment_set_ssr_half_size(bool p_half_size) = 0;
virtual void environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) = 0;
// SSAO
+1
View File
@@ -260,6 +260,7 @@ public:
virtual float environment_get_ssr_fade_out(RID p_env) const = 0;
virtual float environment_get_ssr_depth_tolerance(RID p_env) const = 0;
virtual void environment_set_ssr_half_size(bool p_half_size) = 0;
virtual void environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) = 0;
// SSAO
+2 -1
View File
@@ -3053,6 +3053,7 @@ void RenderingServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("environment_set_volumetric_fog", "env", "enable", "density", "albedo", "emission", "emission_energy", "anisotropy", "length", "p_detail_spread", "gi_inject", "temporal_reprojection", "temporal_reprojection_amount", "ambient_inject", "sky_affect"), &RenderingServer::environment_set_volumetric_fog);
ClassDB::bind_method(D_METHOD("environment_glow_set_use_bicubic_upscale", "enable"), &RenderingServer::environment_glow_set_use_bicubic_upscale);
ClassDB::bind_method(D_METHOD("environment_set_ssr_half_size", "half_size"), &RenderingServer::environment_set_ssr_half_size);
ClassDB::bind_method(D_METHOD("environment_set_ssr_roughness_quality", "quality"), &RenderingServer::environment_set_ssr_roughness_quality);
ClassDB::bind_method(D_METHOD("environment_set_ssao_quality", "quality", "half_size", "adaptive_target", "blur_passes", "fadeout_from", "fadeout_to"), &RenderingServer::environment_set_ssao_quality);
ClassDB::bind_method(D_METHOD("environment_set_ssil_quality", "quality", "half_size", "adaptive_target", "blur_passes", "fadeout_from", "fadeout_to"), &RenderingServer::environment_set_ssil_quality);
@@ -3732,7 +3733,7 @@ void RenderingServer::init() {
GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/environment/glow/upscale_mode", PROPERTY_HINT_ENUM, "Linear (Fast),Bicubic (Slow)"), 1);
GLOBAL_DEF("rendering/environment/glow/upscale_mode.mobile", 0);
GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/environment/screen_space_reflection/roughness_quality", PROPERTY_HINT_ENUM, "Disabled (Fastest),Low (Fast),Medium (Average),High (Slow)"), 1);
GLOBAL_DEF("rendering/environment/screen_space_reflection/half_size", true);
GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/environment/subsurface_scattering/subsurface_scattering_quality", PROPERTY_HINT_ENUM, "Disabled (Fastest),Low (Fast),Medium (Average),High (Slow)"), 1);
GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "rendering/environment/subsurface_scattering/subsurface_scattering_scale", PROPERTY_HINT_RANGE, "0.001,1,0.001"), 0.05);
+2
View File
@@ -1287,6 +1287,8 @@ public:
virtual void environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_in, float p_fade_out, float p_depth_tolerance) = 0;
virtual void environment_set_ssr_half_size(bool p_half_size) = 0;
enum EnvironmentSSRRoughnessQuality {
ENV_SSR_ROUGHNESS_QUALITY_DISABLED,
ENV_SSR_ROUGHNESS_QUALITY_LOW,
@@ -817,6 +817,7 @@ public:
FUNC2(environment_set_camera_feed_id, RID, int)
FUNC6(environment_set_ssr, RID, bool, int, float, float, float)
FUNC1(environment_set_ssr_half_size, bool)
FUNC1(environment_set_ssr_roughness_quality, EnvironmentSSRRoughnessQuality)
FUNC10(environment_set_ssao, RID, bool, float, float, float, float, float, float, float, float)
@@ -578,7 +578,7 @@ float RendererEnvironmentStorage::environment_get_ssr_fade_out(RID p_env) const
float RendererEnvironmentStorage::environment_get_ssr_depth_tolerance(RID p_env) const {
Environment *env = environment_owner.get_or_null(p_env);
ERR_FAIL_NULL_V(env, 0.2);
ERR_FAIL_NULL_V(env, 0.5);
return env->ssr_depth_tolerance;
}
@@ -114,7 +114,7 @@ private:
int ssr_max_steps = 64;
float ssr_fade_in = 0.15;
float ssr_fade_out = 2.0;
float ssr_depth_tolerance = 0.2;
float ssr_depth_tolerance = 0.5;
// SSAO
bool ssao_enabled = false;