Skip to content

Commit

Permalink
IECoreScene : Spline ramp conversions for Arnold and Renderman native…
Browse files Browse the repository at this point in the history
… shaders.
  • Loading branch information
Alex Fuller committed Jan 21, 2025
1 parent af7fe11 commit b89c4af
Show file tree
Hide file tree
Showing 4 changed files with 184 additions and 25 deletions.
4 changes: 2 additions & 2 deletions include/IECoreScene/ShaderNetworkAlgo.h
Original file line number Diff line number Diff line change
Expand Up @@ -149,10 +149,10 @@ IECORESCENE_API void expandSplines( ShaderNetwork *network, std::string targetPr


/// \deprecated: Use collapseSplines on the whole network, which can handle input connections
IECORESCENE_API IECore::ConstCompoundDataPtr collapseSplineParameters( const IECore::ConstCompoundDataPtr& parametersData );
IECORESCENE_API IECore::ConstCompoundDataPtr collapseSplineParameters( const IECore::ConstCompoundDataPtr& parametersData, const std::string shaderType = "", const std::string shaderName = "" );

/// \deprecated: Use expandSplines on the whole network, which can handle input connections
IECORESCENE_API IECore::ConstCompoundDataPtr expandSplineParameters( const IECore::ConstCompoundDataPtr& parametersData );
IECORESCENE_API IECore::ConstCompoundDataPtr expandSplineParameters( const IECore::ConstCompoundDataPtr& parametersData, const std::string shaderType = "", const std::string shaderName = "" );


} // namespace ShaderNetworkAlgo
Expand Down
130 changes: 111 additions & 19 deletions src/IECoreScene/ShaderNetworkAlgo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -811,26 +811,35 @@ std::pair< size_t, size_t > getEndPointDuplication( const T &basis )
}

template<typename Spline>
void expandSpline( const InternedString &name, const Spline &spline, CompoundDataMap &newParameters )
void expandSpline( const InternedString &name, const Spline &spline, CompoundDataMap &newParameters, const std::string shaderType = "", const std::string shaderName = "" )
{
const char *basis = "catmull-rom";
// For Renderman see https://rmanwiki-26.pixar.com/space/REN26/19661691/PxrRamp
const char *riBasis = "catmull-rom";
// For Arnold see https://help.autodesk.com/view/ARNOL/ENU/?guid=arnold_user_guide_ac_texture_shaders_ac_texture_ramp_html
int aiBasisIdx = 2;
if( spline.basis == Spline::Basis::bezier() )
{
basis = "bezier";
}
else if( spline.basis == Spline::Basis::bSpline() )
{
basis = "bspline";
riBasis = "bspline";
}
else if( spline.basis == Spline::Basis::linear() )
{
basis = "linear";
riBasis = "linear";
aiBasisIdx = 1;
}
else if( spline.basis == Spline::Basis::constant() )
{
// Also, "To maintain consistency", "constant splines ignore the first and the two last
// data values."
basis = "constant";
riBasis = "constant";
aiBasisIdx = 0;
}
auto [ duplicateStartPoints, duplicateEndPoints ] = getEndPointDuplication( spline.basis );

Expand Down Expand Up @@ -865,9 +874,42 @@ void expandSpline( const InternedString &name, const Spline &spline, CompoundDat
}
}

newParameters[ name.string() + "Positions" ] = positionsData;
newParameters[ name.string() + "Values" ] = valuesData;
newParameters[ name.string() + "Basis" ] = new StringData( basis );
if( boost::starts_with( shaderType, "ai:" ) && ( shaderName == "ramp_float" || shaderName == "ramp_rgb" ) )
{
newParameters[ "position" ] = positionsData;
if constexpr ( std::is_same_v<Spline, SplinefColor3f> )
{
newParameters[ "color" ] = valuesData;
}
else
{
newParameters[ "value" ] = valuesData;
}
std::vector<int> interp;
interp.resize( spline.points.size() );
std::fill( interp.begin(), interp.end(), aiBasisIdx );
newParameters[ "interpolation" ] = new IntVectorData( interp );
}
// Intentionally OR'd here as many Renderman shaders are OSL so search for the 'Pxr' prefix.
else if( boost::starts_with( shaderType, "ri:" ) || ( boost::starts_with( shaderName, "Pxr" ) ) )
{
newParameters[ name.string() + "_Knots" ] = positionsData;
if constexpr ( std::is_same_v<Spline, SplinefColor3f> )
{
newParameters[ name.string() + "_Colors" ] = valuesData;
}
else
{
newParameters[ name.string() + "_Floats" ] = valuesData;
}
newParameters[ name.string() + "_Interpolation" ] = new StringData( riBasis );
}
else
{
newParameters[ name.string() + "Positions" ] = positionsData;
newParameters[ name.string() + "Values" ] = valuesData;
newParameters[ name.string() + "Basis" ] = new StringData( basis );
}
}

template<typename SplineData>
Expand Down Expand Up @@ -1039,7 +1081,7 @@ void ShaderNetworkAlgo::collapseSplines( ShaderNetwork *network, std::string tar
}

// For nodes which aren't spline adapters, we just need to deal with any parameters that are splines
ConstCompoundDataPtr collapsed = collapseSplineParameters( shader->parametersData() );
ConstCompoundDataPtr collapsed = collapseSplineParameters( shader->parametersData(), shader->getType(), shader->getName());
if( collapsed != shader->parametersData() )
{
// \todo - this const_cast is ugly, although safe because if the return from collapseSplineParameters
Expand Down Expand Up @@ -1166,13 +1208,13 @@ void ShaderNetworkAlgo::expandSplines( ShaderNetwork *network, std::string targe
{
ensureParametersCopy( origParameters, newParametersData, newParameters );
newParameters->erase( name );
expandSpline( name, colorSpline->readable(), *newParameters );
expandSpline( name, colorSpline->readable(), *newParameters, s.second->getType(), s.second->getName() );
}
else if( const SplineffData *floatSpline = runTimeCast<const SplineffData>( value.get() ) )
{
ensureParametersCopy( origParameters, newParametersData, newParameters );
newParameters->erase( name );
expandSpline( name, floatSpline->readable(), *newParameters );
expandSpline( name, floatSpline->readable(), *newParameters, s.second->getType(), s.second->getName() );
}
}

Expand Down Expand Up @@ -1288,27 +1330,64 @@ void ShaderNetworkAlgo::expandSplines( ShaderNetwork *network, std::string targe
}
}

IECore::ConstCompoundDataPtr ShaderNetworkAlgo::collapseSplineParameters( const IECore::ConstCompoundDataPtr &parametersData )
IECore::ConstCompoundDataPtr ShaderNetworkAlgo::collapseSplineParameters( const IECore::ConstCompoundDataPtr &parametersData, const std::string shaderType, const std::string shaderName )
{
const CompoundDataMap &parameters( parametersData->readable() );
CompoundDataPtr newParametersData;
CompoundDataMap *newParameters = nullptr;

std::string basisStr = "Basis";
std::string positionsStr = "Positions";
std::string valuesStr = "Values";

if( boost::starts_with( shaderType, "ai:" ) && ( shaderName == "ramp_float" || shaderName == "ramp_rgb" ) )
{
basisStr = "interpolation";
positionsStr = "position";
valuesStr = "value";
}
else if( boost::starts_with( shaderType, "ri:" ) || boost::starts_with( shaderName, "Pxr" ) )
{
basisStr = "_Interpolation";
positionsStr = "_Knots";
valuesStr = "_Floats";
}

for( const auto &maybeBasis : parameters )
{
if( !boost::ends_with( maybeBasis.first.string(), "Basis" ) )
if( !boost::ends_with( maybeBasis.first.string(), basisStr ) )
{
continue;
}
const StringData *basis = runTimeCast<const StringData>( maybeBasis.second.get() );
StringData *basis = runTimeCast<StringData>( maybeBasis.second.get() );
if( !basis )
{
continue;
const IntVectorData *intBasis = runTimeCast<const IntVectorData>( maybeBasis.second.get() );
if( !intBasis )
{
continue;
}
// Do int to string conversion here, using the first value of the interpolation array
if( intBasis->readable().front() == 0 )
{
basis = new StringData( "constant" );
}
else if( intBasis->readable().front() == 1 )
{
basis = new StringData( "linear" );
}
else if( intBasis->readable().front() == 3 )
{
basis = new StringData( "monotonecubic" );
}
else
{
basis = new StringData( "catmull-rom" );
}
}


std::string prefix = maybeBasis.first.string().substr( 0, maybeBasis.first.string().size() - 5 );
IECore::InternedString positionsName = prefix + "Positions";
std::string prefix = maybeBasis.first.string().substr( 0, maybeBasis.first.string().size() - basisStr.size() );
IECore::InternedString positionsName = prefix + positionsStr;
const auto positionsIter = parameters.find( positionsName );
const FloatVectorData *floatPositions = nullptr;

Expand All @@ -1322,8 +1401,21 @@ IECore::ConstCompoundDataPtr ShaderNetworkAlgo::collapseSplineParameters( const
continue;
}

IECore::InternedString valuesName = prefix + "Values";
const auto valuesIter = parameters.find( valuesName );
IECore::InternedString valuesName = prefix + valuesStr;
auto valuesIter = parameters.find( valuesName );
if( valuesIter == parameters.end() )
{
if( boost::starts_with( shaderType, "ai:" ) )
{
valuesName = prefix + "color";
valuesIter = parameters.find( valuesName );
}
else if( boost::starts_with( shaderType, "ri:" ) )
{
valuesName = prefix + "_Colors";
valuesIter = parameters.find( valuesName );
}
}

IECore::DataPtr foundSpline;
if( valuesIter != parameters.end() )
Expand Down Expand Up @@ -1362,7 +1454,7 @@ IECore::ConstCompoundDataPtr ShaderNetworkAlgo::collapseSplineParameters( const
}
}

IECore::ConstCompoundDataPtr ShaderNetworkAlgo::expandSplineParameters( const IECore::ConstCompoundDataPtr &parametersData )
IECore::ConstCompoundDataPtr ShaderNetworkAlgo::expandSplineParameters( const IECore::ConstCompoundDataPtr &parametersData, const std::string shaderType, const std::string shaderName )
{
const CompoundDataMap &parameters( parametersData->readable() );

Expand All @@ -1375,13 +1467,13 @@ IECore::ConstCompoundDataPtr ShaderNetworkAlgo::expandSplineParameters( const IE
{
ensureParametersCopy( parameters, newParametersData, newParameters );
newParameters->erase( i.first );
expandSpline( i.first, colorSpline->readable(), *newParameters );
expandSpline( i.first, colorSpline->readable(), *newParameters, shaderType, shaderName );
}
else if( const SplineffData *floatSpline = runTimeCast<const SplineffData>( i.second.get() ) )
{
ensureParametersCopy( parameters, newParametersData, newParameters );
newParameters->erase( i.first );
expandSpline( i.first, floatSpline->readable(), *newParameters );
expandSpline( i.first, floatSpline->readable(), *newParameters, shaderType, shaderName );
}
}

Expand Down
8 changes: 4 additions & 4 deletions src/IECoreScene/bindings/ShaderNetworkAlgoBinding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,14 +70,14 @@ void convertOSLComponentConnectionsWrapper( ShaderNetwork *network, int oslVersi
ShaderNetworkAlgo::convertOSLComponentConnections( network, oslVersion );
}

CompoundDataPtr collapseSplineParametersWrapper( CompoundDataPtr parameters )
CompoundDataPtr collapseSplineParametersWrapper( CompoundDataPtr parameters, const std::string shaderType, const std::string shaderName )
{
return boost::const_pointer_cast< CompoundData >( ShaderNetworkAlgo::collapseSplineParameters( parameters ) );
return boost::const_pointer_cast< CompoundData >( ShaderNetworkAlgo::collapseSplineParameters( parameters, shaderType, shaderName ) );
}

CompoundDataPtr expandSplineParametersWrapper( CompoundDataPtr parameters )
CompoundDataPtr expandSplineParametersWrapper( CompoundDataPtr parameters, const std::string shaderType, const std::string shaderName )
{
return boost::const_pointer_cast< CompoundData >( ShaderNetworkAlgo::expandSplineParameters( parameters ) );
return boost::const_pointer_cast< CompoundData >( ShaderNetworkAlgo::expandSplineParameters( parameters, shaderType, shaderName ) );
}

std::string componentConnectionAdapterLabelWrapper()
Expand Down
67 changes: 67 additions & 0 deletions test/IECoreScene/ShaderNetworkAlgoTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -490,6 +490,73 @@ def testSplineConversion( self ):
IECoreScene.ShaderNetworkAlgo.collapseSplines( shaderNetworkInvalid )
self.assertEqual( shaderNetworkInvalid, shaderNetworkInvalidOrig )

def __splineConversionArnold( self, shaderName, valueName, valueType, parms ):

shaderNetworkOrig = IECoreScene.ShaderNetwork(
shaders = { "test" : IECoreScene.Shader( shaderName, "ai:surface", parms ) },
output = "test"
)
shaderNetwork = shaderNetworkOrig.copy()
IECoreScene.ShaderNetworkAlgo.expandSplines( shaderNetwork )

parmsExpanded = shaderNetwork.outputShader().parameters

self.assertEqual( type( parmsExpanded["interpolation"] ), IECore.IntVectorData )
self.assertEqual( type( parmsExpanded["position"] ), IECore.FloatVectorData )
self.assertEqual( type( parmsExpanded[valueName] ), valueType )

IECoreScene.ShaderNetworkAlgo.collapseSplines( shaderNetwork )

self.assertEqual( shaderNetwork, shaderNetworkOrig )

def testSplineConversionArnold( self ):

parmsRgb = IECore.CompoundData()
parmsRgb["ramp"] = IECore.SplinefColor3fData( IECore.SplinefColor3f( IECore.CubicBasisf.catmullRom(),
( ( 0, imath.Color3f(1) ), ( 10, imath.Color3f(2) ), ( 20, imath.Color3f(0) ), ( 30, imath.Color3f(5) ), ( 40, imath.Color3f(2) ), ( 50, imath.Color3f(6) ) ) ) )

self.__splineConversionArnold( "ramp_rgb", "color", IECore.Color3fVectorData, parmsRgb )

parmsFloat = IECore.CompoundData()
parmsFloat["ramp"] = IECore.SplineffData( IECore.Splineff( IECore.CubicBasisf.constant(),
( ( 0, 1 ), ( 0.2, 6 ), ( 0.3, 7 ) ) ) )

self.__splineConversionArnold( "ramp_float", "value", IECore.FloatVectorData, parmsFloat )

def __splineConversionRenderman( self, shaderType ):

parms = IECore.CompoundData()
parms["colorRamp"] = IECore.SplinefColor3fData( IECore.SplinefColor3f( IECore.CubicBasisf.catmullRom(),
( ( 0, imath.Color3f(1) ), ( 10, imath.Color3f(2) ), ( 20, imath.Color3f(0) ), ( 30, imath.Color3f(5) ), ( 40, imath.Color3f(2) ), ( 50, imath.Color3f(6) ) ) ) )
parms["floatRamp"] = IECore.SplineffData( IECore.Splineff( IECore.CubicBasisf.constant(),
( ( 0, 1 ), ( 0.2, 6 ), ( 0.3, 7 ) ) ) )

shaderNetworkOrig = IECoreScene.ShaderNetwork(
shaders = { "test" : IECoreScene.Shader( "PxrSplineMap", shaderType, parms ) },
output = "test"
)
shaderNetwork = shaderNetworkOrig.copy()
IECoreScene.ShaderNetworkAlgo.expandSplines( shaderNetwork )

parmsExpanded = shaderNetwork.outputShader().parameters

self.assertEqual( type( parmsExpanded["colorRamp_Interpolation"] ), IECore.StringData )
self.assertEqual( type( parmsExpanded["colorRamp_Knots"] ), IECore.FloatVectorData )
self.assertEqual( type( parmsExpanded["colorRamp_Colors"] ), IECore.Color3fVectorData )

self.assertEqual( type( parmsExpanded["floatRamp_Interpolation"] ), IECore.StringData )
self.assertEqual( type( parmsExpanded["floatRamp_Knots"] ), IECore.FloatVectorData )
self.assertEqual( type( parmsExpanded["floatRamp_Floats"] ), IECore.FloatVectorData )

IECoreScene.ShaderNetworkAlgo.collapseSplines( shaderNetwork )

self.assertEqual( shaderNetwork, shaderNetworkOrig )

def testSplineConversionRenderman( self ):

self.__splineConversionRenderman( "osl:shader" )
self.__splineConversionRenderman( "ri:surface" )

def testSplineInputs( self ):

fC3fcatmullRom = IECore.SplinefColor3fData( IECore.SplinefColor3f(
Expand Down

0 comments on commit b89c4af

Please sign in to comment.