diff --git a/COPYRIGHT.txt b/COPYRIGHT.txt index c77aa15c6c03..25702a8d29ff 100644 --- a/COPYRIGHT.txt +++ b/COPYRIGHT.txt @@ -170,6 +170,11 @@ Comment: Intel ASSAO and related files Copyright: 2016, Intel Corporation License: Expat +Files: ./servers/rendering/renderer_rd/shaders/ssao.glsl +Comment: Intel XeGTAO +Copyright: 2021, Intel Corporation +License: Expat + Files: servers/rendering/renderer_rd/shaders/effects/taa_resolve.glsl Comment: Temporal Anti-Aliasing resolve implementation Copyright: 2016, Panos Karabelas diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index 293647dc9aad..429509e27b78 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -1113,7 +1113,7 @@ void RasterizerSceneGLES3::environment_set_ssr_half_size(bool p_half_size) { void RasterizerSceneGLES3::environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) { } -void RasterizerSceneGLES3::environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) { +void RasterizerSceneGLES3::environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, RS::EnvironmentSSAOType p_type, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) { } void RasterizerSceneGLES3::environment_set_ssil_quality(RS::EnvironmentSSILQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) { diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h index e46a87885629..21926503ca6e 100644 --- a/drivers/gles3/rasterizer_scene_gles3.h +++ b/drivers/gles3/rasterizer_scene_gles3.h @@ -880,7 +880,7 @@ class RasterizerSceneGLES3 : public RendererSceneRender { void environment_set_ssr_half_size(bool p_half_size) override; void environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) override; - void environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) override; + void environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, RS::EnvironmentSSAOType p_type, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) override; void environment_set_ssil_quality(RS::EnvironmentSSILQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) override; diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index cb5ce09444a9..e0a9822baf25 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -467,7 +467,7 @@ void EditorNode::_update_from_settings() { RS::DOFBlurQuality dof_quality = RS::DOFBlurQuality(int(GLOBAL_GET("rendering/camera/depth_of_field/depth_of_field_bokeh_quality"))); bool dof_jitter = GLOBAL_GET("rendering/camera/depth_of_field/depth_of_field_use_jitter"); RS::get_singleton()->camera_attributes_set_dof_blur_quality(dof_quality, dof_jitter); - RS::get_singleton()->environment_set_ssao_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")); + RS::get_singleton()->environment_set_ssao_quality(RS::EnvironmentSSAOQuality(int(GLOBAL_GET("rendering/environment/ssao/quality"))), RS::EnvironmentSSAOType(int(GLOBAL_GET("rendering/environment/ssao/type"))), 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")); RS::get_singleton()->screen_space_roughness_limiter_set_active(GLOBAL_GET("rendering/anti_aliasing/screen_space_roughness_limiter/enabled"), GLOBAL_GET("rendering/anti_aliasing/screen_space_roughness_limiter/amount"), GLOBAL_GET("rendering/anti_aliasing/screen_space_roughness_limiter/limit")); bool glow_bicubic = int(GLOBAL_GET("rendering/environment/glow/upscale_mode")) > 0; RS::get_singleton()->environment_set_ssil_quality(RS::EnvironmentSSILQuality(int(GLOBAL_GET("rendering/environment/ssil/quality"))), GLOBAL_GET("rendering/environment/ssil/half_size"), GLOBAL_GET("rendering/environment/ssil/adaptive_target"), GLOBAL_GET("rendering/environment/ssil/blur_passes"), GLOBAL_GET("rendering/environment/ssil/fadeout_from"), GLOBAL_GET("rendering/environment/ssil/fadeout_to")); diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp index 32dc79aa4e58..18c230053c48 100644 --- a/scene/resources/environment.cpp +++ b/scene/resources/environment.cpp @@ -357,6 +357,15 @@ float Environment::get_ssao_sharpness() const { return ssao_sharpness; } +void Environment::set_ssao_thickness_heuristic(float p_thickness_heuristic) { + ssao_thickness_heuristic = p_thickness_heuristic; + _update_ssao(); +} + +float Environment::get_ssao_thickness_heuristic() const { + return ssao_thickness_heuristic; +} + void Environment::set_ssao_direct_light_affect(float p_direct_light_affect) { ssao_direct_light_affect = p_direct_light_affect; _update_ssao(); @@ -385,6 +394,7 @@ void Environment::_update_ssao() { ssao_detail, ssao_horizon, ssao_sharpness, + ssao_thickness_heuristic, ssao_direct_light_affect, ssao_ao_channel_affect); } @@ -1284,6 +1294,8 @@ void Environment::_bind_methods() { ClassDB::bind_method(D_METHOD("get_ssao_horizon"), &Environment::get_ssao_horizon); ClassDB::bind_method(D_METHOD("set_ssao_sharpness", "sharpness"), &Environment::set_ssao_sharpness); ClassDB::bind_method(D_METHOD("get_ssao_sharpness"), &Environment::get_ssao_sharpness); + ClassDB::bind_method(D_METHOD("set_ssao_thickness_heuristic", "thickness_heuristic"), &Environment::set_ssao_thickness_heuristic); + ClassDB::bind_method(D_METHOD("get_ssao_thickness_heuristic"), &Environment::get_ssao_thickness_heuristic); ClassDB::bind_method(D_METHOD("set_ssao_direct_light_affect", "amount"), &Environment::set_ssao_direct_light_affect); ClassDB::bind_method(D_METHOD("get_ssao_direct_light_affect"), &Environment::get_ssao_direct_light_affect); ClassDB::bind_method(D_METHOD("set_ssao_ao_channel_affect", "amount"), &Environment::set_ssao_ao_channel_affect); @@ -1297,6 +1309,7 @@ void Environment::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssao_detail", PROPERTY_HINT_RANGE, "0,5,0.01"), "set_ssao_detail", "get_ssao_detail"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssao_horizon", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_ssao_horizon", "get_ssao_horizon"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssao_sharpness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_ssao_sharpness", "get_ssao_sharpness"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssao_thickness_heuristic", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_ssao_thickness_heuristic", "get_ssao_thickness_heuristic"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssao_light_affect", PROPERTY_HINT_RANGE, "0.00,1,0.01"), "set_ssao_direct_light_affect", "get_ssao_direct_light_affect"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ssao_ao_channel_affect", PROPERTY_HINT_RANGE, "0.00,1,0.01"), "set_ssao_ao_channel_affect", "get_ssao_ao_channel_affect"); diff --git a/scene/resources/environment.h b/scene/resources/environment.h index cb6fa57775c6..50a310c48479 100644 --- a/scene/resources/environment.h +++ b/scene/resources/environment.h @@ -133,6 +133,8 @@ class Environment : public Resource { float ssao_detail = 0.5; float ssao_horizon = 0.06; float ssao_sharpness = 0.98; + // Only used for GTAO + float ssao_thickness_heuristic = 0.5; float ssao_direct_light_affect = 0.0; float ssao_ao_channel_affect = 0.0; void _update_ssao(); @@ -299,6 +301,8 @@ class Environment : public Resource { float get_ssao_horizon() const; void set_ssao_sharpness(float p_sharpness); float get_ssao_sharpness() const; + void set_ssao_thickness_heuristic(float p_thickness_heuristic); + float get_ssao_thickness_heuristic() const; void set_ssao_direct_light_affect(float p_direct_light_affect); float get_ssao_direct_light_affect() const; void set_ssao_ao_channel_affect(float p_ao_channel_affect); diff --git a/servers/rendering/dummy/rasterizer_scene_dummy.h b/servers/rendering/dummy/rasterizer_scene_dummy.h index ad255124f8f6..aefd17c3a016 100644 --- a/servers/rendering/dummy/rasterizer_scene_dummy.h +++ b/servers/rendering/dummy/rasterizer_scene_dummy.h @@ -123,7 +123,7 @@ class RasterizerSceneDummy : public RendererSceneRender { void environment_set_ssr_half_size(bool p_half_size) override {} void environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) override {} - void environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) override {} + void environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, RS::EnvironmentSSAOType p_type, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) override {} void environment_set_ssil_quality(RS::EnvironmentSSILQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) override {} diff --git a/servers/rendering/renderer_rd/effects/ss_effects.cpp b/servers/rendering/renderer_rd/effects/ss_effects.cpp index 971bd61abcdb..ec34ed800026 100644 --- a/servers/rendering/renderer_rd/effects/ss_effects.cpp +++ b/servers/rendering/renderer_rd/effects/ss_effects.cpp @@ -177,7 +177,7 @@ SSEffects::SSEffects() { } // 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")); + ssao_set_quality(RS::EnvironmentSSAOQuality(int(GLOBAL_GET("rendering/environment/ssao/quality"))), RS::EnvironmentSSAOType(int(GLOBAL_GET("rendering/environment/ssao/type"))), 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")); { RD::SamplerState sampler; @@ -196,12 +196,13 @@ SSEffects::SSEffects() { ssao_modes.push_back("\n"); ssao_modes.push_back("\n#define SSAO_BASE\n"); ssao_modes.push_back("\n#define ADAPTIVE\n"); + ssao_modes.push_back("\n#define SSAO_TYPE_GTAO\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++) { + for (int i = 0; i <= SSAO_GATHER_GTAO; i++) { ssao.pipelines[pipeline].create_compute_pipeline(ssao.gather_shader.version_get_shader(ssao.gather_shader_version, i)); pipeline++; } @@ -705,7 +706,8 @@ void SSEffects::ssil_allocate_buffers(Ref p_render_buffers // These are automatically cached and cleaned up when our viewport resizes // or when our viewport gets destroyed. - 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... + 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); } @@ -1045,8 +1047,9 @@ void SSEffects::screen_space_indirect_lighting(Ref p_rende /* SSAO */ -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) { +void SSEffects::ssao_set_quality(RS::EnvironmentSSAOQuality p_quality, RS::EnvironmentSSAOType p_type, 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_type = p_type; ssao_half_size = p_half_size; ssao_adaptive_target = p_adaptive_target; ssao_blur_passes = p_blur_passes; @@ -1063,9 +1066,20 @@ void SSEffects::gather_ssao(RD::ComputeListID p_compute_list, const RID *p_ao_sl RD::get_singleton()->compute_list_bind_uniform_set(p_compute_list, p_importance_map_uniform_set, 1); } - RID shader = ssao.gather_shader.version_get_shader(ssao.gather_shader_version, 1); // + int variant_id; + if (ssao_type == RS::ENV_SSAO_TYPE_GTAO) { + variant_id = 3; + } else { + variant_id = 1; + } + RID shader = ssao.gather_shader.version_get_shader(ssao.gather_shader_version, variant_id); // for (int i = 0; i < 4; i++) { + // Only do two pass for GTAO + if ((ssao_type == RS::ENV_SSAO_TYPE_GTAO) && ((i == 1) || (i == 2))) { + continue; + } + if ((ssao_quality == RS::ENV_SSAO_QUALITY_VERY_LOW) && ((i == 1) || (i == 2))) { continue; } @@ -1151,7 +1165,7 @@ void SSEffects::generate_ssao(Ref p_render_buffers, SSAORe memset(&ssao.gather_push_constant, 0, sizeof(SSAOGatherPushConstant)); /* FIRST PASS */ - RID shader = ssao.gather_shader.version_get_shader(ssao.gather_shader_version, SSAO_GATHER); + RID shader = ssao.gather_shader.version_get_shader(ssao.gather_shader_version, SSAO_GATHER_ASSAO); RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); RD::get_singleton()->draw_command_begin_label("Process Screen-Space Ambient Occlusion"); @@ -1204,6 +1218,12 @@ void SSEffects::generate_ssao(Ref p_render_buffers, SSAORe ssao.gather_push_constant.quality = MAX(0, ssao_quality - 1); ssao.gather_push_constant.size_multiplier = ssao_half_size ? 2 : 1; + if (ssao_type == RS::ENV_SSAO_TYPE_GTAO) { + float inv_tan_half_fov_x = p_projection.columns[0][0]; + ssao.gather_push_constant.fov_scale = inv_tan_half_fov_x * p_ssao_buffers.buffer_height; + ssao.gather_push_constant.thickness_heuristic = p_settings.thickness_heuristic; + } + // 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. @@ -1248,11 +1268,11 @@ void SSEffects::generate_ssao(Ref p_render_buffers, SSAORe 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); + RID shader_adaptive = ssao.gather_shader.version_get_shader(ssao.gather_shader_version, SSAO_GATHER_ASSAO_ADAPTIVE); importance_map_uniform_set = uniform_set_cache->get_cache(shader_adaptive, 1, u_pong, u_importance_map, u_load_counter); } - if (ssao_quality == RS::ENV_SSAO_QUALITY_ULTRA) { + if (ssao_type == RS::ENV_SSAO_TYPE_ASSAO && ssao_quality == RS::ENV_SSAO_QUALITY_ULTRA) { 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; @@ -1260,7 +1280,7 @@ void SSEffects::generate_ssao(Ref p_render_buffers, SSAORe ssao.importance_map_push_constant.power = p_settings.power; //base pass - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[SSAO_GATHER_BASE].get_rid()); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[SSAO_GATHER_ASSAO_BASE].get_rid()); gather_ssao(compute_list, ao_pong_slices, p_settings, true, gather_uniform_set, RID()); //generate importance map @@ -1304,10 +1324,16 @@ void SSEffects::generate_ssao(Ref p_render_buffers, SSAORe 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); - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[SSAO_GATHER_ADAPTIVE].get_rid()); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[SSAO_GATHER_ASSAO_ADAPTIVE].get_rid()); RD::get_singleton()->draw_command_end_label(); // Importance Map } else { - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[SSAO_GATHER].get_rid()); + int pipeline_id; + if (ssao_type == RS::ENV_SSAO_TYPE_GTAO) { + pipeline_id = SSAO_GATHER_GTAO; + } else { + pipeline_id = SSAO_GATHER_ASSAO; + } + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[pipeline_id].get_rid()); } gather_ssao(compute_list, ao_deinterleaved_slices, p_settings, false, gather_uniform_set, importance_map_uniform_set); @@ -1390,10 +1416,13 @@ void SSEffects::generate_ssao(Ref p_render_buffers, SSAORe shader = ssao.interleave_shader.version_get_shader(ssao.interleave_shader_version, 0); int interleave_pipeline = SSAO_INTERLEAVE_HALF; - if (ssao_quality == RS::ENV_SSAO_QUALITY_LOW) { - interleave_pipeline = SSAO_INTERLEAVE; - } else if (ssao_quality >= RS::ENV_SSAO_QUALITY_MEDIUM) { - interleave_pipeline = SSAO_INTERLEAVE_SMART; + // Always do half sample interleave for GTAO + if (ssao_type == RS::ENV_SSAO_TYPE_ASSAO) { + if (ssao_quality == RS::ENV_SSAO_QUALITY_LOW) { + interleave_pipeline = SSAO_INTERLEAVE; + } else if (ssao_quality >= RS::ENV_SSAO_QUALITY_MEDIUM) { + interleave_pipeline = SSAO_INTERLEAVE_SMART; + } } RID interleave_shader = ssao.interleave_shader.version_get_shader(ssao.interleave_shader_version, interleave_pipeline - SSAO_INTERLEAVE); @@ -1765,7 +1794,8 @@ void SSEffects::sub_surface_scattering(Ref p_render_buffer p.normal /= p.d; float unit_size = p.normal.x; - { //scale color and depth to half + { + //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(); diff --git a/servers/rendering/renderer_rd/effects/ss_effects.h b/servers/rendering/renderer_rd/effects/ss_effects.h index f41f871bec90..19630ff07b29 100644 --- a/servers/rendering/renderer_rd/effects/ss_effects.h +++ b/servers/rendering/renderer_rd/effects/ss_effects.h @@ -117,7 +117,7 @@ class SSEffects { void screen_space_indirect_lighting(Ref 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); /* SSAO */ - void 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); + void ssao_set_quality(RS::EnvironmentSSAOQuality p_quality, RS::EnvironmentSSAOType p_type, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to); struct SSAORenderBuffers { bool half_size = false; @@ -134,6 +134,8 @@ class SSEffects { float detail = 0.5; float horizon = 0.06; float sharpness = 0.98; + // Only used for GTAO + float thickness_heuristic = 0.5; Size2i full_screen_size; }; @@ -164,6 +166,8 @@ class SSEffects { /* Settings */ RS::EnvironmentSSAOQuality ssao_quality = RS::ENV_SSAO_QUALITY_MEDIUM; + RS::EnvironmentSSAOType ssao_type = RS::ENV_SSAO_TYPE_ASSAO; + bool ssao_half_size = false; float ssao_adaptive_target = 0.5; int ssao_blur_passes = 2; @@ -326,9 +330,10 @@ class SSEffects { /* SSAO */ enum SSAOMode { - SSAO_GATHER, - SSAO_GATHER_BASE, - SSAO_GATHER_ADAPTIVE, + SSAO_GATHER_ASSAO, + SSAO_GATHER_ASSAO_BASE, + SSAO_GATHER_ASSAO_ADAPTIVE, + SSAO_GATHER_GTAO, SSAO_GENERATE_IMPORTANCE_MAP, SSAO_PROCESS_IMPORTANCE_MAPA, SSAO_PROCESS_IMPORTANCE_MAPB, @@ -353,7 +358,6 @@ class SSEffects { float NDC_to_view_mul[2]; float NDC_to_view_add[2]; - float pad[2]; float half_screen_pixel_size_x025[2]; float radius; @@ -363,8 +367,13 @@ class SSEffects { float fade_out_mul; float fade_out_add; + + // ASSAO-specific float horizon_angle_threshold; float inv_radius_near_limit; + // GTAO-specific + float thickness_heuristic; + float fov_scale; uint32_t is_orthogonal; float neg_inv_radius; diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp index c4c6edec30cc..3e1f60437b17 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp @@ -1383,6 +1383,7 @@ void RenderForwardClustered::_process_ssao(Ref p_render_bu settings.detail = environment_get_ssao_detail(p_environment); settings.horizon = environment_get_ssao_horizon(p_environment); settings.sharpness = environment_get_ssao_sharpness(p_environment); + settings.thickness_heuristic = environment_get_ssao_thickness_heuristic(p_environment); settings.full_screen_size = p_render_buffers->get_internal_size(); ss_effects->ssao_allocate_buffers(p_render_buffers, rb_data->ss_effects_data.ssao, settings); @@ -3823,10 +3824,10 @@ RID RenderForwardClustered::_render_buffers_get_velocity_texture(Refget_velocity_buffer(false); } -void RenderForwardClustered::environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) { +void RenderForwardClustered::environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, RS::EnvironmentSSAOType p_type, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) { ERR_FAIL_NULL(ss_effects); ERR_FAIL_COND(p_quality < RS::EnvironmentSSAOQuality::ENV_SSAO_QUALITY_VERY_LOW || p_quality > RS::EnvironmentSSAOQuality::ENV_SSAO_QUALITY_ULTRA); - ss_effects->ssao_set_quality(p_quality, p_half_size, p_adaptive_target, p_blur_passes, p_fadeout_from, p_fadeout_to); + ss_effects->ssao_set_quality(p_quality, p_type, p_half_size, p_adaptive_target, p_blur_passes, p_fadeout_from, p_fadeout_to); } void RenderForwardClustered::environment_set_ssil_quality(RS::EnvironmentSSILQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) { diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h index 3605389b0b62..64c0cca06a2d 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h @@ -775,7 +775,7 @@ class RenderForwardClustered : public RendererSceneRenderRD { virtual RID _render_buffers_get_normal_texture(Ref p_render_buffers) override; virtual RID _render_buffers_get_velocity_texture(Ref p_render_buffers) override; - virtual void environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) override; + virtual void environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, RS::EnvironmentSSAOType p_type, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) override; virtual void environment_set_ssil_quality(RS::EnvironmentSSILQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) override; virtual void environment_set_ssr_half_size(bool p_half_size) override; virtual void environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) override; diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h index ba8409d72858..66b038c0f221 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h @@ -419,7 +419,7 @@ class RenderForwardMobile : public RendererSceneRenderRD { virtual RID _render_buffers_get_normal_texture(Ref p_render_buffers) override; virtual RID _render_buffers_get_velocity_texture(Ref p_render_buffers) override; - virtual void environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) override {} + virtual void environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, RS::EnvironmentSSAOType p_type, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) override {} virtual void environment_set_ssil_quality(RS::EnvironmentSSILQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) override {} virtual void environment_set_ssr_half_size(bool p_half_size) override {} virtual void environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) override {} diff --git a/servers/rendering/renderer_rd/shaders/effects/ssao.glsl b/servers/rendering/renderer_rd/shaders/effects/ssao.glsl index aff529cef171..01dac26a91dc 100644 --- a/servers/rendering/renderer_rd/shaders/effects/ssao.glsl +++ b/servers/rendering/renderer_rd/shaders/effects/ssao.glsl @@ -15,6 +15,7 @@ // File changes (yyyy-mm-dd) // 2016-09-07: filip.strugar@intel.com: first commit // 2020-12-05: clayjohn: convert to Vulkan and Godot +// 2025-09-26: hydrogenc: add initial GTAO implementation /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #[compute] @@ -23,6 +24,30 @@ #VERSION_DEFINES +// Common defines, related to edges +#define SSAO_NORMAL_BASED_EDGES_ENABLE_AT_QUALITY_PRESET (2) // to disable simply set to 99 or similar +#define SSAO_NORMAL_BASED_EDGES_DOT_THRESHOLD (0.5) // use 0-0.1 for super-sharp normal-based edges +// +// WARNING: The edge handling is hard-coded to 'disabled' on quality level 0, and enabled above, +// on the C++ side; while toggling it here will work for testing purposes, it will not yield +// performance gains (or correct results). +#define SSAO_DEPTH_BASED_EDGES_ENABLE_AT_QUALITY_PRESET (1) + +#ifdef SSAO_TYPE_GTAO +// GTAO + +#define GTAO_RADIUS_MULTIPLIER (0.5) +#define GTAO_MAX_DEPTH (1000.0) +#define GTAO_MAX_SCREEN_RADIUS (128.0) +#define GTAO_BIAS_MIP_LEVEL (0) +#define GTAO_FALLOFF_RANGE (0.717) + +const int num_slices[5] = { 2, 4, 5, 6, 8 }; +const int num_taps[5] = { 4, 8, 12, 16, 20 }; + +#else +// Intel ASSAO + #define INTELSSAO_MAIN_DISK_SAMPLE_COUNT (32) const vec4 sample_pattern[INTELSSAO_MAIN_DISK_SAMPLE_COUNT] = { vec4(0.78488064, 0.56661671, 1.500000, -0.126083), vec4(0.26022232, -0.29575172, 1.500000, -1.064030), vec4(0.10459357, 0.08372527, 1.110000, -2.730563), vec4(-0.68286800, 0.04963045, 1.090000, -0.498827), @@ -45,9 +70,6 @@ const int num_taps[5] = { 3, 5, 12, 0, 0 }; #define SSAO_HALOING_REDUCTION_ENABLE_AT_QUALITY_PRESET (1) // to disable simply set to 99 or similar #define SSAO_HALOING_REDUCTION_AMOUNT (0.6) // values from 0.0 - 1.0, 1.0 means max weighting (will cause artifacts, 0.8 is more reasonable) // -#define SSAO_NORMAL_BASED_EDGES_ENABLE_AT_QUALITY_PRESET (2) // to disable simply set to 99 or similar -#define SSAO_NORMAL_BASED_EDGES_DOT_THRESHOLD (0.5) // use 0-0.1 for super-sharp normal-based edges -// #define SSAO_DETAIL_AO_ENABLE_AT_QUALITY_PRESET (1) // whether to use detail; to disable simply set to 99 or similar // // WARNING: The MIP generation on the C++ side will be enabled on quality preset 2 regardless of @@ -55,11 +77,6 @@ const int num_taps[5] = { 3, 5, 12, 0, 0 }; #define SSAO_DEPTH_MIPS_ENABLE_AT_QUALITY_PRESET (2) #define SSAO_DEPTH_MIPS_GLOBAL_OFFSET (-4.3) // best noise/quality/performance tradeoff, found empirically // -// WARNING: The edge handling is hard-coded to 'disabled' on quality level 0, and enabled above, -// on the C++ side; while toggling it here will work for testing purposes, it will not yield -// performance gains (or correct results). -#define SSAO_DEPTH_BASED_EDGES_ENABLE_AT_QUALITY_PRESET (1) -// #define SSAO_REDUCE_RADIUS_NEAR_SCREEN_BORDER_ENABLE_AT_QUALITY_PRESET (1) #define SSAO_MAX_TAPS 32 @@ -67,6 +84,8 @@ const int num_taps[5] = { 3, 5, 12, 0, 0 }; #define SSAO_ADAPTIVE_TAP_FLEXIBLE_COUNT (SSAO_MAX_TAPS - SSAO_ADAPTIVE_TAP_BASE_COUNT) #define SSAO_DEPTH_MIP_LEVELS 4 +#endif + layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; layout(set = 0, binding = 0) uniform sampler2DArray source_depth_mipmaps; @@ -100,7 +119,6 @@ layout(push_constant, std430) uniform Params { vec2 NDC_to_view_mul; vec2 NDC_to_view_add; - vec2 pad2; vec2 half_screen_pixel_size_x025; float radius; @@ -110,9 +128,18 @@ layout(push_constant, std430) uniform Params { float fade_out_mul; float fade_out_add; + + // If we need more space for additional params in the future, + // the following 4 fields can be transformed to a 16-byte union to save space + + // ASSAO-specific float horizon_angle_threshold; float inv_radius_near_limit; + // GTAO-specific + float thickness_heuristic; + float fov_scale; + bool is_orthogonal; float neg_inv_radius; float load_counter_avg_div; @@ -173,6 +200,295 @@ vec3 load_normal(ivec2 p_pos, ivec2 p_offset) { return encoded_normal; } +// The common part +vec4 calculate_all_edges(const uvec2 full_res_coord, const vec3 pixel_normal, const float pix_z, const float pix_left_z, const float pix_right_z, const float pix_top_z, const float pix_bottom_z, int p_quality_level, bool p_adaptive_base) { + // edge mask for between this and left/right/top/bottom neighbor pixels - not used in quality level 0 so initialize to "no edge" (1 is no edge, 0 is edge) + vec4 edgesLRTB = vec4(1.0, 1.0, 1.0, 1.0); + + if (!p_adaptive_base && (p_quality_level >= SSAO_DEPTH_BASED_EDGES_ENABLE_AT_QUALITY_PRESET)) { + edgesLRTB = calculate_edges(pix_z, pix_left_z, pix_right_z, pix_top_z, pix_bottom_z); + } + + // Sharp normals also create edges - but this adds to the cost as well + if (!p_adaptive_base && (p_quality_level >= SSAO_NORMAL_BASED_EDGES_ENABLE_AT_QUALITY_PRESET)) { + vec3 neighbour_normal_left = load_normal(ivec2(full_res_coord), ivec2(-2, 0)); + vec3 neighbour_normal_right = load_normal(ivec2(full_res_coord), ivec2(2, 0)); + vec3 neighbour_normal_top = load_normal(ivec2(full_res_coord), ivec2(0, -2)); + vec3 neighbour_normal_bottom = load_normal(ivec2(full_res_coord), ivec2(0, 2)); + + const float dot_threshold = SSAO_NORMAL_BASED_EDGES_DOT_THRESHOLD; + + vec4 normal_edgesLRTB; + normal_edgesLRTB.x = clamp((dot(pixel_normal, neighbour_normal_left) + dot_threshold), 0.0, 1.0); + normal_edgesLRTB.y = clamp((dot(pixel_normal, neighbour_normal_right) + dot_threshold), 0.0, 1.0); + normal_edgesLRTB.z = clamp((dot(pixel_normal, neighbour_normal_top) + dot_threshold), 0.0, 1.0); + normal_edgesLRTB.w = clamp((dot(pixel_normal, neighbour_normal_bottom) + dot_threshold), 0.0, 1.0); + + edgesLRTB *= normal_edgesLRTB; + } + + return edgesLRTB; +} + +// Calculate fadeout, intensity and power of AO value +float calculate_final_occlusion(float obscurance, float pix_center_z, vec4 edgesLRTB, int p_quality_level, bool p_adaptive_base) { + // calculate fadeout (1 close, gradient, 0 far) + float fade_out = clamp(pix_center_z * params.fade_out_mul + params.fade_out_add, 0.0, 1.0); + + // Reduce the SSAO shadowing if we're on the edge to remove artifacts on edges (we don't care for the lower quality one) + if (!p_adaptive_base && (p_quality_level >= SSAO_DEPTH_BASED_EDGES_ENABLE_AT_QUALITY_PRESET)) { + // when there's more than 2 opposite edges, start fading out the occlusion to reduce aliasing artifacts + float edge_fadeout_factor = clamp((1.0 - edgesLRTB.x - edgesLRTB.y) * 0.35, 0.0, 1.0) + clamp((1.0 - edgesLRTB.z - edgesLRTB.w) * 0.35, 0.0, 1.0); + + fade_out *= clamp(1.0 - edge_fadeout_factor, 0.0, 1.0); + } + + // strength + obscurance = params.intensity * obscurance; + + // clamp + obscurance = min(obscurance, params.shadow_clamp); + + // fadeout + obscurance *= fade_out; + + // conceptually switch to occlusion with the meaning being visibility (grows with visibility, occlusion == 1 implies full visibility), + // to be in line with what is more commonly used. + float occlusion = 1.0 - obscurance; + + // modify the gradient + // note: this cannot be moved to a later pass because of loss of precision after storing in the render target + occlusion = pow(clamp(occlusion, 0.0, 1.0), params.shadow_power); + + return occlusion; +} + +#ifdef SSAO_TYPE_GTAO +// GTAO implementation + +#define PI 3.141592653589793 +#define PI_HALF (PI / 2.0) + +// [Jimenez 2014] Interleaved gradient function +// Use integer coordinates rather than UV since UV varies too little +float quick_hash(vec2 pos) { + const vec3 magic = vec3(0.06711056f, 0.00583715f, 52.9829189f); + return fract(magic.z * fract(dot(pos, magic.xy))); +} + +vec2 get_angle_offset_noise(uvec2 coords) { + coords.y = 4096u - coords.y; + float angle = quick_hash(vec2(coords)); + // [Jorge Jiménez 2016] Practical Real-Time Strategies for Accurate Indirect Occlusion + // Noise Distribution - Spatial Offsets + float noise = 0.25 * float((coords.y - coords.x) & 3u); + return vec2(angle, noise); +} + +// [Eberly 2014] GPGPU Programming for Games and Science +// Fast approximation of arccos +float acos_fast(float x) { + float abs_x = abs(x); + float res = -0.156583 * abs_x + PI_HALF; + res *= sqrt(1.0 - abs_x); + return x >= 0.0 ? res : PI - res; +} + +float GTAO_slice(in int num_taps, vec2 base_uv, vec2 screen_dir, float search_radius, float initial_offset, vec3 view_pos, vec3 view_dir, float falloff_mul, vec3 view_space_normal) { + float scene_depth, sample_delta_len_sq, sample_horizon_cos, falloff; + vec3 sample_delta; + vec2 sample_uv; + const vec2 screen_vec_pixels = screen_dir * params.half_screen_pixel_size; + const float thickness = params.thickness_heuristic; + + // Project view_space_normal onto the plane defined by screen_dir and view_dir + vec3 axis_vec = normalize(cross(view_dir, vec3(screen_dir, 0.0))); + vec3 ortho_dir_vec = cross(view_dir, axis_vec); + vec3 proj_normal_vec = view_space_normal - axis_vec * dot(view_space_normal, axis_vec); + + float proj_normal_len = length(proj_normal_vec) + 0.000001; + + float sign_norm = sign(dot(ortho_dir_vec, proj_normal_vec)); + float cos_norm = dot(proj_normal_vec, view_dir) / proj_normal_len; + float n = sign_norm * acos_fast(cos_norm); + + // this is a lower weight target; not using -1 as in the original paper because it is under horizon + vec2 horizon_cos = vec2(-1.0, -1.0); + // Find the largest angle + for (int i = 0; i < num_taps; ++i) { + vec2 uv_offset = screen_vec_pixels * max(search_radius * (float(i) + initial_offset), float(i) + 1.0); + // Paper: flip y due to texture coordinate system + uv_offset.y *= -1.0; + + // Use HZB tracing for better performance + int mip_level = GTAO_BIAS_MIP_LEVEL; + if (i == 2) { + mip_level++; + } + + if (i >= 3) { + mip_level += 2; + } + + // Positive direction + // Clamp UV coords to avoid artifacts + sample_uv = clamp(base_uv + uv_offset, vec2(0.0), vec2(1.0)); + scene_depth = textureLod(source_depth_mipmaps, vec3(sample_uv, params.pass), mip_level).x; + sample_delta = NDC_to_view_space(sample_uv, scene_depth).xyz - view_pos; + sample_delta_len_sq = dot(sample_delta, sample_delta); + // TODO: This could be replaced with fast sqrt + sample_horizon_cos = dot(sample_delta, view_dir) * inversesqrt(sample_delta_len_sq); + // XeGTAO uses 1/r falloff here, ASSAO uses 1/r^2 falloff instead. + // To make the AO appear sharper, 1/r^2 is chosen + falloff = clamp(sample_delta_len_sq * falloff_mul, 0.0, 1.0); + sample_horizon_cos = mix(sample_horizon_cos, horizon_cos.x, falloff); + + // Thickness heuristic - see "4.3 Implementation details, Height-field assumption considerations" + horizon_cos.x = (sample_horizon_cos > horizon_cos.x) ? sample_horizon_cos : mix(sample_horizon_cos, horizon_cos.x, thickness); + + // Negative direction + sample_uv = clamp(base_uv - uv_offset, vec2(0.0), vec2(1.0)); + scene_depth = textureLod(source_depth_mipmaps, vec3(sample_uv, params.pass), mip_level).x; + sample_delta = NDC_to_view_space(sample_uv, scene_depth).xyz - view_pos; + sample_delta_len_sq = dot(sample_delta, sample_delta); + sample_horizon_cos = dot(sample_delta, view_dir) * inversesqrt(sample_delta_len_sq); + + falloff = clamp(sample_delta_len_sq * falloff_mul, 0.0, 1.0); + sample_horizon_cos = mix(sample_horizon_cos, horizon_cos.y, falloff); + + horizon_cos.y = (sample_horizon_cos > horizon_cos.y) ? sample_horizon_cos : mix(sample_horizon_cos, horizon_cos.y, thickness); + } + + // Convert cosine to angle, `horizon_cos` is now an ANGLE + horizon_cos.x = -acos_fast(clamp(horizon_cos.x, -1.0, 1.0)); + horizon_cos.y = acos_fast(clamp(horizon_cos.y, -1.0, 1.0)); + + // Clamp to normal hemisphere + // XeGTAO: we can skip clamping for a tiny little bit more performance + horizon_cos.x = n + clamp(horizon_cos.x - n, -PI_HALF, PI_HALF); + horizon_cos.y = n + clamp(horizon_cos.y - n, -PI_HALF, PI_HALF); + + // The final formula uses `2 * sin(n)` so we precalculate this value + float two_sin_norm = 2.0 * sin(n); + + float iarc1 = (cos_norm + horizon_cos.x * two_sin_norm - cos(2.0 * horizon_cos.x - n)); + float iarc2 = (cos_norm + horizon_cos.y * two_sin_norm - cos(2.0 * horizon_cos.y - n)); + + float local_visibility = 0.25 * (iarc1 + iarc2) * proj_normal_len; + // Disallow total occlusion + local_visibility = max(0.03, local_visibility); + return local_visibility; +} + +void generate_GTAO_shadows_internal(out float r_shadow_term, out vec4 r_edges, out float r_weight, const vec2 p_pos, int p_quality_level) { + vec2 pos_rounded = trunc(p_pos); + uvec2 upos = uvec2(pos_rounded); + + const int number_of_taps = num_taps[p_quality_level]; + const int number_of_slices = num_slices[p_quality_level]; + float pix_z, pix_left_z, pix_top_z, pix_right_z, pix_bottom_z; + + vec4 valuesUL = textureGather(source_depth_mipmaps, vec3(pos_rounded * params.half_screen_pixel_size, params.pass)); + vec4 valuesBR = textureGather(source_depth_mipmaps, vec3((pos_rounded + vec2(1.0)) * params.half_screen_pixel_size, params.pass)); + + // get this pixel's viewspace depth + pix_z = valuesUL.y; + + // get left right top bottom neighboring pixels for edge detection (gets compiled out on quality_level == 0) + pix_left_z = valuesUL.x; + pix_top_z = valuesUL.z; + pix_right_z = valuesBR.z; + pix_bottom_z = valuesBR.x; + + vec2 normalized_screen_pos = pos_rounded * params.half_screen_pixel_size + params.half_screen_pixel_size_x025; + vec3 pix_center_pos = NDC_to_view_space(normalized_screen_pos, pix_z); + + // Load this pixel's viewspace normal + uvec2 full_res_coord = upos * 2 * params.size_multiplier + params.pass_coord_offset.xy; + vec3 pixel_normal = load_normal(ivec2(full_res_coord)); + + vec4 edgesLRTB = calculate_all_edges(full_res_coord, pixel_normal, pix_z, pix_left_z, pix_right_z, pix_top_z, pix_bottom_z, p_quality_level, false); + + if (pix_z >= GTAO_MAX_DEPTH) { + // Skip GTAO calculation if pixel is too far away + r_shadow_term = 1.0; + r_edges = edgesLRTB; + r_weight = 1.0; + return; + } + + vec3 view_dir = normalize(-pix_center_pos); + + // Calculate rotation angle for slices + float delta_angle = PI / float(number_of_slices); + // Precalculate rotational components for slices + float sin_delta_angle = sin(delta_angle); + float cos_delta_angle = cos(delta_angle); + + float viewspace_radius = params.radius * GTAO_RADIUS_MULTIPLIER; + + // when too close, on-screen sampling disk will grow beyond screen size; limit this to avoid closeup temporal artifacts + const float too_close_limit = clamp(length(pix_center_pos) * params.inv_radius_near_limit, 0.0, 1.0) * 0.8 + 0.2; + + viewspace_radius *= too_close_limit; + + // Multiply the radius by projection[0][0] to make it FOV-independent, same as HBAO + float screenspace_radius = clamp(viewspace_radius * params.fov_scale / pix_center_pos.z, float(number_of_taps), GTAO_MAX_SCREEN_RADIUS); + + // Adjust radius near screen borders to reduce artifacts + float near_screen_border = min(min(normalized_screen_pos.x, 1.0 - normalized_screen_pos.x), min(normalized_screen_pos.y, 1.0 - normalized_screen_pos.y)); + near_screen_border = clamp(10.0 * near_screen_border + 0.6, 0.0, 1.0); + screenspace_radius *= near_screen_border; + + float step_radius = screenspace_radius / float(number_of_taps); + float falloff_range = GTAO_FALLOFF_RANGE * viewspace_radius; + float falloff_mul = 1.0 / (falloff_range * falloff_range); + + // Move center pixel slightly towards camera to avoid imprecision artifacts due to using of 16bit depth buffer. + pix_center_pos.z *= 0.99; + + vec2 noise = get_angle_offset_noise(upos); + // Apply a random offset on to reduce artifacts + float offset = noise.y; + // Get a random direction on the hemisphere + // Screen dir is guaranteed to be already normalized + vec2 screen_dir; + screen_dir.y = sin(noise.x); + screen_dir.x = cos(noise.x); + + // the main obscurance & sample weight storage + float obscurance_sum = 0.0; + float weight_sum = 0.0; + + // Calculate AO values for each slice + for (uint slice = 0; slice < number_of_slices; ++slice) { + // GTAO inner integral gives visibility, which is one minus obscurance + obscurance_sum += 1.0 - GTAO_slice(number_of_taps, normalized_screen_pos, screen_dir, step_radius, offset, pix_center_pos, view_dir, falloff_mul, pixel_normal); + weight_sum += 1.0; + + // XeGTAO calculates screen direction with sincos(angle) every iteration, but that's too slow, + // so we calculate it once and rotate it instead. + vec2 tmp_dir = screen_dir; + screen_dir.x = tmp_dir.x * cos_delta_angle - tmp_dir.y * sin_delta_angle; + screen_dir.y = tmp_dir.x * sin_delta_angle + tmp_dir.y * cos_delta_angle; + offset = fract(offset + 0.617); + } + + // calculate weighted average + float obscurance = obscurance_sum / weight_sum; + + // calculate final occlusion + float occlusion = calculate_final_occlusion(obscurance, pix_center_pos.z, edgesLRTB, p_quality_level, false); + + // outputs! + r_shadow_term = occlusion; // Our final 'occlusion' term (0 means fully occluded, 1 means fully lit) + r_edges = edgesLRTB; // These are used to prevent blurring across edges, 1 means no edge, 0 means edge, 0.5 means half way there, etc. + r_weight = weight_sum; +} + +#else +// Intel ASSAO implementation + // all vectors in viewspace float calculate_pixel_obscurance(vec3 p_pixel_normal, vec3 p_hit_delta, float p_fallof_sq) { float length_sq = dot(p_hit_delta, p_hit_delta); @@ -204,7 +520,7 @@ void SSAO_tap_inner(const int p_quality_level, inout float r_obscurance_sum, ino r_weight_sum += weight; } -void SSAOTap(const int p_quality_level, inout float r_obscurance_sum, inout float r_weight_sum, const int p_tap_index, const mat2 p_rot_scale, const vec3 p_pix_center_pos, vec3 p_pixel_normal, const vec2 p_normalized_screen_pos, const float p_mip_offset, const float p_fallof_sq, float p_weight_mod, vec2 p_norm_xy, float p_norm_xy_length) { +void SSAO_tap(const int p_quality_level, inout float r_obscurance_sum, inout float r_weight_sum, const int p_tap_index, const mat2 p_rot_scale, const vec3 p_pix_center_pos, vec3 p_pixel_normal, const vec2 p_normalized_screen_pos, const float p_mip_offset, const float p_fallof_sq, float p_weight_mod, vec2 p_norm_xy, float p_norm_xy_length) { vec2 sample_offset; float sample_pow_2_len; @@ -298,20 +614,12 @@ void generate_SSAO_shadows_internal(out float r_shadow_term, out vec4 r_edges, o rot_scale_matrix = mat2(rotation_scale.x * pixel_lookup_radius, rotation_scale.y * pixel_lookup_radius, rotation_scale.z * pixel_lookup_radius, rotation_scale.w * pixel_lookup_radius); } + vec4 edgesLRTB = calculate_all_edges(full_res_coord, pixel_normal, pix_z, pix_left_z, pix_right_z, pix_top_z, pix_bottom_z, p_quality_level, p_adaptive_base); + // the main obscurance & sample weight storage float obscurance_sum = 0.0; float weight_sum = 0.0; - // edge mask for between this and left/right/top/bottom neighbor pixels - not used in quality level 0 so initialize to "no edge" (1 is no edge, 0 is edge) - vec4 edgesLRTB = vec4(1.0, 1.0, 1.0, 1.0); - - // Move center pixel slightly towards camera to avoid imprecision artifacts due to using of 16bit depth buffer. - pix_center_pos *= 0.99; - - if (!p_adaptive_base && (p_quality_level >= SSAO_DEPTH_BASED_EDGES_ENABLE_AT_QUALITY_PRESET)) { - edgesLRTB = calculate_edges(pix_z, pix_left_z, pix_right_z, pix_top_z, pix_bottom_z); - } - // adds a more high definition sharp effect, which gets blurred out (reuses left/right/top/bottom samples that we used for edge detection) if (!p_adaptive_base && (p_quality_level >= SSAO_DETAIL_AO_ENABLE_AT_QUALITY_PRESET)) { // disable in case of quality level 4 (reference) @@ -336,23 +644,8 @@ void generate_SSAO_shadows_internal(out float r_shadow_term, out vec4 r_edges, o } } - // Sharp normals also create edges - but this adds to the cost as well - if (!p_adaptive_base && (p_quality_level >= SSAO_NORMAL_BASED_EDGES_ENABLE_AT_QUALITY_PRESET)) { - vec3 neighbour_normal_left = load_normal(ivec2(full_res_coord), ivec2(-2, 0)); - vec3 neighbour_normal_right = load_normal(ivec2(full_res_coord), ivec2(2, 0)); - vec3 neighbour_normal_top = load_normal(ivec2(full_res_coord), ivec2(0, -2)); - vec3 neighbour_normal_bottom = load_normal(ivec2(full_res_coord), ivec2(0, 2)); - - const float dot_threshold = SSAO_NORMAL_BASED_EDGES_DOT_THRESHOLD; - - vec4 normal_edgesLRTB; - normal_edgesLRTB.x = clamp((dot(pixel_normal, neighbour_normal_left) + dot_threshold), 0.0, 1.0); - normal_edgesLRTB.y = clamp((dot(pixel_normal, neighbour_normal_right) + dot_threshold), 0.0, 1.0); - normal_edgesLRTB.z = clamp((dot(pixel_normal, neighbour_normal_top) + dot_threshold), 0.0, 1.0); - normal_edgesLRTB.w = clamp((dot(pixel_normal, neighbour_normal_bottom) + dot_threshold), 0.0, 1.0); - - edgesLRTB *= normal_edgesLRTB; - } + // Move center pixel slightly towards camera to avoid imprecision artifacts due to using of 16bit depth buffer. + pix_center_pos.z *= 0.99; const float global_mip_offset = SSAO_DEPTH_MIPS_GLOBAL_OFFSET; float mip_offset = (p_quality_level < SSAO_DEPTH_MIPS_ENABLE_AT_QUALITY_PRESET) ? (0) : (log2(pixel_lookup_radius) + global_mip_offset); @@ -367,7 +660,7 @@ void generate_SSAO_shadows_internal(out float r_shadow_term, out vec4 r_edges, o // standard, non-adaptive approach if ((p_quality_level != 3) || p_adaptive_base) { for (int i = 0; i < number_of_taps; i++) { - SSAOTap(p_quality_level, obscurance_sum, weight_sum, i, rot_scale_matrix, pix_center_pos, pixel_normal, normalized_screen_pos, mip_offset, fallof_sq, 1.0, norm_xy, norm_xy_length); + SSAO_tap(p_quality_level, obscurance_sum, weight_sum, i, rot_scale_matrix, pix_center_pos, pixel_normal, normalized_screen_pos, mip_offset, fallof_sq, 1.0, norm_xy, norm_xy_length); } } #ifdef ADAPTIVE @@ -404,7 +697,7 @@ void generate_SSAO_shadows_internal(out float r_shadow_term, out vec4 r_edges, o for (uint i = SSAO_ADAPTIVE_TAP_BASE_COUNT; i < additional_samples_to; i++) { additional_sample_count -= 1.0f; float weight_mod = clamp(additional_sample_count * blend_range_inv, 0.0, 1.0); - SSAOTap(p_quality_level, obscurance_sum, weight_sum, int(i), rot_scale_matrix, pix_center_pos, pixel_normal, normalized_screen_pos, mip_offset, fallof_sq, weight_mod, norm_xy, norm_xy_length); + SSAO_tap(p_quality_level, obscurance_sum, weight_sum, int(i), rot_scale_matrix, pix_center_pos, pixel_normal, normalized_screen_pos, mip_offset, fallof_sq, weight_mod, norm_xy, norm_xy_length); } } #endif @@ -422,33 +715,8 @@ void generate_SSAO_shadows_internal(out float r_shadow_term, out vec4 r_edges, o // calculate weighted average float obscurance = obscurance_sum / weight_sum; - // calculate fadeout (1 close, gradient, 0 far) - float fade_out = clamp(pix_center_pos.z * params.fade_out_mul + params.fade_out_add, 0.0, 1.0); - - // Reduce the SSAO shadowing if we're on the edge to remove artifacts on edges (we don't care for the lower quality one) - if (!p_adaptive_base && (p_quality_level >= SSAO_DEPTH_BASED_EDGES_ENABLE_AT_QUALITY_PRESET)) { - // when there's more than 2 opposite edges, start fading out the occlusion to reduce aliasing artifacts - float edge_fadeout_factor = clamp((1.0 - edgesLRTB.x - edgesLRTB.y) * 0.35, 0.0, 1.0) + clamp((1.0 - edgesLRTB.z - edgesLRTB.w) * 0.35, 0.0, 1.0); - - fade_out *= clamp(1.0 - edge_fadeout_factor, 0.0, 1.0); - } - - // strength - obscurance = params.intensity * obscurance; - - // clamp - obscurance = min(obscurance, params.shadow_clamp); - - // fadeout - obscurance *= fade_out; - - // conceptually switch to occlusion with the meaning being visibility (grows with visibility, occlusion == 1 implies full visibility), - // to be in line with what is more commonly used. - float occlusion = 1.0 - obscurance; - - // modify the gradient - // note: this cannot be moved to a later pass because of loss of precision after storing in the render target - occlusion = pow(clamp(occlusion, 0.0, 1.0), params.shadow_power); + // calculate final occlusion + float occlusion = calculate_final_occlusion(obscurance, pix_center_pos.z, edgesLRTB, p_quality_level, p_adaptive_base); // outputs! r_shadow_term = occlusion; // Our final 'occlusion' term (0 means fully occluded, 1 means fully lit) @@ -456,6 +724,8 @@ void generate_SSAO_shadows_internal(out float r_shadow_term, out vec4 r_edges, o r_weight = weight_sum; } +#endif + void main() { float out_shadow_term; float out_weight; @@ -465,17 +735,28 @@ void main() { return; } - vec2 uv = vec2(gl_GlobalInvocationID) + vec2(0.5); + vec2 pix_coord = vec2(gl_GlobalInvocationID) + vec2(0.5); +#ifdef SSAO_TYPE_GTAO + // GTAO + generate_GTAO_shadows_internal(out_shadow_term, out_edges, out_weight, pix_coord, params.quality); + if (params.quality == 0) { + out_edges = vec4(1.0); + } + + imageStore(dest_image, ivec2(gl_GlobalInvocationID.xy), vec4(out_shadow_term, pack_edges(out_edges), 0.0, 0.0)); +#else + // Intel ASSAO #ifdef SSAO_BASE - generate_SSAO_shadows_internal(out_shadow_term, out_edges, out_weight, uv, params.quality, true); + generate_SSAO_shadows_internal(out_shadow_term, out_edges, out_weight, pix_coord, params.quality, true); imageStore(dest_image, ivec2(gl_GlobalInvocationID.xy), vec4(out_shadow_term, out_weight / (float(SSAO_ADAPTIVE_TAP_BASE_COUNT) * 4.0), 0.0, 0.0)); #else - generate_SSAO_shadows_internal(out_shadow_term, out_edges, out_weight, uv, params.quality, false); // pass in quality levels + generate_SSAO_shadows_internal(out_shadow_term, out_edges, out_weight, pix_coord, params.quality, false); // pass in quality levels if (params.quality == 0) { out_edges = vec4(1.0); } imageStore(dest_image, ivec2(gl_GlobalInvocationID.xy), vec4(out_shadow_term, pack_edges(out_edges), 0.0, 0.0)); #endif +#endif } diff --git a/servers/rendering/renderer_scene_cull.h b/servers/rendering/renderer_scene_cull.h index 74f3b42eb6ed..6afb99ed5fe4 100644 --- a/servers/rendering/renderer_scene_cull.h +++ b/servers/rendering/renderer_scene_cull.h @@ -1315,7 +1315,7 @@ class RendererSceneCull : public RenderingMethod { PASS1(environment_set_ssr_roughness_quality, RS::EnvironmentSSRRoughnessQuality) // SSAO - PASS10(environment_set_ssao, RID, bool, float, float, float, float, float, float, float, float) + PASS11(environment_set_ssao, RID, bool, float, float, float, float, float, float, float, float, float) PASS1RC(bool, environment_get_ssao_enabled, RID) PASS1RC(float, environment_get_ssao_radius, RID) @@ -1324,10 +1324,11 @@ class RendererSceneCull : public RenderingMethod { PASS1RC(float, environment_get_ssao_detail, RID) PASS1RC(float, environment_get_ssao_horizon, RID) PASS1RC(float, environment_get_ssao_sharpness, RID) + PASS1RC(float, environment_get_ssao_thickness_heuristic, RID) PASS1RC(float, environment_get_ssao_direct_light_affect, RID) PASS1RC(float, environment_get_ssao_ao_channel_affect, RID) - PASS6(environment_set_ssao_quality, RS::EnvironmentSSAOQuality, bool, float, int, float, float) + PASS7(environment_set_ssao_quality, RS::EnvironmentSSAOQuality, RS::EnvironmentSSAOType, bool, float, int, float, float) // SSIL PASS6(environment_set_ssil, RID, bool, float, float, float, float) diff --git a/servers/rendering/renderer_scene_render.cpp b/servers/rendering/renderer_scene_render.cpp index 3300a55a32bd..6362dc422fcd 100644 --- a/servers/rendering/renderer_scene_render.cpp +++ b/servers/rendering/renderer_scene_render.cpp @@ -581,8 +581,8 @@ float RendererSceneRender::environment_get_ssr_depth_tolerance(RID p_env) const // SSAO -void RendererSceneRender::environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_power, float p_detail, float p_horizon, float p_sharpness, float p_light_affect, float p_ao_channel_affect) { - environment_storage.environment_set_ssao(p_env, p_enable, p_radius, p_intensity, p_power, p_detail, p_horizon, p_sharpness, p_light_affect, p_ao_channel_affect); +void RendererSceneRender::environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_power, float p_detail, float p_horizon, float p_sharpness, float p_thickness_heuristic, float p_light_affect, float p_ao_channel_affect) { + environment_storage.environment_set_ssao(p_env, p_enable, p_radius, p_intensity, p_power, p_detail, p_horizon, p_sharpness, p_thickness_heuristic, p_light_affect, p_ao_channel_affect); } bool RendererSceneRender::environment_get_ssao_enabled(RID p_env) const { @@ -613,6 +613,10 @@ float RendererSceneRender::environment_get_ssao_sharpness(RID p_env) const { return environment_storage.environment_get_ssao_sharpness(p_env); } +float RendererSceneRender::environment_get_ssao_thickness_heuristic(RID p_env) const { + return environment_storage.environment_get_ssao_thickness_heuristic(p_env); +} + float RendererSceneRender::environment_get_ssao_direct_light_affect(RID p_env) const { return environment_storage.environment_get_ssao_direct_light_affect(p_env); } diff --git a/servers/rendering/renderer_scene_render.h b/servers/rendering/renderer_scene_render.h index 44b8764ef07a..103d22b7c15b 100644 --- a/servers/rendering/renderer_scene_render.h +++ b/servers/rendering/renderer_scene_render.h @@ -206,7 +206,7 @@ class RendererSceneRender { virtual void environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) = 0; // SSAO - void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_power, float p_detail, float p_horizon, float p_sharpness, float p_light_affect, float p_ao_channel_affect); + void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_power, float p_detail, float p_horizon, float p_sharpness, float p_thickness_heuristic, float p_light_affect, float p_ao_channel_affect); bool environment_get_ssao_enabled(RID p_env) const; float environment_get_ssao_radius(RID p_env) const; float environment_get_ssao_intensity(RID p_env) const; @@ -214,10 +214,11 @@ class RendererSceneRender { float environment_get_ssao_detail(RID p_env) const; float environment_get_ssao_horizon(RID p_env) const; float environment_get_ssao_sharpness(RID p_env) const; + float environment_get_ssao_thickness_heuristic(RID p_env) const; float environment_get_ssao_direct_light_affect(RID p_env) const; float environment_get_ssao_ao_channel_affect(RID p_env) const; - virtual void environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) = 0; + virtual void environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, RS::EnvironmentSSAOType p_type, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) = 0; // SSIL void environment_set_ssil(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_sharpness, float p_normal_rejection); diff --git a/servers/rendering/rendering_method.h b/servers/rendering/rendering_method.h index 5de00d97e4f1..5e52d046e2f9 100644 --- a/servers/rendering/rendering_method.h +++ b/servers/rendering/rendering_method.h @@ -264,7 +264,7 @@ class RenderingMethod { virtual void environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) = 0; // SSAO - virtual void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_power, float p_detail, float p_horizon, float p_sharpness, float p_light_affect, float p_ao_channel_affect) = 0; + virtual void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_power, float p_detail, float p_horizon, float p_sharpness, float p_thickness_heuristic, float p_light_affect, float p_ao_channel_affect) = 0; virtual bool environment_get_ssao_enabled(RID p_env) const = 0; virtual float environment_get_ssao_radius(RID p_env) const = 0; @@ -276,7 +276,7 @@ class RenderingMethod { virtual float environment_get_ssao_direct_light_affect(RID p_env) const = 0; virtual float environment_get_ssao_ao_channel_affect(RID p_env) const = 0; - virtual void environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) = 0; + virtual void environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, RS::EnvironmentSSAOType p_type, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) = 0; // SSIL diff --git a/servers/rendering/rendering_server.cpp b/servers/rendering/rendering_server.cpp index 8c02698ed5c7..15b9b108fae2 100644 --- a/servers/rendering/rendering_server.cpp +++ b/servers/rendering/rendering_server.cpp @@ -3103,7 +3103,7 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("environment_set_tonemap", "env", "tone_mapper", "exposure", "white"), &RenderingServer::environment_set_tonemap); ClassDB::bind_method(D_METHOD("environment_set_adjustment", "env", "enable", "brightness", "contrast", "saturation", "use_1d_color_correction", "color_correction"), &RenderingServer::environment_set_adjustment); ClassDB::bind_method(D_METHOD("environment_set_ssr", "env", "enable", "max_steps", "fade_in", "fade_out", "depth_tolerance"), &RenderingServer::environment_set_ssr); - ClassDB::bind_method(D_METHOD("environment_set_ssao", "env", "enable", "radius", "intensity", "power", "detail", "horizon", "sharpness", "light_affect", "ao_channel_affect"), &RenderingServer::environment_set_ssao); + ClassDB::bind_method(D_METHOD("environment_set_ssao", "env", "enable", "radius", "intensity", "power", "detail", "horizon", "sharpness", "thickness_heuristic", "light_affect", "ao_channel_affect"), &RenderingServer::environment_set_ssao); ClassDB::bind_method(D_METHOD("environment_set_fog", "env", "enable", "light_color", "light_energy", "sun_scatter", "density", "height", "height_density", "aerial_perspective", "sky_affect", "fog_mode"), &RenderingServer::environment_set_fog, DEFVAL(RS::ENV_FOG_MODE_EXPONENTIAL)); ClassDB::bind_method(D_METHOD("environment_set_fog_depth", "env", "curve", "begin", "end"), &RenderingServer::environment_set_fog_depth); ClassDB::bind_method(D_METHOD("environment_set_sdfgi", "env", "enable", "cascades", "min_cell_size", "y_scale", "use_occlusion", "bounce_feedback", "read_sky", "energy", "normal_bias", "probe_bias"), &RenderingServer::environment_set_sdfgi); @@ -3112,7 +3112,7 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("environment_glow_set_use_bicubic_upscale", "enable"), &RenderingServer::environment_glow_set_use_bicubic_upscale); ClassDB::bind_method(D_METHOD("environment_set_ssr_half_size", "half_size"), &RenderingServer::environment_set_ssr_half_size); ClassDB::bind_method(D_METHOD("environment_set_ssr_roughness_quality", "quality"), &RenderingServer::environment_set_ssr_roughness_quality); - ClassDB::bind_method(D_METHOD("environment_set_ssao_quality", "quality", "half_size", "adaptive_target", "blur_passes", "fadeout_from", "fadeout_to"), &RenderingServer::environment_set_ssao_quality); + ClassDB::bind_method(D_METHOD("environment_set_ssao_quality", "quality", "type", "half_size", "adaptive_target", "blur_passes", "fadeout_from", "fadeout_to"), &RenderingServer::environment_set_ssao_quality); ClassDB::bind_method(D_METHOD("environment_set_ssil_quality", "quality", "half_size", "adaptive_target", "blur_passes", "fadeout_from", "fadeout_to"), &RenderingServer::environment_set_ssil_quality); ClassDB::bind_method(D_METHOD("environment_set_sdfgi_ray_count", "ray_count"), &RenderingServer::environment_set_sdfgi_ray_count); ClassDB::bind_method(D_METHOD("environment_set_sdfgi_frames_to_converge", "frames"), &RenderingServer::environment_set_sdfgi_frames_to_converge); @@ -3752,6 +3752,7 @@ void RenderingServer::init() { GLOBAL_DEF("rendering/camera/depth_of_field/depth_of_field_use_jitter", false); GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/environment/ssao/quality", PROPERTY_HINT_ENUM, "Very Low (Fast),Low (Fast),Medium (Average),High (Slow),Ultra (Custom)"), 2); + GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/environment/ssao/type", PROPERTY_HINT_ENUM, "ASSAO (Fast),GTAO (Average)"), 0); GLOBAL_DEF("rendering/environment/ssao/half_size", true); GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "rendering/environment/ssao/adaptive_target", PROPERTY_HINT_RANGE, "0.0,1.0,0.01"), 0.5); GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/environment/ssao/blur_passes", PROPERTY_HINT_RANGE, "0,6"), 2); diff --git a/servers/rendering/rendering_server.h b/servers/rendering/rendering_server.h index 7fe0d3223c80..eb7319f794e3 100644 --- a/servers/rendering/rendering_server.h +++ b/servers/rendering/rendering_server.h @@ -1298,7 +1298,7 @@ class RenderingServer : public Object { virtual void environment_set_ssr_roughness_quality(EnvironmentSSRRoughnessQuality p_quality) = 0; - virtual void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_power, float p_detail, float p_horizon, float p_sharpness, float p_light_affect, float p_ao_channel_affect) = 0; + virtual void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_power, float p_detail, float p_horizon, float p_sharpness, float p_thickness_heuristic, float p_light_affect, float p_ao_channel_affect) = 0; enum EnvironmentSSAOQuality { ENV_SSAO_QUALITY_VERY_LOW, @@ -1308,7 +1308,12 @@ class RenderingServer : public Object { ENV_SSAO_QUALITY_ULTRA, }; - virtual void environment_set_ssao_quality(EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) = 0; + enum EnvironmentSSAOType { + ENV_SSAO_TYPE_ASSAO, + ENV_SSAO_TYPE_GTAO, + }; + + virtual void environment_set_ssao_quality(EnvironmentSSAOQuality p_quality, EnvironmentSSAOType p_type, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) = 0; virtual void environment_set_ssil(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_sharpness, float p_normal_rejection) = 0; @@ -1996,6 +2001,7 @@ VARIANT_ENUM_CAST(RenderingServer::EnvironmentFogMode); VARIANT_ENUM_CAST(RenderingServer::EnvironmentToneMapper); VARIANT_ENUM_CAST(RenderingServer::EnvironmentSSRRoughnessQuality); VARIANT_ENUM_CAST(RenderingServer::EnvironmentSSAOQuality); +VARIANT_ENUM_CAST(RenderingServer::EnvironmentSSAOType); VARIANT_ENUM_CAST(RenderingServer::EnvironmentSSILQuality); VARIANT_ENUM_CAST(RenderingServer::EnvironmentSDFGIFramesToConverge); VARIANT_ENUM_CAST(RenderingServer::EnvironmentSDFGIRayCount); diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h index 62a155a534c8..14749e88ba12 100644 --- a/servers/rendering/rendering_server_default.h +++ b/servers/rendering/rendering_server_default.h @@ -820,8 +820,8 @@ class RenderingServerDefault : public RenderingServer { FUNC1(environment_set_ssr_half_size, bool) FUNC1(environment_set_ssr_roughness_quality, EnvironmentSSRRoughnessQuality) - FUNC10(environment_set_ssao, RID, bool, float, float, float, float, float, float, float, float) - FUNC6(environment_set_ssao_quality, EnvironmentSSAOQuality, bool, float, int, float, float) + FUNC11(environment_set_ssao, RID, bool, float, float, float, float, float, float, float, float, float) + FUNC7(environment_set_ssao_quality, EnvironmentSSAOQuality, EnvironmentSSAOType, bool, float, int, float, float) FUNC6(environment_set_ssil, RID, bool, float, float, float, float) FUNC6(environment_set_ssil_quality, EnvironmentSSILQuality, bool, float, int, float, float) diff --git a/servers/rendering/storage/environment_storage.cpp b/servers/rendering/storage/environment_storage.cpp index 34a36848620a..f7d7cbdf1315 100644 --- a/servers/rendering/storage/environment_storage.cpp +++ b/servers/rendering/storage/environment_storage.cpp @@ -584,7 +584,7 @@ float RendererEnvironmentStorage::environment_get_ssr_depth_tolerance(RID p_env) // SSAO -void RendererEnvironmentStorage::environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_power, float p_detail, float p_horizon, float p_sharpness, float p_light_affect, float p_ao_channel_affect) { +void RendererEnvironmentStorage::environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_power, float p_detail, float p_horizon, float p_sharpness, float p_thickness_heuristic, float p_light_affect, float p_ao_channel_affect) { Environment *env = environment_owner.get_or_null(p_env); ERR_FAIL_NULL(env); #ifdef DEBUG_ENABLED @@ -599,6 +599,7 @@ void RendererEnvironmentStorage::environment_set_ssao(RID p_env, bool p_enable, env->ssao_detail = p_detail; env->ssao_horizon = p_horizon; env->ssao_sharpness = p_sharpness; + env->ssao_thickness_heuristic = p_thickness_heuristic; env->ssao_direct_light_affect = p_light_affect; env->ssao_ao_channel_affect = p_ao_channel_affect; } @@ -645,6 +646,12 @@ float RendererEnvironmentStorage::environment_get_ssao_sharpness(RID p_env) cons return env->ssao_sharpness; } +float RendererEnvironmentStorage::environment_get_ssao_thickness_heuristic(RID p_env) const { + Environment *env = environment_owner.get_or_null(p_env); + ERR_FAIL_NULL_V(env, 0.5); + return env->ssao_thickness_heuristic; +} + float RendererEnvironmentStorage::environment_get_ssao_direct_light_affect(RID p_env) const { Environment *env = environment_owner.get_or_null(p_env); ERR_FAIL_NULL_V(env, 0.0); diff --git a/servers/rendering/storage/environment_storage.h b/servers/rendering/storage/environment_storage.h index 62852cf37f30..f5edf66b2078 100644 --- a/servers/rendering/storage/environment_storage.h +++ b/servers/rendering/storage/environment_storage.h @@ -124,6 +124,8 @@ class RendererEnvironmentStorage { float ssao_detail = 0.5; float ssao_horizon = 0.06; float ssao_sharpness = 0.98; + // Only used for GTAO + float ssao_thickness_heuristic = 0.5; float ssao_direct_light_affect = 0.0; float ssao_ao_channel_affect = 0.0; @@ -263,7 +265,7 @@ class RendererEnvironmentStorage { float environment_get_ssr_depth_tolerance(RID p_env) const; // SSAO - void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_power, float p_detail, float p_horizon, float p_sharpness, float p_light_affect, float p_ao_channel_affect); + void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_power, float p_detail, float p_horizon, float p_sharpness, float p_thickness_heuristic, float p_light_affect, float p_ao_channel_affect); bool environment_get_ssao_enabled(RID p_env) const; float environment_get_ssao_radius(RID p_env) const; float environment_get_ssao_intensity(RID p_env) const; @@ -271,6 +273,7 @@ class RendererEnvironmentStorage { float environment_get_ssao_detail(RID p_env) const; float environment_get_ssao_horizon(RID p_env) const; float environment_get_ssao_sharpness(RID p_env) const; + float environment_get_ssao_thickness_heuristic(RID p_env) const; float environment_get_ssao_direct_light_affect(RID p_env) const; float environment_get_ssao_ao_channel_affect(RID p_env) const;