OpenGL自制3D游戏引擎入门IV

绘制三角形(cont.)

  1. OpenGL在绘制过程中按照逆时针方向来渲染

  2. 尝试渲染两个三角形(组成矩形)

     float vertices[] = {
         // 第一个三角形
         0.5f, 0.5f, 0.0f,   // 右上角
         0.5f, -0.5f, 0.0f,  // 右下角
         -0.5f, 0.5f, 0.0f,  // 左上角
         // 第二个三角形
         0.5f, -0.5f, 0.0f,  // 右下角
         -0.5f, -0.5f, 0.0f, // 左下角
         -0.5f, 0.5f, 0.0f   // 左上角
     };
    

可以看到,有两个顶点叠加了,一个矩形应该只有4个顶点而不是6个,这样会产生50%的额外开销,我们可以使用 索引缓冲对象(Element Buffer Object,EBO) 来解决这个问题

  1. 定义(不重复的)顶点,和绘制出矩形所需的索引

     float vertices[] = {
         0.5f, 0.5f, 0.0f,   // 右上角
         0.5f, -0.5f, 0.0f,  // 右下角
         -0.5f, -0.5f, 0.0f, // 左下角
         -0.5f, 0.5f, 0.0f   // 左上角
     };
    
     unsigned int indices[] = { // 注意索引从0开始! 
         0, 1, 3, // 第一个三角形
         1, 2, 3  // 第二个三角形
     };
    
  2. 创建缓冲索引对象,与VBO类似,我们先绑定EBO然后用glBufferData把索引复制到缓冲里。同样,和VBO类似,我们会把这些函数调用放在绑定和解绑函数调用之间,只不过这次我们把缓冲的类型定义为GL_ELEMENT_ARRAY_BUFFER

     unsigned int EBO;
     glGenBuffers(1, &EBO);
    
     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
    
  3. 要注意的是,我们传递了GL_ELEMENT_ARRAY_BUFFER当作缓冲目标。最后一件要做的事是用glDrawElements来替换glDrawArrays函数,来指明我们从索引缓冲渲染。使用glDrawElements时,我们会使用当前绑定的索引缓冲对象中的索引进行绘制

     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
     glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
    

第一个参数指定绘制模式,第二个参数指定绘制顶点个数,第三个参数为索引类型,第四个参数为偏移量

  1. glDrawElements函数从当前绑定到GL_ELEMENT_ARRAY_BUFFER目标的EBO中获取索引。这意味着我们必须在每次要用索引渲染一个物体时绑定相应的EBO,这还是有点麻烦。不过顶点数组对象同样可以保存索引缓冲对象的绑定状态。VAO绑定时正在绑定的索引缓冲对象会被保存为VAO的元素缓冲对象。绑定VAO的同时也会自动绑定EBO(当目标是GL_ELEMENT_ARRAY_BUFFER的时候,VAO会储存glBindBuffer的函数调用。这也意味着它也会储存解绑调用,所以确保你没有在解绑VAO之前解绑索引数组缓冲,否则它就没有这个EBO配置了)

傅老师の手绘233
7. 最后总结一下整个的初始化和绘制代码流程:

    // ..:: 初始化代码 :: ..
    // 1. 绑定顶点数组对象
    glBindVertexArray(VAO);
    // 2. 把我们的顶点数组复制到一个顶点缓冲中,供OpenGL使用
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    // 3. 复制我们的索引数组到一个索引缓冲中,供OpenGL使用
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
    // 4. 设定顶点属性指针
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);

    [...]

    // ..:: 绘制代码(渲染循环中) :: ..
    glUseProgram(shaderProgram);
    glBindVertexArray(VAO);
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0)
    glBindVertexArray(0);
  1. 线框模式(Wireframe Mode):要想用线框模式绘制你的三角形,你可以通过glPolygonMode(GL_FRONT_AND_BACK, GL_LINE)函数配置OpenGL如何绘制图元。第一个参数表示我们打算将其应用到所有的三角形的正面和背面,第二个参数告诉我们用线来绘制。之后的绘制调用会一直以线框模式绘制三角形,直到我们用glPolygonMode(GL_FRONT_AND_BACK, GL_FILL)将其设置回默认模式
(下接OpenGL入门V)


OpenGL自制3D游戏引擎入门IV
https://baifabaiquan.cn/2021/03/12/OpenGL入门IV/
作者
白发败犬
发布于
2021年3月12日
许可协议