我正在使用OpenGL中的简单粒子系统,我需要在GPU上生成粒子.通常我将粒子表示为GL_POINTS
并且在开始时仅使用一个粒子生成点.我所做的是创建两个顶点缓冲对象(VBO)并根据最大粒子数在GPU上分配内存.然后创建两个变换反馈缓冲区(TFB),并将它们中的每一个绑定到一个VBO的输出.第一个TFB表示第二个VBO的输入,反之亦然(交换缓冲区).
然后我在几何着色器上生成新顶点(=点,粒子).
几何着色器代码:
#version 330 compatibility
#extension GL_ARB_geometry_shader4 : enable
layout(points) in;
layout(points, max_vertices = 3) out;
in block{
vec4 v_WorldPosition;
vec3 f_Position;
vec3 f_Color;
} In[];
out block{
vec4 v_WorldPosition;
vec4 v_Color;
} Out;
out feedback{
vec3 f_Position;
vec3 f_Color;
} feedOut;
const int i = 0; // No need for loop (points. In.length() == 1)
void main()
{
feedOut.f_Position = In[i].f_Position;
feedOut.f_Color = In[i].f_Color;
if(In[i].f_Color.g == 1){
feedOut.f_Color.g = 0;
}
Out.v_Color = vec4(feedOut.f_Color, 1);
gl_Position = In[i].v_WorldPosition;
EmitVertex();
EndPrimitive();
if(In[i].f_Color.g == 1){
// create new particle
feedOut.f_Position = In[i].f_Position;
feedOut.f_Color = vec3(1,0,0);
Out.v_Color = vec4(feedOut.f_Color, 1);
gl_Position = In[i].v_WorldPosition;
EmitVertex();
EndPrimitive();
}
}
}
Run Code Online (Sandbox Code Playgroud)
目前我使用绿色信息来确定粒子是否应分成两部分.根据某个计时器,此信息会在顶点着色器中定期添加.只有块feedback
存储在TBF中(从上面的代码中删除了不相关的属性变量).
这工作正常,但问题是当我发出比我的缓冲区大小更多的顶点时.我预计在这种情况下不会再创建顶点,但似乎比新创建的顶点覆盖旧顶点.
如何通过变换反馈存储额外发射的顶点?(我无法在任何规范中找到).似乎它结束的情况是第一个粒子是唯一一个稳定的粒子,所有其他粒子逐渐被推出缓冲区并被第一个粒子所产生的粒子所取代.
在最终的程序中,我希望能够从管道中删除顶点并根据一些时间变量等添加新的顶点 - 所以我没有任何指定的缓冲区数据结构.
有没有办法阻止覆盖?我需要在完全缓冲区的情况下实际创建新粒子,并且只有当从缓冲区中删除(=未发射)粒子时才能创建新粒子.这是标准行为吗?
注意:尝试使用GeForce GT 630M和GeForce GTX 260(Windows 7 x64).
我认为您首先应该做的是阅读 gl Query Objects。有一个专门针对 GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 的查询对象。根据规范:记录几何着色器流写入变换反馈对象的基元数量。
一旦你弄清楚是否有太多基元(或者在点的情况下,单个顶点,可能是颜色和位置以及调用 EndPrimitive() 之前的情况)被写入,你可以进行不同的变换反馈更新函数和相应的 glsl prog 与添加基元的函数具有相同的结构,除了这个函数只是更新您已有的或删除当前的。确保您知道每个基元(在本例中为一个点)的大小,以便您可以轻松查询您的大小,以确保您不会超出已分配的内容。另外,给每个人一个计时器也不错,这样你就可以轻松决定一生。与您在顶点着色器中执行的操作类似,看看它们是否应该分开,但不同之处在于您将在几何着色器中检查它们的生命周期,如果它们死了,则不会发出该顶点。