【问题标题】:OpenGL - Index buffers difficultiesOpenGL - 索引缓冲困难
【发布时间】:2014-06-14 11:18:36
【问题描述】:

我有一个自定义文件格式,其中包含 3D 网格所需的所有信息(从 3ds Max 导出)。我已经提取了顶点、顶点索引和法线的数据。

我将顶点数据、顶点索引和法线数据传递给 OpenGL,并通过调用 glDrawElements(GL_TRIANGLES,...) 来渲染网格

一切看起来都正常,但正常。问题是法线有不同的指数。由于 OpenGL 只能使用一个索引缓冲区,因此它对顶点和法线都使用该索引缓冲区。

如果你能建议我如何解决这个问题,我将非常感激。

需要注意的重要一点是顶点/法线数据没有“排序”,因此我无法使用glDrawArrays(GL_TRIANGLES,...) 的功能 - 网格无法正确渲染。

有没有一种方法/算法可以用来对数据进行排序,以便可以使用 glDrawArrays(GL_TRIANGLES,..) 正确绘制网格?但即使有一种算法,还有一个问题——我将不得不复制一些顶点(因为我的顶点缓冲区由唯一的顶点组成——例如,如果你有立方体,我的缓冲区将只有 8 个顶点)而且我不确定如何做到这一点。

【问题讨论】:

  • "问题是法线有不同的索引。"为什么?重新排列索引缓冲区,使法线与顶点匹配。更好的是,交错顶点信息。
  • 在某些网格中,我得到的法线比顶点多,因此无法匹配索引。平时这样吗?
  • 哦,是的,对于某些着色效果,您可能会在同一点获得顶点但具有不同的法线。您将不得不重新排列数据,以便所有内容都对齐,具体取决于您的属性是什么以及您使用的文件格式。但是现在,你还没有真正问过问题,所以我不知道该回答什么。

标签: c++ opengl 3d rendering mesh


【解决方案1】:

对顶点和法线使用单独索引的文件类型与 OpenGL 顶点模型不直接匹配。如您所见,OpenGL 使用一组索引。

您需要为输入中的每个唯一(顶点索引、法线索引)对创建一个 OpenGL 顶点。这需要一些工作,但并不是非常困难,特别是如果您使用可用的数据结构。 STL map 可以很好地解决这个问题,使用 (vertex index, normal index) 对作为键。我不打算提供完整的 C++ 代码,但我可以把它画出来。

假设您已经将顶点读入某种数组/向量数据结构inVertices,其中索引为vertexIdx 的顶点坐标存储在inVertices[vertexIdx] 中。法线也一样,索引为normalIdx 的法线向量存储在inNormals[normalIdx] 中。

现在您可以阅读三角形列表,每个三角形的每个角都由vertexIdxnormalIdx 给出。我们将构建一个新的combinedVertices 数组/向量,其中包含顶点和法线坐标,以及一个新的combinedIndices 索引列表。伪代码:

nextCombinedIdx = 0
indexMap = empty
loop over triangles in input file
    loop over 3 corners of triangle
        read vertexIdx and normalIdx for the corner
        if indexMap.contains(key(vertexIdx, normalIdx)) then
            combinedIdx = indexMap.get(key(vertexIdx, normalIdx))
        else
            combinedIdx = nextCombinedIdx
            indexMap.add(key(vertexIdx, normalIdx), combinedIdx)
            nextCombinedIdx = nextCombinedIdx + 1
            combinedVertices.add(inVertices[vertexIdx], inNormals[normalIdx])
        end if
        combinedIndices.add(combinedIdx)
    end loop
end loop

【讨论】:

    【解决方案2】:

    我设法做到了,而无需使用glDrawArrays(GL_TRIANGLES,..) 将索引缓冲区传递给 OpenGL 我所做的是以下内容: 填充顶点数组、顶点索引数组、法线数组和法线索引数组。 然后我用排序后的数据创建了新的顶点和法线数组,并将它们传递给 OpenGL。

    for i = 0; i < vertexIndices.size(); ++i
        newVertexArray[i] = oldVertexArray[vertexIndices[i]];
    
    for i = 0; i < normalsIndices.size(); ++i
        newNormalsArray[i] = oldNormalsArray[normalsIndices[i]];
    

    我对其进行了一些优化,根本没有填充索引数组。但优化取决于程序员读取网格数据的方式。

    【讨论】:

    • 嗯,是的,如果你不关心内存使用、效率和功耗,那就更简单了。在或多或少规则的网格中,一个顶点通常由大约 6 个三角形共享。根据索引方法的顶点缓存命中率,我希望您在 GPU 上创建大约 3-6 倍的顶点处理负载,相应的内存带宽也会增加。您还将使用将近 6 倍的内存。考虑到使用索引构建网格只需要多几行代码,我认为这绝对值得。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多