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