Sliced mesh caps now generate proper normals, thanks to SurfaceTool.

This commit is contained in:
2026-09-26 01:34:01 -04:00
parent 306db05bfc
commit b6315f3076
+78 -93
View File
@@ -12,6 +12,7 @@
#include <map> #include <map>
#include "godot_cpp/classes/immediate_mesh.hpp" #include "godot_cpp/classes/immediate_mesh.hpp"
#include "godot_cpp/classes/surface_tool.hpp"
#include "godot_cpp/classes/time.hpp" #include "godot_cpp/classes/time.hpp"
#include "godot_cpp/variant/utility_functions.hpp" #include "godot_cpp/variant/utility_functions.hpp"
using namespace godot; using namespace godot;
@@ -62,18 +63,6 @@ PackedVector3Array MeshEditingLibrary::slice_mesh(MeshInstance3D *original_mesh_
std::vector<PackedInt32Array> first_half_indices; first_half_indices.resize(num_surfaces); std::vector<PackedInt32Array> first_half_indices; first_half_indices.resize(num_surfaces);
std::vector<PackedInt32Array> other_half_indices; other_half_indices.resize(num_surfaces); std::vector<PackedInt32Array> other_half_indices; other_half_indices.resize(num_surfaces);
PackedVector3Array cap_section_vertices;
PackedVector3Array cap_section_normals;
PackedVector3Array cap_section_flipped_normals;
PackedFloat32Array cap_section_tangents;
PackedFloat32Array cap_section_flipped_tangents;
PackedVector2Array cap_section_uvs;
PackedVector2Array cap_section_uv2s;
PackedColorArray cap_section_colours;
PackedInt32Array cap_section_bones;
PackedFloat32Array cap_section_weights;
PackedInt32Array cap_section_indices;
std::vector<std::vector<Transform3D>> skinned_vertex_transforms; std::vector<std::vector<Transform3D>> skinned_vertex_transforms;
std::vector<MeshEditEdge3D> clip_edges; std::vector<MeshEditEdge3D> clip_edges;
@@ -484,20 +473,26 @@ PackedVector3Array MeshEditingLibrary::slice_mesh(MeshInstance3D *original_mesh_
PRINT_LOG(MESH_EDITING_LIBRARY_TAG, "Surface ", surface, " split edges at ", time->get_ticks_msec(), "ms"); PRINT_LOG(MESH_EDITING_LIBRARY_TAG, "Surface ", surface, " split edges at ", time->get_ticks_msec(), "ms");
} }
MeshSlicePlaneOrientation uv_plane = MeshSlicePlaneOrientation::Z;
const Basis &mesh_instance_basis = original_mesh_instance->get_basis();
const Vector3 &local_plane_normal = local_plane.get_normal();
if (UtilityFunctions::absf(local_plane_normal.dot(mesh_instance_basis.xform(Vector3(0.0f, 1.0f, 0.0f)))) > 0.5f)
{
uv_plane = MeshSlicePlaneOrientation::Y;
}
else if (UtilityFunctions::absf(local_plane_normal.dot(mesh_instance_basis.xform(Vector3(1.0f, 0.0f, 0.0f)))) > 0.5f)
{
uv_plane = MeshSlicePlaneOrientation::X;
}
if (clip_edges.size() > 0) if (clip_edges.size() > 0)
{ {
MeshSlicePlaneOrientation uv_plane = MeshSlicePlaneOrientation::Z;
const Basis &mesh_instance_basis = original_mesh_instance->get_basis();
const Vector3 &local_plane_normal = local_plane.get_normal();
if (UtilityFunctions::absf(local_plane_normal.dot(mesh_instance_basis.xform(Vector3(0.0f, 1.0f, 0.0f)))) > 0.5f)
{
uv_plane = MeshSlicePlaneOrientation::Y;
}
else if (UtilityFunctions::absf(local_plane_normal.dot(mesh_instance_basis.xform(Vector3(1.0f, 0.0f, 0.0f)))) > 0.5f)
{
uv_plane = MeshSlicePlaneOrientation::X;
}
SurfaceTool *surface_tool_first_half = memnew(SurfaceTool);
SurfaceTool *surface_tool_other_half = memnew(SurfaceTool);
surface_tool_first_half->begin(Mesh::PRIMITIVE_TRIANGLES);
surface_tool_other_half->begin(Mesh::PRIMITIVE_TRIANGLES);
std::vector<MeshEditEdge2D> edges_2d; std::vector<MeshEditEdge2D> edges_2d;
std::vector<MeshEditPolygon2D> polygon_set; std::vector<MeshEditPolygon2D> polygon_set;
std::vector<MeshEditPolygon2D> error_polygons; std::vector<MeshEditPolygon2D> error_polygons;
@@ -507,6 +502,7 @@ PackedVector3Array MeshEditingLibrary::slice_mesh(MeshInstance3D *original_mesh_
const Vector3 &mesh_bounds = original_aabb.get_size(); const Vector3 &mesh_bounds = original_aabb.get_size();
const uint32_t num_polygons = polygon_set.size(); const uint32_t num_polygons = polygon_set.size();
uint32_t polygon_vertex_base = 0;
for (uint32_t polygon_index = 0; polygon_index < num_polygons; polygon_index++) for (uint32_t polygon_index = 0; polygon_index < num_polygons; polygon_index++)
{ {
using Point = std::array<float,2>; using Point = std::array<float,2>;
@@ -517,48 +513,54 @@ PackedVector3Array MeshEditingLibrary::slice_mesh(MeshInstance3D *original_mesh_
Vector3 polygon_centroid; Vector3 polygon_centroid;
const uint32_t polygon_vertex_base = cap_section_vertices.size(); uint32_t polygon_vertex_counter = 0;
for (const MeshEditVert2D &vertex : polygon_set[polygon_index].vertices) for (const MeshEditVert2D &vertex : polygon_set[polygon_index].vertices)
{ {
const Vector3 &position = first_half_vertices[vertex.surface][vertex.index]; const Vector3 &position = first_half_vertices[vertex.surface][vertex.index];
const Transform3D &skinned_vertex_transform = skinned_vertex_transforms[vertex.surface][vertex.index]; const Transform3D &skinned_vertex_transform = skinned_vertex_transforms[vertex.surface][vertex.index];
const Vector3 &local_plane_transformed_normal = skinned_vertex_transform.xform(local_plane_normal).normalized();
cap_section_vertices.append(position); const Vector2 &uv = MeshEditingLibrary::calculate_planar_uv(position, mesh_bounds, uv_plane);
if (surface_has_normal[vertex.surface]) surface_tool_first_half->set_uv(uv);
surface_tool_other_half->set_uv(uv);
if (surface_has_uv2[vertex.surface])
{ {
cap_section_normals.append(local_plane_transformed_normal); surface_tool_first_half->set_uv2(uv);
cap_section_flipped_normals.append(local_plane_transformed_normal * -1.0f); surface_tool_other_half->set_uv2(uv);
} }
if (surface_has_colour[vertex.surface]) { cap_section_colours.append(first_half_colours[vertex.surface][vertex.index]); }
if (surface_has_uv[vertex.surface]) { cap_section_uvs.append(MeshEditingLibrary::calculate_planar_uv(position, mesh_bounds, uv_plane)); } if (surface_has_colour[vertex.surface])
if (surface_has_uv2[vertex.surface]) { cap_section_uv2s.append(first_half_uv2s[vertex.surface][vertex.index]); }
if (surface_has_tangent[vertex.surface])
{ {
for (uint8_t i = 0; i < 4; i++) const Color &colour = first_half_colours[vertex.surface][vertex.index];
surface_tool_first_half->set_color(colour);
surface_tool_other_half->set_color(colour);
}
if (surface_has_bone[vertex.surface] && surface_has_weight[vertex.surface])
{
PackedInt32Array bones; bones.resize(4);
PackedFloat32Array weights; weights.resize(4);
for (uint8_t i = 0; i < surface_num_bones_per_vertex[vertex.surface] && i < 4; i++)
{ {
cap_section_tangents.append(first_half_tangents[vertex.surface][(vertex.index * 4) + i] * -1.0f); bones[i] = first_half_bones[vertex.surface][(vertex.index * surface_num_bones_per_vertex[vertex.surface]) + i];
cap_section_flipped_tangents.append(first_half_tangents[vertex.surface][(vertex.index * 4) + i]); weights[i] = first_half_weights[vertex.surface][(vertex.index * surface_num_bones_per_vertex[vertex.surface]) + i];
}
}
if (surface_has_bone[vertex.surface])
{
for (uint8_t i = 0; i < surface_num_bones_per_vertex[vertex.surface]; i++)
{
cap_section_bones.append(first_half_bones[vertex.surface][(vertex.index * surface_num_bones_per_vertex[vertex.surface]) + i]);
}
}
if (surface_has_weight[vertex.surface])
{
for (uint8_t i = 0; i < surface_num_bones_per_vertex[vertex.surface]; i++)
{
cap_section_weights.append(first_half_weights[vertex.surface][(vertex.index * surface_num_bones_per_vertex[vertex.surface]) + i]);
} }
surface_tool_first_half->set_bones(bones);
surface_tool_first_half->set_weights(weights);
surface_tool_other_half->set_bones(bones);
surface_tool_other_half->set_weights(weights);
} }
surface_tool_first_half->add_vertex(position);
surface_tool_other_half->add_vertex(position);
sub_polygon.push_back({vertex.position.x, vertex.position.y}); sub_polygon.push_back({vertex.position.x, vertex.position.y});
polygon_centroid += position; polygon_centroid += position;
polygon_vertex_counter++;
} }
polygon_centroid /= polygon_set[polygon_index].vertices.size(); polygon_centroid /= polygon_set[polygon_index].vertices.size();
@@ -568,56 +570,39 @@ PackedVector3Array MeshEditingLibrary::slice_mesh(MeshInstance3D *original_mesh_
std::vector<uint32_t> indices = mapbox::earcut<uint32_t>(earcut_polygon); std::vector<uint32_t> indices = mapbox::earcut<uint32_t>(earcut_polygon);
for (uint32_t i = 0; (i+2) < indices.size(); i += 3) for (uint32_t i = 0; (i+2) < indices.size(); i += 3)
{ {
cap_section_indices.append(indices[i+1] + polygon_vertex_base); const uint32_t index1 = indices[i+1] + polygon_vertex_base;
cap_section_indices.append(indices[i] + polygon_vertex_base); const uint32_t index2 = indices[i] + polygon_vertex_base;
cap_section_indices.append(indices[i+2] + polygon_vertex_base); const uint32_t index3 = indices[i+2] + polygon_vertex_base;
surface_tool_first_half->add_index(index1);
surface_tool_first_half->add_index(index2);
surface_tool_first_half->add_index(index3);
surface_tool_other_half->add_index(index1);
surface_tool_other_half->add_index(index3);
surface_tool_other_half->add_index(index2);
} }
polygon_vertex_base += polygon_vertex_counter;
} }
}
surface_tool_first_half->generate_normals();
PRINT_LOG(MESH_EDITING_LIBRARY_TAG, "Created cap surfaces at ", time->get_ticks_msec(), "ms"); surface_tool_other_half->generate_normals();
if (cap_section_vertices.size() > 0 && cap_section_indices.size() > 0) // surface_tool_first_half->generate_tangents();
{ // surface_tool_other_half->generate_tangents();
Array cap_mesh_section;
cap_mesh_section.resize(ArrayMesh::ARRAY_MAX); out_first_half = surface_tool_first_half->commit(out_first_half);
cap_mesh_section[ArrayMesh::ARRAY_VERTEX] = cap_section_vertices; out_other_half = surface_tool_other_half->commit(out_other_half);
cap_mesh_section[ArrayMesh::ARRAY_INDEX] = cap_section_indices;
if (cap_section_normals.size()) cap_mesh_section[ArrayMesh::ARRAY_NORMAL] = cap_section_normals;
// if (cap_section_tangents.size()) cap_mesh_section[ArrayMesh::ARRAY_TANGENT] = cap_section_tangents;
if (cap_section_colours.size()) cap_mesh_section[ArrayMesh::ARRAY_COLOR] = cap_section_colours;
if (cap_section_uvs.size()) cap_mesh_section[ArrayMesh::ARRAY_TEX_UV] = cap_section_uvs;
if (cap_section_uv2s.size()) cap_mesh_section[ArrayMesh::ARRAY_TEX_UV2] = cap_section_uv2s;
if (cap_section_bones.size()) cap_mesh_section[ArrayMesh::ARRAY_BONES] = cap_section_bones;
if (cap_section_weights.size()) cap_mesh_section[ArrayMesh::ARRAY_WEIGHTS] = cap_section_weights;
out_first_half->add_surface_from_arrays(ArrayMesh::PRIMITIVE_TRIANGLES, cap_mesh_section);
out_first_half->surface_set_material(out_first_half->get_surface_count()-1, cap_materials[uv_plane]); out_first_half->surface_set_material(out_first_half->get_surface_count()-1, cap_materials[uv_plane]);
const uint32_t num_cap_triangles = cap_section_indices.size();
for (uint32_t i = 0; i < num_cap_triangles; i += 3)
{
const int32_t old_index = cap_section_indices[i];
cap_section_indices[i] = cap_section_indices[i+1];
cap_section_indices[i+1] = old_index;
}
Array cap_other_mesh_section;
cap_other_mesh_section.resize(ArrayMesh::ARRAY_MAX);
cap_other_mesh_section[ArrayMesh::ARRAY_VERTEX] = cap_section_vertices;
cap_other_mesh_section[ArrayMesh::ARRAY_INDEX] = cap_section_indices;
if (cap_section_normals.size()) cap_other_mesh_section[ArrayMesh::ARRAY_NORMAL] = cap_section_flipped_normals;
// if (cap_section_tangents.size()) cap_other_mesh_section[ArrayMesh::ARRAY_TANGENT] = cap_section_flipped_tangents;
if (cap_section_colours.size()) cap_other_mesh_section[ArrayMesh::ARRAY_COLOR] = cap_section_colours;
if (cap_section_uvs.size()) cap_other_mesh_section[ArrayMesh::ARRAY_TEX_UV] = cap_section_uvs;
if (cap_section_uv2s.size()) cap_other_mesh_section[ArrayMesh::ARRAY_TEX_UV2] = cap_section_uv2s;
if (cap_section_bones.size()) cap_other_mesh_section[ArrayMesh::ARRAY_BONES] = cap_section_bones;
if (cap_section_weights.size()) cap_other_mesh_section[ArrayMesh::ARRAY_WEIGHTS] = cap_section_weights;
out_other_half->add_surface_from_arrays(ArrayMesh::PRIMITIVE_TRIANGLES, cap_other_mesh_section);
out_other_half->surface_set_material(out_other_half->get_surface_count()-1, cap_materials[uv_plane]); out_other_half->surface_set_material(out_other_half->get_surface_count()-1, cap_materials[uv_plane]);
PRINT_LOG(MESH_EDITING_LIBRARY_TAG, "Generated final cap surface at ", time->get_ticks_msec(), "ms"); PRINT_LOG(MESH_EDITING_LIBRARY_TAG, "Created cap surfaces at ", time->get_ticks_msec(), "ms");
} }
PRINT_LOG(MESH_EDITING_LIBRARY_TAG, "Generated final cap surface at ", time->get_ticks_msec(), "ms");
return impact_points; return impact_points;
} }