# Shadow mapping: D3DUSAGE_DEPTHSTENCIL or D3DUSAGE_RENDERTARGET?

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

## Recommended Posts

Hi

pD3DDev->CreateTexture(texWidth, texHeight, 1,
D3DUSAGE_DEPTHSTENCIL, D3DFMT_D24S8, D3DPOOL_DEFAULT,
&pTex);
Note that you must create a corresponding color surface to go along with your
depth surface since Direct3D requires you to set a color surface / z surface pair
when doing a SetRenderTarget(). If you’re not using the color buffer for
anything, it’s best to turn off color writes when rendering to it using the
D3DRS_COLORWRITEENABLE renderstate to save bandwidth.

g_pd3dDevice->CreateTexture( SHADOW_MAP_SIZE, SHADOW_MAP_SIZE, 1,
D3DUSAGE_RENDERTARGET, D3DFMT_R32F,
NULL )

What is appropiate to use?

Seems like the first alternative you need a color surface but you turn off color renderstate to save bandwidth.

But the second alternative you don't???

Edited by Tispe

##### Share on other sites

I think that first example is nvidia specific (which i use also because i don't care about AMD or other cards), with this you can disable color writes (should be faster) and also get free PCF with one texture sampling.

In addition you can pair this with NULL texture (if it is supported) since it does not use any memory but is requierment:

...

Note that you must create a corresponding color surface to go along with your
depth surface since Direct3D requires you to set a color surface / z surface pair...

#define D3DFMT_NULL      ((D3DFORMAT)(MAKEFOURCC('N','U','L','L')))
...
hr = d3d9->CheckDeviceFormat(adapter, deviceType, displayMode.Format, D3DUSAGE_RENDERTARGET, D3DRTYPE_SURFACE, D3DFMT_NULL);
if(SUCCEEDED(hr))
{
hr = d3d9device->CreateTexture(SMAP_DIM.cx, SMAP_DIM.cy, 1, D3DUSAGE_RENDERTARGET, D3DFMT_NULL, D3DPOOL_DEFAULT, &nullTex, NULL);
if(FAILED(hr))
{
MessageBox(0, TEXT("CreateTexture() failed!"), 0, 0);
return;
}
hr = nullTex->GetSurfaceLevel(0, &nullSurface);
if(FAILED(hr))
{
MessageBox(0, TEXT("GetSurfaceLevel() failed!"), 0, 0);
return;
}
}


With other example you lose all above benefits and it is slower but works on most hardware.
Edited by belfegor

##### Share on other sites

I thought the purpose for DirectX was to provide an abstraction layer to be hardware independant. I can see that different cards have different caps, but aren't there a minimum requirement in the DX9 Spec?

Should not AMD cards have support for D3DUSAGE_DEPTHSTENCIL buffers? Does newer models of AMD cards offer free PCF using the same HLSL code? Can I use PCF for a D3DUSAGE_RENDERTARGET, D3DFMT_R32F surface or does it only apply to depthstencil buffers?

I don't want to spend time coding to support all kinds of hardware. I want to code for all hardware that support DX9. Does this mean that rendering the shadow map to a D3DUSAGE_RENDERTARGET, D3DFMT_R32F surface and not worrying about the zbuffer/color pair is the best route to take?

Does the DX9 Spec require cards to support D3DRS_COLORWRITEENABLE?

I'm confused -.-

##### Share on other sites

No by normal means. nVidia however allows something especially for shadow mapping, as was already mentioned.

But to be really sure that your shadow mapping will work, you should use a D3DFMT_R32F texture.

Edited by Tom KQT

##### Share on other sites

What I also don't get is why PCF would be "free" in the sense of just one sample. Because you have to do the depth test first then to do the weighted averaging. So if the sampler does the averaging before the depth test then that would mess up the shadowing?

Where can I find the DX9 Spec, must all DX9 cards support D3DFMT_R32F ?

Then how do you shadow map in D3D9 using depthstencil textures? I'm pretty sure this http://www.cs.berkeley.edu/~ravir/6160/papers/shadow_mapping.pdf article was intended for DX9.

Edited by Tispe

##### Share on other sites

I can't quite explain your first question, maybe someone else will. I will just say that with this there is no depth test and weighted averaging, i just call tex2Dproj and job is done.

Where can I find the DX9 Spec, must all DX9 cards support D3DFMT_R32F ?

Most cards should support this format, maybe some ancient ones (like from 8-9 years ago) and integrated do not.

Then how do you shadow map in D3D9 using depthstencil textures?

1. You set shadow depth and rt surfaces to draw on:

d3d9device->SetRenderTarget(0, nullSurface);
d3d9device->SetDepthStencilSurface(smapDepthSurface);
d3d9device->Clear(...);



2. Set back "main" rt and depth surfaces and read from shadow/depth texture:

d3d9device->SetRenderTarget(0, bbRTSurface);
d3d9device->SetDepthStencilSurface(bbDepthSurface);

d3d9device->SetTexture(0, smapDepthTex);
...



##### Share on other sites

2. Set back "main" rt and depth surfaces and read from shadow/depth texture:

Arent those two conflicting statements?

tex2Dproj

http://msdn.microsoft.com/en-us/library/windows/desktop/bb509681(v=vs.85).aspx says that Shader Model 2.0 and beyond should support this in the pixel shader. Aren't most AMD cards SM2.0 compliant? Would this mean this approach to free PCF would work for AMD cards aswell?

##### Share on other sites

What I also don't get is why PCF would be "free" in the sense of just one sample. Because you have to do the depth test first then to do the weighted averaging. So if the sampler does the averaging before the depth test then that would mess up the shadowing?

It works because the GPU knows that you are doing shadow mapping and does the depth comparison for you. When you sample the depth stencil texture, it directly gives you the information about shadow/light, while it actually compares 4 samples under the hood.

Then how do you shadow map in D3D9 using depthstencil textures? I'm pretty sure this http://www.cs.berkeley.edu/~ravir/6160/papers/shadow_mapping.pdf article was intended for DX9.

You don't.

It works only on nVidia cards. That's the point. You can do it there if you know how. I personally didn't manage to get it working. And when I asked about it on this forum some time ago, I felt like an idiot because nobody believed me that it even was possible

Edited by Tom KQT

##### Share on other sites

It is possible!

I use it in my deferred renderer. I chopped some relevant pieces from my code (edited variable names to be more obvious):

D3DXVECTOR2 offset(0.5f + (0.5f / (float)SMAP_DIM.cx, 0.5f + (0.5f / (float)SMAP_DIM.cx);
D3DXMATRIX texScaleBiasMat(
0.5f,     0.0f,     0.0f,         0.0f,
0.0f,    -0.5f,     0.0f,         0.0f,
0.0f,     0.0f,     1.0f,         0.0f,
offset.x, offset.y, 0.0f,         1.0f );
...
lightViewProjSB =  lightView * lightProj * texScaleBiasMat;
matViewToLightViewProj = inversePlayerView * lightViewProjSB;

...


#pragma pack_matrix(row_major)
...
float3 posVS    = tex2Dproj(gbPosition_samp, IN.TexCoord).xyz;
...
float4 tc    = mul(float4(posVS.xyz, 1.0f), ViewToLightViewProj);
...



You can add additional sampling/averaging for more "softness", like they do for S.T.A.L.K.E.R.

half      sample_hw_pcf    (float4 tc,float4 shift){
static const float     ts = KERNEL / float(SMAP_size);
return tex2Dproj    (s_smap,tc + tc.w*shift*ts).x;
}
half  s0        = sample_hw_pcf    (tc,float4(-1,-1,0,0));
half  s1        = sample_hw_pcf    (tc,float4(+1,-1,0,0));
half  s2        = sample_hw_pcf    (tc,float4(-1,+1,0,0));
half  s3        = sample_hw_pcf    (tc,float4(+1,+1,0,0));
return    (s0+s1+s2+s3)/4.h;
}


or like this:

float shadowSamp(float4 tc)
{
float2 PixelKernel[8] =
{
{ -1, -1 },
{ -1,  0 },
{ -1,  1 },
{  0, -1 },
{  0,  1 },
{  1, -1 },
{  1,  0 },
{  1,  1 }
};

for( int i = 0; i < 8; ++i )
{
shadow += tex2Dproj( smap_samp, float4(tc.xy + (PixelKernel[i].xy / SMapSize) * tc.w, tc.z, tc.w) );
}

}



I tried on some AMD cards but it didn't work.

Edited by belfegor

• ### What is your GameDev Story?

In 2019 we are celebrating 20 years of GameDev.net! Share your GameDev Story with us.

• 13
• 9
• 9
• 15
• 14
• ### Forum Statistics

• Total Topics
634070
• Total Posts
3015330
×