diff --git a/modules/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp index cc4595929f31..f39a2253b491 100644 --- a/modules/csg/csg_shape.cpp +++ b/modules/csg/csg_shape.cpp @@ -232,6 +232,38 @@ static void _unpack_manifold( r_mesh_merge->_regen_face_aabbs(); } +// Errors matching `thirdparty/manifold/include/manifold/manifold.h`. +static std::string manifold_error_to_string(const manifold::Manifold::Error &p_error) { + switch (p_error) { + case manifold::Manifold::Error::NoError: + return "No Error"; + case manifold::Manifold::Error::NonFiniteVertex: + return "Non Finite Vertex"; + case manifold::Manifold::Error::NotManifold: + return "Not Manifold"; + case manifold::Manifold::Error::VertexOutOfBounds: + return "Vertex Out Of Bounds"; + case manifold::Manifold::Error::PropertiesWrongLength: + return "Properties Wrong Length"; + case manifold::Manifold::Error::MissingPositionProperties: + return "Missing Position Properties"; + case manifold::Manifold::Error::MergeVectorsDifferentLengths: + return "Merge Vectors Different Lengths"; + case manifold::Manifold::Error::MergeIndexOutOfBounds: + return "Merge Index Out Of Bounds"; + case manifold::Manifold::Error::TransformWrongLength: + return "Transform Wrong Length"; + case manifold::Manifold::Error::RunIndexWrongLength: + return "Run Index Wrong Length"; + case manifold::Manifold::Error::FaceIDWrongLength: + return "Face ID Wrong Length"; + case manifold::Manifold::Error::InvalidConstruction: + return "Invalid Construction"; + default: + return "Unknown Error"; + }; +} + static void _pack_manifold( const CSGBrush *const p_mesh_merge, manifold::Manifold &r_manifold, @@ -246,7 +278,6 @@ static void _pack_manifold( } manifold::MeshGL64 mesh; - mesh.tolerance = p_snap; mesh.numProp = MANIFOLD_PROPERTY_MAX; mesh.runOriginalID.reserve(faces_by_material.size()); mesh.runIndex.reserve(faces_by_material.size() + 1); @@ -292,11 +323,10 @@ static void _pack_manifold( // runIndex needs an explicit end value. mesh.runIndex.push_back(mesh.triVerts.size()); ERR_FAIL_COND_MSG(mesh.vertProperties.size() % mesh.numProp != 0, "Invalid vertex properties size."); - mesh.Merge(); - r_manifold = manifold::Manifold(mesh); - manifold::Manifold::Error err = r_manifold.Status(); - if (err != manifold::Manifold::Error::NoError) { - print_error(String("Manifold creation from mesh failed:" + itos((int)err))); + if (mesh.Merge()) { + r_manifold = manifold::Manifold(mesh); + } else { + r_manifold = manifold::Manifold(); } } @@ -331,6 +361,15 @@ CSGBrush *CSGShape3D::_get_brush() { HashMap> mesh_materials; manifold::Manifold root_manifold; _pack_manifold(n, root_manifold, mesh_materials, get_snap()); + manifold::Manifold::Error root_error = root_manifold.Status(); + if (root_error != manifold::Manifold::Error::NoError) { + if (get_owner()) { + NodePath root_path = get_owner()->get_path_to(this, true); + print_error(vformat("Root CSGShape3D manifold creation from mesh failed at %s: %s", root_path, manifold_error_to_string(root_error).c_str())); + } else { + print_error(vformat("Root CSGShape3D manifold creation from mesh failed: %s", manifold_error_to_string(root_error).c_str())); + } + } manifold::OpType current_op = ManifoldOperation::convert_csg_op(get_operation()); std::vector manifolds; manifolds.push_back(root_manifold); @@ -347,6 +386,15 @@ CSGBrush *CSGShape3D::_get_brush() { transformed_brush.copy_from(*child_brush, child->get_transform()); manifold::Manifold child_manifold; _pack_manifold(&transformed_brush, child_manifold, mesh_materials, get_snap()); + manifold::Manifold::Error child_error = child_manifold.Status(); + if (child_error != manifold::Manifold::Error::NoError) { + if (child->get_owner()) { + NodePath child_path = child->get_owner()->get_path_to(child, true); + print_error(vformat("Child CSGShape3D manifold creation from mesh failed at %s: %s", child_path, manifold_error_to_string(child_error).c_str())); + } else { + print_error(vformat("Child CSGShape3D manifold creation from mesh failed: %s", manifold_error_to_string(child_error).c_str())); + } + } manifold::OpType child_operation = ManifoldOperation::convert_csg_op(child->get_operation()); if (child_operation != current_op) { manifold::Manifold result = manifold::Manifold::BatchBoolean(manifolds, current_op); @@ -864,7 +912,7 @@ void CSGShape3D::_bind_methods() { ClassDB::bind_method(D_METHOD("bake_collision_shape"), &CSGShape3D::bake_collision_shape); ADD_PROPERTY(PropertyInfo(Variant::INT, "operation", PROPERTY_HINT_ENUM, "Union,Intersection,Subtraction"), "set_operation", "get_operation"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "snap", PROPERTY_HINT_RANGE, "0.000001,1,0.000001,suffix:m"), "set_snap", "get_snap"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "snap", PROPERTY_HINT_RANGE, "0.000001,1,0.000001,suffix:m", PROPERTY_USAGE_NO_EDITOR), "set_snap", "get_snap"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "calculate_tangents"), "set_calculate_tangents", "is_calculating_tangents"); ADD_GROUP("Collision", "collision_"); diff --git a/modules/csg/doc_classes/CSGShape3D.xml b/modules/csg/doc_classes/CSGShape3D.xml index ac62d8dd83dc..6c0676dcd1cd 100644 --- a/modules/csg/doc_classes/CSGShape3D.xml +++ b/modules/csg/doc_classes/CSGShape3D.xml @@ -89,7 +89,7 @@ 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. - + Snap makes the mesh vertices snap to a given distance so that the faces of two meshes can be perfectly aligned. A lower value results in greater precision but may be harder to adjust. The top-level CSG shape's snap value is used for the entire CSG tree.