您的位置:首页 > 其它

【寒江雪】Alpha通道混合技术

2016-12-24 03:51 381 查看

Alpha通道与混合技术

  Alpha通道是计算机中存储一张图片的透明和半透明信息的通道。它是一个8位的灰度通道,用256级灰度来记录图像中的透明度信息,定义透明,不透明和半透明区域,其中黑色表示全透明,白色表示不透明,灰表示半透明。

  混合的英文术语为Blending,是计算机图形学中常用的一种技术,即混合像素。我们通常用已经光栅化的像素光栅化同一位置的像素,或者说是在某图元上混合图元。

Direct3D中的融合因子

  在Direct3D中,使用Alpha通道来实现多个像素颜色值的融合。每个像素都包含四个分量:Alpha,红色分量,绿色分量和蓝色分量。其中,Alpha分量用于指定像素的透明度,在0~255之间取值。根据不同的颜色宏的区别,也有可能是在0.0~1.0之间

  在Direct3D中,融合这一领域有一个权威,那便是Alpha融合公式。Alpha融合公式如下:

OutPutColor=(RGBsrc×Ksrc)op(RGBdst×Kdst);

  其中,RGBsrc和RGBdst分别表示源像素和目标像素的颜色值,为包含四个颜色分量的颜色值。Ksrc和Kdst分别表示源融合因子和目标融合因子。它们指定了源像素和目标像素的颜色值在融合过程中所占的比例,在[0,1]之间取值。通过源融合因子和目标融合因子,我们能够以多种方式来修改源像素和目标像素的颜色值,从而获得我们满意的最终融合后的颜色值。

  OP表示源和目标的融合运算方式,由D3DBLENDOP枚举体来指定,需要注意的是,它的默认值是源计算结果和目标计算结果相加。

融合运算方式的取法

  我们在SetRenderState中设置参数,第二个参数在D3DBLENDOP枚举体中取值,而第一个参数取D3DRS_BLENDOP

  D3DBLENDOP枚举体的定义如下:

typedef enum D3DBLENDOP{
D3DBLENDOP_ADD = 1,
D3DBLENDOP_SUB = 2,
D3DBLENDOP_REVSUBTRACT = 3,
D3DBLENDOP_MIN = 4,
D3DBLENDOP_MAX = 5,
D3DBLENDOP_FORCE_DWORD = 0x7fffffff
}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              = 1,
D3DBLEND_ONE               = 2,
D3DBLEND_SRCCOLOR          = 3,
D3DBLEND_INVSRCCOLOR       = 4,
D3DBLEND_SRCALPHA          = 5,
D3DBLEND_INVSRCALPHA       = 6,
D3DBLEND_DESTALPHA         = 7,
D3DBLEND_INVDESTALPHA      = 8,
D3DBLEND_DESTCOLOR         = 9,
D3DBLEND_INVDESTCOLOR      = 10,
D3DBLEND_SRCALPHASAT       = 11,
D3DBLEND_BOTHSRCALPHA      = 12,
D3DBLEND_BOTHINVSRCALPHA   = 13,
D3DBLEND_BLENDFACTOR       = 14,
D3DBLEND_INVBLENDFACTOR    = 15,
D3DBLEND_SRCCOLOR2         = 16,
D3DBLEND_INVSRCCOLOR2      = 17,
D3DBLEND_FORCE_DWORD       = 0x7fffffff
} 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(0,D3DTSS_ALPHAARG1,D3DTA_DIFFUSE);
g_pd3dDevice->SetTextureStageState(0,D3DTSS_ALPHAOP,D3DTOP_SELECTARG1);


材质的Alpha分量

  场景中物体没有指定纹理的时候,才会启用材质的Alpha分量。在这种情况下,顶点的Alpha值取决于材质属性中漫反射颜色的Alpha系数以及灯光颜色中的Alpha系数,通过材质和光照中的Alpha系数相互作用,计算得到。我们可以这样来设定某材质的Alpha分量值,这句代码中,我们把这种材质的漫反射颜色值的Alpha分量设为了0.2

g_pMaterials.Diffuse.a=0.2f;


纹理的Alpha分量

  作为不可一世的“高富帅”——纹理,既然它在物体表面上使用了,就必须首先满足它的要求,那么,像素的Alpha值就是纹理Alpha混合之后的值了。

  所以这时候混合后的像素就取决于纹理的Alpha混合方式。而纹理Alpha混合方式决定了纹理Alpha混合之后的Alpha值是取自材质,还是取自纹理,抑或是取自这两者的某种运算。若是取自纹理,我们就这样写:

g_pd3dDevice->SetTextureStageState(0,D3DTSS_ALPHAARG1,D3DTA_TEXTURE);//Alpha提取自纹理
g_pd3dDevice->SetTextureStageState(0,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 = 800;
const int WINDOW_HEIGHT = 600;
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 = 0.0f; //一个浮点数,表示帧率
wchar_t g_strFPS[50] = { 0 };   //包含帧速率的字符数组
wchar_t g_strAdapterName[60] = { 0 };//包含显卡名称的字符数组

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 = { 0 };
wc.cbClsExtra = 0;
wc.cbSize = sizeof(WNDCLASSEX);
wc.cbWndExtra = 0;
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"寒江雪消息窗口", 0);
}

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 = { 0 };
while (msg.message != WM_QUIT) {
if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else {
Direct3D_Update(hwnd);
Direct3D_Render(hwnd);
}
}
UnregisterClass(L"MainWindow", hInstance);
return 0;
}

HRESULT Direct3D_Init(HWND hwnd)
{
LPDIRECT3D9 d3d9 = NULL;
d3d9 = Direct3DCreate9(D3D_SDK_VERSION);
if (d3d9 == NULL)
return E_FAIL;

D3DCAPS9 caps;
int vp = 0;
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 = 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;

if (FAILED(d3d9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd,vp, &d3dpp, &g_pd3dDevice)))
return E_FAIL;

//////////////////////////////////
//获取显卡信息
wchar_t TempName[60] = L"当前显卡号:";

D3DADAPTER_IDENTIFIER9 Adapter;//定义一个D3DADAPTER_IDENTIFIER9结构体,用于存储显卡信息
d3d9->GetAdapterIdentifier(D3DADAPTER_DEFAULT, 0, &Adapter);//调用GetAdapterIdentifier,获取显卡信息
int len = MultiByteToWideChar(CP_ACP, 0, Adapter.Description, -1, NULL, 0);

MultiByteToWideChar(CP_ACP, 0, Adapter.Description, -1, 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, 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_pTextAdapterName);
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_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 = 0; 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(0.5f, 0.5f, 0.5f, 1.0f);
light.Diffuse= D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f);
light.Specular= D3DXCOLOR(1.0f,1.0f,1.0f,1.0f );
light.Direction = D3DXVECTOR3(0,0, 1.0f);
g_pd3dDevice->SetLight(0, &light);
g_pd3dDevice->LightEnable(0, true);

g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
g_pd3dDevice->SetTextureStageState(0, 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(0, D3DSAMP_MAXANISOTROPY, 3);
g_pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_ANISOTROPIC);
g_pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_ANISOTROPIC);

return S_OK;
}

VOID Direct3D_Update(HWND hwnd)
{
g_pDInput->GetInput();

static FLOAT fPosX = 0.0f;
static FLOAT fPosY = 0.0f;
static FLOAT fPosZ = 0.0f;

if (g_pDInput->GetKeyDown(DIK_1))
{
for (DWORD i = 0; i < g_dwNumMtrls; i++) {
g_pMaterials[i].Diffuse.a += 0.001;
}
}

if (g_pDInput->GetKeyDown(DIK_2))
{
for (DWORD i = 0; i < g_dwNumMtrls; i++)
{
g_pMaterials[i].Diffuse.a -= 0.001;
}
}

if (g_pDInput->GetMouseButtonDown(0))
{
fPosX += (g_pDInput->MouseX())*0.08f;
fPosY += (g_pDInput->MouseY())*-0.08f;
}

//鼠标滚轮,为观察点收缩操作
fPosZ += (g_pDInput->MouseZ())*0.02f;

//键盘按键控制物体的平移
if (g_pDInput->GetKeyDown(DIK_A))fPosX -= 0.005f;
if (g_pDInput->GetKeyDown(DIK_D))fPosX += 0.005;
if (g_pDInput->GetKeyDown(DIK_W))fPosY += 0.005f;
if (g_pDInput->GetKeyDown(DIK_S))fPosY -= 0.005;

D3DXMatrixTranslation(&g_matWorld, fPosX, fPosY, fPosZ);

//按住鼠标右键并拖动,为旋转操作
static FLOAT fAngleX = D3DX_PI/6, fAngleY = D3DX_PI / 6;
if (g_pDInput->GetMouseButtonDown(1))
{
fAngleX += (g_pDInput->MouseX())*-0.01f;
fAngleY += (g_pDInput->MouseY())*0.01f;
}
//键盘按键旋转物体
if (g_pDInput->GetKeyDown(DIK_UP))fAngleX += 0.005f;
if (g_pDInput->GetKeyDown(DIK_DOWN))fAngleX -= 0.005f;
if (g_pDInput->GetKeyDown(DIK_LEFT))fAngleY += 0.005f;
if (g_pDInput->GetKeyDown(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);

Matrix_Set();

return VOID();
}

VOID Direct3D_Render(HWND hwnd)
{

g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,D3DCOLOR_XRGB(100,100,100),1.0f,0.0f);

RECT formatrect;
GetClientRect(hwnd,&formatrect);

//开始绘制
g_pd3dDevice->BeginScene();

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);
}

//在窗口右上角处,显示每秒帧数
int charCount = swprintf(g_strFPS, 20, _T("FPS:%0.3f"), GET_FPS());

g_pTextFPS->DrawText(NULL, g_strFPS, charCount, &formatrect, DT_TOP | DT_RIGHT, D3DCOLOR_XRGB(0, 239, 136, 255));

//显示显卡类型名
g_pTextAdapterName->DrawText(NULL, g_strAdapterName, -1, &formatrect, DT_TOP | DT_LEFT, D3DXCOLOR(1.0f,0.5f,0.0f,1.0f));

//输出绘制信息
formatrect.top = 30;
static wchar_t strInfo[256] = { 0 };
swprintf_s(strInfo, -1, L"模型横坐标:(%.2f,%.2f,%.2f)", g_matWorld._41, g_matWorld._42, g_matWorld._43);

g_pTextInfo->DrawText(NULL, strInfo, -1, &formatrect, DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DXCOLOR(135, 239, 136, 255));

formatrect.left = 0;
formatrect.top = 380;
g_pTextHelper->DrawText(NULL, L"控制说明:", -1, &formatrect, DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(235, 123, 230, 255));

formatrect.top += 25;
g_pTextHelper->DrawText(NULL, L"按住鼠标左键并拖动,平移模型", -1, &formatrect, DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(235, 123, 230, 255));

formatrect.top += 25;
g_pTextHelper->DrawText(NULL, L"按住鼠标右键并拖动,旋转模型", -1, &formatrect, DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(235, 123, 230, 255));

formatrect.top += 25;
g_pTextHelper->DrawText(NULL, L"滑动鼠标滚轮:拉伸模型", -1, &formatrect, DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(235, 123, 230, 255));

formatrect.top += 25;
g_pTextHelper->DrawText(NULL, L"W,S,A,D键:平移模型", -1, &formatrect, DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(235, 123, 230, 255));

formatrect.top += 25;
g_pTextHelper->DrawText(NULL, L"上下左右方向键:旋转模型", -1, &formatrect, DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(235, 123, 230, 255));

formatrect.top += 25;
g_pTextHelper->DrawText(NULL, L"键盘上1,2,3,4数字键:在四种寻址模式之间切换", -1, &formatrect, DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(235, 123, 230, 255));

formatrect.top += 25;
g_pTextHelper->DrawText(NULL, L"ESC 键盘:退出程序", -1, &formatrect, DT_SINGLELINE | DT_NOCLIP | DT_LEFT, D3DCOLOR_RGBA(235, 123, 230, 255));

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(0.0f, 0.0f, -50.0f);//摄像机的位置
D3DXVECTOR3 vAt(0.0f, 0.0f, 0.0f);//观察点的位置
D3DXVECTOR3 vUp(0.0f, 1.0f, 0.0f);//向上的向量
//取景变换矩阵的设置
D3DXMatrixLookAtLH(&view,&vEye,&vAt,&vUp);
g_pd3dDevice->SetTransform(D3DTS_VIEW, &view);

//投影变换矩阵
D3DXMatrixPerspectiveFovLH(&projection, D3DX_PI / 4.0f, (float)((double)WINDOW_WIDTH / WINDOW_HEIGHT), 1.0f, 1000.0f);
g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &projection);

//设置视口变换
vp.Width = WINDOW_WIDTH;
vp.Height = WINDOW_HEIGHT;
vp.X = 0;
vp.Y = 0;
vp.MinZ = 0;
vp.MaxZ = 1;
g_pd3dDevice->SetViewport(&vp);
return VOID();
}

float GET_FPS()
{
static float fps = 0;   //我们需要计算的FPS值
static int frameCount = 0;//帧数
static float currentTime = 0.0f;//当前时间
static float lastTime = 0.0f;//持续时间
frameCount++;
currentTime = timeGetTime()*0.001f;
if (currentTime - lastTime > 1.0f) {
fps = (float)frameCount / (currentTime - lastTime);
lastTime = currentTime;
frameCount = 0;
}
return fps;

return 0.0f;
}

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(0);
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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: