[3D] 基本概念

时间:2023-02-13 16:16:16
环境光:对场景中所有的对象都提供了固定不变的照明。
点光源:是从一个点发出的光。灯泡就可以理解为点光源。
聚光源:正如它的的名字一样,是有方向和强弱的,电筒就是典型的聚光源。

方向光:常用于模拟太阳光和其它无穷远的光源。这种光源被看作来自无穷远,它的强度不随着接近对象而变化。在唯一的方向上,亮度是固定的。

3D坐标系统

3D图形的目标是用二维的图象来代表三维的场景。之所以图象是二维的因为观察场景的介质--平坦的计算机显示屏是二维的。所以,3D图形意味着同一场景的两种表现--一个是看不见的三维的表现,另一个是在屏幕上显示的二维表现。我们先来讨论看不见的、三维的表现。

在三维的空间里表现物体可以使用提供三个不同的轴的坐标系统来实现。这些轴通常呗称为X,Y和Z轴。

有两种通用的3D坐标系统的变种:左手系和右手系。两者的不同之处在于Z轴的动作。在左手系里,越远的坐标(从观察者的角度看好像很远)Z轴的值越大,越近的坐标Z轴的值越小。在右手系里,Z轴正好相反;越远的坐标Z轴的值越小,越近的坐标Z轴的值越大。Dirext3D使用左手系,所以我们将在这里用它来讨论。

3D空间种的任何一点都可以用三个值的集合来表示。这些值指明了点沿每个轴的位置,并且在这里用三角括号就像这样:<1,2,3>。这些值说明点的三个方向XYZ轴的位置是独立的。

原点

三个轴相交的点称之为原点。位于原点的点XYZ的值都是零<0,0,0>。值离零越远,点离原点也越远。在原点右面的点X的值是正的,在原点左面的点X的值是负的。同样的,在原点上面的点的Y值是正的,在原点下面的点Y值是负的。

向量

向量,同点一样,也由值来表示,但是向量描绘的是一个方向和一种速率但不是一个位置。

比如<0,1,0>,如果我们把这些数字当成一个点,那么这些数字代表了原点上方一个单位的位置(单位可以是任意的:可以代表厘米、米等等)。但是如果我们把同样的三个数字当成一个向量,我们面对的就是一个方向和一种速率,而不是一个位置。在这个例子里,方向是向上,速率是1。用三个数字表示一个向量是有一点不对的,因为一个向量通常需要6个点:3个用来表示开始点,3个用来表示结束点。这才给了我们一个方向(从第一个点到第二个点的方向),和一种速率(两个点之间的距离)。只有开始点是原点能被理解的时候,向量才可以用三个值来表示。

让我们再来看另一个向量:<2,0,0>。这个向量代表向右的方向因为向量开始于原点并且沿着X轴向右移动了2个单位。因为向量<2,0,0>代表了向量<0,1,0>长度的2倍,所以向量<2,0,0>的速率是向量<0,1,0>的2倍。

记住向量和点是不一样的是很重要的。一个点指示了一个位置;一个向量却没有。位置是用来定义向量的,但向量却不能定义一个位置。

平面

平面是一个可以无限延伸的平的表面。平面不是一个正方形或者一个长方形,因为正方形和长方形有边和角的。平面的大小是不能定义的。表示平面的最简单的方法就是用一个轴和一个交集。例如,一个Y轴的值为-3的平面位于原点下方3个单位并沿着X轴和Z轴无限延伸。也就是,这个平面和Y轴垂直地相交于-3。

注意到用一个轴和值来表示一个平面的方法不能描述一个不和轴平行的平面。如果我们像描述一个以45度角切过Y轴的平面,我们需要一种更加复杂的表示。

我们可以使用一个向量来描述平面的方向。如果我们想要一个和Y轴45度相交的平面,我们可以使用向量<0,1,-1>来定义这个倾斜向观察者的平面(该平面垂直于这个向量)。只是这个向量并没有定义这个屏幕安,只有这个平面的方向。我们仍然需要指出这个平面位于什么地方。我们可以再次使用Y值-3来指示这个平面在原点以下3个单位处与Y轴相交。

顶点

顶点是在三维空间中用来代替物体比如面、网(我们马上就要讨论面和网)等的点。顶点,就像点一样,是有特定位置的,所以他们是可见的。Direct3D支持顶点被画成点的模式。这种模式没有太大的实用价值因为基于单独的顶点很难决定画的是什么。事实上,在这种模式里呈现的场景看起来好像3D“连接了点”的难题。(很好--给我一支铅笔)

在Direct3D里,面是一个根据顶点来定义的平面图形元。每个顶点定义了面的角。面上所有的顶点必须在出现在同一个平面内;它们必须定义一个平的面。由不同平面内的点组成的面是不合法的也是画不出来的。

一个面最简单的形式是以三个顶点来定义。很容易就能得到的三角面,有如下几个原因:首先,不可能定义三个点的集合是不在同一个平面内的,所以这个面是不可能不合法的。其次,三角面总是凸的,而凸面用起来比凹面更有效。

(tip:Direct3D使用三角形 其实Direct3D保留将非三角面分割成三角形的模式,因为快速模式接口(并不正确的翻译)只接受三角形)

面通在一个图形系统中通常是唯一可见的物体。一些图形系统可以画曲面但是大多数,包括Direct3D,使用小的,平的面的集合来表示曲面。

网是连起来的面的集合。典型地,在一个场景里,网表示一个物体。网可以有一个或者多个面,可以很复杂。

法线

法线是为面和网计算风格(color不知道具体应该翻译成什么)的向量。有两种形式的法线:面法线和点法线。

面法线是垂直于面的向量。这种法线决定了面的风格和面的哪一边是可见的。

点向量是在网中指派给每一个点的向量。每个向量的方向决定于邻接的面的方向和大小。

用面法线还是点法线决定于表现方式。一些表现方式使用面法线,其它的使用点法线,还有一些表现方式根本不用法线。我们将在这章后面一点讲到表现方式。

在大部分例子里,Direct3D自动地计算和使用法线,所以你没必要知道它们的存在。然而有一些场合,为了达到细节的表现效果,法线是可以被覆盖的。

转换

现在我们知道了在三维的空间里怎样放置物体。我们可以指定顶点,用顶点来定义面,用面来定义网。现在我们需要的是一种移动周围物体的方式。有三种常用的操作(或者叫转换)可以用来移动物体:平移、缩放和旋转。使用这三种操作,可以将一个物体放在任何位置并面向任何方向。

在我们继续之前,让我们构造一个可以讨论平移、缩放和旋转、操作的简单的假想。我们将使用一个简单的网:一个立方体。这个立方体以原点为中心并且尺寸是1*1*1。

注意到因为立方体是以原点为中心的,立方体的每个边从原点向外延伸了1/2个单元。而且注意到每个面都是和轴垂直的。

平移

平移(translate)的字典定义为:以另一种语言表达出来。这种定义和3D图形没什么关系。在这里的意思是平移。

让我们说说我们想让简单的立方体向上移动2个单元。我们可以使用一个平移<0,2,0>来实现。

物体可以在单以的平移里同时沿着几个轴移动,所以没必要将每个轴的移动分开平移。例如:平移<2,2,0>可以将立方体向右移动两个单位同时向上移动两个单位。

缩放

对一个网或者面执行缩放操作改变了它的大小和位置。首先,让我们看一下缩放操作是怎样改变一个物体的大小的。如果我们还是用那个例子1*1*1的立方体,用缩放因子1/2来缩放它,这个立方体每一维上就会变成1/2个单位。如果我们使用缩放因子2,我们将会让该立方体的每一维加倍,产生一个每一维都有2个单位长的立方体。

正如前面提到的,执行缩放操作还可以改变一个物体的位置。如果立方体不以原点为中心,那么立方体的位置也和大小一样受影响。一个缩放操作并不直接缩放物体;他缩放物体的顶点。当缩放因子比1大时,顶点远离原点。当缩放因子比1小时,顶点向原点移近。

经常的,这种影响不值得因为如果你想要缩放一个物体而不改变它的位置,你必须将物体移动到原点,缩放它,然后再将它移回它原始的位置。一些3D系统(包括Direct3D)允许缩放操作只改变物体大小而不改变其位置,不管这个物体是不是以原点为中心。这可以用局部或物体轴的方式实现。在缩放一个局部轴上的物体和缩放一个以原点为中心的物体取得的效果是一样的:物体的大小改变了,但是它的位置(即物体的中心)保持原样。Direct3D缩放物体默认使用物体的局部轴。

你可以为每个轴指定不同的缩放因子。这样可以允许物体伸长和缩短。缩放因子1对物体的顶点没什么影响,所以1可以用来表示不需要变化的轴。如果我们拿一开始的立方体执行缩放操作<2,1,1>,我们将增大立方体的宽度而不影响其它维。

旋转

旋转操作允许我们给物体指派方向。旋转一个物体需要我们决定旋转轴和物体要旋转多大的角度。

我们可以用向量来描述旋转轴,用一个值来描述物体要旋转的角度。

让我们回答立方体的例子并将它沿着Z轴旋转45度。沿Z轴旋转的意思是立方体好像被Z轴戳起来一样旋转并且可以向任何方向*旋转。我们可以用向量<0,0,1>和数字45来表示。

材质贴图

材质贴图是随着ID软件非常流行的DOOM(著名3D动作游戏)的到来而获得许多关注的。DOOM不是材质贴图的最初执行者,但是它的确是最受欢迎的游戏之一。

材质贴图是一个材质在一个或多个面上的应用或者映射(?)。这种映射的发生和物体在三维空间的位置有关。我们不能只是将材质拍击到一个平面上而不考虑物体的位置和观察者的视角。这样的场景是很难令人信服的。我们将在这一章后面讨论材质和透视。目前,要记住的是:正确的材质贴图需要远物体的材质和近物体的材质进行不同的应用。

材质的自然

材质是二维的颜色值的栅格。材质通常被存储在我们熟悉的文件格式比BMP,PCX或者GIF里。几乎所有的二维图象都可以被认为是一个材质。

牢记,虽然你可以把任何一个图象当作一个材质,但是并不是所有的图象都是一个好的材质。好的材质通常不是自身用来看的,但它们将物体描绘得现实。图象完全是完整的场景,通常是差的材质因为你在看一个单独物体的时候并不期望看到整个场景。3D物体比如镜子和图片是这个规则的例外。

材质缩放比例

材质可以以各种不同的方式应用到物体中来。改变材质的一种方式是改变材质的大小。如果一个材质被应用到一个大的缩放因子,那么对于一个给定的物体,只有材质的一部分是合适的。如果缩放因子很小,整个材质将如同一堆重复的瓷砖一样显现在物体上。第二种效果对于你要用一个很小的全景来表现一个大的物体很有用。

材质包装

材质包装决定了材质怎样应用到物体上来的方式。最简单的包装方式是让才是好像是从一支枪里打出来的。材质的各种色彩从物体直直地射出一直到另一端。这种方式通常被称作平包装(有点矛盾,因为你是不能用一个平的东西来包装物体的)

这种方式通常被用在大型物体上,尤其当观察这只看到物体的一面。平包装很容易使用因为它们只需要指明材质应用的方向。因为平材质包装使得材质只往一个方向延伸成物体,物体的侧面通常看起来是有斑纹的。

另一种常用的方法是圆柱形的。圆柱包装方式用弯曲或者将材质包装成一个圆柱形的方法把材质应用到物体。

有一点很重要,材质包装方式和物体被构成的形状是完全独立的。你可以将一个平包装应用到球体上去,就像将一个球包装应用到一个立方体上一样简单。Direct3D支持平、球、圆柱的材质包装。

材质活跃

以不同的材质或者不同的材质包装方式描绘同一个物体叫做材质活跃。一个简单的例子是将同一个材质应用到物体,但是在每个活跃结构里改变材质位置。这使得材质穿越物体。这种技术对表现一个移动的物体比如传送带很有用处。另一个例子是改变材质的尺寸。这两种方法执行起来都很简单(因为它们只需要一个材质),但在实用方面有所欠缺。

一个更强大的材质活跃技术是在同一个物体上对每一种活跃结构用不同的材质。如果,你想要一个电视机的场面(电视机是打开的),为了每一次电视的更新,你可以在电视屏幕上应用一个不同的材质。这种技术是很有效的,但是需要很大的内存如果材质的序列很长或者材质本身很大。

照明灯光

平移、缩放、旋转和材质物体可以在三维世界里存在,但是如果他们在黑暗的环境里就不能被看见。在我们期望看到所有东西之前,我们需要一个光源。当我们看到最后的输出时,场景里的物体会根据场景里光源的性质来被着色。

颜色

所有的光源有一个共同的属性:颜色。正常情况下光是白色的,意味着所有的颜色都处在最大强度。每个图形程序包的照明系统都是不一样的,但是大部分都使用RGB值来定义光源的颜色。在Direct3D里,RGB中的每个值可以是0(关着)到1(开着),所以白光的RGB值是1,1,1。红光是1,0,0。蓝光是0,1,0。除了红绿兰的颜色可以用三种颜色的混合来表现。比如,黄色的RGB值是1,1,0。

照明方式

光源有各种不同的形式。典型的光源包括环境光、点光源和聚光灯。

环境光

最简单的光源就是环境光。环境光没有具体的位置并且以相同的强度照亮了整个场景里的所有物体。这些光是随处可得的因为它们很容易使用。环境光通常和更复杂的光源一起使用。

点光源

点光源朝所有的方向散发光。点光源有一个特殊的位置但是没有方向。电光源在处理过程中是需求公平的因为要求光向每个方向发散。在处理过程中花费的代价通常是值得的,然而,因为制造电光源的现实效果。点光源有时也叫“全”或者“全方位”光。

方向光

点光源的一个计算更有效的替代是方向光。方向光具有方向,但是没有位置。方向光发出的光线是互相平行的。方向光有实际意义,在场景里看起来就像离物体很远。

聚光灯

聚光灯有方向和位置,并且以圆锥的形状制造灯光。圆锥的形状是由本影角和半影角决定的。本影角定义了聚光灯全部照明的圆锥。半影角定义了在本影角周围减少了灯光的圆锥。聚光灯的半影角通常要比本影角更重要。

Direct3D支持环境光、点光源、方向光和聚光灯。Direct3D还提供了一个方向光的一个变种,叫平行光。

透视转化

在这章的开始部分,提到了3D图形的目标是让二维来表现三维的场景。我们已经讲了操作看不见的三维直接,现在我们将要讨论用二维世界制造一个三维世界。

从三维到二维的转换需要透视转化。透视转化确保最终的输出外观和正确动作。正确的动作意思是离观察者近的物体比远的物体显得大。也意味着在场景范围之外的物体或者物体的部分不会被画出来。这需要我们决定一个物体是否太远或太近。

从三维到二维需要我们以一种二维空间能容易形成的方式将三维空间分开。这意味着我们需要决定观察者、照相机位于什么地方,场景的多少部分观察者是可以看见的。观察者位于金字塔的顶点并且向下看金字塔的底部。当金字塔的底部变大时,场景的更多部分被看见了,但是物体却变小了。当金字塔的底部变小时,场景里的物体变大了,但是更少的物体进入了场景。金字塔底部的大小由观察者的视角和视场所决定。

使用不同的观察平截头体设置同改变照相机的镜头类似。使用长焦镜头让你看清远处的物体,但是你不用为你的家人拍照片而站在400英尺远的地方。从另一方面说,你可以为了特写镜头而使用广角镜头,但这并不适合野外观察鸟(除非你观察的鸟在一个笼子里)。

隐藏表面去除技术

3D图象里很重要的一个问题是,决定那些物体是可见的,哪些是被其它物体隐藏的。不关注哪些表面离观察者近,哪些离观察者远而表现一个场景,最终的图象会产生迷惑。解决这一问题的算法就叫隐藏表面去除技术。有很多种隐藏表面去除技术,各有各的有点。Direct3D使用的技术叫做Z-缓冲。

Z-缓冲

Z-缓冲用存储缓冲器来跟踪哪些表面是离物体近的。在缓存里的Z值不必要和Z轴有关;相反地,它们表示表面离观察者有多远。当图象画出来的时候,Z值可以和缓冲区里的Z值进行比较。如果在缓冲区里的值表明当前被画的表面比任何存在的表面离观察者近,那么新的表面就画在老的表面之上。如果新的表面比一个存在的表面远,那么该表面就不被画出。

将表面从前至后排序可以使得执行优化。这优化了执行因为在场景之前的物体先被画,之后的表面就根本不用再画了。幸运的是,Direct3D保留了执行Z-缓冲的模式(包括优化排序)而不需要程序员干涉。

Z-缓冲:正面和反面

Z-缓冲被认为是最简单、最快速的隐藏表面去除技术之一。它在象素上还是精确的(一些算法不是)并且可以高效地处理复杂的场景。Z-缓冲最主要的缺点是Z-缓冲需要大量内存。Z-缓冲至少要输出图象那么大的存储空间并且是32位的。例如,一个800*600运行模式的程序使用16位Z-缓冲光是Z-缓冲需要将近一兆的内存空间。

表现方式

一旦一个场景可以用三维空间模拟出来,还可以转化为二维的,它就可以表现出来了。这最后的一步产生了图象,它可以在你的屏幕上显示出来,这叫描写或者留影。有很多不同的表现技术存在;让我们看一下一些更常用的技术。

再构造

再构造表现看起来不那么真实并且不需要我们讨论过的所有步骤。再构造模式只是画了场景离面的边,用直线来表现它们。

无光

无光表现是从不把光源考虑进去的事实得到名字的。画面的时候用指定的面的颜色和材质而并不考虑光的值或面的方向。无光场景可以快速描绘但是物体会趋于轮廓化。

平面

平面描绘输出的真实性要大于再构造或者无光输出。平面描绘再表面上将光源考虑进去。每个面都要计算出法线并且法线要用来计算整个面的照明属性。平面描绘比再构造或者无光表现需要更大的计算性能。

明暗处理

明暗处理描绘和平面描绘类似,除了法线是为每个点计算的而不是每个面。面是由整个面的平均照明强度描绘出来的。这有点类似于网的周边外貌,单个面变得模糊。明暗处理描绘提供了真实的输出,但是让物体看起来模糊和松散定义。因为使用的是点法线而面强度是平均出来的,明暗处理描绘比平面描绘更需要强大的计算能力。

简单光照

简单光照描绘是明暗处理描绘的进一步提高。就像明暗处理,简单光照使用点法线,但是整个面都计算法线而不是去计算平均数。这种额外的工作提供了一个精确的、可预见的外形。正如你可以想象的,简单光照描绘比明暗处理要慢。没有特征可以提供,因为在写这文章的时候,Direct3D还不支持简单光照。

光线跟踪

光线跟踪比任何表现方式产生更真实的输出。事实上,光线跟踪因它的照片现实甚至宣传现实输出而被知晓。光线跟踪使用和我们所讨论过的方式完全不同的方法,光线跟踪算法自动计算阴影、反射和折射(其它表现方式不能自动执行计算)。不幸的是,光线跟踪慢慢销声匿迹了。单一的图象要用一天或者更长的时间来计算。更不必说,光线跟踪不适合实时图形并且不被Direct3D支持。

活跃

如果不活跃,实时的三维图形就没意思。三维活跃可以通过两种方式来实现:运动属性和键架。

运动属性

达到活跃的最简单的方法之一就是用运动属性。运动属性可以是平移、旋转或者缩放因子在每次屏幕更新时应用到一个或一组物体上。运动属性对简单重复的动作是有用的。一旦一个运动属性指派到一个物体上,物体将会根据属性移动,不受任何干涉。

键架

键架的名字来自于在一个活跃中只是特定的键的帧被画出来的传统的活跃技术。剩下的帧用关键帧中的中间动作来产生。

三维图形里的键架意味着你只要在键的时间里在一个场景中定义物体的位置。计算机负责在剩余的帧里放置物体。

键架需要你决定在一个活跃中帧的数量并且在特殊的帧定义键。例如,如果你想要创建这么一个活跃:物体从屏幕的左上角运动到右上角然后再到右下角,你可以执行如下步骤:

1.在活跃中定义帧的数量(我们在这个例子里用30)
2.在第1帧中指定物体要在屏幕的左上角出现
3.在第15帧中指定物体要在屏幕的右上角出现
4.在第30帧中指定物体要在屏幕的右下角出现

在Direct3D里键架有两种模式:直线的和基于锯齿的。线键架的意思是关键帧之间的活跃移动是线型的;物体在关键证之间以最短路径移动。基于锯齿的活跃在关键帧之间行走弯曲的路径。

用我们的例子来说,线键架使得物体径直地从屏幕的左上角移动到右上角。在第15帧(当物体到达右上角)物体将突然转向移向右下角。基于锯齿的活跃在第15帧将使物体园曲地绕过拐角。物体好像期待着将要拐弯这样一个事实。

在直线和基于锯齿地活跃里,场景中的物体都是精确地在你指定的关键帧中。