我有一个自定义文件格式,其中包含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]
中。
现在,您可以阅读三角形列表,每个三角形的每个角都由vertexIdx
和normalIdx
给出。我们将构建一个新的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]];
我对它进行了一些优化,根本没有填充索引数组。但是优化取决于程序员读取网格数据的方式。