2023-01-05 13:25:55 +01:00
/**************************************************************************/
/* ss_effects.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
2022-06-28 19:10:36 +10:00
# include "ss_effects.h"
2022-09-29 15:37:10 +10:00
# include "core/config/project_settings.h"
2025-09-16 15:17:49 +03:00
# include "servers/rendering/renderer_rd/effects/copy_effects.h"
2022-06-28 19:10:36 +10:00
# include "servers/rendering/renderer_rd/storage_rd/material_storage.h"
2022-08-04 18:40:39 +10:00
# include "servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h"
2022-06-28 19:10:36 +10:00
# include "servers/rendering/renderer_rd/uniform_set_cache_rd.h"
using namespace RendererRD ;
SSEffects * SSEffects : : singleton = nullptr ;
Implement Vector4, Vector4i, Projection
Implement built-in classes Vector4, Vector4i and Projection.
* Two versions of Vector4 (float and integer).
* A Projection class, which is a 4x4 matrix specialized in projection types.
These types have been requested for a long time, but given they were very corner case they were not added before.
Because in Godot 4, reimplementing parts of the rendering engine is now possible, access to these types (heavily used by the rendering code) becomes a necessity.
**Q**: Why Projection and not Matrix4?
**A**: Godot does not use Matrix2, Matrix3, Matrix4x3, etc. naming convention because, within the engine, these types always have a *purpose*. As such, Godot names them: Transform2D, Transform3D or Basis. In this case, this 4x4 matrix is _always_ used as a _Projection_, hence the naming.
2022-07-20 01:11:13 +02:00
static _FORCE_INLINE_ void store_camera ( const Projection & p_mtx , float * p_array ) {
2022-06-28 19:10:36 +10:00
for ( int i = 0 ; i < 4 ; i + + ) {
for ( int j = 0 ; j < 4 ; j + + ) {
2022-10-04 11:44:48 -05:00
p_array [ i * 4 + j ] = p_mtx . columns [ i ] [ j ] ;
2022-06-28 19:10:36 +10:00
}
}
}
SSEffects : : SSEffects ( ) {
singleton = this ;
2022-09-29 15:37:10 +10:00
// Initialize depth buffer for screen space effects
2022-06-28 19:10:36 +10:00
{
Vector < String > downsampler_modes ;
downsampler_modes . push_back ( " \n " ) ;
downsampler_modes . push_back ( " \n #define USE_HALF_SIZE \n " ) ;
downsampler_modes . push_back ( " \n #define GENERATE_MIPS \n " ) ;
downsampler_modes . push_back ( " \n #define GENERATE_MIPS \n #define USE_HALF_SIZE \n " ) ;
downsampler_modes . push_back ( " \n #define USE_HALF_BUFFERS \n " ) ;
downsampler_modes . push_back ( " \n #define USE_HALF_BUFFERS \n #define USE_HALF_SIZE \n " ) ;
downsampler_modes . push_back ( " \n #define GENERATE_MIPS \n #define GENERATE_FULL_MIPS " ) ;
ss_effects . downsample_shader . initialize ( downsampler_modes ) ;
ss_effects . downsample_shader_version = ss_effects . downsample_shader . version_create ( ) ;
for ( int i = 0 ; i < SS_EFFECTS_MAX ; i + + ) {
2025-10-01 14:42:27 -03:00
ss_effects . pipelines [ i ] . create_compute_pipeline ( ss_effects . downsample_shader . version_get_shader ( ss_effects . downsample_shader_version , i ) ) ;
2022-06-28 19:10:36 +10:00
}
ss_effects . gather_constants_buffer = RD : : get_singleton ( ) - > uniform_buffer_create ( sizeof ( SSEffectsGatherConstants ) ) ;
SSEffectsGatherConstants gather_constants ;
const int sub_pass_count = 5 ;
for ( int pass = 0 ; pass < 4 ; pass + + ) {
for ( int subPass = 0 ; subPass < sub_pass_count ; subPass + + ) {
int a = pass ;
int spmap [ 5 ] { 0 , 1 , 4 , 3 , 2 } ;
2023-06-09 17:00:50 +02:00
int b = spmap [ subPass ] ;
2022-06-28 19:10:36 +10:00
float ca , sa ;
2025-04-10 11:21:05 -05:00
float angle0 = ( float ( a ) + float ( b ) / float ( sub_pass_count ) ) * Math : : PI * 0.5f ;
2022-06-28 19:10:36 +10:00
ca = Math : : cos ( angle0 ) ;
sa = Math : : sin ( angle0 ) ;
float scale = 1.0f + ( a - 1.5f + ( b - ( sub_pass_count - 1.0f ) * 0.5f ) / float ( sub_pass_count ) ) * 0.07f ;
gather_constants . rotation_matrices [ pass * 20 + subPass * 4 + 0 ] = scale * ca ;
gather_constants . rotation_matrices [ pass * 20 + subPass * 4 + 1 ] = scale * - sa ;
gather_constants . rotation_matrices [ pass * 20 + subPass * 4 + 2 ] = - scale * sa ;
gather_constants . rotation_matrices [ pass * 20 + subPass * 4 + 3 ] = - scale * ca ;
}
}
RD : : get_singleton ( ) - > buffer_update ( ss_effects . gather_constants_buffer , 0 , sizeof ( SSEffectsGatherConstants ) , & gather_constants ) ;
}
// Initialize Screen Space Indirect Lighting (SSIL)
2022-09-29 15:37:10 +10:00
ssil_set_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 " ) ) ;
2022-06-28 19:10:36 +10:00
{
Vector < String > ssil_modes ;
ssil_modes . push_back ( " \n " ) ;
ssil_modes . push_back ( " \n #define SSIL_BASE \n " ) ;
ssil_modes . push_back ( " \n #define ADAPTIVE \n " ) ;
ssil . gather_shader . initialize ( ssil_modes ) ;
ssil . gather_shader_version = ssil . gather_shader . version_create ( ) ;
for ( int i = SSIL_GATHER ; i < = SSIL_GATHER_ADAPTIVE ; i + + ) {
2025-10-01 14:42:27 -03:00
ssil . pipelines [ i ] . create_compute_pipeline ( ssil . gather_shader . version_get_shader ( ssil . gather_shader_version , i ) ) ;
2022-06-28 19:10:36 +10:00
}
ssil . projection_uniform_buffer = RD : : get_singleton ( ) - > uniform_buffer_create ( sizeof ( SSILProjectionUniforms ) ) ;
}
{
Vector < String > ssil_modes ;
ssil_modes . push_back ( " \n #define GENERATE_MAP \n " ) ;
ssil_modes . push_back ( " \n #define PROCESS_MAPA \n " ) ;
ssil_modes . push_back ( " \n #define PROCESS_MAPB \n " ) ;
ssil . importance_map_shader . initialize ( ssil_modes ) ;
ssil . importance_map_shader_version = ssil . importance_map_shader . version_create ( ) ;
for ( int i = SSIL_GENERATE_IMPORTANCE_MAP ; i < = SSIL_PROCESS_IMPORTANCE_MAPB ; i + + ) {
2025-10-01 14:42:27 -03:00
ssil . pipelines [ i ] . create_compute_pipeline ( ssil . importance_map_shader . version_get_shader ( ssil . importance_map_shader_version , i - SSIL_GENERATE_IMPORTANCE_MAP ) ) ;
2022-06-28 19:10:36 +10:00
}
ssil . importance_map_load_counter = RD : : get_singleton ( ) - > storage_buffer_create ( sizeof ( uint32_t ) ) ;
int zero [ 1 ] = { 0 } ;
RD : : get_singleton ( ) - > buffer_update ( ssil . importance_map_load_counter , 0 , sizeof ( uint32_t ) , & zero ) ;
RD : : get_singleton ( ) - > set_resource_name ( ssil . importance_map_load_counter , " Importance Map Load Counter " ) ;
Vector < RD : : Uniform > uniforms ;
{
RD : : Uniform u ;
u . uniform_type = RD : : UNIFORM_TYPE_STORAGE_BUFFER ;
u . binding = 0 ;
u . append_id ( ssil . importance_map_load_counter ) ;
uniforms . push_back ( u ) ;
}
ssil . counter_uniform_set = RD : : get_singleton ( ) - > uniform_set_create ( uniforms , ssil . importance_map_shader . version_get_shader ( ssil . importance_map_shader_version , 2 ) , 2 ) ;
RD : : get_singleton ( ) - > set_resource_name ( ssil . counter_uniform_set , " Load Counter Uniform Set " ) ;
}
{
Vector < String > ssil_modes ;
ssil_modes . push_back ( " \n #define MODE_NON_SMART \n " ) ;
ssil_modes . push_back ( " \n #define MODE_SMART \n " ) ;
ssil_modes . push_back ( " \n #define MODE_WIDE \n " ) ;
ssil . blur_shader . initialize ( ssil_modes ) ;
ssil . blur_shader_version = ssil . blur_shader . version_create ( ) ;
for ( int i = SSIL_BLUR_PASS ; i < = SSIL_BLUR_PASS_WIDE ; i + + ) {
2025-10-01 14:42:27 -03:00
ssil . pipelines [ i ] . create_compute_pipeline ( ssil . blur_shader . version_get_shader ( ssil . blur_shader_version , i - SSIL_BLUR_PASS ) ) ;
2022-06-28 19:10:36 +10:00
}
}
{
Vector < String > ssil_modes ;
ssil_modes . push_back ( " \n #define MODE_NON_SMART \n " ) ;
ssil_modes . push_back ( " \n #define MODE_SMART \n " ) ;
ssil_modes . push_back ( " \n #define MODE_HALF \n " ) ;
ssil . interleave_shader . initialize ( ssil_modes ) ;
ssil . interleave_shader_version = ssil . interleave_shader . version_create ( ) ;
for ( int i = SSIL_INTERLEAVE ; i < = SSIL_INTERLEAVE_HALF ; i + + ) {
2025-10-01 14:42:27 -03:00
ssil . pipelines [ i ] . create_compute_pipeline ( ssil . interleave_shader . version_get_shader ( ssil . interleave_shader_version , i - SSIL_INTERLEAVE ) ) ;
2022-06-28 19:10:36 +10:00
}
}
2022-09-29 15:37:10 +10:00
// Initialize Screen Space Ambient Occlusion (SSAO)
ssao_set_quality ( RS : : EnvironmentSSAOQuality ( int ( GLOBAL_GET ( " rendering/environment/ssao/quality " ) ) ) , GLOBAL_GET ( " rendering/environment/ssao/half_size " ) , GLOBAL_GET ( " rendering/environment/ssao/adaptive_target " ) , GLOBAL_GET ( " rendering/environment/ssao/blur_passes " ) , GLOBAL_GET ( " rendering/environment/ssao/fadeout_from " ) , GLOBAL_GET ( " rendering/environment/ssao/fadeout_to " ) ) ;
2022-06-28 19:10:36 +10:00
2022-09-29 15:37:10 +10:00
{
2022-06-28 19:10:36 +10:00
RD : : SamplerState sampler ;
sampler . mag_filter = RD : : SAMPLER_FILTER_NEAREST ;
sampler . min_filter = RD : : SAMPLER_FILTER_NEAREST ;
sampler . mip_filter = RD : : SAMPLER_FILTER_NEAREST ;
sampler . repeat_u = RD : : SAMPLER_REPEAT_MODE_MIRRORED_REPEAT ;
sampler . repeat_v = RD : : SAMPLER_REPEAT_MODE_MIRRORED_REPEAT ;
sampler . repeat_w = RD : : SAMPLER_REPEAT_MODE_MIRRORED_REPEAT ;
sampler . max_lod = 4 ;
uint32_t pipeline = 0 ;
{
Vector < String > ssao_modes ;
ssao_modes . push_back ( " \n " ) ;
ssao_modes . push_back ( " \n #define SSAO_BASE \n " ) ;
ssao_modes . push_back ( " \n #define ADAPTIVE \n " ) ;
ssao . gather_shader . initialize ( ssao_modes ) ;
ssao . gather_shader_version = ssao . gather_shader . version_create ( ) ;
for ( int i = 0 ; i < = SSAO_GATHER_ADAPTIVE ; i + + ) {
2025-10-01 14:42:27 -03:00
ssao . pipelines [ pipeline ] . create_compute_pipeline ( ssao . gather_shader . version_get_shader ( ssao . gather_shader_version , i ) ) ;
2022-06-28 19:10:36 +10:00
pipeline + + ;
}
}
{
Vector < String > ssao_modes ;
ssao_modes . push_back ( " \n #define GENERATE_MAP \n " ) ;
ssao_modes . push_back ( " \n #define PROCESS_MAPA \n " ) ;
ssao_modes . push_back ( " \n #define PROCESS_MAPB \n " ) ;
ssao . importance_map_shader . initialize ( ssao_modes ) ;
ssao . importance_map_shader_version = ssao . importance_map_shader . version_create ( ) ;
for ( int i = SSAO_GENERATE_IMPORTANCE_MAP ; i < = SSAO_PROCESS_IMPORTANCE_MAPB ; i + + ) {
2025-10-01 14:42:27 -03:00
ssao . pipelines [ pipeline ] . create_compute_pipeline ( ssao . importance_map_shader . version_get_shader ( ssao . importance_map_shader_version , i - SSAO_GENERATE_IMPORTANCE_MAP ) ) ;
2022-06-28 19:10:36 +10:00
pipeline + + ;
}
ssao . importance_map_load_counter = RD : : get_singleton ( ) - > storage_buffer_create ( sizeof ( uint32_t ) ) ;
int zero [ 1 ] = { 0 } ;
RD : : get_singleton ( ) - > buffer_update ( ssao . importance_map_load_counter , 0 , sizeof ( uint32_t ) , & zero ) ;
RD : : get_singleton ( ) - > set_resource_name ( ssao . importance_map_load_counter , " Importance Map Load Counter " ) ;
Vector < RD : : Uniform > uniforms ;
{
RD : : Uniform u ;
u . uniform_type = RD : : UNIFORM_TYPE_STORAGE_BUFFER ;
u . binding = 0 ;
u . append_id ( ssao . importance_map_load_counter ) ;
uniforms . push_back ( u ) ;
}
ssao . counter_uniform_set = RD : : get_singleton ( ) - > uniform_set_create ( uniforms , ssao . importance_map_shader . version_get_shader ( ssao . importance_map_shader_version , 2 ) , 2 ) ;
RD : : get_singleton ( ) - > set_resource_name ( ssao . counter_uniform_set , " Load Counter Uniform Set " ) ;
}
{
Vector < String > ssao_modes ;
ssao_modes . push_back ( " \n #define MODE_NON_SMART \n " ) ;
ssao_modes . push_back ( " \n #define MODE_SMART \n " ) ;
ssao_modes . push_back ( " \n #define MODE_WIDE \n " ) ;
ssao . blur_shader . initialize ( ssao_modes ) ;
ssao . blur_shader_version = ssao . blur_shader . version_create ( ) ;
for ( int i = SSAO_BLUR_PASS ; i < = SSAO_BLUR_PASS_WIDE ; i + + ) {
2025-10-01 14:42:27 -03:00
ssao . pipelines [ pipeline ] . create_compute_pipeline ( ssao . blur_shader . version_get_shader ( ssao . blur_shader_version , i - SSAO_BLUR_PASS ) ) ;
2022-06-28 19:10:36 +10:00
pipeline + + ;
}
}
{
Vector < String > ssao_modes ;
ssao_modes . push_back ( " \n #define MODE_NON_SMART \n " ) ;
ssao_modes . push_back ( " \n #define MODE_SMART \n " ) ;
ssao_modes . push_back ( " \n #define MODE_HALF \n " ) ;
ssao . interleave_shader . initialize ( ssao_modes ) ;
ssao . interleave_shader_version = ssao . interleave_shader . version_create ( ) ;
for ( int i = SSAO_INTERLEAVE ; i < = SSAO_INTERLEAVE_HALF ; i + + ) {
2025-10-01 14:42:27 -03:00
ssao . pipelines [ pipeline ] . create_compute_pipeline ( ssao . interleave_shader . version_get_shader ( ssao . interleave_shader_version , i - SSAO_INTERLEAVE ) ) ;
2022-06-28 19:10:36 +10:00
pipeline + + ;
}
}
ERR_FAIL_COND ( pipeline ! = SSAO_MAX ) ;
ss_effects . mirror_sampler = RD : : get_singleton ( ) - > sampler_create ( sampler ) ;
}
2022-09-29 15:37:10 +10:00
// Screen Space Reflections
2025-09-16 15:17:49 +03:00
ssr_half_size = GLOBAL_GET ( " rendering/environment/screen_space_reflection/half_size " ) ;
2022-06-28 19:10:36 +10:00
2022-09-29 15:37:10 +10:00
{
2022-06-28 19:10:36 +10:00
{
2025-09-16 15:17:49 +03:00
Vector < String > ssr_downsample_modes ;
ssr_downsample_modes . push_back ( " \n " ) ; // SCREEN_SPACE_REFLECTION_DOWNSAMPLE_DEFAULT
ssr_downsample_modes . push_back ( " \n #define MODE_ODD_WIDTH \n " ) ; // SCREEN_SPACE_REFLECTION_DOWNSAMPLE_ODD_WIDTH
ssr_downsample_modes . push_back ( " \n #define MODE_ODD_HEIGHT \n " ) ; // SCREEN_SPACE_REFLECTION_DOWNSAMPLE_ODD_HEIGHT
ssr_downsample_modes . push_back ( " \n #define MODE_ODD_WIDTH \n #define MODE_ODD_HEIGHT \n " ) ; // SCREEN_SPACE_REFLECTION_DOWNSAMPLE_ODD_WIDTH_AND_HEIGHT
ssr . downsample_shader . initialize ( ssr_downsample_modes ) ;
ssr . downsample_shader_version = ssr . downsample_shader . version_create ( ) ;
for ( uint32_t i = 0 ; i < SCREEN_SPACE_REFLECTION_DOWNSAMPLE_MAX ; i + + ) {
ssr . downsample_pipelines [ i ] . create_compute_pipeline ( ssr . downsample_shader . version_get_shader ( ssr . downsample_shader_version , i ) ) ;
}
2022-06-28 19:10:36 +10:00
}
{
2025-09-16 15:17:49 +03:00
Vector < String > ssr_hiz_modes ;
ssr_hiz_modes . push_back ( " \n " ) ; // SCREEN_SPACE_REFLECTION_HIZ_DEFAULT
ssr_hiz_modes . push_back ( " \n #define MODE_ODD_WIDTH \n " ) ; // SCREEN_SPACE_REFLECTION_HIZ_ODD_WIDTH
ssr_hiz_modes . push_back ( " \n #define MODE_ODD_HEIGHT \n " ) ; // SCREEN_SPACE_REFLECTION_HIZ_ODD_HEIGHT
ssr_hiz_modes . push_back ( " \n #define MODE_ODD_WIDTH \n #define MODE_ODD_HEIGHT \n " ) ; // SCREEN_SPACE_REFLECTION_HIZ_ODD_WIDTH_AND_HEIGHT
2022-06-28 19:10:36 +10:00
2025-09-16 15:17:49 +03:00
ssr . hiz_shader . initialize ( ssr_hiz_modes ) ;
ssr . hiz_shader_version = ssr . hiz_shader . version_create ( ) ;
2022-06-28 19:10:36 +10:00
2025-09-16 15:17:49 +03:00
for ( uint32_t i = 0 ; i < SCREEN_SPACE_REFLECTION_HIZ_MAX ; i + + ) {
ssr . hiz_pipelines [ i ] . create_compute_pipeline ( ssr . hiz_shader . version_get_shader ( ssr . hiz_shader_version , i ) ) ;
2022-06-28 19:10:36 +10:00
}
}
{
Vector < String > ssr_modes ;
2025-09-16 15:17:49 +03:00
ssr_modes . push_back ( " \n " ) ;
2022-06-28 19:10:36 +10:00
2025-09-16 15:17:49 +03:00
ssr . ssr_shader . initialize ( ssr_modes ) ;
ssr . ssr_shader_version = ssr . ssr_shader . version_create ( ) ;
2022-06-28 19:10:36 +10:00
2025-09-16 15:17:49 +03:00
ssr . ssr_pipeline . create_compute_pipeline ( ssr . ssr_shader . version_get_shader ( ssr . ssr_shader_version , 0 ) ) ;
2022-06-28 19:10:36 +10:00
}
{
Vector < String > ssr_filter_modes ;
2025-09-16 15:17:49 +03:00
ssr_filter_modes . push_back ( " \n " ) ;
2022-06-28 19:10:36 +10:00
2025-09-16 15:17:49 +03:00
ssr . filter_shader . initialize ( ssr_filter_modes ) ;
ssr . filter_shader_version = ssr . filter_shader . version_create ( ) ;
2022-06-28 19:10:36 +10:00
2025-09-16 15:17:49 +03:00
ssr . filter_pipeline . create_compute_pipeline ( ssr . filter_shader . version_get_shader ( ssr . filter_shader_version , 0 ) ) ;
}
{
Vector < String > ssr_resolve_modes ;
ssr_resolve_modes . push_back ( " \n " ) ;
ssr . resolve_shader . initialize ( ssr_resolve_modes ) ;
ssr . resolve_shader_version = ssr . resolve_shader . version_create ( ) ;
ssr . resolve_pipeline . create_compute_pipeline ( ssr . resolve_shader . version_get_shader ( ssr . resolve_shader_version , 0 ) ) ;
2022-06-28 19:10:36 +10:00
}
}
2022-08-04 18:40:39 +10:00
// Subsurface scattering
2022-09-29 15:37:10 +10:00
sss_quality = RS : : SubSurfaceScatteringQuality ( int ( GLOBAL_GET ( " rendering/environment/subsurface_scattering/subsurface_scattering_quality " ) ) ) ;
sss_scale = GLOBAL_GET ( " rendering/environment/subsurface_scattering/subsurface_scattering_scale " ) ;
sss_depth_scale = GLOBAL_GET ( " rendering/environment/subsurface_scattering/subsurface_scattering_depth_scale " ) ;
2022-08-04 18:40:39 +10:00
{
Vector < String > sss_modes ;
sss_modes . push_back ( " \n #define USE_11_SAMPLES \n " ) ;
sss_modes . push_back ( " \n #define USE_17_SAMPLES \n " ) ;
sss_modes . push_back ( " \n #define USE_25_SAMPLES \n " ) ;
sss . shader . initialize ( sss_modes ) ;
sss . shader_version = sss . shader . version_create ( ) ;
2025-10-01 14:42:27 -03:00
for ( int i = 0 ; i < SUBSURFACE_SCATTERING_MODE_MAX ; i + + ) {
sss . pipelines [ i ] . create_compute_pipeline ( sss . shader . version_get_shader ( sss . shader_version , i ) ) ;
2022-08-04 18:40:39 +10:00
}
}
2022-06-28 19:10:36 +10:00
}
2025-09-16 15:17:49 +03:00
void SSEffects : : allocate_last_frame_buffer ( Ref < RenderSceneBuffersRD > p_render_buffers , bool p_use_ssil , bool p_use_ssr ) {
Size2i last_frame_size = p_render_buffers - > get_internal_size ( ) ;
uint32_t mipmaps = 1 ;
uint32_t view_count = p_render_buffers - > get_view_count ( ) ;
if ( ! p_use_ssil & & p_use_ssr & & ssr_half_size ) {
last_frame_size / = 2 ;
}
if ( p_use_ssil ) {
mipmaps = 6 ;
}
bool should_create = true ;
bool has_texture = p_render_buffers - > has_texture ( RB_SCOPE_SSLF , RB_LAST_FRAME ) ;
if ( has_texture ) {
RID last_frame_texture = p_render_buffers - > get_texture ( RB_SCOPE_SSLF , RB_LAST_FRAME ) ;
RD : : TextureFormat texture_format = RD : : get_singleton ( ) - > texture_get_format ( last_frame_texture ) ;
should_create = texture_format . width ! = ( uint32_t ) last_frame_size . width | | texture_format . height ! = ( uint32_t ) last_frame_size . height | | texture_format . mipmaps ! = mipmaps | | texture_format . array_layers ! = view_count ;
}
if ( should_create ) {
if ( has_texture ) {
p_render_buffers - > clear_context ( RB_SCOPE_SSLF ) ;
}
RID last_frame_texture = p_render_buffers - > create_texture ( RB_SCOPE_SSLF , RB_LAST_FRAME , RD : : DATA_FORMAT_R16G16B16A16_SFLOAT , RD : : TEXTURE_USAGE_SAMPLING_BIT | RD : : TEXTURE_USAGE_STORAGE_BIT | RD : : TEXTURE_USAGE_CAN_COPY_TO_BIT , RD : : TEXTURE_SAMPLES_1 , last_frame_size , view_count , mipmaps ) ;
RD : : get_singleton ( ) - > texture_clear ( last_frame_texture , Color ( 0 , 0 , 0 , 0 ) , 0 , mipmaps , 0 , view_count ) ;
}
}
void SSEffects : : copy_internal_texture_to_last_frame ( Ref < RenderSceneBuffersRD > p_render_buffers , CopyEffects & p_copy_effects ) {
uint32_t mipmaps = p_render_buffers - > get_texture_format ( RB_SCOPE_SSLF , RB_LAST_FRAME ) . mipmaps ;
for ( uint32_t v = 0 ; v < p_render_buffers - > get_view_count ( ) ; v + + ) {
for ( uint32_t m = 0 ; m < mipmaps ; m + + ) {
RID source ;
if ( m = = 0 ) {
source = p_render_buffers - > get_internal_texture ( v ) ;
} else {
source = p_render_buffers - > get_texture_slice ( RB_SCOPE_SSLF , RB_LAST_FRAME , v , m - 1 ) ;
}
RID dest = p_render_buffers - > get_texture_slice ( RB_SCOPE_SSLF , RB_LAST_FRAME , v , m ) ;
Size2i source_size = RD : : get_singleton ( ) - > texture_size ( source ) ;
Size2i dest_size = RD : : get_singleton ( ) - > texture_size ( dest ) ;
if ( m = = 0 & & source_size = = dest_size ) {
p_copy_effects . copy_to_rect ( source , dest , Rect2i ( Vector2i ( ) , source_size ) ) ;
} else {
p_copy_effects . make_mipmap ( source , dest , dest_size ) ;
}
}
}
}
2022-06-28 19:10:36 +10:00
SSEffects : : ~ SSEffects ( ) {
{
// Cleanup SS Reflections
2025-09-16 15:17:49 +03:00
for ( int i = 0 ; i < SCREEN_SPACE_REFLECTION_DOWNSAMPLE_MAX ; i + + ) {
ssr . downsample_pipelines [ i ] . free ( ) ;
}
for ( int i = 0 ; i < SCREEN_SPACE_REFLECTION_HIZ_MAX ; i + + ) {
ssr . hiz_pipelines [ i ] . free ( ) ;
2025-10-01 14:42:27 -03:00
}
2025-09-16 15:17:49 +03:00
ssr . ssr_pipeline . free ( ) ;
ssr . filter_pipeline . free ( ) ;
ssr . resolve_pipeline . free ( ) ;
2025-10-01 14:42:27 -03:00
2025-09-16 15:17:49 +03:00
ssr . downsample_shader . version_free ( ssr . downsample_shader_version ) ;
ssr . hiz_shader . version_free ( ssr . hiz_shader_version ) ;
ssr . ssr_shader . version_free ( ssr . ssr_shader_version ) ;
ssr . filter_shader . version_free ( ssr . filter_shader_version ) ;
ssr . resolve_shader . version_free ( ssr . resolve_shader_version ) ;
2022-06-28 19:10:36 +10:00
if ( ssr . ubo . is_valid ( ) ) {
2025-06-05 00:49:35 -07:00
RD : : get_singleton ( ) - > free_rid ( ssr . ubo ) ;
2022-06-28 19:10:36 +10:00
}
}
{
// Cleanup SS downsampler
2025-10-01 14:42:27 -03:00
for ( int i = 0 ; i < SS_EFFECTS_MAX ; i + + ) {
ss_effects . pipelines [ i ] . free ( ) ;
}
2022-06-28 19:10:36 +10:00
ss_effects . downsample_shader . version_free ( ss_effects . downsample_shader_version ) ;
2025-06-05 00:49:35 -07:00
RD : : get_singleton ( ) - > free_rid ( ss_effects . mirror_sampler ) ;
RD : : get_singleton ( ) - > free_rid ( ss_effects . gather_constants_buffer ) ;
2022-06-28 19:10:36 +10:00
}
{
// Cleanup SSIL
2025-10-01 14:42:27 -03:00
for ( int i = 0 ; i < SSIL_MAX ; i + + ) {
ssil . pipelines [ i ] . free ( ) ;
}
2022-06-28 19:10:36 +10:00
ssil . blur_shader . version_free ( ssil . blur_shader_version ) ;
ssil . gather_shader . version_free ( ssil . gather_shader_version ) ;
ssil . interleave_shader . version_free ( ssil . interleave_shader_version ) ;
ssil . importance_map_shader . version_free ( ssil . importance_map_shader_version ) ;
2025-06-05 00:49:35 -07:00
RD : : get_singleton ( ) - > free_rid ( ssil . importance_map_load_counter ) ;
RD : : get_singleton ( ) - > free_rid ( ssil . projection_uniform_buffer ) ;
2022-06-28 19:10:36 +10:00
}
{
// Cleanup SSAO
2025-10-01 14:42:27 -03:00
for ( int i = 0 ; i < SSAO_MAX ; i + + ) {
ssao . pipelines [ i ] . free ( ) ;
}
2022-06-28 19:10:36 +10:00
ssao . blur_shader . version_free ( ssao . blur_shader_version ) ;
ssao . gather_shader . version_free ( ssao . gather_shader_version ) ;
ssao . interleave_shader . version_free ( ssao . interleave_shader_version ) ;
ssao . importance_map_shader . version_free ( ssao . importance_map_shader_version ) ;
2025-06-05 00:49:35 -07:00
RD : : get_singleton ( ) - > free_rid ( ssao . importance_map_load_counter ) ;
2022-06-28 19:10:36 +10:00
}
2022-08-04 18:40:39 +10:00
{
// Cleanup Subsurface scattering
2025-10-01 14:42:27 -03:00
for ( int i = 0 ; i < SUBSURFACE_SCATTERING_MODE_MAX ; i + + ) {
sss . pipelines [ i ] . free ( ) ;
}
2022-08-04 18:40:39 +10:00
sss . shader . version_free ( sss . shader_version ) ;
}
2022-06-28 19:10:36 +10:00
singleton = nullptr ;
}
/* SS Downsampler */
2023-02-08 01:30:03 +11:00
void SSEffects : : downsample_depth ( Ref < RenderSceneBuffersRD > p_render_buffers , uint32_t p_view , const Projection & p_projection ) {
2022-06-28 19:10:36 +10:00
UniformSetCacheRD * uniform_set_cache = UniformSetCacheRD : : get_singleton ( ) ;
ERR_FAIL_NULL ( uniform_set_cache ) ;
MaterialStorage * material_storage = MaterialStorage : : get_singleton ( ) ;
ERR_FAIL_NULL ( material_storage ) ;
2023-02-08 01:30:03 +11:00
uint32_t view_count = p_render_buffers - > get_view_count ( ) ;
Size2i full_screen_size = p_render_buffers - > get_internal_size ( ) ;
Size2i size ( ( full_screen_size . x + 1 ) / 2 , ( full_screen_size . y + 1 ) / 2 ) ;
// Make sure our buffers exist, buffers are automatically cleared if view count or size changes.
if ( ! p_render_buffers - > has_texture ( RB_SCOPE_SSDS , RB_LINEAR_DEPTH ) ) {
p_render_buffers - > create_texture ( RB_SCOPE_SSDS , RB_LINEAR_DEPTH , RD : : DATA_FORMAT_R16_SFLOAT , RD : : TEXTURE_USAGE_SAMPLING_BIT | RD : : TEXTURE_USAGE_STORAGE_BIT , RD : : TEXTURE_SAMPLES_1 , size , view_count * 4 , 5 ) ;
}
2022-06-28 19:10:36 +10:00
// Downsample and deinterleave the depth buffer for SSAO and SSIL
RD : : ComputeListID compute_list = RD : : get_singleton ( ) - > compute_list_begin ( ) ;
int downsample_mode = SS_EFFECTS_DOWNSAMPLE ;
2022-09-29 15:37:10 +10:00
bool use_mips = ssao_quality > RS : : ENV_SSAO_QUALITY_MEDIUM | | ssil_quality > RS : : ENV_SSIL_QUALITY_MEDIUM ;
2022-06-28 19:10:36 +10:00
2022-09-29 15:37:10 +10:00
if ( ssao_quality = = RS : : ENV_SSAO_QUALITY_VERY_LOW & & ssil_quality = = RS : : ENV_SSIL_QUALITY_VERY_LOW ) {
2022-06-28 19:10:36 +10:00
downsample_mode = SS_EFFECTS_DOWNSAMPLE_HALF ;
} else if ( use_mips ) {
downsample_mode = SS_EFFECTS_DOWNSAMPLE_MIPMAP ;
}
bool use_half_size = false ;
bool use_full_mips = false ;
2022-09-29 15:37:10 +10:00
if ( ssao_half_size & & ssil_half_size ) {
2022-06-28 19:10:36 +10:00
downsample_mode + + ;
use_half_size = true ;
2022-09-29 15:37:10 +10:00
} else if ( ssao_half_size ! = ssil_half_size ) {
2022-06-28 19:10:36 +10:00
if ( use_mips ) {
downsample_mode = SS_EFFECTS_DOWNSAMPLE_FULL_MIPS ;
use_full_mips = true ;
} else {
// Only need the first two mipmaps, but the cost to generate the next two is trivial
// TODO investigate the benefit of a shader version to generate only 2 mips
downsample_mode = SS_EFFECTS_DOWNSAMPLE_MIPMAP ;
use_mips = true ;
}
}
2023-02-08 01:30:03 +11:00
RID shader = ss_effects . downsample_shader . version_get_shader ( ss_effects . downsample_shader_version , downsample_mode ) ;
2022-06-28 19:10:36 +10:00
int depth_index = use_half_size ? 1 : 0 ;
RD : : get_singleton ( ) - > draw_command_begin_label ( " Downsample Depth " ) ;
2022-09-13 17:49:32 +10:00
2023-02-08 01:30:03 +11:00
RID downsample_uniform_set ;
if ( use_mips ) {
// Grab our downsample uniform set from cache, these are automatically cleaned up if the depth textures are cleared.
// This also ensures we can switch between left eye and right eye uniform sets without recreating the uniform twice a frame.
2024-07-14 22:13:57 +01:00
thread_local LocalVector < RD : : Uniform > u_depths ;
u_depths . clear ( ) ;
2023-02-08 01:30:03 +11:00
// Note, use_full_mips is true if either SSAO or SSIL uses half size, but the other full size and we're using mips.
// That means we're filling all 5 levels.
// In this scenario `depth_index` will be 0.
for ( int i = 0 ; i < ( use_full_mips ? 4 : 3 ) ; i + + ) {
RID depth_mipmap = p_render_buffers - > get_texture_slice ( RB_SCOPE_SSDS , RB_LINEAR_DEPTH , p_view * 4 , depth_index + i + 1 , 4 , 1 ) ;
RD : : Uniform u_depth ;
u_depth . uniform_type = RD : : UNIFORM_TYPE_IMAGE ;
u_depth . binding = i ;
u_depth . append_id ( depth_mipmap ) ;
u_depths . push_back ( u_depth ) ;
2022-06-28 19:10:36 +10:00
}
2023-02-08 01:30:03 +11:00
// This before only used SS_EFFECTS_DOWNSAMPLE_MIPMAP or SS_EFFECTS_DOWNSAMPLE_FULL_MIPS
downsample_uniform_set = uniform_set_cache - > get_cache_vec ( shader , 2 , u_depths ) ;
2022-06-28 19:10:36 +10:00
}
2024-02-14 21:39:39 +08:00
Projection correction ;
correction . set_depth_correction ( false ) ;
Projection temp = correction * p_projection ;
float depth_linearize_mul = - temp . columns [ 3 ] [ 2 ] ;
float depth_linearize_add = temp . columns [ 2 ] [ 2 ] ;
2022-06-28 19:10:36 +10:00
if ( depth_linearize_mul * depth_linearize_add < 0 ) {
depth_linearize_add = - depth_linearize_add ;
}
ss_effects . downsample_push_constant . orthogonal = p_projection . is_orthogonal ( ) ;
ss_effects . downsample_push_constant . z_near = depth_linearize_mul ;
ss_effects . downsample_push_constant . z_far = depth_linearize_add ;
if ( ss_effects . downsample_push_constant . orthogonal ) {
ss_effects . downsample_push_constant . z_near = p_projection . get_z_near ( ) ;
ss_effects . downsample_push_constant . z_far = p_projection . get_z_far ( ) ;
}
2023-02-08 01:30:03 +11:00
ss_effects . downsample_push_constant . pixel_size [ 0 ] = 1.0 / full_screen_size . x ;
ss_effects . downsample_push_constant . pixel_size [ 1 ] = 1.0 / full_screen_size . y ;
2022-06-28 19:10:36 +10:00
ss_effects . downsample_push_constant . radius_sq = 1.0 ;
RID default_sampler = material_storage - > sampler_rd_get_default ( RS : : CANVAS_ITEM_TEXTURE_FILTER_LINEAR , RS : : CANVAS_ITEM_TEXTURE_REPEAT_DISABLED ) ;
2023-02-08 01:30:03 +11:00
RID depth_texture = p_render_buffers - > get_depth_texture ( p_view ) ;
RID depth_mipmap = p_render_buffers - > get_texture_slice ( RB_SCOPE_SSDS , RB_LINEAR_DEPTH , p_view * 4 , depth_index , 4 , 1 ) ;
RD : : Uniform u_depth_buffer ( RD : : UNIFORM_TYPE_SAMPLER_WITH_TEXTURE , 0 , Vector < RID > ( { default_sampler , depth_texture } ) ) ;
RD : : Uniform u_depth_mipmap ( RD : : UNIFORM_TYPE_IMAGE , 0 , Vector < RID > ( { depth_mipmap } ) ) ;
2022-06-28 19:10:36 +10:00
2025-10-01 14:42:27 -03:00
RD : : get_singleton ( ) - > compute_list_bind_compute_pipeline ( compute_list , ss_effects . pipelines [ downsample_mode ] . get_rid ( ) ) ;
2022-06-28 19:10:36 +10:00
RD : : get_singleton ( ) - > compute_list_bind_uniform_set ( compute_list , uniform_set_cache - > get_cache ( shader , 0 , u_depth_buffer ) , 0 ) ;
2023-02-08 01:30:03 +11:00
RD : : get_singleton ( ) - > compute_list_bind_uniform_set ( compute_list , uniform_set_cache - > get_cache ( shader , 1 , u_depth_mipmap ) , 1 ) ;
2022-06-28 19:10:36 +10:00
if ( use_mips ) {
2023-02-08 01:30:03 +11:00
RD : : get_singleton ( ) - > compute_list_bind_uniform_set ( compute_list , downsample_uniform_set , 2 ) ;
2022-06-28 19:10:36 +10:00
}
RD : : get_singleton ( ) - > compute_list_set_push_constant ( compute_list , & ss_effects . downsample_push_constant , sizeof ( SSEffectsDownsamplePushConstant ) ) ;
2023-02-08 01:30:03 +11:00
if ( use_half_size ) {
2024-03-03 14:37:52 +01:00
size = Size2i ( size . x > > 1 , size . y > > 1 ) . maxi ( 1 ) ;
2023-02-08 01:30:03 +11:00
}
2022-06-28 19:10:36 +10:00
RD : : get_singleton ( ) - > compute_list_dispatch_threads ( compute_list , size . x , size . y , 1 ) ;
RD : : get_singleton ( ) - > compute_list_add_barrier ( compute_list ) ;
RD : : get_singleton ( ) - > draw_command_end_label ( ) ;
2023-11-24 08:23:22 -03:00
RD : : get_singleton ( ) - > compute_list_end ( ) ;
2022-06-28 19:10:36 +10:00
ss_effects . used_full_mips_last_frame = use_full_mips ;
ss_effects . used_half_size_last_frame = use_half_size ;
2022-09-13 17:49:32 +10:00
ss_effects . used_mips_last_frame = use_mips ;
2022-06-28 19:10:36 +10:00
}
/* SSIL */
2022-09-29 15:37:10 +10:00
void SSEffects : : ssil_set_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 ) {
ssil_quality = p_quality ;
ssil_half_size = p_half_size ;
ssil_adaptive_target = p_adaptive_target ;
ssil_blur_passes = p_blur_passes ;
ssil_fadeout_from = p_fadeout_from ;
ssil_fadeout_to = p_fadeout_to ;
}
2023-02-08 01:30:03 +11:00
void SSEffects : : gather_ssil ( RD : : ComputeListID p_compute_list , const RID * p_ssil_slices , const RID * p_edges_slices , const SSILSettings & p_settings , bool p_adaptive_base_pass , RID p_gather_uniform_set , RID p_importance_map_uniform_set , RID p_projection_uniform_set ) {
2022-06-28 19:10:36 +10:00
UniformSetCacheRD * uniform_set_cache = UniformSetCacheRD : : get_singleton ( ) ;
ERR_FAIL_NULL ( uniform_set_cache ) ;
RD : : get_singleton ( ) - > compute_list_bind_uniform_set ( p_compute_list , p_gather_uniform_set , 0 ) ;
2022-09-29 15:37:10 +10:00
if ( ( ssil_quality = = RS : : ENV_SSIL_QUALITY_ULTRA ) & & ! p_adaptive_base_pass ) {
2022-06-28 19:10:36 +10:00
RD : : get_singleton ( ) - > compute_list_bind_uniform_set ( p_compute_list , p_importance_map_uniform_set , 1 ) ;
}
RD : : get_singleton ( ) - > compute_list_bind_uniform_set ( p_compute_list , p_projection_uniform_set , 3 ) ;
RID shader = ssil . gather_shader . version_get_shader ( ssil . gather_shader_version , 0 ) ;
for ( int i = 0 ; i < 4 ; i + + ) {
2022-09-29 15:37:10 +10:00
if ( ( ssil_quality = = RS : : ENV_SSIL_QUALITY_VERY_LOW ) & & ( ( i = = 1 ) | | ( i = = 2 ) ) ) {
2022-06-28 19:10:36 +10:00
continue ;
}
RD : : Uniform u_ssil_slice ( RD : : UNIFORM_TYPE_IMAGE , 0 , Vector < RID > ( { p_ssil_slices [ i ] } ) ) ;
RD : : Uniform u_edges_slice ( RD : : UNIFORM_TYPE_IMAGE , 1 , Vector < RID > ( { p_edges_slices [ i ] } ) ) ;
ssil . gather_push_constant . pass_coord_offset [ 0 ] = i % 2 ;
ssil . gather_push_constant . pass_coord_offset [ 1 ] = i / 2 ;
ssil . gather_push_constant . pass_uv_offset [ 0 ] = ( ( i % 2 ) - 0.0 ) / p_settings . full_screen_size . x ;
ssil . gather_push_constant . pass_uv_offset [ 1 ] = ( ( i / 2 ) - 0.0 ) / p_settings . full_screen_size . y ;
ssil . gather_push_constant . pass = i ;
RD : : get_singleton ( ) - > compute_list_bind_uniform_set ( p_compute_list , uniform_set_cache - > get_cache ( shader , 2 , u_ssil_slice , u_edges_slice ) , 2 ) ;
RD : : get_singleton ( ) - > compute_list_set_push_constant ( p_compute_list , & ssil . gather_push_constant , sizeof ( SSILGatherPushConstant ) ) ;
2023-02-24 13:50:13 +11:00
Size2i size ;
// Calculate size same way as we created the buffer
if ( ssil_half_size ) {
size . x = ( p_settings . full_screen_size . x + 3 ) / 4 ;
size . y = ( p_settings . full_screen_size . y + 3 ) / 4 ;
} else {
size . x = ( p_settings . full_screen_size . x + 1 ) / 2 ;
size . y = ( p_settings . full_screen_size . y + 1 ) / 2 ;
}
2022-06-28 19:10:36 +10:00
RD : : get_singleton ( ) - > compute_list_dispatch_threads ( p_compute_list , size . x , size . y , 1 ) ;
}
RD : : get_singleton ( ) - > compute_list_add_barrier ( p_compute_list ) ;
}
2023-02-08 01:30:03 +11:00
void SSEffects : : ssil_allocate_buffers ( Ref < RenderSceneBuffersRD > p_render_buffers , SSILRenderBuffers & p_ssil_buffers , const SSILSettings & p_settings ) {
2022-09-29 15:37:10 +10:00
if ( p_ssil_buffers . half_size ! = ssil_half_size ) {
2023-02-08 01:30:03 +11:00
p_render_buffers - > clear_context ( RB_SCOPE_SSIL ) ;
2022-06-28 19:10:36 +10:00
}
2023-02-08 01:30:03 +11:00
p_ssil_buffers . half_size = ssil_half_size ;
if ( p_ssil_buffers . half_size ) {
2022-06-28 19:10:36 +10:00
p_ssil_buffers . buffer_width = ( p_settings . full_screen_size . x + 3 ) / 4 ;
p_ssil_buffers . buffer_height = ( p_settings . full_screen_size . y + 3 ) / 4 ;
p_ssil_buffers . half_buffer_width = ( p_settings . full_screen_size . x + 7 ) / 8 ;
p_ssil_buffers . half_buffer_height = ( p_settings . full_screen_size . y + 7 ) / 8 ;
} else {
p_ssil_buffers . buffer_width = ( p_settings . full_screen_size . x + 1 ) / 2 ;
p_ssil_buffers . buffer_height = ( p_settings . full_screen_size . y + 1 ) / 2 ;
p_ssil_buffers . half_buffer_width = ( p_settings . full_screen_size . x + 3 ) / 4 ;
p_ssil_buffers . half_buffer_height = ( p_settings . full_screen_size . y + 3 ) / 4 ;
}
2023-02-08 01:30:03 +11:00
uint32_t view_count = p_render_buffers - > get_view_count ( ) ;
Size2i full_size = Size2i ( p_ssil_buffers . buffer_width , p_ssil_buffers . buffer_height ) ;
Size2i half_size = Size2i ( p_ssil_buffers . half_buffer_width , p_ssil_buffers . half_buffer_height ) ;
2022-06-28 19:10:36 +10:00
2023-02-08 01:30:03 +11:00
// We create our intermediate and final results as render buffers.
// These are automatically cached and cleaned up when our viewport resizes
// or when our viewport gets destroyed.
2022-06-28 19:10:36 +10:00
2023-02-08 01:30:03 +11:00
if ( ! p_render_buffers - > has_texture ( RB_SCOPE_SSIL , RB_FINAL ) ) { // We don't strictly have to check if it exists but we only want to clear it when we create it...
RID final = p_render_buffers - > create_texture ( RB_SCOPE_SSIL , RB_FINAL , RD : : DATA_FORMAT_R16G16B16A16_SFLOAT , RD : : TEXTURE_USAGE_SAMPLING_BIT | RD : : TEXTURE_USAGE_STORAGE_BIT | RD : : TEXTURE_USAGE_CAN_COPY_TO_BIT ) ;
RD : : get_singleton ( ) - > texture_clear ( final , Color ( 0 , 0 , 0 , 0 ) , 0 , 1 , 0 , view_count ) ;
}
2022-06-28 19:10:36 +10:00
2023-02-08 01:30:03 +11:00
// As we're not clearing these, and render buffers will return the cached texture if it already exists,
// we don't first check has_texture here
p_render_buffers - > create_texture ( RB_SCOPE_SSIL , RB_DEINTERLEAVED , RD : : DATA_FORMAT_R16G16B16A16_SFLOAT , RD : : TEXTURE_USAGE_SAMPLING_BIT | RD : : TEXTURE_USAGE_STORAGE_BIT , RD : : TEXTURE_SAMPLES_1 , full_size , 4 * view_count ) ;
p_render_buffers - > create_texture ( RB_SCOPE_SSIL , RB_DEINTERLEAVED_PONG , RD : : DATA_FORMAT_R16G16B16A16_SFLOAT , RD : : TEXTURE_USAGE_SAMPLING_BIT | RD : : TEXTURE_USAGE_STORAGE_BIT , RD : : TEXTURE_SAMPLES_1 , full_size , 4 * view_count ) ;
p_render_buffers - > create_texture ( RB_SCOPE_SSIL , RB_EDGES , RD : : DATA_FORMAT_R8_UNORM , RD : : TEXTURE_USAGE_SAMPLING_BIT | RD : : TEXTURE_USAGE_STORAGE_BIT , RD : : TEXTURE_SAMPLES_1 , full_size , 4 * view_count ) ;
p_render_buffers - > create_texture ( RB_SCOPE_SSIL , RB_IMPORTANCE_MAP , RD : : DATA_FORMAT_R8_UNORM , RD : : TEXTURE_USAGE_SAMPLING_BIT | RD : : TEXTURE_USAGE_STORAGE_BIT , RD : : TEXTURE_SAMPLES_1 , half_size ) ;
p_render_buffers - > create_texture ( RB_SCOPE_SSIL , RB_IMPORTANCE_PONG , RD : : DATA_FORMAT_R8_UNORM , RD : : TEXTURE_USAGE_SAMPLING_BIT | RD : : TEXTURE_USAGE_STORAGE_BIT , RD : : TEXTURE_SAMPLES_1 , half_size ) ;
2022-06-28 19:10:36 +10:00
}
2023-02-08 01:30:03 +11:00
void SSEffects : : screen_space_indirect_lighting ( Ref < RenderSceneBuffersRD > p_render_buffers , SSILRenderBuffers & p_ssil_buffers , uint32_t p_view , RID p_normal_buffer , const Projection & p_projection , const Projection & p_last_projection , const SSILSettings & p_settings ) {
2022-06-28 19:10:36 +10:00
UniformSetCacheRD * uniform_set_cache = UniformSetCacheRD : : get_singleton ( ) ;
ERR_FAIL_NULL ( uniform_set_cache ) ;
MaterialStorage * material_storage = MaterialStorage : : get_singleton ( ) ;
ERR_FAIL_NULL ( material_storage ) ;
2025-09-14 01:23:47 +02:00
RD : : get_singleton ( ) - > draw_command_begin_label ( " Process Screen-Space Indirect Lighting " ) ;
2023-02-08 01:30:03 +11:00
// Obtain our (cached) buffer slices for the view we are rendering.
2025-09-16 15:17:49 +03:00
RID last_frame = p_render_buffers - > get_texture_slice ( RB_SCOPE_SSLF , RB_LAST_FRAME , p_view , 0 , 1 , 6 ) ;
2023-02-08 01:30:03 +11:00
RID deinterleaved = p_render_buffers - > get_texture_slice ( RB_SCOPE_SSIL , RB_DEINTERLEAVED , p_view * 4 , 0 , 4 , 1 ) ;
RID deinterleaved_pong = p_render_buffers - > get_texture_slice ( RB_SCOPE_SSIL , RB_DEINTERLEAVED_PONG , 4 * p_view , 0 , 4 , 1 ) ;
RID edges = p_render_buffers - > get_texture_slice ( RB_SCOPE_SSIL , RB_EDGES , 4 * p_view , 0 , 4 , 1 ) ;
RID importance_map = p_render_buffers - > get_texture_slice ( RB_SCOPE_SSIL , RB_IMPORTANCE_MAP , p_view , 0 ) ;
RID importance_pong = p_render_buffers - > get_texture_slice ( RB_SCOPE_SSIL , RB_IMPORTANCE_PONG , p_view , 0 ) ;
RID deinterleaved_slices [ 4 ] ;
RID deinterleaved_pong_slices [ 4 ] ;
RID edges_slices [ 4 ] ;
for ( uint32_t i = 0 ; i < 4 ; i + + ) {
deinterleaved_slices [ i ] = p_render_buffers - > get_texture_slice ( RB_SCOPE_SSIL , RB_DEINTERLEAVED , p_view * 4 + i , 0 ) ;
deinterleaved_pong_slices [ i ] = p_render_buffers - > get_texture_slice ( RB_SCOPE_SSIL , RB_DEINTERLEAVED_PONG , p_view * 4 + i , 0 ) ;
edges_slices [ i ] = p_render_buffers - > get_texture_slice ( RB_SCOPE_SSIL , RB_EDGES , p_view * 4 + i , 0 ) ;
}
2022-06-28 19:10:36 +10:00
//Store projection info before starting the compute list
SSILProjectionUniforms projection_uniforms ;
store_camera ( p_last_projection , projection_uniforms . inv_last_frame_projection_matrix ) ;
RD : : get_singleton ( ) - > buffer_update ( ssil . projection_uniform_buffer , 0 , sizeof ( SSILProjectionUniforms ) , & projection_uniforms ) ;
memset ( & ssil . gather_push_constant , 0 , sizeof ( SSILGatherPushConstant ) ) ;
2023-02-08 01:30:03 +11:00
RID shader = ssil . gather_shader . version_get_shader ( ssil . gather_shader_version , SSIL_GATHER ) ;
2022-06-28 19:10:36 +10:00
RID default_sampler = material_storage - > sampler_rd_get_default ( RS : : CANVAS_ITEM_TEXTURE_FILTER_LINEAR , RS : : CANVAS_ITEM_TEXTURE_REPEAT_DISABLED ) ;
RID default_mipmap_sampler = material_storage - > sampler_rd_get_default ( RS : : CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS , RS : : CANVAS_ITEM_TEXTURE_REPEAT_DISABLED ) ;
RD : : ComputeListID compute_list = RD : : get_singleton ( ) - > compute_list_begin ( ) ;
{
RD : : get_singleton ( ) - > draw_command_begin_label ( " Gather Samples " ) ;
ssil . gather_push_constant . screen_size [ 0 ] = p_settings . full_screen_size . x ;
ssil . gather_push_constant . screen_size [ 1 ] = p_settings . full_screen_size . y ;
2023-02-16 00:16:35 -08:00
ssil . gather_push_constant . half_screen_pixel_size [ 0 ] = 2.0 / p_settings . full_screen_size . x ;
ssil . gather_push_constant . half_screen_pixel_size [ 1 ] = 2.0 / p_settings . full_screen_size . y ;
if ( ssil_half_size ) {
ssil . gather_push_constant . half_screen_pixel_size [ 0 ] * = 2.0 ;
ssil . gather_push_constant . half_screen_pixel_size [ 1 ] * = 2.0 ;
}
ssil . gather_push_constant . half_screen_pixel_size_x025 [ 0 ] = ssil . gather_push_constant . half_screen_pixel_size [ 0 ] * 0.75 ;
ssil . gather_push_constant . half_screen_pixel_size_x025 [ 1 ] = ssil . gather_push_constant . half_screen_pixel_size [ 1 ] * 0.75 ;
2022-10-04 11:44:48 -05:00
float tan_half_fov_x = 1.0 / p_projection . columns [ 0 ] [ 0 ] ;
float tan_half_fov_y = 1.0 / p_projection . columns [ 1 ] [ 1 ] ;
2022-06-28 19:10:36 +10:00
ssil . gather_push_constant . NDC_to_view_mul [ 0 ] = tan_half_fov_x * 2.0 ;
ssil . gather_push_constant . NDC_to_view_mul [ 1 ] = tan_half_fov_y * - 2.0 ;
ssil . gather_push_constant . NDC_to_view_add [ 0 ] = tan_half_fov_x * - 1.0 ;
ssil . gather_push_constant . NDC_to_view_add [ 1 ] = tan_half_fov_y ;
ssil . gather_push_constant . z_near = p_projection . get_z_near ( ) ;
ssil . gather_push_constant . z_far = p_projection . get_z_far ( ) ;
ssil . gather_push_constant . is_orthogonal = p_projection . is_orthogonal ( ) ;
ssil . gather_push_constant . radius = p_settings . radius ;
float radius_near_limit = ( p_settings . radius * 1.2f ) ;
2022-09-29 15:37:10 +10:00
if ( ssil_quality < = RS : : ENV_SSIL_QUALITY_LOW ) {
2022-06-28 19:10:36 +10:00
radius_near_limit * = 1.50f ;
2022-09-29 15:37:10 +10:00
if ( ssil_quality = = RS : : ENV_SSIL_QUALITY_VERY_LOW ) {
2022-06-28 19:10:36 +10:00
ssil . gather_push_constant . radius * = 0.8f ;
}
}
radius_near_limit / = tan_half_fov_y ;
2025-04-10 11:21:05 -05:00
ssil . gather_push_constant . intensity = p_settings . intensity * Math : : PI ;
2022-09-29 15:37:10 +10:00
ssil . gather_push_constant . fade_out_mul = - 1.0 / ( ssil_fadeout_to - ssil_fadeout_from ) ;
ssil . gather_push_constant . fade_out_add = ssil_fadeout_from / ( ssil_fadeout_to - ssil_fadeout_from ) + 1.0 ;
2022-06-28 19:10:36 +10:00
ssil . gather_push_constant . inv_radius_near_limit = 1.0f / radius_near_limit ;
ssil . gather_push_constant . neg_inv_radius = - 1.0 / ssil . gather_push_constant . radius ;
ssil . gather_push_constant . normal_rejection_amount = p_settings . normal_rejection ;
ssil . gather_push_constant . load_counter_avg_div = 9.0 / float ( ( p_ssil_buffers . half_buffer_width ) * ( p_ssil_buffers . half_buffer_height ) * 255 ) ;
2022-09-29 15:37:10 +10:00
ssil . gather_push_constant . adaptive_sample_limit = ssil_adaptive_target ;
2022-06-28 19:10:36 +10:00
2022-09-29 15:37:10 +10:00
ssil . gather_push_constant . quality = MAX ( 0 , ssil_quality - 1 ) ;
ssil . gather_push_constant . size_multiplier = ssil_half_size ? 2 : 1 ;
2022-06-28 19:10:36 +10:00
2023-02-08 01:30:03 +11:00
// We are using our uniform cache so our uniform sets are automatically freed when our textures are freed.
// It also ensures that we're reusing the right cached entry in a multiview situation without us having to
// remember each instance of the uniform set.
RID projection_uniform_set ;
{
RD : : Uniform u_last_frame ;
u_last_frame . uniform_type = RD : : UNIFORM_TYPE_SAMPLER_WITH_TEXTURE ;
u_last_frame . binding = 0 ;
u_last_frame . append_id ( default_mipmap_sampler ) ;
u_last_frame . append_id ( last_frame ) ;
RD : : Uniform u_projection ;
u_projection . uniform_type = RD : : UNIFORM_TYPE_UNIFORM_BUFFER ;
u_projection . binding = 1 ;
u_projection . append_id ( ssil . projection_uniform_buffer ) ;
projection_uniform_set = uniform_set_cache - > get_cache ( shader , 3 , u_last_frame , u_projection ) ;
2022-06-28 19:10:36 +10:00
}
2023-02-08 01:30:03 +11:00
RID gather_uniform_set ;
{
RID depth_texture_view = p_render_buffers - > get_texture_slice ( RB_SCOPE_SSDS , RB_LINEAR_DEPTH , p_view * 4 , ssil_half_size ? 1 : 0 , 4 , 4 ) ;
RD : : Uniform u_depth_texture_view ;
u_depth_texture_view . uniform_type = RD : : UNIFORM_TYPE_SAMPLER_WITH_TEXTURE ;
u_depth_texture_view . binding = 0 ;
2023-02-16 00:16:35 -08:00
u_depth_texture_view . append_id ( ss_effects . mirror_sampler ) ;
2023-02-08 01:30:03 +11:00
u_depth_texture_view . append_id ( depth_texture_view ) ;
RD : : Uniform u_normal_buffer ;
u_normal_buffer . uniform_type = RD : : UNIFORM_TYPE_IMAGE ;
u_normal_buffer . binding = 1 ;
u_normal_buffer . append_id ( p_normal_buffer ) ;
RD : : Uniform u_gather_constants_buffer ;
u_gather_constants_buffer . uniform_type = RD : : UNIFORM_TYPE_UNIFORM_BUFFER ;
u_gather_constants_buffer . binding = 2 ;
u_gather_constants_buffer . append_id ( ss_effects . gather_constants_buffer ) ;
gather_uniform_set = uniform_set_cache - > get_cache ( shader , 0 , u_depth_texture_view , u_normal_buffer , u_gather_constants_buffer ) ;
2022-06-28 19:10:36 +10:00
}
2023-02-08 01:30:03 +11:00
RID importance_map_uniform_set ;
{
RD : : Uniform u_pong ;
u_pong . uniform_type = RD : : UNIFORM_TYPE_IMAGE ;
u_pong . binding = 0 ;
u_pong . append_id ( deinterleaved_pong ) ;
RD : : Uniform u_importance_map ;
u_importance_map . uniform_type = RD : : UNIFORM_TYPE_SAMPLER_WITH_TEXTURE ;
u_importance_map . binding = 1 ;
u_importance_map . append_id ( default_sampler ) ;
u_importance_map . append_id ( importance_map ) ;
RD : : Uniform u_load_counter ;
u_load_counter . uniform_type = RD : : UNIFORM_TYPE_STORAGE_BUFFER ;
u_load_counter . binding = 2 ;
u_load_counter . append_id ( ssil . importance_map_load_counter ) ;
RID shader_adaptive = ssil . gather_shader . version_get_shader ( ssil . gather_shader_version , SSIL_GATHER_ADAPTIVE ) ;
importance_map_uniform_set = uniform_set_cache - > get_cache ( shader_adaptive , 1 , u_pong , u_importance_map , u_load_counter ) ;
2022-06-28 19:10:36 +10:00
}
2022-09-29 15:37:10 +10:00
if ( ssil_quality = = RS : : ENV_SSIL_QUALITY_ULTRA ) {
2022-06-28 19:10:36 +10:00
RD : : get_singleton ( ) - > draw_command_begin_label ( " Generate Importance Map " ) ;
ssil . importance_map_push_constant . half_screen_pixel_size [ 0 ] = 1.0 / p_ssil_buffers . buffer_width ;
ssil . importance_map_push_constant . half_screen_pixel_size [ 1 ] = 1.0 / p_ssil_buffers . buffer_height ;
2025-04-10 11:21:05 -05:00
ssil . importance_map_push_constant . intensity = p_settings . intensity * Math : : PI ;
2023-02-08 01:30:03 +11:00
2022-06-28 19:10:36 +10:00
//base pass
2025-10-01 14:42:27 -03:00
RD : : get_singleton ( ) - > compute_list_bind_compute_pipeline ( compute_list , ssil . pipelines [ SSIL_GATHER_BASE ] . get_rid ( ) ) ;
2023-02-08 01:30:03 +11:00
gather_ssil ( compute_list , deinterleaved_pong_slices , edges_slices , p_settings , true , gather_uniform_set , importance_map_uniform_set , projection_uniform_set ) ;
2022-06-28 19:10:36 +10:00
//generate importance map
2023-02-08 01:30:03 +11:00
RID gen_imp_shader = ssil . importance_map_shader . version_get_shader ( ssil . importance_map_shader_version , 0 ) ;
RD : : Uniform u_ssil_pong_with_sampler ( RD : : UNIFORM_TYPE_SAMPLER_WITH_TEXTURE , 0 , Vector < RID > ( { default_sampler , deinterleaved_pong } ) ) ;
RD : : Uniform u_importance_map ( RD : : UNIFORM_TYPE_IMAGE , 0 , Vector < RID > ( { importance_map } ) ) ;
2022-06-28 19:10:36 +10:00
2025-10-01 14:42:27 -03:00
RD : : get_singleton ( ) - > compute_list_bind_compute_pipeline ( compute_list , ssil . pipelines [ SSIL_GENERATE_IMPORTANCE_MAP ] . get_rid ( ) ) ;
2023-02-08 01:30:03 +11:00
RD : : get_singleton ( ) - > compute_list_bind_uniform_set ( compute_list , uniform_set_cache - > get_cache ( gen_imp_shader , 0 , u_ssil_pong_with_sampler ) , 0 ) ;
RD : : get_singleton ( ) - > compute_list_bind_uniform_set ( compute_list , uniform_set_cache - > get_cache ( gen_imp_shader , 1 , u_importance_map ) , 1 ) ;
2022-06-28 19:10:36 +10:00
RD : : get_singleton ( ) - > compute_list_set_push_constant ( compute_list , & ssil . importance_map_push_constant , sizeof ( SSILImportanceMapPushConstant ) ) ;
RD : : get_singleton ( ) - > compute_list_dispatch_threads ( compute_list , p_ssil_buffers . half_buffer_width , p_ssil_buffers . half_buffer_height , 1 ) ;
RD : : get_singleton ( ) - > compute_list_add_barrier ( compute_list ) ;
// process Importance Map A
2023-02-08 01:30:03 +11:00
RID proc_imp_shader_a = ssil . importance_map_shader . version_get_shader ( ssil . importance_map_shader_version , 1 ) ;
RD : : Uniform u_importance_map_with_sampler ( RD : : UNIFORM_TYPE_SAMPLER_WITH_TEXTURE , 0 , Vector < RID > ( { default_sampler , importance_map } ) ) ;
RD : : Uniform u_importance_map_pong ( RD : : UNIFORM_TYPE_IMAGE , 0 , Vector < RID > ( { importance_pong } ) ) ;
2022-06-28 19:10:36 +10:00
2025-10-01 14:42:27 -03:00
RD : : get_singleton ( ) - > compute_list_bind_compute_pipeline ( compute_list , ssil . pipelines [ SSIL_PROCESS_IMPORTANCE_MAPA ] . get_rid ( ) ) ;
2023-02-08 01:30:03 +11:00
RD : : get_singleton ( ) - > compute_list_bind_uniform_set ( compute_list , uniform_set_cache - > get_cache ( proc_imp_shader_a , 0 , u_importance_map_with_sampler ) , 0 ) ;
RD : : get_singleton ( ) - > compute_list_bind_uniform_set ( compute_list , uniform_set_cache - > get_cache ( proc_imp_shader_a , 1 , u_importance_map_pong ) , 1 ) ;
2022-06-28 19:10:36 +10:00
RD : : get_singleton ( ) - > compute_list_set_push_constant ( compute_list , & ssil . importance_map_push_constant , sizeof ( SSILImportanceMapPushConstant ) ) ;
RD : : get_singleton ( ) - > compute_list_dispatch_threads ( compute_list , p_ssil_buffers . half_buffer_width , p_ssil_buffers . half_buffer_height , 1 ) ;
RD : : get_singleton ( ) - > compute_list_add_barrier ( compute_list ) ;
// process Importance Map B
2023-02-08 01:30:03 +11:00
RID proc_imp_shader_b = ssil . importance_map_shader . version_get_shader ( ssil . importance_map_shader_version , 2 ) ;
RD : : Uniform u_importance_map_pong_with_sampler ( RD : : UNIFORM_TYPE_SAMPLER_WITH_TEXTURE , 0 , Vector < RID > ( { default_sampler , importance_pong } ) ) ;
2022-06-28 19:10:36 +10:00
2025-10-01 14:42:27 -03:00
RD : : get_singleton ( ) - > compute_list_bind_compute_pipeline ( compute_list , ssil . pipelines [ SSIL_PROCESS_IMPORTANCE_MAPB ] . get_rid ( ) ) ;
2023-02-08 01:30:03 +11:00
RD : : get_singleton ( ) - > compute_list_bind_uniform_set ( compute_list , uniform_set_cache - > get_cache ( proc_imp_shader_b , 0 , u_importance_map_pong_with_sampler ) , 0 ) ;
RD : : get_singleton ( ) - > compute_list_bind_uniform_set ( compute_list , uniform_set_cache - > get_cache ( proc_imp_shader_b , 1 , u_importance_map ) , 1 ) ;
2022-06-28 19:10:36 +10:00
RD : : get_singleton ( ) - > compute_list_bind_uniform_set ( compute_list , ssil . counter_uniform_set , 2 ) ;
RD : : get_singleton ( ) - > compute_list_set_push_constant ( compute_list , & ssil . importance_map_push_constant , sizeof ( SSILImportanceMapPushConstant ) ) ;
RD : : get_singleton ( ) - > compute_list_dispatch_threads ( compute_list , p_ssil_buffers . half_buffer_width , p_ssil_buffers . half_buffer_height , 1 ) ;
RD : : get_singleton ( ) - > compute_list_add_barrier ( compute_list ) ;
RD : : get_singleton ( ) - > draw_command_end_label ( ) ; // Importance Map
2025-10-01 14:42:27 -03:00
RD : : get_singleton ( ) - > compute_list_bind_compute_pipeline ( compute_list , ssil . pipelines [ SSIL_GATHER_ADAPTIVE ] . get_rid ( ) ) ;
2022-06-28 19:10:36 +10:00
} else {
2025-10-01 14:42:27 -03:00
RD : : get_singleton ( ) - > compute_list_bind_compute_pipeline ( compute_list , ssil . pipelines [ SSIL_GATHER ] . get_rid ( ) ) ;
2022-06-28 19:10:36 +10:00
}
2023-02-08 01:30:03 +11:00
gather_ssil ( compute_list , deinterleaved_slices , edges_slices , p_settings , false , gather_uniform_set , importance_map_uniform_set , projection_uniform_set ) ;
2022-06-28 19:10:36 +10:00
RD : : get_singleton ( ) - > draw_command_end_label ( ) ; //Gather
}
{
RD : : get_singleton ( ) - > draw_command_begin_label ( " Edge Aware Blur " ) ;
ssil . blur_push_constant . edge_sharpness = 1.0 - p_settings . sharpness ;
ssil . blur_push_constant . half_screen_pixel_size [ 0 ] = 1.0 / p_ssil_buffers . buffer_width ;
ssil . blur_push_constant . half_screen_pixel_size [ 1 ] = 1.0 / p_ssil_buffers . buffer_height ;
2022-09-29 15:37:10 +10:00
int blur_passes = ssil_quality > RS : : ENV_SSIL_QUALITY_VERY_LOW ? ssil_blur_passes : 1 ;
2022-06-28 19:10:36 +10:00
shader = ssil . blur_shader . version_get_shader ( ssil . blur_shader_version , 0 ) ;
for ( int pass = 0 ; pass < blur_passes ; pass + + ) {
int blur_pipeline = SSIL_BLUR_PASS ;
2022-09-29 15:37:10 +10:00
if ( ssil_quality > RS : : ENV_SSIL_QUALITY_VERY_LOW ) {
2022-06-28 19:10:36 +10:00
blur_pipeline = SSIL_BLUR_PASS_SMART ;
if ( pass < blur_passes - 2 ) {
blur_pipeline = SSIL_BLUR_PASS_WIDE ;
}
}
2023-02-08 01:30:03 +11:00
RID blur_shader = ssil . blur_shader . version_get_shader ( ssil . blur_shader_version , blur_pipeline - SSIL_BLUR_PASS ) ;
2022-06-28 19:10:36 +10:00
for ( int i = 0 ; i < 4 ; i + + ) {
2022-09-29 15:37:10 +10:00
if ( ( ssil_quality = = RS : : ENV_SSIL_QUALITY_VERY_LOW ) & & ( ( i = = 1 ) | | ( i = = 2 ) ) ) {
2022-06-28 19:10:36 +10:00
continue ;
}
2025-10-01 14:42:27 -03:00
RD : : get_singleton ( ) - > compute_list_bind_compute_pipeline ( compute_list , ssil . pipelines [ blur_pipeline ] . get_rid ( ) ) ;
2022-06-28 19:10:36 +10:00
if ( pass % 2 = = 0 ) {
2022-09-29 15:37:10 +10:00
if ( ssil_quality = = RS : : ENV_SSIL_QUALITY_VERY_LOW ) {
2023-02-08 01:30:03 +11:00
RD : : Uniform u_ssil_slice ( RD : : UNIFORM_TYPE_SAMPLER_WITH_TEXTURE , 0 , Vector < RID > ( { default_sampler , deinterleaved_slices [ i ] } ) ) ;
RD : : get_singleton ( ) - > compute_list_bind_uniform_set ( compute_list , uniform_set_cache - > get_cache ( blur_shader , 0 , u_ssil_slice ) , 0 ) ;
2022-06-28 19:10:36 +10:00
} else {
2023-02-08 01:30:03 +11:00
RD : : Uniform u_ssil_slice ( RD : : UNIFORM_TYPE_SAMPLER_WITH_TEXTURE , 0 , Vector < RID > ( { ss_effects . mirror_sampler , deinterleaved_slices [ i ] } ) ) ;
RD : : get_singleton ( ) - > compute_list_bind_uniform_set ( compute_list , uniform_set_cache - > get_cache ( blur_shader , 0 , u_ssil_slice ) , 0 ) ;
2022-06-28 19:10:36 +10:00
}
2023-02-08 01:30:03 +11:00
RD : : Uniform u_ssil_pong_slice ( RD : : UNIFORM_TYPE_IMAGE , 0 , Vector < RID > ( { deinterleaved_pong_slices [ i ] } ) ) ;
RD : : get_singleton ( ) - > compute_list_bind_uniform_set ( compute_list , uniform_set_cache - > get_cache ( blur_shader , 1 , u_ssil_pong_slice ) , 1 ) ;
2022-06-28 19:10:36 +10:00
} else {
2022-09-29 15:37:10 +10:00
if ( ssil_quality = = RS : : ENV_SSIL_QUALITY_VERY_LOW ) {
2023-02-08 01:30:03 +11:00
RD : : Uniform u_ssil_pong_slice ( RD : : UNIFORM_TYPE_SAMPLER_WITH_TEXTURE , 0 , Vector < RID > ( { default_sampler , deinterleaved_pong_slices [ i ] } ) ) ;
RD : : get_singleton ( ) - > compute_list_bind_uniform_set ( compute_list , uniform_set_cache - > get_cache ( blur_shader , 0 , u_ssil_pong_slice ) , 0 ) ;
2022-06-28 19:10:36 +10:00
} else {
2023-02-08 01:30:03 +11:00
RD : : Uniform u_ssil_pong_slice ( RD : : UNIFORM_TYPE_SAMPLER_WITH_TEXTURE , 0 , Vector < RID > ( { ss_effects . mirror_sampler , deinterleaved_pong_slices [ i ] } ) ) ;
RD : : get_singleton ( ) - > compute_list_bind_uniform_set ( compute_list , uniform_set_cache - > get_cache ( blur_shader , 0 , u_ssil_pong_slice ) , 0 ) ;
2022-06-28 19:10:36 +10:00
}
2023-02-08 01:30:03 +11:00
RD : : Uniform u_ssil_slice ( RD : : UNIFORM_TYPE_IMAGE , 0 , Vector < RID > ( { deinterleaved_slices [ i ] } ) ) ;
RD : : get_singleton ( ) - > compute_list_bind_uniform_set ( compute_list , uniform_set_cache - > get_cache ( blur_shader , 1 , u_ssil_slice ) , 1 ) ;
2022-06-28 19:10:36 +10:00
}
2023-02-08 01:30:03 +11:00
RD : : Uniform u_edges_slice ( RD : : UNIFORM_TYPE_IMAGE , 0 , Vector < RID > ( { edges_slices [ i ] } ) ) ;
RD : : get_singleton ( ) - > compute_list_bind_uniform_set ( compute_list , uniform_set_cache - > get_cache ( blur_shader , 2 , u_edges_slice ) , 2 ) ;
2022-06-28 19:10:36 +10:00
RD : : get_singleton ( ) - > compute_list_set_push_constant ( compute_list , & ssil . blur_push_constant , sizeof ( SSILBlurPushConstant ) ) ;
2023-02-24 13:50:13 +11:00
// Use the size of the actual buffer we're processing here or we won't cover the entire image.
int x_groups = p_ssil_buffers . buffer_width ;
int y_groups = p_ssil_buffers . buffer_height ;
2022-06-28 19:10:36 +10:00
RD : : get_singleton ( ) - > compute_list_dispatch_threads ( compute_list , x_groups , y_groups , 1 ) ;
}
2024-02-21 14:35:20 -08:00
RD : : get_singleton ( ) - > compute_list_add_barrier ( compute_list ) ;
2022-06-28 19:10:36 +10:00
}
RD : : get_singleton ( ) - > draw_command_end_label ( ) ; // Blur
}
{
RD : : get_singleton ( ) - > draw_command_begin_label ( " Interleave Buffers " ) ;
ssil . interleave_push_constant . inv_sharpness = 1.0 - p_settings . sharpness ;
ssil . interleave_push_constant . pixel_size [ 0 ] = 1.0 / p_settings . full_screen_size . x ;
ssil . interleave_push_constant . pixel_size [ 1 ] = 1.0 / p_settings . full_screen_size . y ;
2022-09-29 15:37:10 +10:00
ssil . interleave_push_constant . size_modifier = uint32_t ( ssil_half_size ? 4 : 2 ) ;
2022-06-28 19:10:36 +10:00
int interleave_pipeline = SSIL_INTERLEAVE_HALF ;
2022-09-29 15:37:10 +10:00
if ( ssil_quality = = RS : : ENV_SSIL_QUALITY_LOW ) {
2022-06-28 19:10:36 +10:00
interleave_pipeline = SSIL_INTERLEAVE ;
2022-09-29 15:37:10 +10:00
} else if ( ssil_quality > = RS : : ENV_SSIL_QUALITY_MEDIUM ) {
2022-06-28 19:10:36 +10:00
interleave_pipeline = SSIL_INTERLEAVE_SMART ;
}
shader = ssil . interleave_shader . version_get_shader ( ssil . interleave_shader_version , 0 ) ;
2025-10-01 14:42:27 -03:00
RD : : get_singleton ( ) - > compute_list_bind_compute_pipeline ( compute_list , ssil . pipelines [ interleave_pipeline ] . get_rid ( ) ) ;
2022-06-28 19:10:36 +10:00
2023-02-08 01:30:03 +11:00
RID final = p_render_buffers - > get_texture_slice ( RB_SCOPE_SSIL , RB_FINAL , p_view , 0 ) ;
RD : : Uniform u_destination ( RD : : UNIFORM_TYPE_IMAGE , 0 , Vector < RID > ( { final } ) ) ;
2022-06-28 19:10:36 +10:00
RD : : get_singleton ( ) - > compute_list_bind_uniform_set ( compute_list , uniform_set_cache - > get_cache ( shader , 0 , u_destination ) , 0 ) ;
2022-09-29 15:37:10 +10:00
if ( ssil_quality > RS : : ENV_SSIL_QUALITY_VERY_LOW & & ssil_blur_passes % 2 = = 0 ) {
2023-02-08 01:30:03 +11:00
RD : : Uniform u_ssil ( RD : : UNIFORM_TYPE_SAMPLER_WITH_TEXTURE , 0 , Vector < RID > ( { default_sampler , deinterleaved } ) ) ;
2022-06-28 19:10:36 +10:00
RD : : get_singleton ( ) - > compute_list_bind_uniform_set ( compute_list , uniform_set_cache - > get_cache ( shader , 1 , u_ssil ) , 1 ) ;
} else {
2023-02-08 01:30:03 +11:00
RD : : Uniform u_ssil_pong ( RD : : UNIFORM_TYPE_SAMPLER_WITH_TEXTURE , 0 , Vector < RID > ( { default_sampler , deinterleaved_pong } ) ) ;
2022-06-28 19:10:36 +10:00
RD : : get_singleton ( ) - > compute_list_bind_uniform_set ( compute_list , uniform_set_cache - > get_cache ( shader , 1 , u_ssil_pong ) , 1 ) ;
}
2023-02-08 01:30:03 +11:00
RD : : Uniform u_edges ( RD : : UNIFORM_TYPE_IMAGE , 0 , Vector < RID > ( { edges } ) ) ;
2022-06-28 19:10:36 +10:00
RD : : get_singleton ( ) - > compute_list_bind_uniform_set ( compute_list , uniform_set_cache - > get_cache ( shader , 2 , u_edges ) , 2 ) ;
RD : : get_singleton ( ) - > compute_list_set_push_constant ( compute_list , & ssil . interleave_push_constant , sizeof ( SSILInterleavePushConstant ) ) ;
RD : : get_singleton ( ) - > compute_list_dispatch_threads ( compute_list , p_settings . full_screen_size . x , p_settings . full_screen_size . y , 1 ) ;
RD : : get_singleton ( ) - > compute_list_add_barrier ( compute_list ) ;
RD : : get_singleton ( ) - > draw_command_end_label ( ) ; // Interleave
}
RD : : get_singleton ( ) - > draw_command_end_label ( ) ; // SSIL
2023-11-24 08:23:22 -03:00
RD : : get_singleton ( ) - > compute_list_end ( ) ;
2022-06-28 19:10:36 +10:00
int zero [ 1 ] = { 0 } ;
2023-11-24 08:23:22 -03:00
RD : : get_singleton ( ) - > buffer_update ( ssil . importance_map_load_counter , 0 , sizeof ( uint32_t ) , & zero ) ;
2022-06-28 19:10:36 +10:00
}
/* SSAO */
2022-09-29 15:37:10 +10:00
void SSEffects : : ssao_set_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 ) {
ssao_quality = p_quality ;
ssao_half_size = p_half_size ;
ssao_adaptive_target = p_adaptive_target ;
ssao_blur_passes = p_blur_passes ;
ssao_fadeout_from = p_fadeout_from ;
ssao_fadeout_to = p_fadeout_to ;
}
2023-02-08 01:30:03 +11:00
void SSEffects : : gather_ssao ( RD : : ComputeListID p_compute_list , const RID * p_ao_slices , const SSAOSettings & p_settings , bool p_adaptive_base_pass , RID p_gather_uniform_set , RID p_importance_map_uniform_set ) {
2022-06-28 19:10:36 +10:00
UniformSetCacheRD * uniform_set_cache = UniformSetCacheRD : : get_singleton ( ) ;
ERR_FAIL_NULL ( uniform_set_cache ) ;
RD : : get_singleton ( ) - > compute_list_bind_uniform_set ( p_compute_list , p_gather_uniform_set , 0 ) ;
2022-09-29 15:37:10 +10:00
if ( ( ssao_quality = = RS : : ENV_SSAO_QUALITY_ULTRA ) & & ! p_adaptive_base_pass ) {
2023-02-08 01:30:03 +11:00
RD : : get_singleton ( ) - > compute_list_bind_uniform_set ( p_compute_list , p_importance_map_uniform_set , 1 ) ;
2022-06-28 19:10:36 +10:00
}
RID shader = ssao . gather_shader . version_get_shader ( ssao . gather_shader_version , 1 ) ; //
for ( int i = 0 ; i < 4 ; i + + ) {
2022-09-29 15:37:10 +10:00
if ( ( ssao_quality = = RS : : ENV_SSAO_QUALITY_VERY_LOW ) & & ( ( i = = 1 ) | | ( i = = 2 ) ) ) {
2022-06-28 19:10:36 +10:00
continue ;
}
2025-05-23 06:52:10 +10:00
RD : : Uniform u_ao_slice ( RD : : UNIFORM_TYPE_IMAGE , 0 , p_ao_slices [ i ] ) ;
2022-06-28 19:10:36 +10:00
ssao . gather_push_constant . pass_coord_offset [ 0 ] = i % 2 ;
ssao . gather_push_constant . pass_coord_offset [ 1 ] = i / 2 ;
ssao . gather_push_constant . pass_uv_offset [ 0 ] = ( ( i % 2 ) - 0.0 ) / p_settings . full_screen_size . x ;
ssao . gather_push_constant . pass_uv_offset [ 1 ] = ( ( i / 2 ) - 0.0 ) / p_settings . full_screen_size . y ;
ssao . gather_push_constant . pass = i ;
RD : : get_singleton ( ) - > compute_list_bind_uniform_set ( p_compute_list , uniform_set_cache - > get_cache ( shader , 2 , u_ao_slice ) , 2 ) ;
RD : : get_singleton ( ) - > compute_list_set_push_constant ( p_compute_list , & ssao . gather_push_constant , sizeof ( SSAOGatherPushConstant ) ) ;
2023-02-24 13:50:13 +11:00
Size2i size ;
// Make sure we use the same size as with which our buffer was created
if ( ssao_half_size ) {
size . x = ( p_settings . full_screen_size . x + 3 ) / 4 ;
size . y = ( p_settings . full_screen_size . y + 3 ) / 4 ;
} else {
size . x = ( p_settings . full_screen_size . x + 1 ) / 2 ;
size . y = ( p_settings . full_screen_size . y + 1 ) / 2 ;
}
2022-06-28 19:10:36 +10:00
RD : : get_singleton ( ) - > compute_list_dispatch_threads ( p_compute_list , size . x , size . y , 1 ) ;
}
RD : : get_singleton ( ) - > compute_list_add_barrier ( p_compute_list ) ;
}
2023-02-08 01:30:03 +11:00
void SSEffects : : ssao_allocate_buffers ( Ref < RenderSceneBuffersRD > p_render_buffers , SSAORenderBuffers & p_ssao_buffers , const SSAOSettings & p_settings ) {
2022-09-29 15:37:10 +10:00
if ( p_ssao_buffers . half_size ! = ssao_half_size ) {
2023-02-08 01:30:03 +11:00
p_render_buffers - > clear_context ( RB_SCOPE_SSAO ) ;
2022-06-28 19:10:36 +10:00
}
2023-02-08 01:30:03 +11:00
p_ssao_buffers . half_size = ssao_half_size ;
2022-09-29 15:37:10 +10:00
if ( ssao_half_size ) {
2022-06-28 19:10:36 +10:00
p_ssao_buffers . buffer_width = ( p_settings . full_screen_size . x + 3 ) / 4 ;
p_ssao_buffers . buffer_height = ( p_settings . full_screen_size . y + 3 ) / 4 ;
p_ssao_buffers . half_buffer_width = ( p_settings . full_screen_size . x + 7 ) / 8 ;
p_ssao_buffers . half_buffer_height = ( p_settings . full_screen_size . y + 7 ) / 8 ;
} else {
p_ssao_buffers . buffer_width = ( p_settings . full_screen_size . x + 1 ) / 2 ;
p_ssao_buffers . buffer_height = ( p_settings . full_screen_size . y + 1 ) / 2 ;
p_ssao_buffers . half_buffer_width = ( p_settings . full_screen_size . x + 3 ) / 4 ;
p_ssao_buffers . half_buffer_height = ( p_settings . full_screen_size . y + 3 ) / 4 ;
}
2023-02-08 01:30:03 +11:00
uint32_t view_count = p_render_buffers - > get_view_count ( ) ;
Size2i full_size = Size2i ( p_ssao_buffers . buffer_width , p_ssao_buffers . buffer_height ) ;
Size2i half_size = Size2i ( p_ssao_buffers . half_buffer_width , p_ssao_buffers . half_buffer_height ) ;
2022-06-28 19:10:36 +10:00
2023-02-08 01:30:03 +11:00
// As we're not clearing these, and render buffers will return the cached texture if it already exists,
// we don't first check has_texture here
2022-06-28 19:10:36 +10:00
2023-02-08 01:30:03 +11:00
p_render_buffers - > create_texture ( RB_SCOPE_SSAO , RB_DEINTERLEAVED , RD : : DATA_FORMAT_R8G8_UNORM , RD : : TEXTURE_USAGE_SAMPLING_BIT | RD : : TEXTURE_USAGE_STORAGE_BIT , RD : : TEXTURE_SAMPLES_1 , full_size , 4 * view_count ) ;
p_render_buffers - > create_texture ( RB_SCOPE_SSAO , RB_DEINTERLEAVED_PONG , RD : : DATA_FORMAT_R8G8_UNORM , RD : : TEXTURE_USAGE_SAMPLING_BIT | RD : : TEXTURE_USAGE_STORAGE_BIT , RD : : TEXTURE_SAMPLES_1 , full_size , 4 * view_count ) ;
p_render_buffers - > create_texture ( RB_SCOPE_SSAO , RB_IMPORTANCE_MAP , RD : : DATA_FORMAT_R8_UNORM , RD : : TEXTURE_USAGE_SAMPLING_BIT | RD : : TEXTURE_USAGE_STORAGE_BIT , RD : : TEXTURE_SAMPLES_1 , half_size ) ;
p_render_buffers - > create_texture ( RB_SCOPE_SSAO , RB_IMPORTANCE_PONG , RD : : DATA_FORMAT_R8_UNORM , RD : : TEXTURE_USAGE_SAMPLING_BIT | RD : : TEXTURE_USAGE_STORAGE_BIT , RD : : TEXTURE_SAMPLES_1 , half_size ) ;
p_render_buffers - > create_texture ( RB_SCOPE_SSAO , RB_FINAL , RD : : DATA_FORMAT_R8_UNORM , RD : : TEXTURE_USAGE_SAMPLING_BIT | RD : : TEXTURE_USAGE_STORAGE_BIT , RD : : TEXTURE_SAMPLES_1 ) ;
2022-06-28 19:10:36 +10:00
}
2023-02-08 01:30:03 +11:00
void SSEffects : : 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 ) {
2022-06-28 19:10:36 +10:00
UniformSetCacheRD * uniform_set_cache = UniformSetCacheRD : : get_singleton ( ) ;
ERR_FAIL_NULL ( uniform_set_cache ) ;
MaterialStorage * material_storage = MaterialStorage : : get_singleton ( ) ;
ERR_FAIL_NULL ( material_storage ) ;
2023-02-08 01:30:03 +11:00
// Obtain our (cached) buffer slices for the view we are rendering.
RID ao_deinterleaved = p_render_buffers - > get_texture_slice ( RB_SCOPE_SSAO , RB_DEINTERLEAVED , p_view * 4 , 0 , 4 , 1 ) ;
RID ao_pong = p_render_buffers - > get_texture_slice ( RB_SCOPE_SSAO , RB_DEINTERLEAVED_PONG , p_view * 4 , 0 , 4 , 1 ) ;
RID importance_map = p_render_buffers - > get_texture_slice ( RB_SCOPE_SSAO , RB_IMPORTANCE_MAP , p_view , 0 ) ;
RID importance_pong = p_render_buffers - > get_texture_slice ( RB_SCOPE_SSAO , RB_IMPORTANCE_PONG , p_view , 0 ) ;
RID ao_final = p_render_buffers - > get_texture_slice ( RB_SCOPE_SSAO , RB_FINAL , p_view , 0 ) ;
RID ao_deinterleaved_slices [ 4 ] ;
RID ao_pong_slices [ 4 ] ;
for ( uint32_t i = 0 ; i < 4 ; i + + ) {
ao_deinterleaved_slices [ i ] = p_render_buffers - > get_texture_slice ( RB_SCOPE_SSAO , RB_DEINTERLEAVED , p_view * 4 + i , 0 ) ;
ao_pong_slices [ i ] = p_render_buffers - > get_texture_slice ( RB_SCOPE_SSAO , RB_DEINTERLEAVED_PONG , p_view * 4 + i , 0 ) ;
}
2022-06-28 19:10:36 +10:00
RD : : ComputeListID compute_list = RD : : get_singleton ( ) - > compute_list_begin ( ) ;
memset ( & ssao . gather_push_constant , 0 , sizeof ( SSAOGatherPushConstant ) ) ;
/* FIRST PASS */
2023-02-08 01:30:03 +11:00
RID shader = ssao . gather_shader . version_get_shader ( ssao . gather_shader_version , SSAO_GATHER ) ;
2022-06-28 19:10:36 +10:00
RID default_sampler = material_storage - > sampler_rd_get_default ( RS : : CANVAS_ITEM_TEXTURE_FILTER_LINEAR , RS : : CANVAS_ITEM_TEXTURE_REPEAT_DISABLED ) ;
2025-09-14 01:23:47 +02:00
RD : : get_singleton ( ) - > draw_command_begin_label ( " Process Screen-Space Ambient Occlusion " ) ;
2022-06-28 19:10:36 +10:00
/* SECOND PASS */
// Sample SSAO
{
RD : : get_singleton ( ) - > draw_command_begin_label ( " Gather Samples " ) ;
ssao . gather_push_constant . screen_size [ 0 ] = p_settings . full_screen_size . x ;
ssao . gather_push_constant . screen_size [ 1 ] = p_settings . full_screen_size . y ;
2023-02-16 00:16:35 -08:00
ssao . gather_push_constant . half_screen_pixel_size [ 0 ] = 2.0 / p_settings . full_screen_size . x ;
ssao . gather_push_constant . half_screen_pixel_size [ 1 ] = 2.0 / p_settings . full_screen_size . y ;
if ( ssao_half_size ) {
ssao . gather_push_constant . half_screen_pixel_size [ 0 ] * = 2.0 ;
ssao . gather_push_constant . half_screen_pixel_size [ 1 ] * = 2.0 ;
}
ssao . gather_push_constant . half_screen_pixel_size_x025 [ 0 ] = ssao . gather_push_constant . half_screen_pixel_size [ 0 ] * 0.75 ;
ssao . gather_push_constant . half_screen_pixel_size_x025 [ 1 ] = ssao . gather_push_constant . half_screen_pixel_size [ 1 ] * 0.75 ;
2022-10-04 11:44:48 -05:00
float tan_half_fov_x = 1.0 / p_projection . columns [ 0 ] [ 0 ] ;
float tan_half_fov_y = 1.0 / p_projection . columns [ 1 ] [ 1 ] ;
2022-06-28 19:10:36 +10:00
ssao . gather_push_constant . NDC_to_view_mul [ 0 ] = tan_half_fov_x * 2.0 ;
ssao . gather_push_constant . NDC_to_view_mul [ 1 ] = tan_half_fov_y * - 2.0 ;
ssao . gather_push_constant . NDC_to_view_add [ 0 ] = tan_half_fov_x * - 1.0 ;
ssao . gather_push_constant . NDC_to_view_add [ 1 ] = tan_half_fov_y ;
ssao . gather_push_constant . is_orthogonal = p_projection . is_orthogonal ( ) ;
ssao . gather_push_constant . radius = p_settings . radius ;
float radius_near_limit = ( p_settings . radius * 1.2f ) ;
2022-09-29 15:37:10 +10:00
if ( ssao_quality < = RS : : ENV_SSAO_QUALITY_LOW ) {
2022-06-28 19:10:36 +10:00
radius_near_limit * = 1.50f ;
2022-09-29 15:37:10 +10:00
if ( ssao_quality = = RS : : ENV_SSAO_QUALITY_VERY_LOW ) {
2022-06-28 19:10:36 +10:00
ssao . gather_push_constant . radius * = 0.8f ;
}
}
radius_near_limit / = tan_half_fov_y ;
ssao . gather_push_constant . intensity = p_settings . intensity ;
ssao . gather_push_constant . shadow_power = p_settings . power ;
ssao . gather_push_constant . shadow_clamp = 0.98 ;
2022-09-29 15:37:10 +10:00
ssao . gather_push_constant . fade_out_mul = - 1.0 / ( ssao_fadeout_to - ssao_fadeout_from ) ;
ssao . gather_push_constant . fade_out_add = ssao_fadeout_from / ( ssao_fadeout_to - ssao_fadeout_from ) + 1.0 ;
2022-06-28 19:10:36 +10:00
ssao . gather_push_constant . horizon_angle_threshold = p_settings . horizon ;
ssao . gather_push_constant . inv_radius_near_limit = 1.0f / radius_near_limit ;
ssao . gather_push_constant . neg_inv_radius = - 1.0 / ssao . gather_push_constant . radius ;
ssao . gather_push_constant . load_counter_avg_div = 9.0 / float ( ( p_ssao_buffers . half_buffer_width ) * ( p_ssao_buffers . half_buffer_height ) * 255 ) ;
2022-09-29 15:37:10 +10:00
ssao . gather_push_constant . adaptive_sample_limit = ssao_adaptive_target ;
2022-06-28 19:10:36 +10:00
ssao . gather_push_constant . detail_intensity = p_settings . detail ;
2022-09-29 15:37:10 +10:00
ssao . gather_push_constant . quality = MAX ( 0 , ssao_quality - 1 ) ;
ssao . gather_push_constant . size_multiplier = ssao_half_size ? 2 : 1 ;
2022-06-28 19:10:36 +10:00
2023-02-08 01:30:03 +11:00
// We are using our uniform cache so our uniform sets are automatically freed when our textures are freed.
// It also ensures that we're reusing the right cached entry in a multiview situation without us having to
// remember each instance of the uniform set.
RID gather_uniform_set ;
{
RID depth_texture_view = p_render_buffers - > get_texture_slice ( RB_SCOPE_SSDS , RB_LINEAR_DEPTH , p_view * 4 , ssao_half_size ? 1 : 0 , 4 , 4 ) ;
RD : : Uniform u_depth_texture_view ;
u_depth_texture_view . uniform_type = RD : : UNIFORM_TYPE_SAMPLER_WITH_TEXTURE ;
u_depth_texture_view . binding = 0 ;
2023-02-16 00:16:35 -08:00
u_depth_texture_view . append_id ( ss_effects . mirror_sampler ) ;
2023-02-08 01:30:03 +11:00
u_depth_texture_view . append_id ( depth_texture_view ) ;
RD : : Uniform u_normal_buffer ;
u_normal_buffer . uniform_type = RD : : UNIFORM_TYPE_IMAGE ;
u_normal_buffer . binding = 1 ;
u_normal_buffer . append_id ( p_normal_buffer ) ;
RD : : Uniform u_gather_constants_buffer ;
u_gather_constants_buffer . uniform_type = RD : : UNIFORM_TYPE_UNIFORM_BUFFER ;
u_gather_constants_buffer . binding = 2 ;
u_gather_constants_buffer . append_id ( ss_effects . gather_constants_buffer ) ;
gather_uniform_set = uniform_set_cache - > get_cache ( shader , 0 , u_depth_texture_view , u_normal_buffer , u_gather_constants_buffer ) ;
2022-06-28 19:10:36 +10:00
}
2023-02-08 01:30:03 +11:00
RID importance_map_uniform_set ;
{
RD : : Uniform u_pong ;
u_pong . uniform_type = RD : : UNIFORM_TYPE_IMAGE ;
u_pong . binding = 0 ;
u_pong . append_id ( ao_pong ) ;
RD : : Uniform u_importance_map ;
u_importance_map . uniform_type = RD : : UNIFORM_TYPE_SAMPLER_WITH_TEXTURE ;
u_importance_map . binding = 1 ;
u_importance_map . append_id ( default_sampler ) ;
u_importance_map . append_id ( importance_map ) ;
RD : : Uniform u_load_counter ;
u_load_counter . uniform_type = RD : : UNIFORM_TYPE_STORAGE_BUFFER ;
u_load_counter . binding = 2 ;
u_load_counter . append_id ( ssao . importance_map_load_counter ) ;
RID shader_adaptive = ssao . gather_shader . version_get_shader ( ssao . gather_shader_version , SSAO_GATHER_ADAPTIVE ) ;
importance_map_uniform_set = uniform_set_cache - > get_cache ( shader_adaptive , 1 , u_pong , u_importance_map , u_load_counter ) ;
2022-06-28 19:10:36 +10:00
}
2022-09-29 15:37:10 +10:00
if ( ssao_quality = = RS : : ENV_SSAO_QUALITY_ULTRA ) {
2022-06-28 19:10:36 +10:00
RD : : get_singleton ( ) - > draw_command_begin_label ( " Generate Importance Map " ) ;
ssao . importance_map_push_constant . half_screen_pixel_size [ 0 ] = 1.0 / p_ssao_buffers . buffer_width ;
ssao . importance_map_push_constant . half_screen_pixel_size [ 1 ] = 1.0 / p_ssao_buffers . buffer_height ;
ssao . importance_map_push_constant . intensity = p_settings . intensity ;
ssao . importance_map_push_constant . power = p_settings . power ;
//base pass
2025-10-01 14:42:27 -03:00
RD : : get_singleton ( ) - > compute_list_bind_compute_pipeline ( compute_list , ssao . pipelines [ SSAO_GATHER_BASE ] . get_rid ( ) ) ;
2023-02-08 01:30:03 +11:00
gather_ssao ( compute_list , ao_pong_slices , p_settings , true , gather_uniform_set , RID ( ) ) ;
2022-06-28 19:10:36 +10:00
//generate importance map
2023-02-08 01:30:03 +11:00
RID gen_imp_shader = ssao . importance_map_shader . version_get_shader ( ssao . importance_map_shader_version , 0 ) ;
2025-10-01 14:42:27 -03:00
RD : : get_singleton ( ) - > compute_list_bind_compute_pipeline ( compute_list , ssao . pipelines [ SSAO_GENERATE_IMPORTANCE_MAP ] . get_rid ( ) ) ;
2022-06-28 19:10:36 +10:00
2023-02-08 01:30:03 +11:00
RD : : Uniform u_ao_pong_with_sampler ( RD : : UNIFORM_TYPE_SAMPLER_WITH_TEXTURE , 0 , Vector < RID > ( { default_sampler , ao_pong } ) ) ;
RD : : get_singleton ( ) - > compute_list_bind_uniform_set ( compute_list , uniform_set_cache - > get_cache ( gen_imp_shader , 0 , u_ao_pong_with_sampler ) , 0 ) ;
2022-06-28 19:10:36 +10:00
2023-02-08 01:30:03 +11:00
RD : : Uniform u_importance_map ( RD : : UNIFORM_TYPE_IMAGE , 0 , Vector < RID > ( { importance_map } ) ) ;
RD : : get_singleton ( ) - > compute_list_bind_uniform_set ( compute_list , uniform_set_cache - > get_cache ( gen_imp_shader , 1 , u_importance_map ) , 1 ) ;
2022-06-28 19:10:36 +10:00
RD : : get_singleton ( ) - > compute_list_set_push_constant ( compute_list , & ssao . importance_map_push_constant , sizeof ( SSAOImportanceMapPushConstant ) ) ;
RD : : get_singleton ( ) - > compute_list_dispatch_threads ( compute_list , p_ssao_buffers . half_buffer_width , p_ssao_buffers . half_buffer_height , 1 ) ;
RD : : get_singleton ( ) - > compute_list_add_barrier ( compute_list ) ;
//process importance map A
2023-02-08 01:30:03 +11:00
RID proc_imp_shader_a = ssao . importance_map_shader . version_get_shader ( ssao . importance_map_shader_version , 1 ) ;
2025-10-01 14:42:27 -03:00
RD : : get_singleton ( ) - > compute_list_bind_compute_pipeline ( compute_list , ssao . pipelines [ SSAO_PROCESS_IMPORTANCE_MAPA ] . get_rid ( ) ) ;
2022-06-28 19:10:36 +10:00
2023-02-08 01:30:03 +11:00
RD : : Uniform u_importance_map_with_sampler ( RD : : UNIFORM_TYPE_SAMPLER_WITH_TEXTURE , 0 , Vector < RID > ( { default_sampler , importance_map } ) ) ;
RD : : get_singleton ( ) - > compute_list_bind_uniform_set ( compute_list , uniform_set_cache - > get_cache ( proc_imp_shader_a , 0 , u_importance_map_with_sampler ) , 0 ) ;
2022-06-28 19:10:36 +10:00
2023-02-08 01:30:03 +11:00
RD : : Uniform u_importance_map_pong ( RD : : UNIFORM_TYPE_IMAGE , 0 , Vector < RID > ( { importance_pong } ) ) ;
RD : : get_singleton ( ) - > compute_list_bind_uniform_set ( compute_list , uniform_set_cache - > get_cache ( proc_imp_shader_a , 1 , u_importance_map_pong ) , 1 ) ;
2022-06-28 19:10:36 +10:00
RD : : get_singleton ( ) - > compute_list_set_push_constant ( compute_list , & ssao . importance_map_push_constant , sizeof ( SSAOImportanceMapPushConstant ) ) ;
RD : : get_singleton ( ) - > compute_list_dispatch_threads ( compute_list , p_ssao_buffers . half_buffer_width , p_ssao_buffers . half_buffer_height , 1 ) ;
RD : : get_singleton ( ) - > compute_list_add_barrier ( compute_list ) ;
//process Importance Map B
2023-02-08 01:30:03 +11:00
RID proc_imp_shader_b = ssao . importance_map_shader . version_get_shader ( ssao . importance_map_shader_version , 2 ) ;
2025-10-01 14:42:27 -03:00
RD : : get_singleton ( ) - > compute_list_bind_compute_pipeline ( compute_list , ssao . pipelines [ SSAO_PROCESS_IMPORTANCE_MAPB ] . get_rid ( ) ) ;
2022-06-28 19:10:36 +10:00
2023-02-08 01:30:03 +11:00
RD : : Uniform u_importance_map_pong_with_sampler ( RD : : UNIFORM_TYPE_SAMPLER_WITH_TEXTURE , 0 , Vector < RID > ( { default_sampler , importance_pong } ) ) ;
RD : : get_singleton ( ) - > compute_list_bind_uniform_set ( compute_list , uniform_set_cache - > get_cache ( proc_imp_shader_b , 0 , u_importance_map_pong_with_sampler ) , 0 ) ;
2022-06-28 19:10:36 +10:00
2023-02-08 01:30:03 +11:00
RD : : get_singleton ( ) - > compute_list_bind_uniform_set ( compute_list , uniform_set_cache - > get_cache ( proc_imp_shader_b , 1 , u_importance_map ) , 1 ) ;
2022-06-28 19:10:36 +10:00
RD : : get_singleton ( ) - > compute_list_bind_uniform_set ( compute_list , ssao . counter_uniform_set , 2 ) ;
RD : : get_singleton ( ) - > compute_list_set_push_constant ( compute_list , & ssao . importance_map_push_constant , sizeof ( SSAOImportanceMapPushConstant ) ) ;
RD : : get_singleton ( ) - > compute_list_dispatch_threads ( compute_list , p_ssao_buffers . half_buffer_width , p_ssao_buffers . half_buffer_height , 1 ) ;
RD : : get_singleton ( ) - > compute_list_add_barrier ( compute_list ) ;
2025-10-01 14:42:27 -03:00
RD : : get_singleton ( ) - > compute_list_bind_compute_pipeline ( compute_list , ssao . pipelines [ SSAO_GATHER_ADAPTIVE ] . get_rid ( ) ) ;
2022-06-28 19:10:36 +10:00
RD : : get_singleton ( ) - > draw_command_end_label ( ) ; // Importance Map
} else {
2025-10-01 14:42:27 -03:00
RD : : get_singleton ( ) - > compute_list_bind_compute_pipeline ( compute_list , ssao . pipelines [ SSAO_GATHER ] . get_rid ( ) ) ;
2022-06-28 19:10:36 +10:00
}
2023-02-08 01:30:03 +11:00
gather_ssao ( compute_list , ao_deinterleaved_slices , p_settings , false , gather_uniform_set , importance_map_uniform_set ) ;
2022-06-28 19:10:36 +10:00
RD : : get_singleton ( ) - > draw_command_end_label ( ) ; // Gather SSAO
}
// /* THIRD PASS */
// // Blur
//
{
2025-09-14 01:23:47 +02:00
RD : : get_singleton ( ) - > draw_command_begin_label ( " Edge-Aware Blur " ) ;
2022-06-28 19:10:36 +10:00
ssao . blur_push_constant . edge_sharpness = 1.0 - p_settings . sharpness ;
ssao . blur_push_constant . half_screen_pixel_size [ 0 ] = 1.0 / p_ssao_buffers . buffer_width ;
ssao . blur_push_constant . half_screen_pixel_size [ 1 ] = 1.0 / p_ssao_buffers . buffer_height ;
2022-09-29 15:37:10 +10:00
int blur_passes = ssao_quality > RS : : ENV_SSAO_QUALITY_VERY_LOW ? ssao_blur_passes : 1 ;
2022-06-28 19:10:36 +10:00
shader = ssao . blur_shader . version_get_shader ( ssao . blur_shader_version , 0 ) ;
for ( int pass = 0 ; pass < blur_passes ; pass + + ) {
int blur_pipeline = SSAO_BLUR_PASS ;
2022-09-29 15:37:10 +10:00
if ( ssao_quality > RS : : ENV_SSAO_QUALITY_VERY_LOW ) {
2022-06-28 19:10:36 +10:00
if ( pass < blur_passes - 2 ) {
blur_pipeline = SSAO_BLUR_PASS_WIDE ;
} else {
blur_pipeline = SSAO_BLUR_PASS_SMART ;
}
}
for ( int i = 0 ; i < 4 ; i + + ) {
2022-09-29 15:37:10 +10:00
if ( ( ssao_quality = = RS : : ENV_SSAO_QUALITY_VERY_LOW ) & & ( ( i = = 1 ) | | ( i = = 2 ) ) ) {
2022-06-28 19:10:36 +10:00
continue ;
}
2023-02-08 01:30:03 +11:00
RID blur_shader = ssao . blur_shader . version_get_shader ( ssao . blur_shader_version , blur_pipeline - SSAO_BLUR_PASS ) ;
2025-10-01 14:42:27 -03:00
RD : : get_singleton ( ) - > compute_list_bind_compute_pipeline ( compute_list , ssao . pipelines [ blur_pipeline ] . get_rid ( ) ) ;
2022-06-28 19:10:36 +10:00
if ( pass % 2 = = 0 ) {
2022-09-29 15:37:10 +10:00
if ( ssao_quality = = RS : : ENV_SSAO_QUALITY_VERY_LOW ) {
2023-02-08 01:30:03 +11:00
RD : : Uniform u_ao_slices_with_sampler ( RD : : UNIFORM_TYPE_SAMPLER_WITH_TEXTURE , 0 , Vector < RID > ( { default_sampler , ao_deinterleaved_slices [ i ] } ) ) ;
RD : : get_singleton ( ) - > compute_list_bind_uniform_set ( compute_list , uniform_set_cache - > get_cache ( blur_shader , 0 , u_ao_slices_with_sampler ) , 0 ) ;
2022-06-28 19:10:36 +10:00
} else {
2023-02-08 01:30:03 +11:00
RD : : Uniform u_ao_slices_with_sampler ( RD : : UNIFORM_TYPE_SAMPLER_WITH_TEXTURE , 0 , Vector < RID > ( { ss_effects . mirror_sampler , ao_deinterleaved_slices [ i ] } ) ) ;
RD : : get_singleton ( ) - > compute_list_bind_uniform_set ( compute_list , uniform_set_cache - > get_cache ( blur_shader , 0 , u_ao_slices_with_sampler ) , 0 ) ;
2022-06-28 19:10:36 +10:00
}
2023-02-08 01:30:03 +11:00
RD : : Uniform u_ao_pong_slices ( RD : : UNIFORM_TYPE_IMAGE , 0 , Vector < RID > ( { ao_pong_slices [ i ] } ) ) ;
RD : : get_singleton ( ) - > compute_list_bind_uniform_set ( compute_list , uniform_set_cache - > get_cache ( blur_shader , 1 , u_ao_pong_slices ) , 1 ) ;
2022-06-28 19:10:36 +10:00
} else {
2022-09-29 15:37:10 +10:00
if ( ssao_quality = = RS : : ENV_SSAO_QUALITY_VERY_LOW ) {
2023-02-08 01:30:03 +11:00
RD : : Uniform u_ao_pong_slices_with_sampler ( RD : : UNIFORM_TYPE_SAMPLER_WITH_TEXTURE , 0 , Vector < RID > ( { default_sampler , ao_pong_slices [ i ] } ) ) ;
RD : : get_singleton ( ) - > compute_list_bind_uniform_set ( compute_list , uniform_set_cache - > get_cache ( blur_shader , 0 , u_ao_pong_slices_with_sampler ) , 0 ) ;
2022-06-28 19:10:36 +10:00
} else {
2023-02-08 01:30:03 +11:00
RD : : Uniform u_ao_pong_slices_with_sampler ( RD : : UNIFORM_TYPE_SAMPLER_WITH_TEXTURE , 0 , Vector < RID > ( { ss_effects . mirror_sampler , ao_pong_slices [ i ] } ) ) ;
RD : : get_singleton ( ) - > compute_list_bind_uniform_set ( compute_list , uniform_set_cache - > get_cache ( blur_shader , 0 , u_ao_pong_slices_with_sampler ) , 0 ) ;
2022-06-28 19:10:36 +10:00
}
2023-02-08 01:30:03 +11:00
RD : : Uniform u_ao_slices ( RD : : UNIFORM_TYPE_IMAGE , 0 , Vector < RID > ( { ao_deinterleaved_slices [ i ] } ) ) ;
RD : : get_singleton ( ) - > compute_list_bind_uniform_set ( compute_list , uniform_set_cache - > get_cache ( blur_shader , 1 , u_ao_slices ) , 1 ) ;
2022-06-28 19:10:36 +10:00
}
RD : : get_singleton ( ) - > compute_list_set_push_constant ( compute_list , & ssao . blur_push_constant , sizeof ( SSAOBlurPushConstant ) ) ;
2023-02-24 13:50:13 +11:00
RD : : get_singleton ( ) - > compute_list_dispatch_threads ( compute_list , p_ssao_buffers . buffer_width , p_ssao_buffers . buffer_height , 1 ) ;
2022-06-28 19:10:36 +10:00
}
2024-02-21 14:35:20 -08:00
RD : : get_singleton ( ) - > compute_list_add_barrier ( compute_list ) ;
2022-06-28 19:10:36 +10:00
}
RD : : get_singleton ( ) - > draw_command_end_label ( ) ; // Blur
}
/* FOURTH PASS */
// Interleave buffers
// back to full size
{
RD : : get_singleton ( ) - > draw_command_begin_label ( " Interleave Buffers " ) ;
ssao . interleave_push_constant . inv_sharpness = 1.0 - p_settings . sharpness ;
ssao . interleave_push_constant . pixel_size [ 0 ] = 1.0 / p_settings . full_screen_size . x ;
ssao . interleave_push_constant . pixel_size [ 1 ] = 1.0 / p_settings . full_screen_size . y ;
2022-09-29 15:37:10 +10:00
ssao . interleave_push_constant . size_modifier = uint32_t ( ssao_half_size ? 4 : 2 ) ;
2022-06-28 19:10:36 +10:00
shader = ssao . interleave_shader . version_get_shader ( ssao . interleave_shader_version , 0 ) ;
int interleave_pipeline = SSAO_INTERLEAVE_HALF ;
2022-09-29 15:37:10 +10:00
if ( ssao_quality = = RS : : ENV_SSAO_QUALITY_LOW ) {
2022-06-28 19:10:36 +10:00
interleave_pipeline = SSAO_INTERLEAVE ;
2022-09-29 15:37:10 +10:00
} else if ( ssao_quality > = RS : : ENV_SSAO_QUALITY_MEDIUM ) {
2022-06-28 19:10:36 +10:00
interleave_pipeline = SSAO_INTERLEAVE_SMART ;
}
2023-02-08 01:30:03 +11:00
RID interleave_shader = ssao . interleave_shader . version_get_shader ( ssao . interleave_shader_version , interleave_pipeline - SSAO_INTERLEAVE ) ;
2025-10-01 14:42:27 -03:00
RD : : get_singleton ( ) - > compute_list_bind_compute_pipeline ( compute_list , ssao . pipelines [ interleave_pipeline ] . get_rid ( ) ) ;
2022-06-28 19:10:36 +10:00
2023-02-08 01:30:03 +11:00
RD : : Uniform u_upscale_buffer ( RD : : UNIFORM_TYPE_IMAGE , 0 , Vector < RID > ( { ao_final } ) ) ;
RD : : get_singleton ( ) - > compute_list_bind_uniform_set ( compute_list , uniform_set_cache - > get_cache ( interleave_shader , 0 , u_upscale_buffer ) , 0 ) ;
2022-06-28 19:10:36 +10:00
2022-09-29 15:37:10 +10:00
if ( ssao_quality > RS : : ENV_SSAO_QUALITY_VERY_LOW & & ssao_blur_passes % 2 = = 0 ) {
2023-02-08 01:30:03 +11:00
RD : : Uniform u_ao ( RD : : UNIFORM_TYPE_SAMPLER_WITH_TEXTURE , 0 , Vector < RID > ( { default_sampler , ao_deinterleaved } ) ) ;
RD : : get_singleton ( ) - > compute_list_bind_uniform_set ( compute_list , uniform_set_cache - > get_cache ( interleave_shader , 1 , u_ao ) , 1 ) ;
2022-06-28 19:10:36 +10:00
} else {
2023-02-08 01:30:03 +11:00
RD : : Uniform u_ao ( RD : : UNIFORM_TYPE_SAMPLER_WITH_TEXTURE , 0 , Vector < RID > ( { default_sampler , ao_pong } ) ) ;
RD : : get_singleton ( ) - > compute_list_bind_uniform_set ( compute_list , uniform_set_cache - > get_cache ( interleave_shader , 1 , u_ao ) , 1 ) ;
2022-06-28 19:10:36 +10:00
}
RD : : get_singleton ( ) - > compute_list_set_push_constant ( compute_list , & ssao . interleave_push_constant , sizeof ( SSAOInterleavePushConstant ) ) ;
RD : : get_singleton ( ) - > compute_list_dispatch_threads ( compute_list , p_settings . full_screen_size . x , p_settings . full_screen_size . y , 1 ) ;
RD : : get_singleton ( ) - > compute_list_add_barrier ( compute_list ) ;
RD : : get_singleton ( ) - > draw_command_end_label ( ) ; // Interleave
}
RD : : get_singleton ( ) - > draw_command_end_label ( ) ; //SSAO
2023-11-24 08:23:22 -03:00
RD : : get_singleton ( ) - > compute_list_end ( ) ;
2022-06-28 19:10:36 +10:00
int zero [ 1 ] = { 0 } ;
2023-11-24 08:23:22 -03:00
RD : : get_singleton ( ) - > buffer_update ( ssao . importance_map_load_counter , 0 , sizeof ( uint32_t ) , & zero ) ;
2022-06-28 19:10:36 +10:00
}
/* Screen Space Reflection */
2025-09-16 15:17:49 +03:00
void SSEffects : : ssr_set_half_size ( bool p_half_size ) {
ssr_half_size = p_half_size ;
2022-09-29 15:37:10 +10:00
}
2025-09-16 15:17:49 +03:00
void SSEffects : : ssr_allocate_buffers ( Ref < RenderSceneBuffersRD > p_render_buffers , SSRRenderBuffers & p_ssr_buffers , const RD : : DataFormat p_color_format ) {
if ( p_ssr_buffers . half_size ! = ssr_half_size ) {
2023-02-08 01:30:03 +11:00
p_render_buffers - > clear_context ( RB_SCOPE_SSR ) ;
2022-10-02 20:08:07 +11:00
}
2025-09-16 15:17:49 +03:00
Vector2i internal_size = p_render_buffers - > get_internal_size ( ) ;
p_ssr_buffers . size = ssr_half_size ? ( internal_size / 2 ) : internal_size ;
2022-06-28 19:10:36 +10:00
2025-09-16 15:17:49 +03:00
uint32_t cur_width = p_ssr_buffers . size . width ;
uint32_t cur_height = p_ssr_buffers . size . height ;
p_ssr_buffers . mipmaps = 1 ;
2022-06-28 19:10:36 +10:00
2025-09-16 15:17:49 +03:00
while ( cur_width > 1 & & cur_height > 1 ) {
if ( cur_width > 1 ) {
cur_width / = 2 ;
}
if ( cur_height > 1 ) {
cur_height / = 2 ;
}
+ + p_ssr_buffers . mipmaps ;
}
p_ssr_buffers . half_size = ssr_half_size ;
uint32_t view_count = p_render_buffers - > get_view_count ( ) ;
2022-06-28 19:10:36 +10:00
2025-09-16 15:17:49 +03:00
if ( ssr_half_size ) {
p_render_buffers - > create_texture ( RB_SCOPE_SSR , RB_NORMAL_ROUGHNESS , RD : : DATA_FORMAT_R8G8B8A8_UNORM , RD : : TEXTURE_USAGE_SAMPLING_BIT | RD : : TEXTURE_USAGE_STORAGE_BIT , RD : : TEXTURE_SAMPLES_1 , p_ssr_buffers . size , view_count ) ;
2022-06-28 19:10:36 +10:00
}
2025-09-16 15:17:49 +03:00
p_render_buffers - > create_texture ( RB_SCOPE_SSR , RB_HIZ , RD : : DATA_FORMAT_R32_SFLOAT , RD : : TEXTURE_USAGE_SAMPLING_BIT | RD : : TEXTURE_USAGE_STORAGE_BIT , RD : : TEXTURE_SAMPLES_1 , p_ssr_buffers . size , view_count , p_ssr_buffers . mipmaps ) ;
p_render_buffers - > create_texture ( RB_SCOPE_SSR , RB_SSR , p_color_format , RD : : TEXTURE_USAGE_SAMPLING_BIT | RD : : TEXTURE_USAGE_STORAGE_BIT , RD : : TEXTURE_SAMPLES_1 , p_ssr_buffers . size , view_count , p_ssr_buffers . mipmaps ) ;
p_render_buffers - > create_texture ( RB_SCOPE_SSR , RB_MIP_LEVEL , RD : : DATA_FORMAT_R8_UNORM , RD : : TEXTURE_USAGE_SAMPLING_BIT | RD : : TEXTURE_USAGE_STORAGE_BIT , RD : : TEXTURE_SAMPLES_1 , p_ssr_buffers . size , view_count ) ;
if ( ssr_half_size ) {
p_render_buffers - > create_texture ( RB_SCOPE_SSR , RB_FINAL , p_color_format , RD : : TEXTURE_USAGE_SAMPLING_BIT | RD : : TEXTURE_USAGE_STORAGE_BIT , RD : : TEXTURE_SAMPLES_1 , internal_size , view_count ) ;
}
2022-06-28 19:10:36 +10:00
}
2025-09-16 15:17:49 +03:00
void SSEffects : : 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 ) {
2022-06-28 19:10:36 +10:00
UniformSetCacheRD * uniform_set_cache = UniformSetCacheRD : : get_singleton ( ) ;
ERR_FAIL_NULL ( uniform_set_cache ) ;
MaterialStorage * material_storage = MaterialStorage : : get_singleton ( ) ;
ERR_FAIL_NULL ( material_storage ) ;
2023-02-08 01:30:03 +11:00
uint32_t view_count = p_render_buffers - > get_view_count ( ) ;
2022-06-28 19:10:36 +10:00
{
// Store some scene data in a UBO, in the near future we will use a UBO shared with other shaders
ScreenSpaceReflectionSceneData scene_data ;
if ( ssr . ubo . is_null ( ) ) {
ssr . ubo = RD : : get_singleton ( ) - > uniform_buffer_create ( sizeof ( ScreenSpaceReflectionSceneData ) ) ;
}
2025-09-16 15:17:49 +03:00
Projection correction ;
correction . set_depth_correction ( true ) ;
2023-02-08 01:30:03 +11:00
for ( uint32_t v = 0 ; v < view_count ; v + + ) {
2025-09-16 15:17:49 +03:00
Projection projection = correction * p_projections [ v ] ;
store_camera ( projection , scene_data . projection [ v ] ) ;
store_camera ( projection . inverse ( ) , scene_data . inv_projection [ v ] ) ;
store_camera ( p_reprojections [ v ] , scene_data . reprojection [ v ] ) ;
2022-06-28 19:10:36 +10:00
scene_data . eye_offset [ v ] [ 0 ] = p_eye_offsets [ v ] . x ;
scene_data . eye_offset [ v ] [ 1 ] = p_eye_offsets [ v ] . y ;
scene_data . eye_offset [ v ] [ 2 ] = p_eye_offsets [ v ] . z ;
2025-09-16 15:17:49 +03:00
scene_data . eye_offset [ v ] [ 3 ] = 0.0f ;
2022-06-28 19:10:36 +10:00
}
2023-11-24 08:23:22 -03:00
RD : : get_singleton ( ) - > buffer_update ( ssr . ubo , 0 , sizeof ( ScreenSpaceReflectionSceneData ) , & scene_data ) ;
2022-06-28 19:10:36 +10:00
}
2025-09-16 15:17:49 +03:00
RID linear_sampler = material_storage - > sampler_rd_get_default ( RS : : CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS , RS : : CANVAS_ITEM_TEXTURE_REPEAT_DISABLED ) ;
RID nearest_sampler = material_storage - > sampler_rd_get_default ( RS : : CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS , RS : : CANVAS_ITEM_TEXTURE_REPEAT_DISABLED ) ;
2022-06-28 19:10:36 +10:00
2025-09-16 15:17:49 +03:00
if ( ssr_half_size ) {
RD : : get_singleton ( ) - > draw_command_begin_label ( " SSR Downsample " ) ;
2022-06-28 19:10:36 +10:00
2025-09-16 15:17:49 +03:00
for ( uint32_t v = 0 ; v < view_count ; v + + ) {
ScreenSpaceReflectionDownsamplePushConstant push_constant ;
push_constant . screen_size [ 0 ] = p_ssr_buffers . size . width ;
push_constant . screen_size [ 1 ] = p_ssr_buffers . size . height ;
2023-02-08 01:30:03 +11:00
2025-09-16 15:17:49 +03:00
RID source_depth_texture = p_render_buffers - > get_depth_texture ( v ) ;
RID dest_depth_texture = p_render_buffers - > get_texture_slice ( RB_SCOPE_SSR , RB_HIZ , v , 0 ) ;
RID dest_normal_roughness_texture = p_render_buffers - > get_texture_slice ( RB_SCOPE_SSR , RB_NORMAL_ROUGHNESS , v , 0 ) ;
Size2i parent_size = RD : : get_singleton ( ) - > texture_size ( source_depth_texture ) ;
bool is_width_odd = ( parent_size . width % 2 ) ! = 0 ;
bool is_height_odd = ( parent_size . height % 2 ) ! = 0 ;
int32_t downsample_mode ;
if ( is_width_odd & & is_height_odd ) {
downsample_mode = SCREEN_SPACE_REFLECTION_DOWNSAMPLE_ODD_WIDTH_AND_HEIGHT ;
} else if ( is_width_odd ) {
downsample_mode = SCREEN_SPACE_REFLECTION_DOWNSAMPLE_ODD_WIDTH ;
} else if ( is_height_odd ) {
downsample_mode = SCREEN_SPACE_REFLECTION_DOWNSAMPLE_ODD_HEIGHT ;
} else {
downsample_mode = SCREEN_SPACE_REFLECTION_DOWNSAMPLE_DEFAULT ;
}
RID downsample_shader = ssr . downsample_shader . version_get_shader ( ssr . downsample_shader_version , downsample_mode ) ;
RD : : Uniform u_source_depth ( RD : : UNIFORM_TYPE_SAMPLER_WITH_TEXTURE , 0 , Vector < RID > { nearest_sampler , source_depth_texture } ) ;
RD : : Uniform u_source_normal_roughness ( RD : : UNIFORM_TYPE_SAMPLER_WITH_TEXTURE , 1 , Vector < RID > { nearest_sampler , p_normal_roughness_slices [ v ] } ) ;
RD : : Uniform u_dest_depth ( RD : : UNIFORM_TYPE_IMAGE , 2 , dest_depth_texture ) ;
RD : : Uniform u_dest_normal_roughness ( RD : : UNIFORM_TYPE_IMAGE , 3 , dest_normal_roughness_texture ) ;
RD : : ComputeListID compute_list = RD : : get_singleton ( ) - > compute_list_begin ( ) ;
2022-06-28 19:10:36 +10:00
2025-09-16 15:17:49 +03:00
RD : : get_singleton ( ) - > compute_list_bind_compute_pipeline ( compute_list , ssr . downsample_pipelines [ downsample_mode ] . get_rid ( ) ) ;
RD : : get_singleton ( ) - > compute_list_bind_uniform_set ( compute_list , uniform_set_cache - > get_cache ( downsample_shader , 0 , u_source_depth , u_source_normal_roughness , u_dest_depth , u_dest_normal_roughness ) , 0 ) ;
RD : : get_singleton ( ) - > compute_list_set_push_constant ( compute_list , & push_constant , sizeof ( push_constant ) ) ;
RD : : get_singleton ( ) - > compute_list_dispatch_threads ( compute_list , push_constant . screen_size [ 0 ] , push_constant . screen_size [ 1 ] , 1 ) ;
2022-06-28 19:10:36 +10:00
2025-09-16 15:17:49 +03:00
RD : : get_singleton ( ) - > compute_list_end ( ) ;
}
2022-06-28 19:10:36 +10:00
2025-09-16 15:17:49 +03:00
RD : : get_singleton ( ) - > draw_command_end_label ( ) ;
} else {
RD : : get_singleton ( ) - > draw_command_begin_label ( " SSR Copy Depth " ) ;
2022-06-28 19:10:36 +10:00
2025-09-16 15:17:49 +03:00
for ( uint32_t v = 0 ; v < view_count ; v + + ) {
RID src_texture = p_render_buffers - > get_depth_texture ( v ) ;
RID dest_texture = p_render_buffers - > get_texture_slice ( RB_SCOPE_SSR , RB_HIZ , v , 0 ) ;
p_copy_effects . copy_depth_to_rect ( src_texture , dest_texture , Rect2i ( Vector2i ( ) , p_ssr_buffers . size ) ) ;
}
2022-06-28 19:10:36 +10:00
2025-09-16 15:17:49 +03:00
RD : : get_singleton ( ) - > draw_command_end_label ( ) ;
}
2022-06-28 19:10:36 +10:00
2025-09-16 15:17:49 +03:00
RD : : get_singleton ( ) - > draw_command_begin_label ( " SSR HI-Z " ) ;
2022-06-28 19:10:36 +10:00
2025-09-16 15:17:49 +03:00
for ( uint32_t v = 0 ; v < view_count ; v + + ) {
for ( uint32_t m = 1 ; m < p_ssr_buffers . mipmaps ; m + + ) {
ScreenSpaceReflectionHizPushConstant push_constant ;
push_constant . screen_size [ 0 ] = MAX ( 1 , p_ssr_buffers . size . width > > m ) ;
push_constant . screen_size [ 1 ] = MAX ( 1 , p_ssr_buffers . size . height > > m ) ;
2022-06-28 19:10:36 +10:00
2025-09-16 15:17:49 +03:00
RID source ;
2022-06-28 19:10:36 +10:00
2025-09-16 15:17:49 +03:00
if ( ! ssr_half_size & & m = = 1 ) { // Reuse the depth texture to not create a dependency on the previous depth copy pass.
source = p_render_buffers - > get_depth_texture ( v ) ;
} else {
source = p_render_buffers - > get_texture_slice ( RB_SCOPE_SSR , RB_HIZ , v , m - 1 ) ;
}
2022-06-28 19:10:36 +10:00
2025-09-16 15:17:49 +03:00
RID dest = p_render_buffers - > get_texture_slice ( RB_SCOPE_SSR , RB_HIZ , v , m ) ;
2022-06-28 19:10:36 +10:00
2025-09-16 15:17:49 +03:00
Size2i parent_size = RD : : get_singleton ( ) - > texture_size ( source ) ;
bool is_width_odd = ( parent_size . width % 2 ) ! = 0 ;
bool is_height_odd = ( parent_size . height % 2 ) ! = 0 ;
2022-06-28 19:10:36 +10:00
2025-09-16 15:17:49 +03:00
int32_t hiz_mode ;
if ( is_width_odd & & is_height_odd ) {
hiz_mode = SCREEN_SPACE_REFLECTION_HIZ_ODD_WIDTH_AND_HEIGHT ;
} else if ( is_width_odd ) {
hiz_mode = SCREEN_SPACE_REFLECTION_HIZ_ODD_WIDTH ;
} else if ( is_height_odd ) {
hiz_mode = SCREEN_SPACE_REFLECTION_HIZ_ODD_HEIGHT ;
2022-06-28 19:10:36 +10:00
} else {
2025-09-16 15:17:49 +03:00
hiz_mode = SCREEN_SPACE_REFLECTION_HIZ_DEFAULT ;
2022-06-28 19:10:36 +10:00
}
2025-09-16 15:17:49 +03:00
RID hiz_shader = ssr . hiz_shader . version_get_shader ( ssr . hiz_shader_version , hiz_mode ) ;
RD : : Uniform u_source ( RD : : UNIFORM_TYPE_SAMPLER_WITH_TEXTURE , 0 , Vector < RID > { nearest_sampler , source } ) ;
RD : : Uniform u_dest ( RD : : UNIFORM_TYPE_IMAGE , 1 , dest ) ;
2022-06-28 19:10:36 +10:00
2025-09-16 15:17:49 +03:00
RD : : ComputeListID compute_list = RD : : get_singleton ( ) - > compute_list_begin ( ) ;
2022-06-28 19:10:36 +10:00
2025-09-16 15:17:49 +03:00
RD : : get_singleton ( ) - > compute_list_bind_compute_pipeline ( compute_list , ssr . hiz_pipelines [ hiz_mode ] . get_rid ( ) ) ;
RD : : get_singleton ( ) - > compute_list_bind_uniform_set ( compute_list , uniform_set_cache - > get_cache ( hiz_shader , 0 , u_source , u_dest ) , 0 ) ;
RD : : get_singleton ( ) - > compute_list_set_push_constant ( compute_list , & push_constant , sizeof ( push_constant ) ) ;
RD : : get_singleton ( ) - > compute_list_dispatch_threads ( compute_list , push_constant . screen_size [ 0 ] , push_constant . screen_size [ 1 ] , 1 ) ;
2022-06-28 19:10:36 +10:00
2025-09-16 15:17:49 +03:00
RD : : get_singleton ( ) - > compute_list_end ( ) ;
2022-06-28 19:10:36 +10:00
}
2025-09-16 15:17:49 +03:00
}
2022-06-28 19:10:36 +10:00
2025-09-16 15:17:49 +03:00
RD : : get_singleton ( ) - > draw_command_end_label ( ) ;
2022-06-28 19:10:36 +10:00
2025-09-16 15:17:49 +03:00
RD : : get_singleton ( ) - > draw_command_begin_label ( " SSR Main " ) ;
2022-06-28 19:10:36 +10:00
2025-09-16 15:17:49 +03:00
RID ssr_shader = ssr . ssr_shader . version_get_shader ( ssr . ssr_shader_version , 0 ) ;
2022-06-28 19:10:36 +10:00
2025-09-16 15:17:49 +03:00
for ( uint32_t v = 0 ; v < view_count ; v + + ) {
RD : : ComputeListID compute_list = RD : : get_singleton ( ) - > compute_list_begin ( ) ;
RD : : get_singleton ( ) - > compute_list_bind_compute_pipeline ( compute_list , ssr . ssr_pipeline . get_rid ( ) ) ;
ScreenSpaceReflectionPushConstant push_constant ;
push_constant . screen_size [ 0 ] = p_ssr_buffers . size . width ;
push_constant . screen_size [ 1 ] = p_ssr_buffers . size . height ;
push_constant . mipmaps = p_ssr_buffers . mipmaps ;
push_constant . num_steps = p_max_steps ;
push_constant . curve_fade_in = p_fade_in ;
push_constant . distance_fade = p_fade_out ;
push_constant . depth_tolerance = p_tolerance ;
push_constant . orthogonal = p_projections [ v ] . is_orthogonal ( ) ;
push_constant . view_index = v ;
RID last_frame_texture = p_render_buffers - > get_texture_slice ( RB_SCOPE_SSLF , RB_LAST_FRAME , v , 0 ) ;
if ( ssr_half_size & & RD : : get_singleton ( ) - > texture_size ( last_frame_texture ) ! = p_ssr_buffers . size ) {
// SSIL is likely also enabled. The texture we need is in the second mipmap in this case.
last_frame_texture = p_render_buffers - > get_texture_slice ( RB_SCOPE_SSLF , RB_LAST_FRAME , v , 1 ) ;
}
RID hiz_texture = p_render_buffers - > get_texture_slice ( RB_SCOPE_SSR , RB_HIZ , v , 0 , 1 , p_ssr_buffers . mipmaps ) ;
RID normal_roughness_texture = ssr_half_size ? p_render_buffers - > get_texture_slice ( RB_SCOPE_SSR , RB_NORMAL_ROUGHNESS , v , 0 ) : p_normal_roughness_slices [ v ] ;
RID ssr_texture = p_render_buffers - > get_texture_slice ( RB_SCOPE_SSR , RB_SSR , v , 0 ) ;
RID mip_level_texture = p_render_buffers - > get_texture_slice ( RB_SCOPE_SSR , RB_MIP_LEVEL , v , 0 ) ;
RD : : Uniform u_last_frame ( RD : : UNIFORM_TYPE_SAMPLER_WITH_TEXTURE , 0 , Vector < RID > { linear_sampler , last_frame_texture } ) ;
RD : : Uniform u_hiz ( RD : : UNIFORM_TYPE_SAMPLER_WITH_TEXTURE , 1 , Vector < RID > { nearest_sampler , hiz_texture } ) ;
RD : : Uniform u_normal_roughness ( RD : : UNIFORM_TYPE_SAMPLER_WITH_TEXTURE , 2 , Vector < RID > { nearest_sampler , normal_roughness_texture } ) ;
RD : : Uniform u_ssr ( RD : : UNIFORM_TYPE_IMAGE , 3 , ssr_texture ) ;
RD : : Uniform u_mip_level ( RD : : UNIFORM_TYPE_IMAGE , 4 , mip_level_texture ) ;
RD : : Uniform u_scene_data ( RD : : UNIFORM_TYPE_UNIFORM_BUFFER , 5 , ssr . ubo ) ;
RD : : get_singleton ( ) - > compute_list_bind_uniform_set ( compute_list , uniform_set_cache - > get_cache ( ssr_shader , 0 , u_last_frame , u_hiz , u_normal_roughness , u_ssr , u_mip_level , u_scene_data ) , 0 ) ;
RD : : get_singleton ( ) - > compute_list_set_push_constant ( compute_list , & push_constant , sizeof ( push_constant ) ) ;
RD : : get_singleton ( ) - > compute_list_dispatch_threads ( compute_list , p_ssr_buffers . size . width , p_ssr_buffers . size . height , 1 ) ;
RD : : get_singleton ( ) - > compute_list_end ( ) ;
}
2022-06-28 19:10:36 +10:00
2025-09-16 15:17:49 +03:00
RD : : get_singleton ( ) - > draw_command_end_label ( ) ;
2022-06-28 19:10:36 +10:00
2025-09-16 15:17:49 +03:00
RD : : get_singleton ( ) - > draw_command_begin_label ( " SSR Roughness Filter " ) ;
2022-06-28 19:10:36 +10:00
2025-09-16 15:17:49 +03:00
RID filter_shader = ssr . filter_shader . version_get_shader ( ssr . filter_shader_version , 0 ) ;
2022-06-28 19:10:36 +10:00
2025-09-16 15:17:49 +03:00
for ( uint32_t v = 0 ; v < view_count ; v + + ) {
for ( uint32_t m = 1 ; m < p_ssr_buffers . mipmaps ; m + + ) {
ScreenSpaceReflectionFilterPushConstant push_constant ;
push_constant . screen_size [ 0 ] = MAX ( 1 , p_ssr_buffers . size . width > > m ) ;
push_constant . screen_size [ 1 ] = MAX ( 1 , p_ssr_buffers . size . height > > m ) ;
push_constant . mip_level = m ;
2022-06-28 19:10:36 +10:00
2025-09-16 15:17:49 +03:00
RID source = p_render_buffers - > get_texture_slice ( RB_SCOPE_SSR , RB_SSR , v , m - 1 ) ;
RID dest = p_render_buffers - > get_texture_slice ( RB_SCOPE_SSR , RB_SSR , v , m ) ;
2022-06-28 19:10:36 +10:00
2025-09-16 15:17:49 +03:00
RD : : Uniform u_source ( RD : : UNIFORM_TYPE_SAMPLER_WITH_TEXTURE , 0 , Vector < RID > { linear_sampler , source } ) ;
RD : : Uniform u_dest ( RD : : UNIFORM_TYPE_IMAGE , 1 , dest ) ;
2022-06-28 19:10:36 +10:00
2025-09-16 15:17:49 +03:00
RD : : ComputeListID compute_list = RD : : get_singleton ( ) - > compute_list_begin ( ) ;
2022-06-28 19:10:36 +10:00
2025-09-16 15:17:49 +03:00
RD : : get_singleton ( ) - > compute_list_bind_compute_pipeline ( compute_list , ssr . filter_pipeline . get_rid ( ) ) ;
RD : : get_singleton ( ) - > compute_list_bind_uniform_set ( compute_list , uniform_set_cache - > get_cache ( filter_shader , 0 , u_source , u_dest ) , 0 ) ;
RD : : get_singleton ( ) - > compute_list_set_push_constant ( compute_list , & push_constant , sizeof ( push_constant ) ) ;
RD : : get_singleton ( ) - > compute_list_dispatch_threads ( compute_list , push_constant . screen_size [ 0 ] , push_constant . screen_size [ 1 ] , 1 ) ;
2022-06-28 19:10:36 +10:00
2025-09-16 15:17:49 +03:00
RD : : get_singleton ( ) - > compute_list_end ( ) ;
}
}
2023-02-08 01:30:03 +11:00
2025-09-16 15:17:49 +03:00
RD : : get_singleton ( ) - > draw_command_end_label ( ) ;
if ( ssr_half_size ) {
RD : : get_singleton ( ) - > draw_command_begin_label ( " SSR Resolve " ) ;
2022-06-28 19:10:36 +10:00
2025-09-16 15:17:49 +03:00
RID resolve_shader = ssr . resolve_shader . version_get_shader ( ssr . resolve_shader_version , 0 ) ;
2022-06-28 19:10:36 +10:00
2025-09-16 15:17:49 +03:00
for ( uint32_t v = 0 ; v < view_count ; v + + ) {
RD : : ComputeListID compute_list = RD : : get_singleton ( ) - > compute_list_begin ( ) ;
2022-06-28 19:10:36 +10:00
2025-09-16 15:17:49 +03:00
RD : : get_singleton ( ) - > compute_list_bind_compute_pipeline ( compute_list , ssr . resolve_pipeline . get_rid ( ) ) ;
2022-06-28 19:10:36 +10:00
2025-09-16 15:17:49 +03:00
Vector2i internal_size = p_render_buffers - > get_internal_size ( ) ;
2022-06-28 19:10:36 +10:00
2025-09-16 15:17:49 +03:00
ScreenSpaceReflectionResolvePushConstant push_constant ;
push_constant . screen_size [ 0 ] = internal_size . x ;
push_constant . screen_size [ 1 ] = internal_size . y ;
2022-06-28 19:10:36 +10:00
2025-09-16 15:17:49 +03:00
RID depth_texture = p_render_buffers - > get_depth_texture ( v ) ;
RID depth_half_texture = p_render_buffers - > get_texture_slice ( RB_SCOPE_SSR , RB_HIZ , v , 0 ) ;
RID normal_roughness_half_texture = p_render_buffers - > get_texture_slice ( RB_SCOPE_SSR , RB_NORMAL_ROUGHNESS , v , 0 ) ;
RID ssr_texture = p_render_buffers - > get_texture_slice ( RB_SCOPE_SSR , RB_SSR , v , 0 , 1 , p_ssr_buffers . mipmaps ) ;
RID mip_level_texture = p_render_buffers - > get_texture_slice ( RB_SCOPE_SSR , RB_MIP_LEVEL , v , 0 ) ;
RID output_texture = p_render_buffers - > get_texture_slice ( RB_SCOPE_SSR , RB_FINAL , v , 0 ) ;
2022-06-28 19:10:36 +10:00
2025-09-16 15:17:49 +03:00
RD : : Uniform u_depth ( RD : : UNIFORM_TYPE_SAMPLER_WITH_TEXTURE , 0 , Vector < RID > { nearest_sampler , depth_texture } ) ;
RD : : Uniform u_normal_roughness ( RD : : UNIFORM_TYPE_SAMPLER_WITH_TEXTURE , 1 , Vector < RID > { nearest_sampler , p_normal_roughness_slices [ v ] } ) ;
RD : : Uniform u_depth_half ( RD : : UNIFORM_TYPE_SAMPLER_WITH_TEXTURE , 2 , Vector < RID > { nearest_sampler , depth_half_texture } ) ;
RD : : Uniform u_normal_roughness_half ( RD : : UNIFORM_TYPE_SAMPLER_WITH_TEXTURE , 3 , Vector < RID > { nearest_sampler , normal_roughness_half_texture } ) ;
RD : : Uniform u_ssr ( RD : : UNIFORM_TYPE_SAMPLER_WITH_TEXTURE , 4 , Vector < RID > { linear_sampler , ssr_texture } ) ;
RD : : Uniform u_mip_level ( RD : : UNIFORM_TYPE_SAMPLER_WITH_TEXTURE , 5 , Vector < RID > { nearest_sampler , mip_level_texture } ) ;
RD : : Uniform u_output ( RD : : UNIFORM_TYPE_IMAGE , 6 , output_texture ) ;
RD : : get_singleton ( ) - > compute_list_bind_uniform_set ( compute_list , uniform_set_cache - > get_cache ( resolve_shader , 0 , u_depth , u_normal_roughness , u_depth_half , u_normal_roughness_half , u_ssr , u_mip_level , u_output ) , 0 ) ;
2022-06-28 19:10:36 +10:00
2025-09-16 15:17:49 +03:00
RD : : get_singleton ( ) - > compute_list_set_push_constant ( compute_list , & push_constant , sizeof ( push_constant ) ) ;
RD : : get_singleton ( ) - > compute_list_dispatch_threads ( compute_list , internal_size . width , internal_size . height , 1 ) ;
RD : : get_singleton ( ) - > compute_list_end ( ) ;
2022-06-28 19:10:36 +10:00
}
RD : : get_singleton ( ) - > draw_command_end_label ( ) ;
}
}
2022-08-04 18:40:39 +10:00
/* Subsurface scattering */
2022-09-29 15:37:10 +10:00
void SSEffects : : sss_set_quality ( RS : : SubSurfaceScatteringQuality p_quality ) {
sss_quality = p_quality ;
}
RS : : SubSurfaceScatteringQuality SSEffects : : sss_get_quality ( ) const {
return sss_quality ;
}
void SSEffects : : sss_set_scale ( float p_scale , float p_depth_scale ) {
sss_scale = p_scale ;
sss_depth_scale = p_depth_scale ;
}
void SSEffects : : sub_surface_scattering ( Ref < RenderSceneBuffersRD > p_render_buffers , RID p_diffuse , RID p_depth , const Projection & p_camera , const Size2i & p_screen_size ) {
2022-08-04 18:40:39 +10:00
UniformSetCacheRD * uniform_set_cache = UniformSetCacheRD : : get_singleton ( ) ;
ERR_FAIL_NULL ( uniform_set_cache ) ;
MaterialStorage * material_storage = MaterialStorage : : get_singleton ( ) ;
ERR_FAIL_NULL ( material_storage ) ;
RID default_sampler = material_storage - > sampler_rd_get_default ( RS : : CANVAS_ITEM_TEXTURE_FILTER_LINEAR , RS : : CANVAS_ITEM_TEXTURE_REPEAT_DISABLED ) ;
// Our intermediate buffer is only created if we haven't created it already.
RD : : DataFormat format = p_render_buffers - > get_base_data_format ( ) ;
uint32_t usage_bits = RD : : TEXTURE_USAGE_SAMPLING_BIT | RD : : TEXTURE_USAGE_CAN_COPY_TO_BIT | RD : : TEXTURE_USAGE_STORAGE_BIT ;
uint32_t layers = 1 ; // We only need one layer, we're handling one view at a time
uint32_t mipmaps = 1 ; // Image::get_image_required_mipmaps(p_screen_size.x, p_screen_size.y, Image::FORMAT_RGBAH);
RID intermediate = p_render_buffers - > create_texture ( SNAME ( " SSR " ) , SNAME ( " intermediate " ) , format , usage_bits , RD : : TEXTURE_SAMPLES_1 , p_screen_size , layers , mipmaps ) ;
Plane p = p_camera . xform4 ( Plane ( 1 , 0 , - 1 , 1 ) ) ;
p . normal / = p . d ;
float unit_size = p . normal . x ;
{ //scale color and depth to half
RD : : ComputeListID compute_list = RD : : get_singleton ( ) - > compute_list_begin ( ) ;
sss . push_constant . camera_z_far = p_camera . get_z_far ( ) ;
sss . push_constant . camera_z_near = p_camera . get_z_near ( ) ;
sss . push_constant . orthogonal = p_camera . is_orthogonal ( ) ;
sss . push_constant . unit_size = unit_size ;
sss . push_constant . screen_size [ 0 ] = p_screen_size . x ;
sss . push_constant . screen_size [ 1 ] = p_screen_size . y ;
sss . push_constant . vertical = false ;
2022-09-29 15:37:10 +10:00
sss . push_constant . scale = sss_scale ;
sss . push_constant . depth_scale = sss_depth_scale ;
2022-08-04 18:40:39 +10:00
2022-09-29 15:37:10 +10:00
RID shader = sss . shader . version_get_shader ( sss . shader_version , sss_quality - 1 ) ;
2025-10-01 14:42:27 -03:00
RD : : get_singleton ( ) - > compute_list_bind_compute_pipeline ( compute_list , sss . pipelines [ sss_quality - 1 ] . get_rid ( ) ) ;
2022-08-04 18:40:39 +10:00
RD : : Uniform u_diffuse_with_sampler ( RD : : UNIFORM_TYPE_SAMPLER_WITH_TEXTURE , 0 , Vector < RID > ( { default_sampler , p_diffuse } ) ) ;
RD : : Uniform u_diffuse ( RD : : UNIFORM_TYPE_IMAGE , 0 , Vector < RID > ( { p_diffuse } ) ) ;
RD : : Uniform u_intermediate_with_sampler ( RD : : UNIFORM_TYPE_SAMPLER_WITH_TEXTURE , 0 , Vector < RID > ( { default_sampler , intermediate } ) ) ;
RD : : Uniform u_intermediate ( RD : : UNIFORM_TYPE_IMAGE , 0 , Vector < RID > ( { intermediate } ) ) ;
RD : : Uniform u_depth_with_sampler ( RD : : UNIFORM_TYPE_SAMPLER_WITH_TEXTURE , 0 , Vector < RID > ( { default_sampler , p_depth } ) ) ;
// horizontal
RD : : get_singleton ( ) - > compute_list_bind_uniform_set ( compute_list , uniform_set_cache - > get_cache ( shader , 0 , u_diffuse_with_sampler ) , 0 ) ;
RD : : get_singleton ( ) - > compute_list_bind_uniform_set ( compute_list , uniform_set_cache - > get_cache ( shader , 1 , u_intermediate ) , 1 ) ;
RD : : get_singleton ( ) - > compute_list_bind_uniform_set ( compute_list , uniform_set_cache - > get_cache ( shader , 2 , u_depth_with_sampler ) , 2 ) ;
RD : : get_singleton ( ) - > compute_list_set_push_constant ( compute_list , & sss . push_constant , sizeof ( SubSurfaceScatteringPushConstant ) ) ;
RD : : get_singleton ( ) - > compute_list_dispatch_threads ( compute_list , p_screen_size . width , p_screen_size . height , 1 ) ;
RD : : get_singleton ( ) - > compute_list_add_barrier ( compute_list ) ;
// vertical
RD : : get_singleton ( ) - > compute_list_bind_uniform_set ( compute_list , uniform_set_cache - > get_cache ( shader , 0 , u_intermediate_with_sampler ) , 0 ) ;
RD : : get_singleton ( ) - > compute_list_bind_uniform_set ( compute_list , uniform_set_cache - > get_cache ( shader , 1 , u_diffuse ) , 1 ) ;
RD : : get_singleton ( ) - > compute_list_bind_uniform_set ( compute_list , uniform_set_cache - > get_cache ( shader , 2 , u_depth_with_sampler ) , 2 ) ;
sss . push_constant . vertical = true ;
RD : : get_singleton ( ) - > compute_list_set_push_constant ( compute_list , & sss . push_constant , sizeof ( SubSurfaceScatteringPushConstant ) ) ;
RD : : get_singleton ( ) - > compute_list_dispatch_threads ( compute_list , p_screen_size . width , p_screen_size . height , 1 ) ;
RD : : get_singleton ( ) - > compute_list_end ( ) ;
}
}