Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Arnold ShaderNetworkAlgo : Add attributeName argument to SubstitutionFunction #6214

Merged
merged 1 commit into from
Jan 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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