我正在尝试制作一个粒子系统而不是纹理,四边形由片段着色器(如下图)渲染。
uniform vec3 color;
uniform float radius;
uniform float edge;
uniform vec2 position;
uniform float alpha;
void main()
{
float dist = distance(gl_FragCoord.xy, position);
float intensity = smoothstep(dist-edge, dist+edge, radius);
gl_FragColor = vec4(color, intensity*alpha);
}
每个粒子都是c ++类的一个对象,它将这个着色器和所有变量包装在一起并绘制它。我使用openFrameworks,因此对我来说隐藏了确切的openGL调用。
我已经读过,通常粒子系统是用纹理完成的,但是,我喜欢这样做,因为这样我可以为粒子添加更多功能。问题是只有30个粒子后,帧率急剧下降。有更有效的方法吗?我想的可能是将每个粒子的变量放入一个数组中,并将这些数组发送到一个片段着色器中,然后将所有粒子一次性渲染。但这意味着粒子的数量会被修复,因为着色器中的统一数组必须事先声明。
基于非纹理的粒子系统是否过于低效而不实际,或者是否有一种设计方法可以让我忽略?
答案 0 :(得分:2)
使用纹理的原因是因为您可以使用GPU移动粒子,这非常快。你可以对一个纹理进行双重缓冲,该纹理存储每个纹素的粒子属性(如位置),以及它们之间的乒乓数据,使用帧缓冲对象绘制它们,片段着色器进行计算,渲染全屏多边形。然后你绘制一个四边形阵列并读取纹理以获得位置。
您可以将它们直接打包到VBO数据中,而不是纹理存储属性。这变得复杂,因为每个粒子有多个顶点,但仍可以通过多种方式完成。我会想到glVertexBindingDivisor
(requires instancing),绘制points或使用几何着色器。转换反馈或image_load_store可用于使用GPU而不是纹理更新VBO。
如果使用CPU移动粒子,则还需要每帧将数据复制到GPU。这很慢,但没有像30粒子这样的问题变慢。这可能与绘制调用次数有关。每次你画一些东西时,GL都会做一些东西来设置操作。出于同样的原因,设置每个基元的均匀值(几乎)是非常昂贵的。如果您拥有一个由管理器同时处理的数据数组,则粒子可以正常工作。在这种情况下,它们非常平行。一般来说,他们的计算很便宜,而且都归结为最小化记忆和保持良好的地方性。
如果你想保持粒子更新CPU方面,我应该这样做:
glTexImage1D
/ glBufferData
/ { {1}})。glMapBuffer
/ glTexSubImage1D
/ glBufferSubData
。绘制粒子时,从纹理中读取位置和其他属性(如果使用VBO,则读取属性),并使用主几何体VBO中的-1到1个四边形作为偏移位置。