Jump to content
  • Advertisement
Sign in to follow this  

Stencil Buffer - incrementing and decrementing

This topic is 4228 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I've been studying how to use stencil buffers these days and I think I got it. But I still have one question: what does really happen when you increment or decrement the value in a pixel at the stencil buffer?! I did some tests in the Shadow Volume sample(DirectX8 :)) modifying the values. First, it renders the front face of the shadow volume mesh in the stencil buffer. It increments the value at the pixels where the depth test succeeds, OK? Initially the stencil value at every pixel is 0, and after increment it will be 1 OK?! Continuing... Then, it renders the back face of the shadow in the stencil buffer. Now, it decrements the stencil of the pixels which pass the depth test. Then, some pixels that were incremented in the previous step get a value 0 and the pixels that had a value 0(some of the ones not incremented previously) will get the maximum value of the stencil buffer(255 maybe =/), OK? The doubt comes due to this: I set the D3DRS_STENCILREF value to 2, set the D3DRS_STENCILFUNC to D3DCMPFUNC_EQUAL and set D3DRS_STENCILPASS to D3DSTENCILOP_KEEP. It means every pixel where the stencil value is equal to 2 will be drawn(mask and write mask are 0xffffffff). And finally it renders the shadow square(which fill the entire screen) and some 'parts' of the square are rendered.Why?!? I just incremented/decremented the stencil of each pixel only one or two times. Then, the pixel at the stencil buffer should have one of these 3 values: 0, 1, or the maximum stencil value. Shouldn't it? When I use others values like 3 or 6 or 7 for the ref value some pixels get rendered too. I'm too confused =/. Any help is very appreciated! Thanks guys . . . :D

Share this post

Link to post
Share on other sites
I believe you also have to tell the renderer what you want to do when the stencil test fails and when the depth buffer test fails, with D3DRS_STENCILFAIL and D3DRS_STENCILZFAIL. If you leave these parameters undefined, you might get unexpected results.

I learned to use the stencil increment/decrement functionality to render mirrors in my portal engine. Every new mirror depth (mirror in mirror) would increment the stencil up by 1 and decrement it back down when the rendering was finished. It was quite handy.

As for your question about what it does: when the stencil test passes and the stencil operation is increment, it increases the value at that pixel location by 1. Decrement decreases it by 1, as expected. So if the entire stencil buffer is 0, and you render a polygon with stencil increment, every corresponding stencil pixel in the polygon will be increased by 1. If you then set a stencil ref of 1 and render another polygon, it will only appear in the same pixels where you drew the first one.

Share this post

Link to post
Share on other sites
Thanks for the fast response. I forgot to mention that I set the D3DRS_STENCILFAIL to D3DSTENCILOP_KEEP, D3DRS_STENCILZFAIL to D3DSTENCILOP_KEEP and D3DRS_STENCILPASS to D3DSTENCILOP_INCR when rendering the front face of the shadow volume and D3DSTENCILOP_DECR when rendering the back face of the shadow volume. When I render the big square I set D3DRS_STENCILPASS to D3DSTENCILOP_KEEP. Hope things are clearer now.

But the thing that is really driving me nuts is that I incremented the pixels only once and there are pixels with values like 3,7,... I dont understand why.

Share this post

Link to post
Share on other sites
Hmm, well I'm not sure then why you're getting stray pixels rendering. I've seen the tutorial on NeHe's site but didn't really dive into it much. It could be depth fighting resulting from float truncations on the surface, but that's the only guess I have at this point.

Share this post

Link to post
Share on other sites
It is not a problem anyway, its just a curiosity about why there are pixels with these values in the stencil buffer because it doesn't makes sense. When I render the shadow its all OK, it is rendered perfectly with no artifacts. And I don't think its due to depth fighting because the values in the stencil buffer should be only those 3 I mentioned =/. thanks for replying :)

Share this post

Link to post
Share on other sites
One more thing. I've taken a closer look to the shadow(when rendering it correctly) and there are some artifacts on it =/. some dots(holes). dont know why...here the code of the renderstates setup(this code is from the Shadow Volume sample from the DirectX8 SDK):

// Disable z-buffer writes and enable the stencil-buffer
m_pd3dDevice->SetRenderState( D3DRS_ZWRITEENABLE, FALSE );
m_pd3dDevice->SetRenderState( D3DRS_STENCILENABLE, TRUE );

// Dont bother with interpolating color
m_pd3dDevice->SetRenderState( D3DRS_SHADEMODE, D3DSHADE_FLAT );

// Set up stencil compare fuction, reference value, and masks
m_pd3dDevice->SetRenderState( D3DRS_STENCILFUNC, D3DCMP_ALWAYS );
m_pd3dDevice->SetRenderState( D3DRS_STENCILZFAIL, D3DSTENCILOP_KEEP );
m_pd3dDevice->SetRenderState( D3DRS_STENCILFAIL, D3DSTENCILOP_KEEP );

// If ztest passes, increment stencil buffer value
m_pd3dDevice->SetRenderState( D3DRS_STENCILPASS, D3DSTENCILOP_INCR );

// Make sure that no pixels get drawn to the frame buffer
m_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
m_pd3dDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_ZERO );
m_pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ONE );

// Draw front-side of shadow volume in stencil only
m_pd3dDevice->SetTransform( D3DTS_WORLD, &m_matObjectMatrix );
m_pShadowVolume->Render( m_pd3dDevice );

// Now reverse cull order so back sides of shadow volume are written.
m_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_CW );

// Decrement stencil buffer value
m_pd3dDevice->SetRenderState( D3DRS_STENCILPASS, D3DSTENCILOP_DECR );

// Draw back-side of shadow volume in stencil only
m_pShadowVolume->Render( m_pd3dDevice );

//Set some renderstates
m_pd3dDevice->SetRenderState( D3DRS_SHADEMODE, D3DSHADE_GOURAUD );
m_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_CCW );
m_pd3dDevice->SetRenderState( D3DRS_ZWRITEENABLE, TRUE );
m_pd3dDevice->SetRenderState( D3DRS_ZENABLE, FALSE );
m_pd3dDevice->SetRenderState( D3DRS_FOGENABLE, FALSE );
m_pd3dDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
m_pd3dDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );

m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );
m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE );

// Only write where stencil val >= 1
m_pd3dDevice->SetRenderState( D3DRS_STENCILREF, 0x1 );
m_pd3dDevice->SetRenderState( D3DRS_STENCILFUNC, D3DCMP_LESSEQUAL );
m_pd3dDevice->SetRenderState( D3DRS_STENCILPASS, D3DSTENCILOP_KEEP );

// Draw a big, gray square
m_pd3dDevice->SetVertexShader( D3DFVF_SHADOWVERTEX );
m_pd3dDevice->SetStreamSource( 0, m_pBigSquareVB, sizeof(SHADOWVERTEX) );
m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2 );

// Restore some render states
m_pd3dDevice->SetRenderState( D3DRS_ZENABLE, TRUE );
m_pd3dDevice->SetRenderState( D3DRS_STENCILENABLE, FALSE );
m_pd3dDevice->SetRenderState( D3DRS_FOGENABLE, TRUE );
m_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE );

This is called after render the full scene.

Share this post

Link to post
Share on other sites
In the increment pass, the value you get will be equal to the overdraw level. If a pixel has more than one triangle drawn over it, its value will be incremented several times.

Share this post

Link to post
Share on other sites
Wow! if this is the truth I must admit that the DXSDK documentation is a bitch. I have never seen it talks about this. But please explain me it better. Is there a way to compute how many times a specific pixel will be incremented/decremented? is it exactly equal to the number of triangles under this pixel?


Share this post

Link to post
Share on other sites
Sign in to follow this  

  • Advertisement

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!