高效地向GLSL着色器传递值

4
我正在尝试为OpenGL ES 2.0编写粒子系统。每个粒子由4个顶点组成,形成小正方形,在其上绘制透明纹理。

问题是:每个粒子都有自己的属性(颜色、位置、大小),这些属性在该粒子的4个顶点中保持不变。每个顶点唯一的变化是它所处正方形的角落。

如果我要通过统一变量发送粒子的属性,我必须执行以下操作:

for(each particle) { // do maaaany times
  glUniform*(...);
  glDrawArray(...); // only draw 4 vertexes
};

这显然很低效,因为每次 glDrawArray 调用只会绘制 4 个顶点。
如果我通过属性变量发送这些属性,则必须为属性缓冲区中的每个片段填充相同的信息 4 次。
struct particle buf[n];

for(each particle) {
  struct particle p;
  p = ...; // Update particle
  buf[i+0] = buf[i+1] = buf[i+2] = buf[i+3] = p;
};

glBufferData(..., buf, ...);
// then draw everithing once afterwards...

什么是内存效率低并且看起来非常丑陋。那么这个问题的解决方案是什么?在每个顶点中更改参数的正确方法是什么?

4个回答

2
使用点精灵解决您的问题,该介绍非常明确。
您还可以将点精灵与point_size_array扩展结合使用。
...
正如Christian Rau所评论的那样,在可编程管道中使用point_size_array没有更多用处:像往常一样设置最大点大小,然后根据OpenGL生成的纹理坐标从点中心派生出片段距离,并基于其距离舍弃。粒子大小应通过额外属性发送。

1
由于他使用ES 2.0,他可以使用自定义浮点属性并将其委托给gl_PointSize,无需使用OES_point_size_array。但是对于点精灵总体而言,加1分,它们的标准应用确实是粒子系统。虽然它们存在一些问题(基于中心的裁剪),但对于小颗粒物可能可以忽略不计。 - Christian Rau
仔细查看规范后,我无法弄清如何从片段着色器内获取纹理坐标。该规范似乎假定存在固定功能管线(在OpenGL ES 2.0中不存在)。 - lvella
经过一番搜索,我找到了这个链接:http://klazuka.tumblr.com/post/249698151/point-sprites-and-opengl-es-2-0 显然,这些扩展都不再适用了,但正如@ChristianRau所说,点精灵仍然值得一试。 - lvella
1
@Ivella 从你提供的链接中看,似乎ES 2.0始终支持点精灵。就像链接中所说的那样,只需从内置的gl_PointCoord变量中获取精灵纹理坐标即可。那么问题在哪里? - Christian Rau
请注意,点精灵存在一些限制。一个点精灵只能够有那么大。而且,点的裁剪是针对点的中心进行的,因此如果粒子的中心移出屏幕,整个粒子就会消失。 - Nicol Bolas

2

GL ES在这方面没有一个好的解决方案。桌面OpenGL允许实例化和其他各种技巧,但ES就没有这些。


0

1
我猜这在 ES 中不太可能被支持。 - Christian Rau

0

通过纹理发送信息。我不确定OpenGL ES 2.0顶点着色器是否支持纹理采样,但如果支持的话,那将是最佳选择。


关于纹理访问远非免费或快速,我不确定这是否真的是最佳选择,但必须进行评估。与渲染到纹理一起,这可能使粒子更新直接在GPU上实现。 - Christian Rau
与通过uniform发送大量数据相比(特别是如果这是一个具有相当数量粒子的粒子系统),我认为这是一种更快的解决方案。 - NickLH

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