1 Introduction  介绍

目录

1  Introduction  介绍

1.1 Graphics Areas  图形学领域

1.2 Major Applications  主要应用

1.3 Graphics APIs  图形API

1.4 Graphics Pipeline  图形管线

1.5 Numerical Issues  数值问题

1.6 Efficiency  效率


1  Introduction  介绍

The term computer graphics describes any use of computers to create and manipulate images. This book introduces the algorithmic and mathematical tools that can be used to create all kinds of images—realistic visual effects, informative technical illustrations, or beautiful computer animations. Graphics can be two- or three-dimensional; images can be completely synthetic or can be produced by manipulating photographs. This book is about the fundamental algorithms and mathematics, especially those used to produce synthetic images of three-dimensional objects and scenes.

计算机图形学”描述了使用计算机创建和处理图像的任何方式。本书介绍了算法和数学工具,它们可以用于创建各种图像逼真的视觉效果、信息技术插图,和美丽的计算机动画。图形可以是二维或三维;图像可以完全是合成的(虚拟的),也可以通过处理照片来生成。这本书是关于基本的算法和数学的,尤其是那些用来产生三维物体、三维场景的虚拟图像的部分。

Actually doing computer graphics inevitably requires knowing about specific hardware, file formats, and usually a graphics API (see Section 1.3) or two. Computer graphics is a rapidly evolving field, so the specifics of that knowledge are a moving target. Therefore, in this book we do our best to avoid depending on any specific hardware or API. Readers are encouraged to supplement the text with relevant documentation for their software and hardware environment. Fortunately, the culture of computer graphics has enough standard terminology and concepts that the discussion in this book should map nicely to most environments.

API: application program interface.

实际上,计算机图形学不可避免地需要了解特定的硬件、文件格式,以及通常还需要了解一两种图形API(参阅第1.3节)。计算机图形学是一个快速发展的领域,所以,知识的具体细节总是在不断变化。因此,在本书中,我们尽量避免依赖特定的硬件或API。鼓励读者就自己使用的软件和硬件环境进行补充。幸运的是,计算机图形学具有足够的标准术语和概念,因此本书中的内容可以适用于大多数情况。

API:应用程序接口 

This chapter defines some basic terminology and provides some historical background, as well as information sources related to computer graphics.

本章定义了一些基本术语,提供了一些历史背景,以及与计算机图形学相关的信息来源。

1.1 Graphics Areas  图形学领域

Imposing categories on any field is dangerous, but most graphics practitioners would agree on the following major areas of computer graphics:

在任何领域,强加类别都是危险的,但是大多数图形学从业者会同意以下计算机图形学的主要领域:

  • Modeling deals with the mathematical specification of shape and appearance properties in a way that can be stored on the computer. For example, a coffee mug might be described as a set of ordered 3D points along with some interpolation rule to connect the points and a reflection model that describes how light interacts with the mug.

建模:使用数学规格进行建模,这些数据是能存储在计算机上的形状和外观属性。例如,一个咖啡杯可以被描述为一组有序的3D点,加上连接这些点的一些插值规则,以及反射模型,该模型描述了光线如何照射在杯子上。

  • Rendering is a term inherited from art and deals with the creation of shaded images from 3D computer models.

渲染:这个术语是从艺术领域借来的,用于生成3D模型的渲染后的图像。

  • Animation is a technique to create an illusion of motion through sequences of images. Animation uses modeling and rendering but adds the key issue of movement over time, which is not usually dealt with in basic modeling and rendering.

动画:是一种通过图像序列创建运动幻觉的技术。动画用到了建模和渲染,但还添加了“随时间推移的运动”的关键问题,这个问题在基本的建模和渲染中并不常见。

There are many other areas that involve computer graphics, and whether they are core graphics areas is a matter of opinion. These will all be at least touched on in the text. Such related areas include the following:

还有许多其他涉及计算机图形学的领域,“它们是否属于核心的图形学领域?”这个问题并没有定论,要看个人的观点。这些内容在本教材中至少会触及一点点。包括以下内容:

  • User interaction deals with the interface between input devices such as mice and tablets, the application, feedback to the user in imagery, and other sensory feedback. Historically, this area is associated with graphics largely because graphics researchers had some of the earliest access to the input/output devices that are now ubiquitous.

用户交互:它处理这些东西之间的接口问题:输入设备(比如鼠标和数位板),应用程序,给用户的图像反馈,以及其他感官反馈。从历史上看,这方面与图形学相关联主要是因为,图形学研究人员是最早接触现在普遍存在的输入/输出设备的人。

  • Virtual reality attempts to immerse the user into a 3D virtual world. This typically requires at least stereo graphics and response to head motion. For true virtual reality, sound and force feedback should be provided as well. Because this area requires advanced 3D graphics and advanced display technology, it is often closely associated with graphics.

虚拟现实:它试图将用户沉浸在3D虚拟世界中。这通常至少需要立体图形,以及对头部运动的响应(因为头上戴着机器吧)。为了获得逼真的虚拟现实,还要有声音和力的反馈。由于这个方面需要先进的3D图形和先进的显示技术,因此通常与图形学密切相关。

  • Visualization attempts to give users insight into complex information via visual display. Often there are graphic issues to be addressed in a visualization problem.

可视化:它用可视的画面,向用户展示复杂的信息。通常,在可视化问题中存在图形学问题。

  • Image processing deals with the manipulation of 2D images and is used in both the fields of graphics and vision.

图像处理:它负责处理2D图像的操纵,在图形学和视觉领域都有用到。

  • 3D scanning uses range-finding technology to create measured 3D models. Such models are useful for creating rich visual imagery, and the processing of such models often requires graphics algorithms.

3D扫描:它使用测距技术,创建测量的3D模型。此类模型在创建丰富的视觉图像上很有用,而且处理这些模型通常要用到图形学算法。

  • Computational photography is the use of computer graphics, computer vision, and image processing methods to enable new ways of photographically capturing objects, scenes, and environments.

计算机摄影:它使用计算机图形学、计算机视觉和图像处理方法来实现新的摄影方式,捕捉对象、场景和环境。

1.2 Major Applications  主要应用

Almost any endeavor can make some use of computer graphics, but the major consumers of computer graphics technology include the following industries:

几乎所有的领域都可以用到计算机图形学,但是计算机图形学技术的主要使用者包括以下行业:

  • Video games increasingly use sophisticated 3D models and rendering algorithms.

电子游戏越来越多地使用复杂的3D模型和渲染算法。

  • Cartoons are often rendered directly from 3D models. Many traditional 2D cartoons use backgrounds rendered from 3D models, which allow a continuously moving viewpoint without huge amounts of artist time.

动画片通常直接由3D模型渲染而成。许多传统的2D卡通都使用由3D模型渲染的背景,从而可以连续不断地移动视点,且无需花费大量艺术家的时间。

  • Visual effects use almost all types of computer graphics technology. Almost every modern film uses digital compositing to superimpose backgrounds with separately filmed foregrounds. Many films also use 3D modeling and animation to create synthetic environments, objects, and even characters that most viewers will never suspect are not real.

视觉效果(视效,VFX)几乎用到了所有类型的计算机图形技术。几乎每部现代电影都使用数字合成技术,将背景与单独拍摄的前景叠加在一起。许多电影还使用3D建模和动画来创建合成环境、对象,甚至大多数观众永远信以为真的角色。

  • Animated films use many of the same techniques that are used for visual effects, but without necessarily aiming for images that look real.

动画电影使用了许多与视觉效果相同的技术,但不一定需要图像看起来很逼真。

  • CAD/CAM stands for computer-aided design and computer-aided manufacturing. These fields use computer technology to design parts and products on the computer and then, using these virtual designs, to guide the manufacturing process. For example, many mechanical parts are designed in a 3D computer modeling package and then automatically produced on a computer-controlled milling device.

CAD / CAM代表计算机辅助设计和计算机辅助制造。这些领域使用计算机技术,在计算机上设计零件和产品,然后使用这些虚拟设计来指导制造过程。例如,许多机械零件是在3D计算机建模包中设计的,然后在计算机控制的铣(xi三声)削设备上自动生产。

  • Simulation can be thought of as accurate video gaming. For example, a flight simulator uses sophisticated 3D graphics to simulate the experience of flying an airplane. Such simulations can be extremely useful for initial training in safety-critical domains such as driving, and for scenario training for experienced users such as specific fire-fighting situations that are too costly or dangerous to create physically.

模拟可以说是精密的视频游戏。例如,飞行模拟器使用复杂的3D图形来模拟开飞机。这样的模拟对于安全很重要的领域的前期培训(如驾驶)、以及对培养有经验的用户的场景培训非常有用(比如过于昂贵、危险的消防场景)。

  • Medical imaging creates meaningful images of scanned patient data. For example, a computed tomography (CT) dataset is composed of a large 3D rectangular array of density values. Computer graphics is used to create shaded images that help doctors extract the most salient information from such data.

医学成像为扫描所得的患者数据创建含义丰富的图像。例如,计算机断层扫描(CT)数据集是由密度值的大型3D矩阵组成的。计算机图形学用于创建渲染后的图像,帮助医生提取出最重要的信息。

  • Information visualization creates images of data that do not necessarily have a “natural” visual depiction. For example, the temporal trend of the price of ten different stocks does not have an obvious visual depiction, but clever graphing techniques can help humans see the patterns in such data.

信息可视化:它创建数据的图像,这些数据不一定自身具有可视性。例如,十种不同股票的价格的变化趋势自身并不是视觉上的图像,但是巧妙的绘图技术可以帮助人们看见其中的规律。

1.3 Graphics APIs  图形API

A key part of using graphics libraries is dealing with a graphics API. An application program interface (API) is a standard collection of functions to perform a set of related operations, and a graphics API is a set of functions that perform basic operations such as drawing images and 3D surfaces into windows on the screen.

使用图形库的关键是使用图形API。应用程序接口(API)是执行一组相关操作的标准函数集合,而图形API是执行将图像和3D表面绘制到屏幕上的窗口之类的基本操作的一组函数。

Every graphics program needs to be able to use two related APIs: a graphics API for visual output and a user-interface API to get input from the user. There are currently two dominant paradigms for graphics and user-interface APIs. The first is the integrated approach, exemplified by Java, where the graphics and user-interface toolkits are integrated and portable packages that are fully standardized and supported as part of the language. The second is represented by Direct3D and OpenGL, where the drawing commands are part of a software library tied to a language such as C++, and the user-interface software is an independent entity that might vary from system to system. In this latter approach, it is problematic to write portable code, although for simple programs it may be possible to use a portable library layer to encapsulate the system specific user-interface code.

每个图形程序都必须能够使用两个相关的API:用于视觉输出的图形API和用于输入的用户界面API。当前,图形和用户界面API有两种主要的典型。第一种是集成方法,以Java为例,其中图形和用户界面工具包是集成的和可移植的程序包,这些程序包已完全标准化并成为语言的一部分。第二种以Direct3DOpenGL为代表的,其中绘图命令是与语言绑定的软件库的一部分(比如C++),并且用户界面软件是一个独立的实体,可能因系统而异。在后一种方法中,编写可移植代码很麻烦,对于简单的程序,也许可以使用可移植库层来封装系统特定的用户界面代码。

Whatever your choice of API, the basic graphics calls will be largely the same, and the concepts of this book will apply.

无论你选择哪种API,基本的图形调用都基本相同,本书的概念也都适用。

1.4 Graphics Pipeline  图形管线

Every desktop computer today has a powerful 3D graphics pipeline. This is a special software/hardware subsystem that efficiently draws 3D primitives in perspective. Usually these systems are optimized for processing 3D triangles with shared vertices. The basic operations in the pipeline map the 3D vertex locations to 2D screen positions and shade the triangles so that they both look realistic and appear in proper back-to-front order.

如今,每台台式计算机都具有强大的3D图形管线。这是一个特殊的软件/硬件子系统,可以有效地绘制3D图元的透视图(图元:拼成整个模型的小三角形或方形)。通常,这些系统经过优化,以处理具有共享顶点的3D三角形(模型是很多很多小三角形连接起来构成的)。流水线中的基本操作将3D顶点位置映射到2D屏幕的位置,并对三角形进行渲染,以使它们看起来很逼真,并以适当的前后顺序显示。

Although drawing the triangles in valid back-to-front order was once the most important research issue in computer graphics, it is now almost always solved using the z-buffer, which uses a special memory buffer to solve the problem in a brute-force manner.

尽管以有效的、从后往前的顺序绘制三角形曾经是计算机图形学中最重要的研究问题,但现在几乎总是使用z缓冲区解决这个问题,z缓冲区使用特殊的内存缓冲区,以蛮力解决该问题。

It turns out that the geometric manipulation used in the graphics pipeline can be accomplished almost entirely in a 4D coordinate space composed of three traditional geometric coordinates and a fourth homogeneous coordinate that helps with perspective viewing. These 4D coordinates are manipulated using 4 × 4 matrices and 4-vectors. The graphics pipeline, therefore, contains much machinery for efficiently processing and composing such matrices and vectors. This 4D coordinate system is one of the most subtle and beautiful constructs used in computer science, and it is certainly the biggest intellectual hurdle to jump when learning computer graphics. A big chunk of the first part of every graphics book deals with these coordinates.

事实证明,图形流水线中使用的几何操作几乎可以全部在一个4D坐标空间中完成,该空间由三个传统的几何坐标和一个有助于显示透视的第四个齐次坐标组成。这些4D坐标是使用4×4矩阵和4维向量处理的。因此,图形流水线包含许多机制,可以高效地处理和合成这样的矩阵和向量。这种4D坐标系是计算机科学中使用的最微妙,最精美的结构之一,而且无疑是学习计算机图形学时需要翻过的最大障碍。每本图形学书的第一部分的绝大部分都在与这些坐标打交道。

The speed at which images can be generated depends strongly on the number of triangles being drawn. Because interactivity is more important in many applications than visual quality, it is worthwhile to minimize the number of triangles used to represent a model. In addition, if the model is viewed in the distance, fewer triangles are needed than when the model is viewed from a closer distance. This suggests that it is useful to represent a model with a varying level of detail (LOD).

生成图像的速度在很大程度上取决于所绘制的三角形的数量。由于交互性在许多应用程序中比视觉质量更重要,因此有必要将用于表示模型的三角形的数量最小化。另外,如果在远处观看模型,则与从近处观看模型时相比,需要的三角形更少。这表明变化的细致程度LOD表示模型很有用。

1.5 Numerical Issues  数值问题

Many graphics programs are really just 3D numerical codes. Numerical issues are often crucial in such programs. In the “old days,” it was very difficult to handle such issues in a robust and portable manner because machines had different internal representations for numbers, and even worse, handled exceptions in different and incompatible ways. Fortunately, almost all modern computers conform to the IEEE floating-point standard (IEEE Standards Association, 1985). This allows the programmer to make many convenient assumptions about how certain numeric conditions will be handled.

许多图形程序实际上只是3D数字代码。在此类程序中,数字问题通常至关重要。在过去,以健壮和可移植的方式处理此类问题非常困难,因为机器内部的数字表示方式不同,甚至以不同且不兼容的方式处理异常。幸运的是,几乎所有现代计算机都符合IEEE浮点标准(IEEE标准协会,1985)。这方便了程序员对如何处理某些特定数值作出判断。

Although IEEE floating-point has many features that are valuable when coding numeric algorithms, there are only a few that are crucial to know for most situations encountered in graphics. First, and most important, is to understand that there are three “special” values for real numbers in IEEE floating-point:

尽管IEEE浮点的许多功能在编写数字算法时非常有用,但对于图形学中的大多数情况,只有少数几个最关键的点。首先,也是最重要的一点,就是要IEEE浮点中的实数有三个“特殊”值:

  1. Infinity (∞). This is a valid number that is larger than all other valid numbers.
  2. Minus infinity (−∞). This is a valid number that is smaller than all other valid numbers.
  3. Not a number (NaN). This is an invalid number that arises from an operation with undefined consequences, such as zero divided by zero.

1.无穷大(∞)。这是一个有效数字,大于所有其他有效数字。

2.负无穷大(-∞)。这是一个有效数字,小于所有其他有效数字。

3.不是数字(NaN)。这是一个无效的数字,它产生于结果无定义的操作,比如零除以零。

 

IEEE floating-point has two representations for zero, one that is treated as positive and one that is treated as negative. The distinction between −0 and +0 only occasionally matters, but it is worth keeping in mind for those occasions when it does.

IEEE浮点有两种表示形式的零,正零和负零。 −0+0之间的区别只偶尔起作用,但那些情况值得牢记。{by计算机组成原理:IEEE 754浮点数由数符S、阶符、阶码E、尾数M构成,E=0M=0时为真值0,此时S可以为正或负,所以有正负零之分(?)}

The designers of IEEE floating-point made some decisions that are extremely convenient for programmers. Many of these relate to the three special values above in handling exceptions such as division by zero. In these cases an exception is logged, but in many cases the programmer can ignore that. Specifically, for any positive real number a, the following rules involving division by infinite values hold:

IEEE浮点的设计人员做出了一些决定,这些决定对于程序员来说非常方便。在处理异常(例如除以0)时,许多处理方式与上述三个特殊值有关。在这些情况下,异常会被计算机记录下来,但在许多情况下,程序员可以忽略该异常。具体来说,对于任何正实数a,涉及无穷大除法的规则是这样的:

+a/(+)=+0,

a/(+)=−0,

+a/(−)=−0,

a/(−)=+0.

Other operations involving infinite values behave the way one would expect. Again for positive a, the behavior is as follows:

其他涉及无限值的运算的行为与人们一般想的一样,对于正数a,是这样的:

+=+

=NaN

×=

/=NaN

/a=

/0=

0/0=NaN.

The rules in a Boolean expression involving infinite values are as expected:

布尔表达式中涉及无限值的规则符合人们一般所想:

  1. All finite valid numbers are less than +∞.
  2. All finite valid numbers are greater than −∞.
  3. −∞ is less than +∞.

1.所有有限有效数均小于+∞。

2.所有有限有效数均大于-∞。

3.-∞小于+∞

The rules involving expressions that have NaN values are simple:

涉及NaN的规则很简单:

  1. Any arithmetic expression that includes NaN results in NaN.
  2. Any Boolean expression involving NaN is false.

1.任何包含NaN的算术表达式结果都是NaN

2.任何涉及NaN的布尔表达式都是false

Perhaps the most useful aspect of IEEE floating-point is how divide-by-zero is handled; for any positive real number a, the following rules involving division by zero values hold:

IEEE浮点数最有用的方面可能是如何处理零除;对于任意正实数a,除以零的规则是这样的:

+a/+0=+,

a/+0=−.

Some care must be taken if negative zero (−0) might arise.

如果可能出现负零(−0),必须格外小心。(?)

There are many numeric computations that become much simpler if the programmer takes advantage of the IEEE rules. For example, consider the expression:

如果程序员用好IEEE规则,那么许多数值计算会变得更简单。比如,对于以下表达式:

Such expressions arise with resistors and lenses. If divide-by-zero resulted in a program crash (as was true in many systems before IEEE floating-point), then two if statements would be required to check for small or zero values of b or c. Instead, with IEEE floating-point, if b or c is zero, we will get a zero value for a as desired. Another common technique to avoid special checks is to take advantage of the Boolean properties of NaN. Consider the following code segment:

这样的表达会出现在电阻和透镜情形中(电阻并联;透镜?)。如果除以零将导致程序崩溃(在IEEE浮点数出现之前,许多系统中都会这样),则将需要两个if语句来检查bc是否为很小的值或零值。而现在有了IEEE浮点数,如果bc为零,我们则将根据需要将a赋值为零。避免特殊情况检查的另一种常用技术是利用NaN的布尔属性。考虑以下代码段:

a = f(x)
if (a > 0) then
do something

Here, the function f may return “ugly” values such as ∞ or NaN, but the if condition is still well-defined: it is false for a = NaN or a = −∞ and true for a = +∞. With care in deciding which values are returned, often the if can make the right choice, with no special checks needed. This makes programs smaller, more robust, and more efficient.

在这里,函数f可能会返回很不想看到的值,例如∞或NaN,但是if语句的条件是明确的:a = NaNa =-∞时为falsea < 0),而a = +∞时为truea > 0)。在确定返回什么值时,if语句通常可以做出正确的选择,无需进行特殊检查。这使程序更小,更可靠和更高效。

1.6 Efficiency  效率

There are no magic rules for making code more efficient. Efficiency is achieved through careful tradeoffs, and these tradeoffs are different for different architectures. However, for the foreseeable future, a good heuristic is that programmers should pay more attention to memory access patterns than to operation counts. This is the opposite of the best heuristic of two decades ago. This switch has occurred because the speed of memory has not kept pace with the speed of processors. Since that trend continues, the importance of limited and coherent memory access for optimization should only increase.

没有使代码更高效的魔法。效率是通过仔细的权衡得到的,这些权衡对于不同的体系结构是不同的。但是,在可预见的将来,一个很好的启发是程序员应该更多地注意内存访问模式,而不是操作次数(访问内存很耗时间,所以要注意减少访存)。这与二十年前的最佳想法相反。之所以发生这种变化,是因为内存的速度无法跟上处理器的速度。由于这种趋势继续存在,因此有限的、一致的内存访问对于优化的重要性只增不减。

A reasonable approach to making code fast is to proceed in the following order, taking only those steps which are needed:

  1. Write the code in the most straightforward way possible. Compute intermediate results as needed on the fly rather than storing them.
  2. Compile in optimized mode.
  3. Use whatever profiling tools exist to find critical bottlenecks.
  4. Examine data structures to look for ways to improve locality. If possible, make data unit sizes match the cache/page size on the target architecture.
  5. If profiling reveals bottlenecks in numeric computations, examine the assembly code generated by the compiler for missed efficiencies. Rewrite source code to solve any problems you find.

一种使代码运行得很快的合理方法是按照以下顺序进行,只用采取所需的步骤:

1.以尽可能直接的方式编写代码。根据需要实时计算中间结果,不存储它们。

2.以优化模式进行编译。

3.使用现有的任何分析工具来查找关键瓶颈。(?)

4.检查数据结构以改善局部性。最好使数据单元的大小与目标系统上的缓存/页面大小一致。

by操作系统:页面是计算机调用数据的单位,按整页存储数据的话,调用起来会快一些)

5.如果分析揭示了数值计算中的瓶颈,则检查编译器生成的汇编代码是否效率低下。重写源代码以解决问题。

The most important of these steps is the first one. Most “optimizations” make the code harder to read without speeding things up. In addition, time spent upfront optimizing code is usually better spent correcting bugs or adding features. Also, beware of suggestions from old texts; some classic tricks such as using integers instead of reals may no longer yield speed because modern CPUs can usually perform floating-point operations just as fast as they perform integer operations. In all situations, profiling is needed to be sure of the merit of any optimization for a specific machine and compiler.

最重要的是第一个步骤。大多数“优化”不仅让代码变得很难读懂,而且还并没有做到加速。还有,与其花时间在前期优化代码,不如在纠正bug和添加功能上花时间。另外,要小心旧教材的建议;一些经典技巧,例如把实数换成整数,可能不再提高速度,因为现代CPU执行浮点运算的速度数运算一样快。在所有情况下,都需要进行简要分析,确保对机器和编译器进行的任何优化是有价值的。

1.7 Designing and Coding Graphics Programs  设计、编写图形程序

Certain common strategies are often useful in graphics programming. In this section we provide some advice that you may find helpful as you implement the methods you learn about in this book.

某些通用方法在图形编程中很有用。在本节中,我们提一些在你学习本书时有所帮助的建议。

I believe strongly in the KISS (“keep it simple, stupid”) principle, and in that light the argument for two classes is not compelling enough to justify the added complexity.

—P.S.

我坚信KISS(“保持简单和笨”)原则,所以即使花费两堂课时间为增加复杂性争辩也不管用。

1.7.1 Class Design  类的设计

A key part of any graphics program is to have good classes or routines for geometric entities such as vectors and matrices, as well as graphics entities such as RGB colors and images. These routines should be made as clean and efficient as possible. A universal design question is whether locations and displacements should be separate classes because they have different operations, e.g., a location multiplied by one-half makes no geometric sense while one-half of a displacement does (Goldman, 1985; DeRose, 1989). There is little agreement on this question, which can spur hours of heated debate among graphics practitioners, but for the sake of example let’s assume we will not make the distinction.

图形程序的关键部分是,为几何实体(例如矢量和矩阵)以及图形实体(例如RGB颜色和图像)提供良好的类和例程。这些例程要尽可能干净有效。一个通用的设计问题是位置和位移要不要归为不同的类,因为它们具有不同的运算,例如,位置乘以二分之一没有几何意义,而位移的二分之一有。在这个问题上几乎没有共识,可能会激起图形从业者数小时的激烈辩论,但是为了举例说明,我们假设不对此加以区分。

I like keeping points and vectors separate because it makes code more readable and can let the compiler catch some bugs.

我喜欢将点和向量分开,因为这样可以使代码更具可读性,并且可以让编译器捕捉到bug

—S.M.

This implies that some basic classes to be written include:

这意味着要编写的基本类有:

  • vector2. A 2D vector class that stores an x- and y-component. It should store these components in a length-2 array so that an indexing operator can be well supported. You should also include operations for vector addition, vector subtraction, dot product, cross product, scalar multiplication, and scalar division.

vector2:存储xy分量的2D向量类。xy分量存储在长度为2的数组中,这样就可以很好地支持索引运算符([])。你还应该包括向量加法,向量减法,点积,叉积,标量乘法和标量除法的运算。

  • vector3. A 3D vector class analogous to vector2.

vector3:类似于vector23D向量类。

  • hvector. A homogeneous vector with four components (see Chapter 7).

hvector:具有四个分量的同构向量(齐次向量)(参见第7章)。

  • rgb. An RGB color that stores three components. You should also include operations for RGB addition, RGB subtraction, RGB multiplication, scalar multiplication, and scalar division.

rgb:存储三个分量的RGB颜色。你还应该包括RGB加法,RGB减法,RGB乘法,标量乘法和标量除法的操作。

  • transform. A 4 × 4 matrix for transformations. You should include a matrix multiply and member functions to apply to locations, directions, and surface normal vectors. As shown in Chapter 6, these are all different.

变换:用于变换的4×4矩阵。你应该包括一个矩阵乘法和成员函数,应用于位置,方向和表面法线向量。如第6章所示,它们都是不同的。

  • image. A 2D array of RGB pixels with an output operation.

图像:带有输出操作的RGB像素的2D数组。

In addition, you might or might not want to add classes for intervals, orthonormal bases, and coordinate frames.

还有,你可以选择为间隔、正交基准和坐标系添加类。

You might also consider a special class for unit-length vectors, although I have found them more pain than they are worth.

您可能还想到了用于单位矢量的特殊类,尽管它们很让人痛苦。

—P.S.

1.7.2 Float vs. Double

Modern architecture suggests that keeping memory use down and maintaining coherent memory access are the keys to efficiency. This suggests using single-precision data. However, avoiding numerical problems suggests using double-precision arithmetic. The tradeoffs depend on the program, but it is nice to have a default in your class definitions.

现代体系结构表明,减少内存使用、保持内存访问一致是提高效率的关键。这意味着使用单精度数据。但是,为了避免数值问题,建议使用双精度数据。这个是由程序权衡的,但是最好在类定义中使用默认值。

I suggest using doubles for geometric computation and floats for color computation. For data that occupies a lot of memory, such as triangle meshes, I suggest storing float data, but converting to double when data is accessed through member functions.

我建议使用double进行几何计算,使用float进行颜色计算。对于占用大量内存的数据(例如三角形网格),我建议使用float存储,但是用成员函数访问数据时转换为双精度。

—P.S.

1.7.3 Debugging Graphics Programs  调试图形程序

If you ask around, you may find that as programmers become more experienced, they use traditional debuggers less and less. One reason for this is that using such debuggers is more awkward for complex programs than for simple programs. Another reason is that the most difficult errors are conceptual ones where the wrong thing is being implemented, and it is easy to waste large amounts of time stepping through variable values without detecting such cases. We have found several debugging strategies to be particularly useful in graphics.

如果你四处询问,可能会发现,随着程序员越来越有经验,他们越来越少使用传统调试器。原因之一是,与简单程序相比,对于复杂程序而言,使用这种调试器很尴尬。另一个原因是,最困难的错误是,在概念的错误中执行了错误的操作,很容易浪费大量时间逐个查看变量,却不能检测到这种情况(?)。有几种调试策略在图形学中特别有用。

I advocate doing all computations with floats until you find evidence that double precision is needed in a particular part of the code.

我主张使用float浮点数进行所有计算,直到发现在代码的特定部分需要双精度double

—S.M.

The Scientific Method  科学的方法

In graphics programs there is an alternative to traditional debugging that is often very useful. The downside to it is that it is very similar to what computer programmers are taught not to do early in their careers, so you may feel “naughty” if you do it: we create an image and observe what is wrong with it. Then, we develop a hypothesis about what is causing the problem and test it. For example, in a ray-tracing program we might have many somewhat random looking dark pixels. This is the classic “shadow acne” problem that most people run into when they write a ray tracer. Traditional debugging is not helpful here; instead, we must realize that the shadow rays are hitting the surface being shaded. We might notice that the color of the dark spots is the ambient color, so the direct lighting is what is missing. Direct lighting can be turned off in shadow, so you might hypothesize that these points are incorrectly being tagged as in shadow when they are not. To test this hypothesis, we could turn off the shadowing check and recompile. This would indicate that these are false shadow tests, and we could continue our detective work. The key reason that this method can sometimes be good practice is that we never had to spot a false value or really determine our conceptual error. Instead, we just narrowed in on our conceptual error experimentally. Typically only a few trials are needed to track things down, and this type of debugging is enjoyable.

在图形程序中,有一种替代传统调试的方法,通常非常有用。缺点是,这与程序员在职业生涯早期不会去做的事情非常相似,所以,如果这样做,你可能会觉得很“调皮”:我们创建图像并观察错误之处。然后,我们对出错的原因进行假设,和测试。例如,在光线跟踪程序中,我们可能会有许多看起来是随机出现的暗像素。这是大多数人在编写光线追踪器时遇到的经典的“阴影痤疮”问题。传统的调试在这里没有帮助;取而代之的是,我们必须意识到阴影射线击中了正在着色的表面我们可能会注意到黑点的颜色是环境颜色,因此缺少的是直接照明。可以在阴影中关闭直接照明,所以你可能假设这些点被错误地标记为“在阴影中”,但实际上它们不是阴影。为了检验这个假设,我们可以关闭阴影检查,重新编译。这将表明这是错误的阴影测试,我们可以继续进行检测工作。这种方法有时候是良好的实践,因为我们不必发现错误的值或真正确定概念错误。相反,我们只是通过试验缩小了我们的概念误差。通常只需要进行几次试验就可以找到问题所在,并且这种调试很有意思。

Images as Coded Debugging Output  调试代码输出的图像

In many cases, the easiest channel by which to get debugging information out of a graphics program is the output image itself. If you want to know the value of some variable for part of a computation that runs for every pixel, you can just modify your program temporarily to copy that value directly to the output image and skip the rest of the calculations that would normally be done. For instance, if you suspect a problem with surface normals is causing a problem with shading, you can copy the normal vectors directly to the image (x goes to red, y goes to green, z goes to blue), resulting in a color-coded illustration of the vectors actually being used in your computation. Or, if you suspect a particular value is sometimes out of its valid range, make your program write bright red pixels where that happens. Other common tricks include drawing the back sides of surfaces with an obvious color (when they are not supposed to be visible), coloring the image by the ID numbers of the objects, or coloring pixels by the amount of work they took to compute.

很多时候,从图形程序中获取调试信息的最简单渠道就是输出的图像本身。如果你想知道每个像素运行的计算中某个变量的值,你可以临时修改程序,将这些变量值直接复制到输出图像,跳过其余计算。例如,如果您觉得表面法线导致了渲染问题,你可以将法线向量直接复制到图像(x变为红色,y变为绿色,z变为蓝色),得到标明了色码的图片,这个图片代表了你的计算过程中的实际向量。或者,如果你怀疑某个值有时候会超出有效范围,可以使程序在这种情况发现的地方画出亮红色像素。其他常见的技巧包括用明显的颜色绘制表面的背面(在背面不应该被看到的情况下),根据对象的ID为图像着色,或根据计算工作量为像素着色。

Using a Debugger  使用调试器

There are still cases, particularly when the scientific method seems to have led to a contradiction, when there’s no substitute for observing exactly what is going on. The trouble is that graphics programs often involve many, many executions of the same code (once per pixel, for instance, or once per triangle), making it completely impractical to step through in the debugger from the start. And the most difficult bugs usually only occur for complicated inputs.

还是有某些情况下,特别是当科学方法好像会导致矛盾时,没有其他方法可以准确地观察正在发生的事情。问题在于,图形程序通常会执行许多相同的代码(例如,每个像素一次,或者每个三角形一次),所以一开始就进入调试器是不现实的。最困难的bug一般只发生在复杂的输入中。

A useful approach is to “set a trap” for the bug. First, make sure your program is deterministic—run it in a single thread and make sure that all random numbers are computed from fixed seeds. Then, find out which pixel or triangle is exhibiting the bug and add a statement before the code you suspect is incorrect that will be executed only for the suspect case. For instance, if you find that pixel (126, 247) exhibits the bug, then add:

一种有用的方法是bug“设置陷阱”。首先,确保您的程序是确定性的——在单线程中运行它,并确保所有随机数都是从固定种子中计算出来的。然后,找出哪个像素或三角形出现了bug,并在您觉得写错的代码前面添加一条语句,该语句仅在可疑情况下才会执行。例如,如果您发现像素(126247)出现错误,就添加:

if x = 126 and y = 247 then
print “blarg!”

A special debugging mode that uses fixed random-number seeds is useful.

使用固定的随机数种子的特殊调试模式很有用。

If you set a breakpoint on the print statement, you can drop into the debugger just before the pixel you’re interested in is computed. Some debuggers have a “conditional breakpoint” feature that can achieve the same thing without modifying the code.

如果你在print语句上设置了断点,你可以在计算您感兴趣的像素之前进入调试器。一些调试器具有“条件断点”功能,可以在不修改代码的情况下达到相同的效果。

In the cases where the program crashes, a traditional debugger is useful for pinpointing the site of the crash. You should then start backtracking in the program, using asserts and recompiles, to find where the program went wrong. These asserts should be left in the program for potential future bugs you will add. This again means the traditional step-through process is avoided, because that would not be adding the valuable asserts to your program.

在程序崩溃的情况下,传统的调试器对于查明崩溃的位置很有用。然后,您应该使用断言和重新编译在程序中开始回溯,以查找程序出了问题的地方。这些断言应留在程序中,以备将来可能添加的错误。这再次意味着避免了传统的逐步过程,因为那样就不会在程序中添加有价值的断言。

Data Visualization for Debugging  数据可视化以进行调试

Often it is hard to understand what your program is doing, because it computes a lot of intermediate results before it finally goes wrong. The situation is similar to a scientific experiment that measures a lot of data, and one solution is the same: make good plots and illustrations for yourself to understand what the data means. For instance, in a ray tracer you might write code to visualize ray trees so you can see what paths contributed to a pixel, or in an image resampling routine you might make plots that show all the points where samples are being taken from the input. Time spent writing code to visualize your program’s internal state is also repaid in a better understanding of its behavior when it comes time to optimize it.

一般来说,很难理解你的程序在做什么,因为它会在最终出错之前会计算出许多中间结果。这种情况类似于测量大量数据的科学实验,它们的解决方案是相同的:为自己做好设计方案和图解,以了解数据的含义。例如,在光线跟踪器中,你可能会编写代码以可视化光线树,以便可以看到对像素有作用的路径,或者在图像重采样例程中,你可能绘图,来显示从输入中采样的所有点。为可视化程序的内部状态所花费的时间,会得到回报,因为在优化时,能够更好地理解程序的行为。

I like to format debugging print statements so that the output happens to be a Matlab or Gnuplot script that makes a helpful plot.

我喜欢格式化调试输出语句,这样的话输出的MatlabGnuplot脚本会显示很有用的图像。

—S.M.

Notes  笔记

The discussion of software engineering is influenced by the Effective C++ series (Meyers, 1995, 1997), the Extreme Programming movement (Beck & Andres, 2004), and The Practice of Programming (Kernighan & Pike, 1999). The discussion of experimental debugging is based on discussions with Steve Parker.

关于软件工程的讨论受到了《Effective C++》系列,“the Extreme Programming运动和《The Practice of Programming的影响。关于调试的讨论基于与Steve Parker的讨论。

There are a number of annual conferences related to computer graphics, including ACM SIGGRAPH and SIGGRAPH Asia, Graphics Interface, the Game Developers Conference (GDC), Eurographics, Pacific Graphics, High Performance Graphics, the Eurographics Symposium on Rendering, and IEEE VisWeek. These can be readily found by web searches on their names.

有许多与计算机图形学有关的年度会议,包括ACM SIGGRAPHSIGGRAPH AsiaGraphics Interface游戏开发者大会(GDC,欧洲图形学会,太平洋图形学会,高性能图形学会,欧洲图形学渲染研讨会和IEEE VisWeek。在网上搜名称很容易找到它们。

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值