Forum

Volumetric Stencil Shadows

Discuss programming topics that involve the OpenGL API.

Moderator: InsideQC Admins

Volumetric Stencil Shadows

Postby r00k » Tue Jan 20, 2015 11:15 pm

Ok so i was bored and finally got around to adding this after oh so many years ... (it's almost silly but..)

I followed Rich Whitehouse's tutorial, and he has it as

As I described above, this is reversing the face culling from the standard
method and changing the increment/decerement to when the depth test fails,
and simply keeping the value otherwise. Next go down to the function
GL_StencilShadowing. After this chunk of code:

while (g_numStencilEnts > 0)
{ //go through the list and do all the shadows
g_numStencilEnts--;
GL_StencilShadowModel(g_stencilEnts[g_numStencilEnts]);
}

We want to add:

glCullFace(GL_FRONT);
glDepthFunc(GL_LEQUAL);

And above that same chunk of code (the while (g_numStencil.. etc. line) we
want to add this:

glDepthFunc(GL_LESS);


but i had to do this to get it to actually work...
Code: Select all

   glStencilFunc(GL_ALWAYS, 0, 255);
   glDepthFunc(GL_LESS);

   while (g_numStencilEnts > 0)
   { //go through the list and do all the shadows
      g_numStencilEnts--;
      GL_StencilShadowModel(g_stencilEnts[g_numStencilEnts]);
   }

   glCullFace(GL_FRONT);
   glDepthFunc(GL_LEQUAL);

   glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );

   //draw a full screen rectangle now - wherever we draw
   //is where our "shadows" will actually be seen.
   glColor4f( 0.0f, 0.0f, 0.0f, 0.6f );

   glStencilFunc( GL_NOTEQUAL, 1, 255 );
   glStencilOp( GL_KEEP, GL_KEEP, GL_KEEP );


my real question is, does this infringe on that copyright i heard about that was the result of Carmack doing his reverse??

edit:
even the original version RwW had didnt work....
Code: Select all

   if (r_shadows.value == 2)
   { //> 2 is a debug feature to draw the shadows outside of the stencil buffer
      glEnable( GL_STENCIL_TEST );
      glColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE );
   }
   else
   {
      glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
      glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
   }

   glStencilFunc( GL_ALWAYS, 1, 0xFFFFFFFF );

   while (g_numStencilEnts > 0)
   { //go through the list and do all the shadows
      g_numStencilEnts--;
      GL_StencilShadowModel(g_stencilEnts[g_numStencilEnts]);
   }

   glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );

   //draw a full screen rectangle now - wherever we draw
   //is where our "shadows" will actually be seen.
   glColor4f( 0.0f, 0.0f, 0.0f, 0.6f );
   glStencilFunc( GL_NOTEQUAL, 0, 0xFFFFFFFF );

   glStencilOp( GL_KEEP, GL_KEEP, GL_KEEP );

   glEnable (GL_BLEND);
   glPushMatrix(); //save the current view matrix
r00k
 
Posts: 1108
Joined: Sat Nov 13, 2004 10:39 pm

Re: Volumetric Stencil Shadows

Postby Barnes » Wed Jan 21, 2015 10:08 am

I do not think it is worth to remember Creative pat now. You're not going to sell it? :)
stencil setup for z-fail volumes
Code: Select all
GL_StencilMask(255);
   GL_StencilFuncSeparate(GL_FRONT_AND_BACK, GL_ALWAYS, 128, 255);
   GL_StencilOpSeparate(GL_BACK, GL_KEEP, GL_INCR_WRAP_EXT, GL_KEEP);
   GL_StencilOpSeparate(GL_FRONT, GL_KEEP, GL_DECR_WRAP_EXT, GL_KEEP);

   GL_Disable(GL_CULL_FACE);
   qglDisable(GL_TEXTURE_2D);
   GL_DepthFunc(GL_LESS);
   GL_Enable(GL_POLYGON_OFFSET_FILL);
   GL_PolygonOffset(0.1, 1);
   GL_ColorMask(0, 0, 0, 0);

R_DrawShadowVolumes();

And for light pass (region in the shadow volume is masked)

Code: Select all
   GL_StencilFunc(GL_EQUAL, 128, 255);
   GL_StencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
   GL_StencilMask(0);
DrawLightMeshes();


If we need to draw masked area (full screen quad)

Code: Select all
GL_StencilFunc(GL_NOTEQUAL, 128, 255);
GL_StencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
GL_StencilMask(0);
GL_ColorMask(1, 1, 1, 1);

R_DrawFullScreenQuad();
User avatar
Barnes
 
Posts: 222
Joined: Thu Dec 24, 2009 2:26 pm
Location: Russia, Moscow

Re: Volumetric Stencil Shadows

Postby Spike » Wed Jan 21, 2015 12:49 pm

LordHavoc's research:
Terminology: Stencil Shadow Volume (sometimes called Stencil Shadows)
An extrusion of the lit faces, beginning at the original geometry and ending
further from the light source than the original geometry (presumably at least
as far as the light's radius, if the light has a radius at all), capped at
both front and back to avoid any problems (extrusion from dark faces also
works but has a different set of problems)

This is normally rendered using Carmack's Reverse technique, in which
backfaces behind zbuffer (zfail) increment the stencil, and frontfaces behind
zbuffer (zfail) decrement the stencil, the result is a stencil value of zero
where shadows did not intersect the visible geometry, suitable as a stencil
mask for rendering lighting everywhere but shadow.


And here's the interesting part:
In our case to hopefully avoid the Creative Labs patent, we draw the backfaces
as decrement and the frontfaces as increment, and we redefine the DepthFunc to
GL_LESS (the patent uses GL_GEQUAL) which causes zfail when behind surfaces
and zpass when infront (the patent draws where zpass with a GL_GEQUAL test),
additionally we clear stencil to 128 to avoid the need for the unclamped
incr/decr extension (not related to patent).

Patent warning:
This algorithm may be covered by Creative's patent (US Patent #6384822),
however that patent is quite specific about increment on backfaces and
decrement on frontfaces where zpass with GL_GEQUAL depth test, which is
opposite this implementation and partially opposite Carmack's Reverse paper
(which uses GL_LESS, but increments on backfaces and decrements on frontfaces).


The truth of this will of course only be decided once someone gets sued (quantum theory applies to law too, apparently).

Of course, if you really want to sidestep the patent, just go for shadow maps instead. They're annoying and have lots of precision issues, but they do at least have soft edges and are patent free. Shadowmaps don't need edge lists, and are thus easier on your VBOs (read: less cpu, less special-case C code).
In FTE, the r_shadows cvar just does circular blob shadows (basically just clipped decals under the various entities).
If you're just trying to do straight-down entity shadows without lighting, you can draw your model to a single-channel binary fbo and then use it as an alpha-mask on a projected texture (read: blob shadow code), and because its a projected texture, its easy to tweak the vertex colours to fade it out with distance, so you don't get quite so weird issues with lights being shadowed by something miles above with no lights above it. And yeah, you can just reuse the same VBO to draw to your model to the fbo instead of having to generate edge lists and other nonsense.
Spike
 
Posts: 2881
Joined: Fri Nov 05, 2004 3:12 am
Location: UK

Re: Volumetric Stencil Shadows

Postby Irritant » Wed Jan 21, 2015 3:10 pm

Yeah, what he said ^^ Forget stencil volumes, they are CPU heavy, and completely outdated visually.

There is a method to blur them however. It requires blitting the FB and sending it to a blur shader, then rendering it with the proper blending over your screen. It's actually quite visually accurate and impressive, but shadows at a distance are quite blurry, and it's also hell on performance. We used to have this code in CRX, but have since stripped it out and gone solely with shadowmapping. The performance and appearance is vastly improved, although in our current code there are still the occasional annoying artifacts. We are still in the process of cleaning it up and optimizing, but you can view the code here - it's quite simple really. http://svn.icculus.org/alienarena/trunk/source/ref_gl/

The files to look at are:

http://svn.icculus.org/*checkout*/alien ... xt%2Fplain
http://svn.icculus.org/*checkout*/alien ... xt%2Fplain

The gist of what occurs is that you render the caster that is going to cast a shadow on the bsp into the depth buffer, then switch back to the main framebuffer and re-render the nearby bsp surfaces that the shadow will be on(rendering the shadow onto white surfaces, and blending into the scene). Then, switch back to the depth buffer and render any casters that might cast a shadow on the original entity(using the original entity's camera perspective), then render the entity using the completed shadowmap. This method has very little overhead as long as you're using VBO. The result is you get shadows on the bsp, and self shadowing plus nearby caster shadowing on the entity. My next goal is adjusting the frustom and perspective of the depth buffer and camera to make more efficient use of the depth buffer, and possibly get some better resolution and performance.

Here is an example of what it looks like - pay no attention to the fps, these shots were taken on my laptop which generally has roughly half the fps of what I get on my NV560 card. However, that same scene, when using blurred stencil volumes was less that half the FPS that you see here ;)

Image
Image
http://red.planetarena.org - Alien Arena and the CRX engine
Irritant
 
Posts: 250
Joined: Mon May 19, 2008 2:54 pm
Location: Maryland

Re: Volumetric Stencil Shadows

Postby Barnes » Wed Jan 21, 2015 7:45 pm

Each technology has drawbacks - shadow volumes strongly hit the vertex processor, shadow maps to the pixel. In quake2 polygonal very low and we can use the shadow volumes. In doom3 Carmack also prefer shadow volumes. But if you look in the debugger, tri-call can be "scary". Q2dm1 - up to 25k opengl calls, and 50-55k tris (3k ambient and light pass). 52k its shadows...
John rightly said - you can use soft shadow volumes, but if we still have the shadow of the level, the load on the video card will be much stronger, because we have to blur the shadow with the depth map. And when we move quickly, you notice the difference "hard or soft shadow" very difficult)
User avatar
Barnes
 
Posts: 222
Joined: Thu Dec 24, 2009 2:26 pm
Location: Russia, Moscow


Return to OpenGL Programming

Who is online

Users browsing this forum: No registered users and 1 guest