/*
版本信息:
作 者: 郭云
完成日期: 2011:4:5 15:41
文件名称: d:\My Documents\Direct3D_GGYY\02_第二章 Direct3D程序设计基础\phong 光照 + Shadowmap\Main.cpp
摘 要: 生成硬阴影.注意:在生成ShadowMap是要整个场景去渲染而不是只阴影物体.
*/
#include "BaseCommen.h"
#include "Camera/BaseCamera.h"
#include "LensFlare/LensFlare.h"
#define ShadowMap_SIZE (512)
//-----------------------------------------------------------------------------
// Desc: 全局变量
//-----------------------------------------------------------------------------
LPDIRECT3D9 g_pD3D = NULL; //Direct3D对象
LPDIRECT3DDEVICE9 g_pd3dDevice = NULL; //Direct3D设备对象
LPD3DXMESH g_pMeshTiny = NULL; //网格模型
LPDIRECT3DTEXTURE9 g_pTextureTiny = NULL; //纹理
LPDIRECT3DVERTEXBUFFER9 g_pVBCylinder = NULL; //圆柱体
LPDIRECT3DVERTEXBUFFER9 g_pVBFloor = NULL; //地板
LPDIRECT3DTEXTURE9 g_pTextureFloor = NULL; //地板纹理
LPDIRECT3DTEXTURE9 g_pShadowMap = NULL; // 阴影纹理
LPDIRECT3DSURFACE9 g_pDSShadow = NULL; // 深度缓存区表面
LPD3DXEFFECT g_pEffect = NULL; //效果
D3DXMATRIX g_LightViewMat; //灯光处View矩阵
D3DXMATRIX g_CameraViewMat; //摄像机处View矩阵
D3DXMATRIX g_ProjMat; //投影矩阵
D3DXMATRIX g_TinyInitWorld; //Tiny初始化矩阵
float g_TinyRotateY; //旋转角
float g_TinyRadius = 0.0f; //Tiny外接求半径
D3DXMATRIX g_FloorInitWorld; //地板初始矩阵
D3DXMATRIX g_CylinderInitWorld; //圆柱初始矩阵
D3DXVECTOR3 g_LightPos; //聚光灯位置
D3DXVECTOR3 g_LightDir; //聚光灯方向
float g_Theta = 0.0f; //内外锥角
D3DXVECTOR3 g_CameraPos; //Camera位置
//Materail
D3DXVECTOR4 g_MaterailAmbient;
D3DXVECTOR4 g_MaterailDiffuse;
D3DXVECTOR4 g_MaterailSpecular;
//light
D3DXVECTOR4 g_lightAmbient;
D3DXVECTOR4 g_lightDiffuse;
D3DXVECTOR4 g_lightSpecular;
CGeneralCamera g_ModelCamera;
CLensFlare g_LensFlare;
//圆柱顶点格式
struct CYLINDERVERTEX
{
D3DXVECTOR3 pos;
DWORD color;
};
#define CYLINDERFVF (D3DFVF_XYZ | D3DFVF_DIFFUSE)
//地板顶点格式
struct FLOORVERTEX
{
D3DXVECTOR3 pos;
D3DXVECTOR3 nor;
D3DXVECTOR2 tex;
};
#define FLOORFVF (D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1)
//加载Tiny
HRESULT LoadMesh( IDirect3DDevice9* g_pd3dDevice, char* strFileName, ID3DXMesh** ppMesh )
{
ID3DXMesh* pMesh = NULL;
//从文件加载网格模型
::D3DXLoadMeshFromX(strFileName, D3DXMESH_MANAGED, g_pd3dDevice, NULL, NULL, NULL, NULL, &pMesh);
//确保网格模型顶点包含法线信息,以满足光照计算的需要
if( !(pMesh->GetFVF() & D3DFVF_NORMAL) )
{
ID3DXMesh* pTempMesh;
pMesh->CloneMeshFVF( pMesh->GetOptions(),
pMesh->GetFVF() | D3DFVF_NORMAL,
g_pd3dDevice, &pTempMesh );
D3DXComputeNormals( pTempMesh, NULL ); //计算法线
if(NULL != pMesh)
{
pMesh->Release();
pMesh = NULL;
}
pMesh = pTempMesh;
}
//对网格模型进行优化,以提高程序运行性能
DWORD *rgdwAdjacency = NULL;
if(NULL == (rgdwAdjacency = new DWORD[pMesh->GetNumFaces() * 3]))
{
return E_FAIL;
}
pMesh->GenerateAdjacency(1e-6f,rgdwAdjacency);
pMesh->OptimizeInplace(D3DXMESHOPT_VERTEXCACHE, rgdwAdjacency, NULL, NULL, NULL); //优化
if(NULL != rgdwAdjacency)
{
delete []rgdwAdjacency;
rgdwAdjacency = NULL;
}
*ppMesh = pMesh;
return S_OK;
}
//初始化Tiny
HRESULT InitMesh()
{
if(E_FAIL == LoadMesh(g_pd3dDevice, "Media\\tiny\\tiny.x", &g_pMeshTiny))
{
MessageBox(GetForegroundWindow(), "tiny.x isn't loaded!" , "tiny", MB_OK);
abort();
}
//计算中心球的半径和中心点
D3DXVECTOR3* pData;
D3DXVECTOR3 vCenter;
g_pMeshTiny->LockVertexBuffer( 0, (LPVOID*) &pData );
::D3DXComputeBoundingSphere( pData, g_pMeshTiny->GetNumVertices(),
D3DXGetFVFVertexSize( g_pMeshTiny->GetFVF() ), &vCenter,
&g_TinyRadius);
g_pMeshTiny->UnlockVertexBuffer();
g_TinyRadius *= 0.02;
::D3DXMatrixIdentity(&g_TinyInitWorld);
::D3DXMatrixTranslation(&g_TinyInitWorld, -vCenter.x, -vCenter.y, -vCenter.z);
D3DXMATRIX matScale;
D3DXMatrixIdentity( &matScale);
D3DXMatrixScaling(&matScale,0.02,0.02, 0.02);
D3DXMATRIX matRotateX;
D3DXMatrixIdentity( &matRotateX);
D3DXMatrixRotationX(&matRotateX,-D3DX_PI*0.5);
D3DXMATRIX matRotateZ;
D3DXMatrixIdentity( &matRotateZ);
D3DXMatrixRotationZ(&matRotateZ,D3DX_PI);
g_TinyInitWorld = g_TinyInitWorld * matScale * matRotateZ * matRotateX;
//创建网格模型纹理
D3DXCreateTextureFromFileEx( g_pd3dDevice, "Media\\tiny\\tiny_skin.dds", D3DX_DEFAULT, D3DX_DEFAULT,
D3DX_DEFAULT, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED,
D3DX_DEFAULT, D3DX_DEFAULT, 0,
NULL, NULL, &g_pTextureTiny );
return S_OK;
}
void UpdateCamera()
{
g_CameraPos = *g_ModelCamera.GetEyePos();
g_CameraViewMat = *g_ModelCamera.GetViewMatrix();
g_ProjMat = *g_ModelCamera.GetProjMatrix();
D3DXMATRIX MatCameraViewProj;
MatCameraViewProj = g_CameraViewMat * g_ProjMat;
g_pEffect->SetMatrix("matCameraViewProj", &MatCameraViewProj);
//Camera
D3DXVECTOR4 v4(g_CameraPos, 1.0);
g_pEffect->SetVector("vCameraPos", &v4);
g_LensFlare.SetCameraPos(g_CameraPos);
g_LensFlare.SetCameraLookAt(D3DXVECTOR3(0.0, 0.0, 0.0));
}
void UpdateEffectStatic()
{
//LightColor
g_pEffect->SetVector("lightAmbient", &g_lightAmbient);
g_pEffect->SetVector("lightDiffuse", &g_lightDiffuse);
g_pEffect->SetVector("lightSpecular", &g_lightSpecular);
g_pEffect->SetFloat("fCosTheta", cosf(g_Theta));
//material
g_pEffect->SetVector("materialAmbient", &g_MaterailAmbient);
g_pEffect->SetVector("materialDiffuse", &g_MaterailDiffuse);
g_pEffect->SetVector("materialSpecular",&g_MaterailSpecular);
}
HRESULT InitD3D( HWND hWnd )
{
//创建Direct3D对象, 该对象用于创建Direct3D设备对象
if( NULL == ( g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )
return E_FAIL;
//设置D3DPRESENT_PARAMETERS结构, 准备创建Direct3D设备对象
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory( &d3dpp, sizeof(d3dpp) );
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_COPY; //D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferWidth = ShadowMap_SIZE;
d3dpp.BackBufferHeight = ShadowMap_SIZE;
d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8; //D3DFMT_UNKNOWN;
d3dpp.EnableAutoDepthStencil = TRUE; //深度
d3dpp.AutoDepthStencilFormat = D3DFMT_D24X8;
d3dpp.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
//创建Direct3D设备对象
if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp, &g_pd3dDevice ) ) )
{
MessageBox(GetForegroundWindow(), "Fialed to CreateDevice!" , "CreateDevice", MB_OK);
abort();
}
//创建矩阵
::D3DXMatrixIdentity(&g_CameraViewMat);
::D3DXMatrixIdentity(&g_ProjMat);
//Camera
g_CameraPos = D3DXVECTOR3(0.0, 8.0, -20.0);
D3DXVECTOR3 vEye = g_CameraPos;
D3DXVECTOR3 vAt(0.0, -2.0, 0.0);
D3DXVECTOR3 vUp(0.0, 1.0, 0.0);
// ::D3DXMatrixLookAtLH(&g_CameraViewMat, &vEye, &vAt, &vUp);
// ::D3DXMatrixPerspectiveFovLH(&g_ProjMat, D3DX_PI * 0.5, 1.0, 1.0, 100.0);
g_ModelCamera.SetViewParam(&vEye, &vAt, &vUp);
g_ModelCamera.SetProjParam(D3DX_PI * 0.5, 1.0, 1.0, 100.0);
g_ModelCamera.UpdateViewMatrix();
g_ModelCamera.UpdateProjMatrix();
//设置视口大小
D3DVIEWPORT9 vp;
vp.X = 0;
vp.Y = 0;
vp.Width = ShadowMap_SIZE;
vp.Height = ShadowMap_SIZE;
vp.MinZ = 0.0f;
vp.MaxZ = 1.0f;
g_pd3dDevice->SetViewport(&vp);
//加载模型
InitMesh();
//加载Floor纹理
if(FAILED(::D3DXCreateTextureFromFile(g_pd3dDevice, "Media\\Desert.jpg", &g_pTextureFloor)))
{
MessageBox(GetForegroundWindow(), "TextureFloor isn't loaded!" , "D3DXCreateTextureFromFile", MB_OK);
abort();
}
D3DXMatrixIdentity(&g_FloorInitWorld); //初始地板矩阵
D3DXMatrixIdentity(&g_CylinderInitWorld); //初始圆