14

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?

Martin
  • 5,945
  • 7
  • 50
  • 77

2 Answers2

8

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
  • 3,146
  • 2
  • 23
  • 21
  • 4
    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 Jul 12 '09 at 00:14
  • This one can supposedly do that: http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=27 Unfortunately I can not compile it with gcc. – stribika Jul 12 '09 at 00:37
  • 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 Jul 12 '09 at 15:26
  • 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 Jul 12 '09 at 22:48
  • Here's a working link to at least the full code: http://www.cs.uiuc.edu/class/sp05/cs419/accum/softshadow.c – andy Jun 01 '12 at 07:20
  • I recommend this (working) code for shadows of arbitrary objects cast onto arbitrary objects: http://www.opengl.org/archives/resources/code/samples/mjktips/rts/index.html – Jose Luis Blanco Nov 07 '13 at 16:11
  • This is a useful tutorial which shows how to map the shadow to arbitraty objects by comparing their distance with the blocking object's distance (no raycasting required, just a simple shadowmap render pass): http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-16-shadow-mapping/ – DankMemes Mar 07 '14 at 20:12
-1

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
  • 2,225
  • 16
  • 8