Skip to content

Commit 9d1232d

Browse files
Merge pull request #1501 from johnhaddon/usdAnimationMaterials
USDScene : Fix loading of animated materials and lights
2 parents fe9d009 + c181d14 commit 9d1232d

File tree

7 files changed

+329
-33
lines changed

7 files changed

+329
-33
lines changed

Changes

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
Fixes
55
-----
66

7+
- USDScene : Fixed reading of animated parameters on materials and lights.
78
- Boost : Fixed compatibility with Boost 1.85.
89

910
Build

contrib/IECoreUSD/include/IECoreUSD/ShaderAlgo.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,16 +58,19 @@ IECOREUSD_API pxr::UsdShadeOutput writeShaderNetwork( const IECoreScene::ShaderN
5858

5959
/// Reads a ShaderNetwork from a material output, typically obtained from `UsdShadeMaterial::GetOutput()`.
6060
/// Returns `nullptr` if `canReadShaderNetwork() == false`, usually because the output has no connected source.
61-
IECOREUSD_API IECoreScene::ShaderNetworkPtr readShaderNetwork( const pxr::UsdShadeOutput &output );
61+
IECOREUSD_API IECoreScene::ShaderNetworkPtr readShaderNetwork( const pxr::UsdShadeOutput &output, pxr::UsdTimeCode timeCode = pxr::UsdTimeCode::Default() );
6262
/// Returns true if `readShaderNetwork()` will return `nullptr`, usually because the output has no
6363
/// connected source.
6464
bool canReadShaderNetwork( const pxr::UsdShadeOutput &output );
65+
IECOREUSD_API bool shaderNetworkMightBeTimeVarying( const pxr::UsdShadeOutput &output );
6566

6667
#if PXR_VERSION >= 2111
6768
/// Writes a UsdLuxLight from a shader network.
6869
IECOREUSD_API void writeLight( const IECoreScene::ShaderNetwork *shaderNetwork, pxr::UsdPrim prim );
6970
/// Reads a ShaderNetwork from a light.
70-
IECOREUSD_API IECoreScene::ShaderNetworkPtr readLight( const pxr::UsdLuxLightAPI &light );
71+
IECOREUSD_API IECoreScene::ShaderNetworkPtr readLight( const pxr::UsdLuxLightAPI &light, pxr::UsdTimeCode timeCode = pxr::UsdTimeCode::Default() );
72+
IECOREUSD_API bool lightMightBeTimeVarying( const pxr::UsdLuxLightAPI &light );
73+
7174
#endif
7275

7376
} // namespace ShaderAlgo

contrib/IECoreUSD/src/IECoreUSD/ShaderAlgo.cpp

Lines changed: 111 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,45 @@ void readNonStandardLightParameters( const pxr::UsdPrim &prim, IECore::CompoundD
162162
#endif
163163
}
164164

165+
bool nonStandardLightParametersMightBeTimeVarying( const pxr::UsdPrim &prim )
166+
{
167+
#if PXR_VERSION >= 2111
168+
if( auto sphereLight = pxr::UsdLuxSphereLight( prim ) )
169+
{
170+
if( sphereLight.GetTreatAsPointAttr().ValueMightBeTimeVarying() )
171+
{
172+
return true;
173+
}
174+
}
175+
else if( auto cylinderLight = pxr::UsdLuxCylinderLight( prim ) )
176+
{
177+
if( cylinderLight.GetTreatAsLineAttr().ValueMightBeTimeVarying() )
178+
{
179+
return true;
180+
}
181+
}
182+
183+
if( auto light = pxr::UsdLuxLightAPI( prim ) )
184+
{
185+
pxr::UsdGeomPrimvarsAPI primVarsAPI( prim );
186+
for( const auto &primVar : primVarsAPI.GetPrimvarsWithAuthoredValues() )
187+
{
188+
pxr::TfToken name = primVar.GetPrimvarName();
189+
if( !boost::starts_with( name.GetString(), "arnold:" ) )
190+
{
191+
continue;
192+
}
193+
194+
if( primVar.ValueMightBeTimeVarying() )
195+
{
196+
return true;
197+
}
198+
}
199+
}
200+
#endif
201+
return false;
202+
}
203+
165204
const std::regex g_arrayIndexFromUSDRegex( ":i([0-9]+)$" );
166205
const std::string g_arrayIndexFromUSDFormat( "[$1]" );
167206
IECore::InternedString fromUSDParameterName( const pxr::TfToken &usdName )
@@ -181,9 +220,9 @@ pxr::TfToken toUSDParameterName( IECore::InternedString cortexName )
181220
);
182221
}
183222

184-
IECoreScene::ShaderNetwork::Parameter readShaderNetworkWalk( const pxr::SdfPath &anchorPath, const pxr::UsdShadeOutput &output, IECoreScene::ShaderNetwork &shaderNetwork );
223+
IECoreScene::ShaderNetwork::Parameter readShaderNetworkWalk( const pxr::SdfPath &anchorPath, const pxr::UsdShadeOutput &output, pxr::UsdTimeCode timeCode, IECoreScene::ShaderNetwork &shaderNetwork );
185224

186-
IECore::InternedString readShaderNetworkWalk( const pxr::SdfPath &anchorPath, const pxr::UsdShadeConnectableAPI &usdShader, IECoreScene::ShaderNetwork &shaderNetwork )
225+
IECore::InternedString readShaderNetworkWalk( const pxr::SdfPath &anchorPath, const pxr::UsdShadeConnectableAPI &usdShader, pxr::UsdTimeCode timeCode, IECoreScene::ShaderNetwork &shaderNetwork )
187226
{
188227
IECore::InternedString handle( usdShader.GetPath().MakeRelativePath( anchorPath ).GetString() );
189228

@@ -226,7 +265,7 @@ IECore::InternedString readShaderNetworkWalk( const pxr::SdfPath &anchorPath, co
226265
if( usdSourceType == pxr::UsdShadeAttributeType::Output )
227266
{
228267
const IECoreScene::ShaderNetwork::Parameter sourceHandle = readShaderNetworkWalk(
229-
anchorPath, usdSource.GetOutput( usdSourceName ), shaderNetwork
268+
anchorPath, usdSource.GetOutput( usdSourceName ), timeCode, shaderNetwork
230269
);
231270
connections.push_back( {
232271
sourceHandle, { handle, fromUSDParameterName( i.GetBaseName() ) }
@@ -241,7 +280,7 @@ IECore::InternedString readShaderNetworkWalk( const pxr::SdfPath &anchorPath, co
241280
}
242281
}
243282

244-
if( IECore::DataPtr d = IECoreUSD::DataAlgo::fromUSD( pxr::UsdAttribute( valueAttribute ) ) )
283+
if( IECore::DataPtr d = IECoreUSD::DataAlgo::fromUSD( pxr::UsdAttribute( valueAttribute ), timeCode ) )
245284
{
246285
parameters[fromUSDParameterName( i.GetBaseName() )] = d;
247286
}
@@ -281,9 +320,9 @@ IECore::InternedString readShaderNetworkWalk( const pxr::SdfPath &anchorPath, co
281320
return handle;
282321
}
283322

284-
IECoreScene::ShaderNetwork::Parameter readShaderNetworkWalk( const pxr::SdfPath &anchorPath, const pxr::UsdShadeOutput &output, IECoreScene::ShaderNetwork &shaderNetwork )
323+
IECoreScene::ShaderNetwork::Parameter readShaderNetworkWalk( const pxr::SdfPath &anchorPath, const pxr::UsdShadeOutput &output, pxr::UsdTimeCode timeCode, IECoreScene::ShaderNetwork &shaderNetwork )
285324
{
286-
IECore::InternedString shaderHandle = readShaderNetworkWalk( anchorPath, pxr::UsdShadeConnectableAPI( output.GetPrim() ), shaderNetwork );
325+
IECore::InternedString shaderHandle = readShaderNetworkWalk( anchorPath, pxr::UsdShadeConnectableAPI( output.GetPrim() ), timeCode, shaderNetwork );
287326
if( output.GetBaseName() != "DEFAULT_OUTPUT" )
288327
{
289328
return IECoreScene::ShaderNetwork::Parameter( shaderHandle, output.GetBaseName().GetString() );
@@ -294,6 +333,45 @@ IECoreScene::ShaderNetwork::Parameter readShaderNetworkWalk( const pxr::SdfPath
294333
}
295334
}
296335

336+
bool shaderNetworkMightBeTimeVaryingWalk( const pxr::UsdShadeConnectableAPI &usdShader, std::unordered_set<pxr::UsdPrim, pxr::TfHash> &visited )
337+
{
338+
if( !visited.insert( usdShader.GetPrim() ).second )
339+
{
340+
return false;
341+
}
342+
343+
std::vector<IECoreScene::ShaderNetwork::Connection> connections;
344+
for( pxr::UsdShadeInput &i : usdShader.GetInputs() )
345+
{
346+
pxr::UsdShadeConnectableAPI usdSource;
347+
pxr::TfToken usdSourceName;
348+
pxr::UsdShadeAttributeType usdSourceType;
349+
350+
pxr::UsdAttribute valueAttribute = i;
351+
if( i.GetConnectedSource( &usdSource, &usdSourceName, &usdSourceType ) )
352+
{
353+
if( usdSourceType == pxr::UsdShadeAttributeType::Output )
354+
{
355+
if( shaderNetworkMightBeTimeVaryingWalk( usdSource, visited ) )
356+
{
357+
return true;
358+
}
359+
}
360+
else
361+
{
362+
valueAttribute = usdSource.GetInput( usdSourceName );
363+
}
364+
}
365+
366+
if( valueAttribute.ValueMightBeTimeVarying() )
367+
{
368+
return true;
369+
}
370+
}
371+
372+
return nonStandardLightParametersMightBeTimeVarying( usdShader.GetPrim() );
373+
}
374+
297375
IECoreScene::ConstShaderNetworkPtr adaptShaderNetworkForWriting( const IECoreScene::ShaderNetwork *shaderNetwork )
298376
{
299377
IECoreScene::ShaderNetworkPtr result = shaderNetwork->copy();
@@ -480,7 +558,7 @@ bool IECoreUSD::ShaderAlgo::canReadShaderNetwork( const pxr::UsdShadeOutput &out
480558
return true;
481559
}
482560

483-
IECoreScene::ShaderNetworkPtr IECoreUSD::ShaderAlgo::readShaderNetwork( const pxr::UsdShadeOutput &output )
561+
IECoreScene::ShaderNetworkPtr IECoreUSD::ShaderAlgo::readShaderNetwork( const pxr::UsdShadeOutput &output, pxr::UsdTimeCode timeCode )
484562
{
485563
pxr::UsdShadeConnectableAPI usdSource;
486564
pxr::TfToken usdSourceName;
@@ -494,7 +572,7 @@ IECoreScene::ShaderNetworkPtr IECoreUSD::ShaderAlgo::readShaderNetwork( const px
494572
}
495573

496574
IECoreScene::ShaderNetworkPtr result = new IECoreScene::ShaderNetwork();
497-
IECoreScene::ShaderNetwork::Parameter outputHandle = readShaderNetworkWalk( usdSource.GetPrim().GetParent().GetPath(), usdSource.GetOutput( usdSourceName ), *result );
575+
IECoreScene::ShaderNetwork::Parameter outputHandle = readShaderNetworkWalk( usdSource.GetPrim().GetParent().GetPath(), usdSource.GetOutput( usdSourceName ), timeCode, *result );
498576

499577
// If the output shader has type "ai:shader" then set its type to
500578
// "ai:surface" or "ai:light" as appropriate. This is just a heuristic,
@@ -529,6 +607,23 @@ IECoreScene::ShaderNetworkPtr IECoreUSD::ShaderAlgo::readShaderNetwork( const px
529607
return result;
530608
}
531609

610+
bool IECoreUSD::ShaderAlgo::shaderNetworkMightBeTimeVarying( const pxr::UsdShadeOutput &output )
611+
{
612+
pxr::UsdShadeConnectableAPI usdSource;
613+
pxr::TfToken usdSourceName;
614+
pxr::UsdShadeAttributeType usdSourceType;
615+
if(
616+
!output.GetConnectedSource( &usdSource, &usdSourceName, &usdSourceType ) ||
617+
usdSourceType != pxr::UsdShadeAttributeType::Output
618+
)
619+
{
620+
return false;
621+
}
622+
623+
std::unordered_set<pxr::UsdPrim, pxr::TfHash> visited;
624+
return shaderNetworkMightBeTimeVaryingWalk( usdSource, visited );
625+
}
626+
532627
#if PXR_VERSION >= 2111
533628

534629
// This is very similar to `writeShaderNetwork` but with these key differences :
@@ -587,13 +682,19 @@ void IECoreUSD::ShaderAlgo::writeLight( const IECoreScene::ShaderNetwork *shader
587682
writeShaderConnections( shaderNetwork, usdShaders );
588683
}
589684

590-
IECoreScene::ShaderNetworkPtr IECoreUSD::ShaderAlgo::readLight( const pxr::UsdLuxLightAPI &light )
685+
IECoreScene::ShaderNetworkPtr IECoreUSD::ShaderAlgo::readLight( const pxr::UsdLuxLightAPI &light, pxr::UsdTimeCode timeCode )
591686
{
592687
IECoreScene::ShaderNetworkPtr result = new IECoreScene::ShaderNetwork();
593-
IECoreScene::ShaderNetwork::Parameter lightHandle = readShaderNetworkWalk( light.GetPath().GetParentPath(), pxr::UsdShadeConnectableAPI( light ), *result );
688+
IECoreScene::ShaderNetwork::Parameter lightHandle = readShaderNetworkWalk( light.GetPath().GetParentPath(), pxr::UsdShadeConnectableAPI( light ), timeCode, *result );
594689
result->setOutput( lightHandle );
595690
IECoreScene::ShaderNetworkAlgo::removeComponentConnectionAdapters( result.get() );
596691
return result;
597692
}
598693

694+
bool IECoreUSD::ShaderAlgo::lightMightBeTimeVarying( const pxr::UsdLuxLightAPI &light )
695+
{
696+
std::unordered_set<pxr::UsdPrim, pxr::TfHash> visited;
697+
return shaderNetworkMightBeTimeVaryingWalk( pxr::UsdShadeConnectableAPI( light ), visited );
698+
}
699+
599700
#endif

contrib/IECoreUSD/src/IECoreUSD/USDScene.cpp

Lines changed: 55 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -531,43 +531,60 @@ std::tuple<pxr::TfToken, pxr::TfToken> materialOutputAndPurpose( const std::stri
531531
return { AttributeAlgo::nameToUSD( attributeName ).name, pxr::UsdShadeTokens->allPurpose };
532532
}
533533

534-
/// SdfPath is the appropriate cache key for _storage_, but we need a
535-
/// `UsdShadeOutput` for computation. This struct provides the implicit
536-
/// conversion that LRUCache needs to make that possible.
537-
struct ShaderNetworkCacheGetterKey : public pxr::UsdShadeOutput
534+
using ShaderNetworkCacheKey = std::pair<pxr::SdfPath, pxr::UsdTimeCode>;
535+
536+
struct ShaderNetworkCacheGetterKey : public ShaderNetworkCacheKey
538537
{
539-
ShaderNetworkCacheGetterKey( const pxr::UsdShadeOutput &output )
540-
: pxr::UsdShadeOutput( output )
538+
ShaderNetworkCacheGetterKey( const pxr::UsdShadeOutput &output, pxr::UsdTimeCode time = pxr::UsdTimeCode::Default() )
539+
: ShaderNetworkCacheKey( output.GetAttr().GetPath(), time ), output( output )
541540
{
542541
}
543542

544-
operator pxr::SdfPath () const
545-
{
546-
return GetAttr().GetPath();
547-
}
543+
const pxr::UsdShadeOutput output;
548544
};
549545

550-
class ShaderNetworkCache : public LRUCache<pxr::SdfPath, IECoreScene::ConstShaderNetworkPtr, LRUCachePolicy::Parallel, ShaderNetworkCacheGetterKey>
546+
class ShaderNetworkCache : public LRUCache<ShaderNetworkCacheKey, IECoreScene::ConstShaderNetworkPtr, LRUCachePolicy::Parallel, ShaderNetworkCacheGetterKey>
551547
{
552548

553549
public :
554550

555551
ShaderNetworkCache( size_t maxBytes )
556-
: LRUCache<pxr::SdfPath, IECoreScene::ConstShaderNetworkPtr, LRUCachePolicy::Parallel, ShaderNetworkCacheGetterKey>( getter, maxBytes )
552+
: LRUCache<ShaderNetworkCacheKey, IECoreScene::ConstShaderNetworkPtr, LRUCachePolicy::Parallel, ShaderNetworkCacheGetterKey>( getter, maxBytes )
557553
{
558554
}
559555

560556
private :
561557

562558
static IECoreScene::ConstShaderNetworkPtr getter( const ShaderNetworkCacheGetterKey &key, size_t &cost )
563559
{
564-
IECoreScene::ConstShaderNetworkPtr result = ShaderAlgo::readShaderNetwork( key );
560+
IECoreScene::ConstShaderNetworkPtr result = ShaderAlgo::readShaderNetwork( key.output, key.second );
565561
cost = result ? result ->Object::memoryUsage() : 0;
566562
return result;
567563
}
568564

569565
};
570566

567+
class ShaderNetworkMightBeTimeVaryingCache : public LRUCache<ShaderNetworkCacheKey, bool, LRUCachePolicy::Parallel, ShaderNetworkCacheGetterKey>
568+
{
569+
570+
public :
571+
572+
ShaderNetworkMightBeTimeVaryingCache( size_t maxBytes )
573+
: LRUCache<ShaderNetworkCacheKey, bool, LRUCachePolicy::Parallel, ShaderNetworkCacheGetterKey>( getter, maxBytes )
574+
{
575+
}
576+
577+
private :
578+
579+
static bool getter( const ShaderNetworkCacheGetterKey &key, size_t &cost )
580+
{
581+
bool result = ShaderAlgo::shaderNetworkMightBeTimeVarying( key.output );
582+
cost = 1;
583+
return result;
584+
}
585+
586+
};
587+
571588
Imath::M44d localTransform( const pxr::UsdPrim &prim, pxr::UsdTimeCode time )
572589
{
573590
pxr::UsdGeomXformable transformable( prim );
@@ -669,6 +686,7 @@ class USDScene::IO : public RefCounted
669686
m_rootPrim( m_stage->GetPseudoRoot() ),
670687
m_timeCodesPerSecond( m_stage->GetTimeCodesPerSecond() ),
671688
m_shaderNetworkCache( 10 * 1024 * 1024 ), // 10Mb
689+
m_shaderNetworkMightBeTimeVaryingCache( 1000 ),
672690
m_uniqueId( g_usdFileCounter.fetch_add( 1, std::memory_order_relaxed ) )
673691
{
674692
// Although the USD API implies otherwise, we need a different
@@ -802,9 +820,23 @@ class USDScene::IO : public RefCounted
802820
return material;
803821
}
804822

805-
IECoreScene::ConstShaderNetworkPtr readShaderNetwork( const pxr::UsdShadeOutput &output )
823+
bool shaderNetworkMightBeTimeVarying( const pxr::UsdShadeOutput &output )
806824
{
807-
return m_shaderNetworkCache.get( output );
825+
return m_shaderNetworkMightBeTimeVaryingCache.get( output );
826+
}
827+
828+
IECoreScene::ConstShaderNetworkPtr readShaderNetwork( const pxr::UsdShadeOutput &output, pxr::UsdTimeCode timeCode )
829+
{
830+
if( shaderNetworkMightBeTimeVarying( output ) )
831+
{
832+
return m_shaderNetworkCache.get( ShaderNetworkCacheGetterKey( output, timeCode ) );
833+
}
834+
else
835+
{
836+
// Omit time, so we don't produce duplicate cache entries
837+
// for non-time-varying shaders.
838+
return m_shaderNetworkCache.get( output );
839+
}
808840
}
809841

810842
inline int uniqueId()
@@ -863,6 +895,7 @@ class USDScene::IO : public RefCounted
863895
pxr::UsdShadeMaterialBindingAPI::CollectionQueryCache m_usdCollectionQueryCache;
864896

865897
ShaderNetworkCache m_shaderNetworkCache;
898+
ShaderNetworkMightBeTimeVaryingCache m_shaderNetworkMightBeTimeVaryingCache;
866899

867900
// Used to identify a file uniquely ( including between different openings of the same filename,
868901
// since closing and reopening a file may cause USD to shuffle the contents ).
@@ -1234,7 +1267,7 @@ ConstObjectPtr USDScene::readAttribute( const SceneInterface::Name &name, double
12341267
#if PXR_VERSION >= 2111
12351268
else if( name == g_lightAttributeName )
12361269
{
1237-
return ShaderAlgo::readLight( pxr::UsdLuxLightAPI( m_location->prim ) );
1270+
return ShaderAlgo::readLight( pxr::UsdLuxLightAPI( m_location->prim ), m_root->timeCode( time ) );
12381271
}
12391272
#endif
12401273
else if( name == g_kindAttributeName )
@@ -1267,7 +1300,7 @@ ConstObjectPtr USDScene::readAttribute( const SceneInterface::Name &name, double
12671300
{
12681301
if( pxr::UsdShadeOutput o = mat.GetOutput( output ) )
12691302
{
1270-
return m_root->readShaderNetwork( o );
1303+
return m_root->readShaderNetwork( o, m_root->timeCode( time ) );
12711304
}
12721305
}
12731306
return nullptr;
@@ -1719,8 +1752,7 @@ void USDScene::attributesHash( double time, IECore::MurmurHash &h ) const
17191752
#if PXR_VERSION >= 2111
17201753
if( m_location->prim.HasAPI<pxr::UsdLuxLightAPI>() )
17211754
{
1722-
/// \todo Consider time-varying lights - see comment below
1723-
/// for materials.
1755+
mightBeTimeVarying = mightBeTimeVarying || ShaderAlgo::lightMightBeTimeVarying( pxr::UsdLuxLightAPI( m_location->prim ) );
17241756
haveAttributes = true;
17251757
}
17261758
#endif
@@ -1751,9 +1783,11 @@ void USDScene::attributesHash( double time, IECore::MurmurHash &h ) const
17511783
{
17521784
if( pxr::UsdShadeMaterial mat = m_root->computeBoundMaterial( m_location->prim, purpose ) )
17531785
{
1754-
// \todo - This does not consider the possibility that the material could contain time-varying
1755-
// attributes
17561786
append( mat.GetPrim().GetPath(), h );
1787+
for( pxr::UsdShadeOutput &o : mat.GetOutputs( /* onlyAuthored = */ true ) )
1788+
{
1789+
mightBeTimeVarying = mightBeTimeVarying || m_root->shaderNetworkMightBeTimeVarying( o );
1790+
}
17571791
haveMaterials = true;
17581792
}
17591793
}

0 commit comments

Comments
 (0)