Ramp UI hint questions

UI Hints for Ramps

Background

The recently introduced UI Hints have provided a unified and consistent way of describing potentially complex authoring interfaces which has significantly helped in providing consistent interfaces. However, ramps were excluded from the initial proposal, and we’d like to assist in defining a possible unified uihint structure. Ramps are generally defined as a combination of multiple properties:

  • Array of positions
  • Array of values
  • Array of interpolation modes (or single value for global interpolation; normally if the renderer does not support per-knot interpolation)
  • Knot count (optional; some renderers such as RenderMan define a property that holds the ramp size, although generally it can be inferred from the array of positions and/or values)

Currently, there isn’t a unified mechanism to declare that these properties should be presented to the user with a ramp widget; and their relationships to eachother.

Idea and questions

Our initial idea is to define metadata (in the uiHints dictionary) that would be set on one of the properties that make up a ramp, to link it to the other properties and describe the widget.

The following example illustrates setting the hints on the positions array:

#usda 1.0

def Shader "example"
{
    float[] my_ramp_positions = [0.0, 0.1, 0.4, 1.0] (
        uiHints = {
            token rampPositionsPropertyName = "my_ramp_positions"
            token rampValuesPropertyName = "my_ramp_values"
            token rampInterpolationsPropertyName = "my_ramp_interpolations"
            token rampSizePropertyName = "my_ramp_size"
        }
    )

    color3f[] my_ramp_values = [(0.0, 0.0, 0.0), (0.0, 1.0, 0.0), (0.0, 0.0, 1.0), (1.0, 1.0, 1.0)] (
        uiHints = {
            bool hidden = 1
        }
    )

    int[] my_ramp_interpolations = [1, 0, 1, 1] (
        uiHints = {
            bool hidden = 1
            dictionary valueLabels = {
                int constant = 0
                int linear = 1
                int bezier = 2
            }
            token[] valueLabelsOrder = ["constant", "linear", "bezier"]
        }
    )

    int my_ramp_size = 4 (
        uiHints = {
            bool hidden = 1
        }
    )
}

The metadata fields are:

  • rampPositionsPropertyName: Name of the property that holds the knot positions.
  • rampValuesPropertyName: Name of the property that holds the knot values.
  • rampInterpolationsPropertyName: Name of the property that holds the knot interpolations.
  • rampSizePropertyName (optional): Name of the property that holds the ramp size (i.e. the knot count).

All properties are expected to be siblings. Properties can have any arbitrary name: the metadata tells the ramp widget where the relevant properties are located so that they can be read and written as the ramp is edited by the user in the UI. This should allow existing scenes to work as-is, with additional metadata helping to tie things together.

The property that defines the ramp metadata becomes the main property. All other properties must be explicitly marked as hidden so as not to show any widget for the companion properties. Naturally, any other metadata, such as display label, would be set in the main property as the others will be hidden.

The type of the values property determines whether the ramp is a color ramp (e.g. color3f[]) or a float ramp (e.g. float[]).

These UI hints would apply equally to both USD Attributes and Shader Properties.

Interpolations

Whether the interpolation is per knot or global does not require a dedicated metadata field. It can be determined based on the topology of the interpolations property: per-knot interpolation if it is an array or global interpolation if it is a scalar.

The selection of interpolations available varies between renderers. The valueLabels metadata would list the possible interpolation modes that the UI will offer to the user. Each of the interpolation modes would be mapped to the actual value that is ultimately set in the referenced interpolations property based on the user selection in the UI.

Although USD would not control what interpolations are available, it could define a list of common ones so that ramp widget implementations can prepare visual representations for them.

Weights

Both Bezier and Hermite curves need weights which would be explicit tangent handles per knot.

Question: We are unsure whether the representation in the data should be interleaved into the knot position structure, or be an additional structure.

Attribute Connections

We believe that connections should be handled using the current system. However, this means that connections per knot would have to be fulfilled by additional multi-input to array node to convert many single float/color values into a single array ready for the shader to comprehend.

Unlike animation splines, we don’t believe there is a requirement for USD value resolution to evaluate values given a point on the ramp, since this is typically handed by the shaders within the renderers.

Conclusion & questions

This is based on our understanding and practical use of ramp style widgets, particularly within shaders. There may well be topics we’ve missed, or considerations we haven’t encountered. We welcome any thoughts or feedback on this, with the aim for us to produce a proposal once we believe we’re not missing any critical information.