8#ifndef PXR_BASE_TS_EVAL_CACHE_H
9#define PXR_BASE_TS_EVAL_CACHE_H
13#include "pxr/base/ts/keyFrameUtils.h"
14#include "pxr/base/ts/mathUtils.h"
15#include "pxr/base/ts/types.h"
16#include "pxr/base/vt/value.h"
22PXR_NAMESPACE_OPEN_SCOPE
25template <
typename T>
class Ts_TypedData;
33 Ts_Bezier(
const TsTime timePoints[4],
const T valuePoints[4]);
34 void DerivePolynomial();
44Ts_Bezier<T>::Ts_Bezier(
const TsTime time[4],
const T value[4])
46 timePoints[0] = time[0];
47 timePoints[1] = time[1];
48 timePoints[2] = time[2];
49 timePoints[3] = time[3];
50 valuePoints[0] = value[0];
51 valuePoints[1] = value[1];
52 valuePoints[2] = value[2];
53 valuePoints[3] = value[3];
59Ts_Bezier<T>::DerivePolynomial()
61 timeCoeff[0] = timePoints[0];
62 timeCoeff[1] = -3.0 * timePoints[0] +
64 timeCoeff[2] = 3.0 * timePoints[0] +
65 -6.0 * timePoints[1] +
67 timeCoeff[3] = -1.0 * timePoints[0] +
69 -3.0 * timePoints[2] +
71 valueCoeff[0] = valuePoints[0];
72 valueCoeff[1] = -3.0 * valuePoints[0] +
74 valueCoeff[2] = 3.0 * valuePoints[0] +
75 -6.0 * valuePoints[1] +
77 valueCoeff[3] = -1.0 * valuePoints[0] +
78 3.0 * valuePoints[1] +
79 -3.0 * valuePoints[2] +
83class Ts_UntypedEvalCache {
85 typedef std::shared_ptr<Ts_UntypedEvalCache> SharedPtr;
90 virtual VtValue Eval(TsTime)
const = 0;
91 virtual VtValue EvalDerivative(TsTime)
const = 0;
106 ~Ts_UntypedEvalCache() =
default;
109 template <
typename T>
110 static void _SetupBezierGeometry(TsTime* timePoints, T* valuePoints,
111 const Ts_TypedData<T>* kf1,
112 const Ts_TypedData<T>* kf2);
116 template <
typename T>
117 static TsTime _GetBezierPoint2Time(
const Ts_TypedData<T>* kf1,
118 const Ts_TypedData<T>* kf2);
122 template <
typename T>
123 static TsTime _GetBezierPoint3Time(
const Ts_TypedData<T>* kf1,
124 const Ts_TypedData<T>* kf2);
128 template <
typename T>
129 static T _GetBezierPoint2Value(
const Ts_TypedData<T>* kf1,
130 const Ts_TypedData<T>* kf2);
134 template <
typename T>
135 static T _GetBezierPoint3Value(
const Ts_TypedData<T>* kf1,
136 const Ts_TypedData<T>* kf2);
140 template <
typename T>
141 static T _GetBezierPoint4Value(
const Ts_TypedData<T>* kf1,
142 const Ts_TypedData<T>* kf2);
145template <typename T, bool INTERPOLATABLE = TsTraits<T>::interpolatable >
149class Ts_EvalQuaternionCache :
public Ts_UntypedEvalCache {
151 static_assert(std::is_same<T, GfQuatf>::value
152 || std::is_same<T, GfQuatd>::value
153 ,
"T must be Quatd or Quatf");
154 Ts_EvalQuaternionCache(
const Ts_EvalQuaternionCache<T> * rhs);
155 Ts_EvalQuaternionCache(
const Ts_TypedData<T>* kf1,
156 const Ts_TypedData<T>* kf2);
157 Ts_EvalQuaternionCache(
const TsKeyFrame & kf1,
161 T TypedEval(TsTime)
const;
162 T TypedEvalDerivative(TsTime)
const;
164 VtValue Eval(TsTime t)
const override;
165 VtValue EvalDerivative(TsTime t)
const override;
167 void _Init(
const Ts_TypedData<T>* kf1,
const Ts_TypedData<T>* kf2);
168 double _kf1_time, _kf2_time;
169 T _kf1_value, _kf2_value;
170 TsKnotType _kf1_knot_type;
174class Ts_EvalCache<
GfQuatf, true> final
175 :
public Ts_EvalQuaternionCache<GfQuatf> {
177 Ts_EvalCache(
const Ts_EvalCache<GfQuatf, true> *rhs) :
178 Ts_EvalQuaternionCache<
GfQuatf>(rhs) {}
179 Ts_EvalCache(
const Ts_TypedData<GfQuatf>* kf1,
180 const Ts_TypedData<GfQuatf>* kf2) :
181 Ts_EvalQuaternionCache<
GfQuatf>(kf1, kf2) {}
183 Ts_EvalQuaternionCache<
GfQuatf>(kf1, kf2) {}
185 typedef std::shared_ptr<Ts_EvalCache<GfQuatf, true> > TypedSharedPtr;
192class Ts_EvalCache<
GfQuatd, true> final
193 :
public Ts_EvalQuaternionCache<GfQuatd> {
195 Ts_EvalCache(
const Ts_EvalCache<GfQuatd, true> *rhs) :
196 Ts_EvalQuaternionCache<
GfQuatd>(rhs) {}
197 Ts_EvalCache(
const Ts_TypedData<GfQuatd>* kf1,
198 const Ts_TypedData<GfQuatd>* kf2) :
199 Ts_EvalQuaternionCache<
GfQuatd>(kf1, kf2) {}
201 Ts_EvalQuaternionCache<
GfQuatd>(kf1, kf2) {}
203 typedef std::shared_ptr<Ts_EvalCache<GfQuatd, true> > TypedSharedPtr;
212class Ts_EvalCache<T, false> final :
public Ts_UntypedEvalCache {
214 Ts_EvalCache(
const Ts_EvalCache<T, false> * rhs);
215 Ts_EvalCache(
const Ts_TypedData<T>* kf1,
const Ts_TypedData<T>* kf2);
217 T TypedEval(TsTime)
const;
218 T TypedEvalDerivative(TsTime)
const;
220 VtValue Eval(TsTime t)
const override;
221 VtValue EvalDerivative(TsTime t)
const override;
223 typedef std::shared_ptr<Ts_EvalCache<T, false> > TypedSharedPtr;
234class Ts_EvalCache<T, true> final :
public Ts_UntypedEvalCache {
236 Ts_EvalCache(
const Ts_EvalCache<T, true> * rhs);
237 Ts_EvalCache(
const Ts_TypedData<T>* kf1,
const Ts_TypedData<T>* kf2);
239 T TypedEval(TsTime)
const;
240 T TypedEvalDerivative(TsTime)
const;
242 VtValue Eval(TsTime t)
const override;
243 VtValue EvalDerivative(TsTime t)
const override;
245 const Ts_Bezier<T>* GetBezier()
const;
247 typedef std::shared_ptr<Ts_EvalCache<T, true> > TypedSharedPtr;
253 void _Init(
const Ts_TypedData<T>* kf1,
const Ts_TypedData<T>* kf2);
269Ts_UntypedEvalCache::_GetBezierPoint2Time(
const Ts_TypedData<T>* kf1,
270 const Ts_TypedData<T>* kf2)
272 switch (kf1->_knotType) {
276 return (2.0 * kf1->GetTime() + kf2->GetTime()) / 3.0;
279 return kf1->GetTime() + kf1->_rightTangentLength;
285Ts_UntypedEvalCache::_GetBezierPoint3Time(
const Ts_TypedData<T>* kf1,
286 const Ts_TypedData<T>* kf2)
290 TsKnotType knotType = (kf1->_knotType == TsKnotHeld) ?
291 TsKnotHeld : kf2->_knotType;
297 return (kf1->GetTime() + 2.0 * kf2->GetTime()) / 3.0;
300 return kf2->GetTime() - kf2->_leftTangentLength;
306Ts_UntypedEvalCache::_GetBezierPoint2Value(
const Ts_TypedData<T>* kf1,
307 const Ts_TypedData<T>* kf2)
309 switch (kf1->_knotType) {
312 return kf1->_GetRightValue();
316 (2.0 * kf1->_GetRightValue() +
317 (kf2->_isDual ? kf2->_GetLeftValue() : kf2->_GetRightValue()));
320 return kf1->_GetRightValue() +
321 kf1->_rightTangentLength * kf1->_GetRightTangentSlope();
327Ts_UntypedEvalCache::_GetBezierPoint3Value(
const Ts_TypedData<T>* kf1,
328 const Ts_TypedData<T>* kf2)
332 if (kf1->_knotType == TsKnotHeld) {
333 return kf1->_GetRightValue();
336 switch (kf2->_knotType) {
339 if (kf1->_knotType != TsKnotLinear) {
340 return kf2->_isDual ? kf2->_GetLeftValue() : kf2->_GetRightValue();
347 (kf1->_GetRightValue() + 2.0 *
348 (kf2->_isDual ? kf2->_GetLeftValue() : kf2->_GetRightValue()));
351 return (kf2->_isDual ? kf2->_GetLeftValue() : kf2->_GetRightValue()) -
352 kf2->_leftTangentLength * kf2->_GetLeftTangentSlope();
358Ts_UntypedEvalCache::_GetBezierPoint4Value(
const Ts_TypedData<T>* kf1,
359 const Ts_TypedData<T>* kf2)
363 if (kf1->_knotType == TsKnotHeld) {
364 return kf1->_GetRightValue();
366 return (kf2->_isDual ? kf2->_GetLeftValue() : kf2->_GetRightValue());
372Ts_UntypedEvalCache::_SetupBezierGeometry(
373 TsTime* timePoints, T* valuePoints,
374 const Ts_TypedData<T>* kf1,
const Ts_TypedData<T>* kf2)
376 timePoints[0] = kf1->GetTime();
377 timePoints[1] = _GetBezierPoint2Time(kf1, kf2);
378 timePoints[2] = _GetBezierPoint3Time(kf1, kf2);
379 timePoints[3] = kf2->GetTime();
380 valuePoints[0] = kf1->_GetRightValue();
381 valuePoints[1] = _GetBezierPoint2Value(kf1, kf2);
382 valuePoints[2] = _GetBezierPoint3Value(kf1, kf2);
383 valuePoints[3] = _GetBezierPoint4Value(kf1, kf2);
390Ts_EvalCache<T, false>::Ts_EvalCache(
const Ts_EvalCache<T, false> * rhs)
392 _value = rhs->_value;
396Ts_EvalCache<T, false>::Ts_EvalCache(
const Ts_TypedData<T>* kf1,
397 const Ts_TypedData<T>* kf2)
400 TF_CODING_ERROR(
"Constructing an Ts_EvalCache from invalid keyframes");
404 _value = kf1->_GetRightValue();
408Ts_EvalCache<T, false>::Ts_EvalCache(
const TsKeyFrame &kf1,
414 Ts_TypedData<T> *data =
415 static_cast<Ts_TypedData<T> const*
>(Ts_GetKeyFrameData(kf1));
417 _value = data->_GetRightValue();
422Ts_EvalCache<T, false>::Eval(TsTime t)
const {
428Ts_EvalCache<T, false>::EvalDerivative(TsTime t)
const {
429 return VtValue(TypedEvalDerivative(t));
434Ts_EvalCache<T, false>::TypedEval(TsTime)
const
441Ts_EvalCache<T, false>::TypedEvalDerivative(TsTime)
const
443 return TsTraits<T>::zero;
450Ts_EvalCache<T, true>::Ts_EvalCache(
const Ts_EvalCache<T, true> * rhs)
452 _interpolate = rhs->_interpolate;
453 _value = rhs->_value;
454 _cache = rhs->_cache;
458Ts_EvalCache<T, true>::Ts_EvalCache(
const Ts_TypedData<T>* kf1,
459 const Ts_TypedData<T>* kf2)
465Ts_EvalCache<T, true>::Ts_EvalCache(
const TsKeyFrame &kf1,
471 _Init(
static_cast<Ts_TypedData<T> const*
>(Ts_GetKeyFrameData(kf1)),
472 static_cast<Ts_TypedData<T> const*
>(Ts_GetKeyFrameData(kf2)));
477Ts_EvalCache<T, true>::_Init(
478 const Ts_TypedData<T>* kf1,
479 const Ts_TypedData<T>* kf2)
482 TF_CODING_ERROR(
"Constructing an Ts_EvalCache from invalid keyframes");
487 _SetupBezierGeometry(_cache.timePoints, _cache.valuePoints, kf1, kf2);
488 _cache.DerivePolynomial();
490 if (kf1->ValueCanBeInterpolated() && kf2->ValueCanBeInterpolated()) {
493 _interpolate =
false;
494 _value = kf1->_GetRightValue();
500Ts_EvalCache<T, true>::Eval(TsTime t)
const {
506Ts_EvalCache<T, true>::EvalDerivative(TsTime t)
const {
507 return VtValue(TypedEvalDerivative(t));
512Ts_EvalCache<T, true>::TypedEval(TsTime time)
const
517 double u =
GfClamp(Ts_SolveCubic(_cache.timeCoeff, time), 0.0, 1.0);
518 return Ts_EvalCubic(_cache.valueCoeff, u);
523Ts_EvalCache<T, true>::TypedEvalDerivative(TsTime time)
const
525 if (!TsTraits<T>::supportsTangents || !_interpolate) {
526 return TsTraits<T>::zero;
539 u =
GfClamp(Ts_SolveCubic(_cache.timeCoeff, time), 0.0, 1.0);
540 T x = Ts_EvalCubicDerivative(_cache.valueCoeff, u);
541 TsTime t = Ts_EvalCubicDerivative(_cache.timeCoeff, u);
542 T derivative = x * (1.0 / t);
548Ts_EvalCache<T, true>::GetBezier()
const
554std::shared_ptr<Ts_EvalCache<T, true> >
560 return static_cast<const Ts_TypedData<T>*
>(
561 Ts_GetKeyFrameData(kf1))->
562 CreateTypedEvalCache(Ts_GetKeyFrameData(kf2));
566std::shared_ptr<Ts_EvalCache<T, false> >
572 return static_cast<const Ts_TypedData<T>*
>(
573 Ts_GetKeyFrameData(kf1))->
574 CreateTypedEvalCache(Ts_GetKeyFrameData(kf2));
581Ts_EvalQuaternionCache<T>::Ts_EvalQuaternionCache(
582 const Ts_EvalQuaternionCache<T> * rhs)
584 _kf1_knot_type = rhs->_kf1_knot_type;
586 _kf1_time = rhs->_kf1_time;
587 _kf2_time = rhs->_kf2_time;
589 _kf1_value = rhs->_kf1_value;
590 _kf2_value = rhs->_kf2_value;
594Ts_EvalQuaternionCache<T>::Ts_EvalQuaternionCache(
595 const Ts_TypedData<T>* kf1,
const Ts_TypedData<T>* kf2)
601Ts_EvalQuaternionCache<T>::Ts_EvalQuaternionCache(
const TsKeyFrame &kf1,
607 _Init(
static_cast<Ts_TypedData<T> const*
>(Ts_GetKeyFrameData(kf1)),
608 static_cast<Ts_TypedData<T> const*
>(Ts_GetKeyFrameData(kf2)));
613Ts_EvalQuaternionCache<T>::_Init(
614 const Ts_TypedData<T>* kf1,
615 const Ts_TypedData<T>* kf2)
619 " from invalid keyframes");
623 _kf1_knot_type = kf1->_knotType;
625 _kf1_time = kf1->GetTime();
626 _kf2_time = kf2->GetTime();
628 _kf1_value = kf1->_GetRightValue();
629 _kf2_value = kf2->_isDual ? kf2->_GetLeftValue() : kf2->_GetRightValue();
634Ts_EvalQuaternionCache<T>::Eval(TsTime t)
const {
639T Ts_EvalQuaternionCache<T>::TypedEval(TsTime time)
const
641 if (_kf1_knot_type == TsKnotHeld) {
652 double u = (time - _kf1_time) / (_kf2_time - _kf1_time);
653 return GfSlerp(_kf1_value, _kf2_value, u);
657VtValue Ts_EvalQuaternionCache<T>::EvalDerivative(TsTime t)
const {
658 return VtValue(TypedEvalDerivative(t));
662T Ts_EvalQuaternionCache<T>::TypedEvalDerivative(TsTime)
const {
663 return TsTraits<T>::zero;
666PXR_NAMESPACE_CLOSE_SCOPE
Basic type: a quaternion, a complex number with a real coefficient and three imaginary coefficients,...
Basic type: a quaternion, a complex number with a real coefficient and three imaginary coefficients,...
Specifies the value of an TsSpline object at a particular point in time.
Provides a container which may hold any type, and provides introspection and iteration over array typ...
Assorted mathematical utility functions.
double GfClamp(double value, double min, double max)
Return the resulting of clamping value to lie between min and max.
#define TF_CODING_ERROR(fmt, args)
Issue an internal programming error, but continue execution.
GF_API GfQuatd GfSlerp(double alpha, const GfQuatd &q0, const GfQuatd &q1)
Spherically linearly interpolate between q0 and q1.
A file containing basic constants and definitions.