From e380a5c06a0b5985144bed62c457e64c8fa6c044 Mon Sep 17 00:00:00 2001 From: sgustafso Date: Wed, 20 Feb 2019 00:01:28 -0800 Subject: [PATCH] Adding GfMatrix4f versions of all computations on UsdSkelSkeletonQuery, UsdSkelAnimQuery and UsdSkelSkinningQuery. Updating UsdSkel's utility methods to work with arbitrary containers as well as both GfMatrix4d and GfMatrix4f types. Misc code cleanup (Internal change: 1940812) (Internal change: 1940994) (Internal change: 1940995) --- pxr/usd/lib/usdSkel/animMapper.cpp | 18 +- pxr/usd/lib/usdSkel/animMapper.h | 9 +- pxr/usd/lib/usdSkel/animQuery.cpp | 17 +- pxr/usd/lib/usdSkel/animQuery.h | 3 +- pxr/usd/lib/usdSkel/animQueryImpl.cpp | 67 +- pxr/usd/lib/usdSkel/animQueryImpl.h | 3 + pxr/usd/lib/usdSkel/skelDefinition.cpp | 285 ++++- pxr/usd/lib/usdSkel/skelDefinition.h | 56 +- pxr/usd/lib/usdSkel/skeletonQuery.cpp | 191 ++-- pxr/usd/lib/usdSkel/skeletonQuery.h | 27 +- pxr/usd/lib/usdSkel/skinningQuery.cpp | 96 +- pxr/usd/lib/usdSkel/skinningQuery.h | 11 +- pxr/usd/lib/usdSkel/topology.cpp | 74 +- pxr/usd/lib/usdSkel/topology.h | 50 +- pxr/usd/lib/usdSkel/utils.cpp | 1217 ++++++++++++++------- pxr/usd/lib/usdSkel/utils.h | 215 +++- pxr/usd/lib/usdSkel/wrapAnimMapper.cpp | 22 +- pxr/usd/lib/usdSkel/wrapSkinningQuery.cpp | 49 +- pxr/usd/lib/usdSkel/wrapTopology.cpp | 6 +- pxr/usd/lib/usdSkel/wrapUtils.cpp | 282 +++-- 20 files changed, 1813 insertions(+), 885 deletions(-) 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"),