Merge pull request #61559 from kleonc/triangle_mesh_from_triangle_strip_or_fan_3x

[3.x] Make `Mesh::generate_triangle_mesh()` handle `PRIMITIVE_TRIANGLE_STRIP` and `PRIMITIVE_TRIANGLE_FAN`
This commit is contained in:
Rémi Verschelde 2022-08-05 22:35:52 +02:00 committed by GitHub
commit 61b5e35de5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 48 additions and 18 deletions

View file

@ -40,7 +40,7 @@
<method name="generate_triangle_mesh" qualifiers="const"> <method name="generate_triangle_mesh" qualifiers="const">
<return type="TriangleMesh" /> <return type="TriangleMesh" />
<description> <description>
Generate a [TriangleMesh] from the mesh. Generate a [TriangleMesh] from the mesh. Considers only surfaces using one of these primitive types: [constant PRIMITIVE_TRIANGLES], [constant PRIMITIVE_TRIANGLE_STRIP], or [constant PRIMITIVE_TRIANGLE_FAN].
</description> </description>
</method> </method>
<method name="get_aabb" qualifiers="const"> <method name="get_aabb" qualifiers="const">

View file

@ -47,32 +47,46 @@ Ref<TriangleMesh> Mesh::generate_triangle_mesh() const {
return triangle_mesh; return triangle_mesh;
} }
int facecount = 0; int faces_size = 0;
for (int i = 0; i < get_surface_count(); i++) { for (int i = 0; i < get_surface_count(); i++) {
if (surface_get_primitive_type(i) != PRIMITIVE_TRIANGLES) { switch (surface_get_primitive_type(i)) {
continue; case PRIMITIVE_TRIANGLES: {
} int len = (surface_get_format(i) & ARRAY_FORMAT_INDEX) ? surface_get_array_index_len(i) : surface_get_array_len(i);
// Don't error if zero, it's valid (we'll just skip it later).
if (surface_get_format(i) & ARRAY_FORMAT_INDEX) { ERR_CONTINUE_MSG((len % 3) != 0, vformat("Ignoring surface %d, incorrect %s count: %d (for PRIMITIVE_TRIANGLES).", i, (surface_get_format(i) & ARRAY_FORMAT_INDEX) ? "index" : "vertex", len));
facecount += surface_get_array_index_len(i); faces_size += len;
} else { } break;
facecount += surface_get_array_len(i); case PRIMITIVE_TRIANGLE_FAN:
case PRIMITIVE_TRIANGLE_STRIP: {
int len = (surface_get_format(i) & ARRAY_FORMAT_INDEX) ? surface_get_array_index_len(i) : surface_get_array_len(i);
// Don't error if zero, it's valid (we'll just skip it later).
ERR_CONTINUE_MSG(len != 0 && len < 3, vformat("Ignoring surface %d, incorrect %s count: %d (for %s).", i, (surface_get_format(i) & ARRAY_FORMAT_INDEX) ? "index" : "vertex", len, (surface_get_primitive_type(i) == PRIMITIVE_TRIANGLE_FAN) ? "PRIMITIVE_TRIANGLE_FAN" : "PRIMITIVE_TRIANGLE_STRIP"));
faces_size += (len == 0) ? 0 : (len - 2) * 3;
} break;
default: {
} break;
} }
} }
if (facecount == 0 || (facecount % 3) != 0) { if (faces_size == 0) {
return triangle_mesh; return triangle_mesh;
} }
PoolVector<Vector3> faces; PoolVector<Vector3> faces;
faces.resize(facecount); faces.resize(faces_size);
PoolVector<Vector3>::Write facesw = faces.write(); PoolVector<Vector3>::Write facesw = faces.write();
int widx = 0; int widx = 0;
for (int i = 0; i < get_surface_count(); i++) { for (int i = 0; i < get_surface_count(); i++) {
if (surface_get_primitive_type(i) != PRIMITIVE_TRIANGLES) { Mesh::PrimitiveType primitive = surface_get_primitive_type(i);
if (primitive != PRIMITIVE_TRIANGLES && primitive != PRIMITIVE_TRIANGLE_FAN && primitive != PRIMITIVE_TRIANGLE_STRIP) {
continue;
}
int len = (surface_get_format(i) & ARRAY_FORMAT_INDEX) ? surface_get_array_index_len(i) : surface_get_array_len(i);
if ((primitive == PRIMITIVE_TRIANGLES && (len <= 0 || (len % 3) != 0)) || ((primitive == PRIMITIVE_TRIANGLE_FAN || primitive == PRIMITIVE_TRIANGLE_STRIP) && len < 3)) {
// Error was already shown, just skip (including zero).
continue; continue;
} }
@ -88,15 +102,31 @@ Ref<TriangleMesh> Mesh::generate_triangle_mesh() const {
PoolVector<int> indices = a[ARRAY_INDEX]; PoolVector<int> indices = a[ARRAY_INDEX];
PoolVector<int>::Read ir = indices.read(); PoolVector<int>::Read ir = indices.read();
if (primitive == PRIMITIVE_TRIANGLES) {
for (int j = 0; j < ic; j++) { for (int j = 0; j < ic; j++) {
int index = ir[j]; int index = ir[j];
facesw[widx++] = vr[index]; facesw[widx++] = vr[index];
} }
} else { // PRIMITIVE_TRIANGLE_FAN, PRIMITIVE_TRIANGLE_STRIP
for (int j = 2; j < ic; j++) {
facesw[widx++] = vr[ir[(primitive == PRIMITIVE_TRIANGLE_FAN) ? 0 : j - 2]];
facesw[widx++] = vr[ir[j - 1]];
facesw[widx++] = vr[ir[j]];
}
}
} else { } else {
if (primitive == PRIMITIVE_TRIANGLES) {
for (int j = 0; j < vc; j++) { for (int j = 0; j < vc; j++) {
facesw[widx++] = vr[j]; facesw[widx++] = vr[j];
} }
} else { // PRIMITIVE_TRIANGLE_FAN, PRIMITIVE_TRIANGLE_STRIP
for (int j = 2; j < vc; j++) {
facesw[widx++] = vr[(primitive == PRIMITIVE_TRIANGLE_FAN) ? 0 : j - 2];
facesw[widx++] = vr[j - 1];
facesw[widx++] = vr[j];
}
}
} }
} }