1
\$\begingroup\$

I've made a fluid simulation using particles in Unity, but now it is painfully slow because all computations are done using the CPU. In order to make it faster, I need to do computations on the GPU, and I learned that I would have to use compute shaders for that.

The problem is, to make a fluid simulation, I need to make and track each particle and perform collisions on each of them on a certain time interval, and I don't understand how this could be achieved using shaders when the concept of shaders (from what I currently understand) is performing calculations on one already made mesh. Also, I'm using prebuilt physics calculations (rigidbody) in Unity, and would using shaders mean that I would not be able to use these?

How can I make this effect more efficient?

\$\endgroup\$
6
  • 1
    \$\begingroup\$ Compute shaders are used to generate meshes for particles quite regularly, and to simulate collisions, so you don't have to worry that this is impossible. You may have some extra work ahead though, capturing information about the colliders interacting with the fluid and converting it to a format the shader can use. Can you show us an example of the effect or explain what constraints it operates in (eg if the fluid is contained in a volume of a certain shape, or only needs to collide with terrain heightmap / a half dozen cubes…)? That can help simplify the problem and make it easier to answer \$\endgroup\$
    – DMGregory
    Mar 18, 2023 at 12:14
  • 1
    \$\begingroup\$ To build on the previous comment, you can create a ComputeBuffer which is an array of a structure you define (say particle position, velocity, maybe some vorticity information, etc). You can then invoke a Compute Shader against that buffer and perform [some operation] for every element in the array. It's up to you to write the code that passes enough information to the compute shader for it to be able to calculate the movement. Ideally you'd just render the results but it's possible to copy them back to the CPU (copying back is VERY slow, so not viable for every frame). \$\endgroup\$
    – Basic
    Mar 18, 2023 at 13:42
  • \$\begingroup\$ @DMGregory Thank you for the explanation :) Right now I want to make the fluid interactable with any mesh without any boundaries and I am using Unity's built in collision system for this(colliders and rigidbodies for all particles; not accurate to fluid motion but it still looks okay) I could try adding boundaries but I still want particles to collide with existing meshes. \$\endgroup\$ Mar 19, 2023 at 23:09
  • \$\begingroup\$ @Basic Thank you! I was looking for the name of the array I could use \$\endgroup\$ Mar 19, 2023 at 23:10
  • 1
    \$\begingroup\$ To interact with an arbitrary mesh, you may want to build a signed distance field representation and have your particles respond to that. This can be done GPU-side very efficiently, without needing the CPU to handle collisions. \$\endgroup\$
    – DMGregory
    Mar 19, 2023 at 23:38

1 Answer 1

1
\$\begingroup\$

Create a compute shader in Unity and write your particle update logic (e.g., position, velocity, collision detection, and response) in the shader code.

Store your particle data in StructuredBuffers or other appropriate buffer types. You will need to create a buffer for the particle positions, velocities, and any other properties you need to track in the simulation.

In your C# script, create and configure the necessary buffers to hold particle data and pass them to the compute shader using the SetBuffer method.

Dispatch the compute shader by invoking the Dispatch method in your C# script. You'll need to specify the number of threads to run in parallel, which should be configured to best match your GPU's capabilities.

After the compute shader finishes executing, retrieve the updated particle data from the buffers in your C# script.

Use the updated particle data to update the positions of your particles in the scene. You can either use the Graphics.DrawMeshInstanced method to render the particles as meshes or update the positions of ParticleSystem particles.

\$\endgroup\$
2
  • 1
    \$\begingroup\$ Wouldn't it be easier to draw the data straight from the GPU with an Indirect draw that reads the compute buffer in-place, with no read-back to CPU/C# land? \$\endgroup\$
    – DMGregory
    Mar 19, 2023 at 21:36
  • \$\begingroup\$ Thank you! I will try all three options and test their performances \$\endgroup\$ Mar 19, 2023 at 23:11

You must log in to answer this question.

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