•      Sign In
• Create Account

## Shadow mapping: D3DUSAGE_DEPTHSTENCIL or D3DUSAGE_RENDERTARGET?

Old topic!

Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

14 replies to this topic

### #1Tispe  Members

1419
Like
0Likes
Like

Posted 01 November 2013 - 07:03 AM

Hi

Reading the nvidia shadow mapping guide it uses a depthstencil surface to render the shadow map:

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.

But in this article http://www.gamedev.net/page/resources/_/technical/graphics-programming-and-theory/soft-edged-shadows-r2193 it seems to render to a texture render target

g_pd3dDevice->CreateTexture( SHADOW_MAP_SIZE, SHADOW_MAP_SIZE, 1,
D3DUSAGE_RENDERTARGET, D3DFMT_R32F,
D3DPOOL_DEFAULT, &g_pShadowMap,
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, 01 November 2013 - 07:04 AM.

### #2belfegor  Members

2833
Like
0Likes
Like

Posted 01 November 2013 - 08:56 AM

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, 01 November 2013 - 08:57 AM.

### #3Tispe  Members

1419
Like
0Likes
Like

Posted 01 November 2013 - 09:59 AM

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 -.-

### #4Tom KQT  Members

1698
Like
1Likes
Like

Posted 01 November 2013 - 10:10 AM

In D3D9 you cannot read from a depthstencil texture in shaders.

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, 01 November 2013 - 10:10 AM.

### #5Tispe  Members

1419
Like
0Likes
Like

Posted 01 November 2013 - 10:51 AM

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 ?

In D3D9 you cannot read from a depthstencil texture in shaders.

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, 01 November 2013 - 10:55 AM.

### #6belfegor  Members

2833
Like
1Likes
Like

Posted 01 November 2013 - 11:28 AM

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(...);

RenderToShadowMap();


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

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

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



### #7Tispe  Members

1419
Like
0Likes
Like

Posted 01 November 2013 - 12:37 PM

In D3D9 you cannot read from a depthstencil texture in shaders.

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?

### #8Tom KQT  Members

1698
Like
2Likes
Like

Posted 01 November 2013 - 12:47 PM

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

Here is the thread of mine, btw http://www.gamedev.net/topic/493911-using-tex2dproj-for-shadows/

Edited by Tom KQT, 01 November 2013 - 12:48 PM.

### #9Mona2000  Members

1948
Like
1Likes
Like

Posted 01 November 2013 - 01:24 PM

Hardware PCF works on all recent (even several years old) NVIDIA and ATI cards.

http://aras-p.info/texts/D3D9GPUHacks.html#shadowmap

Edited by Mona2000, 01 November 2013 - 01:24 PM.

### #10belfegor  Members

2833
Like
1Likes
Like

Posted 01 November 2013 - 01:40 PM

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;

d3d9device->SetPixelShaderConstantF(0, matViewToLightViewProj, 4);
...


And then on screen size quad, pixel shader:

#pragma pack_matrix(row_major)
...
float3 posVS    = tex2Dproj(gbPosition_samp, IN.TexCoord).xyz;
...
float4 tc    = mul(float4(posVS.xyz, 1.0f), ViewToLightViewProj);
float shadow = tex2Dproj( shadowMap_samp, tc + tc.w*(1.0f / SMAP_DIM));
...



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     shadow_hw    (float4 tc)        {
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 }
};

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

return shadow / 8.0f;
}



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

Edited by belfegor, 01 November 2013 - 01:57 PM.

### #11belfegor  Members

2833
Like
1Likes
Like

Posted 01 November 2013 - 02:00 PM

Hi

Reading the nvidia shadow mapping guide it uses a depthstencil surface to render the shadow map:

pD3DDev->CreateTexture(texWidth, texHeight, 1,
D3DUSAGE_DEPTHSTENCIL, D3DFMT_D24S8, D3DPOOL_DEFAULT,
&pTex);

You don't need stencil for shadow/depth texture, use D24X8.

### #12Tispe  Members

1419
Like
1Likes
Like

Posted 01 November 2013 - 02:43 PM

Thanks guys. I think I will go for the D3DUSAGE_RENDERTARGET, D3DFMT_R32F, surface since I am targeting DX9 hardware and I need to most compatibility, and I don't want to complicate things by writing hardware specific code at this stage.

### #13Hodgman  Moderators

49397
Like
1Likes
Like

Posted 02 November 2013 - 05:43 AM

For ultra compatibility, you can use a regular 8888 target, and use the shader to split the 32bit depth value into 4 8bit values (and in the shader that applies shadow, you can put those 4 values back together into the original value using a dot product). However, you have to wonder if GPUs that are this old even have enough horsepower to deliver decent FPS with shadow mapping, etc

You can see here which GPUs will support 32F or 16F render targets:

http://zp.amsnet.pl/cdragan/query.php?dxversion=9&feature=formats&featuregroup=selected&adaptergroup=groups&adapterselected%5B%5D=NVidia&adapterselected%5B%5D=Intel&adapterselected%5B%5D=ATi&featureselected%5B%5D=53&featureselected%5B%5D=50&featureselected%5B%5D=1&resource=TEXTURE&usage=RENDERTARGET&orientation=horizontal

e.g. 32F render targets are ~GeForce 5 upwards and Radeon 9500 upwards, but will not work on Intel's DX9 cards.

You can read a lot of the fancy "vendor specific" D3D9 stuff here:

http://developer.amd.com/wordpress/media/2012/10/Advanced-DX9-Capabilities-for-ATI-Radeon-Cards_v2.pdf

Most of the stuff in that document isn't actually ATI-specific, as the link that Mona2000 posted above shows.

AFAIK, The D24 shadow-map stuff, with built-in automatic hardware PCF via the sampler, is actually supported on more cards than 32F render-targets

Any DX10+ GPU will also work with the INTZ format in the above PDF, which is basically a normal D24S8 depth buffer, but is able to be used as a texture like in D3D10/11. This is my preferred format for depth buffers on D3D9 (when you don't want the automatic in-build PCF stuff) -- I even use it for the main depth buffer so that I can do DOF post-processing, etc... (assuming it's supported -- otherwise I disable the DOF/etc code).

Edited by Hodgman, 02 November 2013 - 06:09 AM.

### #14Tom KQT  Members

1698
Like
0Likes
Like

Posted 02 November 2013 - 12:23 PM

Thanks for the pdf, Hodgman. I may actually try to implement shadow maping using a depthstencil again with this new knowledge

Edited by Tom KQT, 02 November 2013 - 12:23 PM.

### #15Tispe  Members

1419
Like
0Likes
Like

Posted 04 November 2013 - 04:54 PM

Trying to implement this. I've been fiddling with Z buffer issue for hours now. Shadow Map is 512x512, I render to it fine but it seems like Z buffer is disabled, even though I enabled it and clear it properly. After I render to Shadow Map, I set the Back Buffer back, clear it and everything renders as normal. I draw the shadow map texture as a sprite ontop just to verify.

What could be the issue? Do I have to make a special zbuffer aswell? -.-

d3ddev->CreateTexture(512, 512,
1, D3DUSAGE_RENDERTARGET, D3DFMT_X8R8G8B8,	//D3DFMT_R32F
D3DPOOL_DEFAULT, &pShadowMapTexture, NULL);


Edited by Tispe, 04 November 2013 - 04:55 PM.

Old topic!

Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.