Skip to content

Commit

Permalink
Render, InteractiveRender : Add resolvedRenderer output
Browse files Browse the repository at this point in the history
  • Loading branch information
johnhaddon committed Mar 18, 2024
1 parent ba5feee commit 811cf48
Show file tree
Hide file tree
Showing 9 changed files with 173 additions and 69 deletions.
5 changes: 5 additions & 0 deletions Changes.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
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
-----

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
16 changes: 16 additions & 0 deletions python/GafferSceneTest/InteractiveRenderTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -2236,6 +2236,22 @@ def testRendererOptionContext( self ):
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"] ]
81 changes: 57 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 @@ -319,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 @@ -470,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 @@ -480,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 @@ -489,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 811cf48

Please sign in to comment.