Chapter 5: 3D Primitives and Vertex Buffers


When we want Direct3D to render a 3D object for us, we start off by defining that object as a collection of vertices. We then give the object a more solid feel by connecting the vertices together with line segments. 
The vertices define the model in 3D space and the line segments define the object's outer skin or surface by joining the vertices together in groups.
當我們想的Direct3D渲染3D對象對我們來說,我們開始定義的對象作為一個集合的頂點。然後,我們給對象更加堅實的感覺通過連接頂點與線段。
頂點定義模型在三維空間中的線段定義對象的外表面由皮膚或加入頂點一起群體。

image001.jpg  

At first, this seems simple enough but many beginners become confused once they realize that 3D objects are defined completely by their vertices, We never actually define the object's surface by saying, “connect this vertex to that vertex with a line”. 
起初,這看起來簡單,但很多初學者成為困惑一旦他們認識到3D對象的定義完全被他們的頂點,我們從未真正確定物體表面的說,“這個頂點連接到該頂點與一條線”。


So, where do these line segments come from if we don't actually define them? Well, the line segments are simply implied by vertex order and a set of predefined rules for geometry construction which have been laid down by Direct3D. 
那麼,做這些線段來,如果我們不從實際定義呢?
那麼,線段只是隱含頂點秩序和一組預定義的規則的幾何結構已訂下的Direct3D。


These rules are basically defined through what is called a, “3D primitive”, which is a collection of vertices that form a single 3-D entity. 
這些規則是基本確定通過所謂的“3D原始”,這是一個集合的頂點,形成一個三維實體。


When we define a 3D object we need to pick the 3D primitive we want to use and define our object's vertices accordingly so Direct3D can interpret them correctly during rendering.
當我們定義一個3D對象,我們需要選擇我們想要的3D原始的使用和定義我們的對象的頂點因此可以這樣解釋他們的Direct3D過程中正確渲染。
 
Of course, half of these 3D primitives deal specifically with triangles, which I've already described as being the basic building block and work-horse of modern 3D graphics. 
當然,這些 3D基本類型的一半專門處理三角形,我已經描述為基本構件和工作馬現代三維圖形。


The other 3D primitives deal with points and lines, which can be very useful in creating special tools like model and level editors where an artist or modeler may need to manipulate the actual vertices and edges of model's geometry.
其他三維基本類型處理點和線,這是非常有用的工具,如建立專門的編輯模式和水平在一個藝術家或建模可能需要處理的實際頂點和邊模型的幾何形狀。


In all, Direct3D defines six 3D primitives:
總之,Direct3D的三維基本類型定義了六個:

Point Lists
Line Lists
Line Strips
Triangle Lists
Triangle Strips
Triangle Fans
點名單
行列出
條線
三角列表
三角形帶
三角風扇


Direct3D gives each primitive type an enumerated name, which is defined under the D3DPRIMITIVETYPE data type like so:
Direct3D的為每個原始類型枚舉的名稱,是指在 D3DPRIMITIVETYPE 數據類型,象這樣:

typedef enum _D3DPRIMITIVETYPE {
    D3DPT_POINTLIST = 1,
    D3DPT_LINELIST = 2,
    D3DPT_LINESTRIP = 3,
    D3DPT_TRIANGLELIST = 4,
    D3DPT_TRIANGLESTRIP = 5,
    D3DPT_TRIANGLEFAN = 6,
    D3DPT_FORCE_DWORD = 0x7fffffff
} D3DPRIMITIVETYPE;


Point Lists
A point is the simplest of all primitives. If our buffer of vertices is treated as a point list, then each vertex is nothing more than a point in 3D space and no attempt will be made to connect the vertices with edges. 
Obviously, this primitive is seldom used since it's difficult to render any thing of interest with it.
點列表
A點是最簡單的所有基元。如果我們的頂點緩衝被視為一個點的列表,然後每個頂點無非是在三維空間中的點,也沒有試圖將作出連接頂點與邊。
顯然,這種原始的是很少使用,因為它很難提供任何東西與它的利益。

image002.jpg  

Line Lists
In a line list, our vertices are used to create isolated and unconnected line segments. For example, if we call the first four vertices in the buffer v0, v1, v2, and v3; then v0 and v1 defines the first line segment, and v2 and v3 define the second line segment.
線列表
在線路列表,我們的頂點用於創建孤立的和未連接線段。
例如,如果我們所說的前四個頂點緩衝區中的V0,V1,V2和v3,然後 V0和V1定義的第一行段,和v2和v3定義第二個線段。

image003.jpg  

Because line lists pair-up vertices to make line segments, we can not use this primitive with vertex buffers that contain an odd number of vertices.
因為線列表對行動的頂點,使線段,我們不能用這種原始的頂點緩衝區包含一個奇數的頂點。


Line Strips
A line strip is similar to a line list, but instead of rendering a collection of isolated line segments, which may or may not be touching a line strip renders a series of connected line segments by simply connecting each vertex to the last one with an edge.
線條
一條線地帶類似於行列表,而是呈現一個集合的孤立線段,這可能會或可能不會接觸線地帶呈現一系列連接的線段,只需連接每個頂點到最後一個與邊緣。

image004.jpg  


It's apparent that line strips are more restrictive than a line list since all line segments have to touch end-to-end, but if this is what you want, line strips require fewer vertices than a line list because it eliminates redundant vertices where line segments meet. 
這顯然符合線條更嚴格的不是一條線列表,因為所有的線段有觸摸終端到終端的,但如果這是你想要什麼,線帶需要較少的頂點不是一條線列表,因為它消除了多餘的頂點在直線段滿足。


For example, a line list containing two line segments needs four vertices to define the two segments even when connected, but a line strip only needs three vertices to define the same poly line.
例如,一個行列表包含兩個線段需要四個頂點來定義兩部分,即使連接,但只需要一條線地帶三個頂點來定義相同的多線。

image005.jpg  

Saving one vertex, as depicted in the figure above, may not seem like much, but when you're dealing with an object containing thousands of vertices the savings can be considerable.
保存一個頂點,作為描繪在上圖中,可能看起來不多,但是當你處理一個對象,它包含數以千計的頂點儲存相當可觀的。


Triangle Lists 三角列表
A triangle list is a collection of isolated, unconnected triangles, which may or may not be touching each other. 
一個三角形列表是一個集合的分離,未連接的三角形,這可能是也可能不是互相接觸。

 

image006.jpg  

You simply define three vertices for each triangle needed. 
您只需定義每個三角形三個頂點的需要。


Since this primitive is easy to visualize and understand you'll see it used quite a bit in samples and demos.
由於這本原是容易想像和理解你會看到它使用相當多的樣品和演示。

Triangle Strips 三角形帶
Just like line strips, which is a more efficient way of storing line segments, triangle strips are a more efficient way of storing triangles. 
就像線線條,這是一種更有效的方式存儲線段,三角形帶是一種更有效的方式存儲三角形。

 

image007.jpg  


If we have a long run of connected triangles, it will take fewer vertices to store them as a triangle strip than to store them in a triangle list. 
如果我們有一個長遠的連接的三角形,它會採取較少的頂點來存儲它們作為一個三角形地帶,而不是它們存儲在一個三角形的清單。


In the following figure, it's easy to see how vertices can be saved as the first triangle is defined by v0, v1, and v2, but the next triangle only requires the addition of a single vertex, v3, to be defined. 
在下面的圖,很容易看到的頂點可以被保存為第一個三角形定義為 V0,V1和V2,但接下來的三角形只需要另外的一個頂點,V3,待確定。


In other words, once the first triangle has been laid, each additional vertex plotted results in a complete triangle through implied edges which reach back to the last triangle in the strip.
換句話說,一旦第一個三角形已經奠定,每增加一個頂點繪製結果在一個完整的三角形,通過暗示的邊緣這可以追溯到上三角形的地帶。


Triangle strips are by far the most popular primitive used today and considerable research has been done into converting regular un-optimized triangle meshes into tri-strips.
三角形帶是目前最流行的今天,原始的使用相當多的研究已經完成轉換成正規未最佳化三角網格成三條。


Triangle Fans
Like triangle strips, triangle fans also use shared vertices to eliminate redundancy, but instead of just creating a long strip, the potential for sharing is increased by having all triangles within the fan share a single, common vertex. 
三角風扇
像三角帶,三角球迷也使用共享頂點,以消除冗餘,而是只創建一個長條形的,潛在的共享是增加了讓所有的三角形內的風扇共享一個單一的,共同的頂點。

image008.jpg  

For example, the triangle fan illustrated below, not only contains triangles which share vertices with their neighbors, but each triangle shares vertex v0 as a common vertex.
例如,下圖所示的三角形風扇,不僅包含三角形的頂點與鄰國共享,但每個三角形頂點 V0股份作為一個共同的頂點。


It's a little harder to find good places in your models to use fans, but if you can find them, triangle fans are by far the most efficient way of storing 3D geometry.
這是一個有點難以找到好的地方在你的模型使用風扇,但如果你能找到他們,三角形風扇是目前最有效的方式存儲的三維幾何圖形。


Winding Order of Vertices 彎曲順序的頂點
 
When defining the triangles that make up the geometry of our 3D models, it's important to understand that the “winding order” of a triangle's vertices determine whether we're viewing the triangle's front face or its back face. 
當定義的三角形構成的幾何形狀的三維模型,重要的是要明白,“彎曲順序"的一個三角形的頂點確定我們是否正在查看三角形的正面或背面。


At first, this aspect of a triangle may not seem very important since both faces of a triangle look pretty much the same, but it will become very important when it comes time to render our triangles since, by default, only the front face of a triangle gets rendered.
起初,這方面的一個三角形的可能似乎不是很重要,因為既面臨著一個三角形的外觀幾乎相同,但它會變得非常重要,當談到時間,使我們的三角形,因為默認情況下,只有正面的三角形得到渲染。


Of course, there is a way to turn off this feature so that both faces of a triangle get rendered but it's a bad idea to get into this habit, especially if you're concerned with performance. 
當然,還有一種方法可以關閉此功能,這樣既面臨著一個三角形得到呈現,但它是一個壞主意,進入這個習慣,特別是如果你關注性能。

image009.jpg  

The reason for this is Direct3D supports a feature called “back-face culling” which allows 3D applications to run faster by culling away triangles which contribute nothing to the final scene.
究其原因,因為這是Direct3D的支持功能,稱為“後面淘汰”,讓3D應用程序的運行速度藉由淘汰三角形無用的後面。


To understand how back-face culling works, imagine for a moment that we created a 3D model of a highly tessellated sphere where we made sure that the winding order of each triangle placed its front face pointing out and away from the sphere's interior.
要了解“後面淘汰”的作品,想像一下,我們創建了一個三維模型的高度細化領域,我們確信,捲繞順序每一個三角形置於其正面指出,遠離球體的內部。
 
Now, if we were to render our sphere with out any back-face culling, Direct3D would simply push all the triangles that define it onto the video card for processing with out giving it second thought. 
現在,如果我們要呈現我們的領域與任何“後面淘汰”,只會把所有的Direct3D的三角形定義它的視頻卡上加工出來給它的第二個想法。


Unfortunately, this is partial waste of time since the video card will process every triangle – even the ones that lie on the sphere's far side and can't be seen. 
不幸的是,這是局部的浪費時間,因為視頻卡將處理每一個三角形 - 即使是那些趴在球的另一邊,無法看到。


Why would we want to waste time processing triangles that we can't even see? They contribute nothing to the scene! Of course, you already know the answer – use back-face culling. 
為什麼我們要浪費時間處理的三角形,我們甚至不能看?他們無助的場景!當然,你已經知道了答案 - 用“後面淘汰”。


With back face culling turned on, Direct3D will cull away any triangle which has its back facing towards us, and since we modeled our sphere correctly, that would be all triangles on the far side.
隨著背面淘汰打開,Direct3D將撲殺遠離任何三角形都有其背對著對我們,因為我們的領域模型正確,那將是所有三角形的另一邊。


Flexible Vertex Format 彈性頂點格式 <<FVF>>
 
Up until this point, we've been talking about 3D primitives and the vertices they represent under very simplistic terms.  
直到此時,我們一直在談論3D基本類型和他們所代表的頂點在非常簡單的條款。


More specifically, we've been treating our vertices as nothing more than 3D points in 3D space. 
更具體地說,我們一直作為處理的頂點無非3D點在三維空間。


This was perfectly fine when discussing 3D primitives because that's all that really matter at that point (pardon the pun), but to create realistic 3D models we need to add additional information to each vertex. 
這是完全正常的三維圖元時討論,因為這是所有真正的問題在這一點上(特赦雙關語),而是為了創造逼真的三維模型,我們需要添加額外的信息,每一個頂點。


At the very least, we should add a color value per vertex so our geometry can be rendered in other colors besides white, which is the default color in Direct3D. If everything was just white, our scene would hardly look 3D.
至少,我們應該每增加一個顏色值幾何頂點所以我們可以呈現其他顏色,除了白色,這是默認的顏色在Direct3D。如果一切只是白色的,我們的場景將很難看3D。

 

image010.jpg  


Of course, we can't just go around arbitrarily adding things to each vertex with out giving Direct3D a heads-up. 
當然,我們不能只是到處亂加東西出來給每個頂點與 Direct3D的平視。


If we don't tell Direct3D that all of our vertices have both a position and a color, how will it know what its reading when we pass the vertex data to it?
如果我們不告訴 Direct3D的是我們所有的頂點都位置和顏色,如何將它知道它的讀數,當我們通過頂點數據呢?


The answer to this is called a Flexible Vertex Format code. 
在回答這個被稱為彈性頂點格式的代碼。


A Flexible Vertex Format (FVF) code describes the contents of stored vertices to Direct3D so it can clearly decipher what's being passed to it. 
一個彈性頂點格式(FVF)代碼描述的內容儲存頂點的Direct3D所以它可以清楚地解讀什麼被傳遞給它。


Typically, this code is created as a simple define using FVF Flags, which have been predefined for your use by Direct3D. In the following code snippet, we use two FVF Flags, D3DFVF_XYZ and D3DFVF_DIFFUSE, to create a constant called D3DFVF_MY_VERTEX. 
通常,此代碼創建一個簡單的定義使用FVF標誌,已預定為您使用的Direct3D。在下面的代碼片段中,我們使用兩個 FVF標誌,D3DFVF_XYZ和D3DFVF_DIFFUSE,創建一個常數稱為 D3DFVF_MY_VERTEX。


We could have called the constant anything we wanted but its common practice to at least start it off with D3DFVF_ so other programmers know what purpose it serves.
我們也可以稱之為常量任何我們想要但其共同的做法,至少啟動了與 D3DFVF_以便其他程序員知道什麼目的服務。


After we've defined our FVF code we'll need to create a structure for our vertex type so it matches exactly with what our FVF code defines. 
當我們定義了我們的FVF代碼,我們需要建立一個結構類型,以便為我們的頂點與它完全符合我們的FVF代碼定義是什麼。


If we add or leave something out, or change the order of the variables within the structure, Direct3D will misinterpret our vertex data and our application will either render incorrect geometry or crash completely.
如果我們添加或留下點什麼出來,或更改順序的變量在結構,Direct3D將曲解我們的頂點數據和我們的應用程序要么渲染不正確的幾何形狀或完全崩潰。


#define D3DFVF_MY_VERTEX ( D3DFVF_XYZ | D3DFVF_DIFFUSE )


struct Vertex
{
    float x, y, z; // Position of vertex in 3D space
    DWORD color;   // Color of vertex
};


Our vertex structure, which is simply called “Vertex”, allocates space for three floats for its position and a single DWORD for color. 
The variable names could be whatever you want, but the number of variables, their types and order of placement can not be different from what was defined by the FVF Flags used by D3DFVF_MY_VERTEX.
我們的頂點結構,這簡直是所謂的“頂點”,分配空間三個浮點數其位置和一個 DWORD的顏色。
變量名可以不管你想要的,但數量的變量,其類型和順序安排,不能從不同的定義是什麼 FVF標誌使用D3DFVF_MY_VERTEX。


Here's a few of the more popular FVF flags in order along with their associated data types and required layout:
下面是幾個比較流行的FVF標誌,以便與他們相關的數據類型和所需的佈局


D3DFVF_XYZ      - untransformed vertex = 3 floats
D3DFVF_XYZRHW   - transformed vertex   = 4 floats
D3DFVF_NORMAL   - normal vector        = 3 floats
D3DFVF_DIFFUSE  - diffuse color        = 1 DWORD
D3DFVF_SPECULAR - specular color       = 1 DWORD
D3DFVF_TEX1     - texture coordinates  = 1,2,3, or 4 floats



It will no doubt take some time getting used to creating your own vertex structures from scratch so I would suggest looking over the SDK documentation carefully with regards to FVF Flags. 
毫無疑問,需要一段時間來適應創建自己的頂點結構從頭開始,所以我會建議在SDK文檔看仔細問候 FVF標誌。


As we progress through the book we'll return to this subject again and again as we add new flags to our FVF code. 
當我們進步,我們將經書回到這個問題,我們一次又一次地增加新的旗幟,我們的FVF代碼。


As an additional example here is FVF code definition and vertex structure suitable for lit geometry:
作為一個額外的例子是FVF代碼定義和頂點結構適合點亮幾何:


#define D3DFVF_MY_LIT_VERTEX ( D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_DIFFUSE ) 
struct Vertex
{
    float  x,  y,  z; // Position of vertex in 3D space
    float nx, ny, nz; // Normal vector for lighting calculations
    DWORD color;     // Diffuse color of vertex
};


With this configuration, each vertex that makes up our geometry consists of a position, a normal for lighting, and a diffuse color.
有了這個配置中,每個頂點,使我們的幾何圖形組成的一個位置,一個正常的照明,和漫反射顏色。
diffuse color: Diffuse Light,它會均等地對四面八方反射出同樣強度的光線。


Vertex Buffers 頂點緩衝區
Once you've come to grips with the 3D primitives and understand how their vertices get handled by Direct3D, you'll need a way of storing your vertices until it's time to render them.
一旦你是來正視的三維圖元,並了解他們的Direct3D頂點得到處理,你需要一種方法儲存您的頂點,直到畫它們的時候。


When working with Direct3D, we store our vertices using a Vertex Buffer, which is defined by the LPDIRECT3DVERTEXBUFFER9 data type. 
當工作用 Direct3D,我們存放我們的頂點使用頂點緩衝區,是指由LPDIRECT3DVERTEXBUFFER9數據類型。


The creation of a Vertex Buffer is accomplished by calling CreateVertexBuffer, which is one of the methods contained in the IDirect3DDevice9 interface.
創建一個頂點緩衝區是通過調用 CreateVertexBuffer,這是其中一個方法包含在IDirect3DDevice9接口。


HRESULT CreateVertexBuffer( UINT Length,
    DWORD Usage,
    DWORD FVF,
    D3DPOOL Pool,
    IDirect3DVertexBuffer9** ppVertexBuffer,
    HANDLE* pHandle
);
 
The following code snippet demonstrates how to create a Vertex Buffer suitable for holding three vertices. You can follow along using the “vertex_buffer” sample.
下面的代碼片段演示了如何創建一個頂點緩衝區適合持有三個頂點。你可以跟著使用“vertex_buffer”樣本。


LPDIRECT3DVERTEXBUFFER9 g_pVertexBuffer = NULL;
 
#define D3DFVF_MY_VERTEX ( D3DFVF_XYZ | D3DFVF_DIFFUSE )
 
struct Vertex
{
    float x, y, z;      // Position of vertex in 3D space
    DWORD color;   // Color of vertex
};
 
...
 
if( FAILED( g_pd3dDevice->CreateVertexBuffer(

                                              3*sizeof(Vertex),
                                              D3DUSAGE_WRITEONLY,
                                              D3DFVF_MY_VERTEX,
                                              D3DPOOL_DEFAULT,
                                              &g_pVertexBuffer,
                                              NULL ) ) )
{
    // TO DO: Respond to failure of CreateVertexBuffer
    return;
}

For the first argument, Length, we specify how big the buffer needs to be by simply multiply the size of our Vertex structure by three and passing in the result.
對於第一個參數,長度,我們指定多大的緩衝區需要通過簡單的乘法的大小我們的頂點結構由三個傳遞結果。

The second argument, Usage, is where we set any special property flags for our new Vertex Buffer. 
第二個參數,使用方法,是我們設置任何特殊的屬性標誌為我們的新的頂點緩衝區。

By passing D3DUSAGE_WRITEONLY, we are telling Direct3D that we intend to write to our buffer - but never read from it. 
通過傳遞 D3DUSAGE_WRITEONLY,我們告訴 Direct3D的,我們打算寫入我們的緩衝區 - 但不能讀它。

Setting this allows Direct3D to place our new vertex data in the most optimal memory for both writing and rendering. 
設置這使得我們的新的Direct3D頂點放置在最優化的數據存儲為寫入和渲染。

If you are uncertain about your writing and reading needs, just pass 3DPOOL_DEFAULT instead.
如果您不確定您的寫入和讀取需求,用 3DPOOL_DEFAULT 取代。


The third argument, FVF, is where we pass in our custom FVF flags, which gives Direct3D the necessary heads-up concerning the layout of our vertices as defined by the Vertex structure.
第三個參數,FVF,是我們通過在我們自定義的FVF標誌,這就給 Direct3D的必要抬頭關於佈局的頂點所定義的頂點結構。
 
The fourth argument, Pool, is how we specify where the memory for our new Vertex Buffer should be allocated from. 
第四個參數,Pool,是我們如何在指定的內存為我們新的頂點緩衝區應分配的。

This is fairly advanced optimization related feature, so for now we'll leave this decision up to Direct3D by passing D3DPOOL_DEFAULT.
這是相當先進的優化相關的功能,所以現在我們將離開這個決定到Direct3D的傳遞 D3DPOOL_DEFAULT。

The fifth argument, ppVertexBuffer, is where we pass in the pointer to our LPDIRECT3DVERTEXBUFFER9 object. 
第五個參數,ppVertexBuffer,是我們傳遞的指針我們 LPDIRECT3DVERTEXBUFFER9對象。

If the call to CreateVertexBuffer succeeds, the pointer passed in will point to a valid Vertex Buffer that we can use.
如果調用 CreateVertexBuffer成功,指針傳遞將指向一個有效的頂點緩衝,我們可以使用。

And finally, the sixth argument is reserved for future use and we simply set it to NULL.
最後,第六個參數是保留供日後使用,我們簡單地將其設置為 NULL。



Loading Vertex Buffers 載入頂點緩衝區
 
After we've successfully created a Vertex Buffer we'll need to lock it long enough to load our vertex data into to it. 
This is accomplished by calling LPDIRECT3DVERTEXBUFFER9's Lock method:
在我們已經成功地創建了一個頂點緩衝,我們需要鎖定它足夠長的時間來載入我們的頂點數據到它。
這是通過調用 LPDIRECT3DVERTEXBUFFER9的Lock方法:


HRESULT Lock( UINT OffsetToLock,
    UINT SizeToLock,
    VOID **ppbData,
    DWORD Flags
);
 
Locking is necessary with Vertex Buffers since it' unsafe to cache a pointer to the data buffer itself. 
鎖定頂點緩衝區是必要的,因為它是不安全的緩存指針到數據緩衝區本身。


This is because Direct3D is capable of speeding things up by moving the vertex data from system memory to video memory and vice versa if it becomes necessary to free up valuable video memory for more important resources. 
這是因為 Direct3D是能夠加速東西了通過移動頂點數據從系統內存到顯示內存,反之亦然如果有必要,以騰出寶貴的影像記憶體更重要的資源。


Locking basically ensures that we can safely access the vertex data without interfering with Diredt3D's internal memory management. 
鎖定基本上可以確保我們可以安全地訪問頂點數據,而不會干擾 Diredt3D的內部內存管理。


The ability to lock and unlock a vertex buffer is basically what separates a fancy Vertex Buffer from a regular user defined array.
能夠鎖定和解鎖頂點緩衝基本上是分開看中頂點緩衝區從一般使用者定義的數組。


Here's how we call Lock on our Vertex Buffer so we can load it with vertex data:
以下是我們調用鎖我們的頂點緩衝,所以我們可以加載它與頂點數據:


Vertex *pVertices = NULL;
 
if( FAILED( g_pVertexBuffer->Lock( 0, 0, (void**)&pVertices, 0 ) ) )
{
    // TO DO: Respond to the failure of calling Lock on our Vertex Buffer
    // TO DO:響應失敗調用鎖在我們的頂點緩衝
    return;
}
else
{
    //
    // The call to Lock was successful and pVertices now points to the
    // actual vertex buffer. We can now define our triangle's three
    // vertices.
    // 因此,要求鎖定成功和pVertices現在指向的實際頂點緩衝區。
    // 現在,我們可以定義我們的三角形的三個頂點。
 
    // Triangle's left vertex
    pVertices[0].x = -1.0f;
    pVertices[0].y =  0.0f;
    pVertices[0].z =  0.0f;
    pVertices[0].color = D3DCOLOR_COLORVALUE( 1.0, 0.0, 0.0, 1.0 ); // red
 
    // Triangle's top vertex
    pVertices[1].x = 0.0f;
    pVertices[1].y = 1.0f;
    pVertices[1].z = 0.0f;
    pVertices[1].color = D3DCOLOR_COLORVALUE( 0.0, 1.0, 0.0, 1.0 ); // green
 
    // Triangle's right vertex
    pVertices[2].x = 1.0f;
    pVertices[2].y = 0.0f;
    pVertices[2].z = 0.0f;
    pVertices[2].color = D3DCOLOR_COLORVALUE( 0.0, 0.0, 1.0, 1.0 ); // blue
}
 
g_pVertexBuffer->Unlock();
 
The code defines a simple multi-colored triangle and it's important to understand that even though there's no explicit mention of the D3DPT_TRIANGLELIST primitive type, we did define a triangle suitable for it. 
這段代碼定義了一個簡單的多彩色的三角形,重要的是要明白,即使沒有明確提到的D3DPT_TRIANGLELIST基本類型,我們也定義一個三角形適合它。

The actual declaration of the primitive type won't be until we're ready to render using this vertex buffer.
實際申報的原始類型將要到我們已經準備好使用這個渲染頂點緩衝區。

image011.jpg  


Rendering With Vertex Buffers 渲染頂點緩衝區
 
Finally, with our vertex buffer created and loaded with valid data, we're ready to render our triangle. 
The following piece of code demonstrates how to render the triangle we loaded into our vertex buffer:


最後,我們的頂點緩衝創建和裝載了有效的數據,我們就可以使我們的三角形。
下面一段代碼演示了如何呈現三角形,我們加載到我們的頂點緩衝:


g_pd3dDevice->SetStreamSource( 0, g_pVertexBuffer, 0, sizeof(Vertex) );
g_pd3dDevice->SetFVF( D3DFVF_MY_VERTEX );
g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, 1 );
 
The first call to, SetStreamSource, basically binds or identifies our vertex buffer as the primary source of vertex data for our Direct3D device to use.
第一步調用,SetStreamSource,基本上我們的綁定或識別頂點緩衝為主要來源的頂點數據的Direct3D設備來使用。


HRESULT SetStreamSource( UINT StreamNumber,
    IDirect3DVertexBuffer9 *pStreamData,
    UINT OffsetInBytes,
    UINT Stride
);
 
For the first argument, StreamNumber, we simply pick the primary stream by passing a 0. 
對於第一個參數,StreamNumber,我們只是挑主流通過傳遞一個0。


This book will not be covering any topics that require multiple streams, so we will always pass 0 for this argument.
這本書將不涉及任何主題,需要多個數據流,因此,我們將永遠傳遞 0這個說法。
 
The second argument, pStreamData, is where we pass in the actual vertex buffer. 
第二個參數,pStreamData,是我們通過在實際的頂點緩衝區。


In our case, we pass in g_pVertexBuffer, which is the vertex buffer that contains our triangle.
就我們而言,我們通過在g_pVertexBuffer,這是頂點緩衝區包含我們的三角形。
 
The third argument, OffsetInBytes, gives us the ability to skip ahead in the vertex buffer and begin rendering with a primitive other than the first one. 
第三個參數,OffsetInBytes,使我們能夠直接跳過在頂點緩衝區,並開始渲染用基本以外的第一個。


For example, if we had defined two triangles instead of just one for our vertex buffer, we could've skipped the rendering of the first one and started with the second one instead. 
例如,如果我們定義了兩個三角形而不僅是一個為我們的頂點緩衝,我們可能已經跳過了渲染的第一個和第二個開始代替。


Since we only have a single triangle defined and there's nothing else to skip to, we'll simply pass 0. 
由於我們只有一個三角形定義並沒有什麼別的跳過來,我們將簡單地傳遞 0。


Of course, if you did want to use an offset, you would have to make sure that your hardware supports this feature since not all cards allow offsetting of the data stream.
當然,如果你有要使用彌補,你必須確保你的硬件支持此功能,因為不是所有的卡允許彌補的數據流。


The last argument, Stride, tells Direct3D how many bytes are used by each vertex. 
最後一個參數,步幅,告訴 Direct3D每個頂點使用多少字節。


The stride is what allows Direct3D to find the individual vertices in the data stream. 
步幅是允許的Direct3D找到各個頂點的數據流。


The easiest way to set this is to simply call sizeof() on our Vertex structure.
最簡單的方法來設置,這是簡單地調用 sizeof()的對我們的頂點結構。


The second method called is to SetFVF, which helps Direct3D interpret the incoming stream of vertex data by defining the layout of each vertex in the buffer.
第二種方法稱為是SetFVF,這有助於解釋傳入的Direct3D頂點數據流通過定義佈局的每個頂點緩衝區中。


HRESULT SetFVF(
    DWORD FVF
);


The method takes only one argument - the FVF code used by the vertex buffer.
該方法只需要一個參數 - FVF代碼所使用的頂點緩衝區。


In our case, we pass in our custom FVF code which we defined as D3DFVF_MY_VERTEX.
就我們而言,我們通過在我們的自定義 FVF代碼,我們定義為 D3DFVF_MY_VERTEX。


Finally, with our vertex buffer identified as the primary data stream and the FVF code set, we can render our triangle by calling the last method, DrawPrimitive.
最後,我們的頂點緩衝確定為主要的數據流和FVF代碼集,我們可以使我們的三角形通過調用最後一個方法,DrawPrimitive。


HRESULT DrawPrimitive( 
    D3DPRIMITIVETYPE PrimitiveType,
    UINT StartVertex,
    UINT PrimitiveCount
);


We set the first argument, PrimitiveType, to D3DPT_TRIANGLELIST since we loaded our vertex buffer with vertices conforming to this primitive's layout and usage.
我們設置第一個參數,PrimitiveType,以D3DPT_TRIANGLELIST因為我們裝的頂點與頂點緩衝區符合這種原始的佈局和使用情況。
 
The second argument, StartVertex, is similar to the OffsetInBytes argument of the SetStreamSource method since it allows us to skip ahead and start rendering with any vertex we want. 
第二個參數,StartVertex,類似於 OffsetInBytes參數的SetStreamSource方法,因為它使我們能夠開始渲染跳過前進,我們想要的任何頂點。


The main difference is StartVertex skips past vertices by specifying a buffer index instead of specifying the number of raw bytes to skip. 
主要的區別是StartVertex跳過去頂點指定一個緩衝區索引,而不是指定的未經處理位元組數跳過。


Either way, we only have one triangle and we don't want to skip it, so we simply set the starting index to 0.
不管怎樣,我們只有一個三角形,我們不希望跳過它,所以我們只需將起始索引為 0。

The final argument, PrimitiveCount, identifies the total number of primitives that we want to render from our buffer and since we have only one triangle, we'll set it to 1.
最後一個參數,PrimitiveCount,確定了總數的基元我們要呈現我們的緩衝區,並因為我們只有一個三角形,我們將其設置為 1。
 
We'll cover more complicated examples of vertex buffers in a just moment, but we need stop long enough to cover an important topic: double-buffering.
我們將討論更複雜的例子,頂點緩衝區以公正的時刻,但我們需要停止足夠長的時間覆蓋的一個重要課題:雙緩衝。

 


Rendering & Double-Buffering 渲染與雙緩衝
 
Now that you know how to render using a Vertex Buffer and DrawPrimitive, it's important to understand that you can't simply render when ever you want to. 
現在你知道如何呈現使用頂點緩衝區和DrawPrimitive,重要的是要明白,你不能單純渲染每當你想。


The act of rendering 3D geometry must be done in an orderly fashion or things will get ugly quick.
該行為的渲染3D幾何都必須在一種有序的方式或難看的東西就會很快。


The reason for this is due to the way Direct3D based applications write pixel data to the monitor. 
究其原因這是由於這樣的Direct3D應用程序寫入像素數據到顯示器。


It may seem strange to be thinking about pixels when you're working with 3D geometry but displays and monitors only work with pixel data, so the end result of all applications, including 3D applications, is a buffer full of pixels.
這可能看起來很奇怪是思考像素,當你正與三維幾何圖形,但顯示器和監視器只與像素數據,因此最終結果的所有應用,包括3D應用,是一個緩衝區充滿像素。


Of course, writing pixels to the monitor is only part of the reason why we need to synchronize our applications rendering; the other reason has to do with smooth animation. 
當然,寫入像素顯示器只是部分原因,我們需要我們的應用程序進行同步渲染,另一原因,是因為有流暢的動畫。
image012.jpg  


Like a theatre projector, 3D applications produce animated scenes by showing the viewer a rapidly changing succession of images.
像劇院投影機,三維應用程序產生的動畫場景由觀眾呈現出一個快速變化的連續的圖像。


The only real difference between a real-time 3D applications and a theater projector is a real-time 3D application can not store the individual images that make up the scene's motion ahead of time like a projector does with film. 
唯一真正的區別 real-time 三維應用程序和一個影院投影機是一種 real-time 三維應用程序無法儲存單獨影像,使撐場面的議案提前像投影機與電影。


It must dynamically create each image just prior to displaying it. 
它必須動態創建每個圖像之前,為了顯示它。


If these images move fast enough they seem to blur together and the human eye can be fooled into thinking it's seeing a continuous stream of motion.
如果這些圖像移動速度不夠快,他們似乎變得模糊起來,人眼可以被愚弄,以為它看到一個連續的資料流的運動。


If the images move too slowly, the motion becomes jerky and the eye gets wise to the illusion. Needless to say, the faster we can dynamically create and display the individual images, the smoother the motion will be.
如果圖像移動速度太慢,動作變得生澀和眼睛得到明智的錯覺。不用說,我們可以更快的動態創建和顯示個人圖像,流暢的動作。
 
Unfortunately, monitors have physical limits and we can't simply go crazy and begin firing off hundreds of pixel buffers at the monitor and just expect it to display them without trouble. 
不幸的是,顯示器有物理極限,我們不能單純發瘋,並開始發射過上百個像素緩衝區的監控,只是希望它顯示他們沒有麻煩。


The heart of the problem lies with the monitor's refresh-rate and vertical retrace.
問題的重心在於顯示器的刷新率和垂直回掃。


The refresh-rate (measured in Hertz), identifies how many times a second the monitor can be updated without producing any graphical anomalies, while the monitor's vertical retrace identifies the amount of time required after each update before the monitor is ready for the next update. 
刷新速率(測量赫茲),確定有多少次,第二個顯示器可以更新,不產生任何圖形異常,而顯示器的垂直回掃標識量所需的時間後,每次更新前的顯示器是準備好下一次更新。


The following figure demonstrates this situation by tracing out the path taken by the monitor's electron-gun, which is what ultimately produces the final image:
下圖演示了這種情況,通過跟踪路徑採取了顯示器的電子槍,這就是最終生成最終圖像:


With the start of each update or frame of animation, the monitor's electron-gun starts at the upperleft corner and works itself across each scan-line (the blue line) until it reaches the right side. 
隨著每次更新或啟動幀動畫,顯示器的電子槍開始在左上角和工程本身在每個掃描線(藍線),直到達到正確的


As it traverses from left to right, it uses the values passed to it in the pixel buffer to light up each screen pixel with the appropriate color. 
由於它遍歷左到右,它使用的值傳遞給它的像素緩衝區點亮每個屏幕像素用適當的顏色。


Once it reaches the right side, it returns to the left side (the green line) and begins the next row. 
一旦它到達右側,它返回到左側(綠線),並開始下一行。


This continues until it reaches the end of the last row where it then returns the upper–left corner (the red line) to start the next update.
這樣下去,直至達到最終的最後一排的地方,然後返回左上角(紅色線),開始下一次更新。


 The time it takes to return to the top is the vertical retrace.
 所花費的時間返回到頂部垂直回掃。


If we fail to synchronize our updates with the vertical retrace, our animation will suffer an anomaly called “tearing”.
如果我們不能同步的更新與垂直回掃,我們的動畫將遭受一種反常現象稱為“撕裂”。


Tearing occurs when we try to render something to the monitor while the electron-gun is performing its vertical retrace. 
撕裂當我們試圖呈現的東西到顯示器,而電子槍是履行其垂直回掃。


If we attempt an update during the vertical retrace, moving objects will appear to tear since only part of the update containing their new positions end up being rendered to the screen. 
如果我們嘗試更新在垂直回掃,移動的物體會出現撕裂,因為只有部分的更新包含新的職位最終被渲染到屏幕上。


Fortunately, Direct3D has way of freeing us from this problem by using a technique called double-buffering. 
幸運的是,Direct3D的方式釋放了這個問題,我們從使用了一種叫做雙緩衝。


With Double-buffering applications can not directly write to the monitors' buffer, but instead have to synchronize with the vertical retrace by maintaining two separate pixel buffers. 
用雙緩衝應用程序無法直接寫入到監視器的緩衝區,而是要同步的垂直回掃維持兩個獨立的像素緩衝區。


The two buffers are called the front–buffer and the back-buffer.
這兩個緩衝區稱為前台緩衝區和後台緩衝區。


The front-buffer is basically the monitor's buffer and is used to render to the screen. 
前緩衝基本上是顯示器的緩衝區,用於呈現到屏幕上。


The back-buffer is a special off-screen buffer used by the application.
後台緩衝區是一個特殊的屏幕外的緩衝區所使用的應用程序。


By writing only to the back-buffer and swapping the two buffers during the vertical retrace, we can prevent tearing since the monitor can only be updated by completely finished buffers and an accidental write to the front buffer while it's being used is impossible.
通過寫只到後台緩衝區和交換這兩個緩衝區的垂直回掃期間,我們可以防止撕裂,因為顯示器只能通過完全更新完畢的緩衝區和意外寫入到前台緩衝區,而它的使用是不可能的。

image013.jpg  


After we swap or flip the two buffers, we clear out the content of the buffer that used to be the front-buffer and begin rendering to it while the new front-buffer (formerly the back-buffer) is used to update the monitor.
當我們交換或翻轉兩個緩衝區,我們清除了緩衝區的內容曾經是前緩衝區,並開始渲染它,而新的前緩衝器(原後備緩衝器)用於更新監視器。


Working with the Back-Buffer 工作與後台緩衝區
 
Now that you understand why it's important to perform double-buffering, we can cover the special methods defined by the Direct3D device, which actually allow us to work with these buffers properly. 
現在你明白為什麼它是重要的執行雙重緩衝,我們可以覆蓋的特殊方法定義的Direct3D設備,這實際上使我們能夠正確地使用這些緩衝區。


The methods are Clear, BeginScene, EndScene, and Present. As a demonstration of their usage and placement we'll use the same vertex buffer (g_pVertexBuffer ), which we created earlier in the chapter.
其方法是 Clear,BeginScene,EndScene,和 Present。作為演示其用法和安置,我們將使用相同的頂點緩衝區(g_pVertexBuffer),這是我們前面創建的新篇章。


The following code demonstrates the proper way to our render triangle contained in the vertex buffer:
下面的代碼演示了如何正確地包含在我們的渲染三角形的頂點緩衝區:


Listing 5-1: render function of the “vertex_buffer” sample
清單 5-1:渲染功能的“vertex_buffer”樣本


//-----------------------------------------------------------------------------
// Name: render()
// Desc: Render or draw our scene to the back-buffer and flip the buffers.
//-----------------------------------------------------------------------------
void render( void )
{
    //
    // Clear both the back-buffer and z-buffer by filling the back-buffer
    // with black pixels and the z-buffer with the value 1.0f.
    // 同時清除後備緩衝區和Z緩衝區填寫背面緩衝區與黑色像素和z緩衝區的值1.0F。
    //
 
    g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,
                         D3DCOLOR_COLORVALUE(0.0f,0.0f,0.0f,1.0f), 1.0f, 0 );
 
    //
    // Let Direct3D know that scene rendering is about to begin...
    // 讓我們知道,Direct3D的渲染場景即將開始
 
    if( FAILED(g_pd3dDevice->BeginScene()) )
    {
        // TO DO: Respond to the failure of BeginScene
        // Respond to the failure of BeginScene
        return;
    }
 
    //
    // Create a simple world matrix to move the triangle down the Z axis
    // 5 units. If we don't do this, both us and the triangle will be sitting
    // at the coordinate system's origin and we won't be able to see the
    // triangle at all.
    // 創建一個簡單的世界矩陣三角形向下移動 Z軸5個單位。
    // 如果我們不這樣做,我們和三角形會坐在坐標系的原點,我們將無法看到三角形的。
    //
 
    D3DXMATRIX mWorld;
    D3DXMatrixTranslation( &mWorld, 0.0f, 0.0f, 5.0f );
    g_pd3dDevice->SetTransform( D3DTS_WORLD, &mWorld );
 
    g_pd3dDevice->SetStreamSource( 0, g_pVertexBuffer, 0, sizeof(Vertex) );
    g_pd3dDevice->SetFVF( D3DFVF_MY_VERTEX );
    g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, 1 );
 
    //
    // Let Direct3D know that scene rendering is finished...
    // 讓我們知道,Direct3D的場景渲染完成
 
    if( FAILED(g_pd3dDevice->EndScene()) )
    {
        // TO DO: Respond to the failure of EndScene
        // 回應失敗 EndScene
        return;
    }
 
    //
    // Swap or flip the front and back buffers...
    // 交換或翻轉前後緩衝區
    //
 
    g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
}


The sample application will call the render() function once per update and render or draw our simple triangle to the screen. 
示例應用程序將調用 render()函數每一次更新和呈現我們的簡單的三角形或繪製到屏幕上。


The first thing we want to do is call the Clear method and wipe out the contents of the back-buffer before we start. 
首先我們要做的就是調用 Clear方法和消滅的內容後台緩衝區,然後才開始。


This is necessary since the current back-buffer was the front-buffer during the last frame update. 
這是必要的,因為目前的後備緩衝區前在最後一幀緩衝區的更新。


If we don't clean it out, we will simply be rendering on top of the last frame's pixels. 
如果我們不清理出來,我們將簡單地呈現在上面的最後一幀的像素。


Of course, this wouldn't really be a problem if we knew for certain that every single pixel was going to be over-written, but it's often easier to just clear the whole thing out instead trying to guarantee that this will happen under all circumstances.
當然,這不會真的是一個問題,如果我們知道的肯定,每一個像素是要被覆蓋,但它往往更容易清除整個事情剛出來,而不是試圖以保證這會發生在所有情況下。


HRESULT Clear( 
    DWORD Count,
    const D3DRECT *pRects,
    DWORD Flags,
    D3DCOLOR Color,
    float Z,
    DWORD Stencil
);


We'll set the first two arguments, count and pRects, to 0 and NULL respectively since we want to clear the entire buffer. 
我們將前兩個參數設置,數量和pRects,分別為 0和NULL,因為我們要清除整個緩衝區。


If, for some reason, we didn't wanted to clear the whole buffer we could perform a partial clear of one or more rectangular regions of the buffer by passing an array of D3DRECT structures along with the total count.
如果由於某種原因,我們沒有想清除整個緩衝區,我們可以執行部分清除一個或多個矩形區域的緩衝區通過傳遞一個數組 D3DRECT結構隨著總數。


The third argument, Flags, is where we specify which buffers to clear. 
第三個參數,標誌,是我們指定的緩衝區清除。


I say “buffers” (plural) since the Clear method is also used to clear out the z-buffer and stencil-buffer. 
我說“緩衝區”(複數),因為清除方法也可以用來清除z緩衝區和模板緩衝區。


For this sample, we'll pass D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, which tells Clear that we want to wipe out both the back-buffer and z-buffer. 
對於此示例中,我們將通過 D3DCLEAR_TARGET| D3DCLEAR_ZBUFFER,它告訴我們要清除消滅都後緩衝區和Z緩衝區。


We really don't need to pass D3DCLEAR_ZBUFFER in this sample, but it's a good habit to get into since we'll need it cleared more often than not.
我們真的不需要通過 D3DCLEAR_ZBUFFER在此示例,但它是一個好習慣,因為我們需要很多時候把它清除比不清除還多。((我們大多時候是要做Clear這個步驟,比沒有做Clear的步驟更常))


The z-buffer is used to guarantee that pixels belonging to geometry, which is further away, doesn't overwrite pixels belonging to geometry, which is much closer. 
z緩衝區是用來保證像素屬於幾何,這是遠,不屬於幾何覆蓋的像素,這是非常接近。


In other words, the z-buffer eliminates the need to pre-sort our triangles by distance from the viewer's position. 
換句話說,z緩衝區無需預先排序的三角形的距離,檢視器的立場。


Before we had hardware accelerate z-buffers, 3D graphics programmers had to make sure to render their triangles in front-to-back order. 
之前我們已經硬件加速Z緩衝,三維圖形程序員必須確保其呈現三角形前至後順序。


If they didn't render front-to-back, triangles that made up distant and possibly obscured objects would end up getting rendered on top of the triangles of much closer objects. 
如果他們不渲染前端到後端,三角形由遠而且可能模糊的物件最終到渲染在更靠近的物件的三角形頂部。


Who would want to play a race game where triangles from the road kept popping up and blocking out triangles that make up the car's hood? That would just look wrong!
誰希望打一場賽車遊戲三角形從道路不斷彈出,堵塞的三角形構成汽車的引擎罩?這只是看錯!


The fourth argument, Color, is where we specify the color to be used to clear the back-buffer. 
第四個參數,Color,在這裡我們指定的顏色被用來清除後備緩衝區。


Here, we simply set this to pure black by passing D3DCOLOR_COLORVALUE( 0.0f, 0.0f, 0.0f, 1.0f ). 
在這裡,我們簡單地設置為純黑色傳遞 D3DCOLOR_COLORVALUE(0.0f,0.0f,0.0f,1.0F)。


The argument's actual type is D3DCOLOR (a.k.a DWORD), but I've always found that to be a strange type to use for color since most 3D graphics programmers treat colors as being composed of 4 floats, so I decided to be more traditional and use the D3DCOLOR_COLORVALUE macro to convert the color values.  
該參數的實際類型是D3DCOLOR(又名DWORD),但我一直認為是一個奇怪的類型使用顏色,因為大多數 3D圖形程序員把顏色作為是由4浮點數,所以我決定要更傳統和使用在D3DCOLOR_COLORVALUE巨集轉換顏色值。


The first three floats represent the separated red, blue, and green color components while the fourth float represents the color's alpha value. 
前三個浮點數代表分離紅色,藍色和綠色部分,而第四浮動代表顏色的alpha值。


Each value is considered normalized and must be set to something between 1.0f and 0.0f to be accepted as valid. 
每個值被認為是規範化,必須設置的東西之間1.0F和0.0f到被接受為有效。


For the first three floats (red, green, and blue) 1.0f means full-color while a value of 0.0f means none. 
對於前三個浮點數(紅,綠,藍)1.0F指全彩而值0.0f意味著沒有。


The fourth float (alpha) is considered fully opaque at 1.0f and completely transparent at 0.0f. Here are a few examples:
第四浮動(α)被認為是完全不透明的1.0F和完全透明的0.0f。下面是幾個例子:
D3DCOLOR_COLORVALUE( 0.0f, 0.0f, 0.0f, 1.0f ) // black – fully opaque 完全不透明
D3DCOLOR_COLORVALUE( 1.0f, 1.0f, 1.0f, 1.0f ) // white – fully opaque
D3DCOLOR_COLORVALUE( 1.0f, 0.0f, 0.0f, 1.0f ) // red – fully opaque
D3DCOLOR_COLORVALUE( 0.0f, 1.0f, 0.0f, 1.0f ) // green – fully opaque
D3DCOLOR_COLORVALUE( 0.0f, 0.0f, 1.0f, 1.0f ) // blue – fully opaque
D3DCOLOR_COLORVALUE( 1.0f, 1.0f, 0.0f, 1.0f ) // yellow – fully opaque
D3DCOLOR_COLORVALUE( 0.0f, 1.0f, 1.0f, 1.0f ) // aqua – fully opaque
D3DCOLOR_COLORVALUE( 1.0f, 0.0f, 1.0f, 1.0f ) // purple – fully opaque
D3DCOLOR_COLORVALUE( 1.0f, 0.5f, 0.5f, 0.5f ) // pink – semi-transparent 半透明


Making up custom colors in this manner can take a little getting used to, so if you don't quite get it, feel free to play with these values in the sample and see what happens.
製作了自定義顏色以這種方式可能需要一點時間來適應,因此,如果你沒有完全得到它,可以自由地玩這些值的樣本,看看會發生什麼。


The fifth argument, Z, is the value that we want used when clearing the z-buffer. 
第五個參數,Z,是我們想要的值時使用清除z緩衝區。


Again, this is a normalized value and needs to be in the range from 0.0f through 1.0f to be valid. 
再次,這是一個標準值,需要在範圍從 0.0f通過1.0F是有效的。


We'll simply pass 1.0f. 
我們將簡單地通過1.0F。


This will reset the z value of each pixel to 1.0f, which represents the furthest distance that a pixel can be set to.
這將重置每個像素Z值到1.0f,它代表了最遠的距離,一個像素可以設置。


The last argument, Stencil, is used to set the value for clearing the stencil buffer. 
最後一個參數,Stencil,是用來設置值清除模板緩衝區。


Since we are not using the stencil buffer, we'll simply set it to 0.
由於我們沒有使用模板緩衝,我們將簡單地將其設置為0。


Our next method to call is BeginScene. 
我們的下一個方法調用 BeginScene。


Nothing can be drawn or rendered using a Direct3D device until this method has been called and has returned successfully.
沒有什麼可以繪製或使用的Direct3D渲染設備,直到這個方法被調用,並成功返回。


HRESULT BeginScene(VOID);


The BeginScene method gives Direct3D a chance to set things up internally for rendering. 
在BeginScene方法使Direct3D的機會設置的東西了內部的渲染。


If for some reason Direct3D can not begin rendering right away, the method will fail and we can either opt to try again or abort our rendering efforts till the next frame. 
如果由於某種原因不能Direct3D的渲染馬上開始,該方法將失敗,我們可以選擇重試或中止的渲染工作,直到下一幀。


The method doesn't take any arguments so there's not much to cover here. 
該方法不帶任何參數所以沒有太多的涵蓋這裡。


To keeps things simple, our sample's render function will simply return early if BeginScene fails for any reason. 
為了保持事情簡單,我們的樣本的渲染功能將直接返回,如果BeginScene早期失敗的任何理由。


If BeginScene succeeds, we can begin setting up the scene and rendering.
如果BeginScene成功,我們就可以開始設置場景和渲染。


Once we're finished setting up the scene and rendering, we notify Direct3D that we're completely done working on the current frame by calling the EndScene method.
一旦我們完成設置場景和渲染,我們通知的Direct3D,我們正在做的工作完全在當前幀通過調用 EndScene方法。


HRESULT EndScene(VOID);


If this method returns successfully, the current scene has been queued up for rendering by the driver and all that remains to be done is to actually flip or swap the front and back buffers with a call to Present.
如果此方法成功返回,目前場景已被輪候渲染由司機和所有工作要做是真正翻轉或交換前後緩衝區與呼叫到 Present。


HRESULT Present( 
    CONST RECT *pSourceRect,
    CONST RECT *pDestRect,
    HWND hDestWindowOverride,
    CONST RGNDATA *pDirtyRegion
);
 
The proper usage of the four of arguments defined by the Present method is well beyond this book, so all samples will simply pass four NULLs when calling Present. 
正確的用法的四個參數定義該方法是遠遠超出了這本書,因此,所有樣品將簡單地傳遞四個空值時調用現狀。


Please refer to the SDK's documentation for more information.
請參考 SDK的文檔獲取更多信息。


At this point, you can continue your study of 3D primitives and Vertex Buffers by playing around with the second sample called, “3d_primitives”, which actually demonstrates how to use each of the six primitive types by creating, loading, and rendering from six different Vertex Buffers – one for each primitive type. 
在這一點上,你可以繼續你的研究和三維圖元的頂點緩衝器由把玩所謂的第二個樣本,“3d_primitives”,這實際上說明如何使用每六個基本類型創建,加載和渲染來自六個不同頂點緩衝器 - 為每個原始類型。


As you'll soon see, there's really no difference between primitives when it comes to using them in conjunction with a Vertex Buffer. 
正如你很快就會看到,有真的沒有區別,當涉及到基本類型使用它們會同頂點緩衝區。


The only thing you really need to double-check is to make sure you're allocating enough vertices to cover the total number primitives that need to be stored in each buffer.
你唯一真正需要仔細檢查是確保你分配足夠的頂點覆蓋總數基本類型,需要存儲在每個緩衝區。


Creating Geometry From 3D Primitives 建立從三維圖元幾何


The multi-colored triangle created by the “vertex_buffer” sample is a good starting place when learning about 3D primitives, but triangles are flat and uninteresting to look at and teach us nothing about how to create more complex objects out of primitives. 
多彩色三角形所創造的“vertex_buffer”樣本是一個很好的起點,當了解三維基本類型,但三角形是平的,無趣看,教我們如何創建沒有什麼更複雜的對象進行的基元。


Let's put our new knowledge to work and try to build something a little more exciting like a cube which will actually be 3-Dimensional. 
讓我們把我們的新知識,工作,並嘗試建立的東西多一點令人興奮的像一個立方體這實際上是3維的。


You can follow along by checking out the code in the “cube” sample.
您可以跟著勾選出代碼中的“方塊"的樣本。


The first thing will do is define what each vertex of our cube contains by creating a Flexible Vertex Format code and vertex structure for it:
會做的第一件事情是確定了每個頂點的立方體包含我們通過創建一個靈活的頂點格式的代碼和它的頂點結構:

 
#define D3DFVF_CUBE_VERTEX ( D3DFVF_XYZ | D3DFVF_DIFFUSE )
 
struct CubeVertex
{
    float x, y, z; // Position of vertex in 3D space
    DWORD color;   // Color of vertex
}; 


As you may have noticed, we're going to use the same vertex lay-out as the triangle in the “vertex_buffer” sample. 
正如你可能已經注意到,我們將使用相同的頂點佈局設計為三角形的“vertex_buffer”樣本。


The vertex lay-out uses the D3DFVF_XYZ FVF and D3DFVF_DIFFUSE flags to tell Direct3D that each vertex that makes up our cube will contain a position, which is composed of three floats, and a diffuse color represented by the DWORD data type.
頂點佈局設計使用D3DFVF_XYZ FVF和D3DFVF_DIFFUSE標誌告訴 Direct3D的每一個頂點,使我們的立方體將包含一個位置,這是由三個浮點數,和漫反射顏色代表的DWORD數據類型。


The next step is to decide on a 3D primitive to use so we can start defining the cube's data. 
下一步是決定一個​​三維原始的使用,因此我們可以開始定義多維數據集的數據。


For our cube I've decided to define each side of the cube as a tri-strip using D3DPT_TRIANGLESTRIP. 
對於我們的立方體我決定來定義每邊的立方體作為一個三條使用D3DPT_TRIANGLESTRIP。


This may not be the most efficient way to define a cube, but it's fairly easy to follow and allows me demonstrate other items as we progress.
這可能不是最有效的方式來定義一個立方體,但它很容易遵循,並允許我為我們展示的其他項目的進展情況。


Here's our cube's vertex data. Note how we're defining the vertex data in a temporary array. 
這裡是我們的立方體的頂點數據。注意我們如何定義頂點數據在一個臨時數組。


Eventually, it will be loaded into a Vertex Buffer, but for now we'll store the data like this so we can examine it closer.
最終,它會被載入到一個頂點緩衝,但現在我們將存儲的數據是這樣,所以我們可以研究更接近。


CubeVertex g_cubeVertices[] =
{
    // Side #1 - red
    {-1.0f, 1.0f,-1.0f,  D3DCOLOR_COLORVALUE( 1.0, 0.0, 0.0, 1.0 ) },
    { 1.0f, 1.0f,-1.0f,  D3DCOLOR_COLORVALUE( 1.0, 0.0, 0.0, 1.0 ) },
    {-1.0f,-1.0f,-1.0f,  D3DCOLOR_COLORVALUE( 1.0, 0.0, 0.0, 1.0 ) },
    { 1.0f,-1.0f,-1.0f,  D3DCOLOR_COLORVALUE( 1.0, 0.0, 0.0, 1.0 ) },
 
    // Side #2 - green
    {-1.0f, 1.0f, 1.0f,  D3DCOLOR_COLORVALUE( 0.0, 1.0, 0.0, 1.0 ) },
    {-1.0f,-1.0f, 1.0f,  D3DCOLOR_COLORVALUE( 0.0, 1.0, 0.0, 1.0 ) },
    { 1.0f, 1.0f, 1.0f,  D3DCOLOR_COLORVALUE( 0.0, 1.0, 0.0, 1.0 ) },
    { 1.0f,-1.0f, 1.0f,  D3DCOLOR_COLORVALUE( 0.0, 1.0, 0.0, 1.0 ) },
 
    // Side #3 - blue
    {-1.0f, 1.0f, 1.0f,  D3DCOLOR_COLORVALUE( 0.0, 0.0, 1.0, 1.0 ) },
    { 1.0f, 1.0f, 1.0f,  D3DCOLOR_COLORVALUE( 0.0, 0.0, 1.0, 1.0 ) },
    {-1.0f, 1.0f,-1.0f,  D3DCOLOR_COLORVALUE( 0.0, 0.0, 1.0, 1.0 ) },
    { 1.0f, 1.0f,-1.0f,  D3DCOLOR_COLORVALUE( 0.0, 0.0, 1.0, 1.0 ) },
 
    // Side #4 - yellow (red + green)
    {-1.0f,-1.0f, 1.0f,  D3DCOLOR_COLORVALUE( 1.0, 1.0, 0.0, 1.0 ) },
    {-1.0f,-1.0f,-1.0f,  D3DCOLOR_COLORVALUE( 1.0, 1.0, 0.0, 1.0 ) },
    { 1.0f,-1.0f, 1.0f,  D3DCOLOR_COLORVALUE( 1.0, 1.0, 0.0, 1.0 ) },
    { 1.0f,-1.0f,-1.0f,  D3DCOLOR_COLORVALUE( 1.0, 1.0, 0.0, 1.0 ) },
 
    // Side #5 - magenta (red + blue)
    { 1.0f, 1.0f,-1.0f,  D3DCOLOR_COLORVALUE( 1.0, 0.0, 1.0, 1.0 ) },
    { 1.0f, 1.0f, 1.0f,  D3DCOLOR_COLORVALUE( 1.0, 0.0, 1.0, 1.0 ) },
    { 1.0f,-1.0f,-1.0f,  D3DCOLOR_COLORVALUE( 1.0, 0.0, 1.0, 1.0 ) },
    { 1.0f,-1.0f, 1.0f,  D3DCOLOR_COLORVALUE( 1.0, 0.0, 1.0, 1.0 ) },
 
    // Side #6 - cyan (blue + green)
    {-1.0f, 1.0f,-1.0f,  D3DCOLOR_COLORVALUE( 0.0, 1.0, 1.0, 1.0 ) },
    {-1.0f,-1.0f,-1.0f,  D3DCOLOR_COLORVALUE( 0.0, 1.0, 1.0, 1.0 ) },
    {-1.0f, 1.0f, 1.0f,  D3DCOLOR_COLORVALUE( 0.0, 1.0, 1.0, 1.0 ) },
    {-1.0f,-1.0f, 1.0f,  D3DCOLOR_COLORVALUE( 0.0, 1.0, 1.0, 1.0 ) }
};


You should also note that even though we're using a single array to store our cube data, the array actually contains six different tri-strips, one for each of the cube's six sides. 
你也應該注意,即使我們使用一個數組來存儲我們的多維數據集數據,數組實際上包含六種不同的三帶,一為每個立方體的六個面。


To make it easier to see which vertices belong to which side, 
為了更容易地看到哪些頂點屬於哪一方,


I've broken up the array's declaration with comments which delineate the vertex stream. 
我已經打破了數組的聲明和評論的劃定頂點流。


After doing this, it becomes obvious that we use four vertices for each side.
這樣做後,就變得很明顯,我們使用的每邊四個頂點。

image014.jpg  


I know it may seem confusing at first as to how all these vertex points make a cube, so you may have to sit down for a moment and work it all out in your head or plot it onto some graph paper to convince your self, but I assure you it does, in fact, make a cube.
我知道這似乎令人困惑首先,如何使這些頂點的立方體,所以你可能要坐下了一會兒,這一切工作在你的頭或陰謀到一些圖形文件,以說服你的自我,但我向你保證這樣做,其實,做一個立方體。


Now that we have the cube data defined, our next step is to use our Direct3D device object to create a Vertex Buffer to hold our data:
現在,我們有多維數據集數據定義,我們的下一步是用我們的Direct3D設備對象創建一個頂點緩衝區來保存我們的數據:


g_pd3dDevice->CreateVertexBuffer( 24*sizeof(CubeVertex),0, D3DFVF_CUBE_VERTEX,
                                  D3DPOOL_DEFAULT, &g_pVertexBuffer, NULL );
void *pVertices = NULL;
g_pVertexBuffer->Lock( 0, sizeof(g_cubeVertices), (void**)&pVertices, 0 );
{
    memcpy( pVertices, g_cubeVertices, sizeof(g_cubeVertices) );
}
g_pVertexBuffer->Unlock();


Take careful note of how our call to CreateVertexBuffer makes sure to allocate enough space for the 24 vertices that define our cube. 
就拿我們仔細注意如何調用 CreateVertexBuffer 可以確保分配足夠的空間為24頂點定義我們的立方體。

It's Ok to allocate too much space, but not enough and we'll have a problem when we attempt to memcpy the contents of our temporary array into the Vertex Buffer.
這是確定分配過多的空間,但還不夠,我們將有一個問題,當我們試圖 memcpy的內容,我們臨時數組到頂點緩衝區。

Finally, the only thing that remains is to render our cube. 
最後,唯一剩下的工作就是渲染我們的立方體。


To set things up, we set our cube's Vertex Buffer as the stream source with a call to SetStreamSource and to help Direct3D interrupt our data stream correctly, we set our custom FVF code with a call to SetFVF. 
要設置的東西,我們設置我們的立方體的頂點緩衝區的流源與調用 SetStreamSource,並幫助我們的數據流中斷的 Direct3D 正確,我們設置我們自定義的FVF代碼調用 SetFVF。

Once that's done, all we have to do is call DrawPrimitive to render our cube's six sides.
一旦這樣做了,所有我們要做的就是調用 DrawPrimitive來渲染我們的立方體的六個面。


g_pd3dDevice->SetStreamSource( 0, g_pVertexBuffer, 0, sizeof(CubeVertex) );
g_pd3dDevice->SetFVF( D3DFVF_CUBE_VERTEX );
 
g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP,  0, 2 );
g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP,  4, 2 );
g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP,  8, 2 );
g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 12, 2 );
g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 16, 2 );
g_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 20, 2 );
 
As I mentioned earlier, it's important to note that our cube defines its six sides as six separate tri-strips. 
正如我前面提到的,重要的是要注意,我們定義它的六面立方體6個獨立的三帶。


This means that we'll need to call DrawPrimitive six times to render the whole cube. 
這意味著,我們需要調用 DrawPrimitive六次來呈現整個立方體。


And since we stored all the vertices for the six sides in the same Vertex Buffer, we don't need to call SetStreamSource for each side, but we will need to move the start vertex up for each call we make to DrawPrimitive. 
而且,由於我們存儲所有頂點的六面在同一頂點緩衝區,我們不需要調用 SetStreamSource每一面,但我們將需要移動開始為每個頂點調用我們作出 DrawPrimitive。


This is how we can store and access multiple pieces of geometry contained in a single Vertex Buffer.
這是我們如何存儲和訪問多件的幾何形狀包含在一個單一的頂點緩衝區。

image015.jpg  








arrow
arrow
    全站熱搜

    createps 發表在 痞客邦 留言(1) 人氣()