diff --git a/python/IECoreDelightTest/RendererTest.py b/python/IECoreDelightTest/RendererTest.py index 90442048335..5a82cf43908 100644 --- a/python/IECoreDelightTest/RendererTest.py +++ b/python/IECoreDelightTest/RendererTest.py @@ -91,7 +91,7 @@ def testOutput( self ) : "rgba", { "filter" : "gaussian", - "filterwidth" : imath.V2f( 3.5 ), + "filterwidth" : 3.5, } ) ) @@ -156,7 +156,7 @@ def testAOVs( self ) : data, { "filter" : "gaussian", - "filterwidth" : imath.V2f( 3.5 ), + "filterwidth" : 3.5, } ) ) @@ -1498,7 +1498,7 @@ def testOutputLayerNames( self ) : renderer.output( "customLayerName", - IECoreScene.Output( "customLayerName.exr", "exr", "color shader:diffuse.direct", { "layerName" : "myLayerName" } ) + IECoreScene.Output( "customLayerName.exr", "exr", "color shader:diffuse.direct", { "layername" : "myLayerName" } ) ) renderer.render() @@ -1510,6 +1510,56 @@ def testOutputLayerNames( self ) : self.assertEqual( nsi["outputLayer:directDiffuse"]["layername"], "diffuse_direct" ) self.assertEqual( nsi["outputLayer:customLayerName"]["layername"], "myLayerName" ) + def testOutputLayerAttributes( self ) : + + for data, expected in { + "rgba" : { + "variablename": "Ci", + "variablesource": "shader", + "layertype": "color", + "withalpha": 1, + "filter": "gaussian", + "filterwidth": 3.5, + "scalarformat": "half", + "colorprofile": "sRGB", + "layername": "Test", + "dithering": 1 + }, + }.items() : + + r = GafferScene.Private.IECoreScenePreview.Renderer.create( + "3Delight", + GafferScene.Private.IECoreScenePreview.Renderer.RenderType.SceneDescription, + str( self.temporaryDirectory() / "test.nsia" ) + ) + + r.output( + "test", + IECoreScene.Output( + "beauty.exr", + "exr", + data, + { + "filter": "gaussian", + "filterwidth": 3.5, + "scalarformat": "half", + "colorprofile": "sRGB", + "layername": "Test", + "dithering": 1 + } + ) + ) + + r.render() + del r + + nsi = self.__parseDict( self.temporaryDirectory() / "test.nsia" ) + self.assertIn( "outputLayer:test", nsi ) + self.assertEqual( nsi["outputLayer:test"]["nodeType"], "outputlayer") + for k, v in expected.items() : + self.assertIn( k, nsi["outputLayer:test"] ) + self.assertEqual( nsi["outputLayer:test"][k], v ) + # Helper methods used to check that NSI files we write contain what we # expect. The 3delight API only allows values to be set, not queried, # so we build a simple dictionary-based node graph for now. diff --git a/src/IECoreDelight/Renderer.cpp b/src/IECoreDelight/Renderer.cpp index 0ddbe55910b..0b5bb1661c0 100644 --- a/src/IECoreDelight/Renderer.cpp +++ b/src/IECoreDelight/Renderer.cpp @@ -269,10 +269,7 @@ class DelightOutput : public IECore::RefCounted ParameterList driverParams; for( const auto &[parameterName, parameterValue] : output->parameters() ) { - // We can't pass `filter` to the driver, because although it's not - // documented as an attribute (and it _is_ documented that additional - // arbitrary attributes are allowed), 3Delight complains. - if( parameterName != "filter" ) + if( parameterName != "filter" && parameterName != "filterwidth" && parameterName != "scalarformat" && parameterName != "colorprofile" && parameterName != "layername" && parameterName != "withalpha" ) { driverParams.add( parameterName.c_str(), parameterValue.get() ); } @@ -371,7 +368,7 @@ class DelightOutput : public IECore::RefCounted scalarFormat = "float"; } - layerName = parameter( output->parameters(), "layerName", layerName ); + layerName = parameter( output->parameters(), "layername", layerName ); ParameterList layerParams; @@ -381,7 +378,8 @@ class DelightOutput : public IECore::RefCounted layerParams.add( "layername", layerName ); layerParams.add( { "withalpha", &withAlpha, NSITypeInteger, 0, 1, 0 } ); - string colorProfile = "linear"; + scalarFormat = parameter( output->parameters(), "scalarformat", scalarFormat ); + string colorProfile = parameter( output->parameters(), "colorprofile", "linear" ); if( scalarFormat.empty() ) { scalarFormat = this->scalarFormat( output ); @@ -397,6 +395,20 @@ class DelightOutput : public IECore::RefCounted } layerParams.add( "filter", filter ); + const double filterWidth = parameter( output->parameters(), "filterwidth", 3.0 ); + if( filterWidth != 3.0 ) + { + layerParams.add( { "filterwidth", &filterWidth, NSITypeDouble, 0, 1, 0 } ); + } + + for( const auto &[parameterName, parameterValue] : output->parameters() ) + { + if( parameterName != "filter" && parameterName != "filterwidth" && parameterName != "scalarformat" && parameterName != "colorprofile" && parameterName != "layername" ) + { + layerParams.add( parameterName.c_str(), parameterValue.get() ); + } + } + m_layerHandle = DelightHandle( context, "outputLayer:" + name, ownership, "outputlayer", layerParams ); NSIConnect( @@ -425,7 +437,7 @@ class DelightOutput : public IECore::RefCounted { return "uint8"; } - else if( quantize == vector( { 0, 65536, 0, 65536 } ) ) + else if( quantize == vector( { 0, 65535, 0, 65535 } ) ) { return "uint16"; } diff --git a/startup/gui/outputs.py b/startup/gui/outputs.py index 15997a6f514..9f10e6ee823 100644 --- a/startup/gui/outputs.py +++ b/startup/gui/outputs.py @@ -186,6 +186,7 @@ # See `contrib/scripts/3delightOutputs.py` in this repository for a helper script. for name, displayName, source, dataType in [ + ( "rgba", "Beauty", "", "" ), ( "Ci", "Ci", "shader", "color" ), ( "Ci.direct", "Ci (direct)", "shader", "color" ), ( "Ci.indirect", "Ci (indirect)", "shader", "color" ), @@ -225,27 +226,46 @@ ( "motionvector", "Motion Vector", "builtin", "point" ), ( "occlusion", "Ambient Occlusion", "shader", "color" ), ] : + if name == "rgba" : + space = "" + separator = "" + slash = "" + else : + space = " " + separator = ":" + slash ="/" + GafferScene.Outputs.registerOutput( - "Interactive/3Delight/{}/{}".format( source.capitalize(), displayName ), + "Interactive/3Delight/{}{}{}".format( source.capitalize(), slash, displayName ), IECoreScene.Output( name, "ieDisplay", - "{} {}:{}".format( dataType, source, name ), + "{}{}{}{}{}".format( dataType, space, source, separator, name ), { "driverType" : "ClientDisplayDriver", "displayHost" : "localhost", "displayPort" : "${image:catalogue:port}", "remoteDisplayType" : "GafferImage::GafferDisplayDriver", + "scalarformat" : "half", + "colorprofile" : "linear", + "filter" : "blackman-harris", + "filterwidth" : 3.0, } ) ) GafferScene.Outputs.registerOutput( - "Batch/3Delight/{}/{}".format( source.capitalize(), displayName ), + "Batch/3Delight/{}{}{}".format( source.capitalize(), slash, displayName ), IECoreScene.Output( "${project:rootDirectory}/renders/${script:name}/${renderPass}/%s/%s.####.exr" % ( name, name ), "exr", - "{} {}:{}".format( dataType, source, name ), + "{}{}{}{}{}".format( dataType, space, source, separator, name ), + { + "scalarformat" : "half", + "colorprofile" : "linear", + "filter" : "blackman-harris", + "filterwidth" : 3.0, + } ) )