Real Time Shadow With Multiple lights, new tutorial

Started by
22 comments, last by Tree Penguin 19 years, 8 months ago
For the carmack's reverse (the thing with the stencil shadow, its from carmack. There is an article about that on gamedev. Search for Carmack's Reverse) For the multi-pass technic I use to combine all the lights, I dont know if carmack made it like that, But It give the same result. There is a bunch of way to optimise it with shaders and multi-texturing.
Advertisement
For models you can map the silouettes and thus make only one volume rather then many by checking on the CPU for each face in the model if it is front facing or back facing from the light's perspective. Then go through all the edges and those that lie between two faces where one faces toward the light and one away form the silouette. Then just extrude the volume using only those edges. I'm sure you can optimise this better, but anyhow.
[s] [/s]
I can see the fnords.
Ya :) Silouhette determination, I mention that in the tutorial, but its not about that, I just wanted to explain how to compute the shadow ;)
Nice tutorial Daivuk - I skimmed through it and it seems to explain things quite well. I'll have to implement that some time..

It would have been nice with a little more on the actual creation of the shadow volume, because that's the trickiest part, I think.

One little question, about the first screenshot: If the light is in the center of the room, why is the face on the right pillar that is facing away from it lit? [grin]

Quote:Original post by Slaru
Is this the technique that ID used and Creative Labs sued over because they had patented this? Or is that something else to do with the shadows? Just what was it about the technique that Creative Labs had patented?

Yes, that's the one - "Carmack's reverse." The patent has been discussed quite a lot, so I won't say anything more about it here. Do a search, or look here (for example) if you want to find out more.
Nice, so thanks!
r+=7;
Quote:One little question, about the first screenshot: If the light is in the center of the room, why is the face on the right pillar that is facing away from it lit?

Thats because I forgot to make the test : If the face is facing the light. So All the faces receive lighting. With the shadow hidding it, thats dont make any difference, but I'm computing lighting here for nothing, so : Thank to show me up! lol, I will increase my frame rate. :P
How about some source, or a demo?
Quote:How about some source, or a demo?

I put some sources at the end of the tutorial, more about what opengl functions to call in what order.
That can be a good idea to put the little demo I made for this tutorial (but not the source, its about 23 classes, that will not help).
Great tutorial, two thumbs up :).

Now have you tried your tutorial with more complex models?
I would think not since using that code along with a more tesselated mesh with a lot of round areas will result in a not-so pleasing visuals.

Here's how things can be improved:

First of all we render the scene to the color and depth buffer with an ambient shade/color that is independant of all light sources in the scene. We also use the models diffuse texture maps to enhance the attenuation when all rendering passes are completed.

  //Start ambient pass  activateNTextures(&sceneGroupParent, 1);  glPushAttrib(GL_ENABLE_BIT);  glColor3f(0.1f, 0.1f, 0.1f);  triangleCount +=sceneGroupParent.render(RENDER_TEXTURES |ENABLE_FRUSTUM_CULLING);   glPopAttrib();  glColor3f(1,1,1);  activateNTextures(&sceneGroupParent, MAX_TEXTURE_UNITS);   //End ambient pass


Then we do everything you described in your shadowing passes with textures on as well as all the shaders/special effects, but definitely NO ambient since we already made use of it in the first pass.
We can also reduce the amount of geometry sent to the hardware by using vendor specific stencil functions.

       if(renderPath & NV_SHADOW_PASS || renderPath & ATI_SHADOW_PASS){        glDisable(GL_CULL_FACE);        if(renderPath & ATI_SHADOW_PASS){          glStencilFuncSeparateATI(GL_ALWAYS, GL_ALWAYS, 0, ~0);          if(needZFail){            glStencilOpSeparateATI(GL_FRONT, GL_KEEP, GL_DECR_WRAP_EXT, GL_KEEP);            glStencilOpSeparateATI(GL_BACK,  GL_KEEP, GL_INCR_WRAP_EXT, GL_KEEP);          }          else          {            glStencilOpSeparateATI(GL_FRONT, GL_KEEP, GL_KEEP, GL_INCR_WRAP_EXT);            glStencilOpSeparateATI(GL_BACK,  GL_KEEP, GL_KEEP, GL_DECR_WRAP_EXT);          }         }        if(renderPath & NV_SHADOW_PASS){          if(needZFail){            glActiveStencilFaceEXT(GL_BACK);            glStencilFunc(GL_ALWAYS, 0, ~0);            glStencilOp(GL_KEEP, GL_INCR_WRAP_EXT, GL_KEEP);            glActiveStencilFaceEXT(GL_FRONT);            glStencilFunc(GL_ALWAYS, 0, ~0);            glStencilOp(GL_KEEP, GL_DECR_WRAP_EXT, GL_KEEP);          }          else          {            glActiveStencilFaceEXT(GL_FRONT);            glStencilFunc(GL_ALWAYS, 0, ~0);            glStencilOp(GL_KEEP, GL_KEEP, GL_INCR_WRAP_EXT);            glActiveStencilFaceEXT(GL_BACK);            glStencilFunc(GL_ALWAYS, 0, ~0);            glStencilOp(GL_KEEP, GL_KEEP, GL_DECR_WRAP_EXT);               }           glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);        }      }      else      {        if(needZFail){          glStencilOp(GL_KEEP, GL_INCR, GL_KEEP);          glCullFace(GL_FRONT);          shapes-&gt;doShadowPass(lightPosObjSpace, needZFail);<br>          glStencilOp(GL_KEEP, GL_DECR, GL_KEEP);<br>          glCullFace(GL_BACK);   <br>        }<br>        <span class="cpp-keyword">else</span><br>        {<br>          glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);<br>          glCullFace(GL_BACK);<br>          shapes-&gt;doShadowPass(lightPosObjSpace, needZFail);<br>          glStencilOp(GL_KEEP, GL_KEEP, GL_DECR);<br>          glCullFace(GL_FRONT);  <br>        }<br>      }<br>      shapes-&gt;doShadowPass(lightPosObjSpace, needZFail);<br>    }<br>  }<br><br><br><br></pre></div><!–ENDSCRIPT–><br><br>No need for any other passes :)<br><br><img border="0" src="http://www.realityflux.com/abba/Pictures/4Lights.JPG" width="800" height="600"><br><br><!–EDIT–><span class=editedby><!–/EDIT–>[Edited by - JavaCoolDude on August 22, 2004 4:37:57 AM]<!–EDIT–></span><!–/EDIT–>
Daivuk, you lighting model is flawed. Because you accumulate all the light intensities together and only modulate by your texture once at the end you'll loose a whole load of precision and won't get proper overbright behaviour. You need to do a texture modulation after every light pass.

This topic is closed to new replies.

Advertisement