Jump to content

Parse / Serialize Animation Ranges


JCPalmer
 Share

Recommended Posts

I do not see where AnimationRanges can be placed in a .babylon file.  Just thinking out loud, but this might a method of implementing the export of Actions in Blender, which are also named.  I got 90% down the Mocap path using a .bvh, and am just making sure I am really going the right way.  (Questioning myself usually happens when I stopping on something for a while, holidays)

 

The really big reason I went the mocap route is to try to reduce say a 2 second walk @ 120 fps to maybe 5 poses, where the frame number indicates the relative amount of time to interpolate to each pose.  I have code which is starting to do that analysis.  Frame based animation is not scalable, because it "performs" the animation externally (pose>>Animation>>Bake Action) & the file size just explodes. I have no intention of using it.

 

I know Blender had a way of actually posing skeletons on just the key frames, but until I actually started playing with inverse kinematics, posing was impossible.

 

I have performed tests in python & can determine which frames the poses occur in an action.  I think I can @ the skeleton level:

  • iterate through the actions
  • get the key frames of an action
  • iterate through those frames
  • get the bone matrix of each bone

If going to a .babylon / BJS, just make sure every action was baked.  If going to .js / QueuedInterpolation, skip the bake.  Either way, both should able to get multiple animations via AnimationRanges if they can be put in a .babylon.  Also, right now the animation is captured by iterating through every frame in the scene for EVERY bone.  Blends with skeletal animation export very slowing.  One with a 32 bone skeleton should get a 32x speed up when exporting

 

If you have a skeleton you are going to use in a .blend all by itself, then you could add your actions to it.  You can then add those actions to any other .blend using File>>append.  This separates the animation from the character.

 

What am I thinking that is wrong?

Link to comment
Share on other sites

Ok, the range info would need to stored in skeleton during pass 1.  It would then need to be passed to each bone's to_script_file() / to_scene_file() method.  Not a big deal, since these are called within the skeleton's writing method.  What is 2.3 production timeframe?  Will add lines to Skeleton.Parse untested if close.  The .babylon format is usually developed after the .js works, not concurrent.

Link to comment
Share on other sites

I implement the deletion of frames of a range in Animation:

public deleteRange(name: string, deleteFrames?: boolean): void {    for (var index = 0; index < this._ranges.length; index++) {        if (this._ranges[index].name === name) {            if (deleteFrames) {                var from = this._ranges[index].from;                var to = this._ranges[index].to;                 // this loop MUST go high to low for multiple splices to work                for (var key = this._keys.length - 1; key >= 0; key--) {                    if (this._keys[key].frame >= from  && this._keys[key].frame <= to) {                       this._keys.splice(key, 1);                     }                }            }            this._ranges.splice(index, 1);            return;        }    }}

For a whole skeleton, I added this in Skeleton:

public removeAnimationRange(rangeName : string): void {    for (var i = 0, nBones = this.bones.length; i < nBones; i++) {        this.bones[i].animations[0].deleteRange(rangeName, true);    }}

I implemented copyAnimationRange in both bone & skeleton.  Skeleton's call each bones as they were matched up between skeletons.

 

I added range parsing / serializing to Animation & hand edited a .babylon to add one.

 

When I went to change the html, it is started in skeleton.  I looked both skeleton & animation have _ranges.  In order for this to work I need to also parse / serialize at skeleton and change my removeAnimationRange, and put the code inside skeleton.deleteRange.  Right???

Link to comment
Share on other sites

As you know, I never wait for answers.  Over night, I cam to the same conclusion.  Done, now in test.

 

I made it so that skeleton.createAnimationRange(), skeleton.deleteAnimationRange(), also did the same to each bone's animations[0].  The skeleton.Parse calls createAnimationRange(), so the range need only be at the skeleton level in the JSON.

 

This is a new feature for 2.3, so I made a couple of minor changes before they get locked in.

  • deleteFrames arg of deleteRange() is now default true.  Seems to only keep when explicitly requested.
  • changed implementation of ranges- _ranges : { [name: string] : AnimationRange; } = {};

Since a name was always being passed to calls, you can easily access without looping.  Avoids writing loops to validate a range does not already exist in Parse from JSON.  This can occur if a scene serialized, then reloaded.

 

A little more testing, then PR.

Link to comment
Share on other sites

Yeah, I have a few todo, mostly all related to skeletons: this, variableBoneInfluencer, Blender exporter.  Will do all at the same time.

 

Making good progress in Actions support in Blender.  Made this python class, AnimationRange, which has a static actionPrep method which makes the passed in action the current action.  It figures the frames based on 'includeAllFrames' returns an AnimationRange instance.

class AnimationRange:    # constructor called by the static actionPrep method    def __init__(self, name, frames, frameOffset):        self.name = name        self.highest_frame = frames[len(frames) - 1]        self.frame_start = frameOffset + frames[0]        self.frame_end   = frameOffset + self.highest_frame        self.frames = frames# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -    # assume the following JS variables have already been declared: skeleton. animation    def to_script_file(self, file_handler, indent, isSkeleton):        func = 'skeleton.createAnimationRange' if isSkeleton else 'animation.createRange'        file_handler.write(indent + func + '("' + self.name + '", ' + format_int(self.frame_start) + ', ' + format_int(self.frame_start) + ');\n')# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -    @staticmethod    def actionPrep(object, action, includeAllFrames, frameOffset, attrInBlender = None):        # assign the action & test if there is any data for that action for this object        object.animation_data.action = action        if len(object.animation_data.action.fcurves) == 0:            return None                if includeAllFrames:            frame_start, frame_end = [int(x) for x in action.frame_range]            frames = range(frame_start, frame_end        else:            # capture built up from fcurves            frames = dict()            for fcurve in object.animation_data.action.fcurves:                if attrInBlender != None and fcurve.data_path != attrInBlender:                    continue                                for key in fcurve.keyframe_points:                    frame = key.co.x                    frames[frame] = True                                # check that there were frames for this attribute            if (len(frames) == 0):                return None                               frames = sorted(frames)                    return AnimationRange(action.name, frames, frameOffset)

This worked with my preminary test.  The really good thing is you do not have to bake your skeleton poses, in fact you NEVER SHOULD, even when going to a .babylon.  This will simply 'run' the animation and snap the matrices at that point.  If you bake the poses & save the .blend then you cannot edit the key frames, or copy the action as easily.

 

I also pulled iterating through the scene animation at the skeleton level, not bone, and did speed up.

 

Finally, The Mesh, Camera, Light animations will have ranges.  I am wondering if node.ts should convenience AnimationRanges like Skeleton?

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...