diff --git a/doc/classes/DirectionalLight.xml b/doc/classes/DirectionalLight.xml
index 81d62f6b4..91c961d7a 100644
--- a/doc/classes/DirectionalLight.xml
+++ b/doc/classes/DirectionalLight.xml
@@ -24,7 +24,7 @@
The maximum distance for shadow splits. Increasing this value will make directional shadows visible from further away, at the cost of lower overall shadow detail and performance (since more objects need to be included in the directional shadow rendering).
-
+
The light's shadow rendering algorithm. See [enum ShadowMode].
@@ -47,7 +47,10 @@
Splits the view frustum in 2 areas, each with its own shadow map. This shadow mode is a compromise between [constant SHADOW_ORTHOGONAL] and [constant SHADOW_PARALLEL_4_SPLITS] in terms of performance.
-
+
+ Splits the view frustum in 3 areas, each with its own shadow map. This shadow mode is a compromise between [constant SHADOW_ORTHOGONAL] and [constant SHADOW_PARALLEL_4_SPLITS] in terms of performance.
+
+
Splits the view frustum in 4 areas, each with its own shadow map. This is the slowest directional shadow mode.
diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml
index 3e67b3ac4..0ad3992f5 100644
--- a/doc/classes/RenderingServer.xml
+++ b/doc/classes/RenderingServer.xml
@@ -3153,7 +3153,10 @@
Use 2 splits for shadow projection when using directional light.
-
+
+ Use 3 splits for shadow projection when using directional light.
+
+
Use 4 splits for shadow projection when using directional light.
diff --git a/drivers/gles2/rasterizer_scene_gles2.cpp b/drivers/gles2/rasterizer_scene_gles2.cpp
index 52a959e8c..f31db23a5 100644
--- a/drivers/gles2/rasterizer_scene_gles2.cpp
+++ b/drivers/gles2/rasterizer_scene_gles2.cpp
@@ -513,6 +513,7 @@ int RasterizerSceneGLES2::get_directional_light_shadow_size(RID p_light_intance)
case RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL:
break; //none
case RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS:
+ case RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_3_SPLITS:
case RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS:
shadow_size /= 2;
break;
@@ -1906,7 +1907,9 @@ void RasterizerSceneGLES2::_setup_light_type(LightInstance *p_light, ShadowAtlas
} break;
case RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS: {
state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM2, true);
-
+ } break;
+ case RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_3_SPLITS: {
+ state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM3, true);
} break;
case RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS: {
state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM4, true);
@@ -1995,6 +1998,10 @@ void RasterizerSceneGLES2::_setup_light(LightInstance *light, ShadowAtlas *shado
shadow_count = 2;
} break;
+ case RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_3_SPLITS: {
+ shadow_count = 3;
+ } break;
+
case RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS: {
shadow_count = 4;
} break;
@@ -2006,7 +2013,8 @@ void RasterizerSceneGLES2::_setup_light(LightInstance *light, ShadowAtlas *shado
uint32_t width = light->directional_rect.size.x;
uint32_t height = light->directional_rect.size.y;
- if (light_ptr->directional_shadow_mode == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS) {
+ if (light_ptr->directional_shadow_mode == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_3_SPLITS ||
+ light_ptr->directional_shadow_mode == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS) {
width /= 2;
height /= 2;
@@ -2593,6 +2601,7 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements,
state.scene_shader.set_conditional(SceneShaderGLES2::USE_INSTANCING, false);
state.scene_shader.set_conditional(SceneShaderGLES2::USE_RADIANCE_MAP, false);
state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM4, false);
+ state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM3, false);
state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM2, false);
state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM_BLEND, false);
state.scene_shader.set_conditional(SceneShaderGLES2::USE_VERTEX_LIGHTING, false);
@@ -3576,7 +3585,8 @@ void RasterizerSceneGLES2::render_shadow(RID p_light, RID p_shadow_atlas, int p_
width = light_instance->directional_rect.size.width;
height = light_instance->directional_rect.size.height;
- if (light->directional_shadow_mode == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS) {
+ if (light->directional_shadow_mode == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_3_SPLITS
+ || light->directional_shadow_mode == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS) {
width /= 2;
height /= 2;
diff --git a/drivers/gles2/shaders/scene.glsl b/drivers/gles2/shaders/scene.glsl
index 7696ec5ae..3f35603b8 100644
--- a/drivers/gles2/shaders/scene.glsl
+++ b/drivers/gles2/shaders/scene.glsl
@@ -166,18 +166,19 @@ uniform highp float shadow_dual_paraboloid_render_side;
uniform highp mat4 light_shadow_matrix;
varying highp vec4 shadow_coord;
-#if defined(LIGHT_USE_PSSM2) || defined(LIGHT_USE_PSSM4)
+#if defined(LIGHT_USE_PSSM2) || defined(LIGHT_USE_PSSM3) || defined(LIGHT_USE_PSSM4)
uniform highp mat4 light_shadow_matrix2;
varying highp vec4 shadow_coord2;
#endif
-#if defined(LIGHT_USE_PSSM4)
-
+#if defined(LIGHT_USE_PSSM3) || defined(LIGHT_USE_PSSM4)
uniform highp mat4 light_shadow_matrix3;
-uniform highp mat4 light_shadow_matrix4;
varying highp vec4 shadow_coord3;
-varying highp vec4 shadow_coord4;
+#endif
+#if defined(LIGHT_USE_PSSM4)
+uniform highp mat4 light_shadow_matrix4;
+varying highp vec4 shadow_coord4;
#endif
#endif
@@ -648,14 +649,16 @@ VERTEX_SHADER_CODE
vec4 vi4 = vec4(vertex_interp, 1.0);
shadow_coord = light_shadow_matrix * vi4;
-#if defined(LIGHT_USE_PSSM2) || defined(LIGHT_USE_PSSM4)
+#if defined(LIGHT_USE_PSSM2) || defined(LIGHT_USE_PSSM3) || defined(LIGHT_USE_PSSM4)
shadow_coord2 = light_shadow_matrix2 * vi4;
#endif
-#if defined(LIGHT_USE_PSSM4)
+#if defined(LIGHT_USE_PSSM3) || defined(LIGHT_USE_PSSM4)
shadow_coord3 = light_shadow_matrix3 * vi4;
- shadow_coord4 = light_shadow_matrix4 * vi4;
+#endif
+#if defined(LIGHT_USE_PSSM4)
+ shadow_coord4 = light_shadow_matrix4 * vi4;
#endif
#endif //use shadow and use lighting
@@ -1017,15 +1020,16 @@ uniform highp vec4 light_split_offsets;
varying highp vec4 shadow_coord;
-#if defined(LIGHT_USE_PSSM2) || defined(LIGHT_USE_PSSM4)
+#if defined(LIGHT_USE_PSSM2) || defined(LIGHT_USE_PSSM3) || defined(LIGHT_USE_PSSM4)
varying highp vec4 shadow_coord2;
#endif
-#if defined(LIGHT_USE_PSSM4)
-
+#if defined(LIGHT_USE_PSSM3) || defined(LIGHT_USE_PSSM4)
varying highp vec4 shadow_coord3;
-varying highp vec4 shadow_coord4;
+#endif
+#if defined(LIGHT_USE_PSSM4)
+varying highp vec4 shadow_coord4;
#endif
uniform vec4 light_clamp;
@@ -1892,6 +1896,55 @@ FRAGMENT_SHADER_CODE
#endif //LIGHT_USE_PSSM4
+#ifdef LIGHT_USE_PSSM3
+ //take advantage of prefetch
+ float shadow1 = sample_shadow(light_directional_shadow, shadow_coord);
+ float shadow2 = sample_shadow(light_directional_shadow, shadow_coord2);
+ float shadow3 = sample_shadow(light_directional_shadow, shadow_coord3);
+
+ if (depth_z < light_split_offsets.z) {
+ float pssm_fade = 0.0;
+ float shadow_att = 1.0;
+#ifdef LIGHT_USE_PSSM_BLEND
+ float shadow_att2 = 1.0;
+ float pssm_blend = 0.0;
+ bool use_blend = true;
+#endif
+ if (depth_z < light_split_offsets.y) {
+ if (depth_z < light_split_offsets.x) {
+ shadow_att = shadow1;
+
+#ifdef LIGHT_USE_PSSM_BLEND
+ shadow_att2 = shadow2;
+
+ pssm_blend = smoothstep(0.0, light_split_offsets.x, depth_z);
+#endif
+ } else {
+ shadow_att = shadow2;
+
+#ifdef LIGHT_USE_PSSM_BLEND
+ shadow_att2 = shadow3;
+
+ pssm_blend = smoothstep(light_split_offsets.x, light_split_offsets.y, depth_z);
+#endif
+ }
+ } else {
+ shadow_att = shadow3;
+
+#if defined(LIGHT_USE_PSSM_BLEND)
+ use_blend = false;
+#endif
+ }
+#if defined(LIGHT_USE_PSSM_BLEND)
+ if (use_blend) {
+ shadow_att = mix(shadow_att, shadow_att2, pssm_blend);
+ }
+#endif
+ light_att *= mix(shadow_color.rgb, vec3(1.0), shadow_att);
+ }
+
+#endif //LIGHT_USE_PSSM3
+
#ifdef LIGHT_USE_PSSM2
//take advantage of prefetch
@@ -1932,7 +1985,7 @@ FRAGMENT_SHADER_CODE
#endif //LIGHT_USE_PSSM2
-#if !defined(LIGHT_USE_PSSM4) && !defined(LIGHT_USE_PSSM2)
+#if !defined(LIGHT_USE_PSSM4) && !defined(LIGHT_USE_PSSM3) && !defined(LIGHT_USE_PSSM2)
light_att *= mix(shadow_color.rgb, vec3(1.0), sample_shadow(light_directional_shadow, shadow_coord));
#endif //orthogonal
@@ -1942,6 +1995,8 @@ FRAGMENT_SHADER_CODE
{
#ifdef LIGHT_USE_PSSM4
if (depth_z < light_split_offsets.w) {
+#elif defined(LIGHT_USE_PSSM3)
+ if (depth_z < light_split_offsets.z) {
#elif defined(LIGHT_USE_PSSM2)
if (depth_z < light_split_offsets.y) {
#else
@@ -1998,6 +2053,35 @@ FRAGMENT_SHADER_CODE
#endif // LIGHT_USE_PSSM4
+#ifdef LIGHT_USE_PSSM3
+
+ if (depth_z < light_split_offsets.y) {
+ if (depth_z < light_split_offsets.x) {
+ pssm_coord = shadow_coord;
+
+#ifdef LIGHT_USE_PSSM_BLEND
+ pssm_coord2 = shadow_coord2;
+ pssm_blend = smoothstep(0.0, light_split_offsets.x, depth_z);
+#endif
+ } else {
+ pssm_coord = shadow_coord2;
+
+#ifdef LIGHT_USE_PSSM_BLEND
+ pssm_coord2 = shadow_coord3;
+ pssm_blend = smoothstep(light_split_offsets.x, light_split_offsets.y, depth_z);
+#endif
+ }
+ } else {
+ pssm_coord = shadow_coord3;
+ pssm_fade = smoothstep(light_split_offsets.y, light_split_offsets.z, depth_z);
+
+#if defined(LIGHT_USE_PSSM_BLEND)
+ use_blend = false;
+#endif
+ }
+
+#endif // LIGHT_USE_PSSM3
+
#ifdef LIGHT_USE_PSSM2
if (depth_z < light_split_offsets.x) {
pssm_coord = shadow_coord;
@@ -2016,7 +2100,7 @@ FRAGMENT_SHADER_CODE
#endif // LIGHT_USE_PSSM2
-#if !defined(LIGHT_USE_PSSM4) && !defined(LIGHT_USE_PSSM2)
+#if !defined(LIGHT_USE_PSSM4) && !defined(LIGHT_USE_PSSM3) && !defined(LIGHT_USE_PSSM2)
{
pssm_coord = shadow_coord;
}
diff --git a/scene/3d/light.cpp b/scene/3d/light.cpp
index 23d19a5d6..5cb8637be 100644
--- a/scene/3d/light.cpp
+++ b/scene/3d/light.cpp
@@ -363,7 +363,7 @@ void DirectionalLight::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_blend_splits_enabled"), &DirectionalLight::is_blend_splits_enabled);
ADD_GROUP("Directional Shadow", "directional_shadow_");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "directional_shadow_mode", PROPERTY_HINT_ENUM, "Orthogonal (Fast),PSSM 2 Splits (Average),PSSM 4 Splits (Slow)"), "set_shadow_mode", "get_shadow_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "directional_shadow_mode", PROPERTY_HINT_ENUM, "Orthogonal (Fast),PSSM 2 Splits (Average),PSSM 3 Splits (Slow),PSSM 4 Splits (Very Slow)"), "set_shadow_mode", "get_shadow_mode");
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "directional_shadow_split_1", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_param", "get_param", PARAM_SHADOW_SPLIT_1_OFFSET);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "directional_shadow_split_2", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_param", "get_param", PARAM_SHADOW_SPLIT_2_OFFSET);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "directional_shadow_split_3", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_param", "get_param", PARAM_SHADOW_SPLIT_3_OFFSET);
@@ -375,6 +375,7 @@ void DirectionalLight::_bind_methods() {
BIND_ENUM_CONSTANT(SHADOW_ORTHOGONAL);
BIND_ENUM_CONSTANT(SHADOW_PARALLEL_2_SPLITS);
+ BIND_ENUM_CONSTANT(SHADOW_PARALLEL_3_SPLITS);
BIND_ENUM_CONSTANT(SHADOW_PARALLEL_4_SPLITS);
BIND_ENUM_CONSTANT(SHADOW_DEPTH_RANGE_STABLE);
diff --git a/scene/3d/light.h b/scene/3d/light.h
index 995a42b0d..f0cd8e22d 100644
--- a/scene/3d/light.h
+++ b/scene/3d/light.h
@@ -126,6 +126,7 @@ public:
enum ShadowMode {
SHADOW_ORTHOGONAL,
SHADOW_PARALLEL_2_SPLITS,
+ SHADOW_PARALLEL_3_SPLITS,
SHADOW_PARALLEL_4_SPLITS
};
diff --git a/servers/rendering/rendering_server_scene.cpp b/servers/rendering/rendering_server_scene.cpp
index d6f8a17e5..ea56cee36 100644
--- a/servers/rendering/rendering_server_scene.cpp
+++ b/servers/rendering/rendering_server_scene.cpp
@@ -2117,6 +2117,9 @@ bool RenderingServerScene::_light_instance_update_shadow(Instance *p_instance, c
case RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS:
splits = 2;
break;
+ case RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_3_SPLITS:
+ splits = 3;
+ break;
case RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS:
splits = 4;
break;
diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp
index da8051a19..7d8b5b52d 100644
--- a/servers/rendering_server.cpp
+++ b/servers/rendering_server.cpp
@@ -2325,6 +2325,7 @@ void RenderingServer::_bind_methods() {
BIND_ENUM_CONSTANT(LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL);
BIND_ENUM_CONSTANT(LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS);
+ BIND_ENUM_CONSTANT(LIGHT_DIRECTIONAL_SHADOW_PARALLEL_3_SPLITS);
BIND_ENUM_CONSTANT(LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS);
BIND_ENUM_CONSTANT(LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE);
BIND_ENUM_CONSTANT(LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_OPTIMIZED);
diff --git a/servers/rendering_server.h b/servers/rendering_server.h
index bf594a813..2c0faf39a 100644
--- a/servers/rendering_server.h
+++ b/servers/rendering_server.h
@@ -483,6 +483,7 @@ public:
enum LightDirectionalShadowMode {
LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL,
LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS,
+ LIGHT_DIRECTIONAL_SHADOW_PARALLEL_3_SPLITS,
LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS
};