summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJuan Linietsky <reduzio@gmail.com>2019-09-07 14:38:17 -0300
committerJuan Linietsky <reduzio@gmail.com>2020-02-11 12:01:20 +0100
commit88a7debbbc2cd035932facc04b7740fc204bcca6 (patch)
tree0a59df57cc732e2c57af2e115b79981d8ac68322
parent920db604d26e2e82b6289807ad8a0607b310eef6 (diff)
Directional lights and shadow mapping are functional.
-rw-r--r--scene/3d/light.cpp5
-rw-r--r--scene/3d/light.h1
-rw-r--r--servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.cpp73
-rw-r--r--servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.h12
-rw-r--r--servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp66
-rw-r--r--servers/visual/rasterizer_rd/rasterizer_scene_rd.h19
-rw-r--r--servers/visual/rasterizer_rd/rasterizer_storage_rd.cpp1
-rw-r--r--servers/visual/rasterizer_rd/shaders/scene_forward.glsl96
-rw-r--r--servers/visual/rasterizer_rd/shaders/scene_forward_inc.glsl7
-rw-r--r--servers/visual_server.cpp1
-rw-r--r--servers/visual_server.h1
11 files changed, 232 insertions, 50 deletions
diff --git a/scene/3d/light.cpp b/scene/3d/light.cpp
index a646783333..8d3b9bbaf0 100644
--- a/scene/3d/light.cpp
+++ b/scene/3d/light.cpp
@@ -281,6 +281,7 @@ void Light::_bind_methods() {
BIND_ENUM_CONSTANT(PARAM_SHADOW_SPLIT_1_OFFSET);
BIND_ENUM_CONSTANT(PARAM_SHADOW_SPLIT_2_OFFSET);
BIND_ENUM_CONSTANT(PARAM_SHADOW_SPLIT_3_OFFSET);
+ BIND_ENUM_CONSTANT(PARAM_SHADOW_FADE_START);
BIND_ENUM_CONSTANT(PARAM_SHADOW_NORMAL_BIAS);
BIND_ENUM_CONSTANT(PARAM_SHADOW_BIAS);
BIND_ENUM_CONSTANT(PARAM_SHADOW_BIAS_SPLIT_SCALE);
@@ -325,8 +326,10 @@ Light::Light(VisualServer::LightType p_type) {
set_param(PARAM_SHADOW_SPLIT_1_OFFSET, 0.1);
set_param(PARAM_SHADOW_SPLIT_2_OFFSET, 0.2);
set_param(PARAM_SHADOW_SPLIT_3_OFFSET, 0.5);
+ set_param(PARAM_SHADOW_FADE_START, 0.8);
set_param(PARAM_SHADOW_NORMAL_BIAS, 0.0);
set_param(PARAM_SHADOW_BIAS, 0.15);
+ set_param(PARAM_SHADOW_FADE_START, 1);
set_disable_scale(true);
}
@@ -393,6 +396,7 @@ void DirectionalLight::_bind_methods() {
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);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "directional_shadow_fade_start", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param", "get_param", PARAM_SHADOW_FADE_START);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "directional_shadow_blend_splits"), "set_blend_splits", "is_blend_splits_enabled");
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "directional_shadow_normal_bias", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_param", "get_param", PARAM_SHADOW_NORMAL_BIAS);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "directional_shadow_bias_split_scale", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param", "get_param", PARAM_SHADOW_BIAS_SPLIT_SCALE);
@@ -413,6 +417,7 @@ DirectionalLight::DirectionalLight() :
set_param(PARAM_SHADOW_NORMAL_BIAS, 0.8);
set_param(PARAM_SHADOW_BIAS, 0.1);
set_param(PARAM_SHADOW_MAX_DISTANCE, 100);
+ set_param(PARAM_SHADOW_FADE_START, 0.8);
set_param(PARAM_SHADOW_BIAS_SPLIT_SCALE, 0.25);
set_shadow_mode(SHADOW_PARALLEL_4_SPLITS);
set_shadow_depth_range(SHADOW_DEPTH_RANGE_STABLE);
diff --git a/scene/3d/light.h b/scene/3d/light.h
index e7bfa3fc63..7287518ae9 100644
--- a/scene/3d/light.h
+++ b/scene/3d/light.h
@@ -54,6 +54,7 @@ public:
PARAM_SHADOW_SPLIT_1_OFFSET = VS::LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET,
PARAM_SHADOW_SPLIT_2_OFFSET = VS::LIGHT_PARAM_SHADOW_SPLIT_2_OFFSET,
PARAM_SHADOW_SPLIT_3_OFFSET = VS::LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET,
+ PARAM_SHADOW_FADE_START = VS::LIGHT_PARAM_SHADOW_FADE_START,
PARAM_SHADOW_NORMAL_BIAS = VS::LIGHT_PARAM_SHADOW_NORMAL_BIAS,
PARAM_SHADOW_BIAS = VS::LIGHT_PARAM_SHADOW_BIAS,
PARAM_SHADOW_BIAS_SPLIT_SCALE = VS::LIGHT_PARAM_SHADOW_BIAS_SPLIT_SCALE,
diff --git a/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.cpp b/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.cpp
index 41e04ad203..11a3d62cab 100644
--- a/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.cpp
+++ b/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.cpp
@@ -1377,6 +1377,66 @@ void RasterizerSceneForwardRD::_setup_lights(RID *p_light_cull_result, int p_lig
if (scene_state.ubo.directional_light_count >= scene_state.max_directional_lights) {
continue;
}
+
+ DirectionalLightData &light_data = scene_state.directional_lights[scene_state.ubo.directional_light_count];
+
+ Transform light_transform = light_instance_get_base_transform(li);
+
+ Vector3 direction = p_camera_inverse_transform.basis.xform(light_transform.basis.xform(Vector3(0, 0, 1))).normalized();
+
+ light_data.direction[0] = direction.x;
+ light_data.direction[1] = direction.y;
+ light_data.direction[2] = direction.z;
+
+ float sign = storage->light_is_negative(base) ? -1 : 1;
+
+ light_data.energy = sign * storage->light_get_param(base, VS::LIGHT_PARAM_ENERGY) * Math_PI;
+
+ Color linear_col = storage->light_get_color(base).to_linear();
+ light_data.color[0] = linear_col.r;
+ light_data.color[1] = linear_col.g;
+ light_data.color[2] = linear_col.b;
+
+ light_data.specular = storage->light_get_param(base, VS::LIGHT_PARAM_SPECULAR);
+ light_data.mask = storage->light_get_cull_mask(base);
+
+ Color shadow_col = storage->light_get_shadow_color(base).to_linear();
+
+ light_data.shadow_color[0] = shadow_col.r;
+ light_data.shadow_color[1] = shadow_col.g;
+ light_data.shadow_color[2] = shadow_col.b;
+
+ light_data.shadow_enabled = storage->light_has_shadow(base);
+
+ if (light_data.shadow_enabled) {
+
+ VS::LightDirectionalShadowMode smode = storage->light_directional_get_shadow_mode(base);
+
+ int limit = smode == VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL ? 0 : (smode == VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS ? 1 : 3);
+ light_data.blend_splits = storage->light_directional_get_blend_splits(base);
+ for (int j = 0; j < 4; j++) {
+ Rect2 atlas_rect = light_instance_get_directional_shadow_atlas_rect(li, j);
+ CameraMatrix matrix = light_instance_get_shadow_camera(li, j);
+ float split = light_instance_get_directional_shadow_split(li, MIN(limit, j));
+
+ CameraMatrix bias;
+ bias.set_light_bias();
+ CameraMatrix rectm;
+ rectm.set_light_atlas_rect(atlas_rect);
+
+ Transform modelview = (p_camera_inverse_transform * light_instance_get_shadow_transform(li, j)).inverse();
+
+ CameraMatrix shadow_mtx = rectm * bias * matrix * modelview;
+ light_data.shadow_split_offsets[j] = split;
+ store_camera(shadow_mtx, light_data.shadow_matrices[j]);
+ }
+
+ float fade_start = storage->light_get_param(base, VS::LIGHT_PARAM_SHADOW_FADE_START);
+ light_data.fade_from = -light_data.shadow_split_offsets[3] * MIN(fade_start, 0.999);
+ light_data.fade_to = -light_data.shadow_split_offsets[3];
+ }
+
+ scene_state.ubo.directional_light_count++;
} break;
case VS::LIGHT_SPOT:
case VS::LIGHT_OMNI: {
@@ -1476,7 +1536,7 @@ void RasterizerSceneForwardRD::_setup_lights(RID *p_light_cull_result, int p_lig
}
if (scene_state.ubo.directional_light_count) {
- RD::get_singleton()->buffer_update(scene_state.directional_light_buffer, 0, sizeof(DirectionalLightData) * light_count, scene_state.directional_lights, true);
+ RD::get_singleton()->buffer_update(scene_state.directional_light_buffer, 0, sizeof(DirectionalLightData) * scene_state.ubo.directional_light_count, scene_state.directional_lights, true);
}
}
@@ -2092,7 +2152,7 @@ void RasterizerSceneForwardRD::_render_scene(RenderBufferData *p_buffer_data, co
storage->render_target_disable_clear_request(render_buffer->render_target);
- if (true) {
+ if (false) {
if (p_shadow_atlas.is_valid()) {
RID shadow_atlas_texture = shadow_atlas_get_texture(p_shadow_atlas);
Size2 rtsize = storage->render_target_get_size(render_buffer->render_target);
@@ -2101,6 +2161,15 @@ void RasterizerSceneForwardRD::_render_scene(RenderBufferData *p_buffer_data, co
}
}
+ if (true) {
+ if (directional_shadow_get_texture().is_valid()) {
+ RID shadow_atlas_texture = directional_shadow_get_texture();
+ Size2 rtsize = storage->render_target_get_size(render_buffer->render_target);
+
+ effects->copy_to_rect(shadow_atlas_texture, storage->render_target_get_rd_framebuffer(render_buffer->render_target), Rect2(Vector2(), rtsize / 2));
+ }
+ }
+
#if 0
_post_process(env, p_cam_projection);
// Needed only for debugging
diff --git a/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.h b/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.h
index f7d0e419ad..3cf83f7035 100644
--- a/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.h
+++ b/servers/visual/rasterizer_rd/rasterizer_scene_forward_rd.h
@@ -235,16 +235,14 @@ class RasterizerSceneForwardRD : public RasterizerSceneRD {
float energy;
float color[3];
float specular;
- uint32_t mask;
- uint32_t pad[3];
float shadow_color[3];
+ uint32_t mask;
+ uint32_t blend_splits;
uint32_t shadow_enabled;
- float shadow_atlas_rect[4];
+ float fade_from;
+ float fade_to;
float shadow_split_offsets[4];
- float shadow_matrix1[16];
- float shadow_matrix2[16];
- float shadow_matrix3[16];
- float shadow_matrix4[16];
+ float shadow_matrices[4][16];
};
struct InstanceData {
diff --git a/servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp b/servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp
index 72000e824a..1c035d5d55 100644
--- a/servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp
+++ b/servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp
@@ -898,6 +898,8 @@ void RasterizerSceneRD::directional_shadow_atlas_set_size(int p_size) {
return;
}
+ directional_shadow.size = p_size;
+
if (directional_shadow.depth.is_valid()) {
RD::get_singleton()->free(directional_shadow.depth);
directional_shadow.depth = RID();
@@ -925,17 +927,34 @@ void RasterizerSceneRD::set_directional_shadow_count(int p_count) {
directional_shadow.current_light = 0;
}
+static Rect2i _get_directional_shadow_rect(int p_size, int p_shadow_count, int p_shadow_index) {
+
+ int split_h = 1;
+ int split_v = 1;
+
+ while (split_h * split_v < p_shadow_count) {
+ if (split_h == split_v) {
+ split_h <<= 1;
+ } else {
+ split_v <<= 1;
+ }
+ }
+
+ Rect2i rect(0, 0, p_size, p_size);
+ rect.size.width /= split_h;
+ rect.size.height /= split_v;
+
+ rect.position.x = rect.size.width * (p_shadow_index % split_h);
+ rect.position.y = rect.size.height * (p_shadow_index / split_h);
+
+ return rect;
+}
+
int RasterizerSceneRD::get_directional_light_shadow_size(RID p_light_intance) {
ERR_FAIL_COND_V(directional_shadow.light_count == 0, 0);
- int shadow_size;
-
- if (directional_shadow.light_count == 1) {
- shadow_size = directional_shadow.size;
- } else {
- shadow_size = directional_shadow.size / 2; //more than 4 not supported anyway
- }
+ Rect2i r = _get_directional_shadow_rect(directional_shadow.size, directional_shadow.light_count, 0);
LightInstance *light_instance = light_instance_owner.getornull(p_light_intance);
ERR_FAIL_COND_V(!light_instance, 0);
@@ -943,11 +962,11 @@ int RasterizerSceneRD::get_directional_light_shadow_size(RID p_light_intance) {
switch (storage->light_directional_get_shadow_mode(light_instance->light)) {
case VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL:
break; //none
- case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS:
- case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS: shadow_size /= 2; break;
+ case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS: r.size.height /= 2; break;
+ case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS: r.size /= 2; break;
}
- return shadow_size;
+ return MAX(r.size.width, r.size.height);
}
//////////////////////////////////////////////////
@@ -1112,27 +1131,9 @@ void RasterizerSceneRD::render_shadow(RID p_light, RID p_shadow_atlas, int p_pas
if (storage->light_get_type(light_instance->light) == VS::LIGHT_DIRECTIONAL) {
//set pssm stuff
if (light_instance->last_scene_shadow_pass != scene_pass) {
- //assign rect if unassigned
- light_instance->light_directional_index = directional_shadow.current_light;
- light_instance->last_scene_shadow_pass = scene_pass;
+ light_instance->directional_rect = _get_directional_shadow_rect(directional_shadow.size, directional_shadow.light_count, directional_shadow.current_light);
directional_shadow.current_light++;
-
- if (directional_shadow.light_count == 1) {
- light_instance->directional_rect = Rect2(0, 0, directional_shadow.size, directional_shadow.size);
- } else if (directional_shadow.light_count == 2) {
- light_instance->directional_rect = Rect2(0, 0, directional_shadow.size, directional_shadow.size / 2);
- if (light_instance->light_directional_index == 1) {
- light_instance->directional_rect.position.x += light_instance->directional_rect.size.x;
- }
- } else { //3 and 4
- light_instance->directional_rect = Rect2(0, 0, directional_shadow.size / 2, directional_shadow.size / 2);
- if (light_instance->light_directional_index & 1) {
- light_instance->directional_rect.position.x += light_instance->directional_rect.size.x;
- }
- if (light_instance->light_directional_index / 2) {
- light_instance->directional_rect.position.y += light_instance->directional_rect.size.y;
- }
- }
+ light_instance->last_scene_shadow_pass = scene_pass;
}
light_projection = light_instance->shadow_transform[p_pass].camera;
@@ -1168,6 +1169,11 @@ void RasterizerSceneRD::render_shadow(RID p_light, RID p_shadow_atlas, int p_pas
}
}
+ light_instance->shadow_transform[p_pass].atlas_rect = atlas_rect;
+
+ light_instance->shadow_transform[p_pass].atlas_rect.position /= directional_shadow.size;
+ light_instance->shadow_transform[p_pass].atlas_rect.size /= directional_shadow.size;
+
float bias_mult = Math::lerp(1.0f, light_instance->shadow_transform[p_pass].bias_scale, storage->light_get_param(light_instance->light, VS::LIGHT_PARAM_SHADOW_BIAS_SPLIT_SCALE));
zfar = storage->light_get_param(light_instance->light, VS::LIGHT_PARAM_RANGE);
bias = storage->light_get_param(light_instance->light, VS::LIGHT_PARAM_SHADOW_BIAS) * bias_mult;
diff --git a/servers/visual/rasterizer_rd/rasterizer_scene_rd.h b/servers/visual/rasterizer_rd/rasterizer_scene_rd.h
index 83316079d1..a6d3d6b4d1 100644
--- a/servers/visual/rasterizer_rd/rasterizer_scene_rd.h
+++ b/servers/visual/rasterizer_rd/rasterizer_scene_rd.h
@@ -180,6 +180,7 @@ private:
float farplane;
float split;
float bias_scale;
+ Rect2 atlas_rect;
};
VS::LightType light_type;
@@ -409,6 +410,24 @@ public:
return li->shadow_transform[p_index].camera;
}
+ _FORCE_INLINE_ Transform light_instance_get_shadow_transform(RID p_light_instance, int p_index) {
+
+ LightInstance *li = light_instance_owner.getornull(p_light_instance);
+ return li->shadow_transform[p_index].transform;
+ }
+
+ _FORCE_INLINE_ Rect2 light_instance_get_directional_shadow_atlas_rect(RID p_light_instance, int p_index) {
+
+ LightInstance *li = light_instance_owner.getornull(p_light_instance);
+ return li->shadow_transform[p_index].atlas_rect;
+ }
+
+ _FORCE_INLINE_ float light_instance_get_directional_shadow_split(RID p_light_instance, int p_index) {
+
+ LightInstance *li = light_instance_owner.getornull(p_light_instance);
+ return li->shadow_transform[p_index].split;
+ }
+
_FORCE_INLINE_ void light_instance_set_render_pass(RID p_light_instance, uint64_t p_pass) {
LightInstance *li = light_instance_owner.getornull(p_light_instance);
li->last_pass = p_pass;
diff --git a/servers/visual/rasterizer_rd/rasterizer_storage_rd.cpp b/servers/visual/rasterizer_rd/rasterizer_storage_rd.cpp
index b5dffc7762..e80f5f54b9 100644
--- a/servers/visual/rasterizer_rd/rasterizer_storage_rd.cpp
+++ b/servers/visual/rasterizer_rd/rasterizer_storage_rd.cpp
@@ -2104,6 +2104,7 @@ RID RasterizerStorageRD::light_create(VS::LightType p_type) {
light.param[VS::LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET] = 0.1;
light.param[VS::LIGHT_PARAM_SHADOW_SPLIT_2_OFFSET] = 0.3;
light.param[VS::LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET] = 0.6;
+ light.param[VS::LIGHT_PARAM_SHADOW_FADE_START] = 0.8;
light.param[VS::LIGHT_PARAM_SHADOW_NORMAL_BIAS] = 0.1;
light.param[VS::LIGHT_PARAM_SHADOW_BIAS_SPLIT_SCALE] = 0.1;
diff --git a/servers/visual/rasterizer_rd/shaders/scene_forward.glsl b/servers/visual/rasterizer_rd/shaders/scene_forward.glsl
index 3479929774..37919566a5 100644
--- a/servers/visual/rasterizer_rd/shaders/scene_forward.glsl
+++ b/servers/visual/rasterizer_rd/shaders/scene_forward.glsl
@@ -584,7 +584,11 @@ LIGHT_SHADER_CODE
#ifndef USE_NO_SHADOWS
-float sample_shadow(texture2D shadow, vec2 shadow_pixel_size, vec2 pos, float depth) {
+float sample_shadow(texture2D shadow, vec2 shadow_pixel_size, vec4 coord) {
+
+ //todo optimize
+ vec2 pos = coord.xy;
+ float depth = coord.z;
#ifdef SHADOW_MODE_PCF_13
@@ -657,7 +661,7 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 a
if (shadow_color_enabled.w > 0.5) {
// there is a shadowmap
- vec3 splane = (lights.data[idx].shadow_matrix * vec4(vertex, 1.0)).xyz;
+ vec4 splane = (lights.data[idx].shadow_matrix * vec4(vertex, 1.0));
float shadow_len = length(splane);
splane = normalize(splane);
vec4 clamp_rect = lights.data[idx].atlas_rect;
@@ -677,9 +681,9 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 a
splane.xy /= splane.z;
splane.xy = splane.xy * 0.5 + 0.5;
splane.z = shadow_len * lights.data[idx].inv_radius;
-
splane.xy = clamp_rect.xy + splane.xy * clamp_rect.zw;
- float shadow = sample_shadow(shadow_atlas, scene_data.shadow_atlas_pixel_size, splane.xy, splane.z);
+ splane.w = 1.0; //needed? i think it should be 1 already
+ float shadow = sample_shadow(shadow_atlas, scene_data.shadow_atlas_pixel_size, splane);
light_attenuation *= mix(shadow_color_enabled.rgb, vec3(1.0), shadow);
}
@@ -750,9 +754,8 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 a
if (shadow_color_enabled.w > 0.5) {
//there is a shadowmap
vec4 splane = (lights.data[idx].shadow_matrix * vec4(vertex, 1.0));
- splane.xyz /= splane.w;
-
- float shadow = sample_shadow(shadow_atlas, scene_data.shadow_atlas_pixel_size, splane.xy, splane.z);
+ splane /= splane.w;
+ float shadow = sample_shadow(shadow_atlas, scene_data.shadow_atlas_pixel_size, splane);
light_attenuation *= mix(shadow_color_enabled.rgb, vec3(1.0), shadow);
}
@@ -1132,7 +1135,84 @@ FRAGMENT_SHADER_CODE
#endif
}
- //directional light
+ { //directional light
+
+ for (uint i = 0; i < scene_data.directional_light_count; i++) {
+
+ if (!bool(directional_lights.data[i].mask&instances.data[instance_index].layer_mask)) {
+ continue; //not masked
+ }
+
+ vec3 light_attenuation = vec3(1.0);
+
+ if (directional_lights.data[i].shadow_enabled) {
+ float depth_z = -vertex.z;
+
+ vec4 pssm_coord;
+
+ if (depth_z < directional_lights.data[i].shadow_split_offsets.x) {
+ pssm_coord = (directional_lights.data[i].shadow_matrix1 * vec4(vertex, 1.0));
+ } else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) {
+ pssm_coord = (directional_lights.data[i].shadow_matrix2 * vec4(vertex, 1.0));
+ } else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) {
+ pssm_coord = (directional_lights.data[i].shadow_matrix3 * vec4(vertex, 1.0));
+ } else {
+ pssm_coord = (directional_lights.data[i].shadow_matrix4 * vec4(vertex, 1.0));
+ }
+
+ pssm_coord/=pssm_coord.w;
+
+ float shadow = sample_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size, pssm_coord);
+
+ if (directional_lights.data[i].blend_splits) {
+
+ float pssm_blend;
+
+ if (depth_z < directional_lights.data[i].shadow_split_offsets.x) {
+ pssm_coord = (directional_lights.data[i].shadow_matrix2 * vec4(vertex, 1.0));
+ pssm_blend = smoothstep(0.0, directional_lights.data[i].shadow_split_offsets.x, depth_z);
+ } else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) {
+ pssm_coord = (directional_lights.data[i].shadow_matrix3 * vec4(vertex, 1.0));
+ pssm_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.x, directional_lights.data[i].shadow_split_offsets.y, depth_z);
+ } else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) {
+ pssm_coord = (directional_lights.data[i].shadow_matrix4 * vec4(vertex, 1.0));
+ pssm_blend = smoothstep(directional_lights.data[i].shadow_split_offsets.y, directional_lights.data[i].shadow_split_offsets.z, depth_z);
+ } else {
+ pssm_blend = 0.0; //if no blend, same coord will be used (divide by z will result in same value, and already cached)
+ }
+
+ pssm_coord/=pssm_coord.w;
+
+ float shadow2 = sample_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size, pssm_coord);
+ shadow = mix(shadow,shadow2,pssm_blend);
+
+ }
+
+ shadow = mix(shadow,1.0,smoothstep(directional_lights.data[i].fade_from,directional_lights.data[i].fade_to,vertex.z)); //done with negative values for performance
+
+ light_attenuation = vec3(shadow); //mix(directional_lights.data[i].shadow_color, vec3(1.0), shadow);
+ }
+
+
+ light_compute(normal, directional_lights.data[i].direction, normalize(view), directional_lights.data[i].color * directional_lights.data[i].energy, light_attenuation, albedo, roughness, metallic, specular,directional_lights.data[i].specular * specular_blob_intensity,
+#ifdef LIGHT_TRANSMISSION_USED
+ transmission,
+#endif
+#ifdef LIGHT_RIM_USED
+ rim * omni_attenuation, rim_tint,
+#endif
+#ifdef LIGHT_CLEARCOAT_USED
+ clearcoat, clearcoat_gloss,
+#endif
+#ifdef LIGHT_ANISOTROPY_USED
+ binormal, tangent, anisotropy,
+#endif
+#ifdef USE_SHADOW_TO_OPACITY
+ alpha
+#endif
+ diffuse_light, specular_light);
+ }
+ }
{ //omni lights
uint omni_light_count = (instances.data[instance_index].flags >> INSTANCE_FLAGS_FORWARD_OMNI_LIGHT_SHIFT) & INSTANCE_FLAGS_FORWARD_MASK;
diff --git a/servers/visual/rasterizer_rd/shaders/scene_forward_inc.glsl b/servers/visual/rasterizer_rd/shaders/scene_forward_inc.glsl
index 8951f89c13..3e6249e4cb 100644
--- a/servers/visual/rasterizer_rd/shaders/scene_forward_inc.glsl
+++ b/servers/visual/rasterizer_rd/shaders/scene_forward_inc.glsl
@@ -184,11 +184,12 @@ struct DirectionalLightData {
float energy;
vec3 color;
float specular;
- uint mask;
- uint pad0,pad1,pad2;
vec3 shadow_color;
+ uint mask;
+ bool blend_splits;
bool shadow_enabled;
- vec4 shadow_atlas_rect;
+ float fade_from;
+ float fade_to;
vec4 shadow_split_offsets;
mat4 shadow_matrix1;
mat4 shadow_matrix2;
diff --git a/servers/visual_server.cpp b/servers/visual_server.cpp
index 4b3ac207f1..af29f14b77 100644
--- a/servers/visual_server.cpp
+++ b/servers/visual_server.cpp
@@ -2047,6 +2047,7 @@ void VisualServer::_bind_methods() {
BIND_ENUM_CONSTANT(LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET);
BIND_ENUM_CONSTANT(LIGHT_PARAM_SHADOW_SPLIT_2_OFFSET);
BIND_ENUM_CONSTANT(LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET);
+ BIND_ENUM_CONSTANT(LIGHT_PARAM_SHADOW_FADE_START);
BIND_ENUM_CONSTANT(LIGHT_PARAM_SHADOW_NORMAL_BIAS);
BIND_ENUM_CONSTANT(LIGHT_PARAM_SHADOW_BIAS);
BIND_ENUM_CONSTANT(LIGHT_PARAM_SHADOW_BIAS_SPLIT_SCALE);
diff --git a/servers/visual_server.h b/servers/visual_server.h
index 7aae7acf32..2ab521c7c0 100644
--- a/servers/visual_server.h
+++ b/servers/visual_server.h
@@ -404,6 +404,7 @@ public:
LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET,
LIGHT_PARAM_SHADOW_SPLIT_2_OFFSET,
LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET,
+ LIGHT_PARAM_SHADOW_FADE_START,
LIGHT_PARAM_SHADOW_NORMAL_BIAS,
LIGHT_PARAM_SHADOW_BIAS,
LIGHT_PARAM_SHADOW_BIAS_SPLIT_SCALE,