[3D基础]投影矩阵的推导(1)

     转眼我做游戏行业已经八个月了,游戏行业入门门槛低,所以还算学习得比较轻松,总结了当初自己迷惑的几个知识点,本来想写出来给初学者解惑,无赖我是一个懒散的人,一直拖到现在,终于决心白纸黑字的搬到Blog上来,希望大家喜欢。
 
     投影变换:我觉得这个是3D到2D变换中最让初学者头晕的问题,但又是最重要的。

     请看上面这张我用爪子抓出来的图。这个坐标系是DX的左手坐标系,Y向上,X向右,Z向内,几何坐标已经经过了相机坐标系的变换,相机位置为(0,0,0),假设远裁减面距离为f,近裁减面距离为n,近裁减面左边为l,右边为r,上为t,下为b。要投影的2个顶点A和B坐标分别为A(Xa,Ya,Za),B (Xb,Yb,Zb),现在我们要求他们的投影点坐标A0和B0,这里我以B点为例子,讲解投影最简单的几何知识。

     首先我们来计算B0点的X坐标,(虚线都是辅助线),我们看三角形B C O和三角形B0 K O,利用初中几何知识可得他们是相似的,由相似三角形定理可知,B0 K = B C * ( n /  C O );而B C等于Xb, C O等于Zb;所以Xb0 = Xb * n / Zb; 同理Yb0 = Yb * n / Zb;我们知道DX把3D坐标映射到了一个X(-1,1) Y(-1,1) Z(0,1)的一个立方体内。那现在我们就需要对投影后的坐标进行一维映射了,(其实投影就是映射,数学形式为函数,将一个值域一一映射到另外一个值域),现在在X轴上,我们要把l - r这个值域中的值一一映射到-1 - 1之间,what should we do?很显然我们有一个等式  ( x - l ) / ( r - l ) = ( x0 - ( -1) ) / ( 1 - ( -1 )); x是l - r之间的一个值,x0是-1 - 1之间的一个值,我们得到 x0 = (2x - ( r + l )) / ( r - l );这里的x换成Xb0得:x0 = (2n * Xb) / (Zb*( r - l )) - ( r + l )/( r - l );同理:y0 = (2n * Yb) / (Zb*( t - b )) - ( t + b )/( t - b ); Zb映射最简单,将n - f之间的值映射到0 - 1之间, z0 = Zb / ( f - n ) - n / ( f- n );现在我们把这些四则运算用矩阵形式来表示:
[x, y, z, 1] * [ 2n/(r-l)    , 0               , 0             , 0 ]
                   [ 0,            , 2n/(t-b)     , 0             , 0 ]
                   [ -(r+l)/(r-l), -(t+b)/(t-b), z/(f-n)     , 1 ]
                   [ 0,            , 0               , -z*n/(f-n), 0 ]
得到的结构应该是[x0, y0, z0, w]->[x0/w, y0/w, z0/w, 1]

但为了3D引擎后期光栅化时方便的对中间象素的Z值进行线性插值,最好直接保存顶点的1/Z值,然后将1/Z嵌位到0~1之间。

[x, y, z, 1] * [ 2n/(r-l)    , 0               , 0         , 0 ]
                   [ 0,            , 2n/(t-b)     , 0         , 0 ]
                   [ -(r+l)/(r-l), -(t+b)/(t-b), 0         , 1 ]
                   [ 0,            , 0               , 1         , 0 ]    //直接保存1/Z

将1/Z嵌位到0~1之间(线形映射) z0 = (1/Bz - 1/n)/(1/f - 1/n); [1/n->0, 1/f->1]
转换先形式使矩阵理解更加明了:z0 = f/(f-n) - f*n/((f-n)*z)
[x, y, z, 1] * [ 2n/(r-l)    , 0               , 0             , 0 ]
                   [ 0,            , 2n/(t-b)     , 0             , 0 ]
                   [ -(r+l)/(r-l), -(t+b)/(t-b), f/(f-n)      , 1 ]
                   [ 0,            , 0               , -f*n/(f-n) , 0 ]

我看到实时计算机图形学上写出的答案与我推导出来的有点不一样,红色部分符号相反,颇为不解,不知道我错在哪里,希望明白的朋友指点迷津。

posted @ 2008-01-24 18:15 effulgent 阅读(726) 评论(4)  编辑 收藏

  回复  引用    
#1楼 2008-06-04 23:03 | yty [未注册用户]
请问l - r在这里的数值是多少?/
还有这个公式是求bo的x轴吗?x0 = (2n * Xb) / (Zb*( r - l )) - ( r + l )/( r - l );

  回复  引用  查看    
#2楼 [楼主]2008-06-05 18:50 | 易颖      
1。l - r 一般是指 视锥在距离Z=1的地方的左右坐标值
2。是的,是求B0最后投影后的x值(-1~1之间)
  回复  引用    
#3楼 2008-08-01 13:12 | みぃ~☆ [未注册用户]
推导过程粗粗看了下应无错。
红色部分相反,最大的可能是你这个为DX左手,他那个是OpenGL右手。

  回复  引用    
#4楼 2008-09-02 09:51 | zzd [未注册用户]
但为了3D引擎后期光栅化时方便的对中间象素的Z值进行线性插值,最好直接保存顶点的1/Z值,然后将1/Z嵌位到0~1之间。

[x, y, z, 1] * [ 2n/(r-l) , 0 , 0 , 0 ]
[ 0, , 2n/(t-b) , 0 , 0 ]
[ -(r+l)/(r-l), -(t+b)/(t-b), 0 , 1 ]
[ 0, , 0 , 1 , 0 ] //直接保存1/Z

将1/Z嵌位到0~1之间(线形映射) z0 = (1/Bz - 1/n)/(1/f - 1/n); [1/n->0, 1/f->1]


这段不太明白,能详细解释下么?还有将1/Z嵌位到0~1之间的式子是怎么来的?

标题  
姓名  
主页
Email (博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
该文被作者在 2008-01-24 18:17 编辑过
"五向定位"职业成长路线公开课(上海、南京、大连)
Google站内搜索


相关链接: