Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Help  I contact with softbody but it is treated as contact with the rope
#1
Hi, pls take a look at this video



package: https://drive.google.com/file/d/1WNSuRz9...sp=sharing
In this you will find the scene: Assets/Spike/Scenes/Cut the Rope.unity
In the scene you will have the rope cutter object Rope Cutter with script RopeCutOnCollide.cs
and the masterSolver object with script ObiContactDebug.cs

First part of the video, everything is fine, the rope cutter can cut rope at exact element.
But when it hit the softbody ball, it also treated as hit the rope.
Reply
#2
Hi,

Your script is incorrect:

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

//check surface collisions
// retrieve the offset and size of the simplex in the solver.simplices array:
int simplexStart = solver.simplexCounts.GetSimplexStartAndSize(contact.bodyA, out int simplexSize);

// starting at simplexStart, iterate over all particles in the simplex:
if (simplexSize > 1)
{
    //now this is surface collision, we have to find the real particleIndex which is nearest to the local Pos B
    var minDist = 9999f;
    var localPosB = contact.pointB;
    for (int i = 0; i < simplexSize; ++i)
     {
                    var testParticleIndex = solver.simplices[simplexStart + i];
                    var dist = Vector3.Distance(solver.positions[testParticleIndex], localPosB);
                    if (dist < minDist) {
                        minDist = dist;
                        particleIndex = testParticleIndex;
                    }
                }
     }

Say you collide against a simplex of size 1: the if (simplexSize > 1) condition won't be met, so you won't iterate trough all particles in the simplex to find the closest one and instead will keep the original value of particleIndex = solver.simplices[contact.bodyA]; which is incorrect in case the solver contains *any* simplex of size other than 1.

So what's happening is that you collide against the softbody, and since its simplices have size 1 the "if" clause is skipped, so you keep solver.simplices[contact.bodyA] as your particle index which may belong to any other actor - in this case one of the ropes.

Keep in mind that simplices are stored as tuples of particle indices. The first few entries in the solver.simplices array are tuples of 3 (triangle simplices, used by cloth), the ones in the middle are tuples of 2 (used by ropes) and the ones at the end are single particle indices. Given a simplex index, the GetSimplexStartAndSize function will calculate for you the index of its first particle in the simplices array. For instance if you have 4 3-simplices, 5 2-simplices and 10 1-simplices, the starting index of the 6th simplex would be 4*3 + 2*2 = 16. The starting index of the 12th simplex would be 4*3 + 5*2 + 3*1 = 25, so even if its a 1-simplex its starting index would not be 12. If you used 12 as your index instead of 25, you would be accessing a particle belonging to another actor.

So if there's anything other than just 1-simplices in your solver, as seems to be your case, you can't assume solver.simplices[contact.bodyA] will contain the correct index. You must then always use GetSimplexStartAndSize. As per the manual:

http://obi.virtualmethodstudio.com/manua...sions.html

Quote:In case there isn't any actor using surface collisions in your solver, all simplices will have size 1 and the code above can be simplified to:

// get the particle index directly, as all simplices are guaranteed to have size 1:
int particleIndex = solver.simplices[contact.bodyA];
Reply
#3
(14-05-2024, 12:47 PM)josemendez Wrote: Hi,

Your script is incorrect:

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

//check surface collisions
// retrieve the offset and size of the simplex in the solver.simplices array:
int simplexStart = solver.simplexCounts.GetSimplexStartAndSize(contact.bodyA, out int simplexSize);

// starting at simplexStart, iterate over all particles in the simplex:
if (simplexSize > 1)
{
    //now this is surface collision, we have to find the real particleIndex which is nearest to the local Pos B
    var minDist = 9999f;
    var localPosB = contact.pointB;
    for (int i = 0; i < simplexSize; ++i)
     {
                    var testParticleIndex = solver.simplices[simplexStart + i];
                    var dist = Vector3.Distance(solver.positions[testParticleIndex], localPosB);
                    if (dist < minDist) {
                        minDist = dist;
                        particleIndex = testParticleIndex;
                    }
                }
     }

Say you collide against a simplex of size 1: the if (simplexSize > 1) condition won't be met, so you won't iterate trough all particles in the simplex to find the closest one and instead will keep the original value of particleIndex = solver.simplices[contact.bodyA]; which is incorrect in case the solver contains *any* simplex of size other than 1.

So what's happening is that you collide against the softbody, and since its simplices have size 1 the "if" clause is skipped, so you keep solver.simplices[contact.bodyA] as your particle index which may belong to any other actor - in this case one of the ropes.

Keep in mind that simplices are stored as tuples of particle indices. The first few entries in the solver.simplices array are tuples of 3 (triangle simplices, used by cloth), the ones in the middle are tuples of 2 (used by ropes) and the ones at the end are single particle indices. Given a simplex index, the GetSimplexStartAndSize function will calculate for you the index of its first particle in the simplices array. For instance if you have 4 3-simplices, 5 2-simplices and 10 1-simplices, the starting index of the 6th simplex would be 4*3 + 2*2 = 16. The starting index of the 12th simplex would be 4*3 + 5*2 + 3*1 = 25, so even if its a 1-simplex its starting index would not be 12. If you used 12 as your index instead of 25, you would be accessing a particle belonging to another actor.

So if there's anything other than just 1-simplices in your solver, as seems to be your case, you can't assume solver.simplices[contact.bodyA] will contain the correct index. You must then always use GetSimplexStartAndSize. As per the manual:

http://obi.virtualmethodstudio.com/manua...sions.html

Thank you for the explanation! I got it to work with this  Gran sonrisa
Code:
            else {
                particleIndex = solver.simplices[simplexStart];
            }
Reply