Working on cam in shadow vol problem...

I think I may have a solution for the “is the camera in the shadow volume?” problem, but I want to bat it around here before I really spend much time on it.
Reasons:

  1. if it works, ppl might want to know about it
  2. if it doesnt work, I dont want to spend much time on it if somebody has already tried

OK, a little background. What I do is I cast rays from the object’s edge, away from the light (as shadows do, Im told). From there, I draw into the stencil buffer a number of quad strips or triangle strips that define the shadow volume. Prolly everybody here does that.

Now, the trick. When I cast each ray while drawing, I find the point where it intersects the near plane, if it does at all. From there, I draw a poly that’s just a hair forward of the near plane. That should be done on its own stencil pass, with culling turned off and the stencil incrementing (if that’s how you do your shadows). Really, I dont care if it is in front of the camera. If I am inside the shadow volume and am looking towards where the shadow casts, that poly should just “happen” in front of the camera.

OK, I found that there’s a little catch… if the near plane passes thru one “shadow ray” and not the next, a point needs to be plotted in the “near plane poly” where the shadow volume passes out through the plane. Otherwise, you’ll get a point or two, but not a full polygon (and certainly not the poly we want there)

Just wondering, why not use the depth-fail approach? It works exactly the same when the camera is inside a volume as it does when the camera is outside the volume

147-2: isn’t what you’re describing “near capping” for shadow volumes ? I think it’s been known for ages… requires a lot of CPU work, but i’m wondering if it wouldn’t work with a vertex shader. By passing the near plane equation into a constant, and doing the ray/plane intersection in the vertex shader, then offsetting the result by a small value towards the view direction… has anybody tried that?

DopeFish: Depth-fail requires that you cap the shadow volume, so it generates more polygons and fillrate. It makes sense to use Depth-pass whenever possible (ie. when you’re not inside the shadow volume).

Y.

If i uderstand right, you want to cap sv on camera’s near plane? I got the same idea but then i learn that someone got it before me I think i saw it on nVidia’s site, document called StencilShadows_CEDEC_E2.pdf
Read it!

Yeah, I guess it is… I have read a lot about shadow volumes, but for some odd reason haven’t read anything about near capping… Capping was mentioned in one “tutorial” I read which was put out by SGI, but that tutorial was terribly fungled. The program worked, but the code was about three to eight times as long as it needed to be.

Lemme try the stencil method that you mentioned… depth fail capping… gotta remember that. Hmmmmm… gotta do that before rendering the scene for the actual shadow vol placement, eh?

OK, I’ll read up on that nVidia site document.

OK, I read that document, the entire thing this time and I have a question or two. Now I understand that to cap the near plane one should use that modified projection matrix to produce a “shelf” on the near plane, then render the mesh projected from the light.

Now one thing I don’t understand, if you’re gonna play around with matricies, why not go all the way and see if you can come up with a matrix that will allow you to project the mesh as required, instead of doing all of the projection math, then sending it thru? If one were to look into this fully, maybe, just maybe there’s a really killer optimization for you.

I’ll investigate.

I think you want to explore the infinite shadow volumes approach.

Don’t just stop at the CEDEC slides. Mark Kilgard would want you to read about the subsequent work.

Cass

Unfortunately, matrices can’t do everything by themselfs; problem arrise whith calculus precision… Since I’m mathematician, from my point of view it’s rather sad…
When you pass vertex to modelview matrix that projects on znear plane, you can never be shore that it will actualy hit it! And if it is slightely nearer to the “eye” you can’t see it, i.e. it wouldn’t be rasterized.

BTW, about the depth fail algorithm… I’ve got my z-pass algorithm working, it obviously brakes when entering a shadow volume. So I had a look at the z-fail algorithm. couldn’t get it working, so I drew the algoritm on paper just to see. And it looks like it’s flawed :\

ok, here we go…

first shadow volume pass.

glCullFace(GL_FRONT); // draw back facing quads
glStencilOp(GL_KEEP, GL_INCR, GL_KEEP);

      .
     /.\
    / . \ 
   /  .  \ 
  /   .   \ 
 / +1 . +1 \
/     .     \

.------±-----.
| | |
| 0 | 0 |
| | |
|||____
| | |
| 0 | 0 |
| . |
| /.\ |
| / . \ |
| / . \ |
| / . \ |
| / +1 . +1 \ |
|/ . |
. . .
. . .
. . .
. . .
. . .
. . .
v v v

Second shadow volume pass

glCullFace(GL_BACK);
glStencilOp(GL_KEEP, GL_DECR, GL_KEEP);

      .
     / \
    /   \ 
   /     \ 
  /       \ 
 /         \
/           \

.-------------.
| |
| 0 0 |
| |
|___|
| |
| 0 0 |
| |
| |
| |
| |
| |
| |
| |
.-------------.
. .
. -1 -1 .
. .
. .
. .
v v

result in stencil buffer

      .
     /.\
    / . \ 
   /  .  \ 
  /   .   \ 
 /  1 . 1  \
/     .     \

.------±-----.
| | |
| 0 | 0 |
| | |
|||____
| | |
| 0 | 0 |
| . |
| /.\ |
| / . \ |
| / . \ |
| / . \ |
| / 1 . 1 \ |
|/ . |
.----- .------.
. . .
. 0 . 0 .
. . .
. . .
. . .
v v v

and we draw the scene with lights and the stencil function…
glStencilFunc(GL_EQUAL, 0, 0xffffffff);
or, in my case, I draw a full screen transparent overlay to darken things, and use…
glStencilFunc(GL_NOTEQUAL, 0, 0xffffffff);
which falls down to the same thing (at least in z-pass algorithm).

As you can see in the picture above, the triangle shadow itself.
To overcome this, I have to make the back plane also cast a shadow, in this case we get…

      .
     /.\
    / . \ 
   /  .  \ 
  /   .   \ 
 /  1 . 1  \
/     .     \

.------±-----.
| | |
| 0 | 0 |
| | |
|||_____
. | | | .
. 1| 1 | 1 | 1 .
. | . | .
. | /.\ | .
. | / . \ | .
. | / . \ | .
. | / . \ | .
. | / 2 . 2 \ | .
. |/ . | .
. |----- .------| .
. | . | .
.1 | 1 . 1 | 1 .
. | . | .
. | . | .
. | . | .
v v v v v

and then
glStencilFunc(GL_LEQUAL, 1, 0xffffffff);
or, in my case, I draw a full screen transparent overlay to darken things, and use…
glStencilFunc(GL_Greater, 1, 0xffffffff);

Then, unlike Depth pass, it is a requirement to have all your surfaces casting shadows?

Sooo… What Did I fell to understand?

[This message has been edited by oliii (edited 03-01-2003).]

[This message has been edited by oliii (edited 03-01-2003).]

Originally posted by oliii:
in my case, I draw a full screen transparent overlay to darken things

Thats not really the best way to handle things. It wont work with multiple lights correctly, lights wont brighten up shadows cast by other lights, and it looks horrible wrong.

Try drawing your world entirely shadowed first, then, for each light, mark out shadowed regions, and then redraw non-shadowed regions. Looks a lot better imho, especially when using per-pixel lighting.

I did this to try things out. Cheap and nasty, but I just try to get the basics working and get a good understanding of the stencil operations and requirements. As a matter of facts, I think I now what’s wrong. I use ‘open’ geometry. Like a single triangle. Apparently, to use Karmacks algorithm, you need “2-manifold” geometry. Which I guess would mean a closed geometry, without cracks. Am I right?

going back to quality issues, I guess the best solution would be to consider how lighting works in the real world. You first render the geometry with ambient only, to fill the z buffer. Then you render your shadow volumes, and finally render diffuse and specular components of the geometry while checking for stencil values.

[This message has been edited by oliii (edited 03-01-2003).]

another example

              X
               \       ___________________
                \     .\                 /.
                 \    . \_______________/ .
       stencil=1  \   .   ___             .
               ____*__.__/   \            .
              .\    _________/.           .
              . \__| \        .           .
              .       * dec   .           .
              .       .\      .           .
              .       . \     .           .
              .       .  \    .           .
              .       .   \   .           .
              .       .    \  .           .
              .       .     \ .           .
              .       .      \.           .
              .       .       * inc       .
              .       .       .\          .
              .       .       . \         .
              .       .       .  \        .
              .       .       .   \       .
              .       .       .    \      .
                      .       .     \     .
                              .      \    .
                              .       \   .
                              .        \  .
                                        \ .
                                         \.
                                          * inc
                                          .\
                                          . \
                                          .  \

on this example, you can clearly see that the pixels in the light are the one with stencil=1 or stencil=0.

another example

                    X
          stencil=2  \ ___________________
                      \\                 /.
                      .\\_______________/ .
                      . \ ___             .
               _______.__*   \            .
              .\    __.___\__/.           .
              . \__|  .    \  .           .
              .       .     \ .           .
              .       .      \.           .
              .       .       * inc       .
              .       .       .\          .
              .       .       . \         .
              .       .       .  \        .
              .       .       .   \       .
              .       .       .    \      .
              .       .       .     \     .  
              .       .       .      \    .
                      .       .       \   .
                              .        \  .
                              .         \ .
                              .          \.
                                          * inc
                                          .\
                                          . \
                                          .  \

there, the pixels in shadow have stencil=2. But on all the docs, they still use the normal test. “Pixels are in shadow when stencil >= 1”, which is wrong. Pixels are in shadows when stencil>1.

[This message has been edited by oliii (edited 03-01-2003).]

[This message has been edited by oliii (edited 03-01-2003).]

To use the zfail method, you need to cap yourvolumes at infinity and on the face. So, where you have *s where the lines intersect the faces, you should have another decrement.

right… So you’d add the front faces of the model into the shadow volume (with glDepthest(GL_LEQUAL), and probably some polygon offset too), and send the back faces of the model to infinity. Now it starts to make sense. I understand why it is so fill rate intensive compared to the Z-pass. Jeez, two times the rendering + the shadow caping.

Thanks a lot for that.

[This message has been edited by oliii (edited 03-01-2003).]

Woohoo! Got it working. With proper infinite projection matrix, infinite quads, capping, and all. Thanks for your time guys.

If you are interested in the full z-fail algorithm, this doc explains it all. with pseudo code too. It wraps up everything, in a very uncomplicated way. Wish I found that earlier.
http://developer.nvidia.com/docs/IO/2585/ATT/RobustShadowVolumes.pdf

[This message has been edited by oliii (edited 03-01-2003).]

OK, here’s what I did. I did the infinite thing, capped it and all. I used Carmack’s Reverse, and I’ll tell you why. I assume that the camera is going to move often enuf not to warrant creating a display list containing the near plane shadow. So, why deal with it. Carmacks works great if both ends are capped, which is really easy when you consider that all the data can go into a display list. Once I got everything together, I came out with a pretty fast shadow algorithm.

Thanx for the assistance.