Skip to content
Draft
Show file tree
Hide file tree
Changes from 4 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
9 changes: 7 additions & 2 deletions contrib/IECoreUSD/src/IECoreUSD/ShaderAlgo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,12 @@ namespace
{

const pxr::TfToken g_blindDataToken( "cortex:blindData" );
pxr::TfToken g_legacyAdapterLabelToken( IECoreScene::ShaderNetworkAlgo::componentConnectionAdapterLabel().string() );

// Hardcoded to match an old name used by Cortex when writing USD with OSL version earlier than 1.10 (
// ie. a pre-2021 version of gafferDependencies ). We no longer expose this in the API, but I'm not sure
// if we're ready to drop support for loading these old files.
IECore::InternedString g_legacyAdapterLabelString( "cortex_autoAdapter" );
pxr::TfToken g_legacyAdapterLabelToken( g_legacyAdapterLabelString.string() );

std::pair<pxr::TfToken, std::string> shaderIdAndType( const pxr::UsdShadeConnectableAPI &connectable )
{
Expand Down Expand Up @@ -267,7 +272,7 @@ IECore::InternedString readShaderNetworkWalk( const pxr::SdfPath &anchorPath, co
pxr::VtValue metadataValue;
if( usdShader.GetPrim().GetMetadata( g_legacyAdapterLabelToken, &metadataValue ) && metadataValue.Get<bool>() )
{
newShader->blindData()->writable()[ IECoreScene::ShaderNetworkAlgo::componentConnectionAdapterLabel() ] = new IECore::BoolData( true );
newShader->blindData()->writable()[ g_legacyAdapterLabelString ] = new IECore::BoolData( true );
}

shaderNetwork.addShader( handle, std::move( newShader ) );
Expand Down
13 changes: 13 additions & 0 deletions include/IECore/DataAlgo.inl
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
#include "IECore/PathMatcherData.h"
#include "IECore/SimpleTypedData.h"
#include "IECore/SplineData.h"
#include "IECore/RampData.h"
#include "IECore/TransformationMatrixData.h"
#include "IECore/VectorTypedData.h"

Expand Down Expand Up @@ -132,6 +133,12 @@ typename std::invoke_result_t<F, Data *, Args&&...> dispatch( Data *data, F &&fu
return functor( static_cast<SplinefColor3fData *>( data ), std::forward<Args>( args )... );
case SplinefColor4fDataTypeId :
return functor( static_cast<SplinefColor4fData *>( data ), std::forward<Args>( args )... );
case RampffDataTypeId :
return functor( static_cast<RampffData *>( data ), std::forward<Args>( args )... );
case RampfColor3fDataTypeId :
return functor( static_cast<RampfColor3fData *>( data ), std::forward<Args>( args )... );
case RampfColor4fDataTypeId :
return functor( static_cast<RampfColor4fData *>( data ), std::forward<Args>( args )... );
case DateTimeDataTypeId :
return functor( static_cast<DateTimeData *>( data ), std::forward<Args>( args )... );
case BoolVectorDataTypeId :
Expand Down Expand Up @@ -286,6 +293,12 @@ typename std::invoke_result_t<F, const Data *, Args&&...> dispatch( const Data *
return functor( static_cast<const SplinefColor3fData *>( data ), std::forward<Args>( args )... );
case SplinefColor4fDataTypeId :
return functor( static_cast<const SplinefColor4fData *>( data ), std::forward<Args>( args )... );
case RampffDataTypeId :
return functor( static_cast<const RampffData *>( data ), std::forward<Args>( args )... );
case RampfColor3fDataTypeId :
return functor( static_cast<const RampfColor3fData *>( data ), std::forward<Args>( args )... );
case RampfColor4fDataTypeId :
return functor( static_cast<const RampfColor4fData *>( data ), std::forward<Args>( args )... );
case DateTimeDataTypeId :
return functor( static_cast<const DateTimeData *>( data ), std::forward<Args>( args )... );
case BoolVectorDataTypeId :
Expand Down
13 changes: 13 additions & 0 deletions include/IECore/DespatchTypedData.inl
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#include "IECore/DateTimeData.h"
#include "IECore/SimpleTypedData.h"
#include "IECore/SplineData.h"
#include "IECore/RampData.h"
#include "IECore/TransformationMatrixData.h"
#include "IECore/TypeTraits.h"
#include "IECore/VectorTypedData.h"
Expand Down Expand Up @@ -263,6 +264,18 @@ typename Functor::ReturnType despatchTypedData( Data *data, Functor &functor, Er
return
typename Detail::DespatchTypedData< Functor, SplinefColor4fData, ErrorHandler >
::template Func<Enabler>()( static_cast<SplinefColor4fData *>( data ), functor, errorHandler );
case RampffDataTypeId :
return
typename Detail::DespatchTypedData< Functor, RampffData, ErrorHandler >
::template Func<Enabler>()( static_cast<RampffData *>( data ), functor, errorHandler );
case RampfColor3fDataTypeId :
return
typename Detail::DespatchTypedData< Functor, RampfColor3fData, ErrorHandler >
::template Func<Enabler>()( static_cast<RampfColor3fData *>( data ), functor, errorHandler );
case RampfColor4fDataTypeId :
return
typename Detail::DespatchTypedData< Functor, RampfColor4fData, ErrorHandler >
::template Func<Enabler>()( static_cast<RampfColor4fData *>( data ), functor, errorHandler );
Comment on lines +267 to +278
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd be open to omitting this - despatchTypedData() is deprecated so it might even be considered counter-productive to support new types in it.

case DateTimeDataTypeId :
return
typename Detail::DespatchTypedData< Functor, DateTimeData, ErrorHandler >
Expand Down
153 changes: 153 additions & 0 deletions include/IECore/Ramp.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
//////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2025, Image Engine Design Inc. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the name of Image Engine Design nor the names of any
// other contributors to this software may be used to endorse or
// promote products derived from this software without specific prior
// written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////

#ifndef IECORE_RAMP_H
#define IECORE_RAMP_H

#include "IECore/Export.h"
#include "IECore/Spline.h"
#include "IECore/MessageHandler.h"

IECORE_PUSH_DEFAULT_VISIBILITY
#include "Imath/ImathColor.h"
IECORE_POP_DEFAULT_VISIBILITY

#include <map>

namespace IECore
{

// This lives outside the class because we don't want multiple incompatible templated versions of
// the same enum floating around
enum class RampInterpolation
{
Linear = 0,
CatmullRom = 1,
BSpline = 2,
MonotoneCubic = 3,
Constant = 4,
};

/// A Ramp represents a spline-like curve as it is represented in a simple UI: with a set of independent
/// control points, and an interpolation type selected from RampInterpolation.
Comment on lines +62 to +63
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's worth mentioning that another motivation is removing the need to store duplicate endpoints to ensure interpolation to the final values.

///
/// Rather than storing the lower level IECore::Spline*, we now store this Ramp type in shader networks,
/// and only convert to the lower level class with the evaluator() function when evaluation is needed.
template<typename X, typename Y>
class IECORE_EXPORT Ramp
{

public :
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing an indent?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, right, I'd copied this from a Gaffer struct, and I guess I forgot to change the identation. I don't really remember why I switched it to a class, but I'm guessing it had private members at some point during the refactor - maybe it makes sense to keep it as a class in case it gets private members again at some point in the future? I'm also not quite sure why our indentation is different for structs, but that's a topic for another time, I'll just make this indentation consistent for now.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think our indentation is different for structs, at least not intentionally. For another time for sure, but I think maybe what I would like the most is to change the way we do things like so :

struct MyThing // Everything is a struct
{

    MyThing(); // So now public stuff doesn't need to be doubly indented.

    private :

        m_stuff; // Only private stuff needs double indentation.

}


typedef X XType;
typedef Y YType;

typedef CubicBasis<XType> Basis;
typedef std::multimap<X, Y> PointContainer;
typedef typename PointContainer::value_type Point;

Comment on lines +73 to +79
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typedef -> using. Modern C++ innit.



Comment on lines +79 to +81
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Vertical space is at a premium on most monitors, and three blank lines doesn't really convey anything more than one blank line would.

Ramp() : interpolation( RampInterpolation::CatmullRom )
{
}

Ramp( const PointContainer &p, RampInterpolation i )
: points( p ), interpolation( i )
{
}

PointContainer points;
RampInterpolation interpolation;


// Convert to Cortex Spline
// In the future, IECore::Spline may be replaced with IECore::SplineEvaluator, and this
// function would be the only way to setup one.
IECore::Spline<X, Y> evaluator() const;

// In order to write shader parameters to renderers or USD, we need to convert Ramps to a convention
// that can be stored in raw OSL. Based on the arguments to the OSL spline() function, we've come up
// with a convention for storing a string basis and separate position and value arrays, where the
// the position and value arrays contain any duplicated end points necessary for the resulting OSL
// spline to cover the full range of the ramp.
Comment on lines +100 to +104
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"We've come up with a convention" seems a bit misleading - the only convention here is the one defined by OSL's spline() itself. We're literally just generating parameters that will reproduce the ramp exactly in a call to spline().

//
// These functions convert to and from this convention ( and can also be used for converting from other
// similar conventions with some pre-processing ).
//
// NOTE: Some aspects of the convention we've picked are not actually very universal. We haven't
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, the convention isn't ours - it's the one defined by OSL. It's worth documenting that some renderers do their own endpoint duplication for some reason, but OSL is the common standard here, and I don't want to imply that we're the ones deviating from it.

// found any shader's in the wild that actually expect duplicated end point ( aside from Gaffer's
// shader library ). Other shader authors seem to be implementing their own spline functions that don't
// require duplicated endpoints ( 3delight ), or put code to perform the duplication in their shader
// before calling spline ( PRMan ). We've stuck to duplicating the end points because unnecessarily
// duplicating endpoints doesn't cause any problems other than being a minor waste of performance.
// It seems like there's an argument that the best approach would be to put the endpoint duplication
// inside the shader like PRMan, but this is working fine for now.
Comment on lines +115 to +116
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What would the argument be? Surely it's always going to be cheaper to do the duplication once outside the shader than it is to do it per sample inside the renderer?

void fromOSL( const std::string &basis, const std::vector<X> &positions, const std::vector<Y> &values, const std::string &identifier );
void toOSL( std::string &basis, std::vector<X> &positions, std::vector<Y> &values ) const;

// If there are connections to a Ramp, and we convert it to the OSL convention with duplicated endpoints,
// then the connections will need to be offset to match - this defines the offset.
int oslAdaptorOffset() const;
Comment on lines +120 to +122
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I recall we spent a little while debating if the OSL conversions should be provided by members of this class or by ShaderNetworkAlgo, and we went for this one because it had the monotone->bezier code in it already. But this oslAdaptorOffset() thing is new to me, and makes me think that the API might be cleaner if the OSL conversions weren't in here. How doable would that be?


// In Cortex 10.6 and earlier, shader parameters were represented uing IECore::Spline*Data instead of
// IECore::Ramp*Data. This is used in converting SCC files to the new standard.
// \todo : This can probably be removed in the next major version - we're not actually aware of any
// significant users of Cortex who both use SCC files, and cache shaders, so this compatibility shim
// is only needed theoretically.
void fromDeprecatedSpline( const IECore::Spline<X, Y> &deprecated );
Comment on lines +124 to +129
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Likewise, this feels like it clutters up an otherwise very clean class, and I wonder if it wouldn't be better in ShaderNetworkAlgo or hidden in SceneCache (assuming we can achieve that without excessive contortion elsewhere).


bool operator==( const Ramp<X,Y> &rhs ) const;
bool operator!=( const Ramp<X,Y> &rhs ) const;

};

using Rampff = Ramp<float, float>;
using RampfColor3f = Ramp<float, Imath::Color3f>;
using RampfColor4f = Ramp<float, Imath::Color4f>;

template<typename X, typename Y>
inline void murmurHashAppend( IECore::MurmurHash &h, const Ramp<X,Y> &data )
{
h.append( data.interpolation );
for ( auto &p : data.points )
{
h.append( p.first );
h.append( p.second );
}
}

} // namespace IECore

#endif // IECORE_RAMP_H
52 changes: 52 additions & 0 deletions include/IECore/RampData.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
//////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2025, Image Engine Design Inc. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the name of Image Engine Design nor the names of any
// other contributors to this software may be used to endorse or
// promote products derived from this software without specific prior
// written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////

#ifndef IECORE_RAMPDATA_H
#define IECORE_RAMPDATA_H

#include "IECore/Ramp.h"
#include "IECore/TypedData.h"

namespace IECore
{

// Ramp data types.

IECORE_DECLARE_TYPEDDATA( RampffData, Rampff, void, SharedDataHolder )
IECORE_DECLARE_TYPEDDATA( RampfColor3fData, RampfColor3f, void, SharedDataHolder )
IECORE_DECLARE_TYPEDDATA( RampfColor4fData, RampfColor4f, void, SharedDataHolder )

}

#endif // IECORE_RAMPDATA_H
6 changes: 3 additions & 3 deletions include/IECore/TypeIds.h
Original file line number Diff line number Diff line change
Expand Up @@ -203,9 +203,9 @@ enum TypeId
YUVImageWriterTypeId = 265,
DateTimeDataTypeId = 269,
DateTimeParameterTypeId = 270,
TimeDurationDataTypeId = 272, // Obsolete
TimeDurationParameterTypeId = 273, // Obsolete
TimePeriodDataTypeId = 274, // Obsolete
RampffDataTypeId = 272,
RampfColor3fDataTypeId = 273,
RampfColor4fDataTypeId = 274,
TimePeriodParameterTypeId = 275, // Obsolete
FrameListTypeId = 279,
EmptyFrameListTypeId = 280,
Expand Down
10 changes: 10 additions & 0 deletions include/IECore/TypeTraits.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@
#include "IECore/SimpleTypedData.h"
#include "IECore/Spline.h"
#include "IECore/SplineData.h"
#include "IECore/Ramp.h"
#include "IECore/RampData.h"
#include "IECore/TransformationMatrixData.h"
#include "IECore/VectorTypedData.h"

Expand Down Expand Up @@ -293,6 +295,14 @@ template<typename T, typename U> struct IsSpline< const Spline<T, U> > : public
/// IsSplineTypedData
template< typename T > struct IsSplineTypedData : boost::mpl::and_< IsTypedData<T>, IsSpline< typename ValueType<T>::type > > {};

/// IsRamp
template<typename T, typename U = void > struct IsRamp : public boost::false_type {};
template<typename T, typename U> struct IsRamp< Ramp<T, U> > : public boost::true_type {};
template<typename T, typename U> struct IsRamp< const Ramp<T, U> > : public boost::true_type {};

/// IsRampTypedData
template< typename T > struct IsRampTypedData : boost::mpl::and_< IsTypedData<T>, IsRamp< typename ValueType<T>::type > > {};

/// IsStringVectorTypeData
template<typename T> struct IsStringVectorTypedData : public boost::false_type {};
template<> struct IsStringVectorTypedData< TypedData<std::vector<std::string> > > : public boost::true_type {};
Expand Down
47 changes: 47 additions & 0 deletions include/IECorePython/RampBinding.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
//////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2025, Image Engine Design Inc. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the name of Image Engine Design nor the names of any
// other contributors to this software may be used to endorse or
// promote products derived from this software without specific prior
// written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////

#ifndef IECOREPYTHON_RAMPBINDING_H
#define IECOREPYTHON_RAMPBINDING_H

#include "IECorePython/Export.h"

namespace IECorePython
{

IECOREPYTHON_API void bindRamp();

}

#endif // IECOREPYTHON_RAMPBINDING_H
Loading