Skip to content

Commit 1bc1de8

Browse files
committed
LiveScene: Add support to read attributes from Nuke
1 parent 96f3335 commit 1bc1de8

2 files changed

Lines changed: 169 additions & 0 deletions

File tree

src/IECoreNuke/LiveScene.cpp

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444

4545
#include "IECore/Exception.h"
4646
#include "IECore/NullObject.h"
47+
#include "IECore/SimpleTypedData.h"
4748
#include "IECore/TransformationMatrixData.h"
4849

4950
#include "OpenEXR/OpenEXRConfig.h"
@@ -81,6 +82,38 @@ IECore::TransformationMatrixd convertTransformMatrix( DD::Image::Matrix4& from )
8182

8283
tbb::recursive_mutex g_mutex;
8384

85+
IECore::ConstObjectPtr convertAttribute( const DD::Image::Attribute *attribute )
86+
{
87+
switch( attribute->type() )
88+
{
89+
case DD::Image::FLOAT_ATTRIB :
90+
return new IECore::FloatData( attribute->flt( 0 ) );
91+
case DD::Image::INT_ATTRIB :
92+
return new IECore::IntData( attribute->integer( 0 ) );
93+
case DD::Image::STD_STRING_ATTRIB :
94+
return new IECore::StringData( attribute->stdstring( 0 ) );
95+
case DD::Image::STRING_ATTRIB :
96+
{
97+
const char *s = attribute->string( 0 );
98+
return new IECore::StringData( s ? s : "" );
99+
}
100+
case DD::Image::VECTOR2_ATTRIB :
101+
return new IECore::V2fData( IECore::convert<Imath::V2f>( attribute->vector2( 0 ) ) );
102+
case DD::Image::VECTOR3_ATTRIB :
103+
return new IECore::V3fData( IECore::convert<Imath::V3f>( attribute->vector3( 0 ) ) );
104+
case DD::Image::NORMAL_ATTRIB :
105+
return new IECore::V3fData( IECore::convert<Imath::V3f>( attribute->normal( 0 ) ) );
106+
case DD::Image::VECTOR4_ATTRIB :
107+
return new IECore::Color4fData( IECore::convert<Imath::Color4f>( attribute->vector4( 0 ) ) );
108+
case DD::Image::MATRIX3_ATTRIB :
109+
return new IECore::M33fData( IECore::convert<Imath::M33f>( attribute->matrix3( 0 ) ) );
110+
case DD::Image::MATRIX4_ATTRIB :
111+
return new IECore::M44fData( IECore::convert<Imath::M44f>( attribute->matrix4( 0 ) ) );
112+
default :
113+
return nullptr;
114+
}
115+
}
116+
84117
LiveScene::LiveSceneGeometryCache &cachedGeometryListMap()
85118
{
86119
static LiveScene::LiveSceneGeometryCache *cache = new LiveScene::LiveSceneGeometryCache();
@@ -424,15 +457,85 @@ void LiveScene::writeTransform( const Data *transform, double time )
424457

425458
bool LiveScene::hasAttribute( const Name &name ) const
426459
{
460+
const unsigned numObjects = objectNum();
461+
for( unsigned i = 0; i < numObjects; ++i )
462+
{
463+
if( m_pathMatcher.match( geoInfoPath( i ) ) != IECore::PathMatcher::ExactMatch )
464+
{
465+
continue;
466+
}
467+
auto geoInfo = object( i );
468+
if( !geoInfo )
469+
{
470+
return false;
471+
}
472+
// we only support Group_Object because they are only one that makes sense to match to IECoreScene Attributes
473+
// other type of attributes are more akin to PrimitiveVariables
474+
// so we could consider adding support for Group_Primitive/Vertex and Point as such.
475+
auto attr = geoInfo->get_group_attribute( GroupType::Group_Object, name.c_str() );
476+
return attr && attr->size() > 0;
477+
}
427478
return false;
428479
}
429480

430481
void LiveScene::attributeNames( NameList &attrs ) const
431482
{
483+
attrs.clear();
484+
const unsigned numObjects = objectNum();
485+
for( unsigned i = 0; i < numObjects; ++i )
486+
{
487+
if( m_pathMatcher.match( geoInfoPath( i ) ) != IECore::PathMatcher::ExactMatch )
488+
{
489+
continue;
490+
}
491+
auto geoInfo = object( i );
492+
if( !geoInfo )
493+
{
494+
return;
495+
}
496+
const int count = geoInfo->get_attribcontext_count();
497+
for( int j = 0; j < count; ++j )
498+
{
499+
auto context = geoInfo->get_attribcontext( j );
500+
// we only support Group_Object because they are only one that makes sense to match to IECoreScene Attributes
501+
// other type of attributes are more akin to PrimitiveVariables
502+
// so we could consider adding support for Group_Primitive/Vertex and Point as such.
503+
if( context && !context->empty() && context->group == GroupType::Group_Object && context->name )
504+
{
505+
attrs.push_back( context->name );
506+
}
507+
}
508+
return;
509+
}
432510
}
433511

434512
ConstObjectPtr LiveScene::readAttribute( const Name &name, double time ) const
435513
{
514+
const unsigned numObjects = objectNum( &time );
515+
for( unsigned i = 0; i < numObjects; ++i )
516+
{
517+
if( m_pathMatcher.match( geoInfoPath( i ) ) != IECore::PathMatcher::ExactMatch )
518+
{
519+
continue;
520+
}
521+
auto geoInfo = object( i, &time );
522+
if( !geoInfo )
523+
{
524+
return IECore::NullObject::defaultNullObject();
525+
}
526+
// we only support Group_Object because they are only one that makes sense to match to IECoreScene Attributes
527+
// other type of attributes are more akin to PrimitiveVariables
528+
// so we could consider adding support for Group_Primitive/Vertex and Point as such.
529+
auto attr = geoInfo->get_group_attribute( GroupType::Group_Object, name.c_str() );
530+
if( attr && attr->size() > 0 )
531+
{
532+
if( auto converted = convertAttribute( attr ) )
533+
{
534+
return converted;
535+
}
536+
}
537+
return IECore::NullObject::defaultNullObject();
538+
}
436539
return IECore::NullObject::defaultNullObject();
437540
}
438541

test/IECoreNuke/LiveSceneKnobTest.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,72 @@ def testReadObjectMesh(self):
445445
obj = child.readObject(0)
446446
self.assertIsInstance(obj, IECoreScene.MeshPrimitive)
447447

448+
def testEmptySceneAttributes( self ) :
449+
450+
n = nuke.createNode( "ieLiveScene" )
451+
liveScene = n.knob( "scene" ).getValue()
452+
453+
self.assertEqual( liveScene.attributeNames(), [] )
454+
self.assertFalse( liveScene.hasAttribute( "ieName" ) )
455+
self.assertFalse( liveScene.hasAttribute( "nonExistent" ) )
456+
self.assertTrue( isinstance( liveScene.readAttribute( "nonExistent", 0 ), IECore.NullObject ) )
457+
458+
def testAttributes( self ) :
459+
import imath
460+
import IECoreScene
461+
462+
sceneFile = "test/IECoreNuke/scripts/data/liveSceneData.scc"
463+
sceneReader = nuke.createNode( "ieSceneCacheReader" )
464+
sceneReader.knob( "file" ).setValue( sceneFile )
465+
466+
sceneReader.forceValidate()
467+
widget = sceneReader.knob( "sceneView" )
468+
widget.setSelectedItems( ['/root/A/a', '/root/B/b'] )
469+
470+
n = nuke.createNode( "ieLiveScene" )
471+
n.setInput( 0, sceneReader )
472+
473+
liveScene = n.knob( "scene" ).getValue()
474+
475+
# Root and parent locations have no matching GeoInfo, so no attributes.
476+
self.assertEqual( liveScene.attributeNames(), [] )
477+
self.assertFalse( liveScene.hasAttribute( "ieName" ) )
478+
479+
for subPath in ( ["A"], ["B"] ) :
480+
subScene = liveScene.scene( subPath )
481+
self.assertEqual( subScene.attributeNames(), [] )
482+
self.assertFalse( subScene.hasAttribute( "ieName" ) )
483+
484+
# Leaf locations have Group_Object attributes set by ToNukeGeometryConverter.
485+
leafA = liveScene.scene( ["A", "a"] )
486+
self.assertIn( "ieName", leafA.attributeNames() )
487+
self.assertTrue( leafA.hasAttribute( "ieName" ) )
488+
self.assertFalse( leafA.hasAttribute( "nonExistent" ) )
489+
self.assertIsInstance( leafA.readAttribute( "nonExistent", 0 ), IECore.NullObject )
490+
491+
nameAttr = leafA.readAttribute( "ieName", 0 )
492+
self.assertIsInstance( nameAttr, IECore.StringData )
493+
self.assertEqual( nameAttr.value, "/A/a" )
494+
495+
leafB = liveScene.scene( ["B", "b"] )
496+
nameAttr = leafB.readAttribute( "ieName", 0 )
497+
self.assertIsInstance( nameAttr, IECore.StringData )
498+
self.assertEqual( nameAttr.value, "/B/b" )
499+
500+
# Scene attributes from the SCC round-trip through Nuke as Group_Object attributes.
501+
self.assertIn( "user:Mref", leafA.attributeNames() )
502+
self.assertTrue( leafA.hasAttribute( "user:Mref" ) )
503+
504+
# The SCC stores M44dData but Nuke round-trips it as M44fData.
505+
expectedScene = IECoreScene.SharedSceneInterfaces.get( sceneFile )
506+
expectedLeaf = expectedScene.scene( ["A", "a"] )
507+
expectedAttr = expectedLeaf.readAttribute( "user:Mref", 0.5 )
508+
509+
attr = leafA.readAttribute( "user:Mref", 0 )
510+
self.assertIsInstance( attr, IECore.M44fData )
511+
self.assertEqual( attr.value, imath.M44f( expectedAttr.value ) )
512+
513+
448514
if __name__ == "__main__":
449515
unittest.main()
450516

0 commit comments

Comments
 (0)