Contents
Inside Direct3D -- Stencil Buffers
 
 
Printer-Friendly VersionPrinter-Friendly Version
 
Latest News
spacer View All spacer
 
November 8, 2009
 
Iwata: 35% Japanese Connectivity Ratio For Wii, 20% For DS
 
iPhone Dev Storm8 Sued Over User Data Harvesting Allegations [6]
 
Game Boy, The Ball Admitted To National Toy Hall Of Fame
spacer
Latest Jobs
spacer View All     Post a Job     RSS spacer
 
November 8, 2009
 
Visual Concepts
Senior Online Engineer
 
Trion Redwood City
Sr. Evnironment Modeler
 
Trion Redwood City
Sr. Environment Artist
 
FarSight Studios
Software Engineer
 
Sucker Punch Productions
3D Environment Artist
 
Sucker Punch Productions
Character Artist
 
Sucker Punch Productions
Texture Artist
 
Sucker Punch Productions
Network Programmer
spacer
Latest Features
spacer View All spacer
 
November 8, 2009
 
arrow On Bringing Modern Warfare 2 To Life [3]
 
arrow Games Demystified: Dissidia Final Fantasy [1]
 
arrow Building Social Success: Zynga's Perspective [4]
 
arrow Small Developers: Minimizing Risks in Large Productions - Part I [7]
 
arrow Valve's Writers And The Creative Process [11]
 
arrow Sony's Software Strategy: Shuhei Yoshida Speaks [3]
 
arrow A Holistic Approach to Game Dialogue Production [7]
 
arrow Ancients Reborn: Launching League of Legends [4]
spacer
Latest Blogs
spacer View All     Post     RSS spacer
 
November 8, 2009
 
ESD Publishers Boycott Valve’s Steam Service. Seriously?
 
Interaction in Games [1]
 
Space of Possibility and Pacing in Casual Game Design - A PopCap Case Study [3]
spacer
About
spacer News Director:
Leigh Alexander
Features Director:
Christian Nutt
Editor At Large:
Chris Remo
Advertising:
John 'Malik' Watson
Recruitment/Education:
Gina Gross
 
Features
  Inside Direct3D -- Stencil Buffers
by Peter Kovach
0 comments
Share RSS
 
 
August 7, 2000 Article Start Page 1 of 3 Next
 

One aspect of advanced rendering we haven't discussed yet is stenciling, a technique that can be useful for developing commercial applications. If you want your 3D applications to stand apart from the crowd, you'd be wise to combine stenciling with the texturing techniques you learned about in earlier chapters. This chapter will detail how to use stenciling and show you the different types of effects you can generate with it.

Many 3D games and simulations on the market use cinema-quality special effects to add to their dramatic impact. You can use stencil buffers to create effects such as composites, decals, dissolves, fades, outlines, silhouettes, swipes, and shadows. Stencil buffers determine whether the pixels in an image are drawn. To perform this function, stencil buffers let you enable or disable drawing to the render-target surface on a pixel-by-pixel basis. This means your software can "mask" portions of the rendered image so that they aren't displayed.

Advertisement
When the stenciling feature is enabled, Microsoft Direct3D performs a stencil test for each pixel that it plans to write to the render-target surface. The stencil test uses a stencil reference value, a stencil mask, a comparison function, and a pixel value from the stencil buffer that corresponds to the current pixel in the target surface. Here are the specific steps used in this test:

  1. Perform a bitwise AND operation of the stencil reference value with the stencil mask.
  2. Perform a bitwise AND operation on the stencil-buffer value for the current pixel with the stencil mask.
  3. Compare the results of Step 1 and Step 2 by using the comparison function.

By controlling the comparison function, the stencil mask, the stencil reference value, and the action taken when the stencil test passes or fails, you can control how the stencil buffer works. As long as the test succeeds, the current pixel will be written to the target. The default comparison behavior (the value that the D3DCMPFUNC enumerated type defines for D3DCMP_ALWAYS) is to write the pixel without considering the contents of the stencil buffer. You can change the comparison function to any function you want by setting the value of the D3DRENDERSTATE_STENCILFUNC render state and passing one of the members of the D3DCMPFUNC enumerated type.

Creating a Stencil Buffer

Before creating a stencil buffer, you need to determine what stenciling capabilities the target system supports. To do this, call the IDirect3DDevice7::GetCaps method. The dwStencilCaps flags specify the stencil-buffer operations that the device supports. The reported flags are valid for all three stencil-buffer operation render states: D3DRENDERSTATE_STENCILFAIL, D3DRENDERSTATE_STENCILPASS, and D3DRENDERSTATE_STENCILZFAIL. Direct3D defines the following flags for dwStencilCaps:

  • D3DSTENCILCAPS_DECR Indicates that the D3DSTENCILOP_DECR operation is supported
  • D3DSTENCILCAPS_DECRSAT Indicates that the D3DSTENCILOP_DECRSAT operation is supported
  • D3DSTENCILCAPS_INCR Indicates that the
    D3DSTENCILOP_INCR operation is supported
  • D3DSTENCILCAPS_INCRSAT Indicates that the D3DSTENCILOP_INCRSAT operation is supported
  • D3DSTENCILCAPS_INVERT Indicates that the D3DSTENCILOP_INVERT operation is supported
  • D3DSTENCILCAPS_KEEP Indicates that the D3DSTENCILOP_KEEP operation is supported
  • D3DSTENCILCAPS_REPLACE Indicates that the D3DSTENCILOP_REPLACE operation is supported
  • D3DSTENCILCAPS_ZERO Indicates that the D3DSTENCILOP_ZERO operation is supported

Direct3D embeds the stencil-buffer information with the depth-buffer data. To determine what formats of depth buffers and stencil buffers the target system's hardware supports, call the IDirect3D7::EnumZBufferFormats method, which has the following declaration:

HRESULT IDirect3D7::EnumZBufferFormats (
REFCLSID riidDevice,
LPD3DENUMPIXELFORMATSCALLBACK lpEnumCallback,
LPVOID lpContext
);

Parameter
Description
riidDevice A reference to a globally unique identifier (GUID) for the device whose depth-buffer formats you want enumerated
IpEnumCallback The address of a D3DEnumPixelFormatsCallback function you want called for each supported depth-buffer format
IpContext Application-defined data that is passed to the callback function

 

If the method succeeds, it returns the value D3D_OK. If it fails, the method returns one of these four values:

  • DDERR_INVALIDOBJECT
  • DDERR_INVALIDPARAMS
  • DDER_NOZBUFFERHW
  • DDERR_OUTOFMEMORY

The code in listing 1 determines what stencil buffer formats are available and what operations are supported and then creates a stencil buffer. As you can see, this code notes whether the stencil buffer supports more than 1-bit -- some stenciling techniques must be handled differently if only a 1-bit stencil buffer is available.

Listing 1. Formats and Operations of Stencil Buffers

HRESULT CMyD3DApplication::CreateStencilBuffer()
{
g_bCanOnlyDoOneBitStencil=FALSE;

DWORD dwStencilCaps =
m_pDeviceInfo->ddDeviceDesc.dwStencilCaps;

if( (!(dwStencilCaps & D3DSTENCILCAPS_INCR) &&
!(dwStencilCaps & D3DSTENCILCAPS_INCRSAT)) ||
(!(dwStencilCaps & D3DSTENCILCAPS_DECR) &&
!(dwStencilCaps & D3DSTENCILCAPS_DECRSAT)))
{
// Must do 1-bit stencil buffer.
g_bCanOnlyDoOneBitStencil=TRUE;
}
else
{
// Prefer sat ops that cap at 0/max, but can
use other
// ones as long as enough stencil bits.
g_StencIncOp=(dwStencilCaps &
D3DSTENCILCAPS_INCRSAT)?
D3DSTENCILOP_INCRSAT:D3DSTENCILOP_INCR;
g_StencDecOp=(dwStencilCaps &
D3DSTENCILCAPS_DECRSAT)?
D3DSTENCILOP_DECRSAT:D3DSTENCILOP_DECR;
}

m_pddsRenderTarget->DeleteAttachedSurface( 0,NULL );

// Get z-buffer dimensions from the render target.
// Set up the surface description for the z-buffer.
DDSURFACEDESC2 ddsd;
D3DUtil_InitSurfaceDesc( ddsd );
m_pddsRenderTarget->GetSurfaceDesc( &ddsd );
ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT
| DDSD_CAPS | DDSD_PIXELFORMAT;
ddsd.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
ddsd.ddsCaps.dwCaps2 = 0;
ddsd.ddsCaps.dwCaps3 = 0;
ddsd.ddsCaps.dwCaps4 = 0;
ddsd.ddpfPixelFormat.dwFlags = DDPF_ZBUFFER | DDPF_STENCILBUFFER;

if( m_pDeviceInfo->bHardware )
ddsd.ddsCaps.dwCaps |= DDSCAPS_VIDEOMEMORY;
else
ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY;

// Get an appropriate pixel format from an
enumeration of
// the formats.
m_pD3D->EnumZBufferFormats(
(*m_pDeviceInfo->pDeviceGUID),
EnumZBufferFormatsCallback,
(VOID*)&ddsd.ddpfPixelFormat );

assert(ddsd.ddpfPixelFormat.dwStencilBitDepth!=0);

g_bCanOnlyDoOneBitStencil=g_bCanOnlyDoOneBitStencil ||
((1<

g_dwMaxStencilValue=
(1<

// Leave g_bUseOneBitStencil set for the
window-resize case.
if( !g_bUseOneBitStencil )
g_bUseOneBitStencil=g_bCanOnlyDoOneBitStencil;

SetMenuStates();

// Create and attach a z-buffer.
if( FAILED( m_pDD->CreateSurface( &ddsd,
&m_pddsDepthBuffer,
NULL ) ) )
return E_FAIL;

if( FAILED(m_pddsRenderTarget->AddAttachedSurface(
m_pddsDepthBuffer ) ) )
return E_FAIL;

// The SetRenderTarget() call is needed to rebuild
internal
// structures for the newly attached z-buffer.
return m_pd3dDevice->SetRenderTarget
( m_pddsRenderTarget, 0L );
}

//------------------------------------------------------
// Name: EnumZBufferFormatsCallback
// Desc: Enumeration function to report valid pixel
// formats for z-buffers
//------------------------------------------------------
static
HRESULT WINAPI EnumZBufferFormatsCallback(
DDPIXELFORMAT* pddpf,
VOID* pddpfDesired )
{
if( NULL==pddpf || NULL==pddpfDesired )
return D3DENUMRET_CANCEL;

// If the current pixel formats match the desired
// ones (DDPF_ZBUFFER and possibly
// DDPF_STENCILBUFFER), copy it and return. This
// function isn't choosy--it accepts the first
// valid format that comes along.

 

if( pddpf->dwFlags == ((DDPIXELFORMAT*)
pddpfDesired)->dwFlags )
{
memcpy( pddpfDesired, pddpf,
sizeof(DDPIXELFORMAT) );
return D3DENUMRET_CANCEL;
}

return D3DENUMRET_OK;
}

Clearing a Stencil Buffer

The IDirect3DDevice7 interface includes the Clear method, which you can use to simultaneously clear the render target's color buffer, depth buffer, and stencil buffer. Here's the declaration for the IDirect3DDevice7::Clear method:

HRESULT IDirect3DDevice7::Clear(
DWORD dwCount,
LPD3DRECT lpRects,
DWORD dwFlags,
D3DVALUE dvZ,
DWORD dwStencil
);

Parameter
Description
dwCount The number of rectangles in the array at lpRects.
IpRects
An array of D3DRECT structures defining the rectangles to be cleared. You can set a rectangle to the dimensions of the render-target surface to clear the entire surface. Each of these rectangles uses screen coordinates that correspond to points on the render-target surface. The coordinates are clipped to the bounds of the viewport rectangle.
dwFlags Flags indicating which surfaces should be cleared. This parameter can be any combination of the following flags, but at least one flag must be used:
  D3DCLEAR_TARGET Clear the render-target surface to the color in the dwColor parameter. D3DCLEAR_STENCIL Clear the stencil buffer to the value in the dwStencil parameter.
  D3DCLEAR_ZBUFFER Clear the depth buffer to the value in the dvZ parameter.
dwColor D3DCLEAR_ZBUFFER Clear the depth buffer to the value in the dvZ parameter..
dvZ A 32-bit RGBA color value to which the render-target surface will be cleared.
dwStencil The new z value that this method stores in the depth buffer. This parameter can range from 0.0 to 1.0, inclusive. The value of 0.0 represents the nearest distance to the viewer, and 1.0 represents the farthest distance.
  The integer value to store in each stencil-buffer entry. This parameter can range from 0 to 2n-1 inclusive, in which n is the bit depth of the stencil buffer.

The IDirect3DDevice7::Clear method still accepts the older D3DCLEAR_TARGET flag, which clears the render target using an RGBA color you provide in the dwColor parameter. This method also still accepts the D3DCLEAR_ZBUFFER flag, which clears the depth buffer to a depth you specify in dvZ (in which 0.0 is the closest distance and 1.0 is the farthest). DirectX 6 introduced the D3DCLEAR_STENCIL flag, which you can use to reset the stencil bits to the value you specify in the dwStencil parameter. This value can be an integer ranging from 0 to 2n-1, in which n is the bit depth of the stencil buffer.

 
Article Start Page 1 of 3 Next
 
Comments

none
 
Comment:
 


Submit Comment