diff --git a/pxr/usd/lib/usdSkel/animMapper.cpp b/pxr/usd/lib/usdSkel/animMapper.cpp index 88379e116f..f067b5c970 100644 --- a/pxr/usd/lib/usdSkel/animMapper.cpp +++ b/pxr/usd/lib/usdSkel/animMapper.cpp @@ -23,6 +23,8 @@ // #include "pxr/usd/usdSkel/animMapper.h" +#include "pxr/base/gf/matrix4d.h" +#include "pxr/base/gf/matrix4f.h" #include "pxr/base/tf/type.h" #include @@ -226,16 +228,26 @@ BOOST_PP_SEQ_FOR_EACH(_UNTYPED_REMAP, ~, SDF_VALUE_TYPES); } +template bool -UsdSkelAnimMapper::RemapTransforms(const VtMatrix4dArray& source, - VtMatrix4dArray* target, +UsdSkelAnimMapper::RemapTransforms(const VtArray& source, + VtArray* target, int elementSize) const { - static const GfMatrix4d identity(1); + static const Matrix4 identity(1); return Remap(source, target, elementSize, &identity); } +template USDSKEL_API bool +UsdSkelAnimMapper::RemapTransforms(const VtMatrix4dArray&, + VtMatrix4dArray*, int) const; + +template USDSKEL_API bool +UsdSkelAnimMapper::RemapTransforms(const VtMatrix4fArray&, + VtMatrix4fArray*, int) const; + + bool UsdSkelAnimMapper::operator==(const UsdSkelAnimMapper& o) const { diff --git a/pxr/usd/lib/usdSkel/animMapper.h b/pxr/usd/lib/usdSkel/animMapper.h index e6a22aa1d3..d3e100ce11 100644 --- a/pxr/usd/lib/usdSkel/animMapper.h +++ b/pxr/usd/lib/usdSkel/animMapper.h @@ -29,8 +29,10 @@ #include "pxr/pxr.h" #include "pxr/usd/usdSkel/api.h" -#include "pxr/base/vt/array.h" +#include "pxr/base/gf/matrix4d.h" +#include "pxr/base/gf/matrix4f.h" #include "pxr/base/tf/span.h" +#include "pxr/base/vt/array.h" #include "pxr/usd/sdf/types.h" #include @@ -97,9 +99,10 @@ class UsdSkelAnimMapper { /// Convenience method for the common task of remapping transform arrays. /// This performs the same operation as Remap(), but sets the matrix /// identity as the default value. + template USDSKEL_API - bool RemapTransforms(const VtMatrix4dArray& source, - VtMatrix4dArray* target, + bool RemapTransforms(const VtArray& source, + VtArray* target, int elementSize=1) const; /// Returns true if this is an identity map. diff --git a/pxr/usd/lib/usdSkel/animQuery.cpp b/pxr/usd/lib/usdSkel/animQuery.cpp index 5b23372dda..f9672b3eab 100644 --- a/pxr/usd/lib/usdSkel/animQuery.cpp +++ b/pxr/usd/lib/usdSkel/animQuery.cpp @@ -30,6 +30,8 @@ #include "pxr/usd/usd/attribute.h" #include "pxr/base/gf/interval.h" +#include "pxr/base/gf/matrix4d.h" +#include "pxr/base/gf/matrix4f.h" PXR_NAMESPACE_OPEN_SCOPE @@ -42,8 +44,9 @@ UsdSkelAnimQuery::GetPrim() const } +template bool -UsdSkelAnimQuery::ComputeJointLocalTransforms(VtMatrix4dArray* xforms, +UsdSkelAnimQuery::ComputeJointLocalTransforms(VtArray* xforms, UsdTimeCode time) const { if(TF_VERIFY(IsValid(), "invalid anim query.")) { @@ -53,6 +56,15 @@ UsdSkelAnimQuery::ComputeJointLocalTransforms(VtMatrix4dArray* xforms, } +template USDSKEL_API bool +UsdSkelAnimQuery::ComputeJointLocalTransforms( + VtArray*, UsdTimeCode) const; + +template USDSKEL_API bool +UsdSkelAnimQuery::ComputeJointLocalTransforms( + VtArray*, UsdTimeCode) const; + + bool UsdSkelAnimQuery::ComputeJointLocalTransformComponents( VtVec3fArray* translations, @@ -140,7 +152,8 @@ UsdSkelAnimQuery::GetBlendShapeOrder() const bool -UsdSkelAnimQuery::GetBlendShapeWeightTimeSamples(std::vector* times) const +UsdSkelAnimQuery::GetBlendShapeWeightTimeSamples( + std::vector* times) const { return GetBlendShapeWeightTimeSamplesInInterval( GfInterval::GetFullInterval(), times); diff --git a/pxr/usd/lib/usdSkel/animQuery.h b/pxr/usd/lib/usdSkel/animQuery.h index 32fa6cc2c7..2eb485735d 100644 --- a/pxr/usd/lib/usdSkel/animQuery.h +++ b/pxr/usd/lib/usdSkel/animQuery.h @@ -89,9 +89,10 @@ class UsdSkelAnimQuery /// Compute joint transforms in joint-local space. /// Transforms are returned in the order specified by the joint ordering /// of the animation primitive itself. + template USDSKEL_API bool ComputeJointLocalTransforms( - VtMatrix4dArray* xforms, + VtArray* xforms, UsdTimeCode time=UsdTimeCode::Default()) const; /// Compute translation,rotation,scale components of the joint transforms diff --git a/pxr/usd/lib/usdSkel/animQueryImpl.cpp b/pxr/usd/lib/usdSkel/animQueryImpl.cpp index 88a911c2c7..1bfb451067 100644 --- a/pxr/usd/lib/usdSkel/animQueryImpl.cpp +++ b/pxr/usd/lib/usdSkel/animQueryImpl.cpp @@ -23,6 +23,9 @@ // #include "pxr/usd/usdSkel/animQueryImpl.h" +#include "pxr/base/gf/matrix4d.h" +#include "pxr/base/gf/matrix4f.h" + #include "pxr/usd/usd/attributeQuery.h" #include "pxr/usd/usd/prim.h" #include "pxr/usd/usd/attribute.h" @@ -52,7 +55,12 @@ class UsdSkel_SkelAnimationQueryImpl : public UsdSkel_AnimQueryImpl virtual UsdPrim GetPrim() const override { return _anim.GetPrim(); } bool ComputeJointLocalTransforms(VtMatrix4dArray* xforms, - UsdTimeCode time) const override; + UsdTimeCode time) const override + { return _ComputeJointLocalTransforms(xforms, time); } + + bool ComputeJointLocalTransforms(VtMatrix4fArray* xforms, + UsdTimeCode time) const override + { return _ComputeJointLocalTransforms(xforms, time); } bool ComputeJointLocalTransformComponents( VtVec3fArray* translations, @@ -78,6 +86,10 @@ class UsdSkel_SkelAnimationQueryImpl : public UsdSkel_AnimQueryImpl bool BlendShapeWeightsMightBeTimeVarying() const override; +private: + template + bool _ComputeJointLocalTransforms(VtArray* xforms, + UsdTimeCode time) const; private: UsdSkelAnimation _anim; @@ -93,43 +105,54 @@ UsdSkel_SkelAnimationQueryImpl::UsdSkel_SkelAnimationQueryImpl( _scales(anim.GetScalesAttr()), _blendShapeWeights(anim.GetBlendShapeWeightsAttr()) { - if(TF_VERIFY(anim)) { + if (TF_VERIFY(anim)) { anim.GetJointsAttr().Get(&_jointOrder); anim.GetBlendShapesAttr().Get(&_blendShapeOrder); } } +template bool -UsdSkel_SkelAnimationQueryImpl::ComputeJointLocalTransforms( - VtMatrix4dArray* xforms, +UsdSkel_SkelAnimationQueryImpl::_ComputeJointLocalTransforms( + VtArray* xforms, UsdTimeCode time) const { TRACE_FUNCTION(); + if (!xforms) { + TF_CODING_ERROR("'xforms' is null"); + return false; + } + VtVec3fArray translations; VtQuatfArray rotations; VtVec3hArray scales; - if(ComputeJointLocalTransformComponents(&translations, &rotations, + if (ComputeJointLocalTransformComponents(&translations, &rotations, &scales, time)) { - if(UsdSkelMakeTransforms(translations, rotations, scales, xforms)) { - if(xforms->size() == _jointOrder.size()) { + xforms->resize(translations.size()); + if (UsdSkelMakeTransforms(translations, rotations, + scales, *xforms)) { + + if (xforms->size() == _jointOrder.size()) { return true; - } else { - if(xforms->size() == 0) { - // XXX: If the size of all components was zero, we - // infer that the arrays were *intentionally* authored as - // empty, to nullify the animation. Since this is - // suspected to be intentional, we emit no warning. - return false; - } - TF_WARN("%s -- size of transform component arrays [%zu] " - "!= joint order size [%zu].", - _anim.GetPrim().GetPath().GetText(), - xforms->size(), _jointOrder.size()); + } else if (xforms->empty()) { + // If all transform components were empty, that could mean: + // - the attributes were never authored + // - the attributes were blocked + // - the attributes were authored with empty arrays + // (possibly intentionally) + + // In many of these cases, we should expect the animation + // to be silently ignored, so throw no warning. + return false; } + TF_WARN("%s -- size of transform component arrays [%zu] " + "!= joint order size [%zu].", + _anim.GetPrim().GetPath().GetText(), + xforms->size(), _jointOrder.size()); } else { TF_WARN("%s -- failed composing transforms from components.", _anim.GetPrim().GetPath().GetText()); @@ -190,7 +213,7 @@ UsdSkel_SkelAnimationQueryImpl::ComputeBlendShapeWeights( VtFloatArray* weights, UsdTimeCode time) const { - if(TF_VERIFY(_anim, "PackedJointAnimation schema object is invalid.")) { + if (TF_VERIFY(_anim, "PackedJointAnimation schema object is invalid.")) { return _blendShapeWeights.Get(weights, time); } return false; @@ -214,14 +237,14 @@ UsdSkel_SkelAnimationQueryImpl::BlendShapeWeightsMightBeTimeVarying() const // -------------------------------------------------- -// UsdSkel_AnimQuery +// UsdSkel_AnimQueryImpl // -------------------------------------------------- UsdSkel_AnimQueryImplRefPtr UsdSkel_AnimQueryImpl::New(const UsdPrim& prim) { - if(prim.IsA()) { + if (prim.IsA()) { return TfCreateRefPtr(new UsdSkel_SkelAnimationQueryImpl( UsdSkelAnimation(prim))); } diff --git a/pxr/usd/lib/usdSkel/animQueryImpl.h b/pxr/usd/lib/usdSkel/animQueryImpl.h index 88cad508df..5f4ce35507 100644 --- a/pxr/usd/lib/usdSkel/animQueryImpl.h +++ b/pxr/usd/lib/usdSkel/animQueryImpl.h @@ -65,6 +65,9 @@ class UsdSkel_AnimQueryImpl : public TfRefBase virtual bool ComputeJointLocalTransforms(VtMatrix4dArray* xforms, UsdTimeCode time) const = 0; + virtual bool ComputeJointLocalTransforms(VtMatrix4fArray* xforms, + UsdTimeCode time) const = 0; + virtual bool ComputeJointLocalTransformComponents( VtVec3fArray* translations, VtQuatfArray* rotations, diff --git a/pxr/usd/lib/usdSkel/skelDefinition.cpp b/pxr/usd/lib/usdSkel/skelDefinition.cpp index 505fa46a15..78c45e2a5f 100644 --- a/pxr/usd/lib/usdSkel/skelDefinition.cpp +++ b/pxr/usd/lib/usdSkel/skelDefinition.cpp @@ -37,12 +37,42 @@ namespace { enum _Flags { _HaveBindPose = 1 << 0, _HaveRestPose = 1 << 1, - _SkelRestXformsComputed = 1 << 2, - _WorldInverseBindXformsComputed = 1 << 3, - _LocalInverseRestXformsComputed = 1 << 4 + // Matrix4dArray computations + _SkelRestXforms4dComputed = 1 << 2, + _WorldInverseBindXforms4dComputed = 1 << 3, + _LocalInverseRestXforms4dComputed = 1 << 4, + // Matrix4fArray computations + _SkelRestXforms4fComputed = 1 << 5, + _WorldInverseBindXforms4fComputed = 1 << 6, + _LocalInverseRestXforms4fComputed = 1 << 7, }; +template +void +_InvertTransforms(const VtArray& xforms, + VtArray* inverseXforms) +{ + inverseXforms->resize(xforms.size()); + Matrix4* dst = inverseXforms->data(); + for (size_t i = 0; i < xforms.size(); ++i) { + dst[i] = xforms[i].GetInverse(); + } +} + + +void +_Convert4dXformsTo4f(const VtMatrix4dArray& matrix4dArray, + VtMatrix4fArray* matrix4fArray) +{ + matrix4fArray->resize(matrix4dArray.size()); + GfMatrix4f* dst = matrix4fArray->data(); + for (size_t i = 0; i < matrix4dArray.size(); ++i) { + dst[i] = GfMatrix4f(matrix4dArray[i]); + } +} + + } // namespace @@ -104,11 +134,32 @@ UsdSkel_SkelDefinition::_Init(const UsdSkelSkeleton& skel) } +template <> +VtMatrix4dArray& +UsdSkel_SkelDefinition::_XformHolder::Get() +{ return xforms4d; } + +template <> +const VtMatrix4dArray& +UsdSkel_SkelDefinition::_XformHolder::Get() const +{ return xforms4d; } + +template <> +VtMatrix4fArray& +UsdSkel_SkelDefinition::_XformHolder::Get() +{ return xforms4f; } + +template <> +const VtMatrix4fArray& +UsdSkel_SkelDefinition::_XformHolder::Get() const +{ return xforms4f; } + + +template <> bool UsdSkel_SkelDefinition::GetJointLocalRestTransforms(VtMatrix4dArray* xforms) { - int flags = _flags; - + const int flags = _flags; if (flags&_HaveRestPose) { if (!xforms) { @@ -116,6 +167,7 @@ UsdSkel_SkelDefinition::GetJointLocalRestTransforms(VtMatrix4dArray* xforms) return false; } + // double-precision rest xforms are pre-computed. *xforms = _jointLocalRestXforms; return true; } @@ -123,10 +175,30 @@ UsdSkel_SkelDefinition::GetJointLocalRestTransforms(VtMatrix4dArray* xforms) } +template <> bool -UsdSkel_SkelDefinition::GetJointSkelRestTransforms(VtMatrix4dArray* xforms) +UsdSkel_SkelDefinition::GetJointLocalRestTransforms(VtMatrix4fArray* xforms) +{ + if (!xforms) { + TF_CODING_ERROR("'xforms' pointer is null."); + return false; + } + + // float-precision uses uncached conversion from double-precision. + VtMatrix4dArray xforms4d; + if (GetJointLocalRestTransforms(&xforms4d)) { + _Convert4dXformsTo4f(xforms4d, xforms); + return true; + } + return false; +} + + +template +bool +UsdSkel_SkelDefinition::_GetJointSkelRestTransforms(VtArray* xforms) { - int flags = _flags; + const int flags = _flags; if (flags&_HaveRestPose) { if (!xforms) { @@ -134,40 +206,69 @@ UsdSkel_SkelDefinition::GetJointSkelRestTransforms(VtMatrix4dArray* xforms) return false; } - if (ARCH_UNLIKELY(!(flags&_SkelRestXformsComputed))) { - - _ComputeJointSkelRestTransforms(); + if (ARCH_UNLIKELY(!(flags&ComputeFlag))) { + if (!_ComputeJointSkelRestTransforms()) { + return false; + } } - *xforms = _jointSkelRestXforms; + *xforms = _jointSkelRestXforms.Get(); return true; } return false; } -void +template <> +bool +UsdSkel_SkelDefinition::GetJointSkelRestTransforms(VtMatrix4dArray* xforms) +{ + return _GetJointSkelRestTransforms<_SkelRestXforms4dComputed>(xforms); +} + + +template <> +bool +UsdSkel_SkelDefinition::GetJointSkelRestTransforms(VtMatrix4fArray* xforms) +{ + return _GetJointSkelRestTransforms<_SkelRestXforms4fComputed>(xforms); +} + + +template +bool UsdSkel_SkelDefinition::_ComputeJointSkelRestTransforms() { TRACE_FUNCTION(); - std::lock_guard lock(_mutex); + VtArray jointLocalRestXforms; + if (TF_VERIFY(GetJointLocalRestTransforms(&jointLocalRestXforms))) { + + std::lock_guard lock(_mutex); + + VtArray& skelXforms = _jointSkelRestXforms.Get(); + skelXforms.resize(_topology.size()); + + const bool success = + UsdSkelConcatJointTransforms(_topology, jointLocalRestXforms, + skelXforms); - bool success = - UsdSkelConcatJointTransforms(_topology, _jointLocalRestXforms, - &_jointSkelRestXforms); - // XXX: Topology was validated when the definition was constructed, - /// so this should not have failed. - TF_VERIFY(success); + // XXX: Topology was validated when the definition was constructed, + /// so this should not have failed. + TF_VERIFY(success); - _flags = _flags|_SkelRestXformsComputed; + _flags = _flags|ComputeFlag; + + return true; + } + return false; } +template <> bool UsdSkel_SkelDefinition::GetJointWorldBindTransforms(VtMatrix4dArray* xforms) { - int flags = _flags; - + const int flags = _flags; if (flags&_HaveBindPose) { if (!xforms) { @@ -175,6 +276,7 @@ UsdSkel_SkelDefinition::GetJointWorldBindTransforms(VtMatrix4dArray* xforms) return false; } + // double-precision bind xforms are pre-computed. *xforms = _jointWorldBindXforms; return true; } @@ -182,11 +284,31 @@ UsdSkel_SkelDefinition::GetJointWorldBindTransforms(VtMatrix4dArray* xforms) } +template <> bool -UsdSkel_SkelDefinition::GetJointWorldInverseBindTransforms( - VtMatrix4dArray* xforms) +UsdSkel_SkelDefinition::GetJointWorldBindTransforms(VtMatrix4fArray* xforms) +{ + if (!xforms) { + TF_CODING_ERROR("'xforms' pointer is null."); + return false; + } + + // float-precision uses uncached conversion from double-precision. + VtMatrix4dArray xforms4d; + if (GetJointWorldBindTransforms(&xforms4d)) { + _Convert4dXformsTo4f(xforms4d, xforms); + return true; + } + return false; +} + + +template +bool +UsdSkel_SkelDefinition::_GetJointWorldInverseBindTransforms( + VtArray* xforms) { - int flags = _flags; + const int flags = _flags; if (flags&_HaveBindPose) { if (!xforms) { @@ -194,66 +316,129 @@ UsdSkel_SkelDefinition::GetJointWorldInverseBindTransforms( return false; } - if (ARCH_UNLIKELY(!(flags&_WorldInverseBindXformsComputed))) { - _ComputeJointWorldInverseBindTransforms(); + if (ARCH_UNLIKELY(!(flags&ComputeFlag))) { + if (!_ComputeJointWorldInverseBindTransforms< + ComputeFlag,Matrix4>()) { + return false; + } } - *xforms = _jointWorldInverseBindXforms; + *xforms = _jointWorldInverseBindXforms.Get(); return true; } return false; } -void +template <> +bool +UsdSkel_SkelDefinition::GetJointWorldInverseBindTransforms( + VtMatrix4dArray* xforms) +{ + return _GetJointWorldInverseBindTransforms< + _WorldInverseBindXforms4dComputed>(xforms); +} + + +template <> +bool +UsdSkel_SkelDefinition::GetJointWorldInverseBindTransforms( + VtMatrix4fArray* xforms) +{ + return _GetJointWorldInverseBindTransforms< + _WorldInverseBindXforms4fComputed>(xforms); +} + + +template +bool UsdSkel_SkelDefinition::_ComputeJointWorldInverseBindTransforms() { TRACE_FUNCTION(); - std::lock_guard lock(_mutex); + VtArray jointWorldBindXforms; + if (TF_VERIFY(GetJointWorldBindTransforms(&jointWorldBindXforms))) { - VtMatrix4dArray xforms(_jointWorldBindXforms); - for(auto& xf : xforms) { - xf = xf.GetInverse(); - } - _jointWorldInverseBindXforms = xforms; + std::lock_guard lock(_mutex); + + _InvertTransforms( + jointWorldBindXforms, + &_jointWorldInverseBindXforms.Get()); - _flags = _flags|_WorldInverseBindXformsComputed; + _flags = _flags|ComputeFlag; + return true; + } + return false; } +template bool -UsdSkel_SkelDefinition::GetJointLocalInverseRestTransforms( - VtMatrix4dArray* xforms) +UsdSkel_SkelDefinition::_GetJointLocalInverseRestTransforms( + VtArray* xforms) { - int flags = _flags; + const int flags = _flags; if (flags&_HaveRestPose) { + if (!xforms) { TF_CODING_ERROR("'xforms' pointer is null."); + return false; } - if (ARCH_UNLIKELY(!(flags&_LocalInverseRestXformsComputed))) { - _ComputeJointLocalInverseRestTransforms(); + + if (ARCH_UNLIKELY(!(flags&ComputeFlag))) { + if (!_ComputeJointLocalInverseRestTransforms< + ComputeFlag,Matrix4>()) { + return false; + } } - *xforms = _jointLocalInverseRestXforms; + *xforms = _jointLocalInverseRestXforms.Get(); return true; } return false; } -void +template <> +bool +UsdSkel_SkelDefinition::GetJointLocalInverseRestTransforms( + VtMatrix4dArray* xforms) +{ + return _GetJointLocalInverseRestTransforms< + _LocalInverseRestXforms4dComputed>(xforms); + return false; +} + + +template <> +bool +UsdSkel_SkelDefinition::GetJointLocalInverseRestTransforms( + VtMatrix4fArray* xforms) +{ + return _GetJointLocalInverseRestTransforms< + _LocalInverseRestXforms4fComputed>(xforms); + return false; +} + + +template +bool UsdSkel_SkelDefinition::_ComputeJointLocalInverseRestTransforms() { TRACE_FUNCTION(); - std::lock_guard lock(_mutex); + VtArray jointLocalRestXforms; + if (TF_VERIFY(GetJointLocalRestTransforms(&jointLocalRestXforms))) { - VtMatrix4dArray xforms(_jointLocalRestXforms); - for (auto& xf : xforms) { - xf = xf.GetInverse(); - } - _jointLocalInverseRestXforms = xforms; + std::lock_guard lock(_mutex); + + _InvertTransforms( + jointLocalRestXforms, + &_jointLocalInverseRestXforms.Get()); + + _flags = _flags|ComputeFlag; - _flags = _flags|_LocalInverseRestXformsComputed; + return true; + } + return false; } diff --git a/pxr/usd/lib/usdSkel/skelDefinition.h b/pxr/usd/lib/usdSkel/skelDefinition.h index a651f40234..a7acd32994 100644 --- a/pxr/usd/lib/usdSkel/skelDefinition.h +++ b/pxr/usd/lib/usdSkel/skelDefinition.h @@ -29,6 +29,9 @@ #include "pxr/pxr.h" #include "pxr/usd/usdSkel/api.h" +#include "pxr/base/gf/matrix4d.h" +#include "pxr/base/gf/matrix4f.h" + #include "pxr/base/tf/declarePtrs.h" #include "pxr/base/tf/hashmap.h" #include "pxr/base/tf/refBase.h" @@ -73,30 +76,60 @@ class UsdSkel_SkelDefinition : public TfRefBase, public TfWeakBase const UsdSkelTopology& GetTopology() const { return _topology; } /// Returns rest pose joint transforms in joint-local space. - bool GetJointLocalRestTransforms(VtMatrix4dArray* xforms); + template + bool GetJointLocalRestTransforms(VtArray* xforms); /// Returns rest pose joint transforms in skel space. - bool GetJointSkelRestTransforms(VtMatrix4dArray* xforms); + template + bool GetJointSkelRestTransforms(VtArray* xforms); /// Returns bind pose joint transforms in world space. - bool GetJointWorldBindTransforms(VtMatrix4dArray* xforms); + template + bool GetJointWorldBindTransforms(VtArray* xforms); /// Returns the inverse of the world-space joint bind transforms. - bool GetJointWorldInverseBindTransforms(VtMatrix4dArray* xforms); + template + bool GetJointWorldInverseBindTransforms(VtArray* xforms); /// Returns the inverse of the local-space rest transforms. - bool GetJointLocalInverseRestTransforms(VtMatrix4dArray* xforms); + template + bool GetJointLocalInverseRestTransforms(VtArray* xforms); private: UsdSkel_SkelDefinition(); bool _Init(const UsdSkelSkeleton& skel); - void _ComputeJointSkelRestTransforms(); + template + bool _GetJointSkelRestTransforms(VtArray* xforms); + + template + bool _GetJointWorldInverseBindTransforms(VtArray* xforms); + + template + bool _GetJointLocalInverseRestTransforms(VtArray* xforms); + + template + bool _ComputeJointSkelRestTransforms(); - void _ComputeJointWorldInverseBindTransforms(); + template + bool _ComputeJointWorldInverseBindTransforms(); - void _ComputeJointLocalInverseRestTransforms(); + template + bool _ComputeJointLocalInverseRestTransforms(); + + /// Helper for managing a set of cached transforms + /// with both float and double precision. + struct _XformHolder { + template + VtArray& Get(); + + template + const VtArray& Get() const; + + VtMatrix4dArray xforms4d; + VtMatrix4fArray xforms4f; + }; private: UsdSkelSkeleton _skel; @@ -109,9 +142,10 @@ class UsdSkel_SkelDefinition : public TfRefBase, public TfWeakBase // consumption tasks generally require different transforms. // They are cached on the definition in order to provide cache // sharing across instanced skeletons. - VtMatrix4dArray _jointSkelRestXforms; - VtMatrix4dArray _jointWorldInverseBindXforms; - VtMatrix4dArray _jointLocalInverseRestXforms; + _XformHolder _jointSkelRestXforms; + _XformHolder _jointWorldInverseBindXforms; + _XformHolder _jointLocalInverseRestXforms; + std::atomic _flags; std::mutex _mutex; }; diff --git a/pxr/usd/lib/usdSkel/skeletonQuery.cpp b/pxr/usd/lib/usdSkel/skeletonQuery.cpp index 53617c26f3..057b8f7437 100644 --- a/pxr/usd/lib/usdSkel/skeletonQuery.cpp +++ b/pxr/usd/lib/usdSkel/skeletonQuery.cpp @@ -23,10 +23,10 @@ // #include "pxr/usd/usdSkel/skeletonQuery.h" -#include "pxr/usd/usd/prim.h" +#include "pxr/base/tf/span.h" +#include "pxr/usd/usd/prim.h" #include "pxr/usd/usdGeom/xformCache.h" - #include "pxr/usd/usdSkel/animQuery.h" #include "pxr/usd/usdSkel/cacheImpl.h" #include "pxr/usd/usdSkel/skeleton.h" @@ -42,7 +42,7 @@ UsdSkelSkeletonQuery::UsdSkelSkeletonQuery( const UsdSkelAnimQuery& animQuery) : _definition(definition), _animQuery(animQuery) { - if(definition && animQuery) { + if (definition && animQuery) { _animToSkelMapper = UsdSkelAnimMapper(animQuery.GetJointOrder(), definition->GetJointOrder()); } @@ -65,19 +65,20 @@ UsdSkelSkeletonQuery::_HasMappableAnim() const } +template bool -UsdSkelSkeletonQuery::ComputeJointLocalTransforms(VtMatrix4dArray* xforms, +UsdSkelSkeletonQuery::ComputeJointLocalTransforms(VtArray* xforms, UsdTimeCode time, bool atRest) const { TRACE_FUNCTION(); - if(!xforms) { + if (!xforms) { TF_CODING_ERROR("'xforms' pointer is null."); return false; } - if(TF_VERIFY(IsValid(), "invalid skeleton query.")) { + if (TF_VERIFY(IsValid(), "invalid skeleton query.")) { atRest = atRest || !_HasMappableAnim(); return _ComputeJointLocalTransforms(xforms, time, atRest); } @@ -85,16 +86,26 @@ UsdSkelSkeletonQuery::ComputeJointLocalTransforms(VtMatrix4dArray* xforms, } +template USDSKEL_API bool +UsdSkelSkeletonQuery::ComputeJointLocalTransforms(VtArray*, + UsdTimeCode, bool) const; + +template USDSKEL_API bool +UsdSkelSkeletonQuery::ComputeJointLocalTransforms(VtArray*, + UsdTimeCode, bool) const; + + +template bool -UsdSkelSkeletonQuery::_ComputeJointLocalTransforms(VtMatrix4dArray* xforms, +UsdSkelSkeletonQuery::_ComputeJointLocalTransforms(VtArray* xforms, UsdTimeCode time, bool atRest) const { - if(atRest) { + if (atRest) { return _definition->GetJointLocalRestTransforms(xforms); } - if(_animToSkelMapper.IsSparse()) { + if (_animToSkelMapper.IsSparse()) { // Animation does not override all values; // Need to first fill in bind transforms. if (!_definition->GetJointLocalRestTransforms(xforms)) { @@ -108,8 +119,8 @@ UsdSkelSkeletonQuery::_ComputeJointLocalTransforms(VtMatrix4dArray* xforms, } } - VtMatrix4dArray animXforms; - if(_animQuery.ComputeJointLocalTransforms(&animXforms, time)) { + VtArray animXforms; + if (_animQuery.ComputeJointLocalTransforms(&animXforms, time)) { return _animToSkelMapper.RemapTransforms(animXforms, xforms); } else { // Failed to compute anim xforms. @@ -124,19 +135,20 @@ UsdSkelSkeletonQuery::_ComputeJointLocalTransforms(VtMatrix4dArray* xforms, } +template bool -UsdSkelSkeletonQuery::ComputeJointSkelTransforms(VtMatrix4dArray* xforms, +UsdSkelSkeletonQuery::ComputeJointSkelTransforms(VtArray* xforms, UsdTimeCode time, bool atRest) const { TRACE_FUNCTION(); - if(!xforms) { + if (!xforms) { TF_CODING_ERROR("'xforms' pointer is null."); return false; } - if(TF_VERIFY(IsValid(), "invalid skeleton query.")) { + if (TF_VERIFY(IsValid(), "invalid skeleton query.")) { atRest = atRest || !_HasMappableAnim(); return _ComputeJointSkelTransforms(xforms, time, atRest); } @@ -144,20 +156,37 @@ UsdSkelSkeletonQuery::ComputeJointSkelTransforms(VtMatrix4dArray* xforms, } +template USDSKEL_API bool +UsdSkelSkeletonQuery::ComputeJointSkelTransforms(VtArray*, + UsdTimeCode, bool) const; + +template USDSKEL_API bool +UsdSkelSkeletonQuery::ComputeJointSkelTransforms(VtArray*, + UsdTimeCode, bool) const; + + +template bool -UsdSkelSkeletonQuery::_ComputeJointSkelTransforms(VtMatrix4dArray* xforms, +UsdSkelSkeletonQuery::_ComputeJointSkelTransforms(VtArray* xforms, UsdTimeCode time, bool atRest) const { - if(atRest) { + if (atRest) { // This is cached on the definition. return _definition->GetJointSkelRestTransforms(xforms); } - VtMatrix4dArray localXforms; - if(_ComputeJointLocalTransforms(&localXforms, time, atRest)) { + if (!xforms) { + TF_CODING_ERROR("'xforms' is null"); + return false; + } + + VtArray localXforms; + if (_ComputeJointLocalTransforms(&localXforms, time, atRest)) { const auto& topology = _definition->GetTopology(); - return UsdSkelConcatJointTransforms(topology, localXforms, xforms); + + xforms->resize(topology.size()); + return UsdSkelConcatJointTransforms(topology, localXforms, *xforms); } return false; } @@ -166,13 +195,15 @@ UsdSkelSkeletonQuery::_ComputeJointSkelTransforms(VtMatrix4dArray* xforms, namespace { /// Compute `out = a * b`. +template void -_MultTransforms(const GfMatrix4d* a, - const GfMatrix4d* b, - GfMatrix4d* out, - size_t count) +_MultTransforms(TfSpan a, + TfSpan b, + TfSpan out) { - for (size_t i = 0; i < count; ++i) { + TF_DEV_AXIOM(a.size() == b.size() && a.size() == out.size()); + + for (ptrdiff_t i = 0; i < out.size(); ++i) { out[i] = a[i] * b[i]; } } @@ -180,9 +211,10 @@ _MultTransforms(const GfMatrix4d* a, } // namespace +template bool UsdSkelSkeletonQuery::ComputeJointRestRelativeTransforms( - VtMatrix4dArray* xforms, UsdTimeCode time) const + VtArray* xforms, UsdTimeCode time) const { TRACE_FUNCTION(); @@ -191,27 +223,26 @@ UsdSkelSkeletonQuery::ComputeJointRestRelativeTransforms( return false; } - if(TF_VERIFY(IsValid(), "invalid skeleton query.")) { + if (TF_VERIFY(IsValid(), "invalid skeleton query.")) { if (_HasMappableAnim()) { // jointLocalXf = restRelativeXf * restXf // restRelativeXf = jointLocalXf * inv(restXf) // Pull inverse rest transforms first // They are cached on the definition. - VtMatrix4dArray invRestXforms; + VtArray invRestXforms; if (_definition->GetJointLocalInverseRestTransforms( &invRestXforms)) { - VtMatrix4dArray localXforms; + VtArray localXforms; if (_ComputeJointLocalTransforms( &localXforms, time, /*atRest*/ false)) { if (TF_VERIFY(localXforms.size() == invRestXforms.size())) { xforms->resize(localXforms.size()); - _MultTransforms(localXforms.cdata(), - invRestXforms.cdata(), - xforms->data(), xforms->size()); + _MultTransforms(localXforms, + invRestXforms, *xforms); return true; } } @@ -223,7 +254,7 @@ UsdSkelSkeletonQuery::ComputeJointRestRelativeTransforms( } } else { // No bound animation, so rest relative transforms are identity. - xforms->assign(GetTopology().GetNumJoints(), GfMatrix4d(1)); + xforms->assign(GetTopology().size(), Matrix4(1)); return true; } } @@ -231,68 +262,87 @@ UsdSkelSkeletonQuery::ComputeJointRestRelativeTransforms( } +template USDSKEL_API bool +UsdSkelSkeletonQuery::ComputeJointRestRelativeTransforms( + VtArray*, UsdTimeCode) const; + +template USDSKEL_API bool +UsdSkelSkeletonQuery::ComputeJointRestRelativeTransforms( + VtArray*, UsdTimeCode) const; + + +template bool -UsdSkelSkeletonQuery::ComputeJointWorldTransforms(VtMatrix4dArray* xforms, +UsdSkelSkeletonQuery::ComputeJointWorldTransforms(VtArray* xforms, UsdGeomXformCache* xfCache, bool atRest) const { TRACE_FUNCTION(); + if (!xforms) { + TF_CODING_ERROR("'xforms' is null"); + return false; + } + if (!xfCache) { - TF_CODING_ERROR("'xfCache' pointer is null."); + TF_CODING_ERROR("'xfCache' is null."); return false; } - VtMatrix4dArray localXforms; + VtArray localXforms; if (ComputeJointLocalTransforms(&localXforms, xfCache->GetTime(), atRest)) { const auto& topology = _definition->GetTopology(); - GfMatrix4d rootXform = xfCache->GetLocalToWorldTransform(GetPrim()); + const Matrix4 rootXform(xfCache->GetLocalToWorldTransform(GetPrim())); + + xforms->resize(topology.size()); return UsdSkelConcatJointTransforms(topology, localXforms, - xforms, &rootXform); + *xforms, &rootXform); } return false; } +template USDSKEL_API bool +UsdSkelSkeletonQuery::ComputeJointWorldTransforms( + VtArray*, UsdGeomXformCache*, bool) const; + +template USDSKEL_API bool +UsdSkelSkeletonQuery::ComputeJointWorldTransforms( + VtArray*, UsdGeomXformCache*, bool) const; + + +template bool -UsdSkelSkeletonQuery::ComputeSkinningTransforms(VtMatrix4dArray* xforms, +UsdSkelSkeletonQuery::ComputeSkinningTransforms(VtArray* xforms, UsdTimeCode time) const { TRACE_FUNCTION(); - if(!xforms) { + if (!xforms) { TF_CODING_ERROR("'xforms' pointer is null."); return false; } - if(TF_VERIFY(IsValid(), "invalid skeleton query.")) { + if (TF_VERIFY(IsValid(), "invalid skeleton query.")) { return _ComputeSkinningTransforms(xforms, time); } return false; } -namespace { +template USDSKEL_API bool +UsdSkelSkeletonQuery::ComputeSkinningTransforms(VtArray*, + UsdTimeCode) const; -/// Compute xforms = premult*xforms. -void -_PreMultXforms(const VtMatrix4dArray& premult, VtMatrix4dArray* xforms) -{ - TRACE_FUNCTION(); - - const GfMatrix4d* premultData = premult.cdata(); - GfMatrix4d* xformsData = xforms->data(); - for(size_t i = 0; i < xforms->size(); ++i) { - xformsData[i] = premultData[i] * xformsData[i]; - } -} +template USDSKEL_API bool +UsdSkelSkeletonQuery::ComputeSkinningTransforms(VtArray*, + UsdTimeCode) const; -} // namespace - +template bool -UsdSkelSkeletonQuery::_ComputeSkinningTransforms(VtMatrix4dArray* xforms, +UsdSkelSkeletonQuery::_ComputeSkinningTransforms(VtArray* xforms, UsdTimeCode time) const { if (ComputeJointSkelTransforms(xforms, time)) { @@ -301,7 +351,7 @@ UsdSkelSkeletonQuery::_ComputeSkinningTransforms(VtMatrix4dArray* xforms, // skel-space inverse rest transforms are cached on-demand // on the definition - VtMatrix4dArray inverseBindXforms; + VtArray inverseBindXforms; if (!_definition->GetJointWorldInverseBindTransforms( &inverseBindXforms)) { TF_WARN("%s -- Failed fetching bind transforms. The " @@ -311,9 +361,9 @@ UsdSkelSkeletonQuery::_ComputeSkinningTransforms(VtMatrix4dArray* xforms, return false; } - if(xforms->size() == inverseBindXforms.size()) { + if (xforms->size() == inverseBindXforms.size()) { // xforms = inverseBindXforms * xforms - _PreMultXforms(inverseBindXforms, xforms); + _MultTransforms(inverseBindXforms, *xforms, *xforms); return true; } else { TF_WARN("%s -- Size of computed joints transforms [%zu] does not " @@ -326,8 +376,10 @@ UsdSkelSkeletonQuery::_ComputeSkinningTransforms(VtMatrix4dArray* xforms, } +template bool -UsdSkelSkeletonQuery::GetJointWorldBindTransforms(VtMatrix4dArray* xforms) const +UsdSkelSkeletonQuery::GetJointWorldBindTransforms( + VtArray* xforms) const { if (TF_VERIFY(IsValid(), "invalid skeleton query.")) { return _definition->GetJointWorldBindTransforms(xforms); @@ -336,6 +388,15 @@ UsdSkelSkeletonQuery::GetJointWorldBindTransforms(VtMatrix4dArray* xforms) const } +template USDSKEL_API bool +UsdSkelSkeletonQuery::GetJointWorldBindTransforms( + VtArray* xforms) const; + +template USDSKEL_API bool +UsdSkelSkeletonQuery::GetJointWorldBindTransforms( + VtArray* xforms) const; + + UsdPrim UsdSkelSkeletonQuery::GetPrim() const { @@ -346,7 +407,7 @@ UsdSkelSkeletonQuery::GetPrim() const const UsdSkelSkeleton& UsdSkelSkeletonQuery::GetSkeleton() const { - if(TF_VERIFY(IsValid(), "invalid skeleton query.")) { + if (TF_VERIFY(IsValid(), "invalid skeleton query.")) { return _definition->GetSkeleton(); } static UsdSkelSkeleton null; @@ -364,10 +425,10 @@ UsdSkelSkeletonQuery::GetAnimQuery() const const UsdSkelTopology& UsdSkelSkeletonQuery::GetTopology() const { - if(TF_VERIFY(IsValid(), "invalid skeleton query.")) { + if (TF_VERIFY(IsValid(), "invalid skeleton query.")) { return _definition->GetTopology(); } - static const UsdSkelTopology null; + static const UsdSkelTopology null{}; return null; } @@ -375,7 +436,7 @@ UsdSkelSkeletonQuery::GetTopology() const VtTokenArray UsdSkelSkeletonQuery::GetJointOrder() const { - if(TF_VERIFY(IsValid(), "invalid skeleton query.")) { + if (TF_VERIFY(IsValid(), "invalid skeleton query.")) { return _definition->GetJointOrder(); } return VtTokenArray(); @@ -385,7 +446,7 @@ UsdSkelSkeletonQuery::GetJointOrder() const std::string UsdSkelSkeletonQuery::GetDescription() const { - if(IsValid()) { + if (IsValid()) { return TfStringPrintf( "UsdSkelSkeletonQuery (skel = <%s>, anim = <%s>)", GetPrim().GetPath().GetText(), diff --git a/pxr/usd/lib/usdSkel/skeletonQuery.h b/pxr/usd/lib/usdSkel/skeletonQuery.h index 8deac1a698..26ad769b99 100644 --- a/pxr/usd/lib/usdSkel/skeletonQuery.h +++ b/pxr/usd/lib/usdSkel/skeletonQuery.h @@ -130,8 +130,9 @@ class UsdSkelSkeletonQuery /// from the rest pose as a fallback value. /// If valid transforms cannot be computed for the animation source, the /// \p xforms are instead set to the rest transforms. + template USDSKEL_API - bool ComputeJointLocalTransforms(VtMatrix4dArray* xforms, + bool ComputeJointLocalTransforms(VtArray* xforms, UsdTimeCode time, bool atRest=false) const; @@ -140,8 +141,9 @@ class UsdSkelSkeletonQuery /// ComputeJointLocalTransforms(). If \p atRest is true, any bound animation /// source is ignored, and transforms are computed from the rest pose. /// The skeleton-space transforms of the rest pose are cached internally. + template USDSKEL_API - bool ComputeJointSkelTransforms(VtMatrix4dArray* xforms, + bool ComputeJointSkelTransforms(VtArray* xforms, UsdTimeCode time, bool atRest=false) const; @@ -151,8 +153,9 @@ class UsdSkelSkeletonQuery /// \code /// restRelativeTransform * restTransform = jointLocalTransform /// \endcode + template USDSKEL_API - bool ComputeJointRestRelativeTransforms(VtMatrix4dArray* xforms, + bool ComputeJointRestRelativeTransforms(VtArray* xforms, UsdTimeCode time) const; /// Compute joint transforms in world space, at whatever time is configured @@ -162,8 +165,9 @@ class UsdSkelSkeletonQuery /// by the local-to-world transform of the Skeleton prim. /// If \p atRest is true, any bound animation source is ignored, and /// transforms are computed from the rest pose. + template USDSKEL_API - bool ComputeJointWorldTransforms(VtMatrix4dArray* xforms, + bool ComputeJointWorldTransforms(VtArray* xforms, UsdGeomXformCache* xfCache, bool atRest=false) const; @@ -176,13 +180,15 @@ class UsdSkelSkeletonQuery /// \endcode /// /// These are the transforms usually required for skinning. + template USDSKEL_API - bool ComputeSkinningTransforms(VtMatrix4dArray* xforms, + bool ComputeSkinningTransforms(VtArray* xforms, UsdTimeCode time) const; /// Returns the world space joint transforms at bind time. + template USDSKEL_API - bool GetJointWorldBindTransforms(VtMatrix4dArray* xforms) const; + bool GetJointWorldBindTransforms(VtArray* xforms) const; USDSKEL_API std::string GetDescription() const; @@ -195,15 +201,18 @@ class UsdSkelSkeletonQuery bool _HasMappableAnim() const; - bool _ComputeJointLocalTransforms(VtMatrix4dArray* xforms, + template + bool _ComputeJointLocalTransforms(VtArray* xforms, UsdTimeCode time, bool atRest=false) const; - bool _ComputeJointSkelTransforms(VtMatrix4dArray* xforms, + template + bool _ComputeJointSkelTransforms(VtArray* xforms, UsdTimeCode time, bool atRest=false) const; - bool _ComputeSkinningTransforms(VtMatrix4dArray* xforms, + template + bool _ComputeSkinningTransforms(VtArray* xforms, UsdTimeCode time) const; private: diff --git a/pxr/usd/lib/usdSkel/skinningQuery.cpp b/pxr/usd/lib/usdSkel/skinningQuery.cpp index 860eb7847e..38fd7c6590 100644 --- a/pxr/usd/lib/usdSkel/skinningQuery.cpp +++ b/pxr/usd/lib/usdSkel/skinningQuery.cpp @@ -23,6 +23,9 @@ // #include "pxr/usd/usdSkel/skinningQuery.h" +#include "pxr/base/gf/matrix4d.h" +#include "pxr/base/gf/matrix4f.h" + #include "pxr/usd/usd/attribute.h" #include "pxr/usd/usd/prim.h" #include "pxr/usd/usd/relationship.h" @@ -174,7 +177,7 @@ bool UsdSkelSkinningQuery::GetJointOrder(VtTokenArray* jointOrder) const { if (jointOrder) { - if(_jointOrder) { + if (_jointOrder) { *jointOrder = *_jointOrder; return true; } @@ -299,55 +302,67 @@ UsdSkelSkinningQuery::ComputeVaryingJointInfluences(size_t numPoints, } +template bool -UsdSkelSkinningQuery::ComputeSkinnedPoints(const VtMatrix4dArray& xforms, +UsdSkelSkinningQuery::ComputeSkinnedPoints(const VtArray& xforms, VtVec3fArray* points, UsdTimeCode time) const { TRACE_FUNCTION(); - if(!points) { + if (!points) { TF_CODING_ERROR("'points' pointer is null."); return false; } VtIntArray jointIndices; VtFloatArray jointWeights; - if(ComputeVaryingJointInfluences(points->size(), &jointIndices, - &jointWeights, time)) { + if (ComputeVaryingJointInfluences(points->size(), &jointIndices, + &jointWeights, time)) { // If the binding site has a custom joint ordering, the query will have // a mapper that should be used to reorder transforms // (skel order -> binding order) - VtMatrix4dArray orderedXforms(xforms); - if(_mapper) { - if(!_mapper->RemapTransforms(xforms, &orderedXforms)) { + VtArray orderedXforms(xforms); + if (_mapper) { + if (!_mapper->RemapTransforms(xforms, &orderedXforms)) { return false; } } - GfMatrix4d geomBindXform = GetGeomBindTransform(time); + const Matrix4 geomBindXform(GetGeomBindTransform(time)); return UsdSkelSkinPointsLBS(geomBindXform, orderedXforms, jointIndices, jointWeights, - _numInfluencesPerComponent, points); + _numInfluencesPerComponent, + *points); } return false; } +template USDSKEL_API bool +UsdSkelSkinningQuery::ComputeSkinnedPoints(const VtArray&, + VtVec3fArray*, UsdTimeCode) const; + +template USDSKEL_API bool +UsdSkelSkinningQuery::ComputeSkinnedPoints(const VtArray&, + VtVec3fArray*, UsdTimeCode) const; + + +template bool -UsdSkelSkinningQuery::ComputeSkinnedTransform(const VtMatrix4dArray& xforms, - GfMatrix4d* xform, +UsdSkelSkinningQuery::ComputeSkinnedTransform(const VtArray& xforms, + Matrix4* xform, UsdTimeCode time) const { TRACE_FUNCTION(); - if(!xform) { + if (!xform) { TF_CODING_ERROR("'xform' pointer is null."); return false; } - if(!IsRigidlyDeformed()) { + if (!IsRigidlyDeformed()) { TF_CODING_ERROR("Attempted to skin a transform, but " "joint influences are not constant."); return false; @@ -355,19 +370,19 @@ UsdSkelSkinningQuery::ComputeSkinnedTransform(const VtMatrix4dArray& xforms, VtIntArray jointIndices; VtFloatArray jointWeights; - if(ComputeJointInfluences(&jointIndices, &jointWeights, time)) { + if (ComputeJointInfluences(&jointIndices, &jointWeights, time)) { // If the binding site has a custom joint ordering, the query will have // a mapper that should be used to reorder transforms // (skel order -> binding order) - VtMatrix4dArray orderedXforms(xforms); - if(_mapper) { - if(!_mapper->Remap(xforms, &orderedXforms)) { + VtArray orderedXforms(xforms); + if (_mapper) { + if (!_mapper->Remap(xforms, &orderedXforms)) { return false; } } - GfMatrix4d geomBindXform = GetGeomBindTransform(time); + const Matrix4 geomBindXform(GetGeomBindTransform(time)); return UsdSkelSkinTransformLBS(geomBindXform, orderedXforms, jointIndices, jointWeights, xform); } @@ -375,32 +390,46 @@ UsdSkelSkinningQuery::ComputeSkinnedTransform(const VtMatrix4dArray& xforms, } +template USDSKEL_API bool +UsdSkelSkinningQuery::ComputeSkinnedTransform( + const VtArray&, GfMatrix4d*, UsdTimeCode time) const; + +template USDSKEL_API bool +UsdSkelSkinningQuery::ComputeSkinnedTransform( + const VtArray&, GfMatrix4f*, UsdTimeCode time) const; + + +template float UsdSkelSkinningQuery::ComputeExtentsPadding( - const VtMatrix4dArray& skelRestXforms, + const VtArray& skelRestXforms, const UsdGeomBoundable& boundable) const { // Don't use default time; properties may be keyed (and still unvarying) // We do, however, expect the computed quantity to not be time varying. - UsdTimeCode time = UsdTimeCode::EarliestTime(); + const UsdTimeCode time = UsdTimeCode::EarliestTime(); VtVec3fArray boundableExtent; - if(boundable && + if (boundable && boundable.GetExtentAttr().Get(&boundableExtent, time) && boundableExtent.size() == 2) { - VtVec3fArray jointsExtent; - if(UsdSkelComputeJointsExtent(skelRestXforms, &jointsExtent)) { + GfRange3f jointsRange; + if (UsdSkelComputeJointsExtent(skelRestXforms, &jointsRange)) { - GfRange3d range = + // Get the aligned range of the gprim in its bind pose. + const GfRange3d gprimRange = GfBBox3d(GfRange3d(boundableExtent[0], boundableExtent[1]), - GetGeomBindTransform(time)).ComputeAlignedRange(); + GetGeomBindTransform(time)) + .ComputeAlignedRange(); - GfVec3f minDiff = jointsExtent[0] - GfVec3f(range.GetMin()); - GfVec3f maxDiff = GfVec3f(range.GetMax()) - jointsExtent[1]; + const GfVec3f minDiff = + jointsRange.GetMin() - GfVec3f(gprimRange.GetMin()); + const GfVec3f maxDiff = + GfVec3f(gprimRange.GetMax()) - jointsRange.GetMax(); float padding = 0.0f; - for(int i = 0; i < 3; ++i) { + for (int i = 0; i < 3; ++i) { padding = std::max(padding, minDiff[i]); padding = std::max(padding, maxDiff[i]); } @@ -411,6 +440,15 @@ UsdSkelSkinningQuery::ComputeExtentsPadding( } +template USDSKEL_API float +UsdSkelSkinningQuery::ComputeExtentsPadding( + const VtArray&, const UsdGeomBoundable&) const; + +template USDSKEL_API float +UsdSkelSkinningQuery::ComputeExtentsPadding( + const VtArray&, const UsdGeomBoundable&) const; + + GfMatrix4d UsdSkelSkinningQuery::GetGeomBindTransform(UsdTimeCode time) const { diff --git a/pxr/usd/lib/usdSkel/skinningQuery.h b/pxr/usd/lib/usdSkel/skinningQuery.h index 91eafcbeaf..595d46e686 100644 --- a/pxr/usd/lib/usdSkel/skinningQuery.h +++ b/pxr/usd/lib/usdSkel/skinningQuery.h @@ -174,8 +174,9 @@ class UsdSkelSkinningQuery /// at time \p time (which will typically be unvarying). /// /// \sa UsdSkelSkeletonQuery::ComputeSkinningTransforms + template USDSKEL_API - bool ComputeSkinnedPoints(const VtMatrix4dArray& xforms, + bool ComputeSkinnedPoints(const VtArray& xforms, VtVec3fArray* points, UsdTimeCode time=UsdTimeCode::Default()) const; @@ -188,9 +189,10 @@ class UsdSkelSkinningQuery /// no transform will be computed, and the function will return false. /// /// \sa UsdSkelSkeletonQuery::ComputeSkinningTransforms + template USDSKEL_API - bool ComputeSkinnedTransform(const VtMatrix4dArray& xforms, - GfMatrix4d* xform, + bool ComputeSkinnedTransform(const VtArray& xforms, + Matrix4* xform, UsdTimeCode time=UsdTimeCode::Default()) const; /// Helper for computing an *approximate* padding for use in extents @@ -199,8 +201,9 @@ class UsdSkelSkinningQuery /// at rest -- and the extents of the skinned primitive. /// This is intended to provide a suitable, constant metric for padding /// joint extents as computed by UsdSkelComputeJointsExtent. + template USDSKEL_API - float ComputeExtentsPadding(const VtMatrix4dArray& skelRestXforms, + float ComputeExtentsPadding(const VtArray& skelRestXforms, const UsdGeomBoundable& boundable) const; USDSKEL_API diff --git a/pxr/usd/lib/usdSkel/topology.cpp b/pxr/usd/lib/usdSkel/topology.cpp index 3b2eeddace..1e2e30e2d5 100644 --- a/pxr/usd/lib/usdSkel/topology.cpp +++ b/pxr/usd/lib/usdSkel/topology.cpp @@ -39,9 +39,9 @@ using _PathIndexMap = std::unordered_map; int _GetParentIndex(const _PathIndexMap& pathMap, const SdfPath& path) { - if(path.IsPrimPath()) { + if (path.IsPrimPath()) { - bool isAbsPath = path.IsAbsolutePath(); + const bool isAbsPath = path.IsAbsolutePath(); // XXX: A topology is typically constructed using relative // paths, but we make this work regardless. @@ -60,10 +60,11 @@ _GetParentIndex(const _PathIndexMap& pathMap, const SdfPath& path) // Recurse over all parent paths, not just the direct parent. // For instance, if the map includes only paths 'a' and 'a/b/c', // 'a' will be treated as the parent of 'a/b/c'. - for (SdfPath p = path.GetParentPath(); p != end; p = p.GetParentPath()) { + for (SdfPath p = path.GetParentPath(); + p != end; p = p.GetParentPath()) { - auto it = pathMap.find(p); - if(it != pathMap.end()) { + const auto it = pathMap.find(p); + if (it != pathMap.end()) { return it->second; } } @@ -73,72 +74,56 @@ _GetParentIndex(const _PathIndexMap& pathMap, const SdfPath& path) VtIntArray -_ComputeParentIndicesFromPaths(const SdfPath* paths, size_t size) +_ComputeParentIndicesFromPaths(TfSpan paths) { TRACE_FUNCTION(); _PathIndexMap pathMap; - for(size_t i = 0; i < size; ++i) { + for (ptrdiff_t i = 0; i < paths.size(); ++i) { pathMap[paths[i]] = static_cast(i); } VtIntArray parentIndices; - parentIndices.assign(size, -1); + parentIndices.assign(paths.size(), -1); - int* parentIndicesData = parentIndices.data(); - for(size_t i = 0; i < size; ++i) { - parentIndicesData[i] = _GetParentIndex(pathMap, paths[i]); + const auto parentIndicesSpan = TfMakeSpan(parentIndices); + for (ptrdiff_t i = 0; i < paths.size(); ++i) { + parentIndicesSpan[i] = _GetParentIndex(pathMap, paths[i]); } return parentIndices; } VtIntArray -_ComputeParentIndicesFromTokens(const TfToken* tokens, size_t size) +_ComputeParentIndicesFromTokens(TfSpan tokens) { // Convert tokens to paths. - SdfPathVector paths(size); - for(size_t i = 0; i < size; ++i) { + SdfPathVector paths(tokens.size()); + for (ptrdiff_t i = 0; i < tokens.size(); ++i) { paths[i] = SdfPath(tokens[i].GetString()); } - return _ComputeParentIndicesFromPaths(paths.data(), size); + return _ComputeParentIndicesFromPaths(paths); } } // namespace -UsdSkelTopology::UsdSkelTopology() - : _parentIndicesData(nullptr) -{} - - /// TODO: It's convenient to provide this constructor, but /// do we require any common methods to handle the token->path /// conversion? -UsdSkelTopology::UsdSkelTopology(const VtTokenArray& paths) - : UsdSkelTopology(paths.cdata(), paths.size()) -{} - - -UsdSkelTopology::UsdSkelTopology(const TfToken* paths, size_t size) - : UsdSkelTopology(_ComputeParentIndicesFromTokens(paths, size)) +UsdSkelTopology::UsdSkelTopology(TfSpan paths) + : UsdSkelTopology(_ComputeParentIndicesFromTokens(paths)) {} -UsdSkelTopology::UsdSkelTopology(const SdfPathVector& paths) - : UsdSkelTopology(paths.data(), paths.size()) -{} - - -UsdSkelTopology::UsdSkelTopology(const SdfPath* paths, size_t size) - : UsdSkelTopology(_ComputeParentIndicesFromPaths(paths, size)) +UsdSkelTopology::UsdSkelTopology(TfSpan paths) + : UsdSkelTopology(_ComputeParentIndicesFromPaths(paths)) {} UsdSkelTopology::UsdSkelTopology(const VtIntArray& parentIndices) - : _parentIndices(parentIndices), - _parentIndicesData(parentIndices.cdata()) + : _parentIndices(parentIndices) {} @@ -147,22 +132,19 @@ UsdSkelTopology::Validate(std::string* reason) const { TRACE_FUNCTION(); - if(!TF_VERIFY(GetNumJoints() == 0 || _parentIndicesData)) - return false; - - for(size_t i = 0; i < GetNumJoints(); ++i) { - int parent = _parentIndicesData[i]; - if(parent >= 0) { - if(ARCH_UNLIKELY(static_cast(parent) >= i)) { - if(static_cast(parent) == i) { - if(reason) { + for (size_t i = 0; i < size(); ++i) { + const int parent = _parentIndices[i]; + if (parent >= 0) { + if (ARCH_UNLIKELY(static_cast(parent) >= i)) { + if (static_cast(parent) == i) { + if (reason) { *reason = TfStringPrintf( "Joint %zu has itself as its parent.", i); } return false; } - if(reason) { + if (reason) { *reason = TfStringPrintf( "Joint %zu has mis-ordered parent %d. Joints are " "expected to be ordered with parent joints always " diff --git a/pxr/usd/lib/usdSkel/topology.h b/pxr/usd/lib/usdSkel/topology.h index c9a53baf5e..f3f3bfe2b0 100644 --- a/pxr/usd/lib/usdSkel/topology.h +++ b/pxr/usd/lib/usdSkel/topology.h @@ -29,6 +29,7 @@ #include "pxr/pxr.h" #include "pxr/usd/usdSkel/api.h" +#include "pxr/base/tf/span.h" #include "pxr/usd/sdf/path.h" #include "pxr/usd/sdf/types.h" @@ -45,8 +46,7 @@ class UsdSkelTopology { public: /// Construct an empty topology. - USDSKEL_API - UsdSkelTopology(); + UsdSkelTopology() = default; /// Construct a skel topology from \p paths, an array holding ordered joint /// paths as tokens. @@ -54,21 +54,11 @@ class UsdSkelTopology /// objects are already accessible, it is more efficient to use the /// construct taking an SdfPath array. USDSKEL_API - UsdSkelTopology(const VtTokenArray& paths); - - /// Construct a skel topology from \p paths, an array of size \p size, - /// holding ordered joint paths as tokens. - USDSKEL_API - UsdSkelTopology(const TfToken* paths, size_t size); + UsdSkelTopology(TfSpan paths); /// Construct a skel topology from \p paths, an array of joint paths. USDSKEL_API - UsdSkelTopology(const SdfPathVector& paths); - - /// Construct a skel topology from \p paths, an array of joints paths - /// of size \p size. - USDSKEL_API - UsdSkelTopology(const SdfPath* paths, size_t size); + UsdSkelTopology(TfSpan paths); /// Construct a skel topology from an array of parent indices. /// For each joint, this provides the parent index of that @@ -82,16 +72,18 @@ class UsdSkelTopology USDSKEL_API bool Validate(std::string* reason=nullptr) const; - inline const VtIntArray& GetParentIndices() const; + const VtIntArray& GetParentIndices() const { return _parentIndices; } - inline size_t GetNumJoints() const; + size_t GetNumJoints() const { return size(); } + + size_t size() const { return _parentIndices.size(); } /// Returns the parent joint of the \p index'th joint, /// Returns -1 for joints with no parent (roots). inline int GetParent(size_t index) const; /// Returns true if the \p index'th joint is a root joint. - inline bool IsRoot(size_t index) const; + bool IsRoot(size_t index) const { return GetParent(index) < 0; } bool operator==(const UsdSkelTopology& o) const; @@ -101,36 +93,14 @@ class UsdSkelTopology private: VtIntArray _parentIndices; - const int* _parentIndicesData; }; -const VtIntArray& -UsdSkelTopology::GetParentIndices() const -{ - return _parentIndices; -} - - -size_t -UsdSkelTopology::GetNumJoints() const -{ - return _parentIndices.size(); -} - - int UsdSkelTopology::GetParent(size_t index) const { TF_DEV_AXIOM(index < _parentIndices.size()); - return _parentIndicesData[index]; -} - - -bool -UsdSkelTopology::IsRoot(size_t index) const -{ - return GetParent(index) < 0; + return _parentIndices[index]; } diff --git a/pxr/usd/lib/usdSkel/utils.cpp b/pxr/usd/lib/usdSkel/utils.cpp index 6e5074073f..267bd62c1e 100644 --- a/pxr/usd/lib/usdSkel/utils.cpp +++ b/pxr/usd/lib/usdSkel/utils.cpp @@ -23,11 +23,12 @@ // #include "pxr/usd/usdSkel/utils.h" +#include "pxr/base/arch/hints.h" #include "pxr/base/gf/matrix3f.h" -#include "pxr/base/gf/matrix4d.h" #include "pxr/base/gf/range3f.h" #include "pxr/base/gf/rotation.h" #include "pxr/base/gf/vec3d.h" +#include "pxr/base/gf/vec3f.h" #include "pxr/base/tf/diagnostic.h" #include "pxr/base/work/loops.h" @@ -79,63 +80,64 @@ UsdSkelIsSkinnablePrim(const UsdPrim& prim) namespace { -/// Wrapper for parallel loops that execs in serial if \p count -/// is below a reasonable threading threshold. + +/// Wrapper for parallel loops that execs in serial based on the +/// \p inSerial flag, as well as the grain size. template void -_ParallelForN(size_t count, bool forceSerial, Fn&& callback) +_ParallelForN(size_t count, bool inSerial, Fn&& callback, size_t grainSize=1000) { - // XXX: Profiling shows that most of our loops only benefit - // from parallelism past this threshold. - const int threshold = 1000; - - if(count < threshold || forceSerial) { + if (inSerial || count < grainSize) { WorkSerialForN(count, callback); } else { - WorkParallelForN(count, callback); + WorkParallelForN(count, callback, grainSize); } } -} // namespace - +template void -_InvertTransforms(GfMatrix4d* xforms, size_t count) +_InvertTransforms(TfSpan xforms, TfSpan inverseXforms) { - _ParallelForN(count, false, - [xforms](size_t start, size_t end) + TF_DEV_AXIOM(xforms.size() == inverseXforms.size()); + + _ParallelForN(xforms.size(), false, + [&](size_t start, size_t end) { for (size_t i = start; i < end; ++i) { - xforms[i] = xforms[i].GetInverse(); + inverseXforms[i] = xforms[i].GetInverse(); } - }); + }, /*grainSize*/ 1000); } +template bool -UsdSkelConcatJointTransforms(const UsdSkelTopology& topology, - const GfMatrix4d* jointLocalXforms, - GfMatrix4d* xforms, - const GfMatrix4d* rootXform) +UsdSkel_ConcatJointTransforms(const UsdSkelTopology& topology, + TfSpan jointLocalXforms, + TfSpan xforms, + const Matrix4* rootXform) { - if(topology.GetNumJoints() > 0) { - if(!jointLocalXforms) { - TF_CODING_ERROR("'jointLocalXforms' pointer is null."); - return false; - } - if(!xforms) { - TF_CODING_ERROR("'xforms' pointer is null."); - return false; - } + TRACE_FUNCTION(); + + if (ARCH_UNLIKELY(jointLocalXforms.size() != topology.size())) { + TF_WARN("Size of jointLocalXforms [%td] != number of joints [%zu]", + jointLocalXforms.size(), topology.size()); + return false; + } + if (ARCH_UNLIKELY(xforms.size() != topology.size())) { + TF_WARN("Size of xforms [%td] != number of joints [%zu]", + xforms.size(), topology.size()); + return false; } - for(size_t i = 0; i < topology.GetNumJoints(); ++i) { - int parent = topology.GetParent(i); - if(parent >= 0) { - if(static_cast(parent) < i) { + for (size_t i = 0; i < topology.size(); ++i) { + const int parent = topology.GetParent(i); + if (parent >= 0) { + if (static_cast(parent) < i) { xforms[i] = jointLocalXforms[i] * xforms[parent]; } else { - if(static_cast(parent) == i) { + if (static_cast(parent) == i) { TF_WARN("Joint %zu has itself as its parent.", i); } else { TF_WARN("Joint %zu has mis-ordered parent %d. Joints are " @@ -147,7 +149,7 @@ UsdSkelConcatJointTransforms(const UsdSkelTopology& topology, } else { // Root joint. xforms[i] = jointLocalXforms[i]; - if(rootXform) { + if (rootXform) { xforms[i] *= (*rootXform); } } @@ -156,61 +158,104 @@ UsdSkelConcatJointTransforms(const UsdSkelTopology& topology, } +} // namespace + + bool UsdSkelConcatJointTransforms(const UsdSkelTopology& topology, - const VtMatrix4dArray& jointLocalXforms, - VtMatrix4dArray* xforms, + TfSpan jointLocalXforms, + TfSpan xforms, const GfMatrix4d* rootXform) { - TRACE_FUNCTION(); + return UsdSkel_ConcatJointTransforms(topology, jointLocalXforms, + xforms, rootXform); +} - if(jointLocalXforms.size() == topology.GetNumJoints()) { - xforms->resize(topology.GetNumJoints()); - return UsdSkelConcatJointTransforms(topology, jointLocalXforms.cdata(), - xforms->data(), rootXform); - } else { - TF_WARN("jointLocalXforms.size() [%zu] != number of joints [%zu].", - jointLocalXforms.size(), topology.GetNumJoints()); - } - return false; + +bool +UsdSkelConcatJointTransforms(const UsdSkelTopology& topology, + TfSpan jointLocalXforms, + TfSpan xforms, + const GfMatrix4f* rootXform) +{ + return UsdSkel_ConcatJointTransforms(topology, jointLocalXforms, + xforms, rootXform); } +// deprecated bool -UsdSkelComputeJointLocalTransforms(const UsdSkelTopology& topology, - const GfMatrix4d* xforms, - const GfMatrix4d* inverseXforms, - GfMatrix4d* jointLocalXforms, - const GfMatrix4d* rootInverseXform) +UsdSkelConcatJointTransforms(const UsdSkelTopology& topology, + const VtMatrix4dArray& localXforms, + VtMatrix4dArray* xforms, + const GfMatrix4d* rootXform) { - if(topology.GetNumJoints() > 0) { - if(!xforms) { - TF_CODING_ERROR("'xforms' pointer is null."); - return false; - } - if(!inverseXforms) { - TF_CODING_ERROR("'inverseXforms' pointer is null."); - return false; - } - if(!jointLocalXforms) { - TF_CODING_ERROR("'jointLocalXforms' pointer is null."); - return false; - } + if (!xforms) { + TF_CODING_ERROR("'xforms' is null"); + return false; } + xforms->resize(topology.size()); + return UsdSkelConcatJointTransforms( + topology, localXforms, *xforms, rootXform); +} + + +// deprecated +bool +UsdSkelConcatJointTransforms(const UsdSkelTopology& topology, + const GfMatrix4d* jointLocalXforms, + GfMatrix4d* xforms, + const GfMatrix4d* rootXform) +{ + return UsdSkelConcatJointTransforms( + topology, + TfSpan(jointLocalXforms, topology.size()), + TfSpan(xforms, topology.size()), + rootXform); +} +namespace { + + +template +bool +UsdSkel_ComputeJointLocalTransforms(const UsdSkelTopology& topology, + TfSpan xforms, + TfSpan inverseXforms, + TfSpan jointLocalXforms, + const Matrix4* rootInverseXform) +{ + TRACE_FUNCTION(); + + if (ARCH_UNLIKELY(xforms.size() != topology.size())) { + TF_WARN("Size of xforms [%td] != number of joints [%zu]", + xforms.size(), topology.size()); + return false; + } + if (ARCH_UNLIKELY(inverseXforms.size() != topology.size())) { + TF_WARN("Size of inverseXforms [%td] != number of joints [%zu]", + inverseXforms.size(), topology.size()); + return false; + } + if (ARCH_UNLIKELY(jointLocalXforms.size() != topology.size())) { + TF_WARN("Size of jointLocalXforms [%td] != number of joints [%zu]", + jointLocalXforms.size(), topology.size()); + return false; + } + // Skel-space transforms are computed as: // skelXform = jointLocalXform*parentSkelXform // So we want: // jointLocalXform = skelXform*inv(parentSkelXform) - for(size_t i = 0; i < topology.GetNumJoints(); ++i) { - int parent = topology.GetParent(i); - if(parent >= 0) { - if(static_cast(parent) < i) { + for (size_t i = 0; i < topology.size(); ++i) { + const int parent = topology.GetParent(i); + if (parent >= 0) { + if (static_cast(parent) < i) { jointLocalXforms[i] = xforms[i]*inverseXforms[parent]; } else { - if(static_cast(parent) == i) { + if (static_cast(parent) == i) { TF_WARN("Joint %zu has itself as its parent.", i); return false; } @@ -222,7 +267,7 @@ UsdSkelComputeJointLocalTransforms(const UsdSkelTopology& topology, } else { // Root joint. jointLocalXforms[i] = xforms[i]; - if(rootInverseXform) { + if (rootInverseXform) { jointLocalXforms[i] *= (*rootInverseXform); } } @@ -231,19 +276,72 @@ UsdSkelComputeJointLocalTransforms(const UsdSkelTopology& topology, } +template +bool +UsdSkel_ComputeJointLocalTransforms(const UsdSkelTopology& topology, + TfSpan xforms, + TfSpan jointLocalXforms, + const Matrix4* rootInverseXform) +{ + TRACE_FUNCTION(); + + std::vector inverseXforms(xforms.size()); + _InvertTransforms(xforms, inverseXforms); + return UsdSkel_ComputeJointLocalTransforms( + topology, xforms, inverseXforms, jointLocalXforms, rootInverseXform); +} + + +} // namespace + + bool UsdSkelComputeJointLocalTransforms(const UsdSkelTopology& topology, - const VtMatrix4dArray& xforms, - VtMatrix4dArray* jointLocalXforms, + TfSpan xforms, + TfSpan inverseXforms, + TfSpan jointLocalXforms, const GfMatrix4d* rootInverseXform) { - VtMatrix4dArray inverseXforms(xforms); - _InvertTransforms(inverseXforms.data(), xforms.size()); - return UsdSkelComputeJointLocalTransforms( + return UsdSkel_ComputeJointLocalTransforms( + topology, xforms, inverseXforms, jointLocalXforms, rootInverseXform); +} + + +bool +UsdSkelComputeJointLocalTransforms(const UsdSkelTopology& topology, + TfSpan xforms, + TfSpan inverseXforms, + TfSpan jointLocalXforms, + const GfMatrix4f* rootInverseXform) +{ + return UsdSkel_ComputeJointLocalTransforms( topology, xforms, inverseXforms, jointLocalXforms, rootInverseXform); } +bool +UsdSkelComputeJointLocalTransforms(const UsdSkelTopology& topology, + TfSpan xforms, + TfSpan jointLocalXforms, + const GfMatrix4d* rootInverseXform) +{ + return UsdSkel_ComputeJointLocalTransforms( + topology, xforms, jointLocalXforms, rootInverseXform); +} + + +bool +UsdSkelComputeJointLocalTransforms(const UsdSkelTopology& topology, + TfSpan xforms, + TfSpan jointLocalXforms, + const GfMatrix4f* rootInverseXform) +{ + return UsdSkel_ComputeJointLocalTransforms( + topology, xforms, jointLocalXforms, rootInverseXform); +} + + +// deprecated bool UsdSkelComputeJointLocalTransforms(const UsdSkelTopology& topology, const VtMatrix4dArray& xforms, @@ -251,54 +349,95 @@ UsdSkelComputeJointLocalTransforms(const UsdSkelTopology& topology, VtMatrix4dArray* jointLocalXforms, const GfMatrix4d* rootInverseXform) { - TRACE_FUNCTION(); - - if(!jointLocalXforms) { - TF_CODING_ERROR("'jointLocalXforms' pointer is null."); + if (!jointLocalXforms) { + TF_CODING_ERROR("'jointLocalXforms' is null"); return false; } + jointLocalXforms->resize(topology.size()); + return UsdSkelComputeJointLocalTransforms( + topology, xforms, inverseXforms, *jointLocalXforms, rootInverseXform); +} - if(xforms.size() == topology.GetNumJoints()) { - if(inverseXforms.size() == topology.GetNumJoints()) { - jointLocalXforms->resize(xforms.size()); - return UsdSkelComputeJointLocalTransforms( - topology, xforms.cdata(), inverseXforms.cdata(), - jointLocalXforms->data(), rootInverseXform); - } else { - TF_WARN("inverseXforms.size() [%zu] != number of joints [%zu].", - inverseXforms.size(), topology.GetNumJoints()); - } - } else { - TF_WARN("xforms.size() [%zu] != number of joints [%zu].", - xforms.size(), topology.GetNumJoints()); + +// deprecated +bool +UsdSkelComputeJointLocalTransforms(const UsdSkelTopology& topology, + const VtMatrix4dArray& xforms, + VtMatrix4dArray* jointLocalXforms, + const GfMatrix4d* rootInverseXform) +{ + if (!jointLocalXforms) { + TF_CODING_ERROR("'jointLocalXforms' is null"); + return false; } - return false; + jointLocalXforms->resize(topology.size()); + return UsdSkelComputeJointLocalTransforms( + topology, xforms, *jointLocalXforms, rootInverseXform); +} + + +// deprecated +bool +UsdSkelComputeJointLocalTransforms(const UsdSkelTopology& topology, + const GfMatrix4d* xforms, + const GfMatrix4d* inverseXforms, + GfMatrix4d* jointLocalXforms, + const GfMatrix4d* rootInverseXform) +{ + return UsdSkelComputeJointLocalTransforms( + topology, + TfSpan(xforms, topology.size()), + TfSpan(inverseXforms, topology.size()), + TfSpan(jointLocalXforms, topology.size()), + rootInverseXform); } namespace { +/// Helper to return the GfVec3 type with the same precision +/// as the given matrix type. +template +struct _Vec3MatchingMatrix4 {}; + +template <> +struct _Vec3MatchingMatrix4 +{ + using type = GfVec3d; +}; + +template <> +struct _Vec3MatchingMatrix4 +{ + using type = GfVec3f; +}; + + +template bool -_DecomposeTransform(const GfMatrix4d& xform, +_DecomposeTransform(const Matrix4& xform, GfVec3f* translate, GfRotation* rotate, GfVec3h* scale) { - // XXX: GfMatrix4d::Factor() may crash if the value isn't properly aligned. - TF_DEV_AXIOM(size_t(&xform)%alignof(GfMatrix4d) == 0); + // XXX: GfMatrix4x::Factor() may crash if the value isn't properly aligned. + TF_DEV_AXIOM(size_t(&xform)%alignof(Matrix4) == 0); // Decomposition must account for handedness changes due to negative scales. // This is similar to GfMatrix4d::RemoveScaleShear(). - GfMatrix4d scaleOrient, factoredRot, perspMat; - GfVec3d scaleD, translateD; - if(xform.Factor(&scaleOrient, &scaleD, - &factoredRot, &translateD, &perspMat)) { + Matrix4 scaleOrient, factoredRot, perspMat; + + using Vec3 = typename _Vec3MatchingMatrix4::type; + + Vec3 factoredScale, factoredTranslate;; + if (xform.Factor(&scaleOrient, &factoredScale, + &factoredRot, &factoredTranslate, &perspMat)) { - if(factoredRot.Orthonormalize()) { + if (factoredRot.Orthonormalize()) { *rotate = factoredRot.ExtractRotation(); - *scale = GfVec3h(scaleD); - *translate = GfVec3f(translateD); + *scale = GfVec3h(factoredScale); + *translate = GfVec3f(factoredTranslate); return true; } } @@ -306,14 +445,15 @@ _DecomposeTransform(const GfMatrix4d& xform, } +template bool -_DecomposeTransform(const GfMatrix4d& xform, +_DecomposeTransform(const Matrix4& xform, GfVec3f* translate, GfQuatf* rotate, GfVec3h* scale) { GfRotation r; - if(_DecomposeTransform(xform, translate, &r, scale)) { + if (_DecomposeTransform(xform, translate, &r, scale)) { *rotate = GfQuatf(r.GetQuat()); // XXX: Note that even if GfRotation() produces a normal // quaternion, casting down to a lesser precision may @@ -328,21 +468,24 @@ _DecomposeTransform(const GfMatrix4d& xform, } // namespace +template bool -UsdSkelDecomposeTransform(const GfMatrix4d& xform, +UsdSkelDecomposeTransform(const Matrix4& xform, GfVec3f* translate, GfRotation* rotate, GfVec3h* scale) { - if(!translate) { + TRACE_FUNCTION(); + + if (!translate) { TF_CODING_ERROR("'translate' pointer is null."); return false; } - if(!rotate) { + if (!rotate) { TF_CODING_ERROR("'rotate' pointer is null."); return false; } - if(!scale) { + if (!scale) { TF_CODING_ERROR("'scale' pointer is null."); return false; } @@ -350,23 +493,33 @@ UsdSkelDecomposeTransform(const GfMatrix4d& xform, } +template +USDSKEL_API bool UsdSkelDecomposeTransform(const GfMatrix4d&, + GfVec3f*, GfRotation*, GfVec3h*); + +template +USDSKEL_API bool UsdSkelDecomposeTransform(const GfMatrix4f&, + GfVec3f*, GfRotation*, GfVec3h*); + + +template bool -UsdSkelDecomposeTransform(const GfMatrix4d& xform, +UsdSkelDecomposeTransform(const Matrix4& xform, GfVec3f* translate, GfQuatf* rotate, GfVec3h* scale) { TRACE_FUNCTION(); - if(!translate) { + if (!translate) { TF_CODING_ERROR("'translate' pointer is null."); return false; } - if(!rotate) { + if (!rotate) { TF_CODING_ERROR("'rotate' pointer is null."); return false; } - if(!scale) { + if (!scale) { TF_CODING_ERROR("'scale' pointer is null."); return false; } @@ -374,6 +527,92 @@ UsdSkelDecomposeTransform(const GfMatrix4d& xform, } +template +USDSKEL_API bool UsdSkelDecomposeTransform(const GfMatrix4d&, + GfVec3f*, GfQuatf*, GfVec3h*); + +template +USDSKEL_API bool UsdSkelDecomposeTransform(const GfMatrix4f&, + GfVec3f*, GfQuatf*, GfVec3h*); + + +namespace { + + +template +bool +UsdSkel_DecomposeTransforms(TfSpan xforms, + TfSpan translations, + TfSpan rotations, + TfSpan scales) +{ + TRACE_FUNCTION(); + + if (translations.size() != xforms.size()) { + TF_WARN("Size of translations [%td] != size of xforms [%td]", + translations.size(), xforms.size()); + return false; + } + if (rotations.size() != xforms.size()) { + TF_WARN("Size of rotations [%td] != size of xforms [%td]", + rotations.size(), xforms.size()); + return false; + } + if (scales.size() != xforms.size()) { + TF_WARN("Size of scales [%td] != size of xforms [%td]", + scales.size(), xforms.size()); + return false; + } + + // Flag for marking error state from within threads. + std::atomic_bool errors(false); + + _ParallelForN( + xforms.size(), /*inSerial*/ false, + [&](size_t start, size_t end) + { + for (size_t i = start; i < end; ++i) { + + if (!_DecomposeTransform(xforms[i], &translations[i], + &rotations[i], &scales[i])) { + + TF_WARN("Failed decomposing transform %zu. " + "The source transform may be singular.", i); + errors = true; + return; + } + } + }); + + return !errors; +} + + +} // namespace + + +bool +UsdSkelDecomposeTransforms(TfSpan xforms, + TfSpan translations, + TfSpan rotations, + TfSpan scales) +{ + return UsdSkel_DecomposeTransforms(xforms, translations, rotations, scales); +} + + +bool +UsdSkelDecomposeTransforms(TfSpan xforms, + TfSpan translations, + TfSpan rotations, + TfSpan scales) +{ + return UsdSkel_DecomposeTransforms(xforms, translations, rotations, scales); +} + + + +// deprecated bool UsdSkelDecomposeTransforms(const GfMatrix4d* xforms, GfVec3f* translations, @@ -381,55 +620,30 @@ UsdSkelDecomposeTransforms(const GfMatrix4d* xforms, GfVec3h* scales, size_t count) { - if(count > 0) { - if(!xforms) { - TF_CODING_ERROR("'xforms' pointer is null."); - return false; - } - if(!translations) { - TF_CODING_ERROR("'translations' pointer is null."); - return false; - } - if(!rotations) { - TF_CODING_ERROR("'rotations' pointer is null."); - return false; - } - if(!scales) { - TF_CODING_ERROR("'scales' pointer is null."); - return false; - } - - for(size_t i = 0; i < count; ++i) { - if(!_DecomposeTransform(xforms[i], translations+i, - rotations+i, scales+i)) { - // XXX: Should this be a coding error, or a warning? - TF_WARN("Failed decomposing transform %zu. " - "The source transform may be singular.", i); - return false; - } - } - } - return true; + return UsdSkelDecomposeTransforms( + TfSpan(xforms, count), + TfSpan(translations, count), + TfSpan(rotations, count), + TfSpan(scales, count)); } +// deprecated bool UsdSkelDecomposeTransforms(const VtMatrix4dArray& xforms, VtVec3fArray* translations, VtQuatfArray* rotations, VtVec3hArray* scales) { - TRACE_FUNCTION(); - - if(!translations) { + if (!translations) { TF_CODING_ERROR("'translations' pointer is null."); return false; } - if(!rotations) { + if (!rotations) { TF_CODING_ERROR("'rotations' pointer is null."); return false; } - if(!scales) { + if (!scales) { TF_CODING_ERROR("'scales' pointer is null."); return false; } @@ -438,44 +652,128 @@ UsdSkelDecomposeTransforms(const VtMatrix4dArray& xforms, rotations->resize(xforms.size()); scales->resize(xforms.size()); - return UsdSkelDecomposeTransforms(xforms.cdata(), - translations->data(), - rotations->data(), scales->data(), - xforms.size()); + return UsdSkelDecomposeTransforms(xforms, *translations, + *rotations, *scales); } -GfMatrix4d +template +void UsdSkelMakeTransform(const GfVec3f& translate, const GfMatrix3f& rotate, - const GfVec3h& scale) + const GfVec3h& scale, + Matrix4* xform) { - // Order is scale*rotate*translate - return GfMatrix4d(rotate[0][0]*scale[0], - rotate[0][1]*scale[0], - rotate[0][2]*scale[0], 0, + if (xform) { + // Order is scale*rotate*translate + *xform = Matrix4(rotate[0][0]*scale[0], + rotate[0][1]*scale[0], + rotate[0][2]*scale[0], 0, - rotate[1][0]*scale[1], - rotate[1][1]*scale[1], - rotate[1][2]*scale[1], 0, + rotate[1][0]*scale[1], + rotate[1][1]*scale[1], + rotate[1][2]*scale[1], 0, - rotate[2][0]*scale[2], - rotate[2][1]*scale[2], - rotate[2][2]*scale[2], 0, + rotate[2][0]*scale[2], + rotate[2][1]*scale[2], + rotate[2][2]*scale[2], 0, - translate[0], translate[1], translate[2], 1); + translate[0], translate[1], translate[2], 1); + } else { + TF_CODING_ERROR("'xform' is null"); + } } -GfMatrix4d +template USDSKEL_API void +UsdSkelMakeTransform(const GfVec3f&, const GfMatrix3f&, + const GfVec3h&, GfMatrix4d*); + +template USDSKEL_API void +UsdSkelMakeTransform(const GfVec3f&, const GfMatrix3f&, + const GfVec3h&, GfMatrix4f*); + + +template +void UsdSkelMakeTransform(const GfVec3f& translate, const GfQuatf& rotate, - const GfVec3h& scale) + const GfVec3h& scale, + Matrix4* xform) { - return UsdSkelMakeTransform(translate, GfMatrix3f(rotate), scale); + UsdSkelMakeTransform(translate, GfMatrix3f(rotate), scale, xform); } +template USDSKEL_API void +UsdSkelMakeTransform(const GfVec3f&, const GfQuatf&, + const GfVec3h&, GfMatrix4d*); + +template USDSKEL_API void +UsdSkelMakeTransform(const GfVec3f&, const GfQuatf&, + const GfVec3h&, GfMatrix4f*); + + +namespace { + + +template +bool +UsdSkel_MakeTransforms(TfSpan translations, + TfSpan rotations, + TfSpan scales, + TfSpan xforms) +{ + TRACE_FUNCTION(); + + if (ARCH_UNLIKELY(translations.size() != xforms.size())) { + TF_WARN("Size of translations [%td] != size of xforms [%td]", + translations.size(), xforms.size()); + return false; + } + if (ARCH_UNLIKELY(rotations.size() != xforms.size())) { + TF_WARN("Size of rotations [%td] != size of xforms [%td]", + rotations.size(), xforms.size()); + return false; + } + if (ARCH_UNLIKELY(scales.size() != xforms.size())) { + TF_WARN("Size of scales [%td] != size of xforms [%td]", + scales.size(), xforms.size()); + return false; + } + + for (ptrdiff_t i = 0; i < xforms.size(); ++i) { + UsdSkelMakeTransform(translations[i], rotations[i], + scales[i], &xforms[i]); + } + return true; +} + + +} // namespace + + +bool +UsdSkelMakeTransforms(TfSpan translations, + TfSpan rotations, + TfSpan scales, + TfSpan xforms) +{ + return UsdSkel_MakeTransforms(translations, rotations, scales, xforms); +} + + +bool +UsdSkelMakeTransforms(TfSpan translations, + TfSpan rotations, + TfSpan scales, + TfSpan xforms) +{ + return UsdSkel_MakeTransforms(translations, rotations, scales, xforms); +} + + +// deprecated bool UsdSkelMakeTransforms(const GfVec3f* translations, const GfQuatf* rotations, @@ -483,114 +781,107 @@ UsdSkelMakeTransforms(const GfVec3f* translations, GfMatrix4d* xforms, size_t count) { - if(count > 0) { - if(!xforms) { - TF_CODING_ERROR("'xforms' pointer is null."); - return false; - } - if(!translations) { - TF_CODING_ERROR("'translations' pointer is null."); - return false; - } - if(!rotations) { - TF_CODING_ERROR("'rotations' pointer is null."); - return false; - } - if(!scales) { - TF_CODING_ERROR("'scales' pointer is null."); - return false; - } - - for(size_t i = 0; i < count; ++i) { - xforms[i] = UsdSkelMakeTransform( - translations[i], rotations[i], scales[i]); - } - } - return true; + return UsdSkelMakeTransforms( + TfSpan(translations, count), + TfSpan(rotations, count), + TfSpan(scales, count), + TfSpan(xforms, count)); + } +// deprecated bool UsdSkelMakeTransforms(const VtVec3fArray& translations, const VtQuatfArray& rotations, const VtVec3hArray& scales, VtMatrix4dArray* xforms) { - TRACE_FUNCTION(); - - if(!xforms) { + if (!xforms) { TF_CODING_ERROR("'xforms' pointer is null."); return false; } - - if(translations.size() == rotations.size()) { - if(translations.size() == scales.size()) { - - xforms->resize(translations.size()); - - return UsdSkelMakeTransforms( - translations.cdata(), rotations.cdata(), scales.cdata(), - xforms->data(), xforms->size()); - } else { - TF_WARN("Size of translations [%zu] != size of scales [%zu].", - translations.size(), scales.size()); - } - } else { - TF_WARN("Size of translations [%zu] != size of rotations [%zu].", - translations.size(), rotations.size()); - } - return false; + xforms->resize(translations.size()); + + return UsdSkelMakeTransforms( + translations, rotations, scales, *xforms); } +template bool -UsdSkelComputeJointsExtent(const GfMatrix4d* xforms, - size_t count, - VtVec3fArray* extent, +UsdSkelComputeJointsExtent(TfSpan xforms, + GfRange3f* extent, float pad, - const GfMatrix4d* rootXform) + const Matrix4* rootXform) { - if(!extent) { + TRACE_FUNCTION(); + + if (!extent) { TF_CODING_ERROR("'extent' pointer is null."); return false; } - if(count > 0 && !xforms) { - TF_CODING_ERROR("'xforms' pointer is null."); - return false; + for (size_t i = 0; i < xforms.size(); ++i) { + const GfVec3f pivot(xforms[i].ExtractTranslation()); + extent->UnionWith(rootXform ? + rootXform->TransformAffine(pivot) : pivot); } + const GfVec3f padVec(pad); + extent->SetMin(extent->GetMin()-padVec); + extent->SetMax(extent->GetMax()+padVec); + return true; +} - GfRange3f range; - if(count > 0) { - for(size_t i = 0; i < count; ++i) { - GfVec3f pivot(xforms[i].ExtractTranslation()); - range.UnionWith(rootXform ? - rootXform->TransformAffine(pivot) : pivot); - } - const GfVec3f padVec(pad); - range.SetMin(range.GetMin()-padVec); - range.SetMax(range.GetMax()+padVec); - } +template USDSKEL_API bool +UsdSkelComputeJointsExtent(TfSpan, + GfRange3f*, float, const GfMatrix4d*); +template USDSKEL_API bool +UsdSkelComputeJointsExtent(TfSpan, + GfRange3f*, float, const GfMatrix4f*); - extent->resize(2); - (*extent)[0] = range.GetMin(); - (*extent)[1] = range.GetMax(); - return true; -} +// deprecated bool -UsdSkelComputeJointsExtent(const VtMatrix4dArray& xforms, +UsdSkelComputeJointsExtent(const VtMatrix4dArray& joints, VtVec3fArray* extent, float pad, const GfMatrix4d* rootXform) { - TRACE_FUNCTION(); + GfRange3f range; + if (UsdSkelComputeJointsExtent( + joints, &range, pad, rootXform)) { + + extent->resize(2); + (*extent)[0] = range.GetMin(); + (*extent)[1] = range.GetMax(); + return true; + } + return false; +} - return UsdSkelComputeJointsExtent(xforms.cdata(), xforms.size(), - extent, pad, rootXform); + +// deprecated +bool +UsdSkelComputeJointsExtent(const GfMatrix4d* xforms, + size_t count, + VtVec3fArray* extent, + float pad, + const GfMatrix4d* rootXform) +{ + GfRange3f range; + if (UsdSkelComputeJointsExtent( + TfSpan(xforms, count), + &range, pad, rootXform)) { + extent->resize(2); + (*extent)[0] = range.GetMin(); + (*extent)[1] = range.GetMax(); + return true; + } + return false; } @@ -600,13 +891,13 @@ namespace { /// number of influences per component. /// Throws a warning for failed validation. bool -_ValidateArrayShape(size_t size, int numInfluencesPerComponent) +_ValidateArrayShape(ptrdiff_t size, int numInfluencesPerComponent) { - if(numInfluencesPerComponent > 0) { - if(size%numInfluencesPerComponent == 0) { + if (numInfluencesPerComponent > 0) { + if (size%numInfluencesPerComponent == 0) { return true; } else { - TF_WARN("Unexpected array size [%zu]: Size must be a multiple of " + TF_WARN("Unexpected array size [%td]: Size must be a multiple of " "the number of influences per component [%d].", size, numInfluencesPerComponent); } @@ -618,27 +909,35 @@ _ValidateArrayShape(size_t size, int numInfluencesPerComponent) return false; } +} // namespace + bool -_NormalizeWeights(float* weights, size_t numWeights, - int numInfluencesPerComponent) +UsdSkelNormalizeWeights(TfSpan weights, + int numInfluencesPerComponent) { - size_t numComponents = numWeights/numInfluencesPerComponent; + TRACE_FUNCTION(); + + if (!_ValidateArrayShape(weights.size(), numInfluencesPerComponent)) { + return false; + } + + const ptrdiff_t numComponents = weights.size()/numInfluencesPerComponent; _ParallelForN( - numComponents, - /* forceSerial = */ false, + numComponents, /* inSerial = */ false, [&](size_t start, size_t end) { - for(size_t i = start; i < end; ++i) { - float* weightSet = weights + i*numInfluencesPerComponent; + for (size_t i = start; i < end; ++i) { + + float* weightSet = weights.data() + i*numInfluencesPerComponent; float sum = 0.0f; for(int j = 0; j < numInfluencesPerComponent; ++j) { sum += weightSet[j]; } - if(std::abs(sum) > std::numeric_limits::epsilon()) { + if (std::abs(sum) > std::numeric_limits::epsilon()) { for(int j = 0; j < numInfluencesPerComponent; ++j) { weightSet[j] /= sum; } @@ -654,59 +953,58 @@ _NormalizeWeights(float* weights, size_t numWeights, } -} // namespace - - +// deprecated bool -UsdSkelNormalizeWeights(VtFloatArray* weights, - int numInfluencesPerComponent) +UsdSkelNormalizeWeights(VtFloatArray* weights, int numInfluencesPerComponent) { - TRACE_FUNCTION(); - - if(!weights) { + if (!weights) { TF_CODING_ERROR("'weights' pointer is null."); return false; } - - if(!_ValidateArrayShape(weights->size(), numInfluencesPerComponent)) - return false; - - return _NormalizeWeights(weights->data(), weights->size(), - numInfluencesPerComponent); + return UsdSkelNormalizeWeights(*weights, numInfluencesPerComponent); } -namespace { - bool -_SortInfluences(int* indices, float* weights, - size_t numInfluences, - int numInfluencesPerComponent) +UsdSkelSortInfluences(TfSpan indices, + TfSpan weights, + int numInfluencesPerComponent) { - if(numInfluencesPerComponent < 2) { + TRACE_FUNCTION(); + + if (indices.size() != weights.size()) { + TF_WARN("Size of 'indices' [%td] != size of 'weights' [%td].", + indices.size(), weights.size()); + return false; + } + if (!_ValidateArrayShape(indices.size(), numInfluencesPerComponent)) { + return false; + } + + if (numInfluencesPerComponent < 2) { // Nothing to do. return true; } - size_t numComponents = numInfluences/numInfluencesPerComponent; + const ptrdiff_t numComponents = indices.size()/numInfluencesPerComponent; _ParallelForN( - numComponents, - /* forceSerial = */ false, + numComponents, /* inSerial = */ false, [&](size_t start, size_t end) { std::vector > influences; - for(size_t i = start; i < end; ++i) { - float* weightsSet = weights + i*numInfluencesPerComponent; - int *indexSet = indices + i*numInfluencesPerComponent; + for (size_t i = start; i < end; ++i) { + const size_t offset = i*numInfluencesPerComponent; + float* weightsSet = weights.data() + offset; + int *indexSet = indices.data() + offset; influences.resize(numInfluencesPerComponent); - for(int j = 0; j < numInfluencesPerComponent; ++j) { + for (int j = 0; j < numInfluencesPerComponent; ++j) { influences[j] = std::make_pair(weightsSet[j], indexSet[j]); } std::sort(influences.begin(), influences.end(), std::greater >()); - for(int j = 0; j < numInfluencesPerComponent; ++j) { + for (int j = 0; j < numInfluencesPerComponent; ++j) { const auto& pair = influences[j]; weightsSet[j] = pair.first; indexSet[j] = pair.second; @@ -717,37 +1015,23 @@ _SortInfluences(int* indices, float* weights, return true; } -} // namespace - +// deprecated bool UsdSkelSortInfluences(VtIntArray* indices, VtFloatArray* weights, int numInfluencesPerComponent) { - TRACE_FUNCTION(); - - if(!indices) { + if (!indices) { TF_CODING_ERROR("'indices' pointer is null."); return false; } - if(!weights) { + if (!weights) { TF_CODING_ERROR("'weights' pointer is null."); return false; } - if(indices->size() != weights->size()) { - TF_WARN("Size of 'indices' [%zu] != size of 'weights' [%zu].", - indices->size(), weights->size()); - return false; - } - - if(!_ValidateArrayShape(weights->size(), numInfluencesPerComponent)) { - return false; - } - - return _SortInfluences(indices->data(), weights->data(), - indices->size(), numInfluencesPerComponent); + return UsdSkelSortInfluences(*indices, *weights, numInfluencesPerComponent); } @@ -757,19 +1041,19 @@ template bool _ExpandConstantArray(T* array, size_t size) { - if(!array) { + if (!array) { TF_CODING_ERROR("'array' pointer is null."); return false; } - if(size == 0) { + if (size == 0) { array->clear(); } else { size_t numInfluencesPerComponent = array->size(); array->resize(numInfluencesPerComponent*size); auto* data = array->data(); - for(size_t i = 1; i < size; ++i) { + for (size_t i = 1; i < size; ++i) { std::copy(data, data + numInfluencesPerComponent, data + i*numInfluencesPerComponent); } @@ -801,25 +1085,25 @@ bool _ResizeInfluences(VtArray* array, int srcNumInfluencesPerComponent, int newNumInfluencesPerComponent, T defaultVal) { - if(srcNumInfluencesPerComponent == newNumInfluencesPerComponent) + if (srcNumInfluencesPerComponent == newNumInfluencesPerComponent) return true; - if(!array) { + if (!array) { TF_CODING_ERROR("'array' pointer is null."); return false; } - if(!_ValidateArrayShape(array->size(), srcNumInfluencesPerComponent)) + if (!_ValidateArrayShape(array->size(), srcNumInfluencesPerComponent)) return false; size_t numComponents = array->size()/srcNumInfluencesPerComponent; - if(numComponents == 0) + if (numComponents == 0) return true; - if(newNumInfluencesPerComponent < srcNumInfluencesPerComponent) { + if (newNumInfluencesPerComponent < srcNumInfluencesPerComponent) { // Truncate influences in-place. auto* data = array->data(); - for(size_t i = 1; i < numComponents; ++i) { + for (size_t i = 1; i < numComponents; ++i) { size_t srcStart = i*srcNumInfluencesPerComponent; size_t srcEnd = srcStart + newNumInfluencesPerComponent; size_t dstStart = i*newNumInfluencesPerComponent; @@ -835,12 +1119,12 @@ _ResizeInfluences(VtArray* array, int srcNumInfluencesPerComponent, array->resize(numComponents*newNumInfluencesPerComponent); auto* data = array->data(); - for(size_t i = 0; i < numComponents; ++i) { + for (size_t i = 0; i < numComponents; ++i) { // Reverse the order. size_t idx = numComponents-i-1; // Copy source values (*reverse order*) - for(int j = (srcNumInfluencesPerComponent-1); j >= 0; --j) { + for (int j = (srcNumInfluencesPerComponent-1); j >= 0; --j) { TF_DEV_AXIOM( (idx*newNumInfluencesPerComponent + j) < array->size()); @@ -879,9 +1163,9 @@ UsdSkelResizeInfluences(VtFloatArray* weights, { TRACE_FUNCTION(); - if(_ResizeInfluences(weights, srcNumInfluencesPerComponent, + if (_ResizeInfluences(weights, srcNumInfluencesPerComponent, newNumInfluencesPerComponent, 0.0f)) { - if(newNumInfluencesPerComponent < srcNumInfluencesPerComponent) { + if (newNumInfluencesPerComponent < srcNumInfluencesPerComponent) { // Some weights have been stripped off. Need to renormalize. return UsdSkelNormalizeWeights( weights, newNumInfluencesPerComponent); @@ -892,24 +1176,31 @@ UsdSkelResizeInfluences(VtFloatArray* weights, } +namespace { + + +template bool -UsdSkelSkinPointsLBS(const GfMatrix4d& geomBindTransform, - const GfMatrix4d* jointXforms, - size_t numJoints, - const int* jointIndices, - const float* jointWeights, - size_t numInfluences, - int numInfluencesPerPoint, - GfVec3f* points, - size_t numPoints, - bool forceSerial) +_SkinPointsLBS(const Matrix4& geomBindTransform, + TfSpan jointXforms, + TfSpan jointIndices, + TfSpan jointWeights, + int numInfluencesPerPoint, + TfSpan points, + bool inSerial) { TRACE_FUNCTION(); + + if (jointIndices.size() != jointWeights.size()) { + TF_WARN("Size of jointIndices [%td] != size of jointWeights [%td]", + jointIndices.size(), jointWeights.size()); + return false; + } - if(numInfluences != (numPoints*numInfluencesPerPoint)) { - TF_WARN("numInfluences [%zu] != " - "(numPoints [%zu] * numInfluencesPerPoint [%d]).", - numInfluences, numPoints, numInfluencesPerPoint); + if (jointIndices.size() != (points.size()*numInfluencesPerPoint)) { + TF_WARN("Size of jointIndices [%td] != " + "(points.size() [%td] * numInfluencesPerPoint [%d]).", + jointIndices.size(), points.size(), numInfluencesPerPoint); return false; } @@ -917,26 +1208,23 @@ UsdSkelSkinPointsLBS(const GfMatrix4d& geomBindTransform, std::atomic_bool errors(false); _ParallelForN( - numPoints, - /* forceSerial = */ forceSerial, + points.size(), /* inSerial = */ inSerial, [&](size_t start, size_t end) { - for(size_t pi = start; pi < end; ++pi) { + for (size_t pi = start; pi < end; ++pi) { - GfVec3f initialP = geomBindTransform.Transform(points[pi]); + const GfVec3f initialP = geomBindTransform.Transform(points[pi]); GfVec3f p(0,0,0); - for(int wi = 0; wi < numInfluencesPerPoint; ++wi) { - size_t influenceIdx = pi*numInfluencesPerPoint + wi; - TF_DEV_AXIOM(influenceIdx < numInfluences); + for (int wi = 0; wi < numInfluencesPerPoint; ++wi) { + const size_t influenceIdx = pi*numInfluencesPerPoint + wi; + const int jointIdx = jointIndices[influenceIdx]; - int jointIdx = jointIndices[influenceIdx]; - - if(jointIdx >= 0 && - static_cast(jointIdx) < numJoints) { + if (jointIdx >= 0 && + static_cast(jointIdx) < jointXforms.size()) { float w = jointWeights[influenceIdx]; - if(w != 0.0f) { + if (w != 0.0f) { // Since joint transforms are encoded in terms of // t,r,s components, it shouldn't be possible to // encode non-affine transforms, except for the rest @@ -951,7 +1239,7 @@ UsdSkelSkinPointsLBS(const GfMatrix4d& geomBindTransform, // null weights are encountered, we can break out of // the inner loop early. I.e., // - // if(weightIsNull) + // if (weightIsNull) // break; // // This can potentially greatly reduce the number of @@ -969,8 +1257,8 @@ UsdSkelSkinPointsLBS(const GfMatrix4d& geomBindTransform, // Bail out early. TF_WARN("Out of range joint index %d at index %zu" - " (num joints = %zu).", - jointIdx, influenceIdx, numJoints); + " (num joints = %td).", + jointIdx, influenceIdx, jointXforms.size()); errors = true; return; } @@ -985,6 +1273,64 @@ UsdSkelSkinPointsLBS(const GfMatrix4d& geomBindTransform, } +} // namespace + + +bool +UsdSkelSkinPointsLBS(const GfMatrix4d& geomBindTransform, + TfSpan jointXforms, + TfSpan jointIndices, + TfSpan jointWeights, + int numInfluencesPerPoint, + TfSpan points, + bool inSerial) +{ + return _SkinPointsLBS(geomBindTransform, jointXforms, + jointIndices, jointWeights, numInfluencesPerPoint, + points, inSerial); +} + + +bool +UsdSkelSkinPointsLBS(const GfMatrix4f& geomBindTransform, + TfSpan jointXforms, + TfSpan jointIndices, + TfSpan jointWeights, + int numInfluencesPerPoint, + TfSpan points, + bool inSerial) +{ + return _SkinPointsLBS(geomBindTransform, jointXforms, + jointIndices, jointWeights, numInfluencesPerPoint, + points, inSerial); +} + + +// deprecated +bool +UsdSkelSkinPointsLBS(const GfMatrix4d& geomBindTransform, + const GfMatrix4d* jointXforms, + size_t numJoints, + const int* jointIndices, + const float* jointWeights, + size_t numInfluences, + int numInfluencesPerPoint, + GfVec3f* points, + size_t numPoints, + bool inSerial) +{ + return UsdSkelSkinPointsLBS( + geomBindTransform, + TfSpan(jointXforms, numJoints), + TfSpan(jointIndices, numInfluences), + TfSpan(jointWeights, numInfluences), + numInfluencesPerPoint, + TfSpan(points, numPoints), + inSerial); +} + + +// deprecated bool UsdSkelSkinPointsLBS(const GfMatrix4d& geomBindTransform, const VtMatrix4dArray& jointXforms, @@ -993,49 +1339,53 @@ UsdSkelSkinPointsLBS(const GfMatrix4d& geomBindTransform, int numInfluencesPerPoint, VtVec3fArray* points) { - if(!points) { + if (!points) { TF_CODING_ERROR("'points' pointer is null."); return false; } - if(jointIndices.size() == jointWeights.size()) { - return UsdSkelSkinPointsLBS(geomBindTransform, - jointXforms.cdata(), - jointXforms.size(), - jointIndices.cdata(), - jointWeights.cdata(), - jointIndices.size(), - numInfluencesPerPoint, - points->data(), points->size()); - } else { - TF_WARN("jointIndices.size() [%zu] != jointWeights.size() [%zu].", - jointIndices.size(), jointWeights.size()); - } - return false; + return UsdSkelSkinPointsLBS( + geomBindTransform, jointXforms, + jointIndices, jointWeights, + numInfluencesPerPoint, *points); } +namespace { + + +template bool -UsdSkelSkinTransformLBS(const GfMatrix4d& geomBindTransform, - const GfMatrix4d* jointXforms, - size_t numJoints, - const int* jointIndices, - const float* jointWeights, - size_t numInfluences, - GfMatrix4d* xform) +UsdSkel_SkinTransformLBS(const Matrix4& geomBindTransform, + TfSpan jointXforms, + TfSpan jointIndices, + TfSpan jointWeights, + Matrix4* xform) { TRACE_FUNCTION(); - // + + if (!xform) { + TF_CODING_ERROR("'xform' is null"); + return false; + } + + if (jointIndices.size() != jointWeights.size()) { + TF_WARN("Size of jointIndices [%td] != size of jointWeights [%td]", + jointIndices.size(), jointWeights.size()); + return false; + } + // Early-out for the common case where an object is rigidly // bound to a single joint. - if(numInfluences == 1 && GfIsClose(jointWeights[0], 1.0f, 1e-6)) { - int jointIdx = jointIndices[0]; - if(jointIdx >= 0 && static_cast(jointIdx) < numJoints) { + if (jointIndices.size() == 1 && GfIsClose(jointWeights[0], 1.0f, 1e-6)) { + const int jointIdx = jointIndices[0]; + if (jointIdx >= 0 && + static_cast(jointIdx) < jointXforms.size()) { *xform = geomBindTransform*jointXforms[jointIdx]; return true; } else { TF_WARN("Out of range joint index %d at index 0" - " (num joints = %zu).", jointIdx, numJoints); + " (num joints = %td).", jointIdx, jointXforms.size()); return false; } } @@ -1049,7 +1399,7 @@ UsdSkelSkinTransformLBS(const GfMatrix4d& geomBindTransform, // apply normal point deformations, and then derive a skinned transform // from the deformed frame points. - GfVec3f pivot(geomBindTransform.ExtractTranslation()); + const GfVec3f pivot(geomBindTransform.ExtractTranslation()); // XXX: Note that if precision becomes an issue, the offset applied to // produce the points that represent each of the basis vectors can be scaled @@ -1062,39 +1412,86 @@ UsdSkelSkinTransformLBS(const GfMatrix4d& geomBindTransform, pivot, // translate }; - for(int pi = 0; pi < 4; ++pi) { - GfVec3f initialP = framePoints[pi]; + for (int pi = 0; pi < 4; ++pi) { + const GfVec3f initialP = framePoints[pi]; GfVec3f p(0,0,0); - for(size_t wi = 0; wi < numInfluences; ++wi) { - int jointIdx = jointIndices[wi]; - if(jointIdx >= 0 && static_cast(jointIdx) < numJoints) { - float w = jointWeights[wi]; - if(w != 0.0f) { + for (ptrdiff_t wi = 0; wi < jointIndices.size(); ++wi) { + const int jointIdx = jointIndices[wi]; + if (jointIdx >= 0 && + static_cast(jointIdx) < jointXforms.size()) { + const float w = jointWeights[wi]; + if (w != 0.0f) { // XXX: See the notes from _SkinPointsLBS(): // affine transforms should be okay. - p += jointXforms[jointIdx].TransformAffine( - initialP)*w; + p += jointXforms[jointIdx].TransformAffine(initialP)*w; } } else { TF_WARN("Out of range joint index %d at index %zu" - " (num joints = %zu).", - jointIdx, wi, numJoints); + " (num joints = %td).", + jointIdx, wi, jointXforms.size()); return false; } } framePoints[pi] = p; } - GfVec3f skinnedPivot = framePoints[3]; + const GfVec3f skinnedPivot = framePoints[3]; xform->SetTranslate(skinnedPivot); - for(int i = 0; i < 3; ++i) { + for (int i = 0; i < 3; ++i) { xform->SetRow3(i, (framePoints[i]-skinnedPivot)); } return true; } +} // namespace + + +bool +UsdSkelSkinTransformLBS(const GfMatrix4d& geomBindTransform, + TfSpan jointXforms, + TfSpan jointIndices, + TfSpan jointWeights, + GfMatrix4d* xform) +{ + return UsdSkel_SkinTransformLBS(geomBindTransform, jointXforms, + jointIndices, jointWeights, xform); +} + + +bool +UsdSkelSkinTransformLBS(const GfMatrix4f& geomBindTransform, + TfSpan jointXforms, + TfSpan jointIndices, + TfSpan jointWeights, + GfMatrix4f* xform) +{ + return UsdSkel_SkinTransformLBS(geomBindTransform, jointXforms, + jointIndices, jointWeights, xform); +} + + +/// \deprecated +bool +UsdSkelSkinTransformLBS(const GfMatrix4d& geomBindTransform, + const GfMatrix4d* jointXforms, + size_t numJoints, + const int* jointIndices, + const float* jointWeights, + size_t numInfluences, + GfMatrix4d* xform) +{ + return UsdSkel_SkinTransformLBS( + geomBindTransform, + TfSpan(jointXforms, numJoints), + TfSpan(jointIndices, numInfluences), + TfSpan(jointWeights, numInfluences), + xform); +} + + +/// \deprecated bool UsdSkelSkinTransformLBS(const GfMatrix4d& geomBindTransform, const VtMatrix4dArray& jointXforms, @@ -1102,21 +1499,9 @@ UsdSkelSkinTransformLBS(const GfMatrix4d& geomBindTransform, const VtFloatArray& jointWeights, GfMatrix4d* xform) { - if(!xform) { - TF_CODING_ERROR("'xform' pointer is null."); - return false; - } - - if(jointIndices.size() == jointWeights.size()) { - return UsdSkelSkinTransformLBS(geomBindTransform, jointXforms.cdata(), - jointXforms.size(), jointIndices.cdata(), - jointWeights.cdata(), jointIndices.size(), - xform); - } else { - TF_WARN("jointIndices.size() [%zu]! = jointWeights.size() [%zu].", - jointIndices.size(), jointWeights.size()); - } - return false; + return UsdSkel_SkinTransformLBS( + geomBindTransform, jointXforms, + jointIndices, jointWeights, xform); } @@ -1136,7 +1521,7 @@ UsdSkel_ApplyIndexedBlendShape(const float weight, std::atomic_bool errors(false); _ParallelForN( - offsets.size(), /*forceSerial*/ false, + offsets.size(), /*inSerial*/ false, [&](size_t start, size_t end) { for (size_t i = start; i < end; ++i) { @@ -1168,7 +1553,7 @@ UsdSkel_ApplyNonIndexedBlendShape(const float weight, TRACE_FUNCTION(); _ParallelForN( - points.size(), /*forceSerial*/ false, + points.size(), /*inSerial*/ false, [&](size_t start, size_t end) { for (size_t i = start; i < end; ++i) { @@ -1253,8 +1638,8 @@ _GetWorldTransformTimeSamples(const UsdPrim& prim, std::vector tmpTimes; std::vector xformTimeSamples; - for(UsdPrim p = prim; p; p = p.GetParent()) { - if(p.IsA()) { + for (UsdPrim p = prim; p; p = p.GetParent()) { + if (p.IsA()) { UsdGeomXformable::XformQuery( UsdGeomXformable(p)).GetTimeSamplesInInterval( interval, &xformTimeSamples); @@ -1578,7 +1963,7 @@ _BakeSkinnedTransform(const UsdPrim& prim, UsdGeomXformCache* xfCache) { UsdGeomXformable xformable(prim); - if(!xformable) { + if (!xformable) { TF_CODING_ERROR("%s -- Attempted rigid deformation of a non-xformable. " "Skinning currently only understands rigid deformations " "on UsdGeomXformable types.", @@ -1588,7 +1973,7 @@ _BakeSkinnedTransform(const UsdPrim& prim, UsdAttribute xformAttr = xformable.MakeMatrixXform(); - for(size_t i = 0; i < times.size(); ++i) { + for (size_t i = 0; i < times.size(); ++i) { UsdTimeCode time = times[i]; TF_DEBUG(USDSKEL_BAKESKINNING).Msg( @@ -1603,7 +1988,7 @@ _BakeSkinnedTransform(const UsdPrim& prim, // and correctness are greater priorities than performance. VtMatrix4dArray xforms; - if(!skelQuery.ComputeSkinningTransforms(&xforms, time)) { + if (!skelQuery.ComputeSkinningTransforms(&xforms, time)) { TF_DEBUG(USDSKEL_BAKESKINNING).Msg( "[UsdSkelBakeSkinning] Failed computing " "skinning transforms\n"); @@ -1611,7 +1996,7 @@ _BakeSkinnedTransform(const UsdPrim& prim, } GfMatrix4d skinnedXform; - if(skinningQuery.ComputeSkinnedTransform(xforms, &skinnedXform, time)) { + if (skinningQuery.ComputeSkinnedTransform(xforms, &skinnedXform, time)) { // Skinning a transform produces a new transform in *skel* space. // A world-space transform is then computed as: @@ -1635,7 +2020,7 @@ _BakeSkinnedTransform(const UsdPrim& prim, GfMatrix4d newLocalXform; - if(xfCache->GetResetXformStack(prim) || + if (xfCache->GetResetXformStack(prim) || prim.GetPath().IsRootPrimPath()) { // No parent transform to account for. @@ -1665,10 +2050,10 @@ _UpdateExtentsHints(const UsdPrim& prim, const std::vector& times) { std::vector modelsToUpdate; - for(const auto& p : UsdPrimRange(prim)) { - if(p.IsModel()) { + for (const auto& p : UsdPrimRange(prim)) { + if (p.IsModel()) { UsdGeomModelAPI model(p); - if(auto attr = model.GetExtentsHintAttr()) { + if (auto attr = model.GetExtentsHintAttr()) { modelsToUpdate.push_back(model); // Clear any existing time samples, incase they // includes samples that differ from our sampling times. @@ -1681,14 +2066,14 @@ _UpdateExtentsHints(const UsdPrim& prim, "[UsdSkelBakeSkinning] Update model extents hints for %zu models.\n", modelsToUpdate.size()); - if(modelsToUpdate.size() > 0) { + if (modelsToUpdate.size() > 0) { UsdGeomBBoxCache cache(UsdTimeCode(0), UsdGeomImageable::GetOrderedPurposeTokens(), /*useExtentsHint*/ false); - for(UsdTimeCode time : times) { + for (UsdTimeCode time : times) { cache.SetTime(time); - for(auto& model : modelsToUpdate) { + for (auto& model : modelsToUpdate) { model.SetExtentsHint(model.ComputeExtentsHint(cache), time); } } @@ -1715,7 +2100,7 @@ UsdSkelBakeSkinning(const UsdSkelRoot& root, const GfInterval& interval) // Normal consumers of skel data should instead hold a persistent // cache that is shared by all prims. UsdSkelCache skelCache; - if(!skelCache.Populate(root)) + if (!skelCache.Populate(root)) return false; // Resolve the skeletal bindings. @@ -1846,8 +2231,8 @@ UsdSkelBakeSkinning(const UsdPrimRange& range, const GfInterval& interval) { bool success = true; - for(auto it = range.begin(); it != range.end(); ++it) { - if(it->IsA()) { + for (auto it = range.begin(); it != range.end(); ++it) { + if (it->IsA()) { success &= UsdSkelBakeSkinning(UsdSkelRoot(*it), interval); it.PruneChildren(); } diff --git a/pxr/usd/lib/usdSkel/utils.h b/pxr/usd/lib/usdSkel/utils.h index 322af40cd9..1a9f6f2bd2 100644 --- a/pxr/usd/lib/usdSkel/utils.h +++ b/pxr/usd/lib/usdSkel/utils.h @@ -34,7 +34,9 @@ #include "pxr/base/gf/interval.h" #include "pxr/base/gf/quatf.h" -#include "pxr/base/gf/vec3f.h" +#include "pxr/base/gf/matrix4d.h" +#include "pxr/base/gf/matrix4f.h" +#include "pxr/base/gf/vec3h.h" #include "pxr/base/gf/vec3h.h" #include "pxr/base/tf/span.h" #include "pxr/base/vt/array.h" @@ -49,7 +51,7 @@ PXR_NAMESPACE_OPEN_SCOPE class GfMatrix3f; -class GfMatrix4d; +class GfRange3f; class GfRotation; class UsdPrim; class UsdPrimRange; @@ -84,8 +86,10 @@ UsdSkelIsSkinnablePrim(const UsdPrim& prim); /// Compute joint transforms in joint-local space. /// Transforms are computed from \p xforms, holding concatenated /// joint transforms, and \p inverseXforms, providing the inverse -/// of each of those transforms. -/// If the root transforms include an additional, external transformation +/// of each of those transforms. The resulting local space transforms +/// are written to \p jointLocalXforms, which must be the same size +/// as \p topology. +/// If the root joints include an additional, external transformation /// -- eg., such as the skel local-to-world transformation -- then the /// inverse of that transform should be passed as \p rootInverseXform. /// If no \p rootInverseXform is provided, then \p xform and \p inverseXforms @@ -93,17 +97,54 @@ UsdSkelIsSkinnablePrim(const UsdPrim& prim); /// Each transform array must be sized to the number of joints from \p topology. USDSKEL_API bool +UsdSkelComputeJointLocalTransforms(const UsdSkelTopology& topology, + TfSpan xforms, + TfSpan inverseXforms, + TfSpan jointLocalXforms, + const GfMatrix4d* rootInverseXform=nullptr); + +/// \overload +USDSKEL_API +bool +UsdSkelComputeJointLocalTransforms(const UsdSkelTopology& topology, + TfSpan xforms, + TfSpan inverseXforms, + TfSpan jointLocalXforms, + const GfMatrix4f* rootInverseXform=nullptr); + +/// Compute joint transforms in joint-local space. +/// This is a convenience overload, which computes the required inverse +/// transforms internally. +USDSKEL_API +bool +UsdSkelComputeJointLocalTransforms(const UsdSkelTopology& topology, + TfSpan xforms, + TfSpan jointLocalXforms, + const GfMatrix4d* rootInverseXform=nullptr); + +USDSKEL_API +bool +UsdSkelComputeJointLocalTransforms(const UsdSkelTopology& topology, + TfSpan xforms, + TfSpan jointLocalXforms, + const GfMatrix4f* rootInverseXform=nullptr); + + +/// \overload +/// \deprecated Use form that takes TfSpan arguments. +USDSKEL_API +bool UsdSkelComputeJointLocalTransforms(const UsdSkelTopology& topology, const VtMatrix4dArray& xforms, const VtMatrix4dArray& inverseXforms, VtMatrix4dArray* jointLocalXforms, const GfMatrix4d* rootInverseXform=nullptr); + + + /// \overload -/// Convenience overload that computes inverse transforms internally. -/// If the inverse of \p xforms are needed elsewhere, it is more efficine to -/// use the form of this method that takes inverse transforms as an argument, -/// and compute the inverse transforms separately. +/// \deprecated Use form that takes TfSpan arguments. USDSKEL_API bool UsdSkelComputeJointLocalTransforms(const UsdSkelTopology& topology, @@ -113,6 +154,7 @@ UsdSkelComputeJointLocalTransforms(const UsdSkelTopology& topology, /// \overload +/// \deprecated Use form that takes TfSpan arguments. USDSKEL_API bool UsdSkelComputeJointLocalTransforms(const UsdSkelTopology& topology, @@ -125,7 +167,8 @@ UsdSkelComputeJointLocalTransforms(const UsdSkelTopology& topology, /// Compute concatenated joint transforms. /// This concatenates transforms from \p jointLocalXforms, providing joint -/// transforms in joint-local space. +/// transforms in joint-local space. The resulting transforms are written to +/// \p jointLocalXforms, which must be the same size as \p topology. /// If \p rootXform is not provided, or is the identity, the resulting joint /// transforms will be given in skeleton space. Any additional transformations /// may be provided on \p rootXform if an additional level of transformation @@ -133,6 +176,26 @@ UsdSkelComputeJointLocalTransforms(const UsdSkelTopology& topology, /// Each transform array must be sized to the number of joints from \p topology. USDSKEL_API bool +UsdSkelConcatJointTransforms(const UsdSkelTopology& topology, + TfSpan jointLocalXforms, + TfSpan xforms, + const GfMatrix4d* rootXform=nullptr); + + +/// \overload +USDSKEL_API +bool +UsdSkelConcatJointTransforms(const UsdSkelTopology& topology, + TfSpan jointLocalXforms, + TfSpan xforms, + const GfMatrix4f* rootXform=nullptr); + + + +/// \overload +/// \deprecated Use the function form that takes TfSpan arguments. +USDSKEL_API +bool UsdSkelConcatJointTransforms(const UsdSkelTopology& topology, const VtMatrix4dArray& jointLocalXforms, VtMatrix4dArray* xforms, @@ -140,6 +203,7 @@ UsdSkelConcatJointTransforms(const UsdSkelTopology& topology, /// \overload +/// \deprecated Use the form that takes a TfSpan argument. USDSKEL_API bool UsdSkelConcatJointTransforms(const UsdSkelTopology& topology, @@ -152,6 +216,18 @@ UsdSkelConcatJointTransforms(const UsdSkelTopology& topology, /// The \p rootXform may also be set to provide an additional root /// transformation on top of all joints, which is useful for computing /// extent relative to a different space. +template +USDSKEL_API +bool +UsdSkelComputeJointsExtent(TfSpan joints, + GfRange3f* extent, + float pad=0.0f, + const Matrix4* rootXform=nullptr); + + + +/// \overload +/// \deprecated Use form that takes a TfSpan. USDSKEL_API bool UsdSkelComputeJointsExtent(const VtMatrix4dArray& joints, @@ -161,6 +237,7 @@ UsdSkelComputeJointsExtent(const VtMatrix4dArray& joints, /// \overload +/// \deprecated Use form that takes a TfSpan. USDSKEL_API bool UsdSkelComputeJointsExtent(const GfMatrix4d* xforms, @@ -181,23 +258,44 @@ UsdSkelComputeJointsExtent(const GfMatrix4d* xforms, /// Decompose a transform into translate/rotate/scale components. /// The transform order for decomposition is scale, rotate, translate. +template USDSKEL_API bool -UsdSkelDecomposeTransform(const GfMatrix4d& xform, +UsdSkelDecomposeTransform(const Matrix4& xform, GfVec3f* translate, GfRotation* rotate, GfVec3h* scale); /// \overload +template USDSKEL_API bool -UsdSkelDecomposeTransform(const GfMatrix4d& xform, +UsdSkelDecomposeTransform(const Matrix4& xform, GfVec3f* translate, GfQuatf* rotate, GfVec3h* scale); /// Decompose an array of transforms into translate/rotate/scale components. +/// All spans must be the same size. +USDSKEL_API +bool +UsdSkelDecomposeTransforms(TfSpan xforms, + TfSpan translations, + TfSpan rotations, + TfSpan scales); + +/// \overload +USDSKEL_API +bool +UsdSkelDecomposeTransforms(TfSpan xforms, + TfSpan translations, + TfSpan rotations, + TfSpan scales); + + +/// \overload +/// \deprecated Use form that takes TfSpan arguments. USDSKEL_API bool UsdSkelDecomposeTransforms(const VtMatrix4dArray& xforms, @@ -207,6 +305,7 @@ UsdSkelDecomposeTransforms(const VtMatrix4dArray& xforms, /// \overload +/// \deprecated Use form that takes TfSpan arguments. USDSKEL_API bool UsdSkelDecomposeTransforms(const GfMatrix4d* xforms, @@ -218,20 +317,44 @@ UsdSkelDecomposeTransforms(const GfMatrix4d* xforms, /// Create a transform from translate/rotate/scale components. /// This performs the inverse of UsdSkelDecomposeTransform. +template USDSKEL_API -GfMatrix4d +void UsdSkelMakeTransform(const GfVec3f& translate, const GfMatrix3f& rotate, - const GfVec3h& scale); + const GfVec3h& scale, + Matrix4* xform); /// \overload +template USDSKEL_API -GfMatrix4d +void UsdSkelMakeTransform(const GfVec3f& translate, const GfQuatf& rotate, - const GfVec3h& scale); + const GfVec3h& scale, + Matrix4* xform); /// Create transforms from arrays of components. +/// All spans must be the same size. +USDSKEL_API +bool +UsdSkelMakeTransforms(TfSpan translations, + TfSpan rotations, + TfSpan scales, + TfSpan xforms); + + +/// \overload +USDSKEL_API +bool +UsdSkelMakeTransforms(TfSpan translations, + TfSpan rotations, + TfSpan scales, + TfSpan xforms); + + +/// \overload +/// \deprecated Use form that takes TfSpan arguments. USDSKEL_API bool UsdSkelMakeTransforms(const VtVec3fArray& translations, @@ -240,6 +363,7 @@ UsdSkelMakeTransforms(const VtVec3fArray& translations, VtMatrix4dArray* xforms); /// \overload +/// \deprecated Use form that takes TfSpan arguments. USDSKEL_API bool UsdSkelMakeTransforms(const GfVec3f* translations, @@ -262,12 +386,26 @@ UsdSkelMakeTransforms(const GfVec3f* translations, /// \p numInfluencesPerComponent elements. USDSKEL_API bool +UsdSkelNormalizeWeights(TfSpan weights, int numInfluencesPerComponent); + + +/// \overload +/// \deprecated Use form that takes a TfSpan. +USDSKEL_API +bool UsdSkelNormalizeWeights(VtFloatArray* weights, int numInfluencesPerComponent); /// Sort joint influences such that highest weight values come first. USDSKEL_API bool +UsdSkelSortInfluences(TfSpan indices, TfSpan weights, + int numInfluencesPerComponent); + +/// \overload +/// \deprecated Use form that takes TfSpan arguments. +USDSKEL_API +bool UsdSkelSortInfluences(VtIntArray* indices, VtFloatArray* weights, int numInfluencesPerComponent); @@ -323,6 +461,30 @@ UsdSkelResizeInfluences(VtFloatArray* weights, /// were computed in. USDSKEL_API bool +UsdSkelSkinPointsLBS(const GfMatrix4d& geomBindTransform, + TfSpan jointXforms, + TfSpan jointIndices, + TfSpan jointWeights, + int numInfluencesPerPoint, + TfSpan points, + bool inSerial=false); + +/// \overload +USDSKEL_API +bool +UsdSkelSkinPointsLBS(const GfMatrix4f& geomBindTransform, + TfSpan jointXforms, + TfSpan jointIndices, + TfSpan jointWeights, + int numInfluencesPerPoint, + TfSpan points, + bool inSerial=false); + + +/// \overload +/// \deprecated Use form that takes TfSpan arguments. +USDSKEL_API +bool UsdSkelSkinPointsLBS(const GfMatrix4d& geomBindTransform, const VtMatrix4dArray& jointXforms, const VtIntArray& jointIndices, @@ -332,6 +494,7 @@ UsdSkelSkinPointsLBS(const GfMatrix4d& geomBindTransform, /// \overload +/// \deprecated Use form that takes TfSpan arguments. USDSKEL_API bool UsdSkelSkinPointsLBS(const GfMatrix4d& geomBindTransform, @@ -343,7 +506,7 @@ UsdSkelSkinPointsLBS(const GfMatrix4d& geomBindTransform, int numInfluencesPerPoint, GfVec3f* points, size_t numPoints, - bool forceSerial=false); + bool inSerial=false); /// Skin a transform using linear blend skinning (LBS). @@ -353,6 +516,25 @@ UsdSkelSkinPointsLBS(const GfMatrix4d& geomBindTransform, /// a primitive in that same _skeleton space_. USDSKEL_API bool +UsdSkelSkinTransformLBS(const GfMatrix4d& geomBindTransform, + TfSpan jointXforms, + TfSpan jointIndices, + TfSpan jointWeights, + GfMatrix4d* xform); + +/// \overload +USDSKEL_API +bool +UsdSkelSkinTransformLBS(const GfMatrix4f& geomBindTransform, + TfSpan jointXforms, + TfSpan jointIndices, + TfSpan jointWeights, + GfMatrix4f* xform); + +/// \overload +/// \deprecated Use form that takes TfSpan arguments. +USDSKEL_API +bool UsdSkelSkinTransformLBS(const GfMatrix4d& geomBindTransform, const VtMatrix4dArray& jointXforms, const VtIntArray& jointIndices, @@ -361,6 +543,7 @@ UsdSkelSkinTransformLBS(const GfMatrix4d& geomBindTransform, /// \overload +/// \deprecated Use form that takes TfSpan arguments. USDSKEL_API bool UsdSkelSkinTransformLBS(const GfMatrix4d& geomBindTransform, diff --git a/pxr/usd/lib/usdSkel/wrapAnimMapper.cpp b/pxr/usd/lib/usdSkel/wrapAnimMapper.cpp index cc1237156b..3bc1d5635e 100644 --- a/pxr/usd/lib/usdSkel/wrapAnimMapper.cpp +++ b/pxr/usd/lib/usdSkel/wrapAnimMapper.cpp @@ -23,12 +23,16 @@ // #include "pxr/usd/usdSkel/animMapper.h" -#include "pxr/usd/usd/pyConversions.h" +#include "pxr/base/gf/matrix4d.h" +#include "pxr/base/gf/matrix4f.h" + #include "pxr/base/tf/pyContainerConversions.h" #include "pxr/base/tf/pyResultConversions.h" #include "pxr/base/tf/pyUtils.h" #include "pxr/base/tf/wrapTypeHelpers.h" +#include "pxr/usd/usd/pyConversions.h" + #include @@ -52,13 +56,14 @@ _Remap(const UsdSkelAnimMapper& self, } -VtMatrix4dArray +template +VtArray _RemapTransforms(const UsdSkelAnimMapper& self, - const VtMatrix4dArray& source, - const VtMatrix4dArray& target, + const VtArray& source, + const VtArray& target, int elementSize) { - VtMatrix4dArray output(target); + VtArray output(target); self.RemapTransforms(source, &output, elementSize); return output; } @@ -83,7 +88,12 @@ void wrapUsdSkelAnimMapper() arg("elementSize")=1, arg("defaultValue")=VtValue())) - .def("RemapTransforms", &_RemapTransforms, + .def("RemapTransforms", &_RemapTransforms, + (arg("source"), + arg("target"), + arg("elementSize")=1)) + + .def("RemapTransforms", &_RemapTransforms, (arg("source"), arg("target"), arg("elementSize")=1)) diff --git a/pxr/usd/lib/usdSkel/wrapSkinningQuery.cpp b/pxr/usd/lib/usdSkel/wrapSkinningQuery.cpp index f013fd2b57..1b9b0c0576 100644 --- a/pxr/usd/lib/usdSkel/wrapSkinningQuery.cpp +++ b/pxr/usd/lib/usdSkel/wrapSkinningQuery.cpp @@ -23,6 +23,10 @@ // #include "pxr/usd/usdSkel/skinningQuery.h" +#include "pxr/base/gf/interval.h" +#include "pxr/base/gf/matrix4d.h" +#include "pxr/base/gf/matrix4f.h" + #include "pxr/base/tf/pyContainerConversions.h" #include "pxr/base/tf/pyPtrHelpers.h" #include "pxr/base/tf/pyResultConversions.h" @@ -32,8 +36,6 @@ #include "pxr/usd/usd/pyConversions.h" #include "pxr/usd/usdGeom/boundable.h" -#include "pxr/base/gf/interval.h" - #include @@ -50,7 +52,7 @@ _ComputeJointInfluences(const UsdSkelSkinningQuery& self, UsdTimeCode time) { VtIntArray indices; VtFloatArray weights; - if(self.ComputeJointInfluences(&indices, &weights, time)) { + if (self.ComputeJointInfluences(&indices, &weights, time)) { return boost::python::make_tuple(indices, weights); } return object(); @@ -64,7 +66,7 @@ _ComputeVaryingJointInfluences(const UsdSkelSkinningQuery& self, { VtIntArray indices; VtFloatArray weights; - if(self.ComputeVaryingJointInfluences(numPoints, &indices, + if (self.ComputeVaryingJointInfluences(numPoints, &indices, &weights, time)) { return boost::python::make_tuple(indices, weights); } @@ -95,15 +97,16 @@ object _GetJointOrder(const UsdSkelSkinningQuery& self) { VtTokenArray jointOrder; - if(self.GetJointOrder(&jointOrder)) + if (self.GetJointOrder(&jointOrder)) return object(jointOrder); return object(); } +template bool _ComputeSkinnedPoints(const UsdSkelSkinningQuery& self, - const VtMatrix4dArray& xforms, + const VtArray& xforms, VtVec3fArray& points, UsdTimeCode time) { @@ -111,12 +114,13 @@ _ComputeSkinnedPoints(const UsdSkelSkinningQuery& self, } -GfMatrix4d +template +Matrix4 _ComputeSkinnedTransform(const UsdSkelSkinningQuery& self, - const VtMatrix4dArray& xforms, + const VtArray& xforms, UsdTimeCode time) { - GfMatrix4d xform; + Matrix4 xform; self.ComputeSkinnedTransform(xforms, &xform, time); return xform; } @@ -174,15 +178,36 @@ void wrapUsdSkelSkinningQuery() .def("ComputeVaryingJointInfluences", &_ComputeVaryingJointInfluences, (arg("numPoints"), arg("time")=UsdTimeCode::Default())) - .def("ComputeSkinnedPoints", &_ComputeSkinnedPoints, + .def("ComputeSkinnedPoints", &_ComputeSkinnedPoints, + (arg("xforms"), arg("points"), + arg("time")=UsdTimeCode::Default())) + + .def("ComputeSkinnedPoints", &_ComputeSkinnedPoints, (arg("xforms"), arg("points"), arg("time")=UsdTimeCode::Default())) - .def("ComputeSkinnedTransform", &_ComputeSkinnedTransform, + .def("ComputeSkinnedTransform", &_ComputeSkinnedTransform, (arg("xforms"), arg("time")=UsdTimeCode::Default())) - .def("ComputeExentsPadding", &This::ComputeExtentsPadding, + .def("ComputeSkinnedTransform", &_ComputeSkinnedTransform, + (arg("xforms"), + arg("time")=UsdTimeCode::Default())) + + .def("ComputeExentsPadding", + static_cast( + &This::ComputeExtentsPadding), + (arg("skelRestXforms"), + arg("boundable"), + arg("time")=UsdTimeCode::Default())) + + .def("ComputeExentsPadding", + static_cast( + &This::ComputeExtentsPadding), (arg("skelRestXforms"), arg("boundable"), arg("time")=UsdTimeCode::Default())) diff --git a/pxr/usd/lib/usdSkel/wrapTopology.cpp b/pxr/usd/lib/usdSkel/wrapTopology.cpp index c5cffb6daa..b691a65f4e 100644 --- a/pxr/usd/lib/usdSkel/wrapTopology.cpp +++ b/pxr/usd/lib/usdSkel/wrapTopology.cpp @@ -57,9 +57,9 @@ void wrapUsdSkelTopology() using This = UsdSkelTopology; class_("Topology", no_init) - .def(init()) + .def(init()) + .def(init()) .def(init()) - .def(init()) .def("GetParent", &This::GetParent) @@ -70,7 +70,7 @@ void wrapUsdSkelTopology() .def("GetNumJoints", &This::GetNumJoints) - .def("__len__", &This::GetNumJoints) + .def("__len__", &This::size) .def("Validate", &_Validate) ; diff --git a/pxr/usd/lib/usdSkel/wrapUtils.cpp b/pxr/usd/lib/usdSkel/wrapUtils.cpp index bdd0a7faca..3cfb35e423 100644 --- a/pxr/usd/lib/usdSkel/wrapUtils.cpp +++ b/pxr/usd/lib/usdSkel/wrapUtils.cpp @@ -23,13 +23,15 @@ // #include "pxr/usd/usdSkel/utils.h" -#include "pxr/usd/usd/pyConversions.h" #include "pxr/base/gf/matrix4d.h" +#include "pxr/base/gf/matrix4f.h" +#include "pxr/base/gf/range3f.h" #include "pxr/base/tf/pyContainerConversions.h" #include "pxr/base/tf/pyResultConversions.h" #include "pxr/base/tf/pyUtils.h" #include "pxr/base/tf/wrapTypeHelpers.h" +#include "pxr/usd/usd/pyConversions.h" #include "pxr/usd/usd/primRange.h" #include "pxr/usd/usd/relationship.h" @@ -49,66 +51,55 @@ PXR_NAMESPACE_USING_DIRECTIVE namespace { +// deprecated VtMatrix4dArray _ComputeJointLocalTransforms(const UsdSkelTopology& topology, const VtMatrix4dArray& xforms, const VtMatrix4dArray& inverseXforms, - const object& rootInverseXformObj) + const GfMatrix4d* rootInverseXform=nullptr) { VtMatrix4dArray jointLocalXforms; - if(rootInverseXformObj) { - GfMatrix4d rootInverseXform = extract(rootInverseXformObj); - UsdSkelComputeJointLocalTransforms(topology, xforms, inverseXforms, - &jointLocalXforms, &rootInverseXform); - } else { - UsdSkelComputeJointLocalTransforms(topology, xforms, inverseXforms, - &jointLocalXforms); - } + UsdSkelComputeJointLocalTransforms(topology, xforms, inverseXforms, + &jointLocalXforms, rootInverseXform); return jointLocalXforms; } +// deprecated VtMatrix4dArray -_ComputeJointLocalTransforms_NoInvXforms(const UsdSkelTopology& topology, - const VtMatrix4dArray& xforms, - const object& rootInverseXformObj) +_ComputeJointLocalTransforms_NoInvXforms( + const UsdSkelTopology& topology, + const VtMatrix4dArray& xforms, + const GfMatrix4d* rootInverseXform=nullptr) { VtMatrix4dArray jointLocalXforms; - if (rootInverseXformObj) { - GfMatrix4d rootInverseXform = extract(rootInverseXformObj); - UsdSkelComputeJointLocalTransforms(topology, xforms, &jointLocalXforms, - &rootInverseXform); - } else { - UsdSkelComputeJointLocalTransforms(topology, xforms, &jointLocalXforms); - } + UsdSkelComputeJointLocalTransforms(topology, xforms, &jointLocalXforms, + rootInverseXform); return jointLocalXforms; } +// depreacted VtMatrix4dArray _ConcatJointTransforms(const UsdSkelTopology& topology, const VtMatrix4dArray& jointLocalXforms, - const object& rootXformObj) + const GfMatrix4d* rootXform=nullptr) { VtMatrix4dArray xforms; - if(rootXformObj) { - GfMatrix4d rootXform = extract(rootXformObj); - UsdSkelConcatJointTransforms(topology, jointLocalXforms, - &xforms, &rootXform); - } else { - UsdSkelConcatJointTransforms(topology, jointLocalXforms, &xforms); - } + UsdSkelConcatJointTransforms(topology, jointLocalXforms, + &xforms, rootXform); return xforms; } +template tuple -_DecomposeTransform(const GfMatrix4d& mx) +_DecomposeTransform(const Matrix4& mx) { GfVec3f t; GfQuatf r; GfVec3h s; - if(!UsdSkelDecomposeTransform(mx, &t, &r, &s)) { + if (!UsdSkelDecomposeTransform(mx, &t, &r, &s)) { // XXX: Want this case to throw an exception. TF_CODING_ERROR("Failed decomposing transform. " "The transform may be singular."); @@ -117,13 +108,14 @@ _DecomposeTransform(const GfMatrix4d& mx) } +template tuple -_DecomposeTransforms(const VtMatrix4dArray& xforms) +_DecomposeTransforms(const TfSpan& xforms) { - VtVec3fArray t; - VtQuatfArray r; - VtVec3hArray s; - if(!UsdSkelDecomposeTransforms(xforms, &t, &r, &s)) { + VtVec3fArray t(xforms.size()); + VtQuatfArray r(xforms.size()); + VtVec3hArray s(xforms.size()); + if (!UsdSkelDecomposeTransforms(xforms, t, r, s)) { TF_CODING_ERROR("Failed decomposing transforms. " "Some transforms may be singular."); } @@ -136,124 +128,123 @@ _MakeTransform(const GfVec3f& translate, const GfQuatf& rotate, const GfVec3h& scale) { - return UsdSkelMakeTransform(translate, rotate, scale); + GfMatrix4d xform; + UsdSkelMakeTransform(translate, rotate, scale, &xform); + return xform; } VtMatrix4dArray -_MakeTransforms(const VtVec3fArray& translations, - const VtQuatfArray& rotations, - const VtVec3hArray& scales) +_MakeTransforms(TfSpan translations, + TfSpan rotations, + TfSpan scales) { - VtMatrix4dArray xforms; - UsdSkelMakeTransforms(translations, rotations, scales, &xforms); + VtMatrix4dArray xforms(translations.size()); + UsdSkelMakeTransforms(translations, rotations, scales, xforms); return xforms; } - -VtVec3fArray -_ComputeJointsExtent(const VtMatrix4dArray& xforms, float pad, - const object& rootXformObj) -{ - VtVec3fArray extent; - - extract x(rootXformObj); - if(x.check()) { - const GfMatrix4d& rootXform = x; - UsdSkelComputeJointsExtent(xforms, &extent, pad, &rootXform); - } else { - UsdSkelComputeJointsExtent(xforms, &extent, pad); - } - return extent; + +template +GfRange3f +_ComputeJointsExtent(TfSpan xforms, + float pad=0, + const Matrix4* rootXform=nullptr) +{ + GfRange3f range; + UsdSkelComputeJointsExtent(xforms, &range, pad, rootXform); + return range; } +template bool -_NormalizeWeights(VtFloatArray& weights, - int numInfluencesPerComponent) +_ExpandConstantInfluencesToVarying(VtArray& array, size_t size) { - return UsdSkelNormalizeWeights(&weights, numInfluencesPerComponent); + return UsdSkelExpandConstantInfluencesToVarying(&array, size); } +template bool -_SortInfluences(VtIntArray& indices, - VtFloatArray& weights, - int numInfluencesPerComponent) +_ResizeInfluences(VtArray& array, + int srcNumInfluencesPerPoint, + int newNumInfluencesPerPoint) { - return UsdSkelSortInfluences(&indices, &weights, numInfluencesPerComponent); + return UsdSkelResizeInfluences( + &array, srcNumInfluencesPerPoint, newNumInfluencesPerPoint); } -bool -_ExpandConstantInfluencesToVarying(object& arrayObj, size_t size) +template +Matrix4 +_SkinTransformLBS(const Matrix4& geomBindTransform, + TfSpan jointXforms, + TfSpan jointIndices, + TfSpan jointWeights) { - extract x(arrayObj); - if(x.check()) { - VtIntArray& array = x; - return UsdSkelExpandConstantInfluencesToVarying(&array, size); - } else { - VtFloatArray& array = extract(arrayObj); - return UsdSkelExpandConstantInfluencesToVarying(&array, size); + Matrix4 xform; + if (!UsdSkelSkinTransformLBS(geomBindTransform, jointXforms, + jointIndices, jointWeights, &xform)) { + xform = geomBindTransform; } + return xform; } -bool -_ResizeInfluences(object& arrayObj, - int srcNumInfluencesPerPoint, - int newNumInfluencesPerPoint) +template +void _WrapUtilsT() { - extract x(arrayObj); - if(x.check()) { - VtIntArray& array = x; - return UsdSkelResizeInfluences( - &array, srcNumInfluencesPerPoint, newNumInfluencesPerPoint); - } else { - VtFloatArray& array = extract(arrayObj); - return UsdSkelResizeInfluences( - &array, srcNumInfluencesPerPoint, newNumInfluencesPerPoint); - } -} + def("ComputeJointLocalTransforms", + static_cast, + TfSpan, TfSpan, + const Matrix4*)>( + &UsdSkelComputeJointLocalTransforms), + (arg("topology"), arg("xforms"), arg("inverseXforms"), + arg("jointLocalXforms"), arg("rootInverseXform")=object())); + def("ComputeJointLocalTransforms", + static_cast, + TfSpan, const Matrix4*)>( + &UsdSkelComputeJointLocalTransforms), + (arg("topology"), arg("xforms"), + arg("jointLocalXforms"), arg("rootInverseXform")=object())); -bool -_SkinPointsLBS(const GfMatrix4d& geomBindTransform, - const VtMatrix4dArray& jointXforms, - const VtIntArray& jointIndices, - const VtFloatArray& jointWeights, - int numInfluencesPerPoint, - VtVec3fArray& points) -{ - return UsdSkelSkinPointsLBS(geomBindTransform, jointXforms, jointIndices, - jointWeights, numInfluencesPerPoint, &points); -} + def("ConcatJointTransforms", + static_cast, + TfSpan, const Matrix4*)>( + &UsdSkelConcatJointTransforms), + (arg("topology"), arg("jointLocalXforms"), + arg("rootXform")=object())); + def("DecomposeTransform", &_DecomposeTransform, + "Decompose a transform into a (translate,rotate,scale) tuple."); -GfMatrix4d -_SkinTransformLBS(const GfMatrix4d& geomBindTransform, - const VtMatrix4dArray& jointXforms, - const VtIntArray& jointIndices, - const VtFloatArray& jointWeights) -{ - GfMatrix4d xform; - if(!UsdSkelSkinTransformLBS(geomBindTransform, jointXforms, - jointIndices, jointWeights, &xform)) { - xform = geomBindTransform; - } - return xform; -} + def("DecomposeTransforms", &_DecomposeTransforms, + "Decompose a transform array into a " + "(translations,rotations,scales) tuple."); + def("ComputeJointsExtent", _ComputeJointsExtent, + (arg("xforms"), arg("pad")=0.0f, arg("rootXform")=object())); -template -std::vector -_PyListToVector(const list& l) -{ - std::vector vec(len(l)); - for (size_t i = 0; i < vec.size(); ++i) { - vec[i] = extract(l[i]); - } - return vec; + def("SkinPointsLBS", + static_cast, + TfSpan, TfSpan, + int, TfSpan, bool)>( + &UsdSkelSkinPointsLBS), + (arg("geomBindTransform"), + arg("jointXforms"), + arg("jointIndices"), + arg("jointWeights"), + arg("numInfluencesPerPoint"), + arg("points"), + arg("inSerial")=true)); + + def("SkinTransformLBS", &_SkinTransformLBS, + (arg("geomBindTransform"), + arg("jointXforms"), + arg("jointIndices"), + arg("jointWeights"))); } @@ -262,67 +253,64 @@ _PyListToVector(const list& l) void wrapUsdSkelUtils() { + // Wrap methods supporting different matrix precisions. + _WrapUtilsT(); + _WrapUtilsT(); + def("IsSkelAnimationPrim", &UsdSkelIsSkelAnimationPrim, (arg("prim"))); def("IsSkinnablePrim", &UsdSkelIsSkinnablePrim, (arg("prim"))); + // deprecated def("ComputeJointLocalTransforms", &_ComputeJointLocalTransforms, (arg("topology"), arg("xforms"), arg("inverseXforms"), arg("rootInverseXform")=object())); + // deprecated def("ComputeJointLocalTransforms", &_ComputeJointLocalTransforms_NoInvXforms, (arg("topology"), arg("xforms"), arg("rootInverseXform")=object())); + // deprecated def("ConcatJointTransforms", &_ConcatJointTransforms, (arg("topology"), arg("jointLocalXforms"), arg("rootXform")=object())); - def("DecomposeTransform", &_DecomposeTransform, - "Decompose a transform into a (translate,rotate,scale) tuple."); - - def("DecomposeTransforms", &_DecomposeTransforms, - "Decompose a transform array into a " - "(translations,rotations,scales) tuple."); - def("MakeTransform", &_MakeTransform, (arg("translate"), arg("rotate"), arg("scale"))); + // deprecated def("MakeTransforms", &_MakeTransforms, (arg("translations"), arg("rotations"), arg("scales"))); - - def("ComputeJointsExtent", &_ComputeJointsExtent, - (arg("xforms"), arg("pad")=0.0f, arg("rootXform")=object())); - def("NormalizeWeights", &_NormalizeWeights, + def("NormalizeWeights", + static_cast,int)>( + &UsdSkelNormalizeWeights), (arg("weights"), arg("numInfluencesPerComponent"))); - def("SortInfluences", &_SortInfluences, + def("SortInfluences", + static_cast, TfSpan,int)>( + &UsdSkelSortInfluences), (arg("indices"), arg("weights"), arg("numInfluencesPerComponent"))); def("ExpandConstantInfluencesToVarying", - &_ExpandConstantInfluencesToVarying, + &_ExpandConstantInfluencesToVarying, + (arg("array"), arg("size"))); + + def("ExpandConstantInfluencesToVarying", + &_ExpandConstantInfluencesToVarying, (arg("array"), arg("size"))); - def("ResizeInfluences", &_ResizeInfluences, + def("ResizeInfluences", &_ResizeInfluences, (arg("array"), arg("srcNumInfluencesPerComponent"), arg("newNumInfluencesPerComponent"))); - def("SkinPointsLBS", &_SkinPointsLBS, - (arg("geomBindTransform"), - arg("jointXforms"), - arg("jointIndices"), - arg("jointWeights"), - arg("numInfluencesPerPoint"), - arg("points"))); - - def("SkinTransformLBS", &_SkinTransformLBS, - (arg("geomBindTransform"), - arg("jointXforms"), - arg("jointIndices"), - arg("jointWeights"))); + def("ResizeInfluences", &_ResizeInfluences, + (arg("array"), + arg("srcNumInfluencesPerComponent"), + arg("newNumInfluencesPerComponent"))); def("ApplyBlendShape", &UsdSkelApplyBlendShape, (arg("weight"),