深入探索透视投影变换(续)

透视投影的矩阵计算 整理计算机图形学中,3D物体从摄像机坐标转化为规范化投影坐标的求解过程 阅读详情

-潘宏

-2009.4.14

-本人水平有限,疏忽错误在所难免,还请各位数学高手、编程高手不吝赐教

-email: popyy@netease.com

-B站专栏: https://b23.tv/oWsl6PD

 

 

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

 

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

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

(3)       M3G是J2ME平台上的3D开发包,采用了OpenGL作为底层标准进行封装。它的透视投影矩阵使用OpenGL的环境但又进行了简化,值得一提。

 

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

 

OpenGL与D3D的基本差异

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

 

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

 fig1_coordsys.JPG

 

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

 

 fig2_mat_vec_mul.JPG

 

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

 

 

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

 

D3D的透视投影矩阵推导

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

 

fig3_proj_theory.JPG

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

 

fig4_similar_triangles.JPG

 

则有

 

fig5_components.JPG

 

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

fig6_trans_point1.JPG

 

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

fig7_trans_point2.JPG

 

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

 

 fig8_ab.JPG

 

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

 

fig9_persp_proj_ver1.JPG

 

即

fig10_persp_proj_formula.JPG

 

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

fig11_lerp1.JPG

 

使用线性插值,我们有:

 

fig12_lerp2.JPG

 

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

 

fig13_lerp3.JPG

 

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

 

 fig14_half_width.JPG

 

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

 

fig15_remove_half_width.JPG

 

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

 

fig16_remove_half_width2.JPG

 

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

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

(2)       一般情况

我们分别讨论:

 

(1)特殊情况方程

 

fig17_special_case.JPG

 

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

 

fig18_cvv_xy.JPG

 

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

 

fig19_persp_proj_mat1.JPG

 

其中

 

fig20_ab.JPG

 

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

 

fig21_fov.JPG

 

fig22_fov_deduction.JPG

 

  

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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

fig23_aspect_ratio.JPG

 

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

 

(2)一般情况的方程

 

fig24_general_case.JPG

 

 

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

 

 fig25_general_case_xy.JPG

 

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

 

fig26_general_case_mat.JPG

其中

fig27_ab.JPG

 

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

 

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

fig28_opengl_mat.JPG

 

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

M3G的透视投影矩阵

M3G是对OpenGL进行的一个封装,它的透视投影变换矩阵被放到了类Camera里面。因为它封装了OpenGL,因此环境和OpenGL相同:右手坐标系、列向量乘法、CVV范围[-1, 1]。它唯一和OpenGL有些差异的地方就在于它只使用投影平面的中心和x-y平面的中心重合(在x和y方向上都居中)的情况(就是我们上面D3D的第一种特殊情况)。我们用OpenGL透视投影矩阵最终版本来说明(再次提醒,如果读者对此感到迷惑,请参考第一篇文章):

 

fig28_opengl_mat.JPG

 

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

 

fig29_m3g_lerp.JPG

 

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

 

fig30_m3g_remove_half.JPG

 

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

 

fig31_m3g_mat.JPG

 

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

 

结束语

    我们已经完成了对D3D和M3G透视投影矩阵的说明。如果读者理解了上面的内容,可能会觉得有些厌恶——为什么没有一个统一的标准,在同一个原理下为什么要弄出这么多种差别?原因有很多,历史遗留问题、API厂商之间的问题等等。但对于我们来说,抓住了原理以及方法,不论如何变化都应该不会迷失。下次见!

 

「图形学/渲染管线/图元装配」透视投影矩阵的推导和原理解释 透视投影矩阵的推导和原理解释,希望能帮助到你! 阅读详情

相关推荐

OpenGL矩阵推导——模型视图变化(转载需写明作者)

OpenGL矩阵推导——模型视图变化 在三维编程中,模型视图变换是从三维世界到二维屏幕中一个很重要的变换,但是这个变换往往很多人都不太理解,要么是事而非。而这方面的文章不是太少就是讲的太浅没有真正的理解模型视图变换,本人在这个过程中曾经走过很多歪路,不过好在最终在自己的不懈努力下终于降伏了这只猛虎。本人就以自己的理解,通过矩阵推导过程一步一步来了解模型视图变化,最后通过两个OpenGl的程序来进

yanwei2016的专栏 8929

透视投影矩阵推导

透视投影矩阵(Perspective Matrix) 近截面与远截面之间构成的四棱台称为视锥体,而透视投影矩阵的任务就是把位于视锥体内的物体的顶点 x,y,zx,y,zx,y,z 坐标映射到 [−1,1][-1,1][−1,1] 范围。这相当于把这个四棱台扭曲变形成一个立方体。这个立方体叫做规范观察体(Canonical View Volume, CVV)。 矩阵的形式 (1aspect⋅tan⁡(fovy2)00001tan⁡(fovy2)0000−zNear−zFarzNear−zFar2⋅zNea

木·本的博客 1万+

Win11笔记本BIOS设置避坑大全:Secure Boot、RST、UEFI引导,一次讲清

本文详细解析了Win11笔记本BIOS设置中的关键问题,包括Secure Boot、Intel RST和UEFI引导的配置方法,帮助用户避开双系统安装中的常见陷阱。特别针对不同品牌笔记本的BIOS界面差异,提供了实用的操作指南和优化建议,确保系统兼容性和启动效率。

weixin_29251131的博客 689

第五章 OpenGL ES 基础-透视投影矩阵与正交投影矩阵

模型都是3D的,但屏幕是2D的。如何将3D空间投影到2D平面,还能保持深度的视觉效果?在OpenGL中,采用透视投影矩阵作用顶点来实现,即完成缩放、选择、位移之后,进行透视投影的操作。

u012836015的博客 4662

LPC2124定时器实现跑马灯

文章目录一、keil 4新建工程 一、keil 4新建工程 1、Create New Project,注意,最好添加进一个新建好的文件夹里,keil不会帮你新建。 2、添加设备类型:NXP目录下的LPC2124 3、选择启动文件Startu.s 4、new 一个file,保存命名为.c文件 5、添加进project里,右击,add 选中,添加 6、设置编译输出.hex文件 ...

qq_37937830的博客 5753

RTPS规范v2.3(中文版)

DDSI-RTPSv2.3,DDS发现互操作性-实时发布订阅通信协议,中文版

pony12的专栏 752

深入探索透视投影变换续

-潘宏 -2009.4.14 -本人水平有限,疏忽错误在所难免,还请各位数学高手、编程高手不吝赐教 -email: popyy@netease.com     在上一篇文章中我们讨论了透视投影变换的原理,分析了OpenGL所使用的透视投影矩阵的生成方法。正如我们所说,不同的图形API因为左右手坐标系、行向量列向量矩阵以及变换范围等等的不同导致了矩阵的差异,可以有几十个不同的透视投影矩阵

damenhanter的专栏 805

Claude Skills:不是更聪明,而是更“像专家”的 Agent 养成方法

Claude Skills 不是在告诉 Agent“你能做什么”, 而是在约束它“你应该如何思考、如何判断、如何给结论”。

测试者家园 1295

深入探索透视投影变换

深入探索透视投影变换-Twinsen编写-本人水平有限,疏忽错误在所难免,还请各位数学高手、编程高手不吝赐教-email: popyy@netease.com透视投影是3D固定流水线的重要组成部分,是将相机空间中的点从视锥体(frustum)变换到规则观察体(Canonical View Volume)中,待裁剪完毕后进行透视除法的行为。在算法中它是通过透视矩阵乘法和

Popy007(Twinsen)的专栏 11万+

ROS-订阅与处理激光雷达scan话题

激光雷达通常有四个性能衡量指标:测距分辨率、扫描频率(有时也用扫描周期)、角度分辨率及可视范围。测距分辨率衡量在一个给定的距离下测距的精确程度,通常与距离真实值相差在5-20mm;扫描频率衡量激光雷达完成一次完整扫描的快慢,通常在10Hz及以上;角度分辨率直接决定激光雷达一次完整扫描能返回多少个样本点;可视范围指激光雷达完整扫描的广角,可视范围之外即为盲区。

weixin_42438635的博客 4478

深度强化学习-D3QN算法原理与代码

Dueling Double Deep Q Network(D3QN)算法结合了Double DQN和Dueling DQN算法的思想,进一步提升了算法的性能。如果对Doubel DQN和Dueling DQN算法还不太了解的话,可以参考我的这两篇博文:深度强化学习-Doubel DQN算法原理与代码和深度强化学习-Dueling DQN算法原理与代码,分别详细讲述了这两个算法的原理以及代码实现。本文就带领大家了解一下D3QN算法,代码链接见下方。 代码:https://github.com/indigo

weixin_46133643的博客 2万+
上一篇: 深入探索透视投影变换
下一篇: 推导正交投影变换
popy007
博客等级 码龄25年 1026粉丝 18原创
评论 34
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值