Draft 1
- Motivation
- Support Levels
- Common Keywords
- page
- widget
- Arrays
- Conditional visibility or locking
- DCC app integration
User interfaces are important for usability and enforcing conventions across DCCs goes a long way towards makintg artists' work easier.
Currently, OSL defines only a few metadata keywords, representing a subset of Katana's UI capabilities. Then, there are all the other DCCs like Houdini, Maya, Cinema4D, Blender, etc, which support either none, a subset or an entirely different set of UI metadata keywords.
This area is ripe for standardization and having implemented many of these keywords in RenderMan for Maya, I am confident this would greatly improve user experience at a reasonnable cost.
The emphasis of this proposal is to define a somewhat minimal set of UI hints that may be supported by most DCC applications.
Given the number of controls to implement, it may be useful to introduce support levels.
- : Only support a small number of randomly chosen keywords.
- : Support a minimal standard set of keywords.
- : Support most if not all keywords.
One would hope that developers implements at least the basic level, as it would already provide a reasonnable user-experience.
As of today:
- RenderMan plugins are very close to full support.
- 3Delight plugins are very close to full support.
- Arnold plugins mostly ignore parameter metadata as it historically relied on an external metadata file.
- Blender only supports 4 keywords.
- VRay TBD
- Redshift TBD
- Octane TBD
These keywords are supported by all widgets.
Assign the parameter to a page defined as a dot-separated path, i.e. "Specular.Advanced".
Widget options | Type | Description | Level |
---|---|---|---|
open |
int | If 1, the page UI is expanded by default |
color specularTint = 1
[[[
string page = "Specular",
string label = "Tint",
]]],
float specularIOR = 1.5
[[
string page = "Specular",
string label = "Index of Refraction",
float min = 1.0
]]
int specularModel = 1
[[
string page = "Specular",
string label = "Model",
string widget = "mapper",
string options = "Beckmann:0|GGX:1"
]]
Defines which widget type will control the parameter. All parameter types default to a sensible widget if un-defined in the metadata block.
Parameters using a null
widget are invisible in the UI.
string asset_version = "2.3.0"
[[
string widget = "null"
]],
A widget for editable numeric values. This is the default widget used for number parameters.
float ior = 1.5
[[
string widget = "number",
float min = 0.0,
float max = 2.5,
int slider = 1,
string help = "The Substrate's Index Of Refraction"
]],
Default widget type used for string parameters.
string variant = "default"
[[
string widget = "string",
string label = "Variant",
]],
An int parameter displayed as a boolean check box.
int invert = 0
[[
string widget = "checkBox",
string label = "Invert Output"
]],
A widget used to edit color parameters.
Widget options | Type | Description | Level |
---|---|---|---|
color_enableFilmlookVis 1 |
int | Enable color-managed UI. | |
color_restrictComponents |
int | Limit components to [0:1] |
color albedo = "default"
[[
string widget = "color",
int color_enableFilmlookVis = 1,
string label = "Albedo"
]],
Display a pop-up menu or combox box with literal choices for a string parameter.
Widget options | Type | Description | Level |
---|---|---|---|
options |
string | A pipe-delimited list of menu items, i.e. "One|Two|Three" |
|
editable |
int | If non-zero, present an editable field with a side menu |
string sss_mode = "default"
[[
string widget = "popup",
string options = "burley|random walk"
]],
An menu presenting associative choices (like enums) for int, float and string parameters.
Widget options | Type | Description | Level |
---|---|---|---|
options |
string | A pipe-delimited list of menu items : value pairs. |
int compositingMode = 0
[[
string widget = "mapper",
string options = "Over:0|Add:1|Screen:3|Mult:2|Overlay:4",
string label = "Compositing Mode"
]],
A string attributes containing a file path. There should always be an associated button to open a file browser and select the file.
string texture = ""
[[
string widget = "fileInput",
string label = "Texture"
]],
Note
OSL's spline interpolation shadeops only work on static arrays when most users actually want dynamic arrays. This forces the shader writer to copy multiple dynamic arrays to static arrays. I don't know the exact cost of that operation but it would be great to get rid of this limitation.
Note
Start and end knots need to be repeated n-times depending on the interpolation scheme. It would be nice to add an option flag to let the spline shadeop automatically select the correct number of repetitions.
Note
It would be good to make sure DCC app widgets support all standard OSL interpolation modes. Last time I checked Maya did not, blender used other bases, etc.
Note
Do we really want to support per-knot interpolation bases ?
- It adds a lot of complexity to the shader code, as you need to change the number of knots based on the selected basis and compute these extra points positions and values to enforce a predefined c0/c1 continuity heuristic.
- Even if this is partially handled by the DCC UI, it adds a lot of book-keeping.
- Some bases allow for smooth and discontinuous tangents, which is, I believe, flexible enough.
- The artist will be responsible for creating enough knots, beyond the standard beginning/end repetitions, and will be guided by the UI's visual feedback.
Color ramps depend on multiple parameters to provide knots position, knots value and knots interpolation.
The main parameter is an int parameter with a colorRamp
widget. Its value is the number of currently used knots. This representation allows support of fixed-size ramps.
The metadata MUST define 3 additional keywords (rampKnots
, rampColors
and rampInterp
) to be functional. If any of theme is missing, an error should be raised.
Note
Should we extend oslc to validate metadata ?
int colorMap = 4
[[
string label = "Color Map",
string widget = "colorRamp",
string rampKnots = "colorMap_Knots",
string rampColors = "colorMap_Colors",
string rampInterp = "colorMap_Interpolation",
int rampHeight = 25,
]],
float colorMap_Knots[] = {0, 0,
1, 1}
[[
int isDynamicArray = 1,
string widget = "null",
]],
float colorMap_Knots[] = {color(0), color(0),
color(1), color(1)}
[[
int isDynamicArray = 1,
string widget = "null",
int restrictComponents = 1
]],
float colorMap_Interpolation[] = {"catmull-rom", "catmull-rom",
"catmull-rom", "catmull-rom"}
[[
int isDynamicArray = 1,
string widget = "null",
]],
The main parameter is an int parameter with a colorRamp
widget.
- Its value is the number of currently used knots. This representation allows support of fixed-size ramps.
The metadata MUST define 3 additional keywords (rampKnots
, rampColors
and rampInterp
) to be functional.
- If any of theme is missing, an error should be raised.
int attenuationCurve = 5
[[
string label = "Attenuation Curve",
string widget = "floatRamp",
string rampKnots = "attenCrv_Knots",
string rampFloats = "attenCrv_Values",
string rampInterp = "attenCrv_Interpolation",
int rampHeight = 25,
]],
float attenCrv_Knots[] = {0, 0, 0.5, 1, 1}
[[
int isDynamicArray = 1,
string widget = "null",
]],
float attenCrv_Values[] = {0, 0, 0.3333, 1, 1}
[[
int isDynamicArray = 1,
string widget = "null"
]],
float attenCrv_Interpolation[] = {"catmull-rom", "catmull-rom",
"catmull-rom", "catmull-rom",
"catmull-rom"}
[[
int isDynamicArray = 1,
string widget = "null",
]],
OSL support array parameters of any types and the metadata allows writers to decide which widget should be used.
- Dynamic arrays allow the addition, re-ordering and removal of array elements.
- UI Structs are a way to display multiple arrays as if they were a single array of structs, which isn't natively supported by OSL, but useful to group, for example, layer parameters. If the arrays are dynamic, it will be the responsability of the DCC app to keep all participating arrays at the same size at all times.
int triplanarAxisEnable[3] = {1, 1, 1}
[[
string label = "Enable Axis"
string widget = "checkBox",
int size = 3,
string uiStruct = "Triplanar Axes",
]],
string triplanarAxisTexture[3] = {"", "", ""}
[[
string label = "Texture"
string widget = "fileInput",
int size = 3,
string uiStruct = "Triplanar Axes",
]],
float triplanarAxisRepeat[3] = {1.0, 1.0, 1.0}
[[
string label = "Enable Axis",
string widget = "number",
int size = 3,
string uiStruct = "Triplanar Axes",
int slider = 1,
float min = 0.0001,
float slidermax = 10.0
]],
These keywords allow to control a parameter's visibility or editability based on the value of one or more shader parameters. The comparison rules are defined as a set of pair-wise comparisons: prefixPath prefixOp prefixValue
or prefixLeft prefixOp prefixRight
Note
Katana uses conditionalVis
/ conditionalLock
but I prefer a shorter keyword as it is still descriptive enough. TBD.
Note
Pages should also support conditional visibility and locking.
How about pageVis*
and pageLock*
?
The keyword structure is as follows:
- The root token is
vis
orlock
. - It is followed by an optional identifying suffix.
- It ends with one of the following tokens:
Op
,Path
,Value
,Left
,Right
.
// Make linearize_sRGB visible if
// (textureName != "" && textureGain > 0).
// > visLeft = visTexPath visTexOp visTexValue
// > visRight = visGainPath visGainOp visGainValue
// > Visibility = visLeft visOp VisRight
string textureName = ""
[[
string widget = "fileInput"
]],
float textureGain = 1.0
[[
int slider = 1,
float min = 0.0,
float slidermax = 2.0
]]
int linearize_sRGB = 0
[[
string widget = "checkBox",
string visTexPath = "../textureName",
string visTexOp = "notEqualTo",
string visTexValue = ""
string visGainPath = "../textureGain",
string visGainOp = "greaterThan",
string visGainValue = "0.0"
string visLeft = "visTex",
string visOp = "and",
string visRight = "visGain",
]]
Occasionaly, OSL shaders need to carry more metadata to make integrate with host applications.
shader voronoi
[[
string tags[1] = {"texture/2d"},
string 3dl_maya_nodeID = "0x00",
string help = "Computes a procedural voronoi patterns."
]]
(
...
)
Footnotes
-
This is a Katana-ism and I would prefer something more generic like
color_managed
that doesn't mention "film". ↩