OpenGL入门案例:渲染正方形并使其移动

效果图如下所示:

图1

图2

问题:

图1:没有改变窗口大小下,正方形不能移动到最左边
图2:改变窗口大小下,正方形可以移动到最左边。

  • 在没有改变窗口大小的情况下,不能移动到最左边。而改动窗口了就可以移动到了最左边。
    问题解决:因为GLUT/GLTOOL和xcode版本不兼容
控制流程图
正方形移动控制流程图.png
环境搭建:

环境搭建参考链接

绘制正方形
  • 首先定义工具类:
///定义一个着色管理器
GLShaderManager shaderManager;

///简单的批次容器,是GTtools的一个简单的容器类
GLBatch triangleBatch;
  • 定义顶点数组及边长:
//blockSize 边长
GLfloat blockSize = 0.1f;

///正方形的四个点坐标
GLfloat vVerts[] = {
    -blockSize,blockSize,0.0f,
    blockSize,blockSize,0.0f,
    blockSize,-blockSize,0.0f,
    -blockSize,-blockSize,0.0f
};
  • 注册自定义changeSize、RenderScence、SpecialKeys函数:
glutDisplayFunc(RenderScence);
glutReshapeFunc(ChageSize);
glutSpecialFunc(SpecialKeys);
  • 设置初始化函数并开启runloop:
SetupRC();
glutMainLoop();///类似IOS runLoop运行循环
  • 自定义RenderScence函数
    glutDisplayFunc(函数名)注册为显示渲染函数,当屏幕发生变化或者开发者主动渲染会调用此函数,用来实现数据的渲染(绘制)过程
    1. 清除特定缓冲区,缓冲区是一块存在图像信息的储存空间,红色、绿色、蓝色和alpha分量通常一起分量通常一起作为颜色缓存区或像素缓存区引用。
      OpenGL 中不止一种缓冲区(颜色缓存区、深度缓存区和模板缓存区)
      清除缓存区对数值进行预置
      参数:指定将要清除的缓存的
      GL_COLOR_BUFFER_BIT:指示当前激活的用来进行颜色写入缓冲区
      GL_DEPTH_BUFFER_BIT:指示深度缓存区
      GL_STENCIL_BUFFER_BIT:指示模板缓冲区
    2. 设置一组浮点数来表示颜色(即渲染的颜色),
    3. 顶点数据传递到存储着色器,GLT_SHADER_IDENTITY单元着色器 只是使用指定颜色以默认笛卡尔坐标第在屏幕上渲染几何图形,
    4. 提交着色器进行绘制,
    5. 将后台缓冲区进行渲染,然后结束后交换给前台。
void RenderScence(void) {
   glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
   GLfloat vRed[] = {1.0,0.0,0.0,1.0f};
   shaderManager.UseStockShader(GLT_SHADER_IDENTITY,vRed);
   triangleBatch.Draw();
   glutSwapBuffers();
}
  • 自定义changeSize函数
    glutReshaperFunc(函数名),注册为重塑函数,当屏幕大小发生变化/或者第一次创建窗口时。
    回调用changeSize函数调整窗口大小、视口大小
    处理业务:
    1、设置OpenGL视口 2、设置OpenGL投影方式等
void ChageSize(int w,int h){
    glViewport(0, 0, w, h);
}
  • 自定义SetupRC函数
    自定义函数,设置需要渲染的图形的相关顶点数据,颜色数据等数据准备工作
    处理业务:
    1、设置窗口背景颜色
    2、初始化存储着色器shaderManger
    3、设置图像顶点数据,GL_TRIANGLE_FAN:以⼀一个圆点为中⼼心呈扇形排列列,共⽤用相邻顶点的一组三⻆角形
    4、利用三角形批次类将数据传递到着色器中
void SetupRC(){
    glClearColor(0.38f, 0.62f, 0.5f, 1.0f);
    shaderManager.InitializeStockShaders();
    triangleBatch.Begin(GL_TRIANGLE_FAN, 4);
    triangleBatch.CopyVertexData3f(vVerts);
    triangleBatch.End();
}
特殊键位控制效果

首先需要先知道顶点数据是在坐标系上的哪个位置,如以上我们的点在坐标系中的位置如下:

正方形顶点位置.png

其次我们定义好blockSize即顶点到中心的位置,则正方形边长为blockSize*2

  • 重点——注册SpecialKeys函数
    1. 定义步长
    2. 选择好一个顶点作为移动的起始点
    3. 上下左右键位移动处理
    4. 发现移动时可以移出窗口外,故进行窗口边缘检测
    5. 更新顶点数据、重新提交渲染
image.png

具体实现如下:

void SpecialKeys(int key ,int x ,int y){
    GLfloat stepSize = 0.025f;
    GLfloat blockX = vVerts[3];
    GLfloat blockY = vVerts[4];
    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;
    }
    ///碰撞检测
    if (blockX > 1.0) {
        blockX = 1.0;
    }
    if (blockX < -1.0 + 2 * blockSize) {
        blockX = -1.0 +2*blockSize;
    }
    if (blockY > 1.0) {
        blockY = 1.0;
    }
    if (blockY < -1.0 + 2 * blockSize) {
        blockY = -1.0 +2*blockSize;
    }
    vVerts[0] = blockX - blockSize * 2;
    vVerts[1] = blockY;
    vVerts[3] = blockX;
    vVerts[4] = blockY; 
    vVerts[6] = blockX;
    vVerts[7] = blockY-blockSize *2;
    vVerts[9] = blockX - blockSize * 2;
    vVerts[10] = blockY - blockSize * 2;
    triangleBatch.CopyVertexData3f(vVerts);
    glutPostRedisplay();
}
优化处理

如果顶点有很多的话,则我们需要计算每个顶点的坐标,需要写很多的计算代码,所以我们可以利用平移矩阵进行平移处理,则不需要计算每个顶点的坐标位置。平移矩阵可以理解为相对于正方形的中心点进行移动。

//记录移动图形时,在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;
    }
    ///碰撞检测
    if (xPos > 1.0 - blockSize) {
        xPos = 1.0 - blockSize;
    }
    if (xPos < -1.0 + blockSize) {
        xPos = -1.0 + blockSize;
    }
    if (yPos > 1.0 - blockSize) {
        yPos = 1.0 - blockSize;
    }
    if (yPos < -1.0 + blockSize) {
        yPos = -1.0 + blockSize;
    }
    
    glutPostRedisplay();
}

我们需要修改RenderScence函数:

  1. 清除特定缓冲区,定义渲染画笔颜色
  2. 定义平移矩阵
  3. 顶点数据传递到存储着色器,GLT_SHADER_FLAT着色器 以一个圆点为中⼼心呈扇形排列列,共⽤用相邻顶点的一组三⻆角形
  4. 提交着色器进行绘制,
  5. 将后台缓冲区进行渲染,然后结束后交换给前台。
void RenderScence(void) {
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
    GLfloat vRed[] = {1.0,0.0,0.0,1.0f};
    ///定义矩阵
    M3DMatrix44f mTransfromMatix;
    ///平移矩阵
    m3dTranslationMatrix44(mTransfromMatix, xPos, yPos, 0.0);
    shaderManager.UseStockShader(GLT_SHADER_FLAT,mTransfromMatix,vRed);
    ///4、提交着色器进行绘制
    triangleBatch.Draw();
    ///5、将后台缓冲区进行渲染,然后结束后交换给前台
    glutSwapBuffers();
}

至此优化完成。

完整代码见Github -OpenGLDemo02

你可能感兴趣的:(OpenGL入门案例:渲染正方形并使其移动)