OpenGL渲染正方形&平移

588 阅读3分钟

渲染

准备代码

// 定义一个着色器管理器
GLShaderManager shaderManager;

//简单的批次容器,是GLTools的一个简单的容器类
GLBatch triangleBatch;

//设定的边长
GLfloat blockSize = 0.1f;

//正方形的四个点的坐标
GLfloat vVerts[] = {
    -blockSize,-blockSize,0.1f,
    blockSize,-blockSize,0.1f,
    blockSize,blockSize,0.1f,
    -blockSize,blockSize,0.1f,
};

//窗口大小改变时,接收新的宽度和高度
void changeSize(int w,int h){
    glViewport(0, 0, w, h);
}

核心代码


// 显示函数
void RenderScene(void){
    
    // 1. 首先需要清除一个或一组特定的缓存区
    // 清屏
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
    
    // 2. 设置一组浮点数 设定颜色
    GLfloat vRed[] = {0.0f,1.0f,0.0f,1.0f};
    
    // 3. 传递给存储着色器,即GLT_SHADER_IDENTITY着色器,这个着色器只是使用指定颜色 以默认笛卡尔坐标在屏幕上渲染几何图形
    shaderManager.UseStockShader(GLT_SHADER_IDENTITY,vRed);
    
    // 4. 提交着色器 绘制
    triangleBatch.Draw();
    
    // 在开始设置OpenGL窗口的时候,指定一个双缓冲区的渲染环境,这就意味着将在后台缓冲区进行渲染,渲染结束后交还给前台,这种方式可以防止观察者看到 可能伴随着动画帧与动画帧之间 闪烁的渲染过程,缓冲区交换平台将以平台特定的方式进行
    // 5.将后台缓冲区进行渲染,结束后交还给前台
    glutSwapBuffers();
    
}

void setupRC(){
    
    // 设置清屏颜色(背景颜色)
    glClearColor(0.98f, 0.3f, 0.8f, 1.0f);
    
    // 初始化一个渲染管理器
    shaderManager.InitializeStockShaders();
    
    // 指定顶点 GL_TRIANGLE_FAN 绘制连接方式。   
    triangleBatch.Begin(GL_TRIANGLE_FAN, 4);
    triangleBatch.CopyVertexData3f(vVerts);
    triangleBatch.End();
}

绘制连接方式

main函数

int main(int argc, char *argv[]){
    // 设置当前工作目录,针对MACOSX
    gltSetWorkingDirectory(argv[0]);
    // 初始化GLUT库
    glutInit(&argc, argv);
    // 初始化双缓冲窗口,其中标志GLUT_DOUBLE(双缓冲窗口),GLUT_RGBA(RGBA颜色模式),GLUT_DEPTH(深度测试),GLUT_STENCIL(模版缓冲区)
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
    // GLUT窗口大小 标题窗口
    glutInitWindowSize(500, 500);
    glutCreateWindow("Triangle");

    /*
     GLUT内部会运行一个本地消息循环,拦截适当的消息,然后调用我们不同时间注册的回调函数,我们一共注册了2个回调函数
     1.为窗口改变大小而设置的一个回调函数
     2.包含OpenGL 渲染的回调函数
     */
    // 注册重塑函数
    glutReshapeFunc(changeSize);
    // 注册显示函数
    glutDisplayFunc(RenderScene);
    
    GLenum status = glewInit();
    // 驱动程序的初始化是否出现问题
    if (GLEW_OK != status) {
        printf("GLEW error : %s\n",glewGetErrorString(status));
        return 1;
    }
    
    // 设置渲染环境
    setupRC();
    
    glutMainLoop();

    return 0;
}


此时一个正方向就渲染到了页面上.

平移

1.坐标更新方式

void specialKeys(int key, int x, int y){
    
    // 每次移动的长度
    GLfloat stepSize = 0.025f;
    // blockX/blockY: 相对移动顶点D
    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;
    }
    
    // 触碰到边界的处理
    // 最左边
    if (blockX <= -1.0f) {
        blockX = -1.0f;
    }
    // 最右边
    if (blockX >= 1.0f-blockSize*2) {
        blockX = 1.0f-blockSize*2;
    }
    // 最上边
    if (blockY >= 1.0f) {
        blockY = 1.0f;
    }
    // 最下边
    if (blockY <= -1.0f+blockSize*2) {
        blockY = -1.0f+blockSize*2;
    }
    
    // 四个顶点坐标进行更新
    vVerts[0] = blockX;
    vVerts[1] = blockY - blockSize*2;
    
    vVerts[3] = blockX + blockSize*2;
    vVerts[4] = blockY - blockSize*2;
    
    vVerts[6] = blockX + blockSize*2;
    vVerts[7] = blockY;
    
    vVerts[9] = blockX;
    vVerts[10] = blockY;
    //将顶点数组通过GLBatch帮助类将顶点传输到存储着⾊器中,并⼿动触发渲染函数.
    triangleBatch.CopyVertexData3f(vVerts);
    glutPostRedisplay();
    
}

之后,要将specialKeys方法,在mian函数中进行注册

// 注册特殊函数
glutSpecialFunc(specialKeys);

2.矩阵方式

相比坐标更新的方式,矩阵方式适合顶点很多的图形,因为它不需要对每一个顶点的坐标都进行更新,更像根据图形的中心点xPos&yPos的移动进行平移.

添加中心点

// 记录x y 平移的距离
GLfloat xPos = 0.0f;
GLfloat yPos = 0.0f;

修改RenderScene和specialKeys函数

void RenderScene(void){

    // 矩阵计算
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
    GLfloat vRed[] = {0.0f,1.0f,0.0f,1.0f};
    
    // 矩阵
    M3DMatrix44f mTransfromMatrix;
    
    m3dTranslationMatrix44(mTransfromMatrix, xPos , yPos, 0.0f);
    
    // 平面着色器
    shaderManager.UseStockShader(GLT_SHADER_FLAT,mTransfromMatrix,vRed);
    
    triangleBatch.Draw();
    glutSwapBuffers();
    
}

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

推荐: www.jianshu.com/p/acb2f3a1c…