예제 #1
0
        /// <summary>
        /// Rotate/pan/zoom model in response to mouse input.
        ///
        /// Note: This code uses Unity's Input Manager
        /// (`Input`) to read mouse input, whereas previous revisions
        /// used IMGUI events such as `EventType.MouseDown`.
        /// I switched to solely using `Input` because I found that
        /// `EventType.MouseDrag` events were not being generated
        /// in WebGL while holding down either the middle mouse
        /// button or the right mouse button, and I couldn't figure
        /// out why.
        /// </summary>
        protected void ProcessMouseInput()
        {
            // if any GUI element (e.g. checkbox, slider) currently
            // has focus

            if (GUIUtility.hotControl != 0)
            {
                return;
            }

            // Note: The test for Input.touchCount != 0 ensures
            // that the code is only run in response to input from a
            // *real* mouse, rather than mouse events simulated from
            // a touch screen. It would be better/cleaner to set
            // Input.simulateMouseWithTouches to false to achieve this
            // separation, but I found that the setting has no effect
            // (in Unity 2018.3). Moreover, there is a bug where
            // Input.simulateMouseWithTouches is ignored under WebGL:
            // https://forum.unity.com/threads/input-simulatemousewithtouches-is-ignored-in-webgl.388157/

            if (Input.touchCount != 0)
            {
                return;
            }

            MouseButtons buttons      = MouseButtons.None;
            MouseAction  mouseActions = MouseAction.None;
            float        deltaX       = 0f;
            float        deltaY       = 0f;
            float        deltaZ       = 0f;

            if (Input.GetMouseButton(0))
            {
                buttons |= MouseButtons.LeftButton;
            }
            if (Input.GetMouseButton(1))
            {
                buttons |= MouseButtons.RightButton;
            }
            if (Input.GetMouseButton(2))
            {
                buttons |= MouseButtons.MiddleButton;
            }

            if (Input.mouseScrollDelta != Vector2.zero)
            {
                mouseActions = MouseAction.Zoom;
                deltaZ       = Input.mouseScrollDelta.y;
            }

            // Detect mouse drag events by comparing the current
            // mouse button states and cursor position to
            // those of the previous frame.

            if (buttons != MouseButtons.None &&
                buttons == _prevMouseState.Buttons &&
                _prevMouseState.Position.HasValue)
            {
                Vector3 mouseDelta = Input.mousePosition - _prevMouseState.Position.Value;

                if (buttons.HasFlag(MouseButtons.LeftButton))
                {
                    mouseActions |= MouseAction.Rotate;
                }
                if (buttons.HasFlag(MouseButtons.RightButton))
                {
                    mouseActions |= MouseAction.Pan;
                }

                deltaX = mouseDelta.x;
                deltaY = mouseDelta.y;
            }

            // Stop auto-spin ("Spin X" / "Spin Y")
            // whenever the user clicks on the
            // model/background.

            if (Input.GetMouseButtonDown(0) ||
                Input.GetMouseButtonDown(1) ||
                Input.GetMouseButtonDown(2))
            {
                Gui.Instance.ResetSpin();
            }

            if (mouseActions.HasFlag(MouseAction.Rotate))
            {
                ModelManager.Instance.RotateAboutCenter(
                    new Vector3(deltaY, -deltaX, 0) * MouseRotateSpeed);
            }

            if (mouseActions.HasFlag(MouseAction.Pan))
            {
                CameraBehaviour.Instance.PanCamera(
                    new Vector3(-deltaX, -deltaY, 0) * MousePanSpeed);
            }

            if (mouseActions.HasFlag(MouseAction.Zoom))
            {
                CameraBehaviour.Instance.ZoomCamera(deltaZ * MouseZoomSpeed);
            }

            // Record current mouse position and button states
            // for use in the next frame, so that we can detect when
            // button states have changed.

            _prevMouseState.Buttons  = buttons;
            _prevMouseState.Position = Input.mousePosition;
        }
예제 #2
0
        /// <summary>
        /// Handle touch screen input (Android and WebGL).
        ///
        /// Note: This code uses the `Touch` class
        /// from Unity's old input system ("Input Manager").
        /// At the time of coding, I was not aware that there
        /// was a newer Unity input system ("Input System",
        /// introduced in Unity 2019.1), which provides a new touch
        /// input API via `InputSystem.EnhancedTouch.Touch`.
        /// See https://forum.unity.com/threads/inputsystem-enhancedtouch-touch-and-unity-ads.779351/
        /// The code below works fine and is likely to
        /// be supported by Unity for a long time. But if I
        /// ever need to make major changes, I should consider
        /// using the new input system.
        /// </summary>
        protected void ProcessTouchInput()
        {
            // if user is currently interacting with an IMGUI control (e.g. a slider)
            if (GUIUtility.hotControl != 0)
            {
                return;
            }

            // if touch screen input is not supported on the current platform
            if (!Input.touchSupported)
            {
                return;
            }

            MouseAction mouseActions = MouseAction.None;
            bool        mouseDown    = false;
            float       deltaX       = 0f;
            float       deltaY       = 0f;
            float       deltaZ       = 0f;

            // if number of fingers has changed
            if (Input.touchCount != _prevTouchState.TouchCount)
            {
                _prevTouchState.PinchDist     = null;
                _prevTouchState.PinchMidpoint = null;

                // perform mouse click actions when finger(s) first touch screen
                if (_prevTouchState.TouchCount == 0)
                {
                    mouseDown = true;
                }
            }
            else if (Input.touchCount == _prevTouchState.TouchCount)
            {
                // perform mouse drag actions while number of fingers
                // touching screen is > 0 and does not change

                if (Input.touchCount == 1)
                {
                    // one-finger drag -> rotate model

                    Touch touch = Input.GetTouch(0);

                    deltaX = touch.deltaPosition.x * 0.3f;
                    deltaY = -touch.deltaPosition.y * 0.3f;

                    mouseActions |= MouseAction.Rotate;
                }
                else if (Input.touchCount == 2)
                {
                    Touch touch0 = Input.GetTouch(0);
                    Touch touch1 = Input.GetTouch(1);

                    // two fingers pinch -> zoom

                    float pinchDist = (touch1.position - touch0.position).magnitude;

                    if (_prevTouchState.PinchDist.HasValue)
                    {
                        mouseActions |= MouseAction.Zoom;

                        float pinchDelta = pinchDist - _prevTouchState.PinchDist.Value;
                        deltaZ = pinchDelta * 0.03f;
                    }

                    _prevTouchState.PinchDist = pinchDist;

                    // two-finger drag -> pan

                    Vector2 pinchMidpoint = (touch0.position + touch1.position) / 2.0f;
                    if (_prevTouchState.PinchMidpoint.HasValue)
                    {
                        mouseActions |= MouseAction.Pan;

                        Vector2 deltaMidpoint
                            = pinchMidpoint - _prevTouchState.PinchMidpoint.Value;

                        deltaX = deltaMidpoint.x * 1.0f;
                        deltaY = -deltaMidpoint.y * 1.0f;
                    }

                    _prevTouchState.PinchMidpoint = pinchMidpoint;
                }
            }

            // stop auto-spin ("Spin X" / "Spin Y")
            // whenever the user clicks on the
            // model/background.
            if (mouseDown)
            {
                Gui.Instance.ResetSpin();
            }

            if (mouseActions.HasFlag(MouseAction.Rotate))
            {
                ModelManager.Instance.RotateAboutCenter(
                    new Vector3(-deltaY, -deltaX, 0) * MouseRotateSpeed);
            }

            if (mouseActions.HasFlag(MouseAction.Pan))
            {
                CameraBehaviour.Instance.PanCamera(
                    new Vector3(-deltaX, deltaY, 0) * MousePanSpeed);
            }

            if (mouseActions.HasFlag(MouseAction.Zoom))
            {
                CameraBehaviour.Instance.ZoomCamera(deltaZ * MouseZoomSpeed);
            }

            _prevTouchState.TouchCount = Input.touchCount;
        }