浏览代码

Merge pull request #37863 from ExpiredPopsicle/culling5

Fixed false positives in the culling system.
Rémi Verschelde 5 年之前
父节点
当前提交
8d93303483

+ 26 - 2
core/math/aabb.h

@@ -76,7 +76,7 @@ public:
 	bool intersects_ray(const Vector3 &p_from, const Vector3 &p_dir, Vector3 *r_clip = NULL, Vector3 *r_normal = NULL) const;
 	bool intersects_ray(const Vector3 &p_from, const Vector3 &p_dir, Vector3 *r_clip = NULL, Vector3 *r_normal = NULL) const;
 	_FORCE_INLINE_ bool smits_intersect_ray(const Vector3 &p_from, const Vector3 &p_dir, real_t t0, real_t t1) const;
 	_FORCE_INLINE_ bool smits_intersect_ray(const Vector3 &p_from, const Vector3 &p_dir, real_t t0, real_t t1) const;
 
 
-	_FORCE_INLINE_ bool intersects_convex_shape(const Plane *p_planes, int p_plane_count) const;
+	_FORCE_INLINE_ bool intersects_convex_shape(const Plane *p_planes, int p_plane_count, const Vector3 *p_points, int p_point_count) const;
 	_FORCE_INLINE_ bool inside_convex_shape(const Plane *p_planes, int p_plane_count) const;
 	_FORCE_INLINE_ bool inside_convex_shape(const Plane *p_planes, int p_plane_count) const;
 	bool intersects_plane(const Plane &p_plane) const;
 	bool intersects_plane(const Plane &p_plane) const;
 
 
@@ -190,7 +190,7 @@ Vector3 AABB::get_endpoint(int p_point) const {
 	ERR_FAIL_V(Vector3());
 	ERR_FAIL_V(Vector3());
 }
 }
 
 
-bool AABB::intersects_convex_shape(const Plane *p_planes, int p_plane_count) const {
+bool AABB::intersects_convex_shape(const Plane *p_planes, int p_plane_count, const Vector3 *p_points, int p_point_count) const {
 
 
 	Vector3 half_extents = size * 0.5;
 	Vector3 half_extents = size * 0.5;
 	Vector3 ofs = position + half_extents;
 	Vector3 ofs = position + half_extents;
@@ -206,6 +206,30 @@ bool AABB::intersects_convex_shape(const Plane *p_planes, int p_plane_count) con
 			return false;
 			return false;
 	}
 	}
 
 
+	// Make sure all points in the shape aren't fully separated from the AABB on
+	// each axis.
+	int bad_point_counts_positive[3] = { 0 };
+	int bad_point_counts_negative[3] = { 0 };
+
+	for (int k = 0; k < 3; k++) {
+
+		for (int i = 0; i < p_point_count; i++) {
+			if (p_points[i].coord[k] > ofs.coord[k] + half_extents.coord[k]) {
+				bad_point_counts_positive[k]++;
+			}
+			if (p_points[i].coord[k] < ofs.coord[k] - half_extents.coord[k]) {
+				bad_point_counts_negative[k]++;
+			}
+		}
+
+		if (bad_point_counts_negative[k] == p_point_count) {
+			return false;
+		}
+		if (bad_point_counts_positive[k] == p_point_count) {
+			return false;
+		}
+	}
+
 	return true;
 	return true;
 }
 }
 
 

+ 39 - 0
core/math/geometry.cpp

@@ -1185,3 +1185,42 @@ Vector<Vector<Point2> > Geometry::_polypath_offset(const Vector<Point2> &p_polyp
 	}
 	}
 	return polypaths;
 	return polypaths;
 }
 }
+
+Vector<Vector3> Geometry::compute_convex_mesh_points(const Plane *p_planes, int p_plane_count) {
+
+	Vector<Vector3> points;
+
+	// Iterate through every unique combination of any three planes.
+	for (int i = p_plane_count - 1; i >= 0; i--) {
+		for (int j = i - 1; j >= 0; j--) {
+			for (int k = j - 1; k >= 0; k--) {
+
+				// Find the point where these planes all cross over (if they
+				// do at all).
+				Vector3 convex_shape_point;
+				if (p_planes[i].intersect_3(p_planes[j], p_planes[k], &convex_shape_point)) {
+
+					// See if any *other* plane excludes this point because it's
+					// on the wrong side.
+					bool excluded = false;
+					for (int n = 0; n < p_plane_count; n++) {
+						if (n != i && n != j && n != k) {
+							real_t dp = p_planes[n].normal.dot(convex_shape_point);
+							if (dp - p_planes[n].d > CMP_EPSILON) {
+								excluded = true;
+								break;
+							}
+						}
+					}
+
+					// Only add the point if it passed all tests.
+					if (!excluded) {
+						points.push_back(convex_shape_point);
+					}
+				}
+			}
+		}
+	}
+
+	return points;
+}

+ 2 - 0
core/math/geometry.h

@@ -1014,6 +1014,8 @@ public:
 
 
 	static void make_atlas(const Vector<Size2i> &p_rects, Vector<Point2i> &r_result, Size2i &r_size);
 	static void make_atlas(const Vector<Size2i> &p_rects, Vector<Point2i> &r_result, Size2i &r_size);
 
 
+	static Vector<Vector3> compute_convex_mesh_points(const Plane *p_planes, int p_plane_count);
+
 private:
 private:
 	static Vector<Vector<Point2> > _polypaths_do_operation(PolyBooleanOperation p_op, const Vector<Point2> &p_polypath_a, const Vector<Point2> &p_polypath_b, bool is_a_open = false);
 	static Vector<Vector<Point2> > _polypaths_do_operation(PolyBooleanOperation p_op, const Vector<Point2> &p_polypath_a, const Vector<Point2> &p_polypath_b, bool is_a_open = false);
 	static Vector<Vector<Point2> > _polypath_offset(const Vector<Point2> &p_polypath, real_t p_delta, PolyJoinType p_join_type, PolyEndType p_end_type);
 	static Vector<Vector<Point2> > _polypath_offset(const Vector<Point2> &p_polypath, real_t p_delta, PolyJoinType p_join_type, PolyEndType p_end_type);

+ 10 - 4
core/math/octree.h

@@ -34,6 +34,7 @@
 #include "core/list.h"
 #include "core/list.h"
 #include "core/map.h"
 #include "core/map.h"
 #include "core/math/aabb.h"
 #include "core/math/aabb.h"
+#include "core/math/geometry.h"
 #include "core/math/vector3.h"
 #include "core/math/vector3.h"
 #include "core/print_string.h"
 #include "core/print_string.h"
 #include "core/variant.h"
 #include "core/variant.h"
@@ -341,6 +342,8 @@ private:
 
 
 		const Plane *planes;
 		const Plane *planes;
 		int plane_count;
 		int plane_count;
+		const Vector3 *points;
+		int point_count;
 		T **result_array;
 		T **result_array;
 		int *result_idx;
 		int *result_idx;
 		int result_max;
 		int result_max;
@@ -1017,8 +1020,7 @@ void Octree<T, use_pairs, AL>::_cull_convex(Octant *p_octant, _CullConvexData *p
 				continue;
 				continue;
 			e->last_pass = pass;
 			e->last_pass = pass;
 
 
-			if (e->aabb.intersects_convex_shape(p_cull->planes, p_cull->plane_count)) {
-
+			if (e->aabb.intersects_convex_shape(p_cull->planes, p_cull->plane_count, p_cull->points, p_cull->point_count)) {
 				if (*p_cull->result_idx < p_cull->result_max) {
 				if (*p_cull->result_idx < p_cull->result_max) {
 					p_cull->result_array[*p_cull->result_idx] = e->userdata;
 					p_cull->result_array[*p_cull->result_idx] = e->userdata;
 					(*p_cull->result_idx)++;
 					(*p_cull->result_idx)++;
@@ -1043,7 +1045,7 @@ void Octree<T, use_pairs, AL>::_cull_convex(Octant *p_octant, _CullConvexData *p
 				continue;
 				continue;
 			e->last_pass = pass;
 			e->last_pass = pass;
 
 
-			if (e->aabb.intersects_convex_shape(p_cull->planes, p_cull->plane_count)) {
+			if (e->aabb.intersects_convex_shape(p_cull->planes, p_cull->plane_count, p_cull->points, p_cull->point_count)) {
 
 
 				if (*p_cull->result_idx < p_cull->result_max) {
 				if (*p_cull->result_idx < p_cull->result_max) {
 
 
@@ -1059,7 +1061,7 @@ void Octree<T, use_pairs, AL>::_cull_convex(Octant *p_octant, _CullConvexData *p
 
 
 	for (int i = 0; i < 8; i++) {
 	for (int i = 0; i < 8; i++) {
 
 
-		if (p_octant->children[i] && p_octant->children[i]->aabb.intersects_convex_shape(p_cull->planes, p_cull->plane_count)) {
+		if (p_octant->children[i] && p_octant->children[i]->aabb.intersects_convex_shape(p_cull->planes, p_cull->plane_count, p_cull->points, p_cull->point_count)) {
 			_cull_convex(p_octant->children[i], p_cull);
 			_cull_convex(p_octant->children[i], p_cull);
 		}
 		}
 	}
 	}
@@ -1291,11 +1293,15 @@ int Octree<T, use_pairs, AL>::cull_convex(const Vector<Plane> &p_convex, T **p_r
 	if (!root)
 	if (!root)
 		return 0;
 		return 0;
 
 
+	Vector<Vector3> convex_points = Geometry::compute_convex_mesh_points(&p_convex[0], p_convex.size());
+
 	int result_count = 0;
 	int result_count = 0;
 	pass++;
 	pass++;
 	_CullConvexData cdata;
 	_CullConvexData cdata;
 	cdata.planes = &p_convex[0];
 	cdata.planes = &p_convex[0];
 	cdata.plane_count = p_convex.size();
 	cdata.plane_count = p_convex.size();
+	cdata.points = &convex_points[0];
+	cdata.point_count = convex_points.size();
 	cdata.result_array = p_result_array;
 	cdata.result_array = p_result_array;
 	cdata.result_max = p_result_max;
 	cdata.result_max = p_result_max;
 	cdata.result_idx = &result_count;
 	cdata.result_idx = &result_count;

+ 4 - 4
core/math/triangle_mesh.cpp

@@ -511,7 +511,7 @@ bool TriangleMesh::intersect_ray(const Vector3 &p_begin, const Vector3 &p_dir, V
 	return inters;
 	return inters;
 }
 }
 
 
-bool TriangleMesh::intersect_convex_shape(const Plane *p_planes, int p_plane_count) const {
+bool TriangleMesh::intersect_convex_shape(const Plane *p_planes, int p_plane_count, const Vector3 *p_points, int p_point_count) const {
 	uint32_t *stack = (uint32_t *)alloca(sizeof(int) * max_depth);
 	uint32_t *stack = (uint32_t *)alloca(sizeof(int) * max_depth);
 
 
 	//p_fully_inside = true;
 	//p_fully_inside = true;
@@ -548,7 +548,7 @@ bool TriangleMesh::intersect_convex_shape(const Plane *p_planes, int p_plane_cou
 		switch (stack[level] >> VISITED_BIT_SHIFT) {
 		switch (stack[level] >> VISITED_BIT_SHIFT) {
 			case TEST_AABB_BIT: {
 			case TEST_AABB_BIT: {
 
 
-				bool valid = b.aabb.intersects_convex_shape(p_planes, p_plane_count);
+				bool valid = b.aabb.intersects_convex_shape(p_planes, p_plane_count, p_points, p_point_count);
 				if (!valid) {
 				if (!valid) {
 
 
 					stack[level] = (VISIT_DONE_BIT << VISITED_BIT_SHIFT) | node;
 					stack[level] = (VISIT_DONE_BIT << VISITED_BIT_SHIFT) | node;
@@ -629,7 +629,7 @@ bool TriangleMesh::intersect_convex_shape(const Plane *p_planes, int p_plane_cou
 	return false;
 	return false;
 }
 }
 
 
-bool TriangleMesh::inside_convex_shape(const Plane *p_planes, int p_plane_count, Vector3 p_scale) const {
+bool TriangleMesh::inside_convex_shape(const Plane *p_planes, int p_plane_count, const Vector3 *p_points, int p_point_count, Vector3 p_scale) const {
 	uint32_t *stack = (uint32_t *)alloca(sizeof(int) * max_depth);
 	uint32_t *stack = (uint32_t *)alloca(sizeof(int) * max_depth);
 
 
 	enum {
 	enum {
@@ -666,7 +666,7 @@ bool TriangleMesh::inside_convex_shape(const Plane *p_planes, int p_plane_count,
 		switch (stack[level] >> VISITED_BIT_SHIFT) {
 		switch (stack[level] >> VISITED_BIT_SHIFT) {
 			case TEST_AABB_BIT: {
 			case TEST_AABB_BIT: {
 
 
-				bool intersects = scale.xform(b.aabb).intersects_convex_shape(p_planes, p_plane_count);
+				bool intersects = scale.xform(b.aabb).intersects_convex_shape(p_planes, p_plane_count, p_points, p_point_count);
 				if (!intersects) return false;
 				if (!intersects) return false;
 
 
 				bool inside = scale.xform(b.aabb).inside_convex_shape(p_planes, p_plane_count);
 				bool inside = scale.xform(b.aabb).inside_convex_shape(p_planes, p_plane_count);

+ 2 - 2
core/math/triangle_mesh.h

@@ -90,8 +90,8 @@ public:
 	bool is_valid() const;
 	bool is_valid() const;
 	bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_point, Vector3 &r_normal) const;
 	bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_point, Vector3 &r_normal) const;
 	bool intersect_ray(const Vector3 &p_begin, const Vector3 &p_dir, Vector3 &r_point, Vector3 &r_normal) const;
 	bool intersect_ray(const Vector3 &p_begin, const Vector3 &p_dir, Vector3 &r_point, Vector3 &r_normal) const;
-	bool intersect_convex_shape(const Plane *p_planes, int p_plane_count) const;
-	bool inside_convex_shape(const Plane *p_planes, int p_plane_count, Vector3 p_scale = Vector3(1, 1, 1)) const;
+	bool intersect_convex_shape(const Plane *p_planes, int p_plane_count, const Vector3 *p_points, int p_point_count) const;
+	bool inside_convex_shape(const Plane *p_planes, int p_plane_count, const Vector3 *p_points, int p_point_count, Vector3 p_scale = Vector3(1, 1, 1)) const;
 	Vector3 get_area_normal(const AABB &p_aabb) const;
 	Vector3 get_area_normal(const AABB &p_aabb) const;
 	PoolVector<Face3> get_faces() const;
 	PoolVector<Face3> get_faces() const;
 
 

+ 6 - 10
editor/plugins/spatial_editor_plugin.cpp

@@ -669,17 +669,13 @@ void SpatialEditorViewport::_select_region() {
 		}
 		}
 	}
 	}
 
 
-	if (!orthogonal) {
-		Plane near(cam_pos, -_get_camera_normal());
-		near.d -= get_znear();
+	Plane near(cam_pos, -_get_camera_normal());
+	near.d -= get_znear();
+	frustum.push_back(near);
 
 
-		frustum.push_back(near);
-
-		Plane far = -near;
-		far.d += get_zfar();
-
-		frustum.push_back(far);
-	}
+	Plane far = -near;
+	far.d += get_zfar();
+	frustum.push_back(far);
 
 
 	Vector<ObjectID> instances = VisualServer::get_singleton()->instances_cull_convex(frustum, get_tree()->get_root()->get_world()->get_scenario());
 	Vector<ObjectID> instances = VisualServer::get_singleton()->instances_cull_convex(frustum, get_tree()->get_root()->get_world()->get_scenario());
 	Vector<Node *> selected;
 	Vector<Node *> selected;

+ 4 - 2
editor/spatial_editor_gizmos.cpp

@@ -476,11 +476,13 @@ bool EditorSpatialGizmo::intersect_frustum(const Camera *p_camera, const Vector<
 
 
 		Vector<Plane> transformed_frustum;
 		Vector<Plane> transformed_frustum;
 
 
-		for (int i = 0; i < 4; i++) {
+		for (int i = 0; i < p_frustum.size(); i++) {
 			transformed_frustum.push_back(it.xform(p_frustum[i]));
 			transformed_frustum.push_back(it.xform(p_frustum[i]));
 		}
 		}
 
 
-		if (collision_mesh->inside_convex_shape(transformed_frustum.ptr(), transformed_frustum.size(), mesh_scale)) {
+		Vector<Vector3> convex_points = Geometry::compute_convex_mesh_points(p_frustum.ptr(), p_frustum.size());
+
+		if (collision_mesh->inside_convex_shape(transformed_frustum.ptr(), transformed_frustum.size(), convex_points.ptr(), convex_points.size(), mesh_scale)) {
 			return true;
 			return true;
 		}
 		}
 	}
 	}

+ 2 - 1
servers/visual/visual_server_scene.cpp

@@ -1583,12 +1583,13 @@ bool VisualServerScene::_light_instance_update_shadow(Instance *p_instance, cons
 
 
 					float z = i == 0 ? -1 : 1;
 					float z = i == 0 ? -1 : 1;
 					Vector<Plane> planes;
 					Vector<Plane> planes;
-					planes.resize(5);
+					planes.resize(6);
 					planes.write[0] = light_transform.xform(Plane(Vector3(0, 0, z), radius));
 					planes.write[0] = light_transform.xform(Plane(Vector3(0, 0, z), radius));
 					planes.write[1] = light_transform.xform(Plane(Vector3(1, 0, z).normalized(), radius));
 					planes.write[1] = light_transform.xform(Plane(Vector3(1, 0, z).normalized(), radius));
 					planes.write[2] = light_transform.xform(Plane(Vector3(-1, 0, z).normalized(), radius));
 					planes.write[2] = light_transform.xform(Plane(Vector3(-1, 0, z).normalized(), radius));
 					planes.write[3] = light_transform.xform(Plane(Vector3(0, 1, z).normalized(), radius));
 					planes.write[3] = light_transform.xform(Plane(Vector3(0, 1, z).normalized(), radius));
 					planes.write[4] = light_transform.xform(Plane(Vector3(0, -1, z).normalized(), radius));
 					planes.write[4] = light_transform.xform(Plane(Vector3(0, -1, z).normalized(), radius));
+					planes.write[5] = light_transform.xform(Plane(Vector3(0, 0, -z), 0));
 
 
 					int cull_count = p_scenario->octree.cull_convex(planes, instance_shadow_cull_result, MAX_INSTANCE_CULL, VS::INSTANCE_GEOMETRY_MASK);
 					int cull_count = p_scenario->octree.cull_convex(planes, instance_shadow_cull_result, MAX_INSTANCE_CULL, VS::INSTANCE_GEOMETRY_MASK);
 					Plane near_plane(light_transform.origin, light_transform.basis.get_axis(2) * z);
 					Plane near_plane(light_transform.origin, light_transform.basis.get_axis(2) * z);