diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 5e979f80ecb..6215adf3356 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -86,6 +86,7 @@ jobs: env: ARNOLD_LICENSE_ORDER: none # Don't waste time looking for a license that doesn't exist + ARNOLD_FORCE_ABORT_ON_LICENSE_FAIL: 0 # And don't abort because the license isn't found GAFFER_BUILD_DIR: "./build" GAFFER_CACHE_DIR: "./sconsCache" @@ -189,7 +190,7 @@ jobs: import sys import os - for arnoldVersion in [ "7.2.1.0" ] : + for arnoldVersion in [ "7.2.1.0", "7.3.1.0" ] : arnoldRoot = os.path.join( os.environ["GITHUB_WORKSPACE"], "arnoldRoot", arnoldVersion ) os.environ["ARNOLD_ROOT"] = arnoldRoot diff --git a/Changes.md b/Changes.md index 2e48483334c..778c22e82f0 100644 --- a/Changes.md +++ b/Changes.md @@ -4,6 +4,7 @@ Features -------- +- Arnold : Added support for Arnold 7.3. Note that a minimum of 7.3.1.0 is required, meaning that 7.3.0.0 is _not_ supported. - SelectionTool : Added select mode plug. When set to anything except `Standard` using the SelectionTool causes the actual scene location selected to potentially be modified from the originally selected location. Selection modifiers work identically for deselection. Currently, two selectors are implemented : - USD Kind : When selecting, the first ancestor location with a `usd:kind` attribute matching the chosen list of USD Kind will ultimately be selected. USD's Kind Registry includes `Assembly`, `Component`, `Group`, `Model` and `SubComponent` by default and can be extended via USD startup scripts. - Shader Assignment : When selecting, the first ancestor location with a renderable and direct (not inherited) shader attribute will ultimately be selected. This can be used to select either surface or displacement shaders. @@ -13,6 +14,7 @@ Improvements - EditScope : Added a summary of edits in the NodeEditor, with the ability to select the affected objects and quickly navigate to the processor nodes. - Arnold : OSL shaders with connections from multiple outputs are no longer duplicated on export to Arnold. +- ArnoldShader : Added parameter tooltips based on `help` metadata provided by Arnold. Fixes ----- diff --git a/python/GafferArnoldTest/ArnoldColorManagerTest.py b/python/GafferArnoldTest/ArnoldColorManagerTest.py index 8a0b4464a1b..5636e8e799e 100644 --- a/python/GafferArnoldTest/ArnoldColorManagerTest.py +++ b/python/GafferArnoldTest/ArnoldColorManagerTest.py @@ -36,6 +36,8 @@ import unittest +import arnold + import IECore import IECoreScene @@ -48,6 +50,21 @@ class ArnoldColorManagerTest( GafferSceneTest.SceneTestCase ) : + def __expectedOCIOParameters( self, **kw ) : + + result = { + "color_space_linear" : "", + "color_space_narrow" : "", + "config" : "", + } + + if [ int( x ) for x in arnold.AiGetVersion()[:2] ] >= [ 7, 3 ] : + result |= { + "ignore_environment_variable" : False, + } + + return IECore.CompoundData( result | kw ) + def test( self ) : # Loading @@ -95,11 +112,7 @@ def test( self ) : self.assertEqual( cm.outputShader().type, "ai:color_manager" ) self.assertEqual( cm.outputShader().parameters, - IECore.CompoundData( { - "color_space_linear" : "linear", - "color_space_narrow" : "", - "config" : "", - } ) + self.__expectedOCIOParameters( color_space_linear = "linear" ) ) colorManager["enabled"].setValue( False ) @@ -148,11 +161,7 @@ def assertColorManager( scene, config, linear, narrow ) : self.assertEqual( shader.type, "ai:color_manager" ) self.assertEqual( shader.parameters, - IECore.CompoundData( { - "config" : config, - "color_space_linear" : linear, - "color_space_narrow" : narrow, - } ) + self.__expectedOCIOParameters( config = config, color_space_linear = linear, color_space_narrow = narrow ) ) with Gaffer.Context() as context : diff --git a/python/GafferArnoldTest/InteractiveArnoldRenderTest.py b/python/GafferArnoldTest/InteractiveArnoldRenderTest.py index ba1c9f26989..fbe1d2ee9cc 100644 --- a/python/GafferArnoldTest/InteractiveArnoldRenderTest.py +++ b/python/GafferArnoldTest/InteractiveArnoldRenderTest.py @@ -299,7 +299,8 @@ def testQuadLightTextureEdits( self ) : s["Light"].loadShader( "quad_light" ) s["Light"]["transform"]["translate"]["z"].setValue( 2 ) s["Light"]["parameters"]["color"].setInput( s["Tex"]["out"] ) - s["Light"]["parameters"]["exposure"].setValue( 4 ) + s["Light"]["parameters"]["exposure"].setValue( 6 ) + s["Light"]["parameters"]["samples"].setValue( 6 ) s["c"] = GafferScene.Camera() s["c"]["transform"]["translate"]["z"].setValue( 2 ) @@ -341,7 +342,7 @@ def testQuadLightTextureEdits( self ) : self.uiThreadCallHandler.waitFor( 1.0 ) initialColor = self._color4fAtUV( s["catalogue"], imath.V2f( 0.5 ) ) - self.assertAlmostEqual( initialColor.r, 0.09, delta = 0.013 ) + self.assertAlmostEqual( initialColor.r, 0.58, delta = 0.02 ) self.assertAlmostEqual( initialColor.g, 0, delta = 0.01 ) # Edit texture network and make sure the changes take effect @@ -352,7 +353,7 @@ def testQuadLightTextureEdits( self ) : updateColor = self._color4fAtUV( s["catalogue"], imath.V2f( 0.5 ) ) self.assertAlmostEqual( updateColor.r, 0, delta = 0.01 ) - self.assertAlmostEqual( updateColor.g, 0.06, delta = 0.022 ) + self.assertAlmostEqual( updateColor.g, 0.3, delta = 0.02 ) s["r"]["state"].setValue( s["r"].State.Stopped ) diff --git a/python/GafferArnoldUI/ArnoldShaderUI.py b/python/GafferArnoldUI/ArnoldShaderUI.py index 57ef2328f37..2852f2c97e2 100644 --- a/python/GafferArnoldUI/ArnoldShaderUI.py +++ b/python/GafferArnoldUI/ArnoldShaderUI.py @@ -205,6 +205,8 @@ def __translateNodeMetadata( nodeEntry ) : # Shader description. We support Arnold-style "desc" and # OSL style "help". + ## \todo It seems that Arnold's standard is now "help", so + # we may be able to remove "desc". description = __aiMetadataGetStr( nodeEntry, None, "desc", defaultValue = __aiMetadataGetStr( nodeEntry, None, "help" ) @@ -245,7 +247,10 @@ def __translateNodeMetadata( nodeEntry ) : # Parameter description - description = __aiMetadataGetStr( nodeEntry, paramName, "desc" ) + description = __aiMetadataGetStr( + nodeEntry, paramName, "desc", + defaultValue = __aiMetadataGetStr( nodeEntry, paramName, "help" ) + ) if description is not None : __metadata[paramPath]["description"] = description diff --git a/python/GafferArnoldUI/ShaderMenu.py b/python/GafferArnoldUI/ShaderMenu.py index 6047a8d9332..388eed18621 100644 --- a/python/GafferArnoldUI/ShaderMenu.py +++ b/python/GafferArnoldUI/ShaderMenu.py @@ -46,6 +46,11 @@ import GafferUI import GafferArnold +if [ int( x ) for x in arnold.AiGetVersion()[:3] ] < [ 7, 3, 1 ] : + __AI_NODE_IMAGER = arnold.AI_NODE_DRIVER +else : + __AI_NODE_IMAGER = arnold.AI_NODE_IMAGER + ## \todo Rename. This isn't about loading shaders, it's about loading all sorts # of Arnold node definitions. def appendShaders( menuDefinition, prefix="/Arnold" ) : @@ -58,7 +63,7 @@ def appendShaders( menuDefinition, prefix="/Arnold" ) : uncategorisedMenuItems = [] with IECoreArnold.UniverseBlock( writable = False ) : - it = arnold.AiUniverseGetNodeEntryIterator( arnold.AI_NODE_SHADER | arnold.AI_NODE_LIGHT | arnold.AI_NODE_COLOR_MANAGER | arnold.AI_NODE_DRIVER ) + it = arnold.AiUniverseGetNodeEntryIterator( arnold.AI_NODE_SHADER | arnold.AI_NODE_LIGHT | arnold.AI_NODE_COLOR_MANAGER | __AI_NODE_IMAGER ) while not arnold.AiNodeEntryIteratorFinished( it ) : @@ -88,11 +93,12 @@ def appendShaders( menuDefinition, prefix="/Arnold" ) : nodeCreator = functools.partial( __colorManagerCreator, shaderName, nodeName ) displayName = displayName.replace( "Color Manager ", "" ) else : - assert( arnold.AiNodeEntryGetType( nodeEntry ) == arnold.AI_NODE_DRIVER ) - # Imagers don't yet have their own node type, but we can - # identify them using metadata. - if __aiMetadataGetStr( nodeEntry, "", "subtype" ) != "imager" : - continue + assert( arnold.AiNodeEntryGetType( nodeEntry ) == __AI_NODE_IMAGER ) + if [ int( x ) for x in arnold.AiGetVersion()[:3] ] < [ 7, 3, 1 ] : + # Imagers masquerade as drivers, but we can identify them + # using metadata. + if __aiMetadataGetStr( nodeEntry, "", "subtype" ) != "imager" : + continue menuPath = "Globals/Imager" nodeCreator = functools.partial( __shaderCreator, shaderName, GafferArnold.ArnoldShader, nodeName ) displayName = displayName.replace( "Imager ", "" ) diff --git a/python/IECoreArnoldTest/ParameterAlgoTest.py b/python/IECoreArnoldTest/ParameterAlgoTest.py index cfd2c923269..0f189affc97 100644 --- a/python/IECoreArnoldTest/ParameterAlgoTest.py +++ b/python/IECoreArnoldTest/ParameterAlgoTest.py @@ -73,7 +73,7 @@ def testGetParameter( self ) : IECore.FloatData( arnold.AiNodeGetFlt( n, "base" ) ) ) - IECore.FloatData( arnold.AiNodeSetStr( n, "name", "testString" ) ) + arnold.AiNodeSetStr( n, "name", "testString" ) self.assertEqual( IECoreArnold.ParameterAlgo.getParameter( n, "name" ), IECore.StringData( "testString" ), diff --git a/python/IECoreArnoldTest/RendererTest.py b/python/IECoreArnoldTest/RendererTest.py index 89f533d7cf4..0907a6bac75 100644 --- a/python/IECoreArnoldTest/RendererTest.py +++ b/python/IECoreArnoldTest/RendererTest.py @@ -739,6 +739,9 @@ def testOutputFilters( self ) : arnold.AiSceneLoad( universe, str( self.temporaryDirectory() / "test.ass" ), None ) filters = self.__allNodes( universe, type = arnold.AI_NODE_FILTER ) + # Ignore node created automatically by Arnold itself. + filters = [ f for f in filters if arnold.AiNodeGetName( f ) != "_forced_box_filter" ] + self.assertEqual( len( filters ), 1 ) f = filters[0] diff --git a/src/GafferArnold/ArnoldShader.cpp b/src/GafferArnold/ArnoldShader.cpp index 5fce4449013..4fd3d4ed973 100644 --- a/src/GafferArnold/ArnoldShader.cpp +++ b/src/GafferArnold/ArnoldShader.cpp @@ -53,6 +53,7 @@ #include "fmt/format.h" #include "ai_metadata.h" +#include "ai_version.h" using namespace std; using namespace boost; @@ -63,6 +64,10 @@ using namespace GafferArnold; using namespace Gaffer; using namespace GafferOSL; +#if ARNOLD_VERSION_NUM < 70301 +#define AI_NODE_IMAGER AI_NODE_DRIVER +#endif + namespace { @@ -152,7 +157,7 @@ void ArnoldShader::loadShader( const std::string &shaderName, bool keepExistingV case AI_NODE_COLOR_MANAGER : type = "ai:color_manager"; break; - case AI_NODE_DRIVER : + case AI_NODE_IMAGER : type = "ai:imager"; break; default : diff --git a/src/GafferArnold/ParameterHandler.cpp b/src/GafferArnold/ParameterHandler.cpp index 5119d65f5bd..ca2426542ac 100644 --- a/src/GafferArnold/ParameterHandler.cpp +++ b/src/GafferArnold/ParameterHandler.cpp @@ -51,6 +51,7 @@ #include "boost/container/flat_set.hpp" #include "ai_metadata.h" +#include "ai_version.h" using namespace std; using namespace Imath; @@ -59,6 +60,10 @@ using namespace IECore; using namespace Gaffer; using namespace GafferArnold; +#if ARNOLD_VERSION_NUM < 70301 +#define AI_NODE_IMAGER AI_NODE_DRIVER +#endif + namespace { @@ -288,7 +293,7 @@ Gaffer::Plug *setupClosurePlug( const IECore::InternedString ¶meterName, Gaf Gaffer::Plug *setupNodePlug( const AtNodeEntry *nodeEntry, const InternedString ¶meterName, GraphComponent *plugParent, Plug::Direction direction ) { - if( AiNodeEntryGetType( nodeEntry ) == AI_NODE_DRIVER && parameterName == "input" ) + if( AiNodeEntryGetType( nodeEntry ) == AI_NODE_IMAGER && parameterName == "input" ) { return setupPlug( parameterName, plugParent, direction ); } diff --git a/startup/gui/menus.py b/startup/gui/menus.py index c643c983682..3ecf267cdcd 100644 --- a/startup/gui/menus.py +++ b/startup/gui/menus.py @@ -137,12 +137,14 @@ def addHelpMenuItems( items ) : GafferArnoldUI.CacheMenu.appendDefinitions( scriptWindowMenu, "/Tools/Arnold" ) - scriptWindowMenu.append( - "/Tools/Arnold/Populate GPU Cache", - { - "command" : GafferArnoldUI.GPUCache.populateGPUCache, - } - ) + if [ int( x ) for x in arnold.AiGetVersion()[:2] ] < [ 7, 3 ] : + # `AiGPUCachePopulate` was removed in Arnold 7.3.0.0. + scriptWindowMenu.append( + "/Tools/Arnold/Populate GPU Cache", + { + "command" : GafferArnoldUI.GPUCache.populateGPUCache, + } + ) except Exception as m :