Merge pull request #50404 from nekomatata/clean-convex-hull-decomposition
Clean convex hull decomposition code
This commit is contained in:
commit
f9c6dc1d9d
core/math
editor/import
modules/vhacd
scene/resources
@ -37,11 +37,13 @@
|
|||||||
class TriangleMesh : public RefCounted {
|
class TriangleMesh : public RefCounted {
|
||||||
GDCLASS(TriangleMesh, RefCounted);
|
GDCLASS(TriangleMesh, RefCounted);
|
||||||
|
|
||||||
|
public:
|
||||||
struct Triangle {
|
struct Triangle {
|
||||||
Vector3 normal;
|
Vector3 normal;
|
||||||
int indices[3];
|
int indices[3];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
Vector<Triangle> triangles;
|
Vector<Triangle> triangles;
|
||||||
Vector<Vector3> vertices;
|
Vector<Vector3> vertices;
|
||||||
|
|
||||||
@ -86,8 +88,8 @@ public:
|
|||||||
Vector3 get_area_normal(const AABB &p_aabb) const;
|
Vector3 get_area_normal(const AABB &p_aabb) const;
|
||||||
Vector<Face3> get_faces() const;
|
Vector<Face3> get_faces() const;
|
||||||
|
|
||||||
Vector<Triangle> get_triangles() const { return triangles; }
|
const Vector<Triangle> &get_triangles() const { return triangles; }
|
||||||
Vector<Vector3> get_vertices() const { return vertices; }
|
const Vector<Vector3> &get_vertices() const { return vertices; }
|
||||||
void get_indices(Vector<int> *r_triangles_indices) const;
|
void get_indices(Vector<int> *r_triangles_indices) const;
|
||||||
|
|
||||||
void create(const Vector<Vector3> &p_faces);
|
void create(const Vector<Vector3> &p_faces);
|
||||||
|
@ -525,35 +525,46 @@ Vector<Face3> EditorSceneImporterMesh::get_faces() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Vector<Ref<Shape3D>> EditorSceneImporterMesh::convex_decompose(const Mesh::ConvexDecompositionSettings &p_settings) const {
|
Vector<Ref<Shape3D>> EditorSceneImporterMesh::convex_decompose(const Mesh::ConvexDecompositionSettings &p_settings) const {
|
||||||
ERR_FAIL_COND_V(!Mesh::convex_composition_function, Vector<Ref<Shape3D>>());
|
ERR_FAIL_COND_V(!Mesh::convex_decomposition_function, Vector<Ref<Shape3D>>());
|
||||||
|
|
||||||
const Vector<Face3> faces = get_faces();
|
const Vector<Face3> faces = get_faces();
|
||||||
|
int face_count = faces.size();
|
||||||
|
|
||||||
Vector<Vector<Face3>> decomposed = Mesh::convex_composition_function(faces, p_settings);
|
Vector<Vector3> vertices;
|
||||||
|
uint32_t vertex_count = 0;
|
||||||
|
vertices.resize(face_count * 3);
|
||||||
|
Vector<uint32_t> indices;
|
||||||
|
indices.resize(face_count * 3);
|
||||||
|
{
|
||||||
|
Map<Vector3, uint32_t> vertex_map;
|
||||||
|
Vector3 *vertex_w = vertices.ptrw();
|
||||||
|
uint32_t *index_w = indices.ptrw();
|
||||||
|
for (int i = 0; i < face_count; i++) {
|
||||||
|
for (int j = 0; j < 3; j++) {
|
||||||
|
const Vector3 &vertex = faces[i].vertex[j];
|
||||||
|
Map<Vector3, uint32_t>::Element *found_vertex = vertex_map.find(vertex);
|
||||||
|
uint32_t index;
|
||||||
|
if (found_vertex) {
|
||||||
|
index = found_vertex->get();
|
||||||
|
} else {
|
||||||
|
index = ++vertex_count;
|
||||||
|
vertex_map[vertex] = index;
|
||||||
|
vertex_w[index] = vertex;
|
||||||
|
}
|
||||||
|
index_w[i * 3 + j] = index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vertices.resize(vertex_count);
|
||||||
|
|
||||||
|
Vector<Vector<Vector3>> decomposed = Mesh::convex_decomposition_function((real_t *)vertices.ptr(), vertex_count, indices.ptr(), face_count, p_settings, nullptr);
|
||||||
|
|
||||||
Vector<Ref<Shape3D>> ret;
|
Vector<Ref<Shape3D>> ret;
|
||||||
|
|
||||||
for (int i = 0; i < decomposed.size(); i++) {
|
for (int i = 0; i < decomposed.size(); i++) {
|
||||||
Set<Vector3> points;
|
|
||||||
for (int j = 0; j < decomposed[i].size(); j++) {
|
|
||||||
points.insert(decomposed[i][j].vertex[0]);
|
|
||||||
points.insert(decomposed[i][j].vertex[1]);
|
|
||||||
points.insert(decomposed[i][j].vertex[2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector<Vector3> convex_points;
|
|
||||||
convex_points.resize(points.size());
|
|
||||||
{
|
|
||||||
Vector3 *w = convex_points.ptrw();
|
|
||||||
int idx = 0;
|
|
||||||
for (Set<Vector3>::Element *E = points.front(); E; E = E->next()) {
|
|
||||||
w[idx++] = E->get();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ref<ConvexPolygonShape3D> shape;
|
Ref<ConvexPolygonShape3D> shape;
|
||||||
shape.instantiate();
|
shape.instantiate();
|
||||||
shape->set_points(convex_points);
|
shape->set_points(decomposed[i]);
|
||||||
ret.push_back(shape);
|
ret.push_back(shape);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@
|
|||||||
#include "scene/resources/mesh.h"
|
#include "scene/resources/mesh.h"
|
||||||
#include "thirdparty/vhacd/public/VHACD.h"
|
#include "thirdparty/vhacd/public/VHACD.h"
|
||||||
|
|
||||||
static Vector<Vector<Face3>> convex_decompose(const Vector<Face3> &p_faces, const Mesh::ConvexDecompositionSettings &p_settings) {
|
static Vector<Vector<Vector3>> convex_decompose(const real_t *p_vertices, int p_vertex_count, const uint32_t *p_triangles, int p_triangle_count, const Mesh::ConvexDecompositionSettings &p_settings, Vector<Vector<uint32_t>> *r_convex_indices) {
|
||||||
VHACD::IVHACD::Parameters params;
|
VHACD::IVHACD::Parameters params;
|
||||||
params.m_concavity = p_settings.max_concavity;
|
params.m_concavity = p_settings.max_concavity;
|
||||||
params.m_alpha = p_settings.symmetry_planes_clipping_bias;
|
params.m_alpha = p_settings.symmetry_planes_clipping_bias;
|
||||||
@ -49,42 +49,38 @@ static Vector<Vector<Face3>> convex_decompose(const Vector<Face3> &p_faces, cons
|
|||||||
params.m_maxConvexHulls = p_settings.max_convex_hulls;
|
params.m_maxConvexHulls = p_settings.max_convex_hulls;
|
||||||
params.m_projectHullVertices = p_settings.project_hull_vertices;
|
params.m_projectHullVertices = p_settings.project_hull_vertices;
|
||||||
|
|
||||||
Vector<real_t> vertices;
|
|
||||||
vertices.resize(p_faces.size() * 9);
|
|
||||||
Vector<uint32_t> indices;
|
|
||||||
indices.resize(p_faces.size() * 3);
|
|
||||||
|
|
||||||
for (int i = 0; i < p_faces.size(); i++) {
|
|
||||||
for (int j = 0; j < 3; j++) {
|
|
||||||
vertices.write[i * 9 + j * 3 + 0] = p_faces[i].vertex[j].x;
|
|
||||||
vertices.write[i * 9 + j * 3 + 1] = p_faces[i].vertex[j].y;
|
|
||||||
vertices.write[i * 9 + j * 3 + 2] = p_faces[i].vertex[j].z;
|
|
||||||
indices.write[i * 3 + j] = i * 3 + j;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VHACD::IVHACD *decomposer = VHACD::CreateVHACD();
|
VHACD::IVHACD *decomposer = VHACD::CreateVHACD();
|
||||||
decomposer->Compute(vertices.ptr(), vertices.size() / 3, indices.ptr(), indices.size() / 3, params);
|
decomposer->Compute(p_vertices, p_vertex_count, p_triangles, p_triangle_count, params);
|
||||||
|
|
||||||
int hull_count = decomposer->GetNConvexHulls();
|
int hull_count = decomposer->GetNConvexHulls();
|
||||||
|
|
||||||
Vector<Vector<Face3>> ret;
|
Vector<Vector<Vector3>> ret;
|
||||||
|
ret.resize(hull_count);
|
||||||
|
|
||||||
|
if (r_convex_indices) {
|
||||||
|
r_convex_indices->resize(hull_count);
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < hull_count; i++) {
|
for (int i = 0; i < hull_count; i++) {
|
||||||
Vector<Face3> triangles;
|
|
||||||
VHACD::IVHACD::ConvexHull hull;
|
VHACD::IVHACD::ConvexHull hull;
|
||||||
decomposer->GetConvexHull(i, hull);
|
decomposer->GetConvexHull(i, hull);
|
||||||
triangles.resize(hull.m_nTriangles);
|
|
||||||
for (uint32_t j = 0; j < hull.m_nTriangles; j++) {
|
Vector<Vector3> &points = ret.write[i];
|
||||||
Face3 f;
|
points.resize(hull.m_nPoints);
|
||||||
|
|
||||||
|
Vector3 *w = points.ptrw();
|
||||||
|
for (uint32_t j = 0; j < hull.m_nPoints; ++j) {
|
||||||
for (int k = 0; k < 3; k++) {
|
for (int k = 0; k < 3; k++) {
|
||||||
for (int l = 0; l < 3; l++) {
|
w[j][k] = hull.m_points[j * 3 + k];
|
||||||
f.vertex[k][l] = hull.m_points[hull.m_triangles[j * 3 + k] * 3 + l];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
triangles.write[j] = f;
|
|
||||||
|
if (r_convex_indices) {
|
||||||
|
Vector<uint32_t> &indices = r_convex_indices->write[i];
|
||||||
|
indices.resize(hull.m_nTriangles * 3);
|
||||||
|
|
||||||
|
memcpy(indices.ptrw(), hull.m_triangles, hull.m_nTriangles * 3 * sizeof(uint32_t));
|
||||||
}
|
}
|
||||||
ret.push_back(triangles);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
decomposer->Clean();
|
decomposer->Clean();
|
||||||
@ -94,9 +90,9 @@ static Vector<Vector<Face3>> convex_decompose(const Vector<Face3> &p_faces, cons
|
|||||||
}
|
}
|
||||||
|
|
||||||
void register_vhacd_types() {
|
void register_vhacd_types() {
|
||||||
Mesh::convex_composition_function = convex_decompose;
|
Mesh::convex_decomposition_function = convex_decompose;
|
||||||
}
|
}
|
||||||
|
|
||||||
void unregister_vhacd_types() {
|
void unregister_vhacd_types() {
|
||||||
Mesh::convex_composition_function = nullptr;
|
Mesh::convex_decomposition_function = nullptr;
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@
|
|||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
Mesh::ConvexDecompositionFunc Mesh::convex_composition_function = nullptr;
|
Mesh::ConvexDecompositionFunc Mesh::convex_decomposition_function = nullptr;
|
||||||
|
|
||||||
Ref<TriangleMesh> Mesh::generate_triangle_mesh() const {
|
Ref<TriangleMesh> Mesh::generate_triangle_mesh() const {
|
||||||
if (triangle_mesh.is_valid()) {
|
if (triangle_mesh.is_valid()) {
|
||||||
@ -167,59 +167,6 @@ Vector<Face3> Mesh::get_faces() const {
|
|||||||
return tm->get_faces();
|
return tm->get_faces();
|
||||||
}
|
}
|
||||||
return Vector<Face3>();
|
return Vector<Face3>();
|
||||||
/*
|
|
||||||
for (int i=0;i<surfaces.size();i++) {
|
|
||||||
if (RenderingServer::get_singleton()->mesh_surface_get_primitive_type( mesh, i ) != RenderingServer::PRIMITIVE_TRIANGLES )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
Vector<int> indices;
|
|
||||||
Vector<Vector3> vertices;
|
|
||||||
|
|
||||||
vertices=RenderingServer::get_singleton()->mesh_surface_get_array(mesh, i,RenderingServer::ARRAY_VERTEX);
|
|
||||||
|
|
||||||
int len=RenderingServer::get_singleton()->mesh_surface_get_array_index_len(mesh, i);
|
|
||||||
bool has_indices;
|
|
||||||
|
|
||||||
if (len>0) {
|
|
||||||
indices=RenderingServer::get_singleton()->mesh_surface_get_array(mesh, i,RenderingServer::ARRAY_INDEX);
|
|
||||||
has_indices=true;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
len=vertices.size();
|
|
||||||
has_indices=false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (len<=0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const int* indicesr = indices.ptr();
|
|
||||||
const int *indicesptr = indicesr.ptr();
|
|
||||||
|
|
||||||
const Vector3* verticesr = vertices.ptr();
|
|
||||||
const Vector3 *verticesptr = verticesr.ptr();
|
|
||||||
|
|
||||||
int old_faces=faces.size();
|
|
||||||
int new_faces=old_faces+(len/3);
|
|
||||||
|
|
||||||
faces.resize(new_faces);
|
|
||||||
|
|
||||||
Face3* facesw = faces.ptrw();
|
|
||||||
Face3 *facesptr=facesw.ptr();
|
|
||||||
|
|
||||||
|
|
||||||
for (int i=0;i<len/3;i++) {
|
|
||||||
Face3 face;
|
|
||||||
|
|
||||||
for (int j=0;j<3;j++) {
|
|
||||||
int idx=i*3+j;
|
|
||||||
face.vertex[j] = has_indices ? verticesptr[ indicesptr[ idx ] ] : verticesptr[idx];
|
|
||||||
}
|
|
||||||
|
|
||||||
facesptr[i+old_faces]=face;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ref<Shape3D> Mesh::create_convex_shape(bool p_clean, bool p_simplify) const {
|
Ref<Shape3D> Mesh::create_convex_shape(bool p_clean, bool p_simplify) const {
|
||||||
@ -568,35 +515,36 @@ void Mesh::clear_cache() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Vector<Ref<Shape3D>> Mesh::convex_decompose(const ConvexDecompositionSettings &p_settings) const {
|
Vector<Ref<Shape3D>> Mesh::convex_decompose(const ConvexDecompositionSettings &p_settings) const {
|
||||||
ERR_FAIL_COND_V(!convex_composition_function, Vector<Ref<Shape3D>>());
|
ERR_FAIL_COND_V(!convex_decomposition_function, Vector<Ref<Shape3D>>());
|
||||||
|
|
||||||
const Vector<Face3> faces = get_faces();
|
Ref<TriangleMesh> tm = generate_triangle_mesh();
|
||||||
|
ERR_FAIL_COND_V(!tm.is_valid(), Vector<Ref<Shape3D>>());
|
||||||
|
|
||||||
const Vector<Vector<Face3>> decomposed = convex_composition_function(faces, p_settings);
|
const Vector<TriangleMesh::Triangle> &triangles = tm->get_triangles();
|
||||||
|
int triangle_count = triangles.size();
|
||||||
|
|
||||||
|
Vector<uint32_t> indices;
|
||||||
|
{
|
||||||
|
indices.resize(triangle_count * 3);
|
||||||
|
uint32_t *w = indices.ptrw();
|
||||||
|
for (int i = 0; i < triangle_count; i++) {
|
||||||
|
for (int j = 0; j < 3; j++) {
|
||||||
|
w[i * 3 + j] = triangles[i].indices[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const Vector<Vector3> &vertices = tm->get_vertices();
|
||||||
|
int vertex_count = vertices.size();
|
||||||
|
|
||||||
|
Vector<Vector<Vector3>> decomposed = convex_decomposition_function((real_t *)vertices.ptr(), vertex_count, indices.ptr(), triangle_count, p_settings, nullptr);
|
||||||
|
|
||||||
Vector<Ref<Shape3D>> ret;
|
Vector<Ref<Shape3D>> ret;
|
||||||
|
|
||||||
for (int i = 0; i < decomposed.size(); i++) {
|
for (int i = 0; i < decomposed.size(); i++) {
|
||||||
Set<Vector3> points;
|
|
||||||
for (int j = 0; j < decomposed[i].size(); j++) {
|
|
||||||
points.insert(decomposed[i][j].vertex[0]);
|
|
||||||
points.insert(decomposed[i][j].vertex[1]);
|
|
||||||
points.insert(decomposed[i][j].vertex[2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector<Vector3> convex_points;
|
|
||||||
convex_points.resize(points.size());
|
|
||||||
{
|
|
||||||
Vector3 *w = convex_points.ptrw();
|
|
||||||
int idx = 0;
|
|
||||||
for (Set<Vector3>::Element *E = points.front(); E; E = E->next()) {
|
|
||||||
w[idx++] = E->get();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ref<ConvexPolygonShape3D> shape;
|
Ref<ConvexPolygonShape3D> shape;
|
||||||
shape.instantiate();
|
shape.instantiate();
|
||||||
shape->set_points(convex_points);
|
shape->set_points(decomposed[i]);
|
||||||
ret.push_back(shape);
|
ret.push_back(shape);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,9 +191,9 @@ public:
|
|||||||
uint32_t max_convex_hulls = 1;
|
uint32_t max_convex_hulls = 1;
|
||||||
bool project_hull_vertices = true;
|
bool project_hull_vertices = true;
|
||||||
};
|
};
|
||||||
typedef Vector<Vector<Face3>> (*ConvexDecompositionFunc)(const Vector<Face3> &p_faces, const ConvexDecompositionSettings &p_settings);
|
typedef Vector<Vector<Vector3>> (*ConvexDecompositionFunc)(const real_t *p_vertices, int p_vertex_count, const uint32_t *p_triangles, int p_triangle_count, const ConvexDecompositionSettings &p_settings, Vector<Vector<uint32_t>> *r_convex_indices);
|
||||||
|
|
||||||
static ConvexDecompositionFunc convex_composition_function;
|
static ConvexDecompositionFunc convex_decomposition_function;
|
||||||
|
|
||||||
Vector<Ref<Shape3D>> convex_decompose(const ConvexDecompositionSettings &p_settings) const;
|
Vector<Ref<Shape3D>> convex_decompose(const ConvexDecompositionSettings &p_settings) const;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user