Skip to content

Commit

Permalink
OptionInspector : Enable render pass specific option edits
Browse files Browse the repository at this point in the history
When an edit is created from a context containing `renderPass`, create an
option edit specifically for that render pass. This is in order to enable the
upcoming Render Pass Editor UI to display and edit options that vary based
on the value of `${renderPass}`.
  • Loading branch information
murraystevenson committed Dec 14, 2023
1 parent 1498eac commit 03191cd
Show file tree
Hide file tree
Showing 2 changed files with 421 additions and 25 deletions.
354 changes: 352 additions & 2 deletions python/GafferSceneUITest/OptionInspectorTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,12 @@ def testName( self ) :
self.assertEqual( inspector.name(), "option:foo" )

@staticmethod
def __inspect( scene, optionName, editScope = None ) :
def __inspect( scene, optionName, editScope = None, context = Gaffer.Context() ) :

editScopePlug = Gaffer.Plug()
editScopePlug.setInput( editScope["enabled"] if editScope is not None else None )
inspector = GafferSceneUI.Private.OptionInspector( scene, editScopePlug, optionName )
with Gaffer.Context() as context :
with context :
return inspector.inspect()

def __assertExpectedResult(
Expand Down Expand Up @@ -425,5 +425,355 @@ def testReadOnlyMetadataSignalling( self ) :
Gaffer.MetadataAlgo.setReadOnly( editScope, True )
self.assertEqual( len( cs ), 2 ) # Change affects the result of `inspect().editable()`

def testRenderPassValues( self ) :

options = GafferScene.StandardOptions()
options["options"]["renderCamera"]["enabled"].setValue( True )
options["options"]["renderCamera"]["value"].setValue( "/defaultCamera" )

spreadsheet = Gaffer.Spreadsheet()
spreadsheet["selector"].setValue( "${renderPass}" )
spreadsheet["rows"].addColumn( options["options"]["renderCamera"]["value"] )
options["options"]["renderCamera"]["value"].setInput( spreadsheet["out"][0] )

rowA = spreadsheet["rows"].addRow()
rowA["name"].setValue( "renderPassA" )
rowA["cells"][0]["value"].setValue( "/cameraA" )

rowB = spreadsheet["rows"].addRow()
rowB["name"].setValue( "renderPassB" )
rowB["cells"][0]["value"].setValue( "/cameraB" )

with Gaffer.Context() as context :

self.assertEqual(
self.__inspect( options["out"], "render:camera", context = context ).value().value,
"/defaultCamera"
)

context["renderPass"] = "renderPassA"
self.assertEqual(
self.__inspect( options["out"], "render:camera", context = context ).value().value,
"/cameraA"
)

context["renderPass"] = "renderPassB"
self.assertEqual(
self.__inspect( options["out"], "render:camera", context = context ).value().value,
"/cameraB"
)

context["renderPass"] = "renderPassC"
self.assertEqual(
self.__inspect( options["out"], "render:camera", context = context ).value().value,
"/defaultCamera"
)

def testRenderPassSourceAndEdits( self ) :

s = Gaffer.ScriptNode()

s["standardOptions"] = GafferScene.StandardOptions()
s["standardOptions"]["options"]["renderCamera"]["enabled"].setValue( True )
s["standardOptions"]["options"]["renderCamera"]["value"].setValue( "/defaultCamera" )

s["group"] = GafferScene.Group()
s["editScope1"] = Gaffer.EditScope()
s["editScope2"] = Gaffer.EditScope()

s["group"]["in"][0].setInput( s["standardOptions"]["out"] )

s["editScope1"].setup( s["group"]["out"] )
s["editScope1"]["in"].setInput( s["group"]["out"] )

s["editScope2"].setup( s["editScope1"]["out"] )
s["editScope2"]["in"].setInput( s["editScope1"]["out"] )

with Gaffer.Context() as context :

context["renderPass"] = "renderPassA"

# Should be able to edit standardOptions directly.

SourceType = GafferSceneUI.Private.Inspector.Result.SourceType

self.__assertExpectedResult(
self.__inspect( s["group"]["out"], "render:camera", context = context ),
source = s["standardOptions"]["options"]["renderCamera"],
sourceType = SourceType.Other,
editable = True,
edit = s["standardOptions"]["options"]["renderCamera"]
)

# Even if there is an edit scope in the way

self.__assertExpectedResult(
self.__inspect( s["editScope1"]["out"], "render:camera", context = context ),
source = s["standardOptions"]["options"]["renderCamera"],
sourceType = SourceType.Other,
editable = True,
edit = s["standardOptions"]["options"]["renderCamera"]
)

# We shouldn't be able to edit it if we've been told to use an EditScope and it isn't in the history
self.__assertExpectedResult(
self.__inspect( s["group"]["out"], "render:camera", s["editScope1"], context ),
source = s["standardOptions"]["options"]["renderCamera"],
sourceType = SourceType.Other,
editable = False,
nonEditableReason = "The target EditScope (editScope1) is not in the scene history."
)

# If it is in the history though, and we're told to use it, then we will.

inspection = self.__inspect( s["editScope2"]["out"], "render:camera", s["editScope2"], context )
self.assertIsNone(
GafferScene.EditScopeAlgo.acquireRenderPassOptionEdit(
s["editScope2"], "renderPassA", "render:camera", createIfNecessary = False
)
)

self.__assertExpectedResult(
inspection,
source = s["standardOptions"]["options"]["renderCamera"],
sourceType = SourceType.Upstream,
editable = True
)

optionEditScope2Edit = inspection.acquireEdit()
self.assertIsNotNone( optionEditScope2Edit )
self.assertEqual(
optionEditScope2Edit,
GafferScene.EditScopeAlgo.acquireRenderPassOptionEdit(
s["editScope2"], "renderPassA", "render:camera", createIfNecessary = False
)
)

# If there's an edit downstream of the EditScope we're asked to use,
# then we're allowed to be editable still

inspection = self.__inspect( s["editScope2"]["out"], "render:camera", s["editScope1"], context )
self.assertTrue( inspection.editable() )
self.assertEqual( inspection.nonEditableReason(), "" )
self.assertEqual(
inspection.acquireEdit(),
GafferScene.EditScopeAlgo.acquireRenderPassOptionEdit(
s["editScope1"], "renderPassA", "render:camera", createIfNecessary = False
)
)
self.assertEqual( inspection.editWarning(), "" )

# If there is a source node inside an edit scope, make sure we use that

s["editScope1"]["standardOptions2"] = GafferScene.StandardOptions()
s["editScope1"]["standardOptions2"]["options"]["resolutionMultiplier"]["enabled"].setValue( True )
s["editScope1"]["standardOptions2"]["options"]["resolutionMultiplier"]["value"].setValue( 4.0 )
s["editScope1"]["standardOptions2"]["in"].setInput( s["editScope1"]["BoxIn"]["out"] )
s["editScope1"]["RenderPassOptionEdits"]["in"].setInput( s["editScope1"]["standardOptions2"]["out"] )

self.__assertExpectedResult(
self.__inspect( s["editScope2"]["out"], "render:resolutionMultiplier", s["editScope1"], context ),
source = s["editScope1"]["standardOptions2"]["options"]["resolutionMultiplier"],
sourceType = SourceType.EditScope,
editable = True,
edit = s["editScope1"]["standardOptions2"]["options"]["resolutionMultiplier"]
)

# If there is a OptionTweaks node in the scope's processor, make sure we use that

cameraEdit = GafferScene.EditScopeAlgo.acquireRenderPassOptionEdit(
s["editScope1"], "renderPassA", "render:camera", createIfNecessary = True
)
cameraEdit["enabled"].setValue( True )
cameraEdit["value"].setValue( "/bar" )

self.__assertExpectedResult(
self.__inspect( s["editScope2"]["out"], "render:camera", s["editScope1"], context ),
source = cameraEdit,
sourceType = SourceType.EditScope,
editable = True,
edit = cameraEdit
)

# If there is a StandardOptions node downstream of the scope's scene processor, make sure we use that

s["editScope1"]["standardOptions3"] = GafferScene.StandardOptions()
s["editScope1"]["standardOptions3"]["options"]["renderCamera"]["enabled"].setValue( True )
s["editScope1"]["standardOptions3"]["options"]["renderCamera"]["value"].setValue( "/baz" )
s["editScope1"]["standardOptions3"]["in"].setInput( s["editScope1"]["RenderPassOptionEdits"]["out"] )
s["editScope1"]["BoxOut"]["in"].setInput( s["editScope1"]["standardOptions3"]["out"] )

self.__assertExpectedResult(
self.__inspect( s["editScope2"]["out"], "render:camera", s["editScope1"], context ),
source = s["editScope1"]["standardOptions3"]["options"]["renderCamera"],
sourceType = SourceType.EditScope,
editable = True,
edit = s["editScope1"]["standardOptions3"]["options"]["renderCamera"]
)

# If there is a StandardOptions node outside of an edit scope, make sure we use that with no scope

s["independentOptions"] = GafferScene.StandardOptions()
s["independentOptions"]["options"]["renderCamera"]["enabled"].setValue( True )
s["independentOptions"]["options"]["renderCamera"]["value"].setValue( "/camera" )
s["independentOptions"]["in"].setInput( s["editScope2"]["out"] )

self.__assertExpectedResult(
self.__inspect( s["independentOptions"]["out"], "render:camera", None, context ),
source = s["independentOptions"]["options"]["renderCamera"],
sourceType = SourceType.Other,
editable = True,
edit = s["independentOptions"]["options"]["renderCamera"]
)

# Check editWarnings and nonEditableReasons

self.__assertExpectedResult(
self.__inspect( s["independentOptions"]["out"], "render:camera", s["editScope2"], context ),
source = s["independentOptions"]["options"]["renderCamera"],
sourceType = SourceType.Downstream,
editable = True,
edit = optionEditScope2Edit,
editWarning = "Option has edits downstream in independentOptions."
)

s["editScope2"]["enabled"].setValue( False )

self.__assertExpectedResult(
self.__inspect( s["independentOptions"]["out"], "render:camera", s["editScope2"], context ),
source = s["independentOptions"]["options"]["renderCamera"],
sourceType = SourceType.Downstream,
editable = False,
nonEditableReason = "The target EditScope (editScope2) is disabled."
)

s["editScope2"]["enabled"].setValue( True )
Gaffer.MetadataAlgo.setReadOnly( s["editScope2"], True )

self.__assertExpectedResult(
self.__inspect( s["editScope2"]["out"], "render:camera", s["editScope2"], context ),
source = s["editScope1"]["standardOptions3"]["options"]["renderCamera"],
sourceType = SourceType.Upstream,
editable = False,
nonEditableReason = "editScope2 is locked."
)

Gaffer.MetadataAlgo.setReadOnly( s["editScope2"], False )
Gaffer.MetadataAlgo.setReadOnly( s["editScope2"]["RenderPassOptionEdits"]["edits"], True )

self.__assertExpectedResult(
self.__inspect( s["editScope2"]["out"], "render:camera", s["editScope2"], context ),
source = s["editScope1"]["standardOptions3"]["options"]["renderCamera"],
sourceType = SourceType.Upstream,
editable = False,
nonEditableReason = "editScope2.RenderPassOptionEdits.edits is locked."
)

Gaffer.MetadataAlgo.setReadOnly( s["editScope2"]["RenderPassOptionEdits"], True )
self.__assertExpectedResult(
self.__inspect( s["editScope2"]["out"], "render:camera", s["editScope2"], context ),
source = s["editScope1"]["standardOptions3"]["options"]["renderCamera"],
sourceType = SourceType.Upstream,
editable = False,
nonEditableReason = "editScope2.RenderPassOptionEdits is locked."
)

def testMultipleRenderPassOptionEdits( self ) :

s = Gaffer.ScriptNode()

s["standardOptions"] = GafferScene.StandardOptions()
s["standardOptions"]["options"]["renderCamera"]["enabled"].setValue( True )
s["standardOptions"]["options"]["renderCamera"]["value"].setValue( "/defaultCamera" )

s["customOptions"] = GafferScene.CustomOptions()
s["customOptions"]["in"].setInput( s["standardOptions"]["out"] )
s["customOptions"]["options"].addChild( Gaffer.NameValuePlug( "renderPass:type", "default" ) )

s["editScope1"] = Gaffer.EditScope()
s["editScope2"] = Gaffer.EditScope()

s["editScope1"].setup( s["customOptions"]["out"] )
s["editScope1"]["in"].setInput( s["customOptions"]["out"] )

s["editScope2"].setup( s["editScope1"]["out"] )
s["editScope2"]["in"].setInput( s["editScope1"]["out"] )

renderPasses = [ "renderPassA", "renderPassB", "gafferBot_beauty" ]

def assertRenderPassEdits( renderPass, option, defaultValue ) :

with Gaffer.Context() as context :
context["renderPass"] = renderPass

inspection = self.__inspect( s["editScope1"]["out"], option, s["editScope1"], context )
self.assertTrue( inspection.editable() )
self.assertEqual( inspection.nonEditableReason(), "" )
editScope1Edit = inspection.acquireEdit()
self.assertEqual(
editScope1Edit,
GafferScene.EditScopeAlgo.acquireRenderPassOptionEdit(
s["editScope1"], renderPass, option, createIfNecessary = False
)
)
self.assertEqual( inspection.editWarning(), "" )

self.assertEqual(
self.__inspect( s["editScope1"]["out"], option, context = context ).value().value,
defaultValue
)

editScope1Value = "/editScope1/{}".format( renderPass )
editScope1Edit["enabled"].setValue( True )
editScope1Edit["value"].setValue( editScope1Value )

inspection = self.__inspect( s["editScope2"]["out"], option, s["editScope2"], context )
self.assertTrue( inspection.editable() )
self.assertEqual( inspection.nonEditableReason(), "" )
editScope2Edit = inspection.acquireEdit()
self.assertEqual(
editScope2Edit,
GafferScene.EditScopeAlgo.acquireRenderPassOptionEdit(
s["editScope2"], renderPass, option, createIfNecessary = False
)
)
self.assertEqual( inspection.editWarning(), "" )

self.assertEqual(
self.__inspect( s["editScope2"]["out"], option, context = context ).value().value,
editScope1Value
)

editScope2Edit["enabled"].setValue( True )
editScope2Edit["value"].setValue( "/editScope2/{}".format( renderPass ) )

def assertRenderPassEditResults( renderPass, option ) :

with Gaffer.Context() as context :
context["renderPass"] = renderPass

self.assertEqual(
self.__inspect( s["editScope1"]["out"], option, context = context ).value().value,
"/editScope1/{}".format( renderPass )
)

self.assertEqual(
self.__inspect( s["editScope2"]["out"], option, context = context ).value().value,
"/editScope2/{}".format( renderPass )
)

for option, defaultValue in [
( "render:camera", "/defaultCamera" ),
( "renderPass:type", "default" ),
] :
for renderPass in renderPasses :
with self.subTest( renderPass = renderPass, option = option, defaultValue = defaultValue ) :
assertRenderPassEdits( renderPass, option, defaultValue )

for option in [ "render:camera", "renderPass:type" ] :
for renderPass in renderPasses :
with self.subTest( renderPass = renderPass, option = option ) :
assertRenderPassEditResults( renderPass, option )

if __name__ == "__main__" :
unittest.main()
Loading

0 comments on commit 03191cd

Please sign in to comment.