From 88a7debbbc2cd035932facc04b7740fc204bcca6 Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Sat, 7 Sep 2019 14:38:17 -0300 Subject: [PATCH] Directional lights and shadow mapping are functional. --- scene/3d/light.cpp | 5 + scene/3d/light.h | 1 + .../rasterizer_scene_forward_rd.cpp | 73 +++++++++++++- .../rasterizer_scene_forward_rd.h | 12 +-- .../rasterizer_rd/rasterizer_scene_rd.cpp | 66 +++++++------ .../rasterizer_rd/rasterizer_scene_rd.h | 19 ++++ .../rasterizer_rd/rasterizer_storage_rd.cpp | 1 + .../rasterizer_rd/shaders/scene_forward.glsl | 96 +++++++++++++++++-- .../shaders/scene_forward_inc.glsl | 7 +- servers/visual_server.cpp | 1 + servers/visual_server.h | 1 + 11 files changed, 232 insertions(+), 50 deletions(-) diff --git a/scene/3d/light.cpp b/scene/3d/light.cpp index a6467833333..8d3b9bbaf0c 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 e7bfa3fc634..7287518ae97 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 41e04ad2030..11a3d62cab6 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 f7d0e419ad4..3cf83f70352 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 72000e824a5..1c035d5d556 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 83316079d1b..a6d3d6b4d1e 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 b5dffc7762b..e80f5f54b90 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 3479929774e..37919566a54 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 8951f89c13b..3e6249e4cb9 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 4b3ac207f18..af29f14b770 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 7aae7acf322..2ab521c7c0d 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,