网格中损坏的顶点数据 Class

Broken Vertex Data in Mesh Class

我正在尝试实现模型加载,但我遇到了一个问题。当我出于某种原因尝试绘制网格(出于测试目的而手工编写的单个纹理四边形)时,与第一个顶点关联的重复数据被传递到顶点着色器 (RenderDoc screen).

这是一个使用我的 class 精简版的示例,它仍然表现出这种行为:

#define TEST_MESH

#include <glad/glad.h>
#include <GLFW/glfw3.h>

#include <iostream>
#include <vector>

void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow* window);

struct Vertex {
    float position[3];
    float color[3];
};

class Mesh {
public:
    Mesh(std::vector<Vertex> vertices, std::vector<unsigned int> indices);
    ~Mesh();
    Mesh(const Mesh&) = delete;
    Mesh& operator=(const Mesh&) = delete;
    Mesh(Mesh&& other);
    Mesh& operator=(Mesh&& other);

    void Draw(unsigned int program_id);

    std::vector<Vertex> m_Vertices;
    std::vector<unsigned int> m_Indices;

private:
    unsigned int m_VAO, m_VBO, m_EBO;

    void Setup();
    void Release();
};

int main() {
    //GLFW INIT
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    //GLFW Window setup
    const unsigned int SCR_WIDTH = 800;
    const unsigned int SCR_HEIGHT = 600;

    GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "Mesh Test", NULL, NULL);
    if (window == NULL) {
        std::cout << "Failed to create GLFW window" << std::endl;
        glfwTerminate();
        return -1;
    }

    glfwMakeContextCurrent(window);
    glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);

    //GLAD INIT
    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
        std::cout << "Failed to initialize GLAD" << std::endl;
        return -1;
    }

    //Shader setup:
    const char* vertex = "#version 460 core\n"
                         "layout (location = 0) in vec3 aPos;\n"
                         "layout (location = 1) in vec3 aCol;\n"
                         "out vec3 vColor;\n"
                         "void main() {\n"
                         "   gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
                         "   vColor = aCol;\n"
                         "}[=11=]";

    const char* fragment = "#version 460 core\n"
                           "in vec3 vColor;\n"
                           "out vec4 FragColor;\n"
                           "void main() {\n"
                           "    FragColor = vec4(vColor, 1.0);\n"
                           "}[=11=]";

    unsigned int vertexShader;
    vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertex, NULL);
    glCompileShader(vertexShader);

    unsigned int fragmentShader;
    fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragment, NULL);
    glCompileShader(fragmentShader);

    unsigned int program;
    program = glCreateProgram();
    glAttachShader(program, vertexShader);
    glAttachShader(program, fragmentShader);
    glLinkProgram(program);

    glDeleteShader(vertexShader);
    glDeleteShader(fragmentShader);

    //Data:
    float floats[24] = {
        -0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f,
         0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f,
         0.5f,-0.5f, 0.0f, 0.0f, 0.0f, 1.0f,
        -0.5f,-0.5f, 0.0f, 1.0f, 1.0f ,0.0f };

    unsigned int uints[6] = { 0, 1, 2, 2, 3, 0 };

#ifdef TEST_MESH
    //Mesh assembly
    std::vector<Vertex> vertices;
    for (int i = 0; i < 4; i++)
        vertices.push_back(Vertex{ floats[6 * i], floats[6 * i + 1], floats[6 * i + 2],
                                   floats[6 * i + 3], floats[6 * i + 4], floats[6 * i + 5] });

    std::vector<unsigned int> indices{ 0, 1, 2, 2, 3, 0 };

    Mesh mesh(vertices, indices);
#else
    unsigned int VAO, VBO, EBO;
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
    glGenBuffers(1, &EBO);

    glBindVertexArray(VAO);

    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(floats), &floats[0], GL_STATIC_DRAW);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(uints), &uints[0], GL_STATIC_DRAW);

    //Positions
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);
    //Colors
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));
    glEnableVertexAttribArray(1);
#endif

    //Render loop
    while (!glfwWindowShouldClose(window)) {
        processInput(window);

        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

#ifdef TEST_MESH
        mesh.Draw(program);
#else
        glUseProgram(program);
        glBindVertexArray(VAO);
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
        glBindVertexArray(0);
#endif
        glfwSwapBuffers(window);
        glfwPollEvents();
    }

    glfwTerminate();
    return 0;
}

Mesh::Mesh(std::vector<Vertex> vertices, std::vector<unsigned int> indices) {
    m_Vertices = vertices;
    m_Indices = indices;

    Setup();
}

Mesh::Mesh(Mesh&& other)
    : m_VAO(other.m_VAO), m_VBO(other.m_VBO), m_EBO(other.m_EBO)
    , m_Vertices(other.m_Vertices), m_Indices(other.m_Indices)
{
    other.m_VAO = 0;
    other.m_VBO = 0;
    other.m_EBO = 0;
}

Mesh& Mesh::operator=(Mesh&& other) {
    if (this != &other) {
        Release();

        std::swap(m_VAO, other.m_VAO);
        std::swap(m_VBO, other.m_VBO);
        std::swap(m_EBO, other.m_EBO);

        m_Vertices = other.m_Vertices;
        m_Indices = other.m_Indices;
    }
    return *this;
}

Mesh::~Mesh() {
    Release();
}

void Mesh::Release() {
    glDeleteVertexArrays(1, &m_VAO);
    glDeleteBuffers(1, &m_VBO);
    glDeleteBuffers(1, &m_EBO);
}

void Mesh::Setup() {
    glGenVertexArrays(1, &m_VAO);
    glGenBuffers(1, &m_VBO);
    glGenBuffers(1, &m_EBO);

    glBindVertexArray(m_VAO);

    glBindBuffer(GL_ARRAY_BUFFER, m_VBO);
    glBufferData(GL_ARRAY_BUFFER, m_Vertices.size() * sizeof(Vertex), &m_Vertices[0], GL_STATIC_DRAW);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_EBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_Indices.size() * sizeof(unsigned int), &m_Indices[0], GL_STATIC_DRAW);

    //Positions
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, position));
    glEnableVertexAttribArray(0);
    //Colors
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, color));
    glEnableVertexAttribArray(1);

    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
    glBindVertexArray(0);
}

void Mesh::Draw(unsigned int program_id) {
    glUseProgram(program_id);

    glBindVertexArray(m_VAO);
    glDrawElements(GL_TRIANGLES, m_Indices.size(), GL_UNSIGNED_INT, 0);
}

void processInput(GLFWwindow* window) {
    if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
        glfwSetWindowShouldClose(window, true);
}

void framebuffer_size_callback(GLFWwindow* window, int width, int 
height) {
    glViewport(0, 0, width, height);
}

在您的 Mesh::Setup 中,您在末尾有这一行:

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

这会解除您的 EBO 与 VAO 的绑定。您的实现似乎将未定义的读取视为零,因此您看到的只是第 0 个顶点被复制了六次。

绑定EBO后无需解绑

(注意:另一方面,取消绑定 GL_ARRAY_BUFFER 是可以的。这是因为 VBO 在您调用任何 *Pointer 函数时附加到 VAO,而不是在将它绑定到 GL_ARRAY_BUFFER 的时间。)

(注意:由于您使用的是最新的 OpenGL 版本,我强烈建议您使用直接状态访问 (DSA) 函数。在这种情况下,您可以将 EBO 绑定到

glVertexArrayElementBuffer(m_VAO, m_EBO);

调用,我认为这会使错误更加明显。参见 。)