阅读 90

OpenGL入门篇(绘制正方形并用键位控制移动的2种方式)

目的

  • 实现正方形绘制
  • 键位(↑ ↓ ← →)控制正方形移动

绘制正方形

注:绘制正方形常用的两种方式(1、两个三角形拼接。2、四个顶点数据直接连接)两种方式的区别是图元连接方式不同。今天是通过顶点连接方式绘制正方形

  • 首先设置将要绘制的正方形的中心为坐标原点。
    正方形的边长 = blockSize * 2;

GLfloat blockSize = 0.1f;

  • 设置顶点数据
//正方形四个点的坐标(坐标元素为x、y、z)
GLfloat vVerts[] = {
    -blockSize, -blockSize, 0.0f,
    blockSize, -blockSize, 0.0f,
    blockSize, blockSize, 0.0f,
    -blockSize, blockSize, 0.0f,
};
复制代码
  • 设置图元连接方式
//将 GL_TRIANGLES 修改为 GL_TRIANGLE_FAN ,4个顶点
triangleBatch.Begin(GL_TRIANGLE_FAN, 4);
复制代码

重要的绘制步骤已经结束了,接下来就是设置键位控制移动了。

键位移动

  • 首先在main函数注册特殊键位函数回调
//注册特殊函数,通过监听键位的回调,实现方法SpecialKeys实现移动
glutSpecialFunc(SpecialKeys);
复制代码
  • 移动正方形有2种方式(1、坐标系移动。2、矩阵移动)

注:1、注意边界问题,不能让正方形越界。2、移动之后记得重新提交渲染(容易忘记。。)

坐标系移动

  • 正方形总共有4个顶点,使用其中任意一个顶点的坐标。根据监听移动位置来移动。其他每个顶点也要做相应移动处理,保持正方形形态移动。(缺点:要处理每一个顶点移动的位置,比较繁琐)
  • 代码如下(没有什么好解释的,看代码就可以了,直接移动4个顶点坐标)
void SpecialKeys(int key, int x, int y){
    
    GLfloat stepSize = 0.025f;
    
    GLfloat blockX = vVerts[0];
    GLfloat blockY = vVerts[10];
    
    if (key == GLUT_KEY_UP) {
        blockY += stepSize;
    }
    if (key == GLUT_KEY_DOWN) {
        blockY -= stepSize;
    }
    if (key == GLUT_KEY_LEFT) {
        blockX -= stepSize;
    }
    if (key == GLUT_KEY_RIGHT) {
        blockX += stepSize;
    }

    //触碰到边界(4个边界)的处理
    //当正方形移动超过最左边的时候
    if (blockX < -1.0f) {
        blockX = -1.0f;
    }
    //当正方形移动到最右边时
    //1.0 - blockSize * 2 = 总边长 - 正方形的边长 = 最左边点的位置
    if (blockX > (1.0 - blockSize * 2)) {
        blockX = 1.0f - blockSize * 2;
    }
    //当正方形移动到最下面时
    //-1.0 - blockSize * 2 = Y(负轴边界) - 正方形边长 = 最下面点的位置
    if (blockY < -1.0f + blockSize * 2 ) {
        blockY = -1.0f + blockSize * 2;
    }
    //当正方形移动到最上面时
    if (blockY > 1.0f) {
        blockY = 1.0f;
    }
    
    // Recalculate vertex positions
    vVerts[0] = blockX;
    vVerts[1] = blockY - blockSize*2;
    printf("(%f,%f)\n",vVerts[0],vVerts[1]);
    
    vVerts[3] = blockX + blockSize*2;
    vVerts[4] = blockY - blockSize*2;
    printf("(%f,%f)\n",vVerts[3],vVerts[4]);
    
    vVerts[6] = blockX + blockSize*2;
    vVerts[7] = blockY;
    printf("(%f,%f)\n",vVerts[6],vVerts[7]);
    
    vVerts[9] = blockX;
    vVerts[10] = blockY;
    printf("(%f,%f)\n",vVerts[9],vVerts[10]);
    //更新顶点数据
    triangleBatch.CopyVertexData3f(vVerts);
    //重新提交渲染(不要忘记写这个。。)
    glutPostRedisplay();
}
复制代码

矩阵移动

  • 设置一个矩阵,通过正方形在X/Y轴的移动距离。使得所有顶点一起移动。(优点:通过移动图形,不用所有的顶点数据都去一个一个的设置)
  • 要修改2个函数(SpecialKeys、RenderScene)
  • 要设置全局变量(要在2个方法中用到)
//记录移动图形时,在x轴上平移的距离
GLfloat xPos = 0.0f;
//记录移动图形时,在y轴上平移的距离
GLfloat yPos = 0.0f;

GLfloat stepSize = 0.025f;
复制代码
  • 修改移动代码(SpecialKeys)
void SpecialKeys(int key, int x, int y){
    GLfloat stepSize = 0.025f;
    
    if (key == GLUT_KEY_UP) {
        yPos += stepSize;
    }
    if (key == GLUT_KEY_DOWN) {
        yPos -= stepSize;
    }
    if (key == GLUT_KEY_LEFT) {
        xPos -= stepSize;
    }
    if (key == GLUT_KEY_RIGHT) {
        xPos += stepSize;
    }
    //碰撞检测 xPos是平移距离,即移动量
    if (xPos < (-1.0f + blockSize)) {
        xPos = -1.0f + blockSize;
    }
    if (xPos > (1.0f - blockSize)) {
        xPos = 1.0f - blockSize;
    }
    if (yPos < (-1.0f + blockSize)) {
        yPos = -1.0f + blockSize;
    }
    if (yPos > (1.0f - blockSize)) {
        yPos = 1.0f - blockSize;
    }
    glutPostRedisplay();
    
}
复制代码
  • 修改RenderScene函数

使用平移矩阵

void RenderScene(void)

{
    //1.清除一个或者一组特定的缓存区
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
    //1.设置颜色RGBA
    GLfloat vRed[] = {1.0,0.0,0.0,1.0f};
    //定义矩阵
    M3DMatrix44f mTransformMatrix;
    
    //平移矩阵
    m3dTranslationMatrix44(mTransformMatrix, xPos, yPos, 0.0f);
    //参数1:存储着色器类型
    //参数2:使用什么矩阵变换
    //参数3:颜色
    shaderManager.UseStockShader(GLT_SHADER_FLAT, mTransformMatrix, vRed);
    //提交着色器
    triangleBatch.Draw();
    glutSwapBuffers();
}
复制代码

具体流程图等找到比较好用的画图软件在补上。。🤣