guodong's blog

master@zhejiang university
   

三维重建: 裁剪空间以及透视变换的理解

在阅读三维重建的代码时,经常能够看到一些关于透视变换以及裁剪空间的相关知识。

原文章:http://www.devacg.com/?post=522

裁剪空间Clip Space): 与视图空间相似,但是视图体被“压扁”成了一个单位立方体。通常也被称为齐次裁剪空间。顶点要从观察空间转换到裁剪空间,需要乘以一个裁剪矩阵(clip matrix),也可以被称为投影矩阵(projection matrix)。

裁剪空间的目标是能够方便的对渲染图元进行裁剪:完全位于这块空间内部的图元将会被保留,完全位于这块空间外部的图元将会被剔除,而与这块空间边界相交的图元将会被裁剪。那么这块空间是由视锥体(view frustum)来决定的。

视锥体指的是空间中的一块区域,这块区域决定了摄像机可以看到的空间。视锥体由6个平面包围而成,这些平面被称为裁剪平面(clip planes)视锥体由两种类型,这涉及到两种投影类型:一种是正交投影orthographic projection,另一种是透视投影perspective projection

在视锥体的6块裁剪平面中,有两块裁剪平面比较特殊,分别是近裁剪平面near clip plane和远裁剪平面far clip plane,他们决定了摄像机可以看到的深度范围。

透视投影:

正交投影

前面讲到,我们希望根据视锥体转成的区域对图元进行裁剪,但是如果直接使用视锥体定义的空间来进行裁剪,那么不同的视锥体就需要不同的处理过程,而且对于透视投影的视锥体来说,想要判断一个顶点是否处于一个金字塔内部是比较困难的,因此我们需要更加通用的方便的方式来进行裁剪工作,这种方式就是通过一个投影矩阵把顶点转换到一个裁剪空间中。

投影矩阵有两个目的:

  • 首先是为投影做准备。这个是迷惑点,虽然投影矩阵的名称包含了投影两字,但他并没有进行真正的投影工作,而是在为投影做准备。真正的投影是发生在后面的齐次除法homogeneous division过程中,而经过投影矩阵变换后,顶点的w分量将会有特殊的意义。
  • 其次是对xyz分量进行缩放。我们上面所讲的直接使用视锥体的6个裁剪平面来进行裁剪会比较麻烦,而经过投影矩阵的缩放后,我们可以直接使用w分量作为一个范围值,如果xyz分量都位于这个范围内,则说明该顶点位于裁剪空间内。

读者:投影到底是什么意思呢?
答:我们可以理解成一个空间的降维,例如从四维空间投影到三维空间中,而投影矩阵实际上不会进行这个步骤,他会为真正的投影做准备工作,真正的投影会在屏幕映射的时候发生,通过齐次除法来得到而为坐标。

在裁剪空间前,虽然我们使用了齐次坐标来表示顶点和矢量,但他们的第四分量都是固定的:点的w分量是1,方向矢量的w分量是0。经过投影矩阵变换后,我们就会赋予齐次坐标的第4个坐标更加丰富的含义。下面我们来看看两种投影类型使用的投影矩阵具体是什么。

透视投影

视锥体的意义在于定义了场景中的一块三维空间。所有位于这块空间内的物体将会被渲染,否则就会被提出和裁剪。我们已经知道,这块区域由6个裁剪平面定义,那么这6个裁剪平面又是怎么定义的呢?在unity中,他们由camera组件中的参数和game视图的纵横比共同决定。上图可以看出,我们可以通过camera组件中的field of view(简称FOV)属性来改变视锥体竖直方向的张开角度,而clipping planes中的near和far参数可以控制视锥体的近裁剪平面和远裁剪平面距离摄像机的远近。这样,我们可以求出视锥体近裁剪平面和远裁剪平面的高度,也就是:

nearClipPaneHeight=2●Near●tan(FOV/2)
farClipPlaneHeight=2●Far●tan(FOV/2)

现在我们还缺乏横向的信息。这可以通过摄像机的纵横比得到。在unity中,一个摄像机的纵横比由Game视图的纵横比和viewport rect中的W和H属性共同决定,(实际上,unity允许我们在脚本里通过camera aspect进行更改,这里不做讨论)假设当前摄像机的正恒比为Aspect,我们定义:

Aspect=nearClipPlaneWidth/nearClipPlaneHeight
Aspect=farClipPlaneWidth/farClipPlaneHeight

现在我们可以根据已知的near。far。fov和aspect的值来确定投影矩阵。如下

需要注意的是,这里的投影矩阵是建立在unity对坐标系的假定上面的,也就是说,我们针对的是观察空间为右手坐标系,使用列矩阵在矩阵右侧进行相乘,且变换后z分量范围将在[-w ,w]之间的情况。而在类似directX这样的图形接口中,它们希望变换后的分量范围在[0,w]之间,因此就需要对上面的透视矩阵进行一些更改。

而一个顶点和上述投影矩阵相乘后,可以由观察空间变换到裁剪空间中,结果如下:

从结果可以看出,这个投影矩阵本质就是对XYZ分量进行不同程度的缩放,z分量还做了一个平移。缩放的目的是为了方便裁剪。我们可以注意到,此时的顶点的w分量不在是1,而是原先z分量的取反结果。形状我们就可以按如下不等式来判断一个变换后的顶点是否在视锥体内。如果一个顶点在视锥体内,那么它变换后的坐标必须满足:x,y,z∈[-w,w]任何不满足上述条件的元素将被提出或者裁剪。

 

从上图可以看出,此案件矩阵将会改变空间的旋向性:空间从右手坐标系变换到左手坐标系。这意味着离摄像机越远,z值将越大。

正交投影

首先我们还是要看一下正交投影中的6个裁剪平面是怎么定义的。和透视投影类似,在unity中,它们也是有camera组件中的参数和game视图的纵横比共同决定。正交投影的视锥体是一个长方体,因此计算上相比透视投影来说更加简单。上图可以看出,我们通过camera组件的size属性来改变视锥体竖直方向上高度的一般,而clipping planes中的near和far参数可以控制视锥体的近裁剪平面和远裁剪平面距离摄像机的远近。这样,我们可以求出视锥体近裁剪平面和远裁剪平面的高度,也就是:

nearClipPaneHeight=2●size
farClipPlaneHeight=nearClipPaneHeight

现在我们还缺乏横向的信息。同样我们可以通过摄像机的纵横比得到。假设当前摄像机的纵横比为aspect,那么

nearClipPlaneWidth=Aspect●nearClipPlaneHeight
farClipPlaneWidth=nearClipPlaneWidth

现在我们根据已知的Near far size 和aspect的值来确定正交投影的裁剪矩阵,如下:

一个顶点和上述投影矩阵相乘后的结果如下:

注意到,和透视投影不同的是,使用正交投影的投影矩阵对顶点进行变换后,其w分量仍然是1,。本质是因为投影矩阵最后一行的不同,透视投影的透镜矩阵最后一行是0,0,-1,0.而正交投影的投影矩阵最后一行是0,0,0,1。这样的选择是用原因的,是为了齐次除法做准备。经过齐次除法处理后,如图判断一个变换后的顶点是否位于视锥体内,使用的判定方法同上,这种通用性也是为什么咬使用投影矩阵的原因之一。同样,裁剪矩阵改变了空间的旋向性。可以注意到,经过正交投影变换后的顶点实际已经位于一个立方体内了。




上一篇:
下一篇:

头像

guodong

说点什么

avatar
  Subscribe  
提醒