Small World: 精简向量运算库

来源:互联网 发布:js判断奇数偶数 编辑:程序博客网 时间:2024/06/07 17:26


第四章: 工欲善其事必先利其器


上一章,回顾了物理引擎中需要的物理学知识,为了能在系统中对其进行数值计算,还需要最基本的向量运算库,如表示二维或三维空间中的点,矩阵运算,四元数等。最少我需要一下几种功能:


1.多维向量表示及其运算,如叉乘,点积,加减等;

2.二至四维的矩阵,及其运算;

3.三或四维矩阵表示的转移矩阵,进行向量的平移,旋转,缩放;

4.四元数的操作以及转换。


目前只需要以上几种运算,所以使用其他的向量库未免太多复杂而且又难以满足,系统对不同维度变化的需求,所以我准备写了一个精简的向量运算库,目前还在不断改进,代码存在:https://github.com/lxdfigo/SimpleMath 网站上。


第一节 向量


首先,我需要一个维度可变的向量,因为物理引擎需要适应三维和二维两种系统。所以,可以使用模版类对向量维数进行控制,基本方法如下:


template<class T, int DIMENSION>class CVector{private:T Elements[DIMENSION];public:CVector(T f = 0);CVector(T v1, T v2);CVector(T v1, T v2, T v3, ...);CVector(const CVector<int,DIMENSION>& vec);CVector(const CVector<float,DIMENSION>& vec);CVector(const CVector<double,DIMENSION>& vec);bool operator<(const CVector& Vector) const;bool operator>(const CVector& Vector) const;CVector& operator=(const CVector& Vector);CVector operator+(const CVector& Vector) const;inline CVector operator-(const CVector& Vector) const;CVector operator* (T ccalar) const;CVector operator/ (T ccalar) const;CVector operator* (const CVector& Vector) const;CVector operator/ (const CVector& Vector) const;CVector& operator+=(const CVector& Vector);CVector& operator-=(const CVector& Vector);CVector& operator*=(T ccalar);CVector& operator/=(T ccalar);inline T & operator [] (int i) { return Elements[i]; }inline T   operator [] (int i) const { return Elements[i]; }inline T Length() const;inline T Length2() const;inline T Dot(const CVector& Vector) const;T Distance(const CVector& Vector) const;T SquaredDistance(const CVector& Vector) const;void Normalize();void UniformRandomHyperSphere(T rng );T minElement();T maxElement();void setAll(T v);void zero();};

模版参数T控制类型,DIMENSION给出向量维度,其构造函数有三种,当只有一个参数时,赋给所有元素,当有两个或两个以上参数时,按顺序赋给所有元素。根据系统需要,定义了以下几种常用类型:

typedef CVector<float,2> Vec2f;typedef CVector<double,2> Vec2d;typedef CVector<float,3> Vec3f;typedef CVector<double,3> Vec3d;typedef CVector<float,4> Vec4f;typedef CVector<double,4> Vec4d;


第二节 矩阵


根据n维向量,可以定义n x n维的矩阵,同样通过模版参数对维度和类型进行控制,定义如下:

template<class T, int DIMENSION>class CMatrix{private:CVector<T,DIMENSION> Rows[DIMENSION];public:CMatrix(){}inline CVector<T,DIMENSION> & operator [] (int i) { return Rows[i]; }inline CVector<T,DIMENSION>   operator [] (int i) const { return Rows[i]; }CVector<T,DIMENSION> operator * (CVector<T,DIMENSION> &vec);CMatrix operator * (const CMatrix &mat);CMatrix operator * (T scale);CMatrix operator / (T scale);CMatrix operator + (const CMatrix &mat);CMatrix operator - (const CMatrix &mat);CMatrix& operator += (const CMatrix& mat);CMatrix& operator -= (const CMatrix& mat);CMatrix& operator *= (const CMatrix& mat);CMatrix& operator *= (T scale);CMatrix& operator/=(T scale);void zero();};

矩阵运算包括简单的加减,矩阵乘法,矩阵和向量的乘积等。还有矩阵清零的函数,定义常用矩阵如下:


typedef CMatrix<float,2> Mat2x2f;typedef CMatrix<float,3> Mat3x3f;typedef CMatrix<float,4> Mat4x4f;typedef CMatrix<double,3> Mat3x3d;typedef CMatrix<double,4> Mat4x4d;

根据矩阵类型和操作,定义空间变换需要的转移矩阵类型:


template<class T, int DIMENSION>class CTransform{private:CMatrix<T,DIMENSION> mat;public:CTransform();~CTransform(){}void reset();CTransform& makeMoveTrans(CVector<T,DIMENSION-1>& vec);CTransform& makeScaleTrans(CVector<T,DIMENSION-1>& vec);CTransform& makeRotateTrans(Quat<T>& quat);CVector<T,DIMENSION-1>& trans(CVector<T,DIMENSION-1>&  vec);};typedef CTransform<double,3> Trans3x3d;typedef CTransform<float,3> Trans3x3f;typedef CTransform<double,4> Trans4x4d;typedef CTransform<float,4> Trans4x4f;

转移矩阵一般情况下是单位矩阵,根据需要移动的向量和角度的不同可以make成不懂的矩阵。通过trans对向量进行操作。


第三节 四元数


为了避免万向锁问题(即利用欧拉角进行物体旋转时,当第二个角是+-90度时,第一个轴被旋转到和第三个平行,导致失去了一个旋转的自由度,只能进行两个轴的旋转),引入四元数解决这一问题。详细情况google一下,你就知道。


定义四元数的基本操作:


template<class T>class  Quat{public:T  Elements[4];   inline Quat() { Elements[0]=0.0; Elements[1]=0.0; Elements[2]=0.0; Elements[3]=1.0; }inline Quat( T x, T y, T z, T w );inline Quat( const CVector<T,4>& v );inline Quat( T angle, const CVector<T,3>& axis);inline Quat& operator = (const Quat& v);inline bool operator == (const Quat& v) const;inline bool operator != (const Quat& v) const;inline bool operator <  (const Quat& v) const;inline void set(T x, T y, T z, T w);inline T & operator [] (int i) { return Elements[i]; }inline T   operator [] (int i) const { return Elements[i]; }inline T & x() { return Elements[0]; }inline T & y() { return Elements[1]; }inline T & z() { return Elements[2]; }inline T & w() { return Elements[3]; }inline T x() const { return Elements[0]; }inline T y() const { return Elements[1]; }inline T z() const { return Elements[2]; }inline T w() const { return Elements[3]; }inline const Quat operator * (T rhs) const;inline Quat& operator *= (T rhs);inline const Quat operator*(const Quat& rhs) const;inline const Quat operator*(const CVector<T,3>& rhs) const;inline Quat& operator*=(const Quat& rhs);inline Quat operator / (T rhs) const;inline Quat& operator /= (T rhs);inline const Quat operator/(const Quat& denom) const;inline Quat& operator/=(const Quat& denom);inline const Quat operator + (const Quat& rhs) const;inline Quat& operator += (const Quat& rhs);inline const Quat operator - (const Quat& rhs) const;inline Quat& operator -= (const Quat& rhs);inline const Quat operator - () const;T Dot(const Quat& rhs) const;T length() const;T length2() const;inline Quat conj () const;inline const Quat inverse () const;void makeRotate (T  angle,  T  x, T  y, T  z );void makeRotate ( T  angle, const CVector<T,3>& vec );void makeRotate( const CVector<T,3>& vec1, const CVector<T,3>& vec2 );void getRotate ( T & angle, T & x, T & y, T & z ) const;void getRotate ( T & angle, CVector<T,3>& vec ) const;void slerp(T  t, const Quat& from, const Quat& to);CVector<T,3> rotate (const CVector<T,3>& vec ) const;};    typedef Quat<float> Quatf;typedef Quat<double> Quatd;

四元数的操作较为复杂,根据向量或是轴和角的组合来构造,只能和三维向量进行运算,是对三维空间旋转进行操作的类。


有了这三种基本类型,就可以处理二维和三维系统中简单的平移,旋转操作了。



原创粉丝点击