您的位置:首页 > 其它

3D数学基础--向量

2015-06-15 19:33 357 查看

理论基础

向量:它看起来就像一支箭,有大小和方向,没有位置。它的几何意义是表示一段位移,如(1, -2, 3)表示的位移是:向右平移1个单位,向下平移2个单位,向前平移3个单位。它们的执行顺序无关紧要。

向量运算与几何意义

零向量:数学表示(0,0,0),表示没有位移,就像标量0表示没有数量一样。

负向量:几何意义是将得到和原来大小相等,方向相反的向量。

向量的大小:即向量的模,数学表示sqrtf(x*x + y*y + z*z),其几何描述就是勾股定理,直角三角形的临边的平方和等于斜边的平方(x*x + y*y = s*s)。

标量与向量相乘:得到的还是向量,就是将向量的每个分量都与标量相乘即可(除以标量就是乘以它的倒数)。其几何意义是:对向量的长度进行缩放,如果标量小于0则方向也被倒转。

标准化向量:将向量转换为单位向量,即大小为1的向量。这主要用于我们只关心对象方向而对大小并不关心的情况,如:法线。数学计算就是向量除以它的大小(模)即可。

向量与向量加减法:两个向量相加减,将对应分量相加减即可。其几何含义类似前面说的向量表示一段位移含义一样。如某个向量加上这个向量(1, -2, 3)表示将它向右平移1个单位,向下平移2个单位,向前平移3个单位得到的向量(减就是加上方向相反的向量)。

向量点乘:即向量与向量相乘,数学计算是对应分量乘积的和,其结果是一个标量。另一种几何计算是:点乘等于向量大小与向量夹角的cos值的积(这里通过这个夹角就可以判断两向量的方向关系了,如垂直,平行,方向相同,相反)。点乘我们常用还有一个:投影,即将向量分解为平行和垂直于其他向量的两个分量。

向量叉乘:仅用于3D向量,数学计算是交叉相乘,得到的结果是向量,这个向量垂直于原来的两个向量。所以叉乘最重要的应用是用于创建垂直于平面,三角形或多边形的向量。叉乘的长度等于向量的大小与向量夹角sin值的积。

向量类

//
//  Vector3.h
//  hello
//
//  Created by app05 on 15-6-15.
//  Copyright (c) 2015年 app05. All rights reserved.
/*注释:
--是否需要const修饰就是分析其数据是否需要修改,不需要修改就加const,安全性
--一般有两个地方需要考虑是否加const:1,成员函数参数处 2,成员函数本身,即类本身数据不允许修改(修饰的是this)
*/

#ifndef hello_Vector3_h
#define hello_Vector3_h
#include <math.h>

class Vector3
{
public:
float x, y, z;
//构造函数
Vector3() {}
Vector3(const Vector3 &a) : x(a.x), y(a.y), z(a.z) {}
Vector3(float nx, float ny, float nz) : x(nx), y(ny), z(nz) {}
//重载 '='
Vector3 &operator =(const Vector3 &a)
{
x = a.x; y = a.y; z = a.z;
return *this;
}
//重载 '=='
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;
}
//置为零向量
void zero() {x = y = z = 0.0f;}
//重载一元 '-' (即负号)
Vector3 operator -() const {return Vector3(-x, -y, -z);}
//重载二元 '+' '-'(即加,减)
Vector3 operator +(const Vector3 &a) const
{
return Vector3(x + a.z, y + a.y, z + a.z);
}
Vector3 operator -(const Vector3 &a) const
{
return Vector3(x - a.x, y - a.y, z - a.z);
}
//与标量的乘,除法
Vector3 operator *(float a) const
{
return Vector3(x * a, y * a, z * a);
}
Vector3 operator /(float a) const
{
float val = 1.0f / a;  /*这里没有对除数为零进行检查*/
return Vector3(x * val, y * val, z * val);
}
//重载自反运算符
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 val = 1.0f / a;
x *= val; y *= val; z *= val;
return *this;
}
//向量标准化
void normalize()
{
float magSq = x * x + y * y + z * z;
if (magSq > 0)
{
float val = 1.0f / sqrt(magSq);
x *= val;
y *= val;
z *= val;
}
}
//向量点乘
float operator *(const Vector3 &a) const
{
return x * a.x + y * a.y + z * a.z;
}
};

///////////////////////////////////////////////////////////////////////
//
//非成员函数:有些函数写类外面更易懂
//
///////////////////////////////////////////////////////////////////////
/*加inline 可以防止函数重定义,因为内联直接在调用处展开,不会编译成全局的函数调用*/

//求向量的模
inline float vectorMag(const Vector3 &a)
{
return sqrt(a.x * a.x + a.y * a.y + a.z * a.z);
}
//计算向量的叉乘
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
);
}
//实现标量左乘
inline Vector3 operator *(float k, const Vector3 &v)
{
return Vector3(k * v.x, k * v.y, k * v.z);
}
//计算两点间的距离
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);
}

//提供一个全局零向量
extern const Vector3 kZeroVector;

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