Page tree

Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...


Also, the cost of compiling the shaders and shader networks at runtime can become a significant, especially since this compilation phase will prevent multiple threads from running at their highest efficiency. Normally for scenes that take a while to render, this cost is effectively amortized. However, if there are hundreds of thousands of unique shader instances, that cost can start to impact final render times. The Batched mode may have a greater impact on startup time than non-batched but for complex scenes the overall benefit is worthwhile.

...

You can better understand OSL in your scene by outputting stats at varying levels. Note that higher verbosity will impact render times as there is overhead to print messages during render. So it's advised only to use for data mining your scene and not final rendering or lookdev tests where speed is important. The verbosity matches that of standard OSL messaging: 0 nothing, 1 only severe, 2 only severe and error, 3 severe,error,message, 4 severe,error,message,warning, 5 severe,error,message,info These stats are written to the Plugins tab of the Advanced XML stats in RenderMan. Stat output at level 3 and higher adds timing to the stats and can impact performance more than lower levels. Levels 4 and higher should be used in tandem with RenderMan support as well as information on your use of the batched mode or default.


Basic OSL shader writing

...



You create a shader in one or more text files, typically with the .osl extension. You then compile these into shader object files with a .oso extension using the osl compiler, oslc. For convenience, oslc is shipped with RenderMan distribution. These shader object files can then be used directly as Pattern shaders in RenderMan.
We'll go through the following simple shader as an example to illustrate the basics of writing an OSL shader and how that shader is integrated into RenderMan:

shader myMixShader (color a = color(1,0,0),
color b = color(0,1,0),
float mixVal = .5 [[ int lockgeom=0 ]],
output color resultRGB = color(1,1,1) ) {
float finalMix = clamp(mixVal,0.0,1.0);
float doMix = 1.0;
getattribute("allowMixing", doMix);
float mixExponent = 1.0;
getattribute("builtin", "curvature", mixExponent);

    if (doMix != 0) {
finalMix = pow(finalMix, mixExponent);
float mixRemainder = 1.0 - finalMix;
resultRGB = a * finalMix + b * mixRemainder;
} else {
resultRGB = a;
}
}

The first line contains the shader type, the shader name, and the beginning of the parameter list. RenderMan only supports the generic “shader” shader type, not the more specific types of “surface”, “displacement”, “light”, and “volume” shaders used by other renderers. 

Next we have the list of parameters. Each parameter must have a default initializer. Metadata can be specified within the double brackets [[ ]] to provide extra information about the parameters to your renderer and other content creation applications. In this case, the metadata int lockgeom = 0 means that the value mixVal can be interpolated from a mixVal variable attached to the geometry. Currently, RenderMan allows attaching variables of all types supported by OSL except for int and structs.

The results of the shader, in this case the color resultRGB, are connected to the rest of the shading network via parameters declared as outputs. These outputs can be connected to Bxdfs and Displace shader inputs, or other OSL or C++ Pattern shader inputs. This interface is provided in place of the standard closures, which are not supported within RenderMan.

One of the first things the shader does is to declare a local variable, finalMix. It applies the OSL function clamp() to the mixVal input, and stores it in finalMix. Inputs are not writeable in OSL, so we must store it in a second temporary value. Don't worry about the extra variable, though – the render-time optimization step in OSL is good at getting rid of them, so feel free to use temporary variables like this to make your shader code clearer as well.

RenderMan supports almost all of the standard functions built into OSL like clamp() -- you can refer to Known Limitations for the list of unsupported functions and the the OSL documentation for usage of the supported functions. You can write your own functions in OSL, however there is currently no interface for directly linking in functions written in another language such as C++. For that you'll need to write a C++ pattern and pass values via the parameter lists between C++ and OSL. See the section below for details and limitations of mixing C++ and OSL Patterns.

The next bit of interest is the getattribute() call. It allows fetching attributes set for the currently set piece of geometry by attribute name. It also supports an object name to indicate where the attribute should come from. RenderMan supports using “global,” “primvar,” and “builtin” object names, as well as no name or the empty string “”. Using no name or the empty string will fetch RenderMan attributes for the current piece of geometry. Using “global” will fetch options. Since RenderMan Attributes and Options are divided up into categories, so to fetch them you prefix the attribute name with the category and a colon. For exampe, Attribute “dice” “float micropolygonlength” can be fetched using getattribute(“dice:micropolygonlength”). Using “primvar” will only fetch values stored on the geometry itself, separate from the RenderMan attribute state. Using “builtin” will fetch the additional built-in variables provided by RIS but not part of the default global variables of OSL.

...