目前在OpenGL中矩阵变换主要涉及两种方式:
- 观察者不动,物体移动。
- 物体不动,观察者动。
1、观察者不动,物体移动
如图1:
图1
-
其中矩阵堆栈的变换:
矩阵相乘流程
-
应用到观察者矩阵和物体矩阵的变换:
观察者矩阵、物体矩阵 -
代码函数中矩阵设置:
1、SetupRC函数:设置观察者位置,使用GLGeometryTransform管理矩阵堆栈(视图模型矩阵堆栈和投影矩阵堆栈)。
void SetupRC(){
// 1、设置背景颜色
glClearColor(0.7f, 0.7f, 0.7f, 1.0f );
// 2、初始化固定着色器管理器
shaderManager.InitializeStockShaders();
// 3、绘制立体图形的时候,需要开启深度测试
glEnable(GL_DEPTH_TEST);
//4、 通过GLGeometryTransform管理矩阵堆栈
// 使用transformPipeline 管道管理模型视图矩阵堆栈 和 投影矩阵堆栈
//(把两个矩阵作为两个参数放进去)
transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
// 5、为了让效果明显,将观察者坐标位置Z移动往屏幕里移动15个单位位置
// 参数:表示离屏幕之间的距离。 负数,是往屏幕后面移动;正数,往屏幕前面移动
cameraFrame.MoveForward(-15.0f);
//通过三角形创建金字塔
GLfloat vPyramid[12][3]={
-2.0f, 0.0f, -2.0f,
2.0f, 0.0f, -2.0f,
0.0f, 4.0f, 0.0f,
2.0f, 0.0f, -2.0f,
2.0f, 0.0f, 2.0f,
0.0f, 4.0f, 0.0f,
2.0f, 0.0f, 2.0f,
-2.0f, 0.0f, 2.0f,
0.0f, 4.0f, 0.0f,
-2.0f, 0.0f, 2.0f,
-2.0f, 0.0f, -2.0f,
0.0f, 4.0f, 0.0f
};
//每三个顶点定义一个三角形、将顶点数据拷入、完成
triangleBatch.Begin(GL_TRIANGLES, 12);
triangleBatch.CopyVertexData3f(vPyramid);
triangleBatch.End();
}
2、ChangeSize函数:设置投影方式,创建投影矩阵并载入投影矩阵堆栈中。最后的单元矩阵可省略。
//窗口改变
void ChangeSize(int w,int h){
glViewport(0, 0, w, h);
//创建投影矩阵,并将它载入投影矩阵堆栈中
viewFrustum.SetPerspective(35.0f, float(w) / float(h), 1.0f, 500.0f);
projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
//调用顶部载入单元矩阵(可省略)
modelViewMatrix.LoadIdentity();
}
3、RenderScene函数:完成观察者矩阵、物体矩阵的相关变换,压栈、相乘、出栈。
void RenderScene(void){
//清理缓冲区
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
//将观察者的坐标系压栈
modelViewMatrix.PushMatrix();
M3DMatrix44f mCamera;
cameraFrame.GetCameraMatrix(mCamera);
//矩阵乘矩阵堆栈的顶部矩阵,相乘的结果随后存储在堆栈的顶部
modelViewMatrix.MultMatrix(mCamera);
//图形环绕坐标系压栈
M3DMatrix44f mObjectFrame;
//只要使用GetMutrix函数就可以获取矩阵堆栈顶部的值,这个函数可以进行2次重载。
//用来使用GLShaderManager的使用。或者获取顶部矩阵的顶点副本数据。
objectFrame.GetMatrix(mObjectFrame);
//矩阵乘以矩阵堆栈的顶部矩阵。相乘的结果随后存储在堆栈的顶部
modelViewMatrix.MultMatrix(mObjectFrame);
/* GLShaderManager 中的Uniform 值——平面着色器
参数1:平面着色器
参数2:运行为几何图形变换指定一个 4 * 4变换矩阵
--transformPipeline.GetModelViewProjectionMatrix() 获取的
GetMatrix函数就可以获得矩阵堆栈顶部的值
参数3:颜色值(黑色)
*/
//传递到存储着色器
shaderManager.UseStockShader(GLT_SHADER_FLAT,transformPipeLine.GetModelViewProjectionMatrix(),vGreen);
//提交着色器
DrawWireFramedBatch(&triangleBatch);
//还原到单位矩阵
modelViewMatrix.PopMatrix();
//后台缓冲 -> 交换
glutSwapBuffers();
}
4、SpecialKeys函数:上、下、左、右移动。决定观察者或物体围绕x、y、z轴的移动,触发重绘
//特殊键位处理(上、下、左、右移动)
void SpecailKeys(int key,int x,int y){
//围绕xyz固定轴旋转
if (key == GLUT_KEY_UP) {
// objectFrame.RotateLocalX(5.0);
objectFrame.RotateWorld(m3dDegToRad(5.0f), 1.0f, 0.0f, 0.0f);
}
if (key==GLUT_KEY_DOWN){
objectFrame.RotateWorld(m3dDegToRad(-5.0f), 1.0f, 0.0f, 0.0f);
}
if (key==GLUT_KEY_LEFT){
objectFrame.RotateWorld(m3dDegToRad(-5.0f), 0.0f, 1.0f, 0.0f);
}
if (key==GLUT_KEY_RIGHT){
objectFrame.RotateWorld(m3dDegToRad(5.0f), 0.0f, 1.0f, 0.0f);
}
glutPostRedisplay();
}
2、观察者动,物体不动
观察者动,物体不动-
此时设置观察者时
2.1 setupRC函数
void SetupRC(){
//此时的 objectFrame是观察者
objectFrame.MoveForward(15.0f);
}
2.2 RenderScene函数
void RenderScene(void){{
//清理缓冲区
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
//只需将观察者压入栈中即可。此时的 objectFrame是观察者
modelViewMatrix.PushMatrix(objectFrame);
//传递到存储着色器
shaderManager.UseStockShader(GLT_SHADER_FLAT,transformPipeLine.GetModelViewProjectionMatrix(),vGreen);
//提交着色器
DrawWireFramedBatch(&triangleBatch);
//还原到单位矩阵
modelViewMatrix.PopMatrix();
//后台缓冲 -> 交换
glutSwapBuffers();
}
此时objectFrame记录者观察者初始设置时移动的位置,及观察者围绕相应x,y,z轴旋转的弧度。此时观察者记录了所有的变化,所以只需将观察者入栈即可。
Demo链接
demo中setupRC函数和RenderScene中替换注视代码(观察者动/不动)
网友评论