【遊戲程式設計】Direct 3DAlpha融合
阿新 • • 發佈:2018-12-12
執行結果:
原始碼:
#include <d3d9.h> #include <d3dx9.h> #include <tchar.h> #include "DirectInputClass.h" #define WINDOW_WIDTH 800 #define WINDOW_HEIGHT 600 #define WINDOW_TITLE L"Direct 3DAlpha融合" //---------------------------------------【全域性變數宣告部分】------------------------------------------------ //描述:全域性變數的宣告 //----------------------------------------------------------------------------------------------------------- LPDIRECT3DDEVICE9 g_pd3dDevice; //Direct 3D裝置物件 D3DXMATRIX g_matWorld; //世界矩陣 DirectInputClass *g_pDInput; //一個DirectInput類的指標 LPD3DXFONT g_pTextAdapterName; //顯示卡名字的2D文字 LPD3DXFONT g_pTextHelpter; //幫助文字的2D文字 LPD3DXFONT g_pTextInfor; //繪製資訊的2D文字 LPD3DXFONT g_pTextFPS; //FPS文字的2D文字 wchar_t g_strAdapterName[60]; //包括顯示卡名字的字串 wchar_t g_strFPS[50]; //包含幀頻率的字元陣列 LPD3DXMESH g_pMesh; //網格物件 D3DMATERIAL9 *g_pMaterials; //網格的材質資訊 LPDIRECT3DTEXTURE9 *g_pTextures; //網格的紋理資訊 DWORD g_dwNumMtrls; //材質的數目 LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); HRESULT Direct3D_Init(HWND); //在這個函式中繼續Direct3D的初始化 HRESULT Objects_Init(HWND); //在這個函式中進行要繪製的物體的資源初始化 void Direct3D_Render(HWND); //在這個函式中進行Direct3D渲染程式碼的書寫 void Direct3D_ClearUp(); //在這個函式中清理COM資源以及其他資源 void Direct3D_Update(); float Get_FPS(); void Matrix_Set(); //----------------------------------------【WinMain()函式】------------------------------------------------- //描述:Windows應用程式的入口函式 //------------------------------------------------------------------------------------------------------------- int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPreInstance, LPSTR lpCmdLine, int nCmdShow) { WNDCLASSEX wndClass = {0}; wndClass.cbSize = sizeof(WNDCLASSEX); wndClass.style = CS_HREDRAW | CS_VREDRAW; wndClass.lpfnWndProc = (WNDPROC)WndProc; wndClass.cbClsExtra = 0; wndClass.cbWndExtra = 0; wndClass.hInstance = hInstance; wndClass.hIcon = (HICON)LoadImage(NULL, L"icon.ico", IMAGE_ICON, 0, 0, LR_LOADFROMFILE | LR_DEFAULTSIZE); wndClass.hCursor = LoadCursor(NULL, IDC_ARROW); wndClass.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH); wndClass.lpszMenuName = NULL; wndClass.lpszClassName = L"3DGameBase"; if(!RegisterClassEx(&wndClass)) return -1; HWND hWnd = CreateWindow(L"3DGameBase", WINDOW_TITLE, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, WINDOW_WIDTH, WINDOW_HEIGHT, NULL, NULL, hInstance, NULL); MoveWindow(hWnd, 250, 80, WINDOW_WIDTH, WINDOW_HEIGHT, true); ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); g_pDInput = new DirectInputClass(); g_pDInput->Init(hWnd, hInstance, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE); PlaySound(L"Final Fantasy XIII.wav", NULL, SND_LOOP | SND_ASYNC | SND_FILENAME); if(FAILED(Direct3D_Init(hWnd))) MessageBox(hWnd, L"Direct3D 初始化失敗!", L"訊息視窗", 0); MSG msg = {0}; while(msg.message != WM_QUIT) { if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } else { Direct3D_Update(); Direct3D_Render(hWnd); } } UnregisterClass(L"3DGameBase", wndClass.hInstance); return 0; } LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch(message) { case WM_PAINT: Direct3D_Render(hWnd); ValidateRect(hWnd, NULL); //使視窗區域生效 break; case WM_KEYDOWN: if(wParam == VK_ESCAPE) DestroyWindow(hWnd); break; case WM_DESTROY: //呼叫自定義的資源清理函式Direct3D_ClearUp();進行退出前的資源清理 Direct3D_ClearUp(); PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } //---------------------------------------------【Direct3D_Init()函式】----------------------------------------- //描述:Direct3D初始化函式,進行Direct3D的初始化 //--------------------------------------------------------------------------------------------------------------- HRESULT Direct3D_Init(HWND hWnd) { //--------------------------------------------------------------------------------------------------------------- //【Direct3D初始化步驟一】:建立Direct3D介面物件,以便用該Direct3D物件建立Direct3D裝置物件 //--------------------------------------------------------------------------------------------------------------- LPDIRECT3D9 pD3D = NULL; //Direct3D介面物件的建立。 if((pD3D = Direct3DCreate9(D3D_SDK_VERSION)) == NULL) //初始化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 = 1; 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中,並在顯示卡名稱前加上“當前顯示卡型號:”字串 //定義一個D3DADAPTER_IDENTIFIER9結構體,用於儲存顯示卡資訊 D3DADAPTER_IDENTIFIER9 Adapter; //呼叫GetAdapterIdentifier,獲取顯示卡資訊 if(FAILED(pD3D->GetAdapterIdentifier(0, 0, &Adapter))) return E_FAIL; //顯示卡名稱現在已經在Adapter.Description中了,但是其為char型別,我們要將其轉為wchar_t型別 int len = MultiByteToWideChar(CP_ACP, 0, Adapter.Description, -1, NULL, 0); //這步操作完成後,g_strAdapterName中就為當前我們的顯示卡型別名的wchar_t型字串了 MultiByteToWideChar(CP_ACP, 0, Adapter.Description, -1, g_strAdapterName, len); //定義一個臨時字串,且方便了把"當前顯示卡型號:"字串引入我們的目的字串中 wchar_t tempName[50] = L"當前顯示卡型號:"; //把當前我們的顯示卡名加到“當前顯示卡型號:”字串後面,結果存在TempName中 wcscat_s(tempName, g_strAdapterName); //把TempName中的結果拷貝到全域性變數g_strAdapterName中 wcscpy_s(g_strAdapterName, tempName); SAFE_RELEASE(pD3D); //LPDIRECT3D9介面物件的使命完成,將其釋放掉 if(FAILED(Objects_Init(hWnd))) // 呼叫一次Objects_Init,進行渲染資源的初始化 return E_FAIL; return S_OK; } //------------------------------------------【Objects_Init()】函式--------------------------------------------- //描述:渲染資源初始化函式,在此函式中進行要被渲染的物體的資源的初始化 //--------------------------------------------------------------------------------------------------------------- HRESULT Objects_Init(HWND hWnd) { //建立字型 if(FAILED(D3DXCreateFont(g_pd3dDevice, 36, 0, 0, 1000, false, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, 0, L"Calibri", &g_pTextFPS))) return E_FAIL; if(FAILED(D3DXCreateFont(g_pd3dDevice, 20, 0, 0, 1000, false, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, 0, L"華文中宋", &g_pTextAdapterName))) return E_FAIL; if(FAILED(D3DXCreateFont(g_pd3dDevice, 23, 0, 0, 1000, false, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, 0, L"微軟雅黑", &g_pTextHelpter))) return E_FAIL; if(FAILED(D3DXCreateFont(g_pd3dDevice, 26, 0, 0, 1000, false, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, 0, L"黑體", &g_pTextInfor))) return E_FAIL; LPD3DXBUFFER pAdjBuffer; LPD3DXBUFFER pMtrlBuffer; //從X檔案中載入網格資料 D3DXLoadMeshFromX(L"69.X", D3DXMESH_MANAGED, g_pd3dDevice, &pAdjBuffer, &pMtrlBuffer, NULL, &g_dwNumMtrls, &g_pMesh); g_pMaterials = new D3DMATERIAL9[g_dwNumMtrls]; g_pTextures = new LPDIRECT3DTEXTURE9[g_dwNumMtrls]; //讀取材質和紋理資料 //建立一個D3DXMATERIAL結構體用於讀取材質和紋理資訊 D3DXMATERIAL *pMtrls = (D3DXMATERIAL *)pMtrlBuffer->GetBufferPointer(); for(DWORD i = 0; i < g_dwNumMtrls; ++i) { //讀取材質 g_pMaterials[i] = pMtrls[i].MatD3D; //設定材質的Alpha分量 g_pMaterials[i].Diffuse.a = 0.3; //建立一下紋理物件 g_pTextures[i] = NULL; } SAFE_RELEASE(pAdjBuffer); SAFE_RELEASE(pMtrlBuffer); //設定光照 D3DLIGHT9 light; ZeroMemory(&light, sizeof(light)); light.Type = D3DLIGHT_DIRECTIONAL; light.Ambient = D3DXCOLOR(0.5f, 0.5f, 0.5f, 1.0f); light.Diffuse = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f); light.Specular = D3DXCOLOR(0.0f, 0.0f, 0.0f, 1.0f); light.Direction = D3DXVECTOR3(1.0f, 0.0f, 1.0f); g_pd3dDevice->SetLight(0, &light); g_pd3dDevice->LightEnable(0, true); Matrix_Set(); g_pd3dDevice->SetRenderState(D3DRS_NORMALIZENORMALS, true); g_pd3dDevice->SetRenderState(D3DRS_SPECULARENABLE, true); //三部曲之一,開啟Alpha融合 g_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, true); //三部曲之二,設定融合因子 g_pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); g_pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); //三部曲之三.設定融合運算方式(預設ADD) g_pd3dDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD); return S_OK; } void Matrix_Set() { D3DXMATRIX matView; D3DXVECTOR3 vEye(0.0f, 100.0f, -200.0f); D3DXVECTOR3 vAt(0.0f, 0.0f, 0.0f); D3DXVECTOR3 vUp(0.0f, 1.0f, 0.0f); D3DXMatrixLookAtLH(&matView, &vEye, &vAt, &vUp); g_pd3dDevice->SetTransform(D3DTS_VIEW, &matView); D3DXMATRIX matProj; D3DXMatrixPerspectiveFovLH(&matProj, D3DX_PI / 4.0f, (float)WINDOW_WIDTH/WINDOW_HEIGHT, 1.0f, 1000.0f); g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &matProj); D3DVIEWPORT9 vp; vp.X = 0; vp.Y = 0; vp.Width = WINDOW_WIDTH; vp.Height = WINDOW_HEIGHT; vp.MinZ = 0.0f; vp.MaxZ = 1.0f; g_pd3dDevice->SetViewport(&vp); } void Direct3D_Update() { //使用DirectInput類讀取資料 g_pDInput->GetInput(); //通過按鍵的按下來控制漫反射Alpha分量值的變化。 if(g_pDInput->IsKeyDown(DIK_1)) { for(DWORD i = 0; i < g_dwNumMtrls; ++i) g_pMaterials[i].Diffuse.a += 0.001f; } if(g_pDInput->IsKeyDown(DIK_2)) { for(DWORD i = 0; i < g_dwNumMtrls; ++i) g_pMaterials[i].Diffuse.a -= 0.001f; } //按住滑鼠左鍵並拖動,為平移操作 static float fPosX = 0.0f, fPosY = -50.0f, fPosZ = 0.0f; if(g_pDInput->IsMouseButtonDown(0)) { fPosX += g_pDInput->MouseDX() * 0.08f; fPosY -= g_pDInput->MouseDY() * 0.08f; } //滑鼠滾輪,為觀察點收縮操作 fPosZ -= g_pDInput->MouseDZ() * 0.02f; //A,W,S,D鍵平移物體 if(g_pDInput->IsKeyDown(DIK_W)) fPosY += 0.08f; if(g_pDInput->IsKeyDown(DIK_S)) fPosY -= 0.08f; if(g_pDInput->IsKeyDown(DIK_A)) fPosX -= 0.08f; if(g_pDInput->IsKeyDown(DIK_D)) fPosX += 0.08f; D3DXMatrixTranslation(&g_matWorld, fPosX, fPosY, fPosZ); // 按住滑鼠右鍵並拖動,為旋轉操作 static float fAngleX = 0.0f, fAngleY = 0.0f; if(g_pDInput->IsMouseButtonDown(1)) { fAngleX -= g_pDInput->MouseDY() * 0.01f; fAngleY -= g_pDInput->MouseDX() * 0.01f; } //上下左右鍵旋轉物體 if(g_pDInput->IsKeyDown(DIK_UP)) fAngleX += 0.005f; if(g_pDInput->IsKeyDown(DIK_DOWN)) fAngleX -= 0.005f; if(g_pDInput->IsKeyDown(DIK_LEFT)) fAngleY -= 0.005f; if(g_pDInput->IsKeyDown(DIK_RIGHT)) fAngleY += 0.005f; D3DXMATRIX Rx, Ry; D3DXMatrixRotationX(&Rx, fAngleX); D3DXMatrixRotationY(&Ry, fAngleY); g_matWorld = Rx * Ry * g_matWorld; g_pd3dDevice->SetTransform(D3DTS_WORLD, &g_matWorld); } //-----------------------------------------【Get_FPS()函式】--------------------------------------------------- //描述:用於計算幀頻率 //--------------------------------------------------------------------------------------------------------------- float Get_FPS() { //定義四個靜態變數 static int frameCount = 0; //幀數 static float currentTime = 0; //當前時間 static float lastTime = 0; //上次計算幀頻率的時間 static float fps = 0; //需要計算的fps值 ++frameCount; //每呼叫一次此函式,幀數加一 //獲取系統時間, timeGetTime() 返回系統時間,以毫秒為單位,乘以0.001得到秒 currentTime = timeGetTime() * 0.001f; //如果當前時間減去之前計算幀頻率的時間大於1秒鐘,就進行幀頻率的更新,並將幀數歸零 if(currentTime - lastTime > 1.0f) //將時間控制在1秒鐘 { fps = frameCount / (currentTime - lastTime); //計算這一秒的fps值 frameCount = 0; //將本次幀數清零 lastTime = currentTime; //將當前時間賦給上次計算幀頻率的時間,作為下一秒的基準時間 } return fps; } //----------------------------------------【Direct3D_Render()函式】-------------------------------------------- //描述:使用Direct3D進行渲染 //--------------------------------------------------------------------------------------------------------------- void Direct3D_Render(HWND hWnd) { //--------------------------------------------------------------------------------------------------------------- //【Direct3D渲染步驟一】:清屏操作 //--------------------------------------------------------------------------------------------------------------- g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER|D3DCLEAR_STENCIL, D3DCOLOR_XRGB(0,0,0), 1.0f, 0); //定義一個矩形,用來獲取主視窗矩形 RECT formatRect; GetClientRect(hWnd, &formatRect); //--------------------------------------------------------------------------------------------------------------- //【Direct3D渲染步驟二】:開始繪製 //--------------------------------------------------------------------------------------------------------------- g_pd3dDevice->BeginScene(); //開始繪製 //--------------------------------------------------------------------------------------------------------------- //【Direct3D渲染步驟三】:正式繪製 //--------------------------------------------------------------------------------------------------------------- //繪製3D模型 //用一個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); //繪製此部分 } //在縱座標250處寫文字 //在視窗右上角處,顯示每秒幀數 swprintf_s(g_strFPS, L"FPS:%.3f", Get_FPS()); g_pTextFPS->DrawText(0, g_strFPS, -1, &formatRect, DT_TOP | DT_RIGHT, D3DCOLOR_XRGB(255,255,255)); //顯示顯示卡型別名 g_pTextAdapterName->DrawText(0, g_strAdapterName, -1, &formatRect, DT_TOP | DT_LEFT, D3DXCOLOR(1.0f, 0.5f, 0.0f, 1.0f)); formatRect.top = 30; static wchar_t strInfor[256] = {0}; // 輸出繪製資訊 swprintf_s(strInfor, L"模型座標:(%.2f, %.2f, %.2f)", g_matWorld._41, g_matWorld._42, g_matWorld._43); g_pTextInfor->DrawText(0, strInfor, -1, &formatRect, DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(135, 239, 136, 255)); // 輸出幫助資訊 formatRect.top = 380; g_pTextHelpter->DrawText(0, L"控制說明:", -1, &formatRect, DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(235,123,230,255)); formatRect.top += 35; g_pTextHelpter->DrawText(0, L" 按住滑鼠左鍵並拖動:平移模型", -1, &formatRect, DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(255,200,0,255)); formatRect.top += 25; g_pTextHelpter->DrawText(0, L" 按住滑鼠右鍵並拖動:旋轉模型", -1, &formatRect, DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(255,200,0,255)); formatRect.top += 25; g_pTextHelpter->DrawText(0, L" 按住滑鼠滾輪:拉伸模型", -1, &formatRect, DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(255,200,0,255)); formatRect.top += 25; g_pTextHelpter->DrawText(0, L" W、S、A、D鍵:平移模型 ", -1, &formatRect, DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(255,200,0,255)); formatRect.top += 25; g_pTextHelpter->DrawText(0, L" 上、下、左、右鍵:旋轉模型 ", -1, &formatRect, DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(255,200,0,255)); formatRect.top += 25; g_pTextHelpter->DrawText(0, L" 數字鍵1和2:增大或縮小材質的Alpha值", -1, &formatRect, DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(255,200,0,255)); formatRect.top += 25; g_pTextHelpter->DrawText(0, L" ESC鍵 : 退出程式", -1, &formatRect, DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(255,200,0,255)); //--------------------------------------------------------------------------------------------------------------- //【Direct3D渲染步驟四】:結束繪製 //--------------------------------------------------------------------------------------------------------------- g_pd3dDevice->EndScene(); //結束繪製 //--------------------------------------------------------------------------------------------------------------- //【Direct3D渲染步驟五】:顯示翻轉 //--------------------------------------------------------------------------------------------------------------- g_pd3dDevice->Present(NULL, NULL, NULL, NULL); //翻轉與顯示 } //------------------------------------------------【 Direct3D_ClearUp函式】------------------------------------------ //描述:資源清理函式,在此函式中進行程式退出前資源的清理工作 //------------------------------------------------------------------------------------------------------------------- void Direct3D_ClearUp() { SAFE_RELEASE(g_pd3dDevice); //釋放COM介面物件 SAFE_RELEASE(g_pTextFPS); SAFE_RELEASE(g_pTextHelpter); SAFE_RELEASE(g_pTextAdapterName); SAFE_RELEASE(g_pTextInfor); SAFE_DELETE(g_pDInput); SAFE_RELEASE(g_pMesh); SAFE_DELETE(g_pMaterials); for(DWORD i = 0; i < g_dwNumMtrls; ++i) SAFE_RELEASE(g_pTextures[i]); SAFE_DELETE(g_pTextures); }