3D Shadows
DanielH

I was playing SpongeBob's Battle for Bikini Bottom. Make fun of me, it's ok.

I noticed something I didn't think about before.

They figure where SpongeBob is and they place the shadow on the first polygon's that are straight down from a position above him. So If there is nothing above him then the shadows are under him as it should be. But when he walks under an umbrella, the shadows are on top of the umbrella.

Is this normal in games?
Do they do this for speed?

Thoughts please. Not just 'Yes'. ;)

I'm curious because My 3D game I'm working on could use shadows.

Kitty Cat
Quote:

Is this normal in games?
Do they do this for speed?

No. Yes.
;)

I don't know what kind of game that is, so I can't really guess at the technique they're using (it's not one I've played with, at least).

Today, shadows are mostly done using shadow mapping. That's where you take a snapshot of the scene from the light's POV, getting the depth information, then using that when drawing the scene from the camera's POV, and any pixel that's farther from the light source than what's in the previously rendered depth texture, is in shadow. I personally don't like this method since it has a lot of aliasing, and it's not trivial to remove that aliasing, as well as having trouble with point lights (lights that shine out in every direction; which is pretty much every one). It is, however, fairly quick depending on the size of the depth texture.

Another technique used is shadow volumes (as seen Doom3, Quake4, etc). Those basically take the shadow casters, find the polygon edges between what's facing a light and what's facing away, and build a closed volume from the object to infinity. Using a stencil buffer, you can determine which opaque pixels are inside the volume, and shade accordingly. I prefer this method, even though it's a bit harder on the processor/card, because it works perfectly with point lights, and doesn't suffer from the same aliasing issues. It is, however, much harder to remove the hard edges.

kikabo

In Spongebob because not all objects cast a shadow and because of these glitches it's likely that the game is using planar shadows. Each object that casts a shadow probably is projected into a texture and then that texture is alpha blended onto the object in shadow. Each vertices x,z coords in the shadowed object would correspond to the light occluder's shadow texture coords (plus the difference in object position).

The glitches are because it is working on an object by object basis and not polygon by polygon. When there are two shadow casters there has to be some logic to work out which object is shadowing which, it could be comparing centers, min y values etc but obviously in this case it is doing something wrong.

This method is limited pretty much to shadows formed by parallel light projecting directly down but it's advantage is that the shadows can be drawn in one pass with no special hardware requirements.

I use this technique and it work pretty well, the other down side is you don't have time to find Patric's last damn 20 socks for those last two spatulas! ;D

DanielH

I've given up on the socks. It's just too damn hard.

Arthur Kalliokoski

I'm starting to fiddle with shadows in a car racing game, due to 4e6 vertices in the heightfield I don't want to do the two pass stencil thing. Complex objects such as cars will have a simple shape (like a close fitting collision box) to cast a shadow volume, and there's a vector opposite the light direction. If all three vectors from a shadow volume polygon hit the same ground polygon, it just draws a dark alpha polygon slightly above the ground (0.0001 height), else it has to check ground vertices being within the shadow volume and draw dark triangles accordingly.

Simply drawing a shadow directly underneath a car wouldn't look right with the texture already having shadows drawn on it that clearly indicate a low sun angle. Oh, yeah, the car shadow thing has to check if it's in a hillside shadow as well. It's getting complicated. I really should see if I can do a texture that has "feathering" at the edges for penumbra too.

kikabo
Quote:

it just draws a dark alpha polygon slightly above the ground (0.0001 height)

If your worried about z-fighting (I think that's the term), you can do it this way (although the results are pretty much the same).

      glEnable( GL_POLYGON_OFFSET_FILL );
      glPolygonOffset( -0.5f, -0.5f );

      DrawShadow();

      glPolygonOffset( 0.0f, 0.0f );
      glDisable( GL_POLYGON_OFFSET_FILL );

Arthur Kalliokoski

I tried the polygon offset thing and it didn't seem to make any difference for polygons, I got the impression it was only to make sure GL_LINES and GL_POINTS didn't get buried beneath polygons since the line code & polygon rasterizer worked differently...

kikabo

Here's an example where two polygons are drawn at the same depth, press spacebar to change the pollygon offsets.

1#include <allegro.h>
2#include <alleggl.h>
3 
4void InitGL()
5{
6 allegro_init();
7 install_allegro_gl();
8 install_keyboard();
9 
10 set_color_depth (32);
11 allegro_gl_clear_settings();
12 allegro_gl_set(AGL_COLOR_DEPTH, 32);
13 allegro_gl_set(AGL_Z_DEPTH, 8);
14 allegro_gl_set(AGL_WINDOWED, TRUE);
15 allegro_gl_set(AGL_SUGGEST, AGL_COLOR_DEPTH | AGL_Z_DEPTH | AGL_WINDOWED);
16 if (set_gfx_mode(GFX_OPENGL, 640, 480, 0, 0) < 0)
17 {
18 allegro_message ("Error setting OpenGL graphics mode:\n%s\nAllegro GL error : %s\n", allegro_error, allegro_gl_error);
19 remove_allegro_gl();
20 exit(0);
21 }
22 glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
23 glClearDepth(1.0f);
24 glEnable(GL_DEPTH_TEST);
25 glDepthFunc(GL_LEQUAL);
26}
27 
28void Draw(GLvoid)
29{
30 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
31 glLoadIdentity();
32 
33 glEnable( GL_POLYGON_OFFSET_FILL );
34 
35 if(key[KEY_SPACE])
36 glPolygonOffset( 0.0f, 0.0f );
37 else
38 glPolygonOffset( 1.0f, 1.0f );
39 
40 glBegin(GL_TRIANGLES);
41 glColor3f(1.0f,0.0f,0.0f); glVertex3f( 0.0f, 1.0f, 0.0f);
42 glColor3f(0.0f,1.0f,0.0f); glVertex3f(-1.0f,-1.0f, 0.0f);
43 glColor3f(0.0f,0.0f,1.0f); glVertex3f( 1.0f,-1.0f, 0.0f);
44 glEnd();
45 
46 glColor3f(0.5f,0.5f,1.0f);
47 
48 if(key[KEY_SPACE])
49 glPolygonOffset( 1.0f, 1.0f );
50 else
51 glPolygonOffset( 0.0f, 0.0f );
52 
53 glBegin(GL_QUADS);
54 glVertex3f(-0.8f, 0.8f, 0.0f);
55 glVertex3f( 0.8f, 0.8f, 0.0f);
56 glVertex3f( 0.8f,-0.8f, 0.0f);
57 glVertex3f(-0.8f,-0.8f, 0.0f);
58 glEnd();
59 
60 glDisable( GL_POLYGON_OFFSET_FILL );
61}
62 
63int main()
64{
65 InitGL();
66 
67 while (!key[KEY_ESC])
68 {
69 Draw();
70 allegro_gl_flip();
71 }
72 return 0;
73}
74END_OF_MAIN();

Arthur Kalliokoski

Well, that takes care of "learn something new every day" today! Thanks Kikabo!

Thread #588497. Printed from Allegro.cc