Search Unity

Lerp/Smooth a tossed object (from- local expected position -to- server target position) over time?

Discussion in 'Multiplayer' started by CloudyVR, Sep 23, 2017.

  1. CloudyVR

    CloudyVR

    Joined:
    Mar 26, 2017
    Posts:
    715
    I would like a way to ease this transition over 1 second from an expected position to the network target position.

    In the below script I have created the Coroutine called DoWhileGrabbedRoutine(). When started it loops until the the object is ungrabbed. All it does is stores the position from the last frame.

    Once the object is ungrabbed the rigidbody is re-enabled and I use the delta position to calculate and apply a throw velocity.

    After a VR player ungrabs an intractable object I call CmdSetUnGrab which lets the server know to removes grabbed object authority and re-enable the networktransform for all clients.

    When this happens, the client who threw the object sees a sudden change in direction as the disagreement in position is corrected on the client once the networktransorm is enabled.

    So I added the tossEasingRoutine() Coroutine which starts immediately after the ungrab call and runs only on the client who threw the object.
    It runs for one second and I am hoping to find a way to Lerp from an expected position to the target position over that time:

    Code (csharp):
    1.  using VRTK;
    2.  
    3. public class NetworkGrabInteractableObject : NetworkTransform {
    4.  
    5.     Coroutine tossEasingRoutine = null;
    6.     private IEnumerator TossEasingRoutine(Vector3 throwVelocity) {
    7.         if (!isServer) {
    8.             Rigidbody rb = GetComponent<Rigidbody> ();
    9.             var netTansform = gameObject.GetComponent<NetworkTransform> ();
    10.             netTansform.enabled = true; //start sending updates for the palyerarea as it is parented
    11.  
    12.             var startTime = Time.time;
    13.             float zeroToOne = 0;
    14.             while (zeroToOne  <= 1) {
    15.                 yield return null;
    16.                 zeroToOne = Mathf.Clamp01(Time.time - startTime); //go from zero to one in one second
    17.  
    18.                 // Need help finding a way to get the expected position!!!!!!!!!!!!!!!!!!!!
    19.                 // I cant figure out how to override networktransform in any way.
    20.                 var ExpectedPosition = // Not sure how to calculate this?
    21.                 var ExpectedVelocity = // Not sure how to calculate this?
    22.  
    23.                 transform.position = Vector3.Lerp(ExpectedPosition , netTansform.targetSyncPosition, zeroToOne );
    24.                 rb.velocity  = Vector3.Lerp(ExpectedVelocity , netTansform.targetSyncVelocity, zeroToOne );
    25.  
    26.             }
    27.         }
    28.     }
    29.  
    30.  
    31.  
    32.  
    33.     [SerializeField]
    34.     private float throwVelocityMultiplier = 1.0f;
    35.     private Vector3 lastPosition = Vector3.zero; // Store delta position so throw velocity can be calculated.
    36.     private Coroutine graggedCoroutine = null; // Coroutine to run while object is grabbed (and store delta position).
    37.  
    38.     void Start () {
    39.         // Subscribe to the controller grab/ungrab event.
    40.         GetComponent<VRTK_InteractableObject>().InteractableObjectGrabbed += new InteractableObjectEventHandler(ObjectGrabbed);
    41.         GetComponent<VRTK_InteractableObject>().InteractableObjectUngrabbed += new InteractableObjectEventHandler(ObjectUnGrabbed);
    42.     }
    43.  
    44.     //UNGRABBING
    45.     private void ObjectUnGrabbed(object sender, InteractableObjectEventArgs e) {
    46.         transform.parent = null;
    47.  
    48.         var throwVelocity = Vector3.zero;
    49.         if (graggedCoroutine != null) {
    50.             StopCoroutine (graggedCoroutine);
    51.  
    52.             throwVelocity = (transform.position - lastPosition) / Time.deltaTime;
    53.             throwVelocity *= throwVelocityMultiplier;
    54.         }
    55.  
    56.         player.GetComponent<MarineVRPlayerController>().CmdSetUnGrab(gameObject, throwVelocity, playerID);
    57.         tossEasingRoutine = StartCoroutine (TossEasingRoutine(throwVelocity));
    58.     }
    59.  
    60.     IEnumerator DoWhileGrabbedRoutine(object sender) {
    61.         VRTK_InteractableObject controller = ((VRTK_InteractableObject) sender);
    62.         while (isActiveAndEnabled && controller.IsGrabbed()) {
    63.             // Get a delta position so throw velocity can be calculated later.
    64.             lastPosition = transform.position;
    65.             yield return null;
    66.         }
    67.     }
    68. }
    I was thinking of creating an invisible "copy" of the thrown gameobject (without networktransform). Then use it as the "expected" position. And destroy it after 1 second??


    PARTIALLY WORKING CONCEPT:

    By creating a fake gameobject that doesn't interact with anything but does follow the curved path of gravity, then easing between the two over time has made this effect look a lot better on the client who threw the object. However because the fake object goes through the floor and walls its only a partial fix. Hopefully I can create colliders on different layers so the fake object can also interact with the world (just not interact with the overlapping object).
    Code (csharp):
    1.  
    2.     private IEnumerator TossEasingRoutine(Vector3 throwVelocity) {
    3.      
    4.         if (!isServer) {
    5.             var fakeGameobject = new GameObject ();
    6.             Destroy (fakeGameobject, 1.1f);
    7.             var fakeRb = fakeGameobject.AddComponent<Rigidbody> ();
    8.             fakeRb.velocity = throwVelocity;
    9.             var fakeCol = fakeGameobject.AddComponent<BoxCollider> ();
    10.             fakeCol.isTrigger = true;
    11.  
    12.             fakeGameobject.transform.position = transform.position;
    13.             fakeGameobject.transform.rotation = transform.rotation;
    14.  
    15.  
    16.             Rigidbody rb = GetComponent<Rigidbody> ();
    17.             var netTansform = gameObject.GetComponent<NetworkTransform> ();
    18.             netTansform.enabled = true; //start sending updates for the palyerarea as it is parented
    19.  
    20.             var startTime = Time.time;
    21.             float zeroToOne = 0;
    22.             while (zeroToOne  <= 1) {
    23.                 yield return null;
    24.                 zeroToOne = Mathf.Clamp01(Time.time - startTime); //go from zero to one in one second
    25.  
    26.                 transform.position = Vector3.Lerp(fakeGameobject.transform.position, netTansform.targetSyncPosition, zeroToOne);
    27.                 rb.velocity  = Vector3.Lerp(fakeRb.velocity, netTansform.targetSyncVelocity, zeroToOne );
    28.  
    29.             }
    30.         }
    31.     }
    32.  
    Is this a good approach?
     
    Last edited: Sep 23, 2017