现在的位置: 首页 > 综合 > 正文

DirectX 11游戏编程学习笔记之9: 第7章Lighting(光照)

2018年04月09日 ⁄ 综合 ⁄ 共 5517字 ⁄ 字号 评论关闭

        本文由哈利_蜘蛛侠原创,转载请注明出处!有问题欢迎联系2024958085@qq.com

 

        注:我给的电子版是700多页,而实体书是800多页,所以我在提到相关概念的时候,会使用章节号而非页码。同样的情况适合于“龙书”第二版。

 

        上一期的地址:

DX 11 游戏编程学习笔记之8

 

        这一期我们来讲述本书的第7章。这一章其实和“龙书”第二版的第10章内容基本是一样的,学过的同学可以在几个小时之内轻松地完成。

        没看过“龙书”第二版的同学看着也许有点费劲。可能大家已经知道了,在DX 9 中,有专门用来表示光源和材质的结构体(分别是D3DLIGHT9 和D3DMATERIAL9 结构体),所以其实根本不必像在“龙书”第二版中那样自己去实现光照的计算。不过大家查查SDK 文档就知道了,在DX 10 和DX 11 中已经没有这样的两个结构体了。所以,要在DX 11 中实现光照的话,还真得好好研读本章内容,亲手进行计算不可!这样也好,继承了龙书第二版的优良传统;并且,我们亲手实现之后,就不必再惊讶于D3DLIGHT9
和D3DMATERIAL9 是如何变魔术般地起作用了!

        由于这一章的内容与“龙书”第二版对应部分太相似了,所以我会讲得省略些。不过还是有一些小区别的,我会慢慢提到(比如说书里的插图都变成卡通风格渲染的了,非常好看!)。

 

重点回顾

======================================================================

        根据我们的优良传统,我们把本章的学习目标列在下面:

1、 To gain a basic understanding of the interaction between lights and materials.(对光与材质的相互作用有一个基本理解。)

2、 To understand the differences between local illumination and global illumination.(理解局部照明和全局照明之间的区别。)

3、 To find out how we can mathematically describe the direction a point on a surface is “facing” so that we can determine the angle at which incoming light strikes the surface.(发现我们如何可以用数学语言描述面上的一个点所面对的方向,以便我们可以确定入射光击中面的角度。)

4、 To learn how to correctly transform normal vectors.(学会如何正确地对法向量进行变换。)

5、 To be able to distinguish between ambient, diffuse, and specular light.(能够区分环境光、漫反射光和镜面反射光。)

6、 To learn how to implement directional lights, point lights, and spotlights.(学会如何实现方向光、点光源和聚光灯。)

7、 To understand how to vary light intensity as a function of depth by controlling attenuation parameters.(理解如何通过控制衰减参数来随着深度的变换而改变光强。)

 

7.1Light and Material Interaction

        这一节与“龙书”第二版第10.1 节是一样一样的。

 

7.2Normal Vectors

        这一节对应的是“龙书”第二版的10.2.1 小节。不过这里有一点区别,就是在7.2.1 小节最后,给出了一个由面法向量计算顶点法向量的伪代码,写得非常不错,大家可以看看,虽然后面好像没有具体应用。

 

7.3Lambert’s Cosine Law

        这一节对应“龙书”第二版中的10.2.2 小节。

 

7.4Diffuse Lighting

        这一节对应“龙书”第二版中的10.2.3 小节。

 

7.5Ambient Lighting

        这一节是“龙书”第二版中的10.3 节的删减版,没有给出代码。

 

7.6Specular Lighting

        这一节基本上和“龙书”第二版中的10.4 节一样,不过对后者那里的公式进行了完善,也就是那个镜面反射因子要考虑光向量与法向量的点积:

 

7.7Brief Recap

        这里对前面所讲的东西进行了一个小小的总结。这个是“龙书”第二版中所没有的。

 

7.8Specifying Materials

        这一节讲述了材质,内容很简单,并且有了点小技巧。这一节是“龙书”第二版中所没有的。

 

7.9-7.11Parallel Lights, Point Lights, Spotlights

        这三节讲了平行光、点光源和聚光灯。基本上相当于“龙书”第二版的第10.5-10.7 节内容。这里还增加了Range 这一要素,而这是“龙书”第二版中所没有考虑的。基本上,这里就是想实现D3DLIGHT9 的所有特性。

        不过作者在这里偷了点懒。如果你查查D3DLIGHT9 结构体的定义的话,就会发现那里面对于聚光灯(Spotlights)定义了这么几个东西:表示内锥角的Theta,表示外锥角的Phi ,以及从内锥角到外锥角之间变化快慢的量Falloff。作者为了省事,其实只定义了一个锥角,并且这个锥角是通过Spotlight 结构体中的Spot 这个浮点数进行间接控制的。这样做其实减少了不少的计算量,而且其实效果和DX 9 中的Spotlights 效果也差不多。

 

7.12Implementation

        这个长长的节是“龙书”第二版中所没有的,讲了代码细节,包括定义了几个代表各种光源类型的结构体等等。感觉这比“龙书”第二版科学多了,用起来也方便;不过不方便的是,代码比较庞大,而且不太好理解。

 

7.13 Lighting Demo

        这一节讲述了本章的第一个示例程序的思路和结构。这个例子也是“龙书”第二版中所没有的(后者在这一章只给了几个很无趣的例子),而且挺有意思的,希望大家好好研究!

        这一节的最后一小节Normal Computation 基本上就是微积分的内容了,基本上也就是“龙书”第二版第10 章最后一个练习题了。学过微积分的同学(你肯定学过了,不是吗?)应该很轻松地过了这一小节;看不懂的话也没关系,毕竟这个不是重点。

 

7.14 Lit Skull Demo

        这一节很短,甚至没有给出任何的代码;但是这一节的内容并不简单,也很重要。事实上,从这里开始,本书的代码结构就开始发生不小的变动了。粗略地说,就是增加了Effects.h/.cpp 和Vertex.h/.cpp 这几个文件。可能大家对这部分内容看得不是很懂,即使是结合代码来看;其实这个是为了以后而提前做准备的。大家以后慢慢就会知道这里的用意的。

        另外我忽然发现前面我说错了:我之前说作者在这本书中没有对键盘的输入提供支持。其实这个示例代码中在没有使用Direct Input 的情况下仍然可以对键盘输入进行响应:按下数字键0、1、2、3就可以切换不同的光源数目了。当然这个是用Windows Message Loop 实现的,在实际的游戏开发中是不可取的,所以我就将其替换成了Direct Input 的实现方式了。

 

 

        最后值得一提的是,此书在这章里没有讲顶点光照和像素光照的概念。实际上“龙书”第二版中在第10章一直使用的是顶点光照,并且在第10.10
Phong Shading
那里讲到了像素光照;而本书似乎从头至尾使用的都是像素光照。与顶点光照相比,像素光照的镜面反射更加柔和,不刺眼,不过计算量大了很多;所以,在不影响游戏性的情况下,还是建议大家使用顶点光照!

======================================================================

 

勘误

======================================================================

1、 第7.6 节开始后不久有一个行内公式:

其中的向量V 应该是小写的。

2、 第7.12.2 小节Structure Packing 第二个代码块后的第一个自然段第一句话

However,,because this function simply copies raw bytes over, it can lead to hard to finderrors if we are not careful.

中的hard to find 应为 hard-to-find.

3、 第7.12.3 小节的代码块中倒数第二个注释第二行

// the line of site of the light.

中的site 疑为 sight.

4、 第7.13 节开始第一自然段最后的7.10 应为 7.12。

5、 第7.13.2 小节C++ Application Code 第一个代码块写错了,正确的应该是这样的(来自本书示例代码):

D3D11_INPUT_ELEMENT_DESC vertexDesc[] =
{
{"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0,D3D11_INPUT_PER_VERTEX_DATA, 0},
{"NORMAL",    0,DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0}
};

6、 第7.14 节Lit Skull Demo 最后一个自然段

The reader should study the “Lit Skull” demo…

中的 reader 应为 readers。

 

======================================================================

 

习题解答

======================================================================

        这里的习题相比“龙书”第二版第10章的习题要乏味一些,而且比较水,只有第3题是比较有技术含量的。

 

习题1

        这道题目实在是太简单了,把

mDirLight.Diffuse  = XMFLOAT4(0.5f, 0.5f, 0.5f, 1.0f);

改成

mDirLight.Diffuse= XMFLOAT4(1.0f, 0.0f, 0.0f, 1.0f);

再把

mPointLight.Diffuse  = XMFLOAT4(0.7f, 0.7f, 0.7f, 1.0f);

改成

mPointLight.Diffuse= XMFLOAT4(0.0f, 1.0f, 0.0f, 1.0f);

最后把

mSpotLight.Diffuse  = XMFLOAT4(1.0f, 1.0f, 0.0f, 1.0f);

改成

mSpotLight.Diffuse= XMFLOAT4(0.0f, 0.0f, 1.0f, 1.0f);

就行了。你可能会好奇,为何改的都是漫反射光呢?这是因为,漫反射光代表了一个光源发出的光的本质,也是最容易观察到的光。当然你也可以顺便把镜面反射光和环境光给改了。下面是我的程序运行时的一个截图:

 

习题2

        这道题也实在是太简单了,以至于我都不想做了。大家可以自己研究^_^

 

习题3

        这道题基本上就是“龙书”第二版第10章的习题2了。不过在“龙书”第二版中并没有说的很清楚,而这里算是讲清楚了。

        不过这里有一个值得注意的事情:卡通风格渲染的特点就是色彩变化比较突然,所以这里最好是按照书上的示例程序那样,用像素光照,因为用顶点光照的话,在像素着色器中这些颜色又会进行插值,这样在不同色彩交界处还会出现渐变,这样就与卡通风格渲染的目的相悖了。

        下面是我的程序运行时的一个截图,不知道大家觉得怎么样?

 

习题4

        这一道题也很简单,但是对于这种数据可以连续变化的操控,我觉得有一点需要注意。比如说在这里我是通过左右方向键分别来增减锥角的,具体就是按下左方向键,那么Spot 值会减小;而按下右方向键,Spot 值会增加。不过我们不希望每次按下后Spot 值都会立即变化(因为我们认为自己按下一次键后,其实程序会检测到好几次按键的操作,那么当我们一直按着某个键不放的话,那么相应的数值的变化就会非常快,这会给系统带来一些负担);相反,我们可能会希望按下,比如说,右方向键达到1秒钟后,Spot 值会增加2;而在此之前,不会对Spot
的值进行更新。那么应该怎么做呢?

        我之前在学习DX9 编程的时候,也遇到过这样的问题,后来想到了这样的一个方法,就是定义一个表示Spot 值的变化量的static float 变量dSpot,它初始化为0,并且可以快速地变化,并且按下右方向键1秒后它的值增加2.0f。然后我们在dSpot 的值大于2.0f 的时候更新Spot 的值,并且把dSpot 的值归零。这样Spot 的值最多1秒更新一次,减小了系统的负担了。详情请参见我发的答案代码。

 

======================================================================

 

        好啦,这一期讲得还是比较少的。下面是本章示例代码的下载地址:

第7章示例代码下载地址

 

        然后是习题答案的下载地址。注意我把第3题和第4题合在一起做了:

第7章习题答案下载地址

抱歉!评论已关闭.