OpenGL基础变换

2020-07-09  本文已影响0人  东旭39

本章的主要目的是通过修改键盘是的上下左右键,来旋转点、线、三角形,观察形状的变化。 ——视角不动,物体动
opengl平面图形的透视投影,要了解以下知识

  1. 坐标转换


    坐标转换计算

    OpenGL在进行透视投影要经过 model matrix->view matrix -> projection matrix ->viewport transform 这几个矩阵变换,才能看到我们想要的形状。

  2. 需要用到的类

平面图形透视投影

  1. 准备工作,运行环境xcode,导入OpenGL、GLTool、libGLTool及相关头文件
  2. 导入头文件
#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
  1. 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;
}

相关函数:

  1. 需要的对象
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;三角形
  1. 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();
}
  1. 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中与视图矩阵相乘。

  1. 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();
}
  1. 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

关于矩阵堆栈可以参考下图


矩阵堆栈

总结:

  1. 透视投影要经过 model matrix->view matrix -> projection matrix ->viewport transform
  2. modelViewMatrix:用于处理视角矩阵cameraFrame、模型矩阵objectFrame的矩阵变换
  3. projectionMatrix:处理透视矩阵viewFrustum
  4. transformPipeline对projectionMatrix堆栈和modelViewMatrix堆栈处理,最后transformPipeline获取ModelViewProjectionMatrix交给我们的管理者。

参考:

视觉Demo——CC老师
OpenGL基础变化综合练习实践总结——凡几多

上一篇下一篇

猜你喜欢

热点阅读