D3D的投影矩阵推导[转贴]

原帖地址:http://blog.csdn.net/popy007/article/details/4091967

      上一篇文章中我们讨论了透视投影变换的原理,分析了OpenGL所使用的透视投影矩阵的生成方法。正如我们所说,不同的图形API因为左右手坐标系、行向量列向量矩阵以及变换范围等等的不同导致了矩阵的差异,可以有几十个不同的透视投影矩阵,但它们的原理大同小异。这次我们准备讨论一下Direct3D(以下简称D3D)的透视投影矩阵,主要出于以下几个目的:

(1) 我们在写图形引擎的时候需要采用不同的图形API实现,当前主要是OpenGL和D3D。虽然二者的推导极为相似,但D3D的自身特点导致了一些地方仍然需要澄清。

(2) DirectX SDK的手册中有关于透视投影矩阵的一些说明,但并不详细,甚至有一些错误,从而使初学者理解起来变得困难,而这正是本文写作的目的。

     本文努力让读者清楚地了解D3D透视投影矩阵的原理,从而能够知道它与OpenGL的一些差别,为构建跨API的图形引擎打好基础。需要指出的一点是为了完全理解本文的内容,请读者先理解上一篇文章《深入探索透视投影变换》的内容,因为OpenGL和它们的透视投影矩阵的原理非常相似,因此这里不会像上一篇文章从基础知识讲起,而是对比它们的差异来推导变换矩阵。我们开始!

OpenGLD3D的基本差异

        前面提到,不同API的基本差异导致了最终变换矩阵的不同,而导致OpenGL和D3D的透视投影矩阵不同的原因有以下几个:

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

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

(3) OpenGL的归一化CVV的Z范围是[-1, 1],D3D的归一化CVV的Z范围是[0, 1]。

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

D3D的透视投影矩阵推导

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

 

       这里我们考察的是xz平面上的关系,yz平面上的关系同理。这里o是相机位置。np是近裁剪平面,也是投影平面,N是它到相机的距离。fp是远裁剪平面,F是它到相机的位置。p是需要投影的点,p’是投影之后的点。根据相似三角形定理,我们有

则有

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

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

      从而用第三个没用信息点它来存储z(如果读者对这一点不太了解,请参考上一篇文章)。接下来我们求出a和b,从而在z方向上构建CVV。请注意这里是OpenGL和D3D的另一个不同点,OpenGL的归一化CVV的z范围是[-1, 1],而D3D的归一化CVV的z范围是[0, 1]。也就是说,D3D 中在近裁剪平面上的点投影之后的点会处于归一化CVV的z=0平面上,而在远裁剪平面上的点投影之后的点会在归一化CVV的z=1平面上。这样我们的计算方程就是

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

     这个时候第三个分量变换到CVV情形了,归一化CVV的z范围是[0,1]。接下来根据上一篇文章所讲到的,我们要把前两个分量变成归一化CVV情形,归一化CVV的x和y范围是[-1, 1],如下图所示:

使用线性插值,我们有:

      这里left和right是投影平面的左右范围,top和bottom是投影平面的上下范围。xcvv和ycvv是我们需要算出的在归一化CVV情形中的x和y,也就是我们要计算出的结果。但在算出它们之前,我们先把上面的式子写成:

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

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

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

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

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

(2) 一般情况

我们分别讨论:

1)特殊情况方程

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

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

其中

而r-l和t-b可以分别看作是投影平面的宽w和高h。最后那个矩阵就是D3D的透视投影矩阵之一。另外呢,如果我们不知道right、left、top以及bottom这几个参量,也可以根据视野(FOV – Field Of View)参量来求得。下面是两个平面的视野关系图:

其中,两个fov分别是在x-z以及y-z平面上的视野。如果只给了一个视野,也可以通过投影平面的宽高比计算出来:

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

2)一般情况的方程

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

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

其中

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

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

      如果仔细观察,可以发现二者在元素的布局上是一个转置的关系,这个就是由它们使用的左右手坐标系以及使用的行列矩阵的差异造成的。而另外在一些元素的细节上也存在着差异,这是由于D3D的CVV的z范围不同造成的。可见在原理相同的情况下,细微的环境差异可以造成非常大的变化,而这就是透视投影矩阵存在诸多不同版本的原因。一般情况的透视投影矩阵也可以使用视野方式来定义,方法和特殊情况相同。

时间: 2024-08-02 04:18:39

D3D的投影矩阵推导[转贴]的相关文章

opengl 教程(12) 投影矩阵

原帖地址:http://ogldev.atspace.co.uk/www/tutorial12/tutorial12.html        现在我们开始学习如何把三维物体投影到二维平面上,同时保持它的深度.通常的投影包括平行投影和透视投影:平行投影比较简单,就是把顶点垂直的投向投影平面,常用在cad或者机械制图中.另外一种投影是透视投影,这种投影能较好的使二维投影显示立体感,因为人眼观看物体符合透视原理,透视原理也是学美术的人的必修课程.最常见的透视原理表现形式就是三维世界的平行线在透视几何中

极线校正-计算机视觉中给定两幅图像以及投影矩阵情况下,如何计算极线影像?

问题描述 计算机视觉中给定两幅图像以及投影矩阵情况下,如何计算极线影像? 已知条件只有两幅影像和对应投影矩阵,我通过查阅资料发现采用stereoRectify函数可以进行极线校正,最后得到极线影像(就是水平对齐,y视差为0),那么在输入函数参数中,我有以下几个问题: 1.cameraMatrix1,R,T是否可以直接用投影矩阵P分解得到?就是对应的K R T么? 2.distCoeffs参数怎么获取得到呢?或者是默认不存在畸变? 3.本人采用的方法是否正确,就是采用stereoRectify此方

dlt-基础矩阵(F矩阵)和投影矩阵把我弄混了

问题描述 基础矩阵(F矩阵)和投影矩阵把我弄混了 我一直看的是根据两组二维坐标求基础矩阵(也就是F矩阵),可是今天看了一个源码,是根据一组二维坐标和一组三维坐标求投影矩阵(好像叫DLT标定法).那到底是应该先求投影矩阵再根据投影矩阵求内参,外参,还是先求基础矩阵,再根据基础矩阵求投影矩阵?

【线性代数】最小二乘与投影矩阵

        前一篇文章<正交投影>中我们讲述了正交投影,现在我们来从正交投影的角度来看看我们熟悉的最小二乘法.我记得最早知道最小二乘法是在大一上高数课的时候,我们首先回顾一下什么是最小二乘法. 1.最小二乘法         最近机器学习比较火,机器学习中的许多算法都是对信息进行分类,比如说支持向量机就是根据已知信息来分类,神经网络可以找到输入输出的关系(当然,不能给出具体的数学表达式),这两种算法都能找到输入与输出的关系,分类和回归总是相辅相成的.以后有时间也准备写写关于机器学习方面的算

[3D基础]投影矩阵的推导(1)

转眼我做游戏行业已经八个月了,游戏行业入门门槛低,所以还算学习得比较轻松,总结了当初自己迷惑的几个知识点,本来想写出来给初学者解惑,无赖我是一个懒散的人,一直拖到现在,终于决心白纸黑字的搬到Blog上来,希望大家喜欢. 投影变换:我觉得这个是3D到2D变换中最让初学者头晕的问题,但又是最重要的. 请看上面这张我用爪子抓出来的图.这个坐标系是DX的左手坐标系,Y向上,X向右,Z向内,几何坐标已经经过了相机坐标系的变换,相机位置为(0,0,0),假设远裁减面距离为f,近裁减面距离为n,近裁减面左边为

镜面反射矩阵推导

最近公司游戏正在准备上线,所以FlasCC也就没有研究了,偶尔有闲功夫,也是玩玩3DMAX和UNITY3D. 感觉不会3DMAX,是一种局限. 回到主题,记录一下镜面反射矩阵的推导. 在用Irrlicht和RTT做镜面效果的时候,用到了反射矩阵. 就是需要把摄相机镜像,渲染一个RT,贴到镜面模型上.这个其实还纠结了许久,因为之前做水面渲染的时候,水面是平的,很好计算摄相机在水面以下的位置. 但是换成镜面,就不一样了,因为镜面可能是任意面. 于是就需要一个通用的反射矩阵. 反射矩阵的计算是基于平面

OpenGL透视投影后的Z值得范围是多少?可否自己设置矩阵改变Z值坐标?

问题描述 OpenGL透视投影后的Z值得范围是多少?可否自己设置矩阵改变Z值坐标? 透视投影后的Z值取值范围是[-1,1]还是[0,1]? 我想自己设置一个投影矩阵,投影之后使原本Z坐标大的变小,小的变大,达到的效果就是在模型前面设置一个视点,而能看到模型背面的信息? 求大神帮助哇~~

矩阵-怎么感觉OpenGL代码逻辑怪异?

问题描述 怎么感觉OpenGL代码逻辑怪异? 5C 为什么glMatrixMode(GL_PROJECTION);或者glMatrixMode(GL_MODELVIEW)//后面都加了个 glLoadIdentity();//我还没有对投影矩阵(视图)进行操作怎么就能复位了呢?glMatrixMode(...);//不是只是申明一下接下来对什么矩阵进行操作么? 解决方案 glLoadIdentity()是将矩阵变为单位阵 一般初始化的时候用 可能过程中也会用glMatrixMode()有好几种参

Opengl ES 视图与投影

注:不得不转这一篇,因为这一篇里有两个资源链接,而这两篇链接中还有链接,有空儿一定好好读一读. opengl es 视图与投影 博客分类:  android   关于android的投影矩阵,一般有两种,一种是矩阵投影,另一种是透视投影.  矩阵投影主要用于2D画面,但指定此投影的方式却有多种方式,而且对于初入门的人来说,也不容易理解,可以使用glOrthof,此方法使用方式大概如下:  Java代码   GL10 gl = glGraphics.getGL();   gl.glViewport