如何使用OpenGL和着色器创建两个形状

pu3pd22g  于 2022-10-18  发布在  其他
关注(0)|答案(1)|浏览(150)

我正在尝试创建一个圆柱体和平面放在圆柱体下面。在我为平面创建新的顶点缓冲区对象之前,圆柱体渲染得很好。但由于某种原因,当我运行程序时,圆柱体和平面都没有渲染。我已经为圆柱体创建了EBO,但我仍然得到一个黑色窗口。我不知道我是否需要为每个形状创建一个EBO,为每个形状创建一个Vao,或者我的绘图函数是否有问题。谁能指出可能的问题是什么?以下是我的代码:


# include <GL\glew.h>

# include <GLFW\glfw3.h>

# include <iostream>

// GLM library 

# include <glm/glm.hpp>

# include <glm/gtc/matrix_transform.hpp>

# include <glm/gtc/type_ptr.hpp>

using namespace std;

int width, height;
const double PI = 3.14159;
const float toRadians = PI / 180.0f;

// Draw Primitive(s)
void draw() {
    GLenum mode = GL_TRIANGLES;

    GLsizei indices = 60;

    glDrawElements(mode, indices, GL_UNSIGNED_BYTE, nullptr);
}

// Create and Compile Shaders
static GLuint CompileShader(const string& source, GLuint shaderType) {

    // Create Shader Object
    GLuint shaderID = glCreateShader(shaderType);
    const char* src = source.c_str();

    // Attach source code to Shader object
    glShaderSource(shaderID, 1, &src, nullptr);

    // Compile Shader
    glCompileShader(shaderID);

    // Return ID of Compiled shader
    return shaderID;
}

// Create Program Object
static GLuint CreateShaderProgram(const string& vertexShader, const string& fragmentShader) {

    // Compile vertex shader
    GLuint vertexShaderComp = CompileShader(vertexShader, GL_VERTEX_SHADER);

    // Compile fragment shader
    GLuint fragmentShaderComp = CompileShader(fragmentShader, GL_FRAGMENT_SHADER);

    // Create program object
    GLuint shaderProgram = glCreateProgram();

    // Attch vertex and fragment shaders to program object
    glAttachShader(shaderProgram, vertexShaderComp);
    glAttachShader(shaderProgram, fragmentShaderComp);

    // Link shaders to create executable
    glLinkProgram(shaderProgram);

    // Delete compiled vertex and fragment shaders
    glDeleteShader(vertexShaderComp);
    glDeleteShader(fragmentShaderComp);

    // Return Shader Program
    return shaderProgram;
}

int main(void) {

    width = 640; height = 480;

    GLFWwindow* window;

    // Initialize the library
    if (!glfwInit())
        return -1;

    // Create a windowed mode window and its OpenGL context
    window = glfwCreateWindow(width, height, "Main Window", NULL, NULL);
    if (!window) {
        glfwTerminate();
        return -1;
    }

    // Make the window's context current
    glfwMakeContextCurrent(window);

    // Initialize GLEW
    if (glewInit() != GLEW_OK)
        cout << "Error!" << endl;

    GLfloat cylinderVertices[] = {

        // Base of the cylinder     
        // Triangle One                                     // Color
        0.0,                  0.0,                  0.0, 1.0, 0.0, 0.0, // Vertex 0  red
        cos(0 * toRadians), sin(0 * toRadians), 0.0, 0.0, 1.0, 0.0, // Vertex 1  green
        cos(60 * toRadians), sin(60 * toRadians), 0.0, 0.0, 0.0, 1.0, // Vertex 2  blue
        // Part of Triangle Two
        cos(120 * toRadians), sin(120 * toRadians), 0.0, 1.0, 0.0, 1.0, // Vertex 3  purple
        // Part of Triangle Three
        cos(180 * toRadians), sin(180 * toRadians), 0.0, 0.0, 1.0, 0.0, // Vertex 4  greem
        // Part of Triangle Four
        cos(240 * toRadians), sin(240 * toRadians), 0.0, 0.0, 0.0, 1.0, // Vertex 5  blue
        // Part of Triangle Five
        cos(300 * toRadians), sin(300 * toRadians), 0.0, 1.0, 0.0, 1.0, // Vertex 6  purple
        // Part of Triangle Six
        cos(360 * toRadians), sin(360 * toRadians), 0.0, 0.0, 1.0, 0.0,  // Vertex 7  green

        // Sides of the cylinder
        // Part of Triangle Seven
        cos(0 * toRadians), sin(0 * toRadians), 2.0, 1.0, 0.0, 0.0, // Vertex 8 red
        // Part of Triangle Eight
        cos(60 * toRadians), sin(60 * toRadians), 2.0, 0.0, 1.0, 0.0, // Vertex 9 green
        // Part of Triangle Nine
        cos(120 * toRadians), sin(120 * toRadians), 2.0, 0.0, 0.0, 1.0, // Vertex 10 blue
        // Part of Triangle Ten
        cos(180 * toRadians), sin(180 * toRadians), 2.0, 1.0, 0.0, 1.0, // Vertex 11 purple
        // Part of Triangle Eleven
        cos(240 * toRadians), sin(240 * toRadians), 2.0, 1.0, 0.0, 0.0, // Vertex 12 red
        // Part of Triangle Twelve
        cos(300 * toRadians), sin(300 * toRadians), 2.0, 0.0, 1.0, 0.0, // Vertex 13 green

    };

    // Define element indices 
    GLubyte cylinderIndices[] = {
        // Bottom base
        0,1,2,
        0,2,3,
        0,3,4,
        0,4,5,
        0,5,6,
        0,6,7,
        // Sides
        1,2,8,
        2,9,8,
        2,3,9,
        3,10,9,
        3,4,10,
        4,11,10,
        5,11,4,
        5,12,11,
        5,6,12,
        6,13,12,
        6,1,13,
        1,8,13
    };

    GLfloat planeVertices[] = {
        // positon attributes (x,y,z)
         0.0f, 0.0f, 0.0f, // vert 14
         0.0f, 1.0f, 0.0f, // red

        0.0f, 0.866f, 0.0f, // vert 15
        0.0f, 1.0f, 0.0f, // green

        1.0f, 0.0f, 0.0f,  // vert 16
        0.0f, 1.0f, 0.0f, // blue

        1.0f, 0.866f, 0.0f, // vert 17
        1.0f, 0.0f, 1.0f  // purple
    };

    // Define element indices
    GLubyte planeIndices[] = {
        14,16,15,
        16,17,15

    };

    // Enable Depth Buffer
    glEnable(GL_DEPTH_TEST);

    // Wireframe mode
    // glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

    GLuint cylinderVBO, planeVBO, EBO, VAO;

    glGenBuffers(1, &cylinderVBO); // Create VBO and returns ID
    glGenBuffers(1, &planeVBO);
    glGenBuffers(1, &EBO); // Create EBO

    glGenVertexArrays(1, &VAO); // Create VAO
    glBindVertexArray(VAO);

    glBindBuffer(GL_ARRAY_BUFFER, cylinderVBO); // Select VBO and activate buffer
    glBindBuffer(GL_ARRAY_BUFFER, planeVBO);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); // Select EBO

    glBufferData(GL_ARRAY_BUFFER, sizeof(cylinderVertices), cylinderVertices, GL_STATIC_DRAW); // Load vertex attributes
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(cylinderIndices), cylinderIndices, GL_STATIC_DRAW); // Load indices attributes

    glBufferData(GL_ARRAY_BUFFER, sizeof(planeVertices), planeVertices, GL_STATIC_DRAW); // Load vertex attributes
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(planeIndices), planeIndices, GL_STATIC_DRAW); // Load indices attributes

    // Specify attributes location and layout to GPU
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0);
    glEnableVertexAttribArray(0);

    // Color attribute location and layout
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
    glEnableVertexAttribArray(1);

    glBindVertexArray(0);

    // Vertex shader source code
    string vertexShaderSource =
        "#version 330 core\n"
        "layout(location = 0) in vec4 vPosition;"
        "layout(location = 1) in vec4 aColor;"
        "out vec4 oColor;"
        "uniform mat4 model;"
        "uniform mat4 view;"
        "uniform mat4 projection;"
        "void main()\n"
        "{\n"
        "gl_Position = projection * view * model * vPosition;"
        "oColor = aColor;"
        "}\n";

    // Fragment shader source code
    string fragmentShaderSource =
        "#version 330 core\n"
        "in vec4 oColor;"
        "out vec4 fragColor;"
        "void main()\n"
        "{\n"
        "fragColor = oColor;"
        "}\n";

    // Creating Shader Program
    GLuint shaderProgram = CreateShaderProgram(vertexShaderSource, fragmentShaderSource);

    while (!glfwWindowShouldClose(window)) {

        // Resize window and graphics simultaneously
        glfwGetFramebufferSize(window, &width, &height);
        glViewport(0, 0, width, height);

        // Render here
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        // Use Shader Program exe and select VAO before drawing
        glUseProgram(shaderProgram); // Call Shader per-frame when updating attributes

        // Declare identity matrix 
        glm::mat4 modelMatrix(1.0f);
        glm::mat4 viewMatrix(1.0f);
        glm::mat4 projectionMatrix(1.0f);

        // Initialize transforms
        modelMatrix = glm::scale(modelMatrix, glm::vec3(0.5f, 0.5f, 0.5f));

        // I increased the third argument from -3.0f to -6.0f to make the object smaller
        // Moved the cup to the right by increasing the x coordinate
        viewMatrix = glm::translate(viewMatrix, glm::vec3(0.5f, 0.0f, -6.0f));
        // I changed up somme of the arguments, so the object would tilt right instead of toward me
        viewMatrix = glm::rotate(viewMatrix, 45.0f * toRadians, glm::vec3(-0.5f, 1.0f, 1.5f));

        projectionMatrix = glm::perspective(45.0f * toRadians, (GLfloat)width / (GLfloat)height, 0.1f, 100.0f);

        // Select uniform shader and variable
        GLuint modelLoc = glGetUniformLocation(shaderProgram, "model");
        GLuint viewLoc = glGetUniformLocation(shaderProgram, "view");
        GLuint projectionLoc = glGetUniformLocation(shaderProgram, "projection");

        // Pass transform to Shader

        glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(viewMatrix));
        glUniformMatrix4fv(projectionLoc, 1, GL_FALSE, glm::value_ptr(projectionMatrix));

        glBindVertexArray(VAO); // User-defined VAO must be called before draw

        for (GLuint i = 0; i < 4; i++) {

            glm::mat4 modelMatrix(1.0f);

            glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(modelMatrix));

            // Draw primitive(s)
            draw();

        }

        // Unbind Shader exe and VOA after drawing per frame
        glBindVertexArray(0); // In case different VAO will be used after
        glUseProgram(0); // In case different shader will be used after

        glBindVertexArray(VAO);

        // Swap front and back buffers
        glfwSwapBuffers(window);

        // Poll for and process events
        glfwPollEvents();
    }

    glfwTerminate();
    return 0;
}
egmofgnx

egmofgnx1#

好的,所以你的平面和圆柱体缓冲区布局(IND索引)有一点结构问题。

顶点缓冲区

首先,让我们从顶点数据和相关的缓冲区开始(我们将在后面考虑索引)。
对于如何将数据发送到GPU,您有两个选择。
1.为每个形状分离顶点缓冲区。即指定一个圆柱体VBO(具有所有圆柱体顶点)和一个平面VBO(具有所有平面顶点)。
1.将两组顶点合并为单个顶点缓冲区。
如果要单独指定缓冲区,则依次设置每个缓冲区。

// do the cylinder buffer first!
    glGenBuffers(1, &cylinderVBO); 
    glBindBuffer(GL_ARRAY_BUFFER, cylinderVBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(cylinderVertices), cylinderVertices, GL_STATIC_DRAW); // Load vertex attributes

    // NOW do the plane buffer!
    glGenBuffers(1, &planeVBO); 
    glBindBuffer(GL_ARRAY_BUFFER, planeVBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(planeVertices), planeVertices, GL_STATIC_DRAW); // Load vertex attributes

如果您希望将缓冲区合并为一个大的BLOB,则生成一个大的数组:

GLfloat allVertices[] = {

        // -------------  cylinderVertices[]

        // Base of the cylinder     
        // Triangle One                                     // Color
        0.0,                  0.0,                  0.0, 1.0, 0.0, 0.0, // Vertex 0  red
        cos(0 * toRadians), sin(0 * toRadians), 0.0, 0.0, 1.0, 0.0, // Vertex 1  green
        cos(60 * toRadians), sin(60 * toRadians), 0.0, 0.0, 0.0, 1.0, // Vertex 2  blue
        // Part of Triangle Two
        cos(120 * toRadians), sin(120 * toRadians), 0.0, 1.0, 0.0, 1.0, // Vertex 3  purple
        // Part of Triangle Three
        cos(180 * toRadians), sin(180 * toRadians), 0.0, 0.0, 1.0, 0.0, // Vertex 4  greem
        // Part of Triangle Four
        cos(240 * toRadians), sin(240 * toRadians), 0.0, 0.0, 0.0, 1.0, // Vertex 5  blue
        // Part of Triangle Five
        cos(300 * toRadians), sin(300 * toRadians), 0.0, 1.0, 0.0, 1.0, // Vertex 6  purple
        // Part of Triangle Six
        cos(360 * toRadians), sin(360 * toRadians), 0.0, 0.0, 1.0, 0.0,  // Vertex 7  green

        // Sides of the cylinder
        // Part of Triangle Seven
        cos(0 * toRadians), sin(0 * toRadians), 2.0, 1.0, 0.0, 0.0, // Vertex 8 red
        // Part of Triangle Eight
        cos(60 * toRadians), sin(60 * toRadians), 2.0, 0.0, 1.0, 0.0, // Vertex 9 green
        // Part of Triangle Nine
        cos(120 * toRadians), sin(120 * toRadians), 2.0, 0.0, 0.0, 1.0, // Vertex 10 blue
        // Part of Triangle Ten
        cos(180 * toRadians), sin(180 * toRadians), 2.0, 1.0, 0.0, 1.0, // Vertex 11 purple
        // Part of Triangle Eleven
        cos(240 * toRadians), sin(240 * toRadians), 2.0, 1.0, 0.0, 0.0, // Vertex 12 red
        // Part of Triangle Twelve
        cos(300 * toRadians), sin(300 * toRadians), 2.0, 0.0, 1.0, 0.0, // Vertex 13 green

        // -------------  planeVertices[]

        // positon attributes (x,y,z)
         0.0f, 0.0f, 0.0f, // vert 14
         0.0f, 1.0f, 0.0f, // red

        0.0f, 0.866f, 0.0f, // vert 15
        0.0f, 1.0f, 0.0f, // green

        1.0f, 0.0f, 0.0f,  // vert 16
        0.0f, 1.0f, 0.0f, // blue

        1.0f, 0.866f, 0.0f, // vert 17
        1.0f, 0.0f, 1.0f  // purple
    };

    // Now generate a vertex buffer with all vertex data in one buffer
    GLuint allVerticesVBO;
    glGenBuffers(1, & allVerticesVBO); 
    glBindBuffer(GL_ARRAY_BUFFER, allVerticesVBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(allVertices), allVertices, GL_STATIC_DRAW); // Load vertex attributes

索引缓冲区

现在,根据您以前设置顶点缓冲区的方式,您将必须执行一个操作(但不能同时执行两个操作!)以下几个方面。
如果已分离顶点缓冲区(一个用于圆柱体,一个用于平面),则还需要单独的索引缓冲区。

// we need two index buffers, one for the plane, one for the cylinder
    GLuint cylinderIBO, planeIBO;

    //--------------------
    // cylinder
    //--------------------

    // Define element indices 
    GLubyte cylinderIndices[] = {
        // Bottom base
        0,1,2,
        0,2,3,
        0,3,4,
        0,4,5,
        0,5,6,
        0,6,7,
        // Sides
        1,2,8,
        2,9,8,
        2,3,9,
        3,10,9,
        3,4,10,
        4,11,10,
        5,11,4,
        5,12,11,
        5,6,12,
        6,13,12,
        6,1,13,
        1,8,13
    };

    glGenBuffers(1, &cylinderIBO);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cylinderIBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(cylinderIndices), cylinderIndices, GL_STATIC_DRAW); // Load indices attributes

    //--------------------
    // plane
    //--------------------
    GLubyte planeIndices[] = {
        0,2,1, //< NOTE: These must start at ZERO in this case!
        2,3,1

    };

    glGenBuffers(1, &planeIBO);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, planeIBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(planeIndices), planeIndices, GL_STATIC_DRAW); // Load indices attributes

但是,如果您希望将这两个形状合并到单个缓冲区中,请改为执行以下操作:

// we need one index buffer!
    GLuint allIndicesIBO;

    // Define element indices 
    GLubyte allIndices[] = {

        //--------------------
        // cylinder
        //--------------------

        // Bottom base
        0,1,2,
        0,2,3,
        0,3,4,
        0,4,5,
        0,5,6,
        0,6,7,
        // Sides
        1,2,8,
        2,9,8,
        2,3,9,
        3,10,9,
        3,4,10,
        4,11,10,
        5,11,4,
        5,12,11,
        5,6,12,
        6,13,12,
        6,1,13,
        1,8,13, 

        //--------------------
        // plane
        //--------------------

        14,16,15, //< NOTE: these now start at 14!
        16,17,15
    };

    glGenBuffers(1, &allIndicesIBO);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, allIndicesIBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(allIndices), allIndices, GL_STATIC_DRAW); // Load indices attributes

顶点缓冲区对象

如果为每个形状设置了单独的缓冲区,则在设置VAOS的方式上有两个选择。
1.1创建两个Vao,每个形状一个。

GLuint cylinderVAO, planeVAO;

    // generate a bind new VAO for the cylinder
    glGenVertexArrays(1, & cylinderVAO); 
    glBindVertexArray(cylinderVAO);

    // specify which buffers the current VAO should use
    glBindBuffer(GL_ARRAY_BUFFER, cylinderVBO); 
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cylinderIBO); 

    // Specify attributes location and layout to GPU
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0);
    glEnableVertexAttribArray(0);

    // Color attribute location and layout
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
    glEnableVertexAttribArray(1);

    // generate a bind new VAO for the plane
    glGenVertexArrays(1, &planeVAO); 
    glBindVertexArray(planeVAO);

    // specify which buffers the current VAO should use
    glBindBuffer(GL_ARRAY_BUFFER, planeVBO); 
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, planeIBO); 

    // Specify attributes location and layout to GPU
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0);
    glEnableVertexAttribArray(0);

    // Color attribute location and layout
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
    glEnableVertexAttribArray(1);

要呈现这样的数据,您需要2个绘制调用,每个形状一个。

glBindVertexArray(cylinderVAO);
    glDrawElements(mode, 54, GL_UNSIGNED_BYTE, nullptr);

    glBindVertexArray(planeVAO);
    glDrawElements(mode, 6, GL_UNSIGNED_BYTE, nullptr);

1.2设置1个VAO,但在运行时重新绑定顶点和索引缓冲区。

GLuint sharedVAO;

    // generate a bind new VAO for the cylinder
    glGenVertexArrays(1, & sharedVAO); 
    glBindVertexArray(sharedVAO);

    // Specify attributes location and layout to GPU
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0);
    glEnableVertexAttribArray(0);

    // Color attribute location and layout
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
    glEnableVertexAttribArray(1);

要呈现这样的数据,您需要2个绘制调用,每个形状一个。

// specify the shared vertex format
    glBindVertexArray(sharedVAO);

    // specify data sources for cylinder, and render
    glBindBuffer(GL_ARRAY_BUFFER, cylinderVBO); 
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cylinderIBO); 
    glDrawElements(mode, 54, GL_UNSIGNED_BYTE, nullptr);

    // specify data sources for plane, and render
    glBindBuffer(GL_ARRAY_BUFFER, planeVBO); 
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, planeIBO); 
    glDrawElements(mode, 6, GL_UNSIGNED_BYTE, nullptr);

1.但是,如果已指定单个顶点缓冲区和单个索引缓冲区中的所有数据,则可以执行以下操作:

GLuint sharedVAO;

    // generate a bind new VAO for the cylinder
    glGenVertexArrays(1, & sharedVAO); 
    glBindVertexArray(sharedVAO);

    // specify data sources for the VAO
    glBindBuffer(GL_ARRAY_BUFFER, allVerticesVBO); 
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, allIndicesIBO); 

    // Specify attributes location and layout to GPU
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0);
    glEnableVertexAttribArray(0);

    // Color attribute location and layout
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
    glEnableVertexAttribArray(1);

要呈现这样的数据,您需要一次绘制调用。

// render both shapes in one draw call
    glBindVertexArray(sharedVAO);
    glDrawElements(mode, 60, GL_UNSIGNED_BYTE, nullptr);

就是这样。

相关问题