通過調用DirectX SDK庫實現遊戲空間的三維化,也就是我們通常玩的網遊,鼠標拖着主角到處跑去完成任務(個人覺得這種遊戲超無聊)。下面先給出效果圖:
還是先給出其文件目錄吧,從總體把握實例,也是很重要的!
主要代碼如下:
//-----------------------------------【程序說明】----------------------------------------------
// 描述:翱翔於三維空間:第一人稱攝像機的實現 示例程序
// 圖標素材出處: 魔獸爭霸3冰封王座 Dota
// 背景音樂素材出處:雅尼-蘭花
// 人物模型素材出處:真三國無雙6 王元姬 仿製版
//------------------------------------------------------------------------------------------------
//-----------------------------------【宏定義部分】--------------------------------------------
// 描述:定義一些輔助宏
//------------------------------------------------------------------------------------------------
#define WINDOW_WIDTH 932 //爲窗口寬度定義的宏,以方便在此處修改窗口寬度
#define WINDOW_HEIGHT 700 //爲窗口高度定義的宏,以方便在此處修改窗口高度
#define WINDOW_TITLE _T("【致我們永不熄滅的遊戲開發夢想】 翱翔於三維空間:第一人稱攝像機的實現") //爲窗口標題定義的宏
//-----------------------------------【頭文件包含部分】---------------------------------------
// 描述:包含程序所依賴的頭文件
//------------------------------------------------------------------------------------------------
#include <d3d9.h>
#include <d3dx9.h>
#include <tchar.h>
#include <time.h>
#include "DirectInputClass.h"
#include "CameraClass.h"
//-----------------------------------【庫文件包含部分】---------------------------------------
// 描述:包含程序所依賴的庫文件
//------------------------------------------------------------------------------------------------
#pragma comment(lib,"d3d9.lib")
#pragma comment(lib,"d3dx9.lib")
#pragma comment(lib, "dinput8.lib") // 使用DirectInput必須包含的庫文件,注意這裏有8
#pragma comment(lib,"dxguid.lib")
#pragma comment(lib, "winmm.lib")
//定義頂點結構體
struct CUSTOMVERTEX
{
FLOAT _x, _y, _z;
FLOAT _nx, _ny, _nz;
FLOAT _u, _v;
CUSTOMVERTEX(FLOAT x, FLOAT y, FLOAT z,
FLOAT nx, FLOAT ny, FLOAT nz, FLOAT u, FLOAT v)
{
_x = x, _y = y, _z = z;
_nx = nx, _ny = ny, _nz = nz;
_u = u, _v = v;
}
};
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1)
//-----------------------------------【全局變量聲明部分】-------------------------------------
// 描述:全局變量的聲明
//------------------------------------------------------------------------------------------------
LPDIRECT3DDEVICE9 g_pd3dDevice = NULL; //Direct3D設備對象
LPD3DXFONT g_pTextFPS =NULL; //字體COM接口
LPD3DXFONT g_pTextAdaperName = NULL; // 顯卡信息的2D文本
LPD3DXFONT g_pTextHelper = NULL; // 幫助信息的2D文本
LPD3DXFONT g_pTextInfor = NULL; // 繪製信息的2D文本
float g_FPS = 0.0f; //一個浮點型的變量,代表幀速率
wchar_t g_strFPS[50]={0}; //包含幀速率的字符數組
wchar_t g_strAdapterName[60]={0}; //包含顯卡名稱的字符數組
D3DXMATRIX g_matWorld; //世界矩陣
DInputClass* g_pDInput = NULL; //一個DInputClass類的指針
CameraClass* g_pCamera = NULL;
LPD3DXMESH g_pMesh = NULL; // 網格對象
D3DMATERIAL9* g_pMaterials = NULL; // 網格的材質信息
LPDIRECT3DTEXTURE9* g_pTextures = NULL; // 網格的紋理信息
DWORD g_dwNumMtrls = 0; // 材質的數目
LPD3DXMESH g_cylinder = NULL; //柱子網格對象
D3DMATERIAL9 g_MaterialCylinder; //材質
LPDIRECT3DVERTEXBUFFER9 g_pVertexBuffer = NULL; //繪製草地的頂點緩存對象
LPDIRECT3DTEXTURE9 g_pTexture = NULL; //繪製草地的紋理對象
//-----------------------------------【全局函數聲明部分】-------------------------------------
// 描述:全局函數聲明,防止“未聲明的標識”系列錯誤
//------------------------------------------------------------------------------------------------
LRESULT CALLBACK WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam );
HRESULT Direct3D_Init(HWND hwnd,HINSTANCE hInstance);
HRESULT Objects_Init();
void Direct3D_Render( HWND hwnd);
void Direct3D_Update( HWND hwnd);
void Direct3D_CleanUp( );
float Get_FPS();
void HelpText_Render(HWND hwnd);
//-----------------------------------【WinMain( )函數】--------------------------------------
// 描述:Windows應用程序的入口函數,我們的程序從這裏開始
//------------------------------------------------------------------------------------------------
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nShowCmd)
{
//開始設計一個完整的窗口類
WNDCLASSEX wndClass = { 0 }; //用WINDCLASSEX定義了一個窗口類,即用wndClass實例化了WINDCLASSEX,用於之後窗口的各項初始化
wndClass.cbSize = sizeof( WNDCLASSEX ) ; //設置結構體的字節數大小
wndClass.style = CS_HREDRAW | CS_VREDRAW; //設置窗口的樣式
wndClass.lpfnWndProc = WndProc; //設置指向窗口過程函數的指針
wndClass.cbClsExtra = 0;
wndClass.cbWndExtra = 0;
wndClass.hInstance = hInstance; //指定包含窗口過程的程序的實例句柄。
wndClass.hIcon=(HICON)::LoadImage(NULL,_T("icon.ico"),IMAGE_ICON,0,0,LR_DEFAULTSIZE|LR_LOADFROMFILE); //從全局的::LoadImage函數從本地加載自定義ico圖標
wndClass.hCursor = LoadCursor( NULL, IDC_ARROW ); //指定窗口類的光標句柄。
wndClass.hbrBackground=(HBRUSH)GetStockObject(GRAY_BRUSH); //爲hbrBackground成員指定一個灰色畫刷句柄
wndClass.lpszMenuName = NULL; //用一個以空終止的字符串,指定菜單資源的名字。
wndClass.lpszClassName = _T("ForTheDreamOfGameDevelop"); //用一個以空終止的字符串,指定窗口類的名字。
if( !RegisterClassEx( &wndClass ) ) //設計完窗口後,需要對窗口類進行註冊,這樣才能創建該類型的窗口
return -1;
HWND hwnd = CreateWindow( _T("ForTheDreamOfGameDevelop"),WINDOW_TITLE, //喜聞樂見的創建窗口函數CreateWindow
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, WINDOW_WIDTH,
WINDOW_HEIGHT, NULL, NULL, hInstance, NULL );
//Direct3D資源的初始化,調用失敗用messagebox予以顯示
if (!(S_OK==Direct3D_Init (hwnd,hInstance)))
{
MessageBox(hwnd, _T("Direct3D初始化失敗~!"), _T("淺墨的消息窗口"), 0); //使用MessageBox函數,創建一個消息窗口
}
PlaySound(L"雅尼 - 蘭花.wav", NULL, SND_FILENAME | SND_ASYNC|SND_LOOP); //循環播放背景音樂
MoveWindow(hwnd,200,10,WINDOW_WIDTH,WINDOW_HEIGHT,true); //調整窗口顯示時的位置,窗口左上角位於屏幕座標(200,10)處
ShowWindow( hwnd, nShowCmd ); //調用Win32函數ShowWindow來顯示窗口
UpdateWindow(hwnd); //對窗口進行更新,就像我們買了新房子要裝修一樣
//進行DirectInput類的初始化
g_pDInput = new DInputClass();
g_pDInput->Init(hwnd,hInstance,DISCL_FOREGROUND | DISCL_NONEXCLUSIVE,DISCL_FOREGROUND | DISCL_NONEXCLUSIVE);
//消息循環過程
MSG msg = { 0 }; //初始化msg
while( msg.message != WM_QUIT ) //使用while循環
{
if( PeekMessage( &msg, 0, 0, 0, PM_REMOVE ) ) //查看應用程序消息隊列,有消息時將隊列中的消息派發出去。
{
TranslateMessage( &msg ); //將虛擬鍵消息轉換爲字符消息
DispatchMessage( &msg ); //該函數分發一個消息給窗口程序。
}
else
{
Direct3D_Update(hwnd); //調用更新函數,進行畫面的更新
Direct3D_Render(hwnd); //調用渲染函數,進行畫面的渲染
}
}
UnregisterClass(_T("ForTheDreamOfGameDevelop"), wndClass.hInstance);
return 0;
}
//-----------------------------------【WndProc( )函數】--------------------------------------
// 描述:窗口過程函數WndProc,對窗口消息進行處理
//------------------------------------------------------------------------------------------------
LRESULT CALLBACK WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam ) //窗口過程函數WndProc
{
switch( message ) //switch語句開始
{
case WM_PAINT: // 客戶區重繪消息
Direct3D_Render(hwnd); //調用Direct3D_Render函數,進行畫面的繪製
ValidateRect(hwnd, NULL); // 更新客戶區的顯示
break; //跳出該switch語句
case WM_KEYDOWN: // 鍵盤按下消息
if (wParam == VK_ESCAPE) // ESC鍵
DestroyWindow(hwnd); // 銷燬窗口, 併發送一條WM_DESTROY消息
break;
case WM_DESTROY: //窗口銷燬消息
Direct3D_CleanUp(); //調用Direct3D_CleanUp函數,清理COM接口對象
PostQuitMessage( 0 ); //向系統表明有個線程有終止請求。用來響應WM_DESTROY消息
break; //跳出該switch語句
default: //若上述case條件都不符合,則執行該default語句
return DefWindowProc( hwnd, message, wParam, lParam ); //調用缺省的窗口過程來爲應用程序沒有處理的窗口消息提供缺省的處理。
}
return 0; //正常退出
}
//-----------------------------------【Direct3D_Init( )函數】----------------------------------
// 描述:Direct3D初始化函數,進行Direct3D的初始化
//------------------------------------------------------------------------------------------------
HRESULT Direct3D_Init(HWND hwnd,HINSTANCE hInstance)
{
//--------------------------------------------------------------------------------------
// 【Direct3D初始化四步曲之一,創接口】:創建Direct3D接口對象, 以便用該Direct3D對象創建Direct3D設備對象
//--------------------------------------------------------------------------------------
LPDIRECT3D9 pD3D = NULL; //Direct3D接口對象的創建
if( NULL == ( pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) ) //初始化Direct3D接口對象,並進行DirectX版本協商
return E_FAIL;
//--------------------------------------------------------------------------------------
// 【Direct3D初始化四步曲之二,取信息】:獲取硬件設備信息
//--------------------------------------------------------------------------------------
D3DCAPS9 caps; int vp = 0;
if( FAILED( pD3D->GetDeviceCaps( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps ) ) )
{
return E_FAIL;
}
if( caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT )
vp = D3DCREATE_HARDWARE_VERTEXPROCESSING; //支持硬件頂點運算,我們就採用硬件頂點運算,妥妥的
else
vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING; //不支持硬件頂點運算,無奈只好採用軟件頂點運算
//--------------------------------------------------------------------------------------
// 【Direct3D初始化四步曲之三,填內容】:填充D3DPRESENT_PARAMETERS結構體
//--------------------------------------------------------------------------------------
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof(d3dpp));
d3dpp.BackBufferWidth = WINDOW_WIDTH;
d3dpp.BackBufferHeight = WINDOW_HEIGHT;
d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8;
d3dpp.BackBufferCount = 2;
d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
d3dpp.MultiSampleQuality = 0;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow = hwnd;
d3dpp.Windowed = true;
d3dpp.EnableAutoDepthStencil = true;
d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;
d3dpp.Flags = 0;
d3dpp.FullScreen_RefreshRateInHz = 0;
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
//--------------------------------------------------------------------------------------
// 【Direct3D初始化四步曲之四,創設備】:創建Direct3D設備接口
//--------------------------------------------------------------------------------------
if(FAILED(pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
hwnd, vp, &d3dpp, &g_pd3dDevice)))
return E_FAIL;
//獲取顯卡信息到g_strAdapterName中,並在顯卡名稱之前加上“當前顯卡型號:”字符串
wchar_t TempName[60]=L"當前顯卡型號:"; //定義一個臨時字符串,且方便了把"當前顯卡型號:"字符串引入我們的目的字符串中
D3DADAPTER_IDENTIFIER9 Adapter; //定義一個D3DADAPTER_IDENTIFIER9結構體,用於存儲顯卡信息
pD3D->GetAdapterIdentifier(0,0,&Adapter);//調用GetAdapterIdentifier,獲取顯卡信息
int len = MultiByteToWideChar(CP_ACP,0, Adapter.Description, -1, NULL, 0);//顯卡名稱現在已經在Adapter.Description中了,但是其爲char類型,我們要將其轉爲wchar_t類型
MultiByteToWideChar(CP_ACP, 0, Adapter.Description, -1, g_strAdapterName, len);//這步操作完成後,g_strAdapterName中就爲當前我們的顯卡類型名的wchar_t型字符串了
wcscat_s(TempName,g_strAdapterName);//把當前我們的顯卡名加到“當前顯卡型號:”字符串後面,結果存在TempName中
wcscpy_s(g_strAdapterName,TempName);//把TempName中的結果拷貝到全局變量g_strAdapterName中,大功告成~
if(!(S_OK==Objects_Init())) return E_FAIL;
SAFE_RELEASE(pD3D) //LPDIRECT3D9接口對象的使命完成,我們將其釋放掉
return S_OK;
}
//-----------------------------------【Object_Init( )函數】--------------------------------------
// 描述:渲染資源初始化函數,在此函數中進行要被渲染的物體的資源的初始化
//--------------------------------------------------------------------------------------------------
HRESULT Objects_Init()
{
//創建字體
D3DXCreateFont(g_pd3dDevice, 36, 0, 0, 1000, false, DEFAULT_CHARSET,
OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, 0, _T("Calibri"), &g_pTextFPS);
D3DXCreateFont(g_pd3dDevice, 20, 0, 1000, 0, false, DEFAULT_CHARSET,
OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, 0, L"華文中宋", &g_pTextAdaperName);
D3DXCreateFont(g_pd3dDevice, 23, 0, 1000, 0, false, DEFAULT_CHARSET,
OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, 0, L"微軟雅黑", &g_pTextHelper);
D3DXCreateFont(g_pd3dDevice, 26, 0, 1000, 0, false, DEFAULT_CHARSET,
OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, 0, L"黑體", &g_pTextInfor);
// 從X文件中加載網格數據
LPD3DXBUFFER pAdjBuffer = NULL;
LPD3DXBUFFER pMtrlBuffer = NULL;
D3DXLoadMeshFromX(L"WYJ.X", D3DXMESH_MANAGED, g_pd3dDevice,
&pAdjBuffer, &pMtrlBuffer, NULL, &g_dwNumMtrls, &g_pMesh);
// 讀取材質和紋理數據
D3DXMATERIAL *pMtrls = (D3DXMATERIAL*)pMtrlBuffer->GetBufferPointer(); //創建一個D3DXMATERIAL結構體用於讀取材質和紋理信息
g_pMaterials = new D3DMATERIAL9[g_dwNumMtrls];
g_pTextures = new LPDIRECT3DTEXTURE9[g_dwNumMtrls];
for (DWORD i=0; i<g_dwNumMtrls; i++)
{
//獲取材質,並設置一下環境光的顏色值
g_pMaterials[i] = pMtrls[i].MatD3D;
g_pMaterials[i].Ambient = g_pMaterials[i].Diffuse;
//創建一下紋理對象
g_pTextures[i] = NULL;
D3DXCreateTextureFromFileA(g_pd3dDevice, pMtrls[i].pTextureFilename, &g_pTextures[i]);
}
SAFE_RELEASE(pAdjBuffer)
SAFE_RELEASE(pMtrlBuffer)
// 創建一片草坪,50X50=250張紋理
g_pd3dDevice->CreateVertexBuffer(4 * sizeof(CUSTOMVERTEX), 0,
D3DFVF_CUSTOMVERTEX, D3DPOOL_MANAGED, &g_pVertexBuffer, 0);
CUSTOMVERTEX *pVertices = NULL;
g_pVertexBuffer->Lock(0, 0, (void**)&pVertices, 0);
pVertices[0] = CUSTOMVERTEX(-500.0f, 0.0f, -500.0f, 0.0f, 1.0f, 0.0f, 0.0f, 50.0f);
pVertices[1] = CUSTOMVERTEX(-500.0f, 0.0f, 500.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f);
pVertices[2] = CUSTOMVERTEX( 500.0f, 0.0f, -500.0f, 0.0f, 1.0f, 0.0f, 50.0f, 50.0f);
pVertices[3] = CUSTOMVERTEX( 500.0f, 0.0f, 500.0f, 0.0f, 1.0f, 0.0f, 50.0f, 0.0f);
g_pVertexBuffer->Unlock();
// 創建地板紋理
D3DXCreateTextureFromFile(g_pd3dDevice, L"grass.jpg", &g_pTexture);
//創建柱子
D3DXCreateCylinder(g_pd3dDevice, 10.0f, 10.0f, 500.0f, 60, 60, &g_cylinder, 0);
g_MaterialCylinder.Ambient = D3DXCOLOR(0.9f, 0.0f, 0.8f, 1.0f);
g_MaterialCylinder.Diffuse = D3DXCOLOR(0.9f, 0.0f, 0.8f, 1.0f);
g_MaterialCylinder.Specular = D3DXCOLOR(0.9f, 0.2f, 0.9f, 0.9f);
g_MaterialCylinder.Emissive = D3DXCOLOR(0.0f, 0.0f, 0.9f, 1.0f);
// 設置光照
D3DLIGHT9 light;
::ZeroMemory(&light, sizeof(light));
light.Type = D3DLIGHT_DIRECTIONAL;
light.Ambient = D3DXCOLOR(0.7f, 0.7f, 0.7f, 1.0f);
light.Diffuse = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f);
light.Specular = D3DXCOLOR(0.5f, 0.5f, 0.5f, 1.0f);
light.Direction = D3DXVECTOR3(1.0f, 0.0f, 0.0f);
g_pd3dDevice->SetLight(0, &light);
g_pd3dDevice->LightEnable(0, true);
g_pd3dDevice->SetRenderState(D3DRS_NORMALIZENORMALS, true);
g_pd3dDevice->SetRenderState(D3DRS_SPECULARENABLE, true);
// 創建並初始化虛擬攝像機
g_pCamera = new CameraClass(g_pd3dDevice);
g_pCamera->SetCameraPosition(&D3DXVECTOR3(0.0f, 200.0f, -300.0f)); //設置攝像機所在的位置
g_pCamera->SetTargetPosition(&D3DXVECTOR3(0.0f, 300.0f, 0.0f)); //設置目標觀察點所在的位置
g_pCamera->SetViewMatrix(); //設置取景變換矩陣
g_pCamera->SetProjMatrix(); //設置投影變換矩陣
// 設置紋理過濾和紋理尋址方式
g_pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
g_pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
g_pd3dDevice->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);
return S_OK;
}
//-----------------------------------【Direct3D_Update( )函數】--------------------------------
// 描述:不是即時渲染代碼但是需要即時調用的,如按鍵後的座標的更改,都放在這裏
//--------------------------------------------------------------------------------------------------
void Direct3D_Update( HWND hwnd)
{
//使用DirectInput類讀取數據
g_pDInput->GetInput();
// 沿攝像機各分量移動視角
if (g_pDInput->IsKeyDown(DIK_A)) g_pCamera->MoveAlongRightVec(-0.3f);
if (g_pDInput->IsKeyDown(DIK_D)) g_pCamera->MoveAlongRightVec( 0.3f);
if (g_pDInput->IsKeyDown(DIK_W)) g_pCamera->MoveAlongLookVec( 0.3f);
if (g_pDInput->IsKeyDown(DIK_S)) g_pCamera->MoveAlongLookVec(-0.3f);
if (g_pDInput->IsKeyDown(DIK_R)) g_pCamera->MoveAlongUpVec( 0.3f);
if (g_pDInput->IsKeyDown(DIK_F)) g_pCamera->MoveAlongUpVec(-0.3f);
//沿攝像機各分量旋轉視角
if (g_pDInput->IsKeyDown(DIK_LEFT)) g_pCamera->RotationUpVec(-0.003f);
if (g_pDInput->IsKeyDown(DIK_RIGHT)) g_pCamera->RotationUpVec( 0.003f);
if (g_pDInput->IsKeyDown(DIK_UP)) g_pCamera->RotationRightVec(-0.003f);
if (g_pDInput->IsKeyDown(DIK_DOWN)) g_pCamera->RotationRightVec( 0.003f);
if (g_pDInput->IsKeyDown(DIK_Q)) g_pCamera->RotationLookVec( 0.001f);
if (g_pDInput->IsKeyDown(DIK_E)) g_pCamera->RotationLookVec(-0.001f);
//鼠標控制右向量和上向量的旋轉
g_pCamera->RotationUpVec(g_pDInput->MouseDX()* 0.001f);
g_pCamera->RotationRightVec(g_pDInput->MouseDY() * 0.001f);
//鼠標滾輪控制觀察點收縮操作
static FLOAT fPosZ=0.0f;
fPosZ += g_pDInput->MouseDZ()*0.03f;
//計算並設置取景變換矩陣
D3DXMATRIX matView;
g_pCamera->CalculateViewMatrix(&matView);
g_pd3dDevice->SetTransform(D3DTS_VIEW, &matView);
//把正確的世界變換矩陣存到g_matWorld中
D3DXMatrixTranslation(&g_matWorld, 0.0f, 0.0f, fPosZ);
//以下這段代碼用於限制鼠標光標移動區域
POINT lt,rb;
RECT rect;
GetClientRect(hwnd,&rect); //取得窗口內部矩形
//將矩形左上點座標存入lt中
lt.x = rect.left;
lt.y = rect.top;
//將矩形右下座標存入rb中
rb.x = rect.right;
rb.y = rect.bottom;
//將lt和rb的窗口座標轉換爲屏幕座標
ClientToScreen(hwnd,<);
ClientToScreen(hwnd,&rb);
//以屏幕座標重新設定矩形區域
rect.left = lt.x;
rect.top = lt.y;
rect.right = rb.x;
rect.bottom = rb.y;
//限制鼠標光標移動區域
ClipCursor(&rect);
ShowCursor(false); //隱藏鼠標光標
}
//-----------------------------------【Direct3D_Render( )函數】-------------------------------
// 描述:使用Direct3D進行渲染
//--------------------------------------------------------------------------------------------------
void Direct3D_Render(HWND hwnd)
{
//--------------------------------------------------------------------------------------
// 【Direct3D渲染五步曲之一】:清屏操作
//--------------------------------------------------------------------------------------
g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER|D3DCLEAR_STENCIL, D3DCOLOR_XRGB(50, 100, 250), 1.0f, 0);
//--------------------------------------------------------------------------------------
// 【Direct3D渲染五步曲之二】:開始繪製
//--------------------------------------------------------------------------------------
g_pd3dDevice->BeginScene(); // 開始繪製
//--------------------------------------------------------------------------------------
// 【Direct3D渲染五步曲之三】:正式繪製
//--------------------------------------------------------------------------------------
//繪製人物
g_pd3dDevice->SetTransform(D3DTS_WORLD, &g_matWorld);//設置模型的世界矩陣,爲繪製做準備
// 用一個for循環,進行模型的網格各個部分的繪製
for (DWORD i = 0; i < g_dwNumMtrls; i++)
{
g_pd3dDevice->SetMaterial(&g_pMaterials[i]); //設置此部分的材質
g_pd3dDevice->SetTexture(0, g_pTextures[i]);//設置此部分的紋理
g_pMesh->DrawSubset(i); //繪製此部分
}
// 繪製草坪
D3DXMATRIX matWorld;
D3DXMatrixTranslation(&matWorld, 0.0f, 0.0f, 0.0f);
g_pd3dDevice->SetTransform(D3DTS_WORLD, &matWorld);
g_pd3dDevice->SetTexture(0, g_pTexture);
g_pd3dDevice->SetStreamSource(0, g_pVertexBuffer, 0, sizeof(CUSTOMVERTEX));
g_pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX);
g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
//繪製柱子
D3DXMATRIX TransMatrix, RotMatrix, FinalMatrix;
D3DXMatrixRotationX(&RotMatrix, -D3DX_PI * 0.5f);
g_pd3dDevice->SetMaterial(&g_MaterialCylinder);
for(int i = 0; i < 6; i++)
{
D3DXMatrixTranslation(&TransMatrix, -100.0f, 0.0f, -150.0f + (i * 75.0f));
FinalMatrix = RotMatrix * TransMatrix ;
g_pd3dDevice->SetTransform(D3DTS_WORLD, &FinalMatrix);
g_cylinder->DrawSubset(0);
D3DXMatrixTranslation(&TransMatrix, 100.0f, 0.0f, -150.0f + (i * 75.0f));
FinalMatrix = RotMatrix * TransMatrix ;
g_pd3dDevice->SetTransform(D3DTS_WORLD, &FinalMatrix);
g_cylinder->DrawSubset(0);
}
HelpText_Render(hwnd);
//--------------------------------------------------------------------------------------
// 【Direct3D渲染五步曲之四】:結束繪製
//--------------------------------------------------------------------------------------
g_pd3dDevice->EndScene(); // 結束繪製
//--------------------------------------------------------------------------------------
// 【Direct3D渲染五步曲之五】:顯示翻轉
//--------------------------------------------------------------------------------------
g_pd3dDevice->Present(NULL, NULL, NULL, NULL); // 翻轉與顯示
}
//-----------------------------------【HelpText_Render( )函數】-------------------------------
// 描述:封裝了幫助信息的函數
//--------------------------------------------------------------------------------------------------
void HelpText_Render(HWND hwnd)
{
//定義一個矩形,用於獲取主窗口矩形
RECT formatRect;
GetClientRect(hwnd, &formatRect);
//在窗口右上角處,顯示每秒幀數
formatRect.top = 5;
int charCount = swprintf_s(g_strFPS, 20, _T("FPS:%0.3f"), Get_FPS() );
g_pTextFPS->DrawText(NULL, g_strFPS, charCount , &formatRect, DT_TOP | DT_RIGHT, D3DCOLOR_RGBA(0,239,136,255));
//顯示顯卡類型名
g_pTextAdaperName->DrawText(NULL,g_strAdapterName, -1, &formatRect,
DT_TOP | DT_LEFT, D3DXCOLOR(1.0f, 0.5f, 0.0f, 1.0f));
// 輸出幫助信息
formatRect.left = 0,formatRect.top = 380;
g_pTextInfor->DrawText(NULL, L"控制說明:", -1, &formatRect,
DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(235,123,230,255));
formatRect.top += 35;
g_pTextHelper->DrawText(NULL, L" W:向前飛翔 S:向後飛翔 ", -1, &formatRect,
DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(255,200,0,255));
formatRect.top += 25;
g_pTextHelper->DrawText(NULL, L" A:向左飛翔 D:向右飛翔", -1, &formatRect,
DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(255,200,0,255));
formatRect.top += 25;
g_pTextHelper->DrawText(NULL, L" R:垂直向上飛翔 F:垂直向下飛翔", -1, &formatRect,
DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(255,200,0,255));
formatRect.top += 25;
g_pTextHelper->DrawText(NULL, L" Q:向左傾斜 E:向右傾斜", -1, &formatRect,
DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(255,200,0,255));
formatRect.top += 25;
g_pTextHelper->DrawText(NULL, L" 上、下、左、右方向鍵、鼠標移動:視角變化 ", -1, &formatRect,
DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(255,200,0,255));
formatRect.top += 25;
g_pTextHelper->DrawText(NULL, L" 鼠標滾輪:人物模型Y軸方向移動", -1, &formatRect,
DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(255,200,0,255));
formatRect.top += 25;
g_pTextHelper->DrawText(NULL, L" ESC鍵 : 退出程序", -1, &formatRect,
DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(255,200,0,255));
}
//-----------------------------------【Get_FPS( )函數】------------------------------------------
// 描述:用於計算每秒幀速率的一個函數
//--------------------------------------------------------------------------------------------------
float Get_FPS()
{
//定義四個靜態變量
static float fps = 0; //我們需要計算的FPS值
static int frameCount = 0;//幀數
static float currentTime =0.0f;//當前時間
static float lastTime = 0.0f;//持續時間
frameCount++;//每調用一次Get_FPS()函數,幀數自增1
currentTime = timeGetTime()*0.001f;//獲取系統時間,其中timeGetTime函數返回的是以毫秒爲單位的系統時間,所以需要乘以0.001,得到單位爲秒的時間
//如果當前時間減去持續時間大於了1秒鐘,就進行一次FPS的計算和持續時間的更新,並將幀數值清零
if(currentTime - lastTime > 1.0f) //將時間控制在1秒鐘
{
fps = (float)frameCount /(currentTime - lastTime);//計算這1秒鐘的FPS值
lastTime = currentTime; //將當前時間currentTime賦給持續時間lastTime,作爲下一秒的基準時間
frameCount = 0;//將本次幀數frameCount值清零
}
return fps;
}
//-----------------------------------【Direct3D_CleanUp( )函數】--------------------------------
// 描述:對Direct3D的資源進行清理,釋放COM接口對象
//---------------------------------------------------------------------------------------------------
void Direct3D_CleanUp()
{
//釋放COM接口對象
for (DWORD i = 0; i<g_dwNumMtrls; i++)
SAFE_RELEASE(g_pTextures[i]);
SAFE_DELETE(g_pTextures);
SAFE_DELETE(g_pMaterials);
SAFE_DELETE(g_pDInput);
SAFE_RELEASE(g_cylinder);
SAFE_RELEASE(g_pMesh);
SAFE_RELEASE(g_pd3dDevice);
SAFE_RELEASE(g_pTextAdaperName)
SAFE_RELEASE(g_pTextHelper)
SAFE_RELEASE(g_pTextInfor)
SAFE_RELEASE(g_pTextFPS)
SAFE_RELEASE(g_pd3dDevice)
}