def testIterationsContext(self): script = Gaffer.ScriptNode() script["c"] = GafferImage.Constant() script["loop"] = Gaffer.Loop() script["loop"].setup(GafferImage.ImagePlug()) script["loop"]["in"].setInput(script["c"]["out"]) script["grade"] = GafferImage.Grade() script["grade"]["offset"].setValue(imath.Color3f(.1)) script["grade"]["in"].setInput(script["loop"]["previous"]) script["loop"]["next"].setInput(script["grade"]["out"]) script["sampler"] = GafferImage.ImageSampler() script["sampler"]["pixel"].setValue(imath.V2f(10)) script["sampler"]["image"].setInput(script["loop"]["out"]) script["expression"] = Gaffer.Expression() script["expression"].setExpression( inspect.cleandoc(""" assert( context.get( "image:channelName", None ) is None ) assert( context.get( "image:tileOrigin", None ) is None ) parent["loop"]["iterations"] = 4 """)) with script.context(): self.assertAlmostEqual(script["sampler"]["color"]["r"].getValue(), .4)
def testEnabled(self): script = Gaffer.ScriptNode() script["sphere"] = GafferScene.Sphere() script["loop"] = Gaffer.Loop() script["loop"].setup(GafferScene.ScenePlug()) script["loop"]["in"].setInput(script["sphere"]["out"]) script["filter"] = GafferScene.PathFilter() script["filter"]["paths"].setValue(IECore.StringVectorData(["/sphere" ])) script["transform"] = GafferScene.Transform() script["transform"]["transform"]["translate"]["x"].setValue(1) script["transform"]["in"].setInput(script["loop"]["previous"]) script["transform"]["filter"].setInput(script["filter"]["out"]) script["loop"]["next"].setInput(script["transform"]["out"]) script["loop"]["iterations"].setValue(2) self.assertEqual(script["loop"]["out"].transform("/sphere"), imath.M44f().translate(imath.V3f(2, 0, 0))) script["loop"]["enabled"].setValue(False) self.assertEqual(script["loop"]["out"].transform("/sphere"), imath.M44f()) self.assertScenesEqual(script["loop"]["out"], script["sphere"]["out"]) self.assertSceneHashesEqual(script["loop"]["out"], script["sphere"]["out"]) self.assertTrue(script["loop"].correspondingInput( script["loop"]["out"]).isSame(script["loop"]["in"]))
def testIterationsContext(self): script = Gaffer.ScriptNode() script["sphere"] = GafferScene.Sphere() script["loop"] = Gaffer.Loop() script["loop"].setup(GafferScene.ScenePlug()) script["loop"]["in"].setInput(script["sphere"]["out"]) script["filter"] = GafferScene.PathFilter() script["filter"]["paths"].setValue(IECore.StringVectorData(["/sphere" ])) script["transform"] = GafferScene.Transform() script["transform"]["transform"]["translate"]["x"].setValue(1) script["transform"]["in"].setInput(script["loop"]["previous"]) script["transform"]["filter"].setInput(script["filter"]["out"]) script["loop"]["next"].setInput(script["transform"]["out"]) script["expression"] = Gaffer.Expression() script["expression"].setExpression( inspect.cleandoc(""" assert( context.get( "scene:path", None ) is None ) parent["loop"]["iterations"] = 4 """)) self.assertEqual(script["loop"]["out"].transform("/sphere"), imath.M44f().translate(imath.V3f(4, 0, 0)))
def testChildBoundsCancellation( self ) : # Make Sierpinski triangle type thing. script = Gaffer.ScriptNode() script["sphere"] = GafferScene.Sphere() script["loop"] = Gaffer.Loop() script["loop"].setup( script["sphere"]["out"] ) script["loop"]["in"].setInput( script["sphere"]["out"] ) script["loop"]["iterations"].setValue( 12 ) script["filter"] = GafferScene.PathFilter() script["filter"]["paths"].setValue( IECore.StringVectorData( [ "/..." ] ) ) script["transform1"] = GafferScene.Transform() script["transform1"]["in"].setInput( script["loop"]["previous"] ) script["transform1"]["filter"].setInput( script["filter"]["out"] ) script["transform1"]["transform"]["translate"]["x"].setValue( 1 ) script["transform2"] = GafferScene.Transform() script["transform2"]["in"].setInput( script["loop"]["previous"] ) script["transform2"]["filter"].setInput( script["filter"]["out"] ) script["transform2"]["transform"]["translate"]["y"].setValue( 1 ) script["transform3"] = GafferScene.Transform() script["transform3"]["in"].setInput( script["loop"]["previous"] ) script["transform3"]["filter"].setInput( script["filter"]["out"] ) script["transform3"]["transform"]["translate"]["z"].setValue( 1 ) script["group"] = GafferScene.Group() script["group"]["in"][0].setInput( script["transform1"]["out"] ) script["group"]["in"][1].setInput( script["transform2"]["out"] ) script["group"]["in"][2].setInput( script["transform3"]["out"] ) script["group"]["transform"]["scale"].setValue( imath.V3f( 0.666 ) ) script["loop"]["next"].setInput( script["group"]["out"] ) for i in range( 0, 10 ) : # Launch background task to compute root bounds. This will perform # a deep recursion through the hierarchy using parallel tasks. backgroundTask = Gaffer.ParallelAlgo.callOnBackgroundThread( script["loop"]["out"], lambda : script["loop"]["out"].bound( "/" ) ) time.sleep( 0.1 ) # Cancel background task so that we don't perform all the work. # This triggered a crash bug in TaskMutex, but should return # cleanly if it has been fixed. backgroundTask.cancelAndWait()
def testSetup(self): n = Gaffer.Loop() self.assertNotIn("in", n) self.assertNotIn("out", n) self.assertNotIn("previous", n) self.assertNotIn("next", n) n.setup(Gaffer.StringPlug()) self.assertIsInstance(n["in"], Gaffer.StringPlug) self.assertIsInstance(n["out"], Gaffer.StringPlug) self.assertIsInstance(n["previous"], Gaffer.StringPlug) self.assertIsInstance(n["next"], Gaffer.StringPlug)
def testSerialisationUsesSetup(self): s1 = Gaffer.ScriptNode() s1["c"] = Gaffer.Loop() s1["c"].setup(Gaffer.IntPlug()) ss = s1.serialise() self.assertIn("setup", ss) self.assertEqual(ss.count("addChild"), 1) self.assertNotIn("Dynamic", ss) self.assertNotIn("Serialisable", ss) self.assertNotIn("setInput", ss) s2 = Gaffer.ScriptNode() s2.execute(ss) self.assertIn("in", s2["c"]) self.assertIn("out", s2["c"]) self.assertIsInstance(s2["c"]["in"], Gaffer.IntPlug) self.assertIsInstance(s2["c"]["out"], Gaffer.IntPlug) self.assertIsInstance(s2["c"]["previous"], Gaffer.IntPlug) self.assertIsInstance(s2["c"]["next"], Gaffer.IntPlug)
def testLoop(self): script = Gaffer.ScriptNode() script["c"] = GafferImage.Constant() script["loop"] = Gaffer.Loop() script["loop"].setup(GafferImage.ImagePlug()) script["loop"]["in"].setInput(script["c"]["out"]) script["grade"] = GafferImage.Grade() script["grade"]["offset"].setValue(imath.Color3f(.1)) script["grade"]["in"].setInput(script["loop"]["previous"]) script["loop"]["next"].setInput(script["grade"]["out"]) script["sampler"] = GafferImage.ImageSampler() script["sampler"]["pixel"].setValue(imath.V2f(10)) script["sampler"]["image"].setInput(script["loop"]["out"]) with script.context(): script["loop"]["iterations"].setValue(2) self.assertAlmostEqual(script["sampler"]["color"]["r"].getValue(), .2) script["loop"]["iterations"].setValue(4) self.assertAlmostEqual(script["sampler"]["color"]["r"].getValue(), .4) script2 = Gaffer.ScriptNode() script2.execute(script.serialise()) with script2.context(): script2["loop"]["iterations"].setValue(3) self.assertAlmostEqual(script2["sampler"]["color"]["r"].getValue(), .3) script2["loop"]["iterations"].setValue(5) self.assertAlmostEqual(script2["sampler"]["color"]["r"].getValue(), .5)
def testLoop(self): script = Gaffer.ScriptNode() script["sphere"] = GafferScene.Sphere() script["loop"] = Gaffer.Loop() script["loop"].setup(GafferScene.ScenePlug()) script["loop"]["in"].setInput(script["sphere"]["out"]) script["filter"] = GafferScene.PathFilter() script["filter"]["paths"].setValue(IECore.StringVectorData(["/sphere" ])) script["transform"] = GafferScene.Transform() script["transform"]["transform"]["translate"]["x"].setValue(1) script["transform"]["in"].setInput(script["loop"]["previous"]) script["transform"]["filter"].setInput(script["filter"]["out"]) script["loop"]["next"].setInput(script["transform"]["out"]) script["loop"]["iterations"].setValue(2) self.assertEqual(script["loop"]["out"].transform("/sphere"), imath.M44f().translate(imath.V3f(2, 0, 0))) script["loop"]["iterations"].setValue(4) self.assertEqual(script["loop"]["out"].transform("/sphere"), imath.M44f().translate(imath.V3f(4, 0, 0))) script2 = Gaffer.ScriptNode() script2.execute(script.serialise()) script2["loop"]["iterations"].setValue(3) self.assertEqual(script2["loop"]["out"].transform("/sphere"), imath.M44f().translate(imath.V3f(3, 0, 0))) script2["loop"]["iterations"].setValue(5) self.assertEqual(script2["loop"]["out"].transform("/sphere"), imath.M44f().translate(imath.V3f(5, 0, 0)))
def testManyImages(self): allFilter = GafferScene.PathFilter() allFilter["paths"].setValue(IECore.StringVectorData(['/...'])) sphere = GafferScene.Sphere() sphere["transform"]["translate"].setValue(imath.V3f(-3, 0, 0)) standardSurface = GafferArnold.ArnoldShader() standardSurface.loadShader("standard_surface") shaderAssignment = GafferScene.ShaderAssignment() shaderAssignment["in"].setInput(sphere["out"]) shaderAssignment["filter"].setInput(allFilter["out"]) shaderAssignment["shader"].setInput(standardSurface["out"]) uvScaleCode = GafferOSL.OSLCode() uvScaleCode["out"].addChild( Gaffer.V3fPlug("uvScaled", direction=Gaffer.Plug.Direction.Out)) uvScaleCode["code"].setValue('uvScaled = vector( u * 2, v * 2, 0 );') outUV = GafferOSL.OSLShader() outUV.loadShader("ObjectProcessing/OutUV") outUV["parameters"]["value"].setInput(uvScaleCode["out"]["uvScaled"]) outObject2 = GafferOSL.OSLShader() outObject2.loadShader("ObjectProcessing/OutObject") outObject2["parameters"]["in0"].setInput( outUV["out"]["primitiveVariable"]) uvScaleOSL = GafferOSL.OSLObject() uvScaleOSL["in"].setInput(shaderAssignment["out"]) uvScaleOSL["filter"].setInput(allFilter["out"]) uvScaleOSL["shader"].setInput(outObject2["out"]) uvScaleOSL["interpolation"].setValue(5) mapOffset = GafferScene.MapOffset() mapOffset["in"].setInput(uvScaleOSL["out"]) mapOffset["filter"].setInput(allFilter["out"]) mapOffset["udim"].setValue(1033) offsetGroup = GafferScene.Group() offsetGroup["in"]["in0"].setInput(mapOffset["out"]) offsetGroup["name"].setValue('offset') offsetGroup["transform"]["translate"].setValue(imath.V3f(6, 0, 3)) combineGroup = GafferScene.Group() combineGroup["in"]["in0"].setInput(uvScaleOSL["out"]) combineGroup["in"]["in1"].setInput(offsetGroup["out"]) lights = [] for color, rotate in [((1, 0, 0), (0, 0, 0)), ((0, 1, 0), (0, 90, 0)), ((0, 0, 1), (-90, 0, 0))]: light = GafferArnold.ArnoldLight() light.loadShader("distant_light") light["parameters"]["color"].setValue(imath.Color3f(*color)) light["transform"]["rotate"].setValue(imath.V3f(*rotate)) combineGroup["in"][-1].setInput(light["out"]) lights.append(light) arnoldTextureBake = GafferArnold.ArnoldTextureBake() arnoldTextureBake["in"].setInput(combineGroup["out"]) arnoldTextureBake["filter"].setInput(allFilter["out"]) arnoldTextureBake["bakeDirectory"].setValue(self.temporaryDirectory() + '/bakeSpheres/') arnoldTextureBake["defaultResolution"].setValue(32) arnoldTextureBake["aovs"].setValue('beauty:RGBA diffuse:diffuse') arnoldTextureBake["tasks"].setValue(3) arnoldTextureBake["cleanupIntermediateFiles"].setValue(True) # Dispatch the bake script = Gaffer.ScriptNode() script.addChild(arnoldTextureBake) dispatcher = GafferDispatch.LocalDispatcher() dispatcher["jobsDirectory"].setValue(self.temporaryDirectory()) dispatcher.dispatch([arnoldTextureBake]) # Test that we are writing all expected files, and that we have cleaned up all temp files expectedUdims = [i + j for j in [1001, 1033] for i in [0, 1, 10, 11]] self.assertEqual( sorted(os.listdir(self.temporaryDirectory() + '/bakeSpheres/')), ["beauty", "diffuse"]) self.assertEqual( sorted( os.listdir(self.temporaryDirectory() + '/bakeSpheres/beauty')), ["beauty.%i.tx" % i for i in expectedUdims]) self.assertEqual( sorted( os.listdir(self.temporaryDirectory() + '/bakeSpheres/diffuse')), ["diffuse.%i.tx" % i for i in expectedUdims]) # Read back in the 4 udim tiles of a sphere reader = GafferImage.ImageReader() imageTransform = GafferImage.ImageTransform() imageTransform["in"].setInput(reader["out"]) exprBox = Gaffer.Box() expression = Gaffer.Expression() exprBox.addChild(reader) exprBox.addChild(imageTransform) exprBox.addChild(expression) expression.setExpression( inspect.cleandoc( """ i = context.get( "loop:index", 0 ) layer = context.get( "collect:layerName", "beauty" ) x = i % 2 y = i / 2 parent["ImageReader"]["fileName"] = '""" + self.temporaryDirectory() + """/bakeSpheres/%s/%s.%i.tx' % ( layer, layer, 1001 + x + y * 10 ) parent["ImageTransform"]["transform"]["translate"] = imath.V2f( 32 * x, 32 * y ) """), "python") udimLoop = Gaffer.Loop() udimLoop.setup(GafferImage.ImagePlug()) udimLoop["iterations"].setValue(4) udimMerge = GafferImage.Merge() udimMerge["in"]["in0"].setInput(imageTransform["out"]) udimMerge["in"]["in1"].setInput(udimLoop["previous"]) udimLoop["next"].setInput(udimMerge["out"]) aovCollect = GafferImage.CollectImages() aovCollect["in"].setInput(udimLoop["out"]) aovCollect["rootLayers"].setValue( IECore.StringVectorData(['beauty', 'diffuse'])) # We have a little reference image for how the diffuse should look imageReaderRef = GafferImage.ImageReader() imageReaderRef["fileName"].setValue( os.path.dirname(__file__) + "/images/sphereLightBake.exr") resizeRef = GafferImage.Resize() resizeRef["in"].setInput(imageReaderRef["out"]) resizeRef["format"].setValue(GafferImage.Format(64, 64, 1.000)) shuffleRef = GafferImage.Shuffle() shuffleRef["in"].setInput(resizeRef["out"]) for layer in ["beauty", "diffuse"]: for channel in ["R", "G", "B"]: shuffleRef["channels"].addChild( GafferImage.Shuffle.ChannelPlug()) shuffleRef["channels"][-1]["in"].setValue(channel) shuffleRef["channels"][-1]["out"].setValue(layer + "." + channel) differenceMerge = GafferImage.Merge() differenceMerge["in"]["in0"].setInput(aovCollect["out"]) differenceMerge["in"]["in1"].setInput(shuffleRef["out"]) differenceMerge["operation"].setValue( GafferImage.Merge.Operation.Difference) stats = GafferImage.ImageStats() stats["in"].setInput(differenceMerge["out"]) stats["area"].setValue(imath.Box2i(imath.V2i(0, 0), imath.V2i(64, 64))) # We should get a very close match to our single tile low res reference bake stats["channels"].setValue( IECore.StringVectorData( ['diffuse.R', 'diffuse.G', 'diffuse.B', 'diffuse.A'])) for i in range(3): self.assertLess(stats["average"].getValue()[i], 0.002) self.assertLess(stats["max"].getValue()[i], 0.02) # The beauty should be mostly a close match, but with a high max difference due to the spec pings stats["channels"].setValue( IECore.StringVectorData( ['beauty.R', 'beauty.G', 'beauty.B', 'beauty.A'])) for i in range(3): self.assertLess(stats["average"].getValue()[i], 0.1) self.assertGreater(stats["max"].getValue()[i], 0.3)
def intLoop(self): result = Gaffer.Loop() result.setup(Gaffer.IntPlug()) return result
def runBoundaryCorrectness(self, scale): testMerge = GafferImage.Merge() subImageNodes = [] for checkSize, col, bound in [ (2, (0.672299981, 0.672299981, 0), ((11, 7), (61, 57))), (4, (0.972599983, 0.493499994, 1), ((9, 5), (59, 55))), (6, (0.310799986, 0.843800008, 1), ((0, 21), (1024, 41))), (8, (0.958999991, 0.672299981, 0.0296), ((22, 0), (42, 1024))), (10, (0.950900018, 0.0899000019, 0.235499993), ((7, 10), (47, 50))), ]: checkerboard = GafferImage.Checkerboard() checkerboard["format"].setValue( GafferImage.Format(1024 * scale, 1024 * scale, 1.000)) checkerboard["size"].setValue(imath.V2f(checkSize * scale)) checkerboard["colorA"].setValue( imath.Color4f(0.1 * col[0], 0.1 * col[1], 0.1 * col[2], 0.3)) checkerboard["colorB"].setValue( imath.Color4f(0.5 * col[0], 0.5 * col[1], 0.5 * col[2], 0.7)) crop = GafferImage.Crop("Crop") crop["in"].setInput(checkerboard["out"]) crop["area"].setValue( imath.Box2i( imath.V2i(scale * bound[0][0], scale * bound[0][1]), imath.V2i(scale * bound[1][0], scale * bound[1][1]))) crop["affectDisplayWindow"].setValue(False) subImageNodes.append(checkerboard) subImageNodes.append(crop) testMerge["in"][-1].setInput(crop["out"]) testMerge["expression"] = Gaffer.Expression() testMerge["expression"].setExpression( 'parent["operation"] = context[ "loop:index" ]') inverseScale = GafferImage.ImageTransform() inverseScale["in"].setInput(testMerge["out"]) inverseScale["filter"].setValue("box") inverseScale["transform"]["scale"].setValue(imath.V2f(1.0 / scale)) crop1 = GafferImage.Crop() crop1["in"].setInput(inverseScale["out"]) crop1["area"].setValue(imath.Box2i(imath.V2i(0, 0), imath.V2i(64, 64))) loopInit = GafferImage.Constant() loopInit["format"].setValue(GafferImage.Format(896, 64, 1.000)) loopInit["color"].setValue(imath.Color4f(0)) loopOffset = GafferImage.Offset() loopOffset["in"].setInput(crop1["out"]) loopOffset["expression"] = Gaffer.Expression() loopOffset["expression"].setExpression( 'parent["offset"]["x"] = 64 * context[ "loop:index" ]') loopMerge = GafferImage.Merge() loopMerge["in"][1].setInput(loopOffset["out"]) loop = Gaffer.Loop() loop.setup(GafferImage.ImagePlug("in", )) loop["iterations"].setValue(14) loop["in"].setInput(loopInit["out"]) loop["next"].setInput(loopMerge["out"]) loopMerge["in"][0].setInput(loop["previous"]) # Uncomment for debug #imageWriter = GafferImage.ImageWriter( "ImageWriter" ) #imageWriter["in"].setInput( loop["out"] ) #imageWriter['openexr']['dataType'].setValue( "float" ) #imageWriter["fileName"].setValue( "/tmp/mergeBoundaries.exr" ) #imageWriter.execute() reader = GafferImage.ImageReader() reader["fileName"].setValue(self.mergeBoundariesRefPath) self.assertImagesEqual(loop["out"], reader["out"], ignoreMetadata=True, maxDifference=1e-5 if scale > 1 else 0)
def testBlurRange(self): constant = GafferImage.Constant() constant["format"].setValue(GafferImage.Format(5, 5, 1.000)) constant["color"].setValue(imath.Color4f(1, 1, 1, 1)) cropDot = GafferImage.Crop() cropDot["area"].setValue(imath.Box2i(imath.V2i(2, 2), imath.V2i(3, 3))) cropDot["affectDisplayWindow"].setValue(False) cropDot["in"].setInput(constant["out"]) blur = GafferImage.Blur() blur["expandDataWindow"].setValue(True) blur["in"].setInput(cropDot["out"]) blur["radius"]["y"].setInput(blur["radius"]["x"]) expression = Gaffer.Expression() blur.addChild(expression) expression.setExpression( 'parent["radius"]["x"] = context[ "loop:index" ] * 0.2', "python") loopInit = GafferImage.Constant() loopInit["format"].setValue(GafferImage.Format(5, 5, 1.000)) imageLoop = Gaffer.Loop() imageLoop.setup(GafferImage.ImagePlug()) imageLoop["in"].setInput(loopInit["out"]) merge = GafferImage.Merge() merge["in"].addChild( GafferImage.ImagePlug( "in2", flags=Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, )) merge["in"]["in0"].setInput(blur["out"]) merge["in"]["in1"].setInput(imageLoop["previous"]) offset = GafferImage.Offset() offset["offset"].setValue(imath.V2i(-5, 0)) offset["in"].setInput(merge["out"]) imageLoop["next"].setInput(offset["out"]) deleteChannels = GafferImage.DeleteChannels() deleteChannels["mode"].setValue(GafferImage.DeleteChannels.Mode.Keep) deleteChannels["channels"].setValue(IECore.StringVectorData(['R'])) deleteChannels["in"].setInput(imageLoop["out"]) finalCrop = GafferImage.Crop() finalCrop["areaSource"].setValue(1) finalCrop["in"].setInput(deleteChannels["out"]) # Enable to write out images for visual comparison if False: testWriter = GafferImage.ImageWriter() testWriter["in"].setInput(finalCrop["out"]) testWriter["fileName"].setValue("/tmp/blurRange.exr") testWriter["openexr"]["dataType"].setValue('float') testWriter["task"].execute() expectedReader = GafferImage.ImageReader() expectedReader["fileName"].setValue( os.path.dirname(__file__) + "/images/blurRange.exr") self.assertImagesEqual(finalCrop["out"], expectedReader["out"], maxDifference=0.00001, ignoreMetadata=True)