今天帮老师判《三维图形程序设计》的试卷,这门课开卷考,用的教材是段菲翻译的DX9的龙书。判卷过程中发现有两道题虽然不难,但是错的比较多:

  1、Direct3D中深度缓冲区中值的范围?  A.0-1                  B.可以任意设置    C.取近平面远平面的值

  2、Direct3D支持三类光源为点光源、方向光和聚光灯。

第一题

  我仔细看了龙书,也没找到直接答案(感谢@xiaofeii的提醒,其实有答案),但是如果对投影变换内部原理理解比较深入的话,也是可以很容易得到这个答案的。龙书的绘制流水线如图1所示,这个比较利于初学者理解,比较专业绘制流水线如图2所示,可以发现图1其实是对图2的Vertex Shader部分进行了细化(图1中的第一行所有阶段相当于图2的Vertex Shader阶段),而对其他部分进行了简化,个人认为图1的流水线比较适合初学者理解。这里以图2进行说明,Triangle Traversal阶段遍历每个三角形,对三个顶点进行插值,计算三角形中对应光栅设备上的像素点,每个像素点的Z值也是在这个阶段得到,当然,在Pixel Shader中还可以对其进行修改。之后的阶段在这里就不详述了。

图1 龙书中的DX9绘制流水线

图2 DX9绘制流水线

  回到题目,深度缓冲区值的范围?首先必须确定深度缓冲区的Z值来源于哪个阶段,因为经过不同阶段的坐标变换以后Z值范围是不一样的!这里以图1进行说明,很多人选择了B,我猜测他们是认为深度缓冲区存储的是View Space阶段顶点的Z值,但是很遗憾,深度缓冲区存储的是Projection之后的Z值,所以应该选A。

  看到这里,有童鞋肯定纳闷,为什么投影之后Z的范围是0-1呢?投影不是往一个平面上投影吗?最后Z值应该一样的才对啊!这个就要从投影矩阵说起了,虽然投影到一个平面的投影矩阵很简单,但是这个过程是不可逆的。值得注意的是,DX中的所有变换都是可逆的,比方说对顶点P使用矩阵M进行变换,变换后只要乘以M-1即可变回P。为此,聪明的开发人员使用可逆的投影矩阵,具体解释参看MSDN。投影变换后,Z的范围就变为了[0, 1],0表示近裁剪面,1表示远裁剪面,在OpenGL中由于投影矩阵不一样,投影后Z值范围为[-1,1],但是在视口变换的时候将Z值范围变为[0, 1](感谢@xiaofeii的提醒)。

  顺便多嘴提一句,深度缓冲区[0, 1]的范围并不是用浮点数表示,而是用类似整型的方式表示,这样既提高了精度,也为之后的Buffer Compression的相关算法买下伏笔。

附:左手坐标系的投影矩阵,具体说明见MSDN

xScale     0          0               0
0 yScale 0 0
0 0 zf/(zf-zn) 1
0 0 -zn*zf/(zf-zn) 0

  如果书上有直接答案,明确说明深度缓冲区的范围是[0, 1],估计大家基本上都会回答对,但是深入思考其中原理的又会有多少人呢?不仅知其然,而且还要知其所以然,这才是学习的态度。

第二题

  这一题,在书上有,但只是和题目描述略有不同,有些不太理解的童鞋就写成了环境光、漫射光和镜面光。像上一题一样,如果只是知道表面,确实挺模糊的,同样是3个空,同样是和光源相关,凭什么是点光源、方向光和聚光灯而不是环境光、漫射光和镜面光呢?确切的说,前者是光源类型,后者是光照模型,下面将对其进行详细描述。

  从物理的角度来说,光与材质的交互包括两个方面:散射(Scattering)和吸收(Absorption)。散射发生在介质不连续的地方,比如不同材质的交界处,或介质密度变化,它只改变光的方向不改变光的能量;吸收发生在材质内部,它将光的能量转化为其他能量(如热能),但不改变光的方向。介质表面对光的散射包含两种方式,分别为折射和反射。对于透明物体,一部分光在表面进行反射,另一部分光发生折射,进入介质继续传播;对于不透明物体,一部分光在表面进行反射,另一部分光在介质中传播、吸收和散射,最后反射回表面(次表面散射),图3为不透明物体与光作用的示意图。

图3 光与材质作用

  DirectX光照模型中的漫射光镜面光分别对应材质表面的次表面散射表面反射,这两个模型共同模拟了光与材质作用时的散射现象,至于环境光,用来描述间接光照,这就是DirectX光照模型的来历,它们所对应的公式从提出以后一直被不断修正,趋于完善(直到2008年还有一篇文章对镜面光公式进行修正)。DirectX的材质描述了材质对于漫射光、镜面光和环境光的反射,这些对应物理上材质对光的吸收。另外,在材质中还有自发光分量,用于描述自发光的材质。

  到此为止,主要的光照现象已经被模拟了,如果需要其他更逼真的渲染,则需要对可编程管线下手了。例如透明玻璃球的折射,如果仅仅使用alpha融合进行渲染,那就太扯淡了,需要利用相关的物理知识,在可编程管线中模拟真实环境,并进行一定的简化;再比如说人脸的渲染,由于皮肤的次表面散射现象比较明显,所以使用漫射光来进行渲染就会让人觉得很假,需要针对次表面散射的物理现象,结合可编程管线进行逼真的渲染,《GPU GEMS 3》封面的人脸就是使用次表面散射相关技术进行渲染,有兴趣的童鞋可以看看这本书的第14篇文章。

  既然有光,肯定有光源,点光源、聚光灯和方向光正是由现实中的光源抽象而来。对于太阳这种比较大的光源,可以近似认为方向光;对于一些表面积不大的面光源,可以近似用点光源来模拟;至于聚光灯也是根据现实中的聚光灯进行模拟。虽然用这3种光源不能精确的描述现实中的光源,但是可以做到近似。

  回到题目,题目问的是光源类型而不是光照模型,如果理解了这些原理,那么自然想到的是点光源、聚光灯和方向光,无论如何也不可能写成漫射光和镜面光和环境光。虽然DX提供了相关API,但如果能够对其原理进行了解,则使用起来将会得心应手,而且,从DX10开始,取消了固定管线,只有可编程管线,所以理解原理显得更加重要。

写在最后

  本文的目的不是希望大家去背题目,以后看到同样的题目就不会出错,而是希望能够理解内部原理,做到不仅知其然,而且还要知其所以然。社会是浮躁的,在浮躁的环境中需要保持一颗平静的内心,也许原理性的东西短期内不会带来什么效益,但是保持这样的态度,很可能若干年后和别人拉开的差距,比多学几门热门技术要大的多。

DirectX考试判卷心得的更多相关文章

  1. 软件设计师.NET认证考试测试卷(试题及答案)

    软件设计师.NET认证考试测试卷 注意事项:用蓝.黑色钢笔答题.保持卷面整洁. 得分 阅卷人 一.单项选择(40分,每小题1分) 1.以下标识符中不全是关键字的是(D  ) A.case for in ...

  2. 辅助判卷程序的一些小bug

    首先谈一下,double类型 之前查过一些资料,double类型做==(相等)判断时候,会出现一些错误,及61.95与61.95不相等 对main函数中的部分加以改正,下面的answer为string ...

  3. 网友RHCE认证考试经历

    2014年7月,为大力推广RedHat Enterprise Linux7操作系统,红帽将基RHCE认证由RHEL6转换到RHEL7上. 面对新的软件功能.新认证课程内容,初期认证学员的考试通过率一直 ...

  4. 基于Web在线考试系统的设计与实现

    这是一个课程设计的文档,源码及文档数据库我都修改过了,貌似这里复制过来的时候图片不能贴出,下载地址:http://download.csdn.net/detail/sdksdk0/9361973   ...

  5. MongoDB实现问卷/考试设计

    MongoDB的特点 MongoDB是一个面向文档存储的数据库.在MongoDB中,一条记录叫做document(文档),由类似于JSON结构的键值对组成. 由于类似于MongoDB直接存储JSON的 ...

  6. 机器学习进阶-案例实战-答题卡识别判 1.cv2.getPerspectiveTransform(获得投射变化后的H矩阵) 2.cv2.warpPerspective(H获得变化后的图像) 3.cv2.approxPolyDP(近似轮廓) 4.cv2.threshold(二值变化) 7.cv2.countNonezeros(非零像素点个数)6.cv2.bitwise_and(与判断)

    1.H = cv2.getPerspectiveTransform(rect, transform_axes) 获得投射变化后的H矩阵 参数说明:rect表示原始的位置左上,右上,右下,左下, tra ...

  7. java经典题目

    /***********Ryear.java begin********************/ import java.util.Scanner;public class Ryear { /** ...

  8. 哥德尔,图灵和康托尔 part 1 哥德尔编号

    在看计算理论相关的书的时候,偶然看到这个blog,http://skibinsky.com/godel-turing-and-cantor-the-math/,写的很好.我觉得用自动机的方式讲计算理论 ...

  9. 《C# 从现象到本质》出版,免费送书10本

    我的第一本书<C# 从现象到本质>已于近日正式在京东和淘宝天猫上开始销售了.至此,我的图书写作和出版活动正式告一段落.图书销售网址见下. 试读样章 京东 天猫 从看书到写书 借着图书出版之 ...

随机推荐

  1. 【Knockout】二、监控属性Observables

    MVVM和viewModel Knockout是建立在以下三大核心功能之上的: 监控属性和依赖跟踪(Observables and dependency tracking) 声明式绑定(Declara ...

  2. (Android)View.getHeight或getWidth为0时的一些解决方案

    在Android开发过程中,经常需要动态的更改View的大小,有些View的大小可能需要根据其他View的大小来设定,或者你需要得到一些View的大小来进行某项操作,但是有可能你需要在onCreate ...

  3. 如何设置win7任务栏的计算机快速启动

    win7默认会有一个资源管理器的快速启动栏,但是点击的时候会打开“库”,你可能一般不会用这个库,想打开计算机怎么办呢? 其实很简单,再按住shift的同时右键资源管理器的这个快速启动项,然后会出现菜单 ...

  4. Paying for upgrades, by Bob Arnson

    Following content is reprinted from here, please go to the original website for more information. Au ...

  5. 用于主题检测的临时日志(594fb726-af0b-400d-b647-8b1d1b477d72 - 3bfe001a-32de-4114-a6b4-4005b770f6d7)

    这是一个未删除的临时日志.请手动删除它.(f8322da6-c527-47fb-98d2-f12a7d814d19 - 3bfe001a-32de-4114-a6b4-4005b770f6d7)

  6. 关联 Android 源代码 到 Ecplise

    1. 下载android 源码存于本地硬盘; 2. 打开Eclpise, 新建Android Project; 3. 在MainActivity文件中,按住Ctrl 点击Activity类 4. 弹出 ...

  7. 一些值得思考的"小题"一

    如下是我们查找数组中某个元素的一种通常做法 const int *Find(const int *array, int length, int x) { const int *p = array; ; ...

  8. 鼠标滑过提示title

    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1. ...

  9. asp.net导出Excel 按照预定格式,以及解决导出乱码

    protected void ToExcel() { //新建一个Gridview,原因:避免当前窗口GridView外层没有直接跟form标签,从而避免“gridview1未包含在run='serv ...

  10. 基于css3新属性transform及原生js实现鼠标拖动3d立方体旋转

    基于css3新属性transform,实现3d立方体的旋转 通过原生JS,点击事件,鼠标按下.鼠标抬起和鼠标移动事件,实现3d立方体的拖动旋转,并将旋转角度实时的反应至界面上显示 实现原理:通过获取鼠 ...