Advertisement Jump to content
Sign in to follow this  
Tispe

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.

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

Recommended Posts

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

Share this post


Link to post
Share on other sites
Advertisement

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 this post


Link to post
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 this post


Link to post
Share on other sites

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

Share this post


Link to post
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 ?

 


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

Share this post


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

Share this post


Link to post
Share on other sites


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?

Share this post


Link to post
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 biggrin.png

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

Edited by Tom KQT

Share this post


Link to post
Share on other sites

It is possible! smile.png

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

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!