Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Instantiate Rope during Runtime
#1
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.
Reply
#2
(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
Reply
#3
(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.
Reply
#4
(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.
Reply