OpenGL中涉及的基础变换主要有以下5种:
变换 | 解释 |
---|---|
视图变换 | 指定观察者位置 |
模型变换 | 在场景中移动物体 |
模型视图变换 | 描述视图/模型变换的⼆元性(2种看到模型转换的⽅式 ) |
投影变换 | 改变视景体⼤⼩和设置它的投影⽅式 |
视⼝变换 | 伪变化,对窗⼝上最终输出进⾏缩放 |
1. 视觉坐标变换
下图显示了两个不同视点的视觉坐标系。
-
a图中,视觉坐标系是以场景的观察者的角度(也就是垂直于显示器的方向)。
-
b图中,视觉坐标系稍稍进行了旋转,这样就可以更好地观察z 轴的位置关系了。
-
从观察者的角度来看,x 轴和y 轴的正方向分别指向右方和上方。z 轴的正方向从原点指向使用者,而z 轴的负方向则从观察者指向屏幕内部。
image
2. 视图变换
- 视图变换是应用到场景中的第一种变换。
- 在默认情况下,透视投影中的观察点位于原点(0,0,0),并沿着z 轴的负方向进行观察(向显示器内部“看进去”),一般通过moveForward方法来调整观察者位置,moveForward默认的朝向是-z轴,所以向屏幕里面移动传正数值,向屏幕外即+z轴,需要传负数值
-
从大局上考虑,在应用任何其他模型变换之前,必须先应用视图变换。这样做是因为,对于视觉坐标系而言,视图变换移动了当前的工作坐标系。所有后续变换随后都会基于新调整的坐标系进行。
3. 模型变换
- 模型变换其实就是物体通过平移、旋转、缩放的操作,将物体移动到你想要的位置的一个过程.
- 平移
平移void m3dTranslationMatrix44(M3DMatrix44f m ,float x,float y,float z)
- 旋转
旋转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)
-
模型变换中,两个变换的顺序是不能交换的,交换后的矩阵相乘结果是不一致的,如下图,交换平移和旋转的顺序,得到的结果完全不一致
综合变换 -
造成这种情况的根本原因,主要还是因为矩阵相乘采用的是
矩阵的叉乘
,而矩阵叉乘是不满足交换律的。
4. 模型视图变换
- 视图和模型变换按照它们内部效果和对场景的最终外观来说是一样的。将这两者区分开纯粹是为了程序员的方便。将对象向后移动和将参考坐标系向前移动在视觉上没有区别。
- 视图变换和模型变换一样,都应用在整个场景中,在场景中的对象常常在进行视图变换后单独进行模型变换。术语“模型视图”是指这两种变换在变换管线中进行组合,成为一个单独的矩阵,即模型视图矩阵。
5. 投影变换
- 在正投影(或者说平行投影)中,所有多边形都是精确地按照指定的相对大小来在屏幕上绘制的。线和多边形使用平行线来直接映射到2D屏幕上,这就意味着,无论某个物体的位置有多远,它都会按照同样的大小来进行绘制,仅仅是平贴到屏幕上而已。典型情况下,这种投影用于渲染二维图像,例如蓝图或者是文本或屏幕菜单等二维图形。
- 透视投影所显示的场景与现实生活中更加接近,而不是一张蓝图。透视投影的特点就是
透视缩短(foreshortening)
,这种特性使得远处的物体看起来比近处同样大小的物体更小一些
。3D空间中应该是平行的线可能在观察者看来不总是平行的。例如,对于铁轨来说,两根铁轨是平行的,但是在使用透视投影的情况下,它们看起来将在远处的某一点汇聚在一起。
6. 视口变换
-将得到的一个场景的二维投影,它将被映射到屏幕上某处的窗口上。这种到物理窗口标的映射是我们最后要做的变换,称为视口变换
矩阵堆栈的使用
// GLMatrixStack类 这个类的构造函数允许指定堆栈的最大深度,默认的堆栈深度为64.
// 同时这个矩阵堆栈在初始化时,已经在堆栈中包含了单位矩阵。
GLMatrixStack::GLMatrixStack(int iStackDepth = 64);
// 在堆栈顶部载入一个单元矩阵
void GLMatrixStack::LoadIdentity(void);
// 在堆栈顶部载入任何矩阵
void GLMatrixStack::LoadMatrix(const M3DMatrix44f m);
// 矩阵乘以矩阵堆栈顶部矩阵,相乘结果存储到堆栈的顶部
void GLMatrixStack::MultMatrix(const M3DMatrix44f);
// 获取矩阵堆栈顶部的值 GetMatrix 函数
// 为了适应GLShaderManager的使用,或者是获取顶部矩阵的副本
const M3DMatrix44f & GLMatrixStack::GetMatrix(void);
void GLMatrixStack::GetMatrix(M3Datrix44f mMatrix);
压栈/出栈
入栈、相乘、出栈的流程图.png- 原始矩阵堆栈中,拷贝一份栈顶矩阵,压入栈顶
- 当有变换操作时,将变换操作的矩阵与矩阵堆栈栈顶相乘,将其结果覆盖栈顶矩阵
- 如果还有其他矩阵入栈,则继续相乘
- 当没有矩阵需要push,即图形绘制完成后,需要pop栈顶矩阵
在GLTools库中有一个矩阵堆栈来帮助完成矩阵变换,这个类称为GLMatrixStack
。
堆栈操作
初始化
这个类的构造函数允许指定堆栈的最大深度,默认的堆栈深度为64。在初始化堆栈时,已经包含了单位矩阵。
GLMatrixStack::GLMatrixStack(int iStackDepth = 64);
栈顶载入矩阵
单位矩阵
void GLMatrixStack::LoadIdentity(void);
任一矩阵
void GLMatrixStack::LoadMatrix(const M3DMatrix44f m);
矩阵栈顶元素与新元素相乘后的结果存储在堆栈顶部
void GLMatrixStack::MultMatrix(const M3DMatrix44f);
获取栈顶元素
获取值
const M3DMatrix44f & GLMatrixStaxk::GetMatrix(void);
获取副本
void GLMatrixStaxk::GetMatrix(M3DMatrix44f mMatrix);
压栈
栈顶矩阵Copy到栈顶
void GLMatrixStack::PushMatrix(void);
将M3DMatrix44f 矩阵对象压入当前矩阵堆栈
void PushMatrix(const M3DMatrix44f mMatrix);
将GLFrame对象压入堆栈
void PushMatrix(GLFrame &frame);
出栈
void GLMatrixStack::PopMatrix(void);
仿射变换
我们都知道,想要从不同的角度观察一个3D物体,我们有两种方式,一种是移动物体,还有一种就是我们自己移动。在OpenGL中移动观察者就是 仿射变换。
相关代码:
//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);
使用照相机和角色帧进行移动:GLFrame
相关api
//将堆栈的顶部压入任何矩阵
void GLMatrixStack::LoadMatrix(GLFrame &frame);
//矩阵乘以矩阵堆栈顶部的矩阵。相乘结果存储在堆栈的顶部
void GLMatrixStack::MultMatrix(GLFrame &frame);
//将当前的矩阵压栈
void GLMatrixStack::PushMatrix(GLFrame &frame)
获取照相机矩阵
//GLFrame函数,这个函数用来检索条件适合的观察者矩阵
void GetCameraMatrix(M3DMatrix44f m,bool bRotationOnly = flase);
网友评论