Shadow Mac!
By Homam Bahnassi
This tutorial is divided into the following sections:
Skill Requirements
Pretty much nothing! You just need to know how to get a sphere, and attach some shaders in
the render tree.
Introduction
OGLShadowMap is another mysterious real-time shader that's really great and helpful;
only if you know how it can be used! So here comes this hacky tutorial that shows you how
to use this important shader in your daily work.
The OGLShadowMap covers a very common case of shadows rendering, which is useful
for everyday use. Unfortunately, for more advanced cases you'll need to use more advanced
shader systems or write your own shadow map shader (to learn how you can use and write
custom real-time shaders for advanced shader systems take a look at the
X-tasy (ecstasy) with Real-Time Shaders tutorial).
Anyways, even if this shader is not that flexible for true real-time work, it is still
useful for fast pre-viewing and pre-visualizing. And here we go…
Explaining the shader’s concept
As the name of this shader implies “Shadow Map”, this shader uses intermediate 2D generated maps
to render shadows, which is a well-known technique (especially for those who are
involved in the game industry) to compute shadows in 3D.
In short, what the shader does is generate a 2D image that contains per-pixel depth information
about the scene you're rendering with regard to the light’s point of view, and stores it in
a custom buffer (P-Buffer). Then, it projects this image back to the scene. Something like
what mentalRay does when rendering shadow maps.
Because of this technique, we’ll find a bunch of parameters in the shader’s PPG that
control the 2D map generation and projection properties.
We’ll discuss these more in the following sections.
Preparing the scene
Before we deal with this shader, we need to prepare a couple of things in the scene,
so we get the results we expect.
First of all, you should have 3D geometry in your scene that will cast shadows on each other
(very intuitive, huh?). Get a small sphere and a grid for example (or any objects that
you find interesting) and position them so the sphere lies over the grid.
Put all of your 3D geometry in a group, and assign a new material to this group.
This will override all objects’ materials, which is required for controlling
the OGLShadowMap shader. The group contains both transmitter and receiver
objects simultaneously.
Ok, now you need to add a light source that will cast the shadows in your scene.
Grab a spot light and position it so it is focused on your main objects.
It's preferable also to delete the default scene light to make sure that you will not use it
accidentally as a shadow caster instead of your new light.
That’s it! all what is left now is to add the shadow shader.
Adding the shader and explaining its properties
Open the render tree for the group material and get a shadow map shader from the
‘RealTime > More…’ menu.
Plug the node into the ‘Realtime’ input port in the material's node, and switch
your camera shading to ‘Realtime Shaders’.
You’ll see a constant white surface, with a black shadow area. Orbit your camera and
reposition your light until the black shadow area is viewed clearly.
Now let's open the shader’s PPG and see what’s there for us to play with:
-
Light ID, is a very handy parameter when you have more than one light source in your scene.
This allows you to choose which light is the one that will cast the shadows.
Avoid choosing a light ID that doesn’t resemble to a spot light, this is because other
light types are not handled well by this shader and may give unexpected results.
In our case, we’ll leave this set to "0" (assuming that we have only one spot light
in the scene).
-
Field of View, Near plane and Far plane, these control the spot light’s
frustum shape (or “Frustrum” as it’s incorrectly typed in the PPG!).
Check the Show Frustrum option to see how these properties control the size of
the shadow frustum. Tune these parameters until the frustum covers all the objects you
want them to receive shadows, naturally the size of the frustum should be the same as
the spot light’s cone.
The rest of the properties are for controlling and outputting the map used to render the shadows.
We’ll leave these to their defaults now.
Extending the shader tree with shading and texturing nodes
Clearly, the result we've achieved until now is useless, since there’s no shading and
texturing on the objects! We gotta fix this...
So back in the render tree, grab the following nodes OGLDraw, OGLShade and
OGLTexture. Connect them in the same order they're listed here, then reconnect
the OGLShadowmap after your last node (i.e. OGLTexture).
As you connect the OGLDraw node, you'll lose the rendered shadows. Don't worry though,
we'll manage this after a while. Now set the surface and texture properties from the
OGLShade and OGLTexture nodes.
Finally, to retrieve back our shadows, we need to activate alpha blending in the
OGLDraw shader. In its PPG, just check Enable Blending and choose ONE
from the Source list, and SRC_COLOR from Destination list.
This will take the rendered shadow color information and multiply it with the surface’s color.
The final effect will be a nicely blended shadow. Give yourself time to mess with the
blending modes to see how different combinations affect the result.
Sample Scene and good bye
Here’s my sample scene that I tested shadow maps with. Notice how the shader
improves feeling of the scene mood, and as usual, in real-time!
Enjoy.