Skip to content

Commit 4aa69e8

Browse files
IECoreUSD : Load prototype paths inside a PointInstancer as relative
By default, if an instancer named "/inst" contains an internal prototype path like "/inst/Prototypes/proto", that prototype path will now be loaded as "./Prototypes/proto". You can set the env var GAFFERUSD_POINTINSTANCER_RELATIVEPROTOTYPES=0 to get the old behaviour, where prototype paths were always absolute. Or can set the env var GAFFERSCENE_INSTANCER_EXPLICITABSOLUTEPATHS=1 to get the newest behaviour, where prototype paths are assumed to be relative unless they start with a slash, so the prototype path would be loaded as "Prototypes/proto".
1 parent d4569e5 commit 4aa69e8

File tree

3 files changed

+98
-1
lines changed

3 files changed

+98
-1
lines changed

contrib/IECoreUSD/src/IECoreUSD/PointInstancerAlgo.cpp

+41-1
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,20 @@ using namespace IECoreUSD;
5353
namespace
5454
{
5555

56+
bool checkEnvFlag( const char *envVar, bool def )
57+
{
58+
const char *value = getenv( envVar );
59+
if( value )
60+
{
61+
return std::string( value ) != "0";
62+
}
63+
else
64+
{
65+
return def;
66+
}
67+
68+
}
69+
5670
IECore::ObjectPtr readPointInstancer( pxr::UsdGeomPointInstancer &pointInstancer, pxr::UsdTimeCode time, const Canceller *canceller )
5771
{
5872
pxr::VtVec3fArray pointsData;
@@ -108,16 +122,42 @@ IECore::ObjectPtr readPointInstancer( pxr::UsdGeomPointInstancer &pointInstancer
108122

109123
// Prototype paths
110124

125+
const static bool gafferUSDPointInstancersRelativeProtoypes = checkEnvFlag( "GAFFERUSD_POINTINSTANCER_RELATIVEPROTOTYPES", true );
126+
const static bool gafferSceneInstancerExplicitAbsolutePaths = checkEnvFlag( "GAFFERSCENE_INSTANCER_EXPLICITABSOLUTEPATHS", false );
127+
111128
pxr::SdfPathVector targets;
112129
Canceller::check( canceller );
113130
pointInstancer.GetPrototypesRel().GetForwardedTargets( &targets );
114131

132+
const pxr::SdfPath &primPath = pointInstancer.GetPath();
133+
115134
IECore::StringVectorDataPtr prototypeRootsData = new IECore::StringVectorData();
116135
auto &prototypeRoots = prototypeRootsData->writable();
117136
prototypeRoots.reserve( targets.size() );
118137
for( const auto &t : targets )
119138
{
120-
prototypeRoots.push_back( t.GetString() );
139+
if( !gafferUSDPointInstancersRelativeProtoypes )
140+
{
141+
prototypeRoots.push_back( t.GetString() );
142+
}
143+
else
144+
{
145+
if( t.HasPrefix( primPath ) )
146+
{
147+
if( gafferSceneInstancerExplicitAbsolutePaths )
148+
{
149+
prototypeRoots.push_back( t.MakeRelativePath( primPath ).GetString() );
150+
}
151+
else
152+
{
153+
prototypeRoots.push_back( "./" + t.MakeRelativePath( primPath ).GetString() );
154+
}
155+
}
156+
else
157+
{
158+
prototypeRoots.push_back( t.GetString() );
159+
}
160+
}
121161
}
122162

123163
newPoints->variables["prototypeRoots"] = IECoreScene::PrimitiveVariable( IECoreScene::PrimitiveVariable::Constant, prototypeRootsData );

contrib/IECoreUSD/test/IECoreUSD/USDSceneTest.py

+31
Original file line numberDiff line numberDiff line change
@@ -4451,6 +4451,37 @@ def testAssetPathSlashes ( self ) :
44514451
self.assertNotIn( "\\", xform.readAttribute( "render:testAsset", 0 ).value )
44524452
self.assertTrue( pathlib.Path( xform.readAttribute( "render:testAsset", 0 ).value ).is_file() )
44534453

4454+
4455+
@unittest.skipIf( os.environ.get("GAFFERSCENE_INSTANCER_EXPLICITABSOLUTEPATHS") == "1" or os.environ.get("GAFFERUSD_POINTINSTANCER_RELATIVEPROTOTYPES") == "0", "GAFFERSCENE_INSTANCER_EXPLICITABSOLUTEPATHS or GAFFERUSD_POINTINSTANCER_RELATIVEPROTOTYPES is set, running alternate test" )
4456+
def testPointInstancerRelative( self ) :
4457+
root = IECoreScene.SceneInterface.create(
4458+
os.path.join( os.path.dirname( __file__ ), "data", "pointInstancerWeirdPrototypes.usda" ),
4459+
IECore.IndexedIO.OpenMode.Read
4460+
)
4461+
pointInstancer = root.child( "inst" )
4462+
obj = pointInstancer.readObject(0.0)
4463+
self.assertEqual( obj["prototypeRoots"].data, IECore.StringVectorData( [ './Prototypes/sphere', '/cube' ] ) )
4464+
4465+
@unittest.skipIf( not os.environ.get("GAFFERSCENE_INSTANCER_EXPLICITABSOLUTEPATHS") == "1" or os.environ.get("GAFFERUSD_POINTINSTANCER_RELATIVEPROTOTYPES") == "0", "Set GAFFERSCENE_INSTANCER_EXPLICITABSOLUTEPATHS and don't disable GAFFERUSD_POINTINSTANCER_RELATIVEPROTOTYPES to test this" )
4466+
def testPointInstancerRelativeNewStyle( self ) :
4467+
root = IECoreScene.SceneInterface.create(
4468+
os.path.join( os.path.dirname( __file__ ), "data", "pointInstancerWeirdPrototypes.usda" ),
4469+
IECore.IndexedIO.OpenMode.Read
4470+
)
4471+
pointInstancer = root.child( "inst" )
4472+
obj = pointInstancer.readObject(0.0)
4473+
self.assertEqual( obj["prototypeRoots"].data, IECore.StringVectorData( [ 'Prototypes/sphere', '/cube' ] ) )
4474+
4475+
@unittest.skipIf( not os.environ.get("GAFFERUSD_POINTINSTANCER_RELATIVEPROTOTYPES") == "0", "Set GAFFERUSD_POINTINSTANCER_RELATIVEPROTOTYPES=0 to test" )
4476+
def testPointInstancerAbsolute( self ) :
4477+
root = IECoreScene.SceneInterface.create(
4478+
os.path.join( os.path.dirname( __file__ ), "data", "pointInstancerWeirdPrototypes.usda" ),
4479+
IECore.IndexedIO.OpenMode.Read
4480+
)
4481+
pointInstancer = root.child( "inst" )
4482+
obj = pointInstancer.readObject(0.0)
4483+
self.assertEqual( obj["prototypeRoots"].data, IECore.StringVectorData( [ '/inst/Prototypes/sphere', '/cube' ] ) )
4484+
44544485
@unittest.skipIf( not haveVDB, "No IECoreVDB" )
44554486
def testUsdVolVolumeSlashes( self ) :
44564487

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#usda 1.0
2+
(
3+
)
4+
5+
def PointInstancer "inst" (
6+
kind = "group"
7+
)
8+
{
9+
point3f[] positions = [(0, 0, -20), (0, 0, -16), (0, 0, -12), (0, 0, -8), (0, 0, -4), (0, 0, 0), (0, 0, 4), (0, 0, 8), (0, 0, 12), (0, 0, 16)]
10+
int[] protoIndices = [0, 1, 0, 1, 0, 1, 0, 1, 0, 1]
11+
rel prototypes = [ </inst/Prototypes/sphere>, </cube> ]
12+
13+
def Scope "Prototypes" (
14+
kind = "group"
15+
)
16+
{
17+
def Sphere "sphere"
18+
{
19+
double radius = 1
20+
}
21+
}
22+
}
23+
24+
def Cube "cube"
25+
{
26+
}

0 commit comments

Comments
 (0)