Thread Rating:
  • 1 Vote(s) - 5 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Help  Grab the middle of a rope?
#3
(24-08-2017, 05:47 PM)josemendez Wrote: Hi there!

There's no difference in grabbing the ends or any other point in the rope. Ropes are basically chains of particles, you can freeze any particle you wish along the rope and move it around. This is done by setting the inverse mass of the particle to zero, and setting its position to whatever you want. See:

http://obi.virtualmethodstudio.com/tutor...icles.html

Keep in mind that absolutely no solver will be able to handle arbitrarily large forces applied to a body, specially not if collisions are involved. You should clamp the maximum force an user is able to exert when pulling on the rope no matter what solver you use (Obi, PhysX, or any other). This is just a limitation of realtime physics: large and sudden forces need higher computation time to be handled with enough precision, so there will always be a threshold that once surpassed, breaks the simulation. Obi is no exception to this.

I have fully implemented an interaction system for ObiRope using VRTK.

**UPDATED VERSION

Requirments: ObiRope 3.2+ and VRTK 3.3.0 alpha+

Put this on the gameobject with the ObiSolver:

Code:
using System.Collections;
using UnityEngine;
using Obi;
using VRTK;

[System.Serializable]
public class InteractingInfo
{
   [Header("Grab Options")]
   public bool grabbingEnabled;

   [Header("Pin Options")]
   public Vector3 pinOffset;
   [Range(0f, 1f)]
   public float stiffness;

   [HideInInspector]
   public bool isTouchingParticle;
   [HideInInspector]
   public int touchingParticle;
   [HideInInspector]
   public int? grabbedParticle;
   [HideInInspector]
   public int? pinIndex;
   [HideInInspector]
   public VRTK_InteractGrab interactGrab;
   [HideInInspector]
   public Collider collider;
   [HideInInspector]
   public ObiCollider obiCollider;
   [HideInInspector]
   public VRTK_ObiRopeInteraction currentInteraction;

   public void Clear()
   {
       isTouchingParticle = false;
   }
}

[RequireComponent(typeof(ObiSolver))]
public class VRTK_ObiRopeSolver : MonoBehaviour
{
   #region Fields

   [Tooltip("Check if using VRTK_InteractTouch custom collider")]
   public bool customColliders;
   public string colliderObjectName = "Head";

   [Header("Controller Info")]

   public InteractingInfo leftControllerInfo = new InteractingInfo();
   public InteractingInfo rightControllerInfo = new InteractingInfo();

   private ObiSolver solver;

   private GameObject leftController;
   private GameObject rightController;

   #endregion


   #region Mono Events

   private void Awake()
   {
       solver = GetComponent<ObiSolver>();

       VRTK_SDKManager.instance.AddBehaviourToToggleOnLoadedSetupChange(this);
   }

   private void OnDestroy()
   {
       VRTK_SDKManager.instance.RemoveBehaviourToToggleOnLoadedSetupChange(this);
   }

   private void Reset()
   {
       colliderObjectName = "Head";
   }

   private void OnEnable()
   {
       leftController = VRTK.VRTK_DeviceFinder.GetControllerLeftHand(false);
       rightController = VRTK.VRTK_DeviceFinder.GetControllerRightHand(false);

       if (customColliders)
       {
           SetupController(leftController, true);
           SetupController(rightController, false);
       }
       else
       {
           leftController.GetComponent<VRTK_ControllerEvents>().ControllerModelAvailable += ControllerModelAvailiable;
           rightController.GetComponent<VRTK_ControllerEvents>().ControllerModelAvailable += ControllerModelAvailiable;
       }

       if (!ReferenceEquals(solver, null))
       {
           solver.OnCollision += HandleSolverCollision;
       }
   }

   private void OnDisable()
   {
       if (!ReferenceEquals(solver, null))
       {
           solver.OnCollision -= HandleSolverCollision;
       }
   }

   #endregion


   #region Private Methods

   private bool SetupController(GameObject controller, bool isLeft)
   {
       if (controller.transform.childCount == 0) return false;

       Transform colliderObject = customColliders ? controller.transform.Find(colliderObjectName) : controller.transform.GetChild(0).Find(colliderObjectName);
       colliderObject.gameObject.layer = LayerMask.NameToLayer("Default");

       var collider = colliderObject.gameObject.GetComponent<ObiCollider>();

       if (isLeft)
       {
           if (ReferenceEquals(collider, null))
           {
               leftControllerInfo.obiCollider = colliderObject.gameObject.AddComponent<ObiCollider>();
           }
           else
           {
               leftControllerInfo.obiCollider = collider;
           }

           leftControllerInfo.collider = colliderObject.GetComponent<Collider>();

           leftControllerInfo.interactGrab = controller.GetComponent<VRTK_InteractGrab>();
           leftControllerInfo.interactGrab.GrabButtonPressed += HandleGrabButtonPressed;
           leftControllerInfo.interactGrab.GrabButtonReleased += HandleGrabButtonReleased;
       }
       else
       {
           if (ReferenceEquals(collider, null))
           {
               rightControllerInfo.obiCollider = colliderObject.gameObject.AddComponent<ObiCollider>();
           }
           else
           {
               rightControllerInfo.obiCollider = collider;
           }

           rightControllerInfo.collider = colliderObject.GetComponent<Collider>();

           rightControllerInfo.interactGrab = controller.GetComponent<VRTK_InteractGrab>();
           rightControllerInfo.interactGrab.GrabButtonPressed += HandleGrabButtonPressed;
           rightControllerInfo.interactGrab.GrabButtonReleased += HandleGrabButtonReleased;
       }

       return true;
   }

   #endregion


   #region Controller Events

   private void ControllerModelAvailiable(object sender, ControllerInteractionEventArgs e)
   {
       StartCoroutine(ModelLoaded(sender as VRTK_ControllerEvents));
   }

   private IEnumerator ModelLoaded(VRTK_ControllerEvents events)
   {
       yield return new WaitForEndOfFrame();

       bool succeeded = true;

       if (ReferenceEquals(events.gameObject, leftController))
       {
           succeeded = SetupController(events.gameObject as GameObject, true);
       }
       else if (ReferenceEquals(events.gameObject, rightController))
       {
           succeeded = SetupController(events.gameObject as GameObject, false);
       }

       if (!succeeded)
           StartCoroutine(ModelLoaded(events as VRTK_ControllerEvents));
   }

   private void HandleGrabButtonPressed(object sender, ControllerInteractionEventArgs e)
   {
       if (ReferenceEquals(sender, leftControllerInfo.interactGrab) && leftControllerInfo.grabbingEnabled)
       {
           if (leftControllerInfo.isTouchingParticle)
           {
               // Get actor and apply constraint
               leftControllerInfo.currentInteraction.GrabRope(leftControllerInfo);
           }
       }
       else if (ReferenceEquals(sender, rightControllerInfo.interactGrab) && rightControllerInfo.grabbingEnabled)
       {
           if (rightControllerInfo.isTouchingParticle)
           {
               // Get actor and apply constraint
               rightControllerInfo.currentInteraction.GrabRope(rightControllerInfo);
           }
       }
   }

   private void HandleGrabButtonReleased(object sender, ControllerInteractionEventArgs e)
   {
       if (rightControllerInfo.grabbedParticle != null && ReferenceEquals(sender, rightControllerInfo.interactGrab) && rightControllerInfo.grabbingEnabled)
       {
           rightControllerInfo.currentInteraction.ReleaseRope(rightControllerInfo);

           if (leftControllerInfo.pinIndex.HasValue && leftControllerInfo.isTouchingParticle && leftControllerInfo.pinIndex > rightControllerInfo.pinIndex)
               leftControllerInfo.pinIndex--;

           rightControllerInfo.grabbedParticle = null;
           rightControllerInfo.pinIndex = null;

       }
       else if (leftControllerInfo.grabbedParticle != null && ReferenceEquals(sender, leftControllerInfo.interactGrab) && leftControllerInfo.grabbingEnabled)
       {
           leftControllerInfo.currentInteraction.ReleaseRope(leftControllerInfo);

           if (rightControllerInfo.pinIndex.HasValue && rightControllerInfo.isTouchingParticle && rightControllerInfo.pinIndex > leftControllerInfo.pinIndex)
               rightControllerInfo.pinIndex--;

           leftControllerInfo.grabbedParticle = null;
           leftControllerInfo.pinIndex = null;
       }
   }

   #endregion


   #region Obi Solver Events

   private void HandleSolverCollision(object sender, Obi.ObiSolver.ObiCollisionEventArgs e)
   {
       if (e == null || e.contacts == null || !rightControllerInfo.grabbingEnabled && !leftControllerInfo.grabbingEnabled) return;

       // Reset every frame
       leftControllerInfo.Clear();
       rightControllerInfo.Clear();

       for (int i = 0; i < e.contacts.Length; ++i)
       {
           var contact = e.contacts[i];
           var pia = solver.particleToActor[e.contacts[i].particle];
           var actor = pia.actor;
           var particleIndex = pia.indexInActor;

           // make sure this is an actual contact
           if (contact.distance < 0.01f)
           {
               Collider collider = ObiColliderBase.idToCollider[contact.other] as Collider;

               if (ReferenceEquals(collider, leftControllerInfo.collider))
               {
                   leftControllerInfo.isTouchingParticle = true;
                   leftControllerInfo.touchingParticle = particleIndex;
                   leftControllerInfo.currentInteraction = actor.gameObject.GetComponent<VRTK_ObiRopeInteraction>();
               }
               else if (ReferenceEquals(collider, rightControllerInfo.collider))
               {
                   rightControllerInfo.isTouchingParticle = true;
                   rightControllerInfo.touchingParticle = particleIndex;
                   rightControllerInfo.currentInteraction = actor.gameObject.GetComponent<VRTK_ObiRopeInteraction>();
               }
           }
       }
   }

   #endregion

}


Put this on the gameobject with the ObiRope:

Code:
using UnityEngine;
using Obi;

[RequireComponent(typeof(ObiPinConstraints))]
public class VRTK_ObiRopeInteraction : MonoBehaviour
{
   #region Fields
   
   public bool isGrabbable = true;
   
   private ObiPinConstraints pinConstraints;

   #endregion


   #region Mono Events

   private void Awake()
   {
       pinConstraints = GetComponent<ObiPinConstraints>();
   }

   private void Reset()
   {
       isGrabbable = true;
   }

   #endregion


   #region Rope Interaction

   public void GrabRope(InteractingInfo interactingInfo)
   {
       if (!isGrabbable) return;

       ObiPinConstraintBatch batch = pinConstraints.GetBatches()[0] as ObiPinConstraintBatch;

       pinConstraints.RemoveFromSolver(null);

       interactingInfo.pinIndex = batch.ConstraintCount;
       interactingInfo.grabbedParticle = interactingInfo.touchingParticle;
       batch.AddConstraint(interactingInfo.grabbedParticle.Value, interactingInfo.obiCollider, interactingInfo.pinOffset, interactingInfo.stiffness);

       pinConstraints.AddToSolver(null);

       pinConstraints.PushDataToSolver();
   }

   public void ReleaseRope(InteractingInfo interactingInfo)
   {
       if (!isGrabbable) return;

       ObiPinConstraintBatch batch = pinConstraints.GetBatches()[0] as ObiPinConstraintBatch;

       pinConstraints.RemoveFromSolver(null);

       if (interactingInfo.pinIndex.HasValue)
           batch.RemoveConstraint(interactingInfo.pinIndex.Value);

       pinConstraints.AddToSolver(null);

       pinConstraints.PushDataToSolver();
   }

   #endregion

}
Reply


Messages In This Thread
Grab the middle of a rope? - by BlueTel - 24-08-2017, 04:16 PM
RE: Grab the middle of a rope? - by josemendez - 24-08-2017, 05:47 PM
RE: Grab the middle of a rope? - by niZmo - 02-09-2017, 07:56 PM
RE: Grab the middle of a rope? - by Parker - 12-09-2017, 04:12 AM
RE: Grab the middle of a rope? - by niZmo - 12-09-2017, 04:31 AM
RE: Grab the middle of a rope? - by Parker - 12-09-2017, 02:01 PM
RE: Grab the middle of a rope? - by darkcser - 28-04-2018, 10:24 PM
RE: Grab the middle of a rope? - by niZmo - 30-04-2018, 06:42 PM
RE: Grab the middle of a rope? - by BlueTel - 08-09-2017, 04:20 PM
RE: Grab the middle of a rope? - by niZmo - 01-05-2018, 06:08 AM
RE: Grab the middle of a rope? - by darkcser - 02-05-2018, 05:19 AM
RE: Grab the middle of a rope? - by niZmo - 03-05-2018, 12:54 AM
RE: Grab the middle of a rope? - by darkcser - 04-05-2018, 04:13 PM
RE: Grab the middle of a rope? - by darkcser - 05-05-2018, 07:42 PM