diff --git a/Changes.md b/Changes.md index 6cd99ff400d..6280f891ccc 100644 --- a/Changes.md +++ b/Changes.md @@ -5,6 +5,7 @@ Fixes ----- - DisplayTransform : Fixed missing `view` presets when `display` is at the default value (#5392). +- Cycles : The background light's lightgroup is now being set correctly as well as adding a way to set a lightgroup from CyclesOptions when a CyclesBackground is being used instead. 1.3.0.0 (relative to 1.2.10.0) ======= diff --git a/python/GafferCyclesTest/IECoreCyclesPreviewTest/RendererTest.py b/python/GafferCyclesTest/IECoreCyclesPreviewTest/RendererTest.py index 3bfcce70402..1b92cf2eae2 100644 --- a/python/GafferCyclesTest/IECoreCyclesPreviewTest/RendererTest.py +++ b/python/GafferCyclesTest/IECoreCyclesPreviewTest/RendererTest.py @@ -1128,7 +1128,7 @@ def testShaderSubstitutions( self ) : self.assertEqual( self.__colorAtUV( image, imath.V2f( 0.48, 0.5 ) ), imath.Color4f( 1, 0, 0, 1 ) ) self.assertEqual( self.__colorAtUV( image, imath.V2f( 0.52, 0.5 ) ), imath.Color4f( 0, 1, 0, 1 ) ) - def __colorAtUV( self, image, uv, channelName = "" ) : + def __colorAtUV( self, image, uv, channelName = "", alpha = True ) : dimensions = image.dataWindow.size() + imath.V2i( 1 ) @@ -1140,7 +1140,11 @@ def __colorAtUV( self, image, uv, channelName = "" ) : if c != "": c = "%s." % channelName - return imath.Color4f( image[c+"R"][i], image[c+"G"][i], image[c+"B"][i], image[c+"A"][i] ) + a = 1 + if alpha: + a = image[c+"A"][i] + + return imath.Color4f( image[c+"R"][i], image[c+"G"][i], image[c+"B"][i], a ) def __testCustomAttributeType( self, primitive, prefix, customAttribute, outputPlug, data, expectedResult, maxDifference = 0.0 ) : @@ -1823,5 +1827,86 @@ def testUnsupportedShaderParameters( self ) : "Unsupported socket type `transform` for socket `ob_tfm` on node .*" ) + def testBackgroundLightgroup( self ) : + + renderer = GafferScene.Private.IECoreScenePreview.Renderer.create( + "Cycles", + GafferScene.Private.IECoreScenePreview.Renderer.RenderType.Interactive, + ) + + renderer.output( + "testOutput", + IECoreScene.Output( + "test", + "ieDisplay", + "rgba", + { + "driverType" : "ImageDisplayDriver", + "handle" : "testOutput", + } + ) + ) + + renderer.output( + "testEnvOutput", + IECoreScene.Output( + "env", + "ieDisplay", + "lg env", + { + "driverType" : "ImageDisplayDriver", + "handle" : "testEnvOutput", + } + ) + ) + + renderer.light( + "/light", + None, + renderer.attributes( IECore.CompoundObject ( { + "cycles:light" : IECoreScene.ShaderNetwork( + shaders = { + "output" : IECoreScene.Shader( "background_light", "cycles:light", { "color" : imath.Color3f( 0, 1, 0 ), "lightgroup" : "env" } ), + }, + output = "output", + ), + } ) ) + ) + + plane = renderer.object( + "/plane", + IECoreScene.MeshPrimitive.createPlane( + imath.Box2f( imath.V2f( -1 ), imath.V2f( 1 ) ), + ), + renderer.attributes( IECore.CompoundObject ( { + "cycles:surface" : IECoreScene.ShaderNetwork( + shaders = { + "output" : IECoreScene.Shader( + "principled_bsdf", "cycles:shader", + { "base_color" : imath.Color3f( 1, 1, 1 ) } + ), + }, + output = "output", + ) + } ) ) + ) + ## \todo Default camera is facing down +ve Z but should be facing + # down -ve Z. + plane.transform( imath.M44f().translate( imath.V3f( 0, 0, 1 ) ) ) + + renderer.render() + time.sleep( 2 ) + + image = IECoreImage.ImageDisplayDriver.storedImage( "testEnvOutput" ) + self.assertIsInstance( image, IECoreImage.ImagePrimitive ) + + # Slightly off-centre, to avoid triangle edge artifact in centre of image. + testPixel = self.__colorAtUV( image, imath.V2f( 0.55 ), "env", False ) + self.assertEqual( testPixel.r, 0 ) + self.assertGreater( testPixel.g, 0.99 ) + self.assertEqual( testPixel.b, 0 ) + + del plane + if __name__ == "__main__": unittest.main() diff --git a/python/GafferCyclesUI/CyclesOptionsUI.py b/python/GafferCyclesUI/CyclesOptionsUI.py index 92879ba5f65..52fe31e89e9 100644 --- a/python/GafferCyclesUI/CyclesOptionsUI.py +++ b/python/GafferCyclesUI/CyclesOptionsUI.py @@ -302,6 +302,9 @@ def __backgroundSummary( plug ) : if plug["bgTransparentRoughnessThreshold"]["enabled"].getValue() : info.append( "Roughness Threshold {}".format( plug["bgTransparentRoughnessThreshold"]["value"].getValue() ) ) + if plug["bgLightgroup"]["enabled"].getValue() : + info.append( "Lightgroup {}".format( plug["bgLightgroup"]["value"].getValue() ) ) + for childName in ( "Camera", "Diffuse", "Glossy", "Transmission", "Shadow", "Scatter" ) : if plug["bg" + childName + "Visibility"]["enabled"].getValue() : info.append( IECore.CamelCase.toSpaced( childName ) + ( " On" if plug["bg" + childName + "Visibility"]["value"].getValue() else " Off" ) ) @@ -1309,6 +1312,20 @@ def __devicesPreset() : ], + "options.bgLightgroup" : [ + + "description", + """ + The background lightgroup name. This will only be set if a + CyclesBackground is used instead of a background light, + otherwise it will use the lightgroup name from the light itself. + """, + + "layout:section", "Background", + "label", "Lightgroup", + + ], + # Film "options.exposure" : [ diff --git a/src/GafferCycles/CyclesOptions.cpp b/src/GafferCycles/CyclesOptions.cpp index 094bb8309f2..1830ad0da74 100644 --- a/src/GafferCycles/CyclesOptions.cpp +++ b/src/GafferCycles/CyclesOptions.cpp @@ -144,6 +144,8 @@ CyclesOptions::CyclesOptions( const std::string &name ) options->addChild( new Gaffer::NameValuePlug( "cycles:background:volume_step_size", new IECore::FloatData( 0.1f ), false, "volumeStepSize" ) ); + options->addChild( new Gaffer::NameValuePlug( "cycles:background:lightgroup", new IECore::StringData( "" ), false, "bgLightgroup" ) ); + // Film options->addChild( new Gaffer::NameValuePlug( "cycles:film:exposure", new IECore::FloatData( 1.0f ), false, "exposure" ) ); options->addChild( new Gaffer::NameValuePlug( "cycles:film:pass_alpha_threshold", new IECore::FloatData( 0.5f ), false, "passAlphaThreshold" ) ); diff --git a/src/GafferCycles/IECoreCyclesPreview/Renderer.cpp b/src/GafferCycles/IECoreCyclesPreview/Renderer.cpp index aed9ba33f36..e813073f20c 100644 --- a/src/GafferCycles/IECoreCyclesPreview/Renderer.cpp +++ b/src/GafferCycles/IECoreCyclesPreview/Renderer.cpp @@ -2459,8 +2459,9 @@ IECore::InternedString g_numBvhTimeStepsOptionName( "cycles:scene:num_bvh_time_s IECore::InternedString g_hairSubdivisionsOptionName( "cycles:scene:hair_subdivisions" ); IECore::InternedString g_hairShapeOptionName( "cycles:scene:hair_shape" ); IECore::InternedString g_textureLimitOptionName( "cycles:scene:texture_limit" ); -// Background shader +// Background IECore::InternedString g_backgroundShaderOptionName( "cycles:background:shader" ); +IECore::InternedString g_backgroundLightgroupOptionName( "cycles:background:lightgroup" ); // IECore::InternedString g_useFrameAsSeedOptionName( "cycles:integrator:useFrameAsSeed" ); IECore::InternedString g_seedOptionName( "cycles:integrator:seed" ); @@ -2524,6 +2525,7 @@ class CyclesRenderer final : public IECoreScenePreview::Renderer #ifdef WITH_CYCLES_TEXTURE_CACHE m_textureCacheParams( ccl::TextureCacheParams() ), #endif + m_backgroundLightgroup( ccl::ustring( "" ) ), m_deviceName( g_defaultDeviceName ), m_renderType( renderType ), m_frame( 1 ), @@ -2959,6 +2961,17 @@ class CyclesRenderer final : public IECoreScenePreview::Renderer m_backgroundShader = nullptr; } } + else if( name == g_backgroundLightgroupOptionName ) + { + if( value == nullptr ) + { + m_backgroundLightgroup = ccl::ustring( "" ); + } + else if ( const StringData *data = reportedCast( value, "option", name ) ) + { + m_backgroundLightgroup = ccl::ustring( data->readable() ); + } + } else if( const Data *data = reportedCast( value, "option", name ) ) { SocketAlgo::setSocket( (ccl::Node*)background, input, data ); @@ -3387,11 +3400,14 @@ class CyclesRenderer final : public IECoreScenePreview::Renderer } ccl::Shader *lightShader = nullptr; + ccl::ustring lightGroup = ccl::ustring(""); + for( ccl::Light *light : m_scene->lights ) { if( light->get_light_type() == ccl::LIGHT_BACKGROUND ) { lightShader = light->get_shader(); + lightGroup = light->get_lightgroup(); break; } } @@ -3403,14 +3419,17 @@ class CyclesRenderer final : public IECoreScenePreview::Renderer if( m_backgroundShader ) { background->set_shader( m_backgroundShader->shader() ); + background->set_lightgroup( m_backgroundLightgroup ); } else if( lightShader ) { background->set_shader( lightShader ); + background->set_lightgroup( lightGroup ); } else { background->set_shader( m_scene->default_background ); + background->set_lightgroup( m_backgroundLightgroup ); } if( integrator->is_modified() ) @@ -3895,8 +3914,9 @@ class CyclesRenderer final : public IECoreScenePreview::Renderer ccl::Background m_background; ccl::Film m_film; - // Background shader + // Background CyclesShaderPtr m_backgroundShader; + ccl::ustring m_backgroundLightgroup; // Defaults ccl::Camera m_cameraDefault;