Skip to content

Commit 7a59fda

Browse files
committed
Merge branch 'RB-10.4' into main
2 parents b95e027 + 4f558f5 commit 7a59fda

File tree

9 files changed

+163
-35
lines changed

9 files changed

+163
-35
lines changed

Changes

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,18 @@ Breaking Changes
88
- Python : Removed support for Python 2.
99
- Primitive : Changed `variableIndexedView()` return type from `boost::optional` to `std::optional`.
1010

11-
10.4.x.x (relative to 10.4.7.0)
11+
10.4.x.x (relative to 10.4.7.1)
1212
========
1313

14+
10.4.7.1 (relative to 10.4.7.0)
15+
========
16+
17+
Fixes
18+
-----
19+
20+
- USDScene :
21+
- The UsdShadeMaterialBindingAPI schema is now applied to all prims with material bindings, making the written files compatible with `USD_SHADE_MATERIAL_BINDING_API_CHECK=strict` mode.
22+
- Fixed loading of USDGeomXformable's `ResetXformStack` operator.
1423

1524
10.4.7.0 (relative to 10.4.6.0)
1625
========

SConstruct

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3098,6 +3098,7 @@ if doConfigure :
30983098

30993099
usdTestEnv["ENV"]["PYTHONPATH"] += os.pathsep + usdPythonPath
31003100
usdTestEnv["ENV"][testEnv["TEST_LIBRARY_PATH_ENV_VAR"]] += os.pathsep + usdLibPath
3101+
usdTestEnv["ENV"]["USD_SHADE_MATERIAL_BINDING_API_CHECK"] = "strict"
31013102

31023103
# setup pluginInfo for custom file format registration
31033104
testSdfPlugInfo = os.path.join( os.getcwd(), "plugins", "usd", "plugInfo.json" )

contrib/IECoreUSD/src/IECoreUSD/USDScene.cpp

Lines changed: 65 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,47 @@ class ShaderNetworkCache : public LRUCache<pxr::SdfPath, IECoreScene::ConstShade
438438

439439
};
440440

441+
Imath::M44d localTransform( const pxr::UsdPrim &prim, pxr::UsdTimeCode time )
442+
{
443+
pxr::UsdGeomXformable transformable( prim );
444+
if( !transformable )
445+
{
446+
return Imath::M44d();
447+
}
448+
449+
pxr::GfMatrix4d transform;
450+
bool reset = false;
451+
transformable.GetLocalTransformation( &transform, &reset, time );
452+
Imath::M44d result = DataAlgo::fromUSD( transform );
453+
454+
if( reset )
455+
{
456+
// Apply inverse of parent's world transform.
457+
Imath::M44d parentWorldTransform;
458+
pxr::UsdPrim parentPrim = prim.GetParent();
459+
while( parentPrim )
460+
{
461+
parentWorldTransform = parentWorldTransform * localTransform( parentPrim, time );
462+
parentPrim = parentPrim.GetParent();
463+
}
464+
result = result * parentWorldTransform.inverse();
465+
}
466+
467+
if( ( prim.GetParent().IsPseudoRoot() || reset ) && pxr::UsdGeomGetStageUpAxis( prim.GetStage() ) == pxr::UsdGeomTokens->z )
468+
{
469+
// Apply Z-up to Y-up correction
470+
static Imath::M44d b(
471+
0, 0, 1, 0,
472+
1, 0, 0, 0,
473+
0, 1, 0, 0,
474+
0, 0, 0, 1
475+
);
476+
result = result * b;
477+
}
478+
479+
return result;
480+
}
481+
441482
} // namespace
442483

443484
class USDScene::Location : public RefCounted
@@ -667,7 +708,9 @@ USDScene::~USDScene()
667708
}
668709

669710
// Bind the material to this location
670-
pxr::UsdShadeMaterialBindingAPI( m_location->prim ).Bind( mat, pxr::UsdShadeTokens->fallbackStrength, purpose );
711+
pxr::UsdShadeMaterialBindingAPI::Apply( m_location->prim ).Bind(
712+
mat, pxr::UsdShadeTokens->fallbackStrength, purpose
713+
);
671714
}
672715
}
673716
catch( std::exception &e )
@@ -720,33 +763,7 @@ ConstDataPtr USDScene::readTransform( double time ) const
720763

721764
Imath::M44d USDScene::readTransformAsMatrix( double time ) const
722765
{
723-
pxr::UsdGeomXformable transformable( m_location->prim );
724-
if( !transformable )
725-
{
726-
return Imath::M44d();
727-
}
728-
729-
bool zUp = m_location->prim.GetParent().IsPseudoRoot() && pxr::UsdGeomGetStageUpAxis( m_root->getStage() ) == pxr::UsdGeomTokens->z;
730-
731-
pxr::GfMatrix4d transform;
732-
bool reset = false;
733-
734-
transformable.GetLocalTransformation( &transform, &reset, m_root->getTime( time ) );
735-
Imath::M44d returnValue = DataAlgo::fromUSD( transform );
736-
737-
if ( zUp )
738-
{
739-
static Imath::M44d b
740-
(
741-
0, 0, 1, 0,
742-
1, 0, 0, 0,
743-
0, 1, 0, 0,
744-
0, 0, 0, 1
745-
);
746-
747-
returnValue = returnValue * b;
748-
}
749-
return returnValue;
766+
return localTransform( m_location->prim, m_root->getTime( time ) );
750767
}
751768

752769
ConstObjectPtr USDScene::readObject( double time, const Canceller *canceller ) const
@@ -1396,7 +1413,26 @@ void USDScene::transformHash( double time, IECore::MurmurHash &h ) const
13961413
{
13971414
h.append( m_root->fileName() );
13981415
appendPrimOrMasterPath( m_location->prim, h );
1399-
if( xformable.TransformMightBeTimeVarying() )
1416+
1417+
bool mightBeTimeVarying = xformable.TransformMightBeTimeVarying();
1418+
if( !mightBeTimeVarying && xformable.GetResetXformStack() )
1419+
{
1420+
// Because we have to apply the inverse of our parent's transform, if
1421+
// that is time varying then so are we.
1422+
pxr::UsdPrim parentPrim = m_location->prim.GetParent();
1423+
while( parentPrim )
1424+
{
1425+
pxr::UsdGeomXformable parentXFormable( parentPrim );
1426+
if( parentXFormable && parentXFormable.TransformMightBeTimeVarying() )
1427+
{
1428+
mightBeTimeVarying = true;
1429+
break;
1430+
}
1431+
parentPrim = parentPrim.GetParent();
1432+
}
1433+
}
1434+
1435+
if( mightBeTimeVarying )
14001436
{
14011437
h.append( time );
14021438
}

contrib/IECoreUSD/test/IECoreUSD/USDSceneTest.py

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3406,5 +3406,77 @@ def testRoundTripIndexedNormals( self ) :
34063406
root = IECoreScene.SceneInterface.create( fileName, IECore.IndexedIO.OpenMode.Read )
34073407
self.assertEqual( root.child( "mesh").readObject( 0.0 ), mesh )
34083408

3409+
def testResetXFormStack( self ) :
3410+
3411+
fileName = os.path.join( self.temporaryDirectory(), "resetXFormStack.usda" )
3412+
stage = pxr.Usd.Stage.CreateNew( fileName )
3413+
3414+
g1 = pxr.UsdGeom.Xform.Define( stage, "/g1" )
3415+
g1.AddScaleOp().Set( pxr.Gf.Vec3f( 1, 2, 3 ) )
3416+
3417+
g2 = pxr.UsdGeom.Xform.Define( stage, "/g1/g2" )
3418+
g2.AddTranslateOp().Set( pxr.Gf.Vec3f( 4, 5, 6 ) )
3419+
3420+
g3 = pxr.UsdGeom.Xform.Define( stage, "/g1/g2/g3" )
3421+
g3.AddTranslateOp().Set( pxr.Gf.Vec3f( 1, 0, 1 ) )
3422+
g3.SetResetXformStack( True )
3423+
3424+
pxr.UsdGeom.Sphere.Define( stage, "/g1/g2/g3/s" )
3425+
3426+
stage.GetRootLayer().Save()
3427+
del stage
3428+
3429+
worldTransform = imath.M44d()
3430+
location = IECoreScene.SceneInterface.create( fileName, IECore.IndexedIO.OpenMode.Read )
3431+
for name in [ "g1", "g2", "g3", "s" ] :
3432+
location = location.child( name )
3433+
worldTransform = location.readTransformAsMatrix( 0 ) * worldTransform
3434+
self.assertEqual(
3435+
location.hash( location.HashType.TransformHash, 1 ), # There is no animation,
3436+
location.hash( location.HashType.TransformHash, 2 ), # so hashes should be identical
3437+
)
3438+
3439+
self.assertEqual( worldTransform, imath.M44d().translate( imath.V3f( 1, 0, 1 ) ) )
3440+
3441+
def testResetXFormStackHash( self ) :
3442+
3443+
fileName = os.path.join( self.temporaryDirectory(), "resetXFormStackHash.usda" )
3444+
stage = pxr.Usd.Stage.CreateNew( fileName )
3445+
3446+
# /g1 (animated transform)
3447+
# /g2a (reset transform stack)
3448+
# /g2b
3449+
3450+
g1 = pxr.UsdGeom.Xform.Define( stage, "/g1" )
3451+
scaleOp = g1.AddScaleOp()
3452+
scaleOp.Set( pxr.Gf.Vec3f( 2 ), 1 )
3453+
scaleOp.Set( pxr.Gf.Vec3f( 4 ), 2 )
3454+
3455+
g2a = pxr.UsdGeom.Xform.Define( stage, "/g1/g2a" )
3456+
g2a.SetResetXformStack( True )
3457+
pxr.UsdGeom.Xform.Define( stage, "/g1/g2b" )
3458+
3459+
stage.GetRootLayer().Save()
3460+
del stage
3461+
3462+
root = IECoreScene.SceneInterface.create( fileName, IECore.IndexedIO.OpenMode.Read )
3463+
g2a = root.scene( [ "g1", "g2a" ] )
3464+
g2b = root.scene( [ "g1", "g2b" ] )
3465+
3466+
# Hash should be animated because the reset needs to account
3467+
# for animation on parent.
3468+
3469+
self.assertNotEqual(
3470+
g2a.hash( g2a.HashType.TransformHash, 1 ),
3471+
g2a.hash( g2a.HashType.TransformHash, 2 ),
3472+
)
3473+
3474+
# Hash should be static, because there is no reset.
3475+
3476+
self.assertEqual(
3477+
g2b.hash( g2a.HashType.TransformHash, 1 ),
3478+
g2b.hash( g2a.HashType.TransformHash, 2 ),
3479+
)
3480+
34093481
if __name__ == "__main__":
34103482
unittest.main()

contrib/IECoreUSD/test/IECoreUSD/data/arnoldArrayInputs.usda

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#usda 1.0
22

3-
def Sphere "sphere"
3+
def Sphere "sphere" (
4+
prepend apiSchemas = ["MaterialBindingAPI"]
5+
)
46
{
57
rel material:binding = </rampSurface>
68
}

contrib/IECoreUSD/test/IECoreUSD/data/exposedShaderInput.usda

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
def "model"
44
{
55

6-
def Sphere "sphere"
6+
def Sphere "sphere" (
7+
prepend apiSchemas = ["MaterialBindingAPI"]
8+
)
79
{
810
rel material:binding = </model/materials/material1>
911
}

contrib/IECoreUSD/test/IECoreUSD/data/materialPurpose.usda

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
def "model"
44
{
55

6-
def Sphere "sphere"
6+
def Sphere "sphere" (
7+
prepend apiSchemas = ["MaterialBindingAPI"]
8+
)
79
{
810
rel material:binding = </model/materials/material>
911
rel material:binding:full = </model/materials/fullMaterial>

contrib/IECoreUSD/test/IECoreUSD/data/shaderParentLoc.usda

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#usda 1.0
22

3-
def Xform "shaderLocation"
3+
def Xform "shaderLocation" (
4+
prepend apiSchemas = ["MaterialBindingAPI"]
5+
)
46
{
57
rel material:binding = </shaderLocation/materials/testMat>
68

contrib/IECoreUSD/test/IECoreUSD/data/textureParameters.usda

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
def "model"
44
{
55

6-
def Sphere "sphere"
6+
def Sphere "sphere" (
7+
prepend apiSchemas = ["MaterialBindingAPI"]
8+
)
79
{
810
rel material:binding = </model/materials/textureParameterTest>
911
}

0 commit comments

Comments
 (0)