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 #include "pxr/usd/usdSkel/skelDefinition.h"
25
26 #include "pxr/base/arch/hints.h"
27
28 #include "pxr/usd/usdSkel/utils.h"
29
30
31 PXR_NAMESPACE_OPEN_SCOPE
32
33
34 namespace {
35
36
37 enum _Flags {
38 _HaveBindPose = 1 << 0,
39 _HaveRestPose = 1 << 1,
40 // Matrix4dArray computations
41 _SkelRestXforms4dComputed = 1 << 2,
42 _WorldInverseBindXforms4dComputed = 1 << 3,
43 _LocalInverseRestXforms4dComputed = 1 << 4,
44 // Matrix4fArray computations
45 _SkelRestXforms4fComputed = 1 << 5,
46 _WorldInverseBindXforms4fComputed = 1 << 6,
47 _LocalInverseRestXforms4fComputed = 1 << 7,
48 };
49
50
51 template <typename Matrix4>
52 void
_InvertTransforms(const VtArray<Matrix4> & xforms,VtArray<Matrix4> * inverseXforms)53 _InvertTransforms(const VtArray<Matrix4>& xforms,
54 VtArray<Matrix4>* inverseXforms)
55 {
56 inverseXforms->resize(xforms.size());
57 Matrix4* dst = inverseXforms->data();
58 for (size_t i = 0; i < xforms.size(); ++i) {
59 dst[i] = xforms[i].GetInverse();
60 }
61 }
62
63
64 void
_Convert4dXformsTo4f(const VtMatrix4dArray & matrix4dArray,VtMatrix4fArray * matrix4fArray)65 _Convert4dXformsTo4f(const VtMatrix4dArray& matrix4dArray,
66 VtMatrix4fArray* matrix4fArray)
67 {
68 matrix4fArray->resize(matrix4dArray.size());
69 GfMatrix4f* dst = matrix4fArray->data();
70 for (size_t i = 0; i < matrix4dArray.size(); ++i) {
71 dst[i] = GfMatrix4f(matrix4dArray[i]);
72 }
73 }
74
75
76 } // namespace
77
78
79 UsdSkel_SkelDefinitionRefPtr
New(const UsdSkelSkeleton & skel)80 UsdSkel_SkelDefinition::New(const UsdSkelSkeleton& skel)
81 {
82 if(skel) {
83 UsdSkel_SkelDefinitionRefPtr def =
84 TfCreateRefPtr(new UsdSkel_SkelDefinition);
85 if(def->_Init(skel))
86 return def;
87 }
88 return nullptr;
89 }
90
91
UsdSkel_SkelDefinition()92 UsdSkel_SkelDefinition::UsdSkel_SkelDefinition()
93 : _flags(0)
94 {}
95
96
97 bool
_Init(const UsdSkelSkeleton & skel)98 UsdSkel_SkelDefinition::_Init(const UsdSkelSkeleton& skel)
99 {
100 TRACE_FUNCTION();
101
102 skel.GetJointsAttr().Get(&_jointOrder);
103
104 _topology = UsdSkelTopology(_jointOrder);
105 std::string reason;
106 if (!_topology.Validate(&reason)) {
107 TF_WARN("%s -- invalid topology: %s",
108 skel.GetPrim().GetPath().GetText(), reason.c_str());
109 return false;
110 }
111
112 skel.GetBindTransformsAttr().Get(&_jointWorldBindXforms);
113 if (_jointWorldBindXforms.size() == _jointOrder.size()) {
114 _flags = _flags|_HaveBindPose;
115 } else {
116 TF_WARN("%s -- size of 'bindTransforms' attr [%zu] does not "
117 "match the number of joints in the 'joints' attr [%zu].",
118 skel.GetPrim().GetPath().GetText(),
119 _jointWorldBindXforms.size(), _jointOrder.size());
120 }
121
122 skel.GetRestTransformsAttr().Get(&_jointLocalRestXforms);
123 if (_jointLocalRestXforms.size() == _jointOrder.size()) {
124 _flags = _flags|_HaveRestPose;
125 } else {
126 TF_WARN("%s -- size of 'restTransforms' attr [%zu] does not "
127 "match the number of joints in the 'joints' attr [%zu].",
128 skel.GetPrim().GetPath().GetText(),
129 _jointLocalRestXforms.size(), _jointOrder.size());
130 }
131
132 _skel = skel;
133 return true;
134 }
135
136
137 template <>
138 VtMatrix4dArray&
Get()139 UsdSkel_SkelDefinition::_XformHolder::Get<GfMatrix4d>()
140 { return xforms4d; }
141
142 template <>
143 const VtMatrix4dArray&
Get() const144 UsdSkel_SkelDefinition::_XformHolder::Get<GfMatrix4d>() const
145 { return xforms4d; }
146
147 template <>
148 VtMatrix4fArray&
Get()149 UsdSkel_SkelDefinition::_XformHolder::Get<GfMatrix4f>()
150 { return xforms4f; }
151
152 template <>
153 const VtMatrix4fArray&
Get() const154 UsdSkel_SkelDefinition::_XformHolder::Get<GfMatrix4f>() const
155 { return xforms4f; }
156
157
158 template <>
159 bool
GetJointLocalRestTransforms(VtMatrix4dArray * xforms)160 UsdSkel_SkelDefinition::GetJointLocalRestTransforms(VtMatrix4dArray* xforms)
161 {
162 const int flags = _flags;
163 if (flags&_HaveRestPose) {
164
165 if (!xforms) {
166 TF_CODING_ERROR("'xforms' pointer is null.");
167 return false;
168 }
169
170 // double-precision rest xforms are pre-computed.
171 *xforms = _jointLocalRestXforms;
172 return true;
173 }
174 return false;
175 }
176
177
178 template <>
179 bool
GetJointLocalRestTransforms(VtMatrix4fArray * xforms)180 UsdSkel_SkelDefinition::GetJointLocalRestTransforms(VtMatrix4fArray* xforms)
181 {
182 if (!xforms) {
183 TF_CODING_ERROR("'xforms' pointer is null.");
184 return false;
185 }
186
187 // float-precision uses uncached conversion from double-precision.
188 VtMatrix4dArray xforms4d;
189 if (GetJointLocalRestTransforms(&xforms4d)) {
190 _Convert4dXformsTo4f(xforms4d, xforms);
191 return true;
192 }
193 return false;
194 }
195
196
197 template <int ComputeFlag, typename Matrix4>
198 bool
_GetJointSkelRestTransforms(VtArray<Matrix4> * xforms)199 UsdSkel_SkelDefinition::_GetJointSkelRestTransforms(VtArray<Matrix4>* xforms)
200 {
201 const int flags = _flags;
202 if (flags&_HaveRestPose) {
203
204 if (!xforms) {
205 TF_CODING_ERROR("'xforms' pointer is null.");
206 return false;
207 }
208
209 if (ARCH_UNLIKELY(!(flags&ComputeFlag))) {
210 if (!_ComputeJointSkelRestTransforms<ComputeFlag,Matrix4>()) {
211 return false;
212 }
213 }
214 *xforms = _jointSkelRestXforms.Get<Matrix4>();
215 return true;
216 }
217 return false;
218 }
219
220
221 template <>
222 bool
GetJointSkelRestTransforms(VtMatrix4dArray * xforms)223 UsdSkel_SkelDefinition::GetJointSkelRestTransforms(VtMatrix4dArray* xforms)
224 {
225 return _GetJointSkelRestTransforms<_SkelRestXforms4dComputed>(xforms);
226 }
227
228
229 template <>
230 bool
GetJointSkelRestTransforms(VtMatrix4fArray * xforms)231 UsdSkel_SkelDefinition::GetJointSkelRestTransforms(VtMatrix4fArray* xforms)
232 {
233 return _GetJointSkelRestTransforms<_SkelRestXforms4fComputed>(xforms);
234 }
235
236
237 template <int ComputeFlag, typename Matrix4>
238 bool
_ComputeJointSkelRestTransforms()239 UsdSkel_SkelDefinition::_ComputeJointSkelRestTransforms()
240 {
241 TRACE_FUNCTION();
242
243 VtArray<Matrix4> jointLocalRestXforms;
244 if (TF_VERIFY(GetJointLocalRestTransforms(&jointLocalRestXforms))) {
245
246 std::lock_guard<std::mutex> lock(_mutex);
247
248 VtArray<Matrix4>& skelXforms = _jointSkelRestXforms.Get<Matrix4>();
249 skelXforms.resize(_topology.size());
250
251 const bool success =
252 UsdSkelConcatJointTransforms(_topology, jointLocalRestXforms,
253 skelXforms);
254
255 // XXX: Topology was validated when the definition was constructed,
256 /// so this should not have failed.
257 TF_VERIFY(success);
258
259 _flags = _flags|ComputeFlag;
260
261 return true;
262 }
263 return false;
264 }
265
266
267 template <>
268 bool
GetJointWorldBindTransforms(VtMatrix4dArray * xforms)269 UsdSkel_SkelDefinition::GetJointWorldBindTransforms(VtMatrix4dArray* xforms)
270 {
271 const int flags = _flags;
272 if (flags&_HaveBindPose) {
273
274 if (!xforms) {
275 TF_CODING_ERROR("'xforms' pointer is null.");
276 return false;
277 }
278
279 // double-precision bind xforms are pre-computed.
280 *xforms = _jointWorldBindXforms;
281 return true;
282 }
283 return false;
284 }
285
286
287 template <>
288 bool
GetJointWorldBindTransforms(VtMatrix4fArray * xforms)289 UsdSkel_SkelDefinition::GetJointWorldBindTransforms(VtMatrix4fArray* xforms)
290 {
291 if (!xforms) {
292 TF_CODING_ERROR("'xforms' pointer is null.");
293 return false;
294 }
295
296 // float-precision uses uncached conversion from double-precision.
297 VtMatrix4dArray xforms4d;
298 if (GetJointWorldBindTransforms(&xforms4d)) {
299 _Convert4dXformsTo4f(xforms4d, xforms);
300 return true;
301 }
302 return false;
303 }
304
305
306 template <int ComputeFlag, typename Matrix4>
307 bool
_GetJointWorldInverseBindTransforms(VtArray<Matrix4> * xforms)308 UsdSkel_SkelDefinition::_GetJointWorldInverseBindTransforms(
309 VtArray<Matrix4>* xforms)
310 {
311 const int flags = _flags;
312 if (flags&_HaveBindPose) {
313
314 if (!xforms) {
315 TF_CODING_ERROR("'xforms' pointer is null.");
316 return false;
317 }
318
319 if (ARCH_UNLIKELY(!(flags&ComputeFlag))) {
320 if (!_ComputeJointWorldInverseBindTransforms<
321 ComputeFlag,Matrix4>()) {
322 return false;
323 }
324 }
325 *xforms = _jointWorldInverseBindXforms.Get<Matrix4>();
326 return true;
327 }
328 return false;
329 }
330
331
332 template <>
333 bool
GetJointWorldInverseBindTransforms(VtMatrix4dArray * xforms)334 UsdSkel_SkelDefinition::GetJointWorldInverseBindTransforms(
335 VtMatrix4dArray* xforms)
336 {
337 return _GetJointWorldInverseBindTransforms<
338 _WorldInverseBindXforms4dComputed>(xforms);
339 }
340
341
342 template <>
343 bool
GetJointWorldInverseBindTransforms(VtMatrix4fArray * xforms)344 UsdSkel_SkelDefinition::GetJointWorldInverseBindTransforms(
345 VtMatrix4fArray* xforms)
346 {
347 return _GetJointWorldInverseBindTransforms<
348 _WorldInverseBindXforms4fComputed>(xforms);
349 }
350
351
352 template <int ComputeFlag, typename Matrix4>
353 bool
_ComputeJointWorldInverseBindTransforms()354 UsdSkel_SkelDefinition::_ComputeJointWorldInverseBindTransforms()
355 {
356 TRACE_FUNCTION();
357
358 VtArray<Matrix4> jointWorldBindXforms;
359 if (TF_VERIFY(GetJointWorldBindTransforms(&jointWorldBindXforms))) {
360
361 std::lock_guard<std::mutex> lock(_mutex);
362
363 _InvertTransforms<Matrix4>(
364 jointWorldBindXforms,
365 &_jointWorldInverseBindXforms.Get<Matrix4>());
366
367 _flags = _flags|ComputeFlag;
368 return true;
369 }
370 return false;
371 }
372
373
374 template <int ComputeFlag, typename Matrix4>
375 bool
_GetJointLocalInverseRestTransforms(VtArray<Matrix4> * xforms)376 UsdSkel_SkelDefinition::_GetJointLocalInverseRestTransforms(
377 VtArray<Matrix4>* xforms)
378 {
379 const int flags = _flags;
380 if (flags&_HaveRestPose) {
381
382 if (!xforms) {
383 TF_CODING_ERROR("'xforms' pointer is null.");
384 return false;
385 }
386
387 if (ARCH_UNLIKELY(!(flags&ComputeFlag))) {
388 if (!_ComputeJointLocalInverseRestTransforms<
389 ComputeFlag,Matrix4>()) {
390 return false;
391 }
392 }
393 *xforms = _jointLocalInverseRestXforms.Get<Matrix4>();
394 return true;
395 }
396 return false;
397 }
398
399
400 template <>
401 bool
GetJointLocalInverseRestTransforms(VtMatrix4dArray * xforms)402 UsdSkel_SkelDefinition::GetJointLocalInverseRestTransforms(
403 VtMatrix4dArray* xforms)
404 {
405 return _GetJointLocalInverseRestTransforms<
406 _LocalInverseRestXforms4dComputed>(xforms);
407 return false;
408 }
409
410
411 template <>
412 bool
GetJointLocalInverseRestTransforms(VtMatrix4fArray * xforms)413 UsdSkel_SkelDefinition::GetJointLocalInverseRestTransforms(
414 VtMatrix4fArray* xforms)
415 {
416 return _GetJointLocalInverseRestTransforms<
417 _LocalInverseRestXforms4fComputed>(xforms);
418 return false;
419 }
420
421
422 template <int ComputeFlag, typename Matrix4>
423 bool
_ComputeJointLocalInverseRestTransforms()424 UsdSkel_SkelDefinition::_ComputeJointLocalInverseRestTransforms()
425 {
426 TRACE_FUNCTION();
427
428 VtArray<Matrix4> jointLocalRestXforms;
429 if (TF_VERIFY(GetJointLocalRestTransforms(&jointLocalRestXforms))) {
430
431 std::lock_guard<std::mutex> lock(_mutex);
432
433 _InvertTransforms<Matrix4>(
434 jointLocalRestXforms,
435 &_jointLocalInverseRestXforms.Get<Matrix4>());
436
437 _flags = _flags|ComputeFlag;
438
439 return true;
440 }
441 return false;
442 }
443
444
445 bool
HasBindPose()446 UsdSkel_SkelDefinition::HasBindPose()
447 {
448 return _flags&_HaveBindPose;
449 }
450
451 bool
HasRestPose()452 UsdSkel_SkelDefinition::HasRestPose()
453 {
454 return _flags&_HaveRestPose;
455 }
456
457
458 PXR_NAMESPACE_CLOSE_SCOPE
459