Skip to content

Commit

Permalink
New exporter option: Export only key frames (#127)
Browse files Browse the repository at this point in the history
The exporter will now only export key frames of an animation.
  • Loading branch information
oldmanauz authored Sep 30, 2021
1 parent 3ea4257 commit 3952f5e
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 6 deletions.
3 changes: 3 additions & 0 deletions SkeletalAnimation.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,11 @@ So what the exporter does is go frame by frame and have Blender calculate the bo
This means that your animation in Ogre has a keyframe for every single frame from the start of the animation to the end.
As a result of this setting IM_SPLINE for frame interpolation in Ogre would make no difference and might even slow down the skeletal animation.

If you only require key frames exported, then make sure the "Only Keyframes" option is ticked in the exporter properties.

## Exporter Options:
- *EX_ARMATURE_ANIMATION* (Armature Animation) : Export armature animations (updates the .skeleton file), enable this option to export the armature animations.
- *EX_ONLY_KEYFRAMES* (Only Keyframes) : Exports only the key frames. Influences that Inverse Kinematics, Drivers and modified F-Curves have on the animation will be lost.
- *EX_ONLY_DEFORMABLE_BONES* (Only Deformable Bones) : Only exports bones that are deformable. Useful for hiding IK-Bones used in Blender. NOTE: Any bone with deformable children/descendants will be output as well
- *EX_ONLY_KEYFRAMED_BONES* (Only Keyframed Bones) : Only exports bones that have been keyframed for a given animation. Useful to limit the set of bones on a per-animation basis
- *EX_OGRE_INHERIT_SCALE* (OGRE Inherit Scale) : Whether the OGRE bones have the 'inherit scale' flag on. If the animation has scale in it, the exported animation needs to be adjusted to account for the state of the inherit-scale flag in OGRE.
Expand Down
1 change: 1 addition & 0 deletions io_ogre/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
'OGRE_INHERIT_SCALE' : False,
'ARMATURE_ANIMATION' : True,
'TRIM_BONE_WEIGHTS' : 0.01,
'ONLY_KEYFRAMES' : False,

# Mesh
'MESH' : True,
Expand Down
39 changes: 35 additions & 4 deletions io_ogre/ogre/skeleton.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@

logger = logging.getLogger('skeleton')

# Function exports the Ogre .skeleton file
# Called from ogre/scene.py > dot_scene_node_export() function
def dot_skeleton(obj, path, **kwargs):
"""
Create the .skeleton file for this object.
Expand Down Expand Up @@ -374,13 +376,31 @@ def write_animation( self, arm, actionName, frameBegin, frameEnd, doc, parentEle
if bone.shouldOutput:
bone_tracks.append( Bone_Track(bone) )
bone.clear_pose_transform() # clear out any leftover pose transforms in case this bone isn't keyframed
for frame in range( int(frameBegin), int(frameEnd)+1, bpy.context.scene.frame_step):#thanks to Vesa

# Decide keyframes to export:
# ONLY keyframes (Exported animation won't be affected by Inverse Kinematics, Drivers and modified F-Curves)
# OR export keyframe each frame over animation range (Exported animation will be affected by Inverse Kinematics, Drivers and modified F-Curves)
if config.get('ONLY_KEYFRAMES'): # Only keyframes
frame_range = [] # Holds a list of keyframes for export
action = bpy.data.actions[actionName] # actionName is the animation name (NLAtrack child)
# loops through all channels on the f-curve --> Code taken from: https://blender.stackexchange.com/questions/8387/how-to-get-keyframe-data-from-python
for fcu in action.fcurves:
for keyframe in fcu.keyframe_points: # Loops through all the keyframes in the channel
kf = keyframe.co[0] # key frame number
if kf not in frame_range: # only add the key frames in once. Keyframes repeat in different channels
frame_range.append(kf)
else: # Keyframes each frame
frame_range = range( int(frameBegin), int(frameEnd)+1, bpy.context.scene.frame_step) #thanks to Vesa, NOTE: frame_step is [( # of frames / FPS ) / # of frames ] -- I think??

# Add keyframes to export
for frame in frame_range:
bpy.context.scene.frame_set(frame)
for bone in self.roots:
bone.update()
for track in bone_tracks:
track.add_keyframe((frame - frameBegin) / _fps)
# check to see if any animation tracks would be output

# Check to see if any animation tracks would be output
animationFound = False
for track in bone_tracks:
if track.is_pos_animated() or track.is_rot_animated() or track.is_scale_animated():
Expand All @@ -392,8 +412,15 @@ def write_animation( self, arm, actionName, frameBegin, frameEnd, doc, parentEle
parentElement.appendChild( anim )
tracks = doc.createElement('tracks')
anim.appendChild( tracks )
Report.armature_animations.append( '%s : %s [start frame=%s end frame=%s]' %(arm.name, actionName, frameBegin, frameEnd) )


# Report and log
suffix_text = ''
if config.get('ONLY_KEYFRAMES'):
suffix_text = ' - Key frames: ' + str(key_frame_numbers)
logger.info('+ %s Key frames: %s' %(actionName,str(key_frame_numbers)))
Report.armature_animations.append( '%s : %s [start frame=%s end frame=%s]%s' %(arm.name, actionName, frameBegin, frameEnd,suffix_text) )

# Write stuff to skeleton.xml file
anim.setAttribute('name', actionName) # USE the action name
anim.setAttribute('length', '%6f' %( (frameEnd - frameBegin)/_fps ) )

Expand Down Expand Up @@ -460,6 +487,10 @@ def to_xml( self ):
if not len( arm.animation_data.nla_tracks ):
Report.warnings.append('You must assign an NLA strip to armature (%s) that defines the start and end frames' % arm.name)

# Log to console
if config.get('ONLY_KEYFRAMES'):
logger.info('+ Only exporting keyframes')

actions = {} # actions by name
# the only thing NLA is used for is to gather the names of the actions
# it doesn't matter if the actions are all in the same NLA track or in different tracks
Expand Down
8 changes: 6 additions & 2 deletions io_ogre/ui/export.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ def draw(self, context):
"Scene" : ["EX_SCENE", "EX_SELECTED_ONLY", "EX_EXPORT_HIDDEN", "EX_FORCE_CAMERA", "EX_FORCE_LAMPS", "EX_NODE_ANIMATION"],
"Materials" : ["EX_MATERIALS", "EX_SEPARATE_MATERIALS", "EX_COPY_SHADER_PROGRAMS"],
"Textures" : ["EX_DDS_MIPS", "EX_FORCE_IMAGE_FORMAT"],
"Armature" : ["EX_ARMATURE_ANIMATION", "EX_ONLY_DEFORMABLE_BONES", "EX_ONLY_KEYFRAMED_BONES", "EX_OGRE_INHERIT_SCALE", "EX_TRIM_BONE_WEIGHTS"],
"Armature" : ["EX_ARMATURE_ANIMATION", "EX_ONLY_KEYFRAMES", "EX_ONLY_DEFORMABLE_BONES", "EX_ONLY_KEYFRAMED_BONES", "EX_OGRE_INHERIT_SCALE", "EX_TRIM_BONE_WEIGHTS"],
"Mesh" : ["EX_MESH", "EX_MESH_OVERWRITE", "EX_V1_EXTREMITY_POINTS", "EX_Vx_GENERATE_EDGE_LISTS", "EX_GENERATE_TANGENTS", "EX_Vx_OPTIMISE_ANIMATIONS", "EX_V2_OPTIMISE_VERTEX_BUFFERS", "EX_V2_OPTIMISE_VERTEX_BUFFERS_OPTIONS"],
"LOD" : ["EX_LOD_LEVELS", "EX_LOD_DISTANCE", "EX_LOD_PERCENT", "EX_LOD_MESH_TOOLS"],
"Shape Animation" : ["EX_SHAPE_ANIMATIONS", "EX_SHAPE_NORMALS"],
Expand Down Expand Up @@ -165,7 +165,7 @@ def execute(self, context):
kw[ name[3:] ] = getattr(self,name)
config.update(**kw)

print ("_" * 80)
print ("_" * 80,"\n")

target_path, target_file_name = os.path.split(os.path.abspath(self.filepath))
target_file_name = clean_object_name(target_file_name)
Expand Down Expand Up @@ -311,6 +311,10 @@ def execute(self, context):
name="Armature Animation",
description="Export armature animations (updates the .skeleton file)",
default=config.get('ARMATURE_ANIMATION')) = {}
EX_ONLY_KEYFRAMES : BoolProperty(
name="Only Keyframes",
description="Only export keyframes.\nNOTE: Exported animation won't be affected by Inverse Kinematics, Drivers and modified F-Curves",
default=config.get('ONLY_KEYFRAMES')) = {}
EX_ONLY_DEFORMABLE_BONES : BoolProperty(
name="Only Deformable Bones",
description="Only exports bones that are deformable. Useful for hiding IK-Bones used in Blender.\nNOTE: Any bone with deformable children/descendants will be output as well",
Expand Down

0 comments on commit 3952f5e

Please sign in to comment.