天天看點

D3D基礎知識複習(一)

  這一部分我們将讨論Direct3D明暗處理的有關内容。

    • 4.1 明暗處理模式Shade Modes
    • 4.2 各種模式的比較Comparing Shading Modes
    • 4.3 設定明暗處理模式Setting the Shade Mode
    • 4.4 面和頂點法向量Face and Vertex Normal Vectors
  • 4.5 三角形内插Triangle Interpolants

  渲染多邊形時所采用的明暗處理模式對于多邊形的外觀有很大的影響。明暗處理模式決定了一個多邊形的表面上任意一點的顔色和光線的強度。Direct3D目前支援兩種明暗處理模式:

  • 平面明暗處理模式(Flat Shading)
  • Gouraud明暗處理模式(Gouraud Shading)

  使用平面明暗處理模式來渲染一個多邊形時,Direct3D的渲染管道(rendering pipeline)使用多邊形上第一個頂點的材質的顔色來作為整個多邊形的顔色。使用平面明暗處理

D3D基礎知識複習(一)

模式進行渲染的三維對象,在相鄰的不共面的兩個平面之間,會出現較明顯的邊緣。

  左圖顯示了一個采用平面明暗處理模式進行渲染的茶壺的圖檔。圖檔中,每一個多邊形的輪廓都非常清晰。平面明暗處理模式所要使用的計算量是兩種明暗處理模式中最小的。

  使用Gouraud明暗處理模式渲染一個多邊形時,Direct3D利用頂點法線(vertex normal)和燈光參數(lighting parameters)來計算每個頂點的顔色。然後,在多邊形的表面上進行線性内插運算(見“邊面和頂點法向量”部分)。舉例來說,如果頂點1的紅色值為0.9,頂點2的紅色值為0.4,使用Gouraud明暗處理模式和RGB色彩模式,那麼這兩個頂點間連線的中

D3D基礎知識複習(一)

點的的紅顔色的值就是0.6。

  左圖中顯示了使用Gouraud明暗處理模式的效果。圖中的茶壺由許多小的三角形平面所組成。然而Gouraud明暗處理模式使得它的表面看起來非常的平滑和完整。

  Gouraud明暗處理模式也可以用來顯示具有明顯邊緣的對象。具體細節見“表面和頂點法向量”部分。

  在平面明暗處理模式中,下圖中的金字塔的相鄰兩個面之間會有明顯的邊緣。而采用Gouraud明暗處理模式時,邊緣處的明暗值會由内插運算産生,因而最後會得到一個彎曲的表面。

D3D基礎知識複習(一)

  使用Gouraud明暗處理來照亮平坦的表面要比使用平面明暗處理模式更加真實。平面明暗處理模式中的同一個面的顔色是相同的,而Gouraud處理模式允許光線在表面上有更逼真的效果。當離一個表面很近的地方有一個點光源時,它們的差別将會更明顯的表現出來。

  Gouraud模式會将在平面處理模式中明顯的邊緣平滑掉,然而這樣可能會導緻馬赫帶效應(Mach bands)的産生,也就是相鄰的顔色或光線帶之間不能很平滑的互相融合。對于程式開發人員來說,可以通過增加構成對象的多邊形的數目來降低馬赫帶效應,當然也可以通過提高螢幕分辨率,或者增加程式的顔色深度來達到目的。

  使用Gouraud模式可能會丢失一些細節。下圖的例子顯示了這一情況,圖中的聚光燈完全位于一個多邊形表面上。

D3D基礎知識複習(一)

  這樣,當Gouraud模式在兩個頂點間進行内插的同時,也就将聚光燈一同丢失了;渲染出來的表面将不再有聚光燈。

  Direct3D允許每次選中一種明暗處理模式。預設情況下為Gouraud模式。可以通過調用IDirect3DDevice3::SetRenderState方法來改變模式。dwRenderStateType參數應該被設定為D3DRENDERSTATE_SHADEMODE。dwRenderState參數應該被設定為D3DSHADEMODE枚舉類型的一個成員。下面的代碼顯示了如何來設定目前的明暗處理模式。

// Set to flat shading.

// This code fragment assumes that lpDev3 is a valid pointer to 

// an IDirect3DDevice3 interface.

hr = lpDev3->SetRenderState(D3DRENDERSTATE_SHADEMODE, D3DSHADE_FLAT);

if(FAILED(hr))

{

// Code to handle the error goes here.

}

// Set to Gouraud shading (this is the default for Direct3D).

hr = lpDev3->SetRenderState(D3DRENDERSTATE_SHADEMODE,

D3DSHADE_GOURAUD);

if(FAILED(hr))

{

// Code to handle the error goes here.

}

  一個多面體的每一個面都有一個與這個面正交的法向量。這個向量的方向由構成面的頂點的組成順序以及所使用的坐标系統來決定。面的法線總是遠離這個面的正面一側,即由這個面的正面一側開始指向向外的方向。在Direct3D中,隻有面的正面一側是可見的。面的正面也就是指,從這一側來看面上的頂點按照順時針方向來構成這個面。

D3D基礎知識複習(一)

  任何一個面隻有正面和反面兩個面。Direct3D是不對反面進行渲染的,是以反面可以說被Culling掉了(be culled)。(如果需要的話,可以改變Culling模式(culling mode)來對反面進行渲染。纖細内容見“Culling狀态”部分。)

  Direct3D程式不需要對面法向量進行聲明;當需要用到它們時,系統會自動進行計算。在平面明暗處理模式中,我們會用到面法向量。而在Gouraud模式中,Direct3D使用頂點法向量(vertex normal)。它還使用頂點法向量來控制燈光和紋理效果。

D3D基礎知識複習(一)

  Direct3D程式通常使用頂點的D3DVERTEX類型。D3DVERTEX結構的成員用來描述頂點的位置和方向。這裡的方向就是指頂點的法向量。下面的代碼顯示了如何來設定頂點的各種值,包括頂點法向量。其中法向量指向位于世界坐标系的原點的視口(viewport)。這個例子中頂點的位置就位于世界坐标系中。

D3DVERTEX lpVertices[3];

// A vertex can be specified one structure member at a time.

lpVertices[0].x = 0;

lpVertices[0].y = 5;

lpVertices[0].z = 5;

lpVertices[0].nx = 0; // X component of the normal vector.

lpVertices[0].ny = 0; // Y component of the normal vector.

lpVertices[0].nz = -1; // Points the normal back at the origin.

lpVertices[0].tu = 0; // Only used if a texture is being used.

lpVertices[0].tv = 0; // Only used if a texture is being used.

// Vertices can also by specified on one line of code for each vertex

// by using some of the D3DOVERLOADS macros.

lpVertices[1] = D3DVERTEX(D3DVECTOR(-5,-5,5),D3DVECTOR(0,0,-1),0,0);

lpVertices[2] = D3DVERTEX(D3DVECTOR(5,-5,5),D3DVECTOR(0,0,-1),0,0);

  使用Gouraud模式時,Direct3D用頂點法向量來計算光源和表面之間的夾角。它還計算頂點的顔色和亮度,并且在原先的表面上通過内差運算來得到其它點上的值。Direct3D是通過夾角來計算亮度值。夾角越大,表面上光線的亮度就越小。.

  如果你所建立的對象的表面是平坦的,那麼頂點的法向量就應該與對象的表面正交。下圖向我們顯示了這一情況。圖中平坦的表面由兩個三角形構成。所有頂點的法向量都與表面正交。

D3D基礎知識複習(一)

  一般情況下,我們所建立的對象都是由許多的小的三角帶(triangle strip)組成的,并且這些三角形往往是不共面的。這樣,在我們在對對象的表面進行平滑的明暗處理時,就有一種簡單的方法來得到各個頂點的法向量。我們可以先來計算每一個小多邊形平面的法向量,而頂點的法向量就是與這些小平面的法向量的夾角相等的那一個向量。要注意的是,對于複雜的圖元,這種方法可能不夠有效。

  下面左圖中向我們示範了這種方法,圖中由兩個面,S1和S2,我們看到的是它們的側面。S1和S2的法向量用藍色表示。頂點的法向量用紅色表示。我們可以看到,頂點法向量與S1和S2的面法向量的夾角是相等的。使用Gouraud明暗處理模式時,這兩個面之間将是平滑的,不再有明顯的邊緣或棱角。

D3D基礎知識複習(一)

  如果頂點的法向量偏向任何一個面,會使表面上的亮度增加或減少,而這又由它與光源之間的夾角來決定。上面右圖的例子顯示了這一情況。圖中我們還是隻能看到兩個面的側面,并且頂點的法向量偏向S1一側,這樣就使它與光源的夾角比正常情況下有所減小。

  在使用Gouraud明暗處理模式時,我們也可以使一些對象具有尖銳的邊緣。如果正在使用執行緩沖(execute buffers),,那麼程式就需要對邊緣上的點的法向量制作一個副本,如下圖所示,我們可以看到,位于尖銳邊緣的點的法向量都有兩個。

D3D基礎知識複習(一)

  如果使用IDirect3DDevice3::DrawPrimitive或IDirect3DDevice3::DrawIndexedPrimitive方法來渲染場景,必須将具有尖銳邊緣的對象定義為三角形清單(triangle list)的形式,而不是采用三角帶(triangle strip)的形式。如果對象有三角帶來構成,那麼Direct3D就會把它當作由許多三角形面片組成的一個單獨的多邊形來對待。而這時,Gouraud模式對多邊形的每一個面片和兩個相鄰面片之間的部分都有效。這樣最終的結果就會使對象具有平滑的表面。然而以三角形清單的形式構成的多邊形則是由一系列不相連貫的三角形面片來組成,這種情況下,Gouraud模式隻對多邊形的每一個面片有效,而對面片之間的部分是無效的。這時,如果三角形清單中的幾個三角形相鄰的話,那麼他們之間就會出現尖銳的邊緣。

  另一種選擇是使用平面明暗處理模式。這樣在計算量上是很有效的,但是它的效果會不如采用Gouraud模式時的逼真。

當系統渲染一個場景時,它會在三角形上對三角形的頂點間進行内插運算。三角形内插運算包括:

  • 顔色Color
  • 鏡面屬性Specular
  • 阿爾法值Alpha

内插運算在不同的明暗處理模式下也是不同的,如下所示:

  • 平面模式:不進行内插運算。用三角形中的第一個頂點的顔色作為整個面片的顔色。
  • Gouraud模式:在所有三個頂點之間進行線性内插運算。

  當色彩模式不同時,顔色内插和鏡面屬性内插也是不同的。在RGB顔色模式下,系統使用紅、綠、藍三種顔色成分來進行内插。單色模式(或ramp模式)下,系統僅使用頂點顔色的藍色成分。

  顔色的阿爾法成分通常單獨來進行内插運算,這是因為裝置驅動器可以有兩種方法來實作透明效果:紋理融合(texture blending)或點畫法(stippling)。

  程式可以使用D3DPRIMCAPS結構的dwShadeCaps成員來決定目前的裝置驅動器支援哪種内插形式。

源自:http://17de.com/library/d3d_6im/d3dim6_4.htm   是個不錯的網址,不過是DX6.1的,但是很多的技術還可以有學習的價值

繼續閱讀