1、DirectX Tutorials By Andy Pike- 1 -DirectX 8 教程著 Andy P译 Aman JIANGwww.AmanP第一章: 准备就绪What you will need (你需要什么) DirectX 8.0 SDK (可以从 http:/ 下载) VC6(SP5)/VC.NET Windows 程序设计经验 通晓 C+ 和 OOPIntroduction (序)(原著的话)欢迎阅读本 DX 教程。本教程至少能帮你入门、使你了解怎样用 DX8 来开发 Windows 游戏。我写这个教程的原由有二:首先,当出现 DX 时,我还是一个初学者。所以,我想边学习
2、边写一个教程来锻炼自己。其次,对初学者来说,DX SDK 并不是很有帮助。而且,网上也没有什么像样的 Dx8 教程。另外,就像上面我提到的,我也是个初学者,所以,如果你发现教程中有什么地方不对,请给我写信: 。译者言我也是一名初学者,所以,有言在先:如果你读英文能如履平地,建议你还是去读原著。此教程很适合入门,等你入门以后,你会发现,其实一切并没有想象的那样复杂。这是个不错的 Dx8 教程,我会尽最大努力把它翻译好。注:我并没有完全按照原著来译,不适之处,请多包涵。嗯,你应该弄到教程附带的源代码,没有那个可不行!可以到 去下载。欢迎指出我的错误,或与我联系,我的 Email:Chaoyu_JI
3、ANG or Aman_JIANG , QQ:15852673。COM What is COM? COM 是什么呢?COM 就是 Component Object Model, 组件对象模型。COM 接口和 C+的抽象类相似(但不一样),就像抽象类没有与之相关的实际代码一样,COM 描述了一套符号和语法而非实现过程。你也可以把 COM 对象就想象成一套为某个主题而设计的一整套库函数。DX 就提供了一套完整的设计 3D 游戏的库。最棒的就是,使用 DX 时,你不必去直接接触硬件,而由 DX 帮你代理了。这使得一些事情变得简单了。使用 COM 时应该注意,必须在程序结束前释放所有的 COM 对象(
4、或接口)。而且,释放它们的顺序应该和创建它们的顺序相反。就像这样:1. Create interface A.2. Create interface B.3. Release interface B.4. Release interface A. 调用它们的 Release 模块来释放它们。Page Flipping (页翻动)页翻动又是什么呢?嗯,你知道电影的原理吗?电影通过以每秒钟 24 幅的速度连续的闪动图像,每幅图像之间的差别又很小,由于人眼的滞留作用,我们看到的画面就是连续的了。这不难理解。其实,DirectX 也是这样工作的。我们把要显示的物体通通绘制到一个不可见的页上,我们称这个
5、页为“后缓冲区”。绘制完后,快速的把它翻动到可见的“前缓冲区”上,并重复这个过程。当用户正在观看新绘制的可见页(前缓冲区)时,程序要降下一幅要显示的东DirectX Tutorials By Andy Pike- 2 -西绘制到“后缓冲区”上。快速而连续的重复次过程,用户就会看到像电影一样连续的图像了。不过一般情况下,我们每秒钟能绘制的页数要比电影多很多。如果我们不是用页翻动技术,那用户看到的屏幕中的物体,将会一个个的被绘制出来,虽然速度可能很快,但效果会很差,那并不是我们想要的。所以,我们的游戏需要一个循环,称之为“Game Loop”。每次循环,我们都要清除“后缓冲区”,把该绘制的物体按
6、照一定的逻辑都绘制到那上面,然后把它翻动到“前缓冲区”上,然后进入下一次循环。这个循环得直到游戏退出了才能结束。有时我们可能需要好几个这样的“后缓冲区”(多缓冲)来组成一个“交换链”(Swap Chain),以求更好的效果。Devices (设备)What is a device? 设备是什么?简单的说,就是你的 3D 卡。 你得创建一个接口来代表设备,然后使用那个接口来绘制东西。Game Loop (游戏循环)什么是游戏循环呢?游戏循环是一段代码,在游戏退出之前循环执行的代码。这段代码在每次循环中都要:在屏幕上绘制物体(或场景人物随便什么)、处理游戏的逻辑过程(如:物体的移动、人工智能等等)
7、、处理 Windows 的消息等等。基本上就是这样了。Creating Your First Project (创建你的第一个项目)译者:嗯,这部分我就不用译了吧,这可是基础的东西。不过还是说说初学者容易忽略的一点:一定要把你的 DX SDK 的 Include 目录和 Lib 目录的路径添加到 VC 的目录设置列表中去,而且不要把 Include 和 Lib 的地方放错了,而且还要放在第一位。还要把 d3d8.lib 添加到项目设置的 Lib 列表中,否则编译不了。Okay, thats enough theory lets get started. Follow the step-by-s
8、tep guide below to create your first DirectX Graphics project. 1. In Visual C+ create a new Win32 Application.a. File Newb. From the Projects tab select Win32 Applicationc. Enter a name for your project such as “DX Project 1”d. Select a folder for the location of your source code filese. Click Nextf
9、. Select the empty project option.g. Click Finish2. Make sure that your project settings are correct.a. Project Settings.b. On the Link tab, make sure that “d3d8.lib“ is in the list of Object/Library Modules. If it isnt simply type it in.3. Make sure that your search paths are correct.a. Tools Optio
10、ns Directories Tabb. In the “Show directories for“ drop-down, select “include files“.c. If it does not exist already, add the following path: include.d. Make sure that this path is at the top of the list by clicking on the up arrow button (if needed).e. In the “Show directories for“ drop-down, selec
11、t “library files“.f. If it does not exist already, add the following path: lib.g. Make sure that this path is at the top of the list by clicking on the up arrow button (if needed).4. Add the source code.a. File Newb. From the Files tab, select C+ Source Filec. Enter a filename such as “Main.cpp”d. C
12、opy the code segment below, and then paste it into your new file.5. Build and Run the program.a. Press F7 to build your projectb. Press F5 to runDirectX Tutorials By Andy Pike- 3 -下面就是本章的例子了,好好研究吧,不难。#include LPDIRECT3D8 g_pD3D = NULL;LPDIRECT3DDEVICE8 g_pD3DDevice = NULL;HRESULT InitialiseD3D(HWND
13、 hWnd)/First of all, create the main D3D object. If it is created successfully we/should get a pointer to an IDirect3D8 interface.g_pD3D = Direct3DCreate8(D3D_SDK_VERSION);if(g_pD3D = NULL)return E_FAIL;/Get the current display modeD3DDISPLAYMODE d3ddm;if(FAILED(g_pD3D-GetAdapterDisplayMode(D3DADAPT
14、ER_DEFAULT, /Create a structure to hold the settings for our deviceD3DPRESENT_PARAMETERS d3dpp; ZeroMemory(/Fill the structure. /We want our program to be windowed, and set the back buffer to a format/that matches our current display moded3dpp.Windowed = TRUE;d3dpp.SwapEffect = D3DSWAPEFFECT_COPY_VS
15、YNC;d3dpp.BackBufferFormat = d3ddm.Format;/Create a Direct3D device.if(FAILED(g_pD3D-CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, return S_OK;void Render()if(g_pD3DDevice = NULL)return;/Clear the back buffer to a green colourg_pD3DDevice-Clear(0, NULL,
16、D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 255, 0), 1.0f, 0);/Begin the sceneg_pD3DDevice-BeginScene();/Rendering of our game objects will go hereDirectX Tutorials By Andy Pike- 4 -/End the sceneg_pD3DDevice-EndScene();/Filp the back and front buffers so that whatever has been rendered on the/back buffer wi
17、ll now be visible on screen (front buffer).g_pD3DDevice-Present(NULL, NULL, NULL, NULL);void CleanUp()if(g_pD3DDevice != NULL)g_pD3DDevice-Release();g_pD3DDevice = NULL;if(g_pD3D != NULL)g_pD3D-Release();g_pD3D = NULL;void GameLoop()/Enter the game loopMSG msg; BOOL fMessage;PeekMessage(while(msg.me
18、ssage != WM_QUIT)fMessage = PeekMessage(if(fMessage)/Process messageTranslateMessage(DispatchMessage(else/No message to process, so render the current sceneRender();/The windows message handlerLRESULT WINAPI WinProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)switch(msg)case WM_DESTROY:PostQui
19、tMessage(0);return 0;break;case WM_KEYUP: switch (wParam) case VK_ESCAPE:DirectX Tutorials By Andy Pike- 5 -/User has pressed the escape key, so quitDestroyWindow(hWnd);return 0;break; break;return DefWindowProc(hWnd, msg, wParam, lParam);/Application entry pointINT WINAPI WinMain(HINSTANCE hInst,
20、HINSTANCE, LPSTR, INT)/Register the window classWNDCLASSEX wc = sizeof(WNDCLASSEX), CS_CLASSDC, WinProc, 0L, 0L, GetModuleHandle(NULL), NULL, NULL, NULL, NULL,“DX Project 1“, NULL;RegisterClassEx(/Create the applications windowHWND hWnd = CreateWindow(“DX Project 1“, “: Tutorial 1“, WS_OVERLAPPEDWIN
21、DOW, 50, 50, 500, 500,GetDesktopWindow(), NULL, wc.hInstance, NULL);/Initialize Direct3Dif(SUCCEEDED(InitialiseD3D(hWnd) /Show our windowShowWindow(hWnd, SW_SHOWDEFAULT);UpdateWindow(hWnd);/Start game running: Enter the game loopGameLoop();CleanUp();UnregisterClass(“DX Project 1“, wc.hInstance);retu
22、rn 0;你会得到一个绿色背景的窗户(读者:是窗口,白痴),虽然看起来不怎么样,但至少是一个好的开始,不是吗?好地开头,就是成功地半拉!(读者: )DirectX Tutorials By Andy Pike- 6 -(译者:嗯,那个老外用 WinXP?我看还是 Win2K 好 )(读者:切别在那废话。 )WinMain此乃 Win32 程序的入口点,代码会从这里开始执行。这是我们注册、创建、显示窗口的地方。然后,我们要初始化Direct3D 并进入游戏循环(Game Loop)。WinProc这是应用程序的消息处理过程。Windows 发给我们的程序的消息,都要有它处理。注意我们上面的例子
23、,我们处理了两种消息:WM_DESTROY(结束程序) 和 WM_KEYUP(有按键被按下)。其他的消息我们都交给默认消息处理过程 DefWindowProc 处理了。g_pD3D这是指向 IDirect3D8 接口的指针,我们得通过它来创建 Direct3D 设备接口。g_pD3DDevice这是 IDirect3DDevice8(D3D 设备) 的接口的指针,它实际上代表了你的硬件 3D 卡。InitialiseD3D我们的这个函数是用来初始化 Direct3D 的。首先,创建 IDirect3D8 对象,通过这个对象我们得到了当前屏幕的显示模式。然后,根据刚刚我们获取的信息(显示模式),
24、创建了兼容的设备。译者:因为一些显示卡的显示模式并不相同,所以,我们的程序要在每块显卡上都能执行,就要了解这块显卡的显示模式等等一些信息。然后,根据这些信息,创建我们的 D3D 设备。GameLoop这就是上面提到的“游戏循环”的具体实现了。当初始化结束后,它就开始了。他会检测有没有 Windows 的消息,没有的话,就调用 Render 来绘制屏幕。Render首先,我们清除了后缓冲区准备作画。然后,调用了 BeginScene 函数来告知 DX 我们要作画了。这时,我们就可以作画了(教程 2)。结束了绘制,我们调用 EndScene 来告知 DX 我们画完了。最后,我们调用了 Presen
25、t 来完成关键的一步:翻动后缓冲区到前缓冲区(屏幕)。这时,用户就能看到我们画的东西了。CleanUp我们在此做清洁工作:释放所有的被创建的对象。因为程序要推出了。Summary (摘要)译者:嗯,好了,这就是我们教程的第一章了。并不难,不是吗?看起来虽然字不多,翻译起来,蛮累呢!研究明白了的话,看下一章吧!下一章我们就会真正的画一些东西了!呵呵,真是令人期待呢 也让老外说几句吧:Ok, thats it for the first tutorial. I know that the finished program wasnt the most spectacular thing in th
26、e world, but just wait for the next tutorial when we will be drawing some shapes! 第二章:绘制三角形Introduction(序)所有的 3D 图形都是由三角形构成的。为什么是三角形而不是别的图形呢?因为三角形有许多优越之处,例如:绘制效率。(译者:而且我们知道,任意不在同一条直线上的三个点都能构成三角形,这对于在空间中形成某种复杂图形是很有益处的,我的理解)所以,如果我们想得到一个矩形,最有效率的是绘制两个相同的合并的三角形,这样要DirectX Tutorials By Andy Pike- 7 -优于直接
27、绘制一个矩形。所以,本教程下面将告诉你如何绘制复杂物体的最小单元:三角形。(译者:神奇的三角形啊.)Vertices (顶点)顶点(vertex)是什么?顶点就是 3D 空间中的一个点。例如,三角形有三个顶点,而矩形有四个。在 3D 空间中,你可以用三个顶点来指定一个三角形。想做到这些,你需要了解迪卡尔坐标系统。2D Cartesian coordinate system (2D 迪卡尔坐标系统)下面的两幅图演示了 2D 迪卡尔坐标系统是怎样工作的。Fig 2.1 Fig 2.22D 迪卡尔坐标系统是很简单的,用两条轴 x、y 的值来表示点的位置,进而表现出图形的位置。这是初中时我们就学习过的
28、。3D Cartesian coordinate system (3D 迪卡尔坐标系统)下面的两幅图演示了左手 3D 迪卡尔坐标系统是怎样工作的。 Fig 2.3 Fig 2.42D 坐标系统只有 x 轴与 y 轴,因为它是平面的。而在 3D 空间里,两个轴显然不够用了,所以,有了第三个轴:z轴。现在,我们用这三个轴就能在 3D 空间中表示出物体的任意位置了。这其实是很简单的事情,我就不多说了。3D Primitives Primitive 为“原始”之意,3D primitive 就是设备所支持的原始的类型。它包括: 点列、线列、线代、三角形列、三角形带 和 三角扇形。使用 3D primi
29、tive 完成上述的图形是很方便的。以后我们会用 3D primitive 来绘制图形。下面的一些例子演示了上述的各种方式:DirectX Tutorials By Andy Pike- 8 -Point Lists(点列)Fig 2.5Line Lists(线列)Fig 2.6Line Strips(线带)Fig 2.7Triangle Lists(三角形列)Fig 2.8DirectX Tutorials By Andy Pike- 9 -Triangle Strips(三角形带)Fig 2.9Triangle Fans(三角扇形)Fig 2.10Flexible Vertex For
30、mat (FVF) (灵活顶点格式)Flexible 的意思是“灵活的” 。这里不译为“灵活的顶点格式”而译为“灵活顶点格式”是有原因的:前者是一个短语,像是广告词一样;后者才更像是一种名词或术语。所以,我取了后者。灵活顶点格式(FVF)是用来描述顶点属性的一种格式,而这种格式是可以由我们自定义的,所以称它为“灵活顶点格式”。至此,我们至少知道了顶点有三种属性:x 值、y 值和 z 值。其实顶点还可以有其他属性,例如颜色与亮度。利用灵活顶点格式(FVF )我们能方便的指定顶点的属性。如果我们在 Direct3D 指定了一个多边形,这个多边形将可以被它的各个顶点的属性所填充,带有过渡性的属性填充
31、。我知道这个不太好理解,没关系,下面我们有例子,它也正是这样做的:在我们下面的例子中,将会有一个三个顶点所组成的三角形,三角形的每个顶点的颜色都是不同的,他们分别是红、绿、蓝,电脑中的三原色。三角形将会被这三种颜色混合的、渐变的填充起来。Vertex Buffers (顶点缓冲)顶点缓冲就是一块用于保存顶点的内存缓冲区。顶点缓冲可以保存任何的顶点类型。当你的一些顶点已经被保存在顶点缓冲区中,你就可以操作它们了,例如渲染、变换和剪裁。Colours (颜色)在 DirectX 中,如果我们要指定一种颜色,我们可以用 D3DCOLOR_XRGB 宏。宏中有三个参数,每个参数都是 0到 255 间的
32、整数值,分别用于描述颜色的红、绿、蓝分量,然后 D3DCOLOR_XRGB 宏会将它们调和,就像水彩调色一样。例如:D3DCOLOR_XRGB(0, 0, 0) 是黑色(无色)。D3DCOLOR_XRGB(255, 255, 255) 是纯白色(满色调)。D3DCOLOR_XRGB(0, 255, 0) 是亮绿色(没有红与蓝,全是绿色的分量)。D3DCOLOR_XRGB(100, 20, 100) 是暗紫色 (100 红, 20 绿, 100 蓝)。好了,我们第二章的例子就在这了。它和第一个例子差不多,只是添加了一些代码、做了些修改。仔细研究吧!Its easy!DirectX Tutoria
33、ls By Andy Pike- 10 -#include LPDIRECT3D8 g_pD3D = NULL;LPDIRECT3DDEVICE8 g_pD3DDevice = NULL;LPDIRECT3DVERTEXBUFFER8 g_pVertexBuffer = NULL; / Buffer to hold verticesstruct CUSTOMVERTEXFLOAT x, y, z, rhw; / The transformed position for the vertex.DWORD colour; / The vertex colour.;#define D3DFVF_C
34、USTOMVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE)#define SafeRelease(pObject) if(pObject != NULL) pObject-Release(); pObject=NULL;HRESULT InitialiseD3D(HWND hWnd)/First of all, create the main D3D object. If it is created successfully we /should get a pointer to an IDirect3D8 interface.g_pD3D = Direct3DCre
35、ate8(D3D_SDK_VERSION);if(g_pD3D = NULL)return E_FAIL;/Get the current display modeD3DDISPLAYMODE d3ddm;if(FAILED(g_pD3D-GetAdapterDisplayMode(D3DADAPTER_DEFAULT, /Create a structure to hold the settings for our deviceD3DPRESENT_PARAMETERS d3dpp; ZeroMemory(/Fill the structure. /We want our program t
36、o be windowed, and set the back buffer to a format/that matches our current display moded3dpp.Windowed = TRUE;d3dpp.SwapEffect = D3DSWAPEFFECT_COPY_VSYNC;d3dpp.BackBufferFormat = d3ddm.Format;/Create a Direct3D device.if(FAILED(g_pD3D-CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, return S_OK;HRESULT InitialiseVertexBuffer()VOID* pVertices;/Store each point of the triangle together with its colourCUSTOMVERTEX cvVertices =