Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Animation compression #731

Closed
mre4ce opened this issue Sep 27, 2016 · 9 comments
Closed

Animation compression #731

mre4ce opened this issue Sep 27, 2016 · 9 comments

Comments

@mre4ce
Copy link

mre4ce commented Sep 27, 2016

The current setup for animations does allow for some level of "compression". You can obviously omit channels that are not animating, but you can also choose different sub-sampling rates for different channels. However, the latter requires lookups in separate time tables which is not necessarily cheap. Sure you could make the animation system stateful but imho that's just a bad idea (state is the root of all evil). You want to be able to start an animation at any time or play from any point without relying on previously stored state. You can do a binary search through a time table but this is still a log(N) operation which is time consuming for long animations.

In the past I've primarily worked with animation systems that use a fixed sampling rate per animation or channel. This gets rid of the expensive time table lookups. Additionally it makes it easier to omit key frames based on whether or not they can be derived with interpolation. Next to an animation with a fixed sampling rate you can store a bit field with a bit set to one for each key frame that exists. Simple bit operations (bit-count, leading-zero-count etc.) can then be used to directly lookup key frames from this data.

The following example shows a simple example of what this could look like:

"animations": {
    "Animation_001": {
        "frameCount": 219,
        "channels": [
            {
                "node": "car",
                "property": "translation",
                "frameRate": 24,
                "framesPerBlock": 64,
                "blockOffsets": "car_translation_index_accessor",
                "frameBlocks": "car_translation_blocks_accessor"
            },
            {
                "node": "car",
                "property": "rotation",
                "frameRate": 24,
                "framesPerBlock": 64,
                "blockOffsets": "car_rotation_index_accessor",
                "frameBlocks": "car_rotation_blocks_accessor"
            }
        }
   }

Each channel lists the "node" that is animated. The channel lists the "property" of the node that is animated. This is either "translation", "rotation" or "scale". The frame rate of the channel is listed as "frameRate". The animation data is stored in blocks of "framesPerBlock" frames each. The offset to each block can be found in the "blockOffsets". The blocks themselves are stored in "frameBlocks". Each block starts with a bit field of "framesPerBlock" bits. This bit field has a bit set to one for each key frame that is actually stored. A block always stores an initial key frame but any successive frames may be omitted. The initial key frame of the next block is the last key frame of the current block.

Note that this is just an encoding of effectively the same thing. As opposed to using a non-fixed-rate animation with a different time table per channel to space out the key frames differently, the animation is now fixed rate and key frames are explicitly omitted.

@RemiArnaud
Copy link
Contributor

You can easily sample to whatever fix frame rate you need when loading the animation data. There is no need to bloat the animation size in the transmitted data.

@mre4ce
Copy link
Author

mre4ce commented Sep 28, 2016

The "compression" wouldn't bloat the animation size. More than likely it will significantly reduce the animation size considering the current format requires you to store multiple time tables to be able to use different sampling rates per channel. Even if the animation size is the same, decoding the "compressed" format would be much more efficient than searching through multiple time tables. Doing the "compression" at load time defeats the purpose.

@pjcozzi
Copy link
Member

pjcozzi commented Sep 28, 2016

@mre4ce sounds like you have a prominent use case here and that we should update the spec accordingly. I am oversimplifying this by suggesting that just a scale/stride (that defaults to 1) could be applied to the time in each channel?

@pjcozzi
Copy link
Member

pjcozzi commented Sep 28, 2016

I meant:

"I am" -> "Am I"

@mre4ce
Copy link
Author

mre4ce commented Sep 28, 2016

I'm not quite sure what you mean with the "scale / stride". A fixed rate animation makes it easy to lookup key frames.

int keyFrameIndex = int( timeInSeconds * channel.frameRate ) % animation.frameCount;

However, we still want to omit key frames that are not necessary. The keyFrameIndex gets us the blockIndex:

int blockIndex = keyFrameIndex / channel.framesPerBlock;

The offset to the block can be looked up directly from "channel.blockOffsets". The block then stores a bit mask of "channel.framesPerBlock" bits with a bit set to one for key frames that are actually stored, followed by the actual key frame data itself.

Independent from this encoding scheme you would store the 'translation', 'scale' and 'rotations' as 16-bit per component values. To make this flexible you store a "scale & bias" per channel for the 'translation' and 'scale' and you store the largest three components of the 'rotation' quaternion (assuming the quaternions are always normalized).

Now this is just one idea. It'd be good to hear suggestions from others before committing anything to the spec.

@pjcozzi pjcozzi added the 1.1 label Oct 3, 2016
@pjcozzi
Copy link
Member

pjcozzi commented Oct 3, 2016

Ah, OK, this sounds like a pretty significant breaking change. It could be worth it for the memory savings, but this would have to come post 1.0.1 so we can keep 1.0.1 scoped on basically spec bug fixes. Feel free to continue to iterate here in the meantime.

@pjcozzi
Copy link
Member

pjcozzi commented Dec 24, 2017

Orthogonal to this issue, we are also interested in keyframe animation compression in the same sense as mesh compression, #874

@pjcozzi
Copy link
Member

pjcozzi commented Jan 23, 2019

CC Draco animation compression, #1407

@pjcozzi
Copy link
Member

pjcozzi commented Jan 23, 2019

This could be a nice gain in addition to potentially using Draco compression. If this is useful to anyone, please provide a proposal; closing in the meantime.

@pjcozzi pjcozzi closed this as completed Jan 23, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants