Fix: FBX fails to export materials on geometry nodes objects #104530

Merged
Bastien Montagne merged 1 commits from Mysteryem/blender-addons:fbx_fix_geometry_nodes_mat_export_pr into main 2023-04-12 11:27:03 +02:00
2 changed files with 18 additions and 7 deletions
Showing only changes of commit 98017421b4 - Show all commits

View File

@ -1431,7 +1431,7 @@ def fbx_data_mesh_elements(root, me_obj, scene_data, done_meshes):
me_fbxmaterials_idx = scene_data.mesh_material_indices.get(me) me_fbxmaterials_idx = scene_data.mesh_material_indices.get(me)
if me_fbxmaterials_idx is not None: if me_fbxmaterials_idx is not None:
# We cannot use me.materials here, as this array is filled with None in case materials are linked to object... # We cannot use me.materials here, as this array is filled with None in case materials are linked to object...
me_blmaterials = [mat_slot.material for mat_slot in me_obj.material_slots] me_blmaterials = me_obj.materials
if me_fbxmaterials_idx and me_blmaterials: if me_fbxmaterials_idx and me_blmaterials:
lay_ma = elem_data_single_int32(geom, b"LayerElementMaterial", 0) lay_ma = elem_data_single_int32(geom, b"LayerElementMaterial", 0)
elem_data_single_int32(lay_ma, b"Version", FBX_GEOMETRY_MATERIAL_VERSION) elem_data_single_int32(lay_ma, b"Version", FBX_GEOMETRY_MATERIAL_VERSION)
@ -2598,6 +2598,14 @@ 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.
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) 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:
@ -2713,8 +2721,7 @@ def fbx_data_from_scene(scene, depsgraph, settings):
data_materials = {} data_materials = {}
for ob_obj in objects: for ob_obj in objects:
# If obj is not a valid object for materials, wrapper will just return an empty tuple... # If obj is not a valid object for materials, wrapper will just return an empty tuple...
for ma_s in ob_obj.material_slots: for ma in ob_obj.materials:
ma = ma_s.material
if ma is None: if ma is None:
continue # Empty slots! continue # Empty slots!
# Note theoretically, FBX supports any kind of materials, even GLSL shaders etc. # Note theoretically, FBX supports any kind of materials, even GLSL shaders etc.

View File

@ -1174,7 +1174,7 @@ class ObjectWrapper(metaclass=MetaObjectWrapper):
we need to use a key to identify each. we need to use a key to identify each.
""" """
__slots__ = ( __slots__ = (
'name', 'key', 'bdata', 'parented_to_armature', 'name', 'key', 'bdata', 'parented_to_armature', 'override_materials',
'_tag', '_ref', '_dupli_matrix' '_tag', '_ref', '_dupli_matrix'
) )
@ -1229,6 +1229,7 @@ class ObjectWrapper(metaclass=MetaObjectWrapper):
self.bdata = bdata self.bdata = bdata
self._ref = armature self._ref = armature
self.parented_to_armature = False self.parented_to_armature = False
self.override_materials = None
def __eq__(self, other): def __eq__(self, other):
return isinstance(other, self.__class__) and self.key == other.key return isinstance(other, self.__class__) and self.key == other.key
@ -1443,11 +1444,14 @@ class ObjectWrapper(metaclass=MetaObjectWrapper):
return () return ()
bones = property(get_bones) bones = property(get_bones)
def get_material_slots(self): def get_materials(self):
override_materials = self.override_materials
if override_materials is not None:
return override_materials
if self._tag in {'OB', 'DP'}: if self._tag in {'OB', 'DP'}:
return self.bdata.material_slots return tuple(slot.material for slot in self.bdata.material_slots)
return () return ()
material_slots = property(get_material_slots) materials = property(get_materials)
def is_deformed_by_armature(self, arm_obj): def is_deformed_by_armature(self, arm_obj):
if not (self.is_object and self.type == 'MESH'): if not (self.is_object and self.type == 'MESH'):