OSL is a shading language designed for modern physically based rendering, supported starting from Arnold 5.0. It can be used to write shaders that work in Arnold and other renderers. It is an alternative to C++ shaders, with a higher level API that makes writing shaders simpler while at the same time providing advanced optimizations.
OSL shaders are written in .osl files, with each file corresponding to a single Arnold shader node. Here is a simple example:
The shader name
gamma must match the
gamma.osl filename. The shader defines input and output parameters much like Arnold C++ shader nodes, but using a more compact syntax. Here
gamma are input parameters, while
Cout is the output parameter. All parameters must be initialized with default values.
Shaders are compiled automatically when they are found by Arnold in the shader searchpath, from .osl files to .oso files in the same directory. This happens if no corresponding .oso file exists, or if the .osl file was modified since the last compilation.
Alternatively, shaders can be manually compiled using the
oslc program included with Arnold.
.oso files contain intermediate code that is operating system and CPU agnostic. At render time, OSL translates shader networks into machine code on the fly, and in the process heavily optimizes shaders and networks with full knowledge of the shader parameters and other runtime values that could not have been known when the shaders were compiled from .osl source code.
.osl and .oso files are installed the same way as .so and .dll shader files: place them anywhere in the shader searchpath, and Arnold will find them.
kick we can verify that Arnold detects the shader and its parameters.
Manually Loading Shaders
Besides the automatically registered OSL shaders in the search path, it is possible to load shaders manually through an
osl node. This can be useful to insert expressions into a shader network, or to get more control over which shaders are loaded and how their parameters should be interpreted.
osl accepts a
shadername parameter to specify the shader, without the .osl or .oso file extension. As soon as the
shadername parameter is set, the OSL shader parameters are added to the node, with a
For inserting expressions into the network, the .OSL or .OSO code can be embedded as well:
OSL shader parameters are converted to the corresponding Arnold parameters where possible. Arnold only supports one output parameter per node, so if there are multiple output parameters the first parameter will be used.
|OSL Type||Arnold Type|
Boolean and enum parameter types are created with OSL metadata on integers.
Node parameters and user data are available through
Arnold supports most OSL shader globals, like
time. Their meaning is the same as in the C++ shading API.
Ps (for light filters),
dPdtime shader globals are not supported currently.
All shader globals are considered to be read-only, we do not support writing to
P to output closures or displacement. Output parameters should be used instead.
Textures are accessed through the built-in
gettextureinfo() functions. The
texture() function accepts an optional
colorspace argument to indicate the texture's color space to convert from.
Note that unlike the Arnold C++ shading API, the texture origin is assumed to be in the top left corner rather than the bottom left corner, for consistency with the OSL standard. To match, the
v coordinate can be flipped to
1 - v, or
floor(v) + 1 - mod(v, 1) in case of UDIM textures.
Volume channels are available through
texture3d() using object space coordinates.
The following closures are supported, matching the closures in the C++ shader API.
Example shader outputting a closure:
trace() function is supported, for tracing probe rays. The
shade argument to perform shading is not supported. The
traceset argument is supported, using an inclusive traceset by default, and exclusive if the traceset name is prefixed with a
Information about the hit may be retrieved with
v, and arbitrary user data and parameter lookups on the object that was hit.
OSL and C++ shaders can be linked into a single shader network. However there is a small overhead (perhaps 1-2 % overall render time) in connecting the output of an OSL shader into a C++ shader. For the OSL optimizer to be able to do aggressive whole network optimizations, as many OSL shader nodes as possible should be used.
Runtime compilation and optimization of OSL shaders happens the first time the shader is evaluated, during rendering. This increases the time to first pixel, but can pay off in reduced render time overall.
The OSL_OPTIONS environment variable can be used to debug common errors in shaders or print more detailed information: