我正在使用OpenGL中的简单粒子系统,我需要在GPU上生成粒子.通常我将粒子作为GL_POINTS表示,并且在开始时仅使用一个粒子发生器点.
我做的是创建两个顶点缓冲区对象(VBO),并根据最大粒子数量在GPU上分配内存.然后创建两个变换反馈缓冲区(TFB),并且每个都绑定到一个VBO的输出.第一个TFB代表第二个VBO的输入,反之亦然(缓冲区被交换).
我做的是创建两个顶点缓冲区对象(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); Out.v_Color = vec4(FeedOut.f_Color,1); gl_Position = In[i].v_WorldPosition; EmitVertex(); EndPrimitive(); } } }
目前我使用绿色信息来确定粒子是否应该分为两部分.根据某些定时器,这些信息会在顶点着色器中定期添加.只有阻止反馈存储在TBF(从上面的代码中删除的不相关的属性变量).
这工作正常,但问题是当我发出比我的缓冲区大小更多的顶点.我预计在这种情况下不会创建更多的顶点,但似乎不是新创建的顶点覆盖旧的顶点.
通过变换反馈存储额外的发射顶点? (我没有找到任何规格).似乎它的结束是第一颗粒是唯一稳定的颗粒,并且所有其它颗粒逐渐被推出缓冲液并被由第一颗粒所产生的颗粒代替).
在最终的程序中,我想要从管道中删除顶点,并根据一些时间变量等添加新的顶点,所以我没有任何指定的缓冲区数据结构.
有没有办法防止超控?我需要在完全缓冲区的情况下实际创建新的粒子,只有当缓冲区中的粒子被删除(=不发出)时,才能创建新的粒子.这是标准行为吗?
注意:
在GeForce GT 630M和GeForce GTX 260(Windows 7 x64)上进行了试用.
解决方法
我认为你应该首先做的是关于gl
Query Objects.有一个查询对象GL_TRANSFORM_FeedBACK_PRIMITIVES_WRITTEN.从规范:记录由几何着色器流写入变换反馈对象的图元数.
一旦你知道是否有太多的原语(或者在一个点的情况下,一个单一的顶点,可能是颜色和位置,直到调用EndPrimitive()),你可以做一个不同的转换反馈更新功能和相应的glsl prog,其结构与添加原语相同的结构只是更新您已经拥有或删除当前的原语.确保你知道每个基元的大小(在这种情况下是一个点),以便您可以轻松地查询大小,以确保不会超过您分配的内容.此外,给每个定时器这样一个简单的方法就可以很容易地决定一个生命周期是不错的.类似于您在顶点着色器中做什么,看看它们是否应该分开但不同,您将在几何着色器中检查其生命,并且如果它们已经死亡,则不会发出该顶点.