DX9龙书的学习笔记第一弹,主要讲解如何从零开始绘制出一个矩形,也是DX9使用的入门。建议有一定WIN32编程和3D数学的基础知识。学完这本之后就可以慢慢的读些图形学的论文和REAL-TIME RENDERING 3RD了。
关于库文件和头文件的路径设置请参考龙书,这里不再赘述。本文并不使用由该书作者提供的d3dUtility.h和d3dUtility.cpp,不过下一篇开始应该就会使用,因为这两个文件提供了创建DX9程序所需的最基本的定义和操作,可以避免重复劳动,让我们更加专注于新的内容。
本文使用的是vs2010,DirectX SDK版本Microsoft DirectX SDK (June 2010),应该也是目前最新的版本了。
程序基本流程如下:
1. 首先创建一个WIN32空项目,设计,注册并创建一个标题为“First DX9”,大小为640*480的主窗口。
2. 初始化DX9,即使用Direct3Dcreate方法创建对象,D3D_SDK_VERSION为当前SDK版本。并测试图像硬件性能,建议不要略过这一步。
3. 填充D3DPRESENT_PARAMETERS结构,该结构定义了Direct3D设备的信息
4. 创建Direct3D设备,也就代表着我们的图形卡(第一个参数就表示使用哪一块图形卡,默认为当前正在使用的)
5. 创建顶点缓存,按程序中的顺序定义好6个顶点(实质为4个),注意第二个三角顺序有错的话绘制会出现问题(这里我们并不使用索引缓存,各位同学可以自己试试)
6. 设定虚拟摄像机和观察目标的位置,
7. 设置投影矩阵,具体的原理可以参考其他资料。
8. 开始进行绘制,在开始之前应调用BeginScene()方法,而在绘制结束后,必须调用EndScene()方法,两者必须成对出现。这里采用DrawPrimitive进行绘制,方式为D3DPT_TRIANGLELIST,用来绘制一系列三角形,与其他几种方式的区别大家可以参考http://blog.csdn.net/lsmdiao0812/article/details/3166410
另外填充方式这里用的是D3DFILL_WIREFRAME,如果采用SOLID方式,那么就看不出矩形是有两个三角组成的了。
9. 最后进入窗口的消息循环。
10. 退出消息循环返回之前,应当释放Direct3D资源。
代码如下:
#include <Windows.h>
#include <stdio.h>
#include <d3dx9.h>
using namespace std;
#pragma comment(lib,"d3dx9.lib")
#pragma comment(lib,"d3d9.lib")
#pragma comment(lib,"winmm.lib")
IDirect3DVertexBuffer9* VB = 0;
IDirect3DIndexBuffer9* IB = 0;
// Vertex struct
struct Vertex
{
Vertex(){}
Vertex(float x, float y, float z)
{
_x = x; _y = y; _z = z;
}
float _x, _y, _z;
static const DWORD FVF;
};
const DWORD Vertex::FVF = D3DFVF_XYZ; //灵活顶点格式
LRESULT CALLBACK Dx9WndProc(
HWND hwnd, // handle to window
UINT uMsg, // message identifier
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
);
int WINAPI WinMain(
HINSTANCE hInstance, // handle to current instance
HINSTANCE hPrevInstance, // handle to previous instance
LPSTR lpCmdLine, // command line
int nCmdShow // show state
)
{
WNDCLASSEX wndcls;
wndcls.cbSize = sizeof(WNDCLASSEX);
wndcls.cbClsExtra=0;
wndcls.cbWndExtra=0;
wndcls.hbrBackground=(HBRUSH)(COLOR_WINDOW+1);//(HBRUSH)GetStockObject(WHITE_BRUSH);
wndcls.hCursor=LoadCursor(NULL,IDC_CROSS);
wndcls.hIcon=LoadIcon(NULL,IDI_APPLICATION);
wndcls.hIconSm = LoadIcon(NULL,IDI_APPLICATION);
wndcls.hInstance=hInstance;
wndcls.lpfnWndProc=Dx9WndProc;
wndcls.lpszClassName="DX9";
wndcls.lpszMenuName=NULL;
wndcls.style=CS_HREDRAW | CS_VREDRAW;
RegisterClassEx(&wndcls);
HWND hwnd;
hwnd=CreateWindow("DX9","First DX9",WS_OVERLAPPEDWINDOW,
0,0,640,480,NULL,NULL,hInstance,NULL);
// Step1: Dx9 Init
IDirect3D9* pd3d9 = NULL;
pd3d9 = Direct3DCreate9(D3D_SDK_VERSION);
if( !pd3d9 )
{
::MessageBox(0, "Direct3DCreate9() - FAILED", 0, 0);
return false;
}
// Step 2: Check for hardware vp and pixel shaders
D3DCAPS9 caps;
pd3d9->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps);
int vp = 0;
if( caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT )
vp = D3DCREATE_HARDWARE_VERTEXPROCESSING;
else
vp = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
ShowWindow(hwnd,SW_SHOWNORMAL);//显示窗口
UpdateWindow(hwnd);
// Step 3: Fill out the D3DPRESENT_PARAMETERS structure.
D3DPRESENT_PARAMETERS d3dpp;
d3dpp.BackBufferWidth = 640;
d3dpp.BackBufferHeight = 480;
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 = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;//立即提交缓存
// Step 4: Create the device
LPDIRECT3DDEVICE9 g_pd3dDevice = NULL;
if( FAILED( pd3d9->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp, &g_pd3dDevice ) ) )
{
pd3d9->Release(); // done with d3d9 object
::MessageBox(0, "CreateDevice() - FAILED", 0, 0);
return false;
}
// Clear the back buffer to a blue color
//g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(255,0,0), 1.0f, 0 );
//g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
// Step 5: Create vertex buffer
g_pd3dDevice->CreateVertexBuffer(
8 * sizeof(Vertex),
D3DUSAGE_WRITEONLY,
Vertex::FVF,
D3DPOOL_MANAGED,
&VB,
0);
// Step 6: define unique vertices
Vertex* vertices;
VB->Lock(0, 0, (void**)&vertices, 0);
// vertices of rectangle
vertices[0] = Vertex(-1.0f, -1.0f, -1.0f); //左下,Z轴坐标相等(在同一XY平面)
vertices[1] = Vertex(-1.0f, 1.0f, -1.0f); //左上
vertices[2] = Vertex( 1.0f, 1.0f, -1.0f); //右上
vertices[3] = Vertex( 1.0f, -1.0f, -1.0f); //右下
vertices[4] = Vertex(-1.0f, -1.0f, -1.0f);//左下
vertices[5] = Vertex( 1.0f, 1.0f, -1.0f);//右上
VB->Unlock();
// step7: set the position and aim the camera.
D3DXVECTOR3 position(0.0f, 0.0f, -5.0f);
D3DXVECTOR3 target(0.0f, 0.0f, 0.0f);
D3DXVECTOR3 up(0.0f, 1.0f, 0.0f);//上方
D3DXMATRIX V;
D3DXMatrixLookAtLH (&V, &position, &target, &up); //设置摄像机
g_pd3dDevice->SetTransform(D3DTS_VIEW, &V);
// step8: Set the projection matrix.
D3DXMATRIX proj;
D3DXMatrixPerspectiveFovLH(
&proj,
D3DX_PI * 0.5f, // 90 - degree
640 / 480,
1.0f,
1000.0f);
g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &proj);
//
// Switch to wireframe mode.
//
g_pd3dDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);
g_pd3dDevice->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0);
g_pd3dDevice->BeginScene();
g_pd3dDevice->SetStreamSource(0, VB, 0, sizeof(Vertex)); //设置数据源
g_pd3dDevice->SetIndices(IB);
g_pd3dDevice->SetFVF(Vertex::FVF);
g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, 2); //绘制矩阵实质是绘制两个三角形
g_pd3dDevice->EndScene();
g_pd3dDevice->Present(0, 0, 0, 0);
MSG msg;
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
if (NULL != g_pd3dDevice)
{
g_pd3dDevice->Release();
}
if (NULL !=pd3d9)
{
pd3d9->Release();
}
return 0;
}
LRESULT CALLBACK Dx9WndProc(
HWND hwnd, // handle to window
UINT uMsg, // message identifier
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
)
{
switch(uMsg)
{
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd,uMsg,wParam,lParam);
}
return 0;
}
结果如下:
需要说明的是本文的编程风格并不好,主要是为了说明从零开始绘制一个矩形的步骤流程,实际使用时建议将绘制过程放在消息循环里,在没有消息到来时进行绘制。
更新完毕,另外祝贺拜仁夺冠。