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/bindingAPI.h"
25 #include "pxr/usd/usd/schemaRegistry.h"
26 #include "pxr/usd/usd/typed.h"
27 #include "pxr/usd/usd/tokens.h"
28
29 #include "pxr/usd/sdf/types.h"
30 #include "pxr/usd/sdf/assetPath.h"
31
32 PXR_NAMESPACE_OPEN_SCOPE
33
34 // Register the schema with the TfType system.
TF_REGISTRY_FUNCTION(TfType)35 TF_REGISTRY_FUNCTION(TfType)
36 {
37 TfType::Define<UsdSkelBindingAPI,
38 TfType::Bases< UsdAPISchemaBase > >();
39
40 }
41
42 TF_DEFINE_PRIVATE_TOKENS(
43 _schemaTokens,
44 (SkelBindingAPI)
45 );
46
47 /* virtual */
~UsdSkelBindingAPI()48 UsdSkelBindingAPI::~UsdSkelBindingAPI()
49 {
50 }
51
52 /* static */
53 UsdSkelBindingAPI
Get(const UsdStagePtr & stage,const SdfPath & path)54 UsdSkelBindingAPI::Get(const UsdStagePtr &stage, const SdfPath &path)
55 {
56 if (!stage) {
57 TF_CODING_ERROR("Invalid stage");
58 return UsdSkelBindingAPI();
59 }
60 return UsdSkelBindingAPI(stage->GetPrimAtPath(path));
61 }
62
63
64 /* virtual */
_GetSchemaKind() const65 UsdSchemaKind UsdSkelBindingAPI::_GetSchemaKind() const
66 {
67 return UsdSkelBindingAPI::schemaKind;
68 }
69
70 /* static */
71 bool
CanApply(const UsdPrim & prim,std::string * whyNot)72 UsdSkelBindingAPI::CanApply(
73 const UsdPrim &prim, std::string *whyNot)
74 {
75 return prim.CanApplyAPI<UsdSkelBindingAPI>(whyNot);
76 }
77
78 /* static */
79 UsdSkelBindingAPI
Apply(const UsdPrim & prim)80 UsdSkelBindingAPI::Apply(const UsdPrim &prim)
81 {
82 if (prim.ApplyAPI<UsdSkelBindingAPI>()) {
83 return UsdSkelBindingAPI(prim);
84 }
85 return UsdSkelBindingAPI();
86 }
87
88 /* static */
89 const TfType &
_GetStaticTfType()90 UsdSkelBindingAPI::_GetStaticTfType()
91 {
92 static TfType tfType = TfType::Find<UsdSkelBindingAPI>();
93 return tfType;
94 }
95
96 /* static */
97 bool
_IsTypedSchema()98 UsdSkelBindingAPI::_IsTypedSchema()
99 {
100 static bool isTyped = _GetStaticTfType().IsA<UsdTyped>();
101 return isTyped;
102 }
103
104 /* virtual */
105 const TfType &
_GetTfType() const106 UsdSkelBindingAPI::_GetTfType() const
107 {
108 return _GetStaticTfType();
109 }
110
111 UsdAttribute
GetGeomBindTransformAttr() const112 UsdSkelBindingAPI::GetGeomBindTransformAttr() const
113 {
114 return GetPrim().GetAttribute(UsdSkelTokens->primvarsSkelGeomBindTransform);
115 }
116
117 UsdAttribute
CreateGeomBindTransformAttr(VtValue const & defaultValue,bool writeSparsely) const118 UsdSkelBindingAPI::CreateGeomBindTransformAttr(VtValue const &defaultValue, bool writeSparsely) const
119 {
120 return UsdSchemaBase::_CreateAttr(UsdSkelTokens->primvarsSkelGeomBindTransform,
121 SdfValueTypeNames->Matrix4d,
122 /* custom = */ false,
123 SdfVariabilityVarying,
124 defaultValue,
125 writeSparsely);
126 }
127
128 UsdAttribute
GetJointsAttr() const129 UsdSkelBindingAPI::GetJointsAttr() const
130 {
131 return GetPrim().GetAttribute(UsdSkelTokens->skelJoints);
132 }
133
134 UsdAttribute
CreateJointsAttr(VtValue const & defaultValue,bool writeSparsely) const135 UsdSkelBindingAPI::CreateJointsAttr(VtValue const &defaultValue, bool writeSparsely) const
136 {
137 return UsdSchemaBase::_CreateAttr(UsdSkelTokens->skelJoints,
138 SdfValueTypeNames->TokenArray,
139 /* custom = */ false,
140 SdfVariabilityUniform,
141 defaultValue,
142 writeSparsely);
143 }
144
145 UsdAttribute
GetJointIndicesAttr() const146 UsdSkelBindingAPI::GetJointIndicesAttr() const
147 {
148 return GetPrim().GetAttribute(UsdSkelTokens->primvarsSkelJointIndices);
149 }
150
151 UsdAttribute
CreateJointIndicesAttr(VtValue const & defaultValue,bool writeSparsely) const152 UsdSkelBindingAPI::CreateJointIndicesAttr(VtValue const &defaultValue, bool writeSparsely) const
153 {
154 return UsdSchemaBase::_CreateAttr(UsdSkelTokens->primvarsSkelJointIndices,
155 SdfValueTypeNames->IntArray,
156 /* custom = */ false,
157 SdfVariabilityVarying,
158 defaultValue,
159 writeSparsely);
160 }
161
162 UsdAttribute
GetJointWeightsAttr() const163 UsdSkelBindingAPI::GetJointWeightsAttr() const
164 {
165 return GetPrim().GetAttribute(UsdSkelTokens->primvarsSkelJointWeights);
166 }
167
168 UsdAttribute
CreateJointWeightsAttr(VtValue const & defaultValue,bool writeSparsely) const169 UsdSkelBindingAPI::CreateJointWeightsAttr(VtValue const &defaultValue, bool writeSparsely) const
170 {
171 return UsdSchemaBase::_CreateAttr(UsdSkelTokens->primvarsSkelJointWeights,
172 SdfValueTypeNames->FloatArray,
173 /* custom = */ false,
174 SdfVariabilityVarying,
175 defaultValue,
176 writeSparsely);
177 }
178
179 UsdAttribute
GetBlendShapesAttr() const180 UsdSkelBindingAPI::GetBlendShapesAttr() const
181 {
182 return GetPrim().GetAttribute(UsdSkelTokens->skelBlendShapes);
183 }
184
185 UsdAttribute
CreateBlendShapesAttr(VtValue const & defaultValue,bool writeSparsely) const186 UsdSkelBindingAPI::CreateBlendShapesAttr(VtValue const &defaultValue, bool writeSparsely) const
187 {
188 return UsdSchemaBase::_CreateAttr(UsdSkelTokens->skelBlendShapes,
189 SdfValueTypeNames->TokenArray,
190 /* custom = */ false,
191 SdfVariabilityUniform,
192 defaultValue,
193 writeSparsely);
194 }
195
196 UsdRelationship
GetAnimationSourceRel() const197 UsdSkelBindingAPI::GetAnimationSourceRel() const
198 {
199 return GetPrim().GetRelationship(UsdSkelTokens->skelAnimationSource);
200 }
201
202 UsdRelationship
CreateAnimationSourceRel() const203 UsdSkelBindingAPI::CreateAnimationSourceRel() const
204 {
205 return GetPrim().CreateRelationship(UsdSkelTokens->skelAnimationSource,
206 /* custom = */ false);
207 }
208
209 UsdRelationship
GetSkeletonRel() const210 UsdSkelBindingAPI::GetSkeletonRel() const
211 {
212 return GetPrim().GetRelationship(UsdSkelTokens->skelSkeleton);
213 }
214
215 UsdRelationship
CreateSkeletonRel() const216 UsdSkelBindingAPI::CreateSkeletonRel() const
217 {
218 return GetPrim().CreateRelationship(UsdSkelTokens->skelSkeleton,
219 /* custom = */ false);
220 }
221
222 UsdRelationship
GetBlendShapeTargetsRel() const223 UsdSkelBindingAPI::GetBlendShapeTargetsRel() const
224 {
225 return GetPrim().GetRelationship(UsdSkelTokens->skelBlendShapeTargets);
226 }
227
228 UsdRelationship
CreateBlendShapeTargetsRel() const229 UsdSkelBindingAPI::CreateBlendShapeTargetsRel() const
230 {
231 return GetPrim().CreateRelationship(UsdSkelTokens->skelBlendShapeTargets,
232 /* custom = */ false);
233 }
234
235 namespace {
236 static inline TfTokenVector
_ConcatenateAttributeNames(const TfTokenVector & left,const TfTokenVector & right)237 _ConcatenateAttributeNames(const TfTokenVector& left,const TfTokenVector& right)
238 {
239 TfTokenVector result;
240 result.reserve(left.size() + right.size());
241 result.insert(result.end(), left.begin(), left.end());
242 result.insert(result.end(), right.begin(), right.end());
243 return result;
244 }
245 }
246
247 /*static*/
248 const TfTokenVector&
GetSchemaAttributeNames(bool includeInherited)249 UsdSkelBindingAPI::GetSchemaAttributeNames(bool includeInherited)
250 {
251 static TfTokenVector localNames = {
252 UsdSkelTokens->primvarsSkelGeomBindTransform,
253 UsdSkelTokens->skelJoints,
254 UsdSkelTokens->primvarsSkelJointIndices,
255 UsdSkelTokens->primvarsSkelJointWeights,
256 UsdSkelTokens->skelBlendShapes,
257 };
258 static TfTokenVector allNames =
259 _ConcatenateAttributeNames(
260 UsdAPISchemaBase::GetSchemaAttributeNames(true),
261 localNames);
262
263 if (includeInherited)
264 return allNames;
265 else
266 return localNames;
267 }
268
269 PXR_NAMESPACE_CLOSE_SCOPE
270
271 // ===================================================================== //
272 // Feel free to add custom code below this line. It will be preserved by
273 // the code generator.
274 //
275 // Just remember to wrap code in the appropriate delimiters:
276 // 'PXR_NAMESPACE_OPEN_SCOPE', 'PXR_NAMESPACE_CLOSE_SCOPE'.
277 // ===================================================================== //
278 // --(BEGIN CUSTOM CODE)--
279
280
281 #include "pxr/usd/usdGeom/boundable.h"
282 #include "pxr/usd/usdGeom/imageable.h"
283 #include "pxr/usd/usdGeom/tokens.h"
284
285 #include "pxr/usd/usdSkel/skeleton.h"
286 #include "pxr/usd/usdSkel/utils.h"
287
288
289 PXR_NAMESPACE_OPEN_SCOPE
290
291
292 UsdGeomPrimvar
GetJointIndicesPrimvar() const293 UsdSkelBindingAPI::GetJointIndicesPrimvar() const
294 {
295 return UsdGeomPrimvar(GetJointIndicesAttr());
296 }
297
298
299 UsdGeomPrimvar
CreateJointIndicesPrimvar(bool constant,int elementSize) const300 UsdSkelBindingAPI::CreateJointIndicesPrimvar(bool constant,
301 int elementSize) const
302 {
303 return UsdGeomImageable(GetPrim()).CreatePrimvar(
304 UsdSkelTokens->primvarsSkelJointIndices,
305 SdfValueTypeNames->IntArray,
306 constant ? UsdGeomTokens->constant : UsdGeomTokens->vertex,
307 elementSize);
308 }
309
310
311 UsdGeomPrimvar
GetJointWeightsPrimvar() const312 UsdSkelBindingAPI::GetJointWeightsPrimvar() const
313 {
314 return UsdGeomPrimvar(GetJointWeightsAttr());
315 }
316
317
318 UsdGeomPrimvar
CreateJointWeightsPrimvar(bool constant,int elementSize) const319 UsdSkelBindingAPI::CreateJointWeightsPrimvar(bool constant,
320 int elementSize) const
321 {
322 return UsdGeomImageable(GetPrim()).CreatePrimvar(
323 UsdSkelTokens->primvarsSkelJointWeights,
324 SdfValueTypeNames->FloatArray,
325 constant ? UsdGeomTokens->constant : UsdGeomTokens->vertex,
326 elementSize);
327 }
328
329
330 bool
SetRigidJointInfluence(int jointIndex,float weight) const331 UsdSkelBindingAPI::SetRigidJointInfluence(int jointIndex, float weight) const
332 {
333 UsdGeomPrimvar jointIndicesPv =
334 CreateJointIndicesPrimvar(/*constant*/ true, /*elementSize*/ 1);
335 UsdGeomPrimvar jointWeightsPv =
336 CreateJointWeightsPrimvar(/*constant*/ true, /*elementSize*/ 1);
337
338 if (jointIndex < 0) {
339 TF_WARN("Invalid jointIndex '%d'", jointIndex);
340 return false;
341 }
342
343 return jointIndicesPv.Set(VtIntArray(1, jointIndex)) &&
344 jointWeightsPv.Set(VtFloatArray(1, weight));
345 }
346
347
348 namespace {
349
350
351 bool
_HasInactiveAncestor(const UsdStagePtr & stage,const SdfPath & path)352 _HasInactiveAncestor(const UsdStagePtr& stage, const SdfPath& path)
353 {
354 if (path.IsAbsolutePath() && path.IsPrimPath()) {
355 for (SdfPath p = path.GetParentPath();
356 p != SdfPath::AbsoluteRootPath(); p = p.GetParentPath()) {
357 if (UsdPrim prim = stage->GetPrimAtPath(p)) {
358 return !prim.IsActive();
359 }
360 }
361 }
362 return false;
363 }
364
365
366 /// Return the a resolved prim for a target in \p targets.
367 UsdPrim
_GetFirstTargetPrimForRel(const UsdRelationship & rel,const SdfPathVector & targets)368 _GetFirstTargetPrimForRel(const UsdRelationship& rel,
369 const SdfPathVector& targets)
370 {
371 if (targets.size() > 0) {
372 if (targets.size() > 1) {
373 TF_WARN("%s -- relationship has more than one target. "
374 "Only the first will be used.",
375 rel.GetPath().GetText());
376 }
377 const SdfPath& target = targets.front();
378 if (UsdPrim prim = rel.GetStage()->GetPrimAtPath(target))
379 return prim;
380
381 // Should throw a warning about an invalid target.
382 // However, we may not be able to access the prim because one of its
383 // ancestors may be inactive. If so, failing to retrieve the prim is
384 // expected, so we should avoid warning spam.
385 if (!_HasInactiveAncestor(rel.GetStage(), target)) {
386 TF_WARN("%s -- Invalid target <%s>.",
387 rel.GetPath().GetText(), target.GetText());
388 }
389 }
390 return UsdPrim();
391 }
392
393
394 } // namespace
395
396
397 bool
GetSkeleton(UsdSkelSkeleton * skel) const398 UsdSkelBindingAPI::GetSkeleton(UsdSkelSkeleton* skel) const
399 {
400 if (!skel) {
401 TF_CODING_ERROR("'skel' pointer is null.");
402 return false;
403 }
404
405 if (UsdRelationship rel = GetSkeletonRel()) {
406
407 SdfPathVector targets;
408 if (rel.GetForwardedTargets(&targets)) {
409 if (!targets.empty() || rel.HasAuthoredTargets()) {
410 UsdPrim prim = _GetFirstTargetPrimForRel(rel, targets);
411 *skel = UsdSkelSkeleton(prim);
412
413 if (prim && !*skel) {
414 TF_WARN("%s -- target (<%s>) of relationship is not "
415 "a Skeleton.", rel.GetPath().GetText(),
416 prim.GetPath().GetText());
417 }
418 return true;
419 }
420 }
421 }
422 *skel = UsdSkelSkeleton();
423 return false;
424 }
425
426
427 UsdSkelSkeleton
GetInheritedSkeleton() const428 UsdSkelBindingAPI::GetInheritedSkeleton() const
429 {
430 UsdSkelSkeleton skel;
431
432 if (UsdPrim p = GetPrim()) {
433 for( ; !p.IsPseudoRoot(); p = p.GetParent()) {
434 if (UsdSkelBindingAPI(p).GetSkeleton(&skel)) {
435 return skel;
436 }
437 }
438 }
439 return skel;
440 }
441
442
443 bool
GetAnimationSource(UsdPrim * prim) const444 UsdSkelBindingAPI::GetAnimationSource(UsdPrim* prim) const
445 {
446 if (!prim) {
447 TF_CODING_ERROR("'prim' pointer is null.");
448 return false;
449 }
450
451 if (UsdRelationship rel = GetAnimationSourceRel()) {
452
453 SdfPathVector targets;
454 if (rel.GetForwardedTargets(&targets)) {
455 if (!targets.empty() || rel.HasAuthoredTargets()) {
456 *prim = _GetFirstTargetPrimForRel(rel, targets);
457
458 if (*prim && !UsdSkelIsSkelAnimationPrim(*prim)) {
459 TF_WARN("%s -- target (<%s>) of relationship is not a valid "
460 "skel animation source.",
461 rel.GetPath().GetText(),
462 prim->GetPath().GetText());
463 *prim = UsdPrim();
464 }
465 return true;
466 }
467 }
468 }
469 *prim = UsdPrim();
470 return false;
471 }
472
473
474 UsdPrim
GetInheritedAnimationSource() const475 UsdSkelBindingAPI::GetInheritedAnimationSource() const
476 {
477 UsdPrim animPrim;
478
479 if (UsdPrim p = GetPrim()) {
480 for( ; !p.IsPseudoRoot(); p = p.GetParent()) {
481 if (UsdSkelBindingAPI(p).GetAnimationSource(&animPrim)) {
482 return animPrim;
483 }
484 }
485 }
486 return animPrim;
487 }
488
489
490 bool
ValidateJointIndices(TfSpan<const int> indices,size_t numJoints,std::string * reason)491 UsdSkelBindingAPI::ValidateJointIndices(TfSpan<const int> indices,
492 size_t numJoints,
493 std::string* reason)
494 {
495 for (size_t i = 0; i < indices.size(); ++i) {
496 const int jointIndex = indices[i];
497 if (jointIndex < 0 || static_cast<size_t>(jointIndex) >= numJoints) {
498 if (reason) {
499 *reason = TfStringPrintf(
500 "Index [%d] at element %td is not in the range [0,%zu)",
501 jointIndex, i, numJoints);
502 }
503 return false;
504 }
505 }
506 return true;
507 }
508
509
510 PXR_NAMESPACE_CLOSE_SCOPE
511