Skip to content

Commit f367121

Browse files
Defensive check for UsdSkel_SkelAnimationQueryImp to avoid crash
1 parent 6284755 commit f367121

File tree

4 files changed

+183
-3
lines changed

4 files changed

+183
-3
lines changed

pxr/usd/usdSkel/animQueryImpl.cpp

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@ class UsdSkel_SkelAnimationQueryImpl : public UsdSkel_AnimQueryImpl
7373
bool BlendShapeWeightsMightBeTimeVarying() const override;
7474

7575
private:
76+
bool _VerifyAnimation() const {
77+
return TF_VERIFY(_anim, "PackedJointAnimation schema object is invalid.");
78+
}
7679
template <typename Matrix4>
7780
bool _ComputeJointLocalTransforms(VtArray<Matrix4>* xforms,
7881
UsdTimeCode time) const;
@@ -170,6 +173,10 @@ UsdSkel_SkelAnimationQueryImpl::GetJointTransformTimeSamples(
170173
const GfInterval& interval,
171174
std::vector<double>* times) const
172175
{
176+
if (!_VerifyAnimation()) {
177+
return false;
178+
}
179+
173180
return UsdAttribute::GetUnionedTimeSamplesInInterval(
174181
{_translations.GetAttribute(),
175182
_rotations.GetAttribute(),
@@ -180,6 +187,10 @@ bool
180187
UsdSkel_SkelAnimationQueryImpl::GetJointTransformAttributes(
181188
std::vector<UsdAttribute>* attrs) const
182189
{
190+
if (!_VerifyAnimation()) {
191+
return false;
192+
}
193+
183194
attrs->push_back(_translations.GetAttribute());
184195
attrs->push_back(_rotations.GetAttribute());
185196
attrs->push_back(_scales.GetAttribute());
@@ -190,6 +201,10 @@ UsdSkel_SkelAnimationQueryImpl::GetJointTransformAttributes(
190201
bool
191202
UsdSkel_SkelAnimationQueryImpl::JointTransformsMightBeTimeVarying() const
192203
{
204+
if (!_VerifyAnimation()) {
205+
return false;
206+
}
207+
193208
return _translations.ValueMightBeTimeVarying() ||
194209
_rotations.ValueMightBeTimeVarying() ||
195210
_scales.ValueMightBeTimeVarying();
@@ -201,10 +216,10 @@ UsdSkel_SkelAnimationQueryImpl::ComputeBlendShapeWeights(
201216
VtFloatArray* weights,
202217
UsdTimeCode time) const
203218
{
204-
if (TF_VERIFY(_anim, "PackedJointAnimation schema object is invalid.")) {
205-
return _blendShapeWeights.Get(weights, time);
219+
if (!_VerifyAnimation()) {
220+
return false;
206221
}
207-
return false;
222+
return _blendShapeWeights.Get(weights, time);
208223
}
209224

210225

@@ -213,6 +228,9 @@ UsdSkel_SkelAnimationQueryImpl::GetBlendShapeWeightTimeSamples(
213228
const GfInterval& interval,
214229
std::vector<double>* times) const
215230
{
231+
if (!_VerifyAnimation()) {
232+
return false;
233+
}
216234
return _blendShapeWeights.GetTimeSamplesInInterval(interval, times);
217235
}
218236

@@ -221,13 +239,19 @@ bool
221239
UsdSkel_SkelAnimationQueryImpl::GetBlendShapeWeightAttributes(
222240
std::vector<UsdAttribute>* attrs) const
223241
{
242+
if (!_VerifyAnimation()) {
243+
return false;
244+
}
224245
attrs->push_back(_blendShapeWeights.GetAttribute());
225246
return true;
226247
}
227248

228249
bool
229250
UsdSkel_SkelAnimationQueryImpl::BlendShapeWeightsMightBeTimeVarying() const
230251
{
252+
if (!_VerifyAnimation()) {
253+
return false;
254+
}
231255
return _blendShapeWeights.ValueMightBeTimeVarying();
232256
}
233257

pxr/usdImaging/usdSkelImaging/CMakeLists.txt

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,32 @@ pxr_library(usdSkelImaging
3535
plugInfo.json
3636
shaders/skinning.glslfx
3737
)
38+
39+
# Build tests
40+
pxr_build_test(testUsdSkelImagingSkeletonAdapter
41+
LIBRARIES
42+
usdImaging
43+
usdShade
44+
usdGeom
45+
usdSkel
46+
usd
47+
sdf
48+
hd
49+
tf
50+
gf
51+
arch
52+
CPPFILES
53+
testenv/testUsdSkelImagingSkeletonAdapter.cpp
54+
)
55+
56+
# Install (copy test assets and baselines)
57+
pxr_install_test_dir(
58+
SRC testenv/testUsdSkelImagingSkeletonAdapter
59+
DEST testUsdSkelImagingSkeletonAdapter
60+
)
61+
62+
# Register tests
63+
pxr_register_test(testUsdSkelImagingSkeletonAdapter
64+
COMMAND "${CMAKE_INSTALL_PREFIX}/tests/testUsdSkelImagingSkeletonAdapter"
65+
EXPECTED_RETURN_CODE 0
66+
)
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
//
2+
// Copyright 2025 Pixar
3+
//
4+
// Licensed under the terms set forth in the LICENSE.txt file available at
5+
// https://openusd.org/license.
6+
//
7+
8+
#include "pxr/usdImaging/usdImaging/unitTestHelper.h"
9+
10+
#include "pxr/imaging/hd/material.h"
11+
#include "pxr/imaging/hd/renderIndex.h"
12+
#include "pxr/imaging/hd/unitTestNullRenderDelegate.h"
13+
14+
#include "pxr/usd/usd/stage.h"
15+
#include "pxr/usd/usd/editContext.h"
16+
#include "pxr/usd/usdSkel/animation.h"
17+
#include "pxr/usd/usdSkel/bindingAPI.h"
18+
#include "pxr/usd/usdSkel/root.h"
19+
20+
#include <iostream>
21+
22+
PXR_NAMESPACE_USING_DIRECTIVE
23+
24+
static void
25+
TestSkelAnimUpdateCrash()
26+
{
27+
std::cout << "-------------------------------------------------------\n";
28+
std::cout << "TestSkelAnimUpdate\n";
29+
std::cout << "-------------------------------------------------------\n";
30+
31+
const std::string usdPath = "model.usda";
32+
UsdStageRefPtr stage = UsdStage::Open(usdPath);
33+
TF_AXIOM(stage);
34+
35+
// Bring up Hydra
36+
Hd_UnitTestNullRenderDelegate renderDelegate;
37+
std::unique_ptr<HdRenderIndex>
38+
renderIndex(HdRenderIndex::New(&renderDelegate, HdDriverVector()));
39+
auto delegate = std::make_unique<UsdImagingDelegate>(renderIndex.get(),
40+
SdfPath::AbsoluteRootPath());
41+
delegate->Populate(stage->GetPseudoRoot());
42+
delegate->SetTime(0);
43+
delegate->SyncAll(true);
44+
45+
{
46+
UsdEditContext editContext(stage, stage->GetSessionLayer());
47+
// Create new animation
48+
SdfPath animation_new_path("/Animation");
49+
UsdSkelAnimation animation_new = UsdSkelAnimation::Define(stage, animation_new_path);
50+
UsdPrim animation_new_prim = animation_new.GetPrim();
51+
TF_AXIOM(animation_new_prim);
52+
53+
// Update skeleton binding
54+
UsdPrim skeleton_prim = stage->GetPrimAtPath(SdfPath("/Root/Skeleton"));
55+
UsdSkelBindingAPI skeleton_bindingAPI = UsdSkelBindingAPI(skeleton_prim);
56+
skeleton_bindingAPI.GetAnimationSourceRel().SetTargets({animation_new_path});
57+
delegate->SetTime(0);
58+
delegate->SyncAll(true);
59+
60+
// Remove animation and update skelroot's visibility
61+
{
62+
SdfChangeBlock changeBlock;
63+
stage->RemovePrim(animation_new_path);
64+
skeleton_bindingAPI.GetAnimationSourceRel().ClearTargets(false);
65+
UsdPrim skel_root_prim = stage->GetPrimAtPath(SdfPath("/Root"));
66+
UsdSkelRoot skel_root = UsdSkelRoot(skel_root_prim);
67+
skel_root.GetVisibilityAttr().Set(UsdGeomTokens->inherited);
68+
}
69+
70+
// Test crash due to resync by updating visibility in skelroot.
71+
// NOTE: This is a test for a crash that happened in the
72+
// UsdSkelImagingSkeletonAdapter::_IsAffectedByTimeVaryingSkelAnim() method.
73+
delegate->SetTime(0);
74+
delegate->SyncAll(true);
75+
}
76+
}
77+
78+
int main()
79+
{
80+
TestSkelAnimUpdateCrash();
81+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#usda 1.0
2+
(
3+
defaultPrim = "Root"
4+
endTimeCode = 120
5+
metersPerUnit = 0.01
6+
startTimeCode = 0
7+
timeCodesPerSecond = 24
8+
upAxis = "Z"
9+
)
10+
11+
def SkelRoot "Root" (
12+
prepend apiSchemas = ["SkelBindingAPI"]
13+
)
14+
{
15+
matrix4d xformOp:transform = ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1) )
16+
uniform token[] xformOpOrder = ["xformOp:transform"]
17+
18+
def Mesh "box" (
19+
prepend apiSchemas = ["SkelBindingAPI"]
20+
)
21+
{
22+
int[] faceVertexCounts = [4, 4, 4, 4, 4, 4]
23+
int[] faceVertexIndices = [0, 1, 3, 2, 4, 5, 6, 7, 1, 2, 5, 6, 0, 4, 7, 3, 0, 1, 5, 4, 3, 7, 6, 2]
24+
token orientation = "rightHanded"
25+
point3f[] points = [(-0.6, -0.6, 0), (-0.6, 0.6, 0), (0.6, 0.6, 0), (0.6, -0.6, 0), (-0.6, -0.6, 0.14), (-0.6, 0.6, 0.14), (0.6, 0.6, 0.14), (0.6, -0.6, 0.14)]
26+
27+
int[] primvars:skel:jointIndices = [0, 0, 0, 0] (interpolation = "vertex")
28+
float[] primvars:skel:jointWeights = [1., 1., 1., 1.] (interpolation = "vertex")
29+
prepend rel skel:skeleton = </Root/Skeleton>
30+
bool doubleSided = 1
31+
}
32+
33+
def Skeleton "Skeleton" (
34+
prepend apiSchemas = ["SkelBindingAPI"]
35+
)
36+
{
37+
uniform token[] joints = ["Root"]
38+
uniform matrix4d[] bindTransforms = [
39+
((1., 0., 0., 0.), (0., 1., 0., 0.), (0., 0., 1., 0.), (0.0, 0.0, 0.0, 1.)), # Root
40+
]
41+
uniform matrix4d[] restTransforms = [
42+
((1., 0., 0., 0.), (0., 1., 0., 0.), (0., 0., 1., 0.), (0., 0., 0., 1.)), # Root
43+
]
44+
}
45+
}
46+

0 commit comments

Comments
 (0)