Skip to content

Commit

Permalink
FreezeTransform : Imitate __processedObject plug from ObjectProcessor
Browse files Browse the repository at this point in the history
  • Loading branch information
danieldresser-ie authored and johnhaddon committed Sep 19, 2024
1 parent 2149bdb commit fb12ba0
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 29 deletions.
3 changes: 3 additions & 0 deletions Changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ Improvements
- Editor : The node graph is now evaluated in a context determined relative to the focus node.
- LightEditor, RenderPassEditor : The "Disable Edit" right-click menu item and <kdb>D</kdb> shortcut now act as a toggle, where edits disabled in the current session via these actions can be reenabled with <kbd>D</kbd> or by selecting "Reenable Edit" from the right-click menu.
- EditScope : Setting a Viewer or Editor's target edit scope to "None" will now prevent edits from being made within any upstream edit scope. To make edits in an edit scope, it must be set as the target.
- FreezeTransform :
- Improved performance for large meshes by using multithreading.
- Improved UI responsiveness by supporting cancellation of long computes.

Fixes
-----
Expand Down
9 changes: 9 additions & 0 deletions include/GafferScene/FreezeTransform.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ class GAFFERSCENE_API FreezeTransform : public FilteredSceneProcessor
void hash( const Gaffer::ValuePlug *output, const Gaffer::Context *context, IECore::MurmurHash &h ) const override;
void compute( Gaffer::ValuePlug *output, const Gaffer::Context *context ) const override;

Gaffer::ValuePlug::CachePolicy computeCachePolicy( const Gaffer::ValuePlug *output ) const override;

void hashBound( const ScenePath &path, const Gaffer::Context *context, const ScenePlug *parent, IECore::MurmurHash &h ) const override;
void hashTransform( const ScenePath &path, const Gaffer::Context *context, const ScenePlug *parent, IECore::MurmurHash &h ) const override;
void hashObject( const ScenePath &path, const Gaffer::Context *context, const ScenePlug *parent, IECore::MurmurHash &h ) const override;
Expand All @@ -72,6 +74,13 @@ class GAFFERSCENE_API FreezeTransform : public FilteredSceneProcessor
Gaffer::M44fPlug *transformPlug();
const Gaffer::M44fPlug *transformPlug() const;

/// We compute the processed object on this internal plug rather than on
/// `out.object` directly. This allows us to use the TaskCollaboration
/// task policy for processing objects without paying the overhead when
/// we're just passing them through (when the filter doesn't match).
Gaffer::ObjectPlug *processedObjectPlug();
const Gaffer::ObjectPlug *processedObjectPlug() const;

static size_t g_firstPlugIndex;

};
Expand Down
3 changes: 2 additions & 1 deletion python/GafferSceneTest/FreezeTransformTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,8 @@ def testFilter( self ) :
def testAffects( self ) :

t = GafferScene.FreezeTransform()
self.assertEqual( set( t.affects( t["in"]["object"] ) ), set( [ t["out"]["object"] ] ) )
self.assertEqual( set( t.affects( t["in"]["object"] ) ), set( [ t["out"]["object"], t["__processedObject"] ] ) )
self.assertEqual( set( t.affects( t["__processedObject"] ) ), set( [ t["out"]["object"] ] ) )

def testSetFilter( self ) :

Expand Down
97 changes: 69 additions & 28 deletions src/GafferScene/FreezeTransform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@

#include "IECore/DataAlgo.h"
#include "IECore/TypeTraits.h"
#include "IECore/NullObject.h"

using namespace std;
using namespace Imath;
Expand All @@ -60,6 +61,7 @@ FreezeTransform::FreezeTransform( const std::string &name )
{
storeIndexOfNextChild( g_firstPlugIndex );
addChild( new M44fPlug( "__transform", Plug::Out ) );
addChild( new ObjectPlug( "__processedObject", Plug::Out, NullObject::defaultNullObject() ) );

outPlug()->childBoundsPlug()->setFlags( Plug::AcceptsDependencyCycles, true );

Expand All @@ -85,6 +87,16 @@ const Gaffer::M44fPlug *FreezeTransform::transformPlug() const
return getChild<M44fPlug>( g_firstPlugIndex );
}

Gaffer::ObjectPlug *FreezeTransform::processedObjectPlug()
{
return getChild<ObjectPlug>( g_firstPlugIndex + 1 );
}

const Gaffer::ObjectPlug *FreezeTransform::processedObjectPlug() const
{
return getChild<ObjectPlug>( g_firstPlugIndex + 1 );
}

void FreezeTransform::affects( const Gaffer::Plug *input, AffectedPlugsContainer &outputs ) const
{
FilteredSceneProcessor::affects( input, outputs );
Expand Down Expand Up @@ -116,10 +128,18 @@ void FreezeTransform::affects( const Gaffer::Plug *input, AffectedPlugsContainer
}

if(
input == filterPlug() ||
input == inPlug()->objectPlug() ||
input == transformPlug()
)
{
outputs.push_back( processedObjectPlug() );
}

if(
input == filterPlug() ||
input == inPlug()->objectPlug() ||
input == processedObjectPlug()
)
{
outputs.push_back( outPlug()->objectPlug() );
}
Expand All @@ -131,9 +151,14 @@ void FreezeTransform::hash( const Gaffer::ValuePlug *output, const Gaffer::Conte

if( output == transformPlug() )
{
const ScenePath &scenePath = context->get<ScenePath>( ScenePlug::scenePathContextName );
h.append( inPlug()->fullTransformHash( scenePath ) );
h.append( outPlug()->fullTransformHash( scenePath ) );
const ScenePath &path = context->get<ScenePath>( ScenePlug::scenePathContextName );
h.append( inPlug()->fullTransformHash( path ) );
h.append( outPlug()->fullTransformHash( path ) );
}
else if( output == processedObjectPlug() )
{
inPlug()->objectPlug()->hash( h );
transformPlug()->hash( h );
}
}

Expand All @@ -143,17 +168,49 @@ void FreezeTransform::compute( Gaffer::ValuePlug *output, const Gaffer::Context
{
/// \todo Would it speed things up if we computed this from the parent full transforms and
/// the local transforms? So we don't traverse the full path at each location?
const ScenePath &scenePath = context->get<ScenePath>( ScenePlug::scenePathContextName );
const M44f inTransform = inPlug()->fullTransform( scenePath );
const M44f outTransform = outPlug()->fullTransform( scenePath );
const ScenePath &path = context->get<ScenePath>( ScenePlug::scenePathContextName );
const M44f inTransform = inPlug()->fullTransform( path );
const M44f outTransform = outPlug()->fullTransform( path );
const M44f transform = inTransform * outTransform.inverse();
static_cast<M44fPlug *>( output )->setValue( transform );
return;
}
else if( output == processedObjectPlug() )
{
ConstObjectPtr inputObject = inPlug()->objectPlug()->getValue();
ConstObjectPtr result;
const Primitive *inputPrimitive = runTimeCast<const Primitive>( inputObject.get() );
if( !inputPrimitive )
{
result = inputObject;
}
else
{
PrimitivePtr outputPrimitive = inputPrimitive->copy();
const M44f transform = transformPlug()->getValue();
IECoreScenePreview::PrimitiveAlgo::transformPrimitive( *outputPrimitive, transform, context->canceller() );
result = std::move( outputPrimitive );
}

static_cast<ObjectPlug *>( output )->setValue( result );
return;
}

FilteredSceneProcessor::compute( output, context );
}

Gaffer::ValuePlug::CachePolicy FreezeTransform::computeCachePolicy( const Gaffer::ValuePlug *output ) const
{
if( output == processedObjectPlug() )
{
return ValuePlug::CachePolicy::TaskCollaboration;
}
else
{
return FilteredSceneProcessor::computeCachePolicy( output );
}
}

void FreezeTransform::hashBound( const ScenePath &path, const Gaffer::Context *context, const ScenePlug *parent, IECore::MurmurHash &h ) const
{
const unsigned m = filterValue( context );
Expand Down Expand Up @@ -225,38 +282,22 @@ Imath::M44f FreezeTransform::computeTransform( const ScenePath &path, const Gaff

void FreezeTransform::hashObject( const ScenePath &path, const Gaffer::Context *context, const ScenePlug *parent, IECore::MurmurHash &h ) const
{
const unsigned m = filterValue( context );
if( m & ( IECore::PathMatcher::AncestorMatch | IECore::PathMatcher::ExactMatch ) )
if( filterValue( context ) & ( IECore::PathMatcher::AncestorMatch | IECore::PathMatcher::ExactMatch ) )
{
FilteredSceneProcessor::hashObject( path, context, parent, h );
inPlug()->objectPlug()->hash( h );
transformPlug()->hash( h );
h = processedObjectPlug()->hash();
}
else
{
// pass through
h = inPlug()->objectPlug()->hash();
}
}

IECore::ConstObjectPtr FreezeTransform::computeObject( const ScenePath &path, const Gaffer::Context *context, const ScenePlug *parent ) const
{
const unsigned m = filterValue( context );
if( m & ( IECore::PathMatcher::AncestorMatch | IECore::PathMatcher::ExactMatch ) )
if( filterValue( context ) & ( IECore::PathMatcher::AncestorMatch | IECore::PathMatcher::ExactMatch ) )
{
ConstObjectPtr inputObject = inPlug()->objectPlug()->getValue();
const Primitive *inputPrimitive = runTimeCast<const Primitive>( inputObject.get() );
if( !inputPrimitive )
{
return inputObject;
}

PrimitivePtr outputPrimitive = inputPrimitive->copy();

const M44f transform = transformPlug()->getValue();

IECoreScenePreview::PrimitiveAlgo::transformPrimitive( *outputPrimitive, transform, context->canceller() );

return outputPrimitive;
return processedObjectPlug()->getValue();
}
else
{
Expand Down

0 comments on commit fb12ba0

Please sign in to comment.