OpenGL-索引缓冲困难



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

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

除了法线之外,一切看起来都是对的。问题是法线具有不同的索引。因为OpenGL只能使用一个索引缓冲区,所以它对顶点和法线都使用该索引缓冲区。

如果你能建议我如何解决那个问题,我将不胜感激。

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

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

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

您需要做的是为输入中的每个唯一(顶点索引、法线索引)对创建OpenGL顶点。这需要一些工作,但并不十分困难,尤其是在使用可用数据结构的情况下。STL map可以很好地实现这一点,其中(顶点索引、法线索引)对是关键。我不会提供完整的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

我成功地做到了这一点,而没有使用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]];

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

最新更新