Skip to content

Commit

Permalink
Merge branch '1.3_maintenance' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
johnhaddon committed Sep 28, 2023
2 parents 3d78e04 + 8a52db5 commit 2dea749
Show file tree
Hide file tree
Showing 22 changed files with 1,173 additions and 200 deletions.
22 changes: 20 additions & 2 deletions Changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ Breaking Changes
- StringPlug : Removed deprecated `precomputedHash` argument from `getValue()` method.
- OpenColorIOContext : Removed `configEnabledPlug()`, `configValuePlug()`, `workingSpaceEnabledPlug()` and `workingSpaceValuePlug()` methods. Use the OptionalValuePlug child accessors instead.

1.3.x.x (relative to 1.3.3.0)
1.3.x.x (relative to 1.3.4.0)
=======

1.3.4.0 (relative to 1.3.3.0)
=======

Improvements
Expand All @@ -28,11 +31,23 @@ Fixes
- StringPlugValueWidget : Fixed bug handling <kbd>Esc</kbd>.
- Arnold : Fixed unnecessary `opaque` attribute deprecation warnings. These are now only emitted in the case that `opaque` has been explicitly turned off.
- ShaderUI : Fixed bug causing identical but independent shaders in a shader network from being included in the shader browser.
- Encapsulate :
- Fixed bug where global attributes (from the point of encapsulation) were baked into the contents of the capsule instead of being inherited naturally (from the node being rendered).
- Fixed motion blur so that global settings are now taken from the downstream node being rendered, not from the input to the Encapsulate node.

API
---

- SceneTestCase : Added `assertScenesRenderSame()` method.
- RenderController : Added missing `updateRequired()` Python binding.
- CapturingRenderer :
- Added `capturedObjectNames()` method.
- Added `capturedName()` and `capturedLinkTypes()` methods to CapturedObject class.

Build
-----

- Fixed compilation with Boost versions prior to 1.74.

1.3.3.0 (relative to 1.3.2.0)
=======
Expand Down Expand Up @@ -409,7 +424,10 @@ Build
- USD : Updated to version 23.05.
- ZLib : Added version 1.2.13.

1.2.10.x (relative to 1.2.10.3)
1.2.10.x (relative to 1.2.10.4)
========

1.2.10.4 (relative to 1.2.10.3)
========

Fixes
Expand Down
19 changes: 19 additions & 0 deletions include/Gaffer/ThreadMonitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,25 @@

#include <unordered_map>

// Image Engine is on Boost 107300 which doesn't have the specialization of std::hash
// for boost smart pointers
#if BOOST_VERSION < 107400
namespace std
{

template <>
struct hash<Gaffer::ConstPlugPtr>
{
size_t operator()( const Gaffer::ConstPlugPtr &p ) const
{
return std::hash<const void*>()( p.get() );
}
};

} // namespace std
#endif


namespace Gaffer
{

Expand Down
6 changes: 6 additions & 0 deletions include/GafferScene/Capsule.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#pragma once

#include "GafferScene/Private/IECoreScenePreview/Procedural.h"
#include "GafferScene/Private/RendererAlgo.h"
#include "GafferScene/ScenePlug.h"

#include "Gaffer/Context.h"
Expand Down Expand Up @@ -90,6 +91,11 @@ class GAFFERSCENE_API Capsule : public IECoreScenePreview::Procedural
const ScenePlug::ScenePath &root() const;
const Gaffer::Context *context() const;

/// Used to apply the correct render settings to the capsule before rendering it.
/// For internal use only.
void setRenderOptions( const GafferScene::Private::RendererAlgo::RenderOptions &renderOptions );
std::optional<GafferScene::Private::RendererAlgo::RenderOptions> getRenderOptions() const;

private :

void throwIfNoScene() const;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,13 +106,16 @@ class GAFFERSCENE_API CapturingRenderer : public Renderer
/// Introspection
/// =============

const std::string &capturedName() const;

const std::vector<IECore::ConstObjectPtr> &capturedSamples() const;
const std::vector<float> &capturedSampleTimes() const;

const std::vector<Imath::M44f> &capturedTransforms() const;
const std::vector<float> &capturedTransformTimes() const;

const CapturedAttributes *capturedAttributes() const;
std::vector< IECore::InternedString > capturedLinkTypes() const;
const ObjectSet *capturedLinks( const IECore::InternedString &type ) const;

int numAttributeEdits() const;
Expand Down Expand Up @@ -150,6 +153,7 @@ class GAFFERSCENE_API CapturingRenderer : public Renderer

IE_CORE_DECLAREPTR( CapturedObject );

std::vector<std::string> capturedObjectNames() const;
const CapturedObject *capturedObject( const std::string &name ) const;

/// Renderer interface
Expand Down
38 changes: 29 additions & 9 deletions include/GafferScene/Private/RendererAlgo.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,34 @@ namespace Private
namespace RendererAlgo
{

struct GAFFERSCENE_API RenderOptions
{
RenderOptions();
RenderOptions( const ScenePlug *scene );
RenderOptions( const RenderOptions &other ) = default;
RenderOptions& operator=( const RenderOptions &other ) = default;
bool operator==( const RenderOptions &other ) const;
/// The globals from the scene.
IECore::ConstCompoundObjectPtr globals;
/// Convenient access to specific properties, taking into account default
/// values if they have not been specified in the scene.
bool transformBlur;
bool deformationBlur;
Imath::V2f shutter;
IECore::ConstStringVectorDataPtr includedPurposes;
/// Returns true if `includedPurposes` includes the purpose defined by
/// `attributes`.
bool purposeIncluded( const IECore::CompoundObject *attributes ) const;
};

/// Creates the directories necessary to receive the outputs defined in globals.
GAFFERSCENE_API void createOutputDirectories( const IECore::CompoundObject *globals );

/// Set the "times" to a list of times to sample the transform or deformation of a location at, based on the
/// "motionBlur" enable coming from the options, a shutter, and location attributes. Returns a boolean for
/// whether times has been altered ( returns false if times was already set correctly ).
GAFFERSCENE_API bool transformMotionTimes( bool motionBlur, const Imath::V2f &shutter, const IECore::CompoundObject *attributes, std::vector<float> &times );
GAFFERSCENE_API bool deformationMotionTimes( bool motionBlur, const Imath::V2f &shutter, const IECore::CompoundObject *attributes, std::vector<float> &times );
/// Sets `times` to a list of times to sample the transform or deformation of a
/// location at, based on the render options and location attributes. Returns `true`
/// if `times` was altered and `false` if it was already set correctly.
GAFFERSCENE_API bool transformMotionTimes( const RenderOptions &renderOptions, const IECore::CompoundObject *attributes, std::vector<float> &times );
GAFFERSCENE_API bool deformationMotionTimes( const RenderOptions &renderOptions, const IECore::CompoundObject *attributes, std::vector<float> &times );

/// Samples the local transform from the current location in preparation for output to the renderer.
/// "samples" will be set to contain one sample for each sampleTime, unless the samples are all identical,
Expand Down Expand Up @@ -259,10 +279,10 @@ class GAFFERSCENE_API LightLinks : boost::noncopyable

};

GAFFERSCENE_API void outputCameras( const ScenePlug *scene, const IECore::CompoundObject *globals, const RenderSets &renderSets, IECoreScenePreview::Renderer *renderer );
GAFFERSCENE_API void outputLightFilters( const ScenePlug *scene, const IECore::CompoundObject *globals, const RenderSets &renderSets, LightLinks *lightLinks, IECoreScenePreview::Renderer *renderer );
GAFFERSCENE_API void outputLights( const ScenePlug *scene, const IECore::CompoundObject *globals, const RenderSets &renderSets, LightLinks *lightLinks, IECoreScenePreview::Renderer *renderer );
GAFFERSCENE_API void outputObjects( const ScenePlug *scene, const IECore::CompoundObject *globals, const RenderSets &renderSets, const LightLinks *lightLinks, IECoreScenePreview::Renderer *renderer, const ScenePlug::ScenePath &root = ScenePlug::ScenePath() );
GAFFERSCENE_API void outputCameras( const ScenePlug *scene, const RenderOptions &renderOptions, const RenderSets &renderSets, IECoreScenePreview::Renderer *renderer );
GAFFERSCENE_API void outputLightFilters( const ScenePlug *scene, const RenderOptions &renderOptions, const RenderSets &renderSets, LightLinks *lightLinks, IECoreScenePreview::Renderer *renderer );
GAFFERSCENE_API void outputLights( const ScenePlug *scene, const RenderOptions &renderOptions, const RenderSets &renderSets, LightLinks *lightLinks, IECoreScenePreview::Renderer *renderer );
GAFFERSCENE_API void outputObjects( const ScenePlug *scene, const RenderOptions &renderOptions, const RenderSets &renderSets, const LightLinks *lightLinks, IECoreScenePreview::Renderer *renderer, const ScenePlug::ScenePath &root = ScenePlug::ScenePath() );

} // namespace RendererAlgo

Expand Down
13 changes: 7 additions & 6 deletions include/GafferScene/RenderController.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,14 +122,15 @@ class GAFFERSCENE_API RenderController : public Gaffer::Signals::Trackable
DeformationBlurGlobalComponent = 32,
CameraShutterGlobalComponent = 64,
IncludedPurposesGlobalComponent = 128,
CapsuleAffectingGlobalComponents = TransformBlurGlobalComponent | DeformationBlurGlobalComponent | IncludedPurposesGlobalComponent,
AllGlobalComponents = GlobalsGlobalComponent | SetsGlobalComponent | RenderSetsGlobalComponent | CameraOptionsGlobalComponent | TransformBlurGlobalComponent | DeformationBlurGlobalComponent | IncludedPurposesGlobalComponent
};

struct MotionBlurOptions
struct Unused
{
bool transformBlur = false;
bool deformationBlur = false;
Imath::V2f shutter = Imath::V2f( 0 );
bool unused1;
bool unused2;
Imath::V2f unused3;
};

void plugDirtied( const Gaffer::Plug *plug );
Expand Down Expand Up @@ -165,8 +166,8 @@ class GAFFERSCENE_API RenderController : public Gaffer::Signals::Trackable
std::vector<std::unique_ptr<SceneGraph> > m_sceneGraphs;
unsigned m_dirtyGlobalComponents;
unsigned m_changedGlobalComponents;
IECore::ConstCompoundObjectPtr m_globals;
MotionBlurOptions m_motionBlurOptions;
std::unique_ptr<Private::RendererAlgo::RenderOptions> m_renderOptions;
Unused m_unused;
Private::RendererAlgo::RenderSets m_renderSets;
std::unique_ptr<Private::RendererAlgo::LightLinks> m_lightLinks;
IECoreScenePreview::Renderer::ObjectInterfacePtr m_defaultCamera;
Expand Down
65 changes: 64 additions & 1 deletion python/GafferSceneTest/CapsuleTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
#
##########################################################################

import inspect
import unittest

import IECore
Expand Down Expand Up @@ -72,5 +71,69 @@ def test( self ) :
self.assertEqual( capsuleCopy.bound(), sphere["out"].bound( "/" ) )
self.assertEqual( capsuleCopy.hash(), capsule.hash() )

def testInheritedAttributesAreNotBakedIntoCapsuleContents( self ) :

# Make a Capsule which inherits attributes from its parent
# and from the scene globals.

sphere = GafferScene.Sphere()
group = GafferScene.Group()
group["in"][0].setInput( sphere["out"] )

groupFilter = GafferScene.PathFilter()
groupFilter["paths"].setValue( IECore.StringVectorData( [ "/group" ] ) )

groupAttributes = GafferScene.CustomAttributes()
groupAttributes["in"].setInput( group["out"] )
groupAttributes["filter"].setInput( groupFilter["out"] )
groupAttributes["attributes"].addChild( Gaffer.NameValuePlug( "groupAttribute", 10 ) )

globalAttributes = GafferScene.CustomAttributes()
globalAttributes["in"].setInput( groupAttributes["out"] )
globalAttributes["global"].setValue( True )
globalAttributes["attributes"].addChild( Gaffer.NameValuePlug( "globalAttribute", 20 ) )

encapsulate = GafferScene.Encapsulate()
encapsulate["in"].setInput( globalAttributes["out"] )
encapsulate["filter"].setInput( groupFilter["out"] )

# Render it, and check that the capsule object had the inherited attributes applied to it.

renderer = GafferScene.Private.IECoreScenePreview.CapturingRenderer(
GafferScene.Private.IECoreScenePreview.Renderer.RenderType.Batch
)
GafferScene.Private.RendererAlgo.outputObjects(
encapsulate["out"], GafferScene.Private.RendererAlgo.RenderOptions( encapsulate["out"] ), GafferScene.Private.RendererAlgo.RenderSets( encapsulate["out"] ), GafferScene.Private.RendererAlgo.LightLinks(),
renderer
)

capturedGroup = renderer.capturedObject( "/group" )
self.assertIsInstance( capturedGroup.capturedSamples()[0], GafferScene.Capsule )
self.assertEqual(
capturedGroup.capturedAttributes().attributes(),
IECore.CompoundObject( {
"groupAttribute" : IECore.IntData( 10 ),
"globalAttribute" : IECore.IntData( 20 ),
"sets" : IECore.InternedStringVectorData(),
} )
)

# Expand the capsule, and check that it didn't bake the inherited attributes onto
# its contents. It is the responsibity of the Renderer itself to take care of attribute
# inheritance, ideally doing it "live", so that changes to inherited attributes don't
# require re-expansion of the capsule.

renderer = GafferScene.Private.IECoreScenePreview.CapturingRenderer(
GafferScene.Private.IECoreScenePreview.Renderer.RenderType.Batch
)
capturedGroup.capturedSamples()[0].render( renderer )
capturedSphere = renderer.capturedObject( "/sphere" )
self.assertEqual(
capturedSphere.capturedAttributes().attributes(),
IECore.CompoundObject( {
"sets" : IECore.InternedStringVectorData(),
} )
)

if __name__ == "__main__":
unittest.main()
9 changes: 8 additions & 1 deletion python/GafferSceneTest/EncapsulateTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
#
##########################################################################

import inspect
import imath
import unittest
import subprocess

Expand All @@ -56,6 +56,7 @@ def test( self ) :

sphere = GafferScene.Sphere()
sphere["sets"].setValue( "sphereSet" )
sphere["transform"]["translate"].setValue( imath.V3f( 1, 2, 3 ) )

cube = GafferScene.Cube()
cube["sets"].setValue( "cubeSet" )
Expand All @@ -64,11 +65,13 @@ def test( self ) :
groupB["in"][0].setInput( sphere["out"] )
groupB["in"][1].setInput( cube["out"] )
groupB["name"].setValue( "groupB" )
groupB["transform"]["rotate"].setValue( imath.V3f( 100, 200, 300 ) )

groupA = GafferScene.Group()
groupA["in"][0].setInput( groupB["out"] )
groupA["in"][1].setInput( sphere["out"] )
groupA["name"].setValue( "groupA" )
groupA["transform"]["rotate"].setValue( imath.V3f( 400, 500, 600 ) )

# When there is no filter attached, the node
# should be an exact pass-through.
Expand Down Expand Up @@ -136,6 +139,10 @@ def test( self ) :
with self.assertRaisesRegex( Gaffer.ProcessException, "Encapsulate.out.object : Tried to access path \"/groupA/groupB/sphere\", but its ancestor has been converted to a capsule" ):
encapsulate["out"].object( "/groupA/groupB/sphere" )

# Check that the capsule expands during rendering to render the same as the unencapsulated scene.
# ( Except for the light links, which aren't output by the Capsule currently )
self.assertScenesRenderSame( encapsulate["in"], encapsulate["out"], expandProcedurals = True, ignoreLinks = True )

# As a double check, test that this setup works properly with Unencapsulate
unencapsulateFilter = GafferScene.PathFilter()

Expand Down
Loading

0 comments on commit 2dea749

Please sign in to comment.