Fix: Mesh face normal calculation can give zero vectors

Triangles and quads don't check for degenerate faces (where the normal
might be zero), while ngons already set the Z component to 1 for that,
which is also what we do for vertex normals.

Also reorder the face size checks to put quads and triangles before
N-gons, since they are typically more common on high-poly meshes.
And change the check for 2 sided faces into an assert.
This commit is contained in:
Hans Goudey
2023-07-26 22:41:42 -04:00
parent 7548059886
commit f557222a7b

View File

@@ -138,34 +138,33 @@ static float3 normal_calc_ngon(const Span<float3> vert_positions, const Span<int
v_prev = v_curr;
}
if (UNLIKELY(normalize_v3(normal) == 0.0f)) {
normal[2] = 1.0f; /* other axis set to 0.0 */
}
return normal;
}
float3 face_normal_calc(const Span<float3> vert_positions, const Span<int> face_verts)
{
if (face_verts.size() > 4) {
return normal_calc_ngon(vert_positions, face_verts);
}
if (face_verts.size() == 3) {
return math::normal_tri(vert_positions[face_verts[0]],
vert_positions[face_verts[1]],
vert_positions[face_verts[2]]);
}
float3 normal;
if (face_verts.size() == 4) {
float3 normal;
normal_quad_v3(normal,
vert_positions[face_verts[0]],
vert_positions[face_verts[1]],
vert_positions[face_verts[2]],
vert_positions[face_verts[3]]);
return normal;
}
/* horrible, two sided face! */
return float3(0);
else if (face_verts.size() == 3) {
normal = math::normal_tri(vert_positions[face_verts[0]],
vert_positions[face_verts[1]],
vert_positions[face_verts[2]]);
}
else {
BLI_assert(face_verts.size() > 4);
normal = normal_calc_ngon(vert_positions, face_verts);
}
if (UNLIKELY(math::is_zero(normal))) {
normal.z = 1.0f;
}
return normal;
}
/** \} */