Obi Official Forum

Full Version: Extracting acting forces on particle
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Hi,
I'm trying to detect the pulling force on a static particle attachment from an Obi Rope to a static rigidbody. Is it possible to get the forces that are acting on the particle attachment?

My scenario is this:
I have a rope attached to a static rigidbody using a Particle Attachment component in a VR game I'm working on. In the game you can pull the rope, and I want it to translate the pulling to a float based on the amount of pulling force applied to the rope/particle attachment.

I hope my problem is clear from the short description, 

Thanks in advance
I ended up looking at the relative distance between the Particle Attachment point and the next particle on the rope, and using that as a "hacky" way to get the pull on the Particle attachment point.
Not perfect, but it works somewhat (note: the code assumes that the particle attachment is at the start of the rope, i.e. index 0):
Code:
    Vector3 GetPullOnParticleAttachment(ObiActor rope)
    {
        var pAttachment = rope.solverIndices[0];
        var nextP = rope.solverIndices[1];

        var pAttachmentPos= rope.solver.positions[pAttachment];
        var nextPPos= rope.solver.positions[nextP];

        return pAttachmentPos - nextPPos;
    }
Being a position-based engine, Obi does not internally deal with forces. It deals with positional corrections, or lambdas. All constraints have a lambda array that stores positional lagrange multipliers for each constraint. To convert a lagrange multiplier to a force magnitude, divide by timestep squared:


Code:
force = batch.lambas[constraintIndex] / (deltaTime * deltaTime);

To learn how to access constraint data at runtime, see:
http://obi.virtualmethodstudio.com/manua...aints.html

You can also take a look at ObiParticleAttachment.cs for reference. The "BreakDynamicAttachment" method at the end of the file iterates trough the pin constraints in use by the attachment, checks the force applied by each one, and deactivates those above their break threshold like so:
Code:
for (int i = 0; i < pinBatch.activeConstraintCount; i++)
{
        // in case the constraint has been broken:
        if (-solverBatch.lambdas[(offset + i) * 4 + 3] / sqrTime > pinBatch.breakThresholds[i])
        {
              pinBatch.DeactivateConstraint(i);
              dirty = true;
        }
}

In the case of pin constraints, there's 4 lagrange multipliers per constraint: 3 for the rotational part, and 1 for the translational part. Since we are only interested in translational force we only access the fourth one of each constraint, hence the seemingly weird indexing:

Code:
lambdas[(offset + i) * 4 + 3]

And since we only want stretching (not compression) forces, we negate the lambda. Hence the minus (-) sign used for the lambda in the comparison.
(24-08-2021, 04:34 PM)josemendez Wrote: [ -> ]Being a position-based engine, Obi does not internally deal with forces. It deals with positional corrections, or lambdas. All constraints have a lambda array that stores positional lagrange multipliers for each constraint. To convert a lagrange multiplier to a force magnitude, divide by timestep squared:


Code:
force = batch.lambas[constraintIndex] / (deltaTime * deltaTime);

To learn how to access constraint data at runtime, see:
http://obi.virtualmethodstudio.com/manua...aints.html

You can also take a look at ObiParticleAttachment.cs for reference. The "BreakDynamicAttachment" method at the end of the file iterates trough the pin constraints in use by the attachment, checks the force applied by each one, and deactivates those above their break threshold like so:
Code:
for (int i = 0; i < pinBatch.activeConstraintCount; i++)
{
        // in case the constraint has been broken:
        if (-solverBatch.lambdas[(offset + i) * 4 + 3] / sqrTime > pinBatch.breakThresholds[i])
        {
              pinBatch.DeactivateConstraint(i);
              dirty = true;
        }
}

In the case of pin constraints, there's 4 lagrange multipliers per constraint: 3 for the rotational part, and 1 for the translational part. Since we are only interested in translational force we only access the fourth one of each constraint, hence the seemingly weird indexing:

Code:
lambdas[(offset + i) * 4 + 3]

And since we only want stretching (not compression) forces, we negate the lambda. Hence the minus (-) sign used for the lambda in the comparison.

Hi josemendez, I stumbled upon this thread while searching something similar, and I don't understand. I'd like to know the force vector that's applied to an attachment.
I know the solver index of a particle that's in the particle group of the attachment.
I guess I also can know the direction of the force that's being applied to the attachment, because I can subtract the position of a particle to the position of the next particle (like this other user did in their first solution). All that would be left would be to do would be `direction.normalized * batch.lambas[constraintIndex] / (deltaTime * deltaTime)`?
I don't understand how to get the specific batch and the constraint index of a specific particle.

Sorry for reviving an old post and sorry to not be able to understand the previous explanation Triste
(23-06-2023, 06:26 AM)KnotANumber Wrote: [ -> ]I guess I also can know the direction of the force that's being applied to the attachment, because I can subtract the position of a particle to the position of the next particle (like this other user did in their first solution).

It's not possible to know the *exact* direction of the force, because there's no single direction. Every iteration, constraints move particles in the direction of their jacobian (aka, constraint gradient) which changes with every iteration - since each particle is usually affected by more than 1 constraint and each constraint pushes/pulls in a different direction, so to speak. There may be more than 1 iteration per physics step and more than 1 physics step per frame, so by the end of the frame the particle has moved in a multitude of directions. See: http://obi.virtualmethodstudio.com/manua...gence.html

You can use the constraint gradient at the end of the frame as a rough approximation of the net direction (like TimmyVonMoerkel did above), but depending on your use case this may not be accurate enough.

(23-06-2023, 06:26 AM)KnotANumber Wrote: [ -> ]All that would be left would be to do would be `direction.normalized * batch.lambas[constraintIndex] / (deltaTime * deltaTime)`?

Correct.

(23-06-2023, 06:26 AM)KnotANumber Wrote: [ -> ]I don't understand how to get the specific batch and the constraint index of a specific particle.

You can't, for obvious reasons: each particle is not affected by a single constraint, but by many of them and each constraint is in a different batch to avoid race conditions. So the engine -most physics engines, in fact- is optimized for the exact opposite access pattern: for each constraint, list all particles/bodies affected by it.

If you want to get all constraints that affect a single particle, the only way is to iterate trough all constraints in all batches and pick those that reference your particle. This isn't very efficient but luckily, it's usually not needed.

This page in the manual goes into details about how constraints and particles relate to each other, it might help:
http://obi.virtualmethodstudio.com/manua...aints.html

kind regards,