tags:

views:

1966

answers:

3

I have two models, A and B, and one light, L. I would like model A to cast a shadow on model B. I don't want to bother with shadow volumes or proper shadows for the moment, just a simple circle shadow will suffice. The effect is that model A is treated as a sphere for shadow casting purposes.

Here is how I envision the algorithm:

For each triangle in model B, draw the triangle. Project a circle onto the triangle along the line from L to A, increasing the size of the circle depending on how far away the triangle is. Ensure the circle is clipped to the triangle's boundaries (using the stencil buffer in some way, I imagine).

I'm working with OpenGL and plain C.

Any pointers on some reference documentation I can read? Or implmentation ideas?

A: 

I think it is actually easier to implement correct shadows because OpenGL can do the work for you.

I found a working shadow code with lots of documentation here: http://www.opengl.org/resources/code/samples/mjktips/TexShadowReflectLight.html

The code above renders the object twice: first normally then with a special matrix. It does a lot of unrelated things such as control with mouse and reflections. So here are the interesting parts.

This calculates the shadow matrix:

/* Create a matrix that will project the desired shadow. */
void
shadowMatrix(GLfloat shadowMat[4][4],
  GLfloat groundplane[4],
  GLfloat lightpos[4])
{
  GLfloat dot;

  /* Find dot product between light position vector and ground plane normal. */
  dot = groundplane[X] * lightpos[X] +
    groundplane[Y] * lightpos[Y] +
    groundplane[Z] * lightpos[Z] +
    groundplane[W] * lightpos[W];

  shadowMat[0][0] = dot - lightpos[X] * groundplane[X];
  shadowMat[1][0] = 0.f - lightpos[X] * groundplane[Y];
  shadowMat[2][0] = 0.f - lightpos[X] * groundplane[Z];
  shadowMat[3][0] = 0.f - lightpos[X] * groundplane[W];

  shadowMat[X][1] = 0.f - lightpos[Y] * groundplane[X];
  shadowMat[1][1] = dot - lightpos[Y] * groundplane[Y];
  shadowMat[2][1] = 0.f - lightpos[Y] * groundplane[Z];
  shadowMat[3][1] = 0.f - lightpos[Y] * groundplane[W];

  shadowMat[X][2] = 0.f - lightpos[Z] * groundplane[X];
  shadowMat[1][2] = 0.f - lightpos[Z] * groundplane[Y];
  shadowMat[2][2] = dot - lightpos[Z] * groundplane[Z];
  shadowMat[3][2] = 0.f - lightpos[Z] * groundplane[W];

  shadowMat[X][3] = 0.f - lightpos[W] * groundplane[X];
  shadowMat[1][3] = 0.f - lightpos[W] * groundplane[Y];
  shadowMat[2][3] = 0.f - lightpos[W] * groundplane[Z];
  shadowMat[3][3] = dot - lightpos[W] * groundplane[W];

}

I do not pretend to understand this completely. lightpos is the position of the light source. The first 3 coordinates of groundplane are the normal vector of the ground surface. The fourth is the offset (how far is it from 0,0,0).

And this part actually renders the shadow:

glPushMatrix();
/* Project the shadow. */
glMultMatrixf((GLfloat *) floorShadow);
drawDinosaur();
glPopMatrix();

There are some things you need to glEnable/glDisable first for this to work so look at the link.

stribika
This just "flattens" the model onto a plane.. good for projecting a shadow onto a flat surface. The OP wants to render the shadow onto an arbitrarily-shaped 3d object.
Jim Buck
This one can supposedly do that: http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=27Unfortunately I can not compile it with gcc.
stribika
This method seems good, but the cost of drawing the source model once for each face in B seems high. Is there a way to reduce the complexity of this method?
Martin
I have settled (for the moment) for this method, iterated once for each triangle of model B, it seems to work, but the speed leaves something to be desired. Thank you!
Martin
A: 

This paper seems to cover your requirements, using OpenGL and hardware acceleration to create a detailed shadow map.

If I were trying to accomplish this, I would be tempted to use ray casting. For each triangle in B, create a vector from the triangle to the light. If it hits anything along the way, it is in shadow. This would be kind of slow unless you were using a decent acceleration structure and a fast triangle hit test. I like bounding volume hierarchies; many programs use them for collision detection as well.

R Ubben
A: 

Here's a simple approach, will work well with stationary objects. Make things simple...

http://nathan-space.blogspot.com

Nathan