This commit is contained in:
2026-05-17 10:53:44 -07:00
parent 857e0f1e62
commit edec5e56fb

View File

@ -276,10 +276,22 @@ class LeenkxExporter:
if armature.animation_data: if armature.animation_data:
action = armature.animation_data.action action = armature.animation_data.action
if action: if action:
return [fcurve for fcurve in action.fcurves if fcurve.data_path.startswith(path)] fcurves = LeenkxExporter.get_action_fcurves(action, armature.animation_data)
return [fcurve for fcurve in fcurves if fcurve.data_path.startswith(path)]
return [] return []
@staticmethod
def get_action_fcurves(action: bpy.types.Action, anim_data: Optional[bpy.types.AnimData] = None) -> List[bpy.types.FCurve]:
if bpy.app.version >= (5, 0, 0):
if anim_data and anim_data.action_slot:
from bpy_extras import anim_utils
channelbag = anim_utils.action_ensure_channelbag_for_slot(action, anim_data.action_slot)
return channelbag.fcurves if channelbag else []
return []
else:
return action.fcurves
def export_bone(self, armature, bone: bpy.types.Bone, o, action: bpy.types.Action): def export_bone(self, armature, bone: bpy.types.Bone, o, action: bpy.types.Action):
rpdat = lnx.utils.get_rp() rpdat = lnx.utils.get_rp()
bobject_ref = self.bobject_bone_array.get(bone) bobject_ref = self.bobject_bone_array.get(bone)
@ -319,7 +331,7 @@ class LeenkxExporter:
oanim['root_motion_rot'] = action.lnx_root_motion_rot oanim['root_motion_rot'] = action.lnx_root_motion_rot
@staticmethod @staticmethod
def calculate_anim_frame_range(action: bpy.types.Action) -> Tuple[int, int]: def calculate_anim_frame_range(action: bpy.types.Action, anim_data: Optional[bpy.types.AnimData] = None) -> Tuple[int, int]:
"""Calculates the required frame range of the given action by """Calculates the required frame range of the given action by
also taking fcurve modifiers into account. also taking fcurve modifiers into account.
@ -330,14 +342,16 @@ class LeenkxExporter:
start = frame_range[0] start = frame_range[0]
end = frame_range[1] end = frame_range[1]
fcurves = LeenkxExporter.get_action_fcurves(action, anim_data)
# Blender 4.0+ compatibility: Handle zero-length frame ranges # Blender 4.0+ compatibility: Handle zero-length frame ranges
if start == end: if start == end:
start = 1 start = 1
end = 2 end = 2
if action.fcurves: if fcurves:
all_keyframes = [] all_keyframes = []
for fcurve in action.fcurves: for fcurve in fcurves:
if fcurve.keyframe_points: if fcurve.keyframe_points:
for keyframe in fcurve.keyframe_points: for keyframe in fcurve.keyframe_points:
all_keyframes.append(keyframe.co[0]) all_keyframes.append(keyframe.co[0])
@ -350,7 +364,7 @@ class LeenkxExporter:
# Take FCurve modifiers into account if they have a restricted # Take FCurve modifiers into account if they have a restricted
# frame range # frame range
for fcurve in action.fcurves: for fcurve in fcurves:
for modifier in fcurve.modifiers: for modifier in fcurve.modifiers:
if not modifier.use_restricted_range: if not modifier.use_restricted_range:
continue continue
@ -404,7 +418,7 @@ class LeenkxExporter:
o['object_actions'] = [] o['object_actions'] = []
o['object_actions'].append('action_' + action_name + ext) o['object_actions'].append('action_' + action_name + ext)
frame_range = self.calculate_anim_frame_range(action) frame_range = self.calculate_anim_frame_range(action, bobject.animation_data)
out_anim = { out_anim = {
'begin': frame_range[0], 'begin': frame_range[0],
'end': frame_range[1], 'end': frame_range[1],
@ -414,7 +428,8 @@ class LeenkxExporter:
self.export_pose_markers(out_anim, action) self.export_pose_markers(out_anim, action)
unresolved_data_paths = set() unresolved_data_paths = set()
for fcurve in action.fcurves: fcurves = self.get_action_fcurves(action, bobject.animation_data)
for fcurve in fcurves:
data_path = fcurve.data_path data_path = fcurve.data_path
try: try:
@ -535,7 +550,7 @@ class LeenkxExporter:
fcurve_list = self.collect_bone_animation(armature, bone.name) fcurve_list = self.collect_bone_animation(armature, bone.name)
if fcurve_list and pose_bone: if fcurve_list and pose_bone:
begin_frame, end_frame = self.calculate_anim_frame_range(action) begin_frame, end_frame = self.calculate_anim_frame_range(action, armature.animation_data)
out_track = {'target': "transform", 'frames': [], 'values': []} out_track = {'target': "transform", 'frames': [], 'values': []}
o['anim'] = {'tracks': [out_track]} o['anim'] = {'tracks': [out_track]}
@ -653,8 +668,8 @@ class LeenkxExporter:
return fov return fov
return None return None
def write_bone_matrices(self, scene, action): def write_bone_matrices(self, scene, action, anim_data: Optional[bpy.types.AnimData] = None):
begin_frame, end_frame = self.calculate_anim_frame_range(action) begin_frame, end_frame = self.calculate_anim_frame_range(action, anim_data)
if len(self.bone_tracks) > 0: if len(self.bone_tracks) > 0:
hidden_states = {} hidden_states = {}
try: try:
@ -807,7 +822,8 @@ class LeenkxExporter:
# if (shapeKeys.animation_data): # if (shapeKeys.animation_data):
# action = shapeKeys.animation_data.action # action = shapeKeys.animation_data.action
# if (action): # if (action):
# for fcurve in action.fcurves: # fcurves = self.get_action_fcurves(action, shapeKeys.animation_data)
# for fcurve in fcurves:
# if ((fcurve.data_path.startswith("key_blocks[")) and (fcurve.data_path.endswith("].value"))): # if ((fcurve.data_path.startswith("key_blocks[")) and (fcurve.data_path.endswith("].value"))):
# keyName = fcurve.data_path.strip("abcdehklopstuvy[]_.") # keyName = fcurve.data_path.strip("abcdehklopstuvy[]_.")
# if ((keyName[0] == "\"") or (keyName[0] == "'")): # if ((keyName[0] == "\"") or (keyName[0] == "'")):
@ -822,7 +838,8 @@ class LeenkxExporter:
# if ((not action) and (node.animation_data)): # if ((not action) and (node.animation_data)):
# action = node.animation_data.action # action = node.animation_data.action
# if (action): # if (action):
# for fcurve in action.fcurves: # fcurves = self.get_action_fcurves(action, node.animation_data)
# for fcurve in fcurves:
# if ((fcurve.data_path.startswith("data.shape_keys.key_blocks[")) and (fcurve.data_path.endswith("].value"))): # if ((fcurve.data_path.startswith("data.shape_keys.key_blocks[")) and (fcurve.data_path.endswith("].value"))):
# keyName = fcurve.data_path.strip("abcdehklopstuvy[]_.") # keyName = fcurve.data_path.strip("abcdehklopstuvy[]_.")
# if ((keyName[0] == "\"") or (keyName[0] == "'")): # if ((keyName[0] == "\"") or (keyName[0] == "'")):
@ -1324,7 +1341,7 @@ class LeenkxExporter:
_bake_hidden[_obj] = False _bake_hidden[_obj] = False
_obj.hide_viewport = True _obj.hide_viewport = True
start, end = self.calculate_anim_frame_range(action) start, end = self.calculate_anim_frame_range(action, skelobj.animation_data)
bake_result = bpy.ops.nla.bake( bake_result = bpy.ops.nla.bake(
frame_start=start, frame_start=start,
@ -1361,7 +1378,7 @@ class LeenkxExporter:
boneo = {} boneo = {}
self.export_bone(skelobj, bone, boneo, action) self.export_bone(skelobj, bone, boneo, action)
bones.append(boneo) bones.append(boneo)
self.write_bone_matrices(bpy.context.scene, action) self.write_bone_matrices(bpy.context.scene, action, skelobj.animation_data)
if len(bones) > 0 and 'anim' in bones[0]: if len(bones) > 0 and 'anim' in bones[0]:
self.export_pose_markers(bones[0]['anim'], original_action) self.export_pose_markers(bones[0]['anim'], original_action)
self.export_root_motion(bones[0]['anim'], original_action) self.export_root_motion(bones[0]['anim'], original_action)