OpenGL 矩阵操作

2020-08-21  本文已影响0人  君幸食j

向量

1.png

(x,y,z) 既能表示坐标空间中的一个位置,还能表示一个向量。3个值 (x,y,z)组合起来表示两个重要的值,方向和数量。例如,x轴就是向量 (1,0,0),在x方向为+1,而在y方向和z方向则为0。

math3d库有两个数据类型,能够表示⼀个三维或者四维向量。M3DVector3f可以表示⼀个三维向量(x,y,z),⽽M3DVector4f则可以表示⼀个四维向量(x,y,z,w)。在典型情况下,w坐标设为1.0。x,y,z值通过除以w来进⾏缩放。⽽除以1.0则本质上不改变x,y,z值。

typedef float M3DVector3f[3];
typedef float M3DVector4f[4];

//声明一个三分量向量
M3DVector3f vVector;

//声明并初始化一个四分量向量
M3DVector4f vVertex = {0.0f,0.0f,1.0f,1.0f};

//声明一个三分量顶点数组,例如生成一个三角形
M3DVector3f vVerts[] = {-0.5f,0.0f,0.0f,                  
                         0.5f,0.0f,0.0f,                                                     
                         0.0f,0.5f,0.0f};

点乘 2.png

float m3dDotProduct3(const M3DVector3f u,const M3DVector3f v);
float m3dGetAngleBetweenVector3(const M3DVector3f u,const M3DVector3f v);

叉乘

3.png

叉乘运算结果返回⼀个新的向量,这个新的向量与原来的2个向量垂直

void m3dCrossProduct3(M3DVector3f result,const M3DVector3f u ,const M3DVector3f v);

矩阵

矩阵是一组排列在统一的行和列中的数字,用程序设计语言来说就一个二维数组,矩阵中的每一行(或每一列)的元素都必须和其他行(或列)的元素数相同。 4.png

矩阵之间可以进行乘法和加法,也能与向量或者标量相乘。标量就是一个普通的单独数据,用来表示大小和特定量。

typedef float M3DMatrix33f[9];
typedef float M3DMatrix44f[16];

理解变换

把3D数据“压扁”成2D数据的处理过程叫做投影,投影中出现的透视变换就是OpenGL中的一种变换。变换还允许我们旋转、移动、伸展、收缩或扭曲对象。一般渲染一个3D图形,会发生3种类型的几何变换。

变换 应用
视图 指定观察者或照相机的位置
模型 在场景中移动物体
模型视图 描述视图和模型变换的二元性
投影 改变视景体的大小和设置它的投影方式
视口 这是一种伪变换,只是对窗口上的最终输出进行缩放

视觉坐标

视觉坐标是一个虚拟的固定坐标系,通常作为参考坐标系使用。视觉坐标是相对于观察者的视角而言的,可以视为“绝对的”屏幕坐标。 5.png

视图变换

视图变换允许我们把观察点放在任何位置,并允许在任何方向上观察场景。确定视图变换就像在场景中放置照相机并让它指向某个方向。在应用其他模型变换前,必须先应用视图变换。

模型变换

模型变换用于操纵模型和其中的特定对象,平移、旋转或缩放对象。


6.png
7.png

模型视图的二元性

将对象向后移动和将参考坐标系向前移动在视觉上没有区别,视图变换和模型变换一般是结合在一起的。把这两种变换在变换管线中进行组合,成为一个单独的矩阵,即模型视图矩阵。 8.png

投影变换

投影变换将在模型视图变换之后应用到顶点上。这种投影实际上定义了视景体并创建了裁剪平面。分为正投影(或平行投影)和透视投影,正投影大多绘制2D图形,透视投影都应用在3D图形。 9.png

视口变换

把一个场景的二维投影映射到物理窗口称为视口变换,视口变换会将”规范化“设备坐标重新映射到窗口坐标上。

模型视图矩阵

模型视图矩阵是一个 4 x 4 矩阵,它表示一个变换后的坐标系,我们可以用来放置对象和确定对象的方向。可以将单个顶点数据乘以模型视图矩阵得到新的视觉坐标。 10.png

矩阵分为行矩阵和列矩阵。

平移

平移矩阵将顶点沿着3个坐标轴中的一个或多个进行平移。 13.png

在math3d库调用函数如下:

void m3dTranslationMatrix44(M3DMatrix44f m, float x, float y, float z);

旋转

旋转矩阵将一个对象沿着3个坐标轴中的一个或者任意向量进行旋转。 14.png

在math3d库调用函数如下:

m3dRotationMatrix44(M3DMatrix44f m, float angle, float x, float y, float z);

缩放

缩放矩阵沿着3个坐标轴方向按照指定因子放大或缩小所有顶点,以改变对象的大小。 15.png

在math3d库调用函数如下:

void m3dScaleMatrix44(M3DMatrix44f m, float xScale, float yScale, float zScale);

综合变换

将以上变换结合,可以在math3d库调用以下函数将两个矩阵相乘。需要注意的是,矩阵相乘是有顺序的。例如,用一个旋转矩阵乘以一个平移矩阵,与用一个平移矩阵乘以一个旋转矩阵是不同的。

void m3dMatrixMultiply44(M3DMatrix44f product, const M3DMatrix44f a, const M3DMatrix44f b);

变换管线

16.png

首先,顶点将被视为一个 1x4 矩阵,其中前3个值为x,y和z坐标。第4个数字是一个缩放因子,可以手动进行设置。这就是w坐标,默认为1.0,一般很少去直接修改这个值。然后,顶点将乘以模型视图矩阵,生成变换的视觉坐标。随后,视觉坐标再乘以投影矩阵,生成裁剪坐标。裁剪坐标位于+/-1.0单位坐标系内。将有效地将所有位于这个裁剪空间之外的数据消除掉。裁剪坐标随后再除以w坐标,生成规范化的设备坐标。其中w值可能会被投影矩阵或模型视图矩阵修改,这取决于所发生的变换。透视除法将作为图元装配过程的一部分进行。最后,坐标三元组将通过视口变换被映射到2D平面上。这项操作也是由一个矩阵来表示的,但不能直接指定或者修改这个矩阵。OpenGL 将在内部根据指定的 glViewport 值来设置这个矩阵。

使⽤矩阵堆栈

//类型
GLMatrixStack::GLMatrixStack(int iStackDepth = 64);

//在堆栈顶部载⼊⼀个单元矩阵
void GLMatrixStack::LoadIdentity(void);

//在堆栈顶部载⼊任何矩阵
//参数:4*4矩阵
void GLMatrixStack::LoadMatrix(const M3DMatrix44f m);

//矩阵乘以矩阵堆栈顶部矩阵,相乘结果存储到堆栈的顶部
void GLMatrixStack::MultMatrix(const M3DMatrix44f);

//获取矩阵堆栈顶部的值 GetMatrix 函数
//为了适应GLShaderMananger的使⽤,或者获取顶部矩阵的副本
const M3DMatrix44f & GLMatrixStack::GetMatrix(void);
void GLMatrixStack::GetMatrix(M3DMatrix44f mMatrix);

压栈与出栈

//将当前矩阵压⼊堆栈(栈顶矩阵copy ⼀份到栈顶)
void GLMatrixStack::PushMatrix(void);

//将M3DMatrix44f 矩阵对象压⼊当前矩阵堆栈
void PushMatrix(const M3DMatrix44f mMatrix);

//将GLFame 对象压⼊矩阵对象
void PushMatrix(GLFame &frame);

//出栈(出栈指的是移除顶部的矩阵对象)
void GLMatrixStack::PopMatrix(void);
矩阵压栈出栈流程.png

仿射变换

GLMatriStack类也内建了对创建旋转、平移和缩放矩阵的支持。

//Rotate 函数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);

使⽤照相机(摄像机) 和 ⻆⾊帧 进⾏移动

class GLFrame 
{ 
 protected: 
 M3DVector3f vOrigin; // Where am I? 
 M3DVector3f vForward; // Where am I going? 
 M3DVector3f vUp; // Which way is up?
} 
//将堆栈的顶部压⼊任何矩阵
void GLMatrixStack::LoadMatrix(GLFrame &frame); 

//矩阵乘以矩阵堆栈顶部的矩阵。相乘结果存储在堆栈的顶部
void GLMatrixStack::MultMatrix(GLFrame &frame); 

//将当前的矩阵压栈
void GLMatrixStack::PushMatrix(GLFrame &frame); 
上一篇 下一篇

猜你喜欢

热点阅读