使用多个索引渲染网格

65
我有一些顶点数据。位置、法线、纹理坐标。我可能是从一个.obj文件或其他格式加载的。也许我正在绘制一个立方体。但是每个顶点数据都有自己的索引。我能用OpenGL/Direct3D渲染这个网格数据吗?
2个回答

78
从最一般的意义上来说,不行。OpenGL和Direct3D只允许每个顶点有一个索引;索引从每个顶点数据流中获取。因此,每个不同的组合都必须有自己单独的索引。
所以,如果你有一个立方体,其中每个面都有自己的法线,你将需要大量复制位置和法线数据。即使这个立方体只有8个唯一的位置和6个唯一的法线,你也需要24个位置和24个法线。
你最好接受你的数据会更大的事实。很多模型格式会使用多个索引;你需要在渲染之前修复这些顶点数据。很多网格加载工具,如Open Asset Importer,会为您执行此修复操作。
还应该注意的是,大多数网格不是立方体。大多数网格在绝大多数顶点上都是平滑的,只偶尔有不同的法线/纹理坐标等。因此,虽然这经常出现在简单的几何形状中,但真正的模型很少有大量的顶点重复。
GL 3.x和D3D10
对于D3D10/OpenGL 3.x级别的硬件,可以避免执行修复操作并直接使用多个索引属性。然而,请注意这可能会降低渲染性能。
以下讨论将使用OpenGL术语,但Direct3D v10及以上版本具有相当的功能。
想法是手动从顶点着色器中访问不同的顶点属性。传递的实际上是特定顶点的索引,而不是直接发送顶点属性。然后,顶点着色器使用这些索引通过一个或多个缓冲纹理来访问实际属性。
属性可以存储在多个缓冲纹理中或全部存储在一个中。如果使用后者,则着色器将需要一个偏移量以添加到每个索引中,以便在缓冲区中找到相应属性的起始索引。
常规顶点属性可以以多种方式进行压缩。缓冲纹理具有较少的压缩方式,仅允许相对较有限的顶点格式(通过它们支持的图像格式)
请再次注意,任何这些技术都可能降低整体顶点处理性能。因此,在所有其他压缩或优化选项用尽之后,应仅在最受内存限制的情况下使用它。

OpenGL ES 3.0提供缓冲纹理。更高版本的OpenGL使用SSBOs可以更直接地读取缓冲对象,而不是缓冲纹理,这可能具有更好的性能特征。


这里有一篇关于此的文章(第21章 - 可编程顶点拉取),链接在这里:http://openglinsights.com/,但是它不是直接可访问的。不过,这里有相关的代码:https://github.com/OpenGLInsights/OpenGLInsightsCode/blob/master/Chapter%2021%20Programmable%20Vertex%20Pulling/shaders/fetcher.vs。 - jozxyqk
这是因为它没有按顺序访问缓冲区所以变慢了吗? - Samik
@Samik:任何类型的索引访问都将是非顺序的;这就是重点。性能差异通常在具有实际硬件支持顶点拉取的硬件中发挥作用。AMD的GCN架构没有这样的支持,因此他们必须根据您的VAO修补您的顶点着色器,以创建具有硬件顶点拉取幻觉。因此,自己手动执行它可能不会使您变慢。 - Nicol Bolas
你不需要缓冲纹理,可以使用常规纹理。换句话说,您可以在DirectX9和OpenGL 2.1中实现此功能。这里有一个现成的示例:https://stackoverflow.com/a/22009385/128511 。请注意,我并不是在说您应该这样做,我只是想说明这是完全可行的。 - gman
3
为什么会有不同的法线?这是因为一个三角形边缘的锐利程度并不取决于相邻两个三角形之间的角度大小,而是取决于该边缘顶点处的法线是否不同。如果它们相同,那么这就是一条平滑的边缘(或其近似)。而大多数模型都是平滑的。 - Nicol Bolas
显示剩余2条评论

6
我发现了一种方法,可以减少这种重复,这与其他答案中的某些陈述有些违背(但不特别符合此处提出的问题)。它确实涉及到我的问题,这被认为是这个问题的重复。
我刚学到了插值限定符。具体来说,“平面”。我的理解是,在顶点着色器输出上放置平面限定符会导致只有挑选的顶点将其值传递到片段着色器。
这意味着对于这个引用所描述的情况:
“因此,如果你有一个立方体,每个面都有自己的法线,你需要大量复制位置和法线数据。你将需要24个位置和24个法线,即使立方体只有8个唯一的位置和6个唯一的法线。”
你可以有8个顶点,其中6个包含唯一的法线,而2个法线值被忽略,只要你仔细地按照原语索引的顺序排序,使得“激发顶点”包含你想要应用于整个面的法线数据。
编辑:我的理解如下:

enter image description here

enter image description here

enter image description here

enter image description here


那么,你实际上如何做到这一点?你的索引数据应该是什么样子?你如何向VS提供位置和法线,以便它可以完成此操作? - Nicol Bolas
1
我仍在自己实现它。我会用一个基本的例子来更新我的回答,以展示我的理解。 - gunfulker
将文本发布在图像中会使其难以阅读和使用,因此不要这样做。您可以使用图像,只需将文本放在帖子的正文中即可。此外,在涉及图形时,您一直混淆“位置”和“顶点”的术语;它们不能互换。第三,您的索引顺序没有一致的绕组顺序(至少我看不出来)。最后,这个技巧只适用于立方体和位置+法线;如果您需要每个面都有纹理坐标,那么这并没有什么帮助。 - Nicol Bolas
如果你需要每个面都有纹理坐标,我没有考虑到这一点。我的特定应用程序在顶点着色器上生成纹理坐标。 - gunfulker
即使VS生成纹理坐标,你只有8个顶点(因为你只有8个顶点索引)。因此,每个面不能获得不同的纹理坐标。 - Nicol Bolas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接