您的位置:首页 > 其它

3D数学 RotationMatrix

2015-09-22 19:28 190 查看

1. 如何使用矩阵表示方位

通过列出从一个坐标系到另一个坐标系的转变矩阵来表示两个坐标系之间的关系。

例如:从物体坐标系到惯性坐标系的转变矩阵,也可以通过逆矩阵从惯性坐标系转换回物体坐标系。


示例:

我们会看一下如何用一个矩阵将一个点从一个坐标系转变到另一个坐标系。

下图使用一个矩阵将飞机从物体坐标系转换到惯性坐标系。

我们用粗黑箭头指示矩阵的每一行和物体坐标轴的关系。

这个旋转矩阵包含了在惯性坐标系的物体轴。

同时,它是个旋转矩阵。可以用多个行向量跟矩阵相乘,将多个向量从物体坐标系转换到惯性坐标系。





因为旋转矩阵是正交的,因此如果我们想从惯性坐标系转换回物体坐标系,可以使用矩阵的转置(等同于矩阵的逆)作为转换矩阵。

但是,使用矩阵来表示方位有一个问题:不便于程序员阅读和检查代码问题。

2. C++代码实现

/////////////////////////////////////////////////////////////////////////////
//
// 3D Math Primer for Games and Graphics Development
//
// Vector3.h - Declarations for 3D vector class
//
// Visit gamemath.com for the latest version of this file.
//
// For additional comments, see Chapter 6.
//
/////////////////////////////////////////////////////////////////////////////

#ifndef __VECTOR3_H_INCLUDED__
#define __VECTOR3_H_INCLUDED__

#include <math.h>

/////////////////////////////////////////////////////////////////////////////
//
// class Vector3 - a simple 3D vector class
//
/////////////////////////////////////////////////////////////////////////////

class Vector3 {
public:

// Public representation:  Not many options here.

    float x,y,z;

// Constructors

    // Default constructor leaves vector in
    // an indeterminate state

    Vector3() {}

    // Copy constructor

    Vector3(const Vector3 &a) : x(a.x), y(a.y), z(a.z) {}

    // Construct given three values

    Vector3(float nx, float ny, float nz) : x(nx), y(ny), z(nz) {}

// Standard object maintenance

    // Assignment.  We adhere to C convention and
    // return reference to the lvalue

    Vector3 &operator =(const Vector3 &a) {
        x = a.x; y = a.y; z = a.z;
        return *this;
    }

    // Check for equality

    bool operator ==(const Vector3 &a) const {
        return x==a.x && y==a.y && z==a.z;
    }

    bool operator !=(const Vector3 &a) const {
        return x!=a.x || y!=a.y || z!=a.z;
    }

// Vector operations

    // Set the vector to zero

    void zero() { x = y = z = 0.0f; }

    // Unary minus returns the negative of the vector

    Vector3 operator -() const { return Vector3(-x,-y,-z); }

    // Binary + and - add and subtract vectors

    Vector3 operator +(const Vector3 &a) const {
        return Vector3(x + a.x, y + a.y, z + a.z);
    }

    Vector3 operator -(const Vector3 &a) const {
        return Vector3(x - a.x, y - a.y, z - a.z);
    }

    // Multiplication and division by scalar

    Vector3 operator *(float a) const {
        return Vector3(x*a, y*a, z*a);
    }

    Vector3 operator /(float a) const {
        float   oneOverA = 1.0f / a; // NOTE: no check for divide by zero here
        return Vector3(x*oneOverA, y*oneOverA, z*oneOverA);
    }

    // Combined assignment operators to conform to
    // C notation convention

    Vector3 &operator +=(const Vector3 &a) {
        x += a.x; y += a.y; z += a.z;
        return *this;
    }

    Vector3 &operator -=(const Vector3 &a) {
        x -= a.x; y -= a.y; z -= a.z;
        return *this;
    }

    Vector3 &operator *=(float a) {
        x *= a; y *= a; z *= a;
        return *this;
    }

    Vector3 &operator /=(float a) {
        float   oneOverA = 1.0f / a;
        x *= oneOverA; y *= oneOverA; z *= oneOverA;
        return *this;
    }

    // Normalize the vector

    void    normalize() {
        float magSq = x*x + y*y + z*z;
        if (magSq > 0.0f) { // check for divide-by-zero
            float oneOverMag = 1.0f / sqrt(magSq);
            x *= oneOverMag;
            y *= oneOverMag;
            z *= oneOverMag;
        }
    }

    // Vector dot product.  We overload the standard
    // multiplication symbol to do this

    float operator *(const Vector3 &a) const {
        return x*a.x + y*a.y + z*a.z;
    }
};

/////////////////////////////////////////////////////////////////////////////
//
// Nonmember functions
//
/////////////////////////////////////////////////////////////////////////////

// Compute the magnitude of a vector

inline float vectorMag(const Vector3 &a) {
    return sqrt(a.x*a.x + a.y*a.y + a.z*a.z);
}

// Compute the cross product of two vectors

inline Vector3 crossProduct(const Vector3 &a, const Vector3 &b) {
    return Vector3(
        a.y*b.z - a.z*b.y,
        a.z*b.x - a.x*b.z,
        a.x*b.y - a.y*b.x
    );
}

// Scalar on the left multiplication, for symmetry

inline Vector3 operator *(float k, const Vector3 &v) {
    return Vector3(k*v.x, k*v.y, k*v.z);
}

// Compute the distance between two points

inline float distance(const Vector3 &a, const Vector3 &b) {
    float dx = a.x - b.x;
    float dy = a.y - b.y;
    float dz = a.z - b.z;
    return sqrt(dx*dx + dy*dy + dz*dz);
}

// Compute the distance between two points, squared.  Often useful
// when comparing distances, since the square root is slow

inline float distanceSquared(const Vector3 &a, const Vector3 &b) {
    float dx = a.x - b.x;
    float dy = a.y - b.y;
    float dz = a.z - b.z;
    return dx*dx + dy*dy + dz*dz;
}

/////////////////////////////////////////////////////////////////////////////
//
// Global variables
//
/////////////////////////////////////////////////////////////////////////////

// We provide a global zero vector constant

extern const Vector3 kZeroVector;

/////////////////////////////////////////////////////////////////////////////
#endif // #ifndef __VECTOR3_H_INCLUDED__


/////////////////////////////////////////////////////////////////////////////
//
// 3D Math Primer for Games and Graphics Development
//
// RotationMatrix.h - Declarations for class RotationMatrix
//
// Visit gamemath.com for the latest version of this file.
//
// For more details, see RotationMatrix.cpp
//
/////////////////////////////////////////////////////////////////////////////

#ifndef __ROTATIONMATRIX_H_INCLUDED__
#define __ROTATIONMATRIX_H_INCLUDED__

class Vector3;
class EulerAngles;
class Quaternion;

//---------------------------------------------------------------------------
// class RotationMatrix
//
// Implement a simple 3x3 matrix that is used for ROTATION ONLY.  The
// matrix is assumed to be orthogonal.  The direction of transformation
// is specified at the time of transformation.

class RotationMatrix {
public:

// Public data

    // The 9 values of the matrix.  See RotationMatrix.cpp file for
    // the details of the layout

    float   m11, m12, m13;
    float   m21, m22, m23;
    float   m31, m32, m33;

// Public operations

    // Set to identity

    void    identity();

    // Setup the matrix with a specified orientation

    void    setup(const EulerAngles &orientation);

    // Setup the matrix from a quaternion, assuming the
    // quaternion performs the rotation in the
    // specified direction of transformation

    void    fromInertialToObjectQuaternion(const Quaternion &q);
    void    fromObjectToInertialQuaternion(const Quaternion &q);

    // Perform rotations

    Vector3 inertialToObject(const Vector3 &v) const;
    Vector3 objectToInertial(const Vector3 &v) const;
};

/////////////////////////////////////////////////////////////////////////////
#endif // #ifndef __ROTATIONMATRIX_H_INCLUDED__


/////////////////////////////////////////////////////////////////////////////
//
// 3D Math Primer for Games and Graphics Development
//
// RotationMatrix.cpp - Implementation of class RotationMatrix
//
// Visit gamemath.com for the latest version of this file.
//
// For more details see section 11.4.
//
/////////////////////////////////////////////////////////////////////////////

#include "vector3.h"
#include "RotationMatrix.h"
#include "MathUtil.h"
#include "Quaternion.h"
#include "EulerAngles.h"

/////////////////////////////////////////////////////////////////////////////
//
// class RotationMatrix
//
//---------------------------------------------------------------------------
//
// MATRIX ORGANIZATION
//
// A user of this class should rarely care how the matrix is organized.
// However, it is of course important that internally we keep everything
// straight.
//
// The matrix is assumed to be a rotation matrix only, and therefore
// orthoganal.  The "forward" direction of transformation (if that really
// even applies in this case) will be from inertial to object space.
// To perform an object->inertial rotation, we will multiply by the
// transpose.
//
// In other words:
//
// Inertial to object:
//
//                  | m11 m12 m13 |
//     [ ix iy iz ] | m21 m22 m23 | = [ ox oy oz ]
//                  | m31 m32 m33 |
//
// Object to inertial:
//
//                  | m11 m21 m31 |
//     [ ox oy oz ] | m12 m22 m32 | = [ ix iy iz ]
//                  | m13 m23 m33 |
//
// Or, using column vector notation:
//
// Inertial to object:
//
//     | m11 m21 m31 | | ix |   | ox |
//     | m12 m22 m32 | | iy | = | oy |
//     | m13 m23 m33 | | iz |   | oz |
//
// Object to inertial:
//
//     | m11 m12 m13 | | ox |   | ix |
//     | m21 m22 m23 | | oy | = | iy |
//     | m31 m32 m33 | | oz |   | iz |
//
/////////////////////////////////////////////////////////////////////////////

//---------------------------------------------------------------------------
// RotationMatrix::identity
//
// Set the matrix to the identity matrix

void    RotationMatrix::identity() {
    m11 = 1.0f; m12 = 0.0f; m13 = 0.0f;
    m21 = 0.0f; m22 = 1.0f; m23 = 0.0f;
    m31 = 0.0f; m32 = 0.0f; m33 = 1.0f;
}

//---------------------------------------------------------------------------
// RotationMatrix::setup
//
// Setup the matrix with the specified orientation
//
// See 10.6.1

void    RotationMatrix::setup(const EulerAngles &orientation) {

    // Fetch sine and cosine of angles

    float   sh,ch, sp,cp, sb,cb;
    sinCos(&sh, &ch, orientation.heading);
    sinCos(&sp, &cp, orientation.pitch);
    sinCos(&sb, &cb, orientation.bank);

    // Fill in the matrix elements

    m11 = ch * cb + sh * sp * sb;
    m12 = -ch * sb + sh * sp * cb;
    m13 = sh * cp;

    m21 = sb * cp;
    m22 = cb * cp;
    m23 = -sp;

    m31 = -sh * cb + ch * sp * sb;
    m32 = sb * sh + ch * sp * cb;
    m33 = ch * cp;
}

//---------------------------------------------------------------------------
// RotationMatrix::fromInertialToObjectQuaternion
//
// Setup the matrix, given a quaternion that performs an inertial->object
// rotation
//
// See 10.6.3

void    RotationMatrix::fromInertialToObjectQuaternion(const Quaternion &q) {

    // Fill in the matrix elements.  This could possibly be
    // optimized since there are many common subexpressions.
    // We'll leave that up to the compiler...

    m11 = 1.0f - 2.0f * (q.y*q.y + q.z*q.z);
    m12 = 2.0f * (q.x*q.y + q.w*q.z);
    m13 = 2.0f * (q.x*q.z - q.w*q.y);

    m21 = 2.0f * (q.x*q.y - q.w*q.z);
    m22 = 1.0f - 2.0f * (q.x*q.x + q.z*q.z);
    m23 = 2.0f * (q.y*q.z + q.w*q.x);

    m31 = 2.0f * (q.x*q.z + q.w*q.y);
    m32 = 2.0f * (q.y*q.z - q.w*q.x);
    m33 = 1.0f - 2.0f * (q.x*q.x + q.y*q.y);

}

//---------------------------------------------------------------------------
// RotationMatrix::fromObjectToInertialQuaternion
//
// Setup the matrix, given a quaternion that performs an object->inertial
// rotation
//
// See 10.6.3

void    RotationMatrix::fromObjectToInertialQuaternion(const Quaternion &q) {

    // Fill in the matrix elements.  This could possibly be
    // optimized since there are many common subexpressions.
    // We'll leave that up to the compiler...

    m11 = 1.0f - 2.0f * (q.y*q.y + q.z*q.z);
    m12 = 2.0f * (q.x*q.y - q.w*q.z);
    m13 = 2.0f * (q.x*q.z + q.w*q.y);

    m21 = 2.0f * (q.x*q.y + q.w*q.z);
    m22 = 1.0f - 2.0f * (q.x*q.x + q.z*q.z);
    m23 = 2.0f * (q.y*q.z - q.w*q.x);

    m31 = 2.0f * (q.x*q.z - q.w*q.y);
    m32 = 2.0f * (q.y*q.z + q.w*q.x);
    m33 = 1.0f - 2.0f * (q.x*q.x + q.y*q.y);
}

//---------------------------------------------------------------------------
// RotationMatrix::inertialToObject
//
// Rotate a vector from inertial to object space

Vector3 RotationMatrix::inertialToObject(const Vector3 &v) const {

    // Perform the matrix multiplication in the "standard" way.

    return Vector3(
        m11*v.x + m21*v.y + m31*v.z,
        m12*v.x + m22*v.y + m32*v.z,
        m13*v.x + m23*v.y + m33*v.z
    );
}

//---------------------------------------------------------------------------
// RotationMatrix::objectToInertial
//
// Rotate a vector from object to inertial space

Vector3 RotationMatrix::objectToInertial(const Vector3 &v) const {

    // Multiply by the transpose

    return Vector3(
        m11*v.x + m12*v.y + m13*v.z,
        m21*v.x + m22*v.y + m23*v.z,
        m31*v.x + m32*v.y + m33*v.z
    );
}


#include "RotationMatrix.h"
#include <iostream>

using namespace std;

void prfloatVec(Vector3 &vec)
{
    cout << "[" 
        << vec.x << "," 
        << vec.y << "," 
        << vec.z << "]" << endl;
}

int main()
{
    cout << "hello 矩阵的逆" << endl;

    RotationMatrix m;
    m.m11 = 0.866f; m.m12 = 0.0f;   m.m13 = -0.5f;
    m.m21 = 0.0f;   m.m22 = 1.0f;   m.m23 = 0.0f;
    m.m31 = 0.5f;   m.m32 = 0.0f;   m.m33 = 0.866f;

    Vector3 v(10,20,30);
    Vector3 v2;

    v2 = m.inertialToObject(v);
    prfloatVec(v2);

    v2 = m.objectToInertial(v);
    prfloatVec(v2);

}


3. 程序运行结果

hello 矩阵的逆

[23.66,20,20.98]

[-6.34,20,30.98]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: