美文网首页
OpenGL(二) 使用OpenGL画一个正方形,并且控制其移动

OpenGL(二) 使用OpenGL画一个正方形,并且控制其移动

作者: 探索者的旅途 | 来源:发表于2020-07-06 15:40 被阅读0次

    上篇文章介绍了与OpenGL相关的一些常用的名词,这篇文章,我们就开始正式上手了,用OpenGL画一个正方形,并且可以通过键盘的方向键,控制这个正方形的移动。

    一、OpenGL环境搭建

    • 新建macOS项目


      image.png
    • 下载相关资源,然后解压缩

      image.png
    • 解压缩后,里面有两个文件,includelibGLTools.a,把这两个文件拖进刚刚新建好的项目中

      image.png
    • 添加系统库OpenGl.frameworkGLUT.framework

      image.png
    • Build Setting选项卡里面,添加include文件夹的路径

      image.png
    • 删除AppDelegate.hAppDelegate.mmain.mViewController.hViewController.m,并新建一个main.cpp文件(文件名一定要为main)

      image.png
      image.png
    • main.cpp文件里面添加如下代码

    #include <stdio.h>
    #include "GLTools.h"
    #include "GLShaderManager.h"
    #include <GLUT/GLUT.h>
    
    int main(int argc,char* argv[]) {
        return 0;
    }
    
    • command + B,编译一下,如果不报错,说明OpenGL的环境搭建已经成功,🎉🎉🎉

    二、画一个正方形

    • 示例代码:
    #include "GLTools.h"
    #include <GLUT/GLUT.h>
    #include "GLShaderManager.h"
    
    // 着色管理器
    GLShaderManager shaderManager;
    // 批次容器
    GLBatch squareBatch;
    
    // 正方形边长
    GLfloat squareWidth = 0.1f;
    
    // 初始正方形的4个点的坐标
    GLfloat vVerts[] = {
            -squareWidth, -squareWidth, 0.0f,
            squareWidth,  -squareWidth, 0.0f,
            squareWidth,  squareWidth,  0.0f,
            -squareWidth, squareWidth,  0.0f
    };
    
    void changeSize(int w, int h) {
        glViewport(0, 0, w, h);
    }
    
    void renderScene() {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
        GLfloat vRedColor[] = {1.0, 0.0, 0.0, 1.0};
        shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vRedColor);
        squareBatch.Draw();
        glutSwapBuffers();
    }
    
    void setupRC() {
        glClearColor(0.98, 0.4, 0.7, 1.0);
        shaderManager.InitializeStockShaders();
        squareBatch.Begin(GL_TRIANGLE_FAN, 4);
        squareBatch.CopyVertexData3f(vVerts);
        squareBatch.End();
    }
    
    int main(int argc,char* argv[]) {
        gltSetWorkingDirectory(argv[0]);
        glutInit(&argc, argv);
        glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
        
        glutInitWindowSize(500, 500);
        
        glutCreateWindow("正方形移动");
        glutReshapeFunc(changeSize);
        glutDisplayFunc(renderScene);
    
        GLenum status = glewInit();
        if (status != GLEW_OK) {
            return 1;
        }
        setupRC();
        glutMainLoop();
        return 0;
    }
    
    
    • 主要函数说明
    函数 触发时机 处理业务
    void changeSize(int w, int h) 1、新建窗口的时候
    2、改变窗口大小的时候
    设置OpenGL视口
    void renderScene() 系统自动调用 1、清除缓冲区
    2、使用存储着色器
    3、绘制图形
    void setupRC() 手动调用 1、设置窗口颜色
    2、初始化固定着色器
    3、设置图形定点数据
    4、利用GLBatch批次类,将数据传递到着色器
    int main(int argc,char* argv[]) 程序入口 1、绘制的准备工作,例如初始化缓冲区,设置窗口大小、注册自定义函数回调等
    2、启动运行循环,类型RunLoop
    • 具体流程


      图片来自于网络
    • 最终显示效果


      image.png

    三、通过键盘方向键控制正方形移动

    示例.gif
    • 有两种方式控制正方形的移动
      1、坐标更新的方式
      2、矩阵方式

    • 在OpenGL坐标系中,窗口大小为-11,我们选取左上角的点(由于z轴为0,因此在图上没有画出来)

      image.png

    坐标更新的方式

    • 我们需要在上面的示例代码里面加上一个自定义控制函数。注意:注意我们选取的是左上角那个点
    void specialKeys(int key, int x, int y) {
        // 步长
        GLfloat stepSize = 0.025;
        
        // 取出其中一个点(左上角的那个点)
        GLfloat blockX = vVerts[0];
        GLfloat blockY = vVerts[10];
        
        if (key == GLUT_KEY_UP) {
            // 上
            blockY += stepSize;
        }
        if (key == GLUT_KEY_LEFT) {
            // 左
            blockX -= stepSize;
        }
        if (key == GLUT_KEY_DOWN) {
            // 下
            blockY -= stepSize;
        }
        if (key == GLUT_KEY_RIGHT) {
            // 右
            blockX += stepSize;
        }
        
        // 碰撞检测
        // 上边
        if (blockY > 1.0) {
            blockY = 1.0;
        }
        // 左边
        if (blockX < -1.0) {
            blockX = -1.0;
        }
        // 下边
        if (blockY < -(1.0 - squareWidth * 2)) {
            blockY = -(1.0 - squareWidth * 2);
        }
        // 右边
        if (blockX > 1.0 - squareWidth * 2) {
            blockX = 1.0 - squareWidth * 2;
        }
        
        // 第三象限
        vVerts[0] = blockX;
        vVerts[1] = blockY - squareWidth * 2;
        vVerts[2] = 0;
        
        // 第四象限
        vVerts[3] = blockX + squareWidth * 2;
        vVerts[4] = blockY - squareWidth * 2;
        vVerts[5] = 0;
        
        // 第一象限
        vVerts[6] = blockX + squareWidth * 2;
        vVerts[7] = blockY;
        vVerts[8] = 0;
        
        // 第二象限
        vVerts[9] = blockX;
        vVerts[10] = blockY;
        vVerts[11] = 0;
        
        // 更新
        squareBatch.CopyVertexData3f(vVerts);
        
        glutPostRedisplay();
        
    }
    
    int main(int argc,char* argv[]) {
        .
        .
        .
        // 注册重塑函数
        glutReshapeFunc(changeSize);
        
        // 注册显示函数
        glutDisplayFunc(renderScene);
        
        // 注册特殊函数
        glutSpecialFunc(specialKeys);
        
        // 初始化一个GLEW库,确保OpenGL API对程序完全可用。
        GLenum status = glewInit();
        
        const GLubyte *description = glewGetErrorString(status);
        printf("初始化状态: %s\n", description);
        if (status != GLEW_OK) {
            return 1;
        }
        
        // 设置渲染环境
        setupRC();
        
        glutMainLoop();
        
        return 0;
    }
    
    
    
    • 主要流程:
      1、定义一个步长
      2、选取一个顶点(这儿选取的是左上角)
      3、根据键位方向,更新x,y,z
      4、边缘碰撞检测
      5、重新渲染

    矩阵的方式

    我们需要修改下renderScenespecialKeys的代码

    // 记录移动图形时,在x轴上平移的距离
    GLfloat xPos = 0.0f;
    // //记录移动图形时,在y轴上平移的距离
    GLfloat yPos = 0.0f;
    
    void specialKeys(int key, int x, int y) {
        // 步长
        GLfloat stepSize = 0.025;
        // 以正方形中心点为基准,中心点移动
        if (key == GLUT_KEY_UP) {
            // 上
            yPos += stepSize;
        }
        if (key == GLUT_KEY_LEFT) {
            // 左
            xPos -= stepSize;
        }
        if (key == GLUT_KEY_DOWN) {
            // 下
            yPos -= stepSize;
        }
        if (key == GLUT_KEY_RIGHT) {
            // 右
            xPos += stepSize;
        }
        // 碰撞检测
        if (xPos < -1.0 + squareWidth) {
            xPos = -1.0 + squareWidth;
        }
        if (xPos > 1.0 - squareWidth) {
            xPos = 1.0 - squareWidth;
        }
        if (yPos < -1.0 + squareWidth) {
            yPos = -1.0 + squareWidth;
        }
        if (yPos > 1.0 - squareWidth) {
            yPos = 1.0 - squareWidth;
        }
        glutPostRedisplay();
    }
    
    
    void renderScene() {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
        
        // 设置正方形的颜色
        GLfloat vRedColor[] = {1.0, 0.0, 0.0, 1.0};
    
        M3DMatrix44f mTransfromMatrix;    
        // 平移
        m3dTranslationMatrix44(mTransfromMatrix, xPos, yPos, 0.0);
        shaderManager.UseStockShader(GLT_SHADER_FLAT, mTransfromMatrix, vRedColor);
    
        squareBatch.Draw();
        glutSwapBuffers();
    }
    
    
    • 主要流程:
      1、定义步长及两个全局变量(相对于x轴和y轴的平移距离)
      2、根据移动方向,计算移动距离(以正方形中心点为基准进行移动)
      3、边缘碰撞处理
      4、手动触发重新渲染

    完整Demo链接: Demo

    相关文章

      网友评论

          本文标题:OpenGL(二) 使用OpenGL画一个正方形,并且控制其移动

          本文链接:https://www.haomeiwen.com/subject/vadmqktx.html