liuzhiyu123 发表于 2012-10-18 09:04:27

OpenGL揭秘之推导正交投影变换

本帖最后由 liuzhiyu123 于 2012-10-18 14:22 编辑

本文讲述的是关于OpenGL相关矩阵的推导过程,希望对不熟悉OpenGL相关幕后知识的人能有一些帮助。
由于教程里面有图片,所以只好以附件的形式上传




在具体研究之前我觉得有必要把平面投影的分类简单介绍一下,目的是为了让大家有一个总体的认识,从而更好的理解这个知识体系。请看下图:

http://p.blog.csdn.net/images/p_blog_csdn_net/popy007/EntryImages/20090426/fig1_category.jpg

      

平面投影分为平行投影和透视投影两种类型,后者我们在前两篇文章中介绍了。平行投影则是具有矩形观察体的投影方式(透视投影则是视锥观察体),它不会根据物体离视点的远近缩放物体(透视投影则会)。平行投影可以分成侧投影和正交投影两种类型。这两种类型如何区分呢?我们继续看图吧:
http://p.blog.csdn.net/images/p_blog_csdn_net/popy007/EntryImages/20090426/fig2_parallel.jpg

上图中,v是投影平面,n是它的法线。p和q是平面外两点,p’和q’分别是它们在平面上的投影点。q的投影方向向量为Q = 单位化(q’-q),而p的投影方向向量为P = 单位化(p’-p),其中Q不平行于n而P平行于n,则q的投影叫做侧投影,而p的投影叫做正交投影。正交投影是我们今天的研究对象。

实际上上面对平面投影的分类还可以继续向下细分,比如透视投影可以分为一灭点、二灭点以及三灭点透视投影。侧投影则可以继续分为散点侧投、斜二轴侧投等等。而正交投影则可以分成轴侧投影以及多视点正交投影等等。如果读者对此感兴趣,可以参考相关的图形学教程。

接下来我们研究正交投影。分别介绍OpenGL、D3D以及M3G的。我们的环境约定(左右手坐标系、行列向量乘法、CVV范围)仍然尊重相应API自己的设置。
OpenGL正交投影变换

    下图是OpenGL的右手坐标系中观察空间的情形,我们看到的是正交投影的矩形观察体,原点是相机位置,n是近裁剪平面到相机平面的距离,f是远裁剪平面到相机平面的距离。p是观察体中的一个点,p’是它投影之后的点。
http://p.blog.csdn.net/images/p_blog_csdn_net/popy007/EntryImages/20090426/fig3_oglvv.jpg
投影之后我们有关系:
http://p.blog.csdn.net/images/p_blog_csdn_net/popy007/EntryImages/20090426/fig4_pp.jpg

因为是正交投影,没有统一的投影射线目标点,因此投影之后的x和y不会变,而z则永远地变成了-n,跑到了投影平面上(我们让投影平面和近裁剪平面重合),它已经没用了,则我们用这个没用的信息保存z(为了之后片元操作的时候用),写为:
http://p.blog.csdn.net/images/p_blog_csdn_net/popy007/EntryImages/20090426/fig5_p.jpg

从而在z方向上构建 CVV,使得当z在近裁剪平面的时候,az+b=-1,而z在远裁剪平面的时候az+b=1(OpenGL的CVV的z范围是[-1,1],我已经说了三遍了,如果读者感到迷惑不解,强烈建议把前两篇文章理解)。我们算出a和b
http://p.blog.csdn.net/images/p_blog_csdn_net/popy007/EntryImages/20090426/fig6_ab.jpg

然后我们就通过当前的结果反推正交投影矩阵版本一
http://p.blog.csdn.net/images/p_blog_csdn_net/popy007/EntryImages/20090426/fig7_ver1.jpg



接着把x和y建立成CVV情形(简单的线性插值)
http://p.blog.csdn.net/images/p_blog_csdn_net/popy007/EntryImages/20090426/fig8_xy.jpg




反推正交投影矩阵版本二(最终版本)

http://p.blog.csdn.net/images/p_blog_csdn_net/popy007/EntryImages/20090426/fig9_ogl_ortho.jpg





则右边的那个矩阵就是OpenGL的正交投影矩阵,它可以通过glOrtho创建出来。如果你读过并理解了之前两篇文章,你会觉得我的推导越来越简洁利落了:)OpenGL的解决了,下面是D3D的。
D3D正交投影变换

    下图是D3D左手坐标系中观察空间的情形。因为是左手坐标系,因此近裁剪平面在z = n平面,而远裁剪平面在z = f平面。

http://p.blog.csdn.net/images/p_blog_csdn_net/popy007/EntryImages/20090426/fig10_d3dvv2.jpg

投影之后,有                                                                                                   

http://p.blog.csdn.net/images/p_blog_csdn_net/popy007/EntryImages/20090426/fig11_pp.jpg

用第三个没用的信息保存z,写为

http://p.blog.csdn.net/images/p_blog_csdn_net/popy007/EntryImages/20090426/fig12_p.jpg

使得(D3D的CVV的z范围是)

http://p.blog.csdn.net/images/p_blog_csdn_net/popy007/EntryImages/20090426/fig13_ab.jpg
反推正交投影矩阵版本一

http://p.blog.csdn.net/images/p_blog_csdn_net/popy007/EntryImages/20090426/fig14_ver1.jpg
对x和y进行CVV线性插值


http://p.blog.csdn.net/images/p_blog_csdn_net/popy007/EntryImages/20090426/fig15_xy.jpg


分两种情况讨论(如果读者对此不清楚,请参考第二篇文章《深入探索透视投影变换(续)》):

(1)       投影平面居中,销掉两边的1/2,然后反推正交投影矩阵

http://p.blog.csdn.net/images/p_blog_csdn_net/popy007/EntryImages/20090426/fig16_case1.jpg



后面那个矩阵就是相应正交投影矩阵,这个也是D3DXMatrixOrthoLH方法所使用的情况。



(2)       一般情况,投影平面不一定居中,直接通过投影结果反推正交投影矩阵

http://p.blog.csdn.net/images/p_blog_csdn_net/popy007/EntryImages/20090426/fig17_case2.jpg



后面那个矩阵就是相应的正交投影矩阵,这个也是D3DXMatrixOrthoOffCenterLH方法所使用的情况。好了,D3D的也介绍完毕,接下来是M3G的。


M3G正交投影变换

M3G是对OpenGL的封装,因此环境和OpenGL的相同,我们从对x和y的插值来看


http://p.blog.csdn.net/images/p_blog_csdn_net/popy007/EntryImages/20090426/fig18_xy.jpg


M3G只使用居中的投影平面,因此可以销掉两边的1/2,得到


http://p.blog.csdn.net/images/p_blog_csdn_net/popy007/EntryImages/20090426/fig19_case1.jpg


接着反推出正交投影矩阵


http://p.blog.csdn.net/images/p_blog_csdn_net/popy007/EntryImages/20090426/fig20_m3g_ortho.jpg


最后那个矩阵就是M3G的正交投影矩阵,也就是Camera.setParallel所使用的形式。

内容转自:http://blog.csdn.net/popy007/article/details/1797121

tianxiao888 发表于 2012-10-18 11:34:56

支持一个啊~~

liuzhiyu123 发表于 2012-10-18 12:14:38

附件中有帖子全部的内容,结合里面的图片来看,更容易理解,论坛上传图片太费劲了

sea_soft 发表于 2014-1-12 13:59:07

之前看OpenGL教程这块就没看懂过,数学没学好,这下至少能看懂了,太感谢了

xubaolong 发表于 2014-1-13 17:57:32

:D
页: [1]
查看完整版本: OpenGL揭秘之推导正交投影变换