Skip to content

Commit

Permalink
Merge branch '1.3_maintenance'
Browse files Browse the repository at this point in the history
  • Loading branch information
johnhaddon committed Mar 20, 2024
2 parents 68d6793 + 39d3217 commit a63e385
Show file tree
Hide file tree
Showing 9 changed files with 220 additions and 69 deletions.
12 changes: 12 additions & 0 deletions Changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Improvements

- LightPosition Tool : The tool is now only visible for members of the `__lights` set, instead of all objects.
- Catalogue : Added `imageNames` output plug, containing the names of all images in the Catalogue. Among other things this can be used to drive a Wedge or ContactSheet node and a CatalogueSelect.
- Render, InteractiveRender : Added `resolvedRenderer` plug, which outputs the name of the renderer that will be used, taking into account the influence of the `render:defaultRenderer` option [^1].

API
---
Expand All @@ -21,6 +22,7 @@ Fixes
- Catalogue :
- Fixed undo for image reordering via drag & drop.
- Fixed bugs caused by reordering images using `GraphComponent::reorderChildren()`.
- InteractiveRender : Fixed context used to evaluate scene globals when renderer is set to "Default" [^1].

API
---
Expand All @@ -32,6 +34,8 @@ Breaking Changes

- StandardLightVisualiser : Added `attributeName` argument to `surfaceTexture()` virtual method.

[^1]: To be omitted from final release notes for 1.4.0.0.

1.4.0.0b4 (relative to 1.4.0.0b3)
=========

Expand Down Expand Up @@ -350,7 +354,15 @@ Build
1.3.x.x (relative to 1.3.14.0)
=======

Improvements
------------

- Render, InteractiveRender : Added `resolvedRenderer` plug, which outputs the name of the renderer that will be used, taking into account the influence of the `render:defaultRenderer` option.

Fixes
-----

- InteractiveRender : Fixed context used to evaluate scene globals when renderer is set to "Default".

1.3.14.0 (relative to 1.3.13.1)
========
Expand Down
3 changes: 3 additions & 0 deletions include/GafferScene/InteractiveRender.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ class GAFFERSCENE_API InteractiveRender : public Gaffer::ComputeNode
GafferScene::ScenePlug *outPlug();
const GafferScene::ScenePlug *outPlug() const;

Gaffer::StringPlug *resolvedRendererPlug();
const Gaffer::StringPlug *resolvedRendererPlug() const;

Gaffer::ObjectPlug *messagesPlug();
const Gaffer::ObjectPlug *messagesPlug() const;

Expand Down
3 changes: 3 additions & 0 deletions include/GafferScene/Render.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ class GAFFERSCENE_API Render : public GafferDispatch::TaskNode
ScenePlug *outPlug();
const ScenePlug *outPlug() const;

Gaffer::StringPlug *resolvedRendererPlug();
const Gaffer::StringPlug *resolvedRendererPlug() const;

protected :

// Constructor for derived classes which wish to hardcode the renderer type. Perhaps
Expand Down
53 changes: 53 additions & 0 deletions python/GafferSceneTest/InteractiveRenderTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -2199,6 +2199,59 @@ def testRendererOption( self ):
image = IECoreImage.ImageDisplayDriver.storedImage( "testRendererOption" )
self.assertIsInstance( image, IECoreImage.ImagePrimitive )

def testRendererOptionContext( self ):

script = Gaffer.ScriptNode()
script["variables"].addChild( Gaffer.NameValuePlug( "defaultRendererVariable", self.renderer ) )

script["outputs"] = GafferScene.Outputs()
script["outputs"].addOutput(
"beauty",
IECoreScene.Output(
"test",
"ieDisplay",
"rgba",
{
"driverType" : "ImageDisplayDriver",
"handle" : "testRendererOptionContext",
}
)
)

script["standardOptions"] = GafferScene.StandardOptions()
script["standardOptions"]["in"].setInput( script["outputs"]["out"] )
script["standardOptions"]["options"]["defaultRenderer"]["enabled"].setValue( True )
script["standardOptions"]["options"]["defaultRenderer"]["value"].setValue( "${defaultRendererVariable}" )

script["renderer"] = self._createInteractiveRender( useNodeClass = False )
script["renderer"]["renderer"].setValue( "" )
script["renderer"]["in"].setInput( script["standardOptions"]["out"] )

# Check that the globals are evaluated in the right context to provide
# the `defaultRendererVariable` and enable the render.

script["renderer"]["state"].setValue( script["renderer"].State.Running )
time.sleep( 1.0 )

image = IECoreImage.ImageDisplayDriver.storedImage( "testRendererOptionContext" )
self.assertIsInstance( image, IECoreImage.ImagePrimitive )

def testResolvedRenderer( self ) :

standardOptions = GafferScene.StandardOptions()

render = GafferScene.InteractiveRender()
render["in"].setInput( standardOptions["out"] )
self.assertEqual( render["renderer"].getValue(), "" )
self.assertEqual( render["resolvedRenderer"].getValue(), "" )

standardOptions["options"]["defaultRenderer"]["enabled"].setValue( True )
standardOptions["options"]["defaultRenderer"]["value"].setValue( self.renderer )
self.assertEqual( render["resolvedRenderer"].getValue(), self.renderer )

render["renderer"].setValue( "Other" )
self.assertEqual( render["resolvedRenderer"].getValue(), "Other" )

def tearDown( self ) :

GafferSceneTest.SceneTestCase.tearDown( self )
Expand Down
16 changes: 16 additions & 0 deletions python/GafferSceneTest/RenderTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -282,5 +282,21 @@ def testNoRenderer( self ) :
render["task"].execute()
self.assertFalse( ( self.temporaryDirectory() / "test.exr" ).exists() )

def testResolvedRenderer( self ) :

standardOptions = GafferScene.StandardOptions()

render = GafferScene.Render()
render["in"].setInput( standardOptions["out"] )
self.assertEqual( render["renderer"].getValue(), "" )
self.assertEqual( render["resolvedRenderer"].getValue(), "" )

standardOptions["options"]["defaultRenderer"]["enabled"].setValue( True )
standardOptions["options"]["defaultRenderer"]["value"].setValue( self.renderer )
self.assertEqual( render["resolvedRenderer"].getValue(), self.renderer )

render["renderer"].setValue( "Other" )
self.assertEqual( render["resolvedRenderer"].getValue(), "Other" )

if __name__ == "__main__":
unittest.main()
12 changes: 12 additions & 0 deletions python/GafferSceneUI/InteractiveRenderUI.py
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,18 @@ def __rendererPresetNames( plug ) :

],

"resolvedRenderer" : [

"description",
"""
The renderer that will be used, accounting for the value of the
`render:defaultRenderer` option if `renderer` is set to "Default".
""",

"layout:section", "Advanced",

],

"messages" : [

"description",
Expand Down
31 changes: 21 additions & 10 deletions python/GafferSceneUI/RenderUI.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,18 @@ def rendererPresetNames( plug ) :

],

"resolvedRenderer" : [

"description",
"""
The renderer that will be used, accounting for the value of the
`render:defaultRenderer` option if `renderer` is set to "Default".
""",

"layout:section", "Advanced",

],

}
)

Expand All @@ -152,17 +164,16 @@ def _valuesForUpdate( plugs, auxiliaryPlugs ) :
presets = GafferUI.PresetsPlugValueWidget._valuesForUpdate( plugs, [ [] for p in plugs ] )

result = []
for preset, globalsPlugs in zip( presets, auxiliaryPlugs ) :
for preset, resolvedRendererPlugs in zip( presets, auxiliaryPlugs ) :

defaultRenderer = ""
if len( globalsPlugs ) and preset == "Default" :
resolvedRenderer = ""
if len( resolvedRendererPlugs ) :
with IECore.IgnoredExceptions( Gaffer.ProcessException ) :
defaultRenderer = globalsPlugs[0].getValue().get( "option:render:defaultRenderer" )
defaultRenderer = defaultRenderer.value if defaultRenderer is not None else ""
resolvedRenderer = resolvedRendererPlugs[0].getValue()

result.append( {
"preset" : preset,
"defaultRenderer" : defaultRenderer
"resolvedRenderer" : resolvedRenderer
} )

return result
Expand All @@ -172,16 +183,16 @@ def _updateFromValues( self, values, exception ) :
GafferUI.PresetsPlugValueWidget._updateFromValues( self, [ v["preset"] for v in values ], exception )

if self.menuButton().getText() == "Default" :
defaultRenderer = sole( v["defaultRenderer"] for v in values )
resolvedRenderer = sole( v["resolvedRenderer"] for v in values )
self.menuButton().setText(
"Default ({})".format(
defaultRenderer if defaultRenderer else
( "None" if defaultRenderer == "" else "---" )
resolvedRenderer if resolvedRenderer else
( "None" if resolvedRenderer == "" else "---" )
)
)

def _auxiliaryPlugs( self, plug ) :

node = plug.node()
if isinstance( node, ( GafferScene.Render, GafferScene.InteractiveRender ) ) :
return [ node["in"]["globals"] ]
return [ node["resolvedRenderer"] ]
84 changes: 60 additions & 24 deletions src/GafferScene/InteractiveRender.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ InteractiveRender::InteractiveRender( const IECore::InternedString &rendererType
addChild( new StringPlug( rendererType.string().empty() ? "renderer" : "__renderer", Plug::In, rendererType.string() ) );
addChild( new IntPlug( "state", Plug::In, Stopped, Stopped, Paused, Plug::Default & ~Plug::Serialisable ) );
addChild( new ScenePlug( "out", Plug::Out, Plug::Default & ~Plug::Serialisable ) );
addChild( new StringPlug( "resolvedRenderer", Plug::Out, "", Plug::Default & ~Plug::Serialisable ) );
addChild( new ObjectPlug( "messages", Plug::Out, new MessagesData(), Plug::Default & ~Plug::Serialisable ) );
addChild( new ScenePlug( "__adaptedIn", Plug::In, Plug::Default & ~Plug::Serialisable ) );

Expand Down Expand Up @@ -228,34 +229,44 @@ const ScenePlug *InteractiveRender::outPlug() const
return getChild<ScenePlug>( g_firstPlugIndex + 3 );
}

Gaffer::StringPlug *InteractiveRender::resolvedRendererPlug()
{
return getChild<StringPlug>( g_firstPlugIndex + 4 );
}

const Gaffer::StringPlug *InteractiveRender::resolvedRendererPlug() const
{
return getChild<StringPlug>( g_firstPlugIndex + 4 );
}

ObjectPlug *InteractiveRender::messagesPlug()
{
return getChild<ObjectPlug>( g_firstPlugIndex + 4 );
return getChild<ObjectPlug>( g_firstPlugIndex + 5 );
}

const ObjectPlug *InteractiveRender::messagesPlug() const
{
return getChild<ObjectPlug>( g_firstPlugIndex + 4 );
return getChild<ObjectPlug>( g_firstPlugIndex + 5 );
}

ScenePlug *InteractiveRender::adaptedInPlug()
{
return getChild<ScenePlug>( g_firstPlugIndex + 5 );
return getChild<ScenePlug>( g_firstPlugIndex + 6 );
}

const ScenePlug *InteractiveRender::adaptedInPlug() const
{
return getChild<ScenePlug>( g_firstPlugIndex + 5 );
return getChild<ScenePlug>( g_firstPlugIndex + 6 );
}

Gaffer::IntPlug *InteractiveRender::messageUpdateCountPlug()
{
return getChild<IntPlug>( g_firstPlugIndex + 6 );
return getChild<IntPlug>( g_firstPlugIndex + 7 );
}

const Gaffer::IntPlug *InteractiveRender::messageUpdateCountPlug() const
{
return getChild<IntPlug>( g_firstPlugIndex + 6 );
return getChild<IntPlug>( g_firstPlugIndex + 7 );
}

Gaffer::Context *InteractiveRender::getContext()
Expand Down Expand Up @@ -298,6 +309,9 @@ void InteractiveRender::plugSet( const Gaffer::Plug *plug )

void InteractiveRender::update()
{
ConstContextPtr context = effectiveContext();
Context::Scope scope( context.get() );

const State requiredState = (State)statePlug()->getValue();

// Stop the current render if we've been asked to, or if
Expand All @@ -316,26 +330,18 @@ void InteractiveRender::update()
{
m_messageHandler->clear();

std::string rendererType = rendererPlug()->getValue();
/// \todo It'd be great if we could deal with live edits to the `render:defaultRenderer`
/// option, to switch renderer on the fly. The best way of doing this is probably
/// to move the renderer creation to the RenderController. That approach would also
/// allow the RenderController to recreate the renderer when unsupported option edits
/// are made - for instance, changing `cycles:device`.
const std::string rendererType = resolvedRendererPlug()->getValue();
if( rendererType.empty() )
{
/// \todo It'd be great if we could deal with live edits to the `render:defaultRenderer`
/// option, to switch renderer on the fly. The best way of doing this is probably
/// to move the renderer creation to the RenderController. That approach would also
/// allow the RenderController to recreate the renderer when unsupported option edits
/// are made - for instance, changing `cycles:device`.
ConstCompoundObjectPtr globals = adaptedInPlug()->globals();
if( auto rendererData = globals->member<const StringData>( g_rendererOptionName ) )
{
rendererType = rendererData->readable();
}
if( rendererType.empty() )
{
m_messageHandler->handle(
IECore::Msg::Error, "InteractiveRender", "`render:defaultRenderer` option not set"
);
return;
}
m_messageHandler->handle(
IECore::Msg::Error, "InteractiveRender", "`render:defaultRenderer` option not set"
);
return;
}

m_renderer = IECoreScenePreview::Renderer::create(
Expand Down Expand Up @@ -467,6 +473,11 @@ void InteractiveRender::affects( const Plug *input, AffectedPlugsContainer &outp
{
outputs.push_back( messagesPlug() );
}

if( input == rendererPlug() || input == inPlug()->globalsPlug() )
{
outputs.push_back( resolvedRendererPlug() );
}
}

void InteractiveRender::hash( const Gaffer::ValuePlug *output, const Gaffer::Context *context, IECore::MurmurHash &h ) const
Expand All @@ -477,6 +488,18 @@ void InteractiveRender::hash( const Gaffer::ValuePlug *output, const Gaffer::Con
{
m_messageHandler->messagesHash( h );
}
else if( output == resolvedRendererPlug() )
{
const std::string renderer = rendererPlug()->getValue();
if( renderer.empty() )
{
inPlug()->globalsPlug()->hash( h );
}
else
{
h.append( renderer );
}
}
}

void InteractiveRender::compute( Gaffer::ValuePlug *output, const Gaffer::Context *context ) const
Expand All @@ -486,6 +509,19 @@ void InteractiveRender::compute( Gaffer::ValuePlug *output, const Gaffer::Contex
static_cast<ObjectPlug *>( output )->setValue( m_messageHandler->messages() );
return;
}
else if( output == resolvedRendererPlug() )
{
std::string renderer = rendererPlug()->getValue();
if( renderer.empty() )
{
ConstCompoundObjectPtr globals = adaptedInPlug()->globals();
if( auto rendererData = globals->member<const StringData>( g_rendererOptionName ) )
{
renderer = rendererData->readable();
}
}
static_cast<StringPlug *>( output )->setValue( renderer );
}

ComputeNode::compute( output, context );
}
Expand Down
Loading

0 comments on commit a63e385

Please sign in to comment.