Exemplo n.º 1
0
	def testTileHashes( self ) :

		# Test that two tiles within the image have the same hash.
		e = GafferImage.Empty()
		e["format"].setValue( GafferImage.Format( 2048, 1156, 1. ) )

		self.assertEqual(
			e["out"].channelDataHash( "R", imath.V2i( 0 ) ),
			e["out"].channelDataHash( "R", imath.V2i( GafferImage.ImagePlug().tileSize() ) ),
		)

		self.assertEqual(
			e["out"].sampleOffsetsHash( imath.V2i( 0 ) ),
			e["out"].sampleOffsetsHash( imath.V2i( GafferImage.ImagePlug().tileSize() ) ),
		)
Exemplo n.º 2
0
    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)
Exemplo n.º 3
0
    def testSwitching(self):

        in0 = GafferImage.Constant()
        in0["format"].setValue(GafferImage.Format(100, 100, 1.0))
        in0["color"].setValue(imath.Color4f(1, 0, 0, 1))
        in1 = GafferImage.Constant()
        in1["format"].setValue(GafferImage.Format(100, 100, 1.0))
        in0["color"].setValue(imath.Color4f(0, 1, 0, 1))

        switch = Gaffer.Switch()
        switch.setup(GafferImage.ImagePlug())
        switch["in"][0].setInput(in0["out"])
        switch["in"][1].setInput(in1["out"])

        self.assertImageHashesEqual(switch["out"], in0["out"])
        self.assertImagesEqual(switch["out"], in0["out"])

        switch["index"].setValue(1)

        self.assertImageHashesEqual(switch["out"], in1["out"])
        self.assertImagesEqual(switch["out"], in1["out"])

        switch["enabled"].setValue(False)

        self.assertImageHashesEqual(switch["out"], in0["out"])
        self.assertImagesEqual(switch["out"], in0["out"])
Exemplo n.º 4
0
    def testEnabledPlug(self):

        s = Gaffer.Switch()
        s.setup(GafferImage.ImagePlug())
        self.assertTrue(isinstance(s["enabled"], Gaffer.BoolPlug))
        self.assertTrue(s["enabled"].isSame(s.enabledPlug()))
        self.assertFalse("enabled1" in s)
Exemplo n.º 5
0
    def testTileSize(self):

        n = GafferImage.ImageReader()
        n["fileName"].setValue(self.fileName)

        tile = n["out"].channelData("R", IECore.V2i(0))
        self.assertEqual(len(tile), GafferImage.ImagePlug().tileSize()**2)
Exemplo n.º 6
0
    def testTimeWarping(self):

        script = Gaffer.ScriptNode()

        script["constant"] = GafferImage.Constant()

        script["expression"] = Gaffer.Expression()
        script["expression"].setExpression(
            'parent["constant"]["color"]["r"] = context["frame"]')

        script["timeWarp"] = Gaffer.TimeWarp()
        script["timeWarp"].setup(GafferImage.ImagePlug())
        script["timeWarp"]["offset"].setValue(1)
        script["timeWarp"]["in"].setInput(script["constant"]["out"])

        for f in range(0, 10):
            with script.context():

                script.context().setFrame(f)
                c0 = script["constant"]["out"].image()
                c0Hash = script["constant"]["out"].imageHash()
                t = script["timeWarp"]["out"].image()
                tHash = script["timeWarp"]["out"].imageHash()

                script.context().setFrame(f + 1)
                c1 = script["constant"]["out"].image()
                c1Hash = script["constant"]["out"].imageHash()

            self.assertEqual(c1, t)
            self.assertEqual(c1Hash, tHash)
            self.assertNotEqual(c0, c1)
            self.assertNotEqual(c0Hash, c1Hash)
Exemplo n.º 7
0
	def testBlurRange( self ):

		constant = GafferImage.Constant()
		constant["format"].setValue( GafferImage.Format( 5, 5, 1.000 ) )
		constant["color"].setValue( IECore.Color4f( 1, 1, 1, 1 ) )

		

		cropDot = GafferImage.Crop()
		cropDot["area"].setValue( IECore.Box2i( IECore.V2i( 2, 2 ), IECore.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 = GafferImage.ImageLoop()
		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( IECore.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 )
Exemplo n.º 8
0
    def testEnabledPlug(self):

        t = Gaffer.TimeWarp()
        t.setup(GafferImage.ImagePlug())
        self.assertTrue(isinstance(t["enabled"], Gaffer.BoolPlug))
        self.assertTrue(t["enabled"].isSame(t.enabledPlug()))
        self.assertFalse("enabled1" in t)
Exemplo n.º 9
0
    def testAffects(self):

        timeWarp = Gaffer.TimeWarp()
        timeWarp.setup(GafferImage.ImagePlug())

        for n in [
                "format", "dataWindow", "metadata", "channelNames",
                "channelData"
        ]:
            a = timeWarp.affects(timeWarp["in"][n])
            self.assertEqual(len(a), 1)
            self.assertTrue(a[0].isSame(timeWarp["out"][n]))

        for n in ["enabled", "offset", "speed"]:
            a = set([
                plug.relativeName(plug.node())
                for plug in timeWarp.affects(timeWarp[n])
            ])
            self.assertEqual(
                a,
                set([
                    "out.format",
                    "out.dataWindow",
                    "out.metadata",
                    "out.channelNames",
                    "out.channelData",
                ]),
            )
Exemplo n.º 10
0
    def testAcceptsInput(self):

        w = GafferImage.ImageWriter()
        p = GafferImage.ImagePlug(direction=Gaffer.Plug.Direction.Out)

        self.failIf(w['requirements']['requirement0'].acceptsInput(p))
        self.failUnless(w["in"].acceptsInput(p))
Exemplo n.º 11
0
    def testTimeContext(self):

        script = Gaffer.ScriptNode()
        script["constant"] = GafferImage.Constant()
        script["constant"]["format"].setValue(GafferImage.Format(1, 1, 1.0))

        script["e"] = Gaffer.Expression()
        script["e"].setExpression(
            'parent["constant"]["color"] = imath.Color4f( context["frame"] )')

        script["timeWarp"] = Gaffer.TimeWarp()
        script["timeWarp"].setup(GafferImage.ImagePlug())
        script["timeWarp"]["in"].setInput(script["constant"]["out"])
        script["timeWarp"]["speed"].setValue(0)
        script["timeWarp"]["offset"].setValue(3)

        script["sampler"] = GafferImage.ImageSampler()
        script["sampler"]["pixel"].setValue(imath.V2f(0.5, 0.5))
        script["sampler"]["image"].setInput(script["timeWarp"]["out"])

        self.assertEqual(script["sampler"]["color"].getValue(),
                         imath.Color4f(3))

        script["e2"] = Gaffer.Expression()
        script["e2"].setExpression(
            inspect.cleandoc("""
			assert( context.get( "image:channelName", None ) is None )
			assert( context.get( "image:tileOrigin", None ) is None )
			parent["timeWarp"]["offset"] = 5
			"""))

        self.assertEqual(script["sampler"]["color"].getValue(),
                         imath.Color4f(5))
Exemplo n.º 12
0
	def testAcceptsInput( self ) :

		w = GafferImage.ImageWriter()
		p = GafferImage.ImagePlug( direction = Gaffer.Plug.Direction.Out )

		self.failIf( w["preTasks"][0].acceptsInput( p ) )
		self.failUnless( w["in"].acceptsInput( p ) )
Exemplo n.º 13
0
    def testTileNotAvailableInContextExpressions(self):

        # We don't want expressions on the index to be sensitive
        # to the image:tileOrigin or image:channelName context entries,
        # because then an invalid image could result from splicing together
        # different images, even requesting tiles outside the data window.

        script = Gaffer.ScriptNode()

        script["switch"] = Gaffer.Switch()
        script["switch"].setup(GafferImage.ImagePlug())
        script["in0"] = GafferImage.Constant()
        script["in0"]["color"].setValue(imath.Color4f(1, 1, 1, 1))
        script["in1"] = GafferImage.Constant()
        script["in0"]["color"].setValue(imath.Color4f(0, 0, 0, 0))

        script["switch"]["in"][0].setInput(script["in0"]["out"])
        script["switch"]["in"][1].setInput(script["in1"]["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["switch"]["index"] = 1
			"""))

        self.assertEqual(
            script["switch"]["out"].channelData("R", imath.V2i(0))[0], 0)
Exemplo n.º 14
0
	def testChannelDataHashes( self ) :
		# Test that two tiles within the same image have different hashes.
		n = GafferImage.ImageReader()
		n["fileName"].setValue( self.fileName )
		h1 = n["out"].channelData( "R", imath.V2i( 0 ) ).hash()
		h2 = n["out"].channelData( "R", imath.V2i( GafferImage.ImagePlug().tileSize() ) ).hash()

		self.assertNotEqual( h1, h2 )
Exemplo n.º 15
0
	def testCreateCounterpart( self ) :

		p = GafferImage.ImagePlug()
		p2 = p.createCounterpart( "a", Gaffer.Plug.Direction.Out )

		self.assertEqual( p2.getName(), "a" )
		self.assertEqual( p2.direction(), Gaffer.Plug.Direction.Out )
		self.assertEqual( p2.getFlags(), p.getFlags() )
Exemplo n.º 16
0
	def testDisabledChannelDataHashes( self ) :
		# Test that two tiles within the same image have the same hash when disabled.
		n = GafferImage.OpenImageIOReader()
		n["fileName"].setValue( self.fileName )
		n["enabled"].setValue( False )
		h1 = n["out"].channelData( "R", imath.V2i( 0 ) ).hash()
		h2 = n["out"].channelData( "R", imath.V2i( GafferImage.ImagePlug().tileSize() ) ).hash()

		self.assertEqual( h1, h2 )
Exemplo n.º 17
0
 def testTileHashes(self):
     # Test that two tiles within the image have the same hash.
     c = GafferImage.Constant()
     c["format"].setValue(GafferImage.Format(2048, 1156, 1.))
     c["color"][0].setValue(.5)
     h1 = c["out"].channelData("R", IECore.V2i(0)).hash()
     h2 = c["out"].channelData(
         "R", IECore.V2i(GafferImage.ImagePlug().tileSize())).hash()
     self.assertEqual(h1, h2)
Exemplo n.º 18
0
	def testChannelDataHashes( self ) :
		# Create a grade node and save the hash of a tile from each channel.
		i = GafferImage.ImageReader()
		i["fileName"].setValue( self.checkerFile )

		grade = GafferImage.Grade()
		grade["in"].setInput(i["out"])
		grade["gain"].setValue( IECore.Color3f( 2., 2., 2. ) )

		h1 = grade["out"].channelData( "R", IECore.V2i( 0 ) ).hash()
		h2 = grade["out"].channelData( "R", IECore.V2i( GafferImage.ImagePlug().tileSize() ) ).hash()
		self.assertNotEqual( h1, h2 )

		# Test that two tiles within the same image have the same hash when disabled.
		grade["enabled"].setValue(False)
		h1 = grade["out"].channelData( "R", IECore.V2i( 0 ) ).hash()
		h2 = grade["out"].channelData( "R", IECore.V2i( GafferImage.ImagePlug().tileSize() ) ).hash()
		self.assertNotEqual( h1, h2 )
Exemplo n.º 19
0
    def testAffects(self):

        in0 = GafferImage.Constant()
        in1 = GafferImage.Constant()

        switch = Gaffer.Switch()
        switch.setup(GafferImage.ImagePlug())
        switch["in"][0].setInput(in0["out"])
        switch["in"][1].setInput(in1["out"])

        add = GafferTest.AddNode()
        switch["index"].setInput(add["sum"])

        for p in [switch["in"][0], switch["in"][1]]:
            for n in [
                    "format", "dataWindow", "metadata", "deep",
                    "sampleOffsets", "channelNames", "channelData"
            ]:
                a = switch.affects(p[n])
                self.assertEqual(len(a), 1)
                self.assertTrue(a[0].isSame(switch["out"][n]))

        a = set([
            plug.relativeName(plug.node())
            for plug in switch.affects(switch["enabled"])
        ])
        self.assertEqual(
            a,
            set([
                "out.format",
                "out.dataWindow",
                "out.metadata",
                "out.deep",
                "out.sampleOffsets",
                "out.channelNames",
                "out.channelData",
            ]),
        )

        a = set([
            plug.relativeName(plug.node())
            for plug in switch.affects(switch["index"])
        ])
        self.assertEqual(
            a,
            set([
                "out.format",
                "out.dataWindow",
                "out.metadata",
                "out.deep",
                "out.sampleOffsets",
                "out.channelNames",
                "out.channelData",
            ]),
        )
Exemplo n.º 20
0
	def testDynamicSerialisation( self ) :

		s = Gaffer.ScriptNode()
		s["n"] = Gaffer.Node()
		s["n"]["p"] = GafferImage.ImagePlug( flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic )
		ss = s.serialise()

		s = Gaffer.ScriptNode()
		s.execute( ss )

		self.assertTrue( isinstance( s["n"]["p"], GafferImage.ImagePlug ) )
		self.assertEqual( s["n"]["p"].getFlags(), Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic )
Exemplo n.º 21
0
			def __init__( self, viewedPlug = None ) :

				GafferImageUI.ImageView.__init__( self, "MyView" )

				converter = Gaffer.Node()
				converter["in"] = Gaffer.StringPlug()
				converter["out"] = GafferImage.ImagePlug( direction = Gaffer.Plug.Direction.Out )
				converter["text"] = GafferImage.Text()
				converter["text"]["text"].setInput( converter["in"] )
				converter["out"].setInput( converter["text"]["out"] )

				self._insertConverter( converter )

				self["in"].setInput( viewedPlug )
Exemplo n.º 22
0
			def __init__( self, viewedPlug = None ) :

				GafferImageUI.ImageView.__init__( self, "MyView" )

				converter = Gaffer.Node()
				converter["in"] = Gaffer.ObjectPlug( defaultValue = IECore.NullObject.defaultNullObject() )
				converter["out"] = GafferImage.ImagePlug( direction = Gaffer.Plug.Direction.Out )
				converter["constant"] = GafferImage.Constant()
				converter["constant"]["format"].setValue( GafferImage.Format( 20, 20, 1 ) )
				converter["out"].setInput( converter["constant"]["out"] )

				self._insertConverter( converter )

				self["in"].setInput( viewedPlug )
Exemplo n.º 23
0
    def testDefaultFormat(self):

        s = Gaffer.ScriptNode()
        d = GafferImage.Display()
        s.addChild(d)

        p = GafferImage.ImagePlug("in", Gaffer.Plug.Direction.In)
        p.setInput(d["out"])

        with s.context():
            self.assertEqual(p["format"].getValue(),
                             GafferImage.Format.getDefaultFormat(s))
            GafferImage.Format.setDefaultFormat(
                s, GafferImage.Format(200, 150, 1.))
            self.assertEqual(p["format"].getValue(),
                             GafferImage.Format.getDefaultFormat(s))
Exemplo n.º 24
0
    def testSerialisation(self):

        script = Gaffer.ScriptNode()

        script["switch"] = Gaffer.Switch()
        script["switch"].setup(GafferImage.ImagePlug())
        script["in0"] = GafferImage.Constant()
        script["in1"] = GafferImage.Constant()

        script["switch"]["in"][0].setInput(script["in0"]["out"])
        script["switch"]["in"][1].setInput(script["in1"]["out"])

        script2 = Gaffer.ScriptNode()
        script2.execute(script.serialise())

        self.assertTrue(script2["switch"]["in"][0].getInput().isSame(
            script2["in0"]["out"]))
        self.assertTrue(script2["switch"]["in"][1].getInput().isSame(
            script2["in1"]["out"]))
        self.assertTrue(script2["switch"]["in"][2].getInput() is None)
Exemplo n.º 25
0
	def testDefaultFormatChanged( self ) :
		# Create a grade node and check that the format changes if it is unconnected.
		n = GafferImage.Grade()
		s = Gaffer.ScriptNode()
		s.addChild( n )
		
		p = GafferImage.ImagePlug( "test", GafferImage.ImagePlug.Direction.In )
		p.setInput( n["out"] )
		
		with s.context() :
			f1 = p["format"].getValue()

			# Change the default format.
			GafferImage.Format.registerFormat( self.__testFormatValue(), self.__testFormatName() )
			GafferImage.Format.setDefaultFormat( s, self.__testFormatValue() )
		
			# Check that the hash has changed.
			f2 = p["format"].getValue()
		
			self.assertNotEqual( f1, f2 )
Exemplo n.º 26
0
    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)
Exemplo n.º 27
0
            def __init__(self, viewedPlug=None):

                GafferImageUI.ImageView.__init__(
                    self, "MyView",
                    Gaffer.ObjectPlug(
                        "in",
                        defaultValue=IECore.NullObject.defaultNullObject()))

                self["in"].setInput(viewedPlug)

                self.__preprocessor = Gaffer.Node()
                self.__preprocessor["in"] = Gaffer.ObjectPlug(
                    defaultValue=IECore.NullObject.defaultNullObject())
                self.__preprocessor["out"] = GafferImage.ImagePlug(
                    direction=Gaffer.Plug.Direction.Out)
                self.__preprocessor["constant"] = GafferImage.Constant()
                self.__preprocessor["constant"]["format"].setValue(
                    GafferImage.Format(20, 20, 1))
                self.__preprocessor["out"].setInput(
                    self.__preprocessor["constant"]["out"])

                self._setPreprocessor(self.__preprocessor)
Exemplo n.º 28
0
    def testDisabling(self):

        script = Gaffer.ScriptNode()

        script["constant"] = GafferImage.Constant()

        script["expression"] = Gaffer.Expression()
        script["expression"].setExpression(
            'parent["constant"]["color"]["r"] = context["frame"]')

        script["timeWarp"] = Gaffer.TimeWarp()
        script["timeWarp"].setup(GafferImage.ImagePlug())

        script["timeWarp"]["offset"].setValue(1)
        script["timeWarp"]["in"].setInput(script["constant"]["out"])

        with script.context():

            c = script["constant"]["out"].image()
            cHash = script["constant"]["out"].imageHash()
            t = script["timeWarp"]["out"].image()
            tHash = script["timeWarp"]["out"].imageHash()

        self.assertNotEqual(c, t)
        self.assertNotEqual(cHash, tHash)

        script["timeWarp"]["enabled"].setValue(False)

        with script.context():

            c = script["constant"]["out"].image()
            cHash = script["constant"]["out"].imageHash()
            t = script["timeWarp"]["out"].image()
            tHash = script["timeWarp"]["out"].imageHash()

        self.assertEqual(c, t)
        self.assertEqual(cHash, tHash)
Exemplo n.º 29
0
	def testDefaultChannelNamesMethod( self ) :

		channelNames = GafferImage.ImagePlug()['channelNames'].defaultValue()
		self.assertTrue( 'R' in channelNames )
		self.assertTrue( 'G' in channelNames )
		self.assertTrue( 'B' in channelNames )
Exemplo n.º 30
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)