Пример #1
0
    def testShaderNameMatchesFileName(self):

        oslCode = GafferOSL.OSLCode()
        oslCode["out"]["o"] = Gaffer.Color3fPlug(
            direction=Gaffer.Plug.Direction.Out,
            flags=Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic)
        oslCode["code"].setValue("o = color( 0, 1, 0 );")

        info = subprocess.check_output(
            ["oslinfo", self.__osoFileName(oslCode)])
        self.assertTrue(
            info.startswith("shader \"{0}\"".format(
                os.path.basename(self.__osoFileName(oslCode)))))
Пример #2
0
    def testSource(self):

        # Make a shader using the OSLCode node.

        oslCode = GafferOSL.OSLCode()

        oslCode["parameters"]["i"] = Gaffer.Color3fPlug(
            flags=Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic)
        oslCode["out"]["o"] = Gaffer.Color3fPlug(
            direction=Gaffer.Plug.Direction.Out,
            flags=Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic)
        oslCode["code"].setValue("o = i * color( u, v, 0 );")

        # Export it to a .osl file and compile it.

        oslFileName = os.path.join(self.temporaryDirectory(), "test.osl")
        with open(oslFileName, "w") as f:
            f.write(oslCode.source("test"))

        shader = self.compileShader(oslFileName)

        # Load that onto an OSLShader and check that
        # it matches.

        oslShader = GafferOSL.OSLShader()
        oslShader.loadShader(shader)

        self.assertEqual(oslShader["parameters"].keys(),
                         oslCode["parameters"].keys())
        self.assertEqual(oslShader["out"].keys(), oslCode["out"].keys())

        for p in oslShader["parameters"].children():
            p.setFlags(Gaffer.Plug.Flags.Dynamic, True)
            self.assertEqual(repr(p), repr(oslCode["parameters"][p.getName()]))

        for p in oslShader["out"].children():
            p.setFlags(Gaffer.Plug.Flags.Dynamic, True)
            self.assertEqual(repr(p), repr(oslCode["out"][p.getName()]))
Пример #3
0
    def testSettable(self):

        n = Gaffer.Node()
        n["p1"] = Gaffer.Color3fPlug()
        n["p2"] = Gaffer.Color3fPlug()

        self.assertTrue(n["p1"].settable())
        self.assertTrue(n["p2"].settable())

        n["p2"].setInput(n["p1"])

        self.assertTrue(n["p1"].settable())
        self.assertFalse(n["p2"].settable())

        # partially connected plugs should not be considered
        # settable, because all the children are not settable

        n["p2"]["r"].setInput(None)
        self.assertEqual(n["p2"]["r"].getInput(), None)
        self.assertEqual(n["p2"].getInput(), None)

        self.assertTrue(n["p1"].settable())
        self.assertFalse(n["p2"].settable())
Пример #4
0
    def testColor3fAcceptsColor4fInput(self):

        p4 = Gaffer.Color4fPlug(direction=Gaffer.Plug.Direction.Out)
        p3 = Gaffer.Color3fPlug()

        self.failUnless(p3.acceptsInput(p4))

        p3.setInput(p4)

        self.failUnless(p3.getInput().isSame(p4))
        self.failUnless(p3[0].getInput().isSame(p4[0]))
        self.failUnless(p3[1].getInput().isSame(p4[1]))
        self.failUnless(p3[2].getInput().isSame(p4[2]))
        self.assertEqual(p4[3].outputs(), ())
Пример #5
0
	def testAddColumnUsingDynamicPlug( self ) :

		s = Gaffer.ScriptNode()
		s["s"] = Gaffer.Spreadsheet()
		s["s"]["rows"].addColumn( Gaffer.Color3fPlug( "c", flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic ) )
		s["s"]["rows"].addColumn( Gaffer.IntPlug( "i", flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic ) )

		s2 = Gaffer.ScriptNode()
		s2.execute( s.serialise() )

		self.assertEqual( s2["s"]["rows"][0]["cells"].keys(), s["s"]["rows"][0]["cells"].keys() )
		self.assertEqual( s2["s"]["out"].keys(), s["s"]["out"].keys() )

		self.assertEqual( s2.serialise(), s.serialise() )
Пример #6
0
    def testContextTypes(self):

        s = Gaffer.ScriptNode()
        s["n"] = Gaffer.Node()
        s["n"]["user"]["f"] = Gaffer.FloatPlug(flags=Gaffer.Plug.Flags.Default
                                               | Gaffer.Plug.Flags.Dynamic)
        s["n"]["user"]["i"] = Gaffer.IntPlug(flags=Gaffer.Plug.Flags.Default
                                             | Gaffer.Plug.Flags.Dynamic)
        s["n"]["user"]["c"] = Gaffer.Color3fPlug(
            flags=Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic)
        s["n"]["user"]["v"] = Gaffer.V3fPlug(flags=Gaffer.Plug.Flags.Default
                                             | Gaffer.Plug.Flags.Dynamic)
        s["n"]["user"]["s"] = Gaffer.StringPlug(flags=Gaffer.Plug.Flags.Default
                                                | Gaffer.Plug.Flags.Dynamic)

        s["e"] = Gaffer.Expression()
        s["e"].setExpression(
            inspect.cleandoc("""
				parent.n.user.f = context( "f", 1 );
				parent.n.user.i = context( "i", 1 );
				parent.n.user.c = context( "c", color( 1, 2, 3 ) );
				parent.n.user.v = context( "v", vector( 0, 1, 2 ) );
				parent.n.user.s = context( "s", "default" );
				"""), "OSL")

        with Gaffer.Context() as c:

            self.assertEqual(s["n"]["user"]["f"].getValue(), 1)
            self.assertEqual(s["n"]["user"]["i"].getValue(), 1)
            self.assertEqual(s["n"]["user"]["c"].getValue(),
                             IECore.Color3f(1, 2, 3))
            self.assertEqual(s["n"]["user"]["v"].getValue(),
                             IECore.V3f(0, 1, 2))
            self.assertEqual(s["n"]["user"]["s"].getValue(), "default")

            c["f"] = 10
            c["i"] = 11
            c["c"] = IECore.Color3f(4, 5, 6)
            c["v"] = IECore.V3f(1, 2, 3)
            c["s"] = "non-default"

            self.assertEqual(s["n"]["user"]["f"].getValue(), 10)
            self.assertEqual(s["n"]["user"]["i"].getValue(), 11)
            self.assertEqual(s["n"]["user"]["c"].getValue(),
                             IECore.Color3f(4, 5, 6))
            self.assertEqual(s["n"]["user"]["v"].getValue(),
                             IECore.V3f(1, 2, 3))
            self.assertEqual(s["n"]["user"]["s"].getValue(), "non-default")
Пример #7
0
    def testConnect(self):

        plane = GafferScene.Plane()
        shader = GafferSceneTest.TestShader("surface")
        shader["type"].setValue("surface")

        planeFilter = GafferScene.PathFilter()
        planeFilter["paths"].setValue(IECore.StringVectorData(["/plane"]))

        assignment = GafferScene.ShaderAssignment()
        assignment["in"].setInput(plane["out"])
        assignment["filter"].setInput(planeFilter["out"])
        assignment["shader"].setInput(shader["out"])

        originalNetwork = assignment["out"].attributes("/plane")["surface"]
        self.assertEqual(len(originalNetwork), 1)

        textureShader = GafferSceneTest.TestShader("texture")

        tweaks = GafferScene.ShaderTweaks()
        tweaks["in"].setInput(assignment["out"])
        tweaks["filter"].setInput(planeFilter["out"])
        tweaks["shader"].setValue("surface")

        tweaks["tweaks"].addChild(
            GafferScene.TweakPlug("c", Gaffer.Color3fPlug()))
        tweaks["tweaks"][0]["value"].setInput(textureShader["out"])

        tweakedNetwork = tweaks["out"].attributes("/plane")["surface"]
        self.assertEqual(len(tweakedNetwork), 2)
        self.assertEqual(tweakedNetwork.input(("surface", "c")),
                         ("texture", ""))

        tweakedNetwork.removeShader("texture")
        self.assertEqual(tweakedNetwork, originalNetwork)

        textureShader["parameters"]["c"].setValue(imath.Color3f(1, 2, 3))
        tweakedNetwork = tweaks["out"].attributes("/plane")["surface"]
        self.assertEqual(
            tweakedNetwork.getShader("texture").parameters["c"].value,
            imath.Color3f(1, 2, 3))

        tweaks["tweaks"][0]["mode"].setValue(
            GafferScene.TweakPlug.Mode.Multiply)
        with self.assertRaisesRegexp(
                RuntimeError,
                "Mode must be \"Replace\" when inserting a connection"):
            tweaks["out"].attributes("/plane")
Пример #8
0
    def testShaderTypesInAttributes(self):

        surface = GafferSceneTest.TestShader("surface")
        surface["name"].setValue("testSurface")
        surface["type"].setValue("test:surface")
        surface["parameters"]["t"] = Gaffer.Color3fPlug()

        texture = GafferSceneTest.TestShader("texture")
        texture["name"].setValue("testTexture")
        texture["type"].setValue("test:shader")

        surface["parameters"]["t"].setInput(texture["out"])

        network = surface.attributes()["test:surface"]
        self.assertEqual(network[0].type, "test:shader")
        self.assertEqual(network[1].type, "test:surface")
Пример #9
0
	def testPromoteDynamicColorPlugAndSerialise( self ) :

		s = Gaffer.ScriptNode()
		s["n"] = Gaffer.Node()
		s["n"]["c"] = Gaffer.Color3fPlug( flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic )

		b = Gaffer.Box.create( s, Gaffer.StandardSet( [ s["n"] ] ) )
		b.promotePlug( b["n"]["c"] )

		ss = s.serialise()

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

		self.assertTrue( isinstance( s["Box"]["c"], Gaffer.Color3fPlug ) )
		self.assertTrue( s["Box"]["n"]["c"].getInput().isSame( s["Box"]["c"] ) )
Пример #10
0
	def testPromoteDynamicColorPlugAndSerialise( self ) :

		s = Gaffer.ScriptNode()
		s["b"] = Gaffer.Box()
		s["b"]["n"] = Gaffer.Node()
		s["b"]["n"]["c"] = Gaffer.Color3fPlug( flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic )

		Gaffer.PlugAlgo.promote( s["b"]["n"]["c"] )

		ss = s.serialise()

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

		self.assertTrue( isinstance( s["b"]["c"], Gaffer.Color3fPlug ) )
		self.assertTrue( s["b"]["n"]["c"].getInput().isSame( s["b"]["c"] ) )
Пример #11
0
    def testShaderTypesInState(self):

        surface = GafferSceneTest.TestShader("surface")
        surface["name"].setValue("testSurface")
        surface["type"].setValue("test:surface")
        surface["parameters"]["t"] = Gaffer.Color3fPlug()

        texture = GafferSceneTest.TestShader("texture")
        texture["name"].setValue("testTexture")
        texture["type"].setValue("test:shader")

        surface["parameters"]["t"].setInput(texture["out"])

        state = surface.state()
        self.assertEqual(state[0].type, "test:shader")
        self.assertEqual(state[1].type, "test:surface")
Пример #12
0
    def testReconnect(self):

        plane = GafferScene.Plane()
        shader = GafferSceneTest.TestShader("surface")
        shader["type"].setValue("surface")

        textureShader1 = GafferSceneTest.TestShader("texture1")
        shader["parameters"]["c"].setInput(textureShader1["out"])

        planeFilter = GafferScene.PathFilter()
        planeFilter["paths"].setValue(IECore.StringVectorData(["/plane"]))

        assignment = GafferScene.ShaderAssignment()
        assignment["in"].setInput(plane["out"])
        assignment["filter"].setInput(planeFilter["out"])
        assignment["shader"].setInput(shader["out"])

        originalNetwork = assignment["out"].attributes("/plane")["surface"]
        self.assertEqual(len(originalNetwork), 2)
        self.assertEqual(originalNetwork.input(("surface", "c")),
                         ("texture1", ""))

        textureShader2 = GafferSceneTest.TestShader("texture2")

        tweaks = GafferScene.ShaderTweaks()
        tweaks["in"].setInput(assignment["out"])
        tweaks["filter"].setInput(planeFilter["out"])
        tweaks["shader"].setValue("surface")

        tweaks["tweaks"].addChild(
            GafferScene.TweakPlug("c", Gaffer.Color3fPlug()))
        tweaks["tweaks"][0]["value"].setInput(textureShader2["out"])

        tweakedNetwork = tweaks["out"].attributes("/plane")["surface"]
        self.assertEqual(len(tweakedNetwork), 2)
        self.assertEqual(tweakedNetwork.input(("surface", "c")),
                         ("texture2", ""))

        textureShader2["enabled"].setValue(False)
        tweakedNetwork = tweaks["out"].attributes("/plane")["surface"]
        self.assertEqual(len(tweakedNetwork), 1)
        self.assertFalse(tweakedNetwork.input(("surface", "c")))

        textureShader2["enabled"].setValue(True)
        tweaks["tweaks"][0]["enabled"].setValue(False)
        self.assertEqual(tweaks["out"].attributes("/plane")["surface"],
                         originalNetwork)
Пример #13
0
    def testCommonAncestorType(self):

        s = Gaffer.ScriptNode()

        s["n"] = Gaffer.Node()
        s["n"]["user"]["p1"] = Gaffer.IntPlug()
        s["n"]["user"]["p2"] = Gaffer.Color3fPlug()

        self.assertEqual(
            s["n"]["user"]["p1"].commonAncestor(s["n"]["user"]["p2"]["r"]),
            s["n"]["user"])
        self.assertEqual(
            s["n"]["user"]["p1"].commonAncestor(s["n"]["user"]["p2"]["r"],
                                                Gaffer.Plug), s["n"]["user"])
        self.assertEqual(
            s["n"]["user"]["p1"].commonAncestor(s["n"]["user"]["p2"]["r"],
                                                Gaffer.Node), s["n"])
Пример #14
0
    def testPromoteCompoundPlugWithColorPlug(self):

        s = Gaffer.ScriptNode()

        s["b"] = Gaffer.Box()
        s["b"]["n"] = Gaffer.Node()
        s["b"]["n"]["user"]["p"] = Gaffer.Plug(flags=Gaffer.Plug.Flags.Default
                                               | Gaffer.Plug.Flags.Dynamic)
        s["b"]["n"]["user"]["p"]["c"] = Gaffer.Color3fPlug(
            flags=Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic)

        Gaffer.PlugAlgo.promote(s["b"]["n"]["user"]["p"])

        s2 = Gaffer.ScriptNode()
        s2.execute(s.serialise())

        self.assertEqual(len(s2["b"]["n"]["user"]["p"]["c"]), 3)
Пример #15
0
    def testPromoteColor(self):

        s = Gaffer.ScriptNode()
        s["b"] = Gaffer.Box()
        s["b"]["n"] = Gaffer.Node()
        s["b"]["n"]["c"] = Gaffer.Color3fPlug()
        s["b"]["n"]["c"].setValue(IECore.Color3f(1, 0, 1))

        self.assertTrue(Gaffer.PlugAlgo.canPromote(s["b"]["n"]["c"]))
        self.assertFalse(Gaffer.PlugAlgo.isPromoted(s["b"]["n"]["c"]))

        p = Gaffer.PlugAlgo.promote(s["b"]["n"]["c"])

        self.assertTrue(isinstance(p, Gaffer.Color3fPlug))
        self.assertTrue(s["b"]["n"]["c"].getInput().isSame(p))
        self.assertTrue(s["b"]["n"]["c"]["r"].getInput().isSame(p["r"]))
        self.assertTrue(s["b"]["n"]["c"]["g"].getInput().isSame(p["g"]))
        self.assertTrue(s["b"]["n"]["c"]["b"].getInput().isSame(p["b"]))
        self.assertEqual(p.getValue(), IECore.Color3f(1, 0, 1))
Пример #16
0
	def testPromoteColor( self ) :

		s = Gaffer.ScriptNode()
		s["n"] = Gaffer.Node()
		s["n"]["c"] = Gaffer.Color3fPlug()
		s["n"]["c"].setValue( IECore.Color3f( 1, 0, 1 ) )

		b = Gaffer.Box.create( s, Gaffer.StandardSet( [ s["n"] ] ) )

		self.assertTrue( b.canPromotePlug( b["n"]["c"] ) )
		self.assertFalse( b.plugIsPromoted( b["n"]["c"] ) )

		p = b.promotePlug( b["n"]["c"] )

		self.assertTrue( isinstance( p, Gaffer.Color3fPlug ) )
		self.assertTrue( b["n"]["c"].getInput().isSame( p ) )
		self.assertTrue( b["n"]["c"]["r"].getInput().isSame( p["r"] ) )
		self.assertTrue( b["n"]["c"]["g"].getInput().isSame( p["g"] ) )
		self.assertTrue( b["n"]["c"]["b"].getInput().isSame( p["b"] ) )
		self.assertEqual( p.getValue(), IECore.Color3f( 1, 0, 1 ) )
Пример #17
0
    def testReloadWithNestedOutputConnections(self):

        s = Gaffer.ScriptNode()

        s["b"] = Gaffer.Box()
        s["b"]["color"] = Gaffer.Color3fPlug(
            direction=Gaffer.Plug.Direction.Out,
            flags=Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic)
        s["b"].exportForReference(self.temporaryDirectory() + "/test.grf")

        s["a"] = GafferTest.AddNode()

        s["r"] = Gaffer.Reference()
        s["r"].load(self.temporaryDirectory() + "/test.grf")

        s["a"]["op1"].setInput(s["r"]["color"]["g"])

        s["r"].load(self.temporaryDirectory() + "/test.grf")

        self.assertTrue(s["a"]["op1"].getInput().isSame(s["r"]["color"]["g"]))
Пример #18
0
    def testMinimalPerf(self):

        constant = GafferImage.Constant()
        constant["format"].setValue(GafferImage.Format(4096, 4096))

        floatToColor = GafferOSL.OSLShader()
        floatToColor.loadShader("Conversion/FloatToColor")

        oslImage = GafferOSL.OSLImage()
        oslImage["in"].setInput(constant["out"])
        oslImage["channels"].addChild(
            Gaffer.NameValuePlug("", Gaffer.Color3fPlug("value"), True,
                                 "channel"))
        oslImage["channels"]["channel"]["value"].setInput(
            floatToColor["out"]["c"])

        GafferImage.ImageAlgo.image(constant["out"])

        # Run the fastest possible OSLImage on lots of tiles, to highlight any constant overhead
        with GafferTest.TestRunner.PerformanceScope():
            GafferImage.ImageAlgo.image(oslImage["out"])
Пример #19
0
	def testColorUnpromoting( self ) :

		s = Gaffer.ScriptNode()

		s["n"] = Gaffer.Node()
		s["n"]["c"] = Gaffer.Color3fPlug()

		b = Gaffer.Box.create( s, Gaffer.StandardSet( [ s["n"] ] ) )
		p = b.promotePlug( b["n"]["c"] )
		self.assertTrue( b.plugIsPromoted( b["n"]["c"] ) )
		self.assertTrue( b.plugIsPromoted( b["n"]["c"]["r"] ) )
		self.assertTrue( b.plugIsPromoted( b["n"]["c"]["g"] ) )
		self.assertTrue( b.plugIsPromoted( b["n"]["c"]["b"] ) )
		self.assertTrue( p.node().isSame( b ) )

		b.unpromotePlug( b["n"]["c"] )
		self.assertFalse( b.plugIsPromoted( b["n"]["c"] ) )
		self.assertFalse( b.plugIsPromoted( b["n"]["c"]["r"] ) )
		self.assertFalse( b.plugIsPromoted( b["n"]["c"]["g"] ) )
		self.assertFalse( b.plugIsPromoted( b["n"]["c"]["b"] ) )
		self.assertTrue( p.node() is None )
Пример #20
0
    def testColorUnpromoting(self):

        s = Gaffer.ScriptNode()

        s["b"] = Gaffer.Box()
        s["b"]["n"] = Gaffer.Node()
        s["b"]["n"]["c"] = Gaffer.Color3fPlug()

        p = Gaffer.PlugAlgo.promote(s["b"]["n"]["c"])
        self.assertTrue(Gaffer.PlugAlgo.isPromoted(s["b"]["n"]["c"]))
        self.assertTrue(Gaffer.PlugAlgo.isPromoted(s["b"]["n"]["c"]["r"]))
        self.assertTrue(Gaffer.PlugAlgo.isPromoted(s["b"]["n"]["c"]["g"]))
        self.assertTrue(Gaffer.PlugAlgo.isPromoted(s["b"]["n"]["c"]["b"]))
        self.assertTrue(p.node().isSame(s["b"]))

        Gaffer.PlugAlgo.unpromote(s["b"]["n"]["c"])
        self.assertFalse(Gaffer.PlugAlgo.isPromoted(s["b"]["n"]["c"]))
        self.assertFalse(Gaffer.PlugAlgo.isPromoted(s["b"]["n"]["c"]["r"]))
        self.assertFalse(Gaffer.PlugAlgo.isPromoted(s["b"]["n"]["c"]["g"]))
        self.assertFalse(Gaffer.PlugAlgo.isPromoted(s["b"]["n"]["c"]["b"]))
        self.assertTrue(p.node() is None)
Пример #21
0
	def testVectorAndColourOutputs( self ) :

		s = Gaffer.ScriptNode()

		s["n"] = Gaffer.Node()
		s["n"]["user"].addChild( Gaffer.V2fPlug( "v2f", flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic ) )
		s["n"]["user"].addChild( Gaffer.V2iPlug( "v2i", flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic ) )
		s["n"]["user"].addChild( Gaffer.V3fPlug( "v3f", flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic ) )
		s["n"]["user"].addChild( Gaffer.V3iPlug( "v3i", flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic ) )
		s["n"]["user"].addChild( Gaffer.Color3fPlug( "c3f", flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic ) )
		s["n"]["user"].addChild( Gaffer.Color4fPlug( "c4f", flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic ) )

		s["e"] = Gaffer.Expression()
		s["e"]["engine"].setValue( "python" )

		s["e"]["expression"].setValue(
			'import IECore;'
			'parent["n"]["user"]["v2f"] = IECore.V2f( 1, 2 );'
			'parent["n"]["user"]["v2i"] = IECore.V2i( 3, 4 );'
			'parent["n"]["user"]["v3f"] = IECore.V3f( 4, 5, 6 );'
			'parent["n"]["user"]["v3i"] = IECore.V3i( 6, 7, 8 );'
			'parent["n"]["user"]["c3f"] = IECore.Color3f( 9, 10, 11 );'
			'parent["n"]["user"]["c4f"] = IECore.Color4f( 12, 13, 14, 15 );'
		)

		def assertExpectedValues( script ) :

			self.assertEqual( script["n"]["user"]["v2f"].getValue(), IECore.V2f( 1, 2 ) )
			self.assertEqual( script["n"]["user"]["v2i"].getValue(), IECore.V2i( 3, 4 ) )
			self.assertEqual( script["n"]["user"]["v3f"].getValue(), IECore.V3f( 4, 5, 6 ) )
			self.assertEqual( script["n"]["user"]["v3i"].getValue(), IECore.V3i( 6, 7, 8 ) )
			self.assertEqual( script["n"]["user"]["c3f"].getValue(), IECore.Color3f( 9, 10, 11 ) )
			self.assertEqual( script["n"]["user"]["c4f"].getValue(), IECore.Color4f( 12, 13, 14, 15 ) )

		assertExpectedValues( s )

		s2 = Gaffer.ScriptNode()
		s2.execute( s.serialise() )

		assertExpectedValues( s2 )
Пример #22
0
	def testReloadWithNestedInputConnections( self ) :

		s = Gaffer.ScriptNode()

		s["b"] = Gaffer.Box()
		s["b"]["array"] = Gaffer.ArrayPlug( element = Gaffer.IntPlug(), flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic )
		s["b"]["color"] = Gaffer.Color3fPlug( flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic )
		s["b"].exportForReference( self.temporaryDirectory() + "/test.grf" )

		s["a"] = GafferTest.AddNode()

		s["r"] = Gaffer.Reference()
		s["r"].load( self.temporaryDirectory() + "/test.grf" )

		s["r"]["array"][0].setInput( s["a"]["sum"] )
		s["r"]["array"][1].setInput( s["a"]["sum"] )
		s["r"]["color"]["g"].setInput( s["a"]["sum"] )

		s["r"].load( self.temporaryDirectory() + "/test.grf" )

		self.assertTrue( s["r"]["array"][0].getInput().isSame( s["a"]["sum"] ) )
		self.assertTrue( s["r"]["array"][1].getInput().isSame( s["a"]["sum"] ) )
		self.assertTrue( s["r"]["color"]["g"].getInput().isSame( s["a"]["sum"] ) )
Пример #23
0
	def testDynamicPlugSerialisation( self ) :

		s1 = Gaffer.ScriptNode()

		s1["n1"] = GafferTest.AddNode()
		s1["n2"] = GafferTest.AddNode()
		s1["n1"]["dynamicPlug"] = Gaffer.IntPlug( flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic )
		s1["n1"]["dynamicPlug"].setInput( s1["n2"]["sum"] )
		s1["n1"]["dynamicPlug2"] = Gaffer.IntPlug( flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic )
		s1["n1"]["dynamicPlug2"].setValue( 100 )
		s1["n1"]["dynamicStringPlug"] = Gaffer.StringPlug( flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic )
		s1["n1"]["dynamicStringPlug"].setValue( "hiThere" )
		s1["n1"]["dynamicOutPlug"] = Gaffer.IntPlug( flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, direction=Gaffer.Plug.Direction.Out )
		s1["n1"]["dynamicColorOutPlug"] = Gaffer.Color3fPlug( flags = Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic, direction=Gaffer.Plug.Direction.Out )

		s2 = Gaffer.ScriptNode()
		s2.execute( s1.serialise() )

		self.assert_( s2["n1"]["dynamicPlug"].getInput().isSame( s2["n2"]["sum"] ) )
		self.assertEqual( s2["n1"]["dynamicPlug2"].getValue(), 100 )
		self.assertEqual( s2["n1"]["dynamicStringPlug"].getValue(), "hiThere" )
		self.failUnless( isinstance( s2["n1"]["dynamicOutPlug"], Gaffer.IntPlug ) )
		self.failUnless( isinstance( s2["n1"]["dynamicColorOutPlug"], Gaffer.Color3fPlug ) )
Пример #24
0
    def testCantPromoteReadOnlyPlug(self):

        s = Gaffer.ScriptNode()

        s["b"] = Gaffer.Box()
        s["b"]["n"] = Gaffer.Node()
        s["b"]["n"]["i"] = Gaffer.IntPlug()
        s["b"]["n"]["c"] = Gaffer.Color3fPlug()

        self.assertTrue(Gaffer.PlugAlgo.canPromote(s["b"]["n"]["i"]))
        self.assertTrue(Gaffer.PlugAlgo.canPromote(s["b"]["n"]["c"]))
        self.assertTrue(Gaffer.PlugAlgo.canPromote(s["b"]["n"]["c"]["r"]))

        s["b"]["n"]["i"].setFlags(Gaffer.Plug.Flags.ReadOnly, True)
        s["b"]["n"]["c"].setFlags(Gaffer.Plug.Flags.ReadOnly, True)
        s["b"]["n"]["c"]["r"].setFlags(Gaffer.Plug.Flags.ReadOnly, True)

        self.assertFalse(Gaffer.PlugAlgo.canPromote(s["b"]["n"]["i"]))
        self.assertFalse(Gaffer.PlugAlgo.canPromote(s["b"]["n"]["c"]))
        self.assertFalse(Gaffer.PlugAlgo.canPromote(s["b"]["n"]["c"]["r"]))

        self.assertRaises(RuntimeError, Gaffer.PlugAlgo.promote,
                          s["b"]["n"]["i"])
        self.assertRaises(RuntimeError, Gaffer.PlugAlgo.promote,
                          s["b"]["n"]["c"])
        self.assertRaises(RuntimeError, Gaffer.PlugAlgo.promote,
                          s["b"]["n"]["c"]["r"])

        k = s["b"].keys()
        uk = s["b"]["user"].keys()
        try:
            Gaffer.PlugAlgo.promote(s["b"]["n"]["i"])
        except Exception, e:
            self.assertTrue("Cannot promote" in str(e))
            self.assertTrue("read only" in str(e))
            self.assertEqual(s["b"].keys(), k)
            self.assertEqual(s["b"]["user"].keys(), uk)
Пример #25
0
    def testCantDoArithmeticOnConnection(self):

        plane = GafferScene.Plane()
        shader = GafferSceneTest.TestShader("surface")
        shader["type"].setValue("surface")

        textureShader = GafferSceneTest.TestShader("texture1")
        shader["parameters"]["c"].setInput(textureShader["out"])

        planeFilter = GafferScene.PathFilter()
        planeFilter["paths"].setValue(IECore.StringVectorData(["/plane"]))

        assignment = GafferScene.ShaderAssignment()
        assignment["in"].setInput(plane["out"])
        assignment["filter"].setInput(planeFilter["out"])
        assignment["shader"].setInput(shader["out"])

        tweaks = GafferScene.ShaderTweaks()
        tweaks["in"].setInput(assignment["out"])
        tweaks["filter"].setInput(planeFilter["out"])
        tweaks["shader"].setValue("surface")

        tweaks["tweaks"].addChild(
            GafferScene.TweakPlug("c", Gaffer.Color3fPlug()))

        for mode in GafferScene.TweakPlug.Mode.values:

            if mode == GafferScene.TweakPlug.Mode.Replace:
                continue

            tweaks["tweaks"][0]["mode"].setValue(mode)
            with self.assertRaisesRegexp(
                    RuntimeError,
                    "Mode must be \"Replace\" when a previous connection exists"
            ):
                tweaks["out"].attributes("/plane")
Пример #26
0
    def testBadCachePolicyHang(self):

        # Using the legacy cache policy for OSLImage.shadingPlug creates a hang due to tbb task stealing,
        # though it's a bit hard to actually demonstrate

        constant = GafferImage.Constant()
        constant["format"].setValue(GafferImage.Format(128, 128, 1.000))

        # Need a slow to compute OSL code in order to trigger hang
        mandelbrotCode = self.mandelbrotNode()

        # In order to trigger the hang, we need to mix threads which are stuck waiting for an expression which
        # uses the Standard policy with threads that are actually finishing, so that tbb tries to start up new
        # threads while we're waiting for the expression result.  To do this, we use the "var" context variable
        # to create two versions of this OSLCode
        mandelbrotCode["varExpression"] = Gaffer.Expression()
        mandelbrotCode["varExpression"].setExpression(
            'parent.parameters.iterations = 100000 + context( "var", 0 );',
            "OSL")

        oslImage = GafferOSL.OSLImage()
        oslImage["channels"].addChild(
            Gaffer.NameValuePlug(
                "",
                Gaffer.Color3fPlug(
                    "value",
                    defaultValue=imath.Color3f(1, 1, 1),
                    flags=Gaffer.Plug.Flags.Default
                    | Gaffer.Plug.Flags.Dynamic,
                ), True, "channel",
                Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic))
        oslImage["in"].setInput(constant["out"])
        oslImage["channels"]["channel"]["value"][0].setInput(
            mandelbrotCode["out"]["outFloat"])
        oslImage["channels"]["channel"]["value"][1].setInput(
            mandelbrotCode["out"]["outFloat"])
        oslImage["channels"]["channel"]["value"][2].setInput(
            mandelbrotCode["out"]["outFloat"])

        # This imageStats is use to create non-blocking slow calculations
        imageStats = GafferImage.ImageStats()
        imageStats["in"].setInput(oslImage["out"])
        imageStats["area"].setValue(
            imath.Box2i(imath.V2i(0, 0), imath.V2i(64, 64)))

        # This box does the non-blocking slow calculation, followed by a blocking slow calculation.
        # This ensures that tasks which do just the non-block calculation will start finishing while
        # the blocking slow calculation is still running, allowing tbb to try running more threads
        # on the blocking calcluation, realizing they can't run, and stealing tasks onto those threads
        # which can hit the Standard policy lock on the expression upstream and deadlock, unless the
        # OSLImage isolates its threads correctly
        expressionBox = Gaffer.Box()
        expressionBox.addChild(
            Gaffer.FloatVectorDataPlug("inChannelData",
                                       defaultValue=IECore.FloatVectorData(
                                           [])))
        expressionBox.addChild(Gaffer.FloatPlug("inStat"))
        expressionBox.addChild(
            Gaffer.FloatPlug("out", direction=Gaffer.Plug.Direction.Out))
        expressionBox["inChannelData"].setInput(oslImage["out"]["channelData"])
        expressionBox["inStat"].setInput(imageStats["average"]["r"])

        expressionBox["contextVariables"] = Gaffer.ContextVariables()
        expressionBox["contextVariables"].setup(
            Gaffer.FloatVectorDataPlug("in",
                                       defaultValue=IECore.FloatVectorData(
                                           [])))
        expressionBox["contextVariables"]["variables"].addChild(
            Gaffer.NameValuePlug("image:tileOrigin", Gaffer.V2iPlug("value"),
                                 True, "member1"))
        expressionBox["contextVariables"]["variables"].addChild(
            Gaffer.NameValuePlug("image:channelName",
                                 Gaffer.StringPlug("value", defaultValue='R'),
                                 True, "member2"))
        expressionBox["contextVariables"]["variables"].addChild(
            Gaffer.NameValuePlug("var", Gaffer.IntPlug("value",
                                                       defaultValue=1), True,
                                 "member3"))
        expressionBox["contextVariables"]["in"].setInput(
            expressionBox["inChannelData"])

        expressionBox["expression"] = Gaffer.Expression()
        expressionBox["expression"].setExpression(
            inspect.cleandoc("""
			d = parent["contextVariables"]["out"]
			parent["out"] = d[0] + parent["inStat"]
			"""))

        # Create a switch to mix which tasks perform the non-blocking or blocking calculation - we need a mixture
        # to trigger the hang
        switch = Gaffer.Switch()
        switch.setup(Gaffer.IntPlug(
            "in",
            defaultValue=0,
        ))
        switch["in"][0].setInput(expressionBox["out"])
        switch["in"][1].setInput(imageStats["average"]["r"])

        switch["switchExpression"] = Gaffer.Expression()
        switch["switchExpression"].setExpression(
            'parent.index = ( stoi( context( "testContext", "0" ) ) % 10 ) > 5;',
            "OSL")

        # In order to evaluate this expression a bunch of times at once with different values of "testContext",
        # we set up a simple scene that can be evaluated with GafferSceneTest.traversScene.
        # In theory, we could use a simple function that used a parallel_for to evaluate switch["out"], but for
        # some reason we don't entirely understand, this does not trigger the hang
        import GafferSceneTest
        import GafferScene

        sphere = GafferScene.Sphere()

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

        customAttributes = GafferScene.CustomAttributes()
        customAttributes["attributes"].addChild(
            Gaffer.NameValuePlug("foo", Gaffer.FloatPlug("value"), True,
                                 "member1"))
        customAttributes["attributes"]["member1"]["value"].setInput(
            switch["out"])
        customAttributes["in"].setInput(sphere["out"])
        customAttributes["filter"].setInput(pathFilter["out"])

        collectScenes = GafferScene.CollectScenes()
        collectScenes["in"].setInput(customAttributes["out"])
        collectScenes["rootNames"].setValue(
            IECore.StringVectorData([str(i) for i in range(1000)]))
        collectScenes["rootNameVariable"].setValue('testContext')

        # When OSLImage.shadingPlug is not correctly isolated, and grain size on ShadingEngine is smaller than the
        # image tile size, this fails about 50% of the time.  Running it 5 times makes the failure pretty consistent.
        for i in range(5):
            Gaffer.ValuePlug.clearCache()
            Gaffer.ValuePlug.clearHashCache()
            GafferSceneTest.traverseScene(collectScenes["out"])
Пример #27
0
    def testDefaultExpressionForSupportedPlugs(self):

        s = Gaffer.ScriptNode()

        s["n"] = Gaffer.Node()
        s["n"]["user"].addChild(
            Gaffer.IntPlug(flags=Gaffer.Plug.Flags.Default
                           | Gaffer.Plug.Flags.Dynamic))
        s["n"]["user"].addChild(
            Gaffer.FloatPlug(flags=Gaffer.Plug.Flags.Default
                             | Gaffer.Plug.Flags.Dynamic))
        s["n"]["user"].addChild(
            Gaffer.StringPlug(flags=Gaffer.Plug.Flags.Default
                              | Gaffer.Plug.Flags.Dynamic))
        s["n"]["user"].addChild(
            Gaffer.BoolPlug(flags=Gaffer.Plug.Flags.Default
                            | Gaffer.Plug.Flags.Dynamic))
        s["n"]["user"].addChild(
            Gaffer.V2fPlug(flags=Gaffer.Plug.Flags.Default
                           | Gaffer.Plug.Flags.Dynamic))
        s["n"]["user"].addChild(
            Gaffer.V2iPlug(flags=Gaffer.Plug.Flags.Default
                           | Gaffer.Plug.Flags.Dynamic))
        s["n"]["user"].addChild(
            Gaffer.V3fPlug(flags=Gaffer.Plug.Flags.Default
                           | Gaffer.Plug.Flags.Dynamic))
        s["n"]["user"].addChild(
            Gaffer.V3iPlug(flags=Gaffer.Plug.Flags.Default
                           | Gaffer.Plug.Flags.Dynamic))
        s["n"]["user"].addChild(
            Gaffer.Color3fPlug(flags=Gaffer.Plug.Flags.Default
                               | Gaffer.Plug.Flags.Dynamic))
        s["n"]["user"].addChild(
            Gaffer.Color4fPlug(flags=Gaffer.Plug.Flags.Default
                               | Gaffer.Plug.Flags.Dynamic))
        s["n"]["user"].addChild(
            Gaffer.Box2fPlug(flags=Gaffer.Plug.Flags.Default
                             | Gaffer.Plug.Flags.Dynamic))
        s["n"]["user"].addChild(
            Gaffer.Box2iPlug(flags=Gaffer.Plug.Flags.Default
                             | Gaffer.Plug.Flags.Dynamic))
        s["n"]["user"].addChild(
            Gaffer.Box3fPlug(flags=Gaffer.Plug.Flags.Default
                             | Gaffer.Plug.Flags.Dynamic))
        s["n"]["user"].addChild(
            Gaffer.Box3iPlug(flags=Gaffer.Plug.Flags.Default
                             | Gaffer.Plug.Flags.Dynamic))
        s["n"]["user"].addChild(
            Gaffer.IntVectorDataPlug(defaultValue=IECore.IntVectorData([0, 1]),
                                     flags=Gaffer.Plug.Flags.Default
                                     | Gaffer.Plug.Flags.Dynamic))
        s["n"]["user"].addChild(
            Gaffer.FloatVectorDataPlug(
                defaultValue=IECore.FloatVectorData([0, 1]),
                flags=Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic))
        s["n"]["user"].addChild(
            Gaffer.StringVectorDataPlug(
                defaultValue=IECore.StringVectorData(["a", "b"]),
                flags=Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic))
        s["n"]["user"].addChild(
            Gaffer.V3fVectorDataPlug(
                defaultValue=IECore.V3fVectorData([IECore.V3f(1)]),
                flags=Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic))

        s["e"] = Gaffer.Expression()

        for plug in s["n"]["user"]:

            value = plug.getValue()
            s["e"].setExpression(s["e"].defaultExpression(plug, "python"))
            self.assertTrue(plug.getInput().node().isSame(s["e"]))
            self.assertEqual(plug.getValue(), value)
Пример #28
0
    def colorSwitch(self):

        result = Gaffer.Switch()
        result.setup(Gaffer.Color3fPlug())

        return result
Пример #29
0
import Gaffer
import GafferOSL

import GafferUI

scriptWindow = GafferUI.ScriptWindow.acquire(script)

script["OSLCode"] = GafferOSL.OSLCode()
script.setFocus(script["OSLCode"])
oslEditor = GafferUI.NodeEditor.acquire(script["OSLCode"], floating=True)
GafferUI.WidgetAlgo.grab(widget=oslEditor, imagePath="images/blank.png")

script["OSLCode"]["parameters"]["width"] = Gaffer.FloatPlug(defaultValue=0.0)
script["OSLCode"]["parameters"]["width"].setValue(0.025)
script["OSLCode"]["out"]["stripes"] = Gaffer.Color3fPlug(
    direction=Gaffer.Plug.Direction.Out, defaultValue=imath.Color3f(0, 0, 0))
GafferUI.WidgetAlgo.grab(widget=oslEditor, imagePath="images/parameters.png")
oslEditor.parent().setVisible(False)

script["OSLCode"]["code"].setValue(
    "stripes = aastep( 0, sin( v * M_PI / width ) )")
viewer = scriptWindow.getLayout().editors(GafferUI.Viewer)[0]
# delay so it can render
t = time.time() + 3
while time.time() < t:
    GafferUI.EventLoop.waitForIdle(1)
GafferUI.WidgetAlgo.grab(widget=viewer,
                         imagePath="images/shaderBallStripes.png")

script["OSLCode"]["parameters"]["color1"] = Gaffer.Color3fPlug(
    defaultValue=imath.Color3f(0, 0, 0))
Пример #30
0
    def testMerging(self):

        allFilter = GafferScene.PathFilter()
        allFilter["paths"].setValue(IECore.StringVectorData(['/...']))

        plane = GafferScene.Plane()
        plane["divisions"].setValue(imath.V2i(20, 20))

        # Assign a basic gradient shader
        uvGradientCode = GafferOSL.OSLCode()
        uvGradientCode["out"].addChild(
            Gaffer.Color3fPlug("out", direction=Gaffer.Plug.Direction.Out))
        uvGradientCode["code"].setValue('out = color( u, v, 0.5 );')

        shaderAssignment = GafferScene.ShaderAssignment()
        shaderAssignment["in"].setInput(plane["out"])
        shaderAssignment["filter"].setInput(allFilter["out"])
        shaderAssignment["shader"].setInput(uvGradientCode["out"]["out"])

        # Set up a random id from 0 - 3 on each face

        randomCode = GafferOSL.OSLCode()
        randomCode["out"].addChild(
            Gaffer.IntPlug("randomId", direction=Gaffer.Plug.Direction.Out))
        randomCode["code"].setValue(
            'randomId = int(cellnoise( P * 100 ) * 4);')

        outInt = GafferOSL.OSLShader()
        outInt.loadShader("ObjectProcessing/OutInt")
        outInt["parameters"]["name"].setValue('randomId')
        outInt["parameters"]["value"].setInput(randomCode["out"]["randomId"])

        outObject = GafferOSL.OSLShader()
        outObject.loadShader("ObjectProcessing/OutObject")
        outObject["parameters"]["in0"].setInput(
            outInt["out"]["primitiveVariable"])

        oSLObject = GafferOSL.OSLObject()
        oSLObject["in"].setInput(shaderAssignment["out"])
        oSLObject["filter"].setInput(allFilter["out"])
        oSLObject["shader"].setInput(outObject["out"])
        oSLObject["interpolation"].setValue(2)

        # Create 4 meshes by picking each of the 4 ids

        deleteContextVariables = Gaffer.DeleteContextVariables()
        deleteContextVariables.setup(GafferScene.ScenePlug())
        deleteContextVariables["variables"].setValue('collect:rootName')
        deleteContextVariables["in"].setInput(oSLObject["out"])

        pickCode = GafferOSL.OSLCode()
        pickCode["parameters"].addChild(Gaffer.IntPlug("targetId"))
        pickCode["out"].addChild(
            Gaffer.IntPlug("cull", direction=Gaffer.Plug.Direction.Out))
        pickCode["code"].setValue(
            'int randomId; getattribute( "randomId", randomId ); cull = randomId != targetId;'
        )

        expression = Gaffer.Expression()
        pickCode.addChild(expression)
        expression.setExpression(
            'parent.parameters.targetId = stoi( context( "collect:rootName", "0" ) );',
            "OSL")

        outInt1 = GafferOSL.OSLShader()
        outInt1.loadShader("ObjectProcessing/OutInt")
        outInt1["parameters"]["name"].setValue('deleteFaces')
        outInt1["parameters"]["value"].setInput(pickCode["out"]["cull"])

        outObject1 = GafferOSL.OSLShader()
        outObject1.loadShader("ObjectProcessing/OutObject")
        outObject1["parameters"]["in0"].setInput(
            outInt1["out"]["primitiveVariable"])

        oSLObject1 = GafferOSL.OSLObject()
        oSLObject1["in"].setInput(deleteContextVariables["out"])
        oSLObject1["filter"].setInput(allFilter["out"])
        oSLObject1["shader"].setInput(outObject1["out"])
        oSLObject1["interpolation"].setValue(2)

        deleteFaces = GafferScene.DeleteFaces()
        deleteFaces["in"].setInput(oSLObject1["out"])
        deleteFaces["filter"].setInput(allFilter["out"])

        collectScenes = GafferScene.CollectScenes()
        collectScenes["in"].setInput(deleteFaces["out"])
        collectScenes["rootNames"].setValue(
            IECore.StringVectorData(['0', '1', '2', '3']))
        collectScenes["sourceRoot"].setValue('/plane')

        # First variant:  bake everything, covering the whole 1001 UDIM

        customAttributes1 = GafferScene.CustomAttributes()
        customAttributes1["attributes"].addMember(
            'bake:fileName',
            IECore.StringData(
                '${bakeDirectory}/complete/<AOV>/<AOV>.<UDIM>.exr'))
        customAttributes1["in"].setInput(collectScenes["out"])

        # Second vaiant: bake just 2 of the 4 meshes, leaving lots of holes that will need filling
        pruneFilter = GafferScene.PathFilter()
        pruneFilter["paths"].setValue(IECore.StringVectorData(['/2', '/3']))

        prune = GafferScene.Prune()
        prune["in"].setInput(collectScenes["out"])
        prune["filter"].setInput(pruneFilter["out"])

        customAttributes2 = GafferScene.CustomAttributes()
        customAttributes2["attributes"].addMember(
            'bake:fileName',
            IECore.StringData(
                '${bakeDirectory}/incomplete/<AOV>/<AOV>.<UDIM>.exr'))
        customAttributes2["in"].setInput(prune["out"])

        # Third variant: bake everything, but with one mesh at a higher resolution

        customAttributes3 = GafferScene.CustomAttributes()
        customAttributes3["attributes"].addMember(
            'bake:fileName',
            IECore.StringData(
                '${bakeDirectory}/mismatch/<AOV>/<AOV>.<UDIM>.exr'))
        customAttributes3["in"].setInput(collectScenes["out"])

        pathFilter2 = GafferScene.PathFilter()
        pathFilter2["paths"].setValue(IECore.StringVectorData(['/2']))

        customAttributes = GafferScene.CustomAttributes()
        customAttributes["attributes"].addMember('bake:resolution',
                                                 IECore.IntData(200))
        customAttributes["filter"].setInput(pathFilter2["out"])
        customAttributes["in"].setInput(customAttributes3["out"])

        # Merge the 3 variants
        mergeGroup = GafferScene.Group()
        mergeGroup["in"][-1].setInput(customAttributes["out"])
        mergeGroup["in"][-1].setInput(customAttributes1["out"])
        mergeGroup["in"][-1].setInput(customAttributes2["out"])

        arnoldTextureBake = GafferArnold.ArnoldTextureBake()
        arnoldTextureBake["in"].setInput(mergeGroup["out"])
        arnoldTextureBake["filter"].setInput(allFilter["out"])
        arnoldTextureBake["bakeDirectory"].setValue(self.temporaryDirectory() +
                                                    '/bakeMerge/')
        arnoldTextureBake["defaultResolution"].setValue(128)

        # We want to check the intermediate results
        arnoldTextureBake["cleanupIntermediateFiles"].setValue(False)

        # Dispatch the bake
        script = Gaffer.ScriptNode()
        script.addChild(arnoldTextureBake)
        dispatcher = GafferDispatch.LocalDispatcher()
        dispatcher["jobsDirectory"].setValue(self.temporaryDirectory())
        dispatcher.dispatch([arnoldTextureBake])

        # Check results
        imageReader = GafferImage.ImageReader()

        outLayer = GafferOSL.OSLShader()
        outLayer.loadShader("ImageProcessing/OutLayer")
        outLayer["parameters"]["layerColor"].setInput(
            uvGradientCode["out"]["out"])

        outImage = GafferOSL.OSLShader()
        outImage.loadShader("ImageProcessing/OutImage")
        outImage["parameters"]["in0"].setInput(outLayer["out"]["layer"])
        oSLImage = GafferOSL.OSLImage()
        oSLImage["in"].setInput(imageReader["out"])
        oSLImage["shader"].setInput(outImage["out"])

        merge3 = GafferImage.Merge()
        merge3["in"]["in0"].setInput(oSLImage["out"])
        merge3["in"]["in1"].setInput(imageReader["out"])
        merge3["operation"].setValue(10)

        edgeDetect = self.SimpleEdgeDetect()
        edgeDetect["in"].setInput(imageReader["out"])

        edgeStats = GafferImage.ImageStats()
        edgeStats["in"].setInput(edgeDetect["out"])

        refDiffStats = GafferImage.ImageStats()
        refDiffStats["in"].setInput(merge3["out"])

        oneLayerReader = GafferImage.ImageReader()

        grade = GafferImage.Grade()
        grade["in"].setInput(oneLayerReader["out"])
        grade["channels"].setValue('[A]')
        grade["blackPoint"].setValue(imath.Color4f(0, 0, 0, 0.999899983))

        copyChannels = GafferImage.CopyChannels()
        copyChannels["in"]["in0"].setInput(merge3["out"])
        copyChannels["in"]["in1"].setInput(grade["out"])
        copyChannels["channels"].setValue('[A]')

        premultiply = GafferImage.Premultiply()
        premultiply["in"].setInput(copyChannels["out"])

        refDiffCoveredStats = GafferImage.ImageStats()
        refDiffCoveredStats["in"].setInput(premultiply["out"])

        # We are testing 3 different cases:
        # complete : Should be an exact match.
        # incomplete : Expect some mild variance of slopes and some error, because we have to
        #              reconstruct a lot of missing data.
        # mismatch : We should get a larger image, sized to the highest override on any mesh.
        #            Match won't be as perfect, because we're combining source images at
        #            different resolutions
        for name, expectedSize, maxEdge, maxRefDiff, maxMaskedDiff in [
            ("complete", 128, 0.01, 0.000001, 0.000001),
            ("incomplete", 128, 0.05, 0.15, 0.000001),
            ("mismatch", 200, 0.01, 0.01, 0.01)
        ]:
            imageReader["fileName"].setValue(self.temporaryDirectory() +
                                             "/bakeMerge/" + name +
                                             "/beauty/beauty.1001.tx")
            oneLayerReader["fileName"].setValue(self.temporaryDirectory() +
                                                "/bakeMerge/" + name +
                                                "/beauty/beauty.1001.exr")

            self.assertEqual(imageReader["out"]["format"].getValue().width(),
                             expectedSize)
            self.assertEqual(imageReader["out"]["format"].getValue().height(),
                             expectedSize)

            edgeStats["area"].setValue(
                imath.Box2i(imath.V2i(1), imath.V2i(expectedSize - 1)))
            refDiffStats["area"].setValue(
                imath.Box2i(imath.V2i(1), imath.V2i(expectedSize - 1)))
            refDiffCoveredStats["area"].setValue(
                imath.Box2i(imath.V2i(0), imath.V2i(expectedSize)))

            # Blue channel is constant, so everything should line up perfectly
            self.assertEqual(0, edgeStats["max"].getValue()[2])
            self.assertEqual(0, refDiffStats["max"].getValue()[2])
            self.assertEqual(0, refDiffCoveredStats["max"].getValue()[2])

            for i in range(2):

                # Make sure we've got actual data, by checking that we have some error ( we're not expecting
                # to perfectly reconstruct the gradient when the input is incomplete )
                self.assertGreater(edgeStats["max"].getValue()[i], 0.005)
                if name == "incomplete":
                    self.assertGreater(edgeStats["max"].getValue()[i], 0.03)
                    self.assertGreater(refDiffStats["max"].getValue()[i], 0.06)

                self.assertLess(edgeStats["max"].getValue()[i], maxEdge)
                self.assertLess(refDiffStats["max"].getValue()[i], maxRefDiff)
                self.assertLess(refDiffCoveredStats["max"].getValue()[i],
                                maxMaskedDiff)