FBX IO: Speed up transformation animation import #104870
@ -526,7 +526,8 @@ def blen_read_object_transform_preprocess(fbx_props, fbx_obj, rot_alt_mat, use_p
|
|||||||
|
|
||||||
# ---------
|
# ---------
|
||||||
# Animation
|
# Animation
|
||||||
def _blen_read_object_transform_do_anim(transform_data, lcl_translation_mat, lcl_rot_euler, lcl_scale_mat):
|
def _blen_read_object_transform_do_anim(transform_data, lcl_translation_mat, lcl_rot_euler, lcl_scale_mat,
|
||||||
|
extra_pre_matrix, extra_post_matrix):
|
||||||
"""Specialized version of blen_read_object_transform_do for animation that pre-calculates the non-animated matrices
|
"""Specialized version of blen_read_object_transform_do for animation that pre-calculates the non-animated matrices
|
||||||
and returns a function that returns base_mat @ geom_mat.
|
and returns a function that returns base_mat @ geom_mat.
|
||||||
|
|
||||||
@ -561,19 +562,30 @@ def _blen_read_object_transform_do_anim(transform_data, lcl_translation_mat, lcl
|
|||||||
|
|
||||||
post_lcl_translation = rot_ofs @ rot_piv @ pre_rot
|
post_lcl_translation = rot_ofs @ rot_piv @ pre_rot
|
||||||
post_lcl_rotation = transform_data.rot_alt_mat @ pst_rot_inv @ rot_piv_inv @ sca_ofs @ sca_piv
|
post_lcl_rotation = transform_data.rot_alt_mat @ pst_rot_inv @ rot_piv_inv @ sca_ofs @ sca_piv
|
||||||
post_lcl_scaling = sca_piv_inv @ geom_mat
|
post_lcl_scaling = sca_piv_inv @ geom_mat @ extra_post_matrix
|
||||||
|
|
||||||
# Get the bound to_matrix method to avoid re-binding it on each call.
|
# Get the bound to_matrix method to avoid re-binding it on each call.
|
||||||
lcl_rot_to_matrix = lcl_rot_euler.to_matrix
|
lcl_rot_to_matrix = lcl_rot_euler.to_matrix
|
||||||
# Get the unbound Matrix.to_4x4 method to avoid having to look it up again on each call.
|
# Get the unbound Matrix.to_4x4 method to avoid having to look it up again on each call.
|
||||||
matrix_to_4x4 = Matrix.to_4x4
|
matrix_to_4x4 = Matrix.to_4x4
|
||||||
|
|
||||||
return lambda: (lcl_translation_mat @
|
if extra_pre_matrix != Matrix():
|
||||||
post_lcl_translation @
|
# There aren't any other matrices that must be multiplied before lcl_translation_mat that extra_pre_matrix can
|
||||||
matrix_to_4x4(lcl_rot_to_matrix()) @
|
# be combined with, so a separate lambda is required.
|
||||||
post_lcl_rotation @
|
return lambda: (extra_pre_matrix @
|
||||||
lcl_scale_mat @
|
lcl_translation_mat @
|
||||||
post_lcl_scaling)
|
post_lcl_translation @
|
||||||
|
matrix_to_4x4(lcl_rot_to_matrix()) @
|
||||||
|
post_lcl_rotation @
|
||||||
|
lcl_scale_mat @
|
||||||
|
post_lcl_scaling)
|
||||||
|
else:
|
||||||
|
return lambda: (lcl_translation_mat @
|
||||||
|
post_lcl_translation @
|
||||||
|
matrix_to_4x4(lcl_rot_to_matrix()) @
|
||||||
|
post_lcl_rotation @
|
||||||
|
lcl_scale_mat @
|
||||||
|
post_lcl_scaling)
|
||||||
|
|
||||||
|
|
||||||
def _transformation_curves_gen(item, values_arrays, channel_keys):
|
def _transformation_curves_gen(item, values_arrays, channel_keys):
|
||||||
@ -597,8 +609,22 @@ def _transformation_curves_gen(item, values_arrays, channel_keys):
|
|||||||
rot_eul_prev = bl_obj.rotation_euler.copy()
|
rot_eul_prev = bl_obj.rotation_euler.copy()
|
||||||
rot_quat_prev = bl_obj.rotation_quaternion.copy()
|
rot_quat_prev = bl_obj.rotation_quaternion.copy()
|
||||||
|
|
||||||
# Pre-compute inverted local rest matrix of the bone, if relevant.
|
# Pre-compute combined pre matrix
|
||||||
restmat_inv = item.get_bind_matrix().inverted_safe() if item.is_bone else None
|
# Remove that rest pose matrix from current matrix (also in parent space) by computing the inverted local rest
|
||||||
|
# matrix of the bone, if relevant.
|
||||||
|
combined_pre_matrix = item.get_bind_matrix().inverted_safe() if item.is_bone else Matrix()
|
||||||
|
|
||||||
|
# pre-matrix will contain any correction for a parent's correction matrix or the global matrix
|
||||||
|
if item.pre_matrix:
|
||||||
|
combined_pre_matrix @= item.pre_matrix
|
||||||
|
|
||||||
|
# Pre-compute combined post matrix
|
||||||
|
# compensate for changes in the local matrix during processing
|
||||||
|
combined_post_matrix = item.anim_compensation_matrix if item.anim_compensation_matrix else Matrix()
|
||||||
|
|
||||||
|
# post-matrix will contain any correction for lights, camera and bone orientation
|
||||||
|
if item.post_matrix:
|
||||||
|
combined_post_matrix @= item.post_matrix
|
||||||
|
|
||||||
# Create matrices/euler from the initial transformation values of this item.
|
# Create matrices/euler from the initial transformation values of this item.
|
||||||
# These variables will be updated in-place as we iterate through each frame.
|
# These variables will be updated in-place as we iterate through each frame.
|
||||||
@ -634,23 +660,12 @@ def _transformation_curves_gen(item, values_arrays, channel_keys):
|
|||||||
# .data, the memoryview of an np.ndarray, is faster to iterate than the ndarray itself.
|
# .data, the memoryview of an np.ndarray, is faster to iterate than the ndarray itself.
|
||||||
frame_values_it = zip(*(arr.data for arr in values_arrays_converted))
|
frame_values_it = zip(*(arr.data for arr in values_arrays_converted))
|
||||||
|
|
||||||
# Pre-get/calculate these to slightly reduce the work done inside the loop.
|
|
||||||
anim_compensation_matrix = item.anim_compensation_matrix
|
|
||||||
do_anim_compensation_matrix = bool(anim_compensation_matrix)
|
|
||||||
|
|
||||||
pre_matrix = item.pre_matrix
|
|
||||||
do_pre_matrix = bool(pre_matrix)
|
|
||||||
|
|
||||||
post_matrix = item.post_matrix
|
|
||||||
do_post_matrix = bool(post_matrix)
|
|
||||||
|
|
||||||
do_restmat_inv = bool(restmat_inv)
|
|
||||||
|
|
||||||
decompose = Matrix.decompose
|
decompose = Matrix.decompose
|
||||||
to_axis_angle = Quaternion.to_axis_angle
|
to_axis_angle = Quaternion.to_axis_angle
|
||||||
to_euler = Quaternion.to_euler
|
to_euler = Quaternion.to_euler
|
||||||
|
|
||||||
calc_mat = _blen_read_object_transform_do_anim(transform_data, translation_matrix, rotation_euler, scaling_matrix)
|
calc_mat = _blen_read_object_transform_do_anim(transform_data, translation_matrix, rotation_euler, scaling_matrix,
|
||||||
|
combined_pre_matrix, combined_post_matrix)
|
||||||
|
|
||||||
# Iterate through the values for each frame.
|
# Iterate through the values for each frame.
|
||||||
for frame_values in frame_values_it:
|
for frame_values in frame_values_it:
|
||||||
@ -661,22 +676,6 @@ def _transformation_curves_gen(item, values_arrays, channel_keys):
|
|||||||
# Calculate the updated matrix for this frame.
|
# Calculate the updated matrix for this frame.
|
||||||
mat = calc_mat()
|
mat = calc_mat()
|
||||||
|
|
||||||
# compensate for changes in the local matrix during processing
|
|
||||||
if do_anim_compensation_matrix:
|
|
||||||
mat = mat @ anim_compensation_matrix
|
|
||||||
|
|
||||||
# apply pre- and post matrix
|
|
||||||
# post-matrix will contain any correction for lights, camera and bone orientation
|
|
||||||
# pre-matrix will contain any correction for a parent's correction matrix or the global matrix
|
|
||||||
if do_pre_matrix:
|
|
||||||
mat = pre_matrix @ mat
|
|
||||||
if do_post_matrix:
|
|
||||||
mat = mat @ post_matrix
|
|
||||||
|
|
||||||
# And now, remove that rest pose matrix from current mat (also in parent space).
|
|
||||||
if do_restmat_inv:
|
|
||||||
mat = restmat_inv @ mat
|
|
||||||
|
|
||||||
# Now we have a virtual matrix of transform from AnimCurves, we can yield keyframe values!
|
# Now we have a virtual matrix of transform from AnimCurves, we can yield keyframe values!
|
||||||
loc, rot, sca = decompose(mat)
|
loc, rot, sca = decompose(mat)
|
||||||
if rot_mode == 'QUATERNION':
|
if rot_mode == 'QUATERNION':
|
||||||
|
Loading…
Reference in New Issue
Block a user