Sign in to follow this  

Shadow maps in DirectX with D3DXCreateSphere()

Recommended Posts

locksleyu    124
I am in the process of learning how to use shadow mapping in Direct3D. I started out with the ShadowMap example in the DirectX 9 SDK, and then tried to apply that same logic to a simple scene with a single spotlight and Sphere (created with D3DXCreateSphere()). However when I try to render the scene I just see the sphere as a single color, with no shading. Does anyone know what could be causing this to happen? I know it would be easier to troubleshoot with the code, but since the code is over 10 pages I'm not sure if its appropriate to post to the message board. I noticed that changes to the default texture I am applying to the object do effect the rendered color, but changes to the light's diffuse color have no effect. I was thinking that maybe I need to some sort of processing to the object created with D3DXCreateSphere() to get it to shade directly, but I'm not sure exactly what needs to be done. Thanks!

Share this post

Link to post
Share on other sites
Grafalgar    548
How did you apply the logic to the sphere? Did you alter the example, did you copy-paste their code into yours ... ?

Also, I believe the D3D SDK sample prevents self-shadowing (though I cannot remember how, to be honest). Try putting a box under the sphere, and see if the sphere's shadow hits the box.

That is assuming the code is working and was correctly integrated. Otherwise, the best answer we can give you with the info provided is "something went wrong in your integration."

Shadow Mapping has a ton of failure points, and if you're not used it it's a pain to figure out what went wrong when it did.

Share this post

Link to post
Share on other sites
locksleyu    124
It looks like I am going to have to put up my source code in order to get detailed help. Sorry about the length - I tried to cut out the unnecessary functions that don't relate.

Thanks again!

CFirstPersonCamera g_LCamera; // Camera obj to help adjust light
#define SHADOWMAP_SIZE 512
#define NUM_OBJ 2

struct CObj
D3DXMATRIXA16 m_mWorld;

CObj g_Obj[NUM_OBJ]; // Scene object meshes

float g_fLightFov = D3DX_PI / 2.0f; // FOV of the spot light (in radian)

camera_t g_Camera;

ID3DXEffect* g_pEffect = NULL; // D3DX effect interface
LPDIRECT3DTEXTURE9 g_pShadowMap = NULL; // Texture to which the shadow map is rendered
LPDIRECT3DSURFACE9 g_pDSShadow = NULL; // Depth-stencil buffer for rendering to shadow map
LPDIRECT3DTEXTURE9 g_pTexDef = NULL; // Default texture for objects
D3DXMATRIXA16 g_mShadowProj; // Projection matrix for shadow map
D3DXMATRIXA16 ProjectionMatrix;
D3DLIGHT9 g_Light; // create the light struct

// this is the function that sets up the lights and materials
void init_light(IDirect3DDevice9* pd3dDevice)
D3DMATERIAL9 material; // create the material struct

ZeroMemory(&g_Light, sizeof(g_Light)); // clear out the struct for use

g_Light.Type = D3DLIGHT_SPOT;

g_Light.Diffuse.r = 1.0f;
g_Light.Diffuse.g = 1.0f;
g_Light.Diffuse.b = 1.0f;
g_Light.Diffuse.a = 1.0f;

D3DVECTOR vecDirection = {0.0f, -1.0f, 0.0f}; // the direction of the light
g_Light.Direction = vecDirection; // set the direction
D3DXVec3Normalize( ( D3DXVECTOR3* )&g_Light.Direction, ( D3DXVECTOR3* )&g_Light.Direction );

D3DVECTOR pos = {0.0f, 5.0f, 0.0f};
g_Light.Position = pos;
g_Light.Range = 100.0f;
g_Light.Theta = D3DX_PI / 4.0f;
g_Light.Phi = D3DX_PI / 4.0f;

pd3dDevice->SetLight(0, &g_Light); // send the light struct properties to light #0
pd3dDevice->LightEnable(0, TRUE); // turn on light #0

ZeroMemory(&material, sizeof(D3DMATERIAL9)); // clear out the struct for use
material.Diffuse.r = material.Ambient.r = 0.0f; // set the material to full red
material.Diffuse.g = material.Ambient.g = 1.0f; // set the material to full green
material.Diffuse.b = material.Ambient.b = 0.0f; // set the material to full blue
material.Diffuse.a = material.Ambient.a = 1.0f; // set the material to full alpha

pd3dDevice->SetMaterial(&material); // set the globably-used material to &material


bool CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, void* pUserContext )
D3DCAPS9 caps;

pDeviceSettings->d3d9.pp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;

// If device doesn't support HW T&L or doesn't support 1.1 vertex shaders in HW
// then switch to SWVP.
if( ( caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT ) == 0 ||
caps.VertexShaderVersion < D3DVS_VERSION( 1, 1 ) )
pDeviceSettings->d3d9.BehaviorFlags = D3DCREATE_SOFTWARE_VERTEXPROCESSING;

return true;

HRESULT CALLBACK OnD3D9CreateDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc,
void* pUserContext )


// setup the projection matrix (this is done at init time because
// this matrix never changes)

D3DXMatrixPerspectiveFovLH(&ProjectionMatrix, PI/8, 640.0/480.0, 1.0f, 5000.0f);
pd3dDevice->SetTransform(D3DTS_PROJECTION, &ProjectionMatrix);

// set the world transformation matrix (we set it here because we're not
// using it - that's why it's an identity matrix - so it doesn't need to
// be set per frame)
D3DXMATRIXA16 WorldTransformMatrix;
pd3dDevice->SetTransform(D3DTS_WORLD, &WorldTransformMatrix);

g_Camera.Location.x = 4;
g_Camera.Location.y = 4;
g_Camera.Location.z = 11;
g_Camera.Rotation = 0;


if( g_pEffect )
V_RETURN( g_pEffect->OnResetDevice() );

// Create the default texture (used when a triangle does not use a texture)
pd3dDevice->CreateTexture( 1, 1, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &g_pTexDef,
g_pTexDef->LockRect( 0, &lr, NULL, 0 );
*( LPDWORD )lr.pBits = D3DCOLOR_RGBA( 255, 255, 255, 255 );
g_pTexDef->UnlockRect( 0 );

// Initialize the camera
g_LCamera.SetScalers( 0.01f, 8.0f );
g_LCamera.SetRotateButtons( false, false, true );

// Set up the view parameters for the camera
D3DXVECTOR3 vFromPt = D3DXVECTOR3( 0.0f, 5.0f, 0.0f );
D3DXVECTOR3 vLookatPt = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
g_LCamera.SetViewParams( &vFromPt, &vLookatPt );

D3DXCreateSphere(pd3dDevice, 1.0f, 100, 100, &g_Obj[0].m_Mesh, NULL);

D3DXMatrixTranslation(&g_Obj[0].m_mWorld, 0.0f, 1.0f, 0.0f);

D3DXCreateBox(pd3dDevice, 4.0f, 0.1f, 4.0f, &g_Obj[1].m_Mesh, NULL);

D3DXMatrixTranslation(&g_Obj[1].m_mWorld, 0.0f, -1.0f, 0.0f);

// set up shadow map effect

V_RETURN(DXUTFindDXSDKMediaFileCch( str, MAX_PATH, L"ShadowMap.fx" ));

// If this fails, there should be debug output as to
// they the .fx file failed to compile
V_RETURN(D3DXCreateEffectFromFile( pd3dDevice, str, NULL, NULL, dwShaderFlags,
NULL, &g_pEffect, NULL ));

// set basic vertex shader

pd3dDevice->SetRenderState(D3DRS_LIGHTING, TRUE);

return S_OK;

// Create any D3D9 resources that won't live through a device reset (D3DPOOL_DEFAULT)
// or that are tied to the back buffer size
HRESULT CALLBACK OnD3D9ResetDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc,
void* pUserContext )


// Restore the effect variables
V_RETURN( g_pEffect->SetVector( "g_vLightDiffuse", ( D3DXVECTOR4* )&g_Light.Diffuse ) );
V_RETURN( g_pEffect->SetFloat( "g_fCosTheta", cosf( g_Light.Theta ) ) );

// Create the shadow map texture
NULL ) );

// Create the depth-stencil buffer to be used with the shadow map
// We do this to ensure that the depth-stencil buffer is large
// enough and has correct multisample type/quality when rendering
// the shadow map. The default depth-stencil buffer created during
// device creation will not be large enough if the user resizes the
// window to a very small size. Furthermore, if the device is created
// with multisampling, the default depth-stencil buffer will not
// work with the shadow map texture because texture render targets
// do not support multisample.
DXUTDeviceSettings d3dSettings = DXUTGetDeviceSettings();
V_RETURN( pd3dDevice->CreateDepthStencilSurface( SHADOWMAP_SIZE,
NULL ) );

// Initialize the shadow projection matrix
D3DXMatrixPerspectiveFovLH( &g_mShadowProj, g_fLightFov, 1, 0.01f, 100.0f );

return S_OK;

// Handle updates to the scene. This is called regardless of which D3D API is used
void CALLBACK OnFrameMove( double fTime, float fElapsedTime, void* pUserContext )

void RenderScene( IDirect3DDevice9* pd3dDevice, bool bRenderShadow, float fElapsedTime, const D3DXMATRIX* pmView, const D3DXMATRIX* pmProj )
UINT cPass;

// Set the projection matrix
V( g_pEffect->SetMatrix( "g_mProj", pmProj ) );

// Update the light parameters in the effect

// Freely moveable light. Get light parameter
// from the light camera.
D3DXVECTOR3 v = *g_LCamera.GetEyePt();
D3DXVec3Transform( &v4, &v, pmView );
V( g_pEffect->SetVector( "g_vLightPos", &v4 ) );
*( D3DXVECTOR3* )&v4 = *g_LCamera.GetWorldAhead();
v4.w = 0.0f; // Set w 0 so that the translation part doesn't come to play
D3DXVec4Transform( &v4, &v4, pmView ); // Direction in view space
D3DXVec3Normalize( ( D3DXVECTOR3* )&v4, ( D3DXVECTOR3* )&v4 );
V( g_pEffect->SetVector( "g_vLightDir", &v4 ) );

// Clear the render buffers
0x000000ff, 1.0f, 0L ) );

if( bRenderShadow )
V( g_pEffect->SetTechnique( "RenderShadow" ) );

// Begin the scene
if( SUCCEEDED( pd3dDevice->BeginScene() ) )
if( !bRenderShadow )
V( g_pEffect->SetTechnique( "RenderScene" ) );

// Render the objects
for( int obj = 0; obj < NUM_OBJ; ++obj )
D3DXMATRIXA16 mWorldView = g_Obj[obj].m_mWorld;
D3DXMatrixMultiply( &mWorldView, &mWorldView, pmView );
V( g_pEffect->SetMatrix( "g_mWorldView", &mWorldView ) );

LPD3DXMESH pMesh = g_Obj[obj].m_Mesh;
V( g_pEffect->Begin( &cPass, 0 ) );
for( UINT p = 0; p < cPass; ++p )
V( g_pEffect->BeginPass( p ) );
D3DXVECTOR4 vDif( 1.0f, 1.0f, 1.0f, 1.0f);
V( g_pEffect->SetVector( "g_vMaterial", &vDif ) );
V( g_pEffect->SetTexture( "g_txScene", g_pTexDef ) )
V( g_pEffect->CommitChanges() );
V( pMesh->DrawSubset( 0 ) );
V( g_pEffect->EndPass() );
V( g_pEffect->End() );

V( pd3dDevice->EndScene() );

void CALLBACK OnD3D9FrameRender( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext )

// Compute the view matrix for the light
// This changes depending on the light mode
// (free movement or attached)
D3DXMATRIXA16 mLightView;
mLightView = *g_LCamera.GetViewMatrix();

// Render the shadow map
V( pd3dDevice->GetRenderTarget( 0, &pOldRT ) );
if( SUCCEEDED( g_pShadowMap->GetSurfaceLevel( 0, &pShadowSurf ) ) )
pd3dDevice->SetRenderTarget( 0, pShadowSurf );
SAFE_RELEASE( pShadowSurf );
if( SUCCEEDED( pd3dDevice->GetDepthStencilSurface( &pOldDS ) ) )
pd3dDevice->SetDepthStencilSurface( g_pDSShadow );

CDXUTPerfEventGenerator g( DXUT_PERFEVENTCOLOR, L"Shadow Map" );
RenderScene( pd3dDevice, true, fElapsedTime, &mLightView, &g_mShadowProj );

if( pOldDS )
pd3dDevice->SetDepthStencilSurface( pOldDS );
pd3dDevice->SetRenderTarget( 0, pOldRT );

// Now that we have the shadow map, render the scene.
// const D3DXMATRIX* pmView = g_bCameraPerspective ? g_VCamera.GetViewMatrix() :

D3DXMATRIXA16 ViewMatrix;

// set the view matrix
D3DXVECTOR3 EyePoint(g_Camera.Location.x, g_Camera.Location.y, g_Camera.Location.z);
D3DXVECTOR3 LookAt(0.0f,0.0f, 0.0f);
D3DXVECTOR3 UpVector(0.0f, 1.0f, 0.0f);
D3DXMatrixLookAtLH(&ViewMatrix, &EyePoint, &LookAt, &UpVector);

const D3DXMATRIX* pmView = &ViewMatrix;

// Initialize required parameter
V( g_pEffect->SetTexture( "g_txShadow", g_pShadowMap ) );
// Compute the matrix to transform from view space to
// light projection space. This consists of
// the inverse of view matrix * view matrix of light * light projection matrix
D3DXMATRIXA16 mViewToLightProj;
mViewToLightProj = *pmView;
D3DXMatrixInverse( &mViewToLightProj, NULL, &mViewToLightProj );
D3DXMatrixMultiply( &mViewToLightProj, &mViewToLightProj, &mLightView );
D3DXMatrixMultiply( &mViewToLightProj, &mViewToLightProj, &g_mShadowProj );
V( g_pEffect->SetMatrix( "g_mViewToLightProj", &mViewToLightProj ) );

CDXUTPerfEventGenerator g( DXUT_PERFEVENTCOLOR, L"Scene" );
RenderScene( pd3dDevice, false, fElapsedTime, pmView, &ProjectionMatrix );
g_pEffect->SetTexture( "g_txShadow", NULL );

// Enable run-time memory check for debug builds.
#if defined(DEBUG) | defined(_DEBUG)

// Set the callback functions
DXUTSetCallbackD3D9DeviceAcceptable( IsD3D9DeviceAcceptable );
DXUTSetCallbackD3D9DeviceCreated( OnD3D9CreateDevice );
DXUTSetCallbackD3D9DeviceReset( OnD3D9ResetDevice );
DXUTSetCallbackD3D9FrameRender( OnD3D9FrameRender );
DXUTSetCallbackD3D9DeviceLost( OnD3D9LostDevice );
DXUTSetCallbackD3D9DeviceDestroyed( OnD3D9DestroyDevice );
DXUTSetCallbackDeviceChanging( ModifyDeviceSettings );
DXUTSetCallbackMsgProc( MsgProc );
DXUTSetCallbackFrameMove( OnFrameMove );

// TODO: Perform any application-level initialization here

// Initialize DXUT and create the desired Win32 window and Direct3D device for the application
DXUTInit( true, true ); // Parse the command line and show msgboxes
DXUTSetHotkeyHandling( true, true, true ); // handle the default hotkeys
DXUTSetCursorSettings( true, true ); // Show the cursor and clip it when in full screen
DXUTCreateWindow( L"EmptyProject" );
DXUTCreateDevice( true, 640, 480 );

// Start the render loop

// TODO: Perform any application-level cleanup here

return DXUTGetExitCode();

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