bool UsdSkelSkeletonQuery::_ComputeSkinningTransforms(VtMatrix4dArray* xforms, UsdTimeCode time) const { if (ComputeJointSkelTransforms(xforms, time)) { // XXX: Since this is a fairly frequent computation request, // skel-space inverse rest transforms are cached on-demand // on the definition VtMatrix4dArray inverseBindXforms; if (!_definition->GetJointWorldInverseBindTransforms( &inverseBindXforms)) { TF_WARN("%s -- Failed fetching bind transforms. The " "'bindTransforms' attribute may be unauthored, " "or may not match the number of joints.", GetSkeleton().GetPrim().GetPath().GetText()); return false; } if(xforms->size() == inverseBindXforms.size()) { // xforms = inverseBindXforms * xforms _PreMultXforms(inverseBindXforms, xforms); return true; } else { TF_WARN("%s -- Size of computed joints transforms [%zu] does not " "match the number of elements in the 'bindTransforms' " "attr [%zu].", GetSkeleton().GetPrim().GetPath().GetText(), xforms->size(), inverseBindXforms.size()); } } return false; }
bool UsdSkelSkeletonQuery::ComputeJointRestRelativeTransforms( VtMatrix4dArray* xforms, UsdTimeCode time) const { TRACE_FUNCTION(); if (!xforms) { TF_CODING_ERROR("'xforms' pointer is null."); return false; } 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; if (_definition->GetJointLocalInverseRestTransforms( &invRestXforms)) { VtMatrix4dArray 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()); return true; } } } else { TF_WARN("%s -- Failed computing rest-relative transforms: " "the 'restTransforms' of the Skeleton are either unset, " "or do not have a matching number of joints.", GetSkeleton().GetPrim().GetPath().GetText()); } } else { // No bound animation, so rest relative transforms are identity. xforms->assign(GetTopology().GetNumJoints(), GfMatrix4d(1)); return true; } } return false; }
void HdRprim::_PopulateConstantPrimVars(HdSceneDelegate* delegate, HdDrawItem *drawItem, HdDirtyBits *dirtyBits) { HD_TRACE_FUNCTION(); HF_MALLOC_TAG_FUNCTION(); SdfPath const& id = GetId(); HdRenderIndex &renderIndex = delegate->GetRenderIndex(); HdResourceRegistry *resourceRegistry = &HdResourceRegistry::GetInstance(); // XXX: this should be in a different method // XXX: This should be in HdSt getting the HdSt Shader const HdShader *shader = static_cast<const HdShader *>( renderIndex.GetSprim(HdPrimTypeTokens->shader, _surfaceShaderID)); if (shader == nullptr) { shader = static_cast<const HdShader *>( renderIndex.GetFallbackSprim(HdPrimTypeTokens->shader)); } _sharedData.surfaceShader = shader->GetShaderCode(); // update uniforms HdBufferSourceVector sources; if (HdChangeTracker::IsTransformDirty(*dirtyBits, id)) { GfMatrix4d transform = delegate->GetTransform(id); _sharedData.bounds.SetMatrix(transform); // for CPU frustum culling HdBufferSourceSharedPtr source(new HdVtBufferSource( HdTokens->transform, transform)); sources.push_back(source); source.reset(new HdVtBufferSource(HdTokens->transformInverse, transform.GetInverse())); sources.push_back(source); // if this is a prototype (has instancer), // also push the instancer transform separately. if (!_instancerID.IsEmpty()) { // gather all instancer transforms in the instancing hierarchy VtMatrix4dArray rootTransforms = _GetInstancerTransforms(delegate); VtMatrix4dArray rootInverseTransforms(rootTransforms.size()); bool leftHanded = transform.IsLeftHanded(); for (size_t i = 0; i < rootTransforms.size(); ++i) { rootInverseTransforms[i] = rootTransforms[i].GetInverse(); // flip the handedness if necessary leftHanded ^= rootTransforms[i].IsLeftHanded(); } source.reset(new HdVtBufferSource( HdTokens->instancerTransform, rootTransforms, /*staticArray=*/true)); sources.push_back(source); source.reset(new HdVtBufferSource( HdTokens->instancerTransformInverse, rootInverseTransforms, /*staticArray=*/true)); sources.push_back(source); // XXX: It might be worth to consider to have isFlipped // for non-instanced prims as well. It can improve // the drawing performance on older-GPUs by reducing // fragment shader cost, although it needs more GPU memory. // set as int (GLSL needs 32-bit align for bool) source.reset(new HdVtBufferSource( HdTokens->isFlipped, VtValue(int(leftHanded)))); sources.push_back(source); } } if (HdChangeTracker::IsExtentDirty(*dirtyBits, id)) { _sharedData.bounds.SetRange(GetExtent(delegate)); GfVec3d const & localMin = drawItem->GetBounds().GetBox().GetMin(); HdBufferSourceSharedPtr sourceMin(new HdVtBufferSource( HdTokens->bboxLocalMin, VtValue(GfVec4f( localMin[0], localMin[1], localMin[2], 0)))); sources.push_back(sourceMin); GfVec3d const & localMax = drawItem->GetBounds().GetBox().GetMax(); HdBufferSourceSharedPtr sourceMax(new HdVtBufferSource( HdTokens->bboxLocalMax, VtValue(GfVec4f( localMax[0], localMax[1], localMax[2], 0)))); sources.push_back(sourceMax); } if (HdChangeTracker::IsPrimIdDirty(*dirtyBits, id)) { GfVec4f primIdColor; int32_t primId = GetPrimId(); HdBufferSourceSharedPtr source(new HdVtBufferSource( HdTokens->primID, VtValue(primId))); sources.push_back(source); } if (HdChangeTracker::IsAnyPrimVarDirty(*dirtyBits, id)) { TfTokenVector primVarNames = delegate->GetPrimVarConstantNames(id); sources.reserve(sources.size()+primVarNames.size()); TF_FOR_ALL(nameIt, primVarNames) { if (HdChangeTracker::IsPrimVarDirty(*dirtyBits, id, *nameIt)) { VtValue value = delegate->Get(id, *nameIt); // XXX Hydra doesn't support string primvar yet if (value.IsHolding<std::string>()) continue; if (!value.IsEmpty()) { HdBufferSourceSharedPtr source( new HdVtBufferSource(*nameIt, value)); // if it's an unacceptable type, skip it (e.g. std::string) if (source->GetNumComponents() > 0) { sources.push_back(source); } } } } }