Posts: 35
Threads: 15
Joined: May 2018
Reputation:
0
18-03-2022, 03:42 AM
(This post was last modified: 18-03-2022, 03:45 AM by VirtualCucumber.)
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:
When the prefab is instantiated, no collisions events detected from that particle:
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.
Posts: 6,346
Threads: 24
Joined: Jun 2017
Reputation:
400
Obi Owner:
18-03-2022, 08:21 AM
(This post was last modified: 18-03-2022, 08:30 AM by josemendez.)
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.
Posts: 35
Threads: 15
Joined: May 2018
Reputation:
0
18-03-2022, 02:40 PM
(This post was last modified: 18-03-2022, 02:42 PM by VirtualCucumber.)
(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.
Posts: 6,346
Threads: 24
Joined: Jun 2017
Reputation:
400
Obi Owner:
18-03-2022, 02:46 PM
(This post was last modified: 18-03-2022, 02:52 PM by josemendez.)
(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?
Posts: 35
Threads: 15
Joined: May 2018
Reputation:
0
19-03-2022, 06:55 PM
(This post was last modified: 19-03-2022, 08:39 PM by VirtualCucumber.)
(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.
Posts: 6,346
Threads: 24
Joined: Jun 2017
Reputation:
400
Obi Owner:
21-03-2022, 11:34 AM
(This post was last modified: 21-03-2022, 11:48 AM by josemendez.)
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 .
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);
}
Posts: 35
Threads: 15
Joined: May 2018
Reputation:
0
(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 .
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!
|