Fix #104714: Missing shape keys in FBX export when original mesh data cannot be used #104890
@ -2594,12 +2594,30 @@ def fbx_data_from_scene(scene, depsgraph, settings):
|
|||||||
# If modifiers has been altered need to update dependency graph.
|
# If modifiers has been altered need to update dependency graph.
|
||||||
if backup_pose_positions or tmp_mods:
|
if backup_pose_positions or tmp_mods:
|
||||||
depsgraph.update()
|
depsgraph.update()
|
||||||
ob_to_convert = ob.evaluated_get(depsgraph) if settings.use_mesh_modifiers else ob
|
if settings.use_mesh_modifiers:
|
||||||
# NOTE: The dependency graph might be re-evaluating multiple times, which could
|
ob_to_convert = ob.evaluated_get(depsgraph)
|
||||||
# potentially free the mesh created early on. So we put those meshes to bmain and
|
# NOTE: The dependency graph might be re-evaluating multiple times, which could
|
||||||
# free them afterwards. Not ideal but ensures correct ownerwhip.
|
# potentially free the mesh created early on. So we put those meshes to bmain and
|
||||||
tmp_me = bpy.data.meshes.new_from_object(
|
# free them afterwards. Not ideal but ensures correct ownerwhip.
|
||||||
ob_to_convert, preserve_all_data_layers=True, depsgraph=depsgraph)
|
tmp_me = bpy.data.meshes.new_from_object(
|
||||||
|
ob_to_convert, preserve_all_data_layers=True, depsgraph=depsgraph)
|
||||||
|
free = True
|
||||||
|
|
||||||
|
# Usually the materials of the evaluated object will be the same, but modifiers, such as Geometry
|
||||||
|
# Nodes, can change the materials.
|
||||||
|
orig_mats = tuple(slot.material for slot in ob.material_slots)
|
||||||
|
eval_mats = tuple(slot.material.original if slot.material else None
|
||||||
|
for slot in ob_to_convert.material_slots)
|
||||||
|
if orig_mats != eval_mats:
|
||||||
|
# Override the default behaviour of getting materials from ob_obj.bdata.material_slots.
|
||||||
|
ob_obj.override_materials = eval_mats
|
||||||
|
else:
|
||||||
|
# Creates a temporary mesh owned by the Object without adding it to bpy.data.meshes. Most
|
||||||
|
# importantly, compared to bpy.data.meshes.new_from_object, it does not remove shape keys from the
|
||||||
|
# new mesh. We'll forcefully free these temporary meshes at the end of the export.
|
||||||
|
tmp_me = ob.to_mesh(preserve_all_data_layers=True, depsgraph=depsgraph)
|
||||||
|
free = False
|
||||||
|
|
||||||
# Triangulate the mesh if requested
|
# Triangulate the mesh if requested
|
||||||
if settings.use_triangles:
|
if settings.use_triangles:
|
||||||
import bmesh
|
import bmesh
|
||||||
@ -2608,15 +2626,8 @@ def fbx_data_from_scene(scene, depsgraph, settings):
|
|||||||
bmesh.ops.triangulate(bm, faces=bm.faces)
|
bmesh.ops.triangulate(bm, faces=bm.faces)
|
||||||
bm.to_mesh(tmp_me)
|
bm.to_mesh(tmp_me)
|
||||||
bm.free()
|
bm.free()
|
||||||
# Usually the materials of the evaluated object will be the same, but modifiers, such as Geometry Nodes,
|
|
||||||
# can change the materials.
|
data_meshes[ob_obj] = (get_blenderID_key(tmp_me), tmp_me, free)
|
||||||
orig_mats = tuple(slot.material for slot in ob.material_slots)
|
|
||||||
eval_mats = tuple(slot.material.original if slot.material else None
|
|
||||||
for slot in ob_to_convert.material_slots)
|
|
||||||
if orig_mats != eval_mats:
|
|
||||||
# Override the default behaviour of getting materials from ob_obj.bdata.material_slots.
|
|
||||||
ob_obj.override_materials = eval_mats
|
|
||||||
data_meshes[ob_obj] = (get_blenderID_key(tmp_me), tmp_me, True)
|
|
||||||
# Change armatures back.
|
# Change armatures back.
|
||||||
for armature, pose_position in backup_pose_positions:
|
for armature, pose_position in backup_pose_positions:
|
||||||
print((armature, pose_position))
|
print((armature, pose_position))
|
||||||
@ -3007,7 +3018,10 @@ def fbx_scene_data_cleanup(scene_data):
|
|||||||
"""
|
"""
|
||||||
# Delete temp meshes.
|
# Delete temp meshes.
|
||||||
done_meshes = set()
|
done_meshes = set()
|
||||||
for me_key, me, free in scene_data.data_meshes.values():
|
for ob_obj, (me_key, me, free) in scene_data.data_meshes.items():
|
||||||
|
# Clear temporary meshes created by Object.to_mesh().
|
||||||
|
ob_obj.bdata.to_mesh_clear()
|
||||||
|
# Clear temporary meshes created when applying modifiers.
|
||||||
if free and me_key not in done_meshes:
|
if free and me_key not in done_meshes:
|
||||||
bpy.data.meshes.remove(me)
|
bpy.data.meshes.remove(me)
|
||||||
done_meshes.add(me_key)
|
done_meshes.add(me_key)
|
||||||
|
Loading…
Reference in New Issue
Block a user