好吧,如果其他问答的解释不够好,让我试一试。
问题确实在于您使用的是triangle strip。三角带有多种用途,使用它的最重要的原因是为了减少存储顶点的数据量:
使用三角形条带的主要原因是减少创建一系列三角形所需的数据量。存储在内存中的顶点数量从3N减少到N+2,其中N是要绘制的三角形的数量。
(维基百科)
三角形条带通过重用先前三角形的数据来实现这一神奇的特性。它需要前一个三角形的两个顶点和一个额外的顶点,这使您可以在该组点上形成一个新三角形。如果顶点都形成一个连续的曲面,并且每个顶点作为第一个三角形和下一个三角形的一部分都有意义,则此方法非常有效。
例如对于一系列顶点:
0: (0,0)
1: (0,1)
2: (1,0)
3: (1,1)
我们最终得到
1---3
|\ |
| \ |
| \|
0---2
确实,三角形是由索引 (0,1,2) 和 (1,2,3) 组成的。
即使我们添加了纹理,它仍然有效。假设纹理有四个瓦片那么大,我们可能会得到:
0: (0,0) (0 , 0)
1: (0,1) (0 , 0.5)
2: (1,0) (0.5, 0)
3: (1,1) (0.5, 0.5)
4: (2,0) (1 , 0)
5: (2,1) (1 , 0.5)
结果:
1---3---5
|\ |\ |
| \ | \ |
| \| \|
0---2---4
要观察的关键顶点是2和3。对于顶点2,纹理坐标是(0.5, 0),同时是第2个三角形的右边缘和第3个三角形的左边缘。这个顶点自然属于它们,无论是位置还是纹理。
现在,考虑一个瓷砖地图,其中每个方块都可以是不同的瓷砖。通常,这可以通过带有方形图块的纹理图集来实现,每种类型的图块只是存储在不同的偏移量处。
因此,第一对三角形的纹理坐标可能相同,而第二对三角形的纹理坐标可能有一个偏移量,比如 (+5, +5)(假设纹理现在是 100x100,因为这样更容易阅读)。
那么现在顶点 2 和 3 会发生什么?它们不能同时使纹理坐标为 0.5 和 5。它们只是两个三角形的不同顶点,它们恰好在位置上彼此相邻,但在纹理上是完全独立的。三角带重用以前顶点的所有属性现在是障碍。
这就是爆炸开始的地方。您需要单独的三角形,而不是将几何图形绘制为三角形条带。您仍然可以在一个 drawcall 中绘制它们,但您将不得不忍受一些额外的数据重复:
-- triangle 0
0: (0,0) (0 , 0)
1: (0,1) (0 , 0.5)
2: (1,0) (0.5, 0)
-- triangle 1
3: (0,1) (0 , 0.5)
4: (1,0) (0.5, 0)
5: (1,1) (0.5, 0.5)
-- triangle 2
6: (1,0) (5 , 5)
7: (1,1) (5 , 5.5)
8: (2,0) (5.5, 5)
-- triangle 3
9: (1,1) (5 , 5.5)
10: (2,0) (5.5, 5)
11: (2,1) (5.5, 5.5)
这是原始数据,但我知道很难跟踪,所以让我们使用索引再看一遍。假设位置和之前一样 (0-5),纹理坐标是 t0 到 t3 用于第一个三角形,u0 到 u3 用于第二个三角形。现在:
0: 0 t0
1: 1 t1
2: 2 t2
3: 1 t1
4: 2 t2
5: 3 t3
6: 2 u0
7: 3 u1
8: 4 u2
9: 3 u1
10: 4 u2
11: 5 u3
呸!现在更容易发现关键的区别:2 位置与第一个三角形中的 texcoord t2 结合出现,但在第二个三角形中与位置u0 结合出现。同样,位置3 分别与t3 和u1 交互。这是因为顶点 2 是第一个三角形的第三个顶点,但第二个三角形的第一个顶点,依此类推。
就是这样!现在您只需要编写代码来生成这样的布局,随意设置您的 VBO(请记住,位置的顶点属性可能与平铺的 VBO 完全不同,以便更轻松地更新平铺内容而无需重写瓷砖本身),你就完成了。
请记住,正如我之前提到的,这仍然是在一个绘制调用中绘制的。整个 VBO 由 GPU 尽可能快地线性处理,它应该会产生非常好的性能,考虑到我们在这里处理的数据类型和内存大小,稍微高一点的内存使用可以忽略不计现在的典型 GPU。
我有几句结束语,有点像后记
- 事实上,如果您确实使用索引渲染,只会复制索引,而不是实际的顶点数据。在这里使用它是个好主意
- 请记住生成缓冲区时的缠绕顺序。由于您是以编程方式进行的,因此更改并不难,但如果您没有正确执行顺序,可能会导致一些有趣的故障。
- 将纹理索引保存在单独的缓冲区或同一缓冲区中,但不交错似乎很诱人,因为您可以在不触及最终永远不会改变的位置的情况下更新它们。这听起来很诱人,但并非没有缺点。交错格式之所以很好,正是因为它可以使数据紧密地一起使用,这意味着缓冲区提取可以非常非常有效。如果你把它们分开,你会迫使 gpu 从两个不同的内存位置流式传输,可能会导致更差的渲染性能。同样,对于简单的 2D 网格,这可能无关紧要,但请牢记这一点。