Jump to content
  • Advertisement
Oniikuma

DX11 GPU Particle System with Indirect Drawing

Recommended Posts

Hi,

I am fairly inexperienced in DX11 and I am trying to implement a particle system that is handled purely on the GPU. To keep things simple, the particle system will have a fixed number of particles that, once dead, will be respawned at the emitter location. As such, I only have a single compute shader that updates each particle.

Based on the method outlined in 'Practical Rendering and Computation in Direct3D 11', an AppendStructuredBuffer<Particle> and a ConsumeStructuredBuffer<Particle> are bound to the compute shader, so that last frame's particles can be consumed, updated and appended, ready for the next frame.

As I want to minimise the data flowing back to the CPU, I want to make a call to DrawIndexedInstancedIndirect(), feeding the particle data directly from the compute shader to the vertex shader. In the vertex shader, the particle will be expanded to a quad billboard (I am trying to avoid the geometry shader for performance) and sent to the pixel shader for rasterization. As a side-effect, the primitive topology will be set to TRIANGLELIST.  I am using DrawIndexedInstancedIndirect() rather than DrawInstancedIndirect() as the number of particles and, by extension, the index buffer will remain fixed.

However, I am unclear on how to implement indirect draw calls and have the following questions:

- How can I pass the updated particle data from the compute shader to the vertex shader without sending the data back to the CPU? As I understand, the vertex shader cannot read from the AppendStructuredBuffer that was written to by the compute shader.

- How do I generate vertices without a vertex buffer bound to the input assembler? I know that vertices are identified with the semantic SV_VertexID, but I have no input layout bound to the input assembler.

Any help would be greatly appreciated, as I am not very confident with indirect drawing in DX11 and I cannot find any beginner-friendly resources to point me in the right direction.

Share this post


Link to post
Share on other sites
Advertisement
16 hours ago, Oniikuma said:

- How can I pass the updated particle data from the compute shader to the vertex shader without sending the data back to the CPU? As I understand, the vertex shader cannot read from the AppendStructuredBuffer that was written to by the compute shader.

Just create a SRV for the buffer, you can read it back through that. Being an append/consume buffer isn't the property of the backing buffer itself, if you look at it, you specify the append flag during the UAV creation. That means anything that makes that buffer an append buffer, is handled/stuffed in by the UAV, without that it's just a generic data buffer that behaves the way it's own creation flags dictate.

16 hours ago, Oniikuma said:

- How do I generate vertices without a vertex buffer bound to the input assembler? I know that vertices are identified with the semantic SV_VertexID, but I have no input layout bound to the input assembler.

The vertex shader can "emit" vertices, it doesn't have to read them from a vertex buffer, and if you don't read from a VB, you don't need an input layout either, you just submit a draw call with the amount of vertices you want to draw. Basically in your case you take the vertex id input that you have available, and look up the particle data through the SRV you created in the previous step, then using that data you fill out the fields of the vertex. Actual example for point sprites: https://www.slideshare.net/DevCentralAMD/vertex-shader-tricks-bill-bilodeau Slides 15-19

Share this post


Link to post
Share on other sites

Thanks for the link, @LandonJerre, it’s just what I was looking for! I made a few modifications to my particle system to exploit the fixed number of active particles. I use a single RWStructuredBuffer<Particle> to update each particle’s state each frame and an SRV to the particle buffer for the vertex shader to use once updated.

As I have a fixed index buffer and particle count, can I use DrawIndexed() (as it says in the slides) instead of DrawIndexedIndirect(), or does this require copying vertex data back to the CPU?

Share this post


Link to post
Share on other sites

With a fixed size particle buffer, you won't need any indirect draw calls, because you already know the vertex count for the call, without the GPU doing anything. Indirect draw calls enter the picture when your particle buffer only has a maximum size, but it can hold any amount of particles less than that. In that case, the simulation+emission passes determine the actual vertex count to be drawn, so you have to parameterize your draw call on the GPU, to avoid copying and inspecting the result particle buffer, and thats what indirect draw/dispatch calls are for. (Basically instead of passing the parameters to a draw/dispatch call from the CPU as a normal function call, you write those values into a small GPU buffer from a shader, and pass that buffer to the appropriate indirect call. The only practical difference between normal and indirect calls with D3D11 is the place where the "parameters" come from.)

Share this post


Link to post
Share on other sites

Thanks a lot for your advice! It's helped a great deal and I have everything working now.

 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!