• <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>
  • 向量幾何在游戲編程中的使用6

    發表于:2007-04-28來源:作者:點擊數: 標簽:編程開發向量何在游戲
    63-D空間中的基變換與坐標變換 -Twinsen編寫 -本人水平有限,疏忽錯誤在所難免,還請各位數學高手、編程高手不吝賜教 -我的Email-address: popyy@netease.com 一、空間坐標系的基和基矩陣 在3-D空間中,我們用空間坐標系來規范物體的位置,空間坐標系由3個相

    <6>3-D空間中的基變換與坐標變換
    -Twinsen編寫

    -本人水平有限,疏忽錯誤在所難免,還請各位數學高手、編程高手不吝賜教
    -我的Email-address:
    popyy@netease.com

    一、空間坐標系的基和基矩陣

    在3-D空間中,我們用空間坐標系來規范物體的位置,空間坐標系由3個相互垂直的坐標軸組成,我們就把它們作為我們觀察3-D空間的基礎,空間中物體的位置可以通過它們來衡量。當我們把這3個坐標軸上單位長度的向量記為3個相互正交的單位向量i,j,k,空間中每一個點的位置都可以被這3個向量線性表出,如P<1,-2,3>這個點可以表為i-2j+3k。

    我們把這3個正交的單位向量稱為空間坐標系的,它們單位長度為1且正交,所以可以成為標準正交基。三個向量叫做基向量?,F在我們用矩陣形式寫出基向量和基。

           
    i =  | 1 0 0 |
             
    j =  | 0 1 0 | 

    k =  | 0 0 1 |

         
        | i |    | 1 0 0 |
        
    B = | j | =  | 0 1 0 |

        | k |    | 0 0 1 |

    這樣的矩陣我們叫它基矩陣。有了基矩陣,我們就可以把空間坐標系中的一個向量寫成坐標乘上基矩陣的形式,比如上面的向量P可以寫成:

    P = C x B

    =>

                              | 1 0 0 |                          

    | 1 -2 3 | = | 1 -2 3 | x | 0 1 0 |
            
                              | 0 0 1 |

    這樣的話,空間坐標系下的同一個向量在不同的基下的坐標是不同的。


    二、局部坐標系和局部坐標

    和空間坐標系(也可以叫做全局坐標系或者世界坐標系)并存的稱為局部坐標系(也叫坐標架——coordinate frame),它有自己的基,這些基向量把空間坐標系作為參考系。比如
       
         | x'|   | -1  0   0  |
         
    B' = | y'| = | 0   1   0  |

         | z'|   | 0   0   -1 |


          | x''|   | 2^½ /2    0   2^½ /2    |

    B'' = | y''| = | 0        -1   0          |

          | z''|   | -(2^½) /2   0   2^½ /2  |

    就是兩個局部坐標系的基,如圖:

     

    現在我們可以把上面那個空間坐標中的向量P|1 -2 3|(以后都用矩陣表示)表示在不同的基下,我把它寫成一個大長串的式子:



                          | x' |                        | x''|
     
    P = | Px' Py' Pz' | x | y' | = | Px'' Py'' Pz'' | x | y''|

                          | z' |                        | z''|

     

    這里| Px' Py' Pz'|是P在B'下的坐標,| Px'' Py'' Pz''|是P在B''下的坐標,我把它寫的具體點吧:

     


                                | -1 0  0 |                            | 2^½ /2      0   2^½ /2|
     
    | 1 -2 3 | = | -1 -2 -3 | x | 0  1  0 | = | 2*2^½   -2   2^½ | x  | 0          -1   0      |

                                | 0  0 -1 |                            | -(2^½) /2   0   2^½ /2|

     

    這就是說,在空間坐標系下面的向量| 1 -2 3 |在基B'下的坐標為|-1 -2 -3|,在B''下的坐標為| 2*2^½   -2   2^½ |。當然空間坐標系也有自己的基B|i j k|^T(因為是列向量,所以寫成行向量的轉置),但我們現在是拿它當作一個參考系。

    在研究了局部坐標系之后,我現在要分析兩個應用它們的例子,先來看



    三、空間坐標系中一個點圍繞任一軸的旋轉

    上一篇討論3-D空間旋轉的時候說到有一個高檔的方法做3-D空間任意軸旋轉,現在我們的知識儲備已經足夠理解這個方法了(Quake引擎使用的就是這個方法)。


    如上所示,空間坐標系中的一個局部坐標系xyz中有一個向量a(2,5,3)和一個點p(8,4,2)現在我要讓p點圍繞a向量旋轉60度,得到p’點,該如何做呢?從目前掌握的旋轉知識來看,我們有兩個理論基礎:

     

    1)在一個坐標系中的一個點,如果要它圍繞該坐標系中一個坐標軸旋轉,就給它的坐標值乘相應的旋轉矩陣,如

    [cosA -sinA 0 ]
    [sinA cosA  0 ]
    [0    0     1 ]

    等等。

    2)我們已經學習了局部坐標系的理論了,知道空間中一個點在不同的坐標系中的坐標不同。利用這一點,我們可以很方便的讓一個點或者向量在不同的坐標系之間轉換。

    我們聯系這兩個理論根據,得出我們的思路:

    1構造另一個局部坐標系abc,使得a成為該坐標系的一個坐標軸。

    2 把p的坐標變換到abc中,得到p’,用旋轉公式讓p’圍繞已經成為坐標軸的a旋轉,得到p’’。

    3把p’’再變換回坐標系xyz,得到p’’’,則p’’’就是p圍繞a旋轉后的點。

    下面我們逐步說明。

    首先我們構造abc,我們有無數種方法構造,因為只要保證b、c之間以及他們和a之間都正交就可以了,但我們只要一個。根據上圖,我們首先產生一個和a正交的b。這可以通過向量的叉乘來完成:我們取另一個向量v(顯然,這個向量是不能和a共線的任何非零向量),讓它和a決定一個平面x,然后讓v叉乘a得到一個垂直于x的向量b,因為b垂直于x,而a在平面x上,因此b一定垂直于a,然后用a叉乘b得到c,最后單位化a、b、c,這樣就得到了局部坐標系abc。

    然后我們把p點變換到abc坐標系中,得到p’,即p’就是p在abc中的坐標:

    |a  b  c| * p’=  |x  y  z| * p

    p’ = |a  b  c|^-1 * |x  y  z| * p

          |ax bx cx|        |1 0 0|   |px|

    p’ = |ay by cy| ^-1 *  |0 1 0| * |py|

          |az bz cz|        |0 0 1|   |pz|

    注意這里|a b c|^-1即矩陣|a b c|的逆矩陣,因為a、b、c是三個正交向量,并且是單位向量,因此|a b c|是一個正交矩陣,正交矩陣的轉置和逆相等,這是它的一個特性,因此上面的公式就可以寫成:

          |ax ay az|     |1 0 0|   |px|

    p’ = |bx by bz|  *  |0 1 0| * |py|

          |cx cy cz|     |0 0 1|   |pz|

    這個時候p’就是p在abc坐標系下的坐標了。此時a已經是一個坐標軸了,我們可以用旋轉矩陣來做。

    p’’ = RotMatrix * p’

    [1 0          0]   |p’x|
    p’’ = [0 cos60 -sin60] * |p’y|
            [0 sin60  cos60]   |p’z|

     

    最后,我們把p’’再次變換回xyz坐標系,得到最終的p’’’

    |a  b  c| * p’’ = |x  y  z| * p’’’

    p’’’ = |x  y  z|^-1 * |a  b  c| * p’’

    p’’’ = |a  b  c| * p’’

    最后

    p’’’ = |a  b  c| * RotMatrix * |a   b   c|^T * p = M * p

    這樣就得到了xyz坐標系中點p圍繞a旋轉60度后的點。

    最后,我用Quake3引擎的相應函數(來自idSoftware ——quake3-1[1].32b-source——mathlib.c)來完成對這個算法的說明:

    /*

    ===============

    RotatePointAroundVector

    dst是一個float[3],也就是p’’’

    dir相當于a,point就是p,degrees是旋轉度數

    ===============

    */

    void RotatePointAroundVector( vec3_t dst, const vec3_t dir, const vec3_t point,

                              float degrees ) {

        float  m[3][3];

        float  im[3][3];

        float  zrot[3][3];

        float  tmpmat[3][3];

        float  rot[3][3];

        int i;

        vec3_t vr, vup, vf;

        float  rad;

     

        vf[0] = dir[0];

        vf[1] = dir[1];

        vf[2] = dir[2];

       // 首先通過dir得到一個和它垂直的vr

       // PerpendicularVector()函數用于構造和dir垂直的向量

       // 也就是我們上面的第1步

        PerpendicularVector( vr, dir );

       // 通過cross multiply得到vup

       // 現在已經構造出坐標軸向量vr, vup, vf

        CrossProduct( vr, vf, vup );

       // 把這三個單位向量放入矩陣中

        m[0][0] = vr[0];

        m[1][0] = vr[1];

        m[2][0] = vr[2];

     

        m[0][1] = vup[0];

        m[1][1] = vup[1];

        m[2][1] = vup[2];

     

        m[0][2] = vf[0];

        m[1][2] = vf[1];

        m[2][2] = vf[2];

       // 產生轉置矩陣im

        memcpy( im, m, sizeof( im ) );

      

        im[0][1] = m[1][0];

        im[0][2] = m[2][0];

        im[1][0] = m[0][1];

        im[1][2] = m[2][1];

        im[2][0] = m[0][2];

        im[2][1] = m[1][2];

       // 構造旋轉矩陣zrot

        memset( zrot, 0, sizeof( zrot ) );

        zrot[0][0] = zrot[1][1] = zrot[2][2] = 1.0F;

      

        rad = DEG2RAD( degrees );

        zrot[0][0] = cos( rad );

        zrot[0][1] = sin( rad );

        zrot[1][0] = -sin( rad );

        zrot[1][1] = cos( rad );

       // 開始構造變換矩陣M

       // tmpmat = m * zrot

        MatrixMultiply( m, zrot, tmpmat );

       // rot = m * zrot * im

        MatrixMultiply( tmpmat, im, rot );

       // 則 rot = m * zrot * im 和我們上面推出的

       // M = |a  b  c| * RotMatrix * |a   b   c|^T  一致

     

       // 變換point這個點

       // p’’’ = M * p

        for ( i = 0; i < 3; i++ ) {

           dst[i] = rot[i][0] * point[0] + rot[i][1] * point[1] + rot[i][2] * point[2];

        }

    }

     

    四、世界空間到相機空間的變換

     

     

    空間坐標系XYZ,相機坐標系UVN。這時候相機空間的基(以下簡稱相機)在空間坐標系中圍繞各個坐標軸旋轉了一定角度<a,b,c>,然后移動了<x,y,z>。對于模型我們可以看作相對于相機的逆運動,即模型旋轉了一定角度<-a,-b,-c>,然后移動了<-x,-y,-z>,可以把相機和物體的運動看成兩個互逆的變換。這樣,可以通過對相機的變換矩陣求逆來得到模型的變換矩陣。下面來具體看一下,如何得到相機變換矩陣,并且求得它的逆矩陣。

    首先聲明一下,對于一個模型的變換,我們可以給模型矩陣左乘變換矩陣:

    M x P = P'

    | A B C D |     | x |    | Ax + By + Cz + D |

    | E F G H |     | y |    | Ex + Fy + Gz + H |
                 x         = 
    | I J K L |     | z |    | Ix + Jy + Kz + L |

    | M N O P |     | 1 |    | Mx + Ny + Oz + P |

    也可以右乘變換矩陣:

    P^T x M^T = P'^T

                    | A E I M |

                    | B F J N |
    | x y z 1|   x               =  |Ax+By+Cz+D Ex+Fy+Gz+H Ix+Jy+Kz+L Mx+Ny+Oz+P|
                    | C G K O |

                    | D H L P |

    可以看出兩種變換方式是一個轉置關系,結果只是形式上的不同,但這里我們使用后者,即右乘變換矩陣,因為比較普遍。

    很顯然,相機的變換可以分成兩個階段:旋轉和平移。我們先來看旋轉。

    在空間坐標系中,相機旋轉之前世界坐標系xyz和相機坐標系u0v0n0的各個軸向量的方向相同,有關系:

                        | u0 |                  | x |

    P = |Pu0 Pv0 Pn0| x | v0 |  =  |Px Py Pz| x | y |

                        | n0 |                  | z |

    這里P是空間坐標系中的一個向量。|u0 v0 n0|^T是相機基矩陣,|Pu0 Pv0 Pn0|是P在相機基矩陣下的坐標。|x y z|^T是
    世界基矩陣,|Px Py Pz|是P在它下面的坐標。有Pu0 = Px, Pv0 =Py, Pn0 = Pz。

    相機和向量P都旋轉之后,有關系:

                         | u |                   | x |

    P' = |Pu0 Pv0 Pn0| x | v | = |Px' Py' Pz'| x | y |

                         | n |                   | z |

    P'是P同相機一起旋轉后的向量。|u v n|^T是相機旋轉后的基矩陣,|Pu0 Pv0 Pn0|是P'在它下面的坐標,因為P是和相機一起旋轉的,所以坐標不變。|x y z|^T仍為世界基矩陣,|Px' Py' Pz'|是P'在它下面的坐標。

    現在看


                    | u |                   | x |

    |Pu0 Pv0 Pn0| x | v | = |Px' Py' Pz'| x | y |

                    | n |                   | z |

    因為|x y z|^T為一個單位陣,且Pu0 = Px, Pv0 =Py, Pn0 = Pz。 所以得到


                 | u |                   

    |Px Py Pz| x | v | = |Px' Py' Pz'| 

                 | n |                   

    |Px Py Pz|和相機一起旋轉后變成|Px' Py' Pz'|,即P x R = P',而旋轉變換矩陣R就是:

    | u |

    | v |

    | n |

    寫成標準4x4矩陣:

    | ux uy uz 0|

    | vx vy vz 0|

    | nx ny nz 0|

    | 0  0  0  1|

    平移矩陣T很簡單:

    | 1 0 0 0 |

    | 0 1 0 0 |

    | 0 0 1 0 |

    | x y z 1 |

    則相機矩陣就是:

                 | ux uy uz 0 |     | 1 0 0 0 |
                                   
                 | vx vy vz 0 |     | 0 1 0 0 |
    C = R x T =                  x             
                 | nx ny nz 0 |     | 0 0 1 0 |
      
                 | 0  0  0  1 |     | x y z 1 |

    它的逆矩陣,即相機的逆變換矩陣為

                          | 1  0  0  0 |     | ux vx nx 0 |   | ux   vx   nx  0 |
                                            
                          | 0  1  0  0 |     | uy vy ny 0 |   | uy   vy   ny  0 |
    C^-1 = T^-1 x R^-1 =                  x                 =   
                          | 0  0  1  0 |     | uz nz nz 0 |   | uz   vz   nz  0 |

                          | -x -y -z 1 |     | 0  0  0  1 |   |-T.u -T.v -T.n 1 |



    原文轉自:http://www.kjueaiud.com

    老湿亚洲永久精品ww47香蕉图片_日韩欧美中文字幕北美法律_国产AV永久无码天堂影院_久久婷婷综合色丁香五月

  • <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>