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

 

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