You are on page 1of 5

CoShaders & Shader Objects

Traditional RenderMan shaders are split into 4 main types: Surface, Displacement, Light and Volume. With Prman version 13.5, Pixar introduced the concept of co shader and shader objects to expand the pipeline of shading your scenes Shader objects are shaders which can be treated like objects in a programming environment. They can keep values in member variables, which can be used elsewhere in the shader ie in both a displacement and surface shading routine. This for example removes the need for some message passing CoShaders are shaders with no defined type. They can contain more than one shading model - i.e a single shader can contain both displacement and surface information. So for a look of displacement and surface shading, we would normally have to have 2 separate shaders, and apply them both to our geometry in the scene.

Shader Objects Unfortunately, Shader objects havent been fully implemented into RM Studio just yet, but this is a very simple introduction to them. In this example, I am going to build up a simple class based shader, which has both displacements and surface shading information. Here is the basic structure for a shader object: class ShaderObjects(/* parameters */) { public void displacement(output point P; output normal N) { /* DISPLACEMENT CODE */ } public void surface(output color Ci, Oi) { /* SHADER CODE */ } } You can see the class definition, and both the displacement and surface calls. The class section is where we will set our parameter values for controlling the shader. So lets take a look at the displacements. Because we want to control a few parameters, we will specify them in the shader objects parameter list. The uniform floats: texfreq and dispmult are for the pattern frequency and amount of displacement applied First we set our normal and texture coordinates Then calculate our pattern Store the depth in our variable Disp and then apply the displacements

class ShaderObject(uniform float texfreq = 1, DMult = 0.01) { public void displacement(output point P; output normal N) { varying float Disp = 0; float tt = mod(t * texfreq,1); float ss = mod(s * texfreq,1); varying float vstripes = smoothstep(0.2,0.25,tt) - smoothstep(0.750,0.8,tt); varying float hstripes = smoothstep(0.2,0.25,ss) - smoothstep(0.750,0.8,ss); P += normalize(N) * DMult * max(vstripes,hstripes); Disp = max(vstripes,hstripes); N = calculatenormal(P); } public void surface(output color Ci, Oi) { varying normal n = 0;

n = normalize(N); normal nf = faceforward(n, I); color diffusecolor = diffuse(nf); Oi = Os; Ci = Oi * Cs * diffusecolor; } } We can save this file as coshader.sl and compile it with the shader executable. Next take a look at the ribfile: Display "ShaderObjects" "it" "rgba" Format 640 480 1 Projection "perspective" "fov" 40 ShadingRate 1 Translate 0 0 3 Rotate -30 1 0 0 Rotate 0 0 1 0 Scale 1 1 -1 WorldBegin LightSource "pointlight" 1 "intensity" 45 "from" [5 5 5] Color 0.341 0.266 0.184 Surface "plastic" Displacement "dented" Attribute "bound" "displacement" [0.1] Sphere 1 -1 1 360 WorldEnd This contains the standard method for assigning surface and displacement shaders to an object, in this case a simple sphere. So we need to modify it to work with the class based shader we have just compiled. So instead of separate surface and displacement calls, we simple replace them with a single surface call. Display " ShaderObjects" "it" "rgba" Format 640 480 1 Projection "perspective" "fov" 40 ShadingRate 1 Translate 0 0 3 Rotate -30 1 0 0 Rotate 0 0 1 0 Scale 1 1 -1 WorldBegin LightSource "pointlight" 1 "intensity" 45 "from" [5 5 5] Color 0.341 0.266 0.184 Surface "ShaderObject" "DMult" 0.025 Attribute "bound" "displacement" [0.1] Sphere 1 -1 1 360 WorldEnd If you render this ribfile, by running prman shaderobjects.rib you will see a simple sphere with our displacement shader assigned.

Lets go back to the rib file, and set a bigger value for the texture repeats. After the surface call, add texfreq 16.: Surface "ShaderObject" "DMult" 0.025 "texfreq" 16 We can now see the repeating pattern has increased.

Lets add a surface shader to this shaderobject. Place the Kd declaration in the parameters for the diffuse. Next add the surface code into the surface section class ShaderObject(float Kd = 1;uniform float texfreq = 1, DMult = 0.01) { public void displacement(output point P; output normal N) { varying float Disp = 0; float tt = mod(t * texfreq,1); float ss = mod(s * texfreq,1); varying float vstripes = smoothstep(0.2,0.25,tt) - smoothstep(0.750,0.8,tt); varying float hstripes = smoothstep(0.2,0.25,ss) - smoothstep(0.750,0.8,ss); P += normalize(N) * DMult * max(vstripes,hstripes); Disp = max(vstripes,hstripes); N = calculatenormal(P); } public void surface(output color Ci, Oi) { varying normal n = 0; n = normalize(N); normal nf = faceforward(n, I);

color surfcolor = Cs; surfcolor = color(0,0,1); color diffusecolor = Kd * diffuse(nf); Oi = Os; Ci = Oi * surfcolor * diffusecolor; } } Now when you render, you can see our single shader, has both displacement and surface data computed.

The real power of these shader objects, is their ability to share data between them, so information from the displacement routine can be used within the surface shading component for example. Lets change our surface shader based on displacements. I want to have the pits in the displacement to be coloured red, and the extruded parts to be blue. To do this previously, we would have to use message passing, now we can simply set the variables we wish to use before the public calls. Add varying float variables for Disp and Base. We will compare these two values later to see if the surface has been displaced or not. In the displacement shader, make DISP equal to the max value of the pattern We can now take this DISP value from the displacement shader object, and use it in the surface shader object, by using the following IF condition. class ShaderObject(float Kd = 1; uniform float texfreq = 16, DMult = 0.01) { varying float Base = 0; varying float Disp = 0; varying normal n = 0; public void displacement(output point P; output normal N) { float tt = mod(t * texfreq,1); float ss = mod(s * texfreq,1); varying float vstripes = smoothstep(0.2,0.25,tt) - smoothstep(0.750,0.8,tt); varying float hstripes = smoothstep(0.2,0.25,ss) - smoothstep(0.750,0.8,ss); P += normalize(N) * DMult * max(vstripes,hstripes); Disp = max(vstripes,hstripes); N = calculatenormal(P); } public void surface(output color Ci, Oi) { n = normalize(N); normal nf = faceforward(n, I); color surfcolor = Cs; surfcolor = color(0,0,1); color diffusecolor = Kd * diffuse(nf); Oi = Os; Ci = Oi * surfcolor * diffusecolor; } }

Now when we render, you can see the red and blue areas shaded, as the displacement shader passes its information to the surface shader.

You might also like