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

article/2025/10/15 6:12:30

-潘宏

-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厂商之间的问题等等。但对于我们来说,抓住了原理以及方法,不论如何变化都应该不会迷失。下次见!

 


http://chatgpt.dhexx.cn/article/ICuPg0RJ.shtml

相关文章

凯文·凯利:AI将改变一切设计工作

每一项新技术诞生之初都会引发新一轮科技恐慌周期,近期大火的AI生成艺术更是如此。连线杂志创始主编、知名科技思想家凯文凯利(Kevin Kelly)在6个月重度使用之后认为,这次AI进展的确是一次令人震惊的突破。但是,它不会…

鼠标双击退出应用程序简单实现

文章目录 Android 简单模拟鼠标双击退出应用程序,利用Toast提示“再点一次退出”使用Toast鼠标单击提示信息鼠标双击实现退出系统 Android 简单模拟鼠标双击退出应用程序,利用Toast提示“再点一次退出” 使用Toast // 参数:当前上下文环境&…

如何用JavaScript完美地区分双击和单击事件

通过一个悬浮球交互功能的案例来阐述问题,以及解决办法。 实现效果 类似微信里的悬浮窗效果,苹果手机的悬浮球功能效果 1.可以点击拖动,然后吸附在窗口边缘2.点击悬浮球,可以跳转界面,或者更改悬浮球的形态准备 1.移…

单机显示、双击隐藏;事件绑定、单击div、双击div、删除事件;元素显示、隐藏、交替; 向上收缩、向下展开、交替;淡入淡出

单机显示、双击隐藏 <style>div {width: 500px;height: 200px;background-color: green;display: none;} </style> <body><button id"btn">单击显示&#xff0c;双击隐藏</button><br><br><div> </div&…

干货分享 | UE游戏鼠标双击判定

UE虚幻引擎对于游戏开发者来说都不陌生&#xff0c;市面上有47%主机游戏使用虚幻引擎开发游戏。作为是一款游戏的核心动力&#xff0c;它的功能十分完善&#xff0c;囊括了场景制作、灯光渲染、动作镜头、粒子特效、材质蓝图等。本文介绍了虚幻引擎游戏开发过程中游戏鼠标双击判…

鼠标单击变双击问题

解决此问题可以从硬件和软件两方面思考角度入手:我们先把鼠标插在别人的机器上使用,如果没发现问题可能是软件问题,若发现同样的问题则可能是硬件方面的问题。 软件方面:(1)病毒导致将杀毒软件病毒库更新至最新版,全盘扫描。 (2)鼠标属性设置不当我们打开控制面板-&…

鼠标双击事件

随时随地阅读更多技术实战干货&#xff0c;获取项目源码、学习资料&#xff0c;请关注源代码社区公众号(ydmsq666) java中没有给出鼠标双击事件&#xff0c;虽然可以通过事件源e.getClickCount()2来判断鼠标点击次数&#xff0c;但是执行双击事件的同时也执行了单击事件&#x…

关于双击与单击事件冲突解决方案

有时候会要需求要求&#xff0c;比如附件&#xff0c;单击查看详情&#xff0c;双击下载文件时遇到的双击单击事件同时绑定一个节点。 比如单击click&#xff0c;dlbclick同时绑定时&#xff0c;双击会同时触发&#xff0c;而且click会触发两次。单用click来处理双击单击同时存…

TRUE PARTNER迎来戴维斯双击,资产规模业绩双增长

配图来自Canva可画 2020年可谓是黑天鹅乱舞的一年&#xff0c;新冠疫情肆虐全球&#xff1b;原油危机引发的资本市场动荡&#xff1b;地缘政治冲突以及美国大选&#xff0c;市场处于时不时来一波的上蹿下跳的状态当中。 在资本市场波动加剧的大环境中&#xff0c;有这样一家奇…

慧择业务布局成效明显,戴维斯双击可期

“没有一个冬天不会过去&#xff0c;没有一个春天不会到来”。 过去的一年&#xff0c;美股市场波折不断&#xff0c;尤其是2020年3月份的4次熔断&#xff0c;让股神巴菲特都惊呼“活久见”。 过去的一年&#xff0c;美股市场惊喜不断&#xff0c;道琼斯指数更是在2020年11月创…

流动性持续改善,佳源国际迎来“戴维斯双击”?

随着上半年密集的救市政策出台&#xff0c;房地产行业迎来触底回暖。 5月&#xff0c;央行以不低于市场报价利率20个基点调整首套房贷款利率下限&#xff0c;这也让当前金融环境在近几年处于较为宽松的阶段。 据克而瑞研究中心观点&#xff0c;因冲刺年中业绩&#xff0c;房企…

湖人詹姆斯 戴维斯 拉塞尔三人合体就赢!

湖人主力詹姆斯&#xff08;LeBron James&#xff09;球星成为NBA新历史得分王后&#xff0c;连3战因伤缺席&#xff0c;今天主场对抗鹈鹕终于回归&#xff0c;和戴维斯&#xff08;Anthony Davis&#xff09;、拉塞尔&#xff08;DAngelo Russell&#xff09;三人连线&#xf…

九龙证券|游戏板块或继续迎来业绩估值“戴维斯双击”

机构指出&#xff0c;AIGC技术及产品现在已在游戏职业有部分使用&#xff0c;中长期来看&#xff0c;对游戏制作的降本增效、内容质量进步有较强的促进作用&#xff1b;当前游戏版号常态化发放&#xff0c;政策端不确定性降低&#xff0c;预计产品周期是成绩的要害驱动&#xf…

戴维斯双击背后的故事 - 读《戴维斯王朝》

一、序言 作为一个对炒股知识孤陋寡闻的新手&#xff0c;我最近才听说「戴维斯双击」&#xff0c;于是买了《戴维斯王朝》了解了一下戴维斯本人以及他的成功故事。看完书后&#xff0c;我感觉戴维斯本人还真算是一段传奇经历。 戴维斯的投资回报率和巴菲特对等&#xff0c;他投…

科普一下,什么是戴维斯双击和戴维斯双杀?

创业板受到多重利空压制而大跌&#xff0c;上证也受到拖累&#xff0c;只有上证50小幅翻红。创业板依然是下跌趋势&#xff0c;不要瞎猜底部&#xff0c;更不要轻易抄底&#xff0c;要以均线为准&#xff0c;反弹站上5日线才有短线机会。主板部分板块仍然是处于上升趋势&#x…

股票策略 —— 戴维斯双击

1、策略概述 这里的戴维斯是美国的一个投资大师&#xff0c;38 岁才开始投资生涯&#xff0c;初始资金 5 万美元&#xff0c;最终财富达到 9 亿美元&#xff0c;并登上福布斯400 富豪榜。他投资策略中的选股的要点是良好的管理、持续增长及低估值。 后来基于这两个原则&#x…

戴维斯双击策略的实现与验证

戴维斯双击策略的实现与验证 戴维斯效应简述&#xff1a; 戴维斯双击和戴维斯双杀&#xff1a; 戴维斯效应&#xff0c;就是有关市场预期与上市公司价格波动之间的双倍数效应。也就是说当一个公司利润持续增长使得每股收益提高&#xff0c;同时市场给予的估值也提高&#xf…

如何在Github上建立自己的个人博客网站详细教程

概述 之前闲着没事,就利用Github建了一个个人博客网站,效果还不错,今天就来分享一下. 建立自己个人博客网站的好处: 1.面试装逼,这个不必多说… 2.把平时积累的知识和项目记录下来,方便日后查看使用 3.不受其他博客平台的限制 准备工作 开始之前,先大致介绍一下用到的技术和…

怎么创建自己的博客网站

怎么创建自己的博客网站最简单的方法还是使用wordpress系统来搭建&#xff0c;使用者不需要掌握很多的专业知识就能独立操作。 首先&#xff0c;在wordpress官网上&#xff08;https://wordpress.org/&#xff09;下载wordpress-5.1.zip这个压缩包。 其次&#xff0c;登录空间…

新手如何自己搭建一个属于自己的博客网站?

网站开发技术新手建立一个属于自己的个人博客站点&#xff0c;其实是挺容易。现在各类企业、博客、商城类的网站框架比比皆是&#xff0c;也都有对应的操作文档&#xff0c;仔细看一遍文档&#xff0c;操作起来也是非常简单的。那么下面 德阳SEO优化就带着各位准站长操作一下如…