Lighting and Materials

   至今,我們已經描述了頂點處理,頂點處理只是針對頂點的位置和法線。這一章將講述光照和材質,它是用來決定物體的外表。 光照和材質是用來決定頂點的顏色的過程。

  理解光照的計算只是在物體的頂點上進行計算是很重要。這樣,如果物體的頂點描述越粗糙,則計算出來來的光則也是越粗糙。一個通常的錯誤是創建一個很大的立方體,並且把一個光源放置在離其中一個面的中心的很近的位置。通常的解決方案是爲立方體的面提供更多的頂點,來提高場景裏面物體的光照採樣密度,或者使用另外一種方法光照場景,如lightmaps使用紋理化或者在像素shader使用每像素光照。

  光照一個很複雜的過程,牽涉到很多渲染狀態以及其他參數。光是從光源散發出來,並且經過面反射都在進入人的眼睛。Direct3D中的光照計算是在本地計算。也是說,每個頂點的光照計算是獨立的。這意味着Direct3D並不直接計算陰影,因爲每個頂點的光照計算是獨立於其他它表面,即使這些面有可能遮擋了光。類似的,Direct3D並不會直接計算從另外一個表面反射到一個表面的光。 渲染技術如光線跟蹤和光線傳遞都被稱作global照明技術,因爲他們是計算整個場景裏面的光,這些光包括間接從一個表面反射到人的眼睛,陰影,內部反射以及其他全局光照效果和直接從面反射到人眼睛的光。以前仿照物理光照對於交互式的應用程序來說是一個很昂貴的計算過程。然而近來情況有所改善,大多數應用程序使用同樣的近似計算來計算場景裏面反射到人眼睛裏面的光。

   在計算機圖形裏面,我們通常處理三種不同類型的反射光:ambient, diffuse 和 spcullar。 ambient 能反射到場景裏面的所有方向,它的光源是沒有方向的,並且可以照亮場景裏面所有的物體。Diffuse 反射是基於表面法線的,但是與眼睛的位置沒有關係。 specular 反射不僅與表面法線,光的方向有關,而且與眼睛的位置也有光。

   在進入Direct3D的光照計算之前,我們將告訴你怎樣把沒有光照過的頂點(lit vertices)提供給光柵器。接下來,我們將看怎麼定義場景裏面的光源。再接下來,我們將看Direct3D材質的屬性,以及他們怎麼樣與場景裏面的光進行交互。最後,我們將看看怎麼從光的定義和場景的定義來計算每個頂點的光。

Tranformed Vertices

   通過爲每個頂點提供diffuse和specular,應用程序可以執行它的光照計算和提供被lit的頂點。如果應用程序有很特殊的光照計算,你可以單獨計算他們,然後直接修改他們的diffuse和specular。當你的目的只是繪製一個特定的顏色或者顏色漸變,而不需要必要的光照計算,lit vertices也是能用上的。漸變效果可以通過提供給一個primitive的不同顏色來實現它。當光被忽略使,Direct3D使用不透明的白色作爲diffuse,透明和黑色作爲specular顏色。

Lightting Calculations

  

 計算diffuse和specular光照的總體流程如上圖8.1所示。RS Lighting 可以用來enable 和 diable 光照計算。當這個渲染狀態設置爲FALSE,沒有光照計算被執行,diffuse和specular來自於他們本來的頂點組件。當RS Lighting被設置爲TRUE, Direct3D爲每個頂點計算出光線的總量。一個頂點總的反射量被計算出來,是要根據當前材質屬性,enabled光的集合,頂點的位置,面法線,diffuse 和specular顏色組件。所有頂點都有一個位置組件,光照需要頂點必須包含一個面法線組件。diffuse 和 specular 是可選的。如果你的模型沒有面法線,但是你又需要計算光照,這樣,你必須計算頂點的面法線。計算面法線的最好的方法是直接在創建頂點數據的過程裏面創建,D3DXComputeNormals可以用於計算一個mesh的頂點法線。

  爲了從一個三角形裏面計算頂點的面法線,你能通過向量的差積來計算。頂點法線則是取包含這個頂點的所有面的法線的平均。爲了正確的計算光照,頂點法線向量應該是單位向量。在chapter 6,我們已經談到,縮放變換會改變面法線的長度。處理這個情況有好幾種方法:在場景裏面不要使用縮放變換,或者光照之前重新歸一化法線向量。

   在固定功能的光照下,RS Normalize Normals將控制法線的重新歸一化,這是處理縮放問題的最容易的方法。然而,重新歸一化法線需要消耗,你可能使用在建模的時候避免縮放。

   Direct3D計算光照只是使用了頂點的本地信息,並不計算陰影和其他照明效果。光被建模成不同類型反射光的總和。這些光的屬性不僅依靠頂點材質的反射屬性,也依靠光源的顏色。

   Light = Ambient + Diffuse + Specular + Emissive

Ambient光是場景裏面間接的光,可以被視爲背景光。

Diffuse光: 粗糙的表面使入射的光反射,這樣導致了diffuse反射。Direct3D使用朗伯cos法則。反射的強度取決於光和麪法線的夾角,而與視線的方向無關。

Specular光:平滑的面以一種向鏡子似的方式反射入射的光線,這種方式就是specular反射。Direct3D計算specular使用Blinn-Phong的模型,使平滑的面看起來就像被刨光的金屬,玻璃和塑料。反射的強度取決於面法線,光線的方向以及視線的方向。

Emissive:這根本不是一種反射,它實際上是表面本身發出來的光,而且也是總反射量的一部分。雖然它能發光,但它不能算成是Direct3D的光源。例如,一個區域光源可能使用一個只攜帶反射組件的幾何體來做它的模型。

Surface Material Properties

面的反射屬性可能通過設備的狀態以及每頂點的數據來設置。這些屬性定義了物體面表怎麼反射ambient, diffuse和specular光源。SetMaterial和GetMaterial用來管理material的屬性,材質的屬性是通過D3DMATERIAL9結構體來定義的。

HRESULT GetMaterial(D3DMATERIAL9* value);

HRESULT SetMaterial(const D3DMATERIAL9* value);

typedef struct _D3DMATERIAL9

{

   D3DCOLORVALUE Diffuse;

   D3DCOLORVALUE Ambient;

   D3DCOLORVALUE Specular;

   D3DCOLORVALUE Emissive;

   float Power;

} D3DMATERIAL9;

這個結構的diffuse, ambient, specular和emissive都是代表材質的反射屬性的,這裏每個成成員都是一個D3DCOLORVALUE的4浮點數,每個浮點數都代表被材質反射的部分光源。例如,diffuse值是{0.5,0.5,0.5,0.5}代表材質將反射50%的diffuse光。如果一個物體不是光源,場景中所有光的反射係數的和將等於1,符合能量守恆定律。Power成員是單個浮點數,它表示面上鏡面高光的延伸度。越光滑的面,它的光澤度越高,power值就也高。

  RS Color Vertex 決定了材質屬性的源,當它FALSE的時候,材質屬性直接從當前的材質取,當它爲TRUE時,材質屬性是基於RS Ambient Material Source, RS Diffuse Material Source , RS Specular Material Source 和 RS Emissive Material Source.這些材質源屬渲染狀態都是D3DMATERIALCOLORSOURCE 類型。D3DMCS_COLOR1和D3DMCS_COLOR2分貝從頂點的diffuse和specular顏色組件裏面選擇材質屬性。

typedef enum _D3DMATERIALCOLORSOURCE

{

   D3DMCS_MATERIAL = 0,

   D3DMCS_COLOR1 = 1,

   D3DMCS_COLOR2 = 2
} D3DMATERIALCOLORSOURCE

 如果D3DCAPS9::VertexProcessingCaps的D3DVTXPCAPS_MATERIALSOURCE7被設置,設備支持材質源的渲染狀態。否則,使用下面的表裏的默認值。

 

Light Source

  在Direct3D的光照計算中,Ambient光總是被作爲所有的間接光效果的源。RS Ambient定義了場景中環境光的強度,其值是D3DCOLOR值。

  對於其他光源,Direct3D維護D3DLIGHT9結構的數組,每一個都定義了一個光源。應用程序能夠修改這個數組裏面的任何元素,也能夠在場景渲染的時候enable和disable任何一個元素。Direct3D是通過GetLight和SetLight函數來管理這個數組。GetLightEnable可以返回某個光源的狀態。 LightEnable用來控制光源的狀態。

typedef struct _D3DLIGHT9

{

  D3DLIGHTTYPE Type;

  D3DCOLORVALUE  Diffuse;

  D3DCOLORVALUE  Specular;

  D3DCOLORVALUE  Ambient;

  D3DVECTOR      Position;

  D3DVECTOR   Direction;

  float          range;

  float          falloff;

  float          Attenuation0;

  float          Attenuation1;

  float          Attenuation2;

  float          Theta;

  float          Phi;
} D3DLIGHT9;

typedef enum _D3DLIGHTTYPE

{

   D3DLIGHT_DIRECTIONAL = 3,

   D3DLIGHT_POINT = 1,

  D3DLIGHT_SPOT   = 2
} D3DLIGHTTYPE;

 Direct3D 支持三種不同類型的光源:directional, point, spot. 並不是D3DLIGHT9的所有結構成員都可以用於所有類型的光源。Type, ambient,diffuse,specular成員可以用於所有的光源。如下圖,總結了不同類型的光可以使用的成員。Position,Direction和Range都是定義在世界座標系下的。

 應用程序當然可以隨意定義自己想要的光,只要在系統存儲允許的條件下。但是,硬件頂點處理只支持有限的光,一般情況下是8。 D3DCAPS9::MAXActiveLights 給出了渲染時最大能使用的光的數量。處理有限光源最通常的策略是儘量激活那些對primitive影響最大的光。 如果VertexProcessingCAPS設置了D3DVTXPCAPS_DIRECTIONALLIGHTS,則設備支持directional光。如果VertexProcessingCAPS設置了D3DVTXPCAPS_POSITIONALLIGHTS,設備支持point和spot光。

 

  • Directional Lights

 跟其他光源類似,directional light(Ld) 也指定了它的ambient(Al), diffuse(Dl), specular(Sl). 並且還指定了它的方向向量(Dl

Ld = {Al,Dl,Sl,Dl};

例如,太陽距離地球很遠,所有它的光線感覺都是平行的,所以,太陽光線可視爲平行的directional光。

  • Point Lights

 點光源Lp可以向任何方向發射光線,它的發射點是Pl。 當點光源距離物體很遠的時候,可以視作爲directional light. 當點光源距離物體很近的時候,它不同的部分接收光線的角度將不一樣。

  • Spot Lights

 Spot light將從某個位置向某個方向發射一柱光線。

  • Light Attenuation

 Spot light 和 point light都會隨着距離的增加光線強度減弱。減弱度(al)可以通過一個[0,1]的係數表示。 Directional light不會減弱,al =1;point light是隨着它距離頂點的範圍來減弱的,al = ar; Spot light的減弱與距離和光錐的falloff有關, al = aras。

  Ar是根據頂點到光源的距離來計算出來的,當距離超過了光源的範圍,則減弱度就等於0;當距離在光源的範圍以內,減弱度的計算是與三個減弱係數有關,a0l,a1l,a2l。 公式如下:

 spot light光錐的減弱度與它的內椎的角度,外錐的角度以及fallof都有關。它的公司如下:

 

  

 

 

 The Illumination Model

 

 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章