SHADOW MATRIX - THEORY AND PRACTICE
The subject of this text is some theoretical and practical explanations of
how to produce shadow from spotlight using OpenGL. It is assumed that you know
some basic programming, a bit of Linear Algebra and Analytic Geometry and some
basics of OpenGL, although this can easily be applied using some other graphic
libraries.
INTRODUCTION
If you read "Red Book", you can find there useful article on this
topic. But. But what? But it isn't enough. I know because I tried it. Before
we jump in deducing, there are few things we must always have on our minds (
this works with OpenGL ):
1. Every vertex ( extended point ) have four "coordinates" : x, y,
z, w . First three are coordinates in three-dimensional space, and fourth is
used, if I may say, for scaling. That is, every vertex ( x, y, z, w ) is mapped
to ( x/w. y/w. z/w ). What if w=0? I really don't know.
2. Transformation matrices are 4x4 ( four rows and four columns ), and they
are stored in column - order : if you declare float m[16] that means following
matrix :

3. If M is matrix that is already on the matrix stack and you do some transformation
which produce new matrix N ( or just multiply it with glMultMatrix() ), the
new matrix on the stack will be M*N. And remember that the vertices are mapped
in this way : v' = Mv.
THEORY
Here goes the part from "Red Book", with some more details. Assume
that the light is in L( 0, 0, 0 ), and the plane on which we want to project
shadow is given by ax + by + cz + d = 0, where n( a, b, c ) is vector perpendicular
to plane. The one thing that you don't want is that the L is on plane! In this
case, it is enough that d<>0. Now, we want to produce matrix, that maps
each vertex v to proper vertex v' that lies on the given plane. The coordinates
of this vertex is found as intersection of plane and the line that is defined
by L and v :

This line is given by ( one can easily check this ) x = k*vx, y = k*vy, z
= k*vz, where vx, vy and vz are coord's of vertex v, and k is an arbitrary real
number. Plugging this in plane equation gives us :
k*( a*vx + b*vy + c*vz ) + d = 0 ,or in the vector form k*n*v + d = 0.
Second * in last equation is meant to be dot product. Now extract k from this
and plug into line to obtain v':
k = -d/(n*v) and v' = -d*v/(n*v).
Notice that n*v shouldn't be 0. This means that v must not be parallel to plane,
because then there is no intersection between light line and plane. Finally,
our matrix looks like :

To check this, let multiply vertex v( vx, vy, vz, 1 ) by this matrix :

Remember what we sad about fourth coordinate?
Now, suppose that light source isn't in ( 0, 0, 0 ), but in some arbitrary L(
Lx, Ly, Lz ).First thought is : lets translate world by vector L and then apply
previous matrix. We can go back by inverse translation.
It's good, but not enough. What we have forgot? Plane! If we make matrix from
the original plane, and translate world, it's equation remains and that is not
good. What we want is the new plane in same relative position to light. Luckily,
it isn't hard because the normal vector doesn't change, and we have to recalculate
only d. If we translate every point that lies on plane, we have :
a(x + Lx ) + b(y + Ly) + c(z + Lz) + d = 0
which leads to
ax + by + cz + aLx + bLy + cLz + d = 0 ;
so, if we mark fourth parameter of translated plane as d', we have
d' = n*L + d ,
using the vector form. So, if we put this instead of d in previous matrix, we
have our shadow matrix!
PRACTICE
Now that we have derived matrix, let see how can we use it in real applications.
In addition to previous, let T is the matrix that translates world to light
source L and T^-1 is it's inverse. You might want some matrix that transforms
your model - let call it M. Finally, if you're moving through your scene, you
probably have some camera matrix which we can call C. Presuming this, order
line of matrix multiplications should look like this :
C*T*S*T^-1*M
where S is shadow matrix.
And that is almost all. I tried this approach and put it in my code and guess
what happened? Nothing! Whaaaaat?!!?? All this and now you telling me......
OK. Wait a second. I didn't say that calculus was bad. So what went wrong? Something
that I really didn't expect, found, once again, in the "Red book".
They say : some OpenGL systems might not handle negative fourth coordinate (w)
correctly; so keep them positive. I must admit that I was surprised, since I'm
mathematician. Doesn't you simply divide first three coords with fourth? But
what a heck. I just want my shadow!
And now arised a new problem : how can I know that the vertex, after all transformations,
has negative w coordinate in time of making shadow matrix, and before matrices
C and M are even applied? And I found intermediate solution. Since my code didn't
produce any shadow, I realize that all my w coordinates are negative. So make
them positive in S matrix! How? Remember that ( x, y, z, w ) is mapped to (
x/w, y/w, z/w ); if you add negative sign to x, y, z and w, you get same point,
with opposite sign of w. If it was negative, now it's positive. Hence, multiply
S by -1, and you'll obtain this matrix :

This time it works! Here some mathematical background, which wouldn't be derived
here.
What we are interested in is a last row of matrix that will multiply given vertex,
because it gives last coordinate of transformed vertex. Regarding the order
of matrices in multiplaying sequence T*S*T^-1, it is not too hard to calculate
this row ( translation matrix can be found in "Red Book" ); it looks
like this :
So, when you multiply this with column vector ( vx, vy, vz, 1 ), fourth coordinate
would be
-a*vx - b*vy - c*vz + a*Lx + b*Ly + c*Lz,
or in the vector form :
n*L - n*v, hence n*( L - v ) .
What this telling us? If this dot poduct is negative, it means that the ray,
starting at L, and going through v, wouldn't hit the plane! More surprises!
That's all folks! Happy programming, and casting shadows!