透视投影 在不同图形API实现,如OpenGL和D3D

来源:互联网 发布:java开发实战经典 编辑:程序博客网 时间:2024/05/16 01:14

在上一篇文章(http://blog.csdn.net/popy007/article/details/1797121)中我们讨论了透视投影变换的原理,分析了OpenGL所使用的透视投影矩阵的生成方法。

正如我们所说,不同的图形API因为左右手坐标系、行向量列向量矩阵以及变换范围等等的不同导致了矩阵的差异,可以有几十个不同的透视投影矩阵,但它们的原理大同小异。


本文努力让读者清楚地了解D3DM3G透视投影矩阵的原理,

从而能够知道它与OpenGL的一些差别,

为构建跨API的图形引擎打好基础


OpenGLD3D的基本差异

导致OpenGLD3D的透视投影矩阵不同的原因有以下几个:

(1)       OpenGL默认使用右手坐标系,而D3D 默认使用左手坐标系。


(2)       OpenGL使用列向量矩阵乘法而D3D使用行向量矩阵乘法。





(3)       OpenGLCVVZ范围是[-1, 1]D3DCVVZ范围是[0, 1]

以上这些差异导致了最终OpenGLD3D的透视投影矩阵的不同。








D3D的透视投影矩阵推导

我们先来看最最基本的透视关系图(上一篇文章开始的时候使用的图):



根据相似三角形定理,我们有


则有


注意到OpenGL使用右手坐标系,因此应该使用-N(请参考上一篇文章的这一步),而D3D使用左手坐标系,因此使用N,这是者的不同点之一。

-N 说明原因:就是这张左右手图,右手法则向里面是 负数,所以是-N(我这样理解不知道对不对????????)

这样,我们得到投影之后的点


第三个信息点是变换之后的z在投影平面上的位置,也就是N,它已经没用了,我们把p’写成




从而用第三个没用信息点它来存储z(如果读者对这一点不太了解,请参考上一篇文章)。

接下来我们求出ab,从而在z方向上构建CVV

请注意这里是OpenGLD3D的另一个不同点,OpenGLCVVz范围是[-1, 1],而D3DCVVz范围是[0, 1]

也就是说,D3D 中在近裁剪平面上的点投影之后的点会处于CVVz=0平面上,而在远裁剪平面上的点投影之后的点会在CVVz=1平面上。

这样我们的计算方程就是






而openGL则是:

===================================================================================================================================================================================

后面的CVV是一个x,y,z的范围都为[-11]的规则体,便于进行多边形裁剪。而我们可以适当的选择系数ab,使得这个式子在z = -N的时候值为-1,而在z = -F的时候值为1,从而在z方向上构建CVV

 

接下来我们就求出ab


=======================================================================================================================


从而我们得到了透视投影矩阵的第一个版本





这个时候第三个分量变换到CVV情形了,CVVz范围是[0,1]

接下来根据上一篇文章所讲到的,

我们要把前两个分量变成CVV情形CVVxy范围是[-1, 1]

如下图所示:

使用线性插值,我们有:



这里leftright是投影平面的左右范围,

topbottom是投影平面的上下范围。

xcvvycvv是我们需要算出的在CVV情形中的xy

也就是我们要计算出的结果。但在算出它们之前,

我们先把上面的式子写成:

      这个公式 是从上面图的公式变化而来的

这里有一个需要注意的地方,如果投影平面在x方向上居中,则

 

  投影平面在x方向上居中,意味着在中间的点,但是为什么不是 - ½ 呢?????????????????????????

                 

那么第一个式子就可以销掉等号两边的1/2,写成

同理,如果投影平面在y方向上居中,则第二个式子可以写成




则我们现在分两种情况讨论:

(1)       投影平面的中心和x-y平面的中心重合(在xy方向上都居中)

(2)       一般情况

我们分别讨论:



 

1)特殊情况方程



这组是特殊情况,方程比较简单,但也是使用频率最高的方式(这D3DXMatrixPerspectiveLHD3DXMatrixPerspectiveRHD3DXMatrixPerspectiveFovLHD3DXMatrixPerspectiveFovRH四个方法所使用的情况)。我们导出它:


则我们反推出透视投影矩阵:

其中



r-lt-b可以分别看作是投影平面的宽w和高h

最后那个矩阵就是D3D的透视投影矩阵之一。

另外呢,如果我们不知道rightlefttop以及bottom这几个参量,

也可以根据视野(FOV – Field Of View)参量来求得。

下面是两个平面的视野关系图:

其中,两个fov分别是在x-z以及y-z平面上的视野。

如果只给了一个视野,也可以通过投影平面的宽高比计算出来:

用一个视野算出w或者h,然后用宽高比算出h或者w



我的理解:这里值得注意的是 xz屏幕  right还有left 在左右方向

yz屏幕左右是top bottom 在左右方向。?????????




2)一般情况的方程


这组方程比较繁琐,但更具一般性(OpenGL一般矩阵的推导一致,这也是D3DXMatrixPerspectiveOffCenterLHD3DXMatrixPerspectiveOffCenterRH两个方法所使用的情况)。我们导出它:

 


 

我们继续反推出透视投影矩阵:

其中

最后那个矩阵就是D3D一般透视投影矩阵



好了,目前为止,我们已经导出了D3D的两个透视投影矩阵。下面我把上一篇导出的OpenGL的透视投影矩阵写出来,大家可以拿它和刚刚导出的D3D的一般性透视投影矩阵做一个对比。

如果仔细观察,

          可以发现二者在元素的布局上是一个转置的关系,这个就是由它们使用的左右手坐标系以及使用的行列矩阵的差异造成的。

         而另外在一些元素的细节上也存在着差异,这是由于D3DCVVz范围不同造成的。

         可见在原理相同的情况下,细微的环境差异可以造成非常大的变化,而这就是透视投影矩阵存在诸多不同版本的原因。

         一般情况的透视投影矩阵也可以使用视野方式来定义,方法和特殊情况相同


我的解释:这个和  M3G的透视投影矩阵相同,它的透视投影变换矩阵被放到了Camera里面,有助于你得理解。见如下:M3G的透视投影矩阵

???????????











M3G的透视投影矩阵

M3G是对OpenGL进行的一个封装,

它的透视投影变换矩阵被放到了Camera里面

因为它封装了OpenGL,因此环境和OpenGL相同:右手坐标系、列向量乘法、CVV范围[-1 1]

唯一和OpenGL有些差异的地方就在于它只使用投影平面的中心和x-y平面的中心重合(在xy方向上都居中)的情况(就是我们上D3D的第一种特殊情况)。

我们用OpenGL透视投影矩阵最终版本来说明(再次提醒,如果读者对此感到迷惑,请参考第一篇文章):

上面是OpenGL透视投影矩阵的最终版本,也是一般性版本,我们要把它变成特殊性,版本,非常简单,和上面D3D的特殊情况一样,我们从对xy进行插值的那一步来看:



D3D的第一种情况一样,销掉两边的1/2,得到:

则我们反推出透视投影矩阵:

最右边那个矩阵就M3G的透视投影矩阵。仍然可以通过视野参数来设置透视投影矩阵,这里请读者自行推导,方法与上面D3D的完全相同。














0 0
原创粉丝点击