永远也不完美的程序

不断学习,不断实践,不断的重构……

常用链接

统计

积分与排名

好友链接

最新评论

光与材质(转)

转载自:http://www.gesoftfactory.com/developer/LnM.htm

光用于照亮场景中的物体。当光照被启用时,Microsoft® Direct3D®根据下列组合计算每个顶点的颜色。

  • 当前材质的颜色及相关纹理贴图中的纹理像素(texels)。
  • 若已给出顶点的漫反射色和镜面反射色,则使用。
  • 场景中光源产生的光的颜色和强度,或场景中环境光的级别。

当使用Direct3D光照和材质时,应用程序允许Direct3D代为处理照明的各种细节。如果需要的话,高级用户可以执行自己的光照计算。

应用程序如何使用光照和材质使渲染得到的场景有很大区别。材质定义了光在表面上如何反射。直射光和环境光级别定义了反射的光。如果启用了光照,应用程序渲染场景时必须使用材质。对于渲染场景而言,光不是必须的,但是如果渲染的场景没有光,那么会有许多细节不可见。渲染一个未经光照的场景至多也只能得到场景中物体的轮廓,而这对大多数用途而言是不够的。

以下主题包含了更多信息。


Direct3D光照模型与自然光的比较


在自然界,当光从光源发出后,在到达用户的眼睛之前,已经经过了成千上万个物体的反射。每经过一次反射,一部分光被表面吸收,一部分被散射到各个方向,而剩余的则被反射到其它表面或用户的眼睛里。这个过程一直持续,直到光衰减为零或到达用户眼中。

显然,要完美地模拟自然光所需的计算量太大以致于无法用在实时三维图形中。因此,考虑到速度,Microsoft® Direct3D®光照模型对自然光的工作方式进行模拟。Direct3D用红、绿、蓝三原色描述光,并将它们合成产生最终的颜色。

Direct3D中,当光从表面反射时,光的颜色与表面本身以某种数学方式相互作用,并产生最终显示在屏幕上的颜色。有关Direct3D使用的具体算法,请参阅与光照相关的数学

Direct3D光照模型将光归纳为两类:环境光和直射光。每种光具有不同的属性,并以不同的方式与表面材质相互作用。环境光是经过多次散射的光以至于它的方向和来源都无法确定:它给各处提供一个较低级别的光强。摄像师使用的非直射光是环境光的一个很好的例子。Direct3D中的环境光,和自然界中的一样,没有实际的方向和光源,只有颜色和光强。事实上,环境光的级别完全独立于场景中的任何发光物体。环境光不参与镜面反射。

直射光是场景中的光源产生的光,它总是具有颜色和强度,并沿特定的方向传播。直射光与表面材质相互作用产生镜面反射高光(highlight),它的方向用作各种着色算法(包括高洛德着色算法)中的一个因子。当直射光反射时,它不影响场景中的环境光级别。场景中产生直射光的光源具有不同的特征,这些特征影响到光如何照亮场景。更多信息,请参阅光照与材质

另外,多边形的材质具有一些属性,这些属性影响多边形如何反射它接收的光线。应用程序可以设置一个专门的反射系数,用于描述材质如何反射环境光,应用程序还可以设置另一个反射系数以决定材质的镜面反射和漫反射。更多信息请参阅材质


光与材质的颜色值


Microsoft® Direct3D®用四个成员——红、绿、蓝和阿尔法——描述颜色,并将它们合成,产生最终颜色。Direct3D为C++程序定义了D3DCOLORVALUE结构,该结构包含了所有成员,每个成员是一个浮点数,一般在0.0到1.0范围内,闭区间。虽然光照和材质使用相同的结构描述颜色,但对结构中的值的使用略有不同。

光源的颜色值表示它发出的某种光成分的数量。因为光不包含阿尔法成员,所以只有颜色的红、绿和蓝成员是有用的。可以把三种成员想象成投影电视的红、绿、蓝镜头。每个镜头可能被关掉(相应成员的值为0.0),或是位于范围内的某个值。镜头中照射出的颜色组合成光的最终颜色。如R: 1.0, G: 1.0, B: 1.0组合成白光,而R: 0.0, G: 0.0, B: 0.0则完全不发光。也可以产生只发出某个成员颜色的光,这样可以得到纯红、纯绿或纯蓝光,或者也可以将它们组合,得到黄色或紫色。甚至可以将颜色的成员设为负值,这样就产生了实际上将光从场景中移除的“暗光(dark light)”,得到场景变暗的效果。或者,也可以将成员设为大于1.0的值,产生特别亮的光。

另一方面,材质的颜色值表示用该材质渲染的表面对某种光成分的反射度。颜色成员为R: 1.0, G: 1.0, B: 1.0, A: 1.0的材质会反射所有的入射光。同样,成员为R: 0.0, G: 1.0, B: 0.0, A: 1.0的材质会反射所有入射的绿光。具有多重反射系数值(译注:漫反射、镜面反射、等等)的材质可以创建不同类型的效果,更多信息,请参阅材质属性

环境光的颜色值和用于直射光的光源及材质的颜色值是不一样的。更多信息,请参阅直射光与环境光的比较


直射光与环境光的比较


虽然直射光与环境光都用于照亮场景中的物体,但它们互不相关,且具有非常不同的效果,并要按照完全不同的方法使用。

直射光就是直接照射的光。直射光总有方向和颜色,并且用作着色算法的一个因子,如高洛德着色算法。不同类型的光以不同的方式发出直射光,产生特殊的衰减效果。通过调用IDirect3DDevice9::SetLight方法,可以设置一组直射光参数。

环境光存在于场景中的任何地方。可以认为它是充满整个场景的光的强度,与物体及它们在场景中的位置无关。环境光没有位置和方向,只有颜色和强度。每个光源会增加场景中总的环境光级别。可以调用IDirect3DDevice9::SetRenderState方法设置环境光的级别,将State参数指定为D3DRS_AMBIENT,将Value参数设置为希望的RGBA颜色值。

环境反射色采用RGBA值的形式表示,其中每个成分为从0到255之间的整数值。这与Microsoft® Direct3D®中大多数的颜色值有所不同。更多信息,请参阅光源和材质的颜色值

可以用D3DCOLOR_RGBA宏生成RGBA值。红、绿、蓝成分组合成最终的环境反射色值。阿尔法成分控制颜色的透明度。当使用硬件加速或RGB模拟设备时,阿尔法成分被忽略。


光的属性


光的属性描述了光源的类型和颜色。取决于正在使用的光源的类型,光源可以拥有表示衰减和范围的属性,或表示聚光灯效果的属性。但是,并不是所有类型的光源都使用所有的属性。Microsoft® Direct3D®用D3DLIGHT9结构存放所有类型光源的属性。本节包含关于所有光的属性的信息。信息被划分为以下部分。

  • 光的类型
  • 光的颜色
  • 有颜色的顶点(Color Vertices)
  • 光源的位置、范围和衰减
  • 光的方向

光的类型


光的类型属性定义了正在使用的光源是什么类型。光的属性由D3DLIGHT9结构的Type成员的值设置,在C++程序中该成员是一个D3DLIGHTTYPE枚举类型。Microsoft® Direct3D®中有三种类型的光——点光源、聚光灯和平行光。每种类型以不同的方式照亮场景中的物体,所需的计算量也不同。

点光源

场景中的点光源具有颜色和位置,但没有确定的方向。点光源向各个方向发出的光相等,如下图所示。

 

灯泡是点光源的一个很好的例子。点光源受衰减和范围的影响,并基于每个顶点对网格进行照明。在计算光照的过程中,Direct3D使用点光源在世界坐标中的位置和当前顶点的坐标得到光的方向向量,以及光传播的距离。两者连同顶点法向一起,用于计算光在表面照明中所起的作用。

平行光

平行光只有颜色和方向,没有位置。平行光发出平行的光,这意味着所有平行光产生的光在场景中以相同的方向传播。可以认为平行光是位于无限远处的光源,如太阳。平行光不受衰减和范围的影响,因此应用程序指定的方向和颜色是Direct3D计算顶点颜色时要考虑的唯二因子。因为照明因子的数量少,所以平行光是可用的计算量最小的光。

聚光灯

聚光灯具有颜色、位置和发出光的方向。聚光灯发出的光由一个比较亮的内圆锥和一个较大的外圆锥组成,光强由内而外逐渐减小,如下图所示。

 

聚光灯受辐射(falloff)、衰减和范围的影响。这些因子同光到每个顶点的距离一起,参与计算场景中物体的光照效果。由于需要对每个顶点计算这些效果,因此这使得聚光灯成为Direct3D所有类型的光源中最为耗时的。

C++程序中,D3DLIGHT9结构包含了三个仅用于聚光灯的成员。这些成员——FalloffTheta、和Phi——控制聚光灯内外锥的大小,以及光如何在两者之间减弱。

Theta值为聚光灯内锥的角度,以弧度为单位,Phi值为聚光灯外锥的角度。Falloff值控制光强如何从内锥的外侧向外锥的内侧减弱。大多数应用程序将Falloff设为1.0,使光在两个圆锥间平滑地减弱,但也可以根据需要设成其它值。

下图显示了这些成员的值之间的关系,以及它们如何决定聚光灯的内外锥。

 

  • 聚光灯模型

这里包含了有关聚光灯如何工作的更多信息。


聚光灯模型


聚光灯发出圆锥形的光,圆锥分为两部分:较亮的内锥和外锥。内锥中的光最亮,而外锥以外则没有光,在内外锥之间光强逐渐衰减。这种衰减一般被称为辐射。

一个顶点接收到的光的数量(译注:此后简称为光量)取决于顶点在内锥或外锥中的位置。Microsoft® Direct3D®计算聚光灯的方向向量(L)和从顶点到聚光灯的向量(D)的点积。这个值等于两个向量夹角的余弦值,并作为顶点位置的一个指标,可与聚光灯的圆锥角度进行比较以确定顶点位于内锥或外锥的何处。下面提供了这两个向量之间关系的表示图。

 

系统将这个值与聚光灯的内锥和外锥角度的余弦值进行比较。在聚光灯的D3DLIGHT9结构中,ThetaPhi成员表示内锥和外锥的整个圆锥的角度。因为衰减和顶点与照明中心(亦即圆锥的中线)的夹角有关,所以在计算余弦值时Direct3D会将这两个圆锥的角度除以二。

如果向量LD的点积小于等于外锥角度的余弦值,那么顶点位于外锥以外,不接收任何光。如果LD的点积大于内锥角度的余弦值,那么顶点位于内锥里面,接收最多的光量,此时仍需考虑光随距离的衰减。如果顶点位于这两个区域之间的某处,那么Direct3D使用以下公式计算顶点的辐射值。

 

在这个公式中,If为辐射后的光强,对正在计算光照的顶点来说,α为向量LD之间的夹角,F为二分之一外锥角度的余弦值,φ为二分之一内锥角度,为聚光灯在D3DLIGHT9结构中的辐射属性Falloff。这个公式产生一个从0.0到1.0之间的值,用这个值对光强进行缩放就产生了辐射的效果。作为从顶点到聚光灯的距离的因子,衰减同时也被使用。p值对应D3DLIGHT9结构的Falloff成员,控制辐射曲线的形状。下图显示了不同的Falloff值如何作用于辐射曲线。

 

在实际光照中,不同的Falloff值产生的效果是很敏感的,并且如果使用除了1.0之外的值作为Falloff值描述辐射曲线,那么还会导致些许性能下降。为此,这个值一般被设为1.0。


光的颜色


Microsoft® Direct3D®中光源发出三种颜色,这三种颜色单独用于系统的光照计算:漫反射色、环境反射色、和镜面反射色。每种颜色在Direct3D光照模型的协助下,与当前材质中的对应部分相互作用,产生用于渲染的最终颜色。漫反射色与当前材质的漫反射系数属性相互作用,镜面反射色与材质的镜面反射反射系数属性相互作用,依次类推。有关Direct3D如何应用这些颜色的细节,请参阅与光照相关的数学

C++应用程序中,D3DLIGHT9结构包含了三个与这些颜色——漫反射色环境反射色和镜面反射色——相对应的成员,每个成员都是一个D3DCOLORVALUE结构,定义了发出的颜色。

对系统计算量影响最大的颜色类型是漫反射色。最常用的漫反射色是白色(R:1.0 G:1.0 B:1.0),但是应用程序可以根据需要创建其它颜色以达到想要的效果。例如,应用程序可以为火炉使用红光,或者为处于“通行”状态的红绿灯使用绿光。

一般来说,应用程序将光的颜色成员设为从0.0到1.0之间的值,闭区间,但这不是必需的。例如,应用程序可以将所有成员设为2.0,创建出一个“比白色更亮”的光源。当应用程序使用的衰减值不为常数时,这种设定尤其有用。

注意,虽然Direct3D使用RGBA值表示光的颜色,但是并没有使用颜色的阿尔法成员。更多信息,请参阅光和材质和颜色值


有颜色的顶点(Color Vertices)


通常用材质颜色进行光照计算。但是,应用程序可以指定用顶点的漫反射色或镜面反射色覆盖材质颜色——放射色(emissive),环境反射色、漫反射色、和镜面反射色。这可以通过调用IDirect3DDevice9::SetRenderState方法并用下表所列的值设置设备的状态变量来完成。

设备状态变量

含义

类型

默认值

D3DRS_AMBIENTMATERIALSOURCE

定义从何处得到环境光的材质色。

D3DMATERIALCOLORSOURCE

D3DMCS_MATERIAL

D3DRS_DIFFUSEMATERIALSOURCE

定义从何处得到漫反射材质色。

D3DMATERIALCOLORSOURCE

D3DMCS_COLOR1

D3DRS_SPECULARMATERIALSOURCE

定义从何处得到镜面反射材质色。

D3DMATERIALCOLORSOURCE

D3DMCS_COLOR2

D3DRS_EMISSIVEMATERIALSOURCE

定义从何处得到emissive材质色。

D3DMATERIALCOLORSOURCE

D3DMCS_MATERIAL

D3DRS_COLORVERTEX

禁用或启用顶点色。

BOOL

TRUE

阿尔法/透明度值总是从漫反射色的阿尔法通道中得到。

雾因子的值总是从镜面反射色的阿尔法通道中得到。

D3DMATERIALCOLORSOURCE可以为以下值:

  • D3DMCS_MATERIAL - 用材质颜色作为材质颜色的来源。
  • D3DMCS_COLOR1 - 用顶点的漫反射色作为材质颜色的来源。
  • D3DMCS_COLOR2 - 用顶点的镜面反射色作为材质颜色的来源。

光的位置、范围和衰减


位置、范围和衰减属性定义了光源在世界空间中的位置和光源发出的光如何随距离而变化。同C++应用程序中使用的所有其它光的属性一样,这些属性被包含在光源的D3DLIGHT9结构中。

位置

光源的位置用D3DVECTOR结构表示,它对应于D3DLIGHT9结构中的Position成员。约定x,y和z坐标在世界空间中。平行光是唯一不使用位置属性的光源类型。

范围

光源的范围属性决定在世界空间中的距离,场景中与光源相距超出这个距离的网格不再接收该光源发出的光。Range成员是一个浮点数,表示光源在世界空间中的最大范围。平行光不使用范围属性。

衰减

衰减控制光强如何朝范围属性指定的最大范围逐渐减弱。D3DLIGHT9结构中有三个成员用于表示衰减:Attenuation0Attenuation1、和Attenuation2。这些成员为从0.0到无穷大的浮点数,用于控制光强的衰减。一些应用程序将Attenuation1成员设为1.0,而其余的设为0.0,得到光强的变化为1/D,这里D为从光源到顶点之间的距离。光强在光源处最大,在光的最大范围处减弱到1/(Light Range)。一般来说,应用程序将Attenuation0设为0.0,将Attenuation1设为一个常数,将Attenuation2设为0.0。(译注:请参阅与光照相关的数学

为得到更复杂的衰减效果,应用程序可以将衰减值结合起来使用。或者,为创建更奇怪的衰减效果,应用程序也可以将它们设为正常范围外的值。但是,负的衰减值是不允许的。


光的方向


光的方向属性决定光源发出的光在世界空间中传播的方向。只有平行光和聚光灯使用方向,方向用一个向量表示。

C++应用程序在D3DLIGHT结构的Direction成员中设置光的方向。Direction成员为D3DVECTOR类型。方向向量用始于逻辑原点的一段距离描述,与光源在场景中的位置无关。因此,一个笔直指向场景内——沿正z轴——的聚光灯,无论它的位置在哪里,它的方向向量都是<0,0,1>。类似地,通过使用方向为<0,-1,0>的平行光,应用程序可以模拟直射到场景中的阳光。显然,应用程序不一定要创建沿坐标轴照射的光,可以混合搭配这些值,创建出沿某个更有意义的角度照射的光。

注意 虽然应用程序无需归一化光的方向向量,但是要保证该向量长度不为零。换句话说,不要将<0,0,0>用作方向向量。


光的使用


设置和取得光的属性

C++应用程序中,可以通过先准备一个D3DLIGHT9结构,然后调用IDirect3DDevice9::SetLight方法设置光的属性。IDirect3DDevice9::SetLight方法接收一个索引值,告诉设备将这组光属性存放在它的内部属性列表的何处,及定义这些属性的D3DLIGHT9结构的地址。要更新光的照明属性,应用程序可以根据需要用新的属性信息调用IDirect3DDevice9::SetLight

每次应用程序用一个索引值调用IDirect3DDevice9::SetLight,但该索引值从未设置过属性时,系统会分配内存以容纳新的一组光属性。应用程序可以设置许多光源,但是任一时刻只能启用其中的一个子集(译注:子集的大小由硬件能力决定)。要确定设备支持的可激活的光源,应用程序可以在取得设备能力后检查D3DCAPS9结构的MaxActiveLights成员。如果应用不再需要使用某个光源,可以将它禁用或用新的一组光属性将它覆盖。

以下C++示例代码准备并设置了一个白色点光源的属性,它发出的光不会随距离而衰减。

// 假设d3dDevice为一个指向IDirect3DDevice9接口的有效指针。
D3DLIGHT9 d3dLight;
HRESULT   hr;
 
// 初始化结构。
ZeroMemory(&d3dLight, sizeof(d3dLight));
 
// 设置一个白色的点光源。
d3dLight.Type = D3DLIGHT_POINT;
d3dLight.Diffuse.r = 1.0f;
d3dLight.Diffuse.g = 1.0f;
d3dLight.Diffuse.b = 1.0f;
d3dLight.Ambient.r = 1.0f;
d3dLight.Ambient.g = 1.0f;
d3dLight.Ambient.b = 1.0f;
d3dLight.Specular.r = 1.0f;
d3dLight.Specular.g = 1.0f;
d3dLight.Specular.b = 1.0f;
 
// 将它放在场景中的高处,位于用户的后面。
// 记住,这些坐标是在世界空间中的,因此用户也可以在世界空间中的任何位置。
// 根据本示例代码的目的,假设用户位于世界空间的原点。
d3dLight.Position.x = 0.0f;
d3dLight.Position.y = 1000.0f;
d3dLight.Position.z = -100.0f;
 
// 不随距离衰减。
d3dLight.Attenuation0 = 1.0f; 
d3dLight.Range        = 1000.0f;
 
// 设置第一个光源的属性。
hr = d3dDevice->SetLight(0, &d3dLight);
if (SUCCEEDED(hr))
         // 成功后的处理
else
         // 失败后的处理

应用程序可以在任何时候再次调用IDirect3DDevice9::SetLight方法以更新一组光属性。只需指定要更新的那组光属性的索引值和包含新属性的D3DLIGHT9结构的地址。

注意    给设备分配一组光属性并不意味着启用对应的光源。要对设备调用IDirect3DDevice9::LightEnable方法才能启用光源。

C++程序中,通过对设备调用IDirect3DDevice9::GetLight方法,应用程序可以取得一个现存光源的所有属性。

以下示例代码描述了这个过程。

// 假设d3dDevice为一个指向IDirect3DDevice9接口的有效指针。
HRESULT hr;
D3DLIGHT9 light;
 
// 取得第一个光源的属性信息。
hr = pd3dDevice->GetLight(0, &light);
if (SUCCEEDED(hr))
         // 成功后的处理
else
         // 失败后的处理

如果应用程序提供的索引值超出了分配给设备的光源的范围,那么IDirect3DDevice9::GetLight方法将会失败,返回D3DERR_INVALIDCALL错误码。

启用和禁用光源

当应用程序给场景中的光源指定了光属性时,就可以对该设备调用IDirect3DDevice9::LightEnable方法激活这个光源。默认情况下新的光源是禁用的。IDirect3DDevice9::LightEnable方法接收两个参数。将第一个参数设为要用改变的光源的索引值,从零开始计数,将第二个参数设为TRUE启用该光源或FALSE禁用该光源。

以下示例代码描述了用这种方法启用设备的光源属性列表中的第一个光源。

// 假设d3dDevice为一个指向IDirect3DDevice9接口的有效指针。
HRESULT hr;
 
hr = pd3dDevice->LightEnable(0, TRUE);
if (SUCCEEDED(hr))
         // 成功后的处理
else
         // Handle failure

要确定设备支持的最多可激活的光源的数量,应用程序可以在取得设备能力时,检查D3DCAPS9结构的MaxActiveLights成员。

如果应用程序启用或禁用一个光源,但没有调用IDirect3DDevice9::SetLight设置过该光源的属性,那么IDirect3DDevice9::LightEnable方法会先用下表所列的属性创建一个光源,然后再启用或禁用该光源。

成员

默认值

Type

D3DLIGHT_DIRECTIONAL

Diffuse

(R:1, G:1, B:1, A:0)

Specular

(R:0, G:0, B:0, A:0)

Ambient

(R:0, G:0, B:0, A:0)

Position

(0, 0, 0)

Direction

(0, 0, 1)

Range

0

Falloff

0

Attenuation0

0

Attenuation1

0

Attenuation2

0

Theta

0

Phi

0


与光照相关的数学


Microsoft® Direct3D®光照模型涵盖了环境光、漫反射光、镜面反射光和放射光,这足以解决绝大部分的光照情况。我们将场景中光的总和称为全局照明(global illumination,并使用以下公式计算:

全局照明 = 环境光 + 漫反射光 + 镜面反射光 + 放射光

环境光是恒定的光照。它在所有方向上不发生变化,对物体中所有像素产生的作用也完全相同。它计算起来很快,但得到的物体看起来是平面的,没有真实感。要了解Direct3D如何计算环境光,请参阅环境光

漫反射光取决于光的方向和表面的法向。由于光的方向和表面法向量的变化,因此漫反射光会随物体的表面而变化。因为漫反射光随着每个顶点而变化,所以需要更长的时间进行计算,但是使用漫反射光带来的好处是它使物体呈现出明暗变化和三维深度。要了解Direct3D如何计算漫反射光,请参阅漫反射光

镜面反射光代表了当光线照射到物体表面时反射回摄像机形成的明亮的镜面反射高光。它比漫反射光更强,但在物体表面也衰减得更快。计算镜面反射光需要比计算漫反射光更长的时间,但是使用镜面反射光带来的好处是它给表面增添了重要的细节。要了解Direct3D如何计算镜面反射光,请参阅镜面反射光

放射光是物体发出的光,例如光晕(glow)。要了解Direct3D如何计算放射光,请参阅放射光

通过在三维场景中使用这些类型的光,可以得到真实的光照效果。要得到更为真实的光照效果,应用程序可以添加更多的光源,但是,这增加了渲染场景的时间。要达到(游戏)设计师想要的所有效果,一些游戏使用了超出一般的CPU计算能力。在这种情况下,一般通过在使用纹理贴图的同时,使用光照贴图和环境贴图给场景加入光照的效果,这样就可以把光照所需的计算量减到最少。

光照计算在摄像机空间进行。要了解如何计算光照变换,请参阅摄像机空间的变换。经过优化的光照计算可以在建模空间进行,但需满足以下特殊条件:法向量已经归一化(D3DRS_NORMALIZENORMALS为TRUE),不需要进行顶点混合,变换矩阵为正交的,等等。

环境光、漫反射光和镜面反射光会受到给定光源的衰减和聚光灯因子的影响。为环境光、放射光和漫反射光成分计算的颜色值被保存在输出顶点的漫反射色中。漫反射和镜面反射公式都包含了衰减和聚光灯因子属性。更多信息,请参阅衰减和聚光灯因子


环境光


环境光为场景提供了一种恒定不变的光。环境光对所有物体的顶点的照明效果相同,因为它与其余光照因子无关,如顶点法向、光的方向、光的位置、范围或衰减等。环境光是最快的一种类型,但它提供的真实感最少。Microsoft® Direct3D®包含了一个全局的环境光属性,应用程序可以直接使用而无需创建任何光源。另外,应用程序也可以指定某个光源提供环境光。场景中环境光的计算由以下公式描述。

Ambient Lighting = Ca*[Ga + sum(Lai*Attenuationi*SpotFactori)]

环境光的公式不完全正确。应该是Ambient Lighting = Ca*[Ga + sum(Lai)*Atti*Spoti],这里AttSpot为第i个光源的衰减和聚光灯因子。

参数在下表中定义。

参数

默认值

类型

描述

Ca

(0,0,0,0)

D3DCOLORVALUE

材质的环境反射色。

Ga

(0,0,0,0)

D3DCOLORVALUE

全局的环境反射色。

sum

N/A

N/A

所有光源产生的环境光的总和。

Lai

(0,0,0,0)

D3DVECTOR

i个光源产生的环境反射色。

Atteni

(0,0,0,0)

D3DCOLORVALUE

i个光源的衰减因子。请参阅衰减和聚光灯因子

Spoti

(0,0,0,0)

D3DVECTOR

i个光源的聚光灯因子。请参阅衰减和聚光灯因子

Ca的值可以是:

  • 顶点颜色1,如果AMBIENTMATERIALSOURCE = D3DMCS_COLOR1,并且顶点声明中给出了第一个顶点的颜色。
  • 顶点颜色2,如果AMBIENTMATERIALSOURCE = D3DMCS_COLOR2,并且顶点声明中给出了第二个顶点的颜色。
  • 材质的环境反射色。

注意 如果使用了任何一种AMBIENTMATERIALSOURCE,但是没有提供顶点颜色,那么系统会使用材质的环境反射色。

要使用材质的环境反射色,按以下示例代码使用SetMaterial方法。

Ga为全局的环境反射色,通过SetRenderState(D3DRENDERSTATE_AMBIENT)设置。Direct3D场景中只有一个全局环境反射色,它与其余Direct3D光源无关。

Lai为场景中第i个光源的环境反射色。每个Direct3D光源都有一组属性,其中一个就是环境反射色。符号sum(Lai)表示场景中所有环境反射色的总和。

示例

在本例中,通过计算场景的环境光的颜色和材质的环境反射色得到物体的颜色。代码如下所示。

#define GRAY_COLOR                          0x00bfbfbf
 
// 创建材质
D3DMATERIAL9 mtrl;
ZeroMemory( &mtrl, sizeof(mtrl) );
mtrl.Ambient.r = 0.75f;
mtrl.Ambient.g = 0.0f;
mtrl.Ambient.b = 0.0f;
mtrl.Ambient.a = 0.0f;
m_pd3dDevice->SetMaterial( &mtrl );
m_pd3dDevice->SetRenderState( D3DRS_AMBIENT, GRAY_COLOR);

根据公式,得到的物体顶点的颜色是材质颜色和光的颜色的合成。

下面两张图片显示了材质颜色,为灰色,和光的颜色,为红色。

 

渲染得到的场景如下所示。场景中唯一的物体是一个球体。环境光用相同的颜色对物体的所有顶点进行光照计算,它不依赖于顶点法向和光的方向。因此,球体看起来像是二维的圆,因为物体的表面没有明暗变化。

 

要使物体看起来更真实,除了环境光之外,需要再添加漫反射光或镜面反射光。


漫反射光


在根据任何衰减效果调整完光的强度之后,光照引擎用给定的顶点法向与入射光方向之间的夹角,计算剩余的光中有多少会从顶点反射。对于平行光,光照引擎略过这一步,因为平行光不随距离而衰减。系统会考虑两种反射类型,漫反射和镜面反射,并使用不同的公式计算每种类型各反射多少光。在计算完反射光的数量后,Microsoft® Direct3D®把得到的新值应用于当前材质的漫反射和镜面反射反射系数属性。最终的颜色值是漫反射色和镜面反射色成员,会被光栅化器用于计算高洛德着色和镜面反射高光。

漫反射光由以下公式描述。

Diffuse Lighting = sum[Cd*Ld*(N.Ldir)*Atten*Spot]

 

参数

默认值

类型

描述

sum

N/A

N/A

每个光源的漫反射色成分的总和。

Cd

(0,0,0,0)

D3DCOLORVALUE

漫反射色。

Ld

(0,0,0,0)

D3DCOLORVALUE

光源的漫反射色。

N

N/A

D3DVECTOR

顶点法向。

Ldir

N/A

D3DVECTOR

从顶点到光源的方向向量。

Atten

N/A

FLOAT

光的衰减因子。请参阅衰减和聚光灯因子

Spot

N/A

FLOAT

聚光灯因子。请参阅衰减和聚光灯因子

Cd的值可以是:

  • 顶点颜色1,如果DIFFUSEMATERIALSOURCE = D3DMCS_COLOR1,并且顶点声明中给出了第一个顶点的颜色。
  • 顶点颜色2,如果DIFFUSEMATERIALSOURCE = D3DMCS_COLOR2,并且顶点声明中给出了第二个顶点的颜色。
  • 材质的环境反射色。

注意 如果使用了任何一种DIFFUSEMATERIALSOURCE,但是没有提供顶点颜色,那么系统会使用材质的漫反射色。

要计算衰减(Atten)或聚光灯(Spot)属性,请参阅衰减和聚光灯因子

在所有光源都经过单独处理和插值后,漫反射成员被截取到从0到255之间。最终的漫反射光的颜色值是环境光、漫反射光和放射光的颜色值的组合。

示例

在本例中,通过计算光源的漫反射色和材质的漫反射色得到物体的颜色。代码如下所示。

D3DMATERIAL9 mtrl;
ZeroMemory( &mtrl, sizeof(mtrl) );
 
D3DLIGHT9 light;
ZeroMemory( &light, sizeof(light) );
light.Type = D3DLIGHT_DIRECTIONAL;
 
D3DXVECTOR3 vecDir;
vecDir = D3DXVECTOR3(0.5f, 0.0f, -0.5f);
D3DXVec3Normalize( (D3DXVECTOR3*)&light.Direction, &vecDir );
 
// 设置平行光的漫反射色
light.Diffuse.r = 1.0f;
light.Diffuse.g = 1.0f;
light.Diffuse.b = 1.0f;
light.Diffuse.a = 1.0f;
m_pd3dDevice->SetLight( 0, &light );
m_pd3dDevice->LightEnable( 0, TRUE );
 
// 如果使用了材质,那么必须使用SetRenderState。
// 顶点颜色 = 光的漫反射色 * 材质的漫反射色
mtrl.Diffuse.r = 0.75f;
mtrl.Diffuse.g = 0.0f;
mtrl.Diffuse.b = 0.0f;
mtrl.Diffuse.a = 0.0f;
m_pd3dDevice->SetMaterial( &mtrl );
m_pd3dDevice->SetRenderState(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_MATERIAL);

根据公式,得到的物体顶点的颜色是材质颜色和光的颜色的组合。

下面两张图片显示了材质颜色,为灰色,和光的颜色,为红色。

 

渲染得到的场景如下所示。场景中唯一的物体是一个球体。漫反射光照计算取得材质和光的漫反射色,用光的方向和顶点法向的点积作为它们之间的夹角修正得到的颜色。因此,球体的后面变得较黑,因为那部分球面背向光源。

 

将漫反射光和前例产生的环境光结合起来,会使物体的整个表面呈现出明暗效果。环境光使整个表面变亮,而漫反射光则有助于展现出物体的三维形状。

 

漫反射光比环境光需要更多的计算,因为它依赖于顶点的法向和光的方向。我们可以看一下在三维场景中的几何体,漫反射光产生了比环境光更为真实的光照效果。我们还可以使用镜面反射高光来达到更为真实的效果。


镜面反射光


建立一个镜面反射模型需要系统不仅知道光传播的方向,还要知道从顶点到视点的方向。Direct3D光照系统使用了一个经过简化的Phong(译注:冯)镜面反射模型,该简化模型使用一个中间向量(原文:halfway vector,译注:某些图形学书籍译为半角矢量)计算镜面反射光强的近似值。

默认的光照状态不计算镜面反射高光。要启用镜面反射高光,需要将D3DRS_SPECULARENABLE设置为TRUE。

镜面反射光公式

镜面反射光由以下公式描述。

Specular Lighting = Cs*sum[Ls*(N.H)P*Atten*Spot]

下表描述了所有变量,其类型及范围。

参数

默认值

类型

描述

Cs

(0,0,0,0)

D3DCOLORVALUE

镜面反射色。

sum

N/A

N/A

每个光源的镜面反射成员的总和。

N

N/A

D3DVECTOR

顶点法向。

H

N/A

D3DVECTOR

中间向量。请参阅中间向量相关的部分。

P

0.0

FLOAT

镜面反射反射指数。范围从0到正无穷大。

Ls

(0,0,0,0)

D3DCOLORVALUE

光的镜面反射色。

Atten

N/A

FLOAT

光的衰减值。请参阅衰减和聚光灯因子

Spot

N/A

FLOAT

聚光灯因子。请参阅衰减和聚光灯因子

Cs的值可以是:

  • 顶点颜色1,如果SPECULARMATERIALSOURCE = D3DMCS_COLOR1,并且顶点声明中给出了第一个顶点的颜色。
  • 顶点颜色2,如果SPECULARMATERIALSOURCE = D3DMCS_COLOR2,并且顶点声明中给出了第二个顶点的颜色。
  • 材质的环境反射色。

注意 如果使用了任何一种SPECULARMATERIALSOURCE,但是没有提供顶点颜色,那么系统会使用材质的镜面反射色。

在所有光源都经过单独处理和插值后,镜面反射成员被截取到从0到255之间。

中间向量

中间向量(H)位于两个向量之间:从顶点到光源的向量,和从顶点到摄像机位置的向量。Microsoft® Direct3D®提供了两种方法来计算中间向量。当D3DRS_LOCALVIEWER被设为TRUE时,系统使用摄像机的位置和顶点的位置,与光源的方向向量来计算中间向量。以下公式描述了这种方法。

H = norm(norm(Cp - Vp) + Ldir)

 

参数

默认值

类型

描述

Cp

N/A

D3DVECTOR

摄像机的位置。

Vp

N/A

D3DVECTOR

顶点的位置。

Ldir

N/A

D3DVECTOR

从顶点位置到光源位置的向量。

用这种方法计算中间向量的计算量会非常大。另一种可选的方法是将D3DRS_LOCALVIEWER设置为FALSE,告诉系统将视点当作在z轴无限远处进行计算。下面的公式反映了这种方法。

H = norm((0,0,1) + Ldir)

这种设定计算量不很大,但很不精确,因此它最适合用在使用正交投影的应用程序中。

示例

在本例中,通过计算光源的镜面反射色和材质的镜面反射色得到物体的颜色。代码如下所示。

D3DMATERIAL9 mtrl;
ZeroMemory( &mtrl, sizeof(mtrl) );
 
D3DLIGHT9 light;
ZeroMemory( &light, sizeof(light) );
light.Type = D3DLIGHT_DIRECTIONAL;
 
D3DXVECTOR3 vecDir;
vecDir = D3DXVECTOR3(0.5f, 0.0f, -0.5f);
D3DXVec3Normalize( (D3DXVECTOR3*)&light.Direction, &vecDir );
 
light.Specular.r = 1.0f;
light.Specular.g = 1.0f;
light.Specular.b = 1.0f;
light.Specular.a = 1.0f;
 
light.Range = 1000;
light.Falloff = 0;
light.Attenuation0 = 1;
light.Attenuation1 = 0;
light.Attenuation2 = 0;
m_pd3dDevice->SetLight( 0, &light );
m_pd3dDevice->LightEnable( 0, TRUE );
m_pd3dDevice->SetRenderState( D3DRS_SPECULARENABLE, TRUE );
 
mtrl.Specular.r = 1.0f;
mtrl.Specular.g = 1.0f;
mtrl.Specular.b = 1.0f;
mtrl.Specular.a = 1.0f;
mtrl.Power = 20;
m_pd3dDevice->SetMaterial( &mtrl );
m_pd3dDevice->SetRenderState(D3DRS_SPECULARMATERIALSOURCE, D3DMCS_MATERIAL);

根据公式,得到的物体顶点的颜色是材质颜色和光的颜色的组合。

以下两张图片显示了材质颜色,为灰色,和光的颜色,为白色。

 

得到的镜面反射高光如下所示。

 

将镜面反射高光与前例产生的环境光和漫反射光结合起来,会得到以下图像。当所有三种类型的光一起使用时,渲染得到的球体明显看起来更像是真实物体。

 

镜面反射光需要比漫反射光更多的计算量。镜面反射光一般用于以可见的方式提供有关表面材质的信息。镜面反射高光会随着表面材质的不同在大小和颜色上有所不同。


放射光


放射光由一个单独的参数表示。

Emissive Lighting = Ce

这里:

参数

默认值

类型

描述

Ce

(0,0,0,0)

D3DCOLORVALUE

Emissive color.

Ce的值可以是:

  • 顶点颜色1,如果EMISSIVEMATERIALSOURCE = D3DMCS_COLOR1,并且顶点声明中给出了第一个顶点的颜色。
  • 顶点颜色2,如果EMISSIVEMATERIALSOURCE = D3DMCS_COLOR2,并且顶点声明中给出了第二个顶点的颜色。
  • 材质的放射色。

注意 如果使用了任何一种EMSSIVEMATERIALSOURCE,但是没有提供顶点颜色,那么系统会使用材质的放射色。

示例

在本例中,通过计算场景的环境光的颜色和材质的环境反射色得到物体的颜色。代码如下所示。

// 创建材质
D3DMATERIAL9 mtrl;
ZeroMemory( &mtrl, sizeof(mtrl) );
mtrl.Emissive.r = 0.0f;
mtrl.Emissive.g = 0.75f;
mtrl.Emissive.b = 0.0f;
mtrl.Emissive.a = 0.0f;
m_pd3dDevice->SetMaterial( &mtrl );
m_pd3dDevice->SetRenderState(D3DRS_EMISSIVEMATERIALSOURCE, D3DMCS_MATERIAL);

根据公式,得到的物体顶点的颜色为材质的颜色。

下图显示了材质颜色,为绿色。放射光用相同的颜色对物体的所有顶点进行光照计算,它不依赖于顶点法向或光的方向。因此,球体看起来像是二维的圆,因为物体表面没有明暗变化。

 

下图显示了放射光与前例中其余三种类型的光混合后得到的结果。球体的右边是绿色的放射光和红色的环境光的混合。球体的左边,绿色的放射光与红色的环境光和漫反射光混合产生了红色的颜色梯度。中间是白色的镜面反射高光,随着镜面反射高光向周围迅速衰减,产生了一个黄色的圆环,其余区域只有环境光、漫反射光和放射光混合成黄色。

 


摄像机空间的变换


摄像机空间中的顶点通过用世界视矩阵(world view matrix)对顶点进行变换得到。

V = V * wvMatrix

摄像机空间中的顶点法向通过用世界视矩阵的转置逆矩阵对物体的法向进行变换得到。世界视矩阵可能是也可能不是正交的。

N = N * (wvMatrix-1)T

求逆矩阵和转置矩阵的操作在一个4x4矩阵上进行。乘法操作将法向和得到的4x4矩阵中的3x3那部分相乘。

如果渲染状态D3DRENDERSTATE_NORMALIZENORMALS被设置为TURE,那么在变换到摄像机空间后,顶点法向量被归一化,如下所示。

N = norm(N)

摄像机空间中光源的位置通过用视矩阵对光源位置进行变换得到。

Lp = Lp * vMatrix

摄像机空间中平行光的方向通过将光源的方向与视矩阵相乘、归一化、并对结果取反得到。

Ldir = -norm(Ldir * wvMatrix)

D3DLIGHT_POINT和D3DLIGHT_SPOT类型的光源,光的方向用以下公式计算:

Ldir = norm(V * Lp), 这里的参数由下表定义。

参数

默认值

类型

描述

Ldir

N/A

D3DVECTOR

从顶点到光源的方向向量

V

N/A

D3DVECTOR

摄像机空间中顶点的位置

wvMatrix

Identity

D3DMATRIX

包含世界和视变换和合成矩阵

N

N/A

D3DVECTOR

顶点法向

Lp

N/A

D3DVECTOR

摄像机空间中光源的位置

vMatrix

Identity

D3DMATRIX

包含视变换的矩阵


衰减和聚光灯因子


漫反射光和镜面反射光成员的全局照明公式中包含了描述光的衰减和聚光灯因子的属性。这些属性在下面描述。

衰减因子

光的衰减因子取决于光的类型和从光到顶点所在位置的距离。要计算衰减因子,可以使用以下三个公式之一。

Atten = 1/( att0i + att1i * d + att2i * d2)

这里:

参数

默认值

类型

描述

att0i

0.0

FLOAT

线性衰减因子。范围从0到正无穷大

att1i

0.0

FLOAT

平方衰减因子。范围从0到正无穷大

att2i

0.0

FLOAT

指数衰减因子。范围从0到正无穷大。

d

N/A

FLOAT

从顶点位置到光源位置的距离

  • Atten = 1, 如果光源为平行光。
  • Atten = 0, 如果从光源到顶点的距离超出了光的范围。

att0、att1、和att2值由D3DLIGHT9结构的Attenuation0Attenuation1、和Attenuation2成员给出。

从光源到顶点位置的距离总是正的。

d = | Ldir |

这里:

参数

默认值

类型

描述

Ldir

N/A

D3DVECTOR

从顶点位置到光源位置的方向向量

如果d大于光的范围,也就是D3DLIGHT9结构的Range成员,Microsoft® Direct3D®不再进行更进一步的衰减计算,也不应用任何光照效果于该顶点。

衰减常数作为公式中的一个系数——应用程序仅需调整它们的值就可以产生不同的衰减曲线。应用程序可以将Attenuation1设为1.0,创建一个不随距离衰减但仍受距离限制的光源,或者应用程序也可以试验不同的值以达到不同的衰减效果。

位于最大范围处,光的衰减因子不是0.0。为防止光在最大范围处突然出现,应用程序可以增加光的范围。或者,应用程序也可以设置衰减常数使衰减因子在光的最大范围处接近0.0。作为光到达一个顶点所经过的距离的因子,衰减值与光的颜色的红、绿和蓝成分相乘以缩放光强。

聚光灯因子

 

 

参数

默认值

类型

描述

rhoi

N/A

FLOAT

聚光灯i的余弦值(角度)

phii

0.0

FLOAT

聚光灯i的外锥角度,以弧度为单位。范围为:[theta, pi)

thetai

0.0

FLOAT

聚光灯i的内锥角度,以弧度为单位。范围为:[0, pi)

falloff

0.0

FLOAT

辐射因子。范围为:(负无穷,正无穷)

这里:

rho = norm(Ldcs).norm(Ldir)

并且:

参数

默认值

类型

描述

Ldcs

N/A

D3DVECTOR

光在摄像机空间中的方向取反

Ldir

N/A

D3DVECTOR

从顶点位置到光源位置的方向向量

在计算光的衰减后,Direct3D还会考虑:聚光灯效果,如果适用的话,光从表面反射的角度,用于计算顶点的漫反射和镜面反射成员的当前材质的反射系数。更多信息,请参阅聚光灯模型


材质


材质描述在三维场景中的多边形如何反射光或如何发光。本质上,材质是一组属性集合,告诉Microsoft® Direct3D®有关正在渲染的多边形的下列信息。

  • 材质如何反射环境光和漫反射光
  • 材质和镜面反射高光看起来是什么样
  • 多边形发光时看起来是什么样

C++写的Direct3D应用程序用D3DMATERIAL9结构描述材质属性。更多信息,请参阅材质属性

设置材质属性

Direct3D渲染设备在同一时刻可以使用一组材质属性进行渲染。

C++应用程序通过先准备一个D3DMATERIAL9结构,然后调用IDirect3DDevice9::SetMaterial方法设置给系统使用的材质属性。

要准备使用一个D3DMATERIAL9结构,需根据想要创建的渲染效果设置该结构的属性信息。以下示例代码为一个具有高强度白色镜面反射高光的紫色材质设立了相应的D3DMATERIAL9结构。

D3DMATERIAL9 mat;
 
// 设置漫反射反射系数的RGBA值。
mat.Diffuse.r = 0.5f;
mat.Diffuse.g = 0.0f;
mat.Diffuse.b = 0.5f;
mat.Diffuse.a = 1.0f;
 
// 设置环境光反射系数的RGBA值
mat.Ambient.r = 0.5f;
mat.Ambient.g = 0.0f;
mat.Ambient.b = 0.5f;
mat.Ambient.a = 1.0f;
 
// 设置镜面反射高光的颜色和强度。
mat.Specular.r = 1.0f;
mat.Specular.g = 1.0f;
mat.Specular.b = 1.0f;
mat.Specular.a = 1.0f;
mat.Power = 50.0f;
 
// 设置放射光的RGBA颜色值。
mat.Emissive.r = 0.0f;
mat.Emissive.g = 0.0f;
mat.Emissive.b = 0.0f;
mat.Emissive.a = 0.0f;

在准备D3DMATERIAL9结构之后,应用程序通过调用IDirect3DDevice9::SetMaterial方法将材质属性应用于渲染设备。这个方法接收一个准备好的D3DMATERIAL9结构的地址作为它唯一的参数。要更新设备的材质属性,应用程序可以根据需要用新的属性调用IDirect3DDevice9::SetMaterial。以下示例代码显示了这个过程。

// 本示例代码使用本节前面定义的mat变量保存的材质属性。 
// 假设pd3dDev为一个指向IDirect3DDevice9接口的有效指针。
HRESULT hr;
hr = pd3dDev->SetMaterial(&mat);
if(FAILED(hr))
{
    // 错误处理的代码放在这里。
}

当应用程序创建Direct3D设备时,当前材质被自动设为如下表所示的默认值。

成员

Diffuse

(R:1, G:1, B:1, A:0)

Specular

(R:0, G:0, B:0, A:0)

Ambient

(R:0, G:0, B:0, A:0)

Emissive

(R:0, G:0, B:0, A:0)

Power

(0.0)

取得材质属性

通过对设备调用IDirect3DDevice9::GetMaterial方法,应用程序可以取得当前设备正在使用的材质属性。与IDirect3DDevice9::SetMaterial方法不同的是,IDirect3DDevice9::GetMaterial无需准备工作。IDirect3DDevice9::GetMaterial方法接收一个D3DMATERIAL9结构的地址,将描述当前材质属性的信息填入该结构,然后返回。

// 在这个例子中,假设pd3dDev变量为一个指向IDirect3DDevice9接口的有效指针。
HRESULT hr;
D3DMATERIAL9 mat;
 
hr = pd3dDev->GetMaterial(&mat);
if(FAILED(hr))
{
    // 错误处理的代码放在这里。
}

更多关于材质属性的信息,请参阅:

  • 材质属性

注意    如果应用程序不指定渲染使用的材质属性,系统会使用默认的材质。默认的材质反射所有漫反射光——也就是白色——但没有环境反射和镜面反射,也没有放射色。


材质属性


材质属性详细描述了材质的漫反射系数、环境反射系数、发光度和镜面反射高光的特性。Microsoft® Direct3D®使用D3DMATERIAL9结构保存所有材质属性信息。材质属性会影响Direct3D对使用该材质的多边形做光栅化操作得到的颜色。除了镜面反射属性,其余每个属性都用一个RGBA颜色描述,表示该材质对某一给定类型的光的红、绿和蓝成分的反射度,以及一个阿尔法混合因子——RGBA颜色的阿尔法成员。材质的镜面反射属性用两部分描述:颜色和幂指数。更多信息,请参阅光和材质的颜色值

漫反射和环境反射

D3DMATERIAL9结构的DiffuseAmbient成员描述了材质如何反射场景中的环境光和漫反射光。因为大多数场景包含的漫反射光比环境光要多,所以在决定最终颜色的过程中漫反射所起的作用最大。另外,因为漫反射具有方向性,漫反射光的入射角会影响到整个反射光的强度。当光的入射方向与顶点法向平行时,漫反射最强。随着入射方向与顶点法向之间夹角的增大,漫反射效果逐渐减少。反射光的数量是入射光与顶点法向之间夹角的余弦值,如下所示。

 

环境反射和环境光一样,没有方向性。环境反射对被渲染物体最终的颜色影响较小,但它确实会影响最终的颜色,最为明显的就是当材质很少甚至不反射漫反射光时。材质的环境反射受场景中的环境光的影响,场景的环境光通过调用IDirect3DDevice9::SetRenderState方法,并用D3DRS_AMBIENT作为参数设置。

漫反射和环境反射一起用来决定物体反射的颜色,而且通常是相同的值。例如,要渲染一个蓝色水晶物体,应用程序可以创建一个只反射漫反射光和环境光中蓝色成分的材质。当水晶放在有白光的地方,它看起来会是蓝色的。但是,在一个只有红光的地方,同一个水晶看起来就会是黑色的,因为它的材质不反射红光。

放射

材质可以用来使被渲染的物体看起来像是自身发光的。D3DMATERIAL9结构的Emissive成员就是用来描述物体发出的光的颜色和透明度的。放射会影响物体的颜色,也可以使暗的材质变亮并部分呈现出所发光的颜色。

应用程序可以使用材质的发光属性给一个物体增加发光的感觉,这不会导致因为给场景增加光源而带来的计算开销。在蓝色水晶的例子中,如果希望水晶显得亮,但又不照射到场景中的其它物体上,发光属性就很有用。记住,具有发光属性的材质不发射可以被场景中其它物体反射的光。要得到可以被其它物体反射的光,需要在场景中另外增加一个光源。

镜面反射

镜面反射在物体表面产生高光,这使它们看起来像是有光泽的。D3DMATERIAL9结构包含了两个描述镜面反射高光和整体亮度的成员。应用程序可以通过Specular成员将镜面反射高光设为想要的RGBA颜色值——最常用的颜色是白色或淡灰色。应用程序可以设置Power成员的值控制镜面反射效果的剧烈程度。

镜面反射高光可以产生生动的效果。还是以蓝色水晶为例:较大的Power值会产生更为明亮的镜面反射高光,使水晶看起来光芒四射。较小的值增大了产生效果的区域,造成不太明亮的反射,这使水晶看起来像灰色的。要使物体的表面真正是粗糙的,只需将Power成员设为零,并将Specular成员设为黑色。为了根据自己的需要产生真实的反射,可以试验不同的反射系数。下图描绘了两个相同的建模。左边使用了Power为10的镜面反射,而右边没有镜面反射。

 

posted on 2009-08-22 17:44 狂烂球 阅读(2216) 评论(0)  编辑 收藏 引用 所属分类: 图形编程


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理