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 1 SFRotation [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").