From 922398838835468ceec2c976536082e5d9a26b2a Mon Sep 17 00:00:00 2001 From: "K. S. Ernest (iFire) Lee" Date: Sun, 29 Sep 2024 13:13:09 -0700 Subject: [PATCH] Add CSGConvexCage3D --- modules/csg/config.py | 1 + modules/csg/csg.cpp | 34 +++++++++-- modules/csg/csg.h | 5 ++ modules/csg/csg_shape.cpp | 25 ++++++++ modules/csg/csg_shape.h | 7 +++ modules/csg/doc_classes/CSGConvexCage3D.xml | 13 +++++ modules/csg/icons/CSGConvexCage3D.svg | 65 +++++++++++++++++++++ modules/csg/register_types.cpp | 1 + 8 files changed, 145 insertions(+), 6 deletions(-) create mode 100644 modules/csg/doc_classes/CSGConvexCage3D.xml create mode 100644 modules/csg/icons/CSGConvexCage3D.svg diff --git a/modules/csg/config.py b/modules/csg/config.py index 3991b846f96f..c547416e67cf 100644 --- a/modules/csg/config.py +++ b/modules/csg/config.py @@ -17,6 +17,7 @@ def get_doc_classes(): "CSGShape3D", "CSGSphere3D", "CSGTorus3D", + "CSGConvexCage3D", ] diff --git a/modules/csg/csg.cpp b/modules/csg/csg.cpp index 8f6cabd71d60..699960ac97dc 100644 --- a/modules/csg/csg.cpp +++ b/modules/csg/csg.cpp @@ -387,10 +387,8 @@ static void pack_manifold( static void unpack_manifold( const manifold::Manifold &p_manifold, const HashMap> &mesh_materials, + Ref default_material, CSGBrush *r_mesh_merge) { - Ref default_material; - default_material.instantiate(); - manifold::MeshGL64 mesh = p_manifold.GetMeshGL64(); constexpr int32_t order[3] = { 0, 2, 1 }; @@ -426,6 +424,7 @@ static void unpack_manifold( ERR_FAIL_COND_MSG(property_i * mesh.numProp >= mesh.vertProperties.size(), "Invalid index into vertex properties"); + // Position is guaranteed. Others are not. face.vertices[tri_order_i] = Vector3( mesh.vertProperties[property_i * mesh.numProp + MANIFOLD_PROPERTY_POSITION_X], mesh.vertProperties[property_i * mesh.numProp + MANIFOLD_PROPERTY_POSITION_Y], @@ -435,8 +434,12 @@ static void unpack_manifold( mesh.vertProperties[property_i * mesh.numProp + MANIFOLD_PROPERTY_UV_X_0], mesh.vertProperties[property_i * mesh.numProp + MANIFOLD_PROPERTY_UV_Y_0]); - face.smooth = mesh.vertProperties[property_i * mesh.numProp + MANIFOLD_PROPERTY_SMOOTH_GROUP] > 0.5f; - face.invert = mesh.vertProperties[property_i * mesh.numProp + MANIFOLD_PROPERTY_INVERT] > 0.5f; + if (mesh.numProp > MANIFOLD_PROPERTY_SMOOTH_GROUP) { + face.smooth = mesh.vertProperties[property_i * mesh.numProp + MANIFOLD_PROPERTY_SMOOTH_GROUP] > 0.5f; + } + if (mesh.numProp > MANIFOLD_PROPERTY_INVERT) { + face.invert = mesh.vertProperties[property_i * mesh.numProp + MANIFOLD_PROPERTY_INVERT] > 0.5f; + } } r_mesh_merge->faces.push_back(face); @@ -449,6 +452,9 @@ static void unpack_manifold( // CSGBrushOperation void CSGBrushOperation::merge_brushes(Operation p_operation, const CSGBrush &p_brush_a, const CSGBrush &p_brush_b, CSGBrush &r_merged_brush, float p_vertex_snap) { + Ref default_material; + default_material.instantiate(); + HashMap> mesh_materials; manifold::Manifold brush_a; pack_manifold(&p_brush_a, brush_a, mesh_materials, p_vertex_snap); @@ -466,7 +472,23 @@ void CSGBrushOperation::merge_brushes(Operation p_operation, const CSGBrush &p_b merged_brush = brush_a - brush_b; break; } - unpack_manifold(merged_brush, mesh_materials, &r_merged_brush); + unpack_manifold(merged_brush, mesh_materials, default_material, &r_merged_brush); +} + +void make_brush_hull( + CSGBrush *brush, + const Vector &points, + const Ref material) { + + std::vector converted_points; + for (int i = 0; i < points.size(); i++) { + converted_points.push_back(manifold::vec3(points[i].x, points[i].y, points[i].z)); + } + + HashMap> mesh_materials; + manifold::Manifold m; + m = m.Hull(converted_points); + unpack_manifold(m, mesh_materials, material, brush); } // CSGBrushOperation::MeshMerge diff --git a/modules/csg/csg.h b/modules/csg/csg.h index 43ea5e6bdc9a..4845b7ed6f49 100644 --- a/modules/csg/csg.h +++ b/modules/csg/csg.h @@ -207,4 +207,9 @@ struct CSGBrushOperation { void update_faces(const CSGBrush &p_brush_a, const int p_face_idx_a, const CSGBrush &p_brush_b, const int p_face_idx_b, Build2DFaceCollection &p_collection, float p_vertex_snap); }; +extern void make_brush_hull( + CSGBrush *brush, + const Vector &points, + const Ref material); + #endif // CSG_H diff --git a/modules/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp index 296cda627aa3..c946c64c318f 100644 --- a/modules/csg/csg_shape.cpp +++ b/modules/csg/csg_shape.cpp @@ -2444,3 +2444,28 @@ CSGPolygon3D::CSGPolygon3D() { path_joined = false; path = nullptr; } + +/////////////// + +CSGBrush *CSGConvexCage3D::_build_brush() { + CSGBrush *new_brush = memnew(CSGBrush); + Ref mesh = get_mesh(); + Vector points; + if (mesh.is_valid()) { + for (int i = 0; i < mesh->get_surface_count(); ++i) { + Array vertices = mesh->surface_get_arrays(i)[Mesh::ARRAY_VERTEX]; + for (int j = 0; j < vertices.size(); ++j) { + points.push_back(vertices[j]); + } + } + if (points.size() < 4) { + return new_brush; + } + } else { + return new_brush; + } + + make_brush_hull(new_brush, points, get_material()); + + return new_brush; +} diff --git a/modules/csg/csg_shape.h b/modules/csg/csg_shape.h index bb7c8be43155..79aa68913ec4 100644 --- a/modules/csg/csg_shape.h +++ b/modules/csg/csg_shape.h @@ -456,4 +456,11 @@ VARIANT_ENUM_CAST(CSGPolygon3D::Mode) VARIANT_ENUM_CAST(CSGPolygon3D::PathRotation) VARIANT_ENUM_CAST(CSGPolygon3D::PathIntervalType) +class CSGConvexCage3D : public CSGMesh3D { + GDCLASS(CSGConvexCage3D, CSGMesh3D); + +private: + virtual CSGBrush *_build_brush() override; +}; + #endif // CSG_SHAPE_H diff --git a/modules/csg/doc_classes/CSGConvexCage3D.xml b/modules/csg/doc_classes/CSGConvexCage3D.xml new file mode 100644 index 000000000000..2c63c9ec1e5e --- /dev/null +++ b/modules/csg/doc_classes/CSGConvexCage3D.xml @@ -0,0 +1,13 @@ + + + + A CSG convex hull shape. + + + This node creates a mesh based on the convex hull of a set of points for use with the CSG system. + [b]Note:[/b] CSG nodes are intended to be used for level prototyping. Creating CSG nodes has a significant CPU cost compared to creating a [MeshInstance3D] with a [PrimitiveMesh]. Moving a CSG node within another CSG node also has a significant CPU cost, so it should be avoided during gameplay. + + + $DOCS_URL/tutorials/3d/csg_tools.html + + diff --git a/modules/csg/icons/CSGConvexCage3D.svg b/modules/csg/icons/CSGConvexCage3D.svg new file mode 100644 index 000000000000..3704145c24b4 --- /dev/null +++ b/modules/csg/icons/CSGConvexCage3D.svg @@ -0,0 +1,65 @@ + + diff --git a/modules/csg/register_types.cpp b/modules/csg/register_types.cpp index de949e30d846..717558b9fa15 100644 --- a/modules/csg/register_types.cpp +++ b/modules/csg/register_types.cpp @@ -48,6 +48,7 @@ void initialize_csg_module(ModuleInitializationLevel p_level) { GDREGISTER_CLASS(CSGCylinder3D); GDREGISTER_CLASS(CSGTorus3D); GDREGISTER_CLASS(CSGPolygon3D); + GDREGISTER_CLASS(CSGConvexCage3D); GDREGISTER_CLASS(CSGCombiner3D); } #ifdef TOOLS_ENABLED