光照的組成
環(huán)境光:這種類型的光經(jīng)其他表面反射到達物體表面,并照亮整個場景,要想以較低代價粗略模擬這類反射光,環(huán)境光是一個很好的選擇
漫射光:這種類型光沿著特定的方向傳播。當它到達某一表面時,將沿著各個方向均勻反射,無論從哪個方位觀察,表面亮度均相同,所以采用該模型時無須考慮觀察者的位置,這樣,漫射光方程中僅需考慮光傳播的方向以及表面朝向,從一個光源發(fā)出的光一般都是這種類型的。
鏡面光:這種類型的光沿特定方向傳播,當此類光到達一個表面時,將嚴格地沿著另一個方向反射,從而形成只能在一定角度范圍內(nèi)才能觀察到的高亮度照射,所以在鏡面光照方程中不僅需要考慮光線的入射方向和圖元的表面朝向,還需要考慮觀察點的位置。鏡面光可用于模擬物體上的高光點,例如當光線照射到一個拋光的表面所形成的高亮照射。
鏡面光比其他類型光計算量大,因此Direct3D提供了開關(guān)選項,默認狀態(tài)下Direct不進行鏡面反射計算,如果想啟用鏡面光,必須調(diào)用接口進行設置
Device->SetRenderState(D3DRS_SPECULARENABLE, true);
每種類型的光都可用結(jié)構(gòu)D3DCOLORVALUE或者D3DXCOLOR來表示,描述光線的顏色時,D3DXCOLOR類中的Alpha值都將被忽略
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);
材質(zhì)
現(xiàn)實世界中,我們所觀察到的物體的顏色是由該物體所反射的光的顏色決定的,例如一個純紅色的球體反射了全部的紅色入射光,并吸收了所有非紅色的光,所以呈現(xiàn)為紅色。當一個物體吸收了所有的光時,便呈現(xiàn)為黑色,如果一個物體能夠100%地反射紅色光、綠色光、藍色光,它將呈現(xiàn)為白色,Direct3D通過定義物體的材質(zhì)來模擬同樣的現(xiàn)象,材質(zhì)允許我們定義物體表面對各種顏色光的反射比例,材質(zhì)用結(jié)構(gòu)D3DMATERIAL9來表示。
typedef struct D3DMATERIAL9 {
D3DCOLORVALUE Diffuse;
D3DCOLORVALUE Ambient;
D3DCOLORVALUE Specular;
D3DCOLORVALUE Emissive;
float Power;
} D3DMATERIAL9;
Diffuse:指定材質(zhì)對漫射光的反著率
Ambient:指定材質(zhì)對環(huán)境光的反射率
Specular:指定材質(zhì)對鏡面光的反射率
Emissive:該分量用于增強物體的亮度,使之看起來好像可以自己發(fā)光
Power:指定鏡面高光點的銳度,該值越大,高光點的銳度越大
//只反射紅色光
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;
設置材質(zhì)接口SetMaterial
D3DMATERIAL9 blueMaterial;
Device->SetMaterial(&blueMaterial);
//draw...
頂點法線
頂點法線描述的是構(gòu)成多邊形的各個頂點的法線,Direct3D需要知道頂點的法線方向,以確定光線到達表面時的入射角,由于光照計算是對每個頂點進行的,所以Direct3D需要知道表面在每個頂點處的局部朝向(法線方向),描述一個頂點法線需要修改頂點結(jié)構(gòu)
struct Vertex
{
float _x, _y, _z;
float _nx, _ny, _nz;
static const DWORD FVF;
};
const DWORD Vertex::FVF = D3DFVF_XYZ | D3DFVF_NORMAL;
計算三角形三個頂點的法線,可由計算該面的法向量得到,首先計算位于三角形平面內(nèi)的倆個向量
void ComputeNormal(D3DXVECTOR3* p0, D3DXVECTOR3* p1, D3DXVECTOR3* p2, D3DXVECTOR3* out)
{
D3DXVECTOR3 u = *p1 - *p0;
D3DXVECTOR3 v = *p2 - *p0;
D3DXVec3Cross(out, &u, &v);
D3DXVec3Normalize(out, out);
}
當用三角形單元逼近表示曲面時,將面片法向量作為構(gòu)成該面片的頂點法向量不可能產(chǎn)生很平滑的效果,一種更好的求取頂點法向量的方法是計算法向量均值,我們需要求出共享點v的所有三角形的面法向量,然后將這些法向量相加后除以個數(shù)進行平均。
在變換過程中,頂點法線有可能不再是規(guī)范的所以最好的方法是在變換完成后,通過設置繪制狀態(tài)來重新規(guī)范化
Device->SetRenderState(D3DRS_NORMALIZENORMALS, true);
光源
Direct3D支持3種類型的光源,分別是點光源、方向光、聚光燈
點光源:該光源在世界坐標系中有固定的位置,并向所有的方向發(fā)射光線(D3DLIGHT_POINT)
方向光:該光源沒有位置信息,所發(fā)射的光線相互平行地沿某一特定方向傳播(D3DLIGHT_DIRECTIONAL)
聚光燈:這種類型的光源與手電筒類似,該光源有位置信息,其發(fā)射的光線呈錐形沿著特定方向傳播(D3DLIGHT_SPOT)
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;
Type:定義創(chuàng)建的光源類型,可取以下3種枚舉值,D3DLIGHT_POINT、D3DLIGHT_SPOT、D3DLIGHT_DIRECTIONAL
Diffuse:該光源所發(fā)出的漫射光的顏色
Specular:該光源所發(fā)出的鏡面光的顏色
Ambient:該光源所發(fā)出的環(huán)境光的顏色
Position:用于描述光源在世界坐標系中位置的向量,對于方向光該參數(shù)無意義
Direction:一個描述光在世界坐標系中傳播方向的向量,對于點光源該參數(shù)無意思
Range:光線"消亡"前,所能到達的最大光程,該值的最大取值為,對于方向光該參數(shù)無意義
Falloff:該值用于聚光燈,該參數(shù)定義了光強從內(nèi)錐形到外錐形的衰減方式,該參數(shù)一版取為1.0f
Attenuation0、Attenuation1、Attenuation2這些衰減變量定義了光強隨距離衰減的方式,這些變量僅用于點光源和聚光燈,分別表示光的常量、線性、2次距離衰減系數(shù),衰減公式為,其中D為光源到頂點的距離。
Theta:僅用于聚光燈,指定了內(nèi)部錐形的圓錐角,單位為弧度
Phi:僅用于聚光燈,指定了外部錐形的圓錐角,單位為弧度
與D3DMATERIAL9結(jié)構(gòu)初始化類似,當需要一個簡單的光源時,D3DLIGHT9結(jié)構(gòu)的初始化也很繁瑣文章來源:http://www.zghlxwxcb.cn/news/detail-705166.html
D3DLIGHT9 d3d::InitDirectionalLight(D3DXVECTOR3* direction, D3DXCOLOR* color)
{
D3DLIGHT9 light;
::ZeroMemory(&light, sizeof(light));
light.Type = D3DLIGHT_DIRECTIONAL;
light.Ambient = *color * 0.4f;
light.Diffuse = *color;
light.Specular = *color * 0.6f;
light.Direction = *direction;
return light;
}
D3DXVECTOR3 dir(1.0f, 0.0f, 0.0f);
D3DXCOLOR c = d3d::WHITE;
D3DLIGHT9 dirLight = d3d::InitDirectionalLight(&dir, &c);
D3DLIGHT9實例初始化完畢之后,我們需要在Direct3D所維護的一個光源內(nèi)部列表中對所要使用的光源進行注冊,注冊成功后就可以對其開關(guān)狀態(tài)進行控制文章來源地址http://www.zghlxwxcb.cn/news/detail-705166.html
Device->SetLight(0, &light);
Device->LightEnable(0, true);
光照例程
bool SetUpPyramid()
{
//啟用光照(默認是啟用的)
Device->SetRenderState(D3DRS_LIGHTING, true);
Device->CreateVertexBuffer(12 * sizeof(PyramidVertex), D3DUSAGE_WRITEONLY, PyramidVertex::FVF, D3DPOOL_MANAGED, &Pyramid, 0);
PyramidVertex* v;
Pyramid->Lock(0, 0, (void**)&v, 0);
v[0] = PyramidVertex(-1.0f, 0.0f, -1.0f, 0.0f, 0.707f, -0.707f);
v[1] = PyramidVertex(0.0f, 1.0f, 0.0f, 0.0f, 0.707f, -0.707f);
v[2] = PyramidVertex(1.0f, 0.0f, -1.0f, 0.0f, 0.707f, -0.707f);
v[3] = PyramidVertex(-1.0f, 0.0f, 1.0f, -0.707f, 0.707f, 0.0f);
v[4] = PyramidVertex(0.0f, 1.0f, 0.0f, -0.707f, 0.707f, 0.0f);
v[5] = PyramidVertex(-1.0f, 0.0f, -1.0f, -0.707f, 0.707f, 0.0f);
v[6] = PyramidVertex(1.0f, 0.0f, -1.0f, 0.707f, 0.707f, 0.0f);
v[7] = PyramidVertex(0.0f, 1.0f, 0.0f, 0.707f, 0.707f, 0.0f);
v[8] = PyramidVertex(1.0f, 0.0f, 1.0f, 0.707f, 0.707f, 0.0f);
v[9] = PyramidVertex(1.0f, 0.0f, 1.0f, 0.0f, 0.707f, 0.707f);
v[10] = PyramidVertex(0.0f, 1.0f, 0.0f, 0.0f, 0.707f, 0.707f);
v[11] = PyramidVertex(-1.0f, 0.0f, 1.0f, 0.0f, 0.707f, 0.707f);
Pyramid->Unlock();
D3DMATERIAL9 mtrl;
mtrl.Ambient = d3d::WHITE;
mtrl.Diffuse = d3d::WHITE;
mtrl.Specular= d3d::WHITE;
mtrl.Emissive = d3d::BLACK;
mtrl.Power = 5.0f;
Device->SetMaterial(&mtrl);
D3DLIGHT9 dir;
::ZeroMemory(&dir, sizeof(dir));
dir.Type = D3DLIGHT_DIRECTIONAL;
dir.Diffuse = d3d::WHITE;
dir.Specular = d3d::WHITE * 0.3f;
dir.Ambient = d3d::WHITE * 0.6f;
dir.Direction = D3DXVECTOR3(1.0f, 0.0f, 0.0f);
Device->SetLight(0, &dir);
Device->LightEnable(0, true);
//規(guī)范化法向量
Device->SetRenderState(D3DRS_NORMALIZENORMALS, true);
//啟用鏡面高光
Device->SetRenderState(D3DRS_SPECULARENABLE, true);
//取景變換(觀察者坐標系)
D3DXVECTOR3 position(3.0f, 2.0f, -3.0f);
D3DXVECTOR3 target(0.0f, 0.0f, 0.0f);
D3DXVECTOR3 up(0.0f, 1.0f, 0.0f);
D3DXMATRIX V;
D3DXMatrixLookAtLH(&V, &position, &target, &up);
Device->SetTransform(D3DTS_VIEW, &V);
//投影變換
D3DXMATRIX proj;
D3DXMatrixPerspectiveFovLH(&proj, D3DX_PI*0.5f, (float)Width / (float)Height, 1.0f, 1000.0f);
Device->SetTransform(D3DTS_PROJECTION, &proj);
return true;
}
到了這里,關(guān)于Direct3D光照的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!