投影矩阵的推导(Direct3D)

更新时间:2023-05-19 01:24:37 阅读: 评论:0

投影矩阵的推导(Direct3D)
本⽂乃<;投影矩阵的推导>译⽂,原⽂地址为:
译者: 流星上的潴
压抑憋屈的图片
与时俱进造句如需转载,请注明出处,感谢!
在3D图形程序的基本矩阵变换中,投影矩阵是其中⽐较复杂的。平移和缩放浏览⼀下就能理解,旋转矩阵只要掌握了三⾓函数知识也可以理解,但投影矩阵有点棘⼿。如果你曾经看过投影矩阵,你会发现你的常识不⾜以告诉你它是怎么来的。⽽且,我在⽹上还未看到许多关于如何推导投影矩阵的教程资源。本⽂的话题就是如何推导投影矩阵。
对于刚刚开始接触3D图形的⼈,我应该指出,理解投影矩阵如何推导可能是我们对于数学的好奇⼼,它不是必须的。你可以只⽤公式,并且如果你⽤像Direct3D那样的图形API,你甚⾄都不需要使⽤公式,图形API会为你构建⼀个投影矩阵。所以,如果本⽂看起来有点难,不要害怕。只要你理解了投影矩阵做了什么,你没必要在你不想的情况下关注它是怎么做的。本⽂是给那些想了解更多的程序员的。
概述: 什么是投影?
午休的英语
计算机显⽰器是⼀个⼆维表⾯,所以如果你想显⽰三维图像,你需要⼀种⽅法把3D⼏何体转换成⼀种可作为⼆维图像渲染的形式。那也正是投影做的。拿⼀个简单的例⼦来说,⼀种把3D对象投影到2D表⾯的⽅法是简单的把每个坐标点的z坐标丢弃。对⽴⽅体来说,看上去可能像图1:
图1: 通过丢弃Z坐标投影到XY平⾯
当然,这过于简单,并且在⼤多数情况下不是特别有⽤。⾸先,根本不会投影到⼀个平⾯上;相反,投影公式将变换你的⼏何体到⼀个新的空间体中,称为规范视域体(canonical view volume),规范视域体的精确坐标可能在不同的图形API之间互不相同,但作为讨论起见,把它认为是从(-1, -1, 0)延伸
⾄(1, 1, 1)的盒⼦,这也是Direct3D中使⽤的。⼀旦所有顶点被映射到规范视域体,只有它们的x和y坐标被⽤于映射到屏幕上。这并不代表z坐标是⽆⽤的,它通常被深度缓冲⽤于可见度测试。这就是为什么变换到⼀个新的空间体中,⽽不是投影到⼀个平⾯上。
注意,图1描述的是左⼿坐标系,摄像机俯视z轴正⽅向,y轴朝上并且x轴朝右。这是Direct3D中使⽤的坐标系,本⽂中我都将使⽤该坐标系。对于右⼿坐标系系统来说,在计算⽅⾯没有明显差异,在规范视域体⽅⾯有⼀点区别,所以⼀切讨论仍将适⽤即使你的图形API使⽤与Direct3D不同的规定。
现在,可以进⼊实际的投影变换了。有许多投影⽅法,我将介绍最常见的2种:正交和透视。
正交投影(Orthographic Projection)
正交投影,之所以这么称呼是因为所有的投影线都与最终的绘图表⾯垂直,是⼀种相对简单的投影技术。视域体,也就是包含所有你想显⽰的⼏何体的可视空间——是⼀个将被变换到规范视域体的轴对齐盒⼦,见图2:
图2: 正交投影
正如你看见的,视域体由6个⾯定义:
办法英文
因为视域体和规范视域体都是轴对齐盒⼦,这种类型的投影没有距离更正。最终的结果是,事实上,很像图1那样每个坐标点只是丢弃了z坐标。对象在3D空间中的⼤⼩和在投影中的⼤⼩相同,即使⼀个对象⽐另⼀个对象距离摄像机远很多。在3D空间中平⾏的直线在最终的图像上也是平⾏的。使⽤这种类型的投影将出现⼀些问题像第⼀⼈称射击游戏——试想⼀下在不知道任何东西有多远的情况下玩!但它也有它的⽤处。你可能在格⼦游戏中使⽤它,例如,特别是摄像机被绑定在⼀个固定⾓度的⼀款格⼦游戏中,图3显⽰了1个简单的例⼦:
图3: 正交投影的⼀个简单例⼦
所以,事不宜迟,现在开始弄清楚它是如何⼯作的。最简单的⽅法可能是3个坐标轴分开考虑,并且计算如何沿着每个坐标轴将点从视域体映射到规范视域体。从x轴开始,视域体中的点的x坐标范围在[l,
r],想把它变换到范围在[-1, 1]:
现在,准备把范围缩⼩到我们期望的,各项减去l,这样,最左边的项变为0。另⼀种可能考虑的做法是平移范围使其以0为中⼼,⽽不是⼀端为0,但现在这种⽅式代数式更整洁,所以为了可读性起见我将以现在这种⽅式做:
现在,范围的⼀端是0,你可以缩⼩到期望的⼤⼩。你期望x值的范围是2个单位宽,从1到-1,所以把各项乘以2/(r-l)。注意r-l是视域体的宽度,因此始终是⼀个正数,所以不⽤担⼼不等号会改变⽅向:
下⼀步,各项减去1就产⽣了我们期望的范围[-1,1]:
基本代数允许我们将中间项写成⼀个单⼀的分数:
最后,把中间项分成两部分使它形如px+q的形式,我们需要把项组织成这种形式这样我们推导的公式就可以简单的转换成矩阵形式:
这个不等式的中间项告诉了我们把x转换到规范视域体的公式:
获取y的变换公式的步骤是完全⼀样的——只要⽤y替代x,⽤t替代r,⽤b替代l——所以这⾥不重复它们了,只是给出结果:
最后,需要推倒z的变换公式。z的推导有点不同,因为需要把z映射到范围[0, 1]⽽不是[-1, 1],但看上去很相似。z坐标最开始在范围[n,f]:
把各项减去n,这样的话范围的下限就变为了0:
现在剩余要做的就是除以f-n,这样就产⽣了最终的范围[0,1]。和前⾯相同,注意f-n是视域体的深度所以绝对不会为负:
最后,把它分成两部分使它形如px+q的形式:
这样便给出了z的变换公式
现在,可以准备写正交投影矩阵了。总结到⽬前为⽌的⼯作,推导了3个投影公式:
如果写成矩阵形式,就得到了:
就是这样!Direct3D提供了D3DXMatrixOrthoOffCenterLH()(what a mouthful!)⽅法构造⼀个和这个公式相同的正交投影矩阵;你可以在DirectX⽂档中找到。⽅法名中的"LH"代表了你正在使⽤左⼿坐标系。但是,究竟"OffCenter"的意思是什么呢?
这⼀问题的答案引导你到⼀个正交投影矩阵的简化形式。考虑⼏点: ⾸先,在可见空间中,摄像机定位在原点并且沿着z轴⽅向观看。第⼆,你通常希望你的视野在左右⽅向上延伸的同样远,并且在z轴
的上下⽅向上也延伸的同样远。如果是这样的情况,那么z轴正好直接穿过你视域体的的中⼼,所以得到了r = -l并且t = -b。换句话说,你可以把r, l, t和b⼀起忘掉,简单的把视域体定义为1个宽度w和1个⾼度h,以及裁剪⾯f和n。如果你在正交投影矩阵中应⽤上⾯说的,那么你将得到这个相当简化的版本:
这个公式是Direct3D中D3DXMatrixOrthoLH()⽅法的实现。你⼏乎可以⼀直使⽤这个矩阵替代上⾯那个你推导的更通⽤的"OffCenter"版本,除⾮你⽤投影做些奇怪的事情。
在完成这部分之前还有⼀点。它启发我们注意到这个矩阵可以⽤两个简单的变换串联替代:平移其次是缩放。如果你思考⼏何的话这对你是有意义的,因为所有你在正交投影中做的就是从⼀个轴对齐盒⼦转向另⼀个轴对齐盒⼦;视域体不改变它的形状,只改变它的位置和⼤⼩。具体来说,有:
这种投影⽅式可能更直观⼀点因为它让你更容易想象发⽣了什么。⾸先,视域体沿着z轴平移使它的近平⾯和原点重合;然后,应⽤⼀个缩放把它缩⼩到规范视域体⼤⼩。很容易理解吧,对不对?⼀个偏离中⼼(OffCenter)的正交投影矩阵也可以⽤⼀个变换和⼀个缩放代替,它和上⾯的结果很相似所以我在这⾥不列出了。
上⾯就是正交投影,现在可以去接触⼀些更有挑战性的东西了。
透视投影(Perspective Projection)
透视投影是稍复杂的⼀种投影⽅法,并且⽤的越来越平凡,因为它创造了距离感,因此会⽣成更逼真的图像。从⼏何上说,这种⽅法与正交投影不同的地⽅在于透视投影的视域体是⼀个平截头体——也就是,⼀个截断的⾦字塔,⽽不是⼀个轴对称盒⼦。见图4:
德国闪电战图4: 透视投影
正如你所看见的,视域体的近平⾯从(l,b, n)延伸⾄(r, t, n)。远平⾯范围是从原点发射穿过近平⾯四个点的射线直⾄与平⾯z=f相交。由于视域体从原点进⼀步延伸,它变得越来越宽⼤;同时你将这个形状变换到规范视域体盒⼦;视域体的远端⽐视域体的近端压缩的更厉害。因此,视域体远端的物体会变得更⼩,这就给了你距离感。
由于空间体形状的这种变换,透视投影不能像正交投影那样简单的表达为⼀个平移和⼀个缩放。你必须制定⼀些不同的东西。但是,这并不意味着你在正交投影上做的⼯作是⽆⽤的。⼀个⽅便的解决数学问题的⽅法是把问题减少到你已经知道怎么解决的那⼀个。所以,这就是你在这⾥可以做的。上⼀
次,你⼀次检查⼀个坐标,但这次,你将把x和y坐标合起来⼀起做,然后再考虑z坐标。你对x和y的处理可以分2个步骤:
第1步: 给定视域体中的点(x,y, z),把它投影到近平⾯z=n。由于投影点在近平⾯上,所以它的x坐标范围在[l, r],y坐标范围在[b, t]。
第2步: 使⽤你在正交投影中学会推导的公式,把x坐标从[l, r]映射到[-1, 1],把y坐标范围从[b, t]映射到[-1, 1]。
听上去很棒吧?看⼀看图5:
防溺水倡议书
图5: 使⽤相似三⾓形投影⼀个点到z=n平⾯
在这个图中,你从点(x, y, z)到原点画了条直线,注意直线与z=n平⾯相交的那个点——⽤⿊⾊标记的那个。通过这些点,你画了2条相对于z轴的垂线,突然你得到了⼀对相似三⾓形。如果你能够回想起⾼中的⼏何知识,相似三⾓形是拥有相同形状但⼤⼩不⼀定相同的三⾓形。为了证明2个三⾓形是相似的,必须证明它们的同位⾓相等,在这⾥不难做到。⾓1被两个三⾓形共享,显然它和⾃⾝相等。⾓2和⾓3是穿越两条平⾏线形成的同位⾓,所以它们是相等的。同时,直⾓当然是彼此相等的,所以两个三⾓形是相似的。
对于相似三⾓形你应该感兴趣的是它们的每对对应边都是同⽐例的。你知道沿着z轴的边的长度,它们是n和z。那意味着其他对应边的⽐例也是n/z。所以,考虑下你知道了什么。根据勾股定理,从(x, y, z)相对于z轴做的垂线具有以下长度:
如果你知道了从你的投影点到z轴的垂线的长度,那么你就可以计算出该点的x和y坐标。长度怎么求?那太简单了!因为你有了相似三⾓形,所以长度就是简单的L乘以n/z:
党员岗位承诺因此,x坐标是x * n/z,y坐标是y * n/z。第⼀步做完了。
第⼆步只是简单的执⾏你上⼀部分做的同样的映射,所以是时候回顾下你在正交投影中学习到的推导公式了。回想下把x和y坐标映射到规范视域体,像这样:
现在你可以再次调⽤这些公式,除⾮你要考虑到投影;所以,把x⽤x * n/z代替,把y⽤y * n/z代替:
现在,通过乘以z:
这些结果有点奇怪。为了把这些等式写进矩阵,你需要把它们写成这种形式:
但很明显,现在还做不到,所以现在看起来进⼊了僵局。应该做什么呢?如果你能找到个办法获得z'z的公式就像x'z和y'z那样,你就可以写⼀个变换矩阵把(x, y, z)映射到(x'z, y'z, z'z)。然后,你只需要把各部分除以点z,你就会得到你想要的(x', y', z')。
因为你知道z到z'的转换不依赖于x和y,你知道你想要⼀个公式形如z'z= pz + q,p和q是常量。并且,你可以很容易的找到那些常量,因为你知道在两种特殊情况下如何得到z': 因为你要把[n, f]映射到[0, 1],你知道当z=n时z'=0,和z=f时z'=1。当你把第⼀组值代⼊z'z = pz + q,你可以解得:行车记录仪哪个牌子好
现在,把第⼆组值代⼊,得到:
把q的值代⼊等式,你可以很容易的解得p:
现在你有p的值了,并且刚刚你求得了q= –pn,所以你可以解得q:
最后,把p和q的表达式代⼊最原始的公式中,得:
你就快完成了,但是你处理这个问题的不寻常的性质需要你也处理齐次坐标w。通常情况下,只是简单的设置w' = 1 ——你可能已经注意到在⼀个基本的变换下最后⼀⾏总是[0, 0, 0, 1]---但是现在你在为点(x'z, y'z, z'z, w'z)写⼀个变换。所以取⽽代之的,把w' = 1写成w'z = z。因此最后⽤于透视投影的等式如下:

本文发布于:2023-05-19 01:24:37,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/89/914992.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:视域   投影   矩阵   坐标   变换   公式
相关文章
留言与评论(共有 0 条评论)
   
验证码:
推荐文章
排行榜
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图