Ejemplo n.º 1
0
        protected override void OnDragEnded(BaseHandle handle, HandleEventData eventData)
        {
            var gridItem = m_DragObject.GetComponent <AssetGridItem>();

            if (!isOverShoulder(eventData.rayOrigin))
            {
                if (gridItem.m_PreviewObjectTransform)
                {
                    placeObject(gridItem.m_PreviewObjectTransform, m_PreviewPrefabScale);
                }
                else
                {
                    switch (data.type)
                    {
                    case "Prefab":
                    case "Model":
#if UNITY_EDITOR
                        var go        = (GameObject)PrefabUtility.InstantiatePrefab(data.asset);
                        var transform = go.transform;
                        transform.position = gridItem.transform.position;
                        transform.rotation = MathUtilsExt.ConstrainYawRotation(gridItem.transform.rotation);
#else
                        var go = (GameObject)Instantiate(data.asset, gridItem.transform.position, gridItem.transform.rotation);
#endif

                        addToSpatialHash(go);
                        break;
                    }
                }
            }

            StartCoroutine(HideGrabbedObject(m_DragObject.gameObject, gridItem.m_Cube));
        }
Ejemplo n.º 2
0
        void OnPanZoomDragStarted(Transform rayOrigin)
        {
            var referenceTransform = miniWorld.referenceTransform;

            m_StartPosition = referenceTransform.position;
            var rayOriginPosition = miniWorld.miniWorldTransform.InverseTransformPoint(rayOrigin.position);

            // On introduction of second ray
            if (m_Rays.Count == 1)
            {
                var rayToRay = miniWorld.miniWorldTransform.InverseTransformPoint(m_Rays[0].position) - rayOriginPosition;
                var midPoint = rayOriginPosition + rayToRay * 0.5f;
                m_StartScale       = referenceTransform.localScale.x;
                m_StartDistance    = rayToRay.magnitude;
                m_StartMidPoint    = MathUtilsExt.ConstrainYawRotation(referenceTransform.rotation) * midPoint;
                m_StartDirection   = rayToRay;
                m_StartDirection.y = 0;
                m_StartOffset      = m_StartMidPoint * m_StartScale;

                m_StartPosition += m_StartOffset;
                m_StartYaw       = referenceTransform.rotation.eulerAngles.y;
            }
            else
            {
                m_StartMidPoint = rayOriginPosition;
            }
            m_Rays.Add(rayOrigin);
        }
Ejemplo n.º 3
0
        IEnumerator VacuumToViewer(IVacuumable vacuumable)
        {
            var vacuumTransform = vacuumable.transform;
            var startPosition   = vacuumTransform.position;
            var startRotation   = vacuumTransform.rotation;

            var offset = defaultOffset;

            offset.z += vacuumable.vacuumBounds.extents.z;
            offset   *= this.GetViewerScale();

            var camera       = CameraUtils.GetMainCamera().transform;
            var destPosition = camera.position + MathUtilsExt.ConstrainYawRotation(camera.rotation) * offset;
            var destRotation = Quaternion.LookRotation(camera.forward) * defaultTilt;

            var         currentValue    = 0f;
            var         currentVelocity = 0f;
            var         currentDuration = 0f;
            const float kTargetValue    = 1f;
            const float kTargetDuration = 0.5f;

            while (currentDuration < kTargetDuration)
            {
                currentDuration         += Time.deltaTime;
                currentValue             = MathUtilsExt.SmoothDamp(currentValue, kTargetValue, ref currentVelocity, kTargetDuration, Mathf.Infinity, Time.deltaTime);
                vacuumTransform.position = Vector3.Lerp(startPosition, destPosition, currentValue);
                vacuumTransform.rotation = Quaternion.Lerp(startRotation, destRotation, currentValue);
                yield return(null);
            }

            m_VacuumingCoroutines.Remove(vacuumTransform);
        }
Ejemplo n.º 4
0
        public void ConstrainYawRotation()
        {
            var rotation    = new Quaternion(4, 3, 2, 1);
            var newRotation = MathUtilsExt.ConstrainYawRotation(rotation);

            Assert.AreEqual(new Quaternion(0, rotation.y, 0, rotation.w), newRotation);
        }
Ejemplo n.º 5
0
        protected override void OnDragging(BaseHandle baseHandle, HandleEventData eventData)
        {
            if (m_ClickedField)
            {
                var rayOrigin = eventData.rayOrigin;
                m_DragDistance = (rayOrigin.position - m_DragStarts[rayOrigin]).magnitude;

                var numericField = m_ClickedField as NumericInputField;
                if (numericField)
                {
                    if (m_DragDistance > NumericInputField.DragDeadzone)
                    {
                        CancelSingleClick();
                    }

                    numericField.SliderDrag(eventData.rayOrigin);
                }
            }

            if (m_DragObject)
            {
                var previewOrigin = getPreviewOriginForRayOrigin(eventData.rayOrigin);
                MathUtilsExt.LerpTransform(m_DragObject, previewOrigin.position,
                                           MathUtilsExt.ConstrainYawRotation(CameraUtils.GetMainCamera().transform.rotation), m_DragLerp);
            }
        }
Ejemplo n.º 6
0
            internal static void DropPlayerHead(Transform playerHead)
            {
                var cameraRig  = CameraUtils.GetCameraRig();
                var mainCamera = CameraUtils.GetMainCamera().transform;

                // Hide player head to avoid jarring impact
                var playerHeadRenderers = playerHead.GetComponentsInChildren <Renderer>();

                foreach (var renderer in playerHeadRenderers)
                {
                    renderer.enabled = false;
                }

                var rotationDiff = MathUtilsExt.ConstrainYawRotation(Quaternion.Inverse(mainCamera.rotation) * playerHead.rotation);
                var cameraDiff   = cameraRig.position - mainCamera.position;

                cameraDiff.y = 0;
                var rotationOffset = rotationDiff * cameraDiff - cameraDiff;

                var endPosition   = cameraRig.position + (playerHead.position - mainCamera.position) + rotationOffset;
                var endRotation   = cameraRig.rotation * rotationDiff;
                var viewDirection = endRotation * Vector3.forward;

                evr.StartCoroutine(UpdateCameraRig(endPosition, viewDirection, () =>
                {
                    playerHead.parent        = mainCamera;
                    playerHead.localRotation = Quaternion.identity;
                    playerHead.localPosition = Vector3.zero;

                    foreach (var renderer in playerHeadRenderers)
                    {
                        renderer.enabled = true;
                    }
                }));
            }
Ejemplo n.º 7
0
        void MagnetizeTransform(Transform fieldGrabOrigin, Transform transform, float stackingOffset = 0)
        {
            var rotation = MathUtilsExt.ConstrainYawRotation(CameraUtils.GetMainCamera().transform.rotation)
                           * Quaternion.AngleAxis(90, Vector3.left);
            var stackingDirection = rotation * Vector3.one;

            MathUtilsExt.LerpTransform(transform, fieldGrabOrigin.position - stackingDirection * stackingOffset, rotation, m_DragLerp);
        }
Ejemplo n.º 8
0
 protected virtual void OnVerticalDragging(Transform rayOrigin)
 {
     if (m_DragClone)
     {
         var fieldGrabOrigin = this.GetFieldGrabOriginForRayOrigin(rayOrigin);
         var rotation        = MathUtilsExt.ConstrainYawRotation(CameraUtils.GetMainCamera().transform.rotation);
         MathUtilsExt.LerpTransform(m_DragClone, fieldGrabOrigin.position, rotation, m_DragLerp);
     }
 }
Ejemplo n.º 9
0
            void SaveCameraState()
            {
                var camera          = CameraUtils.GetMainCamera();
                var cameraRig       = CameraUtils.GetCameraRig();
                var cameraTransform = camera.transform;
                var cameraRigScale  = cameraRig.localScale.x;

                m_Preferences.cameraRigScale = cameraRigScale;
                m_Preferences.cameraPosition = cameraTransform.position;
                m_Preferences.cameraRotation = MathUtilsExt.ConstrainYawRotation(cameraTransform.rotation);
            }
Ejemplo n.º 10
0
        IEnumerator PlaceSceneObjectCoroutine(Transform obj, Vector3 targetScale)
        {
            // Don't let us direct select while placing
            removeFromSpatialHash(obj.gameObject);

            float start    = Time.realtimeSinceStartup;
            var   currTime = 0f;

            obj.parent = null;
            var startScale     = obj.localScale;
            var startPosition  = obj.position;
            var startRotation  = obj.rotation;
            var targetRotation = MathUtilsExt.ConstrainYawRotation(startRotation);

            //Get bounds at target scale
            var origScale = obj.localScale;

            obj.localScale = targetScale;
            var bounds = ObjectUtils.GetBounds(obj.gameObject);

            obj.localScale = origScale;

            // We want to position the object so that it fits within the camera perspective at its original scale
            var camera      = CameraUtils.GetMainCamera();
            var halfAngle   = camera.fieldOfView * 0.5f;
            var perspective = halfAngle + k_InstantiateFOVDifference;
            var camPosition = camera.transform.position;
            var forward     = obj.position - camPosition;

            var distance       = bounds.size.magnitude / Mathf.Tan(perspective * Mathf.Deg2Rad);
            var targetPosition = obj.position;

            if (distance > forward.magnitude && obj.localScale != targetScale)
            {
                targetPosition = camPosition + forward.normalized * distance;
            }

            while (currTime < k_GrowDuration)
            {
                currTime = Time.realtimeSinceStartup - start;
                var t        = currTime / k_GrowDuration;
                var tSquared = t * t;
                obj.localScale = Vector3.Lerp(startScale, targetScale, tSquared);
                obj.position   = Vector3.Lerp(startPosition, targetPosition, tSquared);
                obj.rotation   = Quaternion.Lerp(startRotation, targetRotation, tSquared);
                yield return(null);
            }
            obj.localScale             = targetScale;
            Selection.activeGameObject = obj.gameObject;

            addToSpatialHash(obj.gameObject);
        }
Ejemplo n.º 11
0
        void SetRingPosition()
        {
            if (!this.IsSharedUpdater(this))
            {
                return;
            }

            var cameraTransform = CameraUtils.GetMainCamera().transform;
            var cameraYaw       = MathUtilsExt.ConstrainYawRotation(cameraTransform.localRotation);
            var ringTransform   = m_Ring.transform;

            ringTransform.localPosition = cameraTransform.localPosition + cameraYaw * k_RingOffset;
            ringTransform.localRotation = cameraYaw;
        }
Ejemplo n.º 12
0
    void MoveWorkspaces()
    {
        const float kMoveMultiplier = 2;

        for (int i = 0; i < allWorkspaces.Count; i++)
        {
            var workspaceTransform = allWorkspaces[i].transform;
            var deltaRotation      = rayOrigin.rotation * Quaternion.Inverse(m_RayOriginStartRotation);
            var deltaPosition      = rayOrigin.position - m_RayOriginStartPosition;
            var yawRotation        = MathUtilsExt.ConstrainYawRotation(deltaRotation);
            var localOffset        = m_WorkspacePositions[i] - m_RayOriginStartPosition;
            workspaceTransform.position = m_RayOriginStartPosition + deltaPosition * kMoveMultiplier + yawRotation * localOffset;
        }

        // Adjust look direction
        this.ResetWorkspaceRotations();
    }
Ejemplo n.º 13
0
        void PlaceModelOrPrefab(Transform itemTransform, AssetData data)
        {
#if UNITY_EDITOR
            var go = (GameObject)PrefabUtility.InstantiatePrefab(data.asset);
#else
            var go = (GameObject)Instantiate(data.asset);
#endif

            var transform = go.transform;
            transform.position = itemTransform.position;
            transform.rotation = MathUtilsExt.ConstrainYawRotation(itemTransform.rotation);

            this.AddToSpatialHash(go);

#if UNITY_EDITOR
            Undo.RegisterCreatedObjectUndo(go, "Project Workspace");
#endif
        }
Ejemplo n.º 14
0
            public void OnDeserializePreferences(object obj)
            {
                if (!preserveCameraRig)
                {
                    return;
                }

                var preferences = (Preferences)obj;

                var camera          = CameraUtils.GetMainCamera();
                var cameraRig       = CameraUtils.GetCameraRig();
                var cameraTransform = camera.transform;
                var cameraRotation  = MathUtilsExt.ConstrainYawRotation(cameraTransform.rotation);
                var inverseRotation = Quaternion.Inverse(cameraRotation);

                cameraRig.position = Vector3.zero;
                cameraRig.rotation = inverseRotation * preferences.cameraRotation;
                SetViewerScale(preferences.cameraRigScale);
                cameraRig.position = preferences.cameraPosition - cameraTransform.position;
            }
Ejemplo n.º 15
0
        protected override void OnDragEnded(BaseHandle handle, HandleEventData eventData)
        {
            var gridItem = m_DragObject.GetComponent <AssetGridItem>();

            var rayOrigin = eventData.rayOrigin;

            this.RemoveRayVisibilitySettings(rayOrigin, this);

            if (!this.IsOverShoulder(eventData.rayOrigin))
            {
                var previewObjectTransform = gridItem.m_PreviewObjectTransform;
                if (previewObjectTransform)
                {
                    Undo.RegisterCreatedObjectUndo(previewObjectTransform.gameObject, "Place Scene Object");
                    this.PlaceSceneObject(previewObjectTransform, m_PreviewPrefabScale);
                }
                else
                {
                    switch (data.type)
                    {
                    case "Prefab":
                    case "Model":
#if UNITY_EDITOR
                        var go        = (GameObject)PrefabUtility.InstantiatePrefab(data.asset);
                        var transform = go.transform;
                        transform.position = gridItem.transform.position;
                        transform.rotation = MathUtilsExt.ConstrainYawRotation(gridItem.transform.rotation);
#else
                        var go = (GameObject)Instantiate(data.asset, gridItem.transform.position, gridItem.transform.rotation);
#endif

                        this.AddToSpatialHash(go);
                        Undo.RegisterCreatedObjectUndo(go, "Project Workspace");
                        break;
                    }
                }
            }

            StartCoroutine(HideGrabbedObject(m_DragObject.gameObject, gridItem.m_Cube));
            base.OnDragEnded(handle, eventData);
        }
Ejemplo n.º 16
0
        IEnumerator PlaceSceneObjectCoroutine(Transform obj, Vector3 targetScale)
        {
            var go = obj.gameObject;

            // Don't let us direct select while placing
            this.RemoveFromSpatialHash(go);

            var start    = Time.realtimeSinceStartup;
            var currTime = 0f;

            obj.parent = null;
            var startScale     = obj.localScale;
            var startPosition  = ObjectUtils.GetBounds(obj).center;
            var pivotOffset    = obj.position - startPosition;
            var startRotation  = obj.rotation;
            var targetRotation = MathUtilsExt.ConstrainYawRotation(startRotation);

            //Get bounds at target scale and rotation (scaled and rotated from bounds center)
            var origScale = obj.localScale;

            obj.localScale = targetScale;
            obj.rotation   = targetRotation;
            var rotationDiff      = Quaternion.Inverse(startRotation) * targetRotation;
            var scaleDiff         = targetScale.magnitude / startScale.magnitude;
            var targetPivotOffset = rotationDiff * pivotOffset * scaleDiff;

            obj.position = startPosition + targetPivotOffset;
            var bounds = ObjectUtils.GetBounds(obj);

            obj.localScale    = origScale;
            obj.localRotation = startRotation;
            obj.position      = startPosition + pivotOffset;

            // We want to position the object so that it fits within the camera perspective at its original scale
            var camera      = CameraUtils.GetMainCamera();
            var halfAngle   = camera.fieldOfView * 0.5f;
            var perspective = halfAngle + k_InstantiateFOVDifference;
            var camPosition = camera.transform.position;
            var forward     = startPosition - camPosition;

            var distance       = bounds.size.magnitude / Mathf.Tan(perspective * Mathf.Deg2Rad);
            var targetPosition = bounds.center;

            if (distance > forward.magnitude && obj.localScale != targetScale)
            {
                targetPosition = camPosition + forward.normalized * distance;
            }

            startPosition  += pivotOffset;
            targetPosition += targetPivotOffset;

            while (currTime < k_GrowDuration)
            {
                currTime = Time.realtimeSinceStartup - start;
                var t        = currTime / k_GrowDuration;
                var tSquared = t * t;
                obj.localScale = Vector3.Lerp(startScale, targetScale, tSquared);
                obj.position   = Vector3.Lerp(startPosition, targetPosition, tSquared);
                obj.rotation   = Quaternion.Lerp(startRotation, targetRotation, tSquared);
                yield return(null);
            }
            obj.localScale             = targetScale;
            Selection.activeGameObject = go;

            this.AddToSpatialHash(go);
#if UNITY_EDITOR
            Undo.IncrementCurrentGroup();
#endif
        }
Ejemplo n.º 17
0
        public void ProcessInput(ActionMapInput input, ConsumeControlDelegate consumeControl)
        {
            var blinkInput = (BlinkLocomotion)input;

            if (m_State == State.Moving)
            {
                return;
            }

            foreach (var linkedObject in linkedObjects)
            {
                if (linkedObject.Equals(this))
                {
                    continue;
                }

                var blinkTool = (BlinkLocomotionTool)linkedObject;
                if (blinkTool.m_State != State.Inactive)
                {
                    return;
                }
            }

            var yawValue     = blinkInput.yaw.value;
            var forwardValue = blinkInput.forward.value;

            m_Grip  = blinkInput.grip.isHeld ? blinkInput.grip : null;
            m_Thumb = blinkInput.thumb.isHeld ? blinkInput.thumb : null;

            if (this.IsSharedUpdater(this))
            {
                if (m_Grip != null)
                {
                    if (m_AllowScaling)
                    {
                        var otherGrip = false;
                        foreach (var linkedObject in linkedObjects)
                        {
                            if (linkedObject.Equals(this))
                            {
                                continue;
                            }

                            var blinkTool = (BlinkLocomotionTool)linkedObject;
                            if (blinkTool.m_Grip != null)
                            {
                                otherGrip = true;
                                consumeControl(m_Grip);
                                consumeControl(blinkTool.m_Grip);

                                var thisPosition   = cameraRig.InverseTransformPoint(rayOrigin.position);
                                var otherRayOrigin = blinkTool.rayOrigin;
                                var otherPosition  = cameraRig.InverseTransformPoint(otherRayOrigin.position);
                                var distance       = Vector3.Distance(thisPosition, otherPosition);

                                var rayToRay = otherPosition - thisPosition;
                                var midPoint = thisPosition + rayToRay * 0.5f;

                                rayToRay.y = 0;                                 // Use for yaw rotation

                                var pivotYaw = MathUtilsExt.ConstrainYawRotation(cameraRig.rotation);

                                if (!m_Scaling)
                                {
                                    m_StartScale     = this.GetViewerScale();
                                    m_StartDistance  = distance;
                                    m_StartMidPoint  = pivotYaw * midPoint * m_StartScale;
                                    m_StartPosition  = cameraRig.position;
                                    m_StartDirection = rayToRay;
                                    m_StartYaw       = cameraRig.rotation.eulerAngles.y;

                                    m_EnableJoystick           = false;
                                    blinkTool.m_EnableJoystick = false;

                                    CreateViewerScaleVisuals(rayOrigin, otherRayOrigin);
                                }

                                m_Scaling = true;

                                var currentScale = m_StartScale * (m_StartDistance / distance);

                                // Press both thumb buttons to reset
                                if (m_Thumb != null && blinkTool.m_Thumb != null)
                                {
                                    m_AllowScaling = false;

                                    rayToRay = otherRayOrigin.position - rayOrigin.position;
                                    midPoint = rayOrigin.position + rayToRay * 0.5f;
                                    var currOffset = midPoint - cameraRig.position;
                                    this.SetViewerScale(1f);
                                    cameraRig.position = midPoint - currOffset / currentScale;
                                    cameraRig.rotation = Quaternion.AngleAxis(m_StartYaw, Vector3.up);

                                    consumeControl(m_Thumb);
                                    consumeControl(blinkTool.m_Thumb);

                                    if (m_ViewerScaleVisuals)
                                    {
                                        ObjectUtils.Destroy(m_ViewerScaleVisuals.gameObject);
                                    }
                                }

                                if (currentScale < k_MinScale)
                                {
                                    currentScale = k_MinScale;
                                }

                                if (currentScale > k_MaxScale)
                                {
                                    currentScale = k_MaxScale;
                                }

                                if (m_AllowScaling)
                                {
                                    var yawSign         = Mathf.Sign(Vector3.Dot(Quaternion.AngleAxis(90, Vector3.down) * m_StartDirection, rayToRay));
                                    var currentYaw      = m_StartYaw + Vector3.Angle(m_StartDirection, rayToRay) * yawSign;
                                    var currentRotation = Quaternion.AngleAxis(currentYaw, Vector3.up);
                                    midPoint = currentRotation * midPoint * currentScale;

                                    cameraRig.position = m_StartPosition + m_StartMidPoint - midPoint;
                                    cameraRig.rotation = currentRotation;

                                    this.SetViewerScale(currentScale);

                                    m_ViewerScaleVisuals.viewerScale = currentScale;
                                    m_BlinkVisuals.viewerScale       = currentScale;
                                    Shader.SetGlobalFloat(k_WorldScaleProperty, 1f / currentScale);
                                }
                                break;
                            }
                        }

                        if (!otherGrip)
                        {
                            CancelScale();
                        }
                    }
                }
                else
                {
                    CancelScale();
                }
            }

            bool isVive = proxyType == typeof(ViveProxy);

            if (m_EnableJoystick && (!isVive || m_Thumb != null))
            {
                var viewerCamera = CameraUtils.GetMainCamera();

                if (Mathf.Abs(yawValue) > Mathf.Abs(forwardValue))
                {
                    if (!Mathf.Approximately(yawValue, 0))
                    {
                        if (node == Node.LeftHand)
                        {
                            var direction = viewerCamera.transform.right;
                            direction.y = 0;
                            direction.Normalize();

                            Translate(yawValue, isVive, direction);
                        }
                        else
                        {
                            var speed     = yawValue * k_SlowRotationSpeed;
                            var threshold = isVive ? k_RotationThresholdVive : k_RotationThreshold;
                            if (Mathf.Abs(yawValue) > threshold)
                            {
                                speed = k_FastRotationSpeed * Mathf.Sign(yawValue);
                            }

                            cameraRig.RotateAround(viewerCamera.transform.position, Vector3.up, speed * Time.deltaTime);
                        }

                        consumeControl(blinkInput.yaw);
                    }
                }
                else
                {
                    if (!Mathf.Approximately(forwardValue, 0))
                    {
                        var direction = Vector3.up;

                        if (node == Node.LeftHand)
                        {
                            direction   = viewerCamera.transform.forward;
                            direction.y = 0;
                            direction.Normalize();
                        }

                        Translate(forwardValue, isVive, direction);
                        consumeControl(blinkInput.forward);
                    }
                }
            }

            if (blinkInput.blink.wasJustPressed && !m_BlinkVisuals.outOfMaxRange)
            {
                m_State = State.Aiming;
                this.HideDefaultRay(rayOrigin);
                this.LockRay(rayOrigin, this);

                m_BlinkVisuals.ShowVisuals();

                consumeControl(blinkInput.blink);
            }
            else if (m_State == State.Aiming && blinkInput.blink.wasJustReleased)
            {
                this.UnlockRay(rayOrigin, this);
                this.ShowDefaultRay(rayOrigin);

                if (!m_BlinkVisuals.outOfMaxRange)
                {
                    m_BlinkVisuals.HideVisuals();
                    StartCoroutine(MoveTowardTarget(m_BlinkVisuals.locatorPosition));
                }
                else
                {
                    m_BlinkVisuals.enabled = false;
                    m_State = State.Inactive;
                }
            }
        }
Ejemplo n.º 18
0
        bool DoTwoHandedScaling(ConsumeControlDelegate consumeControl)
        {
            foreach (var linkedObject in linkedObjects)
            {
                if (((LocomotionTool)linkedObject).m_Rotating)
                {
                    return(false);
                }
            }

            if (this.IsSharedUpdater(this))
            {
                var crawl = m_LocomotionInput.crawl;
                if (crawl.isHeld)
                {
                    if (m_AllowScaling)
                    {
                        var otherGripHeld = false;
                        foreach (var linkedObject in linkedObjects)
                        {
                            var otherLocomotionTool = (LocomotionTool)linkedObject;
                            if (otherLocomotionTool == this)
                            {
                                continue;
                            }

                            var otherLocomotionInput = otherLocomotionTool.m_LocomotionInput;
                            if (otherLocomotionInput == null) // This can occur if crawl is pressed when EVR is opened
                            {
                                continue;
                            }

                            var otherCrawl = otherLocomotionInput.crawl;
                            if (otherCrawl.isHeld)
                            {
                                otherGripHeld = true;
                                consumeControl(crawl);
                                consumeControl(otherCrawl);

                                // Also consume thumbstick axes to disable radial menu
                                consumeControl(m_LocomotionInput.horizontal);
                                consumeControl(m_LocomotionInput.vertical);
                                consumeControl(otherLocomotionInput.horizontal);
                                consumeControl(otherLocomotionInput.vertical);

                                // Pre-emptively consume thumbstick press to override UndoMenu
                                consumeControl(m_LocomotionInput.scaleReset);
                                consumeControl(otherLocomotionInput.scaleReset);

                                // Also pre-emptively consume world-reset
                                consumeControl(m_LocomotionInput.worldReset);
                                consumeControl(otherLocomotionInput.worldReset);

                                var thisPosition   = cameraRig.InverseTransformPoint(rayOrigin.position);
                                var otherRayOrigin = otherLocomotionTool.rayOrigin;
                                var otherPosition  = cameraRig.InverseTransformPoint(otherRayOrigin.position);
                                var distance       = Vector3.Distance(thisPosition, otherPosition);

                                this.AddRayVisibilitySettings(rayOrigin, this, false, false);
                                this.AddRayVisibilitySettings(otherRayOrigin, this, false, false);

                                var rayToRay = otherPosition - thisPosition;
                                var midPoint = thisPosition + rayToRay * 0.5f;

                                rayToRay.y = 0; // Use for yaw rotation

                                var pivotYaw = MathUtilsExt.ConstrainYawRotation(cameraRig.rotation);

                                if (!m_Scaling)
                                {
                                    m_StartScale     = this.GetViewerScale();
                                    m_StartDistance  = distance;
                                    m_StartMidPoint  = pivotYaw * midPoint * m_StartScale;
                                    m_StartPosition  = cameraRig.position;
                                    m_StartDirection = rayToRay;
                                    m_StartYaw       = cameraRig.rotation.eulerAngles.y;

                                    otherLocomotionTool.m_Scaling       = true;
                                    otherLocomotionTool.m_Crawling      = false;
                                    otherLocomotionTool.m_StartCrawling = false;

                                    m_ViewerScaleVisuals.leftHand  = rayOrigin;
                                    m_ViewerScaleVisuals.rightHand = otherRayOrigin;
                                    m_ViewerScaleVisuals.gameObject.SetActive(true);

                                    foreach (var obj in linkedObjects)
                                    {
                                        var locomotionTool = (LocomotionTool)obj;
                                        locomotionTool.HideScaleFeedback();
                                        locomotionTool.HideRotateFeedback();
                                        locomotionTool.HideMainButtonFeedback();
                                        locomotionTool.ShowResetScaleFeedback();
                                    }
                                }

                                m_Scaling       = true;
                                m_StartCrawling = false;
                                m_Crawling      = false;

                                var currentScale = Mathf.Clamp(m_StartScale * (m_StartDistance / distance), k_MinScale, k_MaxScale);

                                var scaleReset     = m_LocomotionInput.scaleReset;
                                var scaleResetHeld = scaleReset.isHeld;

                                var otherScaleReset     = otherLocomotionInput.scaleReset;
                                var otherScaleResetHeld = otherScaleReset.isHeld;

                                // Press both thumb buttons to reset scale
                                if (scaleResetHeld && otherScaleResetHeld)
                                {
                                    m_AllowScaling = false;

                                    rayToRay = otherRayOrigin.position - rayOrigin.position;
                                    midPoint = rayOrigin.position + rayToRay * 0.5f;
                                    var currOffset = midPoint - cameraRig.position;

                                    cameraRig.position = midPoint - currOffset / currentScale;
                                    cameraRig.rotation = Quaternion.AngleAxis(m_StartYaw, Vector3.up);

                                    ResetViewerScale();
                                }

                                var worldReset     = m_LocomotionInput.worldReset;
                                var worldResetHeld = worldReset.isHeld;
                                if (worldResetHeld)
                                {
                                    consumeControl(worldReset);
                                }

                                var otherWorldReset     = otherLocomotionInput.worldReset;
                                var otherWorldResetHeld = otherWorldReset.isHeld;
                                if (otherWorldResetHeld)
                                {
                                    consumeControl(otherWorldReset);
                                }

                                // Press both triggers to reset to origin
                                if (worldResetHeld && otherWorldResetHeld)
                                {
                                    m_AllowScaling     = false;
                                    cameraRig.position = VRView.headCenteredOrigin;
                                    cameraRig.rotation = Quaternion.identity;

                                    ResetViewerScale();
                                }

                                if (m_AllowScaling)
                                {
                                    var yawSign         = Mathf.Sign(Vector3.Dot(Quaternion.AngleAxis(90, Vector3.down) * m_StartDirection, rayToRay));
                                    var currentYaw      = m_StartYaw + Vector3.Angle(m_StartDirection, rayToRay) * yawSign;
                                    var currentRotation = Quaternion.AngleAxis(currentYaw, Vector3.up);
                                    midPoint = currentRotation * midPoint * currentScale;

                                    var pos = m_StartPosition + m_StartMidPoint - midPoint;
                                    cameraRig.position = pos;

                                    cameraRig.rotation = currentRotation;

                                    this.SetViewerScale(currentScale);
                                }
                                break;
                            }
                        }

                        if (!otherGripHeld)
                        {
                            CancelScale();
                        }
                    }
                }
                else
                {
                    CancelScale();
                }
            }

            return(m_Scaling);
        }