Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Help  Particle Collision Not Working On Instantiated Rope
#1
Hi, 

When I instantiate a prefab consisting of ropes (that then get reparented to ObiSolver object in OnEnable), the OnCollision seems to not catch any collision events with the targeted particle (beginning of rope) but when the prefab is already in the scene, OnCollision is detecting collision events with that particle. Its only with that particle, it seems to throw events with other particles along that rope when instantiated.

It working, this is with the prefab placed in the scene from the start:
[Image: giphy.gif?cid=790b7611ce3aac377c22c6242e...y.gif&ct=g]

When the prefab is instantiated, no collisions events detected from that particle:
[Image: giphy.gif?cid=790b76112f9596c9ab90c9faef...y.gif&ct=g]

OnCollision:
Code:
// Just iterate over all contacts in the current frame
foreach (Oni.Contact contact in handCollision.contacts)
{
    // This one is an actual collision
    if (contact.distance > 0.01) return;

    // Get the particle index directly, as all simplices are guaranteed to have size 1:
    int particleIndex = hand.Solver.simplices[contact.bodyA];

    // This is not the particle you are looking for - Obi Wan
    if (particleIndex != hand.SolverIndex) return;

    // Retrieve collider
    ObiColliderBase collider = ObiColliderWorld.GetInstance().colliderHandles[contact.bodyB].owner;

    // Attach hand and collider
    hand.Grab(collider.transform);
}

Getting the start particle:
Code:
_arm.elements[0].particle1;

The particle is still accurate to the solver indices because I am still able to add force to that specific particle. However, it is not being detected by OnCollision.
Reply
#2
Hi!

The contact list passed to OnCollision is the exact same one used internally by the engine to perform the actual simulation. What I mean by this is that if the particle exists in the scene and is colliding with stuff, then it must appear in the contact list. Internal collisions and collision callbacks aren't two separate systems.

How are you determining hand.SolverIndex? Is it _arm.elements[0].particle1? if so, note that this value is only available when the rope is already instantiated.

I assume you're doing something along the lines of hand.SolverIndex = _arm.elements[0].particle1 this at Start(), Awake(), OnEnable() or a similar event, so it may or may not return a correct value depending on the order in which game objects are instantiated, which as you know if undefined in Unity.

If my assumption is correct, you might want to wait for one frame after instantiating the rope to get the value of hand.SolverIndex.
Reply
#3
(18-03-2022, 08:21 AM)josemendez Wrote: Hi!

The contact list passed to OnCollision is the exact same one used internally by the engine to perform the actual simulation. What I mean by this is that if the particle exists in the scene and is colliding with stuff, then it must appear in the contact list. Internal collisions and collision callbacks aren't two separate systems.

How are you determining hand.SolverIndex? Is it _arm.elements[0].particle1? if so, note that this value is only available when the rope is already instantiated.

I assume you're doing something along the lines of hand.SolverIndex = _arm.elements[0].particle1 this at Start(), Awake(), OnEnable() or a similar event, so it may or may not return a correct value depending on the order in which game objects are instantiated, which as you know if undefined in Unity.

If my assumption is correct, you might want to wait for one frame after instantiating the rope to get the value of hand.SolverIndex.

Ah, interesting. Ok, I will give this a try when I am free and come back when I am done testing.

My only concern with this solution is that if the hand.SolverIndex was wrong then I would not be able to add force using Solver.externalForces[SolverIndex] in Hand.cs which works as seen in both gifs. 

Another point and this is the main one, is that if I remove the conditionals in OnCollision just so its catching any particle -> collider collisions and log the event, it will never log any event even though that particle is actively colliding. Every other particle will log an event but not that one. No collision event gets fired at all but it still collides accurately with the cube collider.
Reply
#4
(18-03-2022, 02:40 PM)VirtualCucumber Wrote: My only concern with this solution is that if the hand.SolverIndex was wrong then I would not be able to add force using Solver.externalForces[SolverIndex] in Hand.cs which works as seen in both gifs.

True, if you're able to apply forces to that particle using Solver.externalForces[SolverIndex] then SolverIndex must be correct.

(18-03-2022, 02:40 PM)VirtualCucumber Wrote: No collision event gets fired at all but it still collides accurately with the cube collider.

Thats' simply not possible, since the collision events contain the exact same data used for collision response. The engine reports the contacts that it has solved. If the particle is colliding, there must exist a contact against it in the contact list.

Do any of the ropes in your scene use surface collisions? if so, this assumption is incorrect:
Code:
// Get the particle index directly, as all simplices are guaranteed to have size 1:
int particleIndex = hand.Solver.simplices[contact.bodyA];

When using surface collisions not all simplices will have size 1, so the particleIndex you get is incorrect. Off the top of my head this is the only thing that could result in the behavior you're getting. See retrieving the particle involved in a contact.

In case you're not using surface collisions at all, then the behavior you describe doesn't make sense. Would it be possible for you to share your project, or at least some scene that reproduces it?
Reply
#5
(18-03-2022, 02:46 PM)josemendez Wrote: Thats' simply not possible, since the collision events contain the exact same data used for collision response. The engine reports the contacts that it has solved. If the particle is colliding, there must exist a contact against it in the contact list.

Exactly, I got a bit confused when no collision event was logged whilst t would simulate normally with collisions.

(18-03-2022, 02:46 PM)josemendez Wrote: Do any of the ropes in your scene use surface collisions?

I kept them off.

(18-03-2022, 02:46 PM)josemendez Wrote: In case you're not using surface collisions at all, then the behavior you describe doesn't make sense. Would it be possible for you to share your project, or at least some scene that reproduces it?

For sure, I'll go ahead and send a DM to you with the .zip and directions.
Reply
#6
Hi!

Just realized that your code to iterate over all contacts does this:

Quote:if (contact.distance > 0.01) return;

Which means that once you find the first speculative contact, you exit the function and simply ignore any other contacts.

Same for

Quote:if (particleIndex != hand.SolverIndex) return;

If the first contact in the list is not the one you're looking for, you just stop looking. So your interaction code might or might not work based purely on whether the hand contact is the first one to appear on the list, which is of course 100% luck based Sonrisa.

replace these "return;" with

Quote:continue;

The continue keyword simply jumps to the next iteration of a loop, ignoring all instructions that appear after it in the current iteration. That way, you skip speculative contacts and contacts that you're not interested in, but still process all other contacts to look for the one you want. Still haven't tried the project you sent me but this bug quite likely plays a huge role on the weird behavior you get. Will download the project and try it nonetheless.

Edit: tried the project, and this bug was the culprit indeed. Fixed code:

Code:
// Just iterate over all contacts in the current frame
foreach (Oni.Contact contact in handCollision.contacts)
{
                // This one is an actual collision
                if (contact.distance > 0.01)
                    continue;

                // Get the particle index directly, as all simplices are guaranteed to have size 1:
                int particleIndex = hand.Solver.simplices[contact.bodyA];

                // This is not the particle you are looking for - Obi Wan
                if (particleIndex != hand.SolverIndex) continue;

                // Retrieve collider
                ObiColliderBase collider = ObiColliderWorld.GetInstance().colliderHandles[contact.bodyB].owner;

                // Attach hand and collider
                hand.Grab(collider.transform);
}
Reply
#7
(21-03-2022, 11:34 AM)josemendez Wrote: Hi!

Just realized that your code to iterate over all contacts does this:


Which means that once you find the first speculative contact, you exit the function and simply ignore any other contacts.

Same for


If the first contact in the list is not the one you're looking for, you just stop looking. So your interaction code might or might not work based purely on whether the hand contact is the first one to appear on the list, which is of course 100% luck based Sonrisa.

replace these "return;" with


The continue keyword simply jumps to the next iteration of a loop, ignoring all instructions that appear after it in the current iteration. That way, you skip speculative contacts and contacts that you're not interested in, but still process all other contacts to look for the one you want. Still haven't tried the project you sent me but this bug quite likely plays a huge role on the weird behavior you get. Will download the project and try it nonetheless.

Edit: tried the project, and this bug was the culprit indeed. Fixed code:

Code:
// Just iterate over all contacts in the current frame
foreach (Oni.Contact contact in handCollision.contacts)
{
                // This one is an actual collision
                if (contact.distance > 0.01)
                    continue;

                // Get the particle index directly, as all simplices are guaranteed to have size 1:
                int particleIndex = hand.Solver.simplices[contact.bodyA];

                // This is not the particle you are looking for - Obi Wan
                if (particleIndex != hand.SolverIndex) continue;

                // Retrieve collider
                ObiColliderBase collider = ObiColliderWorld.GetInstance().colliderHandles[contact.bodyB].owner;

                // Attach hand and collider
                hand.Grab(collider.transform);
}

Ah, of course! What a trivial mistake and thank you so much for looking into this and replying back with the solution!
Reply