def __gather_animation_channel(channels: typing.Tuple[bpy.types.FCurve], blender_object: bpy.types.Object, export_settings, bake_bone: typing.Union[str, None], bake_channel: typing.Union[str, None], bake_range_start, bake_range_end, action_name: str, driver_obj ) -> typing.Union[gltf2_io.AnimationChannel, None]: if not __filter_animation_channel(channels, blender_object, export_settings): return None animation_channel = gltf2_io.AnimationChannel( extensions=__gather_extensions(channels, blender_object, export_settings, bake_bone), extras=__gather_extras(channels, blender_object, export_settings, bake_bone), sampler=__gather_sampler(channels, blender_object, export_settings, bake_bone, bake_channel, bake_range_start, bake_range_end, action_name, driver_obj), target=__gather_target(channels, blender_object, export_settings, bake_bone, bake_channel, driver_obj) ) export_user_extensions('gather_animation_channel_hook', export_settings, animation_channel, channels, blender_object, bake_bone, bake_channel, bake_range_start, bake_range_end, action_name) return animation_channel
def __gather_animation_channel(channels: typing.Tuple[bpy.types.FCurve], blender_object: bpy.types.Object, export_settings ) -> typing.Union[gltf2_io.AnimationChannel, None]: if not __filter_animation_channel(channels, blender_object, export_settings): return None return gltf2_io.AnimationChannel( extensions=__gather_extensions(channels, blender_object, export_settings), extras=__gather_extras(channels, blender_object, export_settings), sampler=__gather_sampler(channels, blender_object, export_settings), target=__gather_target(channels, blender_object, export_settings) )
def __gather_animation_channel(channels: typing.Tuple[bpy.types.FCurve], blender_object: bpy.types.Object, export_settings, bake_bone: typing.Union[str, None], bake_channel: typing.Union[str, None], bake_range_start, bake_range_end, force_range: bool, action_name: str, driver_obj, node_channel_is_animated: bool ) -> typing.Union[gltf2_io.AnimationChannel, None]: if not __filter_animation_channel(channels, blender_object, export_settings): return None __target= __gather_target(channels, blender_object, export_settings, bake_bone, bake_channel, driver_obj) if __target.path is not None: sampler = __gather_sampler(channels, blender_object, export_settings, bake_bone, bake_channel, bake_range_start, bake_range_end, force_range, action_name, driver_obj, node_channel_is_animated) if sampler is None: # After check, no need to animate this node for this channel return None animation_channel = gltf2_io.AnimationChannel( extensions=__gather_extensions(channels, blender_object, export_settings, bake_bone), extras=__gather_extras(channels, blender_object, export_settings, bake_bone), sampler=sampler, target=__target ) export_user_extensions('gather_animation_channel_hook', export_settings, animation_channel, channels, blender_object, bake_bone, bake_channel, bake_range_start, bake_range_end, action_name) return animation_channel return None
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