渲染具有多个索引的网格

Posted

技术标签:

【中文标题】渲染具有多个索引的网格【英文标题】:Rendering meshes with multiple indices 【发布时间】:2012-06-22 00:05:01 【问题描述】:

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

【问题讨论】:

【参考方案1】:

在最一般的意义上,没有。 OpenGL 和 Direct3D 只允许每个顶点有一个索引;索引从每个顶点数据流中获取。因此,每个唯一的组件组合都必须有自己独立的索引。

因此,如果您有一个立方体,其中每个面都有自己的法线,您将需要大量复制位置和法线数据。您将需要 24 个位置和 24 个法线,即使立方体只有 8 个 唯一 位置和 6 个唯一法线。

您最好的选择是简单地接受您的数据会更大。许多模型格式将使用多个索引;您需要先修复此顶点数据,然后才能使用它进行渲染。许多网格加载工具,例如 Open Asset Importer,将为您执行此修复。

还应注意,大多数网格不是立方体。大多数网格在绝大多数顶点上都是平滑的,只是偶尔会有不同的法线/纹理坐标等。因此,虽然这通常出现在简单的几何形状中,但实际模型很少有大量的顶点重复。

GL 3.x 和 D3D10

对于 D3D10/OpenGL 3.x 类硬件,可以避免执行修复并直接使用多个索引属性。但是,请注意,这可能会降低渲染性能。

以下讨论将使用 OpenGL 术语,但 Direct3D v10 及更高版本具有相同的功能。

这个想法是从顶点着色器手动访问不同的顶点属性。不是直接发送顶点属性,而是传递的属性实际上是该特定顶点的索引。顶点着色器然后使用索引通过一个或多个buffer textures 访问实际属性。

属性可以存储在多个缓冲区纹理中或全部存储在一个中。如果使用后者,那么着色器将需要为每个索引添加一个偏移量,以便在缓冲区中找到相应属性的起始索引。

常规顶点属性可以通过多种方式进行压缩。缓冲纹理的压缩手段较少,只允许相对limited number of vertex formats (via the image formats they support).

再次请注意,这些技术中的任何一种都可能会降低整体顶点处理性能。因此,它应该只在内存最有限的情况下使用,在所有其他压缩或优化选项都已用尽之后。

OpenGL ES 3.0 也提供缓冲纹理。更高的 OpenGL 版本允许您通过 SSBOs 更直接地读取缓冲区对象,而不是缓冲区纹理,后者可能具有更好的性能特征。

【讨论】:

有一篇关于这个here的文章(第21章-可编程顶点拉取),但不能直接访问。不过有code。 这么慢是不是因为不是缓冲区的顺序访问? @Samik:任何类型的索引访问都将是非顺序的;这就是重点。对于具有实际硬件支持顶点拉动的硬件,性能差异通常会发挥作用。 AMD 的基于 GCN 的架构没有,因此他们必须根据您的 VAO 修补您的顶点着色器,以创建硬件顶点拉动的错觉。因此,自己手动操作可能不会减慢您的速度。 您不需要缓冲纹理。您可以使用常规纹理。换句话说,您可以在 DirectX9、OpenGL 2.1 中执行此操作。现场示例***.com/a/22009385/128511 注意:不是说你应该这样做。只有完全有可能。 @deqyra: "它必然有不同的法线,具体取决于三角形" 为什么?两个三角形之间的锐边和平滑边的区别不是三角形之间的角度,而是边顶点处的法线是否不同。如果它们相同,那么它是一个平滑的边缘(或一个近似值)。而且大多数模型都很平滑。【参考方案2】:

我找到了一种方法,可以减少这种重复,这种重复与其他答案中的某些陈述有些相反(但并不特别适合这里提出的问题)。但是它确实解决了my question,这被认为是这个问题的重复。

我刚刚了解了Interpolation qualifiers。特别是“平”。据我了解,将 flat 限定符放在顶点着色器输出上只会导致 provoking vertex 将其值传递给片段着色器。

这意味着对于这句话中描述的情况:

因此,如果您有一个立方体,其中每个面都有自己的法线,您将需要大量复制位置和法线数据。您将需要 24 个位置和 24 个法线,即使立方体只有 8 个唯一位置和 6 个唯一法线。

您可以拥有 8 个顶点,其中 6 个包含唯一法线,而忽略 2 个法线值,只要您仔细排序基元索引,以使“激发顶点”包含您要应用于的法线数据整张脸。

编辑:我对其工作原理的理解:

【讨论】:

那么,你是怎么做到的呢?您的索引数据必须是什么样的?你如何为 VS 提供位置和法线以便它可以做到这一点? 我还在自己实现它。我将用我的理解的基本示例来更新我的答案。 在图片中张贴文字会使阅读和使用变得困难,所以不要这样做。您可以使用图片,只需将您的文字放在帖子的文字中即可。此外,您不断混淆“位置”和“顶点”的术语;在图形方面,它们不可互换。第三,您的索引排序没有一致的缠绕顺序(至少,我不能说)。最后,这个技巧只适用于立方体并且只适用于位置+法线;如果您需要每个面都有纹理坐标,这将没有帮助。 "如果你需要每个面都有纹理坐标"我没有考虑过。我的特定应用程序在顶点着色器上生成纹理坐标。 即使你的VS生成纹理坐标,你也只有8个顶点(因为你只有8个顶点索引)。所以每个面都无法获得不同的纹理坐标。

以上是关于渲染具有多个索引的网格的主要内容,如果未能解决你的问题,请参考以下文章

渲染具有多个索引的网格

如何有效地渲染具有多边形边缘的网格表面?

具有渲染属性的jsf组件验证失败

在 OpenGL 中渲染网格多边形 - 非常慢

排序子网格/VBO

配置 VAO 以处理具有多个网格的 VBO