diff --git a/doc/classes/BaseMaterial3D.xml b/doc/classes/BaseMaterial3D.xml index 76f9c20f0f7..e76bb5dc9c7 100644 --- a/doc/classes/BaseMaterial3D.xml +++ b/doc/classes/BaseMaterial3D.xml @@ -182,6 +182,9 @@ If [code]true[/code], the object receives no shadow that would otherwise be cast onto it. + + If [code]true[/code], disables specular occlusion even if [member ProjectSettings.rendering/reflections/specular_occlusion/enabled] is [code]false[/code]. + Distance at which the object appears fully opaque. [b]Note:[/b] If [member distance_fade_max_distance] is less than [member distance_fade_min_distance], the behavior will be reversed. The object will start to fade away at [member distance_fade_max_distance] and will fully disappear once it reaches [member distance_fade_min_distance]. @@ -706,7 +709,10 @@ Disables receiving depth-based or volumetric fog. - + + Disables specular occlusion. + + Represents the size of the [enum Flags] enum. diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index 9ab9c088ed6..7713ab327c5 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -3095,6 +3095,9 @@ Lower-end override for [member rendering/reflections/sky_reflections/texture_array_reflections] on mobile devices, due to performance concerns or driver support. + + If [code]true[/code], reduces reflections based on ambient light. + Sets the renderer that will be used by the project. Options are: [b]forward_plus[/b] (Forward+): High-end renderer designed for desktop devices. Has a higher base overhead, but scales well with complex scenes. Not suitable for older devices or mobile. diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index e23e3b935b3..d0d297f7916 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -4225,6 +4225,9 @@ RasterizerSceneGLES3::RasterizerSceneGLES3() { if (config->force_vertex_shading) { global_defines += "\n#define USE_VERTEX_LIGHTING\n"; } + if (!config->specular_occlusion) { + global_defines += "\n#define SPECULAR_OCCLUSION_DISABLED\n"; + } material_storage->shaders.scene_shader.initialize(global_defines); scene_globals.shader_default_version = material_storage->shaders.scene_shader.version_create(); material_storage->shaders.scene_shader.version_bind_shader(scene_globals.shader_default_version, SceneShaderGLES3::MODE_COLOR); diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl index 53cd6988e4d..0fa22f1958c 100644 --- a/drivers/gles3/shaders/scene.glsl +++ b/drivers/gles3/shaders/scene.glsl @@ -2120,8 +2120,18 @@ void main() { #endif // USE_LIGHTMAP_CAPTURE #endif // !DISABLE_LIGHTMAP - ambient_light *= albedo.rgb; ambient_light *= ao; +#ifndef SPECULAR_OCCLUSION_DISABLED + float specular_occlusion = (ambient_light.r * 0.3 + ambient_light.g * 0.59 + ambient_light.b * 0.11) * 2.0; // Luminance of ambient light. + specular_occlusion = min(specular_occlusion * 4.0, 1.0); // This multiplication preserves speculars on bright areas. + + float reflective_f = (1.0 - roughness) * metallic; + // 10.0 is a magic number, it gives the intended effect in most scenarios. + // Low enough for occlusion, high enough for reaction to lights and shadows. + specular_occlusion = max(min(reflective_f * specular_occlusion * 10.0, 1.0), specular_occlusion); + specular_light *= specular_occlusion; +#endif // !SPECULAR_OCCLUSION_DISABLED + ambient_light *= albedo.rgb; #endif // !AMBIENT_LIGHT_DISABLED diff --git a/drivers/gles3/storage/config.cpp b/drivers/gles3/storage/config.cpp index 749947ebc3b..9816061eb48 100644 --- a/drivers/gles3/storage/config.cpp +++ b/drivers/gles3/storage/config.cpp @@ -185,6 +185,7 @@ Config::Config() { #endif force_vertex_shading = GLOBAL_GET("rendering/shading/overrides/force_vertex_shading"); + specular_occlusion = GLOBAL_GET("rendering/reflections/specular_occlusion/enabled"); use_nearest_mip_filter = GLOBAL_GET("rendering/textures/default_filters/use_nearest_mipmap_filter"); use_depth_prepass = bool(GLOBAL_GET("rendering/driver/depth_prepass/enable")); diff --git a/drivers/gles3/storage/config.h b/drivers/gles3/storage/config.h index 531c74002a9..60753d2312a 100644 --- a/drivers/gles3/storage/config.h +++ b/drivers/gles3/storage/config.h @@ -83,6 +83,7 @@ public: bool srgb_framebuffer_supported = false; bool force_vertex_shading = false; + bool specular_occlusion = false; bool support_anisotropic_filter = false; float anisotropic_level = 0.0f; diff --git a/drivers/gles3/storage/material_storage.cpp b/drivers/gles3/storage/material_storage.cpp index 30097741d8d..75f1edb4a26 100644 --- a/drivers/gles3/storage/material_storage.cpp +++ b/drivers/gles3/storage/material_storage.cpp @@ -1382,6 +1382,8 @@ MaterialStorage::MaterialStorage() { } actions.render_mode_defines["fog_disabled"] = "#define FOG_DISABLED\n"; + actions.render_mode_defines["specular_occlusion_disabled"] = "#define SPECULAR_OCCLUSION_DISABLED\n"; + actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP; actions.default_repeat = ShaderLanguage::REPEAT_ENABLE; diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index 4e84e15e73f..206cac213de 100644 --- a/scene/resources/material.cpp +++ b/scene/resources/material.cpp @@ -873,7 +873,9 @@ void BaseMaterial3D::_update_shader() { if (flags[FLAG_DISABLE_FOG]) { code += ", fog_disabled"; } - + if (flags[FLAG_DISABLE_SPECULAR_OCCLUSION]) { + code += ", specular_occlusion_disabled"; + } if (transparency == TRANSPARENCY_ALPHA_DEPTH_PRE_PASS) { code += ", depth_prepass_alpha"; } @@ -3208,6 +3210,7 @@ void BaseMaterial3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "specular_mode", PROPERTY_HINT_ENUM, "SchlickGGX,Toon,Disabled"), "set_specular_mode", "get_specular_mode"); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "disable_ambient_light"), "set_flag", "get_flag", FLAG_DISABLE_AMBIENT_LIGHT); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "disable_fog"), "set_flag", "get_flag", FLAG_DISABLE_FOG); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "disable_specular_occlusion"), "set_flag", "get_flag", FLAG_DISABLE_SPECULAR_OCCLUSION); ADD_GROUP("Vertex Color", "vertex_color"); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "vertex_color_use_as_albedo"), "set_flag", "get_flag", FLAG_ALBEDO_FROM_VERTEX_COLOR); @@ -3466,6 +3469,7 @@ void BaseMaterial3D::_bind_methods() { BIND_ENUM_CONSTANT(FLAG_PARTICLE_TRAILS_MODE); BIND_ENUM_CONSTANT(FLAG_ALBEDO_TEXTURE_MSDF); BIND_ENUM_CONSTANT(FLAG_DISABLE_FOG); + BIND_ENUM_CONSTANT(FLAG_DISABLE_SPECULAR_OCCLUSION); BIND_ENUM_CONSTANT(FLAG_MAX); BIND_ENUM_CONSTANT(DIFFUSE_BURLEY); diff --git a/scene/resources/material.h b/scene/resources/material.h index 4c9044c30f2..d9487769502 100644 --- a/scene/resources/material.h +++ b/scene/resources/material.h @@ -267,6 +267,7 @@ public: FLAG_PARTICLE_TRAILS_MODE, FLAG_ALBEDO_TEXTURE_MSDF, FLAG_DISABLE_FOG, + FLAG_DISABLE_SPECULAR_OCCLUSION, FLAG_MAX }; 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 193a1458099..ff1e6b42b48 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp @@ -4872,6 +4872,11 @@ RenderForwardClustered::RenderForwardClustered() { defines += "\n#define USE_VERTEX_LIGHTING\n"; } + bool specular_occlusion = GLOBAL_GET("rendering/reflections/specular_occlusion/enabled"); + if (!specular_occlusion) { + defines += "\n#define SPECULAR_OCCLUSION_DISABLED\n"; + } + { //lightmaps scene_state.max_lightmaps = MAX_LIGHTMAPS; diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp index 69075ad169f..f13f364f3c1 100644 --- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp @@ -766,6 +766,8 @@ void SceneShaderForwardClustered::init(const String p_defines) { actions.render_mode_defines["debug_shadow_splits"] = "#define DEBUG_DRAW_PSSM_SPLITS\n"; actions.render_mode_defines["fog_disabled"] = "#define FOG_DISABLED\n"; + actions.render_mode_defines["specular_occlusion_disabled"] = "#define SPECULAR_OCCLUSION_DISABLED\n"; + actions.base_texture_binding_index = 1; actions.texture_layout_set = RenderForwardClustered::MATERIAL_UNIFORM_SET; actions.base_uniform_string = "material."; diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp index 5ab4ce570d4..f809077416b 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp @@ -3221,6 +3221,11 @@ RenderForwardMobile::RenderForwardMobile() { defines += "\n#define USE_VERTEX_LIGHTING\n"; } + bool specular_occlusion = GLOBAL_GET("rendering/reflections/specular_occlusion/enabled"); + if (!specular_occlusion) { + defines += "\n#define SPECULAR_OCCLUSION_DISABLED\n"; + } + { //lightmaps scene_state.max_lightmaps = 2; diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp index 7ae930665c1..47250fd6aec 100644 --- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp @@ -698,6 +698,8 @@ void SceneShaderForwardMobile::init(const String p_defines) { actions.render_mode_defines["debug_shadow_splits"] = "#define DEBUG_DRAW_PSSM_SPLITS\n"; actions.render_mode_defines["fog_disabled"] = "#define FOG_DISABLED\n"; + actions.render_mode_defines["specular_occlusion_disabled"] = "#define SPECULAR_OCCLUSION_DISABLED\n"; + actions.base_texture_binding_index = 1; actions.texture_layout_set = RenderForwardMobile::MATERIAL_UNIFORM_SET; actions.base_uniform_string = "material."; diff --git a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl index bb78cd1a7ac..b1812d72f8a 100644 --- a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl +++ b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl @@ -1969,8 +1969,18 @@ void fragment_shader(in SceneData scene_data) { //finalize ambient light here { - ambient_light *= albedo.rgb; ambient_light *= ao; +#ifndef SPECULAR_OCCLUSION_DISABLED + float specular_occlusion = (ambient_light.r * 0.3 + ambient_light.g * 0.59 + ambient_light.b * 0.11) * 2.0; // Luminance of ambient light. + specular_occlusion = min(specular_occlusion * 4.0, 1.0); // This multiplication preserves speculars on bright areas. + + float reflective_f = (1.0 - roughness) * metallic; + // 10.0 is a magic number, it gives the intended effect in most scenarios. + // Low enough for occlusion, high enough for reaction to lights and shadows. + specular_occlusion = max(min(reflective_f * specular_occlusion * 10.0, 1.0), specular_occlusion); + specular_light *= specular_occlusion; +#endif // SPECULAR_OCCLUSION_DISABLED + ambient_light *= albedo.rgb; if (bool(implementation_data.ss_effects_flags & SCREEN_SPACE_EFFECTS_FLAGS_USE_SSIL)) { #ifdef USE_MULTIVIEW diff --git a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl index edbebbd14c3..83fd4bff89a 100644 --- a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl +++ b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl @@ -1437,9 +1437,18 @@ void main() { } //Reflection probes // finalize ambient light here - - ambient_light *= albedo.rgb; ambient_light *= ao; +#ifndef SPECULAR_OCCLUSION_DISABLED + float specular_occlusion = (ambient_light.r * 0.3 + ambient_light.g * 0.59 + ambient_light.b * 0.11) * 2.0; // Luminance of ambient light. + specular_occlusion = min(specular_occlusion * 4.0, 1.0); // This multiplication preserves speculars on bright areas. + + float reflective_f = (1.0 - roughness) * metallic; + // 10.0 is a magic number, it gives the intended effect in most scenarios. + // Low enough for occlusion, high enough for reaction to lights and shadows. + specular_occlusion = max(min(reflective_f * specular_occlusion * 10.0, 1.0), specular_occlusion); + specular_light *= specular_occlusion; +#endif // USE_SPECULAR_OCCLUSION + ambient_light *= albedo.rgb; #endif // !AMBIENT_LIGHT_DISABLED diff --git a/servers/rendering/shader_types.cpp b/servers/rendering/shader_types.cpp index 5eb113c8762..cf8c1bd6ca0 100644 --- a/servers/rendering/shader_types.cpp +++ b/servers/rendering/shader_types.cpp @@ -242,6 +242,7 @@ ShaderTypes::ShaderTypes() { shader_modes[RS::SHADER_SPATIAL].modes.push_back({ PNAME("alpha_to_coverage_and_one") }); shader_modes[RS::SHADER_SPATIAL].modes.push_back({ PNAME("debug_shadow_splits") }); shader_modes[RS::SHADER_SPATIAL].modes.push_back({ PNAME("fog_disabled") }); + shader_modes[RS::SHADER_SPATIAL].modes.push_back({ PNAME("specular_occlusion_disabled") }); } /************ CANVAS ITEM **************************/ diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index f0768c1ef8b..37a9d0947a3 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -3632,6 +3632,7 @@ void RenderingServer::init() { GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/reflections/reflection_atlas/reflection_size", PROPERTY_HINT_RANGE, "0,4096,1"), 256); GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/reflections/reflection_atlas/reflection_size.mobile", PROPERTY_HINT_RANGE, "0,2048,1"), 128); GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/reflections/reflection_atlas/reflection_count", PROPERTY_HINT_RANGE, "0,256,1"), 64); + GLOBAL_DEF_RST("rendering/reflections/specular_occlusion/enabled", true); GLOBAL_DEF("rendering/global_illumination/gi/use_half_resolution", false);