《Fundamentals Of Computer Graphics》第一章 介绍 总结
在开头我应该说下几件重要的事,首先我会通过复述书上的内容然后加上自己的理解来总结每个章节的内容。其次英文原文我是大概看懂了的,就是有时候不知道该怎么恰当地翻译成中文,所以会借助现有的翻译工具,有些翻译错了或者感觉味道不对的地方,我会加以改正的!开篇
第一章就如它的标题“Introduction”所言,主要讲的是一些介绍性的东西。开头即讲到了计算机图形学这个术语描述的是计算机创建和处理图像的任何用途,这本书是关于基础算法和数学,特别是那些利用三维物体和场景生成合成图像的基础算法和数学。我觉得这挺重要的,首先得了解自己学的是什么然后还要粗略地了解书中写的内容。
主要领域(Graphics Areas)
图形学的涉及到的主要领域有建模(Modeling)、渲染(Rendering)、动画(Animation)。
[*]建模:它涉及的是把形状和外观属性储存到计算机中的方法的数学规范。
[*]渲染:这个术语来自艺术领域,它涉及的是通过三维计算机模型生成的着色图像的创建。
[*]动画:它是通过连续的图像制造运动的错觉的技术,虽然使用了建模和渲染,但是涉及到了随时间运动这一关键问题,这通常不会在建模和渲染中所涉及。
主要应用(Major Applications)
它的主要应用有:视频游戏、卡通、视觉特效、动画电影、计算机辅助设计、计算机辅助制造、模拟、医学成像、信息可视化
图形API(Graphics APIs)
使用图形库的一个关键的部分就是和图形API打交道。API(Application Program Interface)即进行一系列相关操作的标准函数集,那么图形API就是例如能把图像和3D表面绘制到屏幕上的窗口的图形函数集。这些图形API一般是和编程语言绑定的,例如D3D12的官方文档中提到C++是唯一被支持进行D3D12开发的语言,如下图所示。因此首先熟悉这些绑定的编程语言是重中之重!
图形管线(Graphics Pipeline)
今天的每台桌面计算机通常都有一个强大的三维图形管线,它是能高效地绘制三维图元的特殊软硬件子系统,这些系统一般都被优化来处理有着共享顶点的三维三角形。在管线中的基础的操作就是把三维顶点位置映射到二维屏幕位置然后着色三角形,来让这些三角形看着很真实的同时又以正确的前后顺序展现到观察者眼前。
尽管以从后往前的顺序绘制三角形在曾今是一个重要的被研究的问题,现在通常都通过深度缓冲(z-buffer)来解决。深度缓冲通过使用一定大小的特殊内存缓冲以一种暴力的方式解决了绘制顺序的问题,从而避免了解决绘制顺序问题中的很多麻烦的地方。
在图形管线中的很多几何操作几乎都能在由三维坐标和齐次坐标(homogeneous coordinate)组成的四维坐标空间中所解决,齐次坐标解决的是透视观察这一问题。四维坐标是通过4x4的矩阵和四维向量所操作的,图形管线可以有效地处理和组合这些矩阵和向量。四维坐标系统是计算机科学中最微妙的构造之一,它也是学习计算机图形学要跨过的最大的一个障碍。不过这本书还是提供了很多方法来理解四维坐标系统和矩阵变换,加上刚入大学的时候学过线性代数,还有写过相关的代码进行实践,我感觉其实没有太多的困难。
图像生成速度很大程度上取决于要绘制的三角形数量,在很多应用中交互性比视觉质量更加重要,减少用于表达模型的三角形的数量是很值得的。而且模型会在不同的距离被观察,相比于近距离观察模型,在远距离观察时其实只需要绘制更少的三角形,因此采用细节等级(LOD——level of detial)方案来表示模型是非常有用的。
数值问题(Numerical Issues)
在进行实践的时候,有些时候会遇到一些很难处理的数值问题。幸运的是,当代的大多数计算机都遵循IEEE浮点数标准,它可以让程序员对某些数值情况的处理做出方便的假设。对于图形学来说有下面要注意的地方
[*]正无穷(\(+\infty\)):它是一个比其它有效数字都大的一个有效数字
[*]负无穷(\(-\infty\)):它是一个比其它有效数字都小的一个有效数字
[*]非数字(\(\text{NaN}\)):它会在进行未定义的操作中出现,例如除以0
IEEE浮点数的设计者做了对编程者非常有利的一些决定,对于正实数\(a\)来说有
\[+a/(+\infty)=+0\]
\[-a/(+\infty)=-0\]
\[+a/(-\infty)=-0\]
\[-a/(-\infty)=+0\]
对于\(\infty\)和正实数\(a\)相关的操作有
\[\infty+\infty=+\infty\]
\[\infty-\infty=\text{NaN}\]
\[\infty \times \infty=\infty\]
\[\infty / \infty=\text{NaN}\]
\[\infty / a=\infty\]
\[\infty / 0=\infty\]
\
此外涉及无穷值的布尔表达式有如下要注意的几点
[*]所有有限的有效数字都小于正无穷
[*]所有有限的有效数字都大于负无穷
[*]负无穷比正无穷小
涉及非数字的表达式的处理规则有如下几点
[*]任何包括非数字的算术表达式的结果都是非数字
[*]任何包括非数字的布尔表达式的结果都为假
对于正实数\(a\)除以0的操作有
\[+a/+0=+\infty\]
\[-a/+0=-\infty\]
效率问题(Efficiency)
对于让代码更加有效率来说没有什么魔法规则,效率是通过谨慎地衡量实现的。对于可见的未来来说一个良好的启发是相比于操作次数,编程者应该更加关心内存读取方式。这和20几年前的想法是不一样的,因为内存速度没有跟上处理器的速度的发展。
此外应该采用如下的合理的步骤顺序,来让代码运行更快
[*]以尽可能最直接的方式编写代码,在运行中直接计算中间值而不是储存它们。
[*]以优化模式编译代码
[*]使用任何性能评估工具来找到最重要的性能瓶颈
[*]检查数据结构来找到更好的方式提升局部性,如果可能的话,让数据单元的大小与目标架构的缓存或页的大小匹配
[*]如果性能评估揭示在数值计算方面的瓶颈,检查编译器生成的汇编代码来找到效率低下的地方。重新编写源代码来解决你找到的任何问题
最重要的也就是第一个步骤,作者也说明了KISS即keep it simple,stupid的准则,大多数优化只能让代码更难阅读,此外应该把时间更多地投入到修复BUG以及增加新的特性上。最后还要注意下有些老的技巧可能不管用了,因为众所周知的是处理器在各种方面正在变得越来越快速。
设计和编写图形程序(Designing and Coding Graphics Programs)
对于设计和编写图形程序来说,有些常用的策略在图形编程中是很实用的
类设计(Class Design)
首先就是类的设计,图形程序中的关键的部分就是对图形实体和几何实体有良好的类和简洁而有效的函数设计。一些基础的类应该包括
[*]二维向量(vector2):储存x、y分量,此外应该还要支持加、减、点乘、叉乘等基础操作。
[*]三维向量(vector3):和二维向量类相似,不过多了一个z分量
[*]齐次向量(hvector):比三维向量多了个齐次坐标w
[*]RGB颜色:RGB颜色存储三个分量,应该支持加、减、乘等操作
[*]变换(Transform):应该包括4x4的用于变换的矩阵,还应该支持与矩阵和向量相乘的操作
[*]图像(Image):带有输出操作的RGB像素的二维数组
看到这里你可能觉得对各种类型的向量和各种类型的矩阵的操作很麻烦,不过对于某个图形API来说,向量、矩阵以及和它们相关的函数都有数学库实现。对于OpenGL和Vulkan来说就有GLM,对于D3D11和D3D12来说有DirectXMath。
单精度VS双精度(Float vs. Double)
现代架构倾向于通过降低内存使用以及保持连续的内存读取来提高效率,这就倾向于使用单精度浮点数。不过有时候为了避免数值问题,这个时候双精度浮点数就派上用场。比如现在想要生成一张分形的图像,如下图所示。当放大倍率过高时,会超出单精度浮点数的精度极限,这个时候使用双精度浮点数可以良好地解决这一问题。
调试图形程序(Debugging Graphics Programs)
说到调试,据我所知现在还是有许多图形调试工具的,例如Nsight、PIX、RenderDoc等等。对于我目前的学习需求来说,我挺喜欢Nsight。不过书中也提供了几种调试方法
科学探究方法(The Scientific Method):当我们创建图像并且观察当中的错误时,这个时候必须提出一种为什么导致这个问题的猜想,并且进行测试。以光线追踪程序为例,有时候可能会看到一些很暗的像素。这是大多数人在写光线追踪器会遇到的一个经典的叫阴影痤疮(shadow acne)问题。传统的调试在这里不起作用,我们应该意识到阴影光线击中了正在被着色的表面,所以看到的暗像素实际上是环境光颜色,正是因为自遮蔽的发生导致了直接光照的缺失。所以这个时候得假设被着色的位置被错误地判断成了在阴影中,为了测试这个假设可以关闭阴影检测并且重新编译。
把图像作为调试输出(Images as Coded Debugging Output):在很多情况下获得调试信息的方法就是输出图像本身。如果想知道对于每个像素的计算的某个部分的变量,可以修改程序来直接把值输出到图像。打个比方就是,如果猜测着色的问题是由表面法线引起的,这个时候可以直接输出法线到图像。
数据可视化调试(Data Visualization for Debugging):可以采用更好的方式来说明计算的过程做了什么,比如对于光线追踪器来说可以写代码来可视化光线树,从而查看哪些路径对当前像素的值有贡献。这样能更好地理解计算机做了什么,而且还有利于代码优化。
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页:
[1]