Particle system that is rigid?

Hey forums,

I spent some time searching for a solution before posting here, and I found some results, but most of the replies that say it isn’t possible are from several years ago, so I thought I would re ask the question, perhaps new functionality has emerged.

I’m looking for a way to modify a particle system to behave as if each particle has a rigid body. Ideally, each particle would be unable to occupy the same physical space. However another solution could be to make each particle prefer not to be in the same space, and therefore repel other particles in that space? Ideally I would prefer to find a solution that achieves the former.

I have tried playing around with both Noise, and force fields, but I cant quite replicate the effect I am looking for.

Any guidance would be appreciated.

That’s been possible for quite a while. Particles can collide. There is Getparticles/SetParticles. There is also a new job based system for doing it in in preview. I think some form of this has been possible since Unity has had particle systems.

Now if you want something you don’t have to do any coding for that I don’t know. Exactly how to implement depends largely on exactly what type of patterns you want to create. How many particles will determine which approaches will perform adequately, etc… You could use particle collisions, you could use boids, 3d sparse grids, following mesh geometry, and the list goes on.

Hey snacktime,

Thanks for confirming it is possible, there were many other posts I ran across claiming it wasn’t. In my scene, I can easily achieve the particles colliding with other rigid bodies in the world, by going to the collision variables, and turning on “Collide with everything”. Unfortunately “everything” doesn’t seem to include other particles from the same particle system.

I will start doing some research on boids and 3d sparse grids, since I don’t have any experience there. Perhaps this will yield a solution for me.

Well, sad to say that after another 5 hours of attempted learning, I still can’t seem to bring this together. I must just not have the experience or knowledge to see the solution.

Some places I fell apart:

  1. “You could try particle collisions”

I can script on an “onparticlecollision” method to the particle emitter, but by default, these collisions seem to look for another game object, not another particle? Don’t know how to tell it to find a particle.

  1. " You can try the new jobs functionality"
    Man, did I get lost down a rabbit hole here, I installed the new version, 2019.3.0a8 and downloaded the file examples from this post here: hmmm it wont seem to let me post the link. The forum post is titled: Particle System C# Job System support

However, after hours of work, I could not figure out a way to get all the definitions/packages working as listed in his example. Specifically “using UnityEngine.ParticleSystemJobs;” wasn’t working. And several other compile errors within the script, which I assume is a result of the above.

At this point, I am considering buying a 30 buck asset of premade “fluids”? Perhaps this will come with the functionality of two particles that do not occupy the same space?

One last ask for help, if anyone has a solution to this problem. All I need is to have the particles emitted from a particle system be unable or unwilling to occupy the same space. Colliders/rigidbodies/appliedforces , doesnt matter.

Like @snacktime said, there is Get/SetParticle, you can do anything you want.

what you want to do:
Get all the particles, apply a reverse-gravity-like “force” to them and re-Set them.
The “particles” you get you should assume some kind of uniform radius for and work by that.
I’d use an animation curve for the gravity strength falloff, it’s much easier to tweak to you desire if ye olde inverse/square/cubed/etc doesn’t cut it.

Ok, I have gone down the Get/Set route, which is the most success I have had so far :slight_smile:

I Attached a script to the particle system and tested it with a basic velocity increase and it was working nicely. Now I removed that part and just need to figure out how to tell the particles to move away from each other I think? Here is the working code:

using UnityEngine;

[RequireComponent(typeof(ParticleSystem))]
public class ParticleGetSetSmush : MonoBehaviour
{
    ParticleSystem m_System;
    ParticleSystem.Particle[] m_Particles;


    private void LateUpdate()
    {
        InitializeIfNeeded();

        // Look for active particles
        int numParticlesAlive = m_System.GetParticles(m_Particles);

        // Change the particles
        for (int i = 0; i < numParticlesAlive; i++)
        {
            //Do something to each Particle //

                            ??????

             //Do something to each Particle //
        }

        // Apply the changes
        m_System.SetParticles(m_Particles, numParticlesAlive);
    }

    void InitializeIfNeeded()
    {
        if (m_System == null)
            m_System = GetComponent<ParticleSystem>();

        if (m_Particles == null || m_Particles.Length < m_System.main.maxParticles)
            m_Particles = new ParticleSystem.Particle[m_System.main.maxParticles];
    }
}

Is anyone able to lend me a hand with the middle part? I imagine the behavior would be something like:

As SparrowsNest said above, assign a radius to each particle here?
For each particle, check if colliding with another particle
If true, apply acceleration away from the center of the other particle?
Though if a particle is touching more than one other particle, it would have to check this more than once?

You can deal with in the in many ways, you’ll want to make a temporary collection (IE another array to store the modified information as to not compromise the data while working on it)

you can see here what variables you get to mess with Unity - Scripting API: Particle

float minDist = 10.0f;
private void LateUpdate()
    {
        InitializeIfNeeded();
        // Look for active particles
        int numParticlesAlive = m_System.GetParticles(m_Particles);
        Vector3[] tmp = new Vector3[numParticlesAlive];
        float minDistSqr = minDist * minDist;
        // Change the particles
        for (int i = 0; i < numParticlesAlive; i++) {
            Vector3 cur = Vector3.zero;
            for(int j = 0; j < numParticlesAlive; j++){
                if( j == i ) //this is us, skip
                    continue;
                Vector3 dir = m_Particles[j].position - m_Particles[i].position; //get the vector from us to particle we're testing against
                if( dir.sqrMagnitude > minDistSquare) //particles too close
                    cur += dir.normalzied * (1 / dir.sqrMagnitude); //feel free to do w/e, the inverse square is just an example

            }
            tmp[i] = cur;
        }
        for (int i = 0; i < numParticlesAlive; i++) {
            m_Particle[i].velocity += tmp[i]; //can change the position directly, this should give you a repulsive force**
        }
        m_System.SetParticles(m_Particles, numParticlesAlive);
    }

*Are you sure you need LateUpdate?

**this should give some kind of repulsive force, kinda like magnetic, only w/o the attraction part.
you can check for the “assumed radius”(that you can multiply with particle.startSize inside the function loop to allow for differently size particles to interact with some regards to the size) we talked about earlier to see if they are intersecting each other and push the position manually, the example above should some-what work but is more for you to understand the idea behind, it can be done much better and much more efficiently.

or something like that…