Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RenderPassEditor : Camera visibility and matte columns #5733

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ Improvements
- USD : Added automatic render-time translation of UsdPreviewSurface shaders to Cycles.
- SetEditor : Added support for dragging a set name onto a node in the Graph Editor to create or modify a connected `SetFilter` node. Holding <kbd>Shift</kbd> while dragging will add to the set expression. Holding <kbd>Control</kbd> will remove from the set expression. Only set expressions with a simple list of sets are supported. Expressions with boolean or hierarchy operators are not supported.
- GraphEditor : Improved pointer used to indicate when dropping a location would find the source node.
- RenderPassEditor :
- Added "Camera Inclusions" and "Camera Exclusions" columns, providing control over the camera visibility of scene locations in each render pass.
- Added "Matte Inclusions" and "Matte Exclusions" columns, providing control over the scene locations used as holdout mattes in each render pass.

Fixes
-----
Expand Down
303 changes: 111 additions & 192 deletions doc/examples/rendering/renderPassEditorArnold.gfr

Large diffs are not rendered by default.

260 changes: 260 additions & 0 deletions python/GafferSceneTest/RenderAdaptorTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -413,3 +413,263 @@ def assertIncludedObjects( scene, paths, inclusions = None, exclusions = None, a
additionalLights = "C",
exclusions = "( __lights - C ) | /group/groupA"
)

def testCameraVisibilityAdaptor( self ) :

# /groupA
# /cube (A, CUBE)
# /sphere (A, SPHERE)

cubeA = GafferScene.Cube()
cubeA["sets"].setValue( "A CUBE" )

sphereA = GafferScene.Sphere()
sphereA["sets"].setValue( "A SPHERE" )

groupA = GafferScene.Group()
groupA["name"].setValue( "groupA" )
groupA["in"][0].setInput( cubeA["out"] )
groupA["in"][1].setInput( sphereA["out"] )

customOptions = GafferScene.CustomOptions()
customOptions["in"].setInput( groupA["out"] )
customOptions["options"].addChild( Gaffer.NameValuePlug( "render:cameraInclusions", "", False, "cameraInclusions" ) )
customOptions["options"].addChild( Gaffer.NameValuePlug( "render:cameraExclusions", "", True, "cameraExclusions" ) )

inclusionAttributesFilter = GafferScene.SetFilter()
inclusionAttributes = GafferScene.CustomAttributes()
inclusionAttributes["in"].setInput( customOptions["out"] )
inclusionAttributes["filter"].setInput( inclusionAttributesFilter["out"] )
inclusionAttributes["attributes"].addChild( Gaffer.NameValuePlug( "ai:visibility:camera", True, True ) )
inclusionAttributes["attributes"].addChild( Gaffer.NameValuePlug( "cycles:visibility:camera", True, True ) )
inclusionAttributes["attributes"].addChild( Gaffer.NameValuePlug( "dl:visibility.camera", True, True ) )

exclusionAttributesFilter = GafferScene.SetFilter()
exclusionAttributes = GafferScene.CustomAttributes()
exclusionAttributes["in"].setInput( inclusionAttributes["out"] )
exclusionAttributes["filter"].setInput( exclusionAttributesFilter["out"] )
exclusionAttributes["attributes"].addChild( Gaffer.NameValuePlug( "ai:visibility:camera", False, True ) )
exclusionAttributes["attributes"].addChild( Gaffer.NameValuePlug( "cycles:visibility:camera", False, True ) )
exclusionAttributes["attributes"].addChild( Gaffer.NameValuePlug( "dl:visibility.camera", False, True ) )

# Create adaptors for the CapturingRenderer
testAdaptors = GafferScene.SceneAlgo.createRenderAdaptors()
testAdaptors["in"].setInput( exclusionAttributes["out"] )

def assertCameraVisibleObjects( paths, cameraInclusions = None, cameraExclusions = None, inclusionOverrides = "", exclusionOverrides = "" ) :

if cameraInclusions is not None :
customOptions["options"]["cameraInclusions"]["value"].setValue( cameraInclusions )
customOptions["options"]["cameraInclusions"]["enabled"].setValue( cameraInclusions is not None )

if cameraExclusions is not None :
customOptions["options"]["cameraExclusions"]["value"].setValue( cameraExclusions )
customOptions["options"]["cameraExclusions"]["enabled"].setValue( cameraExclusions is not None )

inclusionAttributesFilter["setExpression"].setValue( inclusionOverrides )
exclusionAttributesFilter["setExpression"].setValue( exclusionOverrides )

allPaths = {
"/groupA/cube",
"/groupA/sphere",
}

renderer = GafferScene.Private.IECoreScenePreview.CapturingRenderer(
GafferScene.Private.IECoreScenePreview.Renderer.RenderType.Batch
)
GafferScene.Private.RendererAlgo.outputObjects(
testAdaptors["out"], GafferScene.Private.RendererAlgo.RenderOptions( testAdaptors["out"] ), GafferScene.Private.RendererAlgo.RenderSets( testAdaptors["out"] ), GafferScene.Private.RendererAlgo.LightLinks(),
renderer
)

if paths != {} :
self.assertTrue( paths.issubset( allPaths ) )

for path in allPaths :
capturedObject = renderer.capturedObject( path )
for attribute in [ "ai:visibility:camera", "cycles:visibility:camera", "dl:visibility.camera" ] :
if path in paths :
# path is visible by the absence of the attribute, or its presence with a value of True
if attribute in capturedObject.capturedAttributes().attributes() :
self.assertTrue( capturedObject.capturedAttributes().attributes()[attribute].value )
else :
# path is invisible only by the presence of the attribute with a value of False
self.assertTrue( attribute in capturedObject.capturedAttributes().attributes() )
self.assertFalse( capturedObject.capturedAttributes().attributes()[attribute].value )

# By default everything should be camera visible
assertCameraVisibleObjects( { "/groupA/cube", "/groupA/sphere" } )

# All should be visible with the root included
assertCameraVisibleObjects( { "/groupA/cube", "/groupA/sphere" }, cameraInclusions = "/" )

# All should be visible with the group included
assertCameraVisibleObjects( { "/groupA/cube", "/groupA/sphere" }, cameraInclusions = "/groupA" )

# Only the included location should be visible
assertCameraVisibleObjects( { "/groupA/sphere" }, cameraInclusions = "/groupA/sphere" )

# Nothing should be visible if nothing is included
assertCameraVisibleObjects( {}, cameraInclusions = "" )

# Test a variety of cameraInclusions set expressions
assertCameraVisibleObjects( { "/groupA/cube", "/groupA/sphere" }, cameraInclusions = "A" )
assertCameraVisibleObjects( { "/groupA/sphere" }, cameraInclusions = "SPHERE" )
assertCameraVisibleObjects( { "/groupA/cube" }, cameraInclusions = "CUBE" )
assertCameraVisibleObjects( { "/groupA/cube" }, cameraInclusions = "A - SPHERE" )

# Test a variety of cameraExclusions set expressions
assertCameraVisibleObjects( {}, cameraExclusions = "A" )
assertCameraVisibleObjects( { "/groupA/cube" }, cameraExclusions = "SPHERE" )
assertCameraVisibleObjects( { "/groupA/sphere" }, cameraExclusions = "CUBE" )
assertCameraVisibleObjects( { "/groupA/sphere" }, cameraExclusions = "A - SPHERE" )

# Camera exclusions overrides camera inclusions at the same location
assertCameraVisibleObjects( {}, cameraInclusions = "A", cameraExclusions = "A" )

# Camera exclusions overrides camera inclusions at a parent location
assertCameraVisibleObjects( {}, cameraInclusions = "/", cameraExclusions = "A" )

# Test a variety of camera inclusions and exclusions combinations
assertCameraVisibleObjects( { "/groupA/sphere" }, cameraInclusions = "A", cameraExclusions = "CUBE" )
assertCameraVisibleObjects( { "/groupA/sphere" }, cameraInclusions = "/groupA", cameraExclusions = "CUBE" )
assertCameraVisibleObjects( { "/groupA/cube" }, cameraInclusions = "A", cameraExclusions = "SPHERE" )
assertCameraVisibleObjects( { "/groupA/cube" }, cameraInclusions = "/groupA", cameraExclusions = "SPHERE" )

# Camera inclusions overrides camera exclusions at lower locations
assertCameraVisibleObjects( { "/groupA/sphere" }, cameraInclusions = "/groupA/sphere", cameraExclusions = "/groupA" )
assertCameraVisibleObjects( { "/groupA/sphere" }, cameraInclusions = "SPHERE", cameraExclusions = "/groupA" )

# Excluding nothing should leave everything visible
assertCameraVisibleObjects( { "/groupA/cube", "/groupA/sphere" }, cameraExclusions = "" )

# Test interaction with scene attributes
assertCameraVisibleObjects( { "/groupA/sphere" }, cameraInclusions = "A", exclusionOverrides = "/groupA/cube" )
assertCameraVisibleObjects( { "/groupA/cube", "/groupA/sphere" }, cameraInclusions = "A", exclusionOverrides = "/groupA" )
assertCameraVisibleObjects( { "/groupA/cube", "/groupA/sphere" }, cameraInclusions = "CUBE", inclusionOverrides = "/groupA/sphere" )
assertCameraVisibleObjects( { "/groupA/cube", "/groupA/sphere" }, cameraInclusions = "", inclusionOverrides = "A" )
assertCameraVisibleObjects( {}, cameraInclusions = "/", exclusionOverrides = "A" )

def testMatteAdaptor( self ) :

# /groupA
# /cube (A, CUBE)
# /sphere (A, SPHERE)

cubeA = GafferScene.Cube()
cubeA["sets"].setValue( "A CUBE" )

sphereA = GafferScene.Sphere()
sphereA["sets"].setValue( "A SPHERE" )

groupA = GafferScene.Group()
groupA["name"].setValue( "groupA" )
groupA["in"][0].setInput( cubeA["out"] )
groupA["in"][1].setInput( sphereA["out"] )

customOptions = GafferScene.CustomOptions()
customOptions["in"].setInput( groupA["out"] )
customOptions["options"].addChild( Gaffer.NameValuePlug( "render:matteInclusions", "", True, "matteInclusions" ) )
customOptions["options"].addChild( Gaffer.NameValuePlug( "render:matteExclusions", "", True, "matteExclusions" ) )

inclusionAttributesFilter = GafferScene.SetFilter()
inclusionAttributes = GafferScene.CustomAttributes()
inclusionAttributes["in"].setInput( customOptions["out"] )
inclusionAttributes["filter"].setInput( inclusionAttributesFilter["out"] )
inclusionAttributes["attributes"].addChild( Gaffer.NameValuePlug( "ai:matte", True, True, "aiMatte" ) )
inclusionAttributes["attributes"].addChild( Gaffer.NameValuePlug( "cycles:use_holdout", True, True, "cyclesUseHoldout" ) )
inclusionAttributes["attributes"].addChild( Gaffer.NameValuePlug( "dl:matte", True, True, "dlMatte" ) )

exclusionAttributesFilter = GafferScene.SetFilter()
exclusionAttributes = GafferScene.CustomAttributes()
exclusionAttributes["in"].setInput( inclusionAttributes["out"] )
exclusionAttributes["filter"].setInput( exclusionAttributesFilter["out"] )
exclusionAttributes["attributes"].addChild( Gaffer.NameValuePlug( "ai:matte", False, True, "aiMatte" ) )
exclusionAttributes["attributes"].addChild( Gaffer.NameValuePlug( "cycles:use_holdout", False, True, "cyclesUseHoldout" ) )
exclusionAttributes["attributes"].addChild( Gaffer.NameValuePlug( "dl:matte", False, True, "dlMatte" ) )

# Create adaptors for the CapturingRenderer
testAdaptors = GafferScene.SceneAlgo.createRenderAdaptors()
testAdaptors["in"].setInput( exclusionAttributes["out"] )

def assertMatte( paths, matteInclusions = None, matteExclusions = None, inclusionOverrides = "", exclusionOverrides = "" ) :

if matteInclusions is not None :
customOptions["options"]["matteInclusions"]["value"].setValue( matteInclusions )
customOptions["options"]["matteInclusions"]["enabled"].setValue( matteInclusions is not None )

if matteExclusions is not None :
customOptions["options"]["matteExclusions"]["value"].setValue( matteExclusions )
customOptions["options"]["matteExclusions"]["enabled"].setValue( matteExclusions is not None )

inclusionAttributesFilter["setExpression"].setValue( inclusionOverrides )
exclusionAttributesFilter["setExpression"].setValue( exclusionOverrides )

allPaths = {
"/groupA/cube",
"/groupA/sphere",
}

renderer = GafferScene.Private.IECoreScenePreview.CapturingRenderer(
GafferScene.Private.IECoreScenePreview.Renderer.RenderType.Batch
)
GafferScene.Private.RendererAlgo.outputObjects(
testAdaptors["out"], GafferScene.Private.RendererAlgo.RenderOptions( testAdaptors["out"] ), GafferScene.Private.RendererAlgo.RenderSets( testAdaptors["out"] ), GafferScene.Private.RendererAlgo.LightLinks(),
renderer
)

for path in allPaths :
capturedObject = renderer.capturedObject( path )
for attribute in [ "ai:matte", "cycles:use_holdout", "dl:matte" ] :
if path in paths :
# path is matte only by the presence of the attribute with a value of True
self.assertTrue( attribute in capturedObject.capturedAttributes().attributes() )
self.assertTrue( capturedObject.capturedAttributes().attributes()[attribute].value )
else :
# path isn't matte by the absence of the attribute, or its presence with a value of False
if attribute in capturedObject.capturedAttributes().attributes() :
self.assertFalse( capturedObject.capturedAttributes().attributes()[attribute].value )

# Nothing should be matte when matte inclusions and exclusions are empty or undefined
assertMatte( {} )
assertMatte( {}, matteInclusions = "" )
assertMatte( {}, matteExclusions = "" )
assertMatte( {}, matteInclusions = "", matteExclusions = "" )

# Including the root of the scene should make everything matte
assertMatte( { "/groupA/cube", "/groupA/sphere" }, matteInclusions = "/" )

# Including the group should make its descendants matte
assertMatte( { "/groupA/cube", "/groupA/sphere" }, matteInclusions = "/groupA" )
# Unless a descendant has been excluded
assertMatte( { "/groupA/cube" }, matteInclusions = "/groupA", matteExclusions = "/groupA/sphere" )

# Including a specific location should not affect its siblings
assertMatte( { "/groupA/cube" }, matteInclusions = "/groupA/cube" )

# Test a variety of set expressions
assertMatte( { "/groupA/cube", "/groupA/sphere" }, matteInclusions = "A" )
assertMatte( { "/groupA/sphere" }, matteInclusions = "SPHERE" )
assertMatte( { "/groupA/cube" }, matteInclusions = "CUBE" )
assertMatte( { "/groupA/sphere" }, matteInclusions = "A - CUBE" )

# Exclusions should override inclusions
assertMatte( {}, matteInclusions = "A", matteExclusions = "A" )
assertMatte( {}, matteInclusions = "/groupA/sphere", matteExclusions = "/groupA/sphere" )
assertMatte( { "/groupA/sphere" }, matteInclusions = "A", matteExclusions = "CUBE" )
assertMatte( { "/groupA/cube" }, matteInclusions = "/groupA", matteExclusions = "SPHERE" )
assertMatte( { "/groupA/sphere" }, matteInclusions = "A", matteExclusions = "/groupA/cube" )

# Matte inclusions override matte exclusions at lower locations
assertMatte( { "/groupA/sphere" }, matteInclusions = "/groupA/sphere", matteExclusions = "/groupA" )

# Test interaction with scene attributes
assertMatte( { "/groupA/sphere" }, inclusionOverrides = "/groupA/sphere" )
assertMatte( { "/groupA/cube", "/groupA/sphere" }, matteInclusions = "/groupA/cube", inclusionOverrides = "/groupA/sphere" )
assertMatte( { "/groupA/sphere" }, matteExclusions = "/groupA/sphere", inclusionOverrides = "/groupA/sphere" )
assertMatte( { "/groupA/sphere" }, matteExclusions = "/groupA", inclusionOverrides = "/groupA/sphere" )
assertMatte( { "/groupA/cube", "/groupA/sphere" }, matteInclusions = "/groupA", matteExclusions = "/groupA/sphere", inclusionOverrides = "/groupA/sphere" )

assertMatte( {}, matteInclusions = "/groupA/sphere", exclusionOverrides = "/groupA/sphere" )
assertMatte( { "/groupA/sphere" }, matteInclusions = "/groupA/sphere", exclusionOverrides = "/groupA" )
assertMatte( { "/groupA/sphere" }, matteInclusions = "/groupA", exclusionOverrides = "/groupA/cube" )
Loading
Loading