Lesson 1: Getting Started with Direct3D
Lesson 1: 開(kāi)始Direct3D編程
From:
http://www.directxtutorial.com/tutorial9/b-direct3dbasics/dx9b1.aspx#still
Translated By----Double One(王大寶) dfghj77777@gmail.com
課程概述
首先,我正式歡迎您的Direct3D。我想和大家一分享一些基礎(chǔ)知識(shí)及3D編程的高級(jí)話題。無(wú)論你想建立你自己的引擎,借用一個(gè)或者修改它,或者僅僅買(mǎi)一個(gè)并且使用它,你了解它的基本概念,這是很重要的。
和一個(gè)游戲引擎的基本概念一樣重要的,是DirectX的基本概念本身。本課程將涵蓋Direct3D基礎(chǔ)知識(shí)和你你創(chuàng)建你的第一個(gè)DirectX程序所需要知道的。然后,我們將建立一個(gè)窗口內(nèi)的基本的Direct3D程序。
COM
And COM is what?
那是COM是個(gè)啥玩意兒呢?
COM stands for Component Object Model. COM is a method of creating very advanced objects that, well, they act a lot like Legos actually.
COM就是Component Object Model的縮寫(xiě),翻譯成咱天朝語(yǔ)言就是“組件模型模型”。 COM是創(chuàng)建軟件組件的一種方法,事實(shí)上它更像樂(lè)高積木。我知道這么說(shuō)可能還是很多童鞋不理解,沒(méi)關(guān)系,程序?qū)懚嗔俗匀欢痪投恕?/span>
Legos, as you know, can be stuck together to create more advanced shapes. No single Lego actually cares about any other Lego in the set. They are all compatible with each other, and all you have to do is stick them together to get them to work. If you want to change pieces, all you have to do is unplug one piece and put another in its place.
如你所知,樂(lè)高積木可以組合成各種形狀,只要你高興,拼個(gè)小月月都行。同一個(gè)組合里沒(méi)有哪個(gè)單獨(dú)的積木關(guān)心別的積木。任意兩塊積木都可以拼接起來(lái),而你要做的就是把他們擺到一起組成一個(gè)整體。如果你想改變這個(gè)某一片積木,你只要抽出某一塊積木并把另一塊積木插入這個(gè)空缺。
And so it is with COM. COM objects are actually C++ classes or groups of classes from which you can call functions and achieve certain aims. No class requires another to operate, and they don't really need to work together to get things done together, but you can plug them in or unplug them as you desire without changing the rest of the program also.
好了說(shuō)了一堆廢話我們回到正題。COM對(duì)象其實(shí)是C++的類或者你可以調(diào)用的實(shí)現(xiàn)一定目標(biāo)的函數(shù)的組類。每個(gè)類都可以單獨(dú)工作得很好,它們也不需要非得湊一塊完成工作,于是你可以隨心所欲地加載或者卸載某個(gè)類并且你不用改變其他程序。
For example, say you had a game distributed broadly and you want to upgrade it. Well, instead of keeping track of and shipping a new copy to every single user who ever bought your game, all you have to do is say "Upgrade! Right Here!". They download the updated COM object, and the new object plugs right in to your program without further hassle. Nice, huh?
其實(shí)上面那么說(shuō)還是忒抽象了,咱來(lái)點(diǎn)具體的吧。好比說(shuō)你做了一個(gè)游戲,十分火爆,很多宅男都下載安裝并在夜深人靜的時(shí)候偷偷玩上一把,但是現(xiàn)在你想給它做個(gè)更新。回去查查誰(shuí)買(mǎi)了你的游戲然后給每個(gè)人EMS一份新的?好吧,您要有這錢(qián)您也不用做程序員了。我想告訴你的是,你只要大喊:“最新高清無(wú)碼即將和諧速度下載!”讓那幫SB去下載新的COM組件,并正確加載到你的游戲就OK了,是的,這個(gè)主意很棒,請(qǐng)盡情地贊美我吧,哇哈哈哈,好吧,我承認(rèn)這是COM機(jī)制的功勞。
I won't get too detailed into COM, because it is far too complex for what we need. It's job is to get all the complex stuff out of the way so that you have an easy time. And if that's its job, what would be the purpose of learning all that complex material?
好了,關(guān)于COM組件我不想再多說(shuō)了,這又不是講COM的教程。COM的意義就在于把那些復(fù)雜的東西自己攬過(guò)來(lái)這樣我們程序員才能偶爾有點(diǎn)空閑喝茶泡妞打DOTA。既然那是它的工作,你沒(méi)事學(xué)習(xí)那些復(fù)雜的玩意干嘛呢?
So why COM? Well, DirectX is actually a series of COM objects, one of which is Direct3D. Direct3D is a rather advanced class that contains everything you need to run 2D and 3D graphics using software, hardware, or whateverware.
各位親愛(ài)的讀者可能又要問(wèn)了,為什么一定是COM呢?難道你們有什么不可告人的關(guān)系還是它私下給你塞了不少票子。這個(gè)這個(gè),作者我未入黨未入團(tuán),像我這么潔身自愛(ài)的好青年怎么可能是那種人呢。來(lái)來(lái)來(lái),爾等且聽(tīng)我慢慢-----道來(lái):話說(shuō)這DirectX實(shí)際上是一套COM組件,而Direct3D只是DirectX的一小部分。Direct3D是一個(gè)相當(dāng)高級(jí)的類,它封裝了你運(yùn)行2D和3D圖形所需要的全部硬件啊,軟件啊,以及其他隨便什么件。總之就是這方面的事,全都可以交給DirectX去做
So don't be surprised when you see Direct3D functions being called like this:
所以別奇怪Direct3D函數(shù)被這么調(diào)用:
1
d3d->CreateDevice()
2
3
d3d->Release()
4
We use the indirect member access operator here to access the functions CreateDevice() and Release() from the Direct3D interface class. We'll get more into this when we see how it is applied in practice. I'm going to try to avoid unneeded theory from here on out.
我們使用間接成員訪問(wèn)操作符來(lái)訪問(wèn)Direct3D中的CreateDevice()和Release()這兩個(gè)函數(shù),
For now let's go on to the next topic:
好了說(shuō)了半天,現(xiàn)在讓們進(jìn)入下一個(gè)章節(jié),開(kāi)始我們的Dierect3D之旅吧。
交換鏈和頁(yè)交換
A graphics adapter contains in its memory a pointer to a buffer of pixels that contains the image currently being displayed on the screen. When you need to render something, such as a 3D model or texture, the graphics adapter updates this array and sends the information to the monitor to display. The monitor then redraws the screen from top to bottom, adding in the new part rendered.
一個(gè)圖形適配器吧,它的內(nèi)存中包含一個(gè)指向包含目前顯示在屏幕上的圖像的像素緩沖區(qū)的指針。當(dāng)我們需要去渲染一些東西,比如說(shuō)空姐姐的照片或者她的視頻,圖形適配器就會(huì)更新這個(gè)數(shù)組并把信息發(fā)送給顯示器顯示。然后顯示器就會(huì)從上到下掃描屏幕,一行行地渲染新的數(shù)據(jù)。
However, there is a slight problem with this in that the monitor does not refresh as fast as needed for real-time rendering. Most refresh rates range from 60 Hz (60 fps) to about 100 Hz. If another model were rendered to the graphics adapter while the monitor was refreshing, the image displayed would be cut in two, the top half containing the old image and the bottom half containing the new. This effect is called tearing.
正所謂天有不測(cè)風(fēng)云啊,這時(shí)候又有一個(gè)大問(wèn)題橫亙?cè)谖覀兠媲埃蠖鄶?shù)的顯示器刷新速率在60HZ到100HZ.。眾所周知所謂動(dòng)畫(huà)就是一堆連續(xù)的圖片,當(dāng)你顯示器刷新不夠快的時(shí)候,也就是趕不上實(shí)時(shí)渲染的速度的時(shí)候,就會(huì)出現(xiàn)撕裂效應(yīng)。具體表現(xiàn)為上一幀還沒(méi)刷新好,又開(kāi)始刷新下一幀了,于是屏幕的上半部分顯示上一幀,下半部分顯示下一幀,悲劇開(kāi)始了-----好端端一帥哥就會(huì)變成四只眼睛兩個(gè)鼻子的怪物了,但是我相信任何艱難險(xiǎn)阻都難不倒偉大的中國(guó)程序員,因?yàn)槲覀儛?ài)寫(xiě)程序愛(ài)得深沉。
To avoid this, DirectX implements a feature called swapping.
為了避免這一切的發(fā)生,我們對(duì)DirectX實(shí)現(xiàn)了一個(gè)特征稱為交換(swapping)。
Swapping
Instead of rendering new images directly to the monitor, Direct3D draws your images onto a secondary buffer of pixels, known as a back buffer. The front buffer would be the buffer currently being displayed. You draw all your images onto the back buffer, and when you are done, Direct3D will update the front buffer with the contents of the back buffer, discarding the old image.
取代直接在顯示器渲染的辦法是,Direct3D把你的圖畫(huà)到第二像素緩沖區(qū)。現(xiàn)在我們有了兩個(gè)像素緩沖區(qū),我們把他倆分別稱作前臺(tái)緩沖區(qū)和后備緩沖區(qū),前臺(tái)緩沖區(qū)是目前在顯示器上看到的,然后在后備緩沖區(qū)放入剩余的全部圖像,當(dāng)你完成這一切之后,Direct3D會(huì)從后備緩沖區(qū)拿出新的內(nèi)容來(lái)更新前臺(tái)緩沖區(qū),并丟棄現(xiàn)有圖像。
However, doing this can still cause tearing, because the image transfer can still occur while the monitor is refreshing (the CPU is faster than the monitor).
但是后來(lái)有些筒子發(fā)現(xiàn)這么干還是會(huì)引起撕裂,因?yàn)楫?dāng)顯示器正在渲染的時(shí)候還是會(huì)有圖像傳輸。(沒(méi)辦法啊,誰(shuí)讓CPU比顯示器要快得多呢)
In order to avoid this (and to make the whole thing go much faster), DirectX uses a pointer for each buffer (both front and back) and simply switches their values. The back buffer then becomes the front buffer (and vice versa), and no tearing occurs.
為了避免這樣做同時(shí)也是為了讓整個(gè)過(guò)程進(jìn)行得更快。DirectX會(huì)使用一個(gè)指針為每個(gè)緩沖(包括前臺(tái)和后備)方便地交換值。讓后備緩沖區(qū)成為前臺(tái)緩沖區(qū)(反之亦然),這樣就沒(méi)有撕裂了。
這么說(shuō)有點(diǎn)抽象,打個(gè)比方罷,你在飯店喝湯,那么小的碗一碗肯定不夠,第一種情況就是你一邊吃,廚師在旁邊拿著勺子一邊往你碗里加一邊說(shuō)客官多喝點(diǎn)多喝點(diǎn)我們的湯是如此的好喝云云,你要是喝的不夠快,這湯就得滿出來(lái),弄得你衣鞋盡濕,后來(lái)的改進(jìn)方法是給你上一碗湯,再另外拿個(gè)海碗盛一大碗放桌上你自己加,你親愛(ài)的同桌朋友十分熱情地幫你加湯,但是你喝湯實(shí)在太慢了,于是湯又漫出來(lái)了。最后你自己想了一般法,拿上連個(gè)玩,一碗喝著,一碗盛著湯,等你喝完這一碗就把那一碗拿過(guò)來(lái)接著喝,喝完的這個(gè)碗再拿去盛下一碗。你看,所有問(wèn)題都不再是問(wèn)題。

Of course, we could make our game have better performance by adding additional back buffers, like this.
當(dāng)然了,我們可以添加更多的后備緩沖區(qū)來(lái)提高效率。

How can adding additional back buffers get better performance? Well, let's say that every once in a while you finish rendering the back buffer and are ready to swap, but the screen hasn't yet finished drawing the contents of the front buffer. Swapping now would cause more tearing. So what happens instead is your program stops and waits for the screen to finish. You could, of course, be spending this valuable time preparing the next image, and having multiple back buffers allows your program to do just that.
This setup called a swap chain, as it is a chain of buffers, swapping positions each time a new frame is rendered.
各位讀者又要問(wèn)了?增加緩沖區(qū)跟提高性能有嘛關(guān)系呢?你想啊,要是你這碗還沒(méi)喝完,下一碗已經(jīng)盛好了,那盛湯那姑娘豈不是要苦苦地等著你喝完這一碗(不然又是撕裂),于是多加一個(gè)碗,她第二碗盛好了,放那等你喝完第一碗,同時(shí)又拿起第三只碗開(kāi)始盛湯。同理多個(gè)后背緩沖區(qū)也是這個(gè)道理,不讓CPU喝顯卡閑著,如果你喜歡的話還可以繼續(xù)增加第四五六個(gè)后背緩沖區(qū),于是就有了交換鏈-----一連串的緩沖區(qū),每當(dāng)有新的幀渲染時(shí)就交換位置,把后面的換到前面來(lái)。
The Basic Direct3D Program
We won't be making a "Hello World!" application for Direct3D. We will assume that Direct3D is not a language on its own (which it isn't). Instead, we will start by filling our window with blue. For this we have four steps:
1. Create global variables and function prototypes
2. Create a function to initialize Direct3D and create the Direct3D Device
3. Create a function to render a frame
4. Create a function to close Direct3D
Let's go over each function and its parts, then look at the whole picture and how to plug it in to your windows program.
我們不會(huì)去寫(xiě)一個(gè)Direct3D的“Hello World”。因?yàn)槲覀冎?/span>Direct3D不是一門(mén)新的語(yǔ)言,取而代之的是,我們要去寫(xiě)一個(gè)藍(lán)色背景的WINDOWS窗體,具體步驟如下:
1.創(chuàng)建全局變量和函數(shù)原型
2.寫(xiě)一個(gè)函數(shù)來(lái)初始化Direct3D以及創(chuàng)建Direct3D設(shè)備
3.寫(xiě)一個(gè)函數(shù)來(lái)渲染幀
4.寫(xiě)一個(gè)關(guān)閉Dierect3D的函數(shù)
下面讓我們來(lái)看看各個(gè)函數(shù)及其部分細(xì)節(jié)
,以及如何把它們嵌入到我們的Windows 程序中。
1. 創(chuàng)建全局變量和函數(shù)原型
We need to add a few things to the top of our program before we start working with Direct3D in the first place. Let's take a look at these and see what they are.
在主程序開(kāi)始之前我們要添加一些Direct3D的引用和全局變量聲明,我們看看下面的代碼:
1
// include the basic windows header files and the Direct3D header file
2
#include <windows.h>
3
#include <windowsx.h>
4
#include <d3d9.h>
5
// include the Direct3D Library file
6
#pragma comment (lib, "d3d9.lib")
7
// global declarations
8
LPDIRECT3D9 d3d; // the pointer to our Direct3D interface
9
LPDIRECT3DDEVICE9 d3ddev; // the pointer to the device class
10
11
// function prototypes
12
void initD3D(HWND hWnd); // sets up and initializes Direct3D
13
void render_frame(void); // renders a single frame
14
void cleanD3D(void); // closes Direct3D and releases memory
15
16
// the WindowProc function prototype
17
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
18
#include <d3d9.h>
This includes the Direct3D 9 header file. This consists of various declarations to the actual methods contained in the Direct3D library.
這一句包含Direct3D9的頭文件,這里是我們用到的Direct3D庫(kù)里面的類啊函數(shù)啊神馬的聲明。
#pragma comment (lib, "d3d9.lib")
This includes the Direct3D 9 library file. The #pragma comment directive places a certain piece of information in your project's object file. With our first paramter, lib, we indicate that we want to add a library file to the project. We then specify which file, "d3d9.lib".
這一句包含了Direct3D的庫(kù)文件。“#pragma comment”這個(gè)命令是用來(lái)在你的項(xiàng)目中指定包含一個(gè)靜態(tài)庫(kù)文件的。他的第一個(gè)參數(shù)”lib”表明要引入到項(xiàng)目的是一個(gè)靜態(tài)庫(kù)文件,然后第二個(gè)參數(shù)是文件名,這里我們用”d3d9.lib”
LPDIRECT3D9 d3d;
This variable is a long pointer to Direct3D. What this means is that we will create a class called iDirect3D9. When COM makes this class, we will ignore it, and access it only indirectly using this pointer. We will cover how the class is created in a moment.
這是一個(gè)指向Direct3D的長(zhǎng)指針變量。這意思就是說(shuō)我們將創(chuàng)建一個(gè)叫iDirect3D9的類。當(dāng)然我們不需要?jiǎng)邮郑?/span>COM會(huì)自己創(chuàng)建它,而我們只要通過(guò)這個(gè)指針間接訪問(wèn)那個(gè)類。稍后我們會(huì)講到這個(gè)類具體是怎樣被創(chuàng)建的。
LPDIRECT3DDEVICE9 d3ddev;
The Direct3D Device interface holds all the information pertaining to the graphics drivers, the video card, and everything else having to do with the hardware side of graphics. This is a pointer to the class that stores all this information.
Direct3D Device接口里保留著所有與圖形驅(qū)動(dòng),顯卡,以及其他什么東西相關(guān)的信息。而我們定義的這個(gè)指針指向Direct3D Device類存儲(chǔ)所有的信息。
2. 創(chuàng)建一個(gè)函數(shù)來(lái)初始化Direct3D和創(chuàng)建Direct3D Device
The first step to actually coding Direct3D is to create the interface and initialize the graphics device. This is done using two functions and a struct containing graphics device information. Let's take a look at this function here, then go over its parts. I didn't bother to bold the new parts, because the entire thing is new.
實(shí)際上Direct3D編碼的第一步是建立界面和初始化圖形設(shè)備。我們用兩個(gè)函數(shù)加一個(gè)包含圖形設(shè)備信息的結(jié)構(gòu)體來(lái)完成這一步。讓我們看看這個(gè)函數(shù),然后再分析部分代碼。我不想去加粗新的部分,因?yàn)槟且徽麎K都是新的。
1
// this function initializes and prepares Direct3D for use
2
void initD3D(HWND hWnd)
3

{
4
d3d = Direct3DCreate9(D3D_SDK_VERSION); // create the Direct3D interface
5
6
D3DPRESENT_PARAMETERS d3dpp; // create a struct to hold various device information
7
8
ZeroMemory(&d3dpp, sizeof(d3dpp)); // clear out the struct for use
9
d3dpp.Windowed = TRUE; // program windowed, not fullscreen
10
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; // discard old frames
11
d3dpp.hDeviceWindow = hWnd; // set the window to be used by Direct3D
12
13
// create a device class using this information and information from the d3dpp stuct
14
d3d->CreateDevice(D3DADAPTER_DEFAULT,
15
D3DDEVTYPE_HAL,
16
hWnd,
17
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
18
&d3dpp,
19
&d3ddev);
20
} };
21
if the comments here are good enough for you, excellent. Otherwise, I've described each of these commands below.
如果這些注釋足夠你看懂程序,那TM太好了,恭喜你,你可以跳過(guò)下面的詳細(xì)解釋了
d3d = Direct3DCreate9(D3D_SDK_VERSION);
This is where the fun begins. This is the first Direct3D function you will run. It's primary purpose is to create the Direct3D interface. The return value is the address of the interface created, and so we will store this address in the pointer we created earlier, d3d.
這是個(gè)有趣的開(kāi)始。這是你將要運(yùn)行的第一個(gè)Direct3D函數(shù)。它的主要目的是創(chuàng)建Direct3D接口。它的返回值是創(chuàng)建的借口的地址,于是我們就能把這個(gè)地址存儲(chǔ)在名為d3d的指針中。
Then there is the parameter. This parameter is always the same: D3D_SDK_VERSION. Why is this? Well, it really only matters for compatibility on other machines. When a later release of DirectX is published, the users will usually have varying levels of DirectX upgrades. This tells the user's DirectX which version you developed your game for. The user's DirectX can then look back and properly execute your program without implementing the upgrades that have occurred since then. Kinda useful, eh?
然后你發(fā)現(xiàn),哎呀,這還有個(gè)參數(shù)呢。是的是的,我沒(méi)忘記它,這個(gè)參數(shù)他永遠(yuǎn)是這個(gè)單詞“D3D_SDK_VERSION”,這是為神馬呢?原來(lái),他是為了保證在不同機(jī)器上的兼容性。當(dāng)一個(gè)更新版本的DirectX推出以后,用戶一般會(huì)有不同程度的升級(jí)。這個(gè)常量會(huì)告訴用戶的DirectX你寫(xiě)的程序是哪個(gè)版本的。然后用戶的DirectX就不會(huì)調(diào)用升級(jí)后的新特性以便能夠正確執(zhí)行你的程序。
In the version of Direct3D 9c, this value returns 32. Previous versions would return different values, causing DirectX to function in different ways. Note that you should not change this value, as it will cause confusion and is not really needed anyway. Just use D3D_SDK_VERSION, and everything will work out all right.
在DirectX 9c中,這個(gè)返回值是32。更早的版本會(huì)返回其他值。造成DirectX調(diào)用不同的函數(shù)。注意,你不能改變這個(gè)值,這樣會(huì)引起天下大亂而且你也不需要這么做。老老實(shí)實(shí)就就用“D3D_SDK_VERSION”吧,代表國(guó)家感謝你。
D3DPRESENT_PARAMETERS d3dpp;
There are certain factors involved in both beginning and advanced game programming which require certain information to be fed into the graphics device from the start. There are plenty of these, but we will only go into three of them here. For now, D3DPRESENT_PARAMETERS is a struct whose members will contain information about the graphics device. We will go over the ones we use here and cover new members as they come up throughout the tutorial.
在初級(jí)和高級(jí)游戲編程,有一些因素從一開(kāi)始就需要饋入圖形設(shè)備。這樣的因素有許多,但是我們只需要三個(gè)。在這里,D3DPRESENT_PARAMETERS是一個(gè)結(jié)構(gòu)體,它的成員包含了圖形設(shè)備的信息。下面我們將來(lái)了解那些我們現(xiàn)在用到的以及后面將要用到的貫穿這個(gè)教程始終的新成員。
ZeroMemory(&d3dpp, sizeof(d3dpp));
We use ZeroMemory() to quickly initialize the entire d3dpp struct to NULL. That way we don't have to go through every member of the struct and set them individually.
我們ZeroMemory
這個(gè)函數(shù)來(lái)快速初始化我們的結(jié)構(gòu)體d3dpp,將其值置為空。
d3dpp.Windowed = TRUE;
When we run Direct3D in a window like we are now, this value is set to TRUE. Otherwise, it is set to false. Later, when we make our window full-screen, we will change this value to FALSE.
Note: There are other changes to make when an application goes full-screen. Changing this one value will not make your application full-screen, unfortunately. Patience until the next lesson.
當(dāng)我們像現(xiàn)在這樣在窗口中運(yùn)行Direct3D,把它的值設(shè)為TRUE。否則,它會(huì)被設(shè)置為false。之后,當(dāng)我們要讓我們的窗口全屏化,我們需將改變這個(gè)值設(shè)置為false。
注意:要想讓程序全屏。僅僅改變這一個(gè)值可不行,欲知具體如何,請(qǐng)聽(tīng)下節(jié)課分解。
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
Before, we talked about swap chains as the method Direct3D uses to change images on the screen. However, we get to pick which type of swap chain is used. There are three different kinds.
首先,我們討論了交換鏈----也就是使用Direct3D改變屏幕上的圖像的方法。然而,交換鏈?zhǔn)怯泻芏喾N的,我們需要選擇其中一種來(lái)使用。這里有三種。
[Table 1.1 - d3dpp.SwapEffect Flags]
So which one to use? Throughout this tutorial I will be using D3DSWAPEFFECT_DISCARD. The only exception to this will be at some later date when I add additional tutorials on various effects that use the other two methods.
那我們應(yīng)該用哪一個(gè)呢?這個(gè)教程自始至終我都會(huì)選擇D3DSWAPEFFECT_DISCARD。唯一的例外將在以后的某天,我用一個(gè)額外的教程講述其他兩種交換鏈的影響的時(shí)候。
d3dpp.hDeviceWindow = hWnd;
This value sets the handle to the window Direct3D should use. We'll just use the same hWnd we've always been using.
這個(gè)值用于設(shè)定Direct3D的窗口句柄。我們會(huì)始終使用“hWnd”這個(gè)單詞。
d3d->CreateDevice()
This is a big function, but in actual fact, it is quite simple. Most of the parameters will probably stay the same in every game you write.
What this function does is create a graphics device interface. What this means is a new class will be created from which you will handle all the graphics you need. Notice that this function is part of the d3d class. Most of the functions you use in Direct3D will come from here, so we give the pointer a rather simple name, d3ddev, as seen before.
Here is this function's prototype:
這是一個(gè)很大的函數(shù),但實(shí)際上,它還很簡(jiǎn)單的。大多數(shù)參數(shù)可能會(huì)總是一樣,在你寫(xiě)的每個(gè)游戲中。
這個(gè)函數(shù)的作用是創(chuàng)建一個(gè)圖形設(shè)備接口。這意味著一個(gè)新的類將被創(chuàng)建,從從您可以進(jìn)行所有你需要的圖形處理。注意,這個(gè)函數(shù)是D3D的類的一部分。你在Direct3D中使用的大多數(shù)函數(shù)將來(lái)自這里,所以我們給這個(gè)指針一個(gè)相當(dāng)簡(jiǎn)單的名稱,d3ddev,正如我們前面見(jiàn)過(guò)的那樣。
下面是這個(gè)函數(shù)的原型:
1
HRESULT CreateDevice(
2
UINT Adapter,
3
D3DDEVTYPE DeviceType,
4
HWND hFocusWindow,
5
DWORD BehaviorFlags,
6
D3DPRESENT_PARAMETERS *pPresentationParameters,
7
IDirect3DDevice9 **ppReturnedDeviceInterface);
8
現(xiàn)在讓我們來(lái)看看這個(gè)函數(shù)的參數(shù)。他們都很簡(jiǎn)單,那么這將會(huì)很快。
UINT Adapter,
This is an unsigned integer that stores a value indicating what graphics adapter, or video card, Direct3D should use. We could get detailed here, and try to find the better graphics card, but we'll let Direct3D take care of that for us (because in most cases there's only one). To tell Direct3D that it needs to decide, we put into this parameter the value D3DADAPTER_DEFAULT, indicating the default graphics card.
這是一個(gè)無(wú)符號(hào)整數(shù),用于存儲(chǔ)一個(gè)值來(lái)指明我們要使用哪些圖形適配器,或視頻卡,Direct3D。在這里我們可以得到詳細(xì)的,并試圖找到更好的圖形卡,但我們會(huì)讓Direct3D盡量小心(因?yàn)樵诖蠖鄶?shù)情況下只有一個(gè))。要告訴Direct3D它進(jìn)行決斷需要的信息,我們把這個(gè)參數(shù)的值設(shè)為D3DADAPTER_DEFAULT,表示默認(rèn)的圖形卡。
D3DDEVTYPE DeviceType,
While there are four possible values for this parameter, we are only going to be concerned with one of them, and stay away from the others until later. The one we will use is D3DDEVTYPE_HAL.
D3DDEVTYPE_HAL tells Direct3D to use what is called the Hardware Abstraction Layer. The Hardware Abstraction Layer, or HAL, is used to indicate that Direct3D should be using hardware to process graphics (and we would use...what else?). If for some reason our graphics device cannot use hardware to handle something, that something will be rendered by software instead. This is done automatically, but probably won't be done, considering the capabilities of modern cards.
雖然有四個(gè)可能的值,但我們只打算用其中的一個(gè)方面,并且一直用它。他就是D3DDEVTYPE_HAL。
D3DDEVTYPE_HAL告訴Direct3D使用所謂的硬件抽象層。硬件抽象層,或者簡(jiǎn)稱HAL,是用來(lái)指示Direct3D應(yīng)該用硬件來(lái)處理圖像(不然我們還能用什么?)。如果由于某種原因,我們的圖形設(shè)備無(wú)法使用硬件來(lái)處理的東西,這東西會(huì)被軟件渲染來(lái)代替。這都是自動(dòng)完成的,但也可能不會(huì)這么做,考慮到現(xiàn)代卡的性能。
HWND hFocusWindow,
This is the handle to our window. We can just put 'hWnd' in here as we passed the value from WinMain().
這是我們的窗口句柄。我們可以把'hWnd'放在這里,正如我們從WinMain()中傳遞了這個(gè)值一樣。
DWORD BehaviorFlags,
While there are plenty of values we can store in this parameter, there are only three we will cover just now. They are D3DCREATE_SOFTWARE_VERTEXPROCESSING, D3DCREATE_MIXED_VERTEXPROCESSING and D3DCREATE_HARDWARE_VERTEXPROCESSING. These three values are fairly self-explanatory. The software one indicates that all 3D calculations should be done with software, the hardware one with hardware, and the mixed one using a combination of both, depending on which Direct3D sees fit. We will use the software value for compatibility, but you can experiment with these as you desire. At first you will notice no difference, but as we move into advanced topics, you may start to see some differences appear.
盡管有很多的值供我們存儲(chǔ)在此參數(shù)中,但是我們只會(huì)用其中三個(gè)。他們是D3DCREATE_SOFTWARE_VERTEXPROCESSING,D3DCREATE_MIXED_VERTEXPROCESSING和D3DCREATE_HARDWARE_VERTEXPROCESSING。這三個(gè)值是相當(dāng)顧名思義,不言自明,一目了然。第一個(gè)表示,所有的3D計(jì)算應(yīng)用軟件實(shí)現(xiàn),第三個(gè)完全使用硬件,而第二個(gè)兩者都用,這取決于Direct3D認(rèn)為哪個(gè)在這個(gè)工作上哪者更合適。為了兼容性我們會(huì)使用第一個(gè)值,但是你個(gè)人高興的話,試試別的我也不介意。起初,你會(huì)發(fā)現(xiàn)沒(méi)有什么區(qū)別,但是當(dāng)我們玩到更深層次的時(shí)候,你可能會(huì)開(kāi)始看到一些不同之處。
D3DPRESENT_PARAMETERS *pPresentationParameters,
This is a pointer to the d3dpp struct that we filled out earlier. We just fill this with '&d3dpp'.
這是一個(gè)指向我們?cè)缧r(shí)候定義的d3dpp結(jié)構(gòu)體的指針。我們只要在這寫(xiě)上'&d3dpp'。
IDirect3DDevice9 **ppReturnedDeviceInterface
This is a pointer to a pointer to the graphics device interface (if you can understand that). Earlier in the program we defined this pointer as d3ddev, so we will put '&d3ddev' in this parameter.
And that's it! You have an entire function using Direct3D. However, if you run this program (and you should not), you will find that absolutely nothing different occurs. All we have done at this point is prepare for action. Now let's have some action!
這是一個(gè)指向圖形設(shè)備接口(如果你能理解)的指針。早些時(shí)候,我們?cè)诔绦蛑卸x的這個(gè)d3ddev指針,所以我們會(huì)在這使用參數(shù)'&d3ddev'。
就是這樣!然后你就可以使用Direct3D的完整功能。但是,如果你運(yùn)行這個(gè)程序(其實(shí)你不應(yīng)該這么做),你會(huì)發(fā)現(xiàn),絕對(duì)沒(méi)有什么不同的發(fā)生。所有我們?cè)谶@一點(diǎn)上做的準(zhǔn)備動(dòng)作。現(xiàn)在,讓我們有一些行動(dòng)!
3. Create a function to render a frame
In this function we will render a single frame. The frame will be rather simple, and will consist of a blue background. Of course, you can change the color if you want. Here is the code for this function.
1
// this is the function used to render a single frame
2
void render_frame(void)
3

{ // clear the window to a deep blue
4
d3ddev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 40, 100), 1.0f, 0);
5
d3ddev->BeginScene(); // begins the 3D scene
6
// do 3D rendering on the back buffer here
7
d3ddev->EndScene(); // ends the 3D scene
8
d3ddev->Present(NULL, NULL, NULL, NULL); // displays the created frame }
9
10
11
There are four functions to rendering a frame, two of them big (but simple) and two of them small. We'll go over them here.
這兒有個(gè)用來(lái)渲染幀的函數(shù),兩個(gè)大的(但簡(jiǎn)單),兩個(gè)小的。讓我們一起去了解他們。
d3ddev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 40, 100), 1.0f, 0)
This clears a buffer to a specific color. In this case, we are going to clear our back buffer. It's pretty simple.
Because most of the parameters are irrelevant at this point, we will leave most of them alone. The first two have to do with clearing a specific area. You will rarely need this, but will just leave them at 0 and NULL, indicating the entire back buffer is to be cleared. The third parameter, set to D3DCLEAR_TARGET, indicates that we should clear the back buffer. There are other types of buffers, but we want this type. Next we have color. The parameter is the struct D3DCOLOR, and we will use the function D3DCOLOR_XRGB() to build the color. The next two parameters we will get into in later lessons. For now, just set them to '1.0f' and 0.
這將清空一個(gè)特定的顏色緩沖區(qū)。在這短代碼中我們會(huì)清空我們的后緩沖區(qū)。這相當(dāng)簡(jiǎn)單。
由于大多數(shù)參數(shù)里無(wú)關(guān)緊要,所以我們不管他。前兩個(gè)負(fù)責(zé)清除特定區(qū)域。一般咱用不到,所以就給他們0和NULL,這樣整個(gè)背部緩沖區(qū)都將被清除。第三個(gè)參數(shù)“D3DCLEAR_TARGET”表明我們應(yīng)該清除后備緩沖區(qū)。還有其他類型的緩沖區(qū),但我們需要清除的就是這種類型。下一步,我們的顏色參數(shù)是D3DCOLOR結(jié)構(gòu)體,我們將使用函數(shù)D3DCOLOR_XRGB()來(lái)構(gòu)建顏色。接下來(lái)的兩個(gè)參數(shù),我們將在以后的課程了解。現(xiàn)在,只需將它們?cè)O(shè)置為'1 .0 f'和0。
d3ddev->BeginScene()
Next we call the function BeginScene() which tells Direct3D you are ready to start rendering. This function needs to be called for two reasons. First, you need to tell Direct3D that you are in control of the memory. Second, this function does something called locking, where the buffer in the video RAM is 'locked', granting you exclusive access to this memory. There is no guarantee that your memory will stay put and not be moved around while you are trying to work on it. Having your memory suddenly appear somewhere else can be quite a hassle for sure.
接下來(lái)我們調(diào)用函數(shù)BeginScene(),它告訴Direct3D休息時(shí)間結(jié)束,可以開(kāi)始渲染了。這個(gè)函數(shù)需要被調(diào)用的原因有兩個(gè)。首先,你需要告訴Direct3D她現(xiàn)在受內(nèi)存管。其次,這個(gè)函數(shù)會(huì)對(duì)在視頻RAM的緩沖區(qū)進(jìn)行鎖定,授予您獨(dú)家訪問(wèn)此內(nèi)存的權(quán)限。毫無(wú)疑問(wèn),你的內(nèi)存將留在原地,不會(huì)隨意移動(dòng),而你正在試圖進(jìn)行這項(xiàng)工作的保證。如果你的內(nèi)存突然出現(xiàn)在別的地方可以是一個(gè)相當(dāng)肯定的麻煩。
d3ddev->EndScene()
Next we call the function EndScene(). While BeginScene() locked the video memory we wanted, EndScene() unlocks it, making it available by other processes that need access to it.
Note: Locking video RAM is slow, but required. You should call BeginScene() and EndScene() only once per frame to save your valuable CPU ticks.
接下來(lái),我們調(diào)用函數(shù)EndScene()。BeginScene()會(huì)鎖定我們想要的顯存,而EndScene()可以對(duì)之解鎖,使得它可以被其他進(jìn)程訪問(wèn)。
注意:鎖定視頻RAM是很慢的,但又是必要的。你應(yīng)該每幀只調(diào)用BeginScene()和EndScene()一次,節(jié)約寶貴的CPU資源。
d3ddev-> (NULL, NULL, NULL, NULL)
And finally we call the Present() function. The four parameters, all set to NULL, are not going to be used in this tutorial. Three of them have to do with the slowest method of handling the swap chain (which we don't use) and the other one has to do with presenting to a different window (which we won't need and won't go into).
最后,我們調(diào)用Present()函數(shù)。這四個(gè)都設(shè)置為NULL的參數(shù),不會(huì)在本教程中使用。其中3個(gè)是與處理交換鏈的方法中最慢的(本教程堅(jiān)決不用),而另一個(gè)是介紹到不同的窗口(我們不需要,也不會(huì)進(jìn)入)。
4. Create a function to close Direct3D
This is the last (and easiest) step to creating a Direct3D program. We just have two steps here:
這是最后一個(gè)(最簡(jiǎn)單)的步驟,創(chuàng)建一個(gè)Direct3D程序。我們只是在這里有兩個(gè)步驟:
1
// this is the function that cleans up Direct3D and COM
2
3
void cleanD3D(void)
4

{
5
d3ddev->Release(); // close and release the 3D device
6
d3d->Release(); // close and release Direct3D
7
}
8
Here, we call the Release() function from each of the two interfaces we created, d3ddev and d3d. No parameters, nothing spectacular. Just cleans everything up.
在這里,我們從我們創(chuàng)建的兩個(gè)接口調(diào)用Release(),d3ddev和D3D的每一個(gè)功能。沒(méi)有參數(shù),沒(méi)有返回。僅僅是清理一切。
Why? Well, let's say it would be a bad thing to do otherwise. Basically, if you create Direct3D, but never close it, it will just keep on running in the background of the computer until your next reboot, even after the program itself closes. Bad. Especially bad if you have a lot of resources in your game. Releasing these two interfaces let's everything off the hook and allows Windows to take back it's memory.
為什么呢?我得說(shuō)如果不這么做請(qǐng)你后果自負(fù)。基本上,如果你創(chuàng)建了Direct3D卻從來(lái)沒(méi)有關(guān)閉它,它就會(huì)不停地在計(jì)算機(jī)后臺(tái)運(yùn)行直到你重啟電腦,即使在程序本身關(guān)閉之后。特別是如果你有一堆壞的資源在你的游戲中,哦,買(mǎi)雷迪嘎嘎。釋放這兩個(gè)接口吧,讓一切干干凈凈,而Windows也可以收回它的內(nèi)存。
The Finished Program
Wow! That was quite a start, but it will go down from here.
Let's take a look at what we just did. Following is the code we added to our program. The new parts are now in bold.
哇!這僅僅還一個(gè)開(kāi)始,但是我們將從這里邁出第一步。
讓我們來(lái)跑跑看我們剛剛做的程序。以下是我們的代碼。沒(méi)出現(xiàn)的部分會(huì)以粗體顯示。
[Show Code]
And that's it! If you run this program you should get something like this:
那么,不出意外的話,你的程序跑起來(lái)應(yīng)該像這樣:

Image 1.3 - Our First Direct3D Program
Summary
Well, it isn't much yet. But you have begun the journey into the near-inifinite depths of 3D game programming. You've created a window and gotten DirectX to put an image (albeit a somewhat dull image) into it.
嗯,本節(jié)課已經(jīng)沒(méi)有多少了呢。但是我已經(jīng)成功地把你帶進(jìn)3D游戲編程的旅程,雖然現(xiàn)在還在入門(mén)水平。您已經(jīng)成功地創(chuàng)建了一個(gè)窗口,并通過(guò)DirectX成功嵌入一幅圖像(雖然這圖像實(shí)在很無(wú)聊)。
As an exercise, see if you can get your program to change colors while running. Try to make it fade from blue to black, then to blue again, and repeat.
嘗試一下這個(gè)練習(xí)吧,看看你能不能在程序運(yùn)行時(shí)改變它的顏色。嘗試做個(gè)藍(lán)黑漸變,然后再為藍(lán)色,反復(fù)如此。
So we haven't got a game running yet, but we have enough concepts to start. So with that, let's dive right in and start your next step (which is rather short, btw)!
事實(shí)上我們還有沒(méi)有一個(gè)游戲運(yùn)行,但我們有足夠的基礎(chǔ)概念。千里之行,始于足下,各位看官切記,切記!
Next Lesson: Going Fullscreen
下一課:走向全屏
GO!GO!GO!
Finished 20101110,耗時(shí)10天
posted on 2010-11-11 11:57
叫我老王吧 閱讀(2994)
評(píng)論(14) 編輯 收藏 引用 所屬分類:
DierectX