RSL: Manipulating the Termination Angle of a Light
by TheRiverside on Nov.17, 2009, under Renderman II Final Project
In an earlier post, I made notes on how the Renderman Shading Language uses “illuminance” loops to define how a surface shader reacts to light coming from a light source. The “luminance” loop used to define a Lambertian shading model in RSL is:
Nn = normalize(N);
illuminance( P, Nn, PI/2 )
{Ln = normalize(L);
Ci += Cs * Cl * Ln.Nn;}
I mentioned that it is possible to change the termination angle of a light. In reality, if a sphere were to be lit from a light source coming from a specific direction, half the sphere would be in light and half would be in shadow. This termination angle can be defined as being 90 degrees from the light’s direction. If this angle were changed to something above 90, the light would theoretically seem to wrap around the surface.
The illuminance statement needs three arguments. The third of which is a cone angle (measured in radians) used by the shader to sample incoming light (see this post). By default, the angle is “PI/2″ (90 degrees). While this angle is not actually measuring the angle between the light’s direction and the light/shadow termination line, they happen to be equal. If the angle in the illuminance statement were changed to “PI” (180 degrees), the whole surface would be lit.
While it’s possible to manipulate this single value, there is a way to make this a little more useful. By default, light has a natural falloff before the surface transitions completely into shadow. It might be useful to define a point where the transition will start (begin to fade from fully illuminated) and where it will end (the point the surface will be completely in shadow).
This can be done using the following block of code:
color lightColor = color(1,1,1);
color diffuseColor = 0;
normal n = normalize(N);
float lightfall_begin_angle = 0;
float lightfall_end_angle = 90;illuminance(”wrapper”,P, n, PI ) {
//declare illuminance variables vector l = normalize(L);
float dot = n.l;//PROCESS LIGHTWRAP
// note: angle = 0 = facing light
// note: angle = 180 = away from light
float lightfall_begin_radian = radians(lightfall_begin_angle);
float lightfall_end_radian = radians(lightfall_end_angle);
float illum = smoothstep(cos(lightfall_end_radian), cos(lightfall_begin_radian), dot);diffuseColor += Cl * lightColor * illum;
}
1) Define the lightColor and diffuseColor.
2) Normalize the surface normal N.
3) Define the beginning and ending angles for the falloff (measured from the light’s direction vector L).
4) Define the illuminance loop. In this case, the loop will be applied only when using lights with the category of “wrapper”. Notice that instead of the angle defining the cone being PI/2, it is simply PI. This is so that, by default, the entire surface is sampling the light. The falloff will be done inside the illuminance loop, not by it.
5) Normalize the light’s direction vector L.
6) Take the dot product of the normalized normal N and the normalized vector L. This will essentially give the cosine of the two vectors. This means that a point facing the light will have a “dot” value of 1. A point facing 90 degrees from the light will have a “dot” value of 0. A point facing completely away from the light will have a “dot”value of -1.
7) Convert the beginning and ending falloff angles into radians.
8 ) use the “smoothstep” function to apply the gradient. This way, any value before the “lightfall_begin” angle will be white (in light). Any angle above the “lightfall_end” angle will be black (in shadow). There will be a steady gradient between the two values (the falloff). You have to take the cosine of both radian angles so they can be measured against the “dot” value.
December 14th, 2009 on 6:21 pm
It sounds like you’re creating problems yourself by trying to solve this issue instead of looking at why their is a problem in the first place.nba jerseys