Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Changes
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
10.7.x.x (relative to 10.7.1.3)
========

Fixes
-----

- AlembicScene : Added automatic reading of a `__cameras` set, containing the locations of all cameras.

10.7.1.3 (relative to 10.7.1.2)
========
Expand Down
74 changes: 72 additions & 2 deletions contrib/IECoreAlembic/src/IECoreAlembic/AlembicScene.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@

#include "boost/tokenizer.hpp"

#include "tbb/blocked_range.h"
#include "tbb/parallel_for.h"
#include "tbb/spin_mutex.h"

#include "fmt/format.h"
Expand Down Expand Up @@ -1064,6 +1066,21 @@ class AlembicScene::AlembicReader : public AlembicIO

if( !m_xform )
{
// Root.
setNames.push_back( "__cameras" );
// Note : We should not be returning early when
// `includeDescendantSets == true`. But in practice this is
// irrelevant for two reasons :
//
// 1. We've never received an Alembic file containing
// collections - do any DCCs support them?
// 2. We don't implement `writeSet()` at the root
// location, which is the only location where Gaffer tries
// to write sets (this is also the only location Gaffer
// tries to read sets from). Nobody has complained so far.
//
// Since recursing would be fairly expensive and has no current
// use, we don't bother.
return setNames;
}

Expand Down Expand Up @@ -1096,13 +1113,26 @@ class AlembicScene::AlembicReader : public AlembicIO
// ensure our set names are unique
std::sort( setNames.begin(), setNames.end() );
return NameList( setNames.begin(), std::unique( setNames.begin(), setNames.end() ) );

}

IECore::PathMatcher readSet( const Name &name, bool includeDescendantSets, const Canceller *canceller ) const
{
IECore::PathMatcher pathMatcher;
if( !m_xform )
{
if( name == "__cameras" )
{
tbb::this_task_arena::isolate(
[&] {
tbb::task_group_context taskGroupContext( tbb::task_group_context::isolated );
pathMatcher = recurseReadCamerasSet( taskGroupContext, canceller );
}
);
}
return pathMatcher;
}

SceneInterface::Path prefix;
PathMatcher pathMatcher;
recurseReadSet( prefix, name, pathMatcher, includeDescendantSets, canceller );

return pathMatcher;
Expand Down Expand Up @@ -1266,6 +1296,46 @@ class AlembicScene::AlembicReader : public AlembicIO
}
}

IECore::PathMatcher recurseReadCamerasSet( tbb::task_group_context &taskGroupContext, const Canceller *canceller ) const
{
Canceller::check( canceller );

PathMatcher result;
tbb::spin_mutex m;

if( m_objectReader && Alembic::AbcGeom::ICamera::matches( m_objectReader->object().getMetaData() ) )
{
result.addPath( std::vector<IECore::InternedString>() );
}

NameList children;
childNames( children );

tbb::parallel_for(

tbb::blocked_range<size_t>( 0, children.size() ),

[&]( const tbb::blocked_range<size_t> &r )
{
for( size_t i = r.begin(); i != r.end(); ++i )
{
auto &childName = children[i];
ConstAlembicIOPtr c = child( childName, SceneInterface::ThrowIfMissing );
PathMatcher childSet = static_cast<const AlembicReader *>( c.get() )->recurseReadCamerasSet( taskGroupContext, canceller );
if( !childSet.isEmpty() )
{
tbb::spin_mutex::scoped_lock lock( m );
result.addPaths( childSet, { childName } );
}
}
},
taskGroupContext

);

return result;
}

IECore::PathMatcherDataPtr readLocalSet( const Name &name ) const
{
PathMatcherDataPtr pathMatcher = new PathMatcherData();
Expand Down
9 changes: 9 additions & 0 deletions contrib/IECoreAlembic/test/IECoreAlembic/AlembicSceneTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,15 @@ def testCamera( self ) :
c = a.child( "persp" ).readObject( 0 )
self.assertTrue( isinstance( c, IECoreScene.Camera ) )

def testCamerasSet( self ) :

root = IECoreScene.SceneInterface.create( os.path.join( os.path.dirname( __file__ ), "data", "animatedCube.abc" ), IECore.IndexedIO.OpenMode.Read )
self.assertEqual( root.setNames(), [ "__cameras" ] )
self.assertEqual( root.readSet( "__cameras" ), IECore.PathMatcher( [ "/front", "/persp", "/side", "/top" ] ) )

child = root.child( "pCube1" )
self.assertNotIn( "__cameras", child.setNames() )

def testLinearCurves( self ) :

a = IECoreScene.SceneInterface.create( os.path.join( os.path.dirname( __file__ ), "data", "curves.abc" ), IECore.IndexedIO.OpenMode.Read )
Expand Down
Loading