webgl 的空间变换(下):空间变换

  在网上看了不少关于在三维世界中怎么把一个顶点通过一步步变化,最终呈如今咱们的屏幕上的。web

  其实不少博客或者书籍已经讲的很清楚了,那为何我还要特别再写一次博客来阐述本身观点呢?(这里只针对那些学习webgl时,想完全了解清楚空间过程的同窗而言)编程

  由于在我一开始对三维不是很懂的状况下,看了不少书和博客,以为他们写的已经很牛逼了,并且让我受益不浅,可是随着知识量的不断增长 ,我意识到一个问题,那就是我好像理解缺点什么,或者说有的地方的理解甚至是错的,好比说一个问题,也是我记录这篇文章的主要目的,之前我对三维空间的坐标变化理解是这样的:windows

    模型坐标----(模型矩阵,即吧模型坐标系下的坐标变换到世界坐标系下的坐标的过程,其余矩阵也是同样,好比视图矩阵就是把世界坐标系下的坐标变换到视图坐标系下的坐标的过程)----世界坐标 ---- 视图矩阵----投影矩阵----屏幕坐标学习

    基本书上(webgl编程指南)或者网上90%的博客都是这样讲的,这是能够的,可是是不严谨的,由于从投影矩阵到屏幕坐标的转换过程,是不须要你进行处理的,这部分是渲染管线本身执行的。webgl

若是不是由于在工做中遇到一些奇奇怪怪的参数和新的东西,以及和同事的讨论中,发现好多概念根本不懂, 我也不会怀疑本身的理解。因此我找到了webgl的祖宗opengl去一探究竟。spa

    如下是opengl中完整的对三维空间变换的介绍,颇有价值:对象

    另外我补充一点,webgl编程指南中之因此会省略一部分细节不去讲,并非说webgl里面有错,而是那部分细节,不在可编程渲染管线范围内(就是说咱们能够本身编写代码参与到渲染的部分,大概包括,定义顶点位置, 编写顶点着色器和片元着色器。)因此,webgl并无细讲。ip

      

在使用 OpenGL 的应用程序中,当咱们指定了模型的顶点后,顶点依次会变换到不一样的 OpenGL 空间中:博客

  • 世界空间
  • 模型空间(也称为对象空间)
  • 视图空间(也称为视点空间、摄像机空间)
  • 裁剪空间
  • 标准设备坐标空间
  • 窗口空间

在通过这一系列的空间变换以后,顶点才会被显示在屏幕上。cli

世界空间(World Space)

世界空间相对于其余坐标空间来讲是固定不变的。因此,它也被用做空间变换的参考系。咱们把它的坐标系称为世界坐标系。在没有特别说明的状况下,咱们用来描述一个几何对象(点、向量或坐标)的数值数据,都是基于世界坐标系来设定的。

世界坐标系用矩阵来表示就是一个单位矩阵。

模型空间(Model Space)

模型空间,也称为对象空间。若是把世界空间比做现实世界的话,那么模型就比如一座房子或者房子里的一我的等等。假设以人的重心为原点,正面向前的方向为 z-轴,头顶的方向为 y-轴,左侧方向为 x-轴来构建一个坐标系。咱们能够用这个坐标系来描述这我的自身的模型空间。这个坐标系也称为模型坐标系(或对象坐标系)。

模型坐标系并非绝对的,若是以人的鼻尖为原点,头顶的方向改成 z-轴,正面向前的方向为 y-轴,右侧方向为 z-轴来构建其模型坐标系。这个模型坐标系一样能够用来描述这我的自身的模型空间。只不过用不一样坐标系来描述时,描述出来的数据不必定相同。

通常来讲,咱们都是基于世界坐标系来描述模型坐标系的。在这种状况下,世界坐标系能够看做是模型坐标系的父坐标系:

其中,黑色的坐标系为世界坐标系;灰色的坐标系为模型坐标系。

模型变换(模型-世界变换)

默认状况下模型坐标系的原点位于世界坐标系的原点,而且坐标轴的方向与世界坐标系的坐标轴一致。咱们能够经过一系列的缩放、旋转和平移,将模型以任意角度摆在任意位置上。这种状况下,模型上的顶点以及模型自身的坐标系都会相对世界坐标系发生了变化。

模型变换的实质就是将模型上的顶点在模型空间中的描述,转换为在世界空间中的描述。假设有一个模型坐标系表示为矩阵 M(基于世界坐标系来描述),一个顶点在该模型坐标系上的坐标表示为列向量 D。 那么,该顶点在世界坐标系中的坐标 D‘,有以下变换关系:M·D = D’。M 也称为模型矩阵。模型矩阵本质上是一系列缩放、旋转和平移矩阵的复合矩阵。

视图空间(View Space)

视图空间,也称为视点空间或摄像机空间。它是以摄像机(或者观察者)的角度来定义的一个空间。视图空间能够经过视图坐标系(也称为视点坐标系或摄像机坐标系)来描述。从摄像机的角度来看,视图坐标系 x-轴和 y-轴的正方向分别指向摄像机右方和上方,而 z-轴的负方向则指向摄像机的镜头指向。在透视投影中,摄像机位于视图坐标系的原点。因此 z 坐标为正的模型位于摄像机的背后,摄像机没法拍到它;而在正交投影中,摄像机被认为是位于在视图坐标系 z-轴正方向上的无穷远处。


透视投影中,摄像机与视图坐标系的位置关系图


正交投影中,摄像机与视图坐标系的位置关系图

与模型坐标系相似,咱们通常也会基于世界坐标系来描述视图坐标系的。因此在这种状况下,世界坐标系能够看做是视图坐标系的父坐标系:

其中,黑色的坐标系为世界坐标系;蓝色的坐标系为视图坐标系。

视图变换(世界-视图变换)

默认状况下,视图坐标系位于世界坐标系的原点,而且坐标轴的方向与世界坐标系的坐标轴一致。咱们能够经过一系列的缩放、旋转和平移,将摄像机以任意角度摆在任意位置,以方便咱们的拍摄。当摄像机的位置、角度发生变化时,拍摄到的场景也会发生变化(也就是说空间中的模型相对于视图坐标系来讲都发生了变化)。

视图变换的实质就是将某个顶点在世界空间中的描述,转换为在视图空间中的描述。假设有一个顶点在在世界坐标系中的坐标表示为列向量 D‘,一个视图坐标系表示为矩阵 V(基于世界坐标系来描述的),那么该顶点在视图坐标系 V 中的坐标 D,有以下变换关系:V·D = D’(道理和模型变换相似)。设 V 的逆矩阵为 V’,能够推导出变换关系 V‘·D‘ = D,V’ 也被咱们称为视图矩阵

模型视图矩阵(Model-View)

为了渲染一个模型,咱们一般会先将它从模型空间变换到世界空间,而后再从世界空间变换到视图空间。这两个过程都有对应的变换矩阵:模型矩阵和视图矩阵。咱们能够将这两个矩阵结合起来用一个复合矩阵来表示,这样的一个复合矩阵咱们称为模型视图矩阵。经过模型视图矩阵,咱们能够将模型上的顶点从模型空间直接变换到摄像机的视图空间。这样作有两个好处:

  • 假如在世界空间中有许多模型,而且每一个模型包含许多顶点。那么用一个复合矩阵把单个模型的全部顶点一次性变换到视图空间,比对全部顶点都作两次矩阵变换要高效得多。

  • 由于一个空间能够是无限大的,因此将顶点从模型空间变换到世界空间中,所作的变换经常须要用到不一样的精度去计算,这主要依赖于顶点离世界坐标的原点有多远。一样的,当咱们再把顶点从世界空间变换到视图空间时,所作变换的精度也须要依赖于顶点到摄像机的距离有多远。对那些距离摄像机很近的顶点采用高精度是合适的,但对于距离摄像机很远的顶点一样采用高精度则会产生精度损失。想象一下,当模型与摄像机离得很近,而且二者又离世界坐标系的原点很远时,变换两次容易产生精度损失。用复合矩阵能够有效减小精度损失,提升结果的精确性。

裁剪空间(Clip Space)

不难理解,摄像机是没法同时拍摄到场景内全部的东西的。每一个摄像机都会定义一个视景体,视景体决定了摄像机能够看到的空间。彻底位于视景体内的模型将会被保留;彻底位于视景体外的模型将被剔除;而与视景体裁剪平面相交的模型则会被裁减(即保留在视景体内的部分,剔除在视景体外的部分)。这个决定模型是保留仍是剔除的过程,咱们称之为裁剪

视景体指的是空间中的一块区域,它由六个平面包围而成,这些平面被统称为裁剪平面。其中,有两块平面比较重要,它们都垂直都于摄像机的镜头指向,离摄像机比较近的那块被称为近裁剪平面,而离摄像机比较远的那块则被称为远裁剪平面。这两块平面决定了摄像机能够看到的深度范围。


透视投影的视景体示意图


正交投影的视景体示意图

对于不一样的投影,其对应视景体的形状也有所不一样。好比正交投影的视景体是一个长方体。而透视投影的视景体则是一个平截头体(像一个顶部被平截掉的金字塔)。若是咱们直接使用视景体所定义的空间来进行裁剪,那么对不一样的视景体就要采用不一样的处理过程,特别是判断一个顶点是否处于一个平截头体内是比较麻烦的。所以,咱们采用更加通用的裁剪空间来描述不一样视景体所定义的空间。在裁剪空间中,咱们能够用统一的方式来处理不一样视景体的裁剪。

裁剪变换

将一个顶点从视图空间变换到裁剪空间的过程叫做裁剪变换,咱们能够经过一个裁剪矩阵(也称为投影矩阵)来实现该变换。这里有个迷惑点,虽然裁剪矩阵也叫投影矩阵,但其实它并无进行真正的投影工做,只是在为投影作准备工做,真正的投影工做发生在下一阶段的变换中。

透视投影的裁剪变换

透视投影的视景体为一个平截头体,咱们能够经过下面几个参数来定义该平截头体:近裁剪平面、远裁剪平面在视图坐标系中的 z 坐标:near、far,近裁剪平面上下两条边在视图坐标系中的 y 坐标:top、bottom,还有近裁剪平面左右两条边在视图坐标系中的 x 坐标:left、right。

咱们能够根据以上这些已知的参数,来给出透视投影的裁剪矩阵:

对于视图空间坐标为 (x, y, z, 1) 的顶点,通过透视裁剪矩阵变换后的结果以下:

该结果表示顶点在裁剪空间中的坐标。咱们可能注意到了,此时顶点的 w 份量再也不是 1 了,而是变换前 z 份量的取反结果。虽然咱们在裁剪空间以前,就使用齐次坐标来表示空间中的几何对象(点、向量或坐标系),并且 w 份量一直是固定的:点位置的 w 份量为 1,向量的 w 份量表示为 0。在变换到裁剪空间以后,咱们将赋予齐次坐标的 w 份量更加丰富的含义:做为一个临界值来判断一个通过裁剪变换后的顶点是否位于景视体内。若是变换后的坐标值 x、y、z 均在区间 [-w, w] 内,则代表该顶点在视景体内。不然,代表该顶点不在视景体内,将会被抛弃。

正交投影的裁剪变换

正交投影的视景体为一个长方体,平截头体的参数概念对于长方体来讲一样适用。如今,咱们根据这些已知的参数,来给出正交投影的裁剪矩阵:

对于视图空间坐标为 (x, y, z, 1) 的顶点,通过正交裁剪矩阵变换后的结果以下:

很明显,当变换前的 x 坐标在 right 与 left 之间时,变换后的 x 坐标在区间 [-1, 1] 内。对于 y 和 z 坐标同理可证。也就是说,若是变换后的坐标值 x、y 、z 均在区间 [-1, 1] 内,则代表该顶点在视景体内。并且这里的 w 为 1,因此其裁剪的判断规则与透视投影中是一致的。

裁剪空间使用同一套空间标准来描述不一样视景体所定义的空间(经过执行不一样的裁剪矩阵变换),把不一样视景体的裁剪方式进行了统一。除此以外,裁剪空间也为后面真正的投影工做提供了方便。

标准设备坐标空间(NDC Space)

现在,显示屏幕的分辨率多不胜数,咱们很难在每一种分辨率上都能把顶点显示在正确的位置上。

为了解决这个硬件适配的问题,咱们在顶点被渲染到屏幕上以前,将其变换到标准设备坐标空间中。标准设备坐标空间采用一种无量纲的单位坐标来代替设备坐标,直到顶点被输出到屏幕时,单位坐标才会转换为具体的设备坐标。标准设备坐标系的 x、y、z 轴的范围被定义为 [-1, 1]。这样能够将应用程序与具体的显示设备隔离开来,应用程序无需关心显示设备的分辨率,增长了应用程序的可移植性。

对于正交投影,任意顶点在裁剪空间的坐标值 x、y 、z 均在区间 [-1, 1] 内,这种状况下无需任何变换,裁剪空间自己也是标准设备坐标空间。

对于透视投影,咱们只须要对顶点在裁剪空间的坐标执行齐次坐标标准化,使其 w 份量变为 1。对应的 x、y、z 也将会缩小到范围 [-1, 1] 内。这种状况下,标准化的过程其实也是将顶点从裁剪空间坐标变换到到标准设备坐标空间的过程。

并且,由于标准化前的 w 份量与顶点到摄像机的距离成正比。因此,顶点离摄像机越远则 w 越大,w 越大则在标准化时 x、y、z 被缩得越小,这样就达到了透视收缩和投影的效果。因此,标准化的过程也是真正的投影过程。

窗口空间(Windows Space)

窗口空间,实际上指的就是显示屏幕或屏幕上某块区域(好比屏幕桌面上的窗口)的空间。窗口空间不只取决于屏幕的分辨率或窗口的大小,也取决于窗口的位置。由于在标准设备坐标空间中,任意顶点的坐标值都在范围 [-1, 1] 内。因此,不管窗口空间是什么样的,咱们都能很好的把顶点的标准设备坐标映射到具体的屏幕或屏幕的指定显示区域上。