From 38337a3fc709e5b42d9efe00bebe78e169e3b0c4 Mon Sep 17 00:00:00 2001 From: John Haddon Date: Fri, 6 Sep 2024 12:27:06 +0100 Subject: [PATCH] RenderPassWedge : Support customisation via render adaptors This allows passes to be conditionally enabled/disabled based on pipeline-specific queries. --- Changes.md | 1 + python/GafferScene/RenderPassWedge.py | 8 +- python/GafferSceneTest/RenderPassWedgeTest.py | 76 +++++++++++++++++++ python/GafferSceneUI/RenderPassWedgeUI.py | 12 +++ 4 files changed, 95 insertions(+), 2 deletions(-) diff --git a/Changes.md b/Changes.md index a074fd462d6..183a92c4ec4 100644 --- a/Changes.md +++ b/Changes.md @@ -26,6 +26,7 @@ API --- - MetadataWidget : Added `NumericMetadataWidget` class. +- RenderPassWedge : Render adaptors may now be used to delete and/or disable render passes, by passing `client = "RenderPassWedge"` to `SceneAlgo.registerRenderAdaptor()`. Build ----- diff --git a/python/GafferScene/RenderPassWedge.py b/python/GafferScene/RenderPassWedge.py index 89caf27a35f..84a2691b5f9 100644 --- a/python/GafferScene/RenderPassWedge.py +++ b/python/GafferScene/RenderPassWedge.py @@ -51,6 +51,10 @@ def __init__( self, name = "RenderPassWedge" ) : self["out"].setInput( self["in"] ) self["out"].setFlags( Gaffer.Plug.Flags.Serialisable, False ) + self["__Adaptor"] = GafferScene.SceneAlgo.createRenderAdaptors() + self["__Adaptor"]["in"].setInput( self["in"] ) + self["__Adaptor"]["client"].setValue( "RenderPassWedge" ) + self["__ContextQuery"] = Gaffer.ContextQuery() self["__ContextQuery"].addQuery( Gaffer.IntPlug( defaultValue = 1 ) ) self["__ContextQuery"].addQuery( Gaffer.StringPlug() ) @@ -58,8 +62,8 @@ def __init__( self, name = "RenderPassWedge" ) : self["__ContextQuery"]["queries"][1]["name"].setValue( "renderPass" ) self["__TimeWarp"] = Gaffer.TimeWarp() - self["__TimeWarp"].setup( self["in"] ) - self["__TimeWarp"]["in"].setInput( self["in"] ) + self["__TimeWarp"].setup( self["__Adaptor"]["out"] ) + self["__TimeWarp"]["in"].setInput( self["__Adaptor"]["out"] ) self["__TimeWarp"]["speed"].setValue( 0 ) self["__TimeWarp"]["offset"].setInput( self["__ContextQuery"]["out"][0]["value"] ) diff --git a/python/GafferSceneTest/RenderPassWedgeTest.py b/python/GafferSceneTest/RenderPassWedgeTest.py index 032816de5d9..ad14dd095fb 100644 --- a/python/GafferSceneTest/RenderPassWedgeTest.py +++ b/python/GafferSceneTest/RenderPassWedgeTest.py @@ -248,5 +248,81 @@ def testPassNamesEvaluationUsesScriptStartFrame( self ) : } ) + def testAdaptorDeletingPasses( self ) : + + def createAdaptor() : + + node = GafferScene.DeleteRenderPasses() + node["names"].setValue( "fx*" ) + return node + + GafferScene.SceneAlgo.registerRenderAdaptor( "RenderPassWedgeTest", createAdaptor, client = "RenderPassWedge" ) + self.addCleanup( GafferScene.SceneAlgo.deregisterRenderAdaptor, "RenderPassWedgeTest" ) + + script = Gaffer.ScriptNode() + + script["renderPasses"] = GafferScene.RenderPasses() + script["renderPasses"]["names"].setValue( IECore.StringVectorData( [ "char1", "char2", "fx1", "fx2" ] ) ) + + script["log"] = GafferDispatchTest.LoggingTaskNode() + script["log"]["dependsOnPass"] = Gaffer.StringPlug( defaultValue = "${renderPass}" ) + + script["wedge"] = GafferScene.RenderPassWedge() + script["wedge"]["preTasks"].next().setInput( script["log"]["task"] ) + script["wedge"]["in"].setInput( script["renderPasses"]["out"] ) + + script["dispatcher"] = self.__dispatcher() + script["dispatcher"]["tasks"].next().setInput( script["wedge"]["task"] ) + script["dispatcher"]["task"].execute() + + self.assertEqual( + { l.context["renderPass"] for l in script["log"].log }, + { "char1", "char2" } + ) + + def testAdaptorDisablingPasses( self ) : + + def createAdaptor() : + + node = GafferScene.SceneProcessor() + node["options"] = GafferScene.CustomOptions() + node["options"]["in"].setInput( node["in"] ) + node["options"]["options"].addChild( Gaffer.NameValuePlug( "renderPass:enabled", False ) ) + + node["switch"] = Gaffer.NameSwitch() + node["switch"].setup( node["options"]["out"] ) + node["switch"]["in"][0]["value"].setInput( node["in"] ) + node["switch"]["in"][1]["value"].setInput( node["options"]["out"] ) + node["switch"]["in"][1]["name"].setValue( "char*" ) + node["switch"]["selector"].setValue( "${renderPass}" ) + + node["out"].setInput( node["switch"]["out"]["value"] ) + + return node + + GafferScene.SceneAlgo.registerRenderAdaptor( "RenderPassWedgeTest", createAdaptor, client = "RenderPassWedge" ) + self.addCleanup( GafferScene.SceneAlgo.deregisterRenderAdaptor, "RenderPassWedgeTest" ) + + script = Gaffer.ScriptNode() + + script["renderPasses"] = GafferScene.RenderPasses() + script["renderPasses"]["names"].setValue( IECore.StringVectorData( [ "char1", "char2", "fx1", "fx2" ] ) ) + + script["log"] = GafferDispatchTest.LoggingTaskNode() + script["log"]["dependsOnPass"] = Gaffer.StringPlug( defaultValue = "${renderPass}" ) + + script["wedge"] = GafferScene.RenderPassWedge() + script["wedge"]["preTasks"].next().setInput( script["log"]["task"] ) + script["wedge"]["in"].setInput( script["renderPasses"]["out"] ) + + script["dispatcher"] = self.__dispatcher() + script["dispatcher"]["tasks"].next().setInput( script["wedge"]["task"] ) + script["dispatcher"]["task"].execute() + + self.assertEqual( + { l.context["renderPass"] for l in script["log"].log }, + { "fx1", "fx2" } + ) + if __name__ == "__main__": unittest.main() diff --git a/python/GafferSceneUI/RenderPassWedgeUI.py b/python/GafferSceneUI/RenderPassWedgeUI.py index 0f4af4852a7..405fc661f75 100644 --- a/python/GafferSceneUI/RenderPassWedgeUI.py +++ b/python/GafferSceneUI/RenderPassWedgeUI.py @@ -61,6 +61,18 @@ Specific passes can be disabled from wedging by setting the `renderPass:enabled` option to `False` in contexts where that render pass name is the value of the `renderPass` context variable. + + Customisation + ------------- + + The behaviour of the RenderPassWedge node can be customised by registering + an adaptor that conditionally deletes, renames or disables passes. A common + use case is to conditionally enable passes on a per-shot basis according to + the presence or absence of particular assets within the scene. + + Adaptors should be registered using a client value of "RenderPassWedge" - for example : + + `GafferScene.SceneAlgo.registerRenderAdaptor( "MyConditionalPassAdaptor", adaptorCreationFunction, client = "RenderPassWedge" )` """, plugs = {