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 committed Sep 17, 2024
1 parent d8482dc commit b19d68d
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 29 deletions.
1 change: 1 addition & 0 deletions Changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ Improvements
- Spreadsheet : Added yellow underlining to the currently active row.
- PlugLayout : Summaries and activators are now evaluated in a context determined relative to the focus node.
- Editor : The node graph is now evaluated in a context determined relative to the focus node.
- FreezeTransform : Added support for threading, resulting in much better performance when dealing with very large meshes.

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 b19d68d

Please sign in to comment.