Search Unity

Delta Mouse Position with OS Smoothing / Acceleration

Discussion in 'Input System' started by No_exit4You, May 12, 2017.

  1. No_exit4You

    No_exit4You

    Joined:
    May 12, 2017
    Posts:
    6
    This question is regarding the current input system although it could also apply to the new input system if no solution is found in the current input system.

    Problem
    We are looking for a way to get the delta mouse position from the operating system that is subjective to mouse smoothing and mouse acceleration if the user has it enabled in the operating system. This must work in windowed mode on both Windows and Mac in the current (or new) Unity input system without the mouse leaving the window. This however does not seem to be possible in Unity.

    Three ’Solutions’ we tried that do not work
    1) Tracking Input.mousePosition and calculating the delta movement
    This is because you can accidentally move your mouse outside the game window and click. Using CursorLockMode to prevent this has other side effects which are unacceptable.
    Using CursorLockMode.Confined does not work on mac and messes with Input.mousePosition when going close to the border.
    Using CursorLockMode.Locked causes the Input.mousePosition to no longer move and thus you can no longer calculate your delta mouse position.
    Resetting the cursor position by using CursorLockMode.Locked and immediately after CursorLockMode.None causes some Mouse delta commands to be lost and causes mouse jitter which is unusable. The Screen location to which the CursorLockMode.Locked resets seems to also have some consistency issues when resizing, undocking the game window and losing focus.

    2) Input.GetAxisRaw(“Mouse X”)
    This does not take OS mouse acceleration into account. There seem to be other differences compared to a delta mouse movement which we assume to be smoothing.

    3) Input.GetAxis(“Mouse X”)
    This gives the same identical values as “GetAxisRaw”.

    (Tested on Mac in Unity 5.5.0p3)
     
  2. runevision

    runevision

    Joined:
    Nov 28, 2007
    Posts:
    1,892
    Indeed there doesn't currently seem to be a way either with the old or new input system. We'll look into why.
     
  3. No_exit4You

    No_exit4You

    Joined:
    May 12, 2017
    Posts:
    6
    Is it because the Operating Systems do not calculate delta movements anymore once they are in a locked state, and no interface is provided to calculate this in locked state?
     
  4. justprogramming

    justprogramming

    Joined:
    Sep 12, 2014
    Posts:
    21
    Hi there,

    I am just wondering whether you figured out the solution for this problem. I am also trying to make my gameobject to move a similar way as the cursor would in windows system.

    From reading your post, my understanding is that Input.GetAxisRaw(“Mouse X”) gives the delta mouse value from Windows OS and disregard any acceleration function the OS may have. Basically, Input.GetAxisRaw(“Mouse X”) returning the absolute raw value from the OS. Is this correct?

    Thanks in advance.
     
  5. runevision

    runevision

    Joined:
    Nov 28, 2007
    Posts:
    1,892
    Hi, we haven't been able to look further into this, and won't be for the time being. It's one of those things we'd like to get to, but there are a lot of more critical things on our plate we have to prioritize. I understand it's probably frustrating and I'm sorry about that.
     
  6. justprogramming

    justprogramming

    Joined:
    Sep 12, 2014
    Posts:
    21
    I understand. Thanks for your reply.

    I am also trying to confirm that the questions in the second paragraph:
    "...my understanding is that Input.GetAxisRaw(“Mouse X”) gives the delta mouse value from Windows OS and disregard any acceleration function the OS may have. Basically, Input.GetAxisRaw(“Mouse X”) returns the absolute raw value from the OS. Is this correct?"

    Reading the API is really hard to get a clear idea.
     
  7. No_exit4You

    No_exit4You

    Joined:
    May 12, 2017
    Posts:
    6
    We have a ‘workaround’ to get the delta mouse position which includes mouse acceleration.

    You should know though that it is accurately imperfect, can cause the cursor to flicker outside the screen, can cause the window to lose focus. It has some hacks and we are not 100% sure it will work under all conditions. If it fails then it can render the game to be unplayable as the mouse will jump around. It will also make the mouse position locked, normally only once when the game is started.

    It is as follows:
    - Make the cursor invisible
    - Track the Input.mousePosition of the previous frame and calculate the difference with the current input to calculate the delta
    - Once you are afraid that the mouse will get outside of the window in the next frame, reset the Cursor by doing CursorLockMode.Locked and immediately after CursorLockMode.None (same frame). This causes some imprecision but if you don’t do it too often and your frame rate is high enough, you won’t notice it.
    If you reset it every frame, you will definitely notice it and it feels and looks horrible.

    The position that the cursor resets to is inconsistent and is different depending on operating system, resolution, focus, and another reason I haven't managed to track yet but it seems related to losing/gaining focus. You have been warned :). The position where the cursor resets is not always the middle of the game window.
    Having the wrong reset position will cause the delta to be huge and make the system completely unplayable.

    So to know what the "reset" position is of the mouse, we keep on resetting the mouse position each frame until Input.GetAxis is 0 for x and y. We keep that Input.mousePosition until we notice something is changed (resolution, focus) and then we go back to reset the mouse each frame. Most of the time the player will not notice this, or it will magically solve itself before the player can really start to get frustrated.

    Good luck and if you learned something new or have something better then please share :).


    Our testing showed that GetAxis and GetAxisRaw both do not include mouse acceleration for Mac and were identical.
     
  8. justprogramming

    justprogramming

    Joined:
    Sep 12, 2014
    Posts:
    21
    Hi,

    I am trying to implement this solution. However, one problem I face is that I cannot confine the cursor in the game window. Did you face this problem? If you did, how did you solve it?

    Thanks in advance.

     
  9. No_exit4You

    No_exit4You

    Joined:
    May 12, 2017
    Posts:
    6
    "Once you are afraid that the mouse will get outside of the game window in the next frame, reset the Cursor by doing CursorLockMode.Locked and immediately after CursorLockMode.None (same frame). This causes some imprecision but if you don’t do it too often and your frame rate is high enough, you won’t notice it."

    For the actual prediction of whether or not you will go outside the game window in the next frame, I suggest to look at how close you are to the edge of the window. For more precision you can also take the "velocity" and maybe even "acceleration" of the cursor into account so you don't need to take a huge border and reset often.