在 OpenGL 中单独渲染 2 个对象时出现问题

Trouble Rendering 2 Object separately in OpenGL

我拿了两个项目的代码。一个是创建立方体的代码,另一个是创建金字塔的代码。我现在正在尝试在 OpenGL 中渲染这两个对象,我已经完成了问题是对象相互连接。我已经添加了一些代码来分别渲染它们,但是我现在被困在我的立方体只显示 3 个用于创建它的三角形和整个金字塔显示的地方。然而,这些物体仍然相互依附。有任何帮助或指导吗?

#include <iostream>         // cout, cerr
#include <cstdlib>          // EXIT_FAILURE
#include <GL/glew.h>        // GLEW library
#include <GLFW/glfw3.h>     // GLFW library

// GLM Math Header inclusions
#include <glm/glm.hpp>
#include <glm/gtx/transform.hpp>
#include <glm/gtc/type_ptr.hpp>

using namespace std; // Standard namespace
using glm::vec3;
using glm::mat4;
/*Shader program Macro*/
#ifndef GLSL
#define GLSL(Version, Source) "#version " #Version " core \n" #Source
#endif

// Unnamed namespace
namespace
{
    const char* const WINDOW_TITLE = "3D Scene Troubleshooting"; // Macro for window title

    // Variables for window width and height
    const int WINDOW_WIDTH = 800;
    const int WINDOW_HEIGHT = 600;

    // Stores the GL data relative to a given mesh
    struct GLMesh
    {
        GLuint vao;  // Handle for the vertex array object 1
        GLuint vao2; // Handle for the vertex array object 2
        GLuint vbos[2];     // Handles for the vertex buffer objects 1
        GLuint vbos2[2];    // Handles for the vertex buffer objects 2
        GLuint cubeIndices;    // Number of cube indices of the mesh
        GLuint pyramidIndices; // Number of pyramid indices of the mesh
    };

    // Main GLFW window
    GLFWwindow* gWindow = nullptr;
    // Triangle mesh data
    GLMesh gMesh;
    // Shader program
    GLuint gProgramId;
}

/* User-defined Function prototypes to:
 * initialize the program, set the window size,
 * redraw graphics on the window when resized,
 * and render graphics on the screen
 */
bool UInitialize(int, char* [], GLFWwindow** window);
void UResizeWindow(GLFWwindow* window, int width, int height);
void UProcessInput(GLFWwindow* window);
void UCreateMesh(GLMesh& mesh);
void UDestroyMesh(GLMesh& mesh);
void URender();
bool UCreateShaderProgram(const char* vtxShaderSource, const char* fragShaderSource, GLuint& programId);
void UDestroyShaderProgram(GLuint programId);


/* Vertex Shader Source Code*/
const GLchar* vertexShaderSource = GLSL(440,
    layout(location = 0) in vec3 position; // Vertex data from Vertex Attrib Pointer 0
layout(location = 1) in vec4 color;  // Color data from Vertex Attrib Pointer 1

out vec4 vertexColor; // variable to transfer color data to the fragment shader

//Global variables for the  transform matrices
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

void main()
{
    gl_Position = projection * view * model * vec4(position, 1.0f); // transforms vertices to clip coordinates
    vertexColor = color; // references incoming color data
}
);


/* Fragment Shader Source Code*/
const GLchar* fragmentShaderSource = GLSL(440,
    in vec4 vertexColor; // Variable to hold incoming color data from vertex shader

out vec4 fragmentColor;

void main()
{
    fragmentColor = vec4(vertexColor);
}
);


int main(int argc, char* argv[])
{
    if (!UInitialize(argc, argv, &gWindow))
        return EXIT_FAILURE;

    // Create the mesh
    UCreateMesh(gMesh); // Calls the function to create the Vertex Buffer Object

    // Create the shader program
    if (!UCreateShaderProgram(vertexShaderSource, fragmentShaderSource, gProgramId))
        return EXIT_FAILURE;

    // Sets the background color of the window to black (it will be implicitely used by glClear)
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

    // render loop
    // -----------
    while (!glfwWindowShouldClose(gWindow))
    {
        // input
        // -----
        UProcessInput(gWindow);

        // Render this frame
        URender();

        glfwPollEvents();
    }

    // Release mesh data
    UDestroyMesh(gMesh);

    // Release shader program
    UDestroyShaderProgram(gProgramId);

    exit(EXIT_SUCCESS); // Terminates the program successfully
}


// Initialize GLFW, GLEW, and create a window
bool UInitialize(int argc, char* argv[], GLFWwindow** window)
{
    // GLFW: initialize and configure
    // ------------------------------
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 4);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

#ifdef __APPLE__
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif

    // GLFW: window creation
    // ---------------------
    * window = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "3D Scene TroubleShooting", NULL, NULL);
    if (*window == NULL)
    {
        std::cout << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        return false;
    }
    glfwMakeContextCurrent(*window);
    glfwSetFramebufferSizeCallback(*window, UResizeWindow);

    // GLEW: initialize
    // ----------------
    // Note: if using GLEW version 1.13 or earlier
    glewExperimental = GL_TRUE;
    GLenum GlewInitResult = glewInit();

    if (GLEW_OK != GlewInitResult)
    {
        std::cerr << glewGetErrorString(GlewInitResult) << std::endl;
        return false;
    }

    // Displays GPU OpenGL version
    cout << "INFO: OpenGL Version: " << glGetString(GL_VERSION) << endl;

    return true;
}


// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly
void UProcessInput(GLFWwindow* window)
{
    if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
        glfwSetWindowShouldClose(window, true);
}


// glfw: whenever the window size changed (by OS or user resize) this callback function 
executes
void UResizeWindow(GLFWwindow* window, int width, int height)
{
    glViewport(0, 0, width, height);
}


// Functioned called to render a frame
void URender()
{
    // Enable z-depth
    glEnable(GL_DEPTH_TEST);

    // Clear the frame and z buffers
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // 1. Scales the object by 2
    glm::mat4 scale = glm::scale(glm::vec3(2.0f, 2.0f, 2.0f));
    // 2. Rotates shape by 15 degrees in the x axis
    glm::mat4 rotation = glm::rotate(45.0f, glm::vec3(1.0, 1.0f, 1.0f));
    // 3. Place object at the origin
    glm::mat4 translation = glm::translate(glm::vec3(0.5f, -0.3f, -0.1f));
    // Model matrix: transformations are applied right-to-left order
    glm::mat4 model = translation * rotation * scale;

    // Transforms the camera: move the camera back (z axis)
    glm::mat4 view = glm::translate(glm::vec3(-2.6f, 2.9f, -5.0f));

    // Creates a orthographic projection
    glm::mat4 projection = glm::ortho(-5.0f, 5.0f, -5.0f, 5.0f, 0.1f, 100.0f);

    // Set the shader to be used
    glUseProgram(gProgramId);

    // Retrieves and passes transform matrices to the Shader program
    GLint modelLoc = glGetUniformLocation(gProgramId, "model");
    GLint viewLoc = glGetUniformLocation(gProgramId, "view");
    GLint projLoc = glGetUniformLocation(gProgramId, "projection");

    glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
    glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
    glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(projection));

    // Activate the VBOs contained within the mesh's VAO
    glBindVertexArray(gMesh.vao);
    glBindVertexArray(gMesh.vao2);

    // Draws the CUBE
    glDrawElements(GL_TRIANGLES, gMesh.cubeIndices, GL_UNSIGNED_SHORT, NULL); // Draws the triangle
    glDrawArrays(GL_TRIANGLES, 0, 24);

    // Draws the PYRAMID
    glDrawElements(GL_TRIANGLES, gMesh.pyramidIndices, GL_UNSIGNED_SHORT, NULL); // Draws the triangle
    glDrawArrays(GL_TRIANGLES, 0, 54);

    // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
    glfwSwapBuffers(gWindow);    // Flips the the back buffer with the front buffer every frame.
}

void UCylinder(GLUquadric* qobj, GLdouble baseRadius, GLdouble topRadius, GLdouble height, GLint slices, GLint stacks)
{
    GLUquadricObj* quadratic;
    quadratic = gluNewQuadric();
    gluCylinder(quadratic, 0.3f, 0.3f, 3.0f, 32, 32);

    glDrawElements(GL_TRIANGLES, gMesh.cubeIndices, GL_UNSIGNED_SHORT, NULL);
}

// Implements the UCreateMesh function
void UCreateMesh(GLMesh& mesh)
{
    // Position and Color data
    GLfloat verts[] = {
        // Vertex Positions    // Colors (r,g,b,a)
         0.5f,  0.5f, 0.0f,   1.0f, 0.0f, 0.0f, 1.0f, // Top Right Vertex 0 (effects top right and bottom right top sides of cube)
         0.5f, -0.5f, 0.0f,   1.0f, 0.0f, 0.0f, 1.0f, // Bottom Right corner Vertex 1 
        -0.5f, -0.5f, 0.0f,   1.0f, 0.0f, 0.0f, 1.0f, // Bottom center of cube Vertex 2 (effects bottom left and bottomr right sides of cube)
        -0.5f,  0.5f, 0.0f,   1.0f, 0.0f, 0.0f, 1.0f, // Center of cube Vertex 3 (effects top, bottom left and bottom right sides of cube)

         0.5f, -0.5f, -1.0f,  0.0f, 0.0f, 0.0f, 1.0f, //  Bottomside left of cube Vertex 4 (doesn't effect cube color at all with current orientation)
         0.5f,  0.5f, -1.0f,  1.0f, 0.0f, 0.0f, 1.0f, //  Top center of cube Vertex 5
        -0.5f,  0.5f, -1.0f,  1.0f, 0.0f, 0.0f, 1.0f, //  Top left corner cube Vertex 6 (effects both top and bottom left sides of cube)
        -0.5f, -0.5f, -1.0f,  1.0f, 0.0f, 0.0f, 1.0f,  //  Bottom left of cube Vertex 7

        // Vertex Positions    // Colors (r,g,b,a)
     -0.5f, -0.5f, -0.5f,   1.0f, 0.0f, 0.0f, 1.0f, // Vertex 8
       0.5f, -0.5f, -0.5f,   0.0f, 1.0f, 0.0f, 1.0f, // Vertex 9
       0.0f,  0.5f,  0.0f,   0.0f, 0.0f, 1.0f, 1.0f, // Vertex 10

     -0.5f, -0.5f, 0.5f,    1.0f, 1.0f, 0.0f, 1.0f, // Vertex 11
      0.5f, -0.5f, 0.5f,    0.0f, 1.0f, 1.0f, 1.0f, // Vertex 12
      0.0f,  0.5f, 0.0f,    1.0f, 0.0f, 1.0f, 1.0f, // Vertex 13

      -0.5f, -0.5f, -0.5f,  0.0f, 0.0f, 1.0f, 1.0f, // Vertex 14
      -0.5f, -0.5f,  0.5f,  0.0f, 1.0f, 0.0f, 1.0f, // Vertex 15
       0.0f,  0.5f,  0.0f,  1.0f, 0.0f, 0.0f, 1.0f, // Vertex 16

      0.5f, -0.5f, -0.5f,   1.0f, 0.0f, 1.0f, 1.0f, // Vertex 17
      0.5f, -0.5f,  0.5f,   0.0f, 1.0f, 1.0f, 1.0f, // Vertex 18
      0.0f,  0.5f,  0.0f,   1.0f, 1.0f, 0.0f, 1.0f, // Vertex 19

      0.5f, -0.5f, -0.5f,   1.0f, 0.0f, 0.0f, 1.0f, // Vertex 20
      0.5f, -0.5f,  0.5f,   0.0f, 1.0f, 0.0f, 1.0f, // Vertex 21
      0.0f,  0.5f,  0.0f,   0.0f, 0.0f, 1.0f, 1.0f, // Vertex 22

      -0.5f, -0.5f,  0.5f,  1.0f, 1.0f, 0.0f, 1.0f, // Vertex 23
       0.5f, -0.5f, -0.5f,  0.0f, 1.0f, 1.0f, 1.0f, // Vertex 24
       0.0f,  0.5f,  0.0f,  1.0f, 0.0f, 1.0f, 1.0f, // Vertex 25
    };

    // Index data to share position data
    GLushort cubeIndices[] = {
        0, 1, 3,  // Triangle 1
        1, 2, 3,   // Triangle 2
        0, 1, 4,  // Triangle 3
        0, 4, 5,  // Triangle 4
        0, 5, 6, // Triangle 5
        0, 3, 6,  // Triangle 6
        4, 5, 6, // Triangle 7
        4, 6, 7, // Triangle 8
        2, 3, 6, // Triangle 9
        2, 6, 7, // Triangle 10
        1, 4, 7, // Triangle 11
        1, 2, 7, // Triangle 12
    };
    GLushort pyramidIndices[] = {
        8, 9, 10, // Triangle 1
        11, 12, 13, // Triangle 2
        14, 15, 16, // Triangle 3
        17, 18, 19, // Triangle 4
        20, 21, 22, // Triangle 5
        23, 24, 25 // Triangle 6
    };

    const GLuint floatsPerVertex = 3;
    const GLuint floatsPerColor = 4;

    // For CUBE
    glGenVertexArrays(1, &mesh.vao); // we can also generate multiple VAOs or buffers at the same time
    glBindVertexArray(mesh.vao);

    // For PYRAMID
    glGenVertexArrays(1, &mesh.vao2);
    glBindVertexArray(mesh.vao2);

    // Create 2 buffers: first one for the vertex data; second one for the indices for the CUBE
    glGenBuffers(2, mesh.vbos);
    glBindBuffer(GL_ARRAY_BUFFER, mesh.vbos[0]); // Activates the buffer for CUBE
    glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW); // Sends vertex or coordinate data to the GPU for CUBE

    // Create 2 buffers: first one for the vertex data; second one for the indices for the PYRAMID
    glGenBuffers(2, mesh.vbos2);
    glBindBuffer(GL_ARRAY_BUFFER, mesh.vbos2[0]); // Activates the buffer for PYRAMID
    glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW); // Sends vertex or coordinate data to the GPU for PYRAMID
    // For CUBE
    mesh.cubeIndices = sizeof(cubeIndices) / sizeof(cubeIndices[0]);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.vbos[1]);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(cubeIndices), cubeIndices, GL_STATIC_DRAW);
    // For PYRAMID
    mesh.pyramidIndices = sizeof(pyramidIndices) / sizeof(pyramidIndices[0]);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.vbos2[1]);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(pyramidIndices), pyramidIndices, GL_STATIC_DRAW); 

    // Strides between vertex coordinates is 6 (x, y, z, r, g, b, a). A tightly packed stride is 0.
    GLint stride = sizeof(float) * (floatsPerVertex + floatsPerColor);// The number of floats before each

    // Create Vertex Attribute Pointers
    glVertexAttribPointer(0, floatsPerVertex, GL_FLOAT, GL_FALSE, stride, 0);
    glEnableVertexAttribArray(0);

    glVertexAttribPointer(1, floatsPerColor, GL_FLOAT, GL_FALSE, stride, (char*)(sizeof(float) * floatsPerVertex));
    glEnableVertexAttribArray(1);
}


void UDestroyMesh(GLMesh& mesh)
{
    // For CUBE
    glDeleteVertexArrays(1, &mesh.vao);
    glDeleteBuffers(2, mesh.vbos);

    // For PYRAMID
    glDeleteVertexArrays(1, &mesh.vao2);
    glDeleteBuffers(2, mesh.vbos2);
}


// Implements the UCreateShaders function
bool UCreateShaderProgram(const char* vtxShaderSource, const char* fragShaderSource, GLuint& programId)
{
    // Compilation and linkage error reporting
    int success = 0;
    char infoLog[512];

    // Create a Shader program object.
    programId = glCreateProgram();

    // Create the vertex and fragment shader objects
    GLuint vertexShaderId = glCreateShader(GL_VERTEX_SHADER);
    GLuint fragmentShaderId = glCreateShader(GL_FRAGMENT_SHADER);

    // Retrive the shader source
    glShaderSource(vertexShaderId, 1, &vtxShaderSource, NULL);
    glShaderSource(fragmentShaderId, 1, &fragShaderSource, NULL);

    // Compile the vertex shader, and print compilation errors (if any)
    glCompileShader(vertexShaderId); // compile the vertex shader
    // check for shader compile errors
    glGetShaderiv(vertexShaderId, GL_COMPILE_STATUS, &success);
    if (!success)
    {
        glGetShaderInfoLog(vertexShaderId, 512, NULL, infoLog);
        std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;

        return false;
    }

    glCompileShader(fragmentShaderId); // compile the fragment shader
    // check for shader compile errors
    glGetShaderiv(fragmentShaderId, GL_COMPILE_STATUS, &success);
    if (!success)
    {
        glGetShaderInfoLog(fragmentShaderId, sizeof(infoLog), NULL, infoLog);
        std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;

        return false;
    }

    // Attached compiled shaders to the shader program
    glAttachShader(programId, vertexShaderId);
    glAttachShader(programId, fragmentShaderId);

    glLinkProgram(programId);   // links the shader program
    // check for linking errors
    glGetProgramiv(programId, GL_LINK_STATUS, &success);
    if (!success)
    {
        glGetProgramInfoLog(programId, sizeof(infoLog), NULL, infoLog);
        std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;

        return false;
    }

    glUseProgram(programId);    // Uses the shader program

    return true;
}


void UDestroyShaderProgram(GLuint programId)
{
    glDeleteProgram(programId);
}

参见Vertex Specification。您不能同时指定 2 个顶点数组对象。您必须连续执行此操作。 顶点数组绑定是一个全局状态。一次只能绑定一个 VAO。 当调用 glVertexAttribPointerglEnableVertexAttribArrayglBindBuffer(GL_ELEMENT_ARRAY_BUFFER,...)` 等 OpenGL 指令时,当前绑定的顶点数组对象的状态会发生变化。请注意,不同的 VAO 可以使用相同的数据缓冲区。

void UCreateMesh(GLMesh& mesh)
{
    // [...]

    glGenBuffers(1, mesh.vbos);
    glGenBuffers(2, mesh.vbos2);

    // 1 Vertex Buffer for both objects
    glBindBuffer(GL_ARRAY_BUFFER, mesh.vbos[0]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW);

    // Strides between vertex coordinates is 6 (x, y, z, r, g, b, a). A tightly packed stride is 0.
    GLint stride = sizeof(float) * (floatsPerVertex + floatsPerColor);// The number of floats before each

    // CUBE

    glGenVertexArrays(1, &mesh.vao); // we can also generate multiple VAOs or buffers at the same time
    glBindVertexArray(mesh.vao);

    // Create Vertex Attribute Pointers
    glVertexAttribPointer(0, floatsPerVertex, GL_FLOAT, GL_FALSE, stride, 0);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(1, floatsPerColor, GL_FLOAT, GL_FALSE, stride, (char*)(sizeof(float) * floatsPerVertex));
    glEnableVertexAttribArray(1);

    mesh.cubeIndices = sizeof(cubeIndices) / sizeof(cubeIndices[0]);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.vbos[1]);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(cubeIndices), cubeIndices, GL_STATIC_DRAW);

    // PYRAMID

    glGenVertexArrays(1, &mesh.vao2);
    glBindVertexArray(mesh.vao2);

    // Create Vertex Attribute Pointers
    glVertexAttribPointer(0, floatsPerVertex, GL_FLOAT, GL_FALSE, stride, 0);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(1, floatsPerColor, GL_FLOAT, GL_FALSE, stride, (char*)(sizeof(float) * floatsPerVertex));
    glEnableVertexAttribArray(1);

    mesh.pyramidIndices = sizeof(pyramidIndices) / sizeof(pyramidIndices[0]);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.vbos2[1]);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(pyramidIndices), pyramidIndices, GL_STATIC_DRAW); 
}

终于可以一个接一个地画网格了。绘制调用使用来自当前绑定的顶点数组对象的数据。前面已经说过,一次只能绑定一个VAO:

glBindVertexArray(gMesh.vao);
glDrawElements(GL_TRIANGLES, gMesh.cubeIndices, GL_UNSIGNED_SHORT, NULL);

glBindVertexArray(gMesh.vao2);
glDrawElements(GL_TRIANGLES, gMesh.pyramidIndices, GL_UNSIGNED_SHORT, NULL);