Extensions introduced in Castle Game Engine related to the interpolation, which allows to animate various X3D fields.

See also documentation of supported nodes of the Interpolation component and X3D specification of the Interpolation component.

Contents:

As an extension, we add the `ColorSetInterpolator`

(Pascal API: `TColorSetInterpolatorNode`

) node, that generates `MFColor`

values.

ColorSetInterpolator : X3DInterpolatorNode {SFNode [in,out]metadata NULL# [X3DMetadataObject]; defined by X3DNode SFFloat [in]set_fraction# defined by X3DInterpolatorNode MFFloat [in,out]key []# defined by X3DInterpolatorNode MFColor [in,out]keyValue []MFColor [out]value_changed}

The number of items in the "`keyValue`

" field should be a multiple
of the number of items in the "`key`

" field, that is
`keyValue.count = key.count * singleValueChangedCount`

.
When the "`set_fraction`

" input event is received,
we linearly interpolate
the colors, and the "`value_changed`

" event is generated with
a set of `singleValueChangedCount`

colors.

This works and looks exactly like
other interpolation nodes. It is similar to `CoordinateInterpolator`

,
but generates colors. It is similar to `ColorInterpolator`

,
but generates many values. Colors are interpolated in HSV
space.

Useful to interpolate e.g. `Background.skyColor`

values,
or `Color.color`

values.

As an extension, we add the `VectorInterpolator`

(Pascal API: `TVectorInterpolatorNode`

) node, that generates `MFFloat`

values. This is
compatible with InstantReality.

VectorInterpolator : X3DInterpolatorNode {SFNode [in,out]metadata NULL# [X3DMetadataObject]; defined by X3DNode SFFloat [in]set_fraction# defined by X3DInterpolatorNode MFFloat [in,out]key []# defined by X3DInterpolatorNode MFFloat [in,out]keyValue []MFFloat [out]value_changed}

The number of items in the "`keyValue`

" field should be a multiple
of the number of items in the "`key`

" field, that is
`keyValue.count = key.count * singleValueChangedCount`

.
When the "`set_fraction`

" input event is received,
we linearly interpolate
the floats, and the "`value_changed`

" event is generated with
a set of `singleValueChangedCount`

floats.

Useful to interpolate e.g. by `ElevationGrid.set_height`

.

CubicBezierPositionInterpolator : X3DInterpolatorNode {SFNode [in,out]metadata NULL# [X3DMetadataObject]; defined by X3DNode SFFloat [in]set_fraction# defined by X3DInterpolatorNode MFFloat [in,out]key []# defined by X3DInterpolatorNode MFVec3f [in,out]keyValue []MFVec4f [in,out]controlPoints []SFVec3f [out]value_changed}

CubicBezier2DOrientationInterpolator : X3DInterpolatorNode {SFNode [in,out]metadata NULL# [X3DMetadataObject]; defined by X3DNode SFFloat [in]set_fraction# defined by X3DInterpolatorNode MFFloat [in,out]key []# defined by X3DInterpolatorNode MFFloat [in,out]keyValue []MFVec4f [in,out]controlPoints []SFVec3f [in,out]axis []SFRotation [out]value_changed}

These nodes interpolate using *cubic Bezier curves*. They are similar to
standard X3D interpolator nodes (that use linear interpolation between values)
and to X3D `Spline*Interpolator`

nodes (that use Catmull-Rom splines),
but these ones use *cubic Bezier curves*.

`CubicBezierPositionInterpolator`

(Pascal API:`TCubicBezierPositionInterpolatorNode`

) is equivalent to standard`PositionInterpolator`

(Pascal API:`TPositionInterpolatorNode`

), except using cubic Bezier curve instead of linear interpolation.`CubicBezier2DOrientationInterpolator`

(Pascal API:`TCubicBezier2DOrientationInterpolatorNode`

) is equivalent to standard`OrientationInterpolator`

(Pascal API:`TOrientationInterpolatorNode`

), except using cubic Bezier curve instead of linear interpolation, and simplifying parameters for rotations in 2D.

These nodes are particularly useful when converting
Spine
animations with *curve* interpolation to X3D.
That is because Spine uses cubic Bezier curves for interpolation too,
with controls points defined in a similar way.
See Spine JSON docs,
paragraphs *The Bézier curve array has 4 elements...*.
Our Spine reading code automatically uses these nodes where necessary.

Every `CubicBezier*Interpolator`

node has an additional field `controlPoints`

(number of 4D vectors) describing the Bezier curves between they key values. Between every 2 values (on `keyValue`

field) there are 2 additional 2D points (Bezier control points), packed together as 4D vector. So the count of `controlPoints`

must be *n - 1* (additional values are silently ignored, and when missing we assume linear interpolation) where *n* is the count of `key`

s (and `keyValue`

s). Let us call every 4 numbes as *CX1*, *CY1*, *CX2*, *CY2*. Values *CX1* and *CX2* determine the position of handle between previous (0) and next (1) key. Values *CY1* and *CY2* determine the output value, where 0 is the value at previous key and 1 is the value at next key.

For `CubicBezier2DOrientationInterpolator`

, the way we handle
2D rotation interpolation requires additional explanation.
The final rotation (expressed as `SFRotation`

) is always calculated
as a rotation around constant vector (in `axis`

field),
with rotation angle calculated by interpolating (with cubic Bezier curves)
the angles defined in `keyValue`

field (as radians).
This way `CubicBezier2DOrientationInterpolator`

is very efficient for 2D
rotations.

Note that you could also use `NurbsPositionInterpolator`

and `NurbsOrientationInterpolator`

to interpolate using Bezier curves (see NURBS nodes), since NURBS equations already allow to specify Bezier curves. However, this would be less efficient to calculate, as we don't know then that the NURBS "knot" represents a Bezier curve. We can calculate resuls faster knowing that it's a Bezier cubic curve, not anything more generic. Additionally, `CubicBezier2DOrientationInterpolator`

makes extra optimization, knowing that rotation is in 2D.

OrientationInterpolator2D : X3DInterpolatorNode {SFNode [in,out]metadata NULL# [X3DMetadataObject]; defined by X3DNode SFFloat [in]set_fraction# defined by X3DInterpolatorNode MFFloat [in,out]key []# defined by X3DInterpolatorNode MFFloat [in,out]keyValue []SFVec3f [in,out]axis 0 0 1SFRotation [out]value_changed}

Like a standard `OrientationInterpolator`

(Pascal API: `TOrientationInterpolatorNode`

), but with simplified parameters
for rotations in 2D. The axis (in `axis`

field) is constant, only the amount of rotation (single float) changes
(according to `keyValue`

).
This makes it both more efficient, and the interpolation more obvious (no need for "slerp").