Skip to content

Commit

Permalink
Push some warnings for CSG non manifold and other errors.
Browse files Browse the repository at this point in the history
  • Loading branch information
fire committed Dec 13, 2024
1 parent aa8d9b8 commit 7a15e6f
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 15 deletions.
56 changes: 41 additions & 15 deletions modules/csg/csg_shape.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -335,13 +335,13 @@ static String _export_meshgl_as_json(const manifold::MeshGL64 &p_mesh) {
}
#endif // DEV_ENABLED

static void _pack_manifold(
static manifold::Manifold::Error _pack_manifold(
const CSGBrush *const p_mesh_merge,
manifold::Manifold &r_manifold,
HashMap<int32_t, Ref<Material>> &p_mesh_materials,
CSGShape3D *p_csg_shape) {
ERR_FAIL_NULL_MSG(p_mesh_merge, "p_mesh_merge is null");
ERR_FAIL_NULL_MSG(p_csg_shape, "p_shape is null");
ERR_FAIL_NULL_V_MSG(p_mesh_merge, manifold::Manifold::Error::InvalidConstruction, "p_mesh_merge is null");
ERR_FAIL_NULL_V_MSG(p_csg_shape, manifold::Manifold::Error::InvalidConstruction, "p_shape is null");
HashMap<uint32_t, Vector<CSGBrush::Face>> faces_by_material;
for (int face_i = 0; face_i < p_mesh_merge->faces.size(); face_i++) {
const CSGBrush::Face &face = p_mesh_merge->faces[face_i];
Expand Down Expand Up @@ -394,22 +394,14 @@ static void _pack_manifold(
// runIndex needs an explicit end value.
mesh.runIndex.push_back(mesh.triVerts.size());
mesh.tolerance = 2 * FLT_EPSILON;
ERR_FAIL_COND_MSG(mesh.vertProperties.size() % mesh.numProp != 0, "Invalid vertex properties size.");
ERR_FAIL_COND_V_MSG(mesh.vertProperties.size() % mesh.numProp != 0, manifold::Manifold::Error::PropertiesWrongLength, "Invalid vertex properties size.");
mesh.Merge();
#ifdef DEV_ENABLED
print_verbose(_export_meshgl_as_json(mesh));
#endif // DEV_ENABLED
r_manifold = manifold::Manifold(mesh);
manifold::Manifold::Error error = r_manifold.Status();
if (error == manifold::Manifold::Error::NoError) {
return;
}
if (p_csg_shape->get_owner()) {
NodePath path = p_csg_shape->get_owner()->get_path_to(p_csg_shape, true);
print_error(vformat("CSGShape3D manifold creation from mesh failed at %s: %s.", path, manifold_error_to_string(error)));
} else {
print_error(vformat("CSGShape3D manifold creation from mesh failed at .: %s.", manifold_error_to_string(error)));
}
return error;
}

struct ManifoldOperation {
Expand Down Expand Up @@ -442,7 +434,31 @@ CSGBrush *CSGShape3D::_get_brush() {
CSGBrush *n = _build_brush();
HashMap<int32_t, Ref<Material>> mesh_materials;
manifold::Manifold root_manifold;
_pack_manifold(n, root_manifold, mesh_materials, this);
manifold::Manifold::Error manifold_error = _pack_manifold(n, root_manifold, mesh_materials, this);
if (is_root_shape()) {
warnings.clear();
for (int i = 0; i < get_child_count(); i++) {
CSGShape3D *child = Object::cast_to<CSGShape3D>(get_child(i));
if (child) {
child->warnings.clear();
}
}
}
const String manifold_error_message_template = "%s: The CSGShape3D could not be created because of this error. This error has caused the CSGShape3D to be empty. Typical errors occur because the CSGShape3D is not a manifold mesh. A manifold mesh is a 3D model that forms a solid object without any gaps, holes, or loose edges. For a mesh to be manifold, every edge of every triangle must contain the same two vertices (by index) as exactly one other triangle edge, and the start and end vertices must switch places between these two edges. The triangle vertices must appear in clockwise order when viewed from the outside of the manifold.";
if (manifold_error != manifold::Manifold::Error::NoError) {
String error_message = vformat(manifold_error_message_template, manifold_error_to_string(manifold_error));
if (!warnings.has(error_message)) {
warnings.push_back(error_message);
}
for (int i = 0; i < get_child_count(); i++) {
CSGShape3D *child = Object::cast_to<CSGShape3D>(get_child(i));
if (child) {
if (!child->warnings.has(error_message)) {
child->warnings.push_back(error_message);
}
}
}
}
manifold::OpType current_op = ManifoldOperation::convert_csg_op(get_operation());
std::vector<manifold::Manifold> manifolds;
manifolds.push_back(root_manifold);
Expand All @@ -458,7 +474,13 @@ CSGBrush *CSGShape3D::_get_brush() {
CSGBrush transformed_brush;
transformed_brush.copy_from(*child_brush, child->get_transform());
manifold::Manifold child_manifold;
_pack_manifold(&transformed_brush, child_manifold, mesh_materials, child);
manifold::Manifold::Error child_manifold_error = _pack_manifold(&transformed_brush, child_manifold, mesh_materials, child);
if (child_manifold_error != manifold::Manifold::Error::NoError) {
String error_message = vformat(manifold_error_message_template, manifold_error_to_string(child_manifold_error));
if (!child->warnings.has(error_message)) {
child->warnings.push_back(error_message);
}
}
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);
Expand Down Expand Up @@ -939,6 +961,10 @@ Array CSGShape3D::get_meshes() const {
return Array();
}

PackedStringArray CSGShape3D::get_configuration_warnings() const {
return warnings;
}

void CSGShape3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("_update_shape"), &CSGShape3D::_update_shape);
ClassDB::bind_method(D_METHOD("is_root_shape"), &CSGShape3D::is_root_shape);
Expand Down
2 changes: 2 additions & 0 deletions modules/csg/csg_shape.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,8 @@ class CSGShape3D : public GeometryInstance3D {
void _notification(int p_what);
virtual CSGBrush *_build_brush() = 0;
void _make_dirty(bool p_parent_removing = false);
PackedStringArray warnings;
PackedStringArray get_configuration_warnings() const override;

static void _bind_methods();

Expand Down

0 comments on commit 7a15e6f

Please sign in to comment.