Sign in to follow this  
bengaltgrs

DX9 Cube shadow maps

Recommended Posts

bengaltgrs    282
I'm attempting to implement cube mapped shadowing in DX9+HLSL, and I'm just about there, but I don't quite know how to finish the shader to actually display the shadows. The cube map (depth) is being generated correctly, which is evident when I return only the cube map texture in the pixel shader, so I know that part is working correctly. So my question is - how do I go about using the "shadowMap" variable in the pixel shader to properly display shadows?

[code]
float4x4 World;
float4x4 WorldViewProj;
float3 LightPos;

texture ColorTex;
texture CubeShadowTex;

#define SHADOW_EPSILON 0.00005f

sampler ColorSampler = sampler_state
{
Texture = (ColorTex);
MinFilter = LINEAR;
MagFilter = LINEAR;
MipFilter = LINEAR;
};

sampler CubeShadowSampler = sampler_state
{
Texture = (CubeShadowTex);
MinFilter = LINEAR;
MagFilter = LINEAR;
MipFilter = LINEAR;
AddressU = WRAP;
AddressV = WRAP;
};

struct CubeShadowMap_IN
{
float4 Position : POSITION;
float3 Normal : NORMAL;
float2 TexCoord0 : TEXCOORD0;
float3 Tangent : TANGENT;
float3 Binormal : BINORMAL;
};

struct CubeShadowMap_OUT
{
float4 position : POSITION0;
float3 lightDir : TEXCOORD0; // Vector from pixel to light
float2 texCoord : TEXCOORD1;
float depth : TEXCOORD2;
};

void VS(in CubeShadowMap_IN IN, out CubeShadowMap_OUT OUT)
{
//Transform the position from view space to homogeneous projection space
OUT.position = mul(IN.Position, WorldViewProj);

//Compute world space position
float4 WorldPos = mul(IN.Position, World);

//Compute light direction
OUT.lightDir = LightPos - WorldPos;

OUT.depth = length(OUT.lightDir);

// Pass texture coordinates through
OUT.texCoord = IN.TexCoord0;
}

float4 PS(in CubeShadowMap_OUT IN) : COLOR
{
//Pixel to light vector
IN.lightDir = normalize( IN.lightDir );

// Find color of pixel
float shadowMap = (texCUBE(CubeShadowSampler, IN.lightDir).r+SHADOW_EPSILON > IN.depth ? 0.0f : 1.0f);
float4 Color = tex2D(ColorSampler, IN.texCoord);

return Color * shadowMap;
}
[/code]

Share this post


Link to post
Share on other sites
DJTN    207
You check the distance of the current pixel and compare it to the distance data in the shadowmap. If the pixel distance (- some bias) is greater than the pixel data in the shadowmap then it gets shadowed (return darker color).


I went through a difficult learning curve with cubed shadow maps and point lights. In the end I chose a different lighting approach as cube maps eat up resources like crazy, regardless of your rendering technique.



Good luck!

Dj

Share this post


Link to post
Share on other sites
DJTN    207
[quote name='smittix' timestamp='1307847241' post='4822260']
Thanks, yeah that's what I was attempting to do but I'm not sure how to get the proper depth value in the final rendering pass.
[/quote]


Do you mean in the pixel shader or you have multiple passes for each light and you're wanting the shadowed color returned in the final pass?

Share this post


Link to post
Share on other sites
bengaltgrs    282
iI only have one pass per light, which is the shader above. So the issue I'm having is that the IN.depth value used in the pixel shader does not seem to be within the same range as the value returned from the cube shadow map. So in the pixel shader, if I return the shadowMap variable, then I see what looks like a correct shadow map. If I return the IN.depth value though, then I see all white.

Share this post


Link to post
Share on other sites
DJTN    207
[quote name='smittix' timestamp='1307897348' post='4822434']
iI only have one pass per light, which is the shader above. So the issue I'm having is that the IN.depth value used in the pixel shader does not seem to be within the same range as the value returned from the cube shadow map. So in the pixel shader, if I return the shadowMap variable, then I see what looks like a correct shadow map. If I return the IN.depth value though, then I see all white.
[/quote]


When you're creating the cubed shadowmap what image fromat are you using?

Share this post


Link to post
Share on other sites
bengaltgrs    282
The cube map env map and cube map texture are being created like this:

[code]
D3DXCreateRenderToEnvMap(D3DDevice, CUBEMAP_RESOLUTION, 1, BackBufferSurfaceDesc.Format, TRUE, D3DFMT_D24X8, &RenderToEnvMap);
D3DXCreateCubeTexture(D3DDevice, CUBEMAP_RESOLUTION, 1, D3DUSAGE_RENDERTARGET, BackBufferSurfaceDesc.Format, D3DPOOL_DEFAULT, &CubeMapTexture);
[/code]

Where BackBufferSurfaceDesc.Format is set to D3DFMT_X8R8G8B8.

Share this post


Link to post
Share on other sites
DJTN    207
I used the R32F format and it was more percise but not all hardware support it.

Also, when I was sampling my cubeShadowMap I did the following (pseudo code):

[code]

lightDirection.xyz = lightPosition.xyz – positionWS;

float distance = length(lightDirection.xyz);

lightDirection.xyz = lightDirection.xyz / distance;

float smDepth = texCUBE(ShadowMapSampler, float4(-(lightDirection.xyz), 0.0f)).x;

if(distance > smDepth + 0.0001f)

{
//in shadow
}

[/code]

Share this post


Link to post
Share on other sites
DJTN    207
[quote name='smittix' timestamp='1307907432' post='4822495']
Interesting, I got it to kind of work.. I've attached what I have of the full project to this post if you have a moment to check it out.
[/quote]

Sorry Smit, on a box at work and cannot download. Post a screenshot of your results and I'll have a look.

Share this post


Link to post
Share on other sites
bengaltgrs    282
No problem, thanks for your help by the way. I'm including all relevant code below. Basically, the shadow from the sphere is correctly projected onto the wall behind it, but assuming everything was done correctly, the backside of the sphere should have been shadowed as well. However, the backside of the sphere has no shadow applied to it at all.

DX Code
[code]
float ScreenWidth = 640.0F;
float ScreenHeight = 480.0F;

#include <windows.h>
#include <mmsystem.h>
#include <d3d9.h>
#include <d3dx9.h>
#include "DirectInput.h"
#include "Camera.h"

#define CUBEMAP_RESOLUTION 256

// Globals
HWND hwnd = NULL;
IDirect3DDevice9* D3DDevice = NULL;

DirectInput *DInput;
Camera *ActiveCamera;
ID3DXMesh* RoomMesh;
ID3DXMesh* BallMesh;
ID3DXMesh* TeapotMesh;
IDirect3DTexture9* RoomTexture;
IDirect3DTexture9* StoneTexture;
IDirect3DCubeTexture9* CubeMapTexture;
ID3DXRenderToEnvMap* RenderToEnvMap;
ID3DXEffect* EnvMapEffect;
ID3DXEffect* AmbientEffect;

D3DXVECTOR3 LightPosition(-8.0f, 12.0f, 0.0f);
D3DXMATRIX Proj;

//Timer
DWORD CurrentTime;
DWORD LastTime;
float DeltaTime;

// Prototypes
void UpdateDeltaTime(void);
void LoadXFile(char* Filename, ID3DXMesh* &Mesh);
void Setup(void);
void Cleanup(void);
void RenderScene(void);
void RenderTeapot(void);
void RenderSceneIntoEnvMap(D3DXVECTOR3 Position);
D3DXMATRIX GetCubeMapViewMatrix(DWORD dwFace, D3DXVECTOR3 Position);
void Render(void);
void InitializeDirect3D(void);
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow);

///////////////////////////////////////////////////////
// GetDeltaTime
///////////////////////////////////////////////////////
void UpdateDeltaTime(void)
{
CurrentTime = timeGetTime();

DeltaTime = ((float)CurrentTime - (float)LastTime) * 0.001f;

LastTime = timeGetTime();
}

///////////////////////////////////////////////////////
// Load an X File
///////////////////////////////////////////////////////
void LoadXFile(char* Filename, ID3DXMesh* &Mesh)
{
//Zero Mesh and create buffer
Mesh = 0;
ID3DXBuffer* MeshBuffer = 0;

//Load and optimize the mesh
D3DXLoadMeshFromX( Filename, D3DXMESH_MANAGED, D3DDevice, &MeshBuffer, 0, 0, 0, &Mesh);
Mesh->OptimizeInplace( D3DXMESHOPT_ATTRSORT | D3DXMESHOPT_COMPACT | D3DXMESHOPT_VERTEXCACHE, (DWORD*)MeshBuffer->GetBufferPointer(), 0, 0, 0);

//Release and zero the buffer
MeshBuffer->Release(); MeshBuffer = NULL;
}

///////////////////////////////////////////////////////
// Setup
///////////////////////////////////////////////////////
void Setup( void )
{
//Set the Projection matrix
D3DXMatrixPerspectiveFovLH(&Proj, D3DX_PI/4.0f, ScreenWidth / ScreenHeight, 1.0f, 1000.0f);
D3DDevice->SetTransform(D3DTS_PROJECTION, &Proj);

//Get the back buffer description
IDirect3DSurface9* BackBuffer = NULL;
D3DSURFACE_DESC BackBufferSurfaceDesc;
D3DDevice->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &BackBuffer);
BackBuffer->GetDesc(&BackBufferSurfaceDesc);
BackBuffer->Release();

//Create RenderToEnvMap object
D3DXCreateRenderToEnvMap(D3DDevice, CUBEMAP_RESOLUTION, 1, BackBufferSurfaceDesc.Format, TRUE, D3DFMT_D24X8, &RenderToEnvMap);

//Create the cubemap texture
D3DXCreateCubeTexture(D3DDevice, CUBEMAP_RESOLUTION, 1, D3DUSAGE_RENDERTARGET, BackBufferSurfaceDesc.Format, D3DPOOL_DEFAULT, &CubeMapTexture);

//Load the environment map effect
ID3DXBuffer* e = 0;
D3DXCreateEffectFromFile(D3DDevice, "HLSLEnvironmentMap.fx", NULL, NULL, D3DXSHADER_DEBUG, NULL, &EnvMapEffect, &e);
if(e)
{
::MessageBox(0, (char*)e->GetBufferPointer(), 0, 0);
}

D3DXCreateEffectFromFile(D3DDevice, "Ambient.fx", NULL, NULL, D3DXSHADER_DEBUG, NULL, &AmbientEffect, &e);
if(e)
{
::MessageBox(0, (char*)e->GetBufferPointer(), 0, 0);
}

//Load the X files
LoadXFile("Room.X", RoomMesh);
LoadXFile("Ball.X", BallMesh);
LoadXFile("Teapot.X", TeapotMesh);

D3DVERTEXELEMENT9 Elements[] =
{
{ 0, sizeof( float ) * 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
{ 0, sizeof( float ) * 3, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0 },
{ 0, sizeof( float ) * 6, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },
{ 0, sizeof( float ) * 8, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TANGENT, 0 },
{ 0, sizeof( float ) * 11, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BINORMAL, 0 },
D3DDECL_END()
};

//Compute the tangent frame for the mesh. (Needed for normal mapping)
ID3DXMesh* Temp;
RoomMesh->CloneMesh( D3DXMESH_MANAGED, Elements, D3DDevice, &Temp );
RoomMesh->Release();
RoomMesh = Temp;
void* Data;
RoomMesh->LockVertexBuffer(D3DLOCK_DISCARD, &Data);
RoomMesh->UnlockVertexBuffer();
D3DXComputeTangentFrame(RoomMesh, 0);

//Load the texture into RoomTexture
D3DXCreateTextureFromFile( D3DDevice, "conc02.jpg", &RoomTexture );
D3DXCreateTextureFromFile( D3DDevice, "stone_wall.bmp", &StoneTexture );

//Create a new instance of Camera
ActiveCamera = new Camera();

//Disable lighting for this sample
D3DDevice->SetRenderState( D3DRS_LIGHTING, false );

//Set some render states to determine texture quality
D3DDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
D3DDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
D3DDevice->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);
}

///////////////////////////////////////////////////////
// Cleanup
///////////////////////////////////////////////////////
void Cleanup( void )
{
//Release all DX objects
RoomMesh->Release();
BallMesh->Release();
TeapotMesh->Release();
RoomTexture->Release();
StoneTexture->Release();
CubeMapTexture->Release();
RenderToEnvMap->Release();
EnvMapEffect->Release();
AmbientEffect->Release();

//Delete the Direct Input device
delete DInput;

//Delete the Camera object
delete ActiveCamera;

//Release the Direct3D device
D3DDevice->Release();
}

///////////////////////////////////////////////////////
// Render the scene without the teapot
///////////////////////////////////////////////////////
void RenderScene(const D3DXMATRIX& view, const D3DXMATRIX& proj)
{
AmbientEffect->SetTechnique("EnvironmentMap");

//Only one pass in this shader
UINT numPasses = 0;
AmbientEffect->Begin(&numPasses, 0);
AmbientEffect->BeginPass(0);

// Render room
D3DXMATRIX World;
D3DXMatrixIdentity(&World);
AmbientEffect->SetTexture("ColorTex", RoomTexture);
AmbientEffect->SetMatrix("WorldViewProj", &(World * view * proj));
AmbientEffect->CommitChanges();
RoomMesh->DrawSubset(0);

// Render ball
World._41 = 8.0f;
World._42 = 12.0f;
AmbientEffect->SetTexture("ColorTex", StoneTexture);
AmbientEffect->SetMatrix("WorldViewProj", &(World * view * proj));
AmbientEffect->CommitChanges();
BallMesh->DrawSubset(0);

AmbientEffect->EndPass();
AmbientEffect->End();
}

///////////////////////////////////////////////////////
// Render the teapot with environment mapping
///////////////////////////////////////////////////////
void RenderFinalScene(void)
{
//Set the world matrix
D3DXMATRIX World;
D3DXMatrixIdentity(&World);

//Set shader variables
EnvMapEffect->SetMatrix("World", &World);
EnvMapEffect->SetMatrix("WorldViewProj", &(World * ActiveCamera->View * Proj));
EnvMapEffect->SetValue("LightPos", &LightPosition, sizeof(D3DXVECTOR3));
EnvMapEffect->SetTexture("ColorTex", RoomTexture);
EnvMapEffect->SetTexture("CubeShadowTex", CubeMapTexture);
EnvMapEffect->SetTechnique("CubeShadowMap");

//Only one pass in this shader
UINT numPasses = 0;
EnvMapEffect->Begin(&numPasses, 0);
EnvMapEffect->BeginPass(0);

//Draw the teapot with the environment map applied
RoomMesh->DrawSubset(0);

//Render ball
World._41 = 8.0f;
World._42 = 12.0f;
EnvMapEffect->SetMatrix("World", &World);
EnvMapEffect->SetMatrix("WorldViewProj", &(World * ActiveCamera->View * Proj));
EnvMapEffect->SetTexture("ColorTex", StoneTexture);
EnvMapEffect->CommitChanges();
BallMesh->DrawSubset(0);

EnvMapEffect->EndPass();
EnvMapEffect->End();
}

///////////////////////////////////////////////////////
// Render the scene 6 times to make the environment map
///////////////////////////////////////////////////////
void RenderSceneIntoEnvMap(D3DXVECTOR3 Position)
{
//Need a square 90 degree projection to get a seamless environment map texture
D3DXMATRIX NewProj;
D3DXMatrixPerspectiveFovLH( &NewProj, D3DX_PI * 0.5f, 1.0f, 0.5f, 1000.0f );
D3DDevice->SetTransform(D3DTS_PROJECTION, &NewProj);

//Begin rendering to environment map texture
RenderToEnvMap->BeginCube(CubeMapTexture);

for(UINT i = 0; i < 6; i++)
{
//Get cube map render target surface and set it as render target
RenderToEnvMap->Face((D3DCUBEMAP_FACES)i, 0 );

//Set the view transform for this cubemap surface
D3DXMATRIX viewProj = GetCubeMapViewMatrix((D3DCUBEMAP_FACES)i, Position);

//Rrender the scene (except for the teapot)
D3DDevice->Clear( 0, NULL, D3DCLEAR_ZBUFFER, 0x00000000, 1.0f, 0 );
RenderScene(viewProj, NewProj);
}

//End rendering to environment map texture
RenderToEnvMap->End(0);
}

///////////////////////////////////////////////////////
// Get propor view matrix for rendering cubemap texture
///////////////////////////////////////////////////////
D3DXMATRIX GetCubeMapViewMatrix(DWORD dwFace, D3DXVECTOR3 Position)
{
D3DXVECTOR3 LookDir;
D3DXVECTOR3 UpDir;

switch( dwFace )
{
case D3DCUBEMAP_FACE_POSITIVE_X:
LookDir = D3DXVECTOR3( 1.0f, 0.0f, 0.0f ) + Position;
UpDir = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
break;
case D3DCUBEMAP_FACE_NEGATIVE_X:
LookDir = D3DXVECTOR3(-1.0f, 0.0f, 0.0f ) + Position;
UpDir = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
break;
case D3DCUBEMAP_FACE_POSITIVE_Y:
LookDir = D3DXVECTOR3( 0.0f, 1.0f, 0.0f ) + Position;
UpDir = D3DXVECTOR3( 0.0f, 0.0f,-1.0f );
break;
case D3DCUBEMAP_FACE_NEGATIVE_Y:
LookDir = D3DXVECTOR3( 0.0f,-1.0f, 0.0f ) + Position;
UpDir = D3DXVECTOR3( 0.0f, 0.0f, 1.0f );
break;
case D3DCUBEMAP_FACE_POSITIVE_Z:
LookDir = D3DXVECTOR3( 0.0f, 0.0f, 1.0f ) + Position;
UpDir = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
break;
case D3DCUBEMAP_FACE_NEGATIVE_Z:
LookDir = D3DXVECTOR3( 0.0f, 0.0f,-1.0f ) + Position;
UpDir = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
break;
}

// Set the view transform for this cubemap surface
D3DXMATRIX NewView;
D3DXMatrixLookAtLH( &NewView, &Position, &LookDir, &UpDir );
return NewView;
}

///////////////////////////////////////////////////////
// Render
///////////////////////////////////////////////////////
void Render( void )
{
//Update the Delta Time
UpdateDeltaTime();

//Poll the DirectInput device
DInput->Poll();

//Move Camera
float ForwardUnits = 0;
float SidewardUnits = 0;

//Process keyboard presses
if( DInput->KeyDown( DIK_W ) )
ForwardUnits = 50.0f * DeltaTime;
if( DInput->KeyDown( DIK_S ) )
ForwardUnits = -50.0f * DeltaTime;
if( DInput->KeyDown( DIK_A ) )
SidewardUnits = -50.0f * DeltaTime;
if( DInput->KeyDown( DIK_D ) )
SidewardUnits = 50.0f * DeltaTime;

//Process mouse button presses
if( DInput->MouseButtonDown(0) )
ForwardUnits = 50.0f * DeltaTime;
if( DInput->MouseButtonDown(1) )
ForwardUnits = -50.0f * DeltaTime;

//Rotate Camera
ActiveCamera->Pitch -= DInput->MouseState.lY * DeltaTime * 0.1f;
ActiveCamera->Yaw -= DInput->MouseState.lX * DeltaTime * 0.1f;

//Update the camera
ActiveCamera->UpdateCamera(ForwardUnits, SidewardUnits);

//Update the active view
D3DDevice->SetTransform(D3DTS_VIEW, &ActiveCamera->View);

//Create the environment map texture
RenderSceneIntoEnvMap(LightPosition);

D3DDevice->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x00000000, 1.0f, 0 );
D3DDevice->BeginScene();

//Render the teapot with environment mapping
RenderFinalScene();

D3DDevice->EndScene();
D3DDevice->Present( NULL, NULL, NULL, NULL );
}

///////////////////////////////////////////////////////
// WindowProc
///////////////////////////////////////////////////////
LRESULT CALLBACK WindowProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
switch( msg )
{
case WM_KEYDOWN:
{
if( wParam == VK_ESCAPE )
{
PostQuitMessage(0);
break;
}
}
break;

case WM_CLOSE:
{
PostQuitMessage(0);
}

case WM_DESTROY:
{
PostQuitMessage(0);
}
break;

default:
{
return DefWindowProc( hWnd, msg, wParam, lParam );
}
break;
}
return 0;
}

///////////////////////////////////////////////////////
// InitializeDirect3D
///////////////////////////////////////////////////////
void InitializeDirect3D( void )
{
IDirect3D9* D3D = NULL;

D3D = Direct3DCreate9( D3D_SDK_VERSION );

if( !D3D )
{
if( D3D != NULL )
D3D->Release();

::MessageBox(0, "Direct3DCreate9() - Failed", 0, 0);
return;
}

D3DDISPLAYMODE d3ddm;

if( FAILED( D3D->GetAdapterDisplayMode( D3DADAPTER_DEFAULT, &d3ddm ) ) )
{
if( D3D != NULL )
D3D->Release();

::MessageBox(0, "GetAdapterDisplayMode() - Failed", 0, 0);
return;
}

HRESULT hr;

if( FAILED( hr = D3D->CheckDeviceFormat( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
d3ddm.Format, D3DUSAGE_DEPTHSTENCIL,
D3DRTYPE_SURFACE, D3DFMT_D16 ) ) )
{
if( hr == D3DERR_NOTAVAILABLE )
{
if( D3D != NULL )
D3D->Release();

::MessageBox(0, "CheckDeviceFormat() - Failed", 0, 0);
return;
}
}

D3DCAPS9 d3dCaps;

if( FAILED( D3D->GetDeviceCaps( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &d3dCaps ) ) )
{
if( D3D != NULL )
D3D->Release();

::MessageBox(0, "GetDeviceCaps() - Failed", 0, 0);
return;
}

DWORD dwBehaviorFlags = 0;

// Use hardware vertex processing if supported, otherwise default to software
if( d3dCaps.VertexProcessingCaps != 0 )
dwBehaviorFlags |= D3DCREATE_HARDWARE_VERTEXPROCESSING;
else
dwBehaviorFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;

// All system checks passed, create the device

D3DPRESENT_PARAMETERS d3dpp;
memset(&d3dpp, 0, sizeof(d3dpp));

d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.Windowed = TRUE;
d3dpp.EnableAutoDepthStencil = TRUE;
d3dpp.BackBufferHeight = (UINT)ScreenHeight;
d3dpp.BackBufferWidth = (UINT)ScreenWidth;
d3dpp.AutoDepthStencilFormat = D3DFMT_D24X8; // D3DFMT_D24S8;
d3dpp.Flags = D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL;
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE;

if( FAILED( D3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd,
dwBehaviorFlags, &d3dpp, &D3DDevice ) ) )
{
if( D3D != NULL )
D3D->Release();

::MessageBox(0, "CreateDevice() - Failed", 0, 0);
return;
}

// No longer needed, release it
if( D3D != NULL )
D3D->Release();
}

///////////////////////////////////////////////////////
// WinMain
///////////////////////////////////////////////////////
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{
WNDCLASSEX winClass;
MSG uMsg;

memset(&uMsg,0,sizeof(uMsg));

winClass.lpszClassName = "MainWindow";
winClass.cbSize = sizeof(WNDCLASSEX);
winClass.style = CS_HREDRAW | CS_VREDRAW;
winClass.lpfnWndProc = WindowProc;
winClass.hInstance = hInstance;
winClass.hIcon = ::LoadIcon(0, IDI_APPLICATION);
winClass.hIconSm = ::LoadIcon(0, IDI_APPLICATION);
winClass.hCursor = LoadCursor(NULL, IDC_ARROW);
winClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
winClass.lpszMenuName = NULL;
winClass.cbClsExtra = 0;
winClass.cbWndExtra = 0;

if( !RegisterClassEx(&winClass) )
return E_FAIL;

hwnd = CreateWindowEx( NULL, "MainWindow",
"HLSL Dynamic Environment Map - by Chris Smith",
WS_OVERLAPPEDWINDOW,
0, 0, (UINT)ScreenWidth, (UINT)ScreenHeight, NULL, NULL, hInstance, NULL );

if( hwnd == NULL )
return E_FAIL;

ShowWindow( hwnd, nCmdShow );
UpdateWindow( hwnd );

InitializeDirect3D();

//Initialize the Direct Input object
DInput = new DirectInput();
DInput->InitializeDirectInput(hInstance, hwnd, DISCL_NONEXCLUSIVE|DISCL_FOREGROUND,
DISCL_EXCLUSIVE|DISCL_FOREGROUND);

Setup();

while( uMsg.message != WM_QUIT )
{
if( PeekMessage( &uMsg, NULL, 0, 0, PM_REMOVE ) )
{
TranslateMessage( &uMsg );
DispatchMessage( &uMsg );
}
else
Render();
}

Cleanup();

UnregisterClass( "MY_WINDOWS_CLASS", winClass.hInstance );

return (int)uMsg.wParam;
}
[/code]

Shader
[code]
float4x4 World;
float4x4 WorldViewProj;
float3 LightPos;

texture ColorTex;
texture CubeShadowTex;

#define SHADOW_EPSILON 0.00005f

sampler ColorSampler = sampler_state
{
Texture = (ColorTex);
MinFilter = LINEAR;
MagFilter = LINEAR;
MipFilter = LINEAR;
};

sampler CubeShadowSampler = sampler_state
{
Texture = (CubeShadowTex);
MinFilter = LINEAR;
MagFilter = LINEAR;
MipFilter = LINEAR;
AddressU = WRAP;
AddressV = WRAP;
};

struct CubeShadowMap_IN
{
float4 Position : POSITION;
float3 Normal : NORMAL;
float2 TexCoord0 : TEXCOORD0;
float3 Tangent : TANGENT;
float3 Binormal : BINORMAL;
};

struct CubeShadowMap_OUT
{
float4 position : POSITION0;
float3 lightDir : TEXCOORD0; // Vector from pixel to light
float2 texCoord : TEXCOORD1;
float2 depth : TEXCOORD2;
};

void VS(in CubeShadowMap_IN IN, out CubeShadowMap_OUT OUT)
{
//Transform the position from view space to homogeneous projection space
OUT.position = mul(IN.Position, WorldViewProj);

//Compute world space position
float4 WorldPos = mul(IN.Position, World);

//Compute light direction
OUT.lightDir = LightPos.xyz - WorldPos.xyz;

// Pass texture coordinates through
OUT.texCoord = IN.TexCoord0;
}

float4 PS(in CubeShadowMap_OUT IN) : COLOR
{
float dd = length(IN.lightDir);

float depth = IN.lightDir / dd;

// Find color of pixel
float smDepth = texCUBE(CubeShadowSampler, IN.lightDir).x;
float4 Color = tex2D(ColorSampler, IN.texCoord);

if(depth > smDepth+SHADOW_EPSILON)
return Color * 0.5f;
else
return Color;
}

technique CubeShadowMap
{
pass P0
{
vertexShader = compile vs_1_1 VS();
pixelShader = compile ps_2_0 PS();
}
}
[/code]

Share this post


Link to post
Share on other sites
DJTN    207
That is an issue that I was having as well. You can play around with the bias, which I think you're calling "shadow_epsilon", to see if you can get the shadow on the back of the object. Scanning over your code I don't see an issue with your technique. You've got the core principles working its just a matter of tweaking.

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