提问人:ModernEraCaveman 提问时间:1/3/2023 更新时间:1/3/2023 访问量:59
为什么我的索引生成函数不能正确构建三角形基元?
Why is my Index Generation Function not correctly building the triangle primitives?
问:
我正在尝试编写一个函数,该函数会自动填充网格的索引向量容器。从理论上讲,该函数应该可以毫无问题地工作,因为它会以正确的顺序生成适当的索引;但是,三角形不会形成!相反,我只剩下一行。
我的网格生成代码应该构建一个八面体,然后在主游戏循环中渲染它。网格类完整如下所示:
struct vertex
{
glm::vec3 position;
glm::vec3 color;
};
class Mesh
{
public:
GLuint VAO, VBO, EBO;
std::vector <vertex> vtx;
std::vector <glm::vec3> idx;
glm::mat4 modelMatrix = glm::mat4(1.f);
Mesh(glm::vec3 position, glm::vec3 scale)
{
vertexGen(6);
idx = indexGen(6);
modelMatrix = glm::scale(glm::translate(modelMatrix, position), scale);
initMesh();
};
void Render(Shader shaderProgram, Camera camera, bool wireframe)
{
glUseProgram(shaderProgram.ID);
glPatchParameteri(GL_PATCH_VERTICES, 3); // Indicates to the VAO that each group of three vertices is one patch (triangles)
glProgramUniformMatrix4fv(shaderProgram.ID, 0, 1, GL_FALSE, glm::value_ptr(modelMatrix));
glProgramUniformMatrix4fv(shaderProgram.ID, 1, 1, GL_FALSE, glm::value_ptr(camera.camMatrix));
glProgramUniform3fv(shaderProgram.ID, 2, 1, glm::value_ptr(camera.Position));
glBindVertexArray(VAO); // Binds the VAO to the shader program
if (wireframe)
{
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glDisable(GL_CULL_FACE);
}
else
{
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
//glEnable(GL_CULL_FACE);
}
glDrawElements(GL_PATCHES, idx.size(), GL_UNSIGNED_INT, 0); // Tells the shader program how to draw the primitives
}
private:
void vertexGen(int n) {
// Populate the base six vertices
vtx.push_back(vertex{ glm::vec3( 0.0f, 0.5f, 0.0f), glm::vec3(0.f, 1.f, 0.f) });
vtx.push_back(vertex{ glm::vec3(-0.5f, 0.0f, 0.0f), glm::vec3(0.f, 1.f, 0.f) });
vtx.push_back(vertex{ glm::vec3( 0.0f, 0.0f, -0.5f), glm::vec3(0.f, 1.f, 0.f) });
vtx.push_back(vertex{ glm::vec3( 0.5f, 0.0f, 0.0f), glm::vec3(0.f, 1.f, 0.f) });
vtx.push_back(vertex{ glm::vec3( 0.0f, 0.0f, 0.5f), glm::vec3(0.f, 1.f, 0.f) });
vtx.push_back(vertex{ glm::vec3( 0.0f,-0.5f, 0.0f), glm::vec3(0.f, 1.f, 0.f) });
}
std::vector<glm::vec3> indexGen(int n) {
std::vector<glm::vec3> indices;
// Calculate the indices for the top 4 triangles
indices.push_back(glm::vec3( 0, n - 5, n - 4 ));
indices.push_back(glm::vec3( 0, n - 4, n - 3 ));
indices.push_back(glm::vec3( 0, n - 3, n - 2 ));
indices.push_back(glm::vec3( 0, n - 2, n - 5 ));
// Calculate the indices for the bottom 4 triangles
indices.push_back(glm::vec3( 5, n - 5, n - 4));
indices.push_back(glm::vec3( 5, n - 4, n - 3));
indices.push_back(glm::vec3( 5, n - 3, n - 2));
indices.push_back(glm::vec3( 5, n - 2, n - 5));
return indices;
}
void initMesh()
{
glCreateVertexArrays(1, &VAO); // Sets the address of the uint VAO as the location of a gl vertex array object
glCreateBuffers(1, &VBO); // Sets the address of the uint VBO as the location of a gl buffer object
glCreateBuffers(1, &EBO); // Sets the address of the uint EBO as the location of a gl buffer object
glNamedBufferData(VBO, vtx.size() * sizeof(vtx[0]), vtx.data(), GL_STATIC_DRAW); // Sets the data of the buffer named VBO
glNamedBufferData(EBO, idx.size() * sizeof(idx[0]), idx.data(), GL_STATIC_DRAW); // Sets the data of the buffer named EBO
glEnableVertexArrayAttrib(VAO, 0); // Enables an attribute of the VAO in location 0
glEnableVertexArrayAttrib(VAO, 1); // Enables an attribute of the VAO in location 1
glVertexArrayAttribBinding(VAO, 0, 0); // Layout Location of Position Vectors
glVertexArrayAttribBinding(VAO, 1, 0); // Layout Location of Color Values
glVertexArrayAttribFormat(VAO, 0, 3, GL_FLOAT, GL_FALSE, 0); // Size, and Type of Position Vectors
glVertexArrayAttribFormat(VAO, 1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat)); // For the Color Values
glVertexArrayVertexBuffer(VAO, 0, VBO, 0, 6 * sizeof(GLfloat)); // Sets the VBO to indicate the start, offset, and stride of vertex data in the VAO
glVertexArrayElementBuffer(VAO, EBO); // Sets the EBO to index the VAO vertex connections
}
};
我一步一步地回答了这个问题,并在纸上完成了所有的基本数学运算。索引生成函数以正确的顺序返回预期的索引,就像只写出索引一样,但它的不同之处在于,写出的索引生成所需的结果,而生成函数在呈现时只生成一行:
我怀疑问题出在我的网格初始化函数 (initMesh) 上,特别是在 glNamedBufferData 或 glVertexArrayVertexBuffer 中,但我对这些函数的了解非常有限。我尝试将 glNamedBufferData 函数的参数更改为 idx.size()*sizeof(idx[0].x) 的不同变体,但这产生了相同的结果,所以我不知所措。有人可以帮我解决这个问题吗?
答:
glm::vec3 是 s 的向量(我认为),但您告诉 OpenGL 将它们读取为无符号整数。float
浮点 0.0 是 0x00000000(即与 int 0 相同),但浮点 1.0 是 0x3f800000(与 int 1065353216 相同)。它们不是存储数字的兼容方式。您可以尝试哪个是 s 的向量,但我认为大多数人会使用(或)并为每个三角形使用 3 个条目。glm::ivec3
int
std::vector<int>
unsigned int
我认为在这种情况下没关系,但我不喜欢使用类型,比如我的意思是有 3 个单独的 s 并不总是一个好的做法,因为编译器可以在意想不到的地方插入填充。在某些平台上,可能是 3 秒和额外的 4 个字节的填充,总共 16 个字节,而额外的填充字节会抛弃您所依赖的布局。 不会在每 3 个索引之后跳过填充,也没有办法告诉它这样做。顶点是可以的,因为你可以告诉 OpenGL 数据的确切位置。ivec3
int
ivec3
int
glDrawArrays
评论
sizeof(glm::ivec3)
alignof(glm::ivec3)
sizeof(glm::ivec3)
是 12 岁,是 4 岁。我对 c++ 编码很陌生,所以我不确定我该如何告诉向量保留我会保留的项目数量。它是地址/指针调用的某种变体吗?alignof(glm::ivec3)
idx.size()
indices.reserve(24);
评论