Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Help  Untangling ropes and collision detection
#1
       

I have a similar setup as the above image,  How to know if the rope is not tangled anymore? like in the first image. I have enabled the surface collisions and tried with OnParticleCollision but it has not worked for me. can I ray cast from each particle of the rope a bit upward and check if it has collided with another rope? or is there any other simple workaround for this? 
Reply
#2
(17-05-2024, 03:47 PM)Harshid123 Wrote: I have a similar setup as the above image,  How to know if the rope is not tangled anymore? like in the first image. I have enabled the surface collisions and tried with OnParticleCollision but it has not worked for me. can I ray cast from each particle of the rope a bit upward and check if it has collided with another rope? or is there any other simple workaround for this? 
Code:
public IEnumerator CheckIfTangled()
{
     yield return new WaitForSeconds(1);
     int filter = ObiUtils.MakeFilter(ObiUtils.CollideWithEverything, 1);
     for (int i = 0; i < rope.activeParticleCount; ++i)
     {
         yield return null;
         Vector3 pos = rope.GetParticlePosition(rope.solverIndices[i]);
     
         Ray ray = new Ray(pos, Vector3.back * 10f);
         if (solver.Raycast(ray, out QueryResult result, filter, 100, 0.5f))
         {
             int simplexStart = solver.simplexCounts.GetSimplexStartAndSize(result.simplexIndex, out int simplexSize);
             for (int j = 0; j < simplexSize; ++j)
             {
                 yield return null;
                 int particleIndex = solver.simplices[simplexStart + j];
                 ObiSolver.ParticleInActor pa = solver.particleToActor[particleIndex];
                 if (pa.actor != rope)
                 {
                     // rope is tangled here return.
                     yield break;
                 }
             }
         }
     }

   // rope is not tangled here.
}
I am pretty sure there could be other better workaround for this, But This code worked for me
Reply
#3
(20-05-2024, 09:29 AM)Harshid123 Wrote:
Code:
public IEnumerator CheckIfTangled()
{
     yield return new WaitForSeconds(1);
     int filter = ObiUtils.MakeFilter(ObiUtils.CollideWithEverything, 1);
     for (int i = 0; i < rope.activeParticleCount; ++i)
     {
         yield return null;
         Vector3 pos = rope.GetParticlePosition(rope.solverIndices[i]);
     
         Ray ray = new Ray(pos, Vector3.back * 10f);
         if (solver.Raycast(ray, out QueryResult result, filter, 100, 0.5f))
         {
             int simplexStart = solver.simplexCounts.GetSimplexStartAndSize(result.simplexIndex, out int simplexSize);
             for (int j = 0; j < simplexSize; ++j)
             {
                 yield return null;
                 int particleIndex = solver.simplices[simplexStart + j];
                 ObiSolver.ParticleInActor pa = solver.particleToActor[particleIndex];
                 if (pa.actor != rope)
                 {
                     // rope is tangled here return.
                     yield break;
                 }
             }
         }
     }

   // rope is not tangled here.
}
I am pretty sure there could be other better workaround for this, But This code worked for me

This will only work in specific circumstances, since your ray has a fixed direction (Vector3.back). If the rope is colliding against another rope in a direction other than the one specified by your ray, this won't work. Moreover, casting a ray from every particle in your rope is a very brute force approach to this.

A simpler, faster, and more robust way is to use collision callbacks. You can simply count the amount of contacts affecting each rope, and determine whether a rope is colliding (contact count > 0) or not (contact count == 0).

Note you should not do this for every rope in your solver either, it's enough to iterate trough all contacts just once since they already contain references to the ropes involved in them. The typical approach would be to add a component to your ObiSolver, subscribe it to OnParticleCollision, and then count the contacts for each rope only once per frame - as opposed to subscribing every rope to OnParticleCollision and iterating trough all contacts in the solver as many times as ropes you have, which would also be very inefficient.

kind regards,
Reply
#4
Thanks a million. I was finally able to do it with OnParticleCollison. Followed Exactly what you've said and it's now working like a charm!
Reply