一個DrectX程式的基本流程(DXD10以下)
阿新 • • 發佈:2018-12-10
本文章通過一個簡單的示例來說明一下一個D3D程式的基本流程
[注]:本程式使用DirectX 9.0實現並使用了Qt,參照的時候不要連結庫連結錯了哦.
示例<使用D3D渲染一個jpg影象到視窗>
步驟:
1、建立一個Windows視窗程式
2、初始化D3D
3、渲染
1、使用VS2010(或其他版本)建立一個標準的WIN32程式. (這個步驟不多做解釋)
2、以下步驟的操作封裝在D3DRender中
步驟2、3:
封裝一個類(D3DRender)
test.h
#include "d3dx9.h" #include "Windows.h" #include <QImage> class D3DRender { private: static int g_DeviceWidth ; static int g_DeviceHeight ; static LPDIRECT3D9 g_pD3D ; //* 用來建立D3D裝置 static LPDIRECT3DDEVICE9 g_pd3dDevice ; //* D3D裝置 static LPDIRECT3DVERTEXBUFFER9 g_pVertexBuffer ; //* 頂點快取 static LPDIRECT3DTEXTURE9 g_pTexture ; //* 紋理 static HWND g_hTargetWin ; //* 目標視窗(也就是該D3D程式的主視窗) static QImage g_TargetImage ; //* 被渲染的圖片 //響應操作 void onKeyDown(WPARAM wParam, LPARAM lParam); void onPaint(HDC hdc); void getWndClassEx(WNDCLASSEX& wc); public: D3DRender(); ~D3DRender(); HRESULT initD3D(HWND hWnd); void render(); void cleanup(); void renderTest(); };
test.cpp
#include "test.h" #include "atldef.h" // .lib files. #pragma comment(lib, "d3d9.lib") #pragma comment(lib, "d3dx9.lib") int D3DRender::g_DeviceWidth = 0; int D3DRender::g_DeviceHeight = 0; LPDIRECT3D9 D3DRender::g_pD3D = 0; //* 用來建立D3D裝置 LPDIRECT3DDEVICE9 D3DRender::g_pd3dDevice = 0; //* D3D裝置 LPDIRECT3DVERTEXBUFFER9 D3DRender::g_pVertexBuffer = 0; //* 頂點快取 LPDIRECT3DTEXTURE9 D3DRender::g_pTexture = 0; //* 紋理 HWND D3DRender::g_hTargetWin = 0; //* 目標視窗(也就是該D3D程式的主視窗) QImage D3DRender::g_TargetImage ; //* 被渲染的圖片 //* 帶RHW 和 Color格式的頂點 struct CustomVertex_RHW_COLOR { float x,y,z,rhw; unsigned long color; }; #define D3DFVF_CUSTOMERTEX_RHW_COLOR (D3DFVF_XYZRHW|D3DFVF_DIFFUSE) //* 帶TEX1格式的頂點 struct CustomVertex_XYZ_TEX1 { float x,y,z; float tu,tv; }; #define D3DFVF_CUSTOMERTEX_XYZ_TEX1 (D3DFVF_XYZ|D3DFVF_TEX1) void D3DRender::cleanup() { if( g_pVertexBuffer != NULL) g_pVertexBuffer->Release(); if( g_pd3dDevice != NULL) g_pd3dDevice->Release(); if( g_pD3D != NULL) g_pD3D->Release(); } void D3DRender::renderTest() { if( NULL == g_pd3dDevice ) return; float fBlue = 0.01024; //* 初始化背景顏色 g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_COLORVALUE(0.0f, 0.0f, fBlue, 1.0f), 1.0f, 0); //* 開始渲染場景 g_pd3dDevice->BeginScene(); //* 獲取需要渲染的緩衝區 LPDIRECT3DSURFACE9 pBackBuffer; g_pd3dDevice->GetRenderTarget(0, &pBackBuffer); //* 如果紋理被建立則將紋理渲染 if(g_pTexture) { //* 渲染到紋理 LPDIRECT3DSURFACE9 pRenderSurface; g_pTexture->GetSurfaceLevel(0, &pRenderSurface); RECT wrt = {0}; GetWindowRect(g_hTargetWin, &wrt); float currentWindowWidth = wrt.right - wrt.left; float currentWindowHeight = wrt.bottom - wrt.top; float currentImageWidth = g_TargetImage.width(); float currentImaeHeight = g_TargetImage.height(); float showImageWidth = currentImageWidth ; float showImageHeight = currentImaeHeight; //D3DVIEWPORT9 viewPort = {0,0, showImageWidth / aspX, showImageHeight / aspY, 0.0f, 1.0f}; //g_pd3dDevice->SetViewport(&viewPort); //* 將圖片資料拷貝到紋理 D3DLOCKED_RECT lockRect; if(SUCCEEDED(pRenderSurface->LockRect(&lockRect, 0, 0))) { unsigned char* pdata = g_TargetImage.bits(); unsigned char* pDstBits = (unsigned char*)lockRect.pBits; int byteCount = g_TargetImage.byteCount(); memcpy(pDstBits, pdata, byteCount); pRenderSurface->UnlockRect(); } // Make sure that the z-buffer and lighting are disabled g_pd3dDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE); g_pd3dDevice->SetRenderState(D3DRS_LIGHTING, FALSE); // Use the alpha channel g_pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); g_pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); g_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); // Draw our quad g_pd3dDevice->SetTexture( 0, g_pTexture ); g_pd3dDevice->SetStreamSource(0, g_pVertexBuffer, 0 ,sizeof(CustomVertex_XYZ_TEX1)); g_pd3dDevice->SetFVF(D3DFVF_CUSTOMERTEX_XYZ_TEX1); // Render target g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); } //* 結束場景渲染 g_pd3dDevice->EndScene(); //* 重新整理 g_pd3dDevice->Present(NULL, NULL, NULL, NULL); } HRESULT D3DRender::initD3D(HWND hWnd) { g_DeviceWidth = 0; g_DeviceHeight = 0; g_pD3D = 0; g_pd3dDevice = 0; g_pVertexBuffer = 0; g_pTexture = 0; g_hTargetWin = hWnd; //* 載入需要渲染的圖片 if(!g_TargetImage.load("D:/SVN/code/output/W3L/res/Image/Common/Test/GameZoneAD.png")) { return E_FAIL; } //* 根據需要轉換格式 //g_TargetImage = g_TargetImage.convertToFormat(QImage::Format_RGBA8888_Premultiplied); BOOL isWindowMode = TRUE; HRESULT hr = E_FAIL; // 建立D3D物件 if( NULL == ( g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) ) return E_FAIL; // 獲取當前的顯示模式 D3DDISPLAYMODE d3ddm; hr = g_pD3D->GetAdapterDisplayMode( D3DADAPTER_DEFAULT, &d3ddm ); if(FAILED(hr)) return E_FAIL; D3DPRESENT_PARAMETERS d3dpp; ZeroMemory( &d3dpp, sizeof(d3dpp) ); d3dpp.hDeviceWindow = hWnd; d3dpp.Windowed = isWindowMode; // 是否全屏模式 //if(isWindowMode) //{ // RECT rt; // GetWindowRect(hWnd,&rt); // d3dpp.BackBufferWidth = rt.right - rt.left ; // d3dpp.BackBufferHeight = rt.bottom - rt.top ; //} //else //{ // d3dpp.BackBufferWidth = d3ddm.Width ; // d3dpp.BackBufferHeight = d3ddm.Height; //} d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; // 設定交換模式 d3dpp.BackBufferFormat = d3ddm.Format; // 設定背景緩衝區格式為當前左面格式 d3dpp.BackBufferCount = 1; // 建立D3D裝置 // 第一個引數:使用預設的顯示卡 // 第二個引數:請求使用硬體抽象層(HAL) // 第三個引數:視窗控制代碼 // 第四個引數:使用軟體處理頂點 // 第五個引數:建立的引數 // 第六個引數:建立的D3D裝置指標 hr = g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &g_pd3dDevice ); if(FAILED(hr)) { return E_FAIL; } //初始化頂點緩衝區 int w = isWindowMode ? d3ddm.Width : d3dpp.BackBufferWidth; int h = isWindowMode ? d3ddm.Height : d3dpp.BackBufferHeight; g_DeviceWidth = w; g_DeviceHeight = h; //* 注意0~1 是寬度1是實際寬度,0是0,大於1就是放大了 CustomVertex_XYZ_TEX1 vertexs[] = { {-1.0f, 1.0f, 0.0f, 0.0f, 0.0f}, { 1.0f, 1.0f, 0.0f, 1.0f, 0.0f}, {-1.0f, -1.0f, 0.0f, 0.0f, 1.0f}, { 1.0f, -1.0f, 0.0f, 1.0f, 1.0f}, }; int vertexsSize = sizeof(vertexs); //* 建立定點快取 LPDIRECT3DVERTEXBUFFER9 pVertexBuffer; hr = g_pd3dDevice->CreateVertexBuffer(vertexsSize, D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMERTEX_XYZ_TEX1, D3DPOOL_DEFAULT, &pVertexBuffer, NULL); if(FAILED(hr)) { return E_FAIL; } g_pVertexBuffer = pVertexBuffer; void* pVertex = 0; pVertexBuffer->Lock(0, vertexsSize, (void**)&pVertex, 0); memcpy(pVertex, vertexs, vertexsSize); pVertexBuffer->Unlock(); //* 初始化紋理 hr = g_pd3dDevice->CreateTexture(g_TargetImage.width(), g_TargetImage.height(), 1, 0, d3ddm.Format, D3DPOOL_MANAGED, &g_pTexture, NULL); if(FAILED(hr)) { return E_FAIL; } return S_OK; } D3DRender::D3DRender() { } D3DRender::~D3DRender() { cleanup(); } void D3DRender::render() { if( NULL == g_pd3dDevice ) return; renderTest(); return ; }
這個D3DRender最好是最為全域性的單例使用。
在WM_CREATE的處理函式中:
D3DRender::Instance()->initD3D(hWnd);
在WM_PAINT的處理函式中
D3DRender::Instance()->render();
執行程式,得到結果: