diff options
author | Juan Linietsky <reduzio@gmail.com> | 2017-09-07 18:00:47 -0300 |
---|---|---|
committer | Juan Linietsky <reduzio@gmail.com> | 2017-09-07 18:00:47 -0300 |
commit | eedb39091aaa1dc0b8f204844bb1eb270b2349f6 (patch) | |
tree | ed08e5e7baf7d21403da34d531223404688513aa /servers | |
parent | 1eeda0f32f66b48c8df3b93f333bf702b149ba31 (diff) |
Several fixes to directional shadows, closes #10926
Added option to change directional light range mode, between optimized and stable. For Orthogonal, you might need to use optimized.
Diffstat (limited to 'servers')
-rw-r--r-- | servers/visual/rasterizer.h | 3 | ||||
-rw-r--r-- | servers/visual/visual_server_raster.h | 1 | ||||
-rw-r--r-- | servers/visual/visual_server_scene.cpp | 74 | ||||
-rw-r--r-- | servers/visual/visual_server_wrap_mt.h | 1 | ||||
-rw-r--r-- | servers/visual_server.h | 8 |
5 files changed, 75 insertions, 12 deletions
diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h index 187a0b180b..0784fb1049 100644 --- a/servers/visual/rasterizer.h +++ b/servers/visual/rasterizer.h @@ -335,6 +335,9 @@ public: virtual void light_directional_set_shadow_mode(RID p_light, VS::LightDirectionalShadowMode p_mode) = 0; virtual void light_directional_set_blend_splits(RID p_light, bool p_enable) = 0; virtual bool light_directional_get_blend_splits(RID p_light) const = 0; + virtual void light_directional_set_shadow_depth_range_mode(RID p_light, VS::LightDirectionalShadowDepthRangeMode p_range_mode) = 0; + virtual VS::LightDirectionalShadowDepthRangeMode light_directional_get_shadow_depth_range_mode(RID p_light) const = 0; + virtual VS::LightDirectionalShadowMode light_directional_get_shadow_mode(RID p_light) = 0; virtual VS::LightOmniShadowMode light_omni_get_shadow_mode(RID p_light) = 0; diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index 3953bc5f48..7c7ce46268 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -795,6 +795,7 @@ public: BIND2(light_directional_set_shadow_mode, RID, LightDirectionalShadowMode) BIND2(light_directional_set_blend_splits, RID, bool) + BIND2(light_directional_set_shadow_depth_range_mode, RID, LightDirectionalShadowDepthRangeMode) /* PROBE API */ diff --git a/servers/visual/visual_server_scene.cpp b/servers/visual/visual_server_scene.cpp index 0d70b7fc0e..e791f7b443 100644 --- a/servers/visual/visual_server_scene.cpp +++ b/servers/visual/visual_server_scene.cpp @@ -886,12 +886,55 @@ void VisualServerScene::_light_instance_update_shadow(Instance *p_instance, cons float max_distance = p_cam_projection.get_z_far(); float shadow_max = VSG::storage->light_get_param(p_instance->base, VS::LIGHT_PARAM_SHADOW_MAX_DISTANCE); - if (shadow_max > 0) { + if (shadow_max > 0 && !p_cam_orthogonal) { //its impractical (and leads to unwanted behaviors) to set max distance in orthogonal camera max_distance = MIN(shadow_max, max_distance); } max_distance = MAX(max_distance, p_cam_projection.get_z_near() + 0.001); + float min_distance = MIN(p_cam_projection.get_z_near(),max_distance); - float range = max_distance - p_cam_projection.get_z_near(); + VS::LightDirectionalShadowDepthRangeMode depth_range_mode = VSG::storage->light_directional_get_shadow_depth_range_mode(p_instance->base); + + if (depth_range_mode==VS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_OPTIMIZED) { + //optimize min/max + Vector<Plane> planes = p_cam_projection.get_projection_planes(p_cam_transform); + int cull_count = p_scenario->octree.cull_convex(planes, instance_shadow_cull_result, MAX_INSTANCE_CULL, VS::INSTANCE_GEOMETRY_MASK); + Plane base(p_cam_transform.origin,-p_cam_transform.basis.get_axis(2)); + //check distance max and min + + bool found_items=false; + float z_max=-1e20; + float z_min=1e20; + + for(int i=0;i<cull_count;i++) { + + Instance *instance = instance_shadow_cull_result[i]; + if (!instance->visible || !((1 << instance->base_type) & VS::INSTANCE_GEOMETRY_MASK) || !static_cast<InstanceGeometryData *>(instance->base_data)->can_cast_shadows) { + continue; + } + + float max,min; + instance->transformed_aabb.project_range_in_plane(base, min, max); + + if (max>z_max) { + z_max=max; + } + + if (min<z_min) { + z_min=min; + } + + found_items=true; + } + + if (found_items) { + min_distance=MAX(min_distance,z_min); + max_distance=MIN(max_distance,z_max); + } + + } + + + float range = max_distance - min_distance; int splits = 0; switch (VSG::storage->light_directional_get_shadow_mode(p_instance->base)) { @@ -902,9 +945,9 @@ void VisualServerScene::_light_instance_update_shadow(Instance *p_instance, cons float distances[5]; - distances[0] = p_cam_projection.get_z_near(); + distances[0] = min_distance; for (int i = 0; i < splits; i++) { - distances[i + 1] = p_cam_projection.get_z_near() + VSG::storage->light_get_param(p_instance->base, VS::LightParam(VS::LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET + i)) * range; + distances[i + 1] = min_distance + VSG::storage->light_get_param(p_instance->base, VS::LightParam(VS::LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET + i)) * range; }; distances[splits] = max_distance; @@ -984,8 +1027,6 @@ void VisualServerScene::_light_instance_update_shadow(Instance *p_instance, cons { //camera viewport stuff - //this trick here is what stabilizes the shadow (make potential jaggies to not move) - //at the cost of some wasted resolution. Still the quality increase is very well worth it Vector3 center; @@ -1006,7 +1047,7 @@ void VisualServerScene::_light_instance_update_shadow(Instance *p_instance, cons radius = d; } - radius *= texture_size / (texture_size - 2.0); //add a texel by each side, so stepified texture will always fit + radius *= texture_size / (texture_size - 2.0); //add a texel by each side if (i == 0) { first_radius = radius; @@ -1021,12 +1062,19 @@ void VisualServerScene::_light_instance_update_shadow(Instance *p_instance, cons z_max_cam = z_vec.dot(center) + radius; z_min_cam = z_vec.dot(center) - radius; - float unit = radius * 2.0 / texture_size; + if (depth_range_mode==VS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE) { + //this trick here is what stabilizes the shadow (make potential jaggies to not move) + //at the cost of some wasted resolution. Still the quality increase is very well worth it + + float unit = radius * 2.0 / texture_size; + + x_max_cam = Math::stepify(x_max_cam, unit); + x_min_cam = Math::stepify(x_min_cam, unit); + y_max_cam = Math::stepify(y_max_cam, unit); + y_min_cam = Math::stepify(y_min_cam, unit); + } + - x_max_cam = Math::stepify(x_max_cam, unit); - x_min_cam = Math::stepify(x_min_cam, unit); - y_max_cam = Math::stepify(y_max_cam, unit); - y_min_cam = Math::stepify(y_min_cam, unit); } //now that we now all ranges, we can proceed to make the light frustum planes, for culling octree @@ -1069,6 +1117,8 @@ void VisualServerScene::_light_instance_update_shadow(Instance *p_instance, cons } { + + CameraMatrix ortho_camera; real_t half_x = (x_max_cam - x_min_cam) * 0.5; real_t half_y = (y_max_cam - y_min_cam) * 0.5; diff --git a/servers/visual/visual_server_wrap_mt.h b/servers/visual/visual_server_wrap_mt.h index f24049be92..5cf941b93d 100644 --- a/servers/visual/visual_server_wrap_mt.h +++ b/servers/visual/visual_server_wrap_mt.h @@ -233,6 +233,7 @@ public: FUNC2(light_directional_set_shadow_mode, RID, LightDirectionalShadowMode) FUNC2(light_directional_set_blend_splits, RID, bool) + FUNC2(light_directional_set_shadow_depth_range_mode, RID, LightDirectionalShadowDepthRangeMode) /* PROBE API */ diff --git a/servers/visual_server.h b/servers/visual_server.h index d516013ee2..9b88df5c73 100644 --- a/servers/visual_server.h +++ b/servers/visual_server.h @@ -406,6 +406,14 @@ public: virtual void light_directional_set_shadow_mode(RID p_light, LightDirectionalShadowMode p_mode) = 0; virtual void light_directional_set_blend_splits(RID p_light, bool p_enable) = 0; + enum LightDirectionalShadowDepthRangeMode { + LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE, + LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_OPTIMIZED, + + }; + + virtual void light_directional_set_shadow_depth_range_mode(RID p_light, LightDirectionalShadowDepthRangeMode p_range_mode) = 0; + /* PROBE API */ virtual RID reflection_probe_create() = 0; |