Skip to content

Commit

Permalink
Merge pull request #6214 from GafferHQ/shaderSubstitutionAttributeNames
Browse files Browse the repository at this point in the history
Arnold ShaderNetworkAlgo : Add `attributeName` argument to SubstitutionFunction
  • Loading branch information
murraystevenson authored Jan 16, 2025
2 parents 12aae90 + d8f3604 commit 41cef12
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 58 deletions.
4 changes: 4 additions & 0 deletions Changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ API

- TweakPlug : Added `applyElementwiseTweak()` method, for tweaking elements of a `*VectorData`.
- IECoreArnold, IECoreDelight : Added support for config files installed on `GAFFER_STARTUP_PATHS`.
- IECoreArnold::ShaderNetworkAlgo : Added `attributeName` arguments to `SubstitutionFunction` and `SubstitutionHashFunction`. This is an ABI break, which would not normally be allowed without a change of major version. We are making a rare exception in this case, with the following justifications :
- The API is esoteric and was introduced extremely recently, so we believe nobody to be depending on it yet.
- Without the ABI change, the API isn't usable for its original intended purpose anyway.
- Backward compatibility is not trivial to maintain in this case.

1.5.2.0 (relative to 1.5.1.0)
=======
Expand Down
8 changes: 4 additions & 4 deletions include/IECoreArnold/ShaderNetworkAlgo.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,13 +95,13 @@ IECOREARNOLD_API void convertUSDShaders( IECoreScene::ShaderNetwork *shaderNetwo

/// A function that performs substitutions on a shader network, given the full
/// inherited `attributes` for an object. Must be threadsafe.
using SubstitutionFunction = void (*)( IECoreScene::ShaderNetwork *shaderNetwork, const IECore::CompoundObject *attributes );
using SubstitutionFunction = void (*)( IECoreScene::ShaderNetwork *shaderNetwork, IECore::InternedString attributeName, const IECore::CompoundObject *attributes );
/// A function that appends to `hash` to uniquely identify the work that will be
/// performed by a SubstitutionFunction. Particular attention must be paid to
/// the performance of any such function, as it will be called frequently. If a
/// substitution will be a no-op, then nothing should be appended to the hash.
/// Must be threadsafe.
using SubstitutionHashFunction = void (*)( const IECoreScene::ShaderNetwork *shaderNetwork, const IECore::CompoundObject *attributes, IECore::MurmurHash &hash );
using SubstitutionHashFunction = void (*)( const IECoreScene::ShaderNetwork *shaderNetwork, IECore::InternedString attributeName, const IECore::CompoundObject *attributes, IECore::MurmurHash &hash );

/// Registers a just-in-time substitution to be performed on shader
/// networks before the shader is translated to Arnold.
Expand All @@ -110,9 +110,9 @@ IECOREARNOLD_API void registerSubstitution( const std::string &name, Substitutio
IECOREARNOLD_API void deregisterSubstitution( const std::string &name );

/// Hashes all the currently registered substitutions for `shaderNetwork`.
IECOREARNOLD_API void hashSubstitutions( const IECoreScene::ShaderNetwork *shaderNetwork, const IECore::CompoundObject *attributes, IECore::MurmurHash &hash );
IECOREARNOLD_API void hashSubstitutions( const IECoreScene::ShaderNetwork *shaderNetwork, IECore::InternedString attributeName, const IECore::CompoundObject *attributes, IECore::MurmurHash &hash );
/// Applies all the currently registered substitutions to `shaderNetwork`.
IECOREARNOLD_API void applySubstitutions( IECoreScene::ShaderNetwork *shaderNetwork, const IECore::CompoundObject *attributes );
IECOREARNOLD_API void applySubstitutions( IECoreScene::ShaderNetwork *shaderNetwork, IECore::InternedString attributeName, const IECore::CompoundObject *attributes );

} // namespace ShaderNetworkAlgo

Expand Down
98 changes: 50 additions & 48 deletions src/IECoreArnold/Renderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -828,13 +828,13 @@ class ShaderCache : public IECore::RefCounted
}

// Can be called concurrently with other get() calls.
ArnoldShaderPtr get( const IECoreScene::ShaderNetwork *shader, const IECore::CompoundObject *attributes )
ArnoldShaderPtr get( const IECoreScene::ShaderNetwork *shader, IECore::InternedString attributeName, const IECore::CompoundObject *attributes )
{
IECore::MurmurHash h = shader->Object::hash();
IECore::MurmurHash hSubst;
if( attributes )
{
ShaderNetworkAlgo::hashSubstitutions( shader, attributes, hSubst );
ShaderNetworkAlgo::hashSubstitutions( shader, attributeName, attributes, hSubst );
h.append( hSubst );
}

Expand All @@ -851,7 +851,7 @@ class ShaderCache : public IECore::RefCounted
if( hSubst != IECore::MurmurHash() )
{
IECoreScene::ShaderNetworkPtr substitutedShader = shader->copy();
ShaderNetworkAlgo::applySubstitutions( substitutedShader.get(), attributes );
ShaderNetworkAlgo::applySubstitutions( substitutedShader.get(), attributeName, attributes );
writeAccessor->second = new ArnoldShader( substitutedShader.get(), m_nodeDeleter, m_universe, namePrefix, m_parentNode );
}
else
Expand All @@ -862,6 +862,25 @@ class ShaderCache : public IECore::RefCounted
return writeAccessor->second;
}

// Convenience function that search for a shader network with one of the
// specified attributes names, converting the first one found.
ArnoldShaderPtr get( const vector<IECore::InternedString> &attributeNames, const IECore::CompoundObject *attributes )
{
for( auto name : attributeNames )
{
auto it = attributes->members().find( name );
if( it == attributes->members().end() )
{
continue;
}
if( auto shader = reportedCast<const IECoreScene::ShaderNetwork>( it->second.get(), "attribute", name ) )
{
return get( shader, name, attributes );
}
}
return nullptr;
}

// _Must_ be called before `render()` launches Arnold, and must not be
// called concurrently with anything. This removes shaders that are no
// longer in use during interactive renders, and ensures all
Expand Down Expand Up @@ -921,17 +940,12 @@ namespace
// Forward declaration
bool isConvertedProcedural( const AtNode *node );

IECore::InternedString g_surfaceShaderAttributeName( "surface" );
IECore::InternedString g_volumeShaderAttributeName( "volume" );
IECore::InternedString g_lightShaderAttributeName( "light" );
IECore::InternedString g_doubleSidedAttributeName( "doubleSided" );
IECore::InternedString g_setsAttributeName( "sets" );
IECore::InternedString g_automaticInstancingAttributeName( "gaffer:automaticInstancing" );
IECore::InternedString g_muteLightAttributeName( "light:mute" );

IECore::InternedString g_oslSurfaceShaderAttributeName( "osl:surface" );
IECore::InternedString g_oslShaderAttributeName( "osl:shader" );

IECore::InternedString g_cameraVisibilityAttributeName( "ai:visibility:camera" );
IECore::InternedString g_shadowVisibilityAttributeName( "ai:visibility:shadow" );
IECore::InternedString g_shadowGroup( "ai:visibility:shadow_group" );
Expand All @@ -951,11 +965,7 @@ IECore::InternedString g_specularTransmitVisibilityAutoBumpAttributeName( "ai:au
IECore::InternedString g_volumeVisibilityAutoBumpAttributeName( "ai:autobump_visibility:volume" );
IECore::InternedString g_subsurfaceVisibilityAutoBumpAttributeName( "ai:autobump_visibility:subsurface" );

IECore::InternedString g_arnoldSurfaceShaderAttributeName( "ai:surface" );
IECore::InternedString g_arnoldVolumeShaderAttributeName( "ai:volume" );
IECore::InternedString g_arnoldLightShaderAttributeName( "ai:light" );
IECore::InternedString g_arnoldFilterMapAttributeName( "ai:filtermap" );
IECore::InternedString g_arnoldUVRemapAttributeName( "ai:uv_remap" );
IECore::InternedString g_arnoldLightFilterShaderAttributeName( "ai:lightFilter:filter" );

IECore::InternedString g_arnoldReceiveShadowsAttributeName( "ai:receive_shadows" );
Expand Down Expand Up @@ -985,7 +995,6 @@ IECore::InternedString g_polyMeshSubdivFrustumIgnoreAttributeName( "ai:polymesh:
IECore::InternedString g_polyMeshSubdividePolygonsAttributeName( "ai:polymesh:subdivide_polygons" );
IECore::InternedString g_polyMeshSubdivUVSmoothingAttributeName( "ai:polymesh:subdiv_uv_smoothing" );

IECore::InternedString g_dispMapAttributeName( "ai:disp_map" );
IECore::InternedString g_dispHeightAttributeName( "ai:disp_height" );
IECore::InternedString g_dispPaddingAttributeName( "ai:disp_padding" );
IECore::InternedString g_dispZeroValueAttributeName( "ai:disp_zero_value" );
Expand All @@ -1001,6 +1010,23 @@ IECore::InternedString g_lightFilterPrefix( "ai:lightFilter:" );

IECore::InternedString g_filteredLights( "filteredLights" );

const std::vector<IECore::InternedString> g_surfaceShaderAttributeNames = {
"ai:surface",
"osl:surface",
/// \todo Remove support for interpreting "osl:shader" as a surface shader assignment.
"osl:shader",
"surface"
};

const std::vector<IECore::InternedString> g_volumeShaderAttributeNames = {
"ai:volume",
"volume"
};

const std::vector<IECore::InternedString> g_filterMapAttributeNames = { "ai:filtermap" };
const std::vector<IECore::InternedString> g_uvRemapAttributeNames = { "ai:uv_remap" };
const std::vector<IECore::InternedString> g_dispMapAttributeNames = { "ai:disp_map" };

const char *customAttributeName( const std::string &attributeName, bool *hasPrecedence = nullptr )
{
if( boost::starts_with( attributeName, "user:" ) )
Expand Down Expand Up @@ -1051,31 +1077,10 @@ class ArnoldAttributes : public IECoreScenePreview::Renderer::AttributesInterfac
updateShadingFlag( g_arnoldOpaqueAttributeName, Opaque, attributes );
updateShadingFlag( g_arnoldMatteAttributeName, Matte, attributes );

const IECoreScene::ShaderNetwork *surfaceShaderAttribute = attribute<IECoreScene::ShaderNetwork>( g_arnoldSurfaceShaderAttributeName, attributes );
surfaceShaderAttribute = surfaceShaderAttribute ? surfaceShaderAttribute : attribute<IECoreScene::ShaderNetwork>( g_oslSurfaceShaderAttributeName, attributes );
/// \todo Remove support for interpreting "osl:shader" as a surface shader assignment.
surfaceShaderAttribute = surfaceShaderAttribute ? surfaceShaderAttribute : attribute<IECoreScene::ShaderNetwork>( g_oslShaderAttributeName, attributes );
surfaceShaderAttribute = surfaceShaderAttribute ? surfaceShaderAttribute : attribute<IECoreScene::ShaderNetwork>( g_surfaceShaderAttributeName, attributes );
if( surfaceShaderAttribute )
{
m_surfaceShader = shaderCache->get( surfaceShaderAttribute, attributes );
}

const IECoreScene::ShaderNetwork *volumeShaderAttribute = attribute<IECoreScene::ShaderNetwork>( g_arnoldVolumeShaderAttributeName, attributes );
volumeShaderAttribute = volumeShaderAttribute ? volumeShaderAttribute : attribute<IECoreScene::ShaderNetwork>( g_volumeShaderAttributeName, attributes );
if( volumeShaderAttribute )
{
m_volumeShader = shaderCache->get( volumeShaderAttribute, attributes );
}

if( auto filterMapAttribute = attribute<IECoreScene::ShaderNetwork>( g_arnoldFilterMapAttributeName, attributes ) )
{
m_filterMap = shaderCache->get( filterMapAttribute, attributes );
}
if( auto uvRemapAttribute = attribute<IECoreScene::ShaderNetwork>( g_arnoldUVRemapAttributeName, attributes ) )
{
m_uvRemap = shaderCache->get( uvRemapAttribute, attributes );
}
m_surfaceShader = shaderCache->get( g_surfaceShaderAttributeNames, attributes );
m_volumeShader = shaderCache->get( g_volumeShaderAttributeNames, attributes );
m_filterMap = shaderCache->get( g_filterMapAttributeNames, attributes );
m_uvRemap = shaderCache->get( g_uvRemapAttributeNames, attributes );

m_lightShader = attribute<IECoreScene::ShaderNetwork>( g_arnoldLightShaderAttributeName, attributes );
m_lightShader = m_lightShader ? m_lightShader : attribute<IECoreScene::ShaderNetwork>( g_lightShaderAttributeName, attributes );
Expand Down Expand Up @@ -1116,7 +1121,7 @@ class ArnoldAttributes : public IECoreScenePreview::Renderer::AttributesInterfac
}
else if( boost::starts_with( it->first.string(), g_lightFilterPrefix.string() ) )
{
ArnoldShaderPtr filter = shaderCache->get( IECore::runTimeCast<const IECoreScene::ShaderNetwork>( it->second.get() ), attributes );
ArnoldShaderPtr filter = shaderCache->get( IECore::runTimeCast<const IECoreScene::ShaderNetwork>( it->second.get() ), it->first, attributes );
m_lightFilterShaders.push_back( filter );
}
}
Expand Down Expand Up @@ -1590,10 +1595,7 @@ class ArnoldAttributes : public IECoreScenePreview::Renderer::AttributesInterfac

Displacement( const IECore::CompoundObject *attributes, ShaderCache *shaderCache )
{
if( const IECoreScene::ShaderNetwork *mapAttribute = attribute<IECoreScene::ShaderNetwork>( g_dispMapAttributeName, attributes ) )
{
map = shaderCache->get( mapAttribute, attributes );
}
map = shaderCache->get( g_dispMapAttributeNames, attributes );
height = attributeValue<float>( g_dispHeightAttributeName, attributes, 1.0f );
padding = attributeValue<float>( g_dispPaddingAttributeName, attributes, 0.0f );
zeroValue = attributeValue<float>( g_dispZeroValueAttributeName, attributes, 0.0f );
Expand Down Expand Up @@ -3559,7 +3561,7 @@ class ArnoldGlobals
{
if( const IECoreScene::ShaderNetwork *d = reportedCast<const IECoreScene::ShaderNetwork>( value, "option", name ) )
{
m_colorManager = m_shaderCache->get( d, nullptr );
m_colorManager = m_shaderCache->get( d, IECore::InternedString(), nullptr );
}
}
AiNodeSetPtr( options, g_colorManagerArnoldString, m_colorManager ? m_colorManager->root() : nullptr );
Expand All @@ -3572,7 +3574,7 @@ class ArnoldGlobals
{
if( const IECoreScene::ShaderNetwork *d = reportedCast<const IECoreScene::ShaderNetwork>( value, "option", name ) )
{
m_atmosphere = m_shaderCache->get( d, nullptr );
m_atmosphere = m_shaderCache->get( d, IECore::InternedString(), nullptr );
}
}
AiNodeSetPtr( options, g_atmosphereArnoldString, m_atmosphere ? m_atmosphere->root() : nullptr );
Expand All @@ -3585,7 +3587,7 @@ class ArnoldGlobals
{
if( const IECoreScene::ShaderNetwork *d = reportedCast<const IECoreScene::ShaderNetwork>( value, "option", name ) )
{
m_background = m_shaderCache->get( d, nullptr );
m_background = m_shaderCache->get( d, IECore::InternedString(), nullptr );
}
}
AiNodeSetPtr( options, g_backgroundArnoldString, m_background ? m_background->root() : nullptr );
Expand All @@ -3598,7 +3600,7 @@ class ArnoldGlobals
{
if( const IECoreScene::ShaderNetwork *d = reportedCast<const IECoreScene::ShaderNetwork>( value, "option", name ) )
{
m_imager = m_shaderCache->get( d, nullptr );
m_imager = m_shaderCache->get( d, IECore::InternedString(), nullptr );
}
}
for( const auto &output : m_outputs )
Expand All @@ -3614,7 +3616,7 @@ class ArnoldGlobals
{
if( const IECoreScene::ShaderNetwork *d = reportedCast<const IECoreScene::ShaderNetwork>( value, "option", name ) )
{
m_aovShaders[name] = m_shaderCache->get( d, nullptr );
m_aovShaders[name] = m_shaderCache->get( d, IECore::InternedString(), nullptr );
}
}

Expand Down
12 changes: 6 additions & 6 deletions src/IECoreArnold/ShaderNetworkAlgo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1184,11 +1184,11 @@ bool g_textureSubstitutionsRegistration = [] () {
IECoreArnold::ShaderNetworkAlgo::registerSubstitution(
"stringSubstitution",
// Hash
[] ( const IECoreScene::ShaderNetwork *shaderNetwork, const IECore::CompoundObject *attributes, IECore::MurmurHash &hash ) {
[] ( const IECoreScene::ShaderNetwork *shaderNetwork, InternedString attributeName, const IECore::CompoundObject *attributes, IECore::MurmurHash &hash ) {
shaderNetwork->hashSubstitutions( attributes, hash );
},
// Apply
[] ( IECoreScene::ShaderNetwork *shaderNetwork, const IECore::CompoundObject *attributes ) {
[] ( IECoreScene::ShaderNetwork *shaderNetwork, InternedString attributeName, const IECore::CompoundObject *attributes ) {
shaderNetwork->applySubstitutions( attributes );
}
);
Expand Down Expand Up @@ -1233,19 +1233,19 @@ void deregisterSubstitution( const std::string &name )
);
}

void hashSubstitutions( const IECoreScene::ShaderNetwork *shaderNetwork, const IECore::CompoundObject *attributes, IECore::MurmurHash &hash )
void hashSubstitutions( const IECoreScene::ShaderNetwork *shaderNetwork, InternedString attributeName, const IECore::CompoundObject *attributes, IECore::MurmurHash &hash )
{
for( const auto &x : substitutions() )
{
x.hash( shaderNetwork, attributes, hash );
x.hash( shaderNetwork, attributeName, attributes, hash );
}
}

void applySubstitutions( IECoreScene::ShaderNetwork *shaderNetwork, const IECore::CompoundObject *attributes )
void applySubstitutions( IECoreScene::ShaderNetwork *shaderNetwork, InternedString attributeName, const IECore::CompoundObject *attributes )
{
for( const auto &x : substitutions() )
{
x.apply( shaderNetwork, attributes );
x.apply( shaderNetwork, attributeName, attributes );
}
}

Expand Down

0 comments on commit 41cef12

Please sign in to comment.