本文章通过一个简单的示例来说明一下一个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();
运行程序,得到结果: