Skip to content

Commit efe40e2

Browse files
committed
Add nested gprim check to validation framework and additional test cases. This addresses the issue where usdchecker does not emit errors on nested gprims.
Also enabled badGprims usdchecker test now that the validation framework supports this check and also updated baselines. Fixes #3835 (Internal change: 2381216)
1 parent 8d367a2 commit efe40e2

File tree

7 files changed

+132
-3
lines changed

7 files changed

+132
-3
lines changed

pxr/usdValidation/bin/usdchecker/testenv/testUsdChecker/baseline/arkitRules_validationFramework.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@
33
Keywords: RmanUsdValidators
44
SchemaTypes: UsdRiPxrRenderTerminalsAPI
55
isSuite: False
6+
[usdGeomValidators:EncapsulationChecker]:
7+
Doc: Validates there are no nested Gprims.
8+
Keywords: UsdGeomValidators
9+
SchemaTypes: UsdGeomBoundable
10+
isSuite: False
611
[usdGeomValidators:StageMetadataChecker]:
712
Doc: All stages must declare their 'upAxis' and 'metersPerUnit'.
813
Keywords: UsdGeomValidators

pxr/usdValidation/bin/usdchecker/testenv/testUsdChecker/baseline/arkitRules_validationFramework_withRootPackageValidator.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@
33
Keywords: RmanUsdValidators
44
SchemaTypes: UsdRiPxrRenderTerminalsAPI
55
isSuite: False
6+
[usdGeomValidators:EncapsulationChecker]:
7+
Doc: Validates there are no nested Gprims.
8+
Keywords: UsdGeomValidators
9+
SchemaTypes: UsdGeomBoundable
10+
isSuite: False
611
[usdGeomValidators:StageMetadataChecker]:
712
Doc: All stages must declare their 'upAxis' and 'metersPerUnit'.
813
Keywords: UsdGeomValidators

pxr/usdValidation/bin/usdchecker/testenv/testUsdChecker/baseline/baseRules_validationFramework.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@
33
Keywords: RmanUsdValidators
44
SchemaTypes: UsdRiPxrRenderTerminalsAPI
55
isSuite: False
6+
[usdGeomValidators:EncapsulationChecker]:
7+
Doc: Validates there are no nested Gprims.
8+
Keywords: UsdGeomValidators
9+
SchemaTypes: UsdGeomBoundable
10+
isSuite: False
611
[usdGeomValidators:StageMetadataChecker]:
712
Doc: All stages must declare their 'upAxis' and 'metersPerUnit'.
813
Keywords: UsdGeomValidators

pxr/usdValidation/usdGeomValidators/plugInfo.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@
33
{
44
"Info": {
55
"Validators": {
6+
"EncapsulationChecker": {
7+
"doc": "Validates there are no nested Gprims.",
8+
"schemaTypes": [
9+
"UsdGeomBoundable"
10+
]
11+
},
612
"StageMetadataChecker": {
713
"doc": "All stages must declare their 'upAxis' and 'metersPerUnit'."
814
},

pxr/usdValidation/usdGeomValidators/testenv/testUsdGeomValidators.cpp

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ TestUsdGeomValidators()
2929
UsdGeomValidatorNameTokens->subsetFamilies,
3030
UsdGeomValidatorNameTokens->subsetParentIsImageable,
3131
UsdGeomValidatorNameTokens->stageMetadataChecker,
32+
UsdGeomValidatorNameTokens->encapsulationChecker,
3233
};
3334

3435
const UsdValidationRegistry &registry
@@ -42,7 +43,7 @@ TestUsdGeomValidators()
4243
UsdValidationValidatorMetadataVector metadata
4344
= registry.GetValidatorMetadataForPlugin(
4445
_tokens->usdGeomValidatorsPlugin);
45-
TF_AXIOM(metadata.size() == 3);
46+
TF_AXIOM(metadata.size() == 4);
4647
for (const UsdValidationValidatorMetadata &m: metadata) {
4748
validatorMetadataNameSet.insert(m.name);
4849
}
@@ -166,6 +167,21 @@ def Xform "SubsetsTest" (
166167
}
167168
)usda";
168169

170+
static const std::string nestedLayerContents =
171+
R"usda(#usda 1.0
172+
(
173+
defaultPrim = "NestedGprimTest"
174+
upAxis = "Z"
175+
)
176+
def Mesh "NestedGprimTest"
177+
{
178+
def Sphere "NestedPrim"
179+
{
180+
181+
}
182+
}
183+
)usda";
184+
169185
void
170186
TestUsdGeomSubsetFamilies()
171187
{
@@ -364,10 +380,52 @@ TestUsdStageMetadata()
364380
TF_AXIOM(errors.empty());
365381
}
366382

383+
void
384+
TestUsdGeomEncapsulationChecker()
385+
{
386+
UsdValidationRegistry &registry = UsdValidationRegistry::GetInstance();
387+
const UsdValidationValidator *validator = registry.GetOrLoadValidatorByName(
388+
UsdGeomValidatorNameTokens->encapsulationChecker);
389+
TF_AXIOM(validator);
390+
391+
SdfLayerRefPtr layer = SdfLayer::CreateAnonymous(".usda");
392+
layer->ImportFromString(nestedLayerContents);
393+
UsdStageRefPtr usdStage = UsdStage::Open(layer);
394+
TF_AXIOM(usdStage);
395+
396+
const TfToken expectedErrorIdentifier = TfToken(
397+
"usdGeomValidators:EncapsulationChecker.InvalidNestedGprims");
398+
399+
{
400+
const UsdPrim usdPrim = usdStage->GetPrimAtPath(
401+
SdfPath("/NestedGprimTest/NestedPrim"));
402+
403+
const UsdValidationErrorVector errors = validator->Validate(usdPrim);
404+
405+
TF_AXIOM(errors.size() == 1u);
406+
const UsdValidationError &error = errors[0u];
407+
TF_AXIOM(error.GetIdentifier() == expectedErrorIdentifier);
408+
TF_AXIOM(error.GetType() == UsdValidationErrorType::Error);
409+
TF_AXIOM(error.GetSites().size() == 1u);
410+
const UsdValidationErrorSite &errorSite = error.GetSites()[0u];
411+
TF_AXIOM(errorSite.IsValid());
412+
TF_AXIOM(errorSite.IsPrim());
413+
TF_AXIOM(errorSite.GetPrim().GetPath() == usdPrim.GetPath());
414+
const std::string expectedErrorMsg
415+
= "Gprim "
416+
"</NestedGprimTest/NestedPrim> has an ancestor prim that is also "
417+
"a Gprim, which is not allowed.";
418+
419+
TF_AXIOM(error.GetMessage() == expectedErrorMsg);
420+
}
421+
}
422+
423+
367424
int
368425
main()
369426
{
370427
TestUsdGeomValidators();
428+
TestUsdGeomEncapsulationChecker();
371429
TestUsdGeomSubsetFamilies();
372430
TestUsdGeomSubsetParentIsImageable();
373431
TestUsdStageMetadata();

pxr/usdValidation/usdGeomValidators/validatorTokens.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ PXR_NAMESPACE_OPEN_SCOPE
1919
#define USD_GEOM_VALIDATOR_NAME_TOKENS \
2020
((stageMetadataChecker, "usdGeomValidators:StageMetadataChecker")) \
2121
((subsetFamilies, "usdGeomValidators:SubsetFamilies")) \
22-
((subsetParentIsImageable, "usdGeomValidators:SubsetParentIsImageable"))
22+
((subsetParentIsImageable, "usdGeomValidators:SubsetParentIsImageable")) \
23+
((encapsulationChecker, "usdGeomValidators:EncapsulationChecker"))
2324

2425
#define USD_GEOM_VALIDATOR_KEYWORD_TOKENS \
2526
(UsdGeomSubset) \
@@ -29,7 +30,8 @@ PXR_NAMESPACE_OPEN_SCOPE
2930
((missingMetersPerUnitMetadata, "MissingMetersPerUnitMetadata")) \
3031
((missingUpAxisMetadata, "MissingUpAxisMetadata")) \
3132
((invalidSubsetFamily, "InvalidSubsetFamily")) \
32-
((notImageableSubsetParent, "NotImageableSubsetParent"))
33+
((notImageableSubsetParent, "NotImageableSubsetParent")) \
34+
((invalidNestedGprims, "InvalidNestedGprims"))
3335

3436
/// \def USD_GEOM_VALIDATOR_NAME_TOKENS
3537
/// Tokens representing validator names. Note that for plugin provided

pxr/usdValidation/usdGeomValidators/validators.cpp

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,50 @@ _SubsetParentIsImageable(const UsdPrim &usdPrim,
146146
usdPrim.GetPath().GetText(), parentPrim.GetPath().GetText())) };
147147
}
148148

149+
static UsdValidationErrorVector
150+
_HasValidEncapsulation(const UsdPrim &usdPrim,
151+
const UsdValidationTimeRange &/*timeRange*/)
152+
{
153+
UsdValidationErrorVector errors;
154+
const UsdValidationErrorSites primErrorSites
155+
= { UsdValidationErrorSite(usdPrim.GetStage(), usdPrim.GetPath()) };
156+
157+
const UsdPrim parentPrim = usdPrim.GetParent();
158+
159+
if (usdPrim.IsA<UsdGeomBoundable>()){
160+
if (parentPrim) {
161+
// Of course we must allow Boundables under other Boundables, so that
162+
// schemas like UsdGeom.Pointinstancer can nest their prototypes.
163+
// But we disallow a PointInstancer under a Mesh just as we disallow
164+
// a Mesh under a Mesh, for the same reason: we cannot then
165+
// independently adjust visibility for the two objects, nor can we
166+
// reasonably compute the parent Mesh's extent.
167+
std::function<void(const UsdPrim &)> _VerifyGprimAncestor =
168+
[&](const UsdPrim &currentAncestor) {
169+
if (!currentAncestor || currentAncestor.IsPseudoRoot()) {
170+
return;
171+
}
172+
173+
if (currentAncestor.IsA<UsdGeomGprim>()) {
174+
errors.emplace_back(
175+
UsdGeomValidationErrorNameTokens
176+
->invalidNestedGprims,
177+
UsdValidationErrorType::Error,
178+
primErrorSites,
179+
TfStringPrintf(
180+
"Gprim <%s> has an ancestor prim that is also a "
181+
"Gprim, which is not allowed.",
182+
usdPrim.GetPath().GetText()));
183+
return;
184+
}
185+
_VerifyGprimAncestor(currentAncestor.GetParent());
186+
};
187+
_VerifyGprimAncestor(parentPrim);
188+
}
189+
}
190+
return errors;
191+
}
192+
149193
TF_REGISTRY_FUNCTION(UsdValidationRegistry)
150194
{
151195
UsdValidationRegistry &registry = UsdValidationRegistry::GetInstance();
@@ -160,6 +204,10 @@ TF_REGISTRY_FUNCTION(UsdValidationRegistry)
160204
registry.RegisterPluginValidator(
161205
UsdGeomValidatorNameTokens->subsetParentIsImageable,
162206
_SubsetParentIsImageable);
207+
208+
registry.RegisterPluginValidator(
209+
UsdGeomValidatorNameTokens->encapsulationChecker,
210+
_HasValidEncapsulation);
163211
}
164212

165213
PXR_NAMESPACE_CLOSE_SCOPE

0 commit comments

Comments
 (0)