Skip to content

Commit

Permalink
Merge pull request #5729 from johnhaddon/rendererOption
Browse files Browse the repository at this point in the history
StandardOptions : Add `render:renderer` option
  • Loading branch information
johnhaddon committed Mar 15, 2024
2 parents 4e22bea + 8f140c0 commit 07e626f
Show file tree
Hide file tree
Showing 28 changed files with 817 additions and 330 deletions.
10 changes: 10 additions & 0 deletions Changes.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
1.3.x.x (relative to 1.3.13.1)
=======

Features
--------

- Render, InteractiveRender : Added new nodes capable of rendering to any supported renderer, and using the`render:defaultRenderer` option to determine which to use by default.
- StandardOptions : Added `render:defaultRenderer` option, allowing the scene globals to specify which renderer is used by the Render and InteractiveRender nodes.
- RenderPassEditor : Added a column for the `render:defaultRenderer` option, allowing each pass to be rendered in a different renderer.

1.3.13.1 (relative to 1.3.13.0)
========

Expand Down
9 changes: 4 additions & 5 deletions include/GafferScene/Private/IECoreScenePreview/Renderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,10 @@ class GAFFERSCENE_API Renderer : public IECore::RefCounted
/// Performs an arbitrary renderer-specific action.
virtual IECore::DataPtr command( const IECore::InternedString name, const IECore::CompoundDataMap &parameters = IECore::CompoundDataMap() );

using Creator = std::function<Ptr ( RenderType, const std::string &, const IECore::MessageHandlerPtr & )>;
static void registerType( const IECore::InternedString &typeName, Creator creator );
static void deregisterType( const IECore::InternedString &typeName );

protected :

Renderer();
Expand All @@ -331,11 +335,6 @@ class GAFFERSCENE_API Renderer : public IECore::RefCounted

};

private :

static void registerType( const IECore::InternedString &typeName, Ptr (*creator)( RenderType, const std::string &, const IECore::MessageHandlerPtr & ) );


};

IE_CORE_DECLAREPTR( Renderer )
Expand Down
156 changes: 4 additions & 152 deletions python/GafferArnoldTest/ArnoldRenderTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,10 @@
import GafferArnold
import GafferArnoldTest

class ArnoldRenderTest( GafferSceneTest.SceneTestCase ) :
class ArnoldRenderTest( GafferSceneTest.RenderTest ) :

renderer = "Arnold"
sceneDescriptionSuffix = ".ass"

def setUp( self ) :

Expand All @@ -73,110 +76,6 @@ def tearDown( self ) :

GafferScene.SceneAlgo.deregisterRenderAdaptor( "Test" )

def testExecute( self ) :

s = Gaffer.ScriptNode()

s["plane"] = GafferScene.Plane()
s["render"] = GafferArnold.ArnoldRender()
s["render"]["mode"].setValue( s["render"].Mode.SceneDescriptionMode )
s["render"]["in"].setInput( s["plane"]["out"] )

s["expression"] = Gaffer.Expression()
s["expression"].setExpression( f"""parent['render']['fileName'] = '{( self.temporaryDirectory() / "test.%d.ass" ).as_posix()}' % int( context['frame'] )""" )

s["fileName"].setValue( self.__scriptFileName )
s.save()

p = subprocess.Popen(
f"gaffer execute {self.__scriptFileName} -frames 1-3",
shell=True,
stderr = subprocess.PIPE,
)
p.wait()
self.assertFalse( p.returncode )

for i in range( 1, 4 ) :
self.assertTrue( ( self.temporaryDirectory() / f"test.{i}.ass" ).exists() )

def testWaitForImage( self ) :

s = Gaffer.ScriptNode()

s["plane"] = GafferScene.Plane()

s["outputs"] = GafferScene.Outputs()
s["outputs"].addOutput(
"beauty",
IECoreScene.Output(
str( self.temporaryDirectory() / "test.tif" ),
"tiff",
"rgba",
{}
)
)
s["outputs"]["in"].setInput( s["plane"]["out"] )

s["render"] = GafferArnold.ArnoldRender()
s["render"]["in"].setInput( s["outputs"]["out"] )
s["render"]["task"].execute()

self.assertTrue( ( self.temporaryDirectory() / "test.tif" ).exists() )

def testExecuteWithStringSubstitutions( self ) :

s = Gaffer.ScriptNode()

s["plane"] = GafferScene.Plane()
s["render"] = GafferArnold.ArnoldRender()
s["render"]["mode"].setValue( s["render"].Mode.SceneDescriptionMode )
s["render"]["in"].setInput( s["plane"]["out"] )
s["render"]["fileName"].setValue( self.temporaryDirectory() / "test.####.ass" )

s["fileName"].setValue( self.__scriptFileName )
s.save()

p = subprocess.Popen(
f"gaffer execute {self.__scriptFileName} -frames 1-3",
shell=True,
stderr = subprocess.PIPE,
)
p.wait()
self.assertFalse( p.returncode )

for i in range( 1, 4 ) :
self.assertTrue( ( self.temporaryDirectory() / f"test.{i:04d}.ass" ).exists() )

def testImageOutput( self ) :

s = Gaffer.ScriptNode()

s["plane"] = GafferScene.Plane()

s["outputs"] = GafferScene.Outputs()
s["outputs"].addOutput(
"beauty",
IECoreScene.Output(
str( self.temporaryDirectory() / "test.####.tif" ),
"tiff",
"rgba",
{}
)
)
s["outputs"]["in"].setInput( s["plane"]["out"] )

s["render"] = GafferArnold.ArnoldRender()
s["render"]["in"].setInput( s["outputs"]["out"] )

c = Gaffer.Context()
for i in range( 1, 4 ) :
c.setFrame( i )
with c :
s["render"]["task"].execute()

for i in range( 1, 4 ) :
self.assertTrue( ( self.temporaryDirectory() / f"test.{i:04d}.tif" ).exists() )

def testTypeNamePrefixes( self ) :

self.assertTypeNamesArePrefixed( GafferArnold )
Expand All @@ -192,53 +91,6 @@ def testNodesConstructWithDefaultValues( self ) :
self.assertNodesConstructWithDefaultValues( GafferArnold )
self.assertNodesConstructWithDefaultValues( GafferArnoldTest )

def testDirectoryCreation( self ) :

s = Gaffer.ScriptNode()
s["variables"].addChild( Gaffer.NameValuePlug( "renderDirectory", ( self.temporaryDirectory() / "renderTests" ).as_posix() ) )
s["variables"].addChild( Gaffer.NameValuePlug( "assDirectory", ( self.temporaryDirectory() / "assTests" ).as_posix() ) )

s["plane"] = GafferScene.Plane()

s["outputs"] = GafferScene.Outputs()
s["outputs"]["in"].setInput( s["plane"]["out"] )
s["outputs"].addOutput(
"beauty",
IECoreScene.Output(
"$renderDirectory/test.####.exr",
"exr",
"rgba",
{}
)
)

s["render"] = GafferArnold.ArnoldRender()
s["render"]["in"].setInput( s["outputs"]["out"] )
s["render"]["fileName"].setValue( "$assDirectory/test.####.ass" )
s["render"]["mode"].setValue( s["render"].Mode.SceneDescriptionMode )

self.assertFalse( ( self.temporaryDirectory() / "renderTests" ).exists() )
self.assertFalse( ( self.temporaryDirectory() / "assTests" ).exists() )
self.assertFalse( ( self.temporaryDirectory() / "assTests" / "test.0001.ass" ).exists() )

s["fileName"].setValue( self.temporaryDirectory() / "test.gfr" )

with s.context() :
s["render"]["task"].execute()

self.assertTrue( ( self.temporaryDirectory() / "renderTests" ).exists() )
self.assertTrue( ( self.temporaryDirectory() / "assTests" ).exists())
self.assertTrue( ( self.temporaryDirectory() / "assTests"/ "test.0001.ass" ).exists() )

# check it can cope with everything already existing

with s.context() :
s["render"]["task"].execute()

self.assertTrue( ( self.temporaryDirectory() / "renderTests" ).exists() )
self.assertTrue( ( self.temporaryDirectory() / "assTests" ).exists() )
self.assertTrue( ( self.temporaryDirectory() / "assTests" / "test.0001.ass" ).exists() )

def testWedge( self ) :

s = Gaffer.ScriptNode()
Expand Down
1 change: 1 addition & 0 deletions python/GafferArnoldTest/InteractiveArnoldRenderTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
class InteractiveArnoldRenderTest( GafferSceneTest.InteractiveRenderTest ) :

interactiveRenderNodeClass = GafferArnold.InteractiveArnoldRender
renderer = "Arnold"

# Arnold outputs licensing warnings that would cause failures
failureMessageLevel = IECore.MessageHandler.Level.Error
Expand Down
46 changes: 46 additions & 0 deletions python/GafferCyclesTest/CyclesRenderTest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
##########################################################################
#
# Copyright (c) 2024, Cinesite VFX Ltd. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above
# copyright notice, this list of conditions and the following
# disclaimer.
#
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided with
# the distribution.
#
# * Neither the name of John Haddon nor the names of
# any other contributors to this software may be used to endorse or
# promote products derived from this software without specific prior
# written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
##########################################################################

import unittest

import GafferSceneTest

class CyclesRenderTest( GafferSceneTest.RenderTest ) :

renderer = "Cycles"

if __name__ == "__main__":
unittest.main()
1 change: 1 addition & 0 deletions python/GafferCyclesTest/InteractiveCyclesRenderTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
class InteractiveCyclesRenderTest( GafferSceneTest.InteractiveRenderTest ) :

interactiveRenderNodeClass = GafferCycles.InteractiveCyclesRender
renderer = "Cycles"

@unittest.skip( "Resolution edits not supported yet" )
def testEditResolution( self ) :
Expand Down
1 change: 1 addition & 0 deletions python/GafferCyclesTest/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
from .ModuleTest import ModuleTest
from .CyclesLightTest import CyclesLightTest
from .CyclesShaderTest import CyclesShaderTest
from .CyclesRenderTest import CyclesRenderTest

from .IECoreCyclesPreviewTest import *

Expand Down
68 changes: 3 additions & 65 deletions python/GafferDelightTest/DelightRenderTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,76 +34,14 @@
#
##########################################################################

import pathlib
import unittest

import IECore
import IECoreScene

import Gaffer
import GafferScene
import GafferSceneTest
import GafferDelight

class DelightRenderTest( GafferSceneTest.SceneTestCase ) :

def testSceneDescriptionMode( self ) :

plane = GafferScene.Plane()
render = GafferDelight.DelightRender()
render["in"].setInput( plane["out"] )
render["mode"].setValue( render.Mode.SceneDescriptionMode )
render["fileName"].setValue( self.temporaryDirectory() / "test.nsi" )

render["task"].execute()
self.assertTrue( pathlib.Path( render["fileName"].getValue() ).exists() )

def testRenderMode( self ) :

plane = GafferScene.Plane()

outputs = GafferScene.Outputs()
outputs.addOutput(
"beauty",
IECoreScene.Output(
str( self.temporaryDirectory() / "test.exr" ),
"exr",
"rgba",
{}
)
)

render = GafferDelight.DelightRender()
render["in"].setInput( outputs["out"] )
render["mode"].setValue( render.Mode.RenderMode )

render["task"].execute()
self.assertTrue( ( self.temporaryDirectory() / "test.exr" ).exists() )

def testSceneTranslationOnly( self ) :

plane = GafferScene.Plane()

outputs = GafferScene.Outputs()
outputs.addOutput(
"beauty",
IECoreScene.Output(
str( self.temporaryDirectory() / "test.exr" ),
"exr",
"rgba",
{}
)
)

render = GafferDelight.DelightRender()
render["in"].setInput( outputs["out"] )
render["mode"].setValue( render.Mode.RenderMode )

with Gaffer.Context() as context :
context["scene:render:sceneTranslationOnly"] = IECore.BoolData( True )
render["task"].execute()
class DelightRenderTest( GafferSceneTest.RenderTest ) :

self.assertFalse( ( self.temporaryDirectory() / "test.exr" ).exists() )
renderer = "3Delight"
sceneDescriptionSuffix = ".nsi"

if __name__ == "__main__":
unittest.main()
1 change: 1 addition & 0 deletions python/GafferDelightTest/InteractiveDelightRenderTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
class InteractiveDelightRenderTest( GafferSceneTest.InteractiveRenderTest ) :

interactiveRenderNodeClass = GafferDelight.InteractiveDelightRender
renderer = "3Delight"

# Temporarily disable this test (which is implemented in the
# base class) because it fails. The issue is that we're automatically
Expand Down
Loading

0 comments on commit 07e626f

Please sign in to comment.