Exemple #1
0
    def test(self):

        p = Gaffer.CompoundDataPlug()

        m1 = Gaffer.NameValuePlug("a", IECore.IntData(10), "member1")
        p.addChild(m1)
        self.failUnless(isinstance(m1, Gaffer.ValuePlug))
        self.assertEqual(m1.getName(), "member1")
        self.assertEqual(m1["name"].getValue(), "a")
        self.assertEqual(m1["value"].getValue(), 10)
        self.failIf("enabled" in m1)

        d, n = p.memberDataAndName(m1)
        self.assertEqual(d, IECore.IntData(10))
        self.assertEqual(n, "a")

        m1["name"].setValue("b")
        d, n = p.memberDataAndName(m1)
        self.assertEqual(d, IECore.IntData(10))
        self.assertEqual(n, "b")

        m2 = Gaffer.NameValuePlug("c", IECore.FloatData(.5), "member1")
        p.addChild(m2)
        self.failUnless(isinstance(m2, Gaffer.ValuePlug))
        self.assertEqual(m2.getName(), "member2")
        self.assertEqual(m2["name"].getValue(), "c")
        self.assertEqual(m2["value"].getValue(), .5)
        self.failIf("enabled" in m2)

        d, n = p.memberDataAndName(m2)
        self.assertEqual(d, IECore.FloatData(.5))
        self.assertEqual(n, "c")

        m3 = Gaffer.NameValuePlug("o", IECore.StringData("--"), True, name="m")
        p.addChild(m3)
        self.failUnless(isinstance(m3, Gaffer.ValuePlug))
        self.assertEqual(m3.getName(), "m")
        self.assertEqual(m3["name"].getValue(), "o")
        self.assertEqual(m3["value"].getValue(), "--")
        self.failUnless("enabled" in m3)
        self.assertEqual(m3["enabled"].getValue(), True)

        d, n = p.memberDataAndName(m3)
        self.assertEqual(d, IECore.StringData("--"))
        self.assertEqual(n, "o")

        m3["enabled"].setValue(False)
        d, n = p.memberDataAndName(m3)
        self.assertEqual(d, None)
        self.assertEqual(n, "")

        # test if creating a plug from data that has a geometric
        # interpretation specified transfers that interpretation to the plug
        m4 = Gaffer.NameValuePlug(
            "vector",
            IECore.V3fData(imath.V3f(0),
                           IECore.GeometricData.Interpretation.Vector),
            True,
            name="vector")
        p.addChild(m4)
        self.assertEqual(m4["value"].interpretation(),
                         IECore.GeometricData.Interpretation.Vector)
    def testNameValuePlugs(self):

        s = Gaffer.Spreadsheet()
        s["rows"].addColumn(
            Gaffer.NameValuePlug("a", Gaffer.IntPlug(defaultValue=1)))
        s["rows"].addColumn(
            Gaffer.NameValuePlug("b", Gaffer.IntPlug(defaultValue=2)))
        row = s["rows"].addRow()

        def assertNVPEqual(plug, name, enabled, value):
            self.assertEqual(plug["name"].getValue(), name)
            self.assertEqual(plug["value"].getValue(), value)
            if enabled is not None:
                self.assertEqual(plug["enabled"].getValue(), enabled)

        assertNVPEqual(row["cells"][0]["value"], "a", None, 1)
        assertNVPEqual(row["cells"][1]["value"], "b", None, 2)

        data = _ClipboardAlgo.valueMatrix([[row["cells"][1]]])
        _ClipboardAlgo.pasteCells(data, [[row["cells"][0]]], 0)

        assertNVPEqual(row["cells"][0]["value"], "a", None, 2)
        assertNVPEqual(row["cells"][1]["value"], "b", None, 2)

        s["rows"].addColumn(
            Gaffer.NameValuePlug("c", Gaffer.IntPlug(defaultValue=3), True))
        s["rows"].addColumn(
            Gaffer.NameValuePlug("d", Gaffer.IntPlug(defaultValue=4), False))

        assertNVPEqual(row["cells"][2]["value"], "c", True, 3)
        assertNVPEqual(row["cells"][3]["value"], "d", False, 4)

        data = _ClipboardAlgo.valueMatrix([[row["cells"][3]]])
        _ClipboardAlgo.pasteCells(data, [[row["cells"][2]]], 0)

        assertNVPEqual(row["cells"][2]["value"], "c", False, 4)
        assertNVPEqual(row["cells"][3]["value"], "d", False, 4)

        # Test cross-pasting between plugs with/without enabled plugs

        data = _ClipboardAlgo.valueMatrix([[row["cells"][3]]])
        _ClipboardAlgo.pasteCells(data, [[row["cells"][0]]], 0)

        assertNVPEqual(row["cells"][0]["value"], "a", None, 4)

        data = _ClipboardAlgo.valueMatrix([[row["cells"][1]]])
        _ClipboardAlgo.pasteCells(data, [[row["cells"][2]]], 0)

        assertNVPEqual(row["cells"][2]["value"], "c", False, 2)

        # Test cross-pasting between ValuePlugs and NameValuePlugs

        s["rows"].addColumn(Gaffer.IntPlug(defaultValue=5))

        data = _ClipboardAlgo.valueMatrix([[row["cells"][4]]])
        _ClipboardAlgo.pasteCells(data, [[row["cells"][1], row["cells"][2]]],
                                  0)

        assertNVPEqual(row["cells"][1]["value"], "b", None, 5)
        assertNVPEqual(row["cells"][2]["value"], "c", False, 5)

        row["cells"][2]["value"]["value"].setValue(3)

        data = _ClipboardAlgo.valueMatrix([[row["cells"][2]]])
        _ClipboardAlgo.pasteCells(data, [[row["cells"][4]]], 0)

        self.assertEqual(row["cells"][4]["value"].getValue(), 3)
Exemple #3
0
    def __init__(self, name="ArnoldTextureBake"):

        GafferDispatch.TaskNode.__init__(self, name)

        self["in"] = GafferScene.ScenePlug()
        self["filter"] = GafferScene.FilterPlug()
        self["bakeDirectory"] = Gaffer.StringPlug("bakeDirectory",
                                                  defaultValue="")
        self["defaultFileName"] = Gaffer.StringPlug(
            "defaultFileName",
            defaultValue="${bakeDirectory}/<AOV>/<AOV>.<UDIM>.exr")
        self["defaultResolution"] = Gaffer.IntPlug("defaultResolution",
                                                   defaultValue=512)
        self["uvSet"] = Gaffer.StringPlug("uvSet", defaultValue='uv')
        self["normalOffset"] = Gaffer.FloatPlug("offset", defaultValue=0.1)
        self["aovs"] = Gaffer.StringPlug("aovs", defaultValue='beauty:RGBA')
        self["tasks"] = Gaffer.IntPlug("tasks", defaultValue=1)
        self["cleanupIntermediateFiles"] = Gaffer.BoolPlug(
            "cleanupIntermediateFiles", defaultValue=True)

        self["applyMedianFilter"] = Gaffer.BoolPlug("applyMedianFilter",
                                                    Gaffer.Plug.Direction.In,
                                                    False)
        self["medianRadius"] = Gaffer.IntPlug("medianRadius",
                                              Gaffer.Plug.Direction.In, 1)

        # Set up connection to preTasks beforehand
        self["__PreTaskList"] = GafferDispatch.TaskList()
        self["__PreTaskList"]["preTasks"].setInput(self["preTasks"])

        self["__CleanPreTasks"] = Gaffer.DeleteContextVariables()
        self["__CleanPreTasks"].setup(GafferDispatch.TaskNode.TaskPlug())
        self["__CleanPreTasks"]["in"].setInput(self["__PreTaskList"]["task"])
        self["__CleanPreTasks"]["variables"].setValue(
            "BAKE_WEDGE:index BAKE_WEDGE:value_unused")

        # First, setup python commands which will dispatch a chunk of a render or image tasks as
        # immediate execution once they reach the farm - this allows us to run multiple tasks in
        # one farm process.
        self["__RenderDispatcher"] = GafferDispatch.PythonCommand()
        self["__RenderDispatcher"]["preTasks"][0].setInput(
            self["__CleanPreTasks"]["out"])
        self["__RenderDispatcher"]["command"].setValue(
            inspect.cleandoc("""
			import GafferDispatch
			# We need to access frame and "BAKE_WEDGE:index" so that the hash of render varies with the wedge index,
			# so we might as well print what we're doing
			IECore.msg( IECore.MessageHandler.Level.Info, "Bake Process", "Dispatching render task index %i for frame %i" % ( context["BAKE_WEDGE:index"], context.getFrame() ) )
			d = GafferDispatch.LocalDispatcher()
			d.dispatch( [ self.parent()["__bakeDirectoryContext"] ] )
			"""))
        self["__ImageDispatcher"] = GafferDispatch.PythonCommand()
        self["__ImageDispatcher"]["preTasks"][0].setInput(
            self["__RenderDispatcher"]["task"])
        self["__ImageDispatcher"]["command"].setValue(
            inspect.cleandoc("""
			import GafferDispatch
			# We need to access frame and "BAKE_WEDGE:index" so that the hash of render varies with the wedge index,
			# so we might as well print what we're doing
			IECore.msg( IECore.MessageHandler.Level.Info, "Bake Process", "Dispatching image task index %i for frame %i" % ( context["BAKE_WEDGE:index"], context.getFrame() ) )
			d = GafferDispatch.LocalDispatcher()
			d.dispatch( [ self.parent()["__CleanUpSwitch"] ] )
			"""))
        # Connect through the dispatch settings to the render dispatcher
        # ( The image dispatcher runs much quicker, and should be OK using default settings )
        self["__RenderDispatcher"]["dispatcher"].setInput(self["dispatcher"])

        # Set up variables so the dispatcher knows that the render and image dispatches depend on
        # the file paths ( in case they are varying in a wedge )
        for redispatch in [
                self["__RenderDispatcher"], self["__ImageDispatcher"]
        ]:
            redispatch["variables"].addChild(
                Gaffer.NameValuePlug("bakeDirectory", "", "bakeDirectoryVar"))
            redispatch["variables"].addChild(
                Gaffer.NameValuePlug("defaultFileName", "",
                                     "defaultFileNameVar"))

        # Connect the variables via an expression so that get expanded ( this also means that
        # if you put #### in a filename you will get per frame tasks, because the hash will depend
        # on frame number )
        self["__DispatchVariableExpression"] = Gaffer.Expression()
        self["__DispatchVariableExpression"].setExpression(
            inspect.cleandoc("""
			parent["__RenderDispatcher"]["variables"]["bakeDirectoryVar"]["value"] = parent["bakeDirectory"]
			parent["__RenderDispatcher"]["variables"]["defaultFileNameVar"]["value"] = parent["defaultFileName"]
			parent["__ImageDispatcher"]["variables"]["bakeDirectoryVar"]["value"] = parent["bakeDirectory"]
			parent["__ImageDispatcher"]["variables"]["defaultFileNameVar"]["value"] = parent["defaultFileName"]
			"""), "python")

        # Wedge based on tasks into the overall number of tasks to run.  Note that we don't know how
        # much work each task will do until we actually run the render tasks ( this is when scene
        # expansion happens ).  Because we must group all tasks that write to the same file into the
        # same task batch, if tasks is a large number, some tasks batches could end up empty
        self["__MainWedge"] = GafferDispatch.Wedge()
        self["__MainWedge"]["preTasks"][0].setInput(
            self["__ImageDispatcher"]["task"])
        self["__MainWedge"]["variable"].setValue("BAKE_WEDGE:value_unused")
        self["__MainWedge"]["indexVariable"].setValue("BAKE_WEDGE:index")
        self["__MainWedge"]["mode"].setValue(1)
        self["__MainWedge"]["intMin"].setValue(1)
        self["__MainWedge"]["intMax"].setInput(self["tasks"])

        self["task"].setInput(self["__MainWedge"]["task"])
        self["task"].setFlags(Gaffer.Plug.Flags.Serialisable, False)

        # Now set up the render tasks.  This involves doing the actual rendering, and triggering the
        # output of the file list index file.

        # First get rid of options from the upstream scene that could mess up the bake
        self["__OptionOverrides"] = GafferScene.StandardOptions()
        self["__OptionOverrides"]["in"].setInput(self["in"])
        self["__OptionOverrides"]["options"]["pixelAspectRatio"][
            "enabled"].setValue(True)
        self["__OptionOverrides"]["options"]["resolutionMultiplier"][
            "enabled"].setValue(True)
        self["__OptionOverrides"]["options"]["overscan"]["enabled"].setValue(
            True)
        self["__OptionOverrides"]["options"]["renderCropWindow"][
            "enabled"].setValue(True)
        self["__OptionOverrides"]["options"]["cameraBlur"]["enabled"].setValue(
            True)
        self["__OptionOverrides"]["options"]["transformBlur"][
            "enabled"].setValue(True)
        self["__OptionOverrides"]["options"]["deformationBlur"][
            "enabled"].setValue(True)

        self["__CameraSetup"] = self.__CameraSetup()
        self["__CameraSetup"]["in"].setInput(self["__OptionOverrides"]["out"])
        self["__CameraSetup"]["filter"].setInput(self["filter"])
        self["__CameraSetup"]["defaultFileName"].setInput(
            self["defaultFileName"])
        self["__CameraSetup"]["defaultResolution"].setInput(
            self["defaultResolution"])
        self["__CameraSetup"]["uvSet"].setInput(self["uvSet"])
        self["__CameraSetup"]["aovs"].setInput(self["aovs"])
        self["__CameraSetup"]["normalOffset"].setInput(self["normalOffset"])
        self["__CameraSetup"]["tasks"].setInput(self["tasks"])

        self["__Expression"] = Gaffer.Expression()
        self["__Expression"].setExpression(
            'parent["__CameraSetup"]["taskIndex"] = context.get( "BAKE_WEDGE:index", 0 )',
            "python")

        self["__indexFilePath"] = Gaffer.StringPlug()
        self["__indexFilePath"].setFlags(Gaffer.Plug.Flags.Serialisable, False)
        self["__IndexFileExpression"] = Gaffer.Expression()
        self["__IndexFileExpression"].setExpression(
            inspect.cleandoc("""
			import os
			parent["__indexFilePath"] = os.path.join( parent["bakeDirectory"], "BAKE_FILE_INDEX_" +
				str( context.get("BAKE_WEDGE:index", 0 ) ) + ".####.txt" )
			"""), "python")

        self["__outputIndexCommand"] = Gaffer.PythonCommand()
        self["__outputIndexCommand"]["variables"].addChild(
            Gaffer.NameValuePlug("bakeDirectory", Gaffer.StringPlug()))
        self["__outputIndexCommand"]["variables"][0]["value"].setInput(
            self["bakeDirectory"])
        self["__outputIndexCommand"]["variables"].addChild(
            Gaffer.NameValuePlug("indexFilePath", Gaffer.StringPlug()))
        self["__outputIndexCommand"]["variables"][1]["value"].setInput(
            self["__indexFilePath"])
        self["__outputIndexCommand"]["variables"].addChild(
            Gaffer.NameValuePlug(
                "fileList",
                Gaffer.StringVectorDataPlug(
                    defaultValue=IECore.StringVectorData())))
        self["__outputIndexCommand"]["variables"][2]["value"].setInput(
            self["__CameraSetup"]["renderFileList"])
        self["__outputIndexCommand"]["command"].setValue(
            inspect.cleandoc("""
			import os
			import distutils.dir_util

			# Ensure path exists
			distutils.dir_util.mkpath( variables["bakeDirectory"] )

			f = open( variables["indexFilePath"], "w" )

			f.writelines( [ i + "\\n" for i in sorted( variables["fileList"] ) ] )
			f.close()
			IECore.msg( IECore.MessageHandler.Level.Info, "Bake Process", "Wrote list of bake files for this chunk to " + variables["indexFilePath"] )
			"""))

        self["__arnoldRender"] = GafferArnold.ArnoldRender()
        self["__arnoldRender"]["preTasks"][0].setInput(
            self["__outputIndexCommand"]["task"])
        self["__arnoldRender"]["dispatcher"]["immediate"].setValue(True)
        self["__arnoldRender"]["in"].setInput(self["__CameraSetup"]["out"])

        self["__bakeDirectoryContext"] = GafferDispatch.TaskContextVariables()
        self["__bakeDirectoryContext"]["variables"].addChild(
            Gaffer.NameValuePlug("bakeDirectory", Gaffer.StringPlug()))
        self["__bakeDirectoryContext"]["variables"][0]["value"].setInput(
            self["bakeDirectory"])
        self["__bakeDirectoryContext"]["preTasks"][0].setInput(
            self["__arnoldRender"]["task"])

        # Now set up the image tasks.  This involves merging all layers for a UDIM, filling in the
        # background, writing out this image, converting it to tx, and optionally deleting all the exrs

        self["__imageList"] = Gaffer.CompoundObjectPlug(
            "__imageList", defaultValue=IECore.CompoundObject())
        self["__imageList"].setFlags(Gaffer.Plug.Flags.Serialisable, False)

        self["__ImageReader"] = GafferImage.ImageReader()
        self["__CurInputFileExpression"] = Gaffer.Expression()
        self["__CurInputFileExpression"].setExpression(
            inspect.cleandoc("""
			l = parent["__imageList"]
			outFile = context["wedge:outFile"]
			loopIndex = context[ "loop:index" ]
			parent["__ImageReader"]["fileName"] = l[outFile][ loopIndex ]
			"""), "python")

        # Find the max size of any input file
        self["__SizeLoop"] = Gaffer.LoopComputeNode()
        self["__SizeLoop"].setup(Gaffer.IntPlug())

        self["__SizeMaxExpression"] = Gaffer.Expression()
        self["__SizeMaxExpression"].setExpression(
            inspect.cleandoc("""
			f = parent["__ImageReader"]["out"]["format"]
			parent["__SizeLoop"]["next"] = max( f.width(), parent["__SizeLoop"]["previous"] )
			"""), "python")

        # Loop over all input files for this output file, and merge them all together
        self["__ImageLoop"] = Gaffer.LoopComputeNode()
        self["__ImageLoop"].setup(GafferImage.ImagePlug())

        self["__NumInputsForCurOutputExpression"] = Gaffer.Expression()
        self["__NumInputsForCurOutputExpression"].setExpression(
            inspect.cleandoc("""
			l = parent["__imageList"]
			outFile = context["wedge:outFile"]
			numInputs = len( l[outFile] )
			parent["__ImageLoop"]["iterations"] = numInputs
			parent["__SizeLoop"]["iterations"] = numInputs
			"""), "python")

        self["__Resize"] = GafferImage.Resize()
        self["__Resize"]["format"]["displayWindow"]["min"].setValue(
            imath.V2i(0, 0))
        self["__Resize"]['format']["displayWindow"]["max"]["x"].setInput(
            self["__SizeLoop"]["out"])
        self["__Resize"]['format']["displayWindow"]["max"]["y"].setInput(
            self["__SizeLoop"]["out"])
        self["__Resize"]['in'].setInput(self["__ImageReader"]["out"])

        self["__Merge"] = GafferImage.Merge()
        self["__Merge"]["in"][0].setInput(self["__Resize"]["out"])
        self["__Merge"]["in"][1].setInput(self["__ImageLoop"]["previous"])
        self["__Merge"]["operation"].setValue(GafferImage.Merge.Operation.Add)

        self["__ImageLoop"]["next"].setInput(self["__Merge"]["out"])

        # Write out the combined image, so we can immediately read it back in
        # This is just because we're doing enough image processing that we
        # could saturate the cache, and Gaffer wouldn't know that this is
        # the important result to keep
        self["__ImageIntermediateWriter"] = GafferImage.ImageWriter()
        self["__ImageIntermediateWriter"]["in"].setInput(
            self["__ImageLoop"]["out"])

        self["__ImageIntermediateReader"] = GafferImage.ImageReader()

        # Now that we've merged everything together, we can use a BleedFill to fill in the background,
        # so that texture filtering across the edges will pull in colors that are at least reasonable.
        self["__BleedFill"] = GafferImage.BleedFill()
        self["__BleedFill"]["in"].setInput(
            self["__ImageIntermediateReader"]["out"])

        self["__Median"] = GafferImage.Median()
        self["__Median"]["in"].setInput(self["__BleedFill"]["out"])
        self["__Median"]["enabled"].setInput(self["applyMedianFilter"])
        self["__Median"]["radius"]["x"].setInput(self["medianRadius"])
        self["__Median"]["radius"]["y"].setInput(self["medianRadius"])

        # Write out the result
        self["__ImageWriter"] = GafferImage.ImageWriter()
        self["__ImageWriter"]["in"].setInput(self["__Median"]["out"])
        self["__ImageWriter"]["preTasks"][0].setInput(
            self["__ImageIntermediateWriter"]["task"])

        # Convert result to texture
        self["__ConvertCommand"] = GafferDispatch.SystemCommand()
        # We shouldn't need a sub-shell and this prevents S.I.P on the Mac from
        # blocking the dylibs loaded by maketx.
        self["__ConvertCommand"]["shell"].setValue(False)
        self["__ConvertCommand"]["substitutions"].addChild(
            Gaffer.NameValuePlug("inFile", IECore.StringData(), "member1"))
        self["__ConvertCommand"]["substitutions"].addChild(
            Gaffer.NameValuePlug("outFile", IECore.StringData(), "member1"))
        self["__ConvertCommand"]["preTasks"][0].setInput(
            self["__ImageWriter"]["task"])
        self["__ConvertCommand"]["command"].setValue(
            'maketx --wrap clamp {inFile} -o {outFile}')

        self["__CommandSetupExpression"] = Gaffer.Expression()
        self["__CommandSetupExpression"].setExpression(
            inspect.cleandoc("""

			outFileBase = context["wedge:outFile"]
			intermediateExr = outFileBase + ".intermediate.exr"
			parent["__ImageIntermediateWriter"]["fileName"] = intermediateExr
			parent["__ImageIntermediateReader"]["fileName"] = intermediateExr
			tmpExr = outFileBase + ".tmp.exr"
			parent["__ImageWriter"]["fileName"] = tmpExr
			parent["__ConvertCommand"]["substitutions"]["member1"]["value"] = tmpExr
			parent["__ConvertCommand"]["substitutions"]["member2"]["value"] = outFileBase + ".tx"
			"""), "python")

        self["__ImageWedge"] = GafferDispatch.Wedge()
        self["__ImageWedge"]["preTasks"][0].setInput(
            self["__ConvertCommand"]["task"])
        self["__ImageWedge"]["variable"].setValue('wedge:outFile')
        self["__ImageWedge"]["indexVariable"].setValue('wedge:outFileIndex')
        self["__ImageWedge"]["mode"].setValue(int(
            Gaffer.Wedge.Mode.StringList))

        self["__CleanUpCommand"] = GafferDispatch.PythonCommand()
        self["__CleanUpCommand"]["preTasks"][0].setInput(
            self["__ImageWedge"]["task"])
        self["__CleanUpCommand"]["variables"].addChild(
            Gaffer.NameValuePlug(
                "filesToDelete",
                Gaffer.StringVectorDataPlug(
                    defaultValue=IECore.StringVectorData()), "member1"))
        self["__CleanUpCommand"]["command"].setValue(
            inspect.cleandoc("""
			import os
			for tmpFile in variables["filesToDelete"]:
				os.remove( tmpFile )
			"""))

        self["__CleanUpExpression"] = Gaffer.Expression()
        self["__CleanUpExpression"].setExpression(
            inspect.cleandoc("""

			imageList = parent["__imageList"]

			toDelete = []
			for outFileBase, inputExrs in imageList.items():
				tmpExr = outFileBase + ".tmp.exr"
				intermediateExr = outFileBase + ".intermediate.exr"
				toDelete.extend( inputExrs )
				toDelete.append( tmpExr )
				toDelete.append( intermediateExr )
			toDelete.append( parent["__indexFilePath"] )

			parent["__CleanUpCommand"]["variables"]["member1"]["value"] = IECore.StringVectorData( toDelete )
			"""), "python")

        self["__CleanUpSwitch"] = GafferDispatch.TaskSwitch()
        self["__CleanUpSwitch"]["preTasks"][0].setInput(
            self["__ImageWedge"]["task"])
        self["__CleanUpSwitch"]["preTasks"][1].setInput(
            self["__CleanUpCommand"]["task"])
        self["__CleanUpSwitch"]["index"].setInput(
            self["cleanupIntermediateFiles"])

        # Set up the list of input image files to process, and the corresponding list of
        # output files to wedge over
        self["__ImageSetupExpression"] = Gaffer.Expression()
        self["__ImageSetupExpression"].setExpression(
            inspect.cleandoc("""
			f = open( parent["__indexFilePath"], "r" )

			fileList = f.read().splitlines()
			fileDict = {}
			for i in fileList:
				rootName = i.rsplit( ".exr", 1 )[0]
				if rootName in fileDict:
					fileDict[ rootName ].append( i )
				else:
					fileDict[ rootName ] = IECore.StringVectorData( [i] )
			parent["__imageList"] = IECore.CompoundObject( fileDict )

			parent["__ImageWedge"]["strings"] = IECore.StringVectorData( fileDict.keys() )
			"""), "python")
Exemple #4
0
 def testBasicRepr(self):
     p = Gaffer.NameValuePlug("key", IECore.StringData("value"))
     self.assertEqual(
         repr(p),
         'Gaffer.NameValuePlug( "key", Gaffer.StringPlug( "value", defaultValue = \'value\', ), "NameValuePlug" )'
     )
    def test(self):

        # Make a few input scenes

        script = Gaffer.ScriptNode()

        script["Cube"] = GafferScene.Cube("Cube")
        script["Group"] = GafferScene.Group("Group")
        script["Group"]["in"][0].setInput(script["Cube"]["out"])
        script["Group"]["transform"]["translate"].setValue(imath.V3f(30))
        script["PathFilter"] = GafferScene.PathFilter("PathFilter")
        script["PathFilter"]["paths"].setValue(
            IECore.StringVectorData(['/group/cube']))
        script["Transform"] = GafferScene.Transform("Transform")
        script["Transform"]["in"].setInput(script["Group"]["out"])
        script["Transform"]["filter"].setInput(script["PathFilter"]["out"])
        script["CustomAttributes"] = GafferScene.CustomAttributes(
            "CustomAttributes")
        script["CustomAttributes"]["in"].setInput(script["Transform"]["out"])
        script["CustomAttributes"]["filter"].setInput(
            script["PathFilter"]["out"])
        script['CustomAttributes']['attributes'].addChild(
            Gaffer.NameValuePlug("existingAttr", IECore.StringData("test")))
        script["CollectTransforms"] = GafferScene.CollectTransforms(
            "CollectTransforms")
        script["CollectTransforms"]["in"].setInput(
            script["CustomAttributes"]["out"])
        script["CollectTransforms"]["filter"].setInput(
            script["PathFilter"]["out"])
        script["Expression1"] = Gaffer.Expression("Expression1")
        script["Expression1"].setExpression(
            """
s = context.get( "collect:transformName", "attr0" )
i = int( s[4] )
parent["Transform"]["transform"]["translate"] = imath.V3f( i )
""", "python")

        ref = IECore.CompoundObject()
        ref["existingAttr"] = IECore.StringData("test")

        self.assertEqual(
            script["CollectTransforms"]["out"].attributes("/group/cube"), ref)

        script["CollectTransforms"]["attributes"].setValue(
            IECore.StringVectorData(['attr1', 'attr2']))

        ref["attr1"] = IECore.M44fData(imath.M44f().translate(imath.V3f(1)))
        ref["attr2"] = IECore.M44fData(imath.M44f().translate(imath.V3f(2)))
        self.assertEqual(
            script["CollectTransforms"]["out"].attributes("/group/cube"), ref)

        # Switch to writing custom variable, which expression doesn't use, so we don't get
        # special transforms
        script["CollectTransforms"]["attributeContextVariable"].setValue(
            "collect:customVar")

        ref["attr1"] = IECore.M44fData(imath.M44f().translate(imath.V3f(0)))
        ref["attr2"] = IECore.M44fData(imath.M44f().translate(imath.V3f(0)))
        self.assertEqual(
            script["CollectTransforms"]["out"].attributes("/group/cube"), ref)

        # Test requireVariation
        script["CollectTransforms"]["requireVariation"].setValue(True)
        del ref["attr1"]
        del ref["attr2"]
        self.assertEqual(
            script["CollectTransforms"]["out"].attributes("/group/cube"), ref)

        # Test reading custom variable
        script["Expression1"].setExpression(
            """
s =  context.get( "collect:customVar", "attr0" )
i = int( s[4] )
parent["Transform"]["transform"]["translate"] = imath.V3f( i )
""", "python")

        ref["attr1"] = IECore.M44fData(imath.M44f().translate(imath.V3f(1)))
        ref["attr2"] = IECore.M44fData(imath.M44f().translate(imath.V3f(2)))
        self.assertEqual(
            script["CollectTransforms"]["out"].attributes("/group/cube"), ref)

        # Test space
        script["CollectTransforms"]["space"].setValue(
            GafferScene.Transform.Space.World)
        ref["attr1"] = IECore.M44fData(imath.M44f().translate(imath.V3f(31)))
        ref["attr2"] = IECore.M44fData(imath.M44f().translate(imath.V3f(32)))
        self.assertEqual(
            script["CollectTransforms"]["out"].attributes("/group/cube"), ref)

        script["CollectTransforms"]["attributeContextVariable"].setValue(
            "collect:bogus")
        del ref["attr1"]
        del ref["attr2"]
        self.assertEqual(
            script["CollectTransforms"]["out"].attributes("/group/cube"), ref)

        script["CollectTransforms"]["requireVariation"].setValue(False)
        ref["attr1"] = IECore.M44fData(imath.M44f().translate(imath.V3f(30)))
        ref["attr2"] = IECore.M44fData(imath.M44f().translate(imath.V3f(30)))
        self.assertEqual(
            script["CollectTransforms"]["out"].attributes("/group/cube"), ref)

        script["CollectTransforms"]["space"].setValue(
            GafferScene.Transform.Space.Local)

        # Test overwriting existing attribute
        script["Expression1"].setExpression("", "python")
        script["CollectTransforms"]["requireVariation"].setValue(False)
        script["CollectTransforms"]["attributes"].setValue(
            IECore.StringVectorData(['existingAttr']))
        ref = IECore.CompoundObject()
        ref["existingAttr"] = IECore.M44fData(imath.M44f().translate(
            imath.V3f(0)))
        self.assertEqual(
            script["CollectTransforms"]["out"].attributes("/group/cube"), ref)

        # Test naughtily pulling directly on the "transforms" plug
        self.assertEqual(script["CollectTransforms"]["transforms"].getValue(),
                         IECore.CompoundObject())

        context = Gaffer.Context()
        context.set("scene:path",
                    IECore.InternedStringVectorData(["group", "cube"]))
        with context:
            self.assertEqual(
                script["CollectTransforms"]["transforms"].getValue(), ref)
Exemple #6
0
    def testDeep(self):
        # Simple network to swap channels
        inLayer = GafferOSL.OSLShader()
        inLayer.loadShader("ImageProcessing/InLayer")

        colorToFloat = GafferOSL.OSLShader()
        colorToFloat.loadShader("Conversion/ColorToFloat")
        colorToFloat["parameters"]["c"].setInput(inLayer["out"]["layerColor"])

        floatToColor = GafferOSL.OSLShader()
        floatToColor.loadShader("Conversion/FloatToColor")
        floatToColor["parameters"]["r"].setInput(colorToFloat["out"]["b"])
        floatToColor["parameters"]["g"].setInput(colorToFloat["out"]["r"])
        floatToColor["parameters"]["b"].setInput(colorToFloat["out"]["g"])

        # Read in a deep image
        imageReader = GafferImage.ImageReader()
        imageReader["fileName"].setValue(self.representativeDeepImagePath)

        # Try running OSLImage on deep image, then flattening
        oslImageDeep = GafferOSL.OSLImage()
        oslImageDeep["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))
        oslImageDeep["in"].setInput(imageReader["out"])
        oslImageDeep["channels"]["channel"]["value"].setInput(
            floatToColor["out"]["c"])

        postFlatten = GafferImage.DeepToFlat()
        postFlatten["in"].setInput(oslImageDeep["out"])

        # Try running OSLImage on already flattened image
        preFlatten = GafferImage.DeepToFlat()
        preFlatten["in"].setInput(imageReader["out"])

        oslImageFlat = GafferOSL.OSLImage()
        oslImageFlat["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))
        oslImageFlat["in"].setInput(preFlatten["out"])
        oslImageFlat["channels"]["channel"]["value"].setInput(
            floatToColor["out"]["c"])

        # Results should match
        self.assertImagesEqual(postFlatten["out"], oslImageFlat["out"])

        # Also test reading from UV
        shaderGlobals = GafferOSL.OSLShader("Globals")
        shaderGlobals.loadShader("Utility/Globals")

        uvToColor = GafferOSL.OSLShader()
        uvToColor.loadShader("Conversion/FloatToColor")
        uvToColor["parameters"]["r"].setInput(shaderGlobals["out"]["globalU"])
        uvToColor["parameters"]["g"].setInput(shaderGlobals["out"]["globalV"])

        inAlpha = GafferOSL.OSLShader()
        inAlpha.loadShader("ImageProcessing/InChannel")
        inAlpha["parameters"]["channelName"].setValue('A')

        multiplyAlpha = GafferOSL.OSLShader()
        multiplyAlpha.loadShader("Maths/MultiplyColor")
        multiplyAlpha["parameters"]["a"].setInput(uvToColor["out"]["c"])
        multiplyAlpha["parameters"]["b"]["r"].setInput(
            inAlpha["out"]["channelValue"])
        multiplyAlpha["parameters"]["b"]["g"].setInput(
            inAlpha["out"]["channelValue"])
        multiplyAlpha["parameters"]["b"]["b"].setInput(
            inAlpha["out"]["channelValue"])

        oslImageDeep["channels"]["channel"]["value"].setInput(
            multiplyAlpha["out"]["out"])

        outImage = GafferImage.ImageAlgo.image(postFlatten["out"])
        size = outImage.dataWindow.size() + imath.V2i(1)
        i = 0
        for y in range(size.y):
            for x in range(size.x):
                self.assertAlmostEqual(outImage["R"][i],
                                       (x + 0.5) / size.x * outImage["A"][i],
                                       places=5)
                self.assertAlmostEqual(outImage["G"][i], (size.y - y - 0.5) /
                                       size.y * outImage["A"][i],
                                       places=5)
                i += 1
Exemple #7
0
    def test(self):

        plane = GafferScene.Plane()

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

        deleteOptions = GafferScene.DeleteOptions()
        deleteOptions["in"].setInput(options["out"])

        # test that by default the scene is passed through

        self.assertScenesEqual(plane["out"], deleteOptions["out"])
        self.assertSceneHashesEqual(plane["out"],
                                    deleteOptions["out"],
                                    checks=self.allSceneChecks - {"globals"})

        # test that we can delete options

        options["options"].addChild(
            Gaffer.NameValuePlug("test1",
                                 1,
                                 flags=Gaffer.Plug.Flags.Default
                                 | Gaffer.Plug.Flags.Dynamic))
        options["options"].addChild(
            Gaffer.NameValuePlug("test2",
                                 2,
                                 flags=Gaffer.Plug.Flags.Default
                                 | Gaffer.Plug.Flags.Dynamic))
        options["options"].addChild(
            Gaffer.NameValuePlug("test3",
                                 3,
                                 flags=Gaffer.Plug.Flags.Default
                                 | Gaffer.Plug.Flags.Dynamic))

        g = deleteOptions["out"]["globals"].getValue()

        self.assertEqual(g["option:test1"], IECore.IntData(1))
        self.assertEqual(g["option:test2"], IECore.IntData(2))
        self.assertEqual(g["option:test3"], IECore.IntData(3))

        deleteOptions["names"].setValue("test1 test2")

        g = deleteOptions["out"]["globals"].getValue()

        self.assertEqual(g["option:test3"], IECore.IntData(3))
        self.assertFalse("option:test1" in g)
        self.assertFalse("option:test2" in g)

        deleteOptions["names"].setValue("test*")

        g = deleteOptions["out"]["globals"].getValue()

        self.assertFalse("option:test1" in g)
        self.assertFalse("option:test2" in g)
        self.assertFalse("option:test3" in g)

        # test dirty propagation

        cs = GafferTest.CapturingSlot(deleteOptions.plugDirtiedSignal())

        deleteOptions["names"].setValue("")
        self.assertTrue(deleteOptions["out"]["globals"] in set(e[0]
                                                               for e in cs))

        del cs[:]

        deleteOptions["invertNames"].setValue(True)
        self.assertTrue(deleteOptions["out"]["globals"] in set(e[0]
                                                               for e in cs))
Exemple #8
0
	def testVectorData( self ) :

		p = Gaffer.CompoundDataPlug()

		m1 = Gaffer.NameValuePlug( "a", IECore.FloatVectorData( [ 1, 2, 3 ] ) )
		p.addChild( m1 )
		self.assertIsInstance( m1, Gaffer.ValuePlug )

		d, n = p.memberDataAndName( m1 )
		self.assertEqual( d, IECore.FloatVectorData( [ 1, 2, 3 ] ) )
		self.assertEqual( n, "a" )

		m2 = Gaffer.NameValuePlug( "b", IECore.IntVectorData( [ 1, 2, 3 ] ) )
		p.addChild( m2 )
		self.assertIsInstance( m2, Gaffer.ValuePlug )

		d, n = p.memberDataAndName( m2 )
		self.assertEqual( d, IECore.IntVectorData( [ 1, 2, 3 ] ) )
		self.assertEqual( n, "b" )

		m3 = Gaffer.NameValuePlug( "c", IECore.StringVectorData( [ "1", "2", "3" ] ) )
		p.addChild( m3 )
		self.assertIsInstance( m3, Gaffer.ValuePlug )

		d, n = p.memberDataAndName( m3 )
		self.assertEqual( d, IECore.StringVectorData( [ "1", "2", "3" ] ) )
		self.assertEqual( n, "c" )

		m4 = Gaffer.NameValuePlug( "d", IECore.V3fVectorData( [ imath.V3f( x ) for x in range( 1, 5 ) ] ) )
		p.addChild( m4 )
		self.assertIsInstance( m4, Gaffer.ValuePlug )

		d, n = p.memberDataAndName( m4 )
		self.assertEqual( d, IECore.V3fVectorData( [ imath.V3f( x ) for x in range( 1, 5 ) ] ) )
		self.assertEqual( n, "d" )

		m5 = Gaffer.NameValuePlug( "e", IECore.Color3fVectorData( [ imath.Color3f( x ) for x in range( 1, 5 ) ] ) )
		p.addChild( m5 )
		self.assertIsInstance( m5, Gaffer.ValuePlug )

		d, n = p.memberDataAndName( m5 )
		self.assertEqual( d, IECore.Color3fVectorData( [ imath.Color3f( x ) for x in range( 1, 5 ) ] ) )
		self.assertEqual( n, "e" )

		m6 = Gaffer.NameValuePlug( "f", IECore.M44fVectorData( [ imath.M44f() * x for x in range( 1, 5 ) ] ) )
		p.addChild( m6 )
		self.assertIsInstance( m6, Gaffer.ValuePlug )

		d, n = p.memberDataAndName( m6 )
		self.assertEqual( d, IECore.M44fVectorData( [ imath.M44f() * x for x in range( 1, 5 ) ] ) )
		self.assertEqual( n, "f" )

		m7 = Gaffer.NameValuePlug( "g", IECore.V2iVectorData( [ imath.V2i( x ) for x in range( 1, 5 ) ] ) )
		p.addChild( m7 )
		self.assertIsInstance( m7, Gaffer.ValuePlug )

		d, n = p.memberDataAndName( m7 )
		self.assertEqual( d, IECore.V2iVectorData( [ imath.V2i( x ) for x in range( 1, 5 ) ] ) )
		self.assertEqual( n, "g" )

		m8 = Gaffer.NameValuePlug( "h", IECore.M33fVectorData( [ imath.M33f() * x for x in range( 1, 5 ) ] ) )
		p.addChild( m8 )
		self.assertIsInstance( m8, Gaffer.ValuePlug )

		d, n = p.memberDataAndName( m8 )
		self.assertEqual( d, IECore.M33fVectorData( [ imath.M33f() * x for x in range( 1, 5 ) ] ) )
		self.assertEqual( n, "h" )
Exemple #9
0
    def testAttributes(self):

        p = GafferScene.Plane()

        a = GafferScene.CustomAttributes()
        a["attributes"].addChild(Gaffer.NameValuePlug("a", 42.5))
        a["attributes"].addChild(Gaffer.NameValuePlug("b", 12))
        a["attributes"].addChild(Gaffer.NameValuePlug("c", True))
        a["attributes"].addChild(Gaffer.NameValuePlug("d", "blah"))
        a["attributes"].addChild(
            Gaffer.NameValuePlug("e", imath.V3f(0.1, 0.2, 0.3)))
        a["attributes"].addChild(Gaffer.NameValuePlug("f", imath.V2f(0.4,
                                                                     0.5)))
        a["attributes"].addChild(
            Gaffer.NameValuePlug("g", imath.Color3f(0.6, 0.7, 0.8)))
        a["attributes"].addChild(Gaffer.NameValuePlug("h", imath.M44f(3)))
        # There's no Color4f type in OSL, so We can't currently get the 4th component, but we can
        # get the first 3
        a["attributes"].addChild(
            Gaffer.NameValuePlug("i", imath.Color4f(0.6, 0.7, 0.8, 0.9)))

        a["in"].setInput(p["out"])

        o = GafferOSL.OSLObject()
        o["in"].setInput(p["out"])
        o["in"].setInput(a["out"])

        # shading network to output attributes as formatted string.

        inPoint = GafferOSL.OSLShader()
        inPoint.loadShader("ObjectProcessing/InPoint")

        code = GafferOSL.OSLCode()
        code["out"].addChild(
            Gaffer.StringPlug("testString",
                              direction=Gaffer.Plug.Direction.Out))

        o["primitiveVariables"].addChild(Gaffer.NameValuePlug(
            "testString", ""))
        o["primitiveVariables"][0]["value"].setInput(code["out"]["testString"])

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

        a["filter"].setInput(f["out"])
        o["filter"].setInput(f["out"])

        code["code"].setValue(
            inspect.cleandoc("""
			float a = -1;
			getattribute( "a", a );
			float ax = -1;
			getattribute( "ax", ax );
			int b = -1;
			getattribute( "b", b );
			int c = -1;
			getattribute( "c", c );
			string d = "";
			getattribute( "d", d );
			vector e = -1;
			getattribute( "e", e );
			vector f = -1;
			getattribute( "f", f );
			color g = -1;
			getattribute( "g", g );
			matrix h = -1;
			getattribute( "h", h );
			color i = -1;
			getattribute( "i", i );
			testString = format( "TEST STRING : <%.2f><%.2f><%i><%i><%s><%.2f><%.2f><%.2f><%.2f %.2f %.2f %.2f><%.2f>", a, ax, b, c, d, e, f, g, h[0][0], h[0][1], h[1][0], h[1][1], i );
			"""))

        self.assertEqual(
            o["out"].object("/plane")["testString"].data[0],
            "TEST STRING : <-1.00><-1.00><-1><-1><><-1.00 -1.00 -1.00><-1.00 -1.00 -1.00><-1.00 -1.00 -1.00><-1.00 0.00 0.00 -1.00><-1.00 -1.00 -1.00>"
        )
        o["useAttributes"].setValue(True)
        self.assertEqual(
            o["out"].object("/plane")["testString"].data[0],
            "TEST STRING : <42.50><-1.00><12><1><blah><0.10 0.20 0.30><0.40 0.50 0.00><0.60 0.70 0.80><3.00 3.00 3.00 3.00><0.60 0.70 0.80>"
        )

        # Try some bogus attributes
        code["code"].setValue(
            inspect.cleandoc("""
			string badAttribute = "NOT FOUND";
			getattribute( "badAttribute", badAttribute );
			testString = badAttribute;
			"""))

        a["attributes"].addChild(
            Gaffer.NameValuePlug("badAttribute",
                                 imath.Box2f(imath.V2f(-0.5), imath.V2f(0.5))))

        # Check that bad attribute isn't found
        self.assertEqual(o["out"].object("/plane")["testString"].data[0],
                         "NOT FOUND")

        while a["attributes"].children():
            del a["attributes"][0]
        a["attributes"].addChild(
            Gaffer.NameValuePlug("badAttribute",
                                 IECore.FloatVectorData([0, 1, 2])))

        self.assertEqual(o["out"].object("/plane")["testString"].data[0],
                         "NOT FOUND")

        # Try something that isn't even data
        code["code"].setValue(
            inspect.cleandoc("""
			string badAttribute = "NOT FOUND";
			getattribute( "osl:surface", badAttribute );
			testString = badAttribute;
			"""))
        c = GafferOSL.OSLShader()
        c.loadShader("Surface/Constant")
        s = GafferScene.ShaderAssignment()
        s["shader"].setInput(c["out"])
        s["filter"].setInput(f["out"])
        s["in"].setInput(p["out"])
        o["in"].setInput(s["out"])

        self.assertEqual(o["out"].object("/plane")["testString"].data[0],
                         "NOT FOUND")
Exemple #10
0
    def testDirectoryCreation(self):

        s = Gaffer.ScriptNode()
        s["variables"].addChild(
            Gaffer.NameValuePlug(
                "renderDirectory",
                self.temporaryDirectory() + "/renderTests",
                Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic))
        s["variables"].addChild(
            Gaffer.NameValuePlug("appleseedDirectory",
                                 self.temporaryDirectory() + "/appleseedTests",
                                 flags=Gaffer.Plug.Flags.Default
                                 | Gaffer.Plug.Flags.Dynamic))

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

        s["outputs"] = GafferScene.Outputs()
        s["outputs"]["in"].setInput(s["plane"]["out"])
        s["outputs"].addOutput(
            "beauty",
            IECoreScene.Output("$renderDirectory/test.####.exr", "exr", "rgba",
                               {}))

        s["render"] = GafferAppleseed.AppleseedRender()
        s["render"]["in"].setInput(s["outputs"]["out"])
        s["render"]["fileName"].setValue(
            "$appleseedDirectory/test.####.appleseed")
        s["render"]["mode"].setValue(s["render"].Mode.SceneDescriptionMode)

        self.assertFalse(
            os.path.exists(self.temporaryDirectory() + "/renderTests"))
        self.assertFalse(
            os.path.exists(self.temporaryDirectory() + "/appleseedTests"))
        self.assertFalse(
            os.path.exists(self.temporaryDirectory() +
                           "/appleseedTests/test.0001.appleseed"))
        self.assertFalse(os.path.exists(self.__scriptFileName))

        s["fileName"].setValue(self.__scriptFileName)
        s.save()

        with s.context():
            s["render"]["task"].execute()

        self.assertTrue(
            os.path.exists(self.temporaryDirectory() + "/renderTests"))
        self.assertTrue(
            os.path.exists(self.temporaryDirectory() + "/appleseedTests"))
        self.assertTrue(
            os.path.exists(self.temporaryDirectory() +
                           "/appleseedTests/test.0001.appleseed"))
        self.assertTrue(os.path.exists(self.__scriptFileName))

        # check it can cope with everything already existing

        with s.context():
            s["render"]["task"].execute()

        self.assertTrue(
            os.path.exists(self.temporaryDirectory() + "/renderTests"))
        self.assertTrue(
            os.path.exists(self.temporaryDirectory() + "/appleseedTests"))
        self.assertTrue(
            os.path.exists(self.temporaryDirectory() +
                           "/appleseedTests/test.0001.appleseed"))
	def testMissingChannels( self ) :

		# Create some messy data
		representativeImage = GafferImage.ImageReader()
		representativeImage["fileName"].setValue( self.representativeImagePath )

		offset = GafferImage.Offset()
		offset["in"].setInput( representativeImage["out"] )
		offset["offset"].setValue( imath.V2i( 29, 9 ) )

		deepMerge = GafferImage.DeepMerge()
		deepMerge["in"][0].setInput( representativeImage["out"] )
		deepMerge["in"][1].setInput( offset["out"] )

		referenceFlatten = GafferImage.DeepState()
		referenceFlatten["in"].setInput( deepMerge["out"] )
		referenceFlatten["deepState"].setValue( GafferImage.DeepState.TargetState.Flat )

		deleteChannels = GafferImage.DeleteChannels()
		deleteChannels["in"].setInput( deepMerge["out"] )

		self.__assertDeepStateProcessing( deleteChannels["out"], referenceFlatten["out"], [ 0, 0, 0, 0 ], [ 0, 0, 0, 0 ], 100, 0.45 )

		# Having no ZBack should be equivalent to having ZBack = Z
		deleteChannels["channels"].setValue( "ZBack" )

		referenceNoZBack = GafferImage.Shuffle()
		referenceNoZBack["in"].setInput( deepMerge["out"] )
		referenceNoZBack["channels"].addChild( referenceNoZBack.ChannelPlug( "ZBack", "Z" ) )

		referenceFlatten["in"].setInput( referenceNoZBack["out"] )

		self.__assertDeepStateProcessing( deleteChannels["out"], referenceFlatten["out"], [ 0, 0, 0, 0 ], [ 0, 0, 0, 0 ], 100, 0.45 )

		# Removing A results in all samples just getting summed.
		deleteChannels["channels"].setValue( "A" )

		referenceNoAlphaA = GafferImage.DeleteChannels()
		referenceNoAlphaA["in"].setInput( representativeImage["out"] )
		referenceNoAlphaA["channels"].setValue( "A" )

		referenceFlattenA = GafferImage.DeepState()
		referenceFlattenA["in"].setInput( referenceNoAlphaA["out"] )
		referenceFlattenA["deepState"].setValue( GafferImage.DeepState.TargetState.Flat )

		referenceNoAlphaB = GafferImage.DeleteChannels()
		referenceNoAlphaB["in"].setInput( offset["out"] )
		referenceNoAlphaB["channels"].setValue( "A" )

		referenceFlattenB = GafferImage.DeepState()
		referenceFlattenB["in"].setInput( referenceNoAlphaB["out"] )
		referenceFlattenB["deepState"].setValue( GafferImage.DeepState.TargetState.Flat )

		referenceSum = GafferImage.Merge()
		referenceSum['operation'].setValue( GafferImage.Merge.Operation.Add )
		referenceSum['in'][0].setInput( referenceFlattenA["out"] )
		referenceSum['in'][1].setInput( referenceFlattenB["out"] )

		self.__assertDeepStateProcessing( deleteChannels["out"], referenceSum["out"], [ 3e-6, 3e-6, 3e-6, 10 ], [ 2e-8, 2e-8, 2e-8, 10 ], 0, 0 )

		deleteChannels["channels"].setValue( "A ZBack" )

		self.__assertDeepStateProcessing( deleteChannels["out"], referenceSum["out"], [ 3e-6, 3e-6, 3e-6, 10 ], [ 2e-8, 2e-8, 2e-8, 10 ], 0, 0 )

		deleteChannels["channels"].setValue( "A Z ZBack" )

		self.__assertDeepStateProcessing( deleteChannels["out"], referenceSum["out"], [ 3e-6, 3e-6, 3e-6, 10 ], [ 2e-8, 2e-8, 2e-8, 10 ], 0, 0 )

		# Having no Z should be equivalent to having all the samples composited in their current order
		deleteChannels["channels"].setValue( "Z ZBack" )

		try:
			import GafferOSL
		except:
			raise unittest.SkipTest( "Could not load GafferOSL, skipping DeepState missing alpha test" )

		outZIndexCode = GafferOSL.OSLCode( "OSLCode" )
		outZIndexCode["out"].addChild( Gaffer.FloatPlug( "output1", direction = Gaffer.Plug.Direction.Out ) )
		outZIndexCode["code"].setValue( 'output1 = P[2];' )

		replaceDepths = GafferOSL.OSLImage( "OSLImage" )
		replaceDepths["in"].setInput( deepMerge["out"] )
		replaceDepths["channels"].addChild( Gaffer.NameValuePlug( "Z", Gaffer.FloatPlug( "value" ), True ) )
		replaceDepths["channels"].addChild( Gaffer.NameValuePlug( "ZBack", Gaffer.FloatPlug( "value" ), True ) )
		replaceDepths["channels"][0]["value"].setInput( outZIndexCode["out"]["output1"] )
		replaceDepths["channels"][1]["value"].setInput( outZIndexCode["out"]["output1"] )

		referenceFlatten["in"].setInput( replaceDepths["out"] )

		self.__assertDeepStateProcessing( deleteChannels["out"], referenceFlatten["out"], [ 0, 0, 0, 10 ], [ 0, 0, 0, 10 ], 100, 0.45 )

		deleteChannels["channels"].setValue( "[Z]" ) # Removing just Z has the same effect

		self.__assertDeepStateProcessing( deleteChannels["out"], referenceFlatten["out"], [ 0, 0, 0, 10 ], [ 0, 0, 0, 10 ], 100, 0.45 )
Exemple #12
0
graphEditor = mainWindow.getLayout().editors(GafferUI.GraphEditor)[0]
nodeEditor = mainWindow.getLayout().editors(GafferUI.NodeEditor)[0]
sceneInspector = mainWindow.getLayout().editors(
    GafferSceneUI.SceneInspector)[0]
hierarchyView = mainWindow.getLayout().editors(GafferSceneUI.HierarchyView)[0]
pythonEditor = mainWindow.getLayout().editors(GafferUI.PythonEditor)[0]

# Concept: Reading a Context Variable
textNode = GafferScene.Text()
contextVariablesNode = Gaffer.ContextVariables()
contextVariablesNode.setup(GafferScene.ScenePlug("in", ))
contextVariablesNode["variables"].addChild(
    Gaffer.NameValuePlug(
        "",
        Gaffer.StringPlug(
            "value",
            defaultValue='',
            flags=Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic,
        ), True, "member1",
        Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic))
textNode["text"].setValue('${message}')
contextVariablesNode["variables"]["member1"]["name"].setValue('message')
contextVariablesNode["variables"]["member1"]["value"].setValue('received')
contextVariablesNode["in"].setInput(textNode["out"])
script.addChild(textNode)
script.addChild(contextVariablesNode)
script.selection().add(script["ContextVariables"])
graphEditor.frame(script.children(Gaffer.Node))
GafferUI.WidgetAlgo.grab(
    widget=mainWindow,
    imagePath="images/conceptContextsReadingContextVariable.png")
Exemple #13
0
    def testConstantVariables(self):

        sphere = GafferScene.Sphere()
        sphere["name"].setValue("object")

        cube = GafferScene.Cube()
        cube["name"].setValue("object")

        cubeVariables = GafferScene.PrimitiveVariables()
        cubeVariables["in"].setInput(cube["out"])
        cubeVariables["primitiveVariables"].addChild(
            Gaffer.NameValuePlug("ten", IECore.IntData(10)))
        cubeVariables["primitiveVariables"].addChild(
            Gaffer.NameValuePlug("twenty", IECore.IntData(20)))

        copy = GafferScene.CopyPrimitiveVariables()
        copy["in"].setInput(sphere["out"])
        copy["source"].setInput(cubeVariables["out"])

        # Not filtered to anything, so should be a perfect pass through.

        self.assertScenesEqual(sphere["out"], copy["out"])
        self.assertSceneHashesEqual(sphere["out"], copy["out"])

        # Add a filter, should still be a pass through because we haven't
        # asked for any variables to be copied.

        objectFilter = GafferScene.PathFilter()
        objectFilter["paths"].setValue(IECore.StringVectorData(["/object"]))
        copy["filter"].setInput(objectFilter["out"])

        self.assertScenesEqual(sphere["out"], copy["out"])

        # Copy something that doesn't exist. This isn't an error, because the
        # variables are treated as match patterns.

        copy["primitiveVariables"].setValue("these don't exist")
        self.assertScenesEqual(sphere["out"], copy["out"])

        # Copy things that do exist, and check that it has worked.

        copy["primitiveVariables"].setValue("ten twenty")
        self.assertEqual(
            set(copy["out"].object("/object").keys()),
            set(sphere["out"].object("/object").keys()) | {"ten", "twenty"},
        )

        self.assertEqual(
            copy["out"].object("/object")["ten"],
            cubeVariables["out"].object("/object")["ten"],
        )

        self.assertEqual(
            copy["out"].object("/object")["twenty"],
            cubeVariables["out"].object("/object")["twenty"],
        )

        # Check that wildcards work

        copy["primitiveVariables"].setValue("twen*")
        self.assertEqual(
            set(copy["out"].object("/object").keys()),
            set(sphere["out"].object("/object").keys()) | {"twenty"},
        )
    def testImageViewStatus(self):

        script = Gaffer.ScriptNode()
        script["image"] = GafferImage.ImageReader()

        view = GafferUI.View.create(script["image"]["out"])

        tool = GafferSceneUI.CropWindowTool(view)
        tool["active"].setValue(True)

        # Presently, crop window tool updates are coupled to `preRender`, so we
        # need to actually show the View before we can verify our behaviour.

        with GafferUI.Window() as window:
            GafferUI.GadgetWidget(view.viewportGadget())
        window.setVisible(True)

        # Check process exceptions

        script["image"]["fileName"].setValue("/i/do/not/exist.exr")

        self.waitForIdle(1000)
        self.assertEqual(
            tool.status(),
            "Error: image.__oiioReader.out.format : OpenImageIOReader : Could not create ImageInput : Could not open file \"/i/do/not/exist.exr\""
        )

        # Missing metadata

        script["image"]["fileName"].setValue(
            "${GAFFER_ROOT}/resources/images/macaw.exr")

        with IECore.CapturingMessageHandler() as mh:
            self.waitForIdle(1000)

        # Don't fail due to running on computer that can't do GPU color transforms well
        if len(mh.messages):
            self.assertEqual(len(mh.messages), 1)
            self.assertEqual(mh.messages[0].context, "ImageGadget")
            self.assertTrue(mh.messages[0].message.startswith(
                "Could not find supported floating point texture format in OpenGL"
            ))

        self.assertEqual(
            tool.status(),
            "Error: No <b>gaffer:sourceScene</b> metadata in image")

        script["meta"] = GafferImage.ImageMetadata()
        script["meta"]["metadata"].addChild(
            Gaffer.NameValuePlug("gaffer:sourceScene", "options.out", True,
                                 "member1"))
        script["meta"]["in"].setInput(script["image"]["out"])

        script["options"] = GafferScene.StandardOptions()

        view["in"].setInput(script["meta"]["out"])

        # Valid options path

        self.waitForIdle(1000)

        self.assertEqual(
            tool.status(),
            "Info: Editing <b>options.options.renderCropWindow.value</b>")
Exemple #15
0
    def test(self):

        constructed = {}
        constructed["defaults"] = {}
        constructed["specified"] = {}
        constructed["defaults"]["empty"] = Gaffer.NameValuePlug()

        # Note that if we specify the direction and flags without specifying argument names, this is ambiguous
        # with the later forms of the constructor.  I guess this is OK since the old serialised forms
        # of MemberPlug do include the argument names, and we want to deprecate this form anyway
        constructed["specified"]["empty"] = Gaffer.NameValuePlug(
            "foo",
            direction=Gaffer.Plug.Direction.Out,
            flags=Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic)

        constructed["defaults"]["fromData"] = Gaffer.NameValuePlug(
            "key", IECore.IntData(42))
        constructed["specified"]["fromData"] = Gaffer.NameValuePlug(
            "key", IECore.IntData(42), "foo", Gaffer.Plug.Direction.Out,
            Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic)

        constructed["defaults"]["fromPlug"] = Gaffer.NameValuePlug(
            "key", Gaffer.IntPlug(minValue=-3, maxValue=5))
        constructed["specified"]["fromPlug"] = Gaffer.NameValuePlug(
            "key",
            Gaffer.IntPlug(direction=Gaffer.Plug.Direction.Out,
                           flags=Gaffer.Plug.Flags.Default
                           | Gaffer.Plug.Flags.Dynamic), "foo")

        constructed["defaults"]["fromDataEnable"] = Gaffer.NameValuePlug(
            "key", IECore.IntData(42), True)
        constructed["specified"]["fromDataEnable"] = Gaffer.NameValuePlug(
            "key", IECore.IntData(42), True, "foo", Gaffer.Plug.Direction.Out,
            Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic)

        constructed["defaults"]["fromPlugEnable"] = Gaffer.NameValuePlug(
            "key", Gaffer.IntPlug(), True)
        constructed["specified"]["fromPlugEnable"] = Gaffer.NameValuePlug(
            "key",
            Gaffer.IntPlug(minValue=-7,
                           maxValue=15,
                           direction=Gaffer.Plug.Direction.Out,
                           flags=Gaffer.Plug.Flags.Default
                           | Gaffer.Plug.Flags.Dynamic), True, "foo")

        for k in [
                "empty", "fromData", "fromPlug", "fromDataEnable",
                "fromPlugEnable"
        ]:
            defa = constructed["defaults"][k]
            spec = constructed["specified"][k]
            numChildren = 3 if "Enable" in k else 2
            if k == "empty":
                numChildren = 0
            self.assertEqual(len(spec.children()), numChildren)
            self.assertEqual(len(defa.children()), numChildren)

            self.assertEqual(defa.getName(), "NameValuePlug")
            self.assertEqual(spec.getName(), "foo")
            self.assertEqual(defa.direction(), Gaffer.Plug.Direction.In)
            self.assertEqual(spec.direction(), Gaffer.Plug.Direction.Out)
            self.assertEqual(defa.getFlags(), Gaffer.Plug.Flags.Default)
            self.assertEqual(
                spec.getFlags(),
                Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic)

            if k == "empty":
                self.assertNotIn("name", defa)
                self.assertNotIn("name", spec)
                self.assertNotIn("value", defa)
                self.assertNotIn("value", spec)
            else:
                self.assertEqual(defa["name"].getValue(), "key")
                self.assertEqual(spec["name"].getValue(), "key")

                if "fromPlug" in k:
                    self.assertEqual(defa["value"].getValue(), 0)
                    self.assertEqual(spec["value"].getValue(), 0)
                else:
                    self.assertEqual(defa["value"].getValue(), 42)
                    self.assertEqual(spec["value"].getValue(), 42)

            if k == "empty":
                # We don't support serialising NameValuePlugs without name or value
                self.assertRaises(RuntimeError, self.assertPlugSerialises,
                                  spec)
                self.assertRaises(RuntimeError, self.assertCounterpart, defa)
                self.assertRaises(RuntimeError, self.assertCounterpart, spec)
            else:
                self.assertPlugSerialises(spec)
                self.assertCounterpart(defa)
                self.assertCounterpart(spec)
Exemple #16
0
    def testBoundsUpdate(self):

        plane = GafferScene.Plane()

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

        inPoint = GafferOSL.OSLShader()
        inPoint.loadShader("ObjectProcessing/InPoint")

        multiplyVector = GafferOSL.OSLShader()
        multiplyVector.loadShader("Maths/MultiplyVector")
        multiplyVector["parameters"]["a"].setInput(inPoint["out"]["value"])
        multiplyVector["parameters"]["b"].setValue(imath.V3f(2))

        oslObject = GafferOSL.OSLObject()
        oslObject["in"].setInput(plane["out"])
        oslObject["filter"].setInput(planeFilter["out"])

        oslObject["primitiveVariables"].addChild(
            Gaffer.NameValuePlug(
                "aPoint",
                IECore.V3fData(imath.V3f(0),
                               IECore.GeometricData.Interpretation.Point)))
        oslObject["primitiveVariables"][0]["value"].setInput(
            multiplyVector["out"]["out"])

        # Because we're not manipulating "P", the bounding boxes should remain unchanged.

        self.assertEqual(
            oslObject["out"].object("/plane")["aPoint"].data,
            oslObject["in"].object("/plane")["P"].data * imath.V3f(2))

        self.assertScenesEqual(oslObject["out"],
                               oslObject["in"],
                               checks={"bound"})
        self.assertSceneHashesEqual(oslObject["out"],
                                    oslObject["in"],
                                    checks={"bound"})

        # But as soon as we manipulate "P", bounds updates should be triggered.

        oslObject["primitiveVariables"][0]["name"].setValue("P")

        self.assertEqual(
            oslObject["out"].object("/plane")["P"].data,
            oslObject["in"].object("/plane")["P"].data * imath.V3f(2))

        self.assertEqual(oslObject["out"].bound("/plane"),
                         oslObject["out"].object("/plane").bound())
        self.assertSceneValid(oslObject["out"])

        # And we should be able to turn the bounds updates off if we don't want to
        # pay for them.

        oslObject["adjustBounds"].setValue(False)

        self.assertEqual(
            oslObject["out"].object("/plane")["P"].data,
            oslObject["in"].object("/plane")["P"].data * imath.V3f(2))

        self.assertScenesEqual(oslObject["out"],
                               oslObject["in"],
                               checks={"bound"})
        self.assertSceneHashesEqual(oslObject["out"],
                                    oslObject["in"],
                                    checks={"bound"})
Exemple #17
0
    def testHistory(self):

        plane = GafferScene.Plane()

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

        attributes = GafferScene.StandardAttributes()
        attributes["in"].setInput(plane["out"])
        attributes["filter"].setInput(attributesFilter["out"])
        attributes["attributes"].addChild(Gaffer.NameValuePlug("test", 10))

        group = GafferScene.Group()
        group["in"][0].setInput(attributes["out"])

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

        transform = GafferScene.Transform()
        transform["in"].setInput(group["out"])
        transform["filter"].setInput(transformFilter["out"])

        # Transform history

        with Gaffer.Context() as c:
            c.setFrame(10)
            history = GafferScene.SceneAlgo.history(
                transform["out"]["transform"], "/group/plane")

        self.assertEqual(history.scene, transform["out"])
        self.assertEqual(history.context.getFrame(), 10)
        self.assertEqual(history.context["scene:path"],
                         IECore.InternedStringVectorData(["group", "plane"]))
        self.assertEqual(len(history.predecessors), 1)

        history = history.predecessors[0]
        self.assertEqual(history.scene, group["out"])
        self.assertEqual(history.context.getFrame(), 10)
        self.assertEqual(history.context["scene:path"],
                         IECore.InternedStringVectorData(["group", "plane"]))
        self.assertEqual(len(history.predecessors), 1)

        history = history.predecessors[0]
        self.assertEqual(history.scene, plane["out"])
        self.assertEqual(history.context.getFrame(), 10)
        self.assertEqual(history.context["scene:path"],
                         IECore.InternedStringVectorData(["plane"]))
        self.assertEqual(len(history.predecessors), 0)

        # Attributes history

        with Gaffer.Context() as c:
            c.setFrame(20)
            history = GafferScene.SceneAlgo.history(
                transform["out"]["attributes"], "/group/plane")

        self.assertEqual(history.scene, group["out"])
        self.assertEqual(history.context.getFrame(), 20)
        self.assertEqual(history.context["scene:path"],
                         IECore.InternedStringVectorData(["group", "plane"]))
        self.assertEqual(len(history.predecessors), 1)

        history = history.predecessors[0]
        self.assertEqual(history.scene, attributes["out"])
        self.assertEqual(history.context.getFrame(), 20)
        self.assertEqual(history.context["scene:path"],
                         IECore.InternedStringVectorData(["plane"]))
        self.assertEqual(len(history.predecessors), 1)

        history = history.predecessors[0]
        self.assertEqual(history.scene, plane["out"])
        self.assertEqual(history.context.getFrame(), 20)
        self.assertEqual(history.context["scene:path"],
                         IECore.InternedStringVectorData(["plane"]))
        self.assertEqual(len(history.predecessors), 0)
Exemple #18
0
    def testAllTypes(self):

        s = Gaffer.ScriptNode()

        c = GafferScene.Cube()
        s.addChild(c)

        o = GafferOSL.OSLObject()
        s.addChild(o)

        f = GafferScene.PathFilter("PathFilter")
        s.addChild(f)
        f["paths"].setValue(IECore.StringVectorData(['/cube']))
        o["filter"].setInput(f["out"])

        o['in'].setInput(c["out"])
        o["primitiveVariables"].addChild(
            Gaffer.NameValuePlug("testString", "blah"))
        o["primitiveVariables"].addChild(Gaffer.NameValuePlug("testInt", 42))
        o["primitiveVariables"].addChild(
            Gaffer.NameValuePlug("testFloat", 42.42))
        o["primitiveVariables"].addChild(
            Gaffer.NameValuePlug(
                "testVector",
                IECore.V3fData(imath.V3f(1, 2, 3),
                               IECore.GeometricData.Interpretation.Vector)))
        o["primitiveVariables"].addChild(
            Gaffer.NameValuePlug(
                "testPoint",
                IECore.V3fData(imath.V3f(4, 5, 6),
                               IECore.GeometricData.Interpretation.Point)))
        o["primitiveVariables"].addChild(
            Gaffer.NameValuePlug(
                "testNormal",
                IECore.V3fData(imath.V3f(7, 8, 9),
                               IECore.GeometricData.Interpretation.Normal)))
        o["primitiveVariables"].addChild(
            Gaffer.NameValuePlug(
                "testUV",
                IECore.V3fData(imath.V3f(10, 11, -42),
                               IECore.GeometricData.Interpretation.UV)))
        o["primitiveVariables"].addChild(
            Gaffer.NameValuePlug("testColor", imath.Color3f(12, 13, 14)))
        o["primitiveVariables"].addChild(
            Gaffer.NameValuePlug("testMatrix", imath.M44f(15)))

        cubeObject = s['OSLObject']['out'].object("/cube")

        self.assertEqual(cubeObject["testString"].data,
                         IECore.StringVectorData(["blah"] * 8))
        self.assertEqual(cubeObject["testInt"].data,
                         IECore.IntVectorData([42] * 8))
        self.assertEqual(cubeObject["testFloat"].data,
                         IECore.FloatVectorData([42.42] * 8))
        self.assertEqual(
            cubeObject["testVector"].data,
            IECore.V3fVectorData([imath.V3f(1, 2, 3)] * 8,
                                 IECore.GeometricData.Interpretation.Vector))
        self.assertEqual(
            cubeObject["testPoint"].data,
            IECore.V3fVectorData([imath.V3f(4, 5, 6)] * 8,
                                 IECore.GeometricData.Interpretation.Point))
        self.assertEqual(
            cubeObject["testNormal"].data,
            IECore.V3fVectorData([imath.V3f(7, 8, 9)] * 8,
                                 IECore.GeometricData.Interpretation.Normal))
        self.assertEqual(
            cubeObject["testUV"].data,
            IECore.V2fVectorData([imath.V2f(10, 11)] * 8,
                                 IECore.GeometricData.Interpretation.UV))
        self.assertEqual(
            cubeObject["testColor"].data,
            IECore.Color3fVectorData([imath.Color3f(12, 13, 14)] * 8))
        self.assertEqual(cubeObject["testMatrix"].data,
                         IECore.M44fVectorData([imath.M44f(15)] * 8))
Exemple #19
0
    def test(self):

        getRed = GafferOSL.OSLShader()
        getRed.loadShader("ImageProcessing/InChannel")
        getRed["parameters"]["channelName"].setValue("R")

        getGreen = GafferOSL.OSLShader()
        getGreen.loadShader("ImageProcessing/InChannel")
        getGreen["parameters"]["channelName"].setValue("G")

        getBlue = GafferOSL.OSLShader()
        getBlue.loadShader("ImageProcessing/InChannel")
        getBlue["parameters"]["channelName"].setValue("B")

        floatToColor = GafferOSL.OSLShader()
        floatToColor.loadShader("Conversion/FloatToColor")
        floatToColor["parameters"]["r"].setInput(
            getBlue["out"]["channelValue"])
        floatToColor["parameters"]["g"].setInput(
            getGreen["out"]["channelValue"])
        floatToColor["parameters"]["b"].setInput(getRed["out"]["channelValue"])

        outRGB = GafferOSL.OSLShader()
        outRGB.loadShader("ImageProcessing/OutLayer")
        outRGB["parameters"]["layerColor"].setInput(floatToColor["out"]["c"])

        imageShader = GafferOSL.OSLShader()
        imageShader.loadShader("ImageProcessing/OutImage")
        imageShader["parameters"]["in0"].setInput(outRGB["out"]["layer"])

        reader = GafferImage.ImageReader()
        reader["fileName"].setValue(
            os.path.expandvars(
                "$GAFFER_ROOT/python/GafferImageTest/images/rgb.100x100.exr"))

        image = GafferOSL.OSLImage()
        image["in"].setInput(reader["out"])

        # we haven't connected the shader yet, so the node should act as a pass through

        self.assertEqual(GafferImage.ImageAlgo.image(image["out"]),
                         GafferImage.ImageAlgo.image(reader["out"]))

        # that should all change when we hook up a shader

        image["channels"].addChild(
            Gaffer.NameValuePlug("", GafferOSL.ClosurePlug(), "testClosure"))
        cs = GafferTest.CapturingSlot(image.plugDirtiedSignal())

        def checkDirtiness(expected):
            self.assertEqual([i[0].fullName() for i in cs],
                             ["OSLImage." + i for i in expected])
            del cs[:]

        image["channels"]["testClosure"]["value"].setInput(
            imageShader["out"]["out"])

        checkDirtiness([
            "channels.testClosure.value", "channels.testClosure", "channels",
            "__shader", "__shading", "out.channelNames", "out.channelData",
            "out"
        ])

        inputImage = GafferImage.ImageAlgo.image(reader["out"])
        outputImage = GafferImage.ImageAlgo.image(image["out"])

        self.assertNotEqual(inputImage, outputImage)
        self.assertEqual(outputImage["R"], inputImage["B"])
        self.assertEqual(outputImage["G"], inputImage["G"])
        self.assertEqual(outputImage["B"], inputImage["R"])

        # changes in the shader network should signal more dirtiness

        getGreen["parameters"]["channelName"].setValue("R")
        checkDirtiness([
            "channels.testClosure.value", "channels.testClosure", "channels",
            "__shader", "__shading", "out.channelNames", "out.channelData",
            "out"
        ])

        floatToColor["parameters"]["r"].setInput(getRed["out"]["channelValue"])
        checkDirtiness([
            "channels.testClosure.value", "channels.testClosure", "channels",
            "__shader", "__shading", "out.channelNames", "out.channelData",
            "out"
        ])

        inputImage = GafferImage.ImageAlgo.image(reader["out"])
        outputImage = GafferImage.ImageAlgo.image(image["out"])

        self.assertEqual(outputImage["R"], inputImage["R"])
        self.assertEqual(outputImage["G"], inputImage["R"])
        self.assertEqual(outputImage["B"], inputImage["R"])

        image["in"].setInput(None)
        checkDirtiness([
            'in.format', 'in.dataWindow', 'in.metadata', 'in.deep',
            'in.sampleOffsets', 'in.channelNames', 'in.channelData', 'in',
            '__shading', 'out.channelNames', 'out.channelData', 'out.format',
            'out.dataWindow', 'out.metadata', 'out.deep', 'out.sampleOffsets',
            'out'
        ])

        image["defaultFormat"]["displayWindow"]["max"]["x"].setValue(200)
        checkDirtiness([
            'defaultFormat.displayWindow.max.x',
            'defaultFormat.displayWindow.max', 'defaultFormat.displayWindow',
            'defaultFormat', '__defaultIn.format', '__defaultIn.dataWindow',
            '__defaultIn', '__shading', 'out.channelNames', 'out.channelData',
            'out.format', 'out.dataWindow', 'out'
        ])

        constant = GafferImage.Constant()
        image["in"].setInput(constant["out"])

        checkDirtiness([
            'in.format', 'in.dataWindow', 'in.metadata', 'in.deep',
            'in.sampleOffsets', 'in.channelNames', 'in.channelData', 'in',
            '__shading', 'out.channelNames', 'out.channelData', 'out.format',
            'out.dataWindow', 'out.metadata', 'out.deep', 'out.sampleOffsets',
            'out'
        ])
Exemple #20
0
    def testAttributeDirtyPropagation(self):

        sphere = GafferScene.Sphere()
        group = GafferScene.Group()
        options = GafferScene.StandardOptions()

        sphereSet = GafferScene.Set()
        sphereSet["name"].setValue("render:spheres")
        setFilter = GafferScene.PathFilter()
        setFilter["paths"].setValue(IECore.StringVectorData(["/group/sphere"]))
        sphereSet["filter"].setInput(setFilter["out"])

        group["in"][0].setInput(sphere["out"])
        options["in"].setInput(group["out"])
        sphereSet["in"].setInput(options["out"])

        globalAttr = GafferScene.CustomAttributes()
        globalAttrPlug = Gaffer.NameValuePlug("user:globalAttr",
                                              IECore.IntData(0),
                                              flags=Gaffer.Plug.Flags.Default
                                              | Gaffer.Plug.Flags.Dynamic)
        globalAttr["attributes"].addChild(globalAttrPlug)
        globalAttr["global"].setValue(True)

        groupAttr = GafferScene.CustomAttributes()
        groupAttrPlug = Gaffer.NameValuePlug("localAttr1",
                                             IECore.IntData(0),
                                             flags=Gaffer.Plug.Flags.Default
                                             | Gaffer.Plug.Flags.Dynamic)
        groupAttr["attributes"].addChild(groupAttrPlug)
        groupAttrFilter = GafferScene.PathFilter()
        groupAttr["filter"].setInput(groupAttrFilter["out"])
        groupAttrFilter["paths"].setValue(IECore.StringVectorData(["/group"]))

        sphereAttr = GafferScene.CustomAttributes()
        sphereAttrPlug = Gaffer.NameValuePlug("user:localAttr2",
                                              IECore.IntData(0),
                                              flags=Gaffer.Plug.Flags.Default
                                              | Gaffer.Plug.Flags.Dynamic)
        sphereAttr["attributes"].addChild(sphereAttrPlug)
        sphereAttrFilter = GafferScene.PathFilter()
        sphereAttr["filter"].setInput(sphereAttrFilter["out"])
        sphereAttrFilter["paths"].setValue(
            IECore.StringVectorData(["/group/sphere"]))

        globalAttr["in"].setInput(sphereSet["out"])
        groupAttr["in"].setInput(globalAttr["out"])
        sphereAttr["in"].setInput(groupAttr["out"])

        renderer = GafferScene.Private.IECoreScenePreview.CapturingRenderer()
        controller = GafferScene.RenderController(sphereAttr["out"],
                                                  Gaffer.Context(), renderer)
        controller.setMinimumExpansionDepth(10)
        controller.update()

        capturedSphere = renderer.capturedObject("/group/sphere")

        self.assertEqual(capturedSphere.numAttributeEdits(), 1)
        self.assertEqual(
            capturedSphere.capturedAttributes().attributes(),
            IECore.CompoundObject({
                "user:globalAttr":
                IECore.IntData(0),
                "localAttr1":
                IECore.IntData(0),
                "user:localAttr2":
                IECore.IntData(0),
                "sets":
                IECore.InternedStringVectorData(["spheres"])
            }))

        sphereAttrPlug["value"].setValue(1)
        controller.update()

        self.assertEqual(capturedSphere.numAttributeEdits(), 2)
        self.assertEqual(
            capturedSphere.capturedAttributes().attributes(),
            IECore.CompoundObject({
                "user:globalAttr":
                IECore.IntData(0),
                "localAttr1":
                IECore.IntData(0),
                "user:localAttr2":
                IECore.IntData(1),
                "sets":
                IECore.InternedStringVectorData(["spheres"])
            }))

        groupAttrPlug["value"].setValue(2)
        controller.update()

        self.assertEqual(capturedSphere.numAttributeEdits(), 3)
        self.assertEqual(
            capturedSphere.capturedAttributes().attributes(),
            IECore.CompoundObject({
                "user:globalAttr":
                IECore.IntData(0),
                "localAttr1":
                IECore.IntData(2),
                "user:localAttr2":
                IECore.IntData(1),
                "sets":
                IECore.InternedStringVectorData(["spheres"])
            }))

        globalAttrPlug["value"].setValue(3)
        controller.update()

        self.assertEqual(capturedSphere.numAttributeEdits(), 4)
        self.assertEqual(
            capturedSphere.capturedAttributes().attributes(),
            IECore.CompoundObject({
                "user:globalAttr":
                IECore.IntData(3),
                "localAttr1":
                IECore.IntData(2),
                "user:localAttr2":
                IECore.IntData(1),
                "sets":
                IECore.InternedStringVectorData(["spheres"])
            }))

        sphereSet["enabled"].setValue(False)
        controller.update()

        self.assertEqual(capturedSphere.numAttributeEdits(), 5)
        self.assertEqual(
            capturedSphere.capturedAttributes().attributes(),
            IECore.CompoundObject({
                "user:globalAttr": IECore.IntData(3),
                "localAttr1": IECore.IntData(2),
                "user:localAttr2": IECore.IntData(1),
                "sets": IECore.InternedStringVectorData([])
            }))

        options["options"]["renderCamera"]["enabled"].setValue(True)
        controller.update()

        self.assertEqual(capturedSphere.numAttributeEdits(), 5)

        options["options"]["renderCamera"]["value"].setValue("/camera")
        controller.update()

        self.assertEqual(capturedSphere.numAttributeEdits(), 5)

        del capturedSphere
Exemple #21
0
    def test(self):

        constructed = {}
        constructed["defaults"] = {}
        constructed["specified"] = {}
        constructed["defaults"]["empty"] = Gaffer.NameValuePlug()
        constructed["defaults"]["partialEmpty"] = Gaffer.NameValuePlug()
        constructed["defaults"]["partialEmpty"].addChild(
            Gaffer.StringPlug("name", defaultValue="key"))

        # Note that if we specify the direction and flags without specifying argument names, this is ambiguous
        # with the later forms of the constructor.  I guess this is OK since the old serialised forms
        # of MemberPlug do include the argument names, and we want to deprecate this form anyway
        constructed["specified"]["empty"] = Gaffer.NameValuePlug(
            "foo",
            direction=Gaffer.Plug.Direction.Out,
            flags=Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic)
        constructed["specified"]["partialEmpty"] = Gaffer.NameValuePlug(
            "foo",
            direction=Gaffer.Plug.Direction.Out,
            flags=Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic)
        constructed["specified"]["partialEmpty"].addChild(
            Gaffer.StringPlug("name",
                              direction=Gaffer.Plug.Direction.Out,
                              flags=Gaffer.Plug.Flags.Default
                              | Gaffer.Plug.Flags.Dynamic,
                              defaultValue="key"))

        constructed["defaults"]["fromData"] = Gaffer.NameValuePlug(
            "key", IECore.IntData(42))
        constructed["specified"]["fromData"] = Gaffer.NameValuePlug(
            "key", IECore.IntData(42), "foo", Gaffer.Plug.Direction.Out,
            Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic)

        constructed["defaults"]["fromPlug"] = Gaffer.NameValuePlug(
            "key", Gaffer.IntPlug(minValue=-3, maxValue=5))
        constructed["specified"]["fromPlug"] = Gaffer.NameValuePlug(
            "key",
            Gaffer.IntPlug(direction=Gaffer.Plug.Direction.Out,
                           flags=Gaffer.Plug.Flags.Default
                           | Gaffer.Plug.Flags.Dynamic), "foo")

        constructed["defaults"]["fromDataEnable"] = Gaffer.NameValuePlug(
            "key", IECore.IntData(42), True)
        constructed["specified"]["fromDataEnable"] = Gaffer.NameValuePlug(
            "key", IECore.IntData(42), True, "foo", Gaffer.Plug.Direction.Out,
            Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic)

        constructed["defaults"]["fromPlugEnable"] = Gaffer.NameValuePlug(
            "key", Gaffer.IntPlug(), True)
        constructed["specified"]["fromPlugEnable"] = Gaffer.NameValuePlug(
            "key",
            Gaffer.IntPlug(minValue=-7,
                           maxValue=15,
                           direction=Gaffer.Plug.Direction.Out,
                           flags=Gaffer.Plug.Flags.Default
                           | Gaffer.Plug.Flags.Dynamic), True, "foo")

        for k in [
                "empty", "fromData", "fromPlug", "fromDataEnable",
                "fromPlugEnable"
        ]:
            defa = constructed["defaults"][k]
            spec = constructed["specified"][k]
            numChildren = 3 if "Enable" in k else 2
            if k == "empty":
                numChildren = 0
            self.assertEqual(len(spec.children()), numChildren)
            self.assertEqual(len(defa.children()), numChildren)

            self.assertEqual(defa.getName(), "NameValuePlug")
            self.assertEqual(spec.getName(), "foo")
            self.assertEqual(defa.direction(), Gaffer.Plug.Direction.In)
            self.assertEqual(spec.direction(), Gaffer.Plug.Direction.Out)
            self.assertEqual(defa.getFlags(), Gaffer.Plug.Flags.Default)
            self.assertEqual(
                spec.getFlags(),
                Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic)

            if k == "empty":
                self.assertNotIn("name", defa)
                self.assertNotIn("name", spec)
                self.assertNotIn("value", defa)
                self.assertNotIn("value", spec)
            elif k == "partialEmpty":
                self.assertEqual(defa["name"].getValue(), "key")
                self.assertEqual(spec["name"].getValue(), "key")
                self.assertNotIn("value", defa)
                self.assertNotIn("value", spec)
            else:
                self.assertEqual(defa["name"].getValue(), "key")
                self.assertEqual(spec["name"].getValue(), "key")

                if "fromPlug" in k:
                    self.assertEqual(defa["value"].getValue(), 0)
                    self.assertEqual(spec["value"].getValue(), 0)
                else:
                    self.assertEqual(defa["value"].getValue(), 42)
                    self.assertEqual(spec["value"].getValue(), 42)

            if k == "empty":
                # A completely empty NameValuePlug is invalid, but we have to partially
                # support it because old serialisation code will create these before
                # the addChild's run to create name and value
                self.assertCounterpart(defa)
                self.assertCounterpart(spec)

                # We shouldn't ever serialise invalid plugs though - if the children
                # haven't been created by the time we try to serialise, that's a bug
                self.assertRaises(RuntimeError, self.assertPlugSerialises,
                                  spec)
            elif k == "partialEmpty":
                # A NameValuePlug with a name but no value, on the other hand, is just
                # broken
                self.assertRaises(RuntimeError, self.assertPlugSerialises,
                                  spec)
                self.assertRaises(RuntimeError, self.assertCounterpart, defa)
                self.assertRaises(RuntimeError, self.assertCounterpart, spec)
            else:
                self.assertPlugSerialises(spec)
                self.assertCounterpart(defa)
                self.assertCounterpart(spec)
Exemple #22
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"]["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"]["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"].addChild(
            Gaffer.NameValuePlug(
                '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"].addChild(
            Gaffer.NameValuePlug(
                '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"].addChild(
            Gaffer.NameValuePlug(
                '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"].addChild(
            Gaffer.NameValuePlug('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"]["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)
Exemple #23
0
    def testTransformPlug(self):

        p = Gaffer.NameValuePlug("a", Gaffer.TransformPlug())
        self.assertEqual(p["value"].matrix(), imath.M44f())
Exemple #24
0
    def __init__(self, name='BleedFill'):

        GafferImage.ImageProcessor.__init__(self, name)

        self.addChild(Gaffer.BoolPlug("expandDataWindow"))

        self.addChild(Gaffer.IntPlug("__blurIterations"))
        self['__blurIterations'].setFlags(Gaffer.Plug.Flags.Serialisable,
                                          False)

        self["__blurIterationsExpression"] = Gaffer.Expression()
        self["__blurIterationsExpression"].setExpression(
            inspect.cleandoc("""
			import math
			f = parent["in"]["format"]
			parent["__blurIterations"] = int( math.log( min( f.width(), f.height() ), 2 ) )
			"""), "python")

        self["__displayWindowConstant"] = GafferImage.Constant()
        self["__displayWindowConstant"]["color"].setValue(
            imath.Color4f(0, 0, 0, 0))

        self["__displayWindowExpression"] = Gaffer.Expression()
        self["__displayWindowExpression"].setExpression(
            'parent["__displayWindowConstant"]["format"] = parent["in"]["format"]',
            "python")

        self["__expandMerge"] = GafferImage.Merge()
        self["__expandMerge"]["in"][0].setInput(self["in"])
        self["__expandMerge"]["in"][1].setInput(
            self["__displayWindowConstant"]["out"])
        self["__expandMerge"]["operation"].setValue(
            GafferImage.Merge.Operation.Over)

        self["__expandSwitch"] = Gaffer.Switch()
        self["__expandSwitch"].setup(self["in"])
        self["__expandSwitch"]["in"][0].setInput(self["in"])
        self["__expandSwitch"]["in"][1].setInput(self["__expandMerge"]["out"])
        self["__expandSwitch"]["index"].setInput(self["expandDataWindow"])

        # First blur via repeated downsampling
        self["__blurLoop"] = GafferImage.ImageLoop()
        self["__blurLoop"]["iterations"].setInput(self["__blurIterations"])
        self["__blurLoop"]["in"].setInput(self["__expandSwitch"]["out"])

        self["__downsample"] = GafferImage.Resize()
        self["__downsample"]["in"].setInput(self["__blurLoop"]["previous"])
        self["__downsample"]["filter"].setValue("sharp-gaussian")

        self["__downsampleExpression"] = Gaffer.Expression()
        self["__downsampleExpression"].setExpression(
            inspect.cleandoc("""
			import GafferImage
			import IECore

			f = parent["in"]["format"]

			divisor = 2 <<  context.get("loop:index", 0)

			parent["__downsample"]["format"] =  GafferImage.Format( imath.Box2i( f.getDisplayWindow().min() / divisor, f.getDisplayWindow().max() / divisor ), 1.0 )
			"""), "python")

        # Multiply each successive octave by a falloff factor so that we prioritize higher frequencies when they exist
        self["__grade"] = GafferImage.Grade("Grade")
        self["__grade"]['channels'].setValue("*")
        self["__grade"]['multiply'].setValue(imath.Color4f(0.1))
        self["__grade"]['blackClamp'].setValue(False)
        self["__grade"]["in"].setInput(self["__downsample"]["out"])

        self["__blurLoop"]["next"].setInput(self["__grade"]["out"])

        self["__reverseLoopContext"] = GafferImage.ImageContextVariables()
        self["__reverseLoopContext"]["in"].setInput(
            self["__blurLoop"]["previous"])
        self["__reverseLoopContext"]["variables"].addChild(
            Gaffer.NameValuePlug("loop:index", IECore.IntData(0), "loopIndex"))

        self["__reverseLoopExpression"] = Gaffer.Expression()
        self["__reverseLoopExpression"].setExpression(
            inspect.cleandoc("""
			parent["__reverseLoopContext"]["variables"]["loopIndex"]["value"] = parent["__blurIterations"] - context.get( "loop:index", 0 )
			"""), "python")

        # Loop through image resolution levels combining the most downsampled image with less downsampled versions,
        # one level at a time
        self["__combineLoop"] = GafferImage.ImageLoop()

        self["__combineLoopExpression"] = Gaffer.Expression()
        self["__combineLoopExpression"].setExpression(
            'parent["__combineLoop"]["iterations"] = parent["__blurIterations"] + 1',
            "python")

        self["__upsample"] = GafferImage.Resize()
        self["__upsample"]["in"].setInput(self["__combineLoop"]["previous"])
        self["__upsample"]["filter"].setValue("smoothGaussian")

        self["__upsampleExpression"] = Gaffer.Expression()
        self["__upsampleExpression"].setExpression(
            inspect.cleandoc("""
			import GafferImage
			import IECore

			f = parent["in"]["format"]

			divisor = 1 <<  (  parent["__blurIterations"] - context.get("loop:index", 0) )

			parent["__upsample"]["format"] =  GafferImage.Format( imath.Box2i( f.getDisplayWindow().min() / divisor, f.getDisplayWindow().max() / divisor ), 1.0 )
			"""), "python")

        self["__merge"] = GafferImage.Merge()
        self["__merge"]["operation"].setValue(GafferImage.Merge.Operation.Over)
        self["__merge"]["in"][0].setInput(self["__upsample"]["out"])
        self["__merge"]["in"][1].setInput(self["__reverseLoopContext"]["out"])

        self["__combineLoop"]["next"].setInput(self["__merge"]["out"])

        # When downsampling to target display window sizes with a non-square image,
        # the data window size gets rounded up to the nearest integer, potentially introducing
        # a small error in data window size that gets amplified during repeated upsampling.
        # To fix this, crop to the data window after scaling.
        self["__restoreDataSize"] = GafferImage.Crop()
        self["__restoreDataSize"]["in"].setInput(self["__combineLoop"]["out"])
        self["__restoreDataSize"]["affectDisplayWindow"].setValue(False)

        self["__restoreDataExpression"] = Gaffer.Expression()
        self["__restoreDataExpression"].setExpression(
            'parent["__restoreDataSize"]["area"] = parent["__expandSwitch"]["out"]["dataWindow"]',
            "python")

        self["__unpremult"] = GafferImage.Unpremultiply()
        self["__unpremult"]['channels'].setValue("*")
        self["__unpremult"]["in"].setInput(self["__restoreDataSize"]["out"])

        self["__resetAlpha"] = GafferImage.Shuffle()
        self["__resetAlpha"]["channels"].addChild(
            GafferImage.Shuffle.ChannelPlug("A", "__white"))
        self["__resetAlpha"]["in"].setInput(self["__unpremult"]["out"])

        self["__disableSwitch"] = Gaffer.Switch()
        self["__disableSwitch"].setup(self["in"])
        self["__disableSwitch"]["in"][0].setInput(self["in"])
        self["__disableSwitch"]["in"][1].setInput(self["__resetAlpha"]["out"])
        self["__disableSwitch"]["index"].setInput(self["enabled"])

        self['out'].setFlags(Gaffer.Plug.Flags.Serialisable, False)
        self["out"].setInput(self["__disableSwitch"]["out"])
Exemple #25
0
    def testDynamicPlugsAndGIL(self):

        script = Gaffer.ScriptNode()

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

        script["sphere"] = GafferScene.Sphere()

        script["expression"] = Gaffer.Expression()
        script["expression"].setExpression(
            "parent['sphere']['radius'] = context.getFrame()")

        script["instancer"] = GafferScene.Instancer()
        script["instancer"]["in"].setInput(script["plane"]["out"])
        script["instancer"]["instances"].setInput(script["sphere"]["out"])
        script["instancer"]["parent"].setValue("/plane")

        script["attributes"] = GafferScene.CustomAttributes()
        script["attributes"]["in"].setInput(script["instancer"]["out"])

        script["outputs"] = GafferScene.Outputs()
        script["outputs"]["in"].setInput(script["attributes"]["out"])

        # Simulate an InteractiveRender or Viewer traversal of the scene
        # every time it is dirtied. If the GIL isn't released when dirtiness
        # is signalled, we'll end up with a deadlock as the traversal enters
        # python on another thread to evaluate the expression. We increment the frame
        # between each test to ensure the expression result is not cached and
        # we do truly enter python.
        traverseConnection = Gaffer.ScopedConnection(
            GafferSceneTest.connectTraverseSceneToPlugDirtiedSignal(
                script["outputs"]["out"]))
        with Gaffer.Context() as c:

            c.setFrame(1)
            script["attributes"]["attributes"].addChild(
                Gaffer.NameValuePlug("test1", IECore.IntData(10)))

            c.setFrame(2)
            script["attributes"]["attributes"].addChild(
                Gaffer.NameValuePlug("test2", IECore.IntData(20), True))

            c.setFrame(3)
            script["attributes"]["attributes"].addMembers(
                IECore.CompoundData({
                    "test3": 30,
                    "test4": 40,
                }))

            c.setFrame(4)
            p = script["attributes"]["attributes"][0]
            del script["attributes"]["attributes"][p.getName()]

            c.setFrame(5)
            script["attributes"]["attributes"].addChild(p)

            c.setFrame(6)
            script["attributes"]["attributes"].removeChild(p)

            c.setFrame(7)
            script["attributes"]["attributes"].setChild(p.getName(), p)

            c.setFrame(8)
            script["attributes"]["attributes"].removeChild(p)

            c.setFrame(9)
            script["attributes"]["attributes"][p.getName()] = p

            c.setFrame(10)
            script["outputs"].addOutput(
                "test", IECoreScene.Output("beauty.exr", "exr", "rgba"))
Exemple #26
0
    def testOverrideAttributes(self):

        sphere = IECoreScene.SpherePrimitive()
        input = GafferSceneTest.CompoundObjectSource()
        input["in"].setValue(
            IECore.CompoundObject({
                "bound": IECore.Box3fData(sphere.bound()),
                "children": {
                    "ball1": {
                        "object": sphere,
                        "bound": IECore.Box3fData(sphere.bound()),
                    },
                },
            }))

        a = GafferScene.CustomAttributes()
        a["in"].setInput(input["out"])

        a["attributes"].addChild(
            Gaffer.NameValuePlug("ri:shadingRate",
                                 IECore.FloatData(0.25),
                                 flags=Gaffer.Plug.Flags.Default
                                 | Gaffer.Plug.Flags.Dynamic))
        a["attributes"].addChild(
            Gaffer.NameValuePlug("user:something",
                                 IECore.IntData(1),
                                 flags=Gaffer.Plug.Flags.Default
                                 | Gaffer.Plug.Flags.Dynamic))
        self.assertEqual(
            a["out"].attributes("/ball1"),
            IECore.CompoundObject({
                "ri:shadingRate": IECore.FloatData(0.25),
                "user:something": IECore.IntData(1),
            }))

        a2 = GafferScene.CustomAttributes()
        a2["in"].setInput(a["out"])

        self.assertEqual(
            a2["out"].attributes("/ball1"),
            IECore.CompoundObject({
                "ri:shadingRate": IECore.FloatData(0.25),
                "user:something": IECore.IntData(1),
            }))

        a2["attributes"].addChild(
            Gaffer.NameValuePlug("ri:shadingRate",
                                 IECore.FloatData(.5),
                                 flags=Gaffer.Plug.Flags.Default
                                 | Gaffer.Plug.Flags.Dynamic))
        a2["attributes"].addChild(
            Gaffer.NameValuePlug("user:somethingElse",
                                 IECore.IntData(10),
                                 flags=Gaffer.Plug.Flags.Default
                                 | Gaffer.Plug.Flags.Dynamic))

        self.assertEqual(
            a2["out"].attributes("/ball1"),
            IECore.CompoundObject({
                "ri:shadingRate": IECore.FloatData(0.5),
                "user:something": IECore.IntData(1),
                "user:somethingElse": IECore.IntData(10),
            }))
    def testCellEnabled(self):

        # Test that cell enabled states are correctly remapped when
        # cross-pasting between simple, adopted and unadopted columns.

        s = Gaffer.Spreadsheet()
        s["rows"].addColumn(Gaffer.IntPlug(), "valueOnly")
        s["rows"].addColumn(Gaffer.NameValuePlug(
            "a", Gaffer.IntPlug(defaultValue=1), True),
                            "adopted",
                            adoptEnabledPlug=True)
        s["rows"].addColumn(Gaffer.NameValuePlug(
            "u", Gaffer.IntPlug(defaultValue=2), True),
                            "unadopted",
                            adoptEnabledPlug=False)
        row = s["rows"].addRow()

        def resetEnabledState():
            for cell in row["cells"].children():
                cell.enabledPlug().setValue(True)
            row["cells"]["unadopted"]["value"]["enabled"].setValue(True)

        def assertPostCondition(valueOnly, adopted, unadopted,
                                unadoptedEnabled):
            self.assertEqual(
                row["cells"]["valueOnly"].enabledPlug().getValue(), valueOnly)
            self.assertEqual(row["cells"]["adopted"].enabledPlug().getValue(),
                             adopted)
            self.assertEqual(
                row["cells"]["unadopted"].enabledPlug().getValue(), unadopted)
            self.assertEqual(
                row["cells"]["unadopted"]["value"]["enabled"].getValue(),
                unadoptedEnabled)

        self.assertEqual(row["cells"]["valueOnly"].enabledPlug(),
                         row["cells"]["valueOnly"]["enabled"])
        self.assertEqual(row["cells"]["adopted"].enabledPlug(),
                         row["cells"]["adopted"]["value"]["enabled"])
        self.assertEqual(row["cells"]["unadopted"].enabledPlug(),
                         row["cells"]["unadopted"]["enabled"])
        self.assertEqual(
            row["cells"]["unadopted"]["value"]["enabled"].getValue(), True)

        for source, targets, expected in (("valueOnly", ("adopted",
                                                         "unadopted"),
                                           (False, False, False, True)),
                                          ("adopted", ("valueOnly",
                                                       "unadopted"),
                                           (False, False, False, False)),
                                          ("unadopted", ("valueOnly",
                                                         "adopted"),
                                           (False, False, False, True))):

            resetEnabledState()
            row["cells"][source].enabledPlug().setValue(False)

            data = _ClipboardAlgo.valueMatrix([[row["cells"][source]]])
            _ClipboardAlgo.pasteCells(data,
                                      [[row["cells"][t] for t in targets]], 0)

            assertPostCondition(*expected)
Exemple #28
0
    def testHashPassThrough(self):

        sphere = IECoreScene.SpherePrimitive()
        input = GafferSceneTest.CompoundObjectSource()
        input["in"].setValue(
            IECore.CompoundObject({
                "bound": IECore.Box3fData(sphere.bound()),
                "children": {
                    "ball1": {
                        "object": sphere,
                        "bound": IECore.Box3fData(sphere.bound()),
                    },
                    "ball2": {
                        "object": sphere,
                        "bound": IECore.Box3fData(sphere.bound()),
                    },
                },
            }))

        a = GafferScene.CustomAttributes()
        a["in"].setInput(input["out"])

        # when we have no attributes at all, everything should be a pass-through
        self.assertSceneHashesEqual(input["out"], a["out"])

        # when we have some attributes, everything except the attributes plug should
        # be a pass-through.
        a["attributes"].addChild(
            Gaffer.NameValuePlug("ri:shadingRate",
                                 IECore.FloatData(2.0),
                                 flags=Gaffer.Plug.Flags.Default
                                 | Gaffer.Plug.Flags.Dynamic))
        self.assertSceneHashesEqual(input["out"],
                                    a["out"],
                                    checks=self.allSceneChecks -
                                    {"attributes"})
        self.assertSceneHashesNotEqual(input["out"],
                                       a["out"],
                                       checks={"attributes"})

        # when we add a filter, non-matching objects should become pass-throughs
        f = GafferScene.PathFilter()
        f["paths"].setValue(IECore.StringVectorData(["/ball1"]))
        a["filter"].setInput(f["out"])
        self.assertSceneHashesEqual(input["out"],
                                    a["out"],
                                    pathsToIgnore=("/ball1", ))

        c = Gaffer.Context()
        c["scene:path"] = IECore.InternedStringVectorData(["ball1"])
        with c:
            self.assertEqual(a["out"]["childNames"].hash(),
                             input["out"]["childNames"].hash())
            self.assertEqual(a["out"]["transform"].hash(),
                             input["out"]["transform"].hash())
            self.assertEqual(a["out"]["bound"].hash(),
                             input["out"]["bound"].hash())
            self.assertEqual(a["out"]["object"].hash(),
                             input["out"]["object"].hash())
            self.assertNotEqual(a["out"]["attributes"].hash(),
                                input["out"]["attributes"].hash())
    def testLayerMapping(self):

        constant1 = GafferImage.Constant()
        constant1['color'].setValue(imath.Color4f(0.1, 0.2, 0.3, 0.4))
        constant1["format"].setValue(GafferImage.Format(10, 10, 1.000))

        metadata1 = GafferImage.ImageMetadata()
        metadata1["in"].setInput(constant1["out"])
        metadata1["metadata"].addChild(Gaffer.NameValuePlug("test", 1))

        constant2 = GafferImage.Constant()
        constant2['color'].setValue(imath.Color4f(0.2, 0.4, 0.6, 0.8))
        constant2["format"].setValue(GafferImage.Format(20, 20, 1.000))

        metadata2 = GafferImage.ImageMetadata()
        metadata2["in"].setInput(constant2["out"])
        metadata2["metadata"].addChild(Gaffer.NameValuePlug("test", 2))

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

        e = Gaffer.Expression()
        switch.addChild(e)
        e.setExpression(
            'parent["index"] = context["collect:layerName"] != "A"', "python")

        collect = GafferImage.CollectImages()
        collect["in"].setInput(switch["out"])

        # Metadata and format are driven by the first layer

        collect["rootLayers"].setValue(IECore.StringVectorData(['A', 'B']))
        self.assertEqual(collect["out"]["format"].getValue(),
                         GafferImage.Format(10, 10, 1))
        self.assertEqual(collect["out"]["metadata"].getValue(),
                         IECore.CompoundData({"test": 1}))

        collect["rootLayers"].setValue(IECore.StringVectorData(['B', 'A']))
        self.assertEqual(collect["out"]["format"].getValue(),
                         GafferImage.Format(20, 20, 1))
        self.assertEqual(collect["out"]["metadata"].getValue(),
                         IECore.CompoundData({"test": 2}))

        collect["rootLayers"].setValue(IECore.StringVectorData([]))
        self.assertEqual(
            collect["out"]["format"].getValue(),
            constant1["format"].getDefaultFormat(Gaffer.Context.current()))
        self.assertEqual(collect["out"]["metadata"].getValue(),
                         IECore.CompoundData())

        sampler = GafferImage.ImageSampler("ImageSampler")
        sampler["pixel"].setValue(imath.V2f(1, 1))
        sampler["channels"].setValue(
            IECore.StringVectorData(["A.R", "A.G", "A.B", "A.A"]))
        sampler["image"].setInput(collect["out"])

        collect["rootLayers"].setValue(IECore.StringVectorData(['A']))

        self.assertEqual(list(collect["out"]["channelNames"].getValue()),
                         ["A.R", "A.G", "A.B", "A.A"])
        self.assertEqual(sampler["color"].getValue(),
                         imath.Color4f(0.1, 0.2, 0.3, 0.4))

        # Test simple duplicate
        collect["rootLayers"].setValue(IECore.StringVectorData(['A', 'A']))

        self.assertEqual(list(collect["out"]["channelNames"].getValue()),
                         ["A.R", "A.G", "A.B", "A.A"])
        self.assertEqual(sampler["color"].getValue(),
                         imath.Color4f(0.1, 0.2, 0.3, 0.4))

        collect["rootLayers"].setValue(IECore.StringVectorData(['A', 'B']))
        self.assertEqual(
            list(collect["out"]["channelNames"].getValue()),
            ["A.R", "A.G", "A.B", "A.A", "B.R", "B.G", "B.B", "B.A"])
        self.assertEqual(sampler["color"].getValue(),
                         imath.Color4f(0.1, 0.2, 0.3, 0.4))
        sampler["channels"].setValue(
            IECore.StringVectorData(["B.R", "B.G", "B.B", "B.A"]))
        self.assertEqual(sampler["color"].getValue(),
                         imath.Color4f(0.2, 0.4, 0.6, 0.8))

        # Test overlapping names take the first layer
        constant1["layer"].setValue("B")
        collect["rootLayers"].setValue(IECore.StringVectorData(['A', 'A.B']))
        sampler["channels"].setValue(
            IECore.StringVectorData(["A.B.R", "A.B.G", "A.B.B", "A.B.A"]))
        self.assertEqual(list(collect["out"]["channelNames"].getValue()),
                         ["A.B.R", "A.B.G", "A.B.B", "A.B.A"])
        self.assertEqual(sampler["color"].getValue(),
                         imath.Color4f(0.1, 0.2, 0.3, 0.4))
        collect["rootLayers"].setValue(IECore.StringVectorData(['A.B', 'A']))
        self.assertEqual(list(collect["out"]["channelNames"].getValue()),
                         ["A.B.R", "A.B.G", "A.B.B", "A.B.A"])
        self.assertEqual(sampler["color"].getValue(),
                         imath.Color4f(0.2, 0.4, 0.6, 0.8))
Exemple #30
0
    def testBoxPromotion(self):

        s = Gaffer.ScriptNode()

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

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

        def assertPreconditions(script):

            self.assertEqual(script["b"]["n"]["p"].keys(), [])
            self.assertEqual(script["b"]["p"].keys(), [])
            self.assertTrue(script["b"]["n"]["p"].getInput().isSame(
                script["b"]["p"]))

        def assertPostconditions(script):

            self.assertEqual(script["b"]["p"].keys(), ["test"])
            self.assertEqual(script["b"]["n"]["p"].keys(), ["test"])

            self.assertEqual(script["b"]["p"]["test"].keys(),
                             ["name", "value"])
            self.assertEqual(script["b"]["n"]["p"]["test"].keys(),
                             ["name", "value"])

            self.assertTrue(script["b"]["n"]["p"].getInput().isSame(
                script["b"]["p"]))
            self.assertTrue(script["b"]["n"]["p"]["test"].getInput().isSame(
                script["b"]["p"]["test"]))
            self.assertTrue(
                script["b"]["n"]["p"]["test"]["name"].getInput().isSame(
                    script["b"]["p"]["test"]["name"]))
            self.assertTrue(
                script["b"]["n"]["p"]["test"]["value"].getInput().isSame(
                    script["b"]["p"]["test"]["value"]))

        assertPreconditions(s)

        with Gaffer.UndoScope(s):

            p.addChild(
                Gaffer.NameValuePlug(
                    "test", 10, "test", Gaffer.Plug.Direction.In,
                    Gaffer.Plug.Flags.Default | Gaffer.Plug.Flags.Dynamic))

        assertPostconditions(s)

        s.undo()
        assertPreconditions(s)

        s.redo()
        assertPostconditions(s)

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

        assertPostconditions(s2)