本章的主要目的是通过修改键盘是的上下左右键,来旋转点、线、三角形,观察形状的变化。 ——视角不动,物体动
opengl平面图形的透视投影,要了解以下知识
-
坐标转换
坐标转换计算
OpenGL在进行透视投影要经过 model matrix->view matrix -> projection matrix ->viewport transform 这几个矩阵变换,才能看到我们想要的形状。
- 需要用到的类
- GLMatrixStack:矩阵堆栈,用于存放矩阵数据并进行矩阵的变换。
- GLFrame:表示世界坐标系中的任意物体的位置和方向。存储了值:当前位置点,向前方向向量,向上方向向量。可以表示camera和model
- GLFrustum:透视矩阵
- GLGeometryTransform: 几何变换管道,提供了矩阵相乘的方法
平面图形透视投影
- 准备工作,运行环境xcode,导入OpenGL、GLTool、libGLTool及相关头文件
- 导入头文件
#include "GLShaderManager.h"
#include "GLTools.h"
#include <glut/glut.h>
#include "GLFrame.h"
#include "GLMatrixStack.h" //变换管线的矩阵堆栈
#include "GLFrustum.h"
#include "GLGeometryTransform.h" //集合变换的管道
#include <math.h>
#ifdef __APPLE__
#include <glut/glut.h>
#else
#define FREEGLUT_STATIC
#include <GL/glut.h>
#endif
- main函数模板
//程序入口
int main(int argc, char* argv[])
{
//设置当前工作目录,针对MAC OS X
gltSetWorkingDirectory(argv[0]);
//初始化GLUT库
glutInit(&argc, argv);
/*初始化双缓冲窗口,其中标志GLUT_DOUBLE、GLUT_RGBA、GLUT_DEPTH、GLUT_STENCIL分别指
双缓冲窗口、RGBA颜色模式、深度测试、模板缓冲区*/
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
//初始化窗口大小
glutInitWindowSize(800,600);
//创建窗口
glutCreateWindow("Triangle");
//注册回调函数
glutReshapeFunc(ChangeSize);
//点击空格时,调用的函数
glutKeyboardFunc(KeyPressFunc);
//特殊键位函数(上下左右)
glutSpecialFunc(SpecialKeys);
//渲染函数
glutDisplayFunc(RenderScene);
//确保驱动程序的初始化中没有出现任何问题。
GLenum err = glewInit();
if(GLEW_OK != err) {
fprintf(stderr, "glew error:%s\n", glewGetErrorString(err));
return 1;
}
//初始化设置
SetupRC();
//进入调用循环
glutMainLoop();
return 0;
}
相关函数:
- KeyPressFunc: 按空格键切换点、线、三角形的回调函数
- SpecialKeys:按上下左右键,改变物体的方向的回调函数
- ChangeSize: 窗口发生变化的回调函数
- RenderScene:渲染函数,窗口大小、物体形状发生改变就会调用该还是重新渲染,就是上面三个回调函数触发, 该函数也会触发。
- SetupRC:初始化配置
- 需要的对象
GLShaderManager shaderManager;
GLMatrixStack modelViewMatrix; //模型矩阵堆栈
GLMatrixStack projectionMatrix; //投影矩阵堆栈
GLFrame cameraFrame; //视角 ; 对应上图的view matrix
GLFrame objectFrame; //物体 ;对应上图的 model matrix
GLFrustum viewFrustum; //投影矩阵 对应上图的projection matrix
//几何变换的管线
GLGeometryTransform transformPipeline; //提供了矩阵相乘
GLBatch pointBatch; //点
GLBatch lineBatch; //线
GLBatch lineLoopBatch;三角形
- setupRC
void SetupRC()
{
//设置背影颜色
glClearColor(0.7f, 0.7f, 0.7f, 1.0f);
//初始化着色管理器
shaderManager.InitializeStockShaders();
//设置三角形,其中数组vVert包含所有3个顶点的x,y,笛卡尔坐标对。
GLfloat vVerts[] = {
-3.f,0.0f,0.0f,
3.f,0.0f,0.0f,
0.0f,3.f,0.0f,
};
//投影变换矩阵+ 移动变换矩阵 -> 几何变换管道GLGeometryTransform,作用进行矩阵相乘
transformPipeline.SetMatrixStacks(modelViewMatrix,projectionMatrix);
//视角离物体原来越远,
cameraFrame.MoveForward(-15.0f);
//1.点
pointBatch.Begin(GL_POINTS, 3); //开始批次处理
pointBatch.CopyVertexData3f(vVerts);//拷贝顶点数据
pointBatch.End(); //结束批次处理
//2.线
lineBatch.Begin(GL_LINES, 3);
lineBatch.CopyVertexData3f(vVerts);
lineBatch.End();
//3.三角形
lineLoopBatch.Begin(GL_LINE_LOOP, 3);
lineLoopBatch.CopyVertexData3f(vVerts);
lineLoopBatch.End();
}
- ChangeSize中使用窗口维度设置视口和投影矩阵
void ChangeSize(int w, int h)
{
glViewport(0, 0, w, h);
//创建投影矩阵,设置维度
viewFrustum.SetPerspective(35.0f, float(w) / float(h), 1.0f, 500.0f);
//1.获取投影矩阵,并设置到投影矩阵堆栈
projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
//调用顶部载入单元矩阵
modelViewMatrix.LoadIdentity();
}
投影矩阵堆栈主要在这里获取投影矩阵,并在transformPipeline中与视图矩阵相乘。
- SpecialKeys旋转物体
void SpecialKeys(int key,int x,int y){
if (key == GLUT_KEY_UP) {
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();
}
- RenderSence渲染
void RenderScene(void)
{
//清除一个或一组特定的缓冲区
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
modelViewMatrix.PushMatrix();//栈中压入单元矩阵
//观察者矩阵mCamera
M3DMatrix44f mCamera;
cameraFrame.GetCameraMatrix(mCamera); //mCamera的到一个矩阵
modelViewMatrix.MultMatrix(mCamera); //栈顶中的模型矩阵与mCamera相乘得到一个新的矩阵
//物体矩阵坐标系
M3DMatrix44f mObject;
objectFrame.GetMatrix(mObject);
//矩阵相乘->模型视图矩阵
modelViewMatrix.MultMatrix(mObject);
//设置一组浮点数来表示红色
GLfloat vRed[] = {1.0f, 0.0f, 0.0f, 1.0f};
shaderManager.UseStockShader(GLT_SHADER_FLAT,transformPipeline.GetModelViewProjectionMatrix(),vRed);
//提交着色器
switch (nStep) {
case 0:
glPointSize(10.f);
pointBatch.Draw();
glPointSize(1.f);
break;
case 1:
glPointSize(10.f);
lineBatch.Draw();
glPointSize(1.f);
break;
case 2:
glPointSize(10.f);
lineLoopBatch.Draw();
glPointSize(1.f);
break;
default:
break;
}
//移除堆栈
modelViewMatrix.PopMatrix();
//将在后台缓冲区进行渲染,然后在结束时交换到前台
glutSwapBuffers();
}
效果图
截屏2020-07-09 23.11.15.png 截屏2020-07-09 23.11.04.png
关于矩阵堆栈可以参考下图
矩阵堆栈
总结:
- 透视投影要经过 model matrix->view matrix -> projection matrix ->viewport transform
- modelViewMatrix:用于处理视角矩阵cameraFrame、模型矩阵objectFrame的矩阵变换
- projectionMatrix:处理透视矩阵viewFrustum
- transformPipeline对projectionMatrix堆栈和modelViewMatrix堆栈处理,最后transformPipeline获取ModelViewProjectionMatrix交给我们的管理者。
参考:
视觉Demo——CC老师
OpenGL基础变化综合练习实践总结——凡几多
网友评论