Alpha通道與混合技術
Alpha通道是計算機中存儲一張圖檔的透明和半透明資訊的通道。它是一個8位的灰階通道,用256級灰階來記錄圖像中的透明度資訊,定義透明,不透明和半透明區域,其中黑色表示全透明,白色表示不透明,灰表示半透明。
混合的英文術語為Blending,是計算機圖形學中常用的一種技術,即混合像素。我們通常用已經光栅化的像素光栅化同一位置的像素,或者說是在某圖元上混合圖元。
Direct3D中的融合因子
在Direct3D中,使用Alpha通道來實作多個像素顔色值的融合。每個像素都包含四個分量:Alpha,紅色分量,綠色分量和藍色分量。其中,Alpha分量用于指定像素的透明度,在0~255之間取值。根據不同的顔色宏的差別,也有可能是在0.0~1.0之間
在Direct3D中,融合這一領域有一個權威,那便是Alpha融合公式。Alpha融合公式如下:
OutPutColor=(RGB src×K src)op(RGB dst×K dst);
其中,RGB src和RGB dst分别表示源像素和目标像素的顔色值,為包含四個顔色分量的顔色值。K src和K dst分别表示源融合因子和目标融合因子。它們指定了源像素和目标像素的顔色值在融合過程中所占的比例,在[0,1]之間取值。通過源融合因子和目标融合因子,我們能夠以多種方式來修改源像素和目标像素的顔色值,進而獲得我們滿意的最終融合後的顔色值。
OP表示源和目标的融合運算方式,由D3DBLENDOP枚舉體來指定,需要注意的是,它的預設值是源計算結果和目标計算結果相加。
融合運算方式的取法
我們在SetRenderState中設定參數,第二個參數在D3DBLENDOP枚舉體中取值,而第一個參數取D3DRS_BLENDOP
D3DBLENDOP枚舉體的定義如下:
typedef enum D3DBLENDOP{
D3DBLENDOP_ADD = ,
D3DBLENDOP_SUB = ,
D3DBLENDOP_REVSUBTRACT = ,
D3DBLENDOP_MIN = ,
D3DBLENDOP_MAX = ,
D3DBLENDOP_FORCE_DWORD =
}D3DBLENDOP,*LPD3DBLENDOP;
- D3DBLENDOP_ADD:源像素計算結果與目标像素計算結果相加。即【最終結果】=【源】+【目标】
- D3DBLENDOP_SUBTRACT:源像素計算結果與目标像素計算結果相減。即【最終結果】=【源】-【目标】
- D3DBLENDOP_REVSUBTRACT:目标像素的計算結果與源像素計算結果相減。即【最終結果】=【目标】-【源】
- D3DBLENDOP_MIN:在源像素計算結果和目标像素計算結果之間取小者。即【最終結果】=MIN(【源】,【目标】)
- D3DBLENDOP_MAX:在源像素計算結果和目标像素計算結果之間取大者。即【最終結果】=MAX(【源】,【目标】)
融合因子取法
源融合因子和目标融合因子可以在SetRenderState方法中第一個參數取D3DRS_SRCBLEND和D3DRS_DESTBLEND分别進行設定,而第二個參數都是在一個D3DBLEND枚舉體中進行的取值,它的原型如下:
typedef enum D3DBLEND {
D3DBLEND_ZERO = ,
D3DBLEND_ONE = ,
D3DBLEND_SRCCOLOR = ,
D3DBLEND_INVSRCCOLOR = ,
D3DBLEND_SRCALPHA = ,
D3DBLEND_INVSRCALPHA = ,
D3DBLEND_DESTALPHA = ,
D3DBLEND_INVDESTALPHA = ,
D3DBLEND_DESTCOLOR = ,
D3DBLEND_INVDESTCOLOR = ,
D3DBLEND_SRCALPHASAT = ,
D3DBLEND_BOTHSRCALPHA = ,
D3DBLEND_BOTHINVSRCALPHA = ,
D3DBLEND_BLENDFACTOR = ,
D3DBLEND_INVBLENDFACTOR = ,
D3DBLEND_SRCCOLOR2 = ,
D3DBLEND_INVSRCCOLOR2 = ,
D3DBLEND_FORCE_DWORD =
} D3DBLEND, *LPD3DBLEND;
下面通過一個表格來叙述融合因子的含義
* D3DBLEND_ZERO:融合因子(0,0,0,0)
* D3DBLEND_ONE:融合因子(1,1,1,1)
* D3DBLEND_SRCCOLOR:融合因子(Rsrc,Gsrc,Bsrc,Asrc)
* D3DBLEND_INVSRCCOLOR:融合因子(1-Rsrc,1-Gsrc,1-Bsrc,1-Asrc)
* D3DBLEND_SRCALPHASAT:融合因子(1-Asrc,Asrc,Asrc,Asrc)
* D3DBLEND_INVSRCALPHA:融合因子(1-Asrc,1-Asrc,1-Asrc,1-Asrc)
* D3DBLEND_DESTALPHA:融合因子(Adst,Adst,Adst,Adst)
* D3DBLEND_INVDESTALPHA:融合因子(1-Adst,1-Adst,1-Adst,1-Adst)
* D3DBLEND_DESTCOLOR:融合因子(Rdst,Gdst,Bdst,Adst)
* D3DBLEND_INVDESTCOLOR:融合因子(1-Rdst,1-Gdst,1-Bdst,1-Adst)
* D3DBLEND_SRCALPHASAT:融合因子(f,f,f,1),其中f=min(Asrc,1-Asrc)
Alpha的三處來源
源像素和目标像素顔色值的Alpha分量分别來自頂點顔色的Alpha值,材質的Alpha值,紋理的Alpha值。我們通常在這三處源取一處就可以了。它們的優先級如下
紋理>材質>頂點顔色
我們可以通過IDirect3DDevice9::SetTextureStageState方法指定Alpha值的來源,它的原型如下
HRESULT SetTextureStageState(
[in] DWORD Stage,
[in] D3DTEXTURESTAGESTATETYPE Type,
[in] DWORD Value
);
- DWORD Stage:指定目前設定的紋理層為第幾層(0~7)
- D3DTEXTURESTAGESTATETYPE Type:填将要設定的紋理渲染狀态,在枚舉類型D3DTEXTURESTAGESTATETYPE中任意取值。
- DWORD Value:表示所設定的狀态值,它是根據第二個參數來決定具體取什麼值的。
頂點的Alpha分量
如果在程式中指定每個頂點的顔色,那麼可以直接給出每個頂點顔色的Alpha值,并且這些頂點的Alpha值是可以在程式運作過程中動态修改的。
對于頂點Alpha分量,我們就這樣寫:
g_pd3dDevice->SetTextureStageState(,D3DTSS_ALPHAARG1,D3DTA_DIFFUSE);
g_pd3dDevice->SetTextureStageState(,D3DTSS_ALPHAOP,D3DTOP_SELECTARG1);
材質的Alpha分量
場景中物體沒有指定紋理的時候,才會啟用材質的Alpha分量。在這種情況下,頂點的Alpha值取決于材質屬性中漫反射顔色的Alpha系數以及燈光顔色中的Alpha系數,通過材質和光照中的Alpha系數互相作用,計算得到。我們可以這樣來設定某材質的Alpha分量值,這句代碼中,我們把這種材質的漫反射顔色值的Alpha分量設為了0.2
紋理的Alpha分量
作為不可一世的“高富帥”——紋理,既然它在物體表面上使用了,就必須首先滿足它的要求,那麼,像素的Alpha值就是紋理Alpha混合之後的值了。
是以這時候混合後的像素就取決于紋理的Alpha混合方式。而紋理Alpha混合方式決定了紋理Alpha混合之後的Alpha值是取自材質,還是取自紋理,抑或是取自這兩者的某種運算。若是取自紋理,我們就這樣寫:
g_pd3dDevice->SetTextureStageState(,D3DTSS_ALPHAARG1,D3DTA_TEXTURE);//Alpha提取自紋理
g_pd3dDevice->SetTextureStageState(,D3DTSS_ALPHAOP,D3DTOP_SELECTARG1);//将紋理顔色混合的第一個參數的Alpha值用于輸出
Alpha融合使用方法
-
啟用Alpha融合
要啟用Alpha融合,我們可以通過設定D3DRS_ALPHABLENDENABLE渲染狀态為true,即寫上這句代碼:
g_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE,true);
-
設定融合因子
啟用了Alpha融合,第二步便是設定源融合因子和目标融合因子。源融合因子和目标融合因子可以分别在SetRenderState方法中第一個參數取D3DRS_SRCBLEND和D3DRS_DESTBLEND分别進行設定,第二個參數是在一個D3DBLEND枚舉體中取值
g_pd3dDevice->SetRenderState(D3DRS_SRCBLEND,D3DBLEND_SRCALPHA);
g_pd3dDevice->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA);
- 設定Alpha融合運算方式
g_pd3dDevice->SetRenderState(D3DRS_BLENDOP,D3DBLENDOP_SUBTRACT);
示例代碼
#include<Windows.h>
#include<d3dx9.h>
#include<d3d9.h>
#include<time.h>
#include"DirectInput.h"
#pragma comment(lib,"d3dx9.lib")
#pragma comment(lib,"winmm.lib")
#pragma comment(lib,"dxerr.lib")
#pragma comment(lib,"dxguid.lib")
#pragma comment(lib,"d3dx10.lib")
#pragma comment(lib,"d3d9.lib")
#pragma comment(lib,"comctl32.lib")
#define SAFE_RELEASE(p) {if((p)){(p)->Release();(p)=NULL;}}
struct CUSTOMVERTEX
{
FLOAT _x, _y, _z;
FLOAT _u, _v;
CUSTOMVERTEX(FLOAT x, FLOAT y, FLOAT z, FLOAT u, FLOAT v)
:_x(x),_y(y),_z(z),_u(u),_v(v)
{
}
};
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_TEX1)
//全局變量聲明區
const int WINDOW_WIDTH = ;
const int WINDOW_HEIGHT = ;
IDirect3DDevice9 *g_pd3dDevice = NULL;
LPD3DXFONT g_pTextFPS = NULL; //字型COM接口
LPD3DXFONT g_pTextAdapterName = NULL; //顯示卡資訊的2D文本
LPD3DXFONT g_pTextHelper = NULL; //幫助資訊的2D文本
LPD3DXFONT g_pTextInfo = NULL; //繪制資訊的2D文本
float g_FPS = ; //一個浮點數,表示幀率
wchar_t g_strFPS[] = { }; //包含幀速率的字元數組
wchar_t g_strAdapterName[] = { };//包含顯示卡名稱的字元數組
D3DXMATRIX g_matWorld; //世界矩陣
LPDIRECT3DVERTEXBUFFER9 g_pVertexBuffer = NULL; //頂點緩存數組
LPDIRECT3DINDEXBUFFER9 g_pIndexBuffer = NULL; //索引緩存數組
D3DMATERIAL9 *g_pMaterials=NULL;
LPDIRECT3DTEXTURE9 *g_pTextures = NULL;
DWORD g_dwNumMtrls;
LPD3DXMESH g_pMesh = NULL;
LPDIRECT3DTEXTURE9 g_pMipTexture = NULL; //紋理接口對象
DInputClass *g_pDInput = NULL; //一個DInputClass對象
HRESULT Direct3D_Init(HWND hwnd);
HRESULT Object_Init();
VOID Direct3D_Update(HWND hwnd);
VOID Direct3D_Render(HWND hwnd);
VOID Direct3D_CleanUp(HWND hwnd);
VOID Matrix_Set();
float GET_FPS();
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nCmdShow)
{
WNDCLASSEX wc = { };
wc.cbClsExtra = ;
wc.cbSize = sizeof(WNDCLASSEX);
wc.cbWndExtra = ;
wc.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hIcon = NULL;
wc.hIconSm = NULL;
wc.hInstance = hInstance;
wc.lpfnWndProc = WndProc;
wc.lpszClassName = L"MainWindow";
wc.lpszMenuName = NULL;
wc.style = CS_HREDRAW | CS_VREDRAW;
RegisterClassEx(&wc);
HWND hwnd = CreateWindow(L"MainWindow", L"寒江雪", WS_OVERLAPPED, CW_USEDEFAULT, CW_USEDEFAULT, WINDOW_WIDTH, WINDOW_HEIGHT, NULL, NULL, hInstance, NULL);
if (S_OK == Direct3D_Init(hwnd)) {
MessageBox(hwnd, L"DirectX3D 初始化完成", L"寒江雪消息視窗", );
}
g_pDInput = new DInputClass();
g_pDInput->Init(hwnd, hInstance, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE);
PlaySound(L"Through the Arbor.wav", NULL, SND_FILENAME | SND_ASYNC | SND_LOOP); //循環播放背景音樂
ShowWindow(hwnd, SW_SHOW);
UpdateWindow(hwnd);
MSG msg = { };
while (msg.message != WM_QUIT) {
if (PeekMessage(&msg, , , , PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else {
Direct3D_Update(hwnd);
Direct3D_Render(hwnd);
}
}
UnregisterClass(L"MainWindow", hInstance);
return ;
}
HRESULT Direct3D_Init(HWND hwnd)
{
LPDIRECT3D9 d3d9 = NULL;
d3d9 = Direct3DCreate9(D3D_SDK_VERSION);
if (d3d9 == NULL)
return E_FAIL;
D3DCAPS9 caps;
int vp = ;
if (FAILED(d3d9->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps)))
return E_FAIL;
if (caps.DevCaps&D3DDEVCAPS_HWTRANSFORMANDLIGHT)
vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;//支援頂點運算
else
vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof d3dpp);
d3dpp.BackBufferWidth = WINDOW_WIDTH;
d3dpp.BackBufferHeight = WINDOW_HEIGHT;
d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8;
d3dpp.BackBufferCount = ;
d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
d3dpp.MultiSampleQuality = ;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow = hwnd;
d3dpp.Windowed = true;
d3dpp.EnableAutoDepthStencil = true;
d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;
d3dpp.Flags = ;
d3dpp.FullScreen_RefreshRateInHz = ;
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
if (FAILED(d3d9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd,vp, &d3dpp, &g_pd3dDevice)))
return E_FAIL;
//
//擷取顯示卡資訊
wchar_t TempName[] = L"目前顯示卡号:";
D3DADAPTER_IDENTIFIER9 Adapter;//定義一個D3DADAPTER_IDENTIFIER9結構體,用于存儲顯示卡資訊
d3d9->GetAdapterIdentifier(D3DADAPTER_DEFAULT, , &Adapter);//調用GetAdapterIdentifier,擷取顯示卡資訊
int len = MultiByteToWideChar(CP_ACP, , Adapter.Description, -, NULL, );
MultiByteToWideChar(CP_ACP, , Adapter.Description, -, g_strAdapterName, len);
wcscat_s(TempName, g_strAdapterName);
wcscpy_s(g_strAdapterName, TempName);
SAFE_RELEASE(d3d9);
if (FAILED(Object_Init()))
return E_FAIL;
return S_OK;
}
#include<tchar.h>
HRESULT Object_Init()
{
D3DXCreateFont(g_pd3dDevice, , , , , false, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, , _T("Calibri"), &g_pTextFPS);
D3DXCreateFont(g_pd3dDevice, , , , , false, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, , L"楷體", &g_pTextAdapterName);
D3DXCreateFont(g_pd3dDevice, , , , , false, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, , L"楷體", &g_pTextHelper);
D3DXCreateFont(g_pd3dDevice, , , , , false, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, , L"楷體", &g_pTextInfo);
//從X檔案中加載網格資料
LPD3DXBUFFER pAdjBuffer = NULL;
LPD3DXBUFFER pMtrlBuffer = NULL;
D3DXLoadMeshFromX(L"miki.X", D3DXMESH_MANAGED, g_pd3dDevice, &pAdjBuffer,
&pMtrlBuffer, NULL,&g_dwNumMtrls,&g_pMesh);
//讀取材質和紋理資料
D3DXMATERIAL *pMtrls = (D3DXMATERIAL*)pMtrlBuffer->GetBufferPointer();
g_pMaterials = new D3DMATERIAL9[g_dwNumMtrls];
g_pTextures = new LPDIRECT3DTEXTURE9[g_dwNumMtrls];
for (DWORD i = ; i < g_dwNumMtrls; i++) {
g_pMaterials[i] = pMtrls[i].MatD3D;
//g_pMaterials[i].Ambient = g_pMaterials[i].Diffuse;
g_pMaterials[i].Specular = g_pMaterials[i].Diffuse;
//建立下一紋理
g_pTextures[i] = NULL;
//D3DXCreateTextureFromFileA(g_pd3dDevice, pMtrls[i].pTextureFilename, &g_pTextures[i]);
}
SAFE_RELEASE(pAdjBuffer);
SAFE_RELEASE(pMtrlBuffer);
D3DLIGHT9 light;
::ZeroMemory(&light, sizeof(D3DLIGHT9));
light.Type = D3DLIGHT_DIRECTIONAL;
light.Ambient= D3DXCOLOR(, , , );
light.Diffuse= D3DXCOLOR(, , , );
light.Specular= D3DXCOLOR(,,, );
light.Direction = D3DXVECTOR3(,, );
g_pd3dDevice->SetLight(, &light);
g_pd3dDevice->LightEnable(, true);
g_pd3dDevice->SetTextureStageState(, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
g_pd3dDevice->SetTextureStageState(, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
g_pd3dDevice->SetRenderState(D3DRS_NORMALIZENORMALS, true);//初始化頂點法向量
g_pd3dDevice->SetRenderState(D3DRS_SPECULARENABLE, true);
g_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);//開啟背面消隐
g_pd3dDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESS);//将深度測試函數設為D3DCMP_LESS
g_pd3dDevice->SetRenderState(D3DRS_ZWRITEENABLE, true);//深度測試成功後,更新深度緩存
//g_pd3dDevice->SetRenderState(D3DRS_AMBIENT, D3DCOLOR_XRGB(36, 36, 36));//設定環境光
//開啟Alpha融合
g_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, true);
//設定融合因子
g_pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
g_pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
//設定融合運算方式
g_pd3dDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
//各項異性過濾
g_pd3dDevice->SetSamplerState(, D3DSAMP_MAXANISOTROPY, );
g_pd3dDevice->SetSamplerState(, D3DSAMP_MAGFILTER, D3DTEXF_ANISOTROPIC);
g_pd3dDevice->SetSamplerState(, D3DSAMP_MINFILTER, D3DTEXF_ANISOTROPIC);
return S_OK;
}
VOID Direct3D_Update(HWND hwnd)
{
g_pDInput->GetInput();
static FLOAT fPosX = ;
static FLOAT fPosY = ;
static FLOAT fPosZ = ;
if (g_pDInput->GetKeyDown(DIK_1))
{
for (DWORD i = ; i < g_dwNumMtrls; i++) {
g_pMaterials[i].Diffuse.a += ;
}
}
if (g_pDInput->GetKeyDown(DIK_2))
{
for (DWORD i = ; i < g_dwNumMtrls; i++)
{
g_pMaterials[i].Diffuse.a -= ;
}
}
if (g_pDInput->GetMouseButtonDown())
{
fPosX += (g_pDInput->MouseX())*;
fPosY += (g_pDInput->MouseY())*-;
}
//滑鼠滾輪,為觀察點收縮操作
fPosZ += (g_pDInput->MouseZ())*;
//鍵盤按鍵控制物體的平移
if (g_pDInput->GetKeyDown(DIK_A))fPosX -= ;
if (g_pDInput->GetKeyDown(DIK_D))fPosX += ;
if (g_pDInput->GetKeyDown(DIK_W))fPosY += ;
if (g_pDInput->GetKeyDown(DIK_S))fPosY -= ;
D3DXMatrixTranslation(&g_matWorld, fPosX, fPosY, fPosZ);
//按住滑鼠右鍵并拖動,為旋轉操作
static FLOAT fAngleX = D3DX_PI/, fAngleY = D3DX_PI / ;
if (g_pDInput->GetMouseButtonDown())
{
fAngleX += (g_pDInput->MouseX())*-;
fAngleY += (g_pDInput->MouseY())*;
}
//鍵盤按鍵旋轉物體
if (g_pDInput->GetKeyDown(DIK_UP))fAngleX += ;
if (g_pDInput->GetKeyDown(DIK_DOWN))fAngleX -= ;
if (g_pDInput->GetKeyDown(DIK_LEFT))fAngleY += ;
if (g_pDInput->GetKeyDown(DIK_RIGHT))fAngleY -= ;
D3DXMATRIX Rx, Ry;
D3DXMatrixRotationX(&Rx, fAngleX);
D3DXMatrixRotationY(&Ry, fAngleY);
g_matWorld = Rx*Ry*g_matWorld;
g_pd3dDevice->SetTransform(D3DTS_WORLD, &g_matWorld);
Matrix_Set();
return VOID();
}
VOID Direct3D_Render(HWND hwnd)
{
g_pd3dDevice->Clear(, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,D3DCOLOR_XRGB(,,),,);
RECT formatrect;
GetClientRect(hwnd,&formatrect);
//開始繪制
g_pd3dDevice->BeginScene();
for (DWORD i = ; i < g_dwNumMtrls; i++) {
g_pd3dDevice->SetMaterial(&g_pMaterials[i]);
g_pd3dDevice->SetTexture(,g_pTextures[i]);
g_pMesh->DrawSubset(i);
}
//在視窗右上角處,顯示每秒幀數
int charCount = swprintf(g_strFPS, , _T("FPS:%0.3f"), GET_FPS());
g_pTextFPS->DrawText(NULL, g_strFPS, charCount, &formatrect, DT_TOP | DT_RIGHT, D3DCOLOR_XRGB(, , , ));
//顯示顯示卡類型名
g_pTextAdapterName->DrawText(NULL, g_strAdapterName, -, &formatrect, DT_TOP | DT_LEFT, D3DXCOLOR(,,,));
//輸出繪制資訊
formatrect.top = ;
static wchar_t strInfo[] = { };
swprintf_s(strInfo, -, L"模型橫坐标:(%.2f,%.2f,%.2f)", g_matWorld._41, g_matWorld._42, g_matWorld._43);
g_pTextInfo->DrawText(NULL, strInfo, -, &formatrect, DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DXCOLOR(, , , ));
formatrect.left = ;
formatrect.top = ;
g_pTextHelper->DrawText(NULL, L"控制說明:", -, &formatrect, DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(, , , ));
formatrect.top += ;
g_pTextHelper->DrawText(NULL, L"按住滑鼠左鍵并拖動,平移模型", -, &formatrect, DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(, , , ));
formatrect.top += ;
g_pTextHelper->DrawText(NULL, L"按住滑鼠右鍵并拖動,旋轉模型", -, &formatrect, DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(, , , ));
formatrect.top += ;
g_pTextHelper->DrawText(NULL, L"滑動滑鼠滾輪:拉伸模型", -, &formatrect, DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(, , , ));
formatrect.top += ;
g_pTextHelper->DrawText(NULL, L"W,S,A,D鍵:平移模型", -, &formatrect, DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(, , , ));
formatrect.top += ;
g_pTextHelper->DrawText(NULL, L"上下左右方向鍵:旋轉模型", -, &formatrect, DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(, , , ));
formatrect.top += ;
g_pTextHelper->DrawText(NULL, L"鍵盤上1,2,3,4數字鍵:在四種尋址模式之間切換", -, &formatrect, DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(, , , ));
formatrect.top += ;
g_pTextHelper->DrawText(NULL, L"ESC 鍵盤:退出程式", -, &formatrect, DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(, , , ));
g_pd3dDevice->EndScene();
g_pd3dDevice->Present(NULL, NULL, NULL, NULL);
return VOID();
}
VOID Direct3D_CleanUp(HWND hwnd)
{
if (g_pDInput)delete g_pDInput;
SAFE_RELEASE(g_pIndexBuffer);
SAFE_RELEASE(g_pVertexBuffer);
SAFE_RELEASE(g_pTextAdapterName);
SAFE_RELEASE(g_pTextHelper);
SAFE_RELEASE(g_pTextInfo);
SAFE_RELEASE(g_pTextFPS);
SAFE_RELEASE(g_pd3dDevice);
return VOID();
}
VOID Matrix_Set()
{
D3DXMATRIX view;//取景變換矩陣
D3DXMATRIX projection;//投影變換矩陣
D3DVIEWPORT9 vp;//視口變換
D3DXVECTOR3 vEye(, , -);//錄影機的位置
D3DXVECTOR3 vAt(, , );//觀察點的位置
D3DXVECTOR3 vUp(, , );//向上的向量
//取景變換矩陣的設定
D3DXMatrixLookAtLH(&view,&vEye,&vAt,&vUp);
g_pd3dDevice->SetTransform(D3DTS_VIEW, &view);
//投影變換矩陣
D3DXMatrixPerspectiveFovLH(&projection, D3DX_PI / , (float)((double)WINDOW_WIDTH / WINDOW_HEIGHT), , );
g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &projection);
//設定視口變換
vp.Width = WINDOW_WIDTH;
vp.Height = WINDOW_HEIGHT;
vp.X = ;
vp.Y = ;
vp.MinZ = ;
vp.MaxZ = ;
g_pd3dDevice->SetViewport(&vp);
return VOID();
}
float GET_FPS()
{
static float fps = ; //我們需要計算的FPS值
static int frameCount = ;//幀數
static float currentTime = ;//目前時間
static float lastTime = ;//持續時間
frameCount++;
currentTime = timeGetTime()*;
if (currentTime - lastTime > ) {
fps = (float)frameCount / (currentTime - lastTime);
lastTime = currentTime;
frameCount = ;
}
return fps;
return ;
}
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_DESTROY:
Direct3D_CleanUp(hwnd);
PostQuitMessage();
break;
case WM_KEYDOWN:
if (wParam == VK_ESCAPE)
DestroyWindow(hwnd);
break;
default:
return DefWindowProc(hwnd, message, wParam, lParam);
}
//return LRESULT();
}
Copyright© by 寒江雪
Date:2016.12.23