Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Fluid Counter
#1
Hi Sonrisa

i am trying to find out the number of particles of water passing through a collider. 

Emitter produces 400 particulate water. Even if the collider touches all of them, the count remains around 200. 

http://obi.virtualmethodstudio.com/manua...sions.html   I looked here but I don't understand Triste 

https://imgur.com/a/if0G3bu
PHP Code:
   ObiSolver solver;
     [SerializeFieldint counter 0;

     void Awake()
     {
         solver GetComponent<ObiSolver>();
     }

     void OnEnable()
     {
         solver.OnCollision += Solver_OnCollision;
     }

     void OnDisable()
     {
         solver.OnCollision -= Solver_OnCollision;
     }

     void Solver_OnCollision(object senderObi.ObiSolver.ObiCollisionEventArgs e)
     {
         var world ObiColliderWorld.GetInstance();

         // just iterate over all contacts in the current frame:
         foreach (Oni.Contact contact in e.contacts)
         {
             // if this one is an actual collision:
             if (contact.distance 0.01)
             {
                 ObiColliderBase col world.colliderHandles[contact.bodyB].owner;
                 if (col != null && col.gameObject.layer == 7)
                 {
                     // do something with the collider.
                     counter=solver.contactCount;

                 }
             }
         }

     
Reply
#2
Hi!

Your code doesn't make much sense: it iterates trough all contacts, and for all contacts against a collider in layer 7 (which I assume is the white cube in your image) it sets counter = solver.contactCount. So all your code is equivalent to just:

Code:
counter = solver.contactCount

Which is the current amount of contacts in the solver, not the amount of particles that have ever been in touch with the white cube.

Probably what you want is to just count the contacts, by increasing the counter by one each time you find a contact between a particle and the collider:
Code:
void Solver_OnCollision(object sender, Obi.ObiSolver.ObiCollisionEventArgs e)
     {
         var world = ObiColliderWorld.GetInstance();

         // just iterate over all contacts in the current frame:
         foreach (Oni.Contact contact in e.contacts)
         {
             // if this one is an actual collision:
             if (contact.distance < 0.01)
             {
                 ObiColliderBase col = world.colliderHandles[contact.bodyB].owner;
                 if (col != null && col.gameObject.layer == 7)
                 {
                     counter++;
                 }
             }
         }

}

Note this will only work if particles are in contact against the cube for a single frame, which is a rather restrictive assumption. You probably want to store particle indices in a hash set, to determine if a specific particle has already been counted and in that case, ignore it.
Reply
#3
(05-09-2022, 01:40 PM)josemendez Wrote: Hi!

Your code doesn't make much sense: it iterates trough all contacts, and for all contacts against a collider in layer 7 (which I assume is the white cube in your image) it sets counter = solver.contactCount. So all your code is equivalent to just:

Code:
counter = solver.contactCount

Code:
void Solver_OnCollision(object sender, Obi.ObiSolver.ObiCollisionEventArgs e)
     {
         var world = ObiColliderWorld.GetInstance();

         // just iterate over all contacts in the current frame:
         foreach (Oni.Contact contact in e.contacts)
         {
             // if this one is an actual collision:
             if (contact.distance < 0.01)
             {
                 ObiColliderBase col = world.colliderHandles[contact.bodyB].owner;
                 if (col != null && col.gameObject.layer == 7)
                 {
                     counter++;
                 }
             }
         }

}
I was doing silly experiments Sonrisa I added the wrong code I added the wrong code.  Sorry Triste 
counter runs but returns a number greater than 400 particles
Reply
#4
(05-09-2022, 01:49 PM)0hsyn1 Wrote: I was doing silly experiments Sonrisa I added the wrong code I added the wrong code.  Sorry Triste 
counter runs but returns a number greater than 400 particles

Yes, as I explained this will add one to the counter every frame a particle is in contact with the collider. So unless particles are only in contact for one frame (which is highly unlikely), it will return a number far greater than 400.

What you want is to determine if a particle has already been counted and if so, ignore it. There's many ways to do this, easiest is to use a hash set. See:
http://obi.virtualmethodstudio.com/forum...=collision
Reply
#5
(05-09-2022, 01:51 PM)josemendez Wrote: Yes, as I explained this will add one to the counter every frame a particle is in contact with the collider. So unless particles are only in contact for one frame (which is highly unlikely), it will return a number far greater than 400.

What you want is to determine if a particle has already been counted and if so, ignore it. There's many ways to do this, easiest is to use a hash set. See:
http://obi.virtualmethodstudio.com/forum...=collision

Yes, I found the post you shared while doing research.
"idToCollider" "particle"  syntaxes appear as console errors.
Reply
#6
(05-09-2022, 01:58 PM)0hsyn1 Wrote: Yes, I found the post you shared while doing research.
"idToCollider" "particle"  syntaxes appear as console errors.

That code was written for Obi 3.5, idToParticle no longer exists. In >3.5 you get the collider like you were already doing in your original code:
Code:
ObiColliderBase col = world.colliderHandles[contact.bodyB].owner;

However the idea of the code is still perfectly valid: use a hash set to determine which particles have already been counted.

I've modified your code to work properly:

Code:
[RequireComponent(typeof(ObiSolver))]
public class CollisionCounter : MonoBehaviour {

    ObiSolver solver;
    [SerializeField] int counter = 0;

    HashSet<int> particles = new HashSet<int>();

    void Awake(){
        solver = GetComponent<Obi.ObiSolver>();
    }

    void OnEnable () {
        solver.OnCollision += Solver_OnCollision;
    }

    void OnDisable(){
        solver.OnCollision -= Solver_OnCollision;
    }
   
    void Solver_OnCollision (object sender, Obi.ObiSolver.ObiCollisionEventArgs e)
    {
        HashSet<int> currentParticles = new HashSet<int>();

        var world = ObiColliderWorld.GetInstance();

        // just iterate over all contacts in the current frame:
        foreach (Oni.Contact contact in e.contacts)
        {
            // if this one is an actual collision:
            if (contact.distance < 0.01)
            {
                ObiColliderBase col = world.colliderHandles[contact.bodyB].owner;
                if (col != null && col.gameObject.layer == 7)
                {
                    currentParticles.Add(contact.bodyA);
                }
            }
        }

        particles.ExceptWith(currentParticles);
        counter += particles.Count;
        particles = currentParticles;
    }

}
Reply
#7
(05-09-2022, 02:06 PM)josemendez Wrote: That code was written for Obi 3.5, idToParticle no longer exists. You get the collider like you were already doing in your original code:
Code:
ObiColliderBase col = world.colliderHandles[contact.bodyB].owner;

However the idea of the code is still perfectly valid: use a hash set to determine which particles have already been counted.

I've modified your code to work properly:

Code:
[RequireComponent(typeof(ObiSolver))]
public class CollisionCounter : MonoBehaviour {

    ObiSolver solver;
    [SerializeField] int counter = 0;

    HashSet<int> particles = new HashSet<int>();

    void Awake(){
        solver = GetComponent<Obi.ObiSolver>();
    }

    void OnEnable () {
        solver.OnCollision += Solver_OnCollision;
    }

    void OnDisable(){
        solver.OnCollision -= Solver_OnCollision;
    }
   
    void Solver_OnCollision (object sender, Obi.ObiSolver.ObiCollisionEventArgs e)
    {
        HashSet<int> currentParticles = new HashSet<int>();

        var world = ObiColliderWorld.GetInstance();

        // just iterate over all contacts in the current frame:
        foreach (Oni.Contact contact in e.contacts)
        {
            // if this one is an actual collision:
            if (contact.distance < 0.01)
            {
                ObiColliderBase col = world.colliderHandles[contact.bodyB].owner;
                if (col != null && col.gameObject.layer == 7)
                {
                    currentParticles.Add(contact.bodyA);
                }
            }
        }

        particles.ExceptWith(currentParticles);
        counter += particles.Count;
        particles = currentParticles;
    }

}

works perfectly, thank you very much Sonrisa
Reply