From baaa7503c7e0c83c94edf651ac31f03e0ceddac0 Mon Sep 17 00:00:00 2001 From: Hugo Locurcio Date: Fri, 10 Jun 2022 12:47:06 +0200 Subject: [PATCH] Add a shadow opacity property to Light3D This can be used to make shadows translucent for a specific light. The light distance fade system also uses this to smoothly fade the shadow when the light fade transition distance is greater than 0. --- doc/classes/Light3D.xml | 18 ++++++++++------ doc/classes/RenderingServer.xml | 12 +++++++---- drivers/gles3/rasterizer_scene_gles3.cpp | 2 +- drivers/gles3/rasterizer_scene_gles3.h | 2 +- drivers/gles3/shaders/scene.glsl | 2 +- drivers/gles3/storage/light_storage.cpp | 1 + scene/3d/light_3d.cpp | 5 ++++- scene/3d/light_3d.h | 1 + .../renderer_rd/renderer_scene_render_rd.cpp | 21 ++++++++++++------- .../renderer_rd/renderer_scene_render_rd.h | 4 ++-- .../environment/volumetric_fog_process.glsl | 6 +++--- .../renderer_rd/shaders/light_data_inc.glsl | 4 ++-- .../shaders/scene_forward_clustered.glsl | 6 ++++-- .../shaders/scene_forward_lights_inc.glsl | 10 +++++---- .../shaders/scene_forward_mobile.glsl | 4 ++-- .../renderer_rd/storage_rd/light_storage.cpp | 1 + servers/rendering_server.cpp | 1 + servers/rendering_server.h | 1 + 18 files changed, 65 insertions(+), 36 deletions(-) diff --git a/doc/classes/Light3D.xml b/doc/classes/Light3D.xml index 0ebd83c8820..46c3e575475 100644 --- a/doc/classes/Light3D.xml +++ b/doc/classes/Light3D.xml @@ -37,13 +37,12 @@ [b]Note:[/b] Only effective for [OmniLight3D] and [SpotLight3D]. - Distance over which the light fades. The light's energy is progressively reduced over this distance and is completely invisible at the end. + Distance over which the light and its shadow fades. The light's energy and shadow's opacity is progressively reduced over this distance and is completely invisible at the end. [b]Note:[/b] Only effective for [OmniLight3D] and [SpotLight3D]. The distance from the camera at which the light's shadow cuts off (in 3D units). Set this to a value lower than [member distance_fade_begin] + [member distance_fade_length] to further improve performance, as shadow rendering is often more expensive than light rendering itself. [b]Note:[/b] Only effective for [OmniLight3D] and [SpotLight3D], and only when [member shadow_enabled] is [code]true[/code]. - [b]Note:[/b] Due to a rendering engine limitation, shadows will be disabled instantly instead of fading smoothly according to [member distance_fade_length]. This may result in visible pop-in depending on the scene topography. If [code]true[/code], the light only appears in the editor and will not be visible at runtime. @@ -95,6 +94,9 @@ Offsets the lookup into the shadow map by the object's normal. This can be used to reduce self-shadowing artifacts without using [member shadow_bias]. In practice, this value should be tweaked along with [member shadow_bias] to reduce artifacts as much as possible. + + The opacity to use when rendering the light's shadow map. Values lower than [code]1.0[/code] make the light appear through shadows. This can be used to fake global illumination at a low performance cost. + If [code]true[/code], reverses the backface culling of the mesh. This can be useful when you have a flat mesh that has a light behind it. If you need to cast a shadow on both sides of the mesh, set the mesh to use double-sided shadows with [constant GeometryInstance3D.SHADOW_CASTING_SETTING_DOUBLE_SIDED]. @@ -150,15 +152,19 @@ Constant for accessing [member DirectionalLight3D.directional_shadow_pancake_size]. - + + Constant for accessing [member shadow_opacity]. + + Constant for accessing [member shadow_blur]. - + + Constant for accessing [member shadow_fog_fade]. - + Constant for accessing [member shadow_transmittance_bias]. - + Represents the size of the [enum Param] enum. diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml index 1b58b50bc77..c06b2e1d983 100644 --- a/doc/classes/RenderingServer.xml +++ b/doc/classes/RenderingServer.xml @@ -3777,6 +3777,7 @@ The light's energy. + The light's indirect energy multiplier (final indirect energy is [constant LIGHT_PARAM_ENERGY] * [constant LIGHT_PARAM_INDIRECT_ENERGY]). The light's influence on specularity. @@ -3820,14 +3821,17 @@ Sets the size of the directional shadow pancake. The pancake offsets the start of the shadow's camera frustum to provide a higher effective depth resolution for the shadow. However, a high pancake size can cause artifacts in the shadows of large objects that are close to the edge of the frustum. Reducing the pancake size can help. Setting the size to [code]0[/code] turns off the pancaking effect. - + + The light's shadow opacity. Values lower than [code]1.0[/code] make the light appear through shadows. This can be used to fake global illumination at a low performance cost. + + Blurs the edges of the shadow. Can be used to hide pixel artifacts in low resolution shadow maps. A high value can make shadows appear grainy and can cause other unwanted artifacts. Try to keep as near default as possible. - + - + - + Represents the size of the [enum LightParam] enum. diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index 410cd376a7a..7207a6efbb4 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -1650,7 +1650,7 @@ void RasterizerSceneGLES3::_setup_lights(const RenderDataGLES3 *p_render_data, b light_data.specular_amount = light_storage->light_get_param(base, RS::LIGHT_PARAM_SPECULAR) * 2.0; - light_data.shadow_enabled = false; + light_data.shadow_opacity = 0.0; } // TODO, to avoid stalls, should rotate between 3 buffers based on frame index. diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h index e227b2df820..a54d87a3a33 100644 --- a/drivers/gles3/rasterizer_scene_gles3.h +++ b/drivers/gles3/rasterizer_scene_gles3.h @@ -165,7 +165,7 @@ private: float inv_spot_attenuation; float cos_spot_angle; float specular_amount; - uint32_t shadow_enabled; + float shadow_opacity; }; static_assert(sizeof(LightData) % 16 == 0, "LightData size must be a multiple of 16 bytes"); diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl index 4081d73ab04..2550b3a8a1b 100644 --- a/drivers/gles3/shaders/scene.glsl +++ b/drivers/gles3/shaders/scene.glsl @@ -495,7 +495,7 @@ struct LightData { //this structure needs to be as packed as possible mediump float cone_attenuation; mediump float cone_angle; mediump float specular_amount; - bool shadow_enabled; + mediump float shadow_opacity; }; #ifndef DISABLE_LIGHT_OMNI layout(std140) uniform OmniLightData { // ubo:5 diff --git a/drivers/gles3/storage/light_storage.cpp b/drivers/gles3/storage/light_storage.cpp index 22578c9e91c..2e4bfdc15bd 100644 --- a/drivers/gles3/storage/light_storage.cpp +++ b/drivers/gles3/storage/light_storage.cpp @@ -70,6 +70,7 @@ void LightStorage::_light_initialize(RID p_light, RS::LightType p_type) { light.param[RS::LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET] = 0.6; light.param[RS::LIGHT_PARAM_SHADOW_FADE_START] = 0.8; light.param[RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS] = 1.0; + light.param[RS::LIGHT_PARAM_SHADOW_OPACITY] = 1.0; light.param[RS::LIGHT_PARAM_SHADOW_BIAS] = 0.02; light.param[RS::LIGHT_PARAM_SHADOW_BLUR] = 0; light.param[RS::LIGHT_PARAM_SHADOW_PANCAKE_SIZE] = 20.0; diff --git a/scene/3d/light_3d.cpp b/scene/3d/light_3d.cpp index 678c2176768..53c072c318b 100644 --- a/scene/3d/light_3d.cpp +++ b/scene/3d/light_3d.cpp @@ -224,7 +224,7 @@ bool Light3D::is_editor_only() const { } void Light3D::_validate_property(PropertyInfo &property) const { - if (!shadow && (property.name == "shadow_bias" || property.name == "shadow_normal_bias" || property.name == "shadow_reverse_cull_face" || property.name == "shadow_transmittance_bias" || property.name == "shadow_fog_fade" || property.name == "shadow_blur" || property.name == "distance_fade_shadow")) { + if (!shadow && (property.name == "shadow_bias" || property.name == "shadow_normal_bias" || property.name == "shadow_reverse_cull_face" || property.name == "shadow_transmittance_bias" || property.name == "shadow_fog_fade" || property.name == "shadow_opacity" || property.name == "shadow_blur" || property.name == "distance_fade_shadow")) { property.usage = PROPERTY_USAGE_NO_EDITOR; } @@ -299,6 +299,7 @@ void Light3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shadow_reverse_cull_face"), "set_shadow_reverse_cull_face", "get_shadow_reverse_cull_face"); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "shadow_transmittance_bias", PROPERTY_HINT_RANGE, "-16,16,0.001"), "set_param", "get_param", PARAM_TRANSMITTANCE_BIAS); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "shadow_fog_fade", PROPERTY_HINT_RANGE, "0.001,10,0.001"), "set_param", "get_param", PARAM_SHADOW_VOLUMETRIC_FOG_FADE); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "shadow_opacity", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param", "get_param", PARAM_SHADOW_OPACITY); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "shadow_blur", PROPERTY_HINT_RANGE, "0,10,0.001"), "set_param", "get_param", PARAM_SHADOW_BLUR); ADD_GROUP("Distance Fade", "distance_fade_"); @@ -328,6 +329,7 @@ void Light3D::_bind_methods() { BIND_ENUM_CONSTANT(PARAM_SHADOW_NORMAL_BIAS); BIND_ENUM_CONSTANT(PARAM_SHADOW_BIAS); BIND_ENUM_CONSTANT(PARAM_SHADOW_PANCAKE_SIZE); + BIND_ENUM_CONSTANT(PARAM_SHADOW_OPACITY); BIND_ENUM_CONSTANT(PARAM_SHADOW_BLUR); BIND_ENUM_CONSTANT(PARAM_SHADOW_VOLUMETRIC_FOG_FADE); BIND_ENUM_CONSTANT(PARAM_TRANSMITTANCE_BIAS); @@ -375,6 +377,7 @@ Light3D::Light3D(RenderingServer::LightType p_type) { set_param(PARAM_SHADOW_SPLIT_3_OFFSET, 0.5); set_param(PARAM_SHADOW_FADE_START, 0.8); set_param(PARAM_SHADOW_PANCAKE_SIZE, 20.0); + set_param(PARAM_SHADOW_OPACITY, 1.0); set_param(PARAM_SHADOW_BLUR, 1.0); set_param(PARAM_SHADOW_BIAS, 0.03); set_param(PARAM_SHADOW_NORMAL_BIAS, 1.0); diff --git a/scene/3d/light_3d.h b/scene/3d/light_3d.h index 6ff332df5a6..ef003e133d5 100644 --- a/scene/3d/light_3d.h +++ b/scene/3d/light_3d.h @@ -54,6 +54,7 @@ public: PARAM_SHADOW_NORMAL_BIAS = RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS, PARAM_SHADOW_BIAS = RS::LIGHT_PARAM_SHADOW_BIAS, PARAM_SHADOW_PANCAKE_SIZE = RS::LIGHT_PARAM_SHADOW_PANCAKE_SIZE, + PARAM_SHADOW_OPACITY = RS::LIGHT_PARAM_SHADOW_OPACITY, PARAM_SHADOW_BLUR = RS::LIGHT_PARAM_SHADOW_BLUR, PARAM_SHADOW_VOLUMETRIC_FOG_FADE = RS::LIGHT_PARAM_SHADOW_VOLUMETRIC_FOG_FADE, PARAM_TRANSMITTANCE_BIAS = RS::LIGHT_PARAM_TRANSMITTANCE_BIAS, diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp index c6f38012a65..8b3b7050d28 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp @@ -2869,7 +2869,7 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray &p_lights, const WARN_PRINT_ONCE("The DirectionalLight3D PSSM splits debug draw mode is not reimplemented yet."); } - light_data.shadow_enabled = p_using_shadows && light_storage->light_has_shadow(base); + light_data.shadow_opacity = p_using_shadows && light_storage->light_has_shadow(base) ? light_storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_OPACITY) : 0.0; float angular_diameter = light_storage->light_get_param(base, RS::LIGHT_PARAM_SIZE); if (angular_diameter > 0.0) { @@ -2886,7 +2886,7 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray &p_lights, const angular_diameter = 0.0; } - if (light_data.shadow_enabled) { + if (light_data.shadow_opacity > 0.001) { RS::LightDirectionalShadowMode smode = light_storage->light_directional_get_shadow_mode(base); int limit = smode == RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL ? 0 : (smode == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS ? 1 : 3); @@ -3040,19 +3040,26 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray &p_lights, const // Reuse fade begin, fade length and distance for shadow LOD determination later. float fade_begin = 0.0; + float fade_shadow = 0.0; float fade_length = 0.0; real_t distance = 0.0; float fade = 1.0; + float shadow_opacity_fade = 1.0; if (light_storage->light_is_distance_fade_enabled(li->light)) { fade_begin = light_storage->light_get_distance_fade_begin(li->light); + fade_shadow = light_storage->light_get_distance_fade_shadow(li->light); fade_length = light_storage->light_get_distance_fade_length(li->light); distance = camera_plane.distance_to(li->transform.origin); + // Use `smoothstep()` to make opacity changes more gradual and less noticeable to the player. if (distance > fade_begin) { - // Use `smoothstep()` to make opacity changes more gradual and less noticeable to the player. fade = Math::smoothstep(0.0f, 1.0f, 1.0f - float(distance - fade_begin) / fade_length); } + + if (distance > fade_shadow) { + shadow_opacity_fade = Math::smoothstep(0.0f, 1.0f, 1.0f - float(distance - fade_shadow) / fade_length); + } } float energy = sign * light_storage->light_get_param(base, RS::LIGHT_PARAM_ENERGY) * Math_PI * fade; @@ -3120,7 +3127,7 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray &p_lights, const bool in_shadow_range = true; if (needs_shadow && light_storage->light_is_distance_fade_enabled(li->light)) { - if (distance > light_storage->light_get_distance_fade_shadow(li->light)) { + if (distance > light_storage->light_get_distance_fade_shadow(li->light) + light_storage->light_get_distance_fade_length(li->light)) { // Out of range, don't draw shadows to improve performance. in_shadow_range = false; } @@ -3129,7 +3136,7 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray &p_lights, const if (needs_shadow && in_shadow_range) { // fill in the shadow information - light_data.shadow_enabled = true; + light_data.shadow_opacity = light_storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_OPACITY) * shadow_opacity_fade; float shadow_texel_size = light_instance_get_shadow_texel_size(li->self, p_shadow_atlas); light_data.shadow_normal_bias = light_storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS) * shadow_texel_size * 10.0; @@ -3189,7 +3196,7 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray &p_lights, const } } } else { - light_data.shadow_enabled = false; + light_data.shadow_opacity = 0.0; } li->cull_mask = light_storage->light_get_cull_mask(base); @@ -3637,7 +3644,7 @@ void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool if (p_render_data->render_buffers.is_valid()) { bool directional_shadows = false; for (uint32_t i = 0; i < directional_light_count; i++) { - if (cluster.directional_lights[i].shadow_enabled) { + if (cluster.directional_lights[i].shadow_opacity > 0.001) { directional_shadows = true; break; } diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.h b/servers/rendering/renderer_rd/renderer_scene_render_rd.h index 09ec2a9efd1..22e9ead243d 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.h +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.h @@ -608,7 +608,7 @@ private: float inv_spot_attenuation; float cos_spot_angle; float specular_amount; - uint32_t shadow_enabled; + float shadow_opacity; float atlas_rect[4]; // in omni, used for atlas uv, in spot, used for projector uv float shadow_matrix[16]; @@ -633,7 +633,7 @@ private: float softshadow_angle; float soft_shadow_scale; uint32_t blend_splits; - uint32_t shadow_enabled; + float shadow_opacity; float fade_from; float fade_to; uint32_t pad[2]; diff --git a/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl b/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl index e74cfad65c1..6f79b9e771f 100644 --- a/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl +++ b/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl @@ -377,7 +377,7 @@ void main() { for (uint i = 0; i < params.directional_light_count; i++) { vec3 shadow_attenuation = vec3(1.0); - if (directional_lights.data[i].shadow_enabled) { + if (directional_lights.data[i].shadow_opacity > 0.001) { float depth_z = -view_pos.z; vec4 pssm_coord; @@ -486,7 +486,7 @@ void main() { vec3 light = omni_lights.data[light_index].color; - if (omni_lights.data[light_index].shadow_enabled) { + if (omni_lights.data[light_index].shadow_opacity > 0.001) { //has shadow vec4 uv_rect = omni_lights.data[light_index].atlas_rect; vec2 flip_offset = omni_lights.data[light_index].direction.xy; @@ -572,7 +572,7 @@ void main() { vec3 light = spot_lights.data[light_index].color; - if (spot_lights.data[light_index].shadow_enabled) { + if (spot_lights.data[light_index].shadow_opacity > 0.001) { //has shadow vec4 uv_rect = spot_lights.data[light_index].atlas_rect; vec2 flip_offset = spot_lights.data[light_index].direction.xy; diff --git a/servers/rendering/renderer_rd/shaders/light_data_inc.glsl b/servers/rendering/renderer_rd/shaders/light_data_inc.glsl index 61c8488a054..799f7087b6f 100644 --- a/servers/rendering/renderer_rd/shaders/light_data_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/light_data_inc.glsl @@ -15,7 +15,7 @@ struct LightData { //this structure needs to be as packed as possible mediump float cone_attenuation; mediump float cone_angle; mediump float specular_amount; - bool shadow_enabled; + mediump float shadow_opacity; highp vec4 atlas_rect; // rect in the shadow atlas highp mat4 shadow_matrix; @@ -60,7 +60,7 @@ struct DirectionalLightData { highp float softshadow_angle; highp float soft_shadow_scale; bool blend_splits; - bool shadow_enabled; + mediump float shadow_opacity; highp float fade_from; highp float fade_to; uvec2 pad; diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl index 22058b3a06d..dff24b71445 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl @@ -1417,7 +1417,7 @@ void fragment_shader(in SceneData scene_data) { float shadow = 1.0; - if (directional_lights.data[i].shadow_enabled) { + if (directional_lights.data[i].shadow_opacity > 0.001) { float depth_z = -vertex.z; vec3 light_dir = directional_lights.data[i].direction; vec3 base_normal_bias = normalize(normal_interp) * (1.0 - max(0.0, dot(light_dir, -normalize(normal_interp)))); @@ -1626,7 +1626,7 @@ void fragment_shader(in SceneData scene_data) { #ifdef LIGHT_TRANSMITTANCE_USED float transmittance_z = transmittance_depth; - if (directional_lights.data[i].shadow_enabled) { + if (directional_lights.data[i].shadow_opacity > 0.001) { float depth_z = -vertex.z; if (depth_z < directional_lights.data[i].shadow_split_offsets.x) { @@ -1681,6 +1681,8 @@ void fragment_shader(in SceneData scene_data) { } else { shadow = float(shadow1 >> ((i - 4) * 8) & 0xFF) / 255.0; } + + shadow = shadow * directional_lights.data[i].shadow_opacity + 1.0 - directional_lights.data[i].shadow_opacity; #endif blur_shadow(shadow); diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl index e27c81eaeac..50a13de11a7 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl @@ -395,7 +395,7 @@ float get_omni_attenuation(float distance, float inv_range, float decay) { float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) { #ifndef SHADOWS_DISABLED - if (omni_lights.data[idx].shadow_enabled) { + if (omni_lights.data[idx].shadow_opacity > 0.001) { // there is a shadowmap vec2 texel_size = scene_data_block.data.shadow_atlas_pixel_size; vec4 base_uv_rect = omni_lights.data[idx].atlas_rect; @@ -498,6 +498,7 @@ float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) { } shadow /= float(sc_penumbra_shadow_samples); + shadow = mix(1.0, shadow, omni_lights.data[idx].shadow_opacity); } else { //no blockers found, so no shadow @@ -516,7 +517,7 @@ float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) { vec2 pos = shadow_sample.xy / shadow_sample.z; float depth = shadow_len - omni_lights.data[idx].shadow_bias; depth *= omni_lights.data[idx].inv_radius; - shadow = sample_omni_pcf_shadow(shadow_atlas, omni_lights.data[idx].soft_shadow_scale / shadow_sample.z, pos, uv_rect, flip_offset, depth); + shadow = mix(1.0, sample_omni_pcf_shadow(shadow_atlas, omni_lights.data[idx].soft_shadow_scale / shadow_sample.z, pos, uv_rect, flip_offset, depth), omni_lights.data[idx].shadow_opacity); } return shadow; @@ -674,7 +675,7 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v float light_process_spot_shadow(uint idx, vec3 vertex, vec3 normal) { #ifndef SHADOWS_DISABLED - if (spot_lights.data[idx].shadow_enabled) { + if (spot_lights.data[idx].shadow_opacity > 0.001) { vec3 light_rel_vec = spot_lights.data[idx].position - vertex; float light_length = length(light_rel_vec); vec3 spot_dir = spot_lights.data[idx].direction; @@ -735,6 +736,7 @@ float light_process_spot_shadow(uint idx, vec3 vertex, vec3 normal) { } shadow /= float(sc_penumbra_shadow_samples); + shadow = mix(1.0, shadow, spot_lights.data[idx].shadow_opacity); } else { //no blockers found, so no shadow @@ -743,7 +745,7 @@ float light_process_spot_shadow(uint idx, vec3 vertex, vec3 normal) { } else { //hard shadow vec3 shadow_uv = vec3(splane.xy * spot_lights.data[idx].atlas_rect.zw + spot_lights.data[idx].atlas_rect.xy, splane.z); - shadow = sample_pcf_shadow(shadow_atlas, spot_lights.data[idx].soft_shadow_scale * scene_data_block.data.shadow_atlas_pixel_size, shadow_uv); + shadow = mix(1.0, sample_pcf_shadow(shadow_atlas, spot_lights.data[idx].soft_shadow_scale * scene_data_block.data.shadow_atlas_pixel_size, shadow_uv), spot_lights.data[idx].shadow_opacity); } return shadow; diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl index 26d0de46c24..eb73a335586 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl @@ -1134,7 +1134,7 @@ void main() { #ifdef USE_SOFT_SHADOWS //version with soft shadows, more expensive - if (directional_lights.data[i].shadow_enabled) { + if (directional_lights.data[i].shadow_opacity > 0.001) { float depth_z = -vertex.z; vec4 pssm_coord; @@ -1286,7 +1286,7 @@ void main() { #else // Soft shadow disabled version - if (directional_lights.data[i].shadow_enabled) { + if (directional_lights.data[i].shadow_opacity > 0.001) { float depth_z = -vertex.z; vec4 pssm_coord; diff --git a/servers/rendering/renderer_rd/storage_rd/light_storage.cpp b/servers/rendering/renderer_rd/storage_rd/light_storage.cpp index d3831b46183..882afdfa547 100644 --- a/servers/rendering/renderer_rd/storage_rd/light_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/light_storage.cpp @@ -88,6 +88,7 @@ void LightStorage::_light_initialize(RID p_light, RS::LightType p_type) { light.param[RS::LIGHT_PARAM_SHADOW_FADE_START] = 0.8; light.param[RS::LIGHT_PARAM_SHADOW_NORMAL_BIAS] = 1.0; light.param[RS::LIGHT_PARAM_SHADOW_BIAS] = 0.02; + light.param[RS::LIGHT_PARAM_SHADOW_OPACITY] = 1.0; light.param[RS::LIGHT_PARAM_SHADOW_BLUR] = 0; light.param[RS::LIGHT_PARAM_SHADOW_PANCAKE_SIZE] = 20.0; light.param[RS::LIGHT_PARAM_SHADOW_VOLUMETRIC_FOG_FADE] = 0.1; diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index 1ac9b5854da..a54d4f0384a 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -1911,6 +1911,7 @@ void RenderingServer::_bind_methods() { BIND_ENUM_CONSTANT(LIGHT_PARAM_SHADOW_NORMAL_BIAS); BIND_ENUM_CONSTANT(LIGHT_PARAM_SHADOW_BIAS); BIND_ENUM_CONSTANT(LIGHT_PARAM_SHADOW_PANCAKE_SIZE); + BIND_ENUM_CONSTANT(LIGHT_PARAM_SHADOW_OPACITY); BIND_ENUM_CONSTANT(LIGHT_PARAM_SHADOW_BLUR); BIND_ENUM_CONSTANT(LIGHT_PARAM_SHADOW_VOLUMETRIC_FOG_FADE); BIND_ENUM_CONSTANT(LIGHT_PARAM_TRANSMITTANCE_BIAS); diff --git a/servers/rendering_server.h b/servers/rendering_server.h index 297736aec7f..a2fe9caf195 100644 --- a/servers/rendering_server.h +++ b/servers/rendering_server.h @@ -425,6 +425,7 @@ public: LIGHT_PARAM_SHADOW_NORMAL_BIAS, LIGHT_PARAM_SHADOW_BIAS, LIGHT_PARAM_SHADOW_PANCAKE_SIZE, + LIGHT_PARAM_SHADOW_OPACITY, LIGHT_PARAM_SHADOW_BLUR, LIGHT_PARAM_SHADOW_VOLUMETRIC_FOG_FADE, LIGHT_PARAM_TRANSMITTANCE_BIAS,