I am not clear why sometimes choose some specific bits of the stencil buffer to do stencil test. I cannot find examples like only test 1,3,5 bits of one stencil buffer.
The reason is not especially interesting. The stencil buffer usually contains 8 bits per sample, and you're free to use those 8 bits however you like in your application. So the meaning of those bits is up to you.
Often they're used for doing volume intersection tests, such as shadow volumes for stencil shadows (a technique popular circa 2005), where you might use the stencil buffer as a counter. Another example is deferred lighting, where you use a single bit in the stencil buffer to track which pixels are affected by a particular light.
So if you store "this pixel is affected by light #3" in bit 1, then you test bit 1 when you're rendering light #3. It's all up to the application developer.
Related
Me and a friend have been having an ongoing argument about the stencil buffer. In short I haven't been able to find a situation where the stencil buffer would provide any advantage over the programmable pipeline tools in OpenGL 3.2+. Are there any uses to the stencil buffer in modern OpenGL?
[EDIT]
Thanks everyone for all the inputs on the subject.
It is more useful than ever since you can sample stencil index textures from fragment shaders. It should not even be argued that the stencil buffer is not part of the programmable pipeline.
The depth buffer is used for simple pass/fail fragment rejection, which the stencil buffer can also do as suggested in comments. However, the stencil buffer can also accumulate information about test results over multiple passes. All sorts of logic and counting applications exist such as measuring a scene's depth complexity, constructive solid geometry, etc.
To add a recent example to Andon's answer, GTA V uses the stencil buffer kinda like an ID buffer to mark the player character, cars, vegetation etc.
It subsequently uses the stencil buffer to e.g. apply subsurface scattering only to the character or exclude him from motion blur.
See the GTA V Graphics Study (highly recommended, it's a great read!)
Edit: sure you can do this in software. But you can do rasterization or tessellation in software just as well... In the end it's about performance I guess. With depth24stencil8 you have a nice hardware-supported format, and the stencil test is most likely faster then doing discards in the fragment shader.
Just to provide one other use case, shadow volumes (aka "stencil shadows") are still very relevant: https://en.wikipedia.org/wiki/Shadow_volume
They're useful for indoor scenes where shadows are supposed to be pixel perfect, and you're less likely to have alpha-tested foliage messing up the extruded shadow volumes.
It's true that shadow maps are more common, but I suspect that stencil shadows will have a comeback once the brain dead Createive/3DLabs patent expires on the zfail method.
I would like to acquire a stencil buffer, but not suffer the overhead of an attached depth buffer if it's possible, since I wouldn't be using it. Most of the resources I've found suggest that while the stencil buffer is optional (excluding it in favour of gaining more depth buffer precision, for example) I have not seen any code that requests and successfully gets only the 8-bit stencil buffer. The most common configuration I've seen being 24 bit depth buffers with an 8 bit stencil buffer.
Is it possible to request only a stencil buffer with a color buffer?
If it is possible, Is it likely the request would be granted by most OpenGL implementations?
The OpenGL version I'm using is 2.0
edit:
The API I'm using to call OpenGL is SFML, which normally doesn't support stencil allocation for it's FBO wrapper objects, though it allows it for the display surface's framebuffer. I edited the functionality in myself, though that's where I'm stuck.
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT, width, height));
This line decides the storage type I assume. However, GL_DEPTH24_STENCIL8_EXT is the only define I've found that specifies a stencil buffer's creation. (there's no GL_STENCIL8 or anything similar at least)
Researching GL_STENCIL_INDEX8 that was mentioned in the comments, I came across the following line in the the official OpenGL wiki, http://www.opengl.org/wiki/Framebuffer_Object_Examples#Stencil
NEVER EVER MAKE A STENCIL buffer. All GPUs and all drivers do not support an independent stencil buffer. If you need a stencil buffer, then you need to make a Depth=24, Stencil=8 buffer, also called D24S8.
Stress testing the two different allocation schemes, GL_STENCIL_INDEX8_EXT vs GL_DEPTH24_STENCIL8_EXT, the results were roughly equal, both in terms of memory usage and performance. I suspect that it padded the stencil buffer with 24bits anyway. So for sake of portability, going to just use the depth and stencil packed scheme.
according to the books that i've read stencil test is achieved by comparing a reference value with that of the stencil buffer corresponding to a pixel, how ever in one of the books it states that:
A mask is bitwise AND-ed with the value in the stencil planes and with the reference value before the comparison is applied
here i see a third parameter which is the mask, is this a mask related to the stencil buffer or it is another parameter generated by openGL itself??
can someone explain the comparison process and the values that have a role in this process??
glStencilMask (...) is used to enable or disable writing to individual bits in the stencil buffer. To make the number of parameters manageable and accommodate stencil buffers of varying bit-depth, it takes a GLuint instead of individual GLbooleans like glColorMask (...) and glDepthMask (...).
Typically the stencil buffer is 8-bits wide, though it need not be. The default stencil mask is such that every bit-plane is enabled. In an 8-bit stencil buffer, this means the default mask is 0xff (11111111b). Additionally, stenciling can be done separately for front/back facing polygons in OpenGL 2.0+, so there are technically two stencil masks.
In your question, you are likely referring to glStencilFunc (...), which also has a mask. This mask is not associated with the stencil buffer itself, but with the actual stencil test. The principle is the same, however; the above link details how this mask is AND'd together with the ref. value during testing.
A mask is an optional extra that sits between what is rendered and what it sent to be rendered.
Imagine you have a scene being rendered and you suddenly decide that you don't want any red being used by a certain object. You can use the mask to apply a bitwise operation to every pixel that object affects to remove the red values.
r:150 b:50 g:47 becomes r:0 b:50 g:47
r:13 b:255 g:255 becomes r:0 b:255 g:255
etc.
http://www.opengl.org/sdk/docs/man3/xhtml/glColorMask.xml should help explain it a bit more.
I'm not sure if this is possible to do, but it's worth a shot. I'm using the stencil buffer to reduce overdraw for light volumes in a deferred renderer using this algorithm (when the camera is outside the volume):
Using a cheap shader, draw back faces with depth testing set to LEQUAL, marking them in the stencil buffer.
Using the expensive lighting shader, draw front faces with depth testing set to GEQUAL.
This will cause only pixels within the light volume to be shaded. The problem with this comes when drawing multiple lights. First, since state changes are expensive, it's probably not the best idea to repeatedly switch between the cheap and expensive shader for each light. Ideally I'd like to take advantage of all 8 bits of the stencil buffer by rendering 8 light volumes with the cheap shader followed by 8 light volumes with the expensive shader. However, issues arise when lights overlap, as there's no way to tell which pixels belong to which lights.
The solution that comes to mind would be to use 1 bit in the stencil buffer per light. So, for light n, mark the nth bit in the stencil buffer in the cheap pass, then only render pixels with that bit on during the expensive pass.
I haven't used the stencil buffer before, but from what I'm reading this doesn't seem possible. For this to work I'd have to set the stencil buffer using bitwise OR and the stencil function would have to be bitwise AND. However, the only operations on the stencil buffer I can see are: KEEP, ZERO, REPLACE, INCR, DECR, and INVERT, and the only functions are: NEVER, ALWAYS, LESS, EQUAL, LEQUAL, GEQUAL, GREATER, and NOTEQUAL.
Is there any way to somehow get this OR and ANDing behavior using the stencil buffer? And if not, is there an alternative approach to efficiently rendering light volumes?
To get ORing update behavior, use glStencilMask combined with GL_REPLACE. To get ANDing test behavior, use the glStencilFunc mask parameter combined with GL_EQUAL. In both cases, you'll want the ref parameter to glStencilFunc to be 0xff.
I'm not sure if this is possible to do, but it's worth a shot. I'm using the stencil buffer to reduce overdraw for light volumes in a deferred renderer using this algorithm (when the camera is outside the volume):
Using a cheap shader, draw back faces with depth testing set to LEQUAL, marking them in the stencil buffer.
Using the expensive lighting shader, draw front faces with depth testing set to GEQUAL.
This will cause only pixels within the light volume to be shaded. The problem with this comes when drawing multiple lights. First, since state changes are expensive, it's probably not the best idea to repeatedly switch between the cheap and expensive shader for each light. Ideally I'd like to take advantage of all 8 bits of the stencil buffer by rendering 8 light volumes with the cheap shader followed by 8 light volumes with the expensive shader. However, issues arise when lights overlap, as there's no way to tell which pixels belong to which lights.
The solution that comes to mind would be to use 1 bit in the stencil buffer per light. So, for light n, mark the nth bit in the stencil buffer in the cheap pass, then only render pixels with that bit on during the expensive pass.
I haven't used the stencil buffer before, but from what I'm reading this doesn't seem possible. For this to work I'd have to set the stencil buffer using bitwise OR and the stencil function would have to be bitwise AND. However, the only operations on the stencil buffer I can see are: KEEP, ZERO, REPLACE, INCR, DECR, and INVERT, and the only functions are: NEVER, ALWAYS, LESS, EQUAL, LEQUAL, GEQUAL, GREATER, and NOTEQUAL.
Is there any way to somehow get this OR and ANDing behavior using the stencil buffer? And if not, is there an alternative approach to efficiently rendering light volumes?
To get ORing update behavior, use glStencilMask combined with GL_REPLACE. To get ANDing test behavior, use the glStencilFunc mask parameter combined with GL_EQUAL. In both cases, you'll want the ref parameter to glStencilFunc to be 0xff.