• Announcements

    • khawk

      Download the Game Design and Indie Game Marketing Freebook   07/19/17

      GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.
Sign in to follow this  
Followers 0
SIIYA

DX9 + CSM + HW PCF

7 posts in this topic

Hi everyone,

I have a few short questions about PCF. I have read many articles and forum topics about this but couldnt find clear answers.
So here are the questions:


1. Can hardware PCF be done in DirectX 9 by using D24X8 depth stencil buffer as texture, and if so, will it work on both ATI and Nvidia cards (which support DST) ?

2. Do you need to use tex2Dproj() function for it, or any texture fetch function will do the job?

3. If you need to use tex2Dproj(), how can one calculate correct shadow coordinates for cascades?


I have working CSM in DirectX, but I am not satisfied with averaging 3x3 depth compare tests to blur the edges. So, I tried using D24X8 depth buffer for my shadow map and 4 sample fetches with tex2Dproj. I keep getting strange projection (shadow map moves with camera and alike) but it seems that HW PCF is really there because shadows look much softer. I can post some code and pictures if someone wants.

Any help will be appriciated.
Sorry for my english and thanks!
0

Share this post


Link to post
Share on other sites
Yes, you can do hardware PCF on both AMD and Nvidia hardware. The details for ATI/AMD are [url="http://developer.amd.com/gpu_assets/Advanced%20DX9%20Capabilities%20for%20ATI%20Radeon%20Cards_v2.pdf"]here[/url], and the details for Nvidia are [url="http://developer.download.nvidia.com/GPU_Programming_Guide/GPU_Programming_Guide_G80.pdf"]here[/url].
0

Share this post


Link to post
Share on other sites
Thanks for replying MJP. I was using this ATI article as a guide so it seems I am doing something else wrong. Here are few relevant code lines:

[left]Create depth stencil texture:[/left]
[left][CODE]
D3D9Device->CreateTexture( CSMSize * NUMBER_CASCADES, CSMSize, 1, D3DUSAGE_DEPTHSTENCIL,
D3DFMT_D24X8, D3DPOOL_DEFAULT, &CSMRT, NULL );
[/CODE][/left]

[left]Bind the depth stencil texture as an active depth buffer:[/left]
[CODE]
LPDIRECT3DSURFACE9 Surface;
ShadowManager.GetCSMRT()->GetSurfaceLevel( 0, &Surface );
D3D9Device->SetDepthStencilSurface( Surface );
SAFE_RELEASE( Surface );
[/CODE]

Bind a depth buffer texture as a texture for PCF filtering:
[CODE]
m_pEffect->SetTexture( hShadowMap, ShadowManager()->GetCSMRT() );
[/CODE]

Shader code:
[CODE]
// Position is reconstructed position from G-buffer in view space
if( Position.z < CascadeFrustumsEyeSpaceDepths.x )
iCurrentCascadeIndex = 0;
else if( Position.z < CascadeFrustumsEyeSpaceDepths.y )
iCurrentCascadeIndex = 1;
else if( Position.z < CascadeFrustumsEyeSpaceDepths.z )
iCurrentCascadeIndex = 2;

// Transform pixel from view space to light projection space
// ShadowViewProj matrix = CameraViewInverse x LightView x LightProj
float4 Pos = mul( float4(Position,1), ShadowViewProj[iCurrentCascadeIndex] );


float4x4 matTexAdj = { 0.5f , 0.0f, 0.0f, 0.0f,
0.0f, -0.5f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.0f, 1.0f };

// Transform to texture space
Pos = mul(Pos, matTexAdj);

float2 PixelKernel[9] =
{
{ -1, -1 },
{ -1, 0 },
{ -1, 1 },
{ 0, -1 },
{ 0, 0 },
{ 0, 1 },
{ 1, -1 },
{ 1, 0 },
{ 1, 1 }
};

float PercentLit = 0.0f;

for( int i = 0; i < 9; ++i )
{
PercentLit += tex2Dproj( ShadowSampler, float4( Pos.xy + PixelKernel[i] * float2( TexelSizeX, TexelSize ), Pos.z, Pos.w ) );
}

PercentLit /= 9.0f;

[/CODE]


This works when I use only one cascade, but if there are more cascades projection is wrong or it treats whole buffer as a single cascade. I used to scale sampling cordinates after moving to texture space like this:

ShadowTexC.x *= ShadowPartitionSize; // 1.0 / NUMBER_OF_CASCADES
ShadowTexC.x += (ShadowPartitionSize * (float)iCurrentCascadeIndex );
But now with tex2Dproj() I dont now where to calculate for it

Anyway I know I am close to solution but cant find it for 6 days now. Thanks for your help
0

Share this post


Link to post
Share on other sites
Have you considered/tried creating square texture?
It might be easier to manage and share it with all spot/point light casting shadow. This way you can create and reuse only 1 DS RT.

And i think you might want to remove adjustment matrix out of pixel shader and precalculate on CPU.
So:
[code]
ShadowViewProj matrix = CameraViewInverse x LightView x LightProj x matTexAdj;

[/code]

For PCF on ATI i think you need to turn point filtering on ds texture and lerp rgba components. Something like:
[code]
float4 shadow = tex2Dproj(samp, coords);
float2 f = frac(coords.xy * SHMapSize);

float s1 = lerp(shadow.x, shadow.y, f.x);
float s2 = lerp(shadow.z, shadow.w, f.x);
return lerp(s1, s2, f.y);

[/code]
Don't have ATI so i have not tried it.

[code]
// multiply blend
alphablend true
srcblend zero
destblend srccolor

for num cascades
draw depth to DF24 ati or D24X8 nv
draw to fullscreen quad (or boxed area) and accumulate with

for num sh. casting point lights
for each "cube" face
draw depth to DF24 ati or D24X8 nv
draw to sphere stencil culled light volumen

for num sh. casting spotlights
draw depth to DF24 ati or D24X8 nv
draw to cone/pyramid stencil culled light volumen

// even use SSAO here with same blending
draw to fullscreen quad

...

[/code]

EDIT: From ATI article MJP posted:
[code]
// Determine Fetch-4 supported: all ATI Radeon cards supporting Fetch-4
also
// support the DF24 depth texture FourCC format so use this for detection.
#define ATI_FOURCC_DF24 ((D3DFORMAT)(MAKEFOURCC(‘D’,’F’,’2’,’4’)))
HRESULT hr;
hr = pd3d->CheckDeviceFormat(AdapterOrdinal, DeviceType, AdapterFormat,
D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE,
ATI_FOURCC_DF24);
BOOL bFetch4Supported = (hr == D3D_OK);
To enable Fetch-4 on a texture sampler (sampler 0 in this example):
#define FETCH4_ENABLE ((DWORD)MAKEFOURCC('G', 'E', 'T', '4'))
#define FETCH4_DISABLE ((DWORD)MAKEFOURCC('G', 'E', 'T', '1'))
// Enable Fetch-4 on sampler 0 by overloading the MIPMAPLODBIAS render
state
pd3dDevice->SetSamplerState(0, D3DSAMP_MIPMAPLODBIAS, FETCH4_ENABLE);
// Set point sampling filtering (required for Fetch-4 to work)
pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
[/code] Edited by belfegor
0

Share this post


Link to post
Share on other sites
Hi, belfegor,

I will optimize code once I get it working. I am using square texture for point and spot lights, and this one is only for directional light. And maybe I wasnt clear, I got HW PCF working. Its just that I dont get proper projection when using tex2Dproj( samp, coords ) with 3 cascades, so I think my coords are not calculated right.

Here is working implementation without HW PCF and with R32F shadow map:
[CODE]
if( Position.z < CascadeFrustumsEyeSpaceDepths.x )
iCurrentCascadeIndex = 0;
else if( Position.z < CascadeFrustumsEyeSpaceDepths.y )
iCurrentCascadeIndex = 1;
else if( Position.z < CascadeFrustumsEyeSpaceDepths.z )
iCurrentCascadeIndex = 2;

// Transform pixel from camera space to light projection space
// ShadowViewProj matrix = CameraViewInverse x LightView x LightProj
float4 Pos = mul( float4(Position,1), ShadowViewProj[iCurrentCascadeIndex] );

// Transform from light projection space to light texture space.
float2 ShadowTexC = 0.5 * Pos.xy / Pos.w + 0.5;
ShadowTexC.y = 1.0f - ShadowTexC.y;

ShadowTexC.x *= ShadowPartitionSize;
ShadowTexC.x += (ShadowPartitionSize * (float)iCurrentCascadeIndex );


float2 PixelKernel[9] =
{
{ -1, -1 },
{ -1, 0 },
{ -1, 1 },
{ 0, -1 },
{ 0, 0 },
{ 0, 1 },
{ 1, -1 },
{ 1, 0 },
{ 1, 1 }
};

float depthcompare = Pos.z / Pos.w - PCFOffset;

float PercentLit = 0.0f;


for( int i = 0; i < 9; ++i )
{
float shadow = tex2D( ShadowSampler, ShadowTexC + PixelKernel[i] * float2( TexelSizeX, TexelSize ) );
PercentLit += shadow < depthcompare ? 0.0f : 1.0f;
}

PercentLit /= 9.0f;

[/CODE]

ShadowTexC.x *= ShadowPartitionSize;
ShadowTexC.x += (ShadowPartitionSize * (float)iCurrentCascadeIndex );

These lines of code put sampling coordinates in the correct cascade and this information is missing in my coords for tex2Dproj() implementation.


EDIT:
The thing is, that above code only works when shadow map is R32F. As soon as I switch it to D24X8 depth stencil texture I get wrong projection no matter which shader code I use. Maybe it has to do something with depth compares? With R32F texture i output shadow depth as color pos.z / pos.w, and with D24X8 depth stencil texture I just use return mul(Pos, WorldViewProjection) in vertex shader. Edited by SIIYA
0

Share this post


Link to post
Share on other sites
[quote name='belfegor' timestamp='1337354698' post='4941196']
EDIT: From ATI article MJP posted:
[code]
// Determine Fetch-4 supported: all ATI Radeon cards supporting Fetch-4
also
// support the DF24 depth texture FourCC format so use this for detection.
#define ATI_FOURCC_DF24 ((D3DFORMAT)(MAKEFOURCC(‘D’,’F’,’2’,’4’)))
HRESULT hr;
hr = pd3d->CheckDeviceFormat(AdapterOrdinal, DeviceType, AdapterFormat,
D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_TEXTURE,
ATI_FOURCC_DF24);
BOOL bFetch4Supported = (hr == D3D_OK);
To enable Fetch-4 on a texture sampler (sampler 0 in this example):
#define FETCH4_ENABLE ((DWORD)MAKEFOURCC('G', 'E', 'T', '4'))
#define FETCH4_DISABLE ((DWORD)MAKEFOURCC('G', 'E', 'T', '1'))
// Enable Fetch-4 on sampler 0 by overloading the MIPMAPLODBIAS render
state
pd3dDevice->SetSamplerState(0, D3DSAMP_MIPMAPLODBIAS, FETCH4_ENABLE);
// Set point sampling filtering (required for Fetch-4 to work)
pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
[/code]
[/quote]

It also says: Implementations wishing to use Fetch-4 for Percentage-Closer Filtering should prefer the use of DX9 Depth Stencil Textures instead. This is what im trying to use Its on the page 5 of the article.
0

Share this post


Link to post
Share on other sites
I can't say what is exactly wrong, except this:
[code]
ShadowTexC.x *= ShadowPartitionSize;
ShadowTexC.x += (ShadowPartitionSize * (float)iCurrentCascadeIndex );
[/code]
Why do you multiply (first line)? Second line should be enough to get correct offset.

As for fetch-4 try it on single spotlight to see if it works as i suggested and then implement it with CSM. Edited by belfegor
0

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0