Fix #127765: FBX Export: Incorrect materials with Geometry Nodes

Geometry Nodes can change the materials of the Object, for Mesh Objects,
the new materials are present in the evaluated Object, but for non-Mesh
Objects, the new materials may not be present until the evaluated Object
has been converted to a Mesh.

This patch fixes the materials in FBX export, with Apply Modifiers
enabled, of non-Mesh types with Geometry Nodes that change materials.
Rather than getting the materials from the evaluated Object, the
materials are now retrieved from the Mesh created from the evaluated
Object.

To support object-linked material slots, the materials on the new Mesh
are replaced at the same indices as the object-linked material slots.

Pull Request: https://projects.blender.org/blender/blender/pulls/130485
This commit is contained in:
Thomas Barlow
2024-12-02 10:44:00 +01:00
committed by Bastien Montagne
parent d0d4fc45b3
commit 8ed98d592e
2 changed files with 13 additions and 7 deletions

View File

@@ -5,7 +5,7 @@
bl_info = {
"name": "FBX format",
"author": "Campbell Barton, Bastien Montagne, Jens Restemeier, @Mysteryem",
"version": (5, 12, 5),
"version": (5, 12, 6),
"blender": (4, 2, 0),
"location": "File > Import-Export",
"description": "FBX IO meshes, UVs, vertex colors, materials, textures, cameras, lamps and actions",

View File

@@ -2681,17 +2681,23 @@ def fbx_data_from_scene(scene, depsgraph, settings):
# NOTE: The dependency graph might be re-evaluating multiple times, which could
# potentially free the mesh created early on. So we put those meshes to bmain and
# free them afterwards. Not ideal but ensures correct ownership.
# This also converts non-mesh Objects to Mesh data.
tmp_me = bpy.data.meshes.new_from_object(
ob_to_convert, preserve_all_data_layers=True, depsgraph=depsgraph)
# 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)
# Usually the materials of the evaluated Object converted to a Mesh will be the same as the original
# Object, but modifiers, such as Geometry Nodes, can change the materials.
orig_mats = [slot.material for slot in ob.material_slots]
eval_mats = list(tmp_me.materials)
if orig_mats != eval_mats:
# An object-linked material slot replaces the material on the data at the slot's index. If applying
# modifiers changes the materials on the data, the object-linked material slot will replace the new
# material at the same index as before.
for i, slot in zip(range(len(eval_mats)), ob.material_slots):
if slot.link == 'OBJECT':
eval_mats[i] = slot.material
# Override the default behavior of getting materials from `ob_obj.bdata.material_slots`.
ob_obj.override_materials = eval_mats
ob_obj.override_materials = tuple(eval_mats)
elif do_convert:
tmp_me = bpy.data.meshes.new_from_object(ob, preserve_all_data_layers=True, depsgraph=depsgraph)
elif do_copy: