Million Particle System

Started by
24 comments, last by neroziros 10 years ago

Hi there!

My current particle system its based on the example: http://content.gpwiki.org/index.php/D3DBook:Dynamic_Particle_Systems

However I have one remaining doubt. During the development I noticed that the particles emission rate its capped at 128 per frame due the memory limits of the geometry stream output. However, I would like to implement a particle system able to handle millions of particles at the same time. This is possible with the current particle system, but I need to wait 130 seconds to reach the millions (using particles with 130 sec lifetime), which is not very optimal.

I was wondering if any of you knows a way to achieve this using the GPU.

Cheers,

José

Advertisement

I don't see any reference that you are pointing to, but can't you just execute the particle injection draw call more than once per frame?

I don't see any reference that you are pointing to, but can't you just execute the particle injection draw call more than once per frame?

Sorry about that, just updated the post.

The problem its that the particle injection happens inside the geometry shader, so it has a limit of 1024b per emission (that its equal to 128 particles since each one have 8 components)

Cheers

Erm, I happen to be the author of that article :)

Like I mentioned above, just execute the injection shader more than once per frame. Is there some limitation on doing that?

Oh nice now I get what you mean. But in order to do that, wouldn't I need need to separate the Update logic of the particles from the Particle Emission? otherwise the particles will move too fast since I would be executing their update a lot of times per frame.

Thanks for the help and awesome article smile.png

PS: I tried to transfer the particle creation to the CPU using a 3rd buffer which appends the new particles to the streamOutput, however right now it doesn't work and I am not quite sure why. If anyone can check it out I would be more than grateful.

FX Code: https://github.com/neroziros/PSDX11/blob/master/ParticleEffect.fx

Class: https://github.com/neroziros/PSDX11/blob/master/Particleclass.cpp

I believe the main problem its here, in the mapping procedure:

Class: https://github.com/neroziros/PSDX11/blob/master/Particleclass.cpp

I hope my code can also help anyone else interested in building a million particle system based on the GPU :) Cheers


    // CPU PARTICLE CREATION
    // Add new particles if they were created
    if (!newParticlesCreated)
    {
        // Map to the buffer and render the new particles to add them to the pipeline
        D3D11_MAPPED_SUBRESOURCE mappedResource;
        PARTICLE_VERTEX* dataPtr;


        m_D3D->GetDeviceContext()->Map(g_pNewParticles, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
        dataPtr = (PARTICLE_VERTEX*)mappedResource.pData;


        // Copy the data into the vertex buffer.
        memcpy(dataPtr, (void*)newParticlesArr, (sizeof(PARTICLE_VERTEX)* emissionRate));


        // Unmap the buffer
        m_D3D->GetDeviceContext()->Unmap(g_pNewParticles, 0);


        // Set the buffer as the input
        pBuffers[0] = g_pNewParticles;
        UINT stride[1] = { sizeof(PARTICLE_VERTEX) };
        UINT offset[1] = { 0 };
        m_D3D->GetDeviceContext()->IASetVertexBuffers(0, 1, pBuffers, stride, offset);
        m_D3D->GetDeviceContext()->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST);


        // Point to the correct output buffer
        pBuffers[0] = g_pParticleStreamTo;
        m_D3D->GetDeviceContext()->SOSetTargets(1, pBuffers, offset);


        // Draw the buffers
        D3DX11_TECHNIQUE_DESC techDesc;
        g_pAdvanceParticles->GetDesc(&techDesc);
        for (UINT p = 0; p < techDesc.Passes; ++p)
        {
            g_pAdvanceParticles->GetPassByIndex(p)->Apply(0, m_D3D->GetDeviceContext());
            m_D3D->GetDeviceContext()->DrawAuto();
        }


        // Get back to normal
        pBuffers[0] = NULL;
        m_D3D->GetDeviceContext()->SOSetTargets(1, pBuffers, offset);


        // Free the particle array memory
        delete (newParticlesArr);


        // Reset variables
        newParticlesCreated = false;
    }

Hi there, I managed to do as suggested and separated the emission logic from the update logic. Feel free to check the code here:

https://github.com/neroziros/PARTICLESYSTEM/

Now the problem its that I can only reach around 460800 particles before the fps start to drop too low (around 25-35 fps). I have a Phenom II X6 & NVIDIA 560GTX.

This is probably an optimization problem, any suggestion its welcomed.

Cheers!

Are you pursuing this technique because you're stuck on DX10-era hardware? Because this sort of thing can be done more efficiently using compute shaders.

And just to bring up an important point; I don't think you REALLY want to spawn 1,000,000 particles from one emitter in one frame... if nothing else it'll be bloody slow to do and you can do a lot with surprisingly few particles per emitter.

However if you DO want to do this, because you want an effect which has a lot of particles, then I suggest creating them at load time either on the CPU or via a one off GPU task instead of trying to spawn them like normal particles.

(As to why you don't want 1,000,000 particles consider this; a 1920*1200 screen only has 2,304,00 pixel on it so at 1million particles each one would be filling a little over 2 pixels on average. )
@phantom: hmm I hadnt considered that. Though I am ok with just one million particles per simulation, no need for the 60.000.000 particles per second :P

@mjp: actually I must use DX11 ( I plan on using tesselation later for better particle lighting ). I thought that the compute shader performance was similar to the geometry shader's one. But if I am wrong I will gladly check that option

Thanka for the advice! Will read about compute shaders then :)

This topic is closed to new replies.

Advertisement