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)
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")
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)
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
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))
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" )
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")
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 )
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")
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>")
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)
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"})
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)
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))
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' ])
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
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)
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)
def testTransformPlug(self): p = Gaffer.NameValuePlug("a", Gaffer.TransformPlug()) self.assertEqual(p["value"].matrix(), imath.M44f())
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"])
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"))
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)
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))
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)