Added better handling for exporting meshes with negative scaling
The exporter now corrects the face normals of meshes with negative scaling that would otherwise be inverted on export. The face orientation should now always match what is seen in the viewport.
This commit is contained in:
@@ -150,6 +150,8 @@ def build_psk(context, options: PskBuildOptions) -> PskBuildResult:
|
|||||||
|
|
||||||
for object_index, input_mesh_object in enumerate(input_objects.mesh_objects):
|
for object_index, input_mesh_object in enumerate(input_objects.mesh_objects):
|
||||||
|
|
||||||
|
should_flip_normals = False
|
||||||
|
|
||||||
# MATERIALS
|
# MATERIALS
|
||||||
material_indices = [material_names.index(material_slot.material.name) for material_slot in input_mesh_object.material_slots]
|
material_indices = [material_names.index(material_slot.material.name) for material_slot in input_mesh_object.material_slots]
|
||||||
|
|
||||||
@@ -177,8 +179,16 @@ def build_psk(context, options: PskBuildOptions) -> PskBuildResult:
|
|||||||
mesh_object.matrix_world = input_mesh_object.matrix_world
|
mesh_object.matrix_world = input_mesh_object.matrix_world
|
||||||
|
|
||||||
scale = (input_mesh_object.scale.x, input_mesh_object.scale.y, input_mesh_object.scale.z)
|
scale = (input_mesh_object.scale.x, input_mesh_object.scale.y, input_mesh_object.scale.z)
|
||||||
if any(map(lambda x: x < 0, scale)):
|
|
||||||
result.warnings.append(f'Mesh "{input_mesh_object.name}" has negative scaling which may result in inverted normals.')
|
# Negative scaling in Blender results in inverted normals after the scale is applied. However, if the scale
|
||||||
|
# is not applied, the normals will appear unaffected in the viewport. The evaluated mesh data used in the
|
||||||
|
# export will have the scale applied, but this behavior is not obvious to the user.
|
||||||
|
#
|
||||||
|
# In order to have the exporter be as WYSIWYG as possible, we need to check for negative scaling and invert
|
||||||
|
# the normals if necessary. If two axes have negative scaling and the third has positive scaling, the
|
||||||
|
# normals will be correct. We can detect this by checking if the number of negative scaling axes is odd. If
|
||||||
|
# it is, we need to invert the normals of the mesh by swapping the order of the vertices in each face.
|
||||||
|
should_flip_normals = sum(1 for x in scale if x < 0) % 2 == 1
|
||||||
|
|
||||||
# Copy the vertex groups
|
# Copy the vertex groups
|
||||||
for vertex_group in input_mesh_object.vertex_groups:
|
for vertex_group in input_mesh_object.vertex_groups:
|
||||||
@@ -233,6 +243,7 @@ def build_psk(context, options: PskBuildOptions) -> PskBuildResult:
|
|||||||
|
|
||||||
# FACES
|
# FACES
|
||||||
poly_groups, groups = mesh_data.calc_smooth_groups(use_bitflags=True)
|
poly_groups, groups = mesh_data.calc_smooth_groups(use_bitflags=True)
|
||||||
|
psk_face_start_index = len(psk.faces)
|
||||||
for f in mesh_data.loop_triangles:
|
for f in mesh_data.loop_triangles:
|
||||||
face = Psk.Face()
|
face = Psk.Face()
|
||||||
face.material_index = material_indices[f.material_index]
|
face.material_index = material_indices[f.material_index]
|
||||||
@@ -242,6 +253,11 @@ def build_psk(context, options: PskBuildOptions) -> PskBuildResult:
|
|||||||
face.smoothing_groups = poly_groups[f.polygon_index]
|
face.smoothing_groups = poly_groups[f.polygon_index]
|
||||||
psk.faces.append(face)
|
psk.faces.append(face)
|
||||||
|
|
||||||
|
if should_flip_normals:
|
||||||
|
# Invert the normals of the faces.
|
||||||
|
for face in psk.faces[psk_face_start_index:]:
|
||||||
|
face.wedge_indices[0], face.wedge_indices[2] = face.wedge_indices[2], face.wedge_indices[0]
|
||||||
|
|
||||||
# WEIGHTS
|
# WEIGHTS
|
||||||
if armature_object is not None:
|
if armature_object is not None:
|
||||||
armature_data = typing.cast(Armature, armature_object.data)
|
armature_data = typing.cast(Armature, armature_object.data)
|
||||||
|
|||||||
Reference in New Issue
Block a user