【问题标题】:Opengl is adding an extra vertex to the mesh in .obj loaderOpengl 在 .obj 加载器中向网格添加一个额外的顶点
【发布时间】:2014-09-30 05:07:37
【问题描述】:

我创建了一个 .obj 加载器,它从在 blender 2.66 中创建的网格文件中读取数据,并将数据加载到 std::vector 作为 VBO 传递给 Opengl。网格文件中没有一个顶点的位置为 (0,0,0)。 那么网格在中心获得额外顶点的可能原因是什么?因为原始网格只是一个只有四个顶点的三角平面。

struct Vertex
{
    //Position
    GLfloat m_X;
    GLfloat m_Y;
    GLfloat m_Z;

    //Normal
    GLfloat m_NX;
    GLfloat m_NY;
    GLfloat m_NZ;

    //TexCoords
    GLfloat m_U;
    GLfloat m_V;
};

void Mesh::loadMesh(std::string Filename)
{
  ...

    const unsigned int PositionAttribute = 0;
    const unsigned int NormalAttribute   = 1;
    const unsigned int TexCoordAttribute = 2;

    //Create a new VBO and use the variable id to store the VBO id
    glGenBuffers(1, &MeshVBO);

    //make the new VBO active
    glBindBuffer(GL_ARRAY_BUFFER, MeshVBO);

    //Pass the Mesh's vertex data into the VBO to be transferred to super fast Video RAM
    glBufferData(GL_ARRAY_BUFFER, m_Vertices.size() * sizeof(Vertex), &m_Vertices[0], GL_STATIC_DRAW);

    glEnableVertexAttribArray(PositionAttribute);
    glEnableVertexAttribArray(NormalAttribute);
    glEnableVertexAttribArray(TexCoordAttribute);

    //specifies the location and data of an array of vertex
    glVertexAttribPointer(PositionAttribute, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)0);
    glVertexAttribPointer(NormalAttribute, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)(sizeof(GLfloat) * 3)); //12 byte offset
    glVertexAttribPointer(TexCoordAttribute, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)(sizeof(GLfloat) * 6)); //24 byte offset

    //make the new VBO active
    glBindBuffer(GL_ARRAY_BUFFER, MeshVBO);

    glGenBuffers(1, &MeshIBO);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, MeshIBO);

    glBufferData(GL_ELEMENT_ARRAY_BUFFER, (sizeof(GLushort) * m_IndexList.size()), &m_IndexList[0], GL_STATIC_DRAW); 

    //Cleanup
    delete[] m_VertexArray;
    delete[] m_Indices;
    m_VertexArray = NULL;
    m_Indices = NULL;

    return Success;
}

void Mesh::drawMesh()
{
    glDrawElements(GL_POINTS, (GLsizei)m_IndexList.size() + 1, GL_UNSIGNED_SHORT, 0);
}

平面.obj

# Blender v2.66 (sub 1) OBJ File: ''
# www.blender.org
mtllib plane.mtl
o Plane
v 0.622129 -0.622129 0.000000
v -0.622129 -0.622129 0.000000
v 0.622129 0.622129 -0.000000
v -0.622129 0.622129 -0.000000
vn 1.000000 0.000000 0.000000
usemtl None
s off
f 2//1 1//1 3//1
f 4//1 2//1 3//1

【问题讨论】:

  • 可能是glDrawElements() 的第二个参数中的+ 1。看起来您显式渲染的点比您拥有的多一点。
  • 你能把生成的网格文件贴出来吗?如果指定的顶点超过 4 个,您还可以判断问题是否出在此处。虽然我同意@Reto Koradi 的观点,即 +1
  • @RetoKoradi 从 gldrawelements() 中删除“+1”会从网格中删除右下角的顶点。是否有可能我的向量没有以某种方式正确传递索引?调试中检查的索引与文件的索引匹配。
  • @Daniel 我将文件包含在搅拌机生成的帖子中。
  • 请注意,OBJ 文件中的索引是从 1 开始的,而 OpenGL 使用从 0 开始的索引。因此,当您读取文件时,您需要从每个索引中减去 1。如果要支持完整的 OBJ 格式,索引也可以是负数,这意味着它们是相对于最后读取的顶点的。

标签: opengl


【解决方案1】:

您的主要问题是 OBJ 文件中的索引是基于 1 的,而 OpenGL 使用基于 0 的索引。这意味着您必须从从 OBJ 文件中读取的索引中减去 1。这在您阅读解析代码中的索引之后最方便地完成,因为大多数编程语言和 API 都使用从 0 开始的索引。

如果您希望能够读取更广泛的 OBJ 文件选择,您还必须处理输入文件中的负索引值。这似乎并不常用,如果文件来自受良好控制的来源(例如,您总是使用相同的软件自己生成它们),您可能可以跳过它。如果存在,负索引相对于到目前为止读取的顶点的末尾。例如。 index -1 是最新读取的顶点,-2 是第二个最新的,以此类推。

在发布的代码中,您将绘图调用中可用索引的数量加了 1:

glDrawElements(GL_POINTS, (GLsizei)m_IndexList.size() + 1, GL_UNSIGNED_SHORT, 0);

我怀疑您这样做可能是为了补偿错误的索引值。获得正确的索引值后,您应该删除 + 1

有关 OBJ 格式的更详细文档,维基百科页面 (http://en.wikipedia.org/wiki/Wavefront_.obj_file) 包含一个很好的概述。我找到的最详细和最彻底的定义在这里:http://www.martinreddy.net/gfx/3d/OBJ.spec。 OBJ 格式可以包含相当高级的功能,例如 NURBS。如果您编写自己的解析器和渲染器,您可能想要满足于一个子集。否则你会很忙。

如果您想更深入地了解如何有效地从 OBJ 文件渲染网格,这里是我对之前问题的一些相关回答:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-01
    • 2022-10-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多