Merge pull request #37863 from ExpiredPopsicle/culling5

Fixed false positives in the culling system.
This commit is contained in:
Rémi Verschelde 2020-04-30 08:05:11 +02:00 committed by GitHub
commit 8d93303483
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 95 additions and 25 deletions

View File

@ -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;
} }

View File

@ -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;
}

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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 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, Vector3 p_scale = Vector3(1, 1, 1)) 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;

View File

@ -669,17 +669,13 @@ void SpatialEditorViewport::_select_region() {
} }
} }
if (!orthogonal) {
Plane near(cam_pos, -_get_camera_normal()); Plane near(cam_pos, -_get_camera_normal());
near.d -= get_znear(); near.d -= get_znear();
frustum.push_back(near); frustum.push_back(near);
Plane far = -near; Plane far = -near;
far.d += get_zfar(); far.d += get_zfar();
frustum.push_back(far); 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;

View File

@ -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;
} }
} }

View File

@ -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);