• <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>

            天行健 君子當(dāng)自強(qiáng)而不息

            3D中的方位和角位移的C++實(shí)現(xiàn)(1)

            新建網(wǎng)頁 1

             

            數(shù)學(xué)理論基礎(chǔ)請參閱3D中的方位和角位移。

            處理變換是一件非常令人頭疼的事,矩陣更是棘手。如果你曾經(jīng)編寫過關(guān)于矩陣的代碼并且沒有用設(shè)計(jì)良好的類,你會發(fā)現(xiàn)經(jīng)常要處理負(fù)號、轉(zhuǎn)置矩陣或翻轉(zhuǎn)連接順序以使其能正常工作。

            下面這幾個(gè)類正是為了消除在編程中經(jīng)常遇到的這類問題而設(shè)計(jì)的。例如,很少需要直接訪問矩陣或四元數(shù)中的元素,因此特意限制了可用操作的數(shù)目以避免產(chǎn)生迷惑,再如,對cRotationMatrix類,沒有求逆和連接操作,因?yàn)槿绻雌浔旧淼哪康氖褂?/span>cRotationMatrix,這些操作是不應(yīng)該出現(xiàn)或沒有意義的。

            我們還使用了一系列簡單、常用的數(shù)學(xué)常數(shù)和實(shí)用工具函數(shù),它們由MathUtil.hMathUtil.cpp提供。

            MathUtil.h:

                    #ifndef MATH_UTIL_H
                
            #define MATH_UTIL_H
                
                #include <math.h>
                
                
                // declare a global constant for pi and a few multiples.
                

                
            const float G_PI          = 3.14159265f;
                
            const float G_2PI          = G_PI * 2.0f;
                
            const float G_PI_OVER_2   = G_PI / 2.0f;
                
            const float G_1_OVER_PI   = 1.0f / G_PI;
                
            const float G_1_OVER_2PI  = 1.0f / G_2PI;
                
            const float G_PI_OVER_180 = G_PI / 180.0f;
                
            const float G_180_OVER_PI = 180.0f / G_PI;
                
                
            float wrap_pi(float theta);
                
            float safe_acos(float x);
                
                
                // convert between degrees and radians
                
            inline float deg_to_rad(float deg)    { return deg * G_PI_OVER_180; }
                inline 
            float rad_to_deg(float rad)    { return rad * G_180_OVER_PI; }
                
                
                // compute the sin and cosine of an angle. on some platforms, if we know that we need
                // both values, it can be computed faster than computing the two values seperately.
                
            inline void sin_cos(float* ret_sin, float* ret_cos, float theta)
                {
                    
            // for simplicity, we will just use the normal trig functions.
                    // note that on some platforms we may be able to do better.
                

                    *ret_sin = sin(theta);
                    *ret_cos = cos(theta);
                }
                
                
                // convert between "field of view" and "zoom", the fov angle is speficied in radians.
                
            inline float fov_to_zoom(float fov)        { return 1.0f / tan(fov * 0.5f); }
                inline 
            float zoom_to_fov(float zoom)    { return 2.0f * atan(1.0f / zoom); }
                
                
            #endif

            MathUtil.cpp:

            關(guān)于類cVector3的實(shí)現(xiàn)細(xì)節(jié)請參閱一個(gè)3D向量類

                    #include "MathUtil.h"
                #include "vector3.h"
                
                
            const cVector3 g_zero_vector(0.0f, 0.0f, 0.0f);
                
                
            float wrap_pi(float theta)
                {
                    
            // "wrap" an angle in range -pipi by adding the correct multiple of 2 pi
                

                    theta += G_PI;
                    theta -= floor(theta * G_1_OVER_2PI) * G_2PI;
                    theta -= G_PI;
                
                    
            return theta;
                }
                
                
            float safe_acos(float x)
                {
                    
            // Same as acos(x), but if x is out of range, it is "clamped" to the nearest valid value.
                    // The value returned is in range 0pi, the same as the standard C acos() function.
                
                    // check limit conditions
                

                    
            if(x <= -1.0f)
                        
            return G_PI;
                
                    
            if(x >= 1.0f)
                        
            return 0.0f;
                
                    
            // value is in the domain - use standard C function.
                
                return acos(x);
                }

            cEulerAngles類:

            cEulerAngles類用來以歐拉角形式保存方位,使用heading-pitch-bank約定。這個(gè)類非常直觀,為了簡單起見,我們沒有實(shí)現(xiàn)太多操作。特別沒有實(shí)現(xiàn)加、減、標(biāo)量乘等運(yùn)算。因?yàn)槿绻擃惐4娴牟皇欠轿欢墙撬俣然蜃兓?,那么這些運(yùn)算才是有用的。

            EulerAngles.h:

                    #ifndef EULER_ANGLES_H
                
            #define EULER_ANGLES_H
                
                
            class cQuaternion;
                
            class cMatrix4x3;
                
            class cRotationMatrix;
                
                
                //---------------------------------------------------------------------------
                // This class represents a heading-pitch-bank Euler angle triple.
                //---------------------------------------------------------------------------
                
            class cEulerAngles
                {
                
            public:
                    
            // store three angles, in radians.
                
                float heading;
                    
            float pitch;
                    
            float bank;
                
                
            public:
                    cEulerAngles()    {}
                    
                    cEulerAngles(
            float h, float p, float b)
                    {
                        heading = h;
                        pitch   = p;
                        bank    = b;
                    }
                
                    
            // set to identity triple (all zeors)
                
                void identity()
                    {
                        pitch = bank = heading = 0.0f;
                    }
                
                    
            void canonize();
                
                    
            void from_object_to_inertial_quat(const cQuaternion& q);
                    
            void from_inertial_to_object_quat(const cQuaternion& q);
                
                    
            void from_object_to_world_matrix(const cMatrix4x3& m);
                    
            void from_world_to_object_matrix(const cMatrix4x3& m);
                
                    
            void from_rotation_matrix(const cRotationMatrix& m);
                };
                
                
            extern const cEulerAngles g_euler_angles_identity;
                
                
            #endif

            cEulerAngles類的用法也很直觀,只有幾個(gè)地方需要加以詳細(xì)說明:

            (1)canonize()函數(shù)的作用是確保歐拉角位于"限制集"中。

            (2)from_object_to_inertial_quat()from_inertial_to_object_quat()函數(shù)根據(jù)四元數(shù)計(jì)算歐拉角,第一個(gè)函數(shù)的參數(shù)是代表從物體坐標(biāo)系到慣性坐標(biāo)系旋轉(zhuǎn)的四元數(shù),第二個(gè)函數(shù)的參數(shù)是代表從慣性坐標(biāo)系到物體坐標(biāo)系旋轉(zhuǎn)的四元數(shù)。

            (3)同樣,from_object_to_world_matrix()from_world_to_object_matrix()函數(shù)把矩陣的旋轉(zhuǎn)部分的方位轉(zhuǎn)換為歐拉角,假設(shè)這個(gè)被轉(zhuǎn)換的矩陣是正交的。


            EulerAngles.cpp:

                    #include <math.h>
                #include "EulerAngles.h"
                #include "Quaternion.h"
                #include "MathUtil.h"
                #include "Matrix4x3.h"
                #include "RotationMatrix.h"
                
                
            const cEulerAngles g_euler_angles_identity(0.0f, 0.0f, 0.0f);
                
                
                //---------------------------------------------------------------------------
                // Set the Euler angle triple to its "canonical" value.  This does not change
                // the meaning of the Euler angles as a representation of Orientation in 3D,
                // but if the angles are for other purposes such as angular velocities, etc,
                // then the operation might not be valid.
                //---------------------------------------------------------------------------
                
            void cEulerAngles::canonize()
                {
                    
            // first, wrap pitch in range -pi  pi
                
                pitch = wrap_pi(pitch);
                
                    
            // now, check for "the back side" of the matrix, pitch outside the canonical range
                    // of -pi/2  pi/2
                
                if(pitch < -G_PI_OVER_2)
                    {
                        pitch     = -G_PI - pitch;
                        heading += G_PI;
                        bank    += G_PI;
                    }
                    
            else if(pitch > G_PI_OVER_2)
                    {
                        pitch     = G_PI - pitch;
                        heading += G_PI;
                        bank    += G_PI;
                    }
                
                    
            // ok, now check for the gimbel lock case (within a slight tolerance)    
                
                if(fabs(pitch) > G_PI_OVER_2 - 1e-4)
                    {
                        
            // we are in gimbel lock, assign all rotation about the vertical axis to heading.
                
                    heading += bank;
                        bank     = 0.0f;
                    }
                    
            else
                    {
                        
            // not in gimbel lock, wrap the bank angle in canonical range.
                
                    bank = wrap_pi(bank);
                    }
                
                    
            // wrap heading in canonical range
                
                heading = wrap_pi(heading);
                }
                
                
                //---------------------------------------------------------------------------
                // Setup the Euler angles, given an object->inertial rotation quaternion.
                //
                // p = asin(-m23) = asin(-2(yz - wx))
                // 
                // h = atan2(m13, m33)  = atan2(xz + wy, 1/2 - x^2 - y^2)   cosp != 0
                // h = atan2(-m31, m11) = atan2(-xz + wy, 1/2 - y^2 - z^2)  cosp == 0
                //
                // b = atan2(m21, m22) = atan2(xy + wz, 1/2 - x^2 - z^2)    cosp != 0
                // b = 0                                                    cosp == 0
                //---------------------------------------------------------------------------
                
            void cEulerAngles::from_object_to_inertial_quat(const cQuaternion& q)
                {
                    
            // extract sin(pitch)
                
                float sin_pitch = -2.0f * (q.y * q.z - q.w * q.x);
                
                    
            // check for gimbel lock, giving slight tolerance for numerical imprecision.
                
                if(fabs(sin_pitch) > 0.9999f)
                    {
                        
            // looking straight up or down
                
                    pitch = G_PI_OVER_2 * sin_pitch;
                
                        
            // compute heading, slam bank to zero.
                
                    heading = atan2(-q.x * q.z + q.w * q.y, 0.5f - q.y * q.y - q.z * q.z);
                        bank = 0.0f;
                    }
                    
            else
                    {
                        
            // compute angles, we do not have to use the "safe" asin function because we already
                        // checked for range errors when checking for gimbel lock.
                
                    pitch    = asin(sin_pitch);
                        heading = atan2(q.x * q.z + q.w * q.y, 0.5f - q.x * q.x - q.y * q.y);
                        bank    = atan2(q.x * q.y + q.w * q.z, 0.5f - q.x * q.x - q.z * q.z);
                    }
                }
                
                
                //---------------------------------------------------------------------------
                // Setup the Euler angles, given an inertial->object rotation quaternion.
                //
                // p = asin(-m23) = asin(-2(yz + wx))
                // 
                // h = atan2(m13, m33)  = atan2(xz - wy, 1/2 - x^2 - y^2)   cosp != 0
                // h = atan2(-m31, m11) = atan2(-xz - wy, 1/2 - y^2 - z^2)  cosp == 0
                //
                // b = atan2(m21, m22) = atan2(xy - wz, 1/2 - x^2 - z^2)    cosp != 0
                // b = 0                                                    cosp == 0
                //---------------------------------------------------------------------------
                
            void cEulerAngles::from_inertial_to_object_quat(const cQuaternion& q)
                {
                    
            // extract sin(pitch)
                
                float sin_pitch = -2.0f * (q.y * q.z + q.w * q.x);
                
                    
            // check for gimbel lock, giving slight tolerance for numerical imprecision.
                
                if(fabs(sin_pitch) > 0.9999f)
                    {
                        
            // looking straight up or down
                
                    pitch = G_PI_OVER_2 * sin_pitch;
                
                        
            // compute heading, slam bank to zero.
                
                    heading = atan2(-q.x * q.z - q.w * q.y, 0.5f - q.y * q.y - q.z * q.z);
                        bank = 0.0f;
                    }
                    
            else
                    {
                        
            // compute angles, we do not have to use the "safe" asin function because we already
                        // checked for range errors when checking for gimbel lock.
                
                    pitch    = asin(sin_pitch);
                        heading = atan2(q.x * q.z - q.w * q.y, 0.5f - q.x * q.x - q.y * q.y);
                        bank    = atan2(q.x * q.y - q.w * q.z, 0.5f - q.x * q.x - q.z * q.z);
                    }
                }
                
                
                //------------------------------------------------------------------------------------------------
                // Setup the Euler angles, given an object->world transformation matrix.
                // The matrix is assumed to be orthogonal.  The translation portion is ignored.
                //
                //     | cosh * cosb + sinh * sinp * sinb        sinb * cosp    -sinh * cosb + cosh * sinp * sinb |
                // M = | -cosh * sinb + sinh * sinp * cosb        cosb * cosp        sinb * sinh + cosh * sinp * cosb |
                //       | sinh * cosp                            -sinp            cosh * cosp                         |
                //
                // [1]: cosp != 0
                //
                // p = asin(-m32)
                // h = atan2(m31, m33)
                // b = atan2(m12, m22)
                //
                // [2]: cosp = 0, b = 0, sinb = 0, cosb = 1
                //
                //     | cosh            0        -sinh        |
                // M = | sinh * sinp    0        cosh * sinp |
                //       | 0                -sinp    0            |
                //
                // p = pi/2 * (-m32)
                // h = atan2(-m13, m11)
                // b = 0
                //------------------------------------------------------------------------------------------------
                
            void cEulerAngles::from_object_to_world_matrix(const cMatrix4x3& m)
                {
                    
            // extract sin(pitch) from m32
                
                float sin_pitch = -m.m32;
                
                    
            // check for gimbel lock
                
                if(fabs(sin_pitch) > 0.99999f)
                    {
                        
            // locking straight up or down
                
                    pitch = G_PI_OVER_2 * sin_pitch;
                
                        
            // compute heading, slam bank to zero.
                
                        heading = atan2(-m.m13, m.m11);
                        bank = 0.0f;
                    }
                    
            else
                    {
                        
            // compute angles, we do not have to use the "safe" asin function because we already
                        // checked for range errors when checking for gimbel lock.
                
                        heading = atan2(m.m31, m.m33);
                        pitch   = asin(sin_pitch);
                        bank    = atan2(m.m12, m.m22);
                    }
                }
                
                
                //-----------------------------------------------------------------------------------------------------
                // Setup the Euler angles, given a world->object transformation matrix.
                // The matrix is assumed to be orthogonal.  The translation portion is ignored.
                //
                //     | cosh * cosb + sinh * sinp * sinb      -cosh * sinb + sinh * sinp * cosb         sinh * cosp |
                // M = | sinb * cosp                            cosb * cosp                                 -sinp         |
                //       | -sinh * cosb + cosh * sinp * sinb        sinb * sinh + cosh * sinp * cosb        cosh * cosp  |
                //
                // [1]: cosp != 0
                //
                // p = asin(-m23)
                // h = atan2(m13, m33)
                // b = atan2(m21, m22)
                //
                // [2]: cosp = 0, b = 0, sinb = 0, cosb = 1
                //
                //        | cosh      sinh * sinp     0     |
                // M =  | 0            0                -sinp |
                //        | -sinh        cosh * sinp        0      |
                //
                // p = pi/2 * (-m23)
                // h = atan2(-m31, m11)
                // b = 0
                //-----------------------------------------------------------------------------------------------------
                
            void cEulerAngles::from_world_to_object_matrix(const cMatrix4x3& m)
                {
                    
            // extract sin(pitch) from m23
                
                float sin_pitch = -m.m23;
                
                    
            // check for gimbel lock
                
                if(fabs(sin_pitch) > 0.99999f)
                    {
                        
            // locking straight up or down
                
                        pitch = G_PI_OVER_2 * sin_pitch;
                
                        
            // compute heading, slam bank to zero.
                
                        heading = atan2(-m.m31, m.m11);
                        bank = 0.0f;
                    }
                    
            else
                    {
                        
            // compute angles, we do not have to use the "safe" asin function because we already
                        // checked for range errors when checking for gimbel lock.
                
                        heading = atan2(m.m13, m.m33);
                        pitch   = asin(sin_pitch);
                        bank    = atan2(m.m21, m.m22);
                    } 
                }
                
                
                //---------------------------------------------------------------------------
                // Setup the Euler angles, given a rotation matrix.
                //---------------------------------------------------------------------------
                
            void cEulerAngles::from_rotation_matrix(const cRotationMatrix& m)
                {
                    
            // extract sin(pitch) from m23
                
                float sin_pitch = -m.m23;
                
                    
            // check for gimbel lock
                
                if(fabs(sin_pitch) > 0.99999f)
                    {
                        
            // locking straight up or down
                
                        pitch = G_PI_OVER_2 * sin_pitch;
                
                        
            // compute heading, slam bank to zero.
                
                        heading = atan2(-m.m31, m.m11);
                        bank = 0.0f;
                    }
                    
            else
                    {
                        
            // compute angles, we do not have to use the "safe" asin function because we already
                        // checked for range errors when checking for gimbel lock.
                
                        heading = atan2(m.m13, m.m33);
                        pitch   = asin(sin_pitch);
                        bank    = atan2(m.m21, m.m22);
                    } 
                }

            posted on 2008-02-18 10:49 lovedday 閱讀(1120) 評論(0)  編輯 收藏 引用

            公告

            導(dǎo)航

            統(tǒng)計(jì)

            常用鏈接

            隨筆分類(178)

            3D游戲編程相關(guān)鏈接

            搜索

            最新評論

            色88久久久久高潮综合影院| 人妻丰满?V无码久久不卡| 久久精品女人天堂AV麻| 久久中文字幕一区二区| 久久久久久a亚洲欧洲aⅴ | 久久久久久国产精品免费无码| 狠狠色丁香久久婷婷综合| 国内精品伊人久久久影院| 超级97碰碰碰碰久久久久最新| 久久这里只有精品视频99| av色综合久久天堂av色综合在 | 国产精品一区二区久久不卡 | 国产精品xxxx国产喷水亚洲国产精品无码久久一区 | 中文无码久久精品| 99精品久久久久久久婷婷| 久久精品国产久精国产一老狼| 久久精品国产亚洲AV高清热| 久久综合给久久狠狠97色| 久久精品人人槡人妻人人玩AV| …久久精品99久久香蕉国产| 国内精品伊人久久久影院| 午夜精品久久久久久毛片| 精品久久国产一区二区三区香蕉| 久久亚洲精品成人无码网站| 婷婷五月深深久久精品| 一级做a爱片久久毛片| 久久青青草原亚洲av无码app | 欧美日韩精品久久久久 | 999久久久无码国产精品| 青青青青久久精品国产| 亚洲精品NV久久久久久久久久| 久久亚洲国产午夜精品理论片 | 久久伊人中文无码| 性做久久久久久久| 久久99精品国产麻豆婷婷| 久久中文字幕人妻丝袜| 国产AⅤ精品一区二区三区久久| 久久久精品国产免大香伊 | 一本色综合久久| 国产精品九九九久久九九| 亚洲国产精品狼友中文久久久|