Skip to content

Commit d3b84df

Browse files
Add computation to deform normals for CPU
1 parent f6eea7a commit d3b84df

File tree

7 files changed

+890
-19
lines changed

7 files changed

+890
-19
lines changed

pxr/usd/usdSkel/utils.cpp

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2168,6 +2168,41 @@ _SkinFaceVaryingNormals(const TfToken& skinningMethod,
21682168
}
21692169

21702170

2171+
template <typename Matrix3>
2172+
bool
2173+
_SkinFaceVaryingNormals(const TfToken& skinningMethod,
2174+
const Matrix3& geomBindTransform,
2175+
TfSpan<const Matrix3> jointXforms,
2176+
TfSpan<const GfVec2f> influences,
2177+
const int numInfluencesPerPoint,
2178+
TfSpan<const int> faceVertexIndices,
2179+
TfSpan<GfVec3f> normals,
2180+
const bool inSerial)
2181+
{
2182+
if (faceVertexIndices.size() != normals.size()) {
2183+
TF_WARN("Size of faceVertexIndices [%zu] != size of normals [%zu]",
2184+
faceVertexIndices.size(), normals.size());
2185+
return false;
2186+
}
2187+
2188+
const _InterleavedInfluencesFn influenceFn{influences};
2189+
2190+
const int numPoints = influences.size() / numInfluencesPerPoint;
2191+
const _FaceVaryingPointIndexFn indexFn{faceVertexIndices, numPoints};
2192+
2193+
if (skinningMethod == UsdSkelTokens->classicLinear) {
2194+
return _SkinNormalsLBS(geomBindTransform, jointXforms, influenceFn, indexFn,
2195+
numInfluencesPerPoint, normals, inSerial);
2196+
} else if (skinningMethod == UsdSkelTokens->dualQuaternion) {
2197+
return _SkinNormalsDQS(geomBindTransform, jointXforms, influenceFn, indexFn,
2198+
numInfluencesPerPoint, normals, inSerial);
2199+
} else {
2200+
TF_WARN("Unknown skinning method: '%s' ", skinningMethod.GetText());
2201+
return false;
2202+
}
2203+
}
2204+
2205+
21712206
} // namespace
21722207

21732208

@@ -2269,6 +2304,38 @@ UsdSkelSkinFaceVaryingNormals(const TfToken& skinningMethod,
22692304
}
22702305

22712306

2307+
bool
2308+
UsdSkelSkinFaceVaryingNormals(const TfToken& skinningMethod,
2309+
const GfMatrix3d& geomBindTransform,
2310+
TfSpan<const GfMatrix3d> jointXforms,
2311+
TfSpan<const GfVec2f> influences,
2312+
const int numInfluencesPerPoint,
2313+
TfSpan<const int> faceVertexIndices,
2314+
TfSpan<GfVec3f> normals,
2315+
const bool inSerial)
2316+
{
2317+
return _SkinFaceVaryingNormals(
2318+
skinningMethod, geomBindTransform, jointXforms, influences,
2319+
numInfluencesPerPoint, faceVertexIndices, normals, inSerial);
2320+
}
2321+
2322+
2323+
bool
2324+
UsdSkelSkinFaceVaryingNormals(const TfToken& skinningMethod,
2325+
const GfMatrix3f& geomBindTransform,
2326+
TfSpan<const GfMatrix3f> jointXforms,
2327+
TfSpan<const GfVec2f> influences,
2328+
const int numInfluencesPerPoint,
2329+
TfSpan<const int> faceVertexIndices,
2330+
TfSpan<GfVec3f> normals,
2331+
const bool inSerial)
2332+
{
2333+
return _SkinFaceVaryingNormals(
2334+
skinningMethod, geomBindTransform, jointXforms, influences,
2335+
numInfluencesPerPoint, faceVertexIndices, normals, inSerial);
2336+
}
2337+
2338+
22722339
bool
22732340
UsdSkelSkinNormalsLBS(const GfMatrix3d& geomBindTransform,
22742341
TfSpan<const GfMatrix3d> jointXforms,

pxr/usd/usdSkel/utils.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -693,6 +693,31 @@ UsdSkelSkinFaceVaryingNormals(const TfToken& skinningMethod,
693693
bool inSerial=false);
694694

695695

696+
/// \overload
697+
USDSKEL_API
698+
bool
699+
UsdSkelSkinFaceVaryingNormals(const TfToken& skinningMethod,
700+
const GfMatrix3d& geomBindTransform,
701+
TfSpan<const GfMatrix3d> jointXforms,
702+
TfSpan<const GfVec2f> influences,
703+
int numInfluencesPerPoint,
704+
TfSpan<const int> faceVertexIndices,
705+
TfSpan<GfVec3f> normals,
706+
bool inSerial=false);
707+
708+
/// \overload
709+
USDSKEL_API
710+
bool
711+
UsdSkelSkinFaceVaryingNormals(const TfToken& skinningMethod,
712+
const GfMatrix3f& geomBindTransform,
713+
TfSpan<const GfMatrix3f> jointXforms,
714+
TfSpan<const GfVec2f> influences,
715+
int numInfluencesPerPoint,
716+
TfSpan<const int> faceVertexIndices,
717+
TfSpan<GfVec3f> normals,
718+
bool inSerial=false);
719+
720+
696721
USDSKEL_API
697722
bool
698723
UsdSkelSkinNormalsLBS(const GfMatrix3d& geomBindTransform,

pxr/usdImaging/usdSkelImaging/CMakeLists.txt

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,32 @@ pxr_library(usdSkelImaging
4747
plugInfo.json
4848
shaders/skinning.glslfx
4949
)
50+
51+
# Build tests
52+
pxr_build_test(testUsdSkelImagingSkeletonAdapter
53+
LIBRARIES
54+
usdImaging
55+
usdShade
56+
usdGeom
57+
usdSkel
58+
usd
59+
sdf
60+
hd
61+
tf
62+
gf
63+
arch
64+
CPPFILES
65+
testenv/testUsdSkelImagingSkeletonAdapter.cpp
66+
)
67+
68+
# Install (copy test assets and baselines)
69+
pxr_install_test_dir(
70+
SRC testenv/testUsdSkelImagingSkeletonAdapter
71+
DEST testUsdSkelImagingSkeletonAdapter
72+
)
73+
74+
# Register tests
75+
pxr_register_test(testUsdSkelImagingSkeletonAdapter
76+
COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdSkelImagingSkeletonAdapter"
77+
EXPECTED_RETURN_CODE 0
78+
)

pxr/usdImaging/usdSkelImaging/extComputations.cpp

Lines changed: 212 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,17 @@ _TransformPoints(TfSpan<GfVec3f> points, const GfMatrix4d& xform)
5151
}, /*grainSize*/ 1000);
5252
}
5353

54+
static
55+
void
56+
_TransformNormals(TfSpan<GfVec3f> normals, const GfMatrix3d& xformInvTranspose)
57+
{
58+
WorkParallelForN(normals.size(), [&](size_t start, size_t end) {
59+
for (size_t i = start; i < end; ++i) {
60+
normals[i] = GfVec3f(normals[i] * xformInvTranspose);
61+
}
62+
}, /*grainSize*/ 1000);
63+
}
64+
5465
static
5566
void
5667
_ApplyPackedBlendShapes(const TfSpan<const GfVec4f>& offsets,
@@ -73,13 +84,12 @@ _ApplyPackedBlendShapes(const TfSpan<const GfVec4f>& offsets,
7384
}
7485
}
7586

87+
static
7688
void
77-
UsdSkelImagingInvokeExtComputation(
89+
_InvokeSkinningComputationPoints(
7890
const TfToken &skinningMethod,
7991
HdExtComputationContext * const ctx)
8092
{
81-
TRACE_FUNCTION();
82-
8393
const VtValue restPointsValue =
8494
ctx->GetInputValue(
8595
UsdSkelImagingExtAggregatorComputationInputNameTokens
@@ -214,6 +224,205 @@ UsdSkelImagingInvokeExtComputation(
214224
VtValue(skinnedPoints));
215225
}
216226

227+
static
228+
void
229+
_DeformNormalsWithSkinning(
230+
const TfToken& skinningMethod,
231+
const GfMatrix4f& geomBindXform,
232+
const VtMatrix4fArray& skinningXforms,
233+
const VtVec2fArray& influences,
234+
bool hasConstantInfluences,
235+
const int numInfluencesPerComponent,
236+
const VtIntArray& faceVertexIndices,
237+
const GfMatrix4d& seklToPrimLocalXform,
238+
const bool hasFaceVaryingNormals,
239+
VtVec3fArray& skinnedNormals)
240+
{
241+
if (hasConstantInfluences) {
242+
// Have constant influences. Compute a rigid deformation.
243+
GfMatrix4f skinnedTransform;
244+
if (UsdSkelSkinTransform(
245+
skinningMethod,
246+
geomBindXform,
247+
skinningXforms,
248+
influences,
249+
&skinnedTransform)) {
250+
251+
// The computed skinnedTransform is the transform which, when
252+
// applied to the normals of the skinned prim, results in skinned
253+
// normals in *skel* space, and need to be xformed to prim
254+
// local space.
255+
256+
const GfMatrix4d restToPrimLocalSkinnedXf =
257+
GfMatrix4d(skinnedTransform) * seklToPrimLocalXform;
258+
const GfMatrix3d restToPrimLocalSkinnedXfInvTranspose =
259+
restToPrimLocalSkinnedXf.ExtractRotationMatrix().GetInverse().GetTranspose();
260+
261+
_TransformNormals(skinnedNormals, restToPrimLocalSkinnedXfInvTranspose);
262+
}
263+
} else {
264+
// Get geomBindInvTransposeXform
265+
const GfMatrix3d& geomBindInvTransposeXform = GfMatrix4d(geomBindXform)
266+
.ExtractRotationMatrix().GetInverse().GetTranspose();
267+
268+
// Get skinningInvTransposeXforms in parallel
269+
VtMatrix3dArray skinningInvTransposeXforms(skinningXforms.size());
270+
{
271+
auto skinningDst = TfMakeSpan(skinningInvTransposeXforms);
272+
WorkParallelForN(
273+
skinningXforms.size(),
274+
[&](size_t start, size_t end) {
275+
for (size_t i = start; i < end; ++i) {
276+
skinningDst[i] = GfMatrix4d(skinningXforms[i]).ExtractRotationMatrix()
277+
.GetInverse().GetTranspose();
278+
}
279+
});
280+
}
281+
282+
if (hasFaceVaryingNormals) {
283+
UsdSkelSkinFaceVaryingNormals(skinningMethod, geomBindInvTransposeXform,
284+
skinningInvTransposeXforms, influences,
285+
numInfluencesPerComponent,
286+
faceVertexIndices, skinnedNormals);
287+
} else {
288+
UsdSkelSkinNormals(skinningMethod, geomBindInvTransposeXform,
289+
skinningInvTransposeXforms, influences,
290+
numInfluencesPerComponent,
291+
skinnedNormals);
292+
}
293+
294+
// Output of skinning is in *skel* space.
295+
// Transform the result into gprim space.
296+
const GfMatrix3d& skelToGprimInvTransposeXform =
297+
seklToPrimLocalXform.ExtractRotationMatrix().GetInverse().GetTranspose();
298+
_TransformNormals(skinnedNormals, skelToGprimInvTransposeXform);
299+
}
300+
}
301+
302+
static
303+
void
304+
_InvokeSkinningComputationNormals(
305+
const TfToken &skinningMethod,
306+
HdExtComputationContext * const ctx)
307+
{
308+
const VtValue restNormalsValue =
309+
ctx->GetInputValue(
310+
UsdSkelImagingExtAggregatorComputationInputNameTokens
311+
->restNormals);
312+
const VtValue geomBindXformValue =
313+
ctx->GetInputValue(
314+
UsdSkelImagingExtAggregatorComputationInputNameTokens
315+
->geomBindXform);
316+
const VtValue influencesValue =
317+
ctx->GetInputValue(
318+
UsdSkelImagingExtAggregatorComputationInputNameTokens
319+
->influences);
320+
const VtValue numInfluencesPerComponentValue =
321+
ctx->GetInputValue(
322+
UsdSkelImagingExtAggregatorComputationInputNameTokens
323+
->numInfluencesPerComponent);
324+
const VtValue hasConstantInfluencesValue =
325+
ctx->GetInputValue(
326+
UsdSkelImagingExtAggregatorComputationInputNameTokens
327+
->hasConstantInfluences);
328+
const VtValue primWorldToLocalValue =
329+
ctx->GetInputValue(
330+
UsdSkelImagingExtComputationInputNameTokens
331+
->primWorldToLocal);
332+
const VtValue skinningXformsValue =
333+
ctx->GetInputValue(
334+
UsdSkelImagingExtComputationInputNameTokens
335+
->skinningXforms);
336+
const VtValue skelLocalToWorldValue =
337+
ctx->GetInputValue(
338+
UsdSkelImagingExtComputationInputNameTokens
339+
->skelLocalToWorld);
340+
const VtValue faceVertexIndicesValue =
341+
ctx->GetInputValue(
342+
UsdSkelImagingExtAggregatorComputationInputNameTokens
343+
->faceVertexIndices);
344+
const VtValue hasFaceVaryingNormalsValue =
345+
ctx->GetInputValue(
346+
UsdSkelImagingExtAggregatorComputationInputNameTokens
347+
->hasFaceVaryingNormals);
348+
349+
// Ensure inputs are holding the right value types.
350+
if (!restNormalsValue.IsHolding<VtVec3fArray>() ||
351+
!geomBindXformValue.IsHolding<GfMatrix4f>() ||
352+
!influencesValue.IsHolding<VtVec2fArray>() ||
353+
!numInfluencesPerComponentValue.IsHolding<int>() ||
354+
!hasConstantInfluencesValue.IsHolding<bool>() ||
355+
!primWorldToLocalValue.IsHolding<GfMatrix4d>() ||
356+
!skinningXformsValue.IsHolding<VtMatrix4fArray>() ||
357+
!skelLocalToWorldValue.IsHolding<GfMatrix4d>() ||
358+
!faceVertexIndicesValue.IsHolding<VtIntArray>() ||
359+
!hasFaceVaryingNormalsValue.IsHolding<bool>()) {
360+
ctx->RaiseComputationError();
361+
return;
362+
}
363+
364+
VtVec3fArray skinnedNormals =
365+
restNormalsValue.UncheckedGet<VtVec3fArray>();
366+
367+
const int numInfluencesPerComponent =
368+
numInfluencesPerComponentValue.UncheckedGet<int>();
369+
370+
if (numInfluencesPerComponent <= 0) {
371+
ctx->SetOutputValue(
372+
UsdSkelImagingExtComputationOutputNameTokens->skinnedNormals,
373+
VtValue(skinnedNormals));
374+
return;
375+
}
376+
377+
// The points returned above are in skel space, and need to be
378+
// transformed to prim local space.
379+
const GfMatrix4d skelToPrimLocal =
380+
skelLocalToWorldValue.UncheckedGet<GfMatrix4d>() *
381+
primWorldToLocalValue.UncheckedGet<GfMatrix4d>();
382+
_DeformNormalsWithSkinning(
383+
skinningMethod,
384+
geomBindXformValue.UncheckedGet<GfMatrix4f>(),
385+
skinningXformsValue.UncheckedGet<VtMatrix4fArray>(),
386+
influencesValue.UncheckedGet<VtVec2fArray>(),
387+
hasConstantInfluencesValue.UncheckedGet<bool>(),
388+
numInfluencesPerComponent,
389+
faceVertexIndicesValue.UncheckedGet<VtIntArray>(),
390+
skelToPrimLocal,
391+
hasFaceVaryingNormalsValue.UncheckedGet<bool>(),
392+
skinnedNormals);
393+
394+
ctx->SetOutputValue(
395+
UsdSkelImagingExtComputationOutputNameTokens->skinnedNormals,
396+
VtValue(skinnedNormals));
397+
}
398+
399+
void
400+
UsdSkelImagingInvokeExtComputation(
401+
const TfToken &skinningMethod,
402+
HdExtComputationContext * const ctx)
403+
{
404+
TRACE_FUNCTION();
405+
406+
const VtValue* restPointsValuePtr =
407+
ctx->GetOptionalInputValuePtr(
408+
UsdSkelImagingExtAggregatorComputationInputNameTokens->restPoints);
409+
const VtValue* restNormalsValuePtr =
410+
ctx->GetOptionalInputValuePtr(
411+
UsdSkelImagingExtAggregatorComputationInputNameTokens->restNormals);
412+
if(!restPointsValuePtr && !restNormalsValuePtr) {
413+
TF_CODING_ERROR("No rest points or normals provided");
414+
ctx->RaiseComputationError();
415+
return;
416+
}
417+
418+
bool computePoints = restPointsValuePtr != nullptr;
419+
if(computePoints) {
420+
_InvokeSkinningComputationPoints(skinningMethod, ctx);
421+
} else {
422+
_InvokeSkinningComputationNormals(skinningMethod, ctx);
423+
}
424+
}
425+
217426
///////////////////////////////////////////////////////////////////////////////
218427
/// UsdSkelImagingExtComputationCpuCallback
219428

0 commit comments

Comments
 (0)