Fix disparity of FBX custom properties import and export #104702
@ -1719,6 +1719,14 @@ def fbx_data_video_elements(root, vid, scene_data):
|
|||||||
#~ else:
|
#~ else:
|
||||||
#~ elem_data_single_bytes(fbx_vid, b"Content", b"")
|
#~ elem_data_single_bytes(fbx_vid, b"Content", b"")
|
||||||
|
|
||||||
|
# Blender currently has no UI for editing custom properties on Images, but the importer will import Image custom
|
||||||
|
# properties from either a Video Node or a Texture Node, preferring a Video node if one exists. We'll propagate
|
||||||
|
# these custom properties only to Video Nodes because that is most likely where they were imported from, and Texture
|
||||||
|
# Nodes are more like Blender's Shader Nodes than Images, which is what we're exporting here.
|
||||||
|
if scene_data.settings.use_custom_props:
|
||||||
|
fbx_data_element_custom_properties(props, vid)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def fbx_data_armature_elements(root, arm_obj, scene_data):
|
def fbx_data_armature_elements(root, arm_obj, scene_data):
|
||||||
"""
|
"""
|
||||||
|
@ -1777,10 +1777,12 @@ def blen_read_texture_image(fbx_tmpl, fbx_obj, basedir, settings):
|
|||||||
return image
|
return image
|
||||||
|
|
||||||
|
|
||||||
def blen_read_camera(fbx_tmpl, fbx_obj, global_scale):
|
def blen_read_camera(fbx_tmpl, fbx_obj, settings):
|
||||||
# meters to inches
|
# meters to inches
|
||||||
M2I = 0.0393700787
|
M2I = 0.0393700787
|
||||||
|
|
||||||
|
global_scale = settings.global_scale
|
||||||
|
|
||||||
elem_name_utf8 = elem_name_ensure_class(fbx_obj, b'NodeAttribute')
|
elem_name_utf8 = elem_name_ensure_class(fbx_obj, b'NodeAttribute')
|
||||||
|
|
||||||
fbx_props = (elem_find_first(fbx_obj, b'Properties70'),
|
fbx_props = (elem_find_first(fbx_obj, b'Properties70'),
|
||||||
@ -1808,10 +1810,13 @@ def blen_read_camera(fbx_tmpl, fbx_obj, global_scale):
|
|||||||
camera.clip_start = elem_props_get_number(fbx_props, b'NearPlane', 0.01) * global_scale
|
camera.clip_start = elem_props_get_number(fbx_props, b'NearPlane', 0.01) * global_scale
|
||||||
camera.clip_end = elem_props_get_number(fbx_props, b'FarPlane', 100.0) * global_scale
|
camera.clip_end = elem_props_get_number(fbx_props, b'FarPlane', 100.0) * global_scale
|
||||||
|
|
||||||
|
if settings.use_custom_props:
|
||||||
|
blen_read_custom_properties(fbx_obj, camera, settings)
|
||||||
|
|
||||||
return camera
|
return camera
|
||||||
|
|
||||||
|
|
||||||
def blen_read_light(fbx_tmpl, fbx_obj, global_scale):
|
def blen_read_light(fbx_tmpl, fbx_obj, settings):
|
||||||
import math
|
import math
|
||||||
elem_name_utf8 = elem_name_ensure_class(fbx_obj, b'NodeAttribute')
|
elem_name_utf8 = elem_name_ensure_class(fbx_obj, b'NodeAttribute')
|
||||||
|
|
||||||
@ -1841,13 +1846,16 @@ def blen_read_light(fbx_tmpl, fbx_obj, global_scale):
|
|||||||
# TODO, cycles nodes???
|
# TODO, cycles nodes???
|
||||||
lamp.color = elem_props_get_color_rgb(fbx_props, b'Color', (1.0, 1.0, 1.0))
|
lamp.color = elem_props_get_color_rgb(fbx_props, b'Color', (1.0, 1.0, 1.0))
|
||||||
lamp.energy = elem_props_get_number(fbx_props, b'Intensity', 100.0) / 100.0
|
lamp.energy = elem_props_get_number(fbx_props, b'Intensity', 100.0) / 100.0
|
||||||
lamp.distance = elem_props_get_number(fbx_props, b'DecayStart', 25.0) * global_scale
|
lamp.distance = elem_props_get_number(fbx_props, b'DecayStart', 25.0) * settings.global_scale
|
||||||
lamp.use_shadow = elem_props_get_bool(fbx_props, b'CastShadow', True)
|
lamp.use_shadow = elem_props_get_bool(fbx_props, b'CastShadow', True)
|
||||||
if hasattr(lamp, "cycles"):
|
if hasattr(lamp, "cycles"):
|
||||||
lamp.cycles.cast_shadow = lamp.use_shadow
|
lamp.cycles.cast_shadow = lamp.use_shadow
|
||||||
# Keeping this for now, but this is not used nor exposed anymore afaik...
|
# Keeping this for now, but this is not used nor exposed anymore afaik...
|
||||||
lamp.shadow_color = elem_props_get_color_rgb(fbx_props, b'ShadowColor', (0.0, 0.0, 0.0))
|
lamp.shadow_color = elem_props_get_color_rgb(fbx_props, b'ShadowColor', (0.0, 0.0, 0.0))
|
||||||
|
|
||||||
|
if settings.use_custom_props:
|
||||||
|
blen_read_custom_properties(fbx_obj, lamp, settings)
|
||||||
|
|
||||||
return lamp
|
return lamp
|
||||||
|
|
||||||
|
|
||||||
@ -1861,7 +1869,7 @@ class FbxImportHelperNode:
|
|||||||
__slots__ = (
|
__slots__ = (
|
||||||
'_parent', 'anim_compensation_matrix', 'is_global_animation', 'armature_setup', 'armature', 'bind_matrix',
|
'_parent', 'anim_compensation_matrix', 'is_global_animation', 'armature_setup', 'armature', 'bind_matrix',
|
||||||
'bl_bone', 'bl_data', 'bl_obj', 'bone_child_matrix', 'children', 'clusters',
|
'bl_bone', 'bl_data', 'bl_obj', 'bone_child_matrix', 'children', 'clusters',
|
||||||
'fbx_elem', 'fbx_name', 'fbx_transform_data', 'fbx_type',
|
'fbx_elem', 'fbx_data_elem', 'fbx_name', 'fbx_transform_data', 'fbx_type',
|
||||||
'is_armature', 'has_bone_children', 'is_bone', 'is_root', 'is_leaf',
|
'is_armature', 'has_bone_children', 'is_bone', 'is_root', 'is_leaf',
|
||||||
'matrix', 'matrix_as_parent', 'matrix_geom', 'meshes', 'post_matrix', 'pre_matrix')
|
'matrix', 'matrix_as_parent', 'matrix_geom', 'meshes', 'post_matrix', 'pre_matrix')
|
||||||
|
|
||||||
@ -1869,6 +1877,7 @@ class FbxImportHelperNode:
|
|||||||
self.fbx_name = elem_name_ensure_class(fbx_elem, b'Model') if fbx_elem else 'Unknown'
|
self.fbx_name = elem_name_ensure_class(fbx_elem, b'Model') if fbx_elem else 'Unknown'
|
||||||
self.fbx_type = fbx_elem.props[2] if fbx_elem else None
|
self.fbx_type = fbx_elem.props[2] if fbx_elem else None
|
||||||
self.fbx_elem = fbx_elem
|
self.fbx_elem = fbx_elem
|
||||||
|
self.fbx_data_elem = None # FBX elem of a connected NodeAttribute/Geometry for helpers whose bl_data does not exist or is yet to be created.
|
||||||
self.bl_obj = None
|
self.bl_obj = None
|
||||||
self.bl_data = bl_data
|
self.bl_data = bl_data
|
||||||
self.bl_bone = None # Name of bone if this is a bone (this may be different to fbx_name if there was a name conflict in Blender!)
|
self.bl_bone = None # Name of bone if this is a bone (this may be different to fbx_name if there was a name conflict in Blender!)
|
||||||
@ -2199,7 +2208,7 @@ class FbxImportHelperNode:
|
|||||||
for child in self.children:
|
for child in self.children:
|
||||||
child.collect_armature_meshes()
|
child.collect_armature_meshes()
|
||||||
|
|
||||||
def build_skeleton(self, arm, parent_matrix, parent_bone_size=1, force_connect_children=False):
|
def build_skeleton(self, arm, parent_matrix, settings, parent_bone_size=1):
|
||||||
def child_connect(par_bone, child_bone, child_head, connect_ctx):
|
def child_connect(par_bone, child_bone, child_head, connect_ctx):
|
||||||
# child_bone or child_head may be None.
|
# child_bone or child_head may be None.
|
||||||
force_connect_children, connected = connect_ctx
|
force_connect_children, connected = connect_ctx
|
||||||
@ -2246,6 +2255,9 @@ class FbxImportHelperNode:
|
|||||||
self.bl_obj = arm.bl_obj
|
self.bl_obj = arm.bl_obj
|
||||||
self.bl_data = arm.bl_data
|
self.bl_data = arm.bl_data
|
||||||
self.bl_bone = bone.name # Could be different from the FBX name!
|
self.bl_bone = bone.name # Could be different from the FBX name!
|
||||||
|
# Read EditBone custom props the NodeAttribute
|
||||||
|
if settings.use_custom_props and self.fbx_data_elem:
|
||||||
|
blen_read_custom_properties(self.fbx_data_elem, bone, settings)
|
||||||
|
|
||||||
# get average distance to children
|
# get average distance to children
|
||||||
bone_size = 0.0
|
bone_size = 0.0
|
||||||
@ -2274,6 +2286,7 @@ class FbxImportHelperNode:
|
|||||||
# while Blender attaches to the tail.
|
# while Blender attaches to the tail.
|
||||||
self.bone_child_matrix = Matrix.Translation(-bone_tail)
|
self.bone_child_matrix = Matrix.Translation(-bone_tail)
|
||||||
|
|
||||||
|
force_connect_children = settings.force_connect_children
|
||||||
connect_ctx = [force_connect_children, ...]
|
connect_ctx = [force_connect_children, ...]
|
||||||
for child in self.children:
|
for child in self.children:
|
||||||
if child.is_leaf and force_connect_children:
|
if child.is_leaf and force_connect_children:
|
||||||
@ -2282,8 +2295,7 @@ class FbxImportHelperNode:
|
|||||||
child_head = (bone_matrix @ child.get_bind_matrix().normalized()).translation
|
child_head = (bone_matrix @ child.get_bind_matrix().normalized()).translation
|
||||||
child_connect(bone, None, child_head, connect_ctx)
|
child_connect(bone, None, child_head, connect_ctx)
|
||||||
elif child.is_bone and not child.ignore:
|
elif child.is_bone and not child.ignore:
|
||||||
child_bone = child.build_skeleton(arm, bone_matrix, bone_size,
|
child_bone = child.build_skeleton(arm, bone_matrix, settings, bone_size)
|
||||||
force_connect_children=force_connect_children)
|
|
||||||
# Connection to parent.
|
# Connection to parent.
|
||||||
child_connect(bone, child_bone, None, connect_ctx)
|
child_connect(bone, child_bone, None, connect_ctx)
|
||||||
|
|
||||||
@ -2378,15 +2390,18 @@ class FbxImportHelperNode:
|
|||||||
|
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
def set_pose_matrix(self, arm):
|
def set_pose_matrix_and_custom_props(self, arm, settings):
|
||||||
pose_bone = arm.bl_obj.pose.bones[self.bl_bone]
|
pose_bone = arm.bl_obj.pose.bones[self.bl_bone]
|
||||||
pose_bone.matrix_basis = self.get_bind_matrix().inverted_safe() @ self.get_matrix()
|
pose_bone.matrix_basis = self.get_bind_matrix().inverted_safe() @ self.get_matrix()
|
||||||
|
|
||||||
|
if settings.use_custom_props:
|
||||||
|
blen_read_custom_properties(self.fbx_elem, pose_bone, settings)
|
||||||
|
|
||||||
for child in self.children:
|
for child in self.children:
|
||||||
if child.ignore:
|
if child.ignore:
|
||||||
continue
|
continue
|
||||||
if child.is_bone:
|
if child.is_bone:
|
||||||
child.set_pose_matrix(arm)
|
child.set_pose_matrix_and_custom_props(arm, settings)
|
||||||
|
|
||||||
def merge_weights(self, combined_weights, fbx_cluster):
|
def merge_weights(self, combined_weights, fbx_cluster):
|
||||||
indices = elem_prop_first(elem_find_first(fbx_cluster, b'Indexes', default=None), default=())
|
indices = elem_prop_first(elem_find_first(fbx_cluster, b'Indexes', default=None), default=())
|
||||||
@ -2482,18 +2497,18 @@ class FbxImportHelperNode:
|
|||||||
if child.ignore:
|
if child.ignore:
|
||||||
continue
|
continue
|
||||||
if child.is_bone:
|
if child.is_bone:
|
||||||
child.build_skeleton(self, Matrix(), force_connect_children=settings.force_connect_children)
|
child.build_skeleton(self, Matrix(), settings)
|
||||||
|
|
||||||
bpy.ops.object.mode_set(mode='OBJECT')
|
bpy.ops.object.mode_set(mode='OBJECT')
|
||||||
|
|
||||||
arm.hide_viewport = is_hidden
|
arm.hide_viewport = is_hidden
|
||||||
|
|
||||||
# Set pose matrix
|
# Set pose matrix and PoseBone custom properties
|
||||||
for child in self.children:
|
for child in self.children:
|
||||||
if child.ignore:
|
if child.ignore:
|
||||||
continue
|
continue
|
||||||
if child.is_bone:
|
if child.is_bone:
|
||||||
child.set_pose_matrix(self)
|
child.set_pose_matrix_and_custom_props(self, settings)
|
||||||
|
|
||||||
# Add bone children:
|
# Add bone children:
|
||||||
for child in self.children:
|
for child in self.children:
|
||||||
@ -2888,7 +2903,7 @@ def load(operator, context, filepath="",
|
|||||||
continue
|
continue
|
||||||
if fbx_obj.props[-1] == b'Camera':
|
if fbx_obj.props[-1] == b'Camera':
|
||||||
assert(blen_data is None)
|
assert(blen_data is None)
|
||||||
fbx_item[1] = blen_read_camera(fbx_tmpl, fbx_obj, global_scale)
|
fbx_item[1] = blen_read_camera(fbx_tmpl, fbx_obj, settings)
|
||||||
_(); del _
|
_(); del _
|
||||||
|
|
||||||
# ----
|
# ----
|
||||||
@ -2902,7 +2917,7 @@ def load(operator, context, filepath="",
|
|||||||
continue
|
continue
|
||||||
if fbx_obj.props[-1] == b'Light':
|
if fbx_obj.props[-1] == b'Light':
|
||||||
assert(blen_data is None)
|
assert(blen_data is None)
|
||||||
fbx_item[1] = blen_read_light(fbx_tmpl, fbx_obj, global_scale)
|
fbx_item[1] = blen_read_light(fbx_tmpl, fbx_obj, settings)
|
||||||
_(); del _
|
_(); del _
|
||||||
|
|
||||||
# ----
|
# ----
|
||||||
@ -2971,6 +2986,9 @@ def load(operator, context, filepath="",
|
|||||||
if fbx_sdata.id not in {b'Geometry', b'NodeAttribute'}:
|
if fbx_sdata.id not in {b'Geometry', b'NodeAttribute'}:
|
||||||
continue
|
continue
|
||||||
parent.bl_data = bl_data
|
parent.bl_data = bl_data
|
||||||
|
if bl_data is None:
|
||||||
|
# If there's no bl_data, add the fbx_sdata so that it can be read when creating the bl_data/bone
|
||||||
|
parent.fbx_data_elem = fbx_sdata
|
||||||
else:
|
else:
|
||||||
# set parent
|
# set parent
|
||||||
child.parent = parent
|
child.parent = parent
|
||||||
|
Loading…
Reference in New Issue
Block a user