D3D初步 #2

 

III、              投影矩阵(Projection Matrix

据说今天凌晨200可以看见狮子座流星雨,很怀念3年前的那个晚上,美丽的流星雨让我终生难忘;撑到现在,不知道是不是真的能够看到。

投影,就是3D空间中的对象,在2D的屏幕上显示出来的效果。D3D里面的投影方式有两种:透视投影和正交投影。透视投影受视点的影响,观察者距离对象越远,所观察到的对象就越小,这是与真是世界相符合的。正交投影不受距离的影响,在平面上的投影就是对象的实际大小。在制图过程中的三视图就是正交投影。

 

D3DXMATRIX matProj;

D3DXMatrixIdentity( &matProj );

 

// 透视投影

D3DXMatrixPerspectiveForLH( &matProj, fFovY, fAspect, fNearPlane, fFarPlane );

pd3dDevice->SetTransForm( D3DTS_PROJECTION, &matProj );

 

// 正交投影

D3DXMatrixOrthoLH( &matProj, width, height, nearplane, farplane );

pd3dDevice->SetTransForm( D3DTS_PROJECTION, &matProj );

 

以上是基于左手坐标系建立的透视投影和正交投影,DXSDK对于每个函数都有详细的说明;而且很好理解。D3D中每个和矩阵有关系的函数都是这个形式 D3DXMatrix_____

在一些情况下,我们可以把观察矩阵和透视矩阵封装成一个类,就是摄像机。在初始化的时候设定默认值,不需要每次渲染都设定一次。但是因为世界矩阵还是每次渲染都建立的。

D3D进阶

第五,材质:

关于D3D材质的讨论可以很简单,也可以很复杂。它和灯光是结合在一起的,没有灯光,说什么材质都是P话。说得明白点,D3D的材质,实际上就是对象对光线的反射方式,对D3D中各种类型的光的反射方式。D3D对真实世界的光效进行了模拟,包括漫反射、镜面反射,环境反射。

 

设定材质的过程:

D3DMATERIAL9 mtrl;

ZeroMemory( &mtrl, sizeof( D3DMATERIAL9) );

mtrl.Diffuse.r = 1.0f; // 设定对光线的漫反射

mtrl.Diffuse.g = 1.0f;

mtrl.Diffuse.b = 1.0f;

mtrl.Diffuse.a = 1.0f;

mtrl.Specular.r = 1.0f; // 设定对光线的镜面反射

mtrl.Specular.g = 1.0f;

mtrl.Specular.b = 1.0f;

mtrl.Specular.a = 1.0f;

mtrl.Power = 10.0f; // 强度的值越大,高光的锐化程度越高,也就是高光范围越小,越亮

mtrl.Ambient.r = 1.0f; // 设定对环境光的反射

mtrl.Ambient.g = 1.0f;

mtrl.Ambient.b = 1.0f;

mtrl.Ambient.a = 1.0f;

pd3dDevice->SetMaterial( &mtrl ); // 每次渲染时调用

 

以上内容可以参见D3DMATERIAL9 Structure 。漫反射其实就是物体的表面颜色,而镜面反射可以让对象产生高光效果。环境光一般是来控制整个空间的亮度的,还有“气氛”:)。D3D中,组成一个对象的不同多边形甚至都可以拥有不同的材质。

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

环境反射和环境光是没有方向性。环境反射对被渲染物体最终的颜色影响较小,但它确实会影响最终的颜色,最为明显的就是当材质很少甚至不反射漫反射光时。材质的环境反射受场景中的环境光的影响。

材质还有另外一个属性就是放射性,用它渲染的对象看上去就是自己发光一样的效果。D3DMATERIAL9结构的Emissive成员就是用来描述物体发出的光的颜色和透明度的。放射会影响物体的颜色,也可以使暗的材质变亮并部分呈现出所发光的颜色。举例:如果想在应用程序中让某个物体体现出发光效果,又不要对周围的物体产生影响,就可以使用这个属性,这样还可以避免在场景中增加光源所带来的计算消耗。

我对材质的概念其实不是很强,有时候想要一块金属,结果出来的效果却像砖头,唉,毕竟不是学美术的啊。利用一些其他的3D工具可以建立出你所需要的模型,里面可以包含材质信息。然后导出成.x后缀的文件,这个格式的文件可以直接由D3D加载。

 

今天的“小肥羊”很好吃啊!

第六,灯光:

灯光和材质是密不可分,从上一章应该就可以看出一些端倪了。光线和材质的属性都是一一对应的。如果没有设定材质,场景中的光线不会看出任何效果。

光线所有的类型算起来也就是3种,很容易理解的。建议大家创建一个球体作为渲染对象,各种光线和材质的组合都可以在球体上得到很明显的反应;这就像小时候上美术课学静物素描,画的第一幅铁定就是球体和柱体。(我的美术当时还是不错的,可惜啊,一个天才就这样被扼杀在摇篮里了。)

不知道大家有没有玩“奇迹”的经验,里面的光效只能用一个字形容啊,那就是“牛B”!我们的目标就是学会3D以后,做一个也只能用一个字形容的游戏——“更加牛B”!——开始做梦了。

 

第一、   方向光;这种光源只有方向和颜色,没有位置。而且不受衰减和范围的影响,所以方向光是D3D中需要计算量最小的一种光源。一般来说,方向光被认为是光源位于无穷远处的平行光,就像太阳光。

第二、   点光源;特点是有颜色和位置,但是没有方向。它向各个方向发出完全一样的光;但是点光源的光线会受到范围和衰减的影响。如果超出了光线的作用范围,那么该光线就是不可见的了;同时点光源还受衰减的影响,它有一个衰减数值:

 

D3DLIGHT9 light;

light.Type = D3DLIGHT_POINT;

light.Position = D3DVECTOR3( 50.0f, 20.0f, -50.0f );

light.Diffuse.r = light.Diffuse.g = light.Diffuse.b = 1.0f;

light.Range = 100.0f;

light.Attenuation0 = 0.0f;

light.Attenuation1 = 0.1f;

light.Attenuation2 = 0.0f;

 

随着到光源的距离越来越远,光线的强度也会越来越弱。边缘光线强度等于光源处强度的1/Range

第三、   聚光灯;是D3D里面最复杂,计算量最大的一种光源。它包括的属性也是最多的有:位置,方向,颜色,内径光圈,外径光圈,范围还有衰减因子。其中衰减因子对于细微的变化都十分敏感,一般设定为light.Falloff = 1.0f,否则会得到意料之外的效果,但是绝不会是好事。

第四、   另外,还有一种就是环境光,它也是可以用来控制物体的颜色,和漫反射光结合使用,不过,我感觉更多时候环境光还是在控制整个场景的亮度。

 

SDK的帮助文档里面有一段“与光照相关的数学”:

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

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

环境光是恒定的光照。它在所有方向上不发生变化,对物体中所有像素产生的作用也完全相同。它计算起来很快,但得到的物体看起来是平面的,没有真实感。 漫反射光取决于光的方向和表面的法向。由于光的方向和表面法向量的变化,因此漫反射光会随物体的表面而变化。因为漫反射光随着每个顶点而变化,所以需要更长的时间进行计算,但是使用漫反射光带来的好处是它使物体呈现出明暗变化和三维深度。 镜面反射光代表了当光线照射到物体表面时反射回摄像机形成的明亮的镜面反射高光。它比漫反射光更强,但在物体表面也衰减得更快。计算镜面反射光需要比计算漫反射光更长的时间,但是使用镜面反射光带来的好处是它给表面增添了重要的细节。 放射光是物体发出的光,例如光晕(glow)。 通过在三维场景中使用这些类型的光,可以得到真实的光照效果。要得到更为真实的光照效果,应用程序可以添加更多的光源,但是,这增加了渲染场景的时间。要达到(游戏)设计师想要的所有效果,一些游戏使用了超出一般的CPU计算能力。在这种情况下,一般通过在使用纹理贴图的同时,使用光照贴图和环境贴图给场景加入光照的效果,这样就可以把光照所需的计算量减到最少。环境光、漫反射光和镜面反射光会受到给定光源的衰减和聚光灯因子的影响。为环境光、放射光和漫反射光成分计算的颜色值被保存在输出顶点的漫反射色中。漫反射和镜面反射公式都包含了衰减和聚光灯因子属性。

上面的这段话很有说服力,所以我还是说,想真正了解D3D,一定要仔细阅读SDK的帮助文档。:)

今天先这样吧,下一章会单独把IDirect3Ddevice9::SetRenderState(…)这个接口拿出来进行说明。它有点像3D效果的总开关,不知道用这个比喻会不会被人鄙视呢?

 

第七,SetRenderState():

今天有个大问题,鄙人英文不好……

关于SetRenderState()没有什么技巧性的东西,都是一些固定的设定,为了在程序中实现某个效果,你就必须作出相应正确的设定。所以,这一章,我想把SetRenderState()里面的每个参数都做一下说明,说白了就是翻译一下SDK的内容,虽然是这样,这一段还真是晦涩。如果我有不对的地方,大家帮忙指正一下吧,拜托^______^

 

SetRenderState() 的作用是设定单个设备的渲染状态的参数。该接口的第一个参数是 D3DRENDERSTATETYPE 的枚举类型;也是这个接口的关键,第二个参数只是对第一个参数,就是渲染状态的具体设定值。这个枚举类型有 100 多个值,下面一个一个来吧。


已经是凌晨2点多了,哥们我实在是不行了......呼呼!
  • 0
    点赞
  • 0
    收藏
  • 打赏
    打赏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页
评论 9

打赏作者

FishCrazy

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值