def gather_animation_channel_target( action_group: bpy.types.ActionGroup, blender_object: bpy.types.Object, export_settings) -> gltf2_io.AnimationChannelTarget: return gltf2_io.AnimationChannelTarget( extensions=__gather_extensions(action_group, blender_object, export_settings), extras=__gather_extras(action_group, blender_object, export_settings), node=__gather_node(action_group, blender_object, export_settings), path=__gather_path(action_group, blender_object, export_settings))
def gather_animation_channel_target(channels: typing.Tuple[bpy.types.FCurve], blender_object: bpy.types.Object, export_settings ) -> gltf2_io.AnimationChannelTarget: return gltf2_io.AnimationChannelTarget( extensions=__gather_extensions(channels, blender_object, export_settings), extras=__gather_extras(channels, blender_object, export_settings), node=__gather_node(channels, blender_object, export_settings), path=__gather_path(channels, blender_object, export_settings) )
def gather_animation_channel_target( channels: typing.Tuple[bpy.types.FCurve], blender_object: bpy.types.Object, bake_bone: typing.Union[str, None], bake_channel: typing.Union[str, None], driver_obj, export_settings) -> gltf2_io.AnimationChannelTarget: animation_channel_target = gltf2_io.AnimationChannelTarget( extensions=__gather_extensions(channels, blender_object, export_settings, bake_bone), extras=__gather_extras(channels, blender_object, export_settings, bake_bone), node=__gather_node(channels, blender_object, export_settings, bake_bone, driver_obj), path=__gather_path(channels, blender_object, export_settings, bake_bone, bake_channel)) export_user_extensions('gather_animation_channel_target_hook', export_settings, animation_channel_target, channels, blender_object, bake_bone, bake_channel) return animation_channel_target
def __gather_animation(pre_anim, nodes, export_settings): anim_name, (frame_start, frame_end) = pre_anim print(f'exporting animation track {anim_name}') # Star all the tracks named anim_name. Objects without an anim_name # track are considered unanimated. Star the empty temp track for those. anim_nodes = [] for node in nodes: if node.__blender_data[0] != 'OBJECT' and node.__blender_data[ 0] != 'BONE': continue ob = node.__blender_data[1] if not ob.animation_data: continue for track in ob.animation_data.nla_tracks: if track.name == anim_name: track.is_solo = True if ob.type == 'ARMATURE' and node.__blender_data[0] == 'BONE': # only append bones that are animated in current anim actions = __get_blender_actions(ob) for action in actions: if action[1] == anim_name: for fcurve in action[0].fcurves: bone_path = fcurve.data_path.rpartition('.')[0] bone = ob.path_resolve(bone_path) if node.name == bone.name: if node not in anim_nodes: anim_nodes.append(node) else: anim_nodes.append(node) break else: if node.__blender_data[0] == 'OBJECT': node.__temp_nla_track.is_solo = True f_start = math.floor(frame_start) f_end = math.ceil(frame_end) + 1 f_step = export_settings['gltf_frame_step'] # Stores TRS values for each node at each frame data = {} data['translation'] = [[] for _node in nodes] data['rotation'] = [[] for _node in nodes] data['scale'] = [[] for _node in nodes] for f in range(f_start, f_end, f_step): bpy.context.scene.frame_set(f) for i, node in enumerate(anim_nodes): if node.__blender_data[0] == 'OBJECT': t, r, s = __get_gltf_trs_from_object(node.__blender_data[1], export_settings) elif node.__blender_data[0] == 'BONE': arma_ob = node.__blender_data[1] pbone = arma_ob.pose.bones[node.__blender_data[2]] t, r, s = __get_gltf_trs_from_bone(pbone, export_settings) else: assert False data['translation'][i].append(t) data['rotation'][i].append(r) data['scale'][i].append(s) # Put it all together to get the glTF animation channels = [] samplers = [] for i, node in enumerate(anim_nodes): # Get paths used in the NLA track actions = __get_blender_actions(node.__blender_data[1]) paths = [] pathTypes = { 'delta_location': 'translation', 'delta_rotation_euler': 'rotation', 'location': 'translation', 'rotation_axis_angle': 'rotation', 'rotation_euler': 'rotation', 'rotation_quaternion': 'rotation', 'scale': 'scale' } for action in actions: if action[1] == anim_name: for fcurve in action[0].fcurves: data_path = fcurve.data_path if node.__blender_data[0] == 'OBJECT': paths.append(pathTypes.get(data_path)) else: # for armatures paths.append( pathTypes.get(data_path.rpartition('.')[2])) for path in ['translation', 'rotation', 'scale']: if path in paths: sampler = gltf2_io.AnimationSampler( input=__get_keyframe_accessor(f_start, f_end, f_step), output=__encode_output_accessor(data[path][i], path), interpolation='LINEAR', extensions=None, extras=None, ) samplers.append(sampler) channel = gltf2_io.AnimationChannel( sampler=len(samplers) - 1, target=gltf2_io.AnimationChannelTarget( node=node, path=path, extensions=None, extras=None, ), extensions=None, extras=None, ) channels.append(channel) animation = gltf2_io.Animation( name=anim_name, channels=channels, samplers=samplers, extensions=None, extras=None, ) return animation