4
\$\begingroup\$

I've implemented a simple particle system where each particle has a position, velocity, age and lifespan stored in different SSBOs.

Most of the data including all the position, velocity and age is updated through a compute shader. And emiting new particles is handled by CPU since it's a serial process. But in order to track whether each particle is alive or dead, I have to read all the lifespan data back to CPU from the SSBO (using glGetBufferSubData()), which do stalls the GPU I'm afraid.

So I was wondering is there any way to prevent reading the data back from GPU. I found a demo particle system made by AMD using directX, which uses a dead list and an alive list in the compute shader. But I have no idea how to achieve this with GLSL. Any ideas?

Demo code:

...

// The dead list, so any particles that are retired this frame can be added to this list
AppendStructuredBuffer<uint>            g_DeadListToAddTo       : register( u2 );

// The alive list which gets built using this shader
RWStructuredBuffer<float2>              g_IndexBuffer           : register( u3 );

...

// Dead particles are added to the dead list for recycling
if ( pb.m_Age <= 0.0f || killParticle )
{
    pb.m_Age = -1;
    g_DeadListToAddTo.Append( id.x );
}

...
\$\endgroup\$
8
  • \$\begingroup\$ I haven't used compute's yet, but this seems like a CPU-side issue where you need to remove elements from a list that's being iterated. In those cases, you add the "dead" objects into another list and then iterate the "recycling" list, afterwards. Is it possible to use a second computer shader to "iterate" the "dead list", if any, reinitialize the particles on the GPU, and feed them back in, as usual, next frame? Kind of a GPU ping-pong... \$\endgroup\$
    – Jon
    Commented Apr 11, 2015 at 16:04
  • \$\begingroup\$ Second compute would output all "alive" particles, then append any revived particles. \$\endgroup\$
    – Jon
    Commented Apr 11, 2015 at 16:07
  • \$\begingroup\$ @Jon So is there any dynamic data structure in glsl that is similiar to the "AppendStructuredBuffer" or "RWStructuredBuffer" in DirectX? \$\endgroup\$
    – Oscar
    Commented Apr 12, 2015 at 2:59
  • \$\begingroup\$ I'm one of those DirectX people, sorry... I managed to find this but it makes very little sense to me. They are using the geometry shader to emit/kill and don't mention compute shaders at all. \$\endgroup\$
    – Jon
    Commented Apr 12, 2015 at 3:56
  • \$\begingroup\$ The various "XXTransformFeedback" methods appear to have everything to do with routing outputs to inputs. However, if the geometry shader fails to output "dead" particles in the first place, the compute shader would only receive live particles and have nothing to do but chug velocities. \$\endgroup\$
    – Jon
    Commented Apr 12, 2015 at 4:04

1 Answer 1

2
\$\begingroup\$

If the only way your particles die is through age, then there's no need to read the data back from the OpenGL buffers at all. Keep a CPU side buffer that tracks the current age for each particle (or equivalently, remembers the time at which they will die), then your CPU can scan through that list quickly every frame to find particles which need to be re-born. Then you can update just their portion of the GPU buffer.

I would also look into glMapBuffer() (glMapBufferOES() on OpenGL ES 2.0) for updating the GPU buffer, as I've found they have better performance (not stalling the GPU).

Alternatively you might consider checking for particle death within the shader itself. Depending on the complexity of your particle spawn process this may not be practical but if you're just emitting particles from a point source, for example, you could pass this position in as a shader parameter and then your shader could detect old particles and restart them at the emitter position.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .