Skip to content

Commit

Permalink
fixup! ArnoldRenderTest : Add tests for Instancer
Browse files Browse the repository at this point in the history
  • Loading branch information
danieldresser-ie committed Oct 21, 2023
1 parent 2dd3927 commit cb44d52
Showing 1 changed file with 2 additions and 132 deletions.
134 changes: 2 additions & 132 deletions python/GafferArnoldTest/ArnoldRenderTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -1478,136 +1478,6 @@ def testCoordinateSystem( self ) :
# node to have been created for ours.
self.assertIsNone( arnold.AiNodeLookUpByName( universe, "/coordinateSystem" ) )

# For some reason, Arnold writes out nested procedurals with names with "^" in them, which
# AiSceneLoad then fails to read back in. It's easier to tell things are working if we can
# tell what the names are.
def makeAssNamesReadable( self, filename ):
processed = []
for l in open( filename, "r" ).readlines():
if l.startswith( " name" ):
processed.append( l.replace( "^", "&" ) )
else:
processed.append( l )

open( filename, "w" ).writelines( processed )

def listRelevantObjects( self, universe ):
result = {}
it = arnold.AiUniverseGetNodeIterator( universe, 255 )
while not arnold.AiNodeIteratorFinished( it ):
n = arnold.AiNodeIteratorGetNext( it )
typ = arnold.AiNodeEntryGetName( arnold.AiNodeGetNodeEntry( n ) )
if not typ in [ "ortho_camera", "options", "box_filter", "utility", "list_aggregate" ]:
result[ arnold.AiNodeGetName( n ) ] = (
typ,
self.__m44f( arnold.AiNodeGetMatrix( n, "matrix" ) ).translation(),
arnold.AiNodeGetByte( n, "visibility" )
)
return result

def testInstancer( self ) :

s = Gaffer.ScriptNode()

s["plane"] = GafferScene.Plane()

s["sphere"] = GafferScene.Sphere()
s["sphere"]["expression"] = Gaffer.Expression()
s["sphere"]["expression"].setExpression( 'parent["type"] = context.get("P", imath.V3f(0))[0] > 0' )

s["pathFilter"] = GafferScene.PathFilter()
s["pathFilter"]["paths"].setValue( IECore.StringVectorData( [ '/plane' ] ) )

s["instancer"] = GafferScene.Instancer()
s["instancer"]["in"].setInput( s["plane"]["out"] )
s["instancer"]["filter"].setInput( s["pathFilter"]["out"] )
s["instancer"]["prototypes"].setInput( s["sphere"]["out"] )
s["instancer"]["contextVariables"].addChild( GafferScene.Instancer.ContextVariablePlug() )
s["instancer"]["contextVariables"][0]["name"].setValue( "P" )

s["options"] = GafferScene.CustomOptions()
s["options"]["in"].setInput( s["instancer"]["out"] )

s["render"] = GafferArnold.ArnoldRender()
s["render"]["in"].setInput( s["options"]["out"] )
s["render"]["mode"].setValue( s["render"].Mode.SceneDescriptionMode )
s["render"]["fileName"].setValue( self.temporaryDirectory() / "test.ass" )

s["render"]["task"].execute()

with IECoreArnold.UniverseBlock( writable = True ) as universe :

arnold.AiSceneLoad( universe, str( self.temporaryDirectory() / "test.ass" ), None )

rendered = self.listRelevantObjects( universe )

self.assertEqual( len( rendered ), 6 )
self.assertEqual( rendered["/plane/instances/sphere/0"], ( ('ginstance', imath.V3f(-0.5, -0.5, 0), 255) ) )
self.assertEqual( rendered["/plane/instances/sphere/1"], ( ('ginstance', imath.V3f(0.5, -0.5, 0), 255) ) )
self.assertEqual( rendered["/plane/instances/sphere/2"], ( ('ginstance', imath.V3f(-0.5, 0.5, 0), 255) ) )
self.assertEqual( rendered["/plane/instances/sphere/3"], ( ('ginstance', imath.V3f(0.5, 0.5, 0), 255) ) )
for i in rendered.items():
if not i[0].startswith( "/plane/instances/sphere/" ):
self.assertTrue( i[0].startswith( "instance:" ) )
self.assertTrue( i[1][0] in [ "sphere", "polymesh" ] )
self.assertEqual( i[1][1], imath.V3f(0) )
self.assertEqual( i[1][2], 0 )

s["instancer"]["encapsulateInstanceGroups"].setValue( True )
s["render"]["task"].execute()

self.makeAssNamesReadable( self.temporaryDirectory() / "test.ass" )

with IECoreArnold.UniverseBlock( writable = True ) as universe :
arnold.AiSceneLoad( universe, str( self.temporaryDirectory() / "test.ass" ), None )
rendered = self.listRelevantObjects( universe )

self.assertEqual( len( rendered ), 2 )
self.assertEqual( rendered["/plane/instances/sphere"], ( ('ginstance', imath.V3f(0), 255) ) )
for i in rendered.items():
if not i[0].startswith( "/plane/instances/sphere" ):
self.assertTrue( i[0].startswith( "instance:" ) )
self.assertEqual( i[1], ( ('procedural', imath.V3f(0), 0) ) )

s["options"]["options"].addChild( Gaffer.NameValuePlug( "ai:open_procs", Gaffer.BoolPlug( "value", defaultValue = True ), True, "member1" ) )
s["render"]["task"].execute()

self.makeAssNamesReadable( self.temporaryDirectory() / "test.ass" )

with IECoreArnold.UniverseBlock( writable = True ) as universe :
arnold.AiSceneLoad( universe, str( self.temporaryDirectory() / "test.ass" ), None )
rendered = self.listRelevantObjects( universe )

# Exporting an ass file with open_procs set on in Arnold has a weird effect on procedurals
# that are instanced - it expands both the original, and the instance. This doesn't really reflect
# how the actual render works, so we'll just discard half of the results we got
for i in list( rendered.keys() ):
if i.startswith( "&instance:" ):
del rendered[i]

# Because the sub-capsules are expanded separately, we aren't able to share instances of meshes
# that come from different prototype context - so we end up with 4 prototypes and 4 instances,
# where we only need to 2 prototypes. An alternative way to make more sharing happen would be
# if we were able to identify when two prototypes with different contexts end up identical
# ... this would require doing a full comparison of everything within the Capsule hierarchy.
# Hopefully this doesn't happen too often in well optimized scenes, but it easy to end up with
# a situation like this where I've added P to the context, but not done something unique for every
# possible value.
self.assertEqual( len( rendered ), 8 )

# As above, prototypes are visible due to issues with open_procs;
self.assertEqual( rendered["&/plane/instances/sphere&prototype0&/"], ( ('sphere', imath.V3f(0), 255) ) )
self.assertEqual( rendered["&/plane/instances/sphere&prototype1&/"], ( ('polymesh', imath.V3f(0), 255) ) )
self.assertEqual( rendered["&/plane/instances/sphere&prototype2&/"], ( ('sphere', imath.V3f(0), 255) ) )
self.assertEqual( rendered["&/plane/instances/sphere&prototype3&/"], ( ('polymesh', imath.V3f(0), 255) ) )

# Seeing these names with "instancerCapsule" in them confirms that we are seeing results from the
# special Arnold code path
self.assertEqual( rendered["&/plane/instances/sphere&instancerCapsule&instancerCapsule_instance_1&/"], ( ('sphere', imath.V3f(-0.5, -0.5, 0), 255) ) )
self.assertEqual( rendered["&/plane/instances/sphere&instancerCapsule&instancerCapsule_instance_2&/"], ( ('polymesh', imath.V3f(0.5, -0.5, 0), 255) ) )
self.assertEqual( rendered["&/plane/instances/sphere&instancerCapsule&instancerCapsule_instance_3&/"], ( ('sphere', imath.V3f(-0.5, 0.5, 0), 255) ) )
self.assertEqual( rendered["&/plane/instances/sphere&instancerCapsule&instancerCapsule_instance_4&/"], ( ('polymesh', imath.V3f(0.5, 0.5, 0), 255) ) )

@GafferTest.TestRunner.PerformanceTestMethod( repeat = 1 )
def testInstancerPerf( self ) :

Expand All @@ -1634,7 +1504,7 @@ def testInstancerPerf( self ) :
s["render"]["in"].setInput( s["options"]["out"] )
s["render"]["mode"].setValue( s["render"].Mode.SceneDescriptionMode )
s["render"]["fileName"].setValue( self.temporaryDirectory() / "test.ass" )

with Gaffer.Context() as c :
c["scene:render:sceneTranslationOnly"] = IECore.BoolData( True )
with GafferTest.TestRunner.PerformanceScope() :
Expand Down Expand Up @@ -1668,7 +1538,7 @@ def testInstancerEncapsulatePerf( self ) :
s["render"]["in"].setInput( s["options"]["out"] )
s["render"]["mode"].setValue( s["render"].Mode.SceneDescriptionMode )
s["render"]["fileName"].setValue( self.temporaryDirectory() / "test.ass" )

with Gaffer.Context() as c :
c["scene:render:sceneTranslationOnly"] = IECore.BoolData( True )
with GafferTest.TestRunner.PerformanceScope() :
Expand Down

0 comments on commit cb44d52

Please sign in to comment.