投影矩阵的推导(转载)

转载自kanego http://www.cnblogs.com/kanego/articles/2346971.html

[译] - 投影矩阵的推导

原帖地址:

http://www.codeguru.com/cpp/misc/misc/math/article.php/c10123__1/Deriving-Projection-Matrices.htm

译文:

矩阵变换作为3d图形程序员的基本知识,投影矩阵是其中很复杂的内容。平移和缩放是容易理解的,旋转矩阵只需要掌握了基本的三角几何知识,但是投影 矩阵不一样。如果你看过投影矩阵的形式,你会发现你很难很快知道它是怎么来的。而且,我在网上没有发现很多有关推导投影矩阵的资源。本文就是讲述如何推导 投影矩阵。

对于新接触3d图形学的人来说,推导投影矩阵需要有一定的数学基础,但不是必须的。你可以直接使用最后的公式,如果你使用一种图形API,如 Direct3D,通常你不需要关心,因为API已经提供了计算投影矩阵的功能。一旦你理解了如何推导它,这对你没有坏处。这篇文章为了那些需要了解推导 投影矩阵细节的人的。

简介:什么是投影

计算机显示器是一个2d表面,为了显示3d物体,你需要把3d的物体转化成2d的图片,这个过程就是投影。举一个简单例子,最简单的把3d物体变到2d表面上的方法是去掉z坐标。对于1个立方体,如下图1。

图1:去掉z坐标投影到xy平面

当然,图1方法很简单,大多数情况不适用。这里不会投影到一个平面上,相反,这里讲的投影会把物体变换到一个规范的是视空间(canonical view volume这个是叫什么?)。对于规范的视空间的坐标,不同图形API可能不同。作为讨论起见,这里使用Direct3D的,即(-1, -1, 0)到(1, 1, 1)。一旦物体的坐标转换到了规范的视空间里面,其中的x、y坐标就用于映射到屏幕空间,z坐标一般用于z-buffer。

注意图1使用了左手坐标系。这也是Direct3D的形式,本文将一直使用左手坐标系。对于右手坐标系,本文讲述的知识都是适用的。

现在可以开始讲投影变换了。这里主要讲述2中最普遍的形式:正投影和透视投影。

正投影

正投影是一种简单的投影形式,要求所有的投影射线垂直于投影面。正投影最终的规范视空间是一个AAB(axis-aligned box),如下图2。

图2:正投影

从图中可以看出,规范的视空间是由6个面组成的:

左:x = l

右:x = r

下:y = b

上:y = t

近:z = n

远:z = f

由于正投影的视锥(view volume)和规范视空间(canonical view volume)都是AAB,所以不会有像透视投影那样随距离变化的特性。对于正投影,所有的物体的大小不会变化,而且不会随着距离变化。

图3:简单的正投影应用(原文里的图 转帖者添加)

下面开始推导正投影矩阵。一个在view volume中的点的x坐标在[l, r],这需要变换到canonical view volume中的[-1, 1]。

l <= x <= r

0 <= x-l <= r-l

0 <= (x-l)/(r-l) <= 1

0 <= 2(x-l)/(r-l) <= 2

-1 <= 2(x-l)/(r-l) - 1 <= 1

-1 <= (2x-r-l)/(r-l) <= 1

最后你需要得到px+q的形式,所以分解成:

-1 <= 2x/(r-l) - (r+l)/(r-l) <= 1

所以得到了在canonical view volume中的x坐标:

x‘ = 2x/(r-l) - (r+l)/(r-l)

同理得到在canonical view volume中的y坐标:

y‘ = 2y/(t-b) - (t+b)/(t-b)

最后来推导z‘的公式。在view volume中的点的z坐标在[n, f],需要变换到canonical view volume中的[0, 1]。

n <= z <= f

0 <= z-n <= f-n

0 <= (z-n)/(f-n) <= 1

0 <= z/(f-n) - n/(f-n) <= 1

得到z‘的表达式:

z‘ = z/(f-n) - n/(f-n)

总结上面的x‘, y‘和z‘,

x‘ = 2x/(r-l) - (r+l)/(r-l)

y‘ = 2y/(t-b) - (t+b)/(t-b)

z‘ = z/(f-n) - n/(f-n)

如果写成矩阵形式:

在Direct3D中一个函数D3DXMatrixOrthoOffCenterLH()正好提供了这个功能(注意到形式有些不同,是行/类矩阵的区别)。“LH”表示的是左手坐标系,但是“OffCenter”表示的又是什么呢?

第一,在Camera空间,如果Camera被放置在原点,并且方向沿着z轴;第二,如果r = -l,t = -b,并且定义x轴上的宽度w和y轴上的高度h,那么

上面的矩阵和Direct3D中的D3DXMatrixOrthoLH()计算的结果一致。

如果把正投影的矩阵分解成如下:

注意变换形式是:p‘(canonical view volume) = P0 * P(view volume)。

通过这个分解,可以这样来理解正投影矩阵,首先,吧view volume沿z轴把近平面移到原点,其次,缩放使得view volume变换到canonical view volume。

透视投影

透视投影因为可以产生距离的错觉(远方的物体看起来更小),所以可以产生更真实的效果,被广泛使用。它和正投影不同的地方是,透视投影的view volume是一个锥体,如下图4:

图4:透视投影

从图中可以看出view frustum的近平面由(l, b, n)延伸到(r, t, n)。

步骤一:对于view frustum中的一个点(x, y, z),把它投影到近平面z = n。因为 投影点在近平面上,所以x坐标的范围在[l, r],y坐标的范围在[b, t]。如 图5

步骤二:使用在正投影中学习的知识,把在近平面上x的[l, r]隐射到[-1, 1],y的[b,  t]隐射到[-1, 1]。

图5

第一步:得到投影点

所以得到投影点(x*n/z, y*n/z, n)。

第二步:把第一步中得到的投影点,运用正投影中学习的知识隐射。

代入x = x*n/z 和 y = y*n/z,

乘以z,

把(x, y, z)隐射到(x‘z, y‘z, z‘z),所以需要求z‘z

假设z‘z = pz + q,而z坐标的隐射是[n, f]到[0, 1],所以得到:

0 = pn + q

f = pf + q

解方程得:

p = f/(f-n)

q = -fn/(f - n)

所以,

z‘z = fz/(f-n) - fn/(f-n)

总结在一起,

写成矩阵形式:

上面的矩阵可以使得,p * (x, y, z, 1) = (x‘z, y‘z, z‘z, z)。这个也是和Direct3D中的D3DXMatrixPerspectiveOffCenterLH()是一样的(注意行/列区别)。同正投影中, 如果满足一定的条件,r = -l,t = -b,则有下面的矩阵形式:

这个就和Direct3D中的D3DXMatrixPerspectiveLH()结果一样。

最后,有必要说一下牵扯到宽高比的矩阵表示形式。

如图6:

图6

cot(a/2) = n / (h/2) = 2n/h

假设r = w/h,即宽高比

2n/w = 2n/(rh) = (1/r) * cot(a/2)

则有以下形式:

这个形式就和Direct3D中的D3DXMatrixPerspectiveFovLH()结果一样。

注:

本文原本准备翻译,后来没耐心了,话说最近我做事一直都没什么耐心了,所以没怎么按照原文翻译,而是把重要的列出来。

上面说的一些推导公式有些不用那么繁琐,但是总的来看,很值得一读。

时间: 2024-11-03 21:39:33

投影矩阵的推导(转载)的相关文章

投影矩阵的推导(Deriving Projection Matrices)

本文乃<投影矩阵的推导>译文,原文地址为: http://www.codeguru.com/cpp/misc/misc/math/article.php/c10123__1/Deriving-Projection-Matrices.htm,由于本人能力有限,有译的不明白的地方大家可以参考原文,谢谢^-^! 译者: 流星上的潴 如需转载,请注明出处,感谢! 在3D图形程序的基本矩阵变换中,投影矩阵是其中比较复杂的.平移和缩放浏览一下就能理解,旋转矩阵只要掌握了三角函数知识也可以理解,但投影矩阵有

投影矩阵的推导(Deriving Projection Matrices)(转)

本文乃<投影矩阵的推导>译文,原文地址为: http://www.codeguru.com/cpp/misc/misc/math/article.php/c10123__1/Deriving-Projection-Matrices.htm,由于本人能力有限,有译的不明白的地方大家可以参考原文,谢谢^-^! 在3D图形程序的基本矩阵变换中,投影矩阵是其中比较复杂的.平移和缩放浏览一下就能理解,旋转矩阵只要掌握了三角函数知识也可以理解,但投影矩阵有点棘手.如果你曾经看过投影矩阵,你会发现你的常识不

转载+整理 - 计算机图形学 - 模型视图矩阵和投影矩阵

出处:http://blog.csdn.net/qb371/article/details/8650094 根据原文,我将其中关于模型视矩阵和投影矩阵的比较重要的知识整理出来再加工一下,如果有什么地方看得不适合明白的话还是去看一下原文吧. 模型矩阵 我们必须考虑,当空间中点的位置会发生变化的时候,其坐标如何变化.考虑三种基本的变换:平移.旋转和缩放. “变换”的含义就是,将点的初始位置的坐标P映射到平移.旋转.缩放后的位置坐标P’,即: 平移变换是最简单的变换: 旋转变换有一些复杂,先看在二维平

透视矩阵的推导(最直观、最深度、最还原,看完请点赞。)

由参数l,r,b,t,n,f定义的透视投影矩阵的推导困惑了我差不多一个多礼拜,这几天几乎是天天都在思考这个问题,昨天晚上3点多钟我突然醒了,然后我又开始想这个问题,结果终于让我给想通了,于是我赶紧起床把这个思路记在了草稿纸上,还专门照了张照片作证. 为了解决这个问题,前几天我专门发了两篇帖子求答案,结果知网上的竟然沉掉了.而在csdn上也没有得到答案(质疑有关透视投影矩阵的推导).幸亏我自己还是解决了这个问题. 下面推导的是OpenGL中的透视投影矩阵. 已经知道由参数fovy,aspect,n

Android OpenGL ES(六)----进入三维在代码中创建投影矩阵和旋转矩阵

我们现在准备好在代码中添加透视投影了.Android的Matrix类为它准备了两个方法------frustumM()和perspectiveM().不幸的是,frustumM()的个缺陷,它会影响某些类型的投影,而perspectiveM()只是从Android的ICS版本开始才被引入,在早期的Android版本里并没有这个方法.我们可以简单地支持ICS及其以上的版本,但是这样会丢掉很大一部分市场,一些用户依然运行早期的Android版本. 作为替代,我们可以创建我们自己的方法来实现投影矩阵.

写给VR手游开发小白的教程:(四)补充篇,详细介绍Unity中相机的投影矩阵

这篇作为上一篇的补充介绍,主要讲Unity里面的投影矩阵的问题: 上篇的链接写给VR手游开发小白的教程:(三)UnityVR插件CardboardSDKForUnity解析(二) 关于Unity中的Camera,圣典里面对每一项属性都做了简要的介绍,没看过的小伙伴传送门在下面 http://www.ceeger.com/Components/class-Camera.html 一.裁剪面 先从这个专业的词汇开始,以下是圣典对裁剪面的介绍: The Near and Far Clip Plane

【脚下生根】之深度探索安卓OpenGL投影矩阵

世界变化真快,前段时间windows开发技术热还在如火如荼,web技术就开始来势汹汹,正当web呈现欣欣向荣之际,安卓小机器人,咬过一口的苹果,winPhone开发平台又如闪电般划破了混沌的web世界. 相信很多开发者都在疑问,为什么世界不是围着我转?而是我在围着世界转.我的答案是,少林寺的和尚学打架,首先要学会站桩.要练功,先占三年桩.少林寺的和尚打架从来不围着别人转,而是别人围着他转. 世界的原理都是相通的,开发者一样,要做到脚下生根. 最近几天在看OpenGL的投影矩阵,自己也实现了一个投

(数学)最小二乘的几何意义及投影矩阵

主要内容: 什么是最小二乘 最小二乘的几何意义 正交投影矩阵 什么是最小二乘? 假设我们手上有n组成对的数据,{(xi,yi):i=1…n},为了探究y变量与x变量的关系,我们希望用一个多项式来匹配它,可是多项式中的系数怎么确定呢?拿来拼凑肯定是不行的,最小二乘法告诉我们,这个多项式的系数应该让每个点的误差的平方之和最小. (百度百科)最小二乘法(又称最小平方法)是一种数学优化技术.它通过最小化误差的平方和寻找数据的最佳函数匹配.利用最小二乘法可以简便地求得未知的数据,并使得这些求得的数据与实际

【线性代数】如何寻找一个投影矩阵

引言 想一下,在什么情况下可能需要将一个向量往一个子空间投影.在MIT的线代课程中,Gilbert教授给出了一种场景:即我们想要求解\(Ax=b\),但是\(b\)不在\(A\)的列空间中,此时我们希望在\(A\)的列空间中找一个离\(\overrightarrow{b}\)最近的向量\(\overrightarrow{f}\),求解\(A\hat{x}=f\),借由\(\hat{x}\)给出\(x\)的近似解. 矩阵乘法可以表示向量的线性变换,所以本篇笔记的主要内容是记录找到一个投影矩阵\(P