浏览代码

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.

Juan Linietsky 8 年之前
父节点
当前提交
eedb39091a

+ 22 - 64
core/math/camera_matrix.cpp

@@ -265,76 +265,28 @@ void CameraMatrix::get_viewport_size(real_t &r_width, real_t &r_height) const {
 
 
 bool CameraMatrix::get_endpoints(const Transform &p_transform, Vector3 *p_8points) const {
 bool CameraMatrix::get_endpoints(const Transform &p_transform, Vector3 *p_8points) const {
 
 
-	const real_t *matrix = (const real_t *)this->matrix;
-
-	///////--- Near Plane ---///////
-	Plane near_plane = Plane(matrix[3] + matrix[2],
-			matrix[7] + matrix[6],
-			matrix[11] + matrix[10],
-			-matrix[15] - matrix[14]);
-	near_plane.normalize();
-
-	///////--- Far Plane ---///////
-	Plane far_plane = Plane(matrix[2] - matrix[3],
-			matrix[6] - matrix[7],
-			matrix[10] - matrix[11],
-			matrix[15] - matrix[14]);
-	far_plane.normalize();
-
-	///////--- Right Plane ---///////
-	Plane right_plane = Plane(matrix[0] - matrix[3],
-			matrix[4] - matrix[7],
-			matrix[8] - matrix[11],
-			-matrix[15] + matrix[12]);
-	right_plane.normalize();
-
-	///////--- Top Plane ---///////
-	Plane top_plane = Plane(matrix[1] - matrix[3],
-			matrix[5] - matrix[7],
-			matrix[9] - matrix[11],
-			-matrix[15] + matrix[13]);
-	top_plane.normalize();
-
-	Vector3 near_endpoint_left, near_endpoint_right;
-	Vector3 far_endpoint_left, far_endpoint_right;
-
-	bool res = near_plane.intersect_3(right_plane, top_plane, &near_endpoint_right);
-	ERR_FAIL_COND_V(!res, false);
-
-	res = far_plane.intersect_3(right_plane, top_plane, &far_endpoint_right);
-	ERR_FAIL_COND_V(!res, false);
-
-	if ((matrix[8] == 0) && (matrix[9] == 0)) {
-		near_endpoint_left = near_endpoint_right;
-		near_endpoint_left.x = -near_endpoint_left.x;
-
-		far_endpoint_left = far_endpoint_right;
-		far_endpoint_left.x = -far_endpoint_left.x;
-	} else {
-		///////--- Left Plane ---///////
-		Plane left_plane = Plane(matrix[0] + matrix[3],
-				matrix[4] + matrix[7],
-				matrix[8] + matrix[11],
-				-matrix[15] - matrix[12]);
-		left_plane.normalize();
+	Vector<Plane> planes = get_projection_planes(Transform());
+	const Planes intersections[8][3]={
+		{PLANE_FAR,PLANE_LEFT,PLANE_TOP},
+		{PLANE_FAR,PLANE_LEFT,PLANE_BOTTOM},
+		{PLANE_FAR,PLANE_RIGHT,PLANE_TOP},
+		{PLANE_FAR,PLANE_RIGHT,PLANE_BOTTOM},
+		{PLANE_NEAR,PLANE_LEFT,PLANE_TOP},
+		{PLANE_NEAR,PLANE_LEFT,PLANE_BOTTOM},
+		{PLANE_NEAR,PLANE_RIGHT,PLANE_TOP},
+		{PLANE_NEAR,PLANE_RIGHT,PLANE_BOTTOM},
+	};
 
 
-		res = near_plane.intersect_3(left_plane, top_plane, &near_endpoint_left);
-		ERR_FAIL_COND_V(!res, false);
+	for(int i=0;i<8;i++) {
 
 
-		res = far_plane.intersect_3(left_plane, top_plane, &far_endpoint_left);
+		Vector3 point;
+		bool res = planes[intersections[i][0]].intersect_3(planes[intersections[i][1]],planes[intersections[i][2]], &point);
 		ERR_FAIL_COND_V(!res, false);
 		ERR_FAIL_COND_V(!res, false);
+		p_8points[i]=p_transform.xform(point);
 	}
 	}
 
 
-	p_8points[0] = p_transform.xform(Vector3(near_endpoint_right.x, near_endpoint_right.y, near_endpoint_right.z));
-	p_8points[1] = p_transform.xform(Vector3(near_endpoint_right.x, -near_endpoint_right.y, near_endpoint_right.z));
-	p_8points[2] = p_transform.xform(Vector3(near_endpoint_left.x, near_endpoint_left.y, near_endpoint_left.z));
-	p_8points[3] = p_transform.xform(Vector3(near_endpoint_left.x, -near_endpoint_left.y, near_endpoint_left.z));
-	p_8points[4] = p_transform.xform(Vector3(far_endpoint_right.x, far_endpoint_right.y, far_endpoint_right.z));
-	p_8points[5] = p_transform.xform(Vector3(far_endpoint_right.x, -far_endpoint_right.y, far_endpoint_right.z));
-	p_8points[6] = p_transform.xform(Vector3(far_endpoint_left.x, far_endpoint_left.y, far_endpoint_left.z));
-	p_8points[7] = p_transform.xform(Vector3(far_endpoint_left.x, -far_endpoint_left.y, far_endpoint_left.z));
-
 	return true;
 	return true;
+
 }
 }
 
 
 Vector<Plane> CameraMatrix::get_projection_planes(const Transform &p_transform) const {
 Vector<Plane> CameraMatrix::get_projection_planes(const Transform &p_transform) const {
@@ -610,6 +562,12 @@ int CameraMatrix::get_pixels_per_meter(int p_for_pixel_width) const {
 	return int((result.x * 0.5 + 0.5) * p_for_pixel_width);
 	return int((result.x * 0.5 + 0.5) * p_for_pixel_width);
 }
 }
 
 
+bool CameraMatrix::is_orthogonal() const {
+
+	return matrix[3][3]==1.0;
+}
+
+
 real_t CameraMatrix::get_fov() const {
 real_t CameraMatrix::get_fov() const {
 	const real_t *matrix = (const real_t *)this->matrix;
 	const real_t *matrix = (const real_t *)this->matrix;
 
 

+ 2 - 0
core/math/camera_matrix.h

@@ -69,6 +69,7 @@ struct CameraMatrix {
 	real_t get_z_near() const;
 	real_t get_z_near() const;
 	real_t get_aspect() const;
 	real_t get_aspect() const;
 	real_t get_fov() const;
 	real_t get_fov() const;
+	bool is_orthogonal() const;
 
 
 	Vector<Plane> get_projection_planes(const Transform &p_transform) const;
 	Vector<Plane> get_projection_planes(const Transform &p_transform) const;
 
 
@@ -83,6 +84,7 @@ struct CameraMatrix {
 	Plane xform4(const Plane &p_vec4) const;
 	Plane xform4(const Plane &p_vec4) const;
 	_FORCE_INLINE_ Vector3 xform(const Vector3 &p_vec3) const;
 	_FORCE_INLINE_ Vector3 xform(const Vector3 &p_vec3) const;
 
 
+
 	operator String() const;
 	operator String() const;
 
 
 	void scale_translate_to_fit(const Rect3 &p_aabb);
 	void scale_translate_to_fit(const Rect3 &p_aabb);

+ 2 - 2
drivers/gles3/rasterizer_scene_gles3.cpp

@@ -2599,7 +2599,7 @@ void RasterizerSceneGLES3::_setup_directional_light(int p_index, const Transform
 				}
 				}
 			}
 			}
 
 
-			ubo_data.shadow_split_offsets[j] = 1.0 / li->shadow_transform[j].split;
+			ubo_data.shadow_split_offsets[j] = li->shadow_transform[j].split;
 
 
 			Transform modelview = (p_camera_inverse_transform * li->shadow_transform[j].transform).inverse();
 			Transform modelview = (p_camera_inverse_transform * li->shadow_transform[j].transform).inverse();
 
 
@@ -4331,7 +4331,7 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const
 		storage->canvas->draw_generic_textured_rect(Rect2(0, 0, storage->frame.current_rt->width / 2, storage->frame.current_rt->height / 2), Rect2(0, 0, 1, 1));
 		storage->canvas->draw_generic_textured_rect(Rect2(0, 0, storage->frame.current_rt->width / 2, storage->frame.current_rt->height / 2), Rect2(0, 0, 1, 1));
 	}
 	}
 
 
-	if (false && directional_shadow.fbo) {
+	if (true && directional_shadow.fbo) {
 
 
 		//_copy_texture_to_front_buffer(shadow_atlas->depth);
 		//_copy_texture_to_front_buffer(shadow_atlas->depth);
 		storage->canvas->canvas_begin();
 		storage->canvas->canvas_begin();

+ 17 - 0
drivers/gles3/rasterizer_storage_gles3.cpp

@@ -4473,6 +4473,7 @@ RID RasterizerStorageGLES3::light_create(VS::LightType p_type) {
 	light->omni_shadow_mode = VS::LIGHT_OMNI_SHADOW_DUAL_PARABOLOID;
 	light->omni_shadow_mode = VS::LIGHT_OMNI_SHADOW_DUAL_PARABOLOID;
 	light->omni_shadow_detail = VS::LIGHT_OMNI_SHADOW_DETAIL_VERTICAL;
 	light->omni_shadow_detail = VS::LIGHT_OMNI_SHADOW_DETAIL_VERTICAL;
 	light->directional_blend_splits = false;
 	light->directional_blend_splits = false;
+	light->directional_range_mode = VS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE;
 	light->reverse_cull = false;
 	light->reverse_cull = false;
 	light->version = 0;
 	light->version = 0;
 
 
@@ -4625,6 +4626,22 @@ VS::LightDirectionalShadowMode RasterizerStorageGLES3::light_directional_get_sha
 	return light->directional_shadow_mode;
 	return light->directional_shadow_mode;
 }
 }
 
 
+void RasterizerStorageGLES3::light_directional_set_shadow_depth_range_mode(RID p_light, VS::LightDirectionalShadowDepthRangeMode p_range_mode) {
+
+	Light *light = light_owner.getornull(p_light);
+	ERR_FAIL_COND(!light);
+
+	light->directional_range_mode=p_range_mode;
+}
+
+VS::LightDirectionalShadowDepthRangeMode RasterizerStorageGLES3::light_directional_get_shadow_depth_range_mode(RID p_light) const {
+
+	const Light *light = light_owner.getornull(p_light);
+	ERR_FAIL_COND_V(!light, VS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE);
+
+	return light->directional_range_mode;
+}
+
 VS::LightType RasterizerStorageGLES3::light_get_type(RID p_light) const {
 VS::LightType RasterizerStorageGLES3::light_get_type(RID p_light) const {
 
 
 	const Light *light = light_owner.getornull(p_light);
 	const Light *light = light_owner.getornull(p_light);

+ 4 - 0
drivers/gles3/rasterizer_storage_gles3.h

@@ -879,6 +879,7 @@ public:
 		VS::LightOmniShadowMode omni_shadow_mode;
 		VS::LightOmniShadowMode omni_shadow_mode;
 		VS::LightOmniShadowDetail omni_shadow_detail;
 		VS::LightOmniShadowDetail omni_shadow_detail;
 		VS::LightDirectionalShadowMode directional_shadow_mode;
 		VS::LightDirectionalShadowMode directional_shadow_mode;
+		VS::LightDirectionalShadowDepthRangeMode directional_range_mode;
 		bool directional_blend_splits;
 		bool directional_blend_splits;
 		uint64_t version;
 		uint64_t version;
 	};
 	};
@@ -906,6 +907,9 @@ public:
 	virtual VS::LightDirectionalShadowMode light_directional_get_shadow_mode(RID p_light);
 	virtual VS::LightDirectionalShadowMode light_directional_get_shadow_mode(RID p_light);
 	virtual VS::LightOmniShadowMode light_omni_get_shadow_mode(RID p_light);
 	virtual VS::LightOmniShadowMode light_omni_get_shadow_mode(RID p_light);
 
 
+	virtual void light_directional_set_shadow_depth_range_mode(RID p_light, VS::LightDirectionalShadowDepthRangeMode p_range_mode);
+	virtual VS::LightDirectionalShadowDepthRangeMode light_directional_get_shadow_depth_range_mode(RID p_light) const;
+
 	virtual bool light_has_shadow(RID p_light) const;
 	virtual bool light_has_shadow(RID p_light) const;
 
 
 	virtual VS::LightType light_get_type(RID p_light) const;
 	virtual VS::LightType light_get_type(RID p_light) const;

文件差异内容过多而无法显示
+ 411 - 411
drivers/gles3/shaders/scene.glsl


+ 22 - 1
scene/3d/light.cpp

@@ -230,7 +230,6 @@ void Light::_bind_methods() {
 	ADD_PROPERTY(PropertyInfo(Variant::COLOR, "shadow_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_shadow_color", "get_shadow_color");
 	ADD_PROPERTY(PropertyInfo(Variant::COLOR, "shadow_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_shadow_color", "get_shadow_color");
 	ADD_PROPERTYI(PropertyInfo(Variant::REAL, "shadow_bias", PROPERTY_HINT_RANGE, "-16,16,0.01"), "set_param", "get_param", PARAM_SHADOW_BIAS);
 	ADD_PROPERTYI(PropertyInfo(Variant::REAL, "shadow_bias", PROPERTY_HINT_RANGE, "-16,16,0.01"), "set_param", "get_param", PARAM_SHADOW_BIAS);
 	ADD_PROPERTYI(PropertyInfo(Variant::REAL, "shadow_contact", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_param", "get_param", PARAM_CONTACT_SHADOW_SIZE);
 	ADD_PROPERTYI(PropertyInfo(Variant::REAL, "shadow_contact", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_param", "get_param", PARAM_CONTACT_SHADOW_SIZE);
-	ADD_PROPERTYI(PropertyInfo(Variant::REAL, "shadow_max_distance", PROPERTY_HINT_RANGE, "0,65536,0.1"), "set_param", "get_param", PARAM_SHADOW_MAX_DISTANCE);
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shadow_reverse_cull_face"), "set_shadow_reverse_cull_face", "get_shadow_reverse_cull_face");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shadow_reverse_cull_face"), "set_shadow_reverse_cull_face", "get_shadow_reverse_cull_face");
 	ADD_GROUP("Editor", "");
 	ADD_GROUP("Editor", "");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "editor_only"), "set_editor_only", "is_editor_only");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "editor_only"), "set_editor_only", "is_editor_only");
@@ -308,6 +307,18 @@ DirectionalLight::ShadowMode DirectionalLight::get_shadow_mode() const {
 	return shadow_mode;
 	return shadow_mode;
 }
 }
 
 
+void DirectionalLight::set_shadow_depth_range(ShadowDepthRange p_range) {
+	shadow_depth_range=p_range;
+	VS::get_singleton()->light_directional_set_shadow_depth_range_mode(light, VS::LightDirectionalShadowDepthRangeMode(p_range));
+
+}
+
+DirectionalLight::ShadowDepthRange DirectionalLight::get_shadow_depth_range() const {
+
+	return shadow_depth_range;
+}
+
+
 void DirectionalLight::set_blend_splits(bool p_enable) {
 void DirectionalLight::set_blend_splits(bool p_enable) {
 
 
 	blend_splits = p_enable;
 	blend_splits = p_enable;
@@ -324,6 +335,9 @@ void DirectionalLight::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_shadow_mode", "mode"), &DirectionalLight::set_shadow_mode);
 	ClassDB::bind_method(D_METHOD("set_shadow_mode", "mode"), &DirectionalLight::set_shadow_mode);
 	ClassDB::bind_method(D_METHOD("get_shadow_mode"), &DirectionalLight::get_shadow_mode);
 	ClassDB::bind_method(D_METHOD("get_shadow_mode"), &DirectionalLight::get_shadow_mode);
 
 
+	ClassDB::bind_method(D_METHOD("set_shadow_depth_range", "mode"), &DirectionalLight::set_shadow_depth_range);
+	ClassDB::bind_method(D_METHOD("get_shadow_depth_range"), &DirectionalLight::get_shadow_depth_range);
+
 	ClassDB::bind_method(D_METHOD("set_blend_splits", "enabled"), &DirectionalLight::set_blend_splits);
 	ClassDB::bind_method(D_METHOD("set_blend_splits", "enabled"), &DirectionalLight::set_blend_splits);
 	ClassDB::bind_method(D_METHOD("is_blend_splits_enabled"), &DirectionalLight::is_blend_splits_enabled);
 	ClassDB::bind_method(D_METHOD("is_blend_splits_enabled"), &DirectionalLight::is_blend_splits_enabled);
 
 
@@ -335,10 +349,15 @@ void DirectionalLight::_bind_methods() {
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "directional_shadow_blend_splits"), "set_blend_splits", "is_blend_splits_enabled");
 	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_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);
 	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);
+	ADD_PROPERTY(PropertyInfo(Variant::INT, "directional_shadow_depth_range", PROPERTY_HINT_ENUM, "Stable,Optimized"), "set_shadow_depth_range", "get_shadow_depth_range");
+	ADD_PROPERTYI(PropertyInfo(Variant::REAL, "directional_shadow_max_distance", PROPERTY_HINT_RANGE, "0,65536,0.1"), "set_param", "get_param", PARAM_SHADOW_MAX_DISTANCE);
 
 
 	BIND_ENUM_CONSTANT(SHADOW_ORTHOGONAL);
 	BIND_ENUM_CONSTANT(SHADOW_ORTHOGONAL);
 	BIND_ENUM_CONSTANT(SHADOW_PARALLEL_2_SPLITS);
 	BIND_ENUM_CONSTANT(SHADOW_PARALLEL_2_SPLITS);
 	BIND_ENUM_CONSTANT(SHADOW_PARALLEL_4_SPLITS);
 	BIND_ENUM_CONSTANT(SHADOW_PARALLEL_4_SPLITS);
+
+	BIND_ENUM_CONSTANT( SHADOW_DEPTH_RANGE_STABLE );
+	BIND_ENUM_CONSTANT( SHADOW_DEPTH_RANGE_OPTIMIZED );
 }
 }
 
 
 DirectionalLight::DirectionalLight()
 DirectionalLight::DirectionalLight()
@@ -349,6 +368,8 @@ DirectionalLight::DirectionalLight()
 	set_param(PARAM_SHADOW_MAX_DISTANCE, 200);
 	set_param(PARAM_SHADOW_MAX_DISTANCE, 200);
 	set_param(PARAM_SHADOW_BIAS_SPLIT_SCALE, 0.25);
 	set_param(PARAM_SHADOW_BIAS_SPLIT_SCALE, 0.25);
 	set_shadow_mode(SHADOW_PARALLEL_4_SPLITS);
 	set_shadow_mode(SHADOW_PARALLEL_4_SPLITS);
+	set_shadow_depth_range(SHADOW_DEPTH_RANGE_STABLE);
+
 
 
 	blend_splits = false;
 	blend_splits = false;
 }
 }

+ 10 - 0
scene/3d/light.h

@@ -133,9 +133,15 @@ public:
 		SHADOW_PARALLEL_4_SPLITS
 		SHADOW_PARALLEL_4_SPLITS
 	};
 	};
 
 
+	enum ShadowDepthRange {
+		SHADOW_DEPTH_RANGE_STABLE = VS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE,
+		SHADOW_DEPTH_RANGE_OPTIMIZED = VS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_OPTIMIZED,
+	};
+
 private:
 private:
 	bool blend_splits;
 	bool blend_splits;
 	ShadowMode shadow_mode;
 	ShadowMode shadow_mode;
+	ShadowDepthRange shadow_depth_range;
 
 
 protected:
 protected:
 	static void _bind_methods();
 	static void _bind_methods();
@@ -144,6 +150,9 @@ public:
 	void set_shadow_mode(ShadowMode p_mode);
 	void set_shadow_mode(ShadowMode p_mode);
 	ShadowMode get_shadow_mode() const;
 	ShadowMode get_shadow_mode() const;
 
 
+	void set_shadow_depth_range(ShadowDepthRange p_mode);
+	ShadowDepthRange get_shadow_depth_range() const;
+
 	void set_blend_splits(bool p_enable);
 	void set_blend_splits(bool p_enable);
 	bool is_blend_splits_enabled() const;
 	bool is_blend_splits_enabled() const;
 
 
@@ -151,6 +160,7 @@ public:
 };
 };
 
 
 VARIANT_ENUM_CAST(DirectionalLight::ShadowMode)
 VARIANT_ENUM_CAST(DirectionalLight::ShadowMode)
+VARIANT_ENUM_CAST(DirectionalLight::ShadowDepthRange)
 
 
 class OmniLight : public Light {
 class OmniLight : public Light {
 
 

+ 3 - 0
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_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 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 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::LightDirectionalShadowMode light_directional_get_shadow_mode(RID p_light) = 0;
 	virtual VS::LightOmniShadowMode light_omni_get_shadow_mode(RID p_light) = 0;
 	virtual VS::LightOmniShadowMode light_omni_get_shadow_mode(RID p_light) = 0;

+ 1 - 0
servers/visual/visual_server_raster.h

@@ -795,6 +795,7 @@ public:
 
 
 	BIND2(light_directional_set_shadow_mode, RID, LightDirectionalShadowMode)
 	BIND2(light_directional_set_shadow_mode, RID, LightDirectionalShadowMode)
 	BIND2(light_directional_set_blend_splits, RID, bool)
 	BIND2(light_directional_set_blend_splits, RID, bool)
+	BIND2(light_directional_set_shadow_depth_range_mode, RID, LightDirectionalShadowDepthRangeMode)
 
 
 	/* PROBE API */
 	/* PROBE API */
 
 

+ 62 - 12
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 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);
 			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 = MIN(shadow_max, max_distance);
 			}
 			}
 			max_distance = MAX(max_distance, p_cam_projection.get_z_near() + 0.001);
 			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;
 			int splits = 0;
 			switch (VSG::storage->light_directional_get_shadow_mode(p_instance->base)) {
 			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];
 			float distances[5];
 
 
-			distances[0] = p_cam_projection.get_z_near();
+			distances[0] = min_distance;
 			for (int i = 0; i < splits; i++) {
 			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;
 			distances[splits] = max_distance;
@@ -984,8 +1027,6 @@ void VisualServerScene::_light_instance_update_shadow(Instance *p_instance, cons
 
 
 				{
 				{
 					//camera viewport stuff
 					//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;
 					Vector3 center;
 
 
@@ -1006,7 +1047,7 @@ void VisualServerScene::_light_instance_update_shadow(Instance *p_instance, cons
 							radius = d;
 							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) {
 					if (i == 0) {
 						first_radius = radius;
 						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_max_cam = z_vec.dot(center) + radius;
 					z_min_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
 				//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;
 					CameraMatrix ortho_camera;
 					real_t half_x = (x_max_cam - x_min_cam) * 0.5;
 					real_t half_x = (x_max_cam - x_min_cam) * 0.5;
 					real_t half_y = (y_max_cam - y_min_cam) * 0.5;
 					real_t half_y = (y_max_cam - y_min_cam) * 0.5;

+ 1 - 0
servers/visual/visual_server_wrap_mt.h

@@ -233,6 +233,7 @@ public:
 
 
 	FUNC2(light_directional_set_shadow_mode, RID, LightDirectionalShadowMode)
 	FUNC2(light_directional_set_shadow_mode, RID, LightDirectionalShadowMode)
 	FUNC2(light_directional_set_blend_splits, RID, bool)
 	FUNC2(light_directional_set_blend_splits, RID, bool)
+	FUNC2(light_directional_set_shadow_depth_range_mode, RID, LightDirectionalShadowDepthRangeMode)
 
 
 	/* PROBE API */
 	/* PROBE API */
 
 

+ 8 - 0
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_shadow_mode(RID p_light, LightDirectionalShadowMode p_mode) = 0;
 	virtual void light_directional_set_blend_splits(RID p_light, bool p_enable) = 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 */
 	/* PROBE API */
 
 
 	virtual RID reflection_probe_create() = 0;
 	virtual RID reflection_probe_create() = 0;

部分文件因为文件数量过多而无法显示