private void Update()
    {
        if (connectedDeviceChanged)
        {
            connectedDeviceChanged = false;

            OnConnectedDeviceChanged.Invoke();
        }

        if (previousScannedDevice != currentScannedDevice)
        {
            OnScanning.Invoke(0f);
        }
        else if (ViveRole.IsValidIndex(currentScannedDevice) && sentDevice != currentScannedDevice)
        {
            var scannedDuration = Time.time - lastScannedChangedTime;
            if (scannedDuration > scanDuration)
            {
                if (!ViveRole.IsValidIndex(sentDevice) && scannedReticle != null)
                {
                    scannedReticle.gameObject.SetActive(true);
                    scannedReticle.position = VivePose.GetPose(currentScannedDevice, VROrigin).pos;
                }

                OnDeviceScanned.Invoke(sentDevice = currentScannedDevice);
                OnScanning.Invoke(0f);
            }
            else
            {
                OnScanning.Invoke(scannedDuration / scanDuration);
            }
        }
    }
Ejemplo n.º 2
0
    // Update is called once per frame
    void Update()
    {
        trackerPose = VivePose.GetPose(HandRole.RightHand);

        // Engine move
        if (WristBandInput.bBeginMove)
        {
            OnMoveBegin();
        }
        if (WristBandInput.bEndMove)
        {
            OnMoveEnd();
        }
        if (WristBandInput.bIsMoving && stayingColliders.Count == 0)
        {
            Engine.position  += trackerPose.pos - oriTransOfTracker;
            oriTransOfTracker = trackerPose.pos;
        }

        // Call ToolBox
        if (WristBandInput.bToolBox)
        {
            ani.clip = toolboxClip;
            ani.Play();
        }

        // DisAssemble
        if (WristBandInput.bDisAssemble)
        {
            ani.clip = disassembleClip;
            ani.Play();
        }
    }
Ejemplo n.º 3
0
    public IEnumerator WhileTargeting(HandRole origin, GameObject target)
    {
        if (origin == HandRole.RightHand)
        {
            GameObject animation = UIManager.instance.PlayAnimation(AnimationType.ArrowPullPush);

            while (rightIsTargeting && showGuidingArrows)
            {
                UIManager.instance.SetArrowPosition(animation, Vector3.Lerp(VivePose.GetPose(HandRole.RightHand).pos, target.transform.position, 0.5f), VivePose.GetPose(HandRole.RightHand).pos);
                yield return(null);
            }

            UIManager.instance.StopAnimation(animation);
        }
        else if (origin == HandRole.LeftHand)
        {
            GameObject animation = UIManager.instance.PlayAnimation(AnimationType.ArrowPullPush);

            while (leftIsTargeting && showGuidingArrows)
            {
                UIManager.instance.SetArrowPosition(animation, Vector3.Lerp(VivePose.GetPose(HandRole.LeftHand).pos, target.transform.position, 0.5f), VivePose.GetPose(HandRole.LeftHand).pos);
                yield return(null);
            }

            UIManager.instance.StopAnimation(animation);
        }
    }
Ejemplo n.º 4
0
    IEnumerator CheckPose()
    {
        if (hasTexts)
        {
            StartCoroutine(UIManager.instance.ShowText(texts[0]));
        }

        GameObject rightArrow = UIManager.instance.PlayAnimation(AnimationType.ArrowUp);
        GameObject leftArrow  = UIManager.instance.PlayAnimation(AnimationType.ArrowUp);

        float counter  = 0;
        float interval = 0.1f;

        while (!embodied)
        {
            float threshold         = VivePose.GetPose(DeviceRole.Hmd).pos.y *embodyThreshold;
            float rightHandProgress = Mathf.Clamp(VivePose.GetPose(HandRole.RightHand).pos.y / VivePose.GetPose(DeviceRole.Hmd).pos.y, 0, 1);
            float leftHandProgress  = Mathf.Clamp(VivePose.GetPose(HandRole.LeftHand).pos.y / VivePose.GetPose(DeviceRole.Hmd).pos.y, 0, 1);

            UIManager.instance.SetArrowUpPosition(rightArrow, HandRole.RightHand);
            UIManager.instance.SetArrowUpPosition(leftArrow, HandRole.LeftHand);

            if (leftHandProgress > threshold && rightHandProgress > threshold)
            {
                counter += Time.deltaTime;

                if (counter >= interval + 0.02f)
                {
                    ViveInput.TriggerHapticVibration(HandRole.RightHand, interval, 85 * rightHandProgress, 0.25f * rightHandProgress);
                    ViveInput.TriggerHapticVibration(HandRole.LeftHand, interval, 85 * leftHandProgress, 0.25f * leftHandProgress);

                    counter = 0;
                }

                if (VivePose.GetPose(HandRole.RightHand).pos.y > VivePose.GetPose(DeviceRole.Hmd).pos.y&& VivePose.GetPose(HandRole.LeftHand).pos.y > VivePose.GetPose(DeviceRole.Hmd).pos.y)
                {
                    UIManager.instance.StopAnimation(rightArrow);
                    UIManager.instance.StopAnimation(leftArrow);
                    embodied = true;

                    yield return(null);

                    DataRecorder.instance.SetEvent("Embodied");
                    ViveInput.TriggerHapticVibration(HandRole.RightHand, interval, 200, 0.9f);
                    ViveInput.TriggerHapticVibration(HandRole.LeftHand, interval, 200, 0.9f);

                    LocalSceneManager.instance.stage0done = true;
                    PrepStage1();

                    break;
                }
            }

            yield return(null);
        }
    }
Ejemplo n.º 5
0
    public void Move(bool MoveMe)
    {
        Vector3 movementVector = Vector3.forward * 0;

        if (MoveMe)
        {
            movementVector = Vector3.ProjectOnPlane(VivePose.GetPose(viveRole).forward, Vector3.up) * MovementMultiplier;
        }
        player.SimpleMove(movementVector); // always call simple move or you get stuck falling
    }
Ejemplo n.º 6
0
 void Update()
 {
     if (false && VRModule.TryGetConnectedDeviceIndex(trackerSerialNumber, out uint deviceIndex))
     {
         transform.position = VivePose.GetPose(deviceIndex).pos;
         transform.rotation = VivePose.GetPose(deviceIndex).rot;
     }
     else
     {
         transform.position = transformSource.position;
         transform.rotation = transformSource.rotation;
     }
 }
    public virtual void OnNewPoses()
    {
        UpdateRenderModel();

        if (isActiveAndEnabled && m_applyTracking)
        {
            var deviceIndex = GetCurrentDeviceIndex();
            if (VivePose.IsValid(deviceIndex))
            {
                TrackPose(VivePose.GetPose(deviceIndex), m_origin);
            }
        }
    }
Ejemplo n.º 8
0
    IEnumerator RotateBacteria(HandRole hand)
    {
        Vector3 initialControllerPosition = VivePose.GetPose(hand).pos;
        Vector3 controllerOffset;

        while (ControllerManager.instance.GetIsPressed(hand))
        {
            controllerOffset = VivePose.GetPose(hand).pos - initialControllerPosition;

            Rotate(controllerOffset);

            yield return(null);
        }
    }
Ejemplo n.º 9
0
    public virtual void OnNewPoses()
    {
        var deviceIndex = m_viveRole.GetDeviceIndex();

        if (VRModule.IsValidDeviceIndex(deviceIndex))
        {
            m_staticExCamPose = VivePose.GetPose(deviceIndex);
        }

        if (isQuadViewActive)
        {
            RigidPose.SetPose(transform, m_staticExCamPose, m_origin);
        }
    }
Ejemplo n.º 10
0
    public virtual void OnNewPoses()
    {
        var deviceIndex = m_viveRole.GetDeviceIndex();
        var deviceValid = VRModule.IsValidDeviceIndex(deviceIndex);

        if (deviceValid)
        {
            m_staticExCamPose = VivePose.GetPose(deviceIndex);
        }

        if (deviceValid || m_staticExCamEnabled)
        {
            Pose.SetPose(transform, m_staticExCamPose, m_origin);
        }
    }
    private void Update()
    {
        if (ViveInput.GetPressDownEx <HandRole>(HandRole.RightHand, ControllerButton.Trigger))
        {
            if (Time.time - lastFireTime < coolTime)
            {
                return;
            }

            Pose    pose     = VivePose.GetPose(HandRole.RightHand);
            Vector3 position = pose.pos;
            Vector3 forward  = pose.rot * Vector3.forward;
            Spawn(position, forward, 0);

            lastFireTime = Time.time;
        }
    }
        public void UpdateState()
        {
            if (alreadySelected)
            {
                return;
            }
            List <SelectWall> wallCandidates = ReconstructManager.Instance.GetWallCandidate();

            HTC.UnityPlugin.Utility.RigidPose rightHandPose = VivePose.GetPose(HandRole.RightHand);
            Matrix4x4  matRot       = Matrix4x4.Rotate(rightHandPose.rot);
            Vector3    rightArmPos  = rightHandPose.pos;
            Vector3    rightHandDir = matRot.GetColumn(2);
            RaycastHit hit;
            int        hitLayer = (1 << ARRender.UnityRenderOnTopNoShadowLayer);

            if (Physics.Raycast(rightArmPos, rightHandDir, out hit, 99999, hitLayer))
            {
                foreach (SelectWall wall in wallCandidates)
                {
                    int hashL = wall.selectWall.GetHashCode();
                    int hashH = hit.collider.gameObject.GetHashCode();
                    if (hashL == hashH)
                    {
                        wall.SetSelectColor();

                        bool triggerpress = ViveInput.GetPress(HandRole.RightHand, ControllerButton.Trigger);
                        if (triggerpress)
                        {
                            GameObject finalWall = ReconstructManager.SetPivotInMeshCenter(
                                wall.origWall.transform,
                                wall.origWall.GetComponent <MeshCollider>().sharedMesh,
                                ReconstructManager.Instance.selectedWallRoot.transform,
                                ReconstructManager.Instance.selectWallMaterial,
                                wall.origWall.name + "_convexWall : " + wall.area,
                                wall.normal, wall.center);

                            finalWall.layer = AdvanceRender.ScanLiveMeshLayer;
                            break;
                        }
                    }
                }
            }

            alreadySelected = CheckSelectDone(wallCandidates);
        }
Ejemplo n.º 13
0
    // Update is called once per frame
    private void Update()
    {
        curLeftPos  = VivePose.GetPose(leftHandRole).pos;
        curRightPos = VivePose.GetPose(rightHandRole).pos;

        leftPunchDirection  = (curLeftPos - lastLeftPos);
        rightPunchDirection = (curRightPos - lastRightPos);

        leftMomentum  = leftPunchDirection.magnitude / Time.deltaTime;
        rightMomentum = rightPunchDirection.magnitude / Time.deltaTime;

        CheckPunch();
        //CheckJump();
        CheckRun();

        lastLeftPos  = curLeftPos;
        lastRightPos = curRightPos;
    }
Ejemplo n.º 14
0
    /// <summary>
    /// Throws an error of <see cref="currentPoseTransform"/> is not assigned.
    /// </summary>
    private void SetAdjustmentReferencePoses()
    {
        calibrationControllerReferencePose = VivePose.GetPose(calibrationController, null);
        for (int i = 0; i < poseTransforms.Length; i++)
        {
            pointCloudReferencePoses[i].position = poseTransforms[i].transform.position;
            pointCloudReferencePoses[i].rotation = poseTransforms[i].transform.rotation;
        }

        if (skyboxControl)
        {
            skyboxReferenceRotation = skyboxControl.SkyboxMaterial.GetFloat(SkyboxControl._Rotation);
        }
        if (RenderSettings.skybox)
        {
            skyboxReferenceRotation = RenderSettings.skybox.GetFloat(SkyboxControl._Rotation);
        }
    }
Ejemplo n.º 15
0
    private void AdjustSkybox()
    {
        Pose controllerPose = VivePose.GetPose(calibrationController);
        // The delta rotation of the hand controller
        Quaternion rotationOffset = controllerPose.rotation * Quaternion.Inverse(calibrationControllerReferencePose.rotation);

        print("rotationOffset: w=" + rotationOffset.w + " x=" + rotationOffset.x + " y=" + rotationOffset.y + " z=" + rotationOffset.z);

        // Force unity to use "small" angles (below 180 degrees)
        if (rotationOffset.w < 0f)
        {
            rotationOffset.w = -rotationOffset.w;
            rotationOffset.x = -rotationOffset.x;
            rotationOffset.y = -rotationOffset.y;
            rotationOffset.z = -rotationOffset.z;
        }
        rotationOffset.ToAngleAxis(out float deltaRotationAngle, out Vector3 deltaRotationAxis);
        // Force Unity to not switch the axis after 180 degrees rotation. We simply set current rotation as reference
        if (deltaRotationAngle > 150)
        {
            print("Resetting offset angle.");
            SetAdjustmentReferencePoses();
            return;
        }

        print("rotationOffset angle: " + deltaRotationAngle + "\t axis: " + deltaRotationAxis);

        Quaternion scaledRotationOffset      = Quaternion.Slerp(Quaternion.identity, rotationOffset, adjustmentRatio);
        Vector3    scaledRotationOffsetEuler = scaledRotationOffset.eulerAngles;

        print("skyboxReferenceRotation: " + skyboxReferenceRotation);

        float newRotation = skyboxReferenceRotation + scaledRotationOffsetEuler.y;

        newRotation %= 360;
        if (RenderSettings.skybox)
        {
            RenderSettings.skybox.SetFloat(SkyboxControl._Rotation, newRotation);
        }
        else
        {
            SkyboxControl.SkyboxRotation_Event.Invoke(this, newRotation);
        }
    }
Ejemplo n.º 16
0
    // Update is called once per frame
    void Update()
    {
        last      = VivePose.GetPose(rightHandRole).pos;
        uiHandRot = VivePose.GetPose(rightHandRole).rot;

        //transform.LookAt(Camera.main.transform);

        Vector3 euler  = righthand.eulerAngles;
        float   eulery = Mathf.Abs(euler.y - 360.0f);


        if (eulery >= 35.0f && eulery < 200.0f && last.y >= 1.6f)
        {
            handui.gameObject.SetActive(true);
        }
        else if (last.y <= 1.5)
        {
            handui.gameObject.SetActive(false);
        }
    }
Ejemplo n.º 17
0
    private void AdjustPointcloud(TrackerTransform targetTransform, Pose refPose)
    {
        Pose controllerPose = VivePose.GetPose(calibrationController);
        // The delta rotation of the hand controller
        Quaternion rotationOffset = controllerPose.rotation * Quaternion.Inverse(calibrationControllerReferencePose.rotation);

        print("rotationOffset: w=" + rotationOffset.w + " x=" + rotationOffset.x + " y=" + rotationOffset.y + " z=" + rotationOffset.z);
        // Force Unity to use "small" angles (below 180 degrees)
        if (rotationOffset.w < 0f)
        {
            rotationOffset.w = -rotationOffset.w;
            rotationOffset.x = -rotationOffset.x;
            rotationOffset.y = -rotationOffset.y;
            rotationOffset.z = -rotationOffset.z;
        }
        rotationOffset.ToAngleAxis(out float deltaRotationAngle, out Vector3 deltaRotationAxis);
        // Force Unity to not switch the axis after 180 degrees rotation. We simply set current rotation as reference
        if (deltaRotationAngle > 150)
        {
            SetAdjustmentReferencePoses();
            return;
        }
        print("rotationOffset angle: " + deltaRotationAngle + "\t axis: " + deltaRotationAxis);
        Vector3 positionOffset = controllerPose.position - calibrationControllerReferencePose.position;


        // Always rotate and position from the reference
        targetTransform.transform.rotation = refPose.rotation;
        targetTransform.transform.position = refPose.position;

        Quaternion scaledRotationOffset = Quaternion.Slerp(Quaternion.identity, rotationOffset, adjustmentRatio);

        print("scaledRotationOffset: " + scaledRotationOffset);
        scaledRotationOffset.ToAngleAxis(out float scaledDeltaRotationAngle, out Vector3 scaledDeltaRotationAxis);
        print("scaledRotationOffset angle: " + scaledDeltaRotationAngle + "\t axis: " + scaledDeltaRotationAxis);


        targetTransform.transform.RotateAround(calibrationControllerReferencePose.position, scaledDeltaRotationAxis, scaledDeltaRotationAngle);
        targetTransform.transform.position += (positionOffset * adjustmentRatio);
    }
Ejemplo n.º 18
0
    void SendAnnotations()
    {
        Dictionary <string, object> data = new Dictionary <string, object>();

        data["head_Position_x"]             = Camera.main.transform.position.x;
        data["head_Position_y"]             = Camera.main.transform.position.y;
        data["head_Position_z"]             = Camera.main.transform.position.z;
        data["head_rotation_x"]             = Camera.main.transform.rotation.eulerAngles.x;
        data["head_rotation_y"]             = Camera.main.transform.rotation.eulerAngles.y;
        data["head_rotation_z"]             = Camera.main.transform.rotation.eulerAngles.z;
        data["left_controller_Position_x"]  = VivePose.GetPose(HandRole.LeftHand).pos.x;
        data["left_controller_Position_y"]  = VivePose.GetPose(HandRole.LeftHand).pos.y;
        data["left_controller_Position_z"]  = VivePose.GetPose(HandRole.LeftHand).pos.z;
        data["right_controller_Position_x"] = VivePose.GetPose(HandRole.RightHand).pos.x;
        data["right_controller_Position_y"] = VivePose.GetPose(HandRole.RightHand).pos.y;
        data["right_controller_Position_z"] = VivePose.GetPose(HandRole.RightHand).pos.z;
        data["left_controller_rotation_x"]  = VivePose.GetPose(HandRole.LeftHand).rot.eulerAngles.x;
        data["left_controller_rotation_y"]  = VivePose.GetPose(HandRole.LeftHand).rot.eulerAngles.y;
        data["left_Controller_rotation_z"]  = VivePose.GetPose(HandRole.LeftHand).rot.eulerAngles.z;
        data["right_controller_rotation_x"] = VivePose.GetPose(HandRole.RightHand).rot.eulerAngles.x;
        data["right_controller_rotation_y"] = VivePose.GetPose(HandRole.RightHand).rot.eulerAngles.y;
        data["right_controller_rotation_z"] = VivePose.GetPose(HandRole.RightHand).rot.eulerAngles.z;
        data["left_controller_pressed"]     = ControllerManager.instance.GetIsPressed(HandRole.RightHand);
        data["right_controller_pressed"]    = ControllerManager.instance.GetIsPressed(HandRole.LeftHand);
        data["AOI_left_controller"]         = GetControllerAOI(HandRole.LeftHand);
        data["AOI_right_controller"]        = GetControllerAOI(HandRole.RightHand);

        if (GetAOI() != null)
        {
            data["AOI_name"] = LocalSceneManager.instance.currentStage.thisScene + "_" + GetAOI().name;
        }
        else
        {
            data["AOI_name"] = "";
        }
        data["Event_name"] = GetEvent();

        annotationPub.SendAnnotation(label: "Custom Data", customData: data);
    }
Ejemplo n.º 19
0
 public void SetArrowUpPosition(GameObject arrow, HandRole hand)
 {
     arrow.transform.position = VivePose.GetPose(hand).pos + Vector3.up * upArrowDistance;
 }
Ejemplo n.º 20
0
 // Use this for initialization
 private void Start()
 {
     lastLeftPos  = VivePose.GetPose(leftHandRole).pos;
     lastRightPos = VivePose.GetPose(rightHandRole).pos;
     rb           = GetComponent <Rigidbody>();
 }
Ejemplo n.º 21
0
 void Start()
 {
     handui = transform.GetComponentInChildren <Image>();
     first  = VivePose.GetPose(rightHandRole).pos;
 }
Ejemplo n.º 22
0
    /*private IEnumerator PullPush(Vector3 target, HandRole hand, Action<Direction> action)
     * {
     *  yield return null;
     *
     *  float threshold = 20;
     *  Debug.Log("Registering Pull and Push");
     *
     *  Vector3 playerForward = target - Camera.main.transform.position;
     *  if (hand == HandRole.RightHand)
     *  {
     *      while (GetIsPressed(hand))
     *      {
     *          if (VivePose.GetAngularVelocity(hand).sqrMagnitude > 30)
     *          {
     *              if (Vector3.Cross(playerForward, VivePose.GetAngularVelocity(hand)).x < threshold * -1 && Mathf.Abs(Vector3.Dot(playerForward, VivePose.GetAngularVelocity(hand))) < 30)
     *              {
     *                  Debug.Log("Push");
     *                  action(Direction.Backward);
     *                  break;
     *              }
     *              else if (Vector3.Cross(playerForward, VivePose.GetAngularVelocity(hand)).x > threshold && Mathf.Abs(Vector3.Dot(playerForward, VivePose.GetAngularVelocity(hand))) < 30)
     *              {
     *                  Debug.Log("Pull");
     *                  action(Direction.Forward);
     *                  break;
     *              }
     *          }
     *          yield return null;
     *      }
     *  }
     *  else if (hand == HandRole.LeftHand)
     *  {
     *      while (GetIsPressed(hand))
     *      {
     *          if (VivePose.GetAngularVelocity(hand).sqrMagnitude > 30)
     *          {
     *              if (Vector3.Cross(playerForward, VivePose.GetAngularVelocity(hand)).x < threshold * -1 && Mathf.Abs(Vector3.Dot(playerForward, VivePose.GetAngularVelocity(hand))) < 30)
     *              {
     *                  Debug.Log("Pull");
     *                  action(Direction.Forward);
     *                  break;
     *              }
     *              else if (Vector3.Cross(playerForward, VivePose.GetAngularVelocity(hand)).x > threshold && Mathf.Abs(Vector3.Dot(playerForward, VivePose.GetAngularVelocity(hand))) < 30)
     *              {
     *                  Debug.Log("Push");
     *                  action(Direction.Backward);
     *                  break;
     *              }
     *          }
     *          yield return null;
     *      }
     *  }
     * }*/
    private IEnumerator PullPush(HandRole hand, Action <Direction> action)
    {
        yield return(null);

        Vector3   velocity;
        Transform camera = Camera.main.transform;

        while (GetIsPressed(hand))
        {
            velocity = VivePose.GetVelocity(hand);

            if (velocity.sqrMagnitude > 2)
            {
                if (velocity.y > -1 && velocity.y < 1)
                {
                    float dot   = Vector3.Dot(Vector3.forward, camera.InverseTransformVector(velocity) - camera.InverseTransformVector(VivePose.GetPose(hand).pos));
                    float angle = Vector3.Angle(Vector3.forward, camera.InverseTransformVector(velocity) - camera.InverseTransformVector(VivePose.GetPose(hand).pos));

                    if (angle < 60 || angle > 120)
                    {
                        showGuidingArrows = false;

                        yield return(null);

                        if (Mathf.Sign(dot) == 1)
                        {
                            DataRecorder.instance.SetEvent("Push");
                            action(Direction.Backward);

                            break;
                        }
                        else if (Mathf.Sign(dot) == -1)
                        {
                            DataRecorder.instance.SetEvent("Pull");
                            action(Direction.Forward);

                            break;
                        }
                    }
                }
            }

            yield return(null);
        }
    }
    public virtual void OnNewPoses()
    {
        previousScannedDevice = currentScannedDevice;
        currentScannedDevice  = ViveRole.INVALID_DEVICE_INDEX;

        for (uint i = 0; i < ViveRole.MAX_DEVICE_COUNT; ++i)
        {
            if (ChangeProp.Set(ref deviceConnected[i], VivePose.IsConnected(i)))
            {
                connectedDeviceChanged = true;

                if (!deviceConnected[i] && sentDevice == i)
                {
                    if (sentDevice == i)
                    {
                        sentDevice = ViveRole.INVALID_DEVICE_INDEX;
                    }

                    if (scannedReticle != null)
                    {
                        scannedReticle.gameObject.SetActive(false);
                    }
                }
            }

            if (!deviceConnected[i])
            {
                continue;
            }

            var pose = VivePose.GetPose(i, VROrigin);

            if (sentDevice == i && scannedReticle != null)
            {
                scannedReticle.position = pose.pos;
            }

            hits[0] = null;
            var hitCount = Physics.OverlapSphereNonAlloc(pose.pos, radius, hits);
            if (hitCount > 0 && hits[0].transform.IsChildOf(transform))
            {
                if (!ViveRole.IsValidIndex(currentScannedDevice))
                {
                    // not scanned any device yet this frame
                    currentScannedDevice = i;
                }
                else
                {
                    // multiple device scanned this frame
                    currentScannedDevice = ViveRole.INVALID_DEVICE_INDEX;
                    break;
                }

                hits[0] = null;
            }
        }

        if (previousScannedDevice != currentScannedDevice)
        {
            lastScannedChangedTime = Time.time;
        }
    }
Ejemplo n.º 24
0
    IEnumerator Grabbing()
    {
        yield return(null);

        if (hand == HandRole.LeftHand)
        {
            while (!ControllerManager.instance.GetIsPressed(HandRole.RightHand))
            {
                yield return(null);
            }
        }
        else if (hand == HandRole.RightHand)
        {
            while (!ControllerManager.instance.GetIsPressed(HandRole.LeftHand))
            {
                yield return(null);
            }
        }

        RigidPose  vivePose        = VivePose.GetPose(hand);
        Quaternion initialRotation = vivePose.rot;
        float      timer           = 0;
        float      vibrationTimer  = 0;

        if (hand == HandRole.RightHand)
        {
            rotationPoint.transform.LookAt(Stage3Manager.instance.activeMoleculeSet.manager.nam.bindings[5]);
        }
        else if (hand == HandRole.LeftHand)
        {
            rotationPoint.transform.LookAt(Stage3Manager.instance.activeMoleculeSet.manager.nag.atoms[2]);
        }
        GameObject animation = null;

        if (Stage3Manager.instance.showAnimations)
        {
            animation = UIManager.instance.PlayAnimation(AnimationType.ArrowRotation, rotationPoint);
        }

        while (ControllerManager.instance.GetIsPressed(hand))
        {
            vivePose = VivePose.GetPose(hand);

            currentAngle = Mathf.Abs(Mathf.DeltaAngle(initialRotation.eulerAngles.z, vivePose.rot.eulerAngles.z));

            //UIManager.instance.SetArrowPosition(animation, rotationPoint.position);


            progress = Mathf.Clamp((currentAngle - Stage3Manager.instance.twistMinThreshold) / (angle - Stage3Manager.instance.twistMinThreshold), 0, 1);

            timer += Time.deltaTime;

            //if (timer >= 0.31f) ViveInput.TriggerHapticVibration(hand, 0.3f, 40 + 60 * progress, 0.1f);

            switch (Stage3Manager.instance.activeMoleculeSet.manager.currentState)
            {
            case MoleculeManager.MoleculeState.sn1:
                if (hand == HandRole.RightHand)
                {
                    RenderLine(new Vector3[] { _o.position, Stage3Manager.instance.activeMoleculeSet.manager.nam.bindings[5].position });
                }
                else
                {
                    lineRenderer.enabled = false;
                }
                break;

            case MoleculeManager.MoleculeState.sn2:

                if (hand == HandRole.RightHand)
                {
                    RenderLine(new Vector3[] { _o.position, Stage3Manager.instance.activeMoleculeSet.manager.nam.bindings[5].position });
                }
                else
                {
                    RenderLine(new Vector3[] { _o.position, Stage3Manager.instance.activeMoleculeSet.manager.nag.atoms[3].position });
                }

                break;

            case MoleculeManager.MoleculeState.state2:
                if (hand == HandRole.RightHand)
                {
                    RenderLine(new Vector3[] { _o.position, Stage3Manager.instance.activeMoleculeSet.manager.nam.bindings[5].position });
                }
                else
                {
                    RenderLine(new Vector3[] { _o.position, Stage3Manager.instance.activeMoleculeSet.manager.nag.bindings[2].position });
                }
                break;

            default:
                lineRenderer.enabled = false;
                break;
            }

            if (currentAngle > Stage3Manager.instance.twistTargetAngle && hand == HandRole.RightHand)
            {
                vibrationTimer += Time.deltaTime;
                if (vibrationTimer >= 0.5f)
                {
                    vibrationTimer = 0;
                    ViveInput.TriggerHapticVibration(hand, 0.5f, Mathf.Clamp(20 * Stage3Manager.instance.breakTime, 0, 85));
                }

                if (timer >= Stage3Manager.instance.breakTime && !(Stage3Manager.instance.breakTime >= 10))
                {
                    Stage3Manager.instance.activeMoleculeSet.manager.nag.thresholdReached = true;
                    StartCoroutine(Stage3Manager.instance.CompleteMoleculeSet());
                    ControllerManager.instance.SetIsPressed(HandRole.RightHand, false);
                    ControllerManager.instance.SetIsPressed(HandRole.LeftHand, false);
                }
            }

            yield return(new WaitForEndOfFrame());
        }

        if (Stage3Manager.instance.showAnimations)
        {
            UIManager.instance.StopAnimation(animation);
        }

        currentAngle         = 0;
        progress             = 0;
        lineRenderer.enabled = false;

        yield return(null);
    }