处理具有多种顶点格式的 GLTF 节点

Posted

技术标签:

【中文标题】处理具有多种顶点格式的 GLTF 节点【英文标题】:Handling GLTF nodes with multiple vertex formats 【发布时间】:2021-12-24 22:25:14 【问题描述】:

我正在使用 Vulkan 和 C++ 在爱好渲染器中实现对 GLTF 2.0 的支持。 https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html

最初,我实现了对一些测试 GLTF 文件的基本支持。然而,在仔细阅读规范后,我发现了一些难以处理的细节。

根据规范,一个节点由一个或多个网格组成,一个网格由一个或多个基元组成。在同一个 Node 内,每个 Primitive 可以使用不同的顶点格式,包括:

不同数量的属性(即:仅位置与位置+正常) 不同的属性排序(即:Position+Normal vs Normal+Position)。 指向结构数组的访问器与其他使用元素数组的访问器相比。

在我看来,这造成了一种情况,为了制作一个可以处理一般 GLTF 模型的强大渲染器,需要创建一堆着色器排列以用于 Primitive 可能使用的各种顶点格式。到目前为止,我想到的关于如何避免着色器排列爆炸的唯一想法如下:

使用包含所有规范定义属性的顶点格式定义着色器。解析 GLTF 文件时,对任何缺失的属性使用默认值。从文件中读取顶点数据时,如果存在属性但具有不同的数据类型,则将该数据转换为预期的类型(即:将 short 提升为 ints)。将属性重新排序为着色器所期望的。此外,当检测到一些众所周知的顶点格式时,还有一些其他专用着色器(即:如果格式为 Position+Normal+Coord0,则使用着色器 Foo)。

我尝试了上述方法的变体,但加载模型非常慢。此外,这似乎是一种脆弱的方法。

还有什么方法可以减轻对单个节点进行大量管道更改的需求?和/或需要为所有不同的情况定义许多着色器?

【问题讨论】:

从广义上讲,制作“一切渲染器”并不是一条有趣的路。当您可以对您正在做的事情施加一些基本限制时,作为 API 的 Vulkan 处于最佳状态,您施加的限制越多,您所做的一切就越高效。如果您决心找到一种方法将某些 glTF 文件提供给您的 任何内容 投射到屏幕上,那么您将不得不接受由此带来的一些后果。 【参考方案1】:

每个基元都是一个单独的绘图调用,可能带有单独的着色器程序。

请注意,图元的不同不仅仅在于顶点属性。图元包含自己的材质参考,因此它可以是与同一网格拥有的其他图元完全分开的材质。

基元的存在是为了提供一种机制来在单个网格中包含多种材质,但它们需要单独的绘制调用和单独的着色器来实现。这在Meshes Overview section 中有讨论。

【讨论】:

以上是关于处理具有多种顶点格式的 GLTF 节点的主要内容,如果未能解决你的问题,请参考以下文章

surfer如何导出三维gltf文件

具有所需顶点的有向加权图

广度优先搜索。顶点是不是可以具有具有不同父级的相邻顶点并且已被发现但未处理

Draco - glTF模型压缩利器

树的每对顶点之间的最大流量和

各种顶点格式和vbo