Qt3D-Animation-Clip-API

From Qt Wiki
Jump to navigation Jump to search

Thin Wrapper API

Thin wrapper around raw data (assuming bezier curve type interpolation for now).

This is the easiest to implement as requires no additional logic and it offers full control of everything.

However, it is quite verbose to use as an API since each component can have it's own time points - flexible but noisy.

We could make it slightly higher level by automatically creating leftHandle/rightHandle values if not specified.

Also we need to add explicit support for changing the interpolation type. Here we assume bezier but would be good to be able to specify say e.g. linear so that the leftHandle/rightHandle values are not needed, or for selecting the pre-canned easing curve types.

AnimationClip {
   channels: [
       Channel {
           name: "Location"
           components: [
               ChannelComponent {
                   name: "Location X"
                   keyFrames: [
                       KeyFrame { coords: Qt.vector2d(0, 0); leftHandle: Qt.vector2d(-1, 0); rightHandle: Qt.vector2d(1, 0) },
                       KeyFrame { coords: Qt.vector2d(2.45, 5); leftHandle: Qt.vector2d(1.45, 5); rightHandle: Qt.vector2d(3.45, 5) }
                   ]
               },
               ChannelComponent {
                   name: "Location Y"
                   keyFrames: [
                       KeyFrame { coords: Qt.vector2d(0, 0); leftHandle: Qt.vector2d(-1, 0); rightHandle: Qt.vector2d(1, 0) },
                       KeyFrame { coords: Qt.vector2d(2.45, 0); leftHandle: Qt.vector2d(1.45, 0); rightHandle: Qt.vector2d(3.45, 0) }
                   ]
               },
               ChannelComponent {
                   name: "Location Z"
                   keyFrames: [
                       KeyFrame { coords: Qt.vector2d(0, 0); leftHandle: Qt.vector2d(-1, 0); rightHandle: Qt.vector2d(1, 0) },
                       KeyFrame { coords: Qt.vector2d(2.45, 0); leftHandle: Qt.vector2d(1.45, 0); rightHandle: Qt.vector2d(3.45, 0) }
                   ]
               }
           ]
       }
   ]
}

For a fair comparison with next option, without handles (auto created for bezier interp or usign linear) this would look like:

AnimationClip {
   channels: [
       Channel {
           name: "Location"
           components: [
               ChannelComponent {
                   name: "Location X"
                   keyFrames: [
                       KeyFrame { coords: Qt.vector2d(0, 0) },
                       KeyFrame { coords: Qt.vector2d(2.45, 5) }
                   ]
               },
               ChannelComponent {
                   name: "Location Y"
                   keyFrames: [
                       KeyFrame { coords: Qt.vector2d(0, 0) },
                       KeyFrame { coords: Qt.vector2d(2.45, 0) }
                   ]
               },
               ChannelComponent {
                   name: "Location Z"
                   keyFrames: [
                       KeyFrame { coords: Qt.vector2d(0, 0) },
                       KeyFrame { coords: Qt.vector2d(2.45, 0) }
                   ]
               }
           ]
       }
   ]
}

Need to see how we can map this C++ with value types to save memory costs there.

Simplified API

Slightly higher level typed API (again assuming bezier interpolation).

Same comments as for 1) apply about interpolation mode and the need for leftHandle/rightHandle values. Restriction of this approach is that components within a channel must share common time values. Not a problem as long as we don't mind having the superset of all keyframe times and calculating suitable handles to preserve the gradient.

AnimationClip {
   channels: [
       Vector3DChannel {
           name: "Location"
           
           keyFrames: [
               Vector3DKeyFrame { time: 0; value: Qt.vector3d(0, 0, 0) },      // Auto-generates leftHandle, rightHandle values
               Vector3DKeyFrame { time: 2.45; value: Qt.vector3d(5, 0, 0) }    // Auto-generates leftHandle, rightHandle values
           ]
       }
   ]
}

or with leftHandle/rightHandle values:

AnimationClip {
   channels: [
       Vector3DChannel {
           name: "Location"
           
           keyFrames: [
               Vector3DKeyFrame { time: 0; value: Qt.vector3d(0, 0, 0)
                                  leftHandleTime: -1; leftHandleValue: Qt.vector3d(0, 0, 0)
                                  rightHandleTime: 1; rightHandleValue: Qt.vector3d(0, 0, 0) },
               Vector3DKeyFrame { time: 2.45; value: Qt.vector3d(5, 0, 0)
                                  leftHandleTime: 1.45; leftHandleValue: Qt.vector3d(5, 0, 0)
                                  rightHandleTime: 3.45; rightHandleValue: Qt.vector3d(5, 0, 0) }
           ]
       }
   ]
}


Qt Quick-like API

API more similar to existing Qt Quick animations but which generates data for backend AnimationClip.

QQ2 animations in effect specify the curve between two key frames along with the mapping to the target objects and properties.

ParallelAnimations map to channels evaluating at the same/overlapping times. Sequential animations splice parts of clips together, end-to-end.

So we could offer API that looks like existing Qt Quick 2 property animations and from that extract both AnimationClip data and the ChannelMapper data or even a ClipAnimator. This could make a nice porting tool from Qt Quick Animations to Qt 3D's animation framework.


Higher Level Helpers

High level helpers such as generating AnimationClip data to allow a camera/entity to follow along a path (bezier curve or whatever). There are helpers for this kind of thing in Blender which makes life much easier there.

Another good example is to modify a curve with noise e.g. use perlin noise to the location/orientation of a camera to add camera shake.