Sign in to follow this  
belfegor

[DX9][C++] Deffered shadows troubles [SOLVED]

Recommended Posts

I was "following" MJP's XNA "DeferredCascadedShadowMaps" and tried to "convert" it to C++ project except that i will render only 1 shadow, but i have trouble to get proper shadow coords: Full screen quad:
extern int ScreenWidth;//1024
extern int ScreenHeight;//1024

struct FSVertex
{
	D3DXVECTOR3 Position;
	D3DXVECTOR3 TexCoord0;
};

class FSQuad
{
private:
    D3DXVECTOR3 Corners[4];//frustum corners

...
    D3DXVECTOR3* GetCorners() { return &Corners[0]; }
...
// init
    D3DVERTEXELEMENT9 VertexElements[] =
    {
        {0,   0,  D3DDECLTYPE_FLOAT3,  D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION,  0},
	  {0,  12,  D3DDECLTYPE_FLOAT3,  D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD,  0},
	  D3DDECL_END()
    };
    hr = D3D9Device->CreateVertexDeclaration(VertexElements, &VDeclaration);
...
    D3DPOOL pool  = D3DPOOL_DEFAULT;
    DWORD usage   = D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC;
    UINT length   = sizeof(FSVertex) * 4;
    hr = D3D9Device->CreateVertexBuffer(length, usage, NULL, pool, &VBuffer, NULL);
...
    float   x1 = ((0.0f - 0.5f) * ((1.0f / (float)ScreenWidth) * 2.0f)) - 1.0f;
    float	x2 = (((float)ScreenWidth - 0.5f) * ((1.0f / (float)ScreenWidth) * 2.0f)) - 1.0f; 
    float	y1 = 1.0f - ((0.0f - 0.5f) * ((1.0f / (float)ScreenHeight) * 2.0f));
    float	y2 = 1.0f - (((float)ScreenHeight - 0.5f) * ((1.0f / (float)ScreenHeight) * 2.0f));
    float	z  = 0.0f;

    float    FOV   = D3DXToRadian(45.0f);//Copied fov value from my camera class(this is small project and i didnt want (yet) to pass camera until i got all this working)
    float    Near  = 1.0f;//also this
    float    Far   = 1500.0f;//also this
    float    NearH = 2 * tan(FOV) * Near;
    float    NearW = NearH;
    float    FarH  = 2 * tan(FOV) * Far;
    float    FarW  = FarH;
    float    NearX = NearW * 0.5f;
    float    NearY = NearH * 0.5f;
    float    FarX  = FarW * 0.5f;
    float    FarY  = FarH * 0.5f;

  //everything below goes CW:
  //              0---------1 
  //              |         | 
  //              |         |  
  //              |         | 
  //              3---------2

    Corners[0] = D3DXVECTOR3(-FarX,  FarY, Far);
    Corners[1] = D3DXVECTOR3( FarX,  FarY, Far);
    Corners[2] = D3DXVECTOR3( FarX, -FarY, Far);
    Corners[3] = D3DXVECTOR3(-FarX, -FarY, Far);

    PPVertex* pVertices = 0;
    VBuffer->Lock(0, 0, (LPVOID*)&pVertices, 0);
    pVertices[0].Position   = D3DXVECTOR3( x1,  y1,  z);
    pVertices[1].Position   = D3DXVECTOR3( x2,  y1,  z);
    pVertices[2].Position   = D3DXVECTOR3( x2,  y2,  z);
    pVertices[3].Position   = D3DXVECTOR3( x1,  y2,  z);

    pVertices[0].TexCoord0  = D3DXVECTOR3(0.0f, 0.0f, 0.0f);//3rd component is index (as in MJP's demo)
    pVertices[1].TexCoord0  = D3DXVECTOR3(1.0f, 0.0f, 1.0f);
    pVertices[2].TexCoord0  = D3DXVECTOR3(1.0f, 1.0f, 2.0f);
    pVertices[3].TexCoord0  = D3DXVECTOR3(0.0f, 1.0f, 3.0f);
    VBuffer->Unlock();

...//indices
    USHORT* pIndices = 0;
    IBuffer->Lock(0, 0, (LPVOID*)&pIndices, 0);
    pIndices[0]       = 0;
    pIndices[1]       = 1;
    pIndices[2]       = 2;
    pIndices[3]       = 0;
    pIndices[4]       = 2;
    pIndices[5]       = 3;
    IBuffer->Unlock();
};


send transformed corners
D3DXVECTOR3 TransformVector3(D3DXMATRIX mat, D3DXVECTOR3 vec)
{
	D3DXVECTOR3 tmp0 = vec;
	vec.x = tmp0.x*mat.m[0][0] + tmp0.y*mat.m[1][0] + tmp0.z*mat.m[2][0] + mat.m[3][0];
	vec.y = tmp0.x*mat.m[0][1] + tmp0.y*mat.m[1][1] + tmp0.z*mat.m[2][1] + mat.m[3][1];
	vec.z = tmp0.x*mat.m[0][2] + tmp0.y*mat.m[1][2] + tmp0.z*mat.m[2][2] + mat.m[3][2];
	return vec;
}

void RenderShadowsToFS()
{
      ...
      D3DXVECTOR3* Corners = fsQuad->GetCorners();
	D3DXVECTOR3 FCorners[4];
	FCorners[0] = TransformVector3(gCamera->View, Corners[0]);
	FCorners[1] = TransformVector3(gCamera->View, Corners[1]);
	FCorners[2] = TransformVector3(gCamera->View, Corners[2]);
	FCorners[3] = TransformVector3(gCamera->View, Corners[3]);
      gShadowedEffect->SetValue("FrustumCorners", &FCorners[0], sizeof(D3DXVECTOR3) * 4);
      ...
}


All shaders are the same except "ShadowMap.fx" pixel shader:
//global
float3 FrustumCorners[4];
...vertex shader
    OUT.FrustumC               = FrustumCorners[IN.TexCoord0.z];
..pixel shader
    float fPixelDepth     = tex2D(DepthSamp, IN.TexCoord0).r;// DepthSamp rendered from "player" camera (R32F, size same as screen 1024x1024)
    float4 vPositionVS    = float4(fPixelDepth * IN.FrustumC.xyz, 1.0f);

    float4x4 matViewToLightViewProj = mul(InvView, LightViewProj);//only one shadow light view proj
    float4 vPositionLightCS         = mul(vPositionVS, matViewToLightViewProj);

   float2 vShadowTexCoord          = 0.5 * vPositionLightCS.xy / vPositionLightCS.w + float2(0.5f, 0.5f);
   vShadowTexCoord.y               = 1.0f - vShadowTexCoord.y;
   vShadowTexCoord                += (0.5f / 1024.0f);
   float Shadow                    = tex2D(ShadowSamp, vShadowTexCoord).r;// ShadowSamp rendered from "light" camera (R32F, size same as screen 1024x1024)


   OUT.Color                       = Shadow;
   OUT.Color.a                     = 1.0f;


then i combine above in other shader:
...pixel shader
    float4 diffuse = tex2D(allModelsDifffuseSamp, tc);
    float4 shadow  = tex2D(shadowSamp, tc);// from prev. shader
    OUT.Color      = diffuse * shadow;
    OUT.Color.a    = 1.0f;


and i got everything rendered except shadows. This nightmare longs almost two weeks now. [Edited by - belfegor on April 1, 2010 9:51:51 AM]

Share this post


Link to post
Share on other sites
Ok. i got this working by using MJP's "Reconstructing position from depth"
without "frustum corners" method.


float3 VSPositionFromDepth(float2 vTexCoord)
{
float z = tex2D(DepthSamp, vTexCoord);
float x = vTexCoord.x * 2 - 1;
float y = (1 - vTexCoord.y) * 2 - 1;
float4 vProjectedPos = float4(x, y, z, 1.0f);
float4 vPositionVS = mul(vProjectedPos, InvProjection);
return vPositionVS.xyz / vPositionVS.w;
}



but i would like to know what am i doing wrong with previous "corners" method.

Also i use :

float fNear = 1.0f;
float fFar = 1500.0f;
float aspect = 1.0f;
float Fov = D3DXToRadian(45.0f);
D3DXMatrixPerspectiveFovLH(&gLightProjection, Fov, aspect, fNear, fFar);



instead:

D3DXMatrixOrthoLH(&gLightProjection, 1500.0f, 1500.0f, 0.0f, 1.0f);



because i got nothing rendered to rt with it???

Can someone provide code/hint for proper 4 corners that i have trouble with.

Share this post


Link to post
Share on other sites
To simplify my question i just need to know how to
calculate 4 needed corners based on this:

light projection matrix

float fNear = 1.0f;
float fFar = 1500.0f;
float aspect = (float)SHADOW_RT_SIZE / (float)SHADOW_RT_SIZE;//1.0f
float Fov = D3DXToRadian(45.0f);
D3DXMatrixPerspectiveFovLH(&gLightProjection, Fov, aspect, fNear, fFar);





screen quad

float c = 1.0f;
float z = 0.0f;

SSVertex* pVertices = 0;
VBuffer->Lock(0, 0, (LPVOID*)&pVertices, 0);

pVertices[0].Position = D3DXVECTOR3( -c, c, z);
pVertices[1].Position = D3DXVECTOR3( c, c, z);
pVertices[2].Position = D3DXVECTOR3( c, -c, z);
pVertices[3].Position = D3DXVECTOR3( -c, -c, z);

pVertices[0].TexCoord0 = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
pVertices[1].TexCoord0 = D3DXVECTOR3(1.0f, 0.0f, 1.0f);
pVertices[2].TexCoord0 = D3DXVECTOR3(1.0f, 1.0f, 2.0f);
pVertices[3].TexCoord0 = D3DXVECTOR3(0.0f, 1.0f, 3.0f);

VBuffer->Unlock();





render

...
D3DXVECTOR3 Corners[4] = ???
Effect->SetValue("corners", &Corners, sizeof(D3DXVECTOR3) * 4);
...





so that i can reconstruct position in shder

float3 corners[4];
...vertex shader
OUT.Corners = corners[IN.TexCoord0.z];
...pixel shader
float fPixelDepth = tex2D(DepthSamp, IN.TexCoord0.xy).r;
float4 vPositionVS = float4(fPixelDepth * IN.Corners.xyz, 1.0f);
...





Please.

EDIT; i made i mistake. I ve posted light camera projection instead "player"
camera, but they are basicly same except aspect:


D3DXMatrixPerspectiveFovLH(&Projection, D3DXToRadian(45.0f), (float)ScreenWidth / (float)ScreenHeight, fNear, fFar);




EDIT2; and if you need shader that render depth from "player" cam view:

...vertex shader
float4x4 wv = mul(World, View);
float4 wvPos = mul(float4(IN.Position.xyz, 1.0f), wv);
OUT.Position = mul(wvPos, Projection);
OUT.Depth = OUT.Position.zw;
...pixel shader
float d = IN.Depth.x / IN.Depth.y;// z/w
OUT.Color = float4(d, 1.0f, 1.0f, 1.0f);



[Edited by - belfegor on April 1, 2010 4:15:42 AM]

Share this post


Link to post
Share on other sites
OK. Forget about everything above.
I have started this project from beg.

Can you confirm this information below to be correct?:

axis aligned far frustum corners (how to call them otherwise)

float c = 1.0f;
float z = 0.0f;

float Fov = cameraFov;//D3DX_PI / 4.0f;
float Far = camFar;//1500
float FarY = tan(Fov / 2.0f) * Far;
float FarX = FarY * (cameraAspect);

// going CW same as i build my quad vertices/texcoords
FrustumCorners[0] = D3DXVECTOR3(-FarX, FarY, Far);
FrustumCorners[1] = D3DXVECTOR3( FarX, FarY, Far);
FrustumCorners[2] = D3DXVECTOR3( FarX, -FarY, Far);
FrustumCorners[3] = D3DXVECTOR3(-FarX, -FarY, Far);



then i transform these corners by "player" camera view matrix
and send them to shader:


float3 corners[4];
...vertex shader
OUT.Corners = corners[IN.TexCoord0.z];
...pixel shader
float fPixelDepth = tex2D(DepthSamp, IN.TexCoord0.xy).r;
float4 vPositionVS = float4(fPixelDepth * IN.Corners.xyz, 1.0f);



and if all this is correct how do i build proper light ortho projection matrix
because i got nothing rendered (on this rt) from light point of view if i use this:


float arbitaryValue = 1000.0f;// dont know what to store here
D3DXMatrixOrthoLH(&gLightProjection, arbitaryValue , arbitaryValue , 0.0f, 1.0f);


I am rendering (centered at origin) simple plane (100.0x100.0) and sphere
above it (radius 30.0).

when i run this with PIX (using above ortho projection) RT is completly white
but when i use
D3DXMatrixPerspectiveFovLH(&gLightProjection, Fov, aspect, fNear, fFar);
projection RT looks ok but final output is
wrong.

Share this post


Link to post
Share on other sites
EDIT;
shader that renders depth from "player" camera view:

float4x4 World;
float4x4 View;
float4x4 Projection;
float4x4 WorldViewProj;

struct A2V
{
float3 Position : POSITION;
};

struct V2P
{
float4 Position : POSITION;
float Depth : TEXCOORD0;
};

struct P2A
{
float4 Color : COLOR;
};

void VertexMain(in A2V IN, out V2P OUT)
{
float4x4 wv = mul(World, View);
float4 wvPos = mul(float4(IN.Position.xyz, 1.0f), wv);
OUT.Position = mul(wvPos, Projection);
OUT.Depth = wvPos.z;
}

void PixelMain(in V2P IN, out P2A OUT)
{
float d = IN.Depth.x / 1500.0f;
OUT.Color = float4(d, 1.0f, 1.0f, 1.0f);
}

technique tDepthMain
{
pass p0
{
VertexShader = compile vs_3_0 VertexMain();
PixelShader = compile ps_3_0 PixelMain();

ZEnable = true;
ZWriteEnable = true;
CullMode = CCW;
FillMode = Solid;
AlphaBlendEnable = false;
AlphaTestEnable = false;
}
}



shader that renders depth from light view:

float4x4 WorldViewProjection;

struct A2V
{
float3 Position : POSITION;
};

struct V2P
{
float4 Position : POSITION;
float2 Depth : TEXCOORD0;
};

struct P2A
{
float4 Color : COLOR;
};

void VertexMain(in A2V IN, out V2P OUT)
{
OUT.Position = mul(float4(IN.Position, 1.0f), WorldViewProjection);
OUT.Depth = OUT.Position.zw;
}

void PixelMain(in V2P IN, out P2A OUT)
{
float d = IN.Depth.x / IN.Depth.y;
OUT.Color = float4(d, 1.0f, 1.0f, 1.0f);
}

technique tDepth
{
pass p0
{
VertexShader = compile vs_3_0 VertexMain();
PixelShader = compile ps_3_0 PixelMain();
ZEnable = true;
ZWriteEnable = true;
CullMode = CCW;
FillMode = Solid;
AlphaBlendEnable = false;
AlphaTestEnable = false;
}
}

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