1 //
2 // Copyright 2016 Pixar
3 //
4 // Licensed under the Apache License, Version 2.0 (the "Apache License")
5 // with the following modification; you may not use this file except in
6 // compliance with the Apache License and the following modification to it:
7 // Section 6. Trademarks. is deleted and replaced with:
8 //
9 // 6. Trademarks. This License does not grant permission to use the trade
10 //    names, trademarks, service marks, or product names of the Licensor
11 //    and its affiliates, except as required to comply with Section 4(c) of
12 //    the License and to reproduce the content of the NOTICE file.
13 //
14 // You may obtain a copy of the Apache License at
15 //
16 //     http://www.apache.org/licenses/LICENSE-2.0
17 //
18 // Unless required by applicable law or agreed to in writing, software
19 // distributed under the Apache License with the above modification is
20 // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21 // KIND, either express or implied. See the Apache License for the specific
22 // language governing permissions and limitations under the Apache License.
23 //
24 #ifndef PXR_USD_USD_INTERPOLATORS_H
25 #define PXR_USD_USD_INTERPOLATORS_H
26 
27 #include "pxr/pxr.h"
28 #include "pxr/usd/usd/common.h"
29 #include "pxr/usd/usd/clipSet.h"
30 #include "pxr/usd/usd/valueUtils.h"
31 #include "pxr/usd/sdf/layer.h"
32 #include "pxr/base/gf/math.h"
33 
34 PXR_NAMESPACE_OPEN_SCOPE
35 
36 class UsdAttribute;
37 
38 /// \class Usd_InterpolatorBase
39 ///
40 /// Base class for objects implementing interpolation for attribute
41 /// values. This is invoked during value resolution for times that do not have
42 /// authored time samples.
43 ///
44 class Usd_InterpolatorBase
45 {
46 public:
47     virtual bool Interpolate(
48         const SdfLayerRefPtr& layer, const SdfPath& path,
49         double time, double lower, double upper) = 0;
50     virtual bool Interpolate(
51         const Usd_ClipSetRefPtr& clipSet, const SdfPath& path,
52         double time, double lower, double upper) = 0;
53 };
54 
55 /// \class Usd_NullInterpolator
56 ///
57 /// Null interpolator object for use in cases where interpolation is
58 /// not expected.
59 ///
60 class Usd_NullInterpolator
61     : public Usd_InterpolatorBase
62 {
63 public:
Interpolate(const SdfLayerRefPtr & layer,const SdfPath & path,double time,double lower,double upper)64     virtual bool Interpolate(
65         const SdfLayerRefPtr& layer, const SdfPath& path,
66         double time, double lower, double upper) final
67     {
68         return false;
69     }
70 
Interpolate(const Usd_ClipSetRefPtr & clipSet,const SdfPath & path,double time,double lower,double upper)71     virtual bool Interpolate(
72         const Usd_ClipSetRefPtr& clipSet, const SdfPath& path,
73         double time, double lower, double upper)
74     {
75         return false;
76     }
77 };
78 
79 /// \class Usd_UntypedInterpolator
80 ///
81 /// Interpolator used for type-erased value access.
82 ///
83 /// The type-erased value API does not provide information about the
84 /// expected value type, so this interpolator needs to do more costly
85 /// type lookups to dispatch to the appropriate interpolator.
86 ///
87 class Usd_UntypedInterpolator
88     : public Usd_InterpolatorBase
89 {
90 public:
Usd_UntypedInterpolator(const UsdAttribute & attr,VtValue * result)91     Usd_UntypedInterpolator(const UsdAttribute& attr, VtValue* result)
92         : _attr(attr)
93         , _result(result)
94     {
95     }
96 
97     virtual bool Interpolate(
98         const SdfLayerRefPtr& layer, const SdfPath& path,
99         double time, double lower, double upper) final;
100 
101     virtual bool Interpolate(
102         const Usd_ClipSetRefPtr& clipSet, const SdfPath& path,
103         double time, double lower, double upper) final;
104 
105 private:
106     template <class Src>
107     bool _Interpolate(
108         const Src& src, const SdfPath& path,
109         double time, double lower, double upper);
110 
111 private:
112     const UsdAttribute& _attr;
113     VtValue* _result;
114 };
115 
116 /// \class Usd_HeldInterpolator
117 ///
118 /// Object implementing "held" interpolation for attribute values.
119 ///
120 /// With "held" interpolation, authored time sample values are held constant
121 /// across time until the next authored time sample. In other words, the
122 /// attribute value for a time with no samples authored is the nearest
123 /// preceding value.
124 ///
125 template <class T>
126 class Usd_HeldInterpolator
127     : public Usd_InterpolatorBase
128 {
129 public:
Usd_HeldInterpolator(T * result)130     Usd_HeldInterpolator(T* result)
131         : _result(result)
132     {
133     }
134 
Interpolate(const SdfLayerRefPtr & layer,const SdfPath & path,double time,double lower,double upper)135     virtual bool Interpolate(
136         const SdfLayerRefPtr& layer, const SdfPath& path,
137         double time, double lower, double upper) final
138     {
139         return layer->QueryTimeSample(path, lower, _result);
140     }
141 
Interpolate(const Usd_ClipSetRefPtr & clipSet,const SdfPath & path,double time,double lower,double upper)142     virtual bool Interpolate(
143         const Usd_ClipSetRefPtr& clipSet, const SdfPath& path,
144         double time, double lower, double upper) final
145     {
146         return clipSet->QueryTimeSample(path, lower, this, _result);
147     }
148 
149 private:
150     T* _result;
151 };
152 
153 template <class T>
154 inline T
Usd_Lerp(double alpha,const T & lower,const T & upper)155 Usd_Lerp(double alpha, const T &lower, const T &upper)
156 {
157     return GfLerp(alpha, lower, upper);
158 }
159 
160 inline GfQuath
Usd_Lerp(double alpha,const GfQuath & lower,const GfQuath & upper)161 Usd_Lerp(double alpha, const GfQuath &lower, const GfQuath &upper)
162 {
163     return GfSlerp(alpha, lower, upper);
164 }
165 
166 inline GfQuatf
Usd_Lerp(double alpha,const GfQuatf & lower,const GfQuatf & upper)167 Usd_Lerp(double alpha, const GfQuatf &lower, const GfQuatf &upper)
168 {
169     return GfSlerp(alpha, lower, upper);
170 }
171 
172 inline GfQuatd
Usd_Lerp(double alpha,const GfQuatd & lower,const GfQuatd & upper)173 Usd_Lerp(double alpha, const GfQuatd &lower, const GfQuatd &upper)
174 {
175     return GfSlerp(alpha, lower, upper);
176 }
177 
178 /// \class Usd_LinearInterpolator
179 ///
180 /// Object implementing linear interpolation for attribute values.
181 ///
182 /// With linear interpolation, the attribute value for a time with no samples
183 /// will be linearly interpolated from the previous and next time samples.
184 ///
185 template <class T>
186 class Usd_LinearInterpolator
187     : public Usd_InterpolatorBase
188 {
189 public:
Usd_LinearInterpolator(T * result)190     Usd_LinearInterpolator(T* result)
191         : _result(result)
192     {
193     }
194 
Interpolate(const SdfLayerRefPtr & layer,const SdfPath & path,double time,double lower,double upper)195     virtual bool Interpolate(
196         const SdfLayerRefPtr& layer, const SdfPath& path,
197         double time, double lower, double upper) final
198     {
199         return _Interpolate(layer, path, time, lower, upper);
200     }
201 
Interpolate(const Usd_ClipSetRefPtr & clipSet,const SdfPath & path,double time,double lower,double upper)202     virtual bool Interpolate(
203         const Usd_ClipSetRefPtr& clipSet, const SdfPath& path,
204         double time, double lower, double upper) final
205     {
206         return _Interpolate(clipSet, path, time, lower, upper);
207     }
208 
209 private:
210     template <class Src>
_Interpolate(const Src & src,const SdfPath & path,double time,double lower,double upper)211     bool _Interpolate(
212         const Src& src, const SdfPath& path,
213         double time, double lower, double upper)
214     {
215         T lowerValue, upperValue;
216 
217         // In the presence of a value block we use held interpolation.
218         // We know that a failed call to QueryTimeSample is a block
219         // because the provided time samples should all have valid values.
220         // So this call fails because our <T> is not an SdfValueBlock,
221         // which is the type of the contained value.
222         Usd_LinearInterpolator<T> lowerInterpolator(&lowerValue);
223         Usd_LinearInterpolator<T> upperInterpolator(&upperValue);
224 
225         if (!Usd_QueryTimeSample(
226                 src, path, lower, &lowerInterpolator, &lowerValue)) {
227             return false;
228         }
229         else if (!Usd_QueryTimeSample(
230                 src, path, upper, &upperInterpolator, &upperValue)) {
231             upperValue = lowerValue;
232         }
233 
234         const double parametricTime = (time - lower) / (upper - lower);
235         *_result = Usd_Lerp(parametricTime, lowerValue, upperValue);
236         return true;
237     }
238 
239 private:
240     T* _result;
241 };
242 
243 // Specialization to linearly interpolate each element for
244 // array types.
245 template <class T>
246 class Usd_LinearInterpolator<VtArray<T> >
247     : public Usd_InterpolatorBase
248 {
249 public:
Usd_LinearInterpolator(VtArray<T> * result)250     Usd_LinearInterpolator(VtArray<T>* result)
251         : _result(result)
252     {
253     }
254 
Interpolate(const SdfLayerRefPtr & layer,const SdfPath & path,double time,double lower,double upper)255     virtual bool Interpolate(
256         const SdfLayerRefPtr& layer, const SdfPath& path,
257         double time, double lower, double upper) final
258     {
259         return _Interpolate(layer, path, time, lower, upper);
260     }
261 
Interpolate(const Usd_ClipSetRefPtr & clipSet,const SdfPath & path,double time,double lower,double upper)262     virtual bool Interpolate(
263         const Usd_ClipSetRefPtr& clipSet, const SdfPath& path,
264         double time, double lower, double upper) final
265     {
266         return _Interpolate(clipSet, path, time, lower, upper);
267     }
268 
269 private:
270     template <class Src>
_Interpolate(const Src & src,const SdfPath & path,double time,double lower,double upper)271     bool _Interpolate(
272         const Src& src, const SdfPath& path,
273         double time, double lower, double upper)
274     {
275         VtArray<T> lowerValue, upperValue;
276 
277         // In the presence of a value block we use held interpolation.
278         // We know that a failed call to QueryTimeSample is a block
279         // because the provided time samples should all have valid values.
280         // So this call fails because our <T> is not an SdfValueBlock,
281         // which is the type of the contained value.
282         Usd_LinearInterpolator<VtArray<T> > lowerInterpolator(&lowerValue);
283         Usd_LinearInterpolator<VtArray<T> > upperInterpolator(&upperValue);
284 
285         if (!Usd_QueryTimeSample(
286                 src, path, lower, &lowerInterpolator, &lowerValue)) {
287             return false;
288         }
289         else if (!Usd_QueryTimeSample(
290                 src, path, upper, &upperInterpolator, &upperValue)) {
291             upperValue = lowerValue;
292         }
293 
294         _result->swap(lowerValue);
295 
296         // Fall back to held interpolation (_result is set to lowerValue above)
297         // if sizes don't match. We don't consider this an error because
298         // that would be too restrictive. Consumers will be responsible for
299         // implementing their own interpolation in cases where this occurs
300         // (e.g. meshes with varying topology)
301         if (_result->size() != upperValue.size()) {
302             return true;
303         }
304 
305         const double parametricTime = (time - lower) / (upper - lower);
306         if (parametricTime == 0.0) {
307             // do nothing.
308         }
309         else if (parametricTime == 1.0) {
310             // just swap the upper value in.
311             _result->swap(upperValue);
312         }
313         else {
314             // must actually calculate interpolated values.
315             T *rptr = _result->data();
316             for (size_t i = 0, j = _result->size(); i != j; ++i) {
317                 rptr[i] = Usd_Lerp(parametricTime, rptr[i], upperValue[i]);
318             }
319         }
320 
321         return true;
322     }
323 
324 private:
325     VtArray<T>* _result;
326 };
327 
328 /// If \p lower == \p upper, sets \p result to the time sample at
329 /// that time in the given \p src clip or layer. Otherwise,
330 /// interpolates the value at the given \p time between \p lower
331 /// and \p upper using the given \p interpolator.
332 template <class Src, class T>
333 inline bool
Usd_GetOrInterpolateValue(const Src & src,const SdfPath & path,double time,double lower,double upper,Usd_InterpolatorBase * interpolator,T * result)334 Usd_GetOrInterpolateValue(
335     const Src& src, const SdfPath& path,
336     double time, double lower, double upper,
337     Usd_InterpolatorBase* interpolator, T* result)
338 {
339     if (GfIsClose(lower, upper, /* epsilon = */ 1e-6)) {
340         bool queryResult = Usd_QueryTimeSample(
341             src, path, lower, interpolator, result);
342         return queryResult && (!Usd_ClearValueIfBlocked(result));
343     }
344 
345     return interpolator->Interpolate(src, path, time, lower, upper);
346 }
347 
348 PXR_NAMESPACE_CLOSE_SCOPE
349 
350 #endif // PXR_USD_USD_INTERPOLATORS_H
351