Skip to content

Commit 328d591

Browse files
committed
IECoreUSD : Support IECore::Object references when determining primvar type.
`IECore::Object` avoids some data duplication by writing an internal object's data a single time while saving, and then writing a reference path to the data container if other internal objects share the same pointer. One case in which this situation has presented itself is creating a "Pref" primvar to hold the rest positions of a primitive. In the following example, the created "Pref" primitive variable receives a shallow copy of the "P" primitive variable. So, the internal "data" and "indices" members point to the same shared data. Therefore, a reference is created when the primitive object saves itself. ``` box = IECoreScene.MeshPrimitive.createBox( imath.Box3f( imath.V3f(-1), imath.V3f(1) ) ) box['Pref'] = box['P'] ```
1 parent 47b1dc2 commit 328d591

File tree

2 files changed

+53
-10
lines changed

2 files changed

+53
-10
lines changed

contrib/IECoreUSD/src/IECoreUSD/SceneCacheData.cpp

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -661,7 +661,7 @@ void SceneCacheData::loadPrimVars( const SceneInterface::Path& currentPath, TfTo
661661
// variables
662662
SceneInterface::Path variablesPath;
663663
variablesPath.push_back( g_ioRoot );
664-
for ( auto& p : currentPath )
664+
for ( const auto& p : currentPath )
665665
{
666666
// avoid injecting the internal root because
667667
// the path would be invalid in the IndexedIO hierarchy
@@ -675,20 +675,21 @@ void SceneCacheData::loadPrimVars( const SceneInterface::Path& currentPath, TfTo
675675

676676
variablesPath.insert( variablesPath.end(), g_staticIoVariablesPath.begin(), g_staticIoVariablesPath.end() );
677677

678-
if ( auto variables = m_sceneio->directory( variablesPath, IndexedIO::MissingBehaviour::NullIfMissing ) )
678+
if ( const auto variables = m_sceneio->directory( variablesPath, IndexedIO::MissingBehaviour::NullIfMissing ) )
679679
{
680680
IndexedIO::EntryIDList variableLists;
681681
variables->entryIds( variableLists );
682-
for( auto& var: variableLists )
682+
683+
for( const auto& var: variableLists )
683684
{
684-
auto it = find( g_defaultPrimVars.cbegin(), g_defaultPrimVars.cend(), var.value() );
685+
const auto it = find( g_defaultPrimVars.cbegin(), g_defaultPrimVars.cend(), var.value() );
685686
if( it != g_defaultPrimVars.cend() )
686687
{
687688
continue;
688689
}
689690

690691
// interpolation
691-
auto variableIO = variables->subdirectory( var, IndexedIO::MissingBehaviour::NullIfMissing );
692+
const auto variableIO = variables->subdirectory( var, IndexedIO::MissingBehaviour::NullIfMissing );
692693
int interpolationValue = 0;
693694
TfToken usdInterpolation;
694695
if ( !variableIO || !variableIO->hasEntry( g_ioInterpolation ) )
@@ -701,17 +702,45 @@ void SceneCacheData::loadPrimVars( const SceneInterface::Path& currentPath, TfTo
701702
usdInterpolation = PrimitiveAlgo::toUSD( static_cast<PrimitiveVariable::Interpolation>( interpolationValue ) );
702703

703704
// data type
704-
auto dataType = variableIO->subdirectory( g_ioData, IndexedIO::MissingBehaviour::NullIfMissing );
705-
std::string dataTypeValue;
706-
if( !dataType || !dataType->hasEntry( g_ioType ) )
705+
if( !variableIO->hasEntry( g_ioData ) )
706+
{
707+
IECore::msg( IECore::Msg::Warning, "SceneCacheData::loadPrimVars", boost::format( "Unable to find data for Primitive Variable \"%s\" at location \"%s\"." ) % var % primPath );
708+
continue;
709+
}
710+
711+
ConstIndexedIOPtr dataIO;
712+
const IndexedIO::Entry dataEntry = variableIO->entry( g_ioData );
713+
if( dataEntry.entryType() == IndexedIO::File)
714+
{
715+
if( dataEntry.dataType() != IndexedIO::InternedStringArray )
716+
{
717+
IECore::msg( IECore::Msg::Warning, "SceneCacheData::loadPrimVars", boost::format( "Unable to find reference to data for Primitive Variable \"%s\" at location \"%s\"." ) % var % primPath );
718+
continue;
719+
}
720+
// IECore::Object has saved a reference to the data, so we need to follow the link to the referenced
721+
// directory in order to find the dataType
722+
IndexedIO::EntryIDList referencedPath( dataEntry.arrayLength() );
723+
InternedString *p = referencedPath.data();
724+
variableIO->read( g_ioData, p, dataEntry.arrayLength() );
725+
dataIO = variableIO->directory( referencedPath, IndexedIO::MissingBehaviour::NullIfMissing );
726+
}
727+
else
728+
{
729+
// Get the data subdirectory
730+
dataIO = variableIO->subdirectory( g_ioData, IndexedIO::MissingBehaviour::NullIfMissing );
731+
}
732+
733+
if( !dataIO || !dataIO->hasEntry( g_ioType ) )
707734
{
708735
IECore::msg( IECore::Msg::Warning, "SceneCacheData::loadPrimVars", boost::format( "Unable to find data type for Primitive Variable \"%s\" at location \"%s\"." ) % var % primPath );
709736
continue;
710737
}
711-
dataType->read( g_ioType, dataTypeValue );
738+
739+
std::string dataTypeValue;
740+
dataIO->read( g_ioType, dataTypeValue );
712741

713742
// interpretation
714-
auto interpretationData = dataType->subdirectory( g_ioData, IndexedIO::MissingBehaviour::NullIfMissing );
743+
const auto interpretationData = dataIO->subdirectory( g_ioData, IndexedIO::MissingBehaviour::NullIfMissing );
715744
IntDataPtr interpretationValue = nullptr;
716745
if ( interpretationData && interpretationData->hasEntry( g_interpretation ) )
717746
{

contrib/IECoreUSD/test/IECoreUSD/SceneCacheFileFormatTest.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,9 @@ def testCustomPrimvars( self ):
527527
mesh["customPoint"] = IECoreScene.PrimitiveVariable( IECoreScene.PrimitiveVariable.Interpolation.Vertex, v )
528528
mesh["customIndexedInt"] = IECoreScene.PrimitiveVariable( IECoreScene.PrimitiveVariable.Interpolation.Uniform, IECore.IntVectorData( [12] ), IECore.IntVectorData( [ 0 ] * vertexSize ) )
529529

530+
# Test a shallow copy of a primvar which causes IECore.Object to write a reference into the IndexedIO file
531+
mesh["Pref"] = mesh["P"]
532+
530533
box.writeObject( mesh, 1.0 )
531534
del m, box
532535

@@ -557,6 +560,14 @@ def testCustomPrimvars( self ):
557560
customIndexedInt = prim.GetAttribute( "primvars:customIndexedInt" )
558561
self.assertEqual( customIndexedInt.GetMetadata( "interpolation" ), pxr.UsdGeom.Tokens.uniform )
559562

563+
# Pref
564+
Pref = prim.GetAttribute( "primvars:Pref" )
565+
self.assertIsNotNone( Pref )
566+
self.assertFalse( Pref.GetMetadata( "custom" ) )
567+
self.assertEqual( Pref.GetMetadata( "typeName" ), pxr.Sdf.ValueTypeNames.Point3fArray )
568+
self.assertEqual( Pref.Get( 24.0 ), pxr.UsdGeom.Mesh( prim ).GetPointsAttr().Get( 24.0 ) )
569+
self.assertEqual( Pref.GetMetadata( "interpolation" ), pxr.UsdGeom.Tokens.vertex )
570+
560571
# round trip
561572
exportPath = os.path.join( self.temporaryDirectory(), "testUSDExportCustomPrimVar.scc" )
562573
stage.Export( exportPath )
@@ -581,6 +592,9 @@ def testCustomPrimvars( self ):
581592
# indices
582593
self.assertEqual( mesh["customIndexedInt"].indices, IECore.IntVectorData( [0] * vertexSize ) )
583594

595+
# copy
596+
self.assertEqual( mesh["Pref"], mesh["P"] )
597+
584598
def testCornersAndCreases( self ):
585599
fileName = os.path.join( self.temporaryDirectory(), "testUSDCornerAndCreases.scc" )
586600
m = IECoreScene.SceneCache( fileName, IECore.IndexedIO.OpenMode.Write )

0 commit comments

Comments
 (0)