Obi Official Forum

Full Version: Rope Tear Snapback
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Hi there,

I'm trying to develop a simulation of a ship mooring line breaking and snapping back. So far I've been able to get the rope to tear at one end programmatically, and it looks pretty good, but there are a few problems I'd like to solve: 

1. How does one increase the speed the rope flings back after being broken? I would assume it's tied to the tension, but I'm not 100% sure how to increase the tension without shrinking the rope (see below), which is what I saw suggested on another forum post here. Ideally I'd like a different way of doing this. 
2. After breaking the rope, it seemingly gets a lot smaller than its original size. See the images attached. In the custom script I wrote, I use a Cursor to reduce the size of the rope at the start so that the tension is increased. However, after breaking, it seems to get much smaller than what I set it to. Ideally I would like the rope to maintain its original length after being broken, so it could fling back and potentially reach its full length in the opposite direction.

Here's my very simple code so far:

Code:
public class TensionScript : MonoBehaviour
{
    public Transform attachmentA;
    public Transform attachmentB;
    public float timeScale;
    public bool reduceLength;
    public float length;
    ObiRope rope;

    void Start()
    {
        Time.timeScale = timeScale;
        rope = GetComponent<ObiRope>();
        if(reduceLength) GetComponent<ObiRopeCursor>().ChangeLength(Vector3.Distance(attachmentA.position, attachmentB.position) * length);
    }

    [ContextMenu("Tear")]
    void TearRope()
    {
        rope.Tear(rope.elements[rope.elements.Count - 1]);
        rope.RebuildConstraintsFromElements();
    }
}

Just to note: 
  • The rope only has two control points, one at each end.
  • All the bend and distance constraint options are set to 0. I believe this makes the rope as rigid as I want it, but let me know if I should change anything here.
  • Both ends have an ObiParticleAttachment on them.
  • After breaking, the rope swings around the bollard seemingly indefinitely, even though I have a dampening value set on the solver. Not sure what causes this.

Hopefully you understand my issue and what I would like to achieve here.

Cheers,
Balin
(11-05-2023, 03:28 AM)Balin Wrote: [ -> ]1. How does one increase the speed the rope flings back after being broken? I would assume it's tied to the tension, but I'm not 100% sure how to increase the tension without shrinking the rope (see below), which is what I saw suggested on another forum post here. Ideally I'd like a different way of doing this. 

Tension (or rather, strain) is defined as the ratio between the rope's rest length and its current length:

Code:
float tension =rope.CalculateLength() / rope.restLength;

So the only ways to increase tension are to either stretch the rope more to increase its current length, or reduce its rest length.

You could also just set the velocity of the particles at either end of the cut, which allows you to control the exact magnitude and direction they fling back. See:
http://obi.virtualmethodstudio.com/manua...icles.html

(11-05-2023, 03:28 AM)Balin Wrote: [ -> ]2. After breaking the rope, it seemingly gets a lot smaller than its original size. See the images attached. In the custom script I wrote, I use a Cursor to reduce the size of the rope at the start so that the tension is increased. However, after breaking, it seems to get much smaller than what I set it to.

Ideally I would like the rope to maintain its original length after being broken, so it could fling back and potentially reach its full length in the opposite direction.

You're reducing the length of the rope via the cursor, so it won't keep its original length after being torn: it will keep the rest length you set by calling cursor.ChangeLength().

Calling rope.Tear() directly like you do in TearRope() will tear the rope at a specific element, regardless of its length. There's no need to increase tension via reducing its rest length with a cursor.

kind regards,
Thanks for the reply.


Instead of increasing strain in the rope by shrinking it, I've instead done what you suggested by setting the rope's velocity after tearing it. As it turns out, this suited my needs much better, and is also much easier to control.

Here's my new code in case anyone's interested:
Code:
using Obi;
using UnityEngine;

public class RopeSnapback : MonoBehaviour
{
    public Transform targetA;
    public Transform targetB;
    public float timeScale;
    public float distanceMultiplier;
    public float snapPoint; // as a fraction of the rope's length
    private ObiRope rope;

    void Start()
    {
        Time.timeScale = timeScale;
        rope = GetComponent<ObiRope>();
    }

    [ContextMenu("Tear")]
    public void TearRope()
    {
        int snapIndex = Mathf.Clamp(Mathf.RoundToInt(rope.elements.Count * snapPoint), 1, rope.elements.Count - 1); // get element from fraction

        rope.Tear(rope.elements[snapIndex]);

        SetVelocities();

        rope.RebuildConstraintsFromElements();
    }

    private void SetVelocities()
    {
        Vector4 localTargetA = rope.solver.transform.InverseTransformPoint(targetA.position);
        Vector4 localTargetB = rope.solver.transform.InverseTransformPoint(targetB.position);

        int elementSnapIndex = Mathf.Clamp(Mathf.RoundToInt(rope.elements.Count * snapPoint), 1, rope.elements.Count - 1);
        int solverSnapIndex = rope.elements[elementSnapIndex].particle2;

        for (int i = 0; i < rope.solverIndices.Length; i++)
        {
            int solverIndex = rope.solverIndices[i];
            Vector4 target;

            // figure out which side of the snap point the current particle is on
            if(solverIndex < solverSnapIndex)
            {
                target = localTargetA;
            }
            else
            {
                target = localTargetB;
            }

            rope.solver.velocities[solverIndex] = (target - rope.solver.positions[solverIndex]) * distanceMultiplier;
        }
    }
}

I managed to fix the rope shrinking problem by setting the Stretching Scale to 1 on the distance constraint, as I had previously misunderstood what this value is used for. Also, after increasing the number of solver iterations for the distance constraint, the rope is much more responsive than it was.


Thanks again.