网格类中的断开顶点数据



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

下面是一个使用我的类的精简版本的例子,它仍然表现出这种行为:

#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 coren"
"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"
"}";
const char* fragment = "#version 460 coren"
"in vec3 vColor;n"
"out vec4 FragColor;n"
"void main() {n"
"    FragColor = vec4(vColor, 1.0);n"
"}";
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);

电话,我认为这会使错误更加明显。查看VAO状态的快速参考以及用于操作它的推荐功能。(

最新更新