D3D9學習筆記之光照

2021-09-27 03:05:18 字數 4674 閱讀 7008

學習目標:

為了場景的真實感,可為場景增加光照。光照有助於描述實體形狀和立體感。

使用光照時,無需自行指定頂點的顏色值; direct3d 會將頂點送入光照計算引擎,依據光源型別,材質以及物體表面相對於光源的朝向,計算出每個頂點的顏色值。基於某種光照模型計算出各頂點的顏色,會使繪製結果更逼真。

在 direct3d 的光照模型中,光源發出的光由一下3個分量或3種型別的光組成。

direct->setrenderstate(d3drs_specularenable, true);
光線的表示:

每種型別的光都可以用結構d3dcolorvalue 或 d3dxcolor來表示,這些型別描述了光線的顏色。

幾種光線顏色的例子:

d3dxcolor redambient(1.0f, 0.0f, 0.0f, 1.0f);

d3dxcolor bluediffuse(0.0f, 0.0f, 1.0f, 1.0f);

d3dxcolor whitespecular(1.0f, 1.0f, 1.0f, 1.0f);

注意:描述光線顏色時,d3dxcolor 類中的 alpha 值都將被忽略。

在現實世界中,我們所觀察到的物體的顏色是由該物體所反射的光的顏色決定的。例如,乙個純紅色的球體反**全部的紅色入射光,所以該球體呈現成紅色。direct3d 通過定義物體的材質來模擬同樣的現象。材質允許我們定義物體表面對各種顏色光的反射比例。

材質的表示:

typedef struct d3dmaterial9d3dmaterial9 *lpd3dmaterial9;
d3dmaterial9 red;

::zeromemory(&red, sizeof(red));

red.diffuse = d3dxcolor(1.0f, 0.0f, 0.0f, 1.0f);

red.ambient = d3dxcolor(1.0f, 0.0f, 0.0f, 1.0f);

red.specular = d3dxcolor(1.0f, 0.0f, 0.0f, 1.0f);

red.emissive = d3dxcolor(0.0f, 0.0f, 0.0f, 1.0f);

red.power = 5.0f;

這裡將綠色和藍色分量設為0,表明該材質對這些顏色的光的反射率為0%。將紅色分量設為1,表面該材質對紅色光的反射率為100%。注意,我們可以控制材質在各種型別光照下哪種顏色的光將被反射。

還需要注意,如果用乙個只能發射藍色光的光源來照射乙個紅色的球體,則由於藍色光被完全吸收,而反射的紅色光為0,所以該球體將無法被照亮。當乙個物體吸收來所有光時,便呈現為黑色。類似的,如果乙個物體能夠100%的反射紅色光,綠色光和藍色光,它將呈現為白色。

為了減輕手工初始化材質結構 d3dmaterial9 的負擔,我們可在**中新增如下實用函式以及全域性材質產量。

d3dmaterial9 d3d::initmtr1(d3dxcolor a, d3dxcolor d, d3dxcolor s, d3dxcolor e, float p);

namespace d3d

;

材質設定:

頂點結構中不含有材質屬性,但我們必須對當前材質進行設定。下面這個函式可用來對當前材質進行設定:

idirect3ddevice9::setmaterial(const d3dmaterial9* pmaterial);
繪製材質不同的物體需要先更換材質設定:

d3dmaterial9 bluematerial, redmaterial;

device->setmaterial(&bluematerial);

drawsphere(); //藍球

device->setmaterial(&redmaterial);

drawsphere(); //紅球

什麼是頂點法線?:

面法線是乙個描述多邊形朝向的向量

頂點法線正是基於上述思路而產生的,但它並不用於指定每個多邊形的法向量。頂點法線描述的是構成多邊形的各個頂點的法線。

頂點法線有什麼?:

direct3d需要知道頂點的法線方向,以確定光線到達表面時的射入角。而且,由於光照計算是對每個頂點進行的,所以 direct3d 需要知道表面在每個頂點處的區域性朝向(法線方向)。

請注意:頂點法線與表面法線不一定相同。近似的球體或圓是說明頂點法線和三角形麵片法線不一致的很好的例子。

頂點法線表示:

為了描述乙個頂點的頂點法線,我們必須修改頂點的結構:

struct vertex;

const dword vertex::fvf = d3dfvf_xyz | d3dfvf_normal;

注意:上述的結構中,沒有表示顏色的成員變數。這是因為我們將用光照來計算頂點的顏色。

計算面法線:

對於簡單的物體,如立方體和球體,可以通過觀察得到頂點的法線。

對於複雜的網格面,我們需要一種機械化的方法:

假定乙個三角形由頂點p0, p1, p2 構成,現在我們來計算每個頂點的頂點法相量 n0, n1, n1。

最簡單的做法是求出這3個頂點構成的三角形的面法線向量,並將該面法線向量作為各頂點的法向量。

首先計算位於三角形平面內的兩個向量。

p1 - p0 = u

p2 - p0 = v

則面法線為:

n = u * v

由於每個頂點的法向量與面的法向量相同,所以:

n0 = n1 = n2 = n

下面是乙個用於計算乙個由3個頂點構成的三角形所在面的法向量的 c語言 函式。

注意:該函式中假定頂點的指定順序為順時針繞序。如果頂點的指定順序為逆時針,則計算出的法向量將指向反方向。

void computenormal(d3dxvector3* p0, d3dxvector3* p1, d3dxvector3* p2, d3dxvector3* out)

計算頂點法線:

當用三角形單元逼近表示曲面時,將麵片法線向量作為構成該麵片的頂點法向量不可能產生很平滑的效果,一種更好的求取頂點法向量的方法是計算法向量均值,為了求出頂點 v 的頂點法向量 vn,我們需要求出共享頂點 v 的所有三角形的面法向量。則 v 的法向量可由這些面法向量的均值取得。假定有3個三角形單元共享頂點 v,其面法向量分別為 n0,n1,n2,則 v 的法向量計算方法為:

vn = 1/3(n0+n1+n2)

在變換過程中,頂點法線有可能不再是規範化的,所以最好的方法是在變換完成後,通過設定 d3drs_normalizenormals 繪製狀態使所有的法向量重新規範化。

direct3d 支援3種型別的光源

光源的表示:

在程式**中,光源用結構 d3dlight9 來表示:

typedef struct _d3dlight9  d3dlight9;
namespace d3d
這些函式實現簡單,下面僅列出 initdirectionallight 函式的實現,其他函式的實現方法類似:

d3dlight9 d3d::initdirectionallight(d3dxvector3* direction, d3dxcolor* color)

接下來在建立乙個傳播方向平行於 x 軸的方向光光源,我們可以這樣寫:

d3dxvector3 dir(1.0f, 0.0f, 0.0f);

d3dxvector3 c = d3d::white;

d3dlight9 dirlight = d3d::initdirectionallight(&dir, &c);

當 d3dlight9 例項初始化完畢之後,我們需要在 direct3d 所維護的乙個內部光源列表中對所要使用的光源進行註冊:

device->setlight(

0, //要設定的燈光列表中的元素,範圍是0-maxlights

&light //要設定的d3dlight9結構的位址

);

一旦光源註冊成功,我們就可對其開關狀態進行控制,如下列所示:

device->lightenable(

0; //要啟用/禁用的燈光列表中的元素

true //true=開,false=關

);

D3D9學習筆記之顏色

學習目標 顏色的表示 在 direct3d 中,顏色用 rgb 三元組來表示。將顏色分解為紅色 red 綠色 green 藍色 blue 這三個分量的加性混合決定了最終的顏色。我們可用該三個分量的不同組合來表示上百萬種顏色。rgb資料可用兩種不同的結構來儲存 第一種是結構是 d3dcolor,它實際...

(一)D3D9渲染原理

su ce和texture。使用su ce相對來說比使用texture要簡單一些,但是不如使用texture靈活。抽象概念 direct3d的抽象概念包括 devices 裝置 swap chains 交換鏈 和resources 資源 device 裝置 用於渲染3d場景。例如單色裝置就會渲染黑白...

D3D9學習筆記之渲染狀態關鍵字

d3drs fillmode繪製模式設定,可設定為點,線與面模式3種分別是 d3dfill point d3dfill wireframe,d3dfill solid d3drs cullmode消隱模式,按照三角形單元的頂點繞序進行背面消隱,可設定為 禁用背面消隱d3dcull none,對順時針...