如何在OpenGL中绘制两个或多个三角形?

Posted

技术标签:

【中文标题】如何在OpenGL中绘制两个或多个三角形?【英文标题】:How to draw two or more triangles in OpenGL? 【发布时间】:2020-12-21 06:45:45 【问题描述】:

谁能告诉我如何修改我的代码,以便我可以绘制多个三角形?

我希望完成如下图所示的事情:

// Include standard headers
#include <stdio.h>
#include <stdlib.h>

// Include GLEW
#include <GL/glew.h>

// Include GLFW
#include <GLFW/glfw3.h>
GLFWwindow* window;

// Include GLM
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
using namespace glm;

#include <common/shader.hpp>

int main(void)

    // Initialise GLFW
    if (!glfwInit())
    
        fprintf(stderr, "Failed to initialize GLFW\n");
        getchar();
        return -1;
    

    glfwWindowHint(GLFW_SAMPLES, 4);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // To make MacOS happy; should not be needed
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    // Open a window and create its OpenGL context
    window = glfwCreateWindow(1024, 768, "Tutorial 04 - Colored Cube", NULL, NULL);
    if (window == NULL) 
        fprintf(stderr, "Failed to open GLFW window. If you have an Intel GPU, they are not 3.3 compatible. Try the 2.1 version of the tutorials.\n");
        getchar();
        glfwTerminate();
        return -1;
    
    glfwMakeContextCurrent(window);

    // Initialize GLEW
    glewExperimental = true; // Needed for core profile
    if (glewInit() != GLEW_OK) 
        fprintf(stderr, "Failed to initialize GLEW\n");
        getchar();
        glfwTerminate();
        return -1;
    

    // Ensure we can capture the escape key being pressed below
    glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE);

    // Dark blue background
    glClearColor(0.0f, 0.0f, 0.4f, 0.0f);

    // Enable depth test
    glEnable(GL_DEPTH_TEST);
    // Accept fragment if it closer to the camera than the former one
    glDepthFunc(GL_LESS);

    GLuint VertexArrayID;
    glGenVertexArrays(1, &VertexArrayID);
    glBindVertexArray(VertexArrayID);

    // Create and compile our GLSL program from the shaders
    GLuint programID = LoadShaders("TransformVertexShader.vertexshader", "ColorFragmentShader.fragmentshader");

    // Get a handle for our "MVP" uniform
    GLuint MatrixID = glGetUniformLocation(programID, "MVP");


    int verticeCount = 3;
    static const GLfloat g_vertex_buffer_data[] = 
        -0.5f, 0.5f, 0.0f,
         0.5f, 0.5f, 0.0f,
         0.5f, -0.5f, 0.0f,
    ;
    static const GLfloat g_color_buffer_data[] = 
        1.0f,  0.0f,  0.0f,
        1.0f,  0.0f,  0.0f,
        1.0f,  0.0f,  0.0f,
    ;

    GLuint vertexbuffer;
    glGenBuffers(1, &vertexbuffer);
    glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertex_buffer_data), g_vertex_buffer_data, GL_STATIC_DRAW);

    GLuint colorbuffer;
    glGenBuffers(1, &colorbuffer);
    glBindBuffer(GL_ARRAY_BUFFER, colorbuffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(g_color_buffer_data), g_color_buffer_data, GL_STATIC_DRAW);

    do 
        // Clear the screen
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        // Use our shader
        glUseProgram(programID);

        glm::mat4 MVP = glm::mat4(1.0);

        // Send our transformation to the currently bound shader, 
        // in the "MVP" uniform
        glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &MVP[0][0]);

        // 1rst attribute buffer : vertices
        glEnableVertexAttribArray(0);
        glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
        glVertexAttribPointer(
            0,                  // attribute. No particular reason for 0, but must match the layout in the shader.
            3,                  // size
            GL_FLOAT,           // type
            GL_FALSE,           // normalized?
            0,                  // stride
            (void*)0            // array buffer offset
        );

        // 2nd attribute buffer : colors
        glEnableVertexAttribArray(1);
        glBindBuffer(GL_ARRAY_BUFFER, colorbuffer);
        glVertexAttribPointer(
            1,                                // attribute. No particular reason for 1, but must match the layout in the shader.
            3,                                // size
            GL_FLOAT,                         // type
            GL_FALSE,                         // normalized?
            0,                                // stride
            (void*)0                          // array buffer offset
        );

        // Draw the triangle !
        glDrawArrays(GL_TRIANGLES, 0, verticeCount * 3);

        glDisableVertexAttribArray(0);
        glDisableVertexAttribArray(1);

        // Swap buffers
        glfwSwapBuffers(window);
        glfwPollEvents();

     // Check if the ESC key was pressed or the window was closed
    while (glfwGetKey(window, GLFW_KEY_ESCAPE) != GLFW_PRESS &&
        glfwWindowShouldClose(window) == 0);

    // Cleanup VBO and shader
    glDeleteBuffers(1, &vertexbuffer);
    glDeleteBuffers(1, &colorbuffer);
    glDeleteProgram(programID);
    glDeleteVertexArrays(1, &VertexArrayID);

    // Close OpenGL window and terminate GLFW
    glfwTerminate();

    return 0;

【问题讨论】:

【参考方案1】:

它实际上就在你的鼻子前面。

三角形由 3 个顶点定义。

static const GLfloat g_vertex_buffer_data[] = 
    -0.5f, 0.5f, 0.0f,
    0.5f, 0.5f, 0.0f,
    0.5f, -0.5f, 0.0f,
;

在这里,您使用 3 个 3 维顶点初始化了顶点数据数组。那是 1 个三角形。

向这个数组添加更多的三角形,即 3 组 3 个顶点是您所要做的,同时扩展 g_color_buffer_data 数组并相应地更改 verticeCount

所以这个:

static const GLfloat g_vertex_buffer_data[] = 
    -0.50f, +0.50f, +0.00f,
    +0.50f, +0.50f, +0.00f,
    +0.50f, -0.50f, +0.00f,
     
    -0.50f, -0.25f, +0.00f,
    -0.50f, -0.50f, +0.00f,
    -0.25f, -0.50f, +0.00f,
;

static const GLfloat g_color_buffer_data[] = 
    1.0f, 0.0f, 0.0f,
    1.0f, 0.0f, 0.0f,
    1.0f, 0.0f, 0.0f,
    
    0.0f, 0.0f, 1.0f,
    0.0f, 0.0f, 1.0f,
    0.0f, 0.0f, 1.0f,
;

会给你 2 个三角形:1 个红色,1 个蓝色。

您也可以将verticeCount 定义为:

int verticeCount = sizeof(g_vertex_buffer_data) / (sizeof(g_vertex_buffer_data[0]) * 3);

(Thread on finding the size of a C-style array in C++)

这样您就不必手动更改它。

【讨论】:

【参考方案2】:

您始终可以创建一个新的顶点缓冲区,但通常最好实现顶点和片段着色器。如果选择使用着色器,可以绘制缓冲区,变换顶点着色器,然后再次绘制缓冲区。片段着色器还提供了一种更好的动态指定颜色的方法。您可以在https://learnopengl.com/Getting-started/Shaders

阅读更多内容并查看一些示例

【讨论】:

以上是关于如何在OpenGL中绘制两个或多个三角形?的主要内容,如果未能解决你的问题,请参考以下文章

无法在opengl中绘制多个对象

OpenGL:一个 VBO 的多个 VAO

绘制三角形带时,啥控制 OpenGL 的行为?

如何绘制多个形状

OpenGL:使用退化三角形绘制线

如何在 OpenGL 中绘制由 5 个三角形组成的 VAO?