什么是 Cg

  本书将教你如何使用一种叫 Cg 的编程语言。Cg 语言使得控制使用可编程图形硬件画的物体的形状、外观和运动成为了可能。它把这些属性的可编程控制和当今难以置信的高速度和高性能图形处理器很好的结合在一起。在此之前从来没有计算机图形从业者,无论是美工人员还是程序员,在他们生成自己的实时图像的时候有如此多的控制能力。

  Cg 为开发人员提供了一整套使用方便的编程平台,使得迅速生成特殊的效果和在多种平台上体验实时电影效果成为可能。通过提供一个新的抽象层,Cg 使开发人员不需要再直接使用图形硬件汇编语言,因此非常适合 OpenGL、DirectX、Windwos、Linux、Macintosh OS X 和游戏平台,例如 Xbox。Cg 是在和 Microsoft 公司密切合作的情况下开发的,因此 Cg 与 OpenGL API 和 Microsoft 的 DirectX9.0 高级光照语言完全兼容。

  Cg 代表 “用于图形的 C 语言” (C for graphics)。C 语言是一种非常流行的、开发于 20 世纪 70 年代的通用编程语言。因为它的流行和简洁的设计,C 语言为后续的几种编程语言提供了坚实的基础。例如,C++ 和 Java 的语法和结构都是基于 C 的。Cg 语言本身也是基于 C 语言的。如果你熟悉 C 语言或者是从 C 语言派生出来的其他语言,Cg 将会非常容易掌握。

  另一方面,如果你不熟悉 C 语言,或者甚至没接触过一般的编程语言,但是你非常喜欢计算机图形并且想学一些新东西,无论如何都请继续阅读本书。Cg 程序都非常短小和易于理解。

  本章的大部分都在讲述背景知识,将为你理解 Cg 和有效地使用 Cg 提供有价值的上下文关系。另一方面,你将发现通过实践 Cg 是非常容易学习的。如果你想马上进入 Cg 教程,那么可以随时直接跳到第 2 章去。


1.1.1 为可编程图形硬件设计的语言

  Cg 不同于 C、C++ 和 Java,因为它非常特别。没有人会用 Cg 写电子制表软件或者文字处理应用程序。相反,Cg 的目标是为使用图形硬件渲染的物体的形状、外观和运动提供可编程控制的能力。从广义上讲,这种类型的语言被称为光照语言。但是,Cg 可以做光照以外的很多事情。例如,Cg 程序可以实现物理模拟、混合和其他非光照任务。

  你可以把 Cg 看作是一个非常详细的通过使用可编程图形硬件渲染物体的 “处方”。例如,你可以编写一个 Cg 程序来使物体的外表看起来非常凹凸不平,或者使一个虚拟的人物运动起来。以后,在第 1.3 节中,你将学习许多光照语言的历史和 Cg 是如何融入这个历史中的。


1.1.2 Cg 的数据流模型

  除了专门为图形设计以外,Cg 和其他光照语言与传统的编程语言是不同的,因为它们是基于数据流模型的。在这样一个模型里,计算的发生是为了响应流经一序列处理过程的数据。

  Cg 程序运行在渲染一幅图像时被处理的顶点和片段上(如果你不知道什么是片段,现在就把它当作像素)。你可以把 Cg 程序想象成一个黑箱,顶点和片段从一边流入,经过某些变换后,从另一边流出。但是,这个箱子并不是一个真正的黑箱,因为你可以通过编写 Cg 程序来决定它到底起什么作用。

  在渲染三维场景的时候,每当一个顶点被处理或者光栅器产生一个片段,你对应的顶点或者片段 Cg 程序就会被执行。第 1.3 节会进一步解释 Cg 的数据流模型。

  大部分最新的个人计算机和所有最近的游戏平台都包括一个图形处理器(GPU),来专门处理图形任务,例如变换和光栅化三维模型。你的 Cg 程序实际上是在你计算机中的图形处理器上执行的。


1.1.3 图形处理器的特殊性和中央处理器的通用性

  无论是个人计算机或者游戏平台是否拥有一个图形处理器,它都必须有一个中央处理器来运行操作系统和应用程序。中央处理器是以多种用途为目的设计的。中央处理器所执行的程序(例如,文字处理器和统计软件包)是用多用途的语言编写的,例如 C++ 或者 Java。

  因为图形处理器是专门设计的,它执行图形任务要比多用途的中央处理器快许多,例如渲染三维场景。新的图形处理器可以在一秒钟内处理好几千万的顶点和光栅化几亿或者甚至是几十亿片段。未来的图形处理器会更快。这绝对比中央处理器处理类似数量的顶点和片段的速度快许多。但是,图形处理器不能像中央处理器那样运行任意的多种多样的程序。

  图形处理器的这种专用性和高性能是 Cg 为什么存在的原因。多用途的编程语言对处理顶点和片段这项专门的任务来说太自由了。相反,Cg 语言是专用于这项任务的。Cg 同样也提供了一个和图形处理器的执行模型相符合的抽象执行模型。你将在第 1.2 小节学习图形处理器独特的执行模型。


1.1.4 Cg 性能的基本原理

  为了支持想象的交互性,一个三维应用程序需要维护每秒显示 15 帧或更多图像的刷新率。通常,我们认为 60 帧/s 或更高的刷新率为实时,在这样的刷新率下与应用程序的交互看起来就像同时发生的。计算机的显示屏幕也许有 100 万或更多的像素需要重画。对一个三维场景而言,图形处理器一般对屏幕上的一个像素需要处理好几次,因为场景中的物体总是相互重叠的,或者是为了提高每个像素的表现。这就意味着实时三维应用程序每秒钟需要更新几亿个像素。随同需要处理的像素是由顶点组成的三维模型,这些顶点在被正确地变换之后,才能被组成多边形、线段和点,然后光栅化成像素。这就需要每秒钟变换上千万的顶点。

  而且,在这种图形处理之外还需要中央处理器相当大的工作来为每个新图像更新显示。事实上,我们同时需要中央处理器和图形处理器专门面向图形的功能。以一个可交互的刷新率和三维应用程序和游戏所要求的质量标准来渲染场景同时需要这两种处理器。这意味着一个开发人员可以用 C++ 写一个三维应用程序或游戏,然后使用 Cg 来充分利用图形处理器的额外的图形处理能力。


1.1.5 与传统编程语言共存

  Cg 绝不是用来代替现存的多用途编程语言。Cg 是一种辅助语言,是专门为图形处理器设计的。使用 C 或者 C++ 等传统编程语言为中央处理器编写的程序可以使用 Cg 的运行程序(将会在第 1.4.2 小节进行解释)来加载在图形处理器上执行的 Cg 程序。Cg runtime(Cg 运行库)是一个用来加载、编译、操作和设置 Cg 程序在图形处理器上执行的标准子程序集合。应用程序使用 Cg 程序来指示图形处理器如何完成这些可编程的渲染效果,这些效果在中央处理器上不可能达到图形处理器所能获得的渲染速度。

  Cg 使得一种专门类型的并行处理成为可能。当你的中央处理器执行一个传统的应用程序的时候,这个应用程序将通过 Cg 编写的程序来协调图形处理器对顶点和片段进行并行处理。如果一个实时光照语言是这样好的一个主意的话,为什么没有人早一点发明 Cg 呢?这个问题的答案与计算机硬件的发展有关。在 2001 年以前,大部分计算机图形硬件,当然是那种不是很昂贵的用于个人计算机和游戏控制台的图形硬件,采用硬件连线方式实现顶点和片段的处理任务。硬件连线方式是指这些算法是固定在硬件里的,与可以被图形应用程序使用的可编程方式相反。即使是这些硬件连线方式的图形算法可以被图形应用程序通过多种方式设置,应用程序仍然不能重新调整硬件来实现硬件的设计者没有预期到的任务。幸运的是这种情况已经改变了。

  图形硬件的设计已经发展了,而且近来的图形处理器中的顶点和片段处理单元是完全可编程的。在可编程图形硬件到来之前,没有理由为它提供一种编程语言。现在,既然这种硬件能够被使用了,使得编程使用这种硬件更容易些的需求就变的非常明显。Cg 使得编写图形处理器程序就像 C 使得编写中央处理器程序那样变得更加容易。

  在 Cg 存在之前,展示图形处理器可编程能力只能靠低级的汇编语言。汇编语言(例如 DirectX8 的顶点,像素着色器和一些 OpenGL 扩展)所需要的这种密码似的指令语法和硬件寄存器操作,对大部分开发人员来说都是一项痛苦的工作。由于图形处理器技术使得更长和更复杂的汇编语言程序成为可能,这使得对高级语言的需求越来越明显。为了达到优化性能的目的需要大量的低级编程,现在这些程序被升级为优化代码输出和处理冗长乏味的指令调度的编译器。

  相反,注释清晰的 Cg 程序非常简便、清晰、容易调试和容易再使用。在提供了与低级汇编代码一样的性能的同时,Cg 能给你高级语言(例如 C)的优点。


1.1.6 Cg 的其他方面

  Cg 是一种非常简单容易使用的编程语言。这使得它比现代多用途语言更简单,例如 C++。因为 Cg 是专门用来变换顶点和片段的,它现在还没有包含许多大量软件工程任务所需要的复杂的性能。不像 C++ 和 Java,Cg 不需要支持类和其他在面向对象编程中大量使用的特点。现在的 Cg 实现不提供指针乃至内存分配(虽然以后的实现会提供,并且关键字已经适当保留了)。Cg 当然没有对文件输入和输出进行支持。基本上,这些限制并不是语言上永久的限制,也不是当今高性能图形处理器的标志性功能。由于技术发展到允许图形处理器提供许多通过编程能力,你可以预期到 Cg 将会适当成长。因为 Cg 是紧密基于 C 的,未来对 Cg 的更新可能也会从 C 和 C++ 采用许多语言特性。

  Cg 提供了数组和结构。它拥有所有现在语言的流控制:循环、条件和函数调用。

  Cg 天生就支持向量和矩阵,因为这些数据类型和相关的数学操作是图形学的基础,并且大部分的图形硬件直接支持向量数据类型。Cg 有一个函数库叫做标准函数库(Standard Library),这个函数库非常适合图形学所需要的各种操作。例如,Cg 标准函数库包括一个反射(reflect)函数用来计算反射向量。

  Cg 程序的执行是相对独立的。这意味着对一个特殊的顶点或片段的处理对在同一时间处理的其他顶点或片段没有影响。执行一个 Cg 程序没有任何副作用。在顶点和片段之间缺乏相互依赖使得 Cg 程序非常适合使用高度流水和并行的硬件来执行。


1.1.7 Cg 程序的有限执行环境

  当你使用一种语言在现代操作系统上为先进的中央处理器编写一个程序的时候,你可以预期到差不多任何程序只要程序本身正确,就可以正常地编译和执行。这是因为中央处理器是设计用来执行多用途程序的,对这样的程序综合系统拥有太多的资源。

  但是,图形处理器是专用的而不是多用途的,并且图形处理器的特征集还在发展中,并不是你用 Cg 写的所有东西都可以被编译然后在一个所给的图形处理器上执行。Cg 包含了一个硬件的概念 “配制” (profile),当你在编译一个 Cg 程序的时候,你必须指定其中一个配置。每一个配置对应一种特别的硬件和图形 API 的组合。例如,一个特定的片段配置也许会限制你每个片段不能使用多于四个纹理。

  随着图形处理器的发展,Cg 将会支持更多的与性能更强的图形处理器体系结构相对应的 profile。在不久的将来,当图形处理器变得功能越来越全面的时候,profile 将会变得越不重要。但是,现在的 Cg 程序员将需要限制程序来确保它们可以在现有的图形处理器上编译和执行。通常,未来的 profile 将会是目前的 profile 的超集,因此所有为现在的 profile 编写的程序可以在未来的 profile 上不经修改直接编译。

  这种情形看起来会带来一些限制,但是实际上本书所显示的 Cg 程序可以在上千万的图形处理器上工作并生成引人注目的渲染效果。另一个限制程序大小和范围的原因是,你的 Cg 程序越小越有效,它们运行地就会越快。实时图形学常常需要在增长的环境复杂度、动画速度和改善光照中取得平衡。因此通过明智地 Cg 编程最大化渲染效果始终是一件好事。记住 profile 所强加的限制是当前的图形处理器的限制所造成的,而不是 Cg 本身所造成的。Cg 语言本身功能是非常强大的,足够表达目前所有的图形处理器还没能支持的光照技术。随着时间的过去,图形处理器的功能将会发展到 Cg profile 将能够运行令人惊讶的复杂 Cg 程序。Cg 是一种适于现在和未来图形处理器的语言。

🔚