Skip to content

Commit 099c2f3

Browse files
ShaderNetworkAlgo::expand/collapseSpline : Support Prman convention for shaders prefixed with "Pxr"
1 parent ad90eac commit 099c2f3

File tree

4 files changed

+223
-97
lines changed

4 files changed

+223
-97
lines changed

Changes

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
10.6.x.x (relative to 10.6.0.2)
22
========
33

4+
Features
5+
--------
6+
7+
- ShaderNetworkAlgo::expandSplines/collapseSplines : Support splines that use the PRMan spline convention.
8+
49
Fixes
510
-----
611

include/IECoreScene/ShaderNetworkAlgo.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,10 +148,12 @@ IECORESCENE_API void collapseSplines( ShaderNetwork *network, std::string target
148148
IECORESCENE_API void expandSplines( ShaderNetwork *network, std::string targetPrefix = "" );
149149

150150

151-
/// \deprecated: Use collapseSplines on the whole network, which can handle input connections
151+
/// \deprecated: Use collapseSplines on the whole network, which can handle input connections, and supports
152+
/// different spline conventions for different renderers' shader libraries
152153
IECORESCENE_API IECore::ConstCompoundDataPtr collapseSplineParameters( const IECore::ConstCompoundDataPtr& parametersData );
153154

154-
/// \deprecated: Use expandSplines on the whole network, which can handle input connections
155+
/// \deprecated: Use expandSplines on the whole network, which can handle input connections, and supports
156+
/// different spline conventions for different renderers' shader libraries
155157
IECORESCENE_API IECore::ConstCompoundDataPtr expandSplineParameters( const IECore::ConstCompoundDataPtr& parametersData );
156158

157159

src/IECoreScene/ShaderNetworkAlgo.cpp

Lines changed: 171 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
#include "boost/regex.hpp"
5151

5252
#include <array>
53+
#include <filesystem>
5354
#include <unordered_map>
5455
#include <unordered_set>
5556

@@ -811,8 +812,36 @@ std::pair< size_t, size_t > getEndPointDuplication( const T &basis )
811812
return std::make_pair( 0, 0 );
812813
}
813814

815+
std::tuple< const std::string*, const std::string*, const std::string*, const std::string*, const std::string* >
816+
lookupSplinePlugSuffixes( const std::string &shaderName )
817+
{
818+
// We seem to be able to identify shaders that should use the PRMan convention by whether they start
819+
// with one of the PRMan prefixes.
820+
// NOTE : This will fail if a shader is loaded from an explicit path, rather than being found in the
821+
// search path, because the shader name will include the full file path. We consider this an
822+
// acceptable failure, because shaders should be found in the search paths.
823+
if( boost::starts_with( shaderName, "Pxr" ) || boost::starts_with( shaderName, "Lama" ) )
824+
{
825+
// The convention used by the PRMan shader library.
826+
static const std::string positions( "_Knots" );
827+
static const std::string floatValues( "_Floats" );
828+
static const std::string colorValues( "_Colors" );
829+
static const std::string basis( "_Interpolation" );
830+
static const std::string count( "" );
831+
return { &positions, &floatValues, &colorValues, &basis, &count };
832+
}
833+
else
834+
{
835+
// The convention used by the OSL shaders that we ship with Gaffer.
836+
static const std::string positions( "Positions" );
837+
static const std::string values( "Values" );
838+
static const std::string basis( "Basis" );
839+
return { &positions, &values, &values, &basis, nullptr };
840+
}
841+
}
842+
814843
template<typename Spline>
815-
void expandSpline( const InternedString &name, const Spline &spline, CompoundDataMap &newParameters )
844+
void expandSpline( const InternedString &name, const Spline &spline, CompoundDataMap &newParameters, const std::string &shaderName )
816845
{
817846
const char *basis = "catmull-rom";
818847
if( spline.basis == Spline::Basis::bezier() )
@@ -866,9 +895,23 @@ void expandSpline( const InternedString &name, const Spline &spline, CompoundDat
866895
}
867896
}
868897

869-
newParameters[ name.string() + "Positions" ] = positionsData;
870-
newParameters[ name.string() + "Values" ] = valuesData;
871-
newParameters[ name.string() + "Basis" ] = new StringData( basis );
898+
auto [ positionsSuffix, floatValuesSuffix, colorValuesSuffix, basisSuffix, countSuffix ] = lookupSplinePlugSuffixes( shaderName );
899+
900+
newParameters[ name.string() + *positionsSuffix ] = positionsData;
901+
if constexpr( std::is_same_v< typename Spline::YType, float > )
902+
{
903+
newParameters[ name.string() + *floatValuesSuffix ] = valuesData;
904+
}
905+
else
906+
{
907+
newParameters[ name.string() + *colorValuesSuffix ] = valuesData;
908+
}
909+
newParameters[ name.string() + *basisSuffix ] = new StringData( basis );
910+
911+
if( countSuffix )
912+
{
913+
newParameters[ name.string() + *countSuffix ] = new IntData( positionsData->readable().size() );
914+
}
872915
}
873916

874917
template<typename SplineData>
@@ -929,6 +972,122 @@ IECore::DataPtr loadSpline(
929972
return resultData;
930973
}
931974

975+
void ensureParametersCopy(
976+
const IECore::CompoundDataMap &parameters,
977+
IECore::CompoundDataPtr &parametersDataCopy, CompoundDataMap *&parametersCopy
978+
)
979+
{
980+
if( !parametersDataCopy )
981+
{
982+
parametersDataCopy = new CompoundData();
983+
parametersCopy = &parametersDataCopy->writable();
984+
*parametersCopy = parameters;
985+
}
986+
}
987+
988+
IECore::ConstCompoundDataPtr collapseSplineParametersInternal( const IECore::ConstCompoundDataPtr &parametersData, const std::string &shaderName )
989+
{
990+
991+
auto [ positionsSuffix, floatValuesSuffix, colorValuesSuffix, basisSuffix, countSuffix ] = lookupSplinePlugSuffixes( shaderName );
992+
993+
const CompoundDataMap &parameters( parametersData->readable() );
994+
CompoundDataPtr newParametersData;
995+
CompoundDataMap *newParameters = nullptr;
996+
997+
for( const auto &maybeBasis : parameters )
998+
{
999+
if( !boost::ends_with( maybeBasis.first.string(), *basisSuffix ) )
1000+
{
1001+
continue;
1002+
}
1003+
const StringData *basis = runTimeCast<const StringData>( maybeBasis.second.get() );
1004+
if( !basis )
1005+
{
1006+
continue;
1007+
}
1008+
1009+
1010+
std::string prefix = maybeBasis.first.string().substr( 0, maybeBasis.first.string().size() - basisSuffix->size() );
1011+
const IECore::InternedString positionsName = prefix + *positionsSuffix;
1012+
const FloatVectorData *floatPositions = parametersData->member<const FloatVectorData>( positionsName );
1013+
if( !floatPositions )
1014+
{
1015+
continue;
1016+
}
1017+
1018+
IECore::InternedString countName;
1019+
const IntData *countData = nullptr;
1020+
1021+
if( countSuffix )
1022+
{
1023+
countName = prefix + *countSuffix;
1024+
countData = parametersData->member<const IntData>( countName );
1025+
1026+
if( !countData )
1027+
{
1028+
IECore::msg(
1029+
Msg::Error, "ShaderNetworkAlgo",
1030+
"Using spline format that expects count parameter, but no int count parameter found matching \"" + countName.string() + "\""
1031+
);
1032+
}
1033+
else
1034+
{
1035+
if( (int)floatPositions->readable().size() != countData->readable() )
1036+
{
1037+
IECore::msg(
1038+
Msg::Error, "ShaderNetworkAlgo",
1039+
"Spline count \"" + countName.string() + "\" does not match length of data: " + std::to_string( countData->readable() ) + " != " + std::to_string( floatPositions->readable().size() ) + "\""
1040+
);
1041+
}
1042+
}
1043+
}
1044+
1045+
IECore::InternedString valuesName = prefix + *floatValuesSuffix;
1046+
IECore::DataPtr foundSpline;
1047+
if( const FloatVectorData *floatValues = parametersData->member<const FloatVectorData>( valuesName ) )
1048+
{
1049+
foundSpline = loadSpline<SplineffData>( basis, floatPositions, floatValues );
1050+
}
1051+
else
1052+
{
1053+
valuesName = prefix + *colorValuesSuffix;
1054+
if( const Color3fVectorData *color3Values = parametersData->member<const Color3fVectorData>( valuesName ) )
1055+
{
1056+
foundSpline = loadSpline<SplinefColor3fData>( basis, floatPositions, color3Values );
1057+
}
1058+
else if( const Color4fVectorData *color4Values = parametersData->member<const Color4fVectorData>( valuesName ) )
1059+
{
1060+
foundSpline = loadSpline<SplinefColor4fData>( basis, floatPositions, color4Values );
1061+
}
1062+
1063+
}
1064+
1065+
if( foundSpline )
1066+
{
1067+
ensureParametersCopy( parameters, newParametersData, newParameters );
1068+
newParameters->erase( maybeBasis.first );
1069+
newParameters->erase( positionsName );
1070+
newParameters->erase( valuesName );
1071+
if( countData )
1072+
{
1073+
newParameters->erase( countName );
1074+
}
1075+
1076+
(*newParameters)[prefix] = foundSpline;
1077+
1078+
}
1079+
}
1080+
1081+
if( newParametersData )
1082+
{
1083+
return newParametersData;
1084+
}
1085+
else
1086+
{
1087+
return parametersData;
1088+
}
1089+
}
1090+
9321091
const std::string g_oslShader( "osl:shader" );
9331092

9341093
const std::string g_colorToArrayAdapter( "Utility/__ColorToArray" );
@@ -1003,19 +1162,6 @@ std::pair< InternedString, int > createSplineInputAdapter(
10031162
return std::make_pair( adapterHandle, getEndPointDuplication( splineData->readable().basis ).first );
10041163
}
10051164

1006-
void ensureParametersCopy(
1007-
const IECore::CompoundDataMap &parameters,
1008-
IECore::CompoundDataPtr &parametersDataCopy, CompoundDataMap *&parametersCopy
1009-
)
1010-
{
1011-
if( !parametersDataCopy )
1012-
{
1013-
parametersDataCopy = new CompoundData();
1014-
parametersCopy = &parametersDataCopy->writable();
1015-
*parametersCopy = parameters;
1016-
}
1017-
}
1018-
10191165
} // namespace
10201166

10211167
void ShaderNetworkAlgo::collapseSplines( ShaderNetwork *network, std::string targetPrefix )
@@ -1040,12 +1186,12 @@ void ShaderNetworkAlgo::collapseSplines( ShaderNetwork *network, std::string tar
10401186
}
10411187

10421188
// For nodes which aren't spline adapters, we just need to deal with any parameters that are splines
1043-
ConstCompoundDataPtr collapsed = collapseSplineParameters( shader->parametersData() );
1189+
ConstCompoundDataPtr collapsed = collapseSplineParametersInternal( shader->parametersData(), shader->getName() );
10441190
if( collapsed != shader->parametersData() )
10451191
{
1046-
// \todo - this const_cast is ugly, although safe because if the return from collapseSplineParameters
1192+
// \todo - this const_cast is ugly, although safe because if the return from collapseSplineParameterInternals
10471193
// doesn't match the input, it is freshly allocated. Once collapseSplineParameters is fully
1048-
// deprecated, and no longer visible publicly, an internal version of collapseSplineParameters could
1194+
// deprecated, and no longer visible publicly, collapseSplineParametersInternal could
10491195
// just return a non-const new parameter data, or nullptr if no changes are needed.
10501196
network->setShader( name, std::move( new Shader( shader->getName(), shader->getType(), const_cast< CompoundData *>( collapsed.get() ) ) ) );
10511197
}
@@ -1167,13 +1313,13 @@ void ShaderNetworkAlgo::expandSplines( ShaderNetwork *network, std::string targe
11671313
{
11681314
ensureParametersCopy( origParameters, newParametersData, newParameters );
11691315
newParameters->erase( name );
1170-
expandSpline( name, colorSpline->readable(), *newParameters );
1316+
expandSpline( name, colorSpline->readable(), *newParameters, s.second->getName() );
11711317
}
11721318
else if( const SplineffData *floatSpline = runTimeCast<const SplineffData>( value.get() ) )
11731319
{
11741320
ensureParametersCopy( origParameters, newParametersData, newParameters );
11751321
newParameters->erase( name );
1176-
expandSpline( name, floatSpline->readable(), *newParameters );
1322+
expandSpline( name, floatSpline->readable(), *newParameters, s.second->getName() );
11771323
}
11781324
}
11791325

@@ -1291,76 +1437,7 @@ void ShaderNetworkAlgo::expandSplines( ShaderNetwork *network, std::string targe
12911437

12921438
IECore::ConstCompoundDataPtr ShaderNetworkAlgo::collapseSplineParameters( const IECore::ConstCompoundDataPtr &parametersData )
12931439
{
1294-
const CompoundDataMap &parameters( parametersData->readable() );
1295-
CompoundDataPtr newParametersData;
1296-
CompoundDataMap *newParameters = nullptr;
1297-
1298-
for( const auto &maybeBasis : parameters )
1299-
{
1300-
if( !boost::ends_with( maybeBasis.first.string(), "Basis" ) )
1301-
{
1302-
continue;
1303-
}
1304-
const StringData *basis = runTimeCast<const StringData>( maybeBasis.second.get() );
1305-
if( !basis )
1306-
{
1307-
continue;
1308-
}
1309-
1310-
1311-
std::string prefix = maybeBasis.first.string().substr( 0, maybeBasis.first.string().size() - 5 );
1312-
IECore::InternedString positionsName = prefix + "Positions";
1313-
const auto positionsIter = parameters.find( positionsName );
1314-
const FloatVectorData *floatPositions = nullptr;
1315-
1316-
if( positionsIter != parameters.end() )
1317-
{
1318-
floatPositions = runTimeCast<const FloatVectorData>( positionsIter->second.get() );
1319-
}
1320-
1321-
if( !floatPositions )
1322-
{
1323-
continue;
1324-
}
1325-
1326-
IECore::InternedString valuesName = prefix + "Values";
1327-
const auto valuesIter = parameters.find( valuesName );
1328-
1329-
IECore::DataPtr foundSpline;
1330-
if( valuesIter != parameters.end() )
1331-
{
1332-
if( const FloatVectorData *floatValues = runTimeCast<const FloatVectorData>( valuesIter->second.get() ) )
1333-
{
1334-
foundSpline = loadSpline<SplineffData>( basis, floatPositions, floatValues );
1335-
}
1336-
else if( const Color3fVectorData *color3Values = runTimeCast<const Color3fVectorData>( valuesIter->second.get() ) )
1337-
{
1338-
foundSpline = loadSpline<SplinefColor3fData>( basis, floatPositions, color3Values );
1339-
}
1340-
else if( const Color4fVectorData *color4Values = runTimeCast<const Color4fVectorData>( valuesIter->second.get() ) )
1341-
{
1342-
foundSpline = loadSpline<SplinefColor4fData>( basis, floatPositions, color4Values );
1343-
}
1344-
}
1345-
1346-
if( foundSpline )
1347-
{
1348-
ensureParametersCopy( parameters, newParametersData, newParameters );
1349-
(*newParameters)[prefix] = foundSpline;
1350-
newParameters->erase( maybeBasis.first );
1351-
newParameters->erase( positionsName );
1352-
newParameters->erase( valuesName );
1353-
}
1354-
}
1355-
1356-
if( newParametersData )
1357-
{
1358-
return newParametersData;
1359-
}
1360-
else
1361-
{
1362-
return parametersData;
1363-
}
1440+
return collapseSplineParametersInternal( parametersData, "" );
13641441
}
13651442

13661443
IECore::ConstCompoundDataPtr ShaderNetworkAlgo::expandSplineParameters( const IECore::ConstCompoundDataPtr &parametersData )
@@ -1376,13 +1453,13 @@ IECore::ConstCompoundDataPtr ShaderNetworkAlgo::expandSplineParameters( const IE
13761453
{
13771454
ensureParametersCopy( parameters, newParametersData, newParameters );
13781455
newParameters->erase( i.first );
1379-
expandSpline( i.first, colorSpline->readable(), *newParameters );
1456+
expandSpline( i.first, colorSpline->readable(), *newParameters, "" );
13801457
}
13811458
else if( const SplineffData *floatSpline = runTimeCast<const SplineffData>( i.second.get() ) )
13821459
{
13831460
ensureParametersCopy( parameters, newParametersData, newParameters );
13841461
newParameters->erase( i.first );
1385-
expandSpline( i.first, floatSpline->readable(), *newParameters );
1462+
expandSpline( i.first, floatSpline->readable(), *newParameters, "" );
13861463
}
13871464
}
13881465

0 commit comments

Comments
 (0)