《Fundamentals of Computer Grahpics》虎书第三版翻译——第一章 介绍
1.1 图形领域
强分类在任何领域都是具有风险性的,并非所有人都能够成功地实现。然而,在图形学行业中许多人确实认同并认为属于其专业领域的是那些主要领域的技术与方法。
建模:基于数学规范建立模型。这些数据能够表示计算机中可存储的形状及其外观特性。比如一个咖啡杯可被视为由一系列按照特定插值规则排列的三维空间中的点构成,并配合反射模型模拟光与表面之间的相互作用机制
渲染:出自美术的一个专业术语,用于生成从3D计算机模型渲染后的图像
动画:基于一系列图像创造幻觉运动的技术。除了在传统的建模与渲染中未涉及外,在本研究的基本框架下提出了这一核心挑战。
还存在许多其他领域与计算机图形学相关,
但这一学科是否属于计算机核心领域存在争议。
这些主题在本书中将至少提及一部分。
涉及的内容包括:
它负责处理用户的输入设备与系统之间的接口例如鼠标键盘等常用输入设备以及应用程序将图像反馈给用户以提供视觉听觉等感官信息。从历史发展来看该领域与图形学研究有着紧密联系由于图形学领域的先驱们最先接触到这些广泛应用于各个领域的输入输出设备。
虚拟现实技术:旨在使用户身临其境地沉浸于3D世界。
这通常需要三维图像以及对头部动作的响应。
为了更为逼真的虚拟现实体验,同时需要相应的声音反馈与力觉反馈。
由于这一领域对高精度的三维图像生成与显示技术要求较高,因此它通常与图形学研究紧密相关。
可视化:利用可视化帮助用户理解复杂的信息。这些图像通常与图形学问题紧密相关
图像处理:处理2D图像的操作。被用于图像和视觉两个领域。
3D扫描:基于距离测量技术生成三维模型。这些模型对于构建复杂的视觉图像非常有用,并且处理这些模型需要用到常见的图形学算法。
Computational photography employs a variety of computer graphics, computer vision, and image processing techniques to enable the new approach of capturing objects, scenes, and environments comprehensively.
1.2 主要应用
几乎每个领域都可以应用计算机图形学技术,并非所有领域都需要依赖它。然而,在这些行业中使用该技术最普遍的是哪些具体行业?
电子游戏:对复杂的3D模型和渲染算法的使用日益增长
卡通:一般由3D模型即时呈现效果。传统的二维卡通动画往往采用基于三维模型进行背景渲染的方式,并通过不断变换观众视角来实现视觉效果的变化与保持。
视觉效果方面:主要运用了多种类别的计算机图形学手段。绝大多数现代电影都会借助数字合成技术将前景与背景巧妙地结合在一起。一些电影则采用三维建模与动画技术来构建虚拟环境以及物体模型。即便如此,在许多观众也不会质疑其真实性的人也常被创造出来。
动画电影类作品:运用了与视觉呈现效果相似的技术手段,并未要求图像具有高度的真实感
CAD/CAM 涵盖计算机辅助设计与计算机辅助制造技术。 这些领域运用计算机技术在电脑上设计制造零件与产品,并通过这些仿真软件来进行辅助制造。 例如,在三维计算机建模环境中可以设计复杂的机械部件,随后在由计算机控制的加工设备上自动完成生产过程。
模拟:可以被认为是精密且高度专业的视频游戏活动。例如,在航空领域中使用的飞行模拟器通常采用高精度的3D建模技术来逼真地呈现飞行操作。这种模拟对于那些安全性十分重视的领域在前期培训上很有帮助,例如驾驶类职业,以及对培养有经验用户的场景培训非常有用,比如创造成本高昂或危险的特殊消防场景。
医学成像:通过分析患者的扫描数据生成重要图像。例如,CT成像系统将患者的扫描数据转换为由密度值构成的三维矩阵,并利用计算机图形学生成渲染后的图像,从而帮助医生提取出最重要的信息。
信息可视化:不需要形象化描述就能创建数据的图形表示方法。例如,这些高级的数据可视化工具能够有效地展示不同股票价格的趋势变化,从而帮助人们很容易找出这些数据中的规律和模式
1.3 图形API
构建图形库的核心在于使用图形学API。应用程序接口(API)是提供一组标准函数集合的工具,在这些函数集合中包含了将图像和3D表面绘制到屏幕上的基本操作。每个图形程序都必须能够调用两个相关的API:一个是用于视觉输出的图形API(Computer Graphics API),另一个是用于用户输入界面的AIPI(人机交互接口)。当前有两种主要的方法来实现这一目标:第一种是以Java为例的集成方法,在这种情况下相关的工具包已经被完全标准化并成为了Java语言的一部分;第二种则是以Direct3D和OpenGL为代表的软件库方法,在这种情况下绘图命令通常与编程语言直接绑定在一起(例如在C++编程中),而人机交互界面则是一个独立运行的应用程序系统,在不同计算机上可能实现方式不同。在后一种方法中尽管对于简单的程序也许可以使用可移植化的库层来封装系统特定的人机交互代码但编写真正意义上的可移植代码仍然较为繁琐。无论选择哪种技术路线基本的操作流程都是相似的因此本书所介绍的概念和技术仍然完全适用
1.4 图形管线
如今,每台台式电脑都有一个强大的3d图形管道。他是一个特殊的软/硬件子系统,可以有效的绘制基本的3D物体的透视图。通常这些系统可以优化那些具有共享顶点的三维三角形。管线的基本操作是将3D顶点位置映射到2D屏幕位置并对三角形进行渲染,使他们看上去很逼真,并以适当的前后顺序显示。
尽管以有效地以从后往前的顺序绘制三角形在当时是最重要的研究问题,但是现在总能使用Z缓冲区解决,它使用了一个特殊的内存缓冲区来以蛮力解决这个问题。
事实证明在图形管线所使用的几何操作几乎能在由三个传统的几何坐标和辅助透视用的第四个齐次坐标组成的思维空间坐标完成。这些4D坐标是使用4×4矩阵和4维向量处理的。因此,图形流水线包含了许多机器,以便有效地处理和组成各种各样的矩阵和向量。四维坐标系是计算机科学中使用的最微妙和美丽的结构之一,这无疑是学习计算机图形学时需要翻过的最大的障碍。每本图形学书的第一部分的绝大部分都在与这些坐标打交道。
图像生成的速度很大程度取决于绘制三角形的数量。由于交互性在很多应用程序比视觉质量更重要,因此很有必要让表示一个模型所使用到的三角形数量尽可能的最小。此外,如果模型离视野很远的话,需要三角形的数量应该比离视野近的要少。这表面以多细节层次处理(LOD level of detail )表示三角形是很有用的。
1.5 数值问题
这些特殊值包括正无穷大、负无穷大以及零
- 正无穷(∞)被视为一个上界数值,在数值系统中它大于所有的有限有效数字。
- 负无穷(-∞)则被视为一个下界数值,在数值系统中它小于所有的有限有效数字。
- NaN(Not a Number)不是一个合法的数值;它表示由于无法定义的操作而导致的结果。
IEEE 754浮点数分为正零和负零两种形式。 虽然−0与+0之间存在细微差别,在特定情况下可能会显现出来。 遇到这种情况时,最好牢记这一点。
IEEE浮点标准的设计师做出的一些设计对于程序员来说非常方便。在处理除0异常的时候,许多处理方式于前面三个特殊值有密切关系。在这些情况下,异常会被计算机记录下来,但在许多情况下,程序员可以忽略该异常。具体来说,对于任何正实数a,涉及无穷大除法的规则是这样的:
+a/(+∞) = +0
−a/(+∞) = −0
+a/(−∞) = −0
−a/(−∞) = +0
涉及无穷的运算法则和人们预想的一样,对于正数a,例如:
∞+∞= +∞
∞ − ∞=NaN
∞ × ∞=∞
∞/∞=NaN
∞/a =∞
∞/0 =∞
0/0 = NaN
包含无穷值的布尔表达式中的规则如下所示:
- 所有有限有效数均小于+∞
- 所有有效数效数均大于+∞
- -无穷小于+无穷
涉及具有NaN值的表达式的规则很简单:
- 所有包含NaN的算术表达式计算的结果必然是NaN
- 所有涉及NaN的布尔表达式的计算结果必然是false
IEEE浮点运算最突出的功能可能是对零除操作的支持;对于任意正实数a而言,在执行除法运算时有如下规则:当分母为+0时结果为正无穷大(即+a/+0 = +∞),而当分母为-0时结果则为负无穷大(即−a/+0 = −∞)。
当程序员遵循IEEE规则时,在数值计算中会更加简便许多。例如,在工程领域中经常遇到这种情况:
这种表达式常见于电阻与透镜的情形中。当遇到除以零的情况,在许多系统中,在IEEE浮点数出现之前……但现在有了IEEE浮点数后,则根据需求将a设为零。另外一种避免特殊检查的技术是利用NaN的布尔属性。考虑以下代码段:
A等于f(x)
如果A大于0,则执行以下操作:
Do something
在处理过程中,在某些情况下函数f可能会输出不太期望的结果例如无穷大或者非数值型结果NaN等但在使用if语句判断条件方面非常直观明确当变量a取NaN或-∞值时其判断结果为false即满足条件表达式(a < 0)反之当变量a取+∞值时判断结果则为true即满足条件表达式(a > 0)。在决定如何处理这些异常情况的时候如果语句通常能够做出正确的选择而不需额外检查从而简化了程序逻辑提升了代码效率并确保了系统的可靠性
1.6 效率
没有魔法可以使代码高效运行。效率通过细致地权衡实现,在不同的架构上这些权衡有所不同。然而,在不久的将来一个好的启发表明程序员应更关注内存访问模式而非操作次数。这与十年前最成功的建议相反。这种情况发生的原因在于处理器速度已经无法跟上内存速度。由于这种趋势一直持续下去有限且一致的内存访问对性能优化的重要性只会越来越突出。要提高代码运行速度请根据具体需求采用以下分步策略:首先评估算法复杂度;其次优化数据结构;最后减少I/O操作频率;这样可以显著提升执行效率;
- 采用直接开发策略实现软件功能。
- 采用最佳实践进行编译处理。
- 通过使用性能分析工具识别性能瓶颈位置。
- 分析数据结构布局来提升空间 locality。
最佳实践:建议选择的数据块尺寸应匹配目标系统的缓存或页 sizes. - 一旦发现数值计算中的性能瓶颈问题,则需对生成的汇编代码进行效率评估。
然后通过重新审视并修改原始源码来提升整体性能。
在这系列步骤中占据核心地位的是第一步。大多数优化措施虽然提升了性能但却牺牲了代码易读性,并且这些改进效果并不显著。与其将时间和精力投入到代码优化上不如专注于修复已知问题或增加新功能;另外需要注意的是旧教材中的某些经典技巧可能会失效;例如,在现代硬件环境下将实数类型转换为整数类型未必能带来预期的性能提升。无论是在软件层面还是硬件层面,在开发过程中都应致力于不断优化机器指令和编译器性能
1.7 设计和编写图形程序
某些通用的方法在图形学程序中存在一定的适用性。
本节将为你提供一些学习本书时会有所裨益的建议。
1.7.1 类设计
任何图形学的核心在于为几何实体(如矩阵与向量)以及视觉实体(如RGB三原色与图片)提供良好的类或者示例。
这些示例应当尽可能高效且简洁。
一个常见的设计问题是:是否应该将位置参数_1/2与位移参数区分为不同的类别?这是因为它们所遵循的运算规则存在差异。
位置参数_1/2不具备任何几何意义(除非它们是在某个特定坐标系下),而位移参数_1/2则具备明确的意义。
尽管这个问题几乎没有共识的答案(这可能导致图形学领域的从业者进行多小时激烈的争论),但为了举例说明我们暂且假设不会对它们进行分类区分。
这意味着我们需要编写以下几种基础类型的类:
- Vecrtor2:二维向量类
- Vecrtor3:类似于Vecrtor2
- hvector:具有四个分量的同质向量(齐次坐标)
- Rgb:存储三个分量的颜色RGB
- Transform:用于变换四行四列矩阵
这些变换操作应包含对位置、方向及表面法向量的应用操作 - Image: 二维RGB像素数组
您可能还会想到为单位向量设计的特殊类型呢?尽管这些类型确实让人感到棘手。
在体系结构表面可以看到, 减少内存使用的同时又能保证内存访问一致性是提升效率的关键所在。
这意味着我们倾向于采用单精度数据存储。
然而, 为了避免数值问题, 建议在算法设计中选用双精度策略。
权衡之下, 我认为最好在类中设置一个默认值以供初始化。
因此, 我建议在几何运算与颜色计算中使用double类型。
对于占用大量内存的数据(例如三角形网格), 我们推荐使用float存储,
但当成员函数访问数据时必须转换回双精度以确保准确性。
随着经验丰富的程序员逐渐减少对传统调试器的依赖,
尤其是在图形界面应用开发中,
我们发现一些调试方法特别适合解决实际问题,
特别是在图形化界面开发中发现了一些特别有效的调试手段,
而概念错误往往是最难以察觉的问题,
因为执行了错误的操作却不容易找到具体的错误所在,
这使得调试工作显得异常繁琐而具挑战性。
科学的方法:在图形程序中有一种很有用的替代传统调试的方法。它的缺点是与计算机程序员早期被教导不要做的行为非常相似因此如果你选择这样做你会觉得有些"不寻常":我们创建一个图像并观察其问题然后假设出错原因并进行测试这种方法在光线追踪程序中表现尤为明显例如许多看起来像暗像素的情况就是典型的"阴影痤疮"问题传统的调试方法在这里并不奏效相反我们必须认识到阴影射线击中的是正在着色的表面我们可以注意到这些黑色像素的颜色与周围环境一致因此缺少直射光直射光可以在阴影中关闭从而我们可以假设这些黑色像素被错误地标记为阴影但实际上它们并不是为了验证这一假设我们可以关闭阴影检查重新编译以确定这些问题是否确实是由阴影标记引起的这种方法有时被视为一种良好的实践因为它不需要发现错误的具体数值或者真正确认概念上的错误相反它只是通过试验来缩小概念上的误差通常只需要进行几次试验就能找到问题所在而且这种调试过程非常有趣
if x等于126且y等于247时
Print “blarg!”
如果你在打印的句子中设置了断点,则可以在计算您感兴趣的像素之前进入调试器。某些调试器具备“条件断点”功能,在不修改代码的情况下实现相同效果的可能性。
当程序崩溃发生时,在程序崩溃的情况下传统的调试方法对于定位崩溃位置仍然很有用。然后,请使用设置断点并在重新编译后开始回溯的方法来查找问题所在的位置。这些断言应保留在程序中以便未来可能添加错误的情况处理。这也意味着避免了传统逐步排查的方法。
通过数据可视化手段进行程序调试通常会遇到困难。
