Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Help  Detect specific rope collision.
#1
Good morning,

I was wondering If it's possible to detect which rope has received a collision when having multiple ropes in an Obi Solver.
Right now I use the OnCollision event from the ObiSolver but I don't find a way to detect which specific rope is receiving the collision.

Regards!
Reply
#2
Hi there! see:
http://obi.virtualmethodstudio.com/tutor...sions.html


Quote:You can get a reference to the ObiActor (ObiCloth,ObiRope,ObiEmitter...) involved in any contact by doing:

ObiSolver.ParticleInActor pa = solver.particleToActor[contact.particle];

From ParticleInActor you can get a reference to the actor, as well as the index of the particle in that actor.
Reply
#3
(05-10-2020, 08:47 AM)josemendez Wrote: Hi there! see:
http://obi.virtualmethodstudio.com/tutor...sions.html



From ParticleInActor you can get a reference to the actor, as well as the index of the particle in that actor.

Thanks, that allowed me to fix my issue!
Reply
#4
Hi again Jose!
I'm trying to detect if NO collision between different ropes happens at the Update, but don't understand how to do it..
Look, here's a short script (actually it is slightly changed CollisionHandler from obi samples):

Code:
public class RopeCollision : MonoBehaviour {

    ObiSolver solver;
    
    Obi.ObiSolver.ObiCollisionEventArgs frame;

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

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

    void OnDisable(){
        solver.OnParticleCollision -= Solver_OnCollision;
    }
    
    void Solver_OnCollision (object sender, Obi.ObiSolver.ObiCollisionEventArgs e)
    {
        foreach (Oni.Contact contact in e.contacts)
        {
            // this one is an actual collision:
            if (contact.distance < 0.01)
            {
                ObiSolver.ParticleInActor pa = solver.particleToActor[contact.particle];
                ObiSolver.ParticleInActor po = solver.particleToActor[contact.other];
                if (pa.actor.gameObject != po.actor.gameObject)
                {
                    Debug.Log("rope collides: " + pa.actor.blueprint.name + " " + po.actor.blueprint.name, pa.actor.gameObject);
                }
            }
        }
    }
It works nice and triggers when ropes collides. But how to detect when they don't?
Reply
#5
(09-11-2020, 09:53 PM)Elegar Wrote: Hi again Jose!
I'm trying to detect if NO collision between different ropes happens at the Update, but don't understand how to do it..
Look, here's a short script (actually it is slightly changed CollisionHandler from obi samples):

Code:
public class RopeCollision : MonoBehaviour {

ObiSolver solver;

Obi.ObiSolver.ObiCollisionEventArgs frame;

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

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

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

void Solver_OnCollision (object sender, Obi.ObiSolver.ObiCollisionEventArgs e)
{
foreach (Oni.Contact contact in e.contacts)
{
// this one is an actual collision:
if (contact.distance < 0.01)
{
ObiSolver.ParticleInActor pa = solver.particleToActor[contact.particle];
ObiSolver.ParticleInActor po = solver.particleToActor[contact.other];
if (pa.actor.gameObject != po.actor.gameObject)
{
Debug.Log("rope collides: " + pa.actor.blueprint.name + " " + po.actor.blueprint.name, pa.actor.gameObject);
}
}
}
}
It works nice and triggers when ropes collides. But how to detect when they don't?

The collision callback gives you a list of all contacts every frame. So you know an actor isn't colliding, when you can't find a contact for that actor. Simple as that Sonrisa.

Just keep track of which actors appear in the contact list, and at the end of the callback (right after the foreach(contacts)), any actor that hasn't appeared isn't colliding with anything.
Reply
#6
(10-11-2020, 09:37 AM)josemendez Wrote: The collision callback gives you a list of all contacts every frame. So you know an actor isn't colliding, when you can't find a contact for that actor. Simple as that Sonrisa.

Just keep track of which actors appear in the contact list, and at the end of the callback (right after the foreach(contacts)), any actor that hasn't appeared isn't colliding with anything.
Ah, really simple Sonrisa I thought that collision callback triggers on every collision, that confused me. Now everything works, thank you!
Reply
#7
(11-11-2020, 12:16 PM)Elegar Wrote: Ah, really simple Sonrisa 

Glad you got it working  Interesante .

(11-11-2020, 12:16 PM)Elegar Wrote: I thought that collision callback triggers on every collision, that confused me.
That's what Unity does, but with as many particles/contacts as we typically deal with, a callback for each contact wouldn't be very performant. For this reason we simply give access to the full contact list in raw form.
Reply
#8
I am trying to do the same thing for my game. I have an Obi Solver and it has around 20-25 ropes as childs. I attached the script to the obi solver and asked for a collider reference. However, those references are only the Unity objects like cubes and spheres. I have 4 ropes that are colliding with each other but they are not referenced in those reference list and when I attach the game object, I experience a major FPS drop although the substep is 2 and the time settings like fixed timestep are at the default references. I am probably missing a point here but how can I get around using it? Just like in the original OnCollision and OnTrigger callbacks, I would like to receive a reference when a rope is collided with another rope and I want to adress to the rope that is colliding with the other ones. Self collisions are open and the constraint iterations are 5 at most with 1 relaxation. What am I missing here?

The script is attached to the obi solver parent object. I tried to attach the script to the ropes and made a few adjustments on the code but in both cases, the same outcome occured for me.
Reply
#9
(19-11-2020, 02:03 PM)canerozdemir Wrote: I am trying to do the same thing for my game. I have an Obi Solver and it has around 20-25 ropes as childs. I attached the script to the obi solver and asked for a collider reference. However, those references are only the Unity objects like cubes and spheres. I have 4 ropes that are colliding with each other but they are not referenced in those reference list and when I attach the game object, I experience a major FPS drop although the substep is 2 and the time settings like fixed timestep are at the default references. I am probably missing a point here but how can I get around using it? Just like in the original OnCollision and OnTrigger callbacks, I would like to receive a reference when a rope is collided with another rope and I want to adress to the rope that is colliding with the other ones. Self collisions are open and the constraint iterations are 5 at most with 1 relaxation. What am I missing here?

For particle-particle collisions, you should use OnParticleCollision event ,instead of the OnCollision event as explained in the docs:
http://obi.virtualmethodstudio.com/tutor...sions.html

Quote:To request the particle-collider contact list from the solver, subscribe to its OnCollision event. To retrieve the particle-particle contact list, subscribe to its OnParticleCollision event.
Reply
#10
(19-11-2020, 02:14 PM)josemendez Wrote: For particle-particle collisions, you should use OnParticleCollision event ,instead of the OnCollision event as explained in the docs:
http://obi.virtualmethodstudio.com/tutor...sions.html

Oh, I missed that one. However, the outcome is still the same. FPS drop happens and the game becomes unplayable. This is the code: 


Code:
public class RopeCollision : MonoBehaviour
{
    private ObiSolver _solver;

    private ObiSolver.ObiCollisionEventArgs _collisionEvent;

    private void Awake()
    {
        _solver = GetComponent<ObiSolver>();
    }

    private void OnEnable ()
    {
        _solver.OnParticleCollision += Solver_OnParticleCollision;
    }

    private void OnDisable()
    {
        _solver.OnParticleCollision -= Solver_OnParticleCollision;
    }

    private void Solver_OnParticleCollision (object sender, ObiSolver.ObiCollisionEventArgs e)
    {
        var world = ObiColliderWorld.GetInstance();
        foreach (var contact in e.contacts)
        {
            // this one is an actual collision:
            if (contact.distance < 0.01)
            {
                var theCollider = world.colliderHandles[contact.other].owner;
                if (theCollider)
                {
                    print(theCollider.name);
                }
            }
        }
    }
}
Reply