Obi Official Forum
Instantiate Rope during Runtime - Printable Version

+- Obi Official Forum (https://obi.virtualmethodstudio.com/forum)
+-- Forum: Obi Users Category (https://obi.virtualmethodstudio.com/forum/forum-1.html)
+--- Forum: Obi Rope (https://obi.virtualmethodstudio.com/forum/forum-4.html)
+--- Thread: Instantiate Rope during Runtime (/thread-840.html)



Instantiate Rope during Runtime - crychair - 28-01-2019

Code:
    public void makeRope(Vector3 pos1, Vector3 pos2, GameObject obj1, GameObject obj2) {
        
        
        GameObject rope = Instantiate(obiRopePrefab);
        BetterRopeHelper helper = rope.GetComponent<BetterRopeHelper>();
        helper.SetPoints(pos1, pos2);
        helper.GenerateRope(obj1, obj2);

    }
Code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Obi;

[RequireComponent(typeof(ObiRope))]
[RequireComponent(typeof(ObiCatmullRomCurve))]
public class BetterRopeHelper : MonoBehaviour
{


   public ObiSolver solver;
   public ObiRopeSection section;
   public Material material;
   private ObiActor actor;
   private ObiRope rope;
   private ObiCatmullRomCurve path;

   private Vector3 start, end;

   public void SetPoints(Vector3 startpoint, Vector3 endpoint)
   {
       // Get all needed components and interconnect them:
       rope = GetComponent<ObiRope>();
       path = GetComponent<ObiCatmullRomCurve>();
       rope.Solver = solver;
       rope.ropePath = path;
       rope.section = section;
       GetComponent<MeshRenderer>().material = material;

       // Calculate rope start/end and direction in local space:
       start = startpoint;
       end = endpoint;
       Vector3 localStart = startpoint;
       Vector3 localEnd = endpoint;
       Vector3 direction = (localEnd - localStart).normalized;

       // Generate rope path:
       path.controlPoints.Clear();
       path.controlPoints.Add(localStart - direction);
       path.controlPoints.Add(localStart);
       path.controlPoints.Add(localEnd);
       path.controlPoints.Add(localEnd + direction);
   }

   public void GenerateRope(GameObject obj1, GameObject obj2)
   {
       // Setup the simulation:
       StartCoroutine(Setup(obj1, obj2));
   }

   IEnumerator Setup(GameObject obj1, GameObject obj2)
   {

       // Generate particles and add them to solver:
       yield return StartCoroutine(rope.GeneratePhysicRepresentationForMesh());
       rope.AddToSolver(null);

       // Fix first and last particle in place:
       //rope.invMasses[0] = 0;
       //rope.invMasses[rope.UsedParticles - 1] = 0;
       //Oni.SetParticleInverseMasses(solver.OniSolver, new float[] { 0 }, 1, rope.particleIndices[0]);
       //Oni.SetParticleInverseMasses(solver.OniSolver, new float[] { 0 }, 1, rope.particleIndices[rope.UsedParticles - 1]);
       //rope.PushDataToSolver(ParticleData.INV_MASSES);


       //batchConstraints = pinConstraints.GetBatches() as ObiPinConstraintBatch;
       //pinConstraints.RemoveFromSolver(null);
       //Debug.Log(obj1.name);
       //batchConstraints.AddConstraint(0, obj1.GetComponent<ObiCollider>(), Vector3.zero, 0f);
       //batchConstraints.AddConstraint(rope.UsedParticles - 1, obj2.GetComponent<ObiCollider>(), Vector3.zero, 0f);
       //pinConstraints.AddToSolver(null);
       //pinConstraints.PushDataToSolver();
       rope.PinConstraints.RemoveFromSolver(null);
       ObiPinConstraintBatch batch = (ObiPinConstraintBatch)rope.PinConstraints.GetFirstBatch();
       Vector3 offset1 = obj1.transform.InverseTransformPoint(start);
       Vector3 offset2 = obj1.transform.InverseTransformPoint(start);
       batch.AddConstraint(0, obj1.GetComponent<ObiCollider>(), offset1, 1f);
       batch.AddConstraint(rope.UsedParticles - 1, obj2.GetComponent<ObiCollider>(), offset2, 1f);
       rope.PinConstraints.AddToSolver(null);


       //actor.enabled = true;
   }
}


I have the method and helper above and it works. My issue is that I want the rope to be taught on instantiation rather than modifying it after. Is there some way to do this. currently when the rope is generated it become slack and weighs itself down. 

Any help is appreciated.


RE: Instantiate Rope during Runtime - josemendez - 28-01-2019

(28-01-2019, 05:02 PM)crychair Wrote:
Code:
    public void makeRope(Vector3 pos1, Vector3 pos2, GameObject obj1, GameObject obj2) {
        
        
        GameObject rope = Instantiate(obiRopePrefab);
        BetterRopeHelper helper = rope.GetComponent<BetterRopeHelper>();
        helper.SetPoints(pos1, pos2);
        helper.GenerateRope(obj1, obj2);

    }
Code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Obi;

[RequireComponent(typeof(ObiRope))]
[RequireComponent(typeof(ObiCatmullRomCurve))]
public class BetterRopeHelper : MonoBehaviour
{


   public ObiSolver solver;
   public ObiRopeSection section;
   public Material material;
   private ObiActor actor;
   private ObiRope rope;
   private ObiCatmullRomCurve path;

   private Vector3 start, end;

   public void SetPoints(Vector3 startpoint, Vector3 endpoint)
   {
       // Get all needed components and interconnect them:
       rope = GetComponent<ObiRope>();
       path = GetComponent<ObiCatmullRomCurve>();
       rope.Solver = solver;
       rope.ropePath = path;
       rope.section = section;
       GetComponent<MeshRenderer>().material = material;

       // Calculate rope start/end and direction in local space:
       start = startpoint;
       end = endpoint;
       Vector3 localStart = startpoint;
       Vector3 localEnd = endpoint;
       Vector3 direction = (localEnd - localStart).normalized;

       // Generate rope path:
       path.controlPoints.Clear();
       path.controlPoints.Add(localStart - direction);
       path.controlPoints.Add(localStart);
       path.controlPoints.Add(localEnd);
       path.controlPoints.Add(localEnd + direction);
   }

   public void GenerateRope(GameObject obj1, GameObject obj2)
   {
       // Setup the simulation:
       StartCoroutine(Setup(obj1, obj2));
   }

   IEnumerator Setup(GameObject obj1, GameObject obj2)
   {

       // Generate particles and add them to solver:
       yield return StartCoroutine(rope.GeneratePhysicRepresentationForMesh());
       rope.AddToSolver(null);

       // Fix first and last particle in place:
       //rope.invMasses[0] = 0;
       //rope.invMasses[rope.UsedParticles - 1] = 0;
       //Oni.SetParticleInverseMasses(solver.OniSolver, new float[] { 0 }, 1, rope.particleIndices[0]);
       //Oni.SetParticleInverseMasses(solver.OniSolver, new float[] { 0 }, 1, rope.particleIndices[rope.UsedParticles - 1]);
       //rope.PushDataToSolver(ParticleData.INV_MASSES);


       //batchConstraints = pinConstraints.GetBatches() as ObiPinConstraintBatch;
       //pinConstraints.RemoveFromSolver(null);
       //Debug.Log(obj1.name);
       //batchConstraints.AddConstraint(0, obj1.GetComponent<ObiCollider>(), Vector3.zero, 0f);
       //batchConstraints.AddConstraint(rope.UsedParticles - 1, obj2.GetComponent<ObiCollider>(), Vector3.zero, 0f);
       //pinConstraints.AddToSolver(null);
       //pinConstraints.PushDataToSolver();
       rope.PinConstraints.RemoveFromSolver(null);
       ObiPinConstraintBatch batch = (ObiPinConstraintBatch)rope.PinConstraints.GetFirstBatch();
       Vector3 offset1 = obj1.transform.InverseTransformPoint(start);
       Vector3 offset2 = obj1.transform.InverseTransformPoint(start);
       batch.AddConstraint(0, obj1.GetComponent<ObiCollider>(), offset1, 1f);
       batch.AddConstraint(rope.UsedParticles - 1, obj2.GetComponent<ObiCollider>(), offset2, 1f);
       rope.PinConstraints.AddToSolver(null);


       //actor.enabled = true;
   }
}


I have the method and helper above and it works. My issue is that I want the rope to be taught on instantiation rather than modifying it after. Is there some way to do this. currently when the rope is generated it become slack and weighs itself down. 

Any help is appreciated.

Hi there,

You could perform a few simulation steps in-place after creating the rope, by calling rope.Solver.SimulateStep(deltaTime) in a loop, similar to what the particle editor does. (See the Update() method of ObiParticleActorEditor.cs for reference)

Another, less expensive method is to use the catenary equation to determine initial particle positions. This is the shape adopted by any rope at rest. See:
https://en.wikipedia.org/wiki/Catenary


RE: Instantiate Rope during Runtime - crychair - 28-01-2019

(28-01-2019, 09:03 PM)josemendez Wrote: Hi there,

You could perform a few simulation steps in-place after creating the rope, by calling rope.Solver.SimulateStep(deltaTime) in a loop, similar to what the particle editor does. (See the Update() method of ObiParticleActorEditor.cs for reference)

Another, less expensive method is to use the catenary equation to determine initial particle positions. This is the shape adopted by any rope at rest. See:
https://en.wikipedia.org/wiki/Catenary

Currently If I pick two points in space the and create the rope it sags pretty heavily under its own weight. I would like it to be taught and have less slack than it does. Is there a way to instantiate a variable to do this at the time of creation? No matter the distance the rope seems to take on and extra piece of length that is longer than the distance between the two points I chose.


RE: Instantiate Rope during Runtime - josemendez - 29-01-2019

(28-01-2019, 09:56 PM)crychair Wrote: Currently If I pick two points in space the and create the rope it sags pretty heavily under its own weight. I would like it to be taught and have less slack than it does. Is there a way to instantiate a variable to do this at the time of creation? No matter the distance the rope seems to take on and extra piece of length that is longer than the distance between the two points I chose.

Oh sorry, I thought you were asking the opposite actually, starting with a taught rope and wanting it to start out with some slack.

Rope tension depends on the amount of distance constraint iterations you use to enforce its length. Increasing the amount of distance constraint iterations in the solver should make it taught (er). Let me know how it goes.