【游戏程序设计】Direct 3D变换
运行结果:
源代码:
#include <d3d9.h>
#include <d3dx9.h>
#include <time.h>
#define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 600
#define WINDOW_TITLE L"Direct 3D变换"
#define SAFE_RELEASE(p) { if(p) {(p)->Release(); (p) = NULL;}} //销毁指针
struct CUSTOMVERTEX
{
float x, y, z;
DWORD color;
};
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ | D3DFVF_DIFFUSE)
//---------------------------------------【全局变量声明部分】------------------------------------------------
//描述:全局变量的声明
//-----------------------------------------------------------------------------------------------------------
LPDIRECT3DDEVICE9 g_pd3dDevice; //Direct 3D设备对象
ID3DXFont* g_pFont; //字体COM接口
LPDIRECT3DVERTEXBUFFER9 g_pVertexBuffer;
LPDIRECT3DINDEXBUFFER9 g_pIndexBuffer;
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 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);
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_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_pd3dDevice->SetRenderState(D3DRS_LIGHTING, false); //关闭光照
SAFE_RELEASE(pD3D); //LPDIRECT3D9接口对象的使命完成,将其释放掉
if(FAILED(Objects_Init(hWnd))) // 调用一次Objects_Init,进行渲染资源的初始化
return E_FAIL;
return S_OK;
}
//---------------------------------------------------------------------------------------------------------------
//------------------------------------------【Objects_Init()】函数---------------------------------------------
//描述:渲染资源初始化函数,在此函数中进行要被渲染的物体的资源的初始化
//---------------------------------------------------------------------------------------------------------------
HRESULT Objects_Init(HWND hWnd)
{
srand(time(NULL)); //设置随机数种子
//创建字体
if(FAILED(D3DXCreateFont(g_pd3dDevice, 72, 0, 0, 1, false, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
DEFAULT_QUALITY, 0, TEXT("微软雅黑"), &g_pFont)))
return E_FAIL;
if(FAILED(g_pd3dDevice->CreateVertexBuffer(8 * sizeof(CUSTOMVERTEX), 0, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT,
&g_pVertexBuffer, NULL)))
return E_FAIL;
if(FAILED(g_pd3dDevice->CreateIndexBuffer(36 * sizeof(WORD), 0, D3DFMT_INDEX16, D3DPOOL_DEFAULT,
&g_pIndexBuffer, NULL)))
return E_FAIL;
CUSTOMVERTEX Vertices[] =
{
{-20.0f, 20.0f, -20.0f, D3DCOLOR_XRGB(rand() % 256, rand() % 256, rand() % 256)},
{-20.0f, 20.0f, 20.0f, D3DCOLOR_XRGB(rand() % 256, rand() % 256, rand() % 256)},
{20.0f, 20.0f, 20.0f, D3DCOLOR_XRGB(rand() % 256, rand() % 256, rand() % 256)},
{20.0f, 20.0f, -20.0f, D3DCOLOR_XRGB(rand() % 256, rand() % 256, rand() % 256)},
{-20.0f, -20.0f, -20.0f, D3DCOLOR_XRGB(rand() % 256, rand() % 256, rand() % 256)},
{-20.0f, -20.0f, 20.0f, D3DCOLOR_XRGB(rand() % 256, rand() % 256, rand() % 256)},
{20.0f, -20.0f, 20.0f, D3DCOLOR_XRGB(rand() % 256, rand() % 256, rand() % 256)},
{20.0f, -20.0f, -20.0f, D3DCOLOR_XRGB(rand() % 256, rand() % 256, rand() % 256)}
};
void *pVertices = NULL;
if(FAILED(g_pVertexBuffer->Lock(0, sizeof(Vertices), &pVertices, 0)))
return E_FAIL;
memcpy(pVertices, Vertices, sizeof(Vertices));
if(FAILED(g_pVertexBuffer->Unlock()))
return E_FAIL;
WORD *pIndices = NULL;
if(FAILED(g_pIndexBuffer->Lock(0, 36*sizeof(WORD), (void**)&pIndices, 0)))
return E_FAIL;
//顶面
pIndices[0] = 0, pIndices[1] = 1, pIndices[2] = 2;
pIndices[3] = 0, pIndices[4] = 2, pIndices[5] = 3;
//前面
pIndices[6] = 0, pIndices[7] = 3, pIndices[8] = 7;
pIndices[9] = 0, pIndices[10] = 7, pIndices[11] = 4;
//左侧面
pIndices[12] = 0, pIndices[13] = 4, pIndices[14] = 5;
pIndices[15] = 0, pIndices[16] = 5, pIndices[17] = 1;
//右侧面
pIndices[18] = 2, pIndices[19] = 6, pIndices[20] = 7;
pIndices[21] = 2, pIndices[22] = 7, pIndices[23] = 3;
//后面
pIndices[24] = 2, pIndices[25] = 5, pIndices[26] = 6;
pIndices[27] = 2, pIndices[28] = 1, pIndices[29] = 5;
//底面
pIndices[30] = 4, pIndices[31] = 6, pIndices[32] = 5;
pIndices[33] = 4, pIndices[34] = 7, pIndices[35] = 6;
if(FAILED(g_pIndexBuffer->Unlock()))
return E_FAIL;
return S_OK;
}
//-------------------------------------------------【 Matrix_Set()函数】-----------------------------------------
//函数中封装了教材中讲到的试图变换,投影变换和视图变换
//---------------------------------------------------------------------------------------------------------------
void Matrix_Set()
{
//---------------------------------------------------------------------------------------------------------------
//视图变换矩阵的设置
//---------------------------------------------------------------------------------------------------------------
D3DXMATRIX matWorld, Rx, Ry, Rz;
D3DXMatrixIdentity(&matWorld); //将矩阵单位化
D3DXMatrixRotationX(&Rx, D3DX_PI * (timeGetTime() / 1000.0f)); //开机时间 绕X轴旋转
D3DXMatrixRotationY(&Ry, D3DX_PI * (timeGetTime() / 1000.0f / 2)); //绕Y轴旋转
D3DXMatrixRotationZ(&Rz, D3DX_PI * (timeGetTime() / 1000.0f / 3)); //绕Z轴旋转
matWorld = Rx * Ry * Rz * matWorld; //得到最终的变换矩阵
g_pd3dDevice->SetTransform(D3DTS_WORLD, &matWorld); //设置变换矩阵
//---------------------------------------------------------------------------------------------------------------
//设置D3DXMatrixLookAtLH函数进行先相关视图变换
//---------------------------------------------------------------------------------------------------------------
D3DXMATRIX matView;
D3DXVECTOR3 vEye(0.0f, 0.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, 1.0f, 1.0f, 1000.f); //计算投影变换矩阵
g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &matProj); //设置投影变换矩阵
//---------------------------------------------------------------------------------------------------------------
//设置视口变换矩阵
//---------------------------------------------------------------------------------------------------------------
D3DVIEWPORT9 vp; //实例化一个D3DVIEWPORT9 的构图,并进行相关的参数设置
vp.X = 0; //视口相对于窗口的X坐标
vp.Y = 0; //视口相对于窗口的Y坐标
vp.Width = WINDOW_WIDTH; //视口的宽度
vp.Height = WINDOW_HEIGHT; //视口的高度
vp.MinZ = 0.0f; //视口深度缓存中最小深度值
vp.MaxZ = 1.0f; //视口深度缓存中最大深度值
g_pd3dDevice->SetViewport(&vp); //视口的设置
}
//----------------------------------------【Direct3D_Render()函数】--------------------------------------------
//描述:使用Direct3D进行渲染
//---------------------------------------------------------------------------------------------------------------
void Direct3D_Render(HWND hWnd)
{
//---------------------------------------------------------------------------------------------------------------
//【Direct3D渲染步骤一】:清屏操作
//---------------------------------------------------------------------------------------------------------------
g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(255,214,158), 1.0f, 0);
//定义一个矩形,用来获取主窗口矩形
RECT formatRect;
GetClientRect(hWnd, &formatRect);
//---------------------------------------------------------------------------------------------------------------
//【Direct3D渲染步骤二】:开始绘制
//---------------------------------------------------------------------------------------------------------------
g_pd3dDevice->BeginScene(); //开始绘制
//---------------------------------------------------------------------------------------------------------------
//【Direct3D渲染步骤三】:正式绘制
//---------------------------------------------------------------------------------------------------------------
Matrix_Set(); //调用该函数进行视图变换,投影变换和视口变换
if(GetAsyncKeyState('1') & 0x8000) //按下1,进行线框绘制
g_pd3dDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);
if(GetAsyncKeyState('2') & 0x8000) //按下1,进行实体绘制
g_pd3dDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
g_pd3dDevice->SetStreamSource(0, g_pVertexBuffer, 0, sizeof(CUSTOMVERTEX));
g_pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX);
g_pd3dDevice->SetIndices(g_pIndexBuffer);
g_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 8, 0, 12);
//---------------------------------------------------------------------------------------------------------------
//【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_pFont);
SAFE_RELEASE(g_pVertexBuffer);
SAFE_RELEASE(g_pIndexBuffer);
}