计算机图形是数据可视化的基础。从实际角度来看,可视化是将数据转换为一组图形基元的过程。然后使用计算机图形的方法将这些基元转换为图片或动画。本章讨论了基本的计算机图形原理。我们首先描述了光线和物体如何相互作用形成我们所看到的景象。接下来,我们将介绍如何使用计算机图形技术模拟这些相互作用。硬件问题在这里扮演着重要角色,因为现代计算机内置了图形硬件支持。本章最后通过一系列示例说明了我们针对3D计算机图形的面向对象模型。
计算机图形是使用计算机生成图像的过程。我们称这个过程为渲染。有许多类型的渲染过程,从2D绘图程序到复杂的3D技术。在本章中,我们将重点介绍用于可视化的基本3D技术。
我们可以将渲染视为将图形数据转换为图像的过程。在数据可视化中,我们的目标是将数据转换为图形数据或图形基元,然后进行渲染。我们的渲染目标并不是照片般的逼真,而是信息内容。我们还努力实现交互式图形显示,使我们能够直接操纵底层数据。本章解释了从图形数据渲染图像的过程。我们首先看一下光线、摄像机和物体(或演员)在我们周围的世界中是如何相互作用的。基于这一基础,我们解释了如何在计算机上模拟这个过程。
图3-1展示了我们看物体(比如一个立方体)时发生的简化过程。光线从光源向各个方向发射。(在这个例子中,我们假设光源是太阳。)一些光线碰巧击中了立方体,其表面吸收了部分入射光并反射了剩余的光。一部分反射光可能朝向我们并进入我们的眼睛。如果这样发生,那么我们就“看到”了这个物体。同样,太阳的一些光线会照射到地面,其中一小部分会反射进入我们的眼睛。
可以想象,一束光线从太阳穿过空间击中一个相对较小的行星上的一个小物体的几率是很低的。这种情况又受到光线反射到我们的眼睛的几率很低的影响。我们之所以能看到物体,只是因为太阳产生了如此巨大的光量,以至于它压倒了这些几率。虽然在现实生活中这种情况可以成立,但尝试用计算机模拟它可能会很困难。幸运的是,有其他方法来解决这个问题。
一种常见且有效的3D计算机图形技术叫做光线追踪或光线投射。光线追踪通过跟踪每条光线的路径来模拟光线与物体的相互作用。通常情况下,我们从观察者的眼睛反向跟踪光线,直到确定光线击中了什么物体。光线的方向是朝向我们所看的方向(即视线方向),包括透视效果(如果需要的话)。当一条光线与一个物体相交时,我们可以确定该点是否被我们的光源照亮。这是通过从交点处向光源追踪一条光线来实现的。如果光线与光源相交,那么该点就被照亮。如果在到达光源之前光线与其他物体相交,那么该光源就不会对该点产生照明效果。对于多个光源,我们只需为每个光源重复这个过程。所有光源的总贡献,再加上任何环境散射光,将决定该点的总照明或阴影。通过反向跟踪光线的路径,光线追踪只关注最终进入观察者眼睛的光线。这极大地减少了模拟程序需要计算的光线数量。
尽管我们将光线追踪描述为一种渲染过程,但令人惊讶的是,许多图形界的成员并不使用它。这是因为光线追踪是一种相对缓慢的图像生成方法,因为它通常是通过软件实现的。其他图形技术已经发展出来,使用专用计算机硬件生成图像。要理解为什么会出现这种情况,我们需要简要了解计算机图形的分类和历史。
图像顺序和物体顺序方法
渲染过程可以分为两类:图像顺序和物体顺序。光线追踪是一种图像顺序过程。它通过逐个确定每条光线的行为来工作。物体顺序过程则是逐个渲染每个物体。在上面的例子中,物体顺序技术首先会渲染地面,然后再渲染立方体。
换个角度考虑绘制一幅谷仓的图片。使用图像顺序算法,你会从画布的左上角开始放下正确颜色的油漆滴(每个油漆滴被称为像素)。然后你会向右移动一点,放下另一滴油漆。你会一直持续到达画布的右边,然后你会向下移动一点,开始下一行。每次放下油漆滴,你都要确保它是画布上每个像素的正确颜色。完成后,你会得到一幅谷仓的画。
一种替代方法是基于更自然(至少对许多人来说)的物体顺序过程。我们通过绘制场景中的不同物体来工作,与物体实际位置无关。我们可能从后到前、从前到后或以任意顺序绘制。例如,我们可以先绘制天空,然后再加入地面。在这两个物体绘制完成后,我们再加入谷仓。在图像顺序过程中,我们以非常有条不紊的方式在画布上工作,从左到右,从上到下。而在物体顺序过程中,我们往往会根据正在绘制的物体跳跃到画布的另一部分。
计算机图形学领域最初使用物体顺序过程。早期的工作大部分与硬件显示设备密切相关,最初是矢量显示器。这不过是一种示波器,但它鼓励将图形数据绘制为一系列线段。随着最初的矢量显示器被目前无处不在的光栅显示器所取代,将图形数据表示为一系列要绘制的物体的概念得以保留。IBM的Bresenham [Bresenham65] 在早期的工作中主要关注如何将线段正确地转换为适合于线绘图仪的形式。同样的工作也应用于将线段渲染到取代示波器的光栅显示器上。从那时起,硬件变得更加强大,能够显示比线段更复杂的基元。
直到20世纪80年代初,Turner Whitted [Whitted80] 的一篇论文促使许多人从更物理的角度来考虑渲染。最终,光线追踪成为传统物体顺序渲染技术的一个严肃竞争者,部分原因是它能够产生高度逼真的图像。物体顺序渲染因为有大量专门设计用于快速渲染物体的图形硬件而保持其流行。光线追踪往往是在没有任何专门的硬件支持下进行的,因此是一个耗时的过程。
表面渲染与体积渲染
到目前为止,本文的讨论在默许的情况下假设,当我们渲染一个物体时,我们看到的是物体的表面以及它们与光的相互作用。然而,常见的物体,如云、水和雾,是半透明的,或者散射通过它们的光。这样的物体不能使用仅基于表面相互作用的模型来渲染。相反,我们需要考虑物体内部的变化特性才能正确地渲染它们。我们将这两种渲染模型称为表面渲染(即渲染物体的表面)和体积渲染(即渲染物体的表面和内部)。
一般来说,当我们使用表面渲染技术渲染一个物体时,我们会用表面描述(如点、线、三角形、多边形或2D和3D样条线)对物体进行数学建模。物体的内部没有被描述,或者只是从表面表示中隐含地表示(即表面是体积的边界)。尽管存在一些允许我们使表面透明或半透明的技术,仍然有许多现象不能仅通过表面渲染技术来模拟(例如散射或光的发射)。特别是当我们试图渲染物体内部的数据,如来自CT扫描的X射线强度时,情况尤其如此。
体积渲染技术允许我们看到物体内部的不均匀性。在先前的CT示例中,我们可以通过考虑数据的表面和内部的强度值来实现真实地再现X射线图像。虽然在本文的这一点上描述这个过程为时尚早,但你可以想象将我们在前一节中的光线追踪示例扩展。因此,光线不仅与物体的表面相互作用,还与内部相互作用。
在本章中,我们将重点介绍表面渲染技术。虽然没有体积渲染强大,但表面渲染被广泛使用,因为它相对于体积技术来说速度比较快,并且允许我们为各种数据和物体创建图像。第7章 - 高级计算机图形更详细地描述了体积渲染。
可视化而非图形学
尽管作者很乐意提供一份关于计算机图形的全面论述,但这样的讨论超出了本文的范围。相反,我们区分了可视化(探索、转换和映射数据)和计算机图形(映射和渲染)。重点将放在可视化的原则和实践上,而不是3D计算机图形。在本章和第7章 - 高级计算机图形中,我们介绍了基本概念,并提供了对3D计算机图形的实用知识。对于那些对这个领域更感兴趣的人,我们建议您参考本章末尾的“参考文献注”中推荐的书籍。
我们对这种立场的一个遗憾是,某些渲染技术本质上是可视化技术。我们在前一段中可以看到这一点的暗示,那里我们使用“映射”这个术语来描述可视化和计算机图形。目前并且很可能永远不会有一个明确的可视化和图形之间的界限。例如,许多研究人员认为体积渲染完全属于可视化领域,因为它涉及到了最重要的可视化数据形式之一。我们的区分主要是为了我们自己的方便,并为我们提供了完成本文的机会。我们建议认真学习可视化的学生用更深入的计算机图形和体积渲染书籍来补充本文提供的材料。
接下来的几页中,我们将更详细地描述渲染过程。我们首先描述了几种颜色模型。接下来,我们将检查渲染过程的主要组成部分。有光源,如太阳,我们希望渲染的物体,如立方体或球体(我们将这些物体称为演员),还有一个看向世界的摄像机。这些术语来自电影行业,大多数人都比较熟悉。演员代表图形数据或物体,光源照亮演员,摄像机通过将演员投影到视图平面上构建图像。我们将光源、摄像机和演员的组合称为场景,并将渲染过程称为渲染场景。
对于人类可见的电磁波谱,包含了从大约400到700纳米的波长。进入我们眼睛的光由这些波长的不同强度组成,如图3-2所示的一个例子。这种强度图定义了光的颜色,因此不同的图导致了不同的颜色。不幸的是,我们可能察觉不到这种差异,因为人眼会丢弃大部分这些信息。人眼中有三种颜色感受器,称为锥体。每种类型对应400到700纳米波长范围的一个子集,如图3-3所示。我们看到的任何颜色都被我们的眼睛编码为这三种重叠的响应。这是从实际进入我们眼睛的信息量大大减少。结果,人眼无法识别出任何颜色的不同,其响应曲线应用于人眼响应曲线时,产生相同的三重响应。这也意味着我们可以使用简化形式在计算机中存储和表示颜色,而人眼无法识别出其中的差异。
我们用来描述颜色的两个简化的组件系统是RGB和HSV颜色系统。RGB系统根据红、绿和蓝的强度表示颜色。这可以被认为是一个三维空间,其轴是红、绿和蓝。一些常见的颜色及其RGB分量如图3-4所示。
HSV系统根据色调、饱和度和亮度表示颜色。亮度分量也称为亮度或强度分量,表示颜色中有多少光。0.0的值将始终给你黑色,而1.0的值将给你一些明亮的东西。色调表示颜色的主导波长,并且通常使用一个圆圈来进行说明,如图3-5所示。这个圆圈上的每个位置表示一个不同的色调,可以使用一个角度来指定。当我们指定一个色调时,我们使用从零到一的范围,其中零对应于色调圈上的零度,而一对应于360度。饱和度表示色调在颜色中的混合程度。例如,我们可以将值设置为1,这将给我们一个明亮的颜色,将色调设置为0.66,这将给我们一个主导波长为蓝色的颜色。现在,如果我们将饱和度设置为1,颜色将是一个明亮的原色蓝。如果我们将饱和度设置为0.5,颜色将是天蓝色,一种混入更多白色的蓝色。如果我们将饱和度设置为零,这表示颜色中没有主导波长(色调)比其他波长多。结果,最终颜色将是白色(无论色调值如何)。图3-4列出了一些常见颜色的HSV值。
Color |
RGB |
HSV |
---|---|---|
Black |
0,0,0 |
,,0 |
White |
1,1,1 |
*,0,1 |
Red |
1,0,0 |
0,1,1 |
Green |
0,1,0 |
1/3,1,1 |
Blue |
0,0,1 |
2/3,1,1 |
Yellow |
1,1,0 |
1/6,1,1 |
Cyan |
0,1,1 |
1/2,1,1 |
Magenta |
1,0,1 |
5/6,1,1 |
Sky Blue |
1/2,1/2,1 |
2/3,1/2,1 |
控制渲染过程的重要因素之一是光与场景中的角色的相互作用。如果没有灯光,最终的图像将是黑色且缺乏信息。在很大程度上,发射光线与场景中角色的表面(有时还包括内部)的相互作用定义了我们所看到的东西。一旦光线与场景中的角色相互作用,我们就有了相机可以观看的东西。
在计算机图形中使用的许多不同类型的灯光中,我们将讨论最简单的一种,即无限远的点光源。与我们在家里和工作中使用的灯光相比,这是一个简化的模型。我们习惯使用的灯光通常是从空间中的一个区域辐射出来的(白炽灯泡中的灯丝,或者荧光灯中的发光气体)。点光源照明模型假定光是从空间中的一个点向所有方向发射的。对于无限远的光源,我们假设它位于被照亮的物体的无限远处。这是很重要的,因为这意味着来自这样一个光源的入射光线将彼此平行。而本地光源(例如房间中的灯)的发射光线则不是平行的。图3-6说明了有限体积的本地光源与无限点光源之间的差异。我们的无限光源发出的光的强度在传播过程中也保持恒定,与物理光实际上遵循的1/距离平方关系形成对比。正如你所看到的,这是一个很大的简化,这将使我们能够使用更简单的光照方程。