Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.

Mouse Delta Input

Discussion in 'Input System' started by caseyc, Mar 18, 2019.

  1. caseyc

    caseyc

    Joined:
    Jul 2, 2012
    Posts:
    18
    I was checking out the new input system over the weekend, I'm a big fan so far of the features but I was wondering what the correct way to process the callback for mouse delta is.

    I've tried this:

    Code (CSharp):
    1.     private void Update()
    2.     {
    3.         transform.rotation = Quaternion.Euler(_rotation);
    4.     }
    5.  
    6.  
    7.     private void OnLook(InputAction.CallbackContext context)
    8.     {
    9.         Vector2 lookValue = context.ReadValue<Vector2>();
    10.  
    11.         _rotation.x += -lookValue.y * 0.022f * _sensitivity;
    12.         _rotation.y += lookValue.x * 0.022f * _sensitivity;
    13.     }
    And also this:

    Code (CSharp):
    1.     private void Update()
    2.     {
    3.         _rotation.x += -_lookValue.y * 0.022f * _sensitivity;
    4.         _rotation.y += _lookValue.x * 0.022f * _sensitivity;
    5.  
    6.         transform.rotation = Quaternion.Euler(_rotation);
    7.     }
    8.  
    9.  
    10.     private void OnLook(InputAction.CallbackContext context)
    11.     {
    12.         _lookValue = context.ReadValue<Vector2>();
    13.     }
    I have noticed that I receive several updates to the mouse delta per frame, so it seems like the first way is the correct manner to process the input. However, I was expecting this function to create a similar look speed to cs:go (0.022 is the constant m_yaw value in cs:go) and the second function seems to get closer to the expected result (although it is still a little faster). What units is the mouse delta returned in and what is the correct way to process it if I would want to create a similar sensitivity to source engine games? Thanks in advance for any help!
     
  2. Rene-Damm

    Rene-Damm

    Unity Technologies

    Joined:
    Sep 15, 2012
    Posts:
    1,779
    "delta" is in pixels, i.e. the amount of change on "position".

    Applying in Update() without taking time into account will essentially make rotation speeds dependent on framerate. To get constant speeds, scale by Time.deltaTime.
     
    DonPuno and Xepherys like this.
  3. caseyc

    caseyc

    Joined:
    Jul 2, 2012
    Posts:
    18
    For mouse movement wouldn't you want to take the raw change in pixels each frame though? I understand for a joystick you would want to get the direction the joystick is pointing and apply that by a rotation speed * deltaTime each frame but for a mouse you are measuring how far the user actually moved the mouse since the last update (or in this case the last time OnLook was called). For instance if the user was moving the mouse at at 10 inches/second on their mousepad and the mouse had a pixels per inch of 400 it would move 4000 pixels/second. If the framerate were 60 frames/sec it would be 4000/60 = 66.66 pixels per frame. If the framerate was 120 frames/sec it would be 4000/120 = 33.33 pixels per frame. In either case the overall speed of 4000 pixels/second is the same and not affected by the frame deltaTime. Unless I'm completely misunderstanding how this works lol. Thanks for you help!
     
    customphase, mowax74, DonPuno and 2 others like this.
  4. caseyc

    caseyc

    Joined:
    Jul 2, 2012
    Posts:
    18
    So I set up a quick test to see what was going on with the mouse delta being passed and now I'm even more confused than before.

    Code (CSharp):
    1.     private void Update()
    2.     {
    3.         Vector2 calculatedDelta = _mousePosition - _previousPosition;
    4.         _previousPosition = _mousePosition;
    5.  
    6.         if(_passedDelta != calculatedDelta)
    7.         {
    8.             Debug.Log("Passed Delta Mismatch: " + _passedDelta + ": " + calculatedDelta);
    9.         }
    10.  
    11.         if(_cumulativePassedDelta != calculatedDelta)
    12.         {
    13.             Debug.Log("Cumulative Passed Delta Mismatch: " + _cumulativePassedDelta + ": " + calculatedDelta);
    14.         }
    15.  
    16.         _cumulativePassedDelta = Vector2.zero;
    17.     }
    18.  
    19.  
    20.     private void OnLook(InputAction.CallbackContext context)
    21.     {
    22.         Vector2 delta = context.ReadValue<Vector2>();
    23.  
    24.         _passedDelta = delta;
    25.         _cumulativePassedDelta += delta;
    26.     }
    27.  
    28.     private void OnMousePositionChanged(InputAction.CallbackContext context)
    29.     {
    30.         _mousePosition = context.ReadValue<Vector2>();
    31.     }
    I basically set up a test where I calculate my own mouse delta manually using the mouse position, and compare it to the cumulative passed delta during a frame as well as the most recent passed delta in a frame. Neither the cumulative nor the raw passed delta seems to be accurate. The cumulative is way off, the passed one is closer but still off. What exactly is being passed with mouse delta?
     
  5. Rene-Damm

    Rene-Damm

    Unity Technologies

    Joined:
    Sep 15, 2012
    Posts:
    1,779
    There's some magic going on under the hood that makes things confusing for actions. Something that's still on the list to be looked at.

    In short, deltas will accumulate and reset automatically.

    Bear with me here... :)

    Let's say we get three deltas in a given frame. (1,1), (2,2), and (3,3). At the event level, this means that we get three events that have those exact deltas in them. At the state level (i.e. the memory that keeps the state of the mouse), however, we see accumulation. So after the *second* event the state is (3,3) and after the *third* event the state is (6,6). I.e. you get the accumulated mouse motion in the frame. And on the beginning of the next frame, it automatically resets to (0,0).

    This is done so that if you do Mouse.current.delta.ReadValue() in Update(), you don't just get the last delta of the last mouse event -- which could be (0,0) even though the frame actually did have mouse motion.

    However... for actions, this isn't what you'd expect. Actions observe every single state change. So what you expect is to get (1,1), (2,2) and (3,3) one after the other in the frame. What you actually get right now instead is (1,1),(3,3),(6,6). AND the action will observe the reset. I.e. you will *also* see (0,0) at the beginning of the next frame.

    This same problem crops up in other places, too, where something that does make sense for querying state in Update() or FixedUpdate() does not make sense for querying state in actions.

    What should probably happen is that Update() and FixedUpdate() see the accumulation happening but the actions do not. Something that still needs looking at.
     
    CiroContns and DonPuno like this.
  6. caseyc

    caseyc

    Joined:
    Jul 2, 2012
    Posts:
    18
    Thanks for the reply! I tried a similar test where I used Mouse.current.delta.ReadValue() in Update() but it was giving me the correct value with some framerates and not the correct one with others (i turned off vsync and was testing at about 2,000 fps vs capping to 30 to see if there was a difference). I tried playing with the input system update mode to correct this but it didn't seem to affect it at all. I suspect that the mouse delta isn't getting reset each frame but is being reset at some other point in time but I can't quite tell when. I'm on 2018.3.9 if that makes any difference. Thanks again!
     
  7. Elhimp

    Elhimp

    Joined:
    Jan 6, 2013
    Posts:
    23
    I'm no mathematician, but this look quite opposite to definition of delta. Anyway...

    So, is it gonna be beneficial to have some InputAction("name", "<Mouse>/delta")* with multiple callbacks per frame, which I should ignore completely? Or it would be better to just "manually" calculate difference between previous and current cursor positions in scope of preferred update rate, or just read latest value from Mouse.current.delta?

    *considering I don't need to make composite action of multiple Vector2 sources.
     
    Last edited: Sep 10, 2020
    customphase and FlavioIT like this.
  8. Wokky

    Wokky

    Joined:
    Apr 3, 2014
    Posts:
    11
    This seems similar to an issue I encountered after experimenting with converting a first-person character controller over to the new input system. Mouse input became jittery and felt out-of-sync with my mouse movements. After finding this thread I tried changing from using an action callback to
    Mouse.current.delta.ReadValue()
    but it doesn't appear to have resolved the problem.



    This toy example roughly illustrates what I'm observing - the position of the orange square is being offset in Update() via the old input system with
    Input.GetAxisRaw()
    while the blue is offset by
    Mouse.current.delta.ReadValue()


    Where the acceleration of the orange square generally matches that of the cursor, the blue square seems to unpredictably lag or jump ahead. The second half of the video also demonstrates its movement becoming out of sync: dragging the cursor from a point and eventually returning to that same point means that the orange square also returns to its initial position as expected, but the blue square comes to rest in a different location.
     
    Last edited: Jul 18, 2019
    DonPuno, Kokowolo, kmowers and 11 others like this.
  9. Sonorpearl

    Sonorpearl

    Joined:
    Sep 8, 2017
    Posts:
    32
    @Rene-Damm It would be nice to get an Update for the problem, which is shown in the video from @Wokky.
    It´s an essential feature, which shouldn't be broken for long. ^^
     
    cxode likes this.
  10. Marble

    Marble

    Joined:
    Aug 29, 2005
    Posts:
    1,254
    I just ran into this myself. Is there intent to make frame by frame delta input more usable in actions?
     
    Last edited: Sep 28, 2019
  11. Laumania

    Laumania

    Joined:
    Jun 27, 2012
    Posts:
    189
    I'm listening here too...and my mouse is now behaving a little wierd I think in my FPS controller.
     
  12. Laumania

    Laumania

    Joined:
    Jun 27, 2012
    Posts:
    189
    @Rene-Damm Any update to this issue? Or work arounds? Seems like a pretty big thing not working properly, as "mouse" is kind of a populate controller for games :)
     
    cxode likes this.
  13. Laumania

    Laumania

    Joined:
    Jun 27, 2012
    Posts:
    189
    By the way, I'm not using mouse input as events, I'm polling and still it works very wierd and not at all like the old input. It's clearly depending on the DPI/Resolution or something like that, which is not ideal.

    Code (CSharp):
    1. private void Update()
    2. {
    3. LookDelta  = _defaultControls.Player.Look.ReadValue<Vector2>() * Time.deltaTime;
    4. }
     
  14. Rene-Damm

    Rene-Damm

    Unity Technologies

    Joined:
    Sep 15, 2012
    Posts:
    1,779
    Hey guys, sorry for the huge lag here.

    @Wokky Could you file a ticket with the Unity bug reporter using that setup you have there? Would like to take a closer look at that.

    I did some quick some testing and even trying to account for the various scaling/alterations that the old input manager applies (even if you do GetAxisRaw), while I see a difference in magnitude, I don't see grave differences in behavior. Still, we've seen enough reports about wonky behavior with mouse delta input to warrant a close examination.

    upload_2019-10-8_18-20-54.png

    As far as actions bound to deltas are concerned, I'm not sure yet how to most elegantly solve that. Problem is most often it *does* make most sense to tap the accumulated delta (such as when you do a polled ReadValue in Update or when you just store the latest value in an action callback) but sometimes it doesn't (such as when you really just want motion updates one by one). One potential way of solving it is having two controls for each delta-style control (i.e. position and scroll deltas): one that accumulates and one that doesn't. Then in bindings, one can decide which to tap.

    Just to note that, in the old input system, you *always* get an accumulated value. I.e. "Mouse X" and "Mouse Y" are always accumulated frame to frame. (at least on Windows; haven't checked the myriads of other platforms)

    ////EDIT: Just for reference, this is the test script I used above. (relying on Squiggle for graphing)

    Code (CSharp):
    1. public class MouseDeltaTest : MonoBehaviour
    2. {
    3.     private InputAction m_Action;
    4.  
    5.     void Start()
    6.     {
    7.         m_Action = new InputAction(type: InputActionType.Value, binding: "<Mouse>/delta");
    8.         m_Action.Enable();
    9.     }
    10.  
    11.     void Update()
    12.     {
    13.         var vertical = Input.GetAxis("Mouse Y");
    14.         var horizontal = Input.GetAxis("Mouse X");
    15.         var delta = m_Action.ReadValue<Vector2>();
    16.  
    17.         // Account for scaling applied directly in Windows code by old input system.
    18.         delta *= 0.5f;
    19.  
    20.         // Account for sensitivity setting on old Mouse X and Y axes.
    21.         delta *= 0.1f;
    22.  
    23.         DebugGraph.Log("Old", new Vector2(horizontal, vertical));
    24.         DebugGraph.Log("New", delta);
    25.     }
    26. }
    27.  
     
    Peter77 and cxode like this.
  15. Laumania

    Laumania

    Joined:
    Jun 27, 2012
    Posts:
    189
    @Rene-Damm Well, the reason you might not see an issue is because you have multiplying with these magic numbers? :D

    Code (CSharp):
    1. // Account for scaling applied directly in Windows code by old input system.
    2.         delta *= 0.5f;
    3.         // Account for sensitivity setting on old Mouse X and Y axes.
    4.         delta *= 0.1f;

    I was just creating a demo project, when I discovered that my problem was a combination of two things:

    1. I were missing your magic values
    2. I were, for some reason, multiplying by Time.deltaTime.

    Multiplying by magic values and removing the Time.deltaTime solved my issue it seems.


    Code (CSharp):
    1.  var lookDeltaRaw = _defaultControls.Player.Look.ReadValue<Vector2>();
    2.                
    3.                 // Account for scaling applied directly in Windows code by old input system.
    4.                 lookDeltaRaw *= 0.5f;
    5.                
    6.                 // Account for sensitivity setting on old Mouse X and Y axes.
    7.                 lookDeltaRaw *= 0.1f;
    8.  
    9.                 return lookDeltaRaw;
     
    DonPuno likes this.
  16. Laumania

    Laumania

    Joined:
    Jun 27, 2012
    Posts:
    189
    ...and after that I actually ended up removing the "magic values" and just adjust my sensitivity on my FirstPersonController to fit.

    Seems to work...so right now it looks like my mistake was to * Time.deltaTime...just if others get here too with same wierd behavior.
     
  17. Rene-Damm

    Rene-Damm

    Unity Technologies

    Joined:
    Sep 15, 2012
    Posts:
    1,779
    @Laumania If the problem is scaling of values, that'll be easy to correct e.g. by applying processors. We can certainly tweak that on the managed side. ATM the deltas are served pretty much raw from the platform.

    However, problems like the one illustrated by @Wokky seem to go deeper and hint at differences of deltas not just in magnitude but in distribution over time. If that is indeed the case, scaling alone unfortunately won't do the trick.
     
  18. Laumania

    Laumania

    Joined:
    Jun 27, 2012
    Posts:
    189
    Yeah I actually know about the scale, but didn't added that, just adjusted sensitivity. But as it's down to 0,2 for me right now...I might want to apply some scale, to have a better range of sensitivity ingame.

    At least I don't have an issue anymore with the mouse input in the new input system. I'll let you know if I run into problems :)
     
  19. bonickhausen

    bonickhausen

    Joined:
    Jan 20, 2014
    Posts:
    103
    Soo, any updates from this? It still feels off.
     
  20. Laumania

    Laumania

    Joined:
    Jun 27, 2012
    Posts:
    189
    Well, I ended up getting my to work fine. Feels as it use to.

    Can you share code, maybe we can spot the issue?
     
  21. Hellzbellz123

    Hellzbellz123

    Joined:
    May 15, 2019
    Posts:
    12
    so ive been trying to setup a camera controller and the delta doesnt seem to get reset to 0 when you stop moving the mouse. am i missing something here?
     
  22. Jichaels

    Jichaels

    Joined:
    Dec 27, 2018
    Posts:
    237
    You're probably not polling the action, and using only callbacks. Try polling for movement/camera, it's much better and easier
     
  23. Hellzbellz123

    Hellzbellz123

    Joined:
    May 15, 2019
    Posts:
    12
    polling is if statements right? how would i even do something like that. sorry if its a super noob thing
     
  24. Jichaels

    Jichaels

    Joined:
    Dec 27, 2018
    Posts:
    237
    No it's not, you just get a reference of one of your action (let's say Movement) using a sfield

    Code (CSharp):
    1. [SerializedField] private InputActionReference _inputActionReferenceMovement;
    2. private Vector2 _inputMovement;
    Then in your update method :

    Code (CSharp):
    1. _inputMovement = inputActionReferenceMovement.action.ReadValue<Vector2>();
    2.  
    3. // now use _inputMovement
     
  25. Laumania

    Laumania

    Joined:
    Jun 27, 2012
    Posts:
    189
    This is work in progress and this InputManager change all the time, but this is how it looks right now. I already know I need to simplify it.

    This solves more than just your mouse challenge, but might be interested to see either way.

    I wanted to have all my actual handling of input in one place, the InputManager, and then i trigger custon events, set properties etc on that one, so that all my other scripts just use this InputManager to get there data.
    This way, it easier to change from old input to the new input system, and in the future to the new new input system, when that hits at some point :)

    Anyway, this works good for me and for your look, it's the LookDelta property you need to look at.

    Code (CSharp):
    1. public class InputManager : MonoBehaviour
    2.     {
    3.         private DefaultControls     _defaultControls;
    4.         private static InputManager _instance;
    5.         private InputContext        _currentInputContext;
    6.  
    7.         [HideInInspector]
    8.         public UnityEvent OnHideUITriggered;
    9.         [HideInInspector]
    10.         public UnityEvent OnInventoryButtonTriggered;
    11.         [HideInInspector]
    12.         public ItemSlotTriggeredEvent OnItemSlotButtonTriggered;
    13.  
    14.         private void Awake()
    15.         {
    16.             if (_instance != null && _instance != this)
    17.             {
    18.                 Destroy(this.gameObject);
    19.             }
    20.             else
    21.             {
    22.                 _instance = this;
    23.             }
    24.  
    25.             _defaultControls = new DefaultControls();
    26.         }
    27.  
    28.         private void Start()
    29.         {
    30.             SetContext(InputContext.GamePlay);
    31.  
    32.             _defaultControls.Player.Enable();
    33.             _defaultControls.UI.Enable();
    34.  
    35.             _defaultControls.Player.Running.performed         += (ctx) => IsRunning = true;
    36.             _defaultControls.Player.Running.canceled          += (ctx) => IsRunning = false;
    37.  
    38.             _defaultControls.Player.PrimaryAction.performed   += (ctx) => PrimaryActionPressed = true;
    39.             _defaultControls.Player.PrimaryAction.canceled    += (ctx) => PrimaryActionPressed = false;
    40.  
    41.             _defaultControls.Player.SecondaryAction.performed += (ctx) => SecondaryActionPressed = true;
    42.             _defaultControls.Player.SecondaryAction.canceled  += (ctx) => SecondaryActionPressed = false;
    43.  
    44.             _defaultControls.Player.RotateSnap.performed      += (ctx) => RotateSnapPressed = true;
    45.             _defaultControls.Player.RotateSnap.canceled       += (ctx) =>
    46.             {
    47.                 RotateSnapPressed   = false;
    48.                 RotateSnapCanceled  = true;
    49.             };
    50.            
    51.             _defaultControls.Player.RotateAction.performed  += (ctx) =>
    52.             {
    53.                 RotateActionPressed = true;
    54.                
    55.                 //Todo: Should be handled by input context/states?
    56.                 _defaultControls.Player.Look.Disable();
    57.             };
    58.             _defaultControls.Player.RotateAction.canceled += (ctx) =>
    59.             {
    60.                 RotateActionPressed = false;
    61.  
    62.                 //Todo: Should be handled by input context/states?
    63.                 _defaultControls.Player.Look.Enable();
    64.             };
    65.  
    66.             _defaultControls.UI.HideHUD.performed += (ctx) =>
    67.             {
    68.                 if (OnHideUITriggered != null)
    69.                     OnHideUITriggered.Invoke();
    70.             };
    71.  
    72.             _defaultControls.Player.Inventory.performed += (ctx) =>
    73.             {
    74.                 if (OnInventoryButtonTriggered != null)
    75.                     OnInventoryButtonTriggered.Invoke();
    76.             };
    77.  
    78.             _defaultControls.Player.ItemSlot01.performed += (ctx) => ExecuteOnItemSlotButtonTriggered(1);
    79.             _defaultControls.Player.ItemSlot02.performed += (ctx) => ExecuteOnItemSlotButtonTriggered(2);
    80.             _defaultControls.Player.ItemSlot03.performed += (ctx) => ExecuteOnItemSlotButtonTriggered(3);
    81.         }
    82.  
    83.         private void ExecuteOnItemSlotButtonTriggered(int itemSlotIndex)
    84.         {
    85.             if (OnItemSlotButtonTriggered != null)
    86.                 OnItemSlotButtonTriggered.Invoke(itemSlotIndex);
    87.         }
    88.  
    89.         public void SetContext(InputContext context)
    90.         {
    91.             _currentInputContext = context;
    92.             //Debug.Log($"Set UIContext = '{context}'");
    93.  
    94.             switch (_currentInputContext)
    95.             {
    96.                 case InputContext.GamePlay:
    97.                     _defaultControls.Player.Enable();
    98.                     _defaultControls.UI.Enable();
    99.                     SetCursorLocked(true);
    100.                     break;
    101.                 case InputContext.GameMenu:
    102.                     _defaultControls.Player.Disable();
    103.                     _defaultControls.UI.Disable();
    104.                     SetCursorLocked(false);
    105.                     break;
    106.                 case InputContext.GameInventory:
    107.                     _defaultControls.Player.Disable();
    108.                     _defaultControls.UI.Disable();
    109.                     _defaultControls.Player.Movement.Enable();
    110.                     _defaultControls.Player.Inventory.Enable();
    111.                     SetCursorLocked(false);
    112.                     break;
    113.                 default:
    114.                     Debug.LogError($"Unknown InputContext: '{_currentInputContext}'");
    115.                     break;
    116.             }
    117.         }
    118.  
    119.         private void SetCursorLocked(bool isLocked)
    120.         {
    121.             Cursor.lockState    = isLocked ? CursorLockMode.Locked : CursorLockMode.None;
    122.             Cursor.visible      = isLocked ? false : true;
    123.         }
    124.  
    125.         private void FixedUpdate()
    126.         {
    127.             Movement    = _defaultControls.Player.Movement.ReadValue<Vector2>();
    128.         }
    129.  
    130.         private void Update()
    131.         {
    132.             LookDelta                   = _defaultControls.Player.Look.ReadValue<Vector2>();
    133.             RotateAxisDelta             = _defaultControls.Player.RotateAxis.ReadValue<Vector2>();          
    134.             Jump                        = _defaultControls.Player.Jump.triggered;
    135.             InteractButtonUp            = _defaultControls.Player.Interact.triggered;
    136.             SecondaryActionTriggered    = _defaultControls.Player.SecondaryAction.triggered;
    137.             RotateActionTriggered       = _defaultControls.Player.RotateAction.triggered;
    138.             RotateSnapTriggered         = _defaultControls.Player.RotateSnap.triggered;
    139.             GrabDistance                = _defaultControls.Player.GrabDistance.ReadValue<float>();
    140.  
    141.             UIBackButtonTriggered       = _defaultControls.UI.Back.triggered;
    142.         }
    143.         private void LateUpdate()
    144.         {
    145.             //Reset
    146.             RotateSnapCanceled = false;
    147.         }
    148.  
    149.         public static InputManager Instance     { get { return _instance; } }
    150.         public InputContext CurrentContext      { get { return _currentInputContext; } }
    151.  
    152.         public Vector2 LookDelta                { get; private set; } = new Vector2(0.5f, 0.5f);
    153.         public Vector2 Movement                 { get; private set; } = Vector2.zero;
    154.         public bool IsRunning                   { get; private set; } = false;
    155.         public bool Jump                        { get; private set; } = false;
    156.         public bool InteractButtonUp            { get; private set; } = false;
    157.         public bool PrimaryActionPressed        { get; private set; } = false;
    158.         public bool SecondaryActionPressed      { get; private set; } = false;
    159.         public bool SecondaryActionTriggered    { get; private set; } = false;
    160.         public bool RotateActionPressed         { get; private set; } = false;
    161.         public bool RotateActionTriggered       { get; private set; } = false;
    162.         public bool RotateSnapTriggered         { get; private set; } = false;
    163.         public bool RotateSnapPressed           { get; private set; } = false;
    164.         public bool RotateSnapCanceled          { get; private set; } = false;
    165.         public Vector2 RotateAxisDelta          { get; private set; } = Vector2.zero;
    166.         public float GrabDistance               { get; private set; } = 0f;
    167.  
    168.         public bool UIBackButtonTriggered       { get; private set; } = false;
    169.     }
    170.  
    171.     [System.Serializable]
    172.     public class ItemSlotTriggeredEvent : UnityEvent<int>
    173.     {
    174.     }
    175.  
    176.     public enum InputContext
    177.     {
    178.         GamePlay = 1,
    179.         GameMenu = 2,
    180.         GameInventory = 3
    181.     }
     
    DonPuno and Arkade like this.
  26. Hellzbellz123

    Hellzbellz123

    Joined:
    May 15, 2019
    Posts:
    12
    this was written before i saw above post
    Code (CSharp):
    1. using Cinemachine;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5. using UnityEngine.InputSystem;
    6. using UnityEngine.InputSystem.Controls;
    7. using VanillaCoffee;
    8.  
    9. public class InputManager : MonoBehaviour
    10. {
    11.     [SerializeField] private InputActionReference _inputActionReferenceAiming;
    12.     public InputAction AimingAction;
    13.  
    14.     Vector2 look;
    15.     private Vector2 _inputAim;
    16.  
    17.     void Start() => CinemachineCore.GetInputAxis = GetAxisCustom;
    18.  
    19.     private void OnEnable()
    20.     {
    21.         {
    22.             _inputActionReferenceAiming.action.performed += ctx => look = ctx.ReadValue<Vector2>();
    23.             _inputActionReferenceAiming.action.Enable();
    24.         }
    25.  
    26.     }
    27.  
    28.     private void OnDisable()
    29.     {
    30.         _inputActionReferenceAiming.action.performed -= ctx => look = Vector2.zero;
    31.         _inputActionReferenceAiming.action.Disable();
    32.     }
    33.  
    34.  
    35.     public float GetAxisCustom(string axisName)
    36.     {
    37.         //Log();
    38.         _inputAim = _inputActionReferenceAiming.action.ReadValue<Vector2>();
    39.  
    40.         look = _inputAim;
    41.  
    42.         if (axisName == "Mouse X")
    43.         {
    44.             return look.x;
    45.         }
    46.  
    47.         else if (axisName == "Mouse Y")
    48.         {
    49.             return look.y;
    50.         }
    51.         return 0;
    52.     }
    53.  
    54.     void Log()
    55.     {
    56.         string lookdir = look.ToString();
    57.  
    58.         Debug.Log(lookdir); //
    59.     }
    60. }
    this is all ive managed to piece together but now im not getting any input
    this was written before i saw above post
     
    Last edited: Oct 22, 2019
  27. Jichaels

    Jichaels

    Joined:
    Dec 27, 2018
    Posts:
    237
    If you're polling, you don't need to assign callbacks to OnEnable/OnDisable, simply remove all that part. Look isn't usefull anymore, you're just copying a vector2 to a vector2
     
  28. Laumania

    Laumania

    Joined:
    Jun 27, 2012
    Posts:
    189
    Yeah try and look at my sample and take out only the things you need and post what you end up with. Try and do it in a similar manner as I am doing. Then when you get it working, then you refactor if you want to some other way.

    The trick it to try and keep things as simple as possible, which is also the hardest thing to do :)
     
  29. bonickhausen

    bonickhausen

    Joined:
    Jan 20, 2014
    Posts:
    103
    polling mouse delta is still wrong for me.

    by using the good old "Input.GetAxisRaw("Mouse X")"/MouseY and creating a Vector2 with those values, I get a far smoother experience than by polling mouse delta with the new input system.

    I am not using callbacks; I am polling values straight from the action.

    I am creating a first person shooter; the new system does not work properly with very suble movements.

    If I move my mouse veeeeery slowly, it does not pick up any delta at all but the old system works just fine.

    Mouse delta is broken.
     
    T410 likes this.
  30. Hellzbellz123

    Hellzbellz123

    Joined:
    May 15, 2019
    Posts:
    12
    you might try using mouse position to do small movements
    and then switching?
     
  31. Jichaels

    Jichaels

    Joined:
    Dec 27, 2018
    Posts:
    237

    Mmmh that's not the case for me (and mind you, I'm at 400dpi on desktop). Even the slightest movement is getting picked up. Maybe you're doing something wrong ?

    What I'm using :

    Code (CSharp):
    1. _inputRotation = inputActionCameraRotation.action.ReadValue<Vector2>();
    2.  
    3. if (_currentControlScheme == CustomControlScheme.MouseKeyboard)
    4. {            
    5.     _inputRotation *= Rules.RotationSpeedMouse;
    6. }
    7. else if (_currentControlScheme == CustomControlScheme.Gamepad)
    8. {
    9.     if (Mathf.Abs(_inputRotation.x) < Rules.JoystickDeadZone && Mathf.Abs(_inputRotation.y) < Rules.JoystickDeadZone) return;
    10.     _inputRotation *= Time.deltaTime * Rules.RotationSpeedJoystick;
    11. }
    12. _transform.Rotate(Vector3.up, _inputRotation.x);
    13. _currentLocalRotationEulers.x = Mathf.Clamp(_currentLocalRotationEulers.x - _inputRotation.y, -80, 80);
    14. HeadSet.CameraTransform.localEulerAngles = _currentLocalRotationEulers;
    And it just works fine !
     
  32. bonickhausen

    bonickhausen

    Joined:
    Jan 20, 2014
    Posts:
    103
    I must be doing something wrong then. I'll double check.
     
  33. Hellzbellz123

    Hellzbellz123

    Joined:
    May 15, 2019
    Posts:
    12
    so im still having issues with this damn system however it seems to be just how the mouse gets handled. would you mind showing me the settings you are using inside the Input ACtions file thingy?


    I FIGURED IT OUT THAT TOOK WAY TOO LONG HOLY CRAP.

    for anyone else who has this issue
    mouse delta input needs too come from a action type: Value, Control Type: Vector 2
     

    Attached Files:

    Last edited: Oct 25, 2019
    Vazili_KZ likes this.
  34. Jichaels

    Jichaels

    Joined:
    Dec 27, 2018
    Posts:
    237
    Action is Value / Vector2. The binding is Delta [Mouse]. Nothing else
     
  35. Laumania

    Laumania

    Joined:
    Jun 27, 2012
    Posts:
    189
    Great you solved it! What did you set it to before where it didn't work?
     
  36. Hellzbellz123

    Hellzbellz123

    Joined:
    May 15, 2019
    Posts:
    12
    anything other than what it was set too i even tried value at first but it wasnt set to vector2 i set it to axis and something else
     
  37. deeprest

    deeprest

    Joined:
    Jun 8, 2016
    Posts:
    17
    On MacOS, values are generated for the mouse delta while the cursor is motionless. I've submitted a bug report, FogBugz ticket here.

    MacbookPro macOS 10.13.6
    Unity 2019.2.6f1
    Input System 1.0.0 preview.1

    Here's a horribly-made demonstration. The red timer resets when the mouse delta is non-zero.


    Here the code for the test
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.InputSystem;
    5. using UnityEngine.UI;
    6.  
    7. // Bug: intermittent. Mouse delta sometimes has non-zero values while mouse is not moving, apparent only when clicking.
    8. // To reproduce: move cursor then keep cursor motionless. Then click and observe debug logs generated
    9. // because mouse delta is non-zero. May take a few tries before bug is apparent.
    10.  
    11. public class bug : MonoBehaviour
    12. {
    13.   Controls Controls;
    14.   public Vector2 currentDelta;
    15.   public Vector2 readValue;
    16.  
    17.   public Text delta;
    18.   public Text deltaNow;
    19.   public Text value;
    20.   public Text valueNow;
    21.   public Text timeSinceLastNonZero;
    22.  
    23.   private void Start()
    24.   {
    25.     Controls = new Controls();
    26.     Controls.Enable();
    27.     Controls.BipedActions.Enable();
    28.   }
    29.  
    30.   float timeNonZero;
    31.  
    32.   void Update()
    33.   {
    34.     currentDelta = Mouse.current.delta.ReadValue();
    35.     if( currentDelta.magnitude > 0.0f )
    36.     {
    37.       timeNonZero = Time.time;
    38.       Debug.LogFormat( "Last nonzero Mouse.current.delta {0} {1}", currentDelta.x, currentDelta.y );
    39.       delta.text = "Last nonzero delta " + currentDelta.x + " " + currentDelta.y;
    40.     }
    41.     deltaNow.text = "Current delta " + currentDelta.x + " " + currentDelta.y;
    42.  
    43.     readValue = Controls.BipedActions.Aim.ReadValue<Vector2>();
    44.     if( readValue.magnitude > 0.0f )
    45.     {
    46.       timeNonZero = Time.time;
    47.       Debug.LogFormat( "Last nonzero ReadValue<Vector2>() {0} {1}", readValue.x, readValue.y );
    48.       value.text = "Last nonzero ReadValue<Vector2>() " + readValue.x + " " + readValue.y;
    49.     }
    50.     valueNow.text = "Last nonzero ReadValue<Vector2>() " + readValue.x + " " + readValue.y;
    51.  
    52.     timeSinceLastNonZero.text = (Time.time - timeNonZero).ToString();
    53.   }
    54. }
    55.  
    Same result if use Mouse.current.delta or read the value from an Action.

    Here's what it looks like in my game
     
  38. Saucyminator

    Saucyminator

    Joined:
    Nov 23, 2015
    Posts:
    56
    I'm also having trouble upgrading to the new input system where I used to have Input.GetAxis("Mouse X") (and Y), and now trying to read the mouse delta.

    I've setup a Mouse action to "action type: Value, control type: Vector2" and the binding is using the path "Delta [Mouse]".

    New system is very jittery and I cannot replicate the same movement for my weapon sway.

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class Sway : MonoBehaviour {
    4.   [SerializeField] private bool useNewInputs = true;
    5.   [SerializeField] private float swayAmount = 0.02f;
    6.   [SerializeField] private float maxSwayAmount = 0.06f;
    7.   [SerializeField] private float swaySmoothValue = 4f;
    8.  
    9.   private Vector3 initialSwayPosition;
    10.   private InputMaster inputs;
    11.   private Vector2 mouse;
    12.  
    13.   private void Awake () {
    14.     inputs = new InputMaster();
    15.   }
    16.  
    17.   private void OnEnable () {
    18.     inputs.Weapon.Mouse.Enable();
    19.   }
    20.  
    21.   private void OnDisable () {
    22.     inputs.Weapon.Mouse.Disable();
    23.   }
    24.  
    25.   private void Start () {
    26.     initialSwayPosition = transform.localPosition;
    27.   }
    28.  
    29.   private void LateUpdate () {
    30.     mouse = inputs.Weapon.Mouse.ReadValue<Vector2>();
    31.  
    32.     float movementX = (useNewInputs) ? -mouse.x * swayAmount : -Input.GetAxis("Mouse X") * swayAmount;
    33.     float movementY = (useNewInputs) ? -mouse.y * swayAmount : -Input.GetAxis("Mouse Y") * swayAmount;
    34.  
    35.     movementX = Mathf.Clamp(movementX, -maxSwayAmount, maxSwayAmount);
    36.     movementY = Mathf.Clamp(movementY, -maxSwayAmount, maxSwayAmount);
    37.  
    38.     Vector3 finalSwayPosition = new Vector3(movementX, movementY, 0f);
    39.     transform.localPosition = Vector3.Lerp(transform.localPosition, finalSwayPosition + initialSwayPosition, Time.deltaTime * swaySmoothValue);
    40.   }
    41. }
    42.  
    Album with two GIFs showing old and new input system:
    https://imgur.com/a/cLCF1tH
     
    nerdsarewinning and cxode like this.
  39. nerdsarewinning

    nerdsarewinning

    Joined:
    Apr 1, 2013
    Posts:
    15
    Is there any way to fix the jittering movement? Like smoothing etc, does anyone solved this?
     
  40. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,326
    I was missing these magic values too. After I had upgraded to the new input system, mouse input felt rather bad compared to the old system, where I tweaked the values for. Once I added "Scale" Processsor's to the "Delta [Mouse]" action, to replicate these magic values, input feels like before again.

    You should put these magic multipliers and a description into a "How to upgrade to the New Input System" document.
     
    BaraShiro, DonPuno and PutridEx like this.
  41. cxode

    cxode

    Joined:
    Jun 7, 2017
    Posts:
    260
    I was having a lot of issues with this in past versions, but as of 2019.3.2f1 and InputSystem 1.0.0-preview.5, Mouse.current.delta.ReadValue() is performing exactly as Input.GetAxis does.

    This is the script I used to verify the behavior. Attach it to two objects in a UI canvas, and set one to "new input" and the other to "old input".

    I have found that Old Input with sensitivity 1 moves exactly the same as New Input with sensitivity 0.5.

    Code (CSharp):
    1.  
    2. using UnityEngine;
    3. using UnityEngine.InputSystem;
    4.  
    5. [RequireComponent(typeof(RectTransform))]
    6. public class MouseTest : MonoBehaviour
    7. {
    8.     enum Mode
    9.     {
    10.         Old,
    11.         New,
    12.     }
    13.  
    14.     [SerializeField] Mode InputMode;
    15.     [SerializeField] float Sensitivity = 1f;
    16.  
    17.     private void LateUpdate()
    18.     {
    19.         var delta = new Vector2();
    20.  
    21.         if (InputMode == Mode.New)
    22.             delta = Mouse.current.delta.ReadValue();
    23.        
    24.         if (InputMode == Mode.Old)
    25.             delta = new Vector2(Input.GetAxis("Mouse X"), Input.GetAxis("Mouse Y"));
    26.  
    27.  
    28.         delta *= Sensitivity;
    29.  
    30.         ((RectTransform)transform).anchoredPosition += delta;
    31.     }
    32. }
    33.  
     
  42. sillidev

    sillidev

    Joined:
    Mar 5, 2020
    Posts:
    2
    @Rene-Damm I'm learning Unity for 1 month. I'm using the New Input System and notice that the mouse-delta isn't match with my pointer movement.

    Ex: In my 2D shooting game, if I move pointer around then get back to the original position, the crosshair won't get back to its original position. It's the same issue described in Wokky video, except in my case the Old Input (getAxis) is also inconsistent.

    Here's my screen record - https://drive.google.com/file/d/1Q-UhK6_VoIUIcEkqnmhmVOJwVvmpP4Jo/view?usp=sharing

    Unity 2019.2.15f1 - Input System version 1.0.0

    And my code
    Code (CSharp):
    1. public class MouseController : MonoBehaviour
    2. {
    3.     // Start is called before the first frame update
    4.  
    5.     Transform other;
    6.     bool isHold = false;
    7.     void Start()
    8.     {
    9.         other = gameObject.transform.Find("Others");
    10.     }
    11.  
    12.  
    13.  
    14.     public void OnLook(InputValue value)
    15.     {
    16.         if (isHold){
    17.             var delta = value.Get<Vector2>();
    18.             other.transform.position += (Vector3) delta * .005f;
    19.         }
    20.     }
    21.  
    22.     public void OnFire(InputValue value)
    23.     {
    24.         isHold = !isHold;
    25.     }
    26. }
    So my questions are:
    1. Is it an Unity bug or limitation (because it happened on both Old & New Input) ? Maybe I'm doing something wrong ?
    2. Just in case it's a limitation, what are options to make the best out of it ?

    Thanks
     
  43. Rene-Damm

    Rene-Damm

    Unity Technologies

    Joined:
    Sep 15, 2012
    Posts:
    1,779
    @sillidev This would be expected given that the mouse delta control has accumulation built into it (i.e. it accumulates over the frame and then resets to 0 at the beginning of the next frame). So if there's multiple mouse motion events in a frame, you get OnLook called for every single one but with a cumulative effect on the delta. So the += on the position essentially applies the current delta *and* every prior delta in the frame that was already applied.

    Do you get the behavior more in line with what you expect with something like this?

    Code (CSharp):
    1. public class MouseController : MonoBehaviour
    2. {
    3.     private InputAction m_Fire;
    4.     private InputAction m_Look;
    5.  
    6.     public void Awake()
    7.     {
    8.         m_Fire = new InputAction("fire", binding: "<Mouse>/leftButton");
    9.         m_Look = new InputAction("look", binding: "<Mouse>/delta");
    10.     }
    11.  
    12.     public void OnEnable()
    13.     {
    14.         m_Fire.Enable();
    15.         m_Look.Enable();
    16.     }
    17.  
    18.     public void OnDisable()
    19.     {
    20.         m_Fire.Disable();
    21.         m_Look.Disable();
    22.     }
    23.  
    24.     public void Update()
    25.     {
    26.         if (m_Fire.ReadValue<float>() > 0) // There's an IsPressed() API coming.
    27.             transform.position += (Vector3)m_Look.ReadValue<Vector2>() * 0.005f;
    28.     }
    29. }
    30.  
     
    sillidev likes this.
  44. sillidev

    sillidev

    Joined:
    Mar 5, 2020
    Posts:
    2
    @Rene-Damm Thx for the quick reply. It's more in line with my expectation when following your suggestion. I guess moving code inside Update is the key.

    But using Update does slow the moving speed. If I increase the speed (eg: .005 -> .008) then Update is just slightly better than OnLook

    In this screen record (link) I use mouse to move 3 circles:
    • Brown: using OnMove (delta * 0.005)
    • Red: using Update (delta * 0.005)
    • Green: using Update (delta * 0.008)
    You can see brown & green are moving in pretty much same speed, and green one is less far off from the starting point. I think Update is better choice for now.

    Thx @Rene-Damm again for the explanation and suggestion.
     
  45. Gooren

    Gooren

    Joined:
    Nov 20, 2015
    Posts:
    319
    @Rene-Damm I had to do this
    upload_2020-3-14_22-11-10.png
    just to keep sensitivity approximately the same as with old UnityEngine.Input API.
    Why is the sensitivity with the new InputSystem so crazy high by default? Is this a correct approach?

    Cheers!
     
    Janikpleyy likes this.
  46. Rene-Damm

    Rene-Damm

    Unity Technologies

    Joined:
    Sep 15, 2012
    Posts:
    1,779
    The delta is relayed from the platform as is. I.e. if the platform says the mouse moved 10 units in X and 5 in Y, that's the delta we report. The old input input system backends arbitrarily scale motion deltas down with what they deem some sensible default factor which leads to different platforms applying different scaling factors. IMO it doesn't make sense to report the mouse moved from position (640,480) to (644,484) but then arbitrarily report a delta of (2,2) instead of (4,4) just for the sake of mouse look.

    An overall goal with the input system has been to move decisions up and out of platform code and surface things as is to managed code where then it's easier and more flexible to wire things up differently.

    That said, good mouse sensitivity scaling (sitting in-between the mouse device input and action output) that comes out of the box and is user-adjustable is definitely a missing piece from the input system. It's on the list and will get looked at after 1.0.

    Also, we do still see reports around oddities with mouse deltas which we're trying to track down.
     
    cxode and Gooren like this.
  47. Gooren

    Gooren

    Joined:
    Nov 20, 2015
    Posts:
    319
    Thanks for the quick and informative answer :)
     
  48. Gooren

    Gooren

    Joined:
    Nov 20, 2015
    Posts:
    319
    I just encountered one such oddity on 1.0.0 preview.6.
    With the mouse delta setup I posted here (#45), I never get [0,0] delta vector after stopping mouse movement in case I have multiple bindings on mouse delta.
    I have two bindings for mouse delta from two different actions both active at the same time. Only one of them always sends (in the perform event) zero vector after I stop moving the mouse. The other one sends something like [0.2, 0.05] in the last perform invocation.

    Interesting thing is that it seems to send the exact value I used for the scale vector processor the most.

    EDIT:
    My fault... the other action had Button set as an Action Type. It still worked perfectly, this is what confused me. Well except for the the fact it never sent the zero vector :)
     
  49. mmuijsert

    mmuijsert

    Joined:
    Feb 25, 2020
    Posts:
    1
    I'm having the issue that mouse delta value stays zero when moving the mouse when locked, but when unlocked there's a mouse delta. I opened an issue for this on the github: https://github.com/Unity-Technologies/InputSystem/issues/1149

    It seems that this works fine on windows, but does not on linux (ubuntu).
     
    ashtorak likes this.
  50. Keizer

    Keizer

    Joined:
    Mar 19, 2019
    Posts:
    1
    Is there any update on this? I am seeing the action events fire after Update and Late Update, so it seems that anything that uses mouseDelta cannot be used in a polling fashion. They must be used directly from each action callback. This leads to a problem: How do you tell when the accumulation is finished?

    I'll be honest, I don't really understand how this is supposed to be used at all without a some sort of processor to announce when the accumulation is finished for a given frame.
     
    FlavioIT and Gooren like this.