Skip to content

Commit

Permalink
Not working. WIP Add the ability to lock faces.
Browse files Browse the repository at this point in the history
A CSG brush property to lock faces that defaults to off.

Useful to avoid high levels of mesh simplification.
  • Loading branch information
fire committed Jan 30, 2025
1 parent 71d80b2 commit 6fe3f3a
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 0 deletions.
1 change: 1 addition & 0 deletions modules/csg/csg.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ struct CSGBrush {

Vector<Face> faces;
Vector<Ref<Material>> materials;
bool lock_faces = false;

inline void _regen_face_aabbs() {
for (int i = 0; i < faces.size(); i++) {
Expand Down
59 changes: 59 additions & 0 deletions modules/csg/csg_shape.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
};

Expand Down Expand Up @@ -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<Face> faces;
// Vector<Ref<Material>> 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<Vector3> &p_vertices, const Vector<Vector2> &p_uvs, const Vector<bool> &p_smooth, const Vector<Ref<Material>> &p_materials, const Vector<bool> &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,
Expand All @@ -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<uint32_t, Vector<CSGBrush::Face>> 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);
Expand All @@ -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 };
Expand All @@ -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] = material_id * face_i + face_i;
} else {
vert[MANIFOLD_PROPERTY_FACE_LOCK] = 0.0f;
}
}
face_i++;
}
}
// runIndex needs an explicit end value.
Expand Down Expand Up @@ -434,6 +475,9 @@ CSGBrush *CSGShape3D::_get_brush() {
}
brush = nullptr;
CSGBrush *n = _build_brush();
if (!n) {
n->lock_faces = lock_faces;
}
HashMap<int32_t, Ref<Material>> mesh_materials;
manifold::Manifold root_manifold;
_pack_manifold(n, root_manifold, mesh_materials, this);
Expand All @@ -449,6 +493,9 @@ CSGBrush *CSGShape3D::_get_brush() {
if (!child_brush) {
continue;
}
if (!child_brush) {
child_brush->lock_faces = child->lock_faces;
}
CSGBrush transformed_brush;
transformed_brush.copy_from(*child_brush, child->get_transform());
manifold::Manifold child_manifold;
Expand Down Expand Up @@ -996,6 +1043,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("get_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");
Expand Down Expand Up @@ -2784,3 +2835,11 @@ CSGPolygon3D::CSGPolygon3D() {
path_joined = false;
path = nullptr;
}

void CSGShape3D::set_lock_faces(bool p_lock) {
lock_faces = p_lock;
}

bool CSGShape3D::get_lock_faces() const {
return lock_faces;
}
5 changes: 5 additions & 0 deletions modules/csg/csg_shape.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ class CSGShape3D : public GeometryInstance3D {

bool calculate_tangents = true;

bool lock_faces = false;

Ref<ArrayMesh> root_mesh;

struct Vector3Hasher {
Expand Down Expand Up @@ -134,6 +136,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;

Expand Down
3 changes: 3 additions & 0 deletions modules/csg/doc_classes/CSGShape3D.xml
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@
<member name="collision_priority" type="float" setter="set_collision_priority" getter="get_collision_priority" default="1.0">
The priority used to solve colliding when occurring penetration. Only effective if [member use_collision] is [code]true[/code]. The higher the priority is, the lower the penetration into the object will be. This can for example be used to prevent the player from breaking through the boundaries of a level.
</member>
<member name="lock_faces" type="bool" setter="set_lock_faces" getter="get_lock_faces" default="false">
Locks the faces of the CSG shape so they are lightly optimized.
</member>
<member name="operation" type="int" setter="set_operation" getter="get_operation" enum="CSGShape3D.Operation" default="0">
The operation that is performed on this shape. This is ignored for the first CSG child node as the operation is between this node and the previous child of this nodes parent.
</member>
Expand Down

0 comments on commit 6fe3f3a

Please sign in to comment.