Skip to content

Commit 9f86796

Browse files
committed
USD ShaderAlgo : Refactor shader reading
- Simplify `readShaderNetwork()` public interface, and move "does the output have a connection?" logic from USDScene into ShaderAlgo. - Introduce `readShaderNetworkWalk()` overload which takes an output and returns a handle for that output. This removes the repetition of the `DEFAULT_OUTPUT` special case. - Simplify connection handling by building `vector<Connection>` directly, rather than packing and unpacking a recipe for making a connection. - Remove unused `inputs` variable. - Remove bogus comment - there is no such variable as `handles[0]`.
1 parent 8e6bcd8 commit 9f86796

File tree

3 files changed

+46
-64
lines changed

3 files changed

+46
-64
lines changed

contrib/IECoreUSD/include/IECoreUSD/ShaderAlgo.h

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,8 @@ namespace ShaderAlgo
5353
/// Write ShaderNetwork to USD, placing the shaders under the Prim `shaderContainer`
5454
IECOREUSD_API pxr::UsdShadeOutput writeShaderNetwork( const IECoreScene::ShaderNetwork *shaderNetwork, pxr::UsdPrim shaderContainer );
5555

56-
/// Read ShaderNetwork from a USD node ( and its connected inputs )
57-
/// `anchorPath` is the ancestor path that shaders will be named relative to
58-
/// `outputHandle` specifies which output of the USD node is being used ( the ShaderNetwork must have
59-
/// a corresponding output set )
60-
IECoreScene::ShaderNetworkPtr readShaderNetwork( const pxr::SdfPath &anchorPath, const pxr::UsdShadeShader &outputShader, const pxr::TfToken &outputHandle );
61-
56+
/// Reads a ShaderNetwork from a material output, typically obtained from `UsdShadeMaterial::GetOutput()`.
57+
IECoreScene::ShaderNetworkPtr readShaderNetwork( const pxr::UsdShadeOutput &output );
6258

6359

6460
} // namespace ShaderAlgo

contrib/IECoreUSD/src/IECoreUSD/ShaderAlgo.cpp

Lines changed: 43 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ namespace
5353

5454
pxr::TfToken g_adapterLabelToken( IECoreScene::ShaderNetworkAlgo::componentConnectionAdapterLabel().string() );
5555

56+
IECoreScene::ShaderNetwork::Parameter readShaderNetworkWalk( const pxr::SdfPath &anchorPath, const pxr::UsdShadeOutput &output, IECoreScene::ShaderNetwork &shaderNetwork );
57+
5658
IECore::InternedString readShaderNetworkWalk( const pxr::SdfPath &anchorPath, const pxr::UsdShadeShader &usdShader, IECoreScene::ShaderNetwork &shaderNetwork )
5759
{
5860
IECore::InternedString handle( usdShader.GetPath().MakeRelativePath( anchorPath ).GetString() );
@@ -84,8 +86,7 @@ IECore::InternedString readShaderNetworkWalk( const pxr::SdfPath &anchorPath, co
8486

8587
IECore::CompoundDataPtr parametersData = new IECore::CompoundData();
8688
IECore::CompoundDataMap &parameters = parametersData->writable();
87-
std::vector< std::tuple< IECore::InternedString, pxr::UsdShadeConnectableAPI, IECore::InternedString > > connections;
88-
std::vector< pxr::UsdShadeInput > inputs = usdShader.GetInputs();
89+
std::vector<IECoreScene::ShaderNetwork::Connection> connections;
8990
for( pxr::UsdShadeInput &i : usdShader.GetInputs() )
9091
{
9192
pxr::UsdShadeConnectableAPI usdSource;
@@ -95,9 +96,14 @@ IECore::InternedString readShaderNetworkWalk( const pxr::SdfPath &anchorPath, co
9596
pxr::UsdAttribute valueAttribute = i;
9697
if( i.GetConnectedSource( &usdSource, &usdSourceName, &usdSourceType ) )
9798
{
98-
if( !usdSource.IsContainer() )
99+
if( usdSourceType == pxr::UsdShadeAttributeType::Output )
99100
{
100-
connections.push_back( { i.GetBaseName().GetString(), usdSource, usdSourceName.GetString() } );
101+
const IECoreScene::ShaderNetwork::Parameter sourceHandle = readShaderNetworkWalk(
102+
anchorPath, usdSource.GetOutput( usdSourceName ), shaderNetwork
103+
);
104+
connections.push_back( {
105+
sourceHandle, { handle, IECore::InternedString( i.GetBaseName().GetString() ) }
106+
} );
101107
}
102108
else
103109
{
@@ -124,33 +130,28 @@ IECore::InternedString readShaderNetworkWalk( const pxr::SdfPath &anchorPath, co
124130
}
125131
shaderNetwork.addShader( handle, std::move( newShader ) );
126132

133+
// Can only add connections after we've added the shader.
127134
for( const auto &c : connections )
128135
{
129-
IECore::InternedString attributeName;
130-
pxr::UsdShadeConnectableAPI usdSource;
131-
IECore::InternedString sourceAttributeName;
132-
std::tie( attributeName, usdSource, sourceAttributeName ) = c;
133-
IECore::InternedString sourceHandle = readShaderNetworkWalk( anchorPath, pxr::UsdShadeShader( usdSource.GetPrim() ), shaderNetwork );
134-
135-
if( sourceAttributeName == "DEFAULT_OUTPUT" )
136-
{
137-
shaderNetwork.addConnection( IECoreScene::ShaderNetwork::Connection(
138-
{ sourceHandle, "" },
139-
{ handle, attributeName }
140-
) );
141-
}
142-
else
143-
{
144-
shaderNetwork.addConnection( IECoreScene::ShaderNetwork::Connection(
145-
{ sourceHandle, sourceAttributeName },
146-
{ handle, attributeName }
147-
) );
148-
}
136+
shaderNetwork.addConnection( c );
149137
}
150138

151139
return handle;
152140
}
153141

142+
IECoreScene::ShaderNetwork::Parameter readShaderNetworkWalk( const pxr::SdfPath &anchorPath, const pxr::UsdShadeOutput &output, IECoreScene::ShaderNetwork &shaderNetwork )
143+
{
144+
IECore::InternedString shaderHandle = readShaderNetworkWalk( anchorPath, pxr::UsdShadeShader( output.GetPrim() ), shaderNetwork );
145+
if( output.GetBaseName() != "DEFAULT_OUTPUT" )
146+
{
147+
return IECoreScene::ShaderNetwork::Parameter( shaderHandle, output.GetBaseName().GetString() );
148+
}
149+
else
150+
{
151+
return IECoreScene::ShaderNetwork::Parameter( shaderHandle );
152+
}
153+
}
154+
154155
} // namespace
155156

156157
pxr::UsdShadeOutput IECoreUSD::ShaderAlgo::writeShaderNetwork( const IECoreScene::ShaderNetwork *shaderNetwork, pxr::UsdPrim shaderContainer )
@@ -249,10 +250,21 @@ pxr::UsdShadeOutput IECoreUSD::ShaderAlgo::writeShaderNetwork( const IECoreScene
249250
return networkOutUsd;
250251
}
251252

252-
IECoreScene::ShaderNetworkPtr IECoreUSD::ShaderAlgo::readShaderNetwork( const pxr::SdfPath &anchorPath, const pxr::UsdShadeShader &outputShader, const pxr::TfToken &outputParameter )
253+
IECoreScene::ShaderNetworkPtr IECoreUSD::ShaderAlgo::readShaderNetwork( const pxr::UsdShadeOutput &output )
253254
{
255+
pxr::UsdShadeConnectableAPI usdSource;
256+
pxr::TfToken usdSourceName;
257+
pxr::UsdShadeAttributeType usdSourceType;
258+
if(
259+
!output.GetConnectedSource( &usdSource, &usdSourceName, &usdSourceType ) ||
260+
usdSourceType != pxr::UsdShadeAttributeType::Output
261+
)
262+
{
263+
return new IECoreScene::ShaderNetwork();
264+
}
265+
254266
IECoreScene::ShaderNetworkPtr result = new IECoreScene::ShaderNetwork();
255-
IECore::InternedString outputHandle = readShaderNetworkWalk( anchorPath, outputShader, *result );
267+
IECoreScene::ShaderNetwork::Parameter outputHandle = readShaderNetworkWalk( usdSource.GetPrim().GetParent().GetPath(), usdSource.GetOutput( usdSourceName ), *result );
256268

257269
// For the output shader, set the type to "ai:surface" if it is "ai:shader".
258270
// This is complete nonsense - there is nothing to suggest that this shader is
@@ -265,22 +277,15 @@ IECoreScene::ShaderNetworkPtr IECoreUSD::ShaderAlgo::readShaderNetwork( const px
265277
// don't use the suffix of the shader type for anything, and we should just set
266278
// everything to prefix:shader ( aside from lights, which are a bit of a
267279
// different question )
268-
if( result->getShader( outputHandle )->getType() == "ai:shader" )
280+
const IECoreScene::Shader *outputShader = result->getShader( outputHandle.shader );
281+
if( outputShader->getType() == "ai:shader" )
269282
{
270-
IECoreScene::ShaderPtr o = result->getShader( outputHandle )->copy();
283+
IECoreScene::ShaderPtr o = outputShader->copy();
271284
o->setType( "ai:surface" );
272-
result->setShader( outputHandle, std::move( o ) );
285+
result->setShader( outputHandle.shader, std::move( o ) );
273286
}
274287

275-
// handles[0] is the handle of the first shader added, which is always the output shader
276-
if( outputParameter.GetString() != "DEFAULT_OUTPUT" )
277-
{
278-
result->setOutput( IECoreScene::ShaderNetwork::Parameter( outputHandle, outputParameter.GetString() ) );
279-
}
280-
else
281-
{
282-
result->setOutput( IECoreScene::ShaderNetwork::Parameter( outputHandle ) );
283-
}
288+
result->setOutput( outputHandle );
284289

285290
IECoreScene::ShaderNetworkAlgo::removeComponentConnectionAdapters( result.get() );
286291

contrib/IECoreUSD/src/IECoreUSD/USDScene.cpp

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -415,26 +415,7 @@ class ShaderNetworkCache : public LRUCache<pxr::SdfPath, IECoreScene::ConstShade
415415

416416
static IECoreScene::ConstShaderNetworkPtr getter( const ShaderNetworkCacheGetterKey &key, size_t &cost )
417417
{
418-
IECoreScene::ConstShaderNetworkPtr result;
419-
420-
/// \todo I'm pretty sure that the `readShaderNetwork()` signature is overly complex,
421-
/// and it should just be passed a single `UsdShadeOutput &` like this function.
422-
/// I suspect that `writeShaderNetwork()` could take a single `UsdShadeOutput &` too,
423-
/// for symmetry between the two functions.
424-
425-
pxr::UsdShadeConnectableAPI source;
426-
pxr::TfToken sourceName;
427-
pxr::UsdShadeAttributeType sourceType;
428-
if( key.GetConnectedSource( &source, &sourceName, &sourceType ) )
429-
{
430-
pxr::UsdShadeShader s( source.GetPrim() );
431-
result = ShaderAlgo::readShaderNetwork( source.GetPrim().GetParent().GetPath(), s, sourceName );
432-
}
433-
else
434-
{
435-
result = new IECoreScene::ShaderNetwork();
436-
}
437-
418+
IECoreScene::ConstShaderNetworkPtr result = ShaderAlgo::readShaderNetwork( key );
438419
cost = result->Object::memoryUsage();
439420
return result;
440421
}

0 commit comments

Comments
 (0)