• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            積木

            No sub title

              C++博客 :: 首頁 :: 聯系 :: 聚合  :: 管理
              140 Posts :: 1 Stories :: 11 Comments :: 0 Trackbacks

            常用鏈接

            留言簿(1)

            我參與的團隊

            搜索

            •  

            最新評論

            閱讀排行榜

            評論排行榜

            原文轉自:http://www.gesoftfactory.com/developer/Transform.htm

            (提示:原文有圖片。)

            三維變換

            在使用三維圖形的應用程序中,可以用變換做以下事情:

            • 描述一個物體相對于另一個物體的位置。
            • 旋轉并改變物體的大小。
            • 改變觀察的位置、方向和視角。

            可以用一個4 x 4矩陣將任意點(x,y,z)變換為另一個點(x',y',z')。

            對(x,y,z)和矩陣執行以下操作產生點(x',y',z')。

             

            最常見的變換是平移、旋轉和縮放。可以將產生這些效果的矩陣合并成單個矩陣,這樣就可以一次計算多種變換。例如,可以構造單個矩陣,對一系列的點進行平移和旋轉。更多信息,請參閱矩陣串接

            矩陣以行列順序書寫。一個沿每根軸均勻縮放頂點的矩陣,也稱為統一縮放,用如下數學符號表示。

             

            在C++應用程序中,Microsoft® Direct3D®使用D3DMATRIX結構,將矩陣聲明為一個二維數組。以下示例代碼顯示了如何初始化一個D3DMATRIX結構,使之成為一個統一縮放矩陣。

            // 本例中,s為浮點類型的變量

             

            D3DMATRIX scale = {

                s,               0.0f,            0.0f,            0.0f,

                0.0f,            s,               0.0f,            0.0f,

                0.0f,            0.0f,            s,               0.0f,

                0.0f,            0.0f,            0.0f,            1.0f

            };


            平移和縮放


            平移

            以下變換將點(x,y,z)平移到一個新的點(x',y',z')。

             

            可以在C++應用程序中手工創建一個平移矩陣。以下示例代碼顯示了的一個函數的源碼,該函數創建一個矩陣用于平移頂點。

            D3DXMATRIX Translate(const float dx, const float dy, const float dz) {
                D3DXMATRIX ret;
             
                D3DXMatrixIdentity(&ret); // 由Direct3DX實現
                ret(3, 0) = dx;
                ret(3, 1) = dy;
                ret(3, 2) = dz;
                return ret;
            }    // 平移結束

            為了方便,Direct3DX工具庫提供了D3DXMatrixTranslation函數。

            縮放

            以下變換用指定值縮放點(x,y,z)的x-,y-和z-方向,產生新的點(x',y',z')。

             


            旋轉


            這里描述的變換是基于左手坐標系的,也許和別處見到的變換矩陣不同。更多信息,請參閱三維坐標系

            以下變換將點(x,y,z)圍繞x軸旋轉,產生新的點(x',y',z')。

             

            以下變換將點圍繞y軸旋轉。

             

            以下變換將點圍繞z軸旋轉。

             

            在這些示例矩陣中,希臘字母(θ)表示旋轉的角度,以弧度為單位。當沿著旋轉軸朝原點看時,角度以順時針方向計量。

            C++應用程序可以用Direct3D擴展(D3DX)工具庫提供的D3DXMatrixRotationXD3DXMatrixRotationXD3DXMatrixRotationX函數創建旋轉矩陣。以下示例是D3DXMatrixRotationX函數的源碼。

            D3DXMATRIX* WINAPI D3DXMatrixRotationX
                ( D3DXMATRIX *pOut, float angle )
            {
            #if DBG
                if(!pOut)
                    return NULL;
            #endif
             
                float sin, cos;
                sincosf(angle, &sin, &cos); // 計算角度的正弦和余弦值。
             
                pOut->_11 = 1.0f; pOut->_12 = 0.0f;   pOut->_13 = 0.0f; pOut->_14 = 0.0f;
                pOut->_21 = 0.0f; pOut->_22 = cos;    pOut->_23 = sin; pOut->_24 = 0.0f;
                pOut->_31 = 0.0f; pOut->_32 = -sin;    pOut->_33 = cos; pOut->_34 = 0.0f;
                pOut->_41 = 0.0f; pOut->_42 = 0.0f;   pOut->_43 = 0.0f; pOut->_44 = 1.0f;
             
                return pOut;
            }

             

            ( D3DXMATRIX *pOut, float angle )

             

             

            if(!pOut)

            return NULL;

             

             

            float sin, cos;

            sincosf(angle, &sin, &cos); // Determine sin and cos of angle.

             

            pOut->_11 = 1.0f; pOut->_12 = 0.0f;   pOut->_13 = 0.0f; pOut->_14 = 0.0f;

            pOut->_21 = 0.0f; pOut->_22 = cos;    pOut->_23 = sin; pOut->_24 = 0.0f;

            pOut->_31 = 0.0f; pOut->_32 = -sin;    pOut->_33 = cos; pOut->_34 = 0.0f;

            pOut->_41 = 0.0f; pOut->_42 = 0.0f;   pOut->_43 = 0.0f; pOut->_44 = 1.0f;

             

            return pOut;

             


            矩陣串接


            使用矩陣的一個優勢就是可以通過把兩個以上的矩陣相乘,將它們的效果合并在一起。這意味著,要先旋轉一個建模然后把它平移到某個位置,無需使用兩個矩陣,只要把旋轉矩陣和平移矩陣相乘,產生一個包含了所有效果的合成矩陣。這個過程被稱為矩陣串接,可以寫成以下公式。

             

            在這個公式中,C是將被創建的合成矩陣,M1Mn是矩陣C包含的單個矩陣。雖然大多數情況下,只需要串接兩三個矩陣,但實際上并沒有數量上的限制。

            可以使用D3DXMatrixMultiply函數進行矩陣乘法。

            進行矩陣乘法時先后次序是至關重要的。前面的公式反映了矩陣串接從左到右的規則。也就是說,用來創建合成矩陣的每個矩陣產生的直觀效果會按從左到右的次序出現。下面顯示了一個典型的世界變換矩陣。想象一下給一個旋轉飛行的碟子創建世界變換矩陣。應用程序也許想讓飛行的碟子繞它的中心——建模空間中的y軸——旋轉,然后把它平移到場景中的另一個位置。要實現這樣的效果,首先創建一個旋轉矩陣,然后將它與平移矩陣相乘,如以下公式所示。

             

            在這個公式中,Ry是繞y軸的旋轉矩陣,Tw是平移到世界坐標中某個位置的矩陣。

            矩陣相乘的順序很重要,因為矩陣乘法是不可交換的,這和兩個標量相乘不同。將矩陣以相反的順序相乘會產生這樣的直觀效果:先把飛行中的碟子平移到世界空間中的某個位置,然后將它圍繞世界坐標的原點旋轉。

            無論創建何種類型的矩陣,都要記住從左到右的規則,這樣才能保證得到想要的效果。


            世界變換


            對世界變換的討論介紹了基本概念,并提供了如何在Microsoft® Direct3D®應用程序中設置世界變換矩陣的細節。

            什么是世界變換

            世界變換將坐標從建模空間,在這個空間中的頂點相對于建模的局部原點定義,轉變到世界空間,在這個空間中的頂點相對于場景中所有物體共有的原點定義。本質上,世界變換將一個建模放到世界中,并由此而得名。下圖描繪了世界坐標系統和建模的局部坐標系統間的關系。

             

            世界變換可以包含任意數量的平移、旋轉和縮放的合并。有關對變換的數學討論,請參閱三維變換

            設置世界矩陣

            同任何其它變換一樣,通過將一系列變換矩陣串接成單個矩陣,應用程序可以創建包含這些矩陣全部效果的世界矩陣。最簡單的情況下,建模在世界的原點并且它的局部坐標軸與世界空間的方向相同,這時世界矩陣就是單位矩陣。更通常的情況下,世界矩陣是一系列矩陣的合成,包含一個平移矩陣,并且根據需要可能有一個以上的旋轉矩陣。

            以下示例,來自一個用C++編寫的假想三維建模類,使用Direct3D擴展(D3DX)工具庫提供的幫助函數創建了一個世界矩陣,這個世界矩陣包含了三個旋轉矩陣,用于調整三維建模的方向,以及一個平移矩陣,用來根據建模在世界空間中的相對坐標重新確定它的位置。

            /*
             * 根據本示例的目的,假設以下變量都是有效的并經過初始化。
            *
             * 變量m_xPos,m_yPos,m_zPos包含了建模在世界坐標中的位置。
            *
             * 變量m_fPitch,m_fYaw和m_fRoll為浮點數,包含了建模的方向,
             * 用pitch,yaw和roll旋轉角表示,以弧度為單位。
             */
             
            void C3DModel::MakeWorldMatrix( D3DXMATRIX* pMatWorld )
            {
                D3DXMATRIX MatTemp; // 用于旋轉的臨時矩陣
                D3DXMATRIX MatRot;   // 最終的旋轉矩陣,應用于pMatWorld.
             
                // 使用從左到右的矩陣串接順序,在旋轉之前對物體在世界空間中
                // 的位置進行平移。
                D3DXMatrixTranslation(pMatWorld, m_xPos, m_yPos, m_zPos);
                D3DXMatrixIdentity(&MatRot);
             
                // 現在將方向變量應用于世界矩陣
                if(m_fPitch || m_fYaw || m_fRoll) {
                    // 產生并合成旋轉矩陣。
                    D3DXMatrixRotationX(&MatTemp, m_fPitch);         // Pitch
                    D3DXMatrixMultiply(&MatRot, &MatRot, &MatTemp);
                    D3DXMatrixRotationY(&MatTemp, m_fYaw);           // Yaw
                    D3DXMatrixMultiply(&MatRot, &MatRot, &MatTemp);
                    D3DXMatrixRotationZ(&MatTemp, m_fRoll);          // Roll
                    D3DXMatrixMultiply(&MatRot, &MatRot, &MatTemp);
             
                    // 應用旋轉矩陣,得到最后的世界矩陣。
                    D3DXMatrixMultiply(pMatWorld, &MatRot, pMatWorld);
                }
            }

            當準備好世界變換矩陣后,應該調用IDirect3DDevice9::SetTransform方法設置它,并把第一個參數指定D3DTS_WORLD宏。

            注意    Direct3D使用應用程序設置的世界和觀察矩陣配置許多內部數據結構。應用程序每次設置新的世界或觀察矩陣時,系統都要重新計算相關的內部數據結構。頻繁地設置這些矩陣——例如,每幀上千次——是計算量很大的。通過將世界矩陣和觀察矩陣串接成一個世界/觀察矩陣,并將該矩陣設置為世界矩陣,然后將觀察矩陣設置為單位矩陣,應用程序可以將所需的計算次數減到最少。最好保存一份單獨的世界矩陣和觀察矩陣的副本在高速緩存中,這樣就可以根據需要修改、串接及重置世界矩陣。為清晰起見,本文檔中的Direct3D示例很少使用這項優化。


            觀察變換


            本節介紹觀察變換的基本概念,并提供有關如何在Microsoft® Direct3D®應用程序中設置觀察矩陣的細節。信息被分為以下主題。

            什么是觀察變換?

            觀察變換根據觀察者在世界空間中的位置,把頂點變換到攝像機空間。在攝像機空間中,攝像機,或觀察者,位于原點,朝sz軸的正向看去。再次提醒一下,因為Direct3D使用左手坐標系,所以z軸的正向是朝著場景的。觀察矩陣根據攝像機的位置——攝像機空間的原點——和方向重定位世界中的所有物體。

            有兩方法可以創建觀察矩陣。所有情況下,攝像機在世界空間中的邏輯位置和方向會被用作起始點來創建觀察矩陣,得到的觀察矩陣會被應用于場景中的三維建模。觀察矩陣平移并旋轉物體,將它們放入攝像機空間中,攝像機位于原點。創建觀察矩陣的一種方法是把平移矩陣和圍繞每根坐標軸旋轉的旋轉矩陣合并。這種方法使用了以下通用矩陣公式。

             

            在這個公式中,V是要創建的觀察矩陣,T是在世界中重定位物體的平移矩陣,RxRz分別是繞x軸,y軸和z軸旋轉物體的旋轉矩陣。平移和旋轉矩陣基于攝像機在世界空間中邏輯位置和方向。因此,如果攝像機在世界中的邏輯位置是<10,20,100>,那么平移矩陣的目的是沿x軸移動物體-10單位,沿y軸移動-20單位,沿z軸移動-100單位。公式中的旋轉矩陣基于攝像機的方向,根據攝像機空間的坐標軸與世界空間的坐標軸間的夾角決定。例如,如果前面提到的攝像機是垂直向下放的,那么它的z軸與世界空間的z軸有90度夾角,如下圖所示。

             

            旋轉矩陣將角度相同但方向相反的旋轉量應用于場景中的建模。這個攝像機的觀察矩陣包含了一個繞x軸-90度的旋轉。旋轉矩陣與平移矩陣合并生成觀察矩陣,觀察矩陣調整物體在場景中的位置和方向,使它們的頂部朝著攝像機,看起來就好像攝像機在建模的上方一樣。

            設置觀察矩陣

            D3DXMatrixLookAtLHD3DXMatrixLookAtRH輔助函數根據攝像機的位置和被觀察點創建一個觀察矩陣。

            以下示例代碼創建了一個用于右手系的觀察矩陣。

            D3DXMATRIX out;
            D3DXVECTOR3 eye(2,3,3);
            D3DXVECTOR3 at(0,0,0);
            D3DXVECTOR3 up(0,1,0);
            D3DXMatrixLookAtRH(&out, &eye, &at, &up);

            Direct3D使用應用程序設置的世界矩陣和觀察矩陣配置許多內部數據結構。每次應用程序設置一個新的世界矩陣或觀察矩陣,系統都要重新計算相關的內部數據結構。頻繁地設置這些矩陣——例如,每幀20,000次——計算量非常大。通過將世界矩陣和觀察矩陣串接成一個世界/觀察矩陣,并將之設置為世界矩陣,然后將觀察矩陣設為單位矩陣,應用程序可以將所需的計算量減到最小。最好保存一份單獨的世界矩陣和觀察矩陣的副本在高速緩存中,這樣就可以根據需要修改、串接及重置世界矩陣。為清晰起見,Direct3D示例很少使用這項優化。


            投影變換


            可以認為投影變換是控制攝像機的內部參數,這選擇攝像機的鏡頭有些相似。這是三種類型的變換中最為復雜的。對投影變換的討論被分為以下主題。


            什么是投影變換?


            典型的投影變換就是一個縮放和透視投影。投影變換將視棱錐轉變為一個立方體。因為視棱錐的近端比遠端小,所以這就產生了離攝像機近的物體被放大的效果,這就是透視如何被應用于場景的。

            視棱錐中,攝像機與觀察變換空間的原點之間的距離被定義為D,因此投影矩陣看起來是這樣:

             

            通過在z方向平移-D,觀察矩陣將攝像機平移到原點。平移矩陣如下所示:

             

            將平移矩陣與投影矩陣相乘(T*P),得到合成的投影矩陣。如下:

             

            下圖描繪了透視投影如何將視棱錐轉變到新的坐標空間。注意棱錐變成了立方體,同時原點從場景的右上角移到了中心。(譯注:應該是從前裁剪平面的中心移到了原點)

             

            在透視變換中,x和y方向的邊界值是-1和1。Z方向的邊界值分別是,0對應于前平面,1對應于后平面。

            這個矩陣根據指定的從攝像機到近裁剪平面的距離,平移并縮放物體,但沒有考慮視角(fov),并且用它為遠處物體產生的z值可能幾乎相同,這使深度比較變得困難。以下矩陣解決了這些問題,并根據視區的縱橫比調整頂點,這使它成為透視投影的一個很好的選擇。

             

            在這個矩陣中,Zn是近裁剪平面的z值。變量whQ有以下含義。注意fovwfovh表示視區在水平和垂直方向上的視角,以弧度為單位。

             

            對應用程序而言,使用視角的角度定義x和y的比例系數可能不如使用視區在水平和垂直方向上的大小(在攝像機空間中)方便。可以用數學推導,得出下面兩個使用視區大小計算wh的公式,它們與前面的公式是等價的。

             

            在這兩個公式中,Zn表示近裁剪平面的位置,VwVh變量表示視區在攝像機空間的寬和高。

            對于C++應用程序而言,這兩個大小直接對應于D3DVIEWPORT9結構的WidthHeight成員。(譯注:雖然直接對應,但是不等價的,因為VwVh位于攝像機空間,而WidthHeight位于屏幕空間)

            無論決定使用什么公式,非常重要的一點是要盡可能將Zn設得大,因為接近攝像機的z值變化不大。這使得用16位z緩存的深度比較變得有點復雜。

            同世界變換和觀察變換一樣,應用程序調用IDirect3DDevice9::SetTransform方法設置投影矩陣。


            設置投影矩陣


            以下ProjectionMatrix示例函數設置了前后裁剪平面,以及在水平和垂直方向上視角的角度。此處的代碼與什么是投影矩陣?主題中討論的方法相似。視角應該小于弧度π。

            D3DXMATRIX 
            ProjectionMatrix(const float near_plane, // 到近裁剪平面的距離
                             const float far_plane, // 到遠裁剪平面的距離
                             const float fov_horiz, // 水平視角,用弧度表示
                             const float fov_vert)   // 垂直視角,用弧度表示
            {
                float    h, w, Q;
             
                w = (float)1/tan(fov_horiz*0.5); // 1/tan(x) == cot(x)
                h = (float)1/tan(fov_vert*0.5);   // 1/tan(x) == cot(x)
                Q = far_plane/(far_plane - near_plane);
             
                D3DXMATRIX ret;
                ZeroMemory(&ret, sizeof(ret));
             
                ret(0, 0) = w;
                ret(1, 1) = h;
                ret(2, 2) = Q;
                ret(3, 2) = -Q*near_plane;
                ret(2, 3) = 1;
                return ret;
            }   // End of ProjectionMatrix

            在創建矩陣之后,調用IDirect3DDevice9::SetTransform方法設置投影矩陣,要將第一個參數設為D3DTS_PROJECTION

            Direct3D擴展(D3DX)工具庫提供了以下函數,幫助應用程序設置投影矩陣。

            • D3DXMatrixPerspectiveLH
            • D3DXMatrixPerspectiveRH
            • D3DXMatrixPerspectiveFovLH
            • D3DXMatrixPerspectiveFovRH
            • D3DXMatrixPerspectiveOffCenterLH
            • D3DXMatrixPerspectiveOffCenterRH

            W友好投影矩陣


            對于已經用世界、觀察和投影矩陣變換過的頂點,Microsoft® Direct3D®使用頂點的W成員進行深度緩存中基于深度的計算或計算霧效果。類似這樣的計算要求應用程序歸一化投影矩陣,使生成的W與世界空間中的Z相同。簡而言之,如果應用程序的投影矩陣包含的(3,4)系數不為1,那么為了生成適用的矩陣,應用程序必須用(3,4)系數的倒數縮放所有的系數。如果應用程序不提供符合這樣要求的矩陣,那么會造成霧效果和深度緩存不正確。什么是投影矩陣?中推薦的矩陣符合基于w的計算的要求。

            下圖顯示了不符合要求的投影矩陣,以及對同一個矩陣進行縮放,這樣就可以啟用基于視點的霧。

             

            我們假設在前面的矩陣中,所有變量都不為零。更多有關相對于視點的霧的信息,請參閱基于視點的深度與基于Z的深度的比較。更多有關基于w的深度緩存,請參閱深度緩存

            注意 Direct3D在基于w的深度計算中使用當前設置的投影矩陣。因此,即使應用程序不使用Direct3D變換流水線,但是為了使用基于w的特性,應用程序必須設置一個符合要求的投影矩陣。

             



            posted on 2012-08-31 16:31 Jacc.Kim 閱讀(743) 評論(0)  編輯 收藏 引用 所屬分類: VC / C++
            精品熟女少妇aⅴ免费久久| 久久成人影院精品777| 狠狠色丁香久久婷婷综合| 久久午夜无码鲁丝片秋霞| 久久国产精品无码一区二区三区| 99久久久精品| 久久亚洲国产精品成人AV秋霞| 亚洲精品无码久久久久sm| 久久激情亚洲精品无码?V| 77777亚洲午夜久久多人| 国产综合成人久久大片91| 色综合久久久久久久久五月| 精品久久久久中文字幕一区| 久久亚洲日韩精品一区二区三区| 精品久久久久久无码人妻蜜桃| 久久99热这里只有精品国产| 久久精品99无色码中文字幕| 99久久无码一区人妻a黑| 日批日出水久久亚洲精品tv| 久久久久夜夜夜精品国产| 一本久久a久久精品亚洲| 女人高潮久久久叫人喷水| 亚洲午夜久久久精品影院| 91精品国产高清久久久久久io| 久久亚洲精品无码aⅴ大香 | 久久夜色精品国产噜噜亚洲AV| 久久久WWW成人免费毛片| 91精品婷婷国产综合久久| 丁香五月网久久综合| 成人免费网站久久久| AV无码久久久久不卡蜜桃 | 久久这里只有精品久久| 久久精品人人做人人爽电影蜜月| 狠狠色婷婷久久一区二区| 久久亚洲AV成人无码软件| 色偷偷88欧美精品久久久| 久久久久免费视频| 中文字幕久久亚洲一区| 久久九九久精品国产免费直播| 久久久久高潮综合影院| 亚洲国产精品18久久久久久|