5

如何渲染网格(由三角形组成),其中每个三角形具有相同的颜色,而无需在顶点数组中为每个三角形指定该颜色 3 次。

假设我要绘制 2 个三角形。三角形 1:

Vertex 1,  position:(x1,y1) , color: (r1,g1,b1,a1)
Vertex 2,  position:(x2,y2) , color: (r1,g1,b1,a1)
Vertex 3,  position:(x3,y3) , color: (r1,g1,b1,a1)

三角形 2:

Vertex 4,  position:(x4,y4) , color: (r2,g2,b2,a2)
Vertex 5,  position:(x5,y5) , color: (r2,g2,b2,a2)
Vertex 6,  position:(x6,y6) , color: (r2,g2,b2,a2)

我知道这可以通过创建 2 个顶点缓冲区来完成:

Vertex Buffer 1:
[x1, y1]
[x2, y2]
[x3, y3]
[x4, y4]
[x5, y5]
[x6, y6]


Vertex Buffer 2:
[r1, g1, b1, a1]
[r1, g1, b1, a1]
[r1, g1, b1, a1]
[r2, g2, b2, a2]
[r2, g2, b2, a2]
[r2, g2, b2, a2]

我现在可以将它们绑定到不同的属性位置并执行通常的绘图调用。

顶点缓冲区 1 很好,因为所有数据都是唯一的,但我的问题是,顶点缓冲区 2 不是这样浪费空间吗!?如果我有数千个三角形,并且使用这种方法,我会为每个三角形复制两次颜色。必须有一种更智能的方式来存储冗余属性。我不知道。有人可以告诉吗?

4

2 回答 2

1

(警告:以下解决方案可能不值得麻烦,因为它不是固定的功能管道。请通知我此答案中的任何错误/错误信息。)

据我所知,在 OpenGL 中,任何顶点都必须知道它直接使用的每个顶点或间接使用的数据。您可以说:“下一次绘制调用中的所有顶点都使用此数据”,或者您可以使用索引将每个顶点与其对应的数据打包在一个或多个缓冲区中(就像您所做的那样)。因为只能有一组索引,所以只能将一个顶点链接到一种颜色,因此每个顶点都需要一种新颜色,即使它们相同。这意味着无论如何,如果您想在一次绘制调用中执行这些类型的事情,您将拥有重复的数据。

但是,您可以通过在着色器中引用带有索引的颜色来减小此重复数据的大小。这样,您可以(例如)在网格中拥有 256 种不同的颜色,并且每个顶点只有 1 个字节的颜色索引(或 256*256 种颜色和 1 个短索引等)。对于这样一个“简单”的问题,这是一个令人厌烦的解决方案,但我一直在寻找它是唯一的解决方案。

这个想法是这样的:

  1. 创建一个包含您需要的所有颜色的缓冲区。

  2. 创建一个具有顶点属性的网格,将顶点链接到正确的颜色,并使用索引。

  3. 创建一个接受属性的顶点着色器,查看缓冲区内部,检索颜色并将其传递给片段着色器,然后片段着色器根据此颜色更改其输出。

您仍然会有重复的数据,但每个三角形将是 2 个字节,而不是两种颜色(即 2*(4*)4 个字节)。此解决方案假定您的网格中有固定的少量不同颜色,这很可能是这种情况。此解决方案最适合小索引引用的大块数据。

对我来说,这个解决方案确实非常丑陋和低效,但在我有限的 OGL 经验中,它是我为您提供的唯一解决方案。我想听听有人有更好的解决方案,因为我正在处理类似的问题!

PS:请记住,顶点数据喜欢是二次方的大小,如果您可以使用它来避免填充无用数据,您可能只需要此解决方案。

于 2013-07-09T18:50:55.643 回答
1

这种闻起来像是过早的优化。

在内存消耗方面保持批判性当然很好,但在大多数情况下,您的纹理数据将使用几何图形更多的内存(请记住 FBO/Renderbuffers!)。在这里和那里削减几个字节很快就会成为一项非常昂贵的改进,性能可能会更差。也许您最终还是要填充顶点数据以进行对齐?

就像在另一个答案中提到的那样,您可以通过以下方式做到这一点:

  • 创建调色板
  • 将颜色/调色板索引存储在顶点数组中
  • 通过纹理或 UBO 发送调色板

如果您想支持顶点颜色,请使其简单并完全支持它。您似乎在这里针对特殊情况进行了优化。如果您突然想使用一个具有平滑顶点绘制的模型,将调色板大小增加到数千个条目怎么办?

保持简单并使用详细格式。如果需要,稍后针对特殊情况进行优化。

就我个人而言,如果调色板的目的不是减少数据大小,我只会这样做。也许您想动态更改颜色数据?在这种情况下,使用 256 个整体(纹理或 UBO)更新一维数组很方便。

如果您使用实例化(一次绘制调用多次绘制模型),您当然可以通过定义属性除数来定义每个实例的唯一值。(在此示例中可能无效)

于 2013-07-10T02:05:46.837 回答