一、OpenGL 向量的 API 介绍
向量
在 3D 笛卡尔坐标系,基本上,一个顶点就是坐标系空间中的一个点。而在空间中给定一个位置,是由一个单独的 xyz 定义的,而这样的 xyz 就是向量。
长度为1的向量,称为单位向量。
向量长度,即向量的模,计算公式 百度百科
如果一个向量不是单位向量,而我们把它缩放到 1,这个过程叫做标准化,也叫做单位化向量。
math3d 库
三维向量: M3DVector3f (x, y, z)
四维向量: M3DVector4f (x, y, z, w) w 缩放因子
// 声明三维向量
M3DVector3f vVertor;
// 声明四维向量
M3DVector4f vVertex = {0, 0, 1, 1};
向量:点乘
点乘只能发生在两个向量之间。
两个单位向量进行点乘运算,将的到一个标量。它表示两个向量之间的夹角。
其范围为[-1, 1]. 这个值就是夹角的 cos 值(余弦值)。
如果要求两个普通向量的夹角,将两个向量单位化,然后进行点乘。 单位化向量:xyz -> (x/|xyz|, y/|xyz|, z/|xyz|)。
math3d 提供 API:
// 获得连个向量的点乘结果(即夹角)
float m3dDotProduct3(const M3DVector3f u, const M3DVector3f v)
// 获得两个向量的夹角的弧度
float m3dGetAngleBetweenVectors3(const M3DVector3f u, const M3DVector3f v)
向量:叉乘
两个向量之间叉乘,就可以得到另外一个向量,新的向量会与原阿里 2 个向量定义的平面垂直。 叉乘不必为单位向量。
math3d 提供 API:
// 向量叉乘:结果向量,向量1,向量2
m3dCrossProduct3(M3DVector3f result, const M3DVector3f u, const M3DVector3f v)
二、OpenGL 中的矩阵
// 三维矩阵
typedef float M3DMatrix33f[9];
// 四维矩阵
typedef float M3DMatrix44f[16];
OpenGL 倾向使用一维数组。
因为 OpenGL 使用的是 Column-Major(以列为主)矩阵排序的约定。
OpenGL 使用矩阵表示空间中的一个特定位置。
这四列中,每一列都是四个元素组成的向量。
如果将一个对象所有的顶点向量,乘以这个矩阵,就能让这个对象变换到空间中给定的位置和方向。
OpenGL 初始化矩阵
// 第一种
GLfloat m[] = {
1,0,0,0, // x Column
0,1,0,0, // y Column
0,0,1,0, // z Column
0,0,0,1 // translation Column
}
// 第二种
M3DMatrix44f m {
1,0,0,0, // x Column
0,1,0,0, // y Column
0,0,1,0, // z Column
0,0,0,1 // translation Column
}
// 第三种
void m3dLoadIdentity44(M3DMatrix44f m);
单元矩阵
1,0,0,0,
0,1,0,0,
0,0,1,0,
0,0,0,1
一个向量与单元矩阵相乘,不会发生任何改变。
矩阵左乘是行变换,矩阵右乘是列变换。
由于 OpenGL 是以列为主,因此当我们要对一个顶点矩阵进行变化的时候,采用矩阵右乘。
三、OpenGL 里的变换
| 变换 | 解释 |
|---|---|
| 视图变换 | 指定观察者位置 |
| 模型变换 | 在场景中移动物体 |
| 模型视图 | 描述视图/模型变换的二元性 |
| 投影 | 改变视景体大小和设置它的投影方式 |
| 视口 | 伪变化,对窗口上最终输入进行缩放 |
视图变换 将观察者放在你希望的任何位置,并允许在任何方向上观察场景,确定视图变换就像在场景中防止观察者,并让它指向某一个方向。
在应用任何其他模型变换之前,必须先应用视图变换。因为视图变换移动了当前的工作的坐标系;后续变换都会基于新调整的坐标系进行。
模型变换
对模型进行旋转、缩放、平移,实现需要的变化。
模型平移
void m3dTranslationMatrix44(M3DMatrix44f m, float x, float y, float z)
模型旋转
// angle 旋转弧度, 可以使用 m3dDegToRad 宏进行度数->弧度转换
void m3dRotationMatrix44(M3DMatrix44f m, float angle, float x, float y, float z)
模型缩放
void m3dScaleMatrix44(M3DMatrix44f m, float xScale, float yScale, float zScale)
模型变换-综合变换
void m3dMatrixMultiply44(M3DMatrix44f product, const M3DMatrix44f a, const M3DMatrix44f b);
四、矩阵堆栈的使用
矩阵堆栈基本API
// 初始化
GLMatrixStack::GLMatrixStack(int iStackDepth = 64);
// 在堆栈顶部载入一个单元矩阵
void GLMatrixStack::LoadIdentity(void);
// 在堆栈顶部载入任何矩阵
void GLMatrixStack::LoadMatrix(const M3DMatrix44f m);
// 矩阵乘以矩阵堆栈顶部矩阵,相乘结果存在堆栈的顶部
void GLMatrixStack::MultMatrix(const M3DMatrix44f);
// 获取矩阵堆栈顶部的值 GetMatrix 函数
const M3DMatrix44f & GLMatrixStack::GetMatrix(void);
// 也可以获取顶部矩阵副本
void glMatrixStack::GetMatrix(M3DMatrix44f mMatrix);
// 将当前矩阵压入堆栈
void GLMatrixStack::PushMatrix(void);
// 将 M3DMatrix44f 矩阵对象压入当前矩阵堆栈
void PushMatrix(const M3DMatrix44f mMatrix);
// 将 GLFrame 对象压入矩阵堆栈
void PushMatrix(GLFrame &frame);
// 出栈, 移除栈顶矩阵对象
void GLMatrixStack::PopMatrix(void);
仿射变换
// angle 是角度,非弧度
void MatrixStack::Rotate(GLfloat angle, GLfloat x, glfloat y, glfloat z);
void MatrixStack::Translate(GLfloat x, GLfloat y, GLfloat z);
void MatrixStack::Scale(GLfloat x, GLfloat y, GLfloat z);
GLFrame 使用
// 将堆栈的顶部压入任何矩阵
void GLMatrixStack::LoadMatrix(GLFrame &frame);
// 矩阵乘以矩阵堆栈顶部的矩阵。相乘结果存储在堆栈的顶部
void GLMatrixStack::MultMatrix(GLFrame &frame);
// 将当前的矩阵压栈
void GLMatrixStack::PushMatrix(GLFrame &frame);
// 检索条件合适的观察者矩阵
void GetCameraMatrix(M3DMatrix44f m, bool bRotationOnly = false);