custom shading functions


This page shows the results of creating custom shading functions written in the RenderMan Shading Language.






Basic idea:

The purpose of this project is to write a custom shading function in RSL.
I chose to make a fake rim light shader using facing ratio and user
variables to control the light wrapping effect, combined
with diffuse and specular functions added in.


fig. 1
color my_rim ( normal Nf; vector V; float rim_width )
{
  float facing = 1 - Nf.V;
  color C = smoothstep(1.0 - rim_width, 1.0, facing);
  return C;
}

float facing sets the inverse of the facing ratio, otherwise 
it will be black on the edges.
smoothstep takes 3 values that will use a user variable 
rim_width to calculate how large the fake rim is.
		




Humble beginings:

This is how the function gets integrated into the shader along
with how it will soon interact with everything else.


fig.2
Ci = Oi * (Cs * (Ka * ambient() + Kd*my_rim(Nf,V,rim_width)) * rim_strength)

my_rim is multiplied by rim_strength, also a rim_width user
variable is plugged into the fig.2 function, which exists in 
shading.h, a header file.
		




Plain english version:

This attatches the lighting model to the shader, which will
describe but one property of how it will respond to
lights in the scene.


fig.3
Ci = Oi * (Cs * (Ka * ambient() + Kd*my_rim(Nf,V,rim_width)) * rim_strength)
	* (Kd * my_diffuse(N))

The combined rim is multiplied by my_diffuse, which attatches 
a lighting model to it.

my_diffuse looks as such:
color my_diffuse ( normal N )
{
  color C = 0;
  illuminance( P, N, PI/2 )
     C += Cl * normalize(L).N;
  return C;
}

an illuminance loop defines how the surface reacts to light.
Diffuse is calculated by the dot product of N.L
normalize simply makes it fall between 0 and 1.
		




More user control:

This allows for the user to control a uniform amount of
fake rim, not just the areas in which light is hitting
the object.


fig.4
Ci = Oi * (Cs * (Ka * ambient() + Kd*my_rim(Nf,V,rim_width)) * rim_strength)
	* (Kd * my_diffuse(N) + ((-my_diffuse(N) + rim_ambient) * rim_ambient_strength))

rim_ambient and rim_ambient_strength user variables are introduced
the non illuminated diffuse sides (-my_diffuse) of the object are mixed with 
the variables, and added to the shader to give control over an overall rim.
		




Specular:
The specular is added on top of the existing shader.
I struggled a bit with understanding how the specular
gets implemented in and out. After deconstructing each
part of the code, it made more sense:
color glossy_specular (normal Nn; vector V; float roughness, sharpness_glossyspec)
English: Glossy specular is a color, we must give it a normal and a vector
to do it's calculations inside the function.
glossy_specular(Nf,V,roughness, glossiness)
English: In addition, we pass it the user defined variable roughness
and glossiness to drive calculations in the function.


fig.5
Ci = Oi * (Cs * (Ka * ambient() + Kd*my_rim(Nf,V,rim_width)) * rim_strength)
	* (Kd * my_diffuse(N) + ((-my_diffuse(N) + rim_ambient) * rim_ambient_strength))
	+ specularcolor * Ks * glossy_specular(Nf,V,roughness, glossiness)

Finally, a glossy specular is added over it all.

//Based on Larry Gritz's glossy spec.//
//Additional thanks to Virginia Wissler//
color glossy_specular (normal Nn; vector V; float roughness, sharpness_glossyspec)
{
	extern point P;
	color C = 0;
	float w = 0.5 * (1 - sharpness_glossyspec);

	illuminance (P, Nn, PI/2) {
		vector H = normalize (normalize(L) + V);
		C += (smoothstep (.5-w, .5+w, pow (max (0, Nn.H), 1/roughness))) * Cl;	
	}

	return C;
}
		


In action:

With all these user controls, let's see what we can do in
Maya with this shader on actual objects with form.


fig.6
Ci = Oi * (Cs * (Ka * ambient() + Kd*my_rim(Nf,V,rim_width)) * rim_strength)
	* (Kd * my_diffuse(N) + ((-my_diffuse(N) + rim_ambient) * rim_ambient_strength)) + (Kd * (my_diffuse(N))
	+ specularcolor * Ks * glossy_specular(Nf,V,roughness, glossiness)

Finally, the actual diffuse of the surface (not the rim) is added.

		




Default Settings, no light.



		




Default Settings, 1 key light.


rim_strength 2.2
rim_ambient 1.4
rim_ambient_strength 0.08
rim_width 0.7
		




Wide, softer rim, lower ambient, 1 key light.


rim_strength 2
rim_ambient .741
rim_ambient_strength 0.08
rim_width 0.98
		




Focused, higher ambient + rim strength, 1 key light.


rim_strength 2.761
rim_ambient 1.016
rim_ambient_strength 0.17
rim_width 0.59
		




Very low light, high rim + ambient rim


rim_strength 3.278
rim_ambient 1.949
rim_ambient_strength 0.14
rim_width 0.78
		



Conclusion: The use of functions to call upon is quite powerful, it allows
you to reuse portions of your code again. The next things I would
do is add controls to invert the rim and possibly an eclipsing
of the outside function.