From 839c5924baaa3b16f0f494a56732fbf8db0b0c1d Mon Sep 17 00:00:00 2001 From: "K. S. Ernest (iFire) Lee" Date: Thu, 30 Jan 2025 07:35:22 -0800 Subject: [PATCH] Add the ability to lock faces. A CSG brush property to lock faces that defaults to off. Useful to avoid high levels of mesh simplification. --- modules/csg/csg.h | 1 + modules/csg/csg_shape.cpp | 56 +++++++++++++++++++++++++++++++++++++++ modules/csg/csg_shape.h | 3 +++ 3 files changed, 60 insertions(+) diff --git a/modules/csg/csg.h b/modules/csg/csg.h index 3c1d4d8fbeee..bcdada72afd7 100644 --- a/modules/csg/csg.h +++ b/modules/csg/csg.h @@ -51,6 +51,7 @@ struct CSGBrush { Vector faces; Vector> materials; + bool lock_faces = false; inline void _regen_face_aabbs() { for (int i = 0; i < faces.size(); i++) { diff --git a/modules/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp index b9f33dc7571a..45f902b4fc33 100644 --- a/modules/csg/csg_shape.cpp +++ b/modules/csg/csg_shape.cpp @@ -218,6 +218,7 @@ enum ManifoldProperty { MANIFOLD_PROPERTY_SMOOTH_GROUP, MANIFOLD_PROPERTY_UV_X_0, MANIFOLD_PROPERTY_UV_Y_0, + MANIFOLD_PROPERTY_FACE_LOCK, MANIFOLD_PROPERTY_MAX }; @@ -339,6 +340,38 @@ static String _export_meshgl_as_json(const manifold::MeshGL64 &p_mesh) { } #endif // DEV_ENABLED +// Yes, Manifold removes extra triangles from coplanar faces. There are several ways to make them stay - probably the easiest is adding any kind of extra vertex property. +// +// TODO: Adding any kind of extra vertex property to lock the faces. + +// struct CSGBrush { +// struct Face { +// Vector3 vertices[3]; +// Vector2 uvs[3]; +// AABB aabb; +// bool smooth = false; +// bool invert = false; +// int material = 0; +// }; + +// Vector faces; +// Vector> materials; +// bool lock_faces = false; + +// inline void _regen_face_aabbs() { +// for (int i = 0; i < faces.size(); i++) { +// faces.write[i].aabb = AABB(); +// faces.write[i].aabb.position = faces[i].vertices[0]; +// faces.write[i].aabb.expand_to(faces[i].vertices[1]); +// faces.write[i].aabb.expand_to(faces[i].vertices[2]); +// } +// } + +// // Create a brush from faces. +// void build_from_faces(const Vector &p_vertices, const Vector &p_uvs, const Vector &p_smooth, const Vector> &p_materials, const Vector &p_invert_faces); +// void copy_from(const CSGBrush &p_brush, const Transform3D &p_xform); +// }; + static void _pack_manifold( const CSGBrush *const p_mesh_merge, manifold::Manifold &r_manifold, @@ -347,6 +380,7 @@ static void _pack_manifold( ERR_FAIL_NULL_MSG(p_mesh_merge, "p_mesh_merge is null"); ERR_FAIL_NULL_MSG(p_csg_shape, "p_shape is null"); HashMap> faces_by_material; + bool lock_faces = p_mesh_merge->lock_faces; for (int face_i = 0; face_i < p_mesh_merge->faces.size(); face_i++) { const CSGBrush::Face &face = p_mesh_merge->faces[face_i]; faces_by_material[face.material].push_back(face); @@ -373,6 +407,7 @@ static void _pack_manifold( } p_mesh_materials.insert(reserved_id, material); + int face_i = 0; for (const CSGBrush::Face &face : faces) { for (int32_t tri_order_i = 0; tri_order_i < 3; tri_order_i++) { constexpr int32_t order[3] = { 0, 2, 1 }; @@ -392,7 +427,13 @@ static void _pack_manifold( vert[MANIFOLD_PROPERTY_UV_Y_0] = face.uvs[i].y; vert[MANIFOLD_PROPERTY_SMOOTH_GROUP] = face.smooth ? 1.0f : 0.0f; vert[MANIFOLD_PROPERTY_INVERT] = face.invert ? 1.0f : 0.0f; + if (lock_faces) { + vert[MANIFOLD_PROPERTY_FACE_LOCK] = face_i; + } else { + vert[MANIFOLD_PROPERTY_FACE_LOCK] = 0.0f; + } } + face_i++; } } // runIndex needs an explicit end value. @@ -996,6 +1037,10 @@ void CSGShape3D::_bind_methods() { ClassDB::bind_method(D_METHOD("bake_static_mesh"), &CSGShape3D::bake_static_mesh); ClassDB::bind_method(D_METHOD("bake_collision_shape"), &CSGShape3D::bake_collision_shape); + ClassDB::bind_method(D_METHOD("set_lock_faces", "lock"), &CSGShape3D::set_lock_faces); + ClassDB::bind_method(D_METHOD("set_lock_faces"), &CSGShape3D::get_lock_faces); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "lock_faces"), "set_lock_faces", "get_lock_faces"); ADD_PROPERTY(PropertyInfo(Variant::INT, "operation", PROPERTY_HINT_ENUM, "Union,Intersection,Subtraction"), "set_operation", "get_operation"); #ifndef DISABLE_DEPRECATED ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "snap", PROPERTY_HINT_RANGE, "0.000001,1,0.000001,suffix:m", PROPERTY_USAGE_NONE), "set_snap", "get_snap"); @@ -2784,3 +2829,14 @@ CSGPolygon3D::CSGPolygon3D() { path_joined = false; path = nullptr; } +void CSGShape3D::set_lock_faces(bool p_lock) { + if (brush) { + brush->lock_faces = p_lock; + } +} +bool CSGShape3D::get_lock_faces() const { + if (brush) { + return brush->lock_faces; + } + return false; +} diff --git a/modules/csg/csg_shape.h b/modules/csg/csg_shape.h index 39b42afc085b..2cf09af80eb5 100644 --- a/modules/csg/csg_shape.h +++ b/modules/csg/csg_shape.h @@ -134,6 +134,9 @@ class CSGShape3D : public GeometryInstance3D { public: Array get_meshes() const; + void set_lock_faces(bool p_lock); + bool get_lock_faces() const; + void set_operation(Operation p_operation); Operation get_operation() const;