1
0
mirror of https://github.com/godotengine/godot.git synced 2025-11-04 12:00:25 +00:00

Optimize Convex Collision

Implements the Gauss Mapping optimization to SAT convex collision test.

* Described [here](https://ubm-twvideo01.s3.amazonaws.com/o1/vault/gdc2013/slides/822403Gregorius_Dirk_TheSeparatingAxisTest.pdf) by Dirk Gregorius.
* Requires adding of face information to edges in MeshData
* Took the chance to convert MeshData to LocalVector for performance.
This commit is contained in:
Juan Linietsky
2022-09-23 12:37:40 +02:00
parent 99bc4905cb
commit 71d2e38cb5
11 changed files with 170 additions and 81 deletions

View File

@@ -62,6 +62,7 @@ subject to the following restrictions:
#include "core/math/aabb.h"
#include "core/math/math_defs.h"
#include "core/os/memory.h"
#include "core/templates/oa_hash_map.h"
#include "core/templates/paged_allocator.h"
#include <string.h>
@@ -2252,19 +2253,62 @@ Error ConvexHullComputer::convex_hull(const Vector<Vector3> &p_points, Geometry3
r_mesh.vertices = ch.vertices;
// Tag which face each edge belongs to
LocalVector<int32_t> edge_faces;
edge_faces.resize(ch.edges.size());
for (uint32_t i = 0; i < ch.edges.size(); i++) {
edge_faces[i] = -1;
}
for (uint32_t i = 0; i < ch.faces.size(); i++) {
const Edge *e_start = &ch.edges[ch.faces[i]];
const Edge *e = e_start;
do {
int64_t ofs = e - ch.edges.ptr();
edge_faces[ofs] = i;
e = e->get_next_edge_of_face();
} while (e != e_start);
}
// Copy the edges over. There's two "half-edges" for every edge, so we pick only one of them.
r_mesh.edges.resize(ch.edges.size() / 2);
OAHashMap<uint64_t, int32_t> edge_map;
edge_map.reserve(ch.edges.size() * 4); // The higher the capacity, the faster the insert
uint32_t edges_copied = 0;
for (uint32_t i = 0; i < ch.edges.size(); i++) {
ERR_CONTINUE(edge_faces[i] == -1); // Sanity check
uint32_t a = (&ch.edges[i])->get_source_vertex();
uint32_t b = (&ch.edges[i])->get_target_vertex();
if (a < b) { // Copy only the "canonical" edge. For the reverse edge, this will be false.
ERR_BREAK(edges_copied >= (uint32_t)r_mesh.edges.size());
r_mesh.edges.write[edges_copied].a = a;
r_mesh.edges.write[edges_copied].b = b;
r_mesh.edges[edges_copied].vertex_a = a;
r_mesh.edges[edges_copied].vertex_b = b;
r_mesh.edges[edges_copied].face_a = edge_faces[i];
r_mesh.edges[edges_copied].face_b = -1;
uint64_t key = a;
key <<= 32;
key |= b;
edge_map.insert(key, edges_copied);
edges_copied++;
} else {
uint64_t key = b;
key <<= 32;
key |= a;
int32_t index;
if (!edge_map.lookup(key, index)) {
ERR_PRINT("Invalid edge");
} else {
r_mesh.edges[index].face_b = edge_faces[i];
}
}
}
if (edges_copied != (uint32_t)r_mesh.edges.size()) {
ERR_PRINT("Invalid edge count.");
}
@@ -2273,7 +2317,7 @@ Error ConvexHullComputer::convex_hull(const Vector<Vector3> &p_points, Geometry3
for (uint32_t i = 0; i < ch.faces.size(); i++) {
const Edge *e_start = &ch.edges[ch.faces[i]];
const Edge *e = e_start;
Geometry3D::MeshData::Face &face = r_mesh.faces.write[i];
Geometry3D::MeshData::Face &face = r_mesh.faces[i];
do {
face.indices.push_back(e->get_target_vertex());
@@ -2284,8 +2328,8 @@ Error ConvexHullComputer::convex_hull(const Vector<Vector3> &p_points, Geometry3
// reverse indices: Godot wants clockwise, but this is counter-clockwise
if (face.indices.size() > 2) {
// reverse all but the first index.
int *indices = face.indices.ptrw();
for (int c = 0; c < (face.indices.size() - 1) / 2; c++) {
int *indices = face.indices.ptr();
for (uint32_t c = 0; c < (face.indices.size() - 1) / 2; c++) {
SWAP(indices[c + 1], indices[face.indices.size() - 1 - c]);
}
}