Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice

Question Sampling XR controller positions and linear velocity independent of frame rate and physics time step

Discussion in 'XR Interaction Toolkit and Input' started by HopefulDeveloper, Dec 12, 2022.

  1. HopefulDeveloper

    HopefulDeveloper

    Joined:
    Jan 17, 2022
    Posts:
    10
    Hi, I’m working on a Unity v2021.3 LTS VR game with Quest 2. I would like to sample the Quest 2 controller positions and linear velocity independent of frame rate / physics time step. Ideally I want to sample the Quest 2 controllers every 2 milliseconds. Right now they are getting sampled every 13.8ms via monobehavior.Update calls.

    I have determined that Update, FixedUpdate, Corountines, and WaitForSeconds are not a valid approach because all of these approaches are tied to the frame rate / physics time step.

    I’m struggling to find a working solution for this problem. I’m looking into using the new input system and setting the pollingFrequency to be higher. I’m not sure if the new input system will work for my use case?

    Does anyone have any insight to my problem?
     
  2. Arnold_2013

    Arnold_2013

    Joined:
    Nov 24, 2013
    Posts:
    287
    This would be great. Where you able to make any progress with this?

    I am currently trying to get more input values using the "InputActionTrace".
    With InputSystem.pollingFrequency = 1000;
    With the Application.targetFrameRate = 1;
    using the keyboard I can get multiple actions from the keyboard in 1 frame to be logged. But for OpenXR + SteamVR + Valve index + in editor, the controller velocity the trace.count is always just 1 :confused:.
     
  3. Arnold_2013

    Arnold_2013

    Joined:
    Nov 24, 2013
    Posts:
    287
    I've now also tried the "InputEventTrace", but it seems to also just produce 1 value per frame.

    From the input debugger it looks like all openXR data is jammed into 1 data struct, in this case since you can only provide a Device to the constructor of the trace, this might be expected.
    Also the events in the input debugger also seem to be framerate dependent, its not like these are running at normal frequency while target framerate is 1.

    Edit: Adding to this, I also tried running the input in the fixed update, so that it could be sampled multiple times per frame. But this also did not do anything. (not with the input system update mode set to fixedupdate, or with manually calling InputSystem.Update(); in the fixedupdate().
    It does not matter much, since the fixed update steps all run at the start of the frame and then idle until the targetframerate.
     
    Last edited: Jun 5, 2023
  4. Arnold_2013

    Arnold_2013

    Joined:
    Nov 24, 2013
    Posts:
    287
    Filed a bug report for this (IN-43099).

    Here is the code I used to show keyboard input being framerate independent, while openXR input is not. I don't have the skill level to dig any deeper into the code. I also was not expecting input to be an issue, since valve already stopped supporting their unity plugin in favor of openXR years ago.

    Keyboard working with framerate independence (inspired by : https://www.clpsplug.com/en/2023/01/22/input-frame.html) :
    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.InputSystem;
    3. using UnityEngine.InputSystem.Utilities;
    4.  
    5. public class KeyboardFramerateIndependantInputWorks : MonoBehaviour
    6. {
    7.  
    8.     private InputActionTrace _trace;
    9.     public InputActionReference theActionRef;
    10.     private int frame;
    11.  
    12.     private void OnEnable()
    13.     {
    14.         theActionRef.action.Enable();
    15.         Application.targetFrameRate = 1;
    16.     }
    17.  
    18.     private void OnDisable()
    19.     {
    20.         theActionRef.action.Disable();
    21.     }
    22.  
    23.  
    24.     private void Awake()
    25.     {
    26.         _trace = new InputActionTrace();
    27.         _trace.SubscribeTo(theActionRef.action);
    28.         InputSystem.pollingFrequency = 500;
    29.     }
    30.  
    31.     private void Update()
    32.     {
    33.         Debug.Log($"Frame : {frame}");
    34.         frame++;
    35.  
    36.         InputSystem.Update();
    37.  
    38.         Debug.Log(_trace.count);
    39.  
    40.         foreach (var action in _trace)
    41.         {      
    42.              var diff = Time.realtimeSinceStartupAsDouble - action.time;
    43.              Debug.Log($"This action has occurred {diff.ToString("F3")} seconds before this frame.");      
    44.         }
    45.  
    46.         _trace.Clear();
    47.     }
    48.  
    49.     private void OnDestroy()
    50.     {
    51.         _trace.UnsubscribeFromAll();
    52.         _trace.Dispose();
    53.     }
    54. }
    55.  

    VR controller not being framerate independant :
    Code (CSharp):
    1. using Unity.Mathematics;
    2. using UnityEngine;
    3. using UnityEngine.InputSystem;
    4. using UnityEngine.InputSystem.Utilities;
    5.  
    6. public class VrControllerFramerateIndependantInputFails : MonoBehaviour
    7. {
    8.     private InputActionTrace _trace;
    9.     public InputActionReference theActionRef;
    10.     private int frame;
    11.  
    12.     private void OnEnable()
    13.     {
    14.         theActionRef.action.Enable();  
    15.         Application.targetFrameRate = 1;
    16.     }
    17.  
    18.     private void OnDisable()
    19.     {
    20.         theActionRef.action.Disable();
    21.     }
    22.  
    23.  
    24.     private void Awake()
    25.     {
    26.         _trace = new InputActionTrace();
    27.         _trace.SubscribeTo(theActionRef.action);
    28.         InputSystem.pollingFrequency = 500;
    29.     }
    30.  
    31.     private void Update()
    32.     {
    33.         Debug.Log($"Frame : {frame}");
    34.         frame++;
    35.  
    36.         InputSystem.Update();
    37.  
    38.         Debug.Log(_trace.count);
    39.  
    40.         foreach (var action in _trace)
    41.         {
    42.             Debug.Log($"veclocity in action = {action.ReadValue<float3>()}"); // not needed for the bug, but a sanity check to see its not returning strange values.
    43.          
    44.              var diff = Time.realtimeSinceStartupAsDouble - action.time;
    45.              Debug.Log($"This action has occurred {diff.ToString("F4")} seconds before this frame.");      
    46.         }
    47.  
    48.         _trace.Clear();
    49.     }
    50.  
    51.     private void OnDestroy()
    52.     {
    53.         _trace.UnsubscribeFromAll();
    54.         _trace.Dispose();
    55.     }
    56. }
    57.  


    Input system low level code to also not be framerate independant for VR :
    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.InputSystem;
    3. using UnityEngine.InputSystem.LowLevel;
    4.  
    5. public class VrControllerViaLowLevelAlsoFails : MonoBehaviour
    6. {
    7.     public InputActionReference theActionRef;
    8.     private InputEventTrace _trace;
    9.     private int frame;
    10.  
    11.     private void OnEnable()
    12.     {  
    13.         Application.targetFrameRate = 1;
    14.     }
    15.  
    16.     private void OnDisable()
    17.     {
    18.         theActionRef.action.Disable();
    19.     }
    20.  
    21.  
    22.     private void Awake()
    23.     {    
    24.         _trace = new InputEventTrace();
    25.         _trace.Enable();
    26.  
    27.         theActionRef.action.Enable();  
    28.         InputSystem.pollingFrequency = 500;
    29.     }
    30.  
    31.     private void Update()
    32.     {
    33.    
    34.         if (theActionRef.action.activeControl == null)
    35.         {
    36.             Debug.Log("no active device");
    37.             return;
    38.         }
    39.  
    40.         if (_trace.deviceId == InputDevice.InvalidDeviceId)
    41.         {
    42.             var device = theActionRef.action.activeControl.device;
    43.             _trace.deviceId = device.deviceId;
    44.         }
    45.  
    46.         Debug.Log($"Frame : {frame}");
    47.         frame++;
    48.  
    49.         InputSystem.Update();
    50.  
    51.         Debug.Log($"eventCount : {_trace.eventCount}");
    52.  
    53.         foreach (var inputevent in _trace)
    54.         {
    55.             Debug.Log(inputevent.ToString());
    56.  
    57.             var diff = Time.realtimeSinceStartupAsDouble - inputevent.time;
    58.             Debug.Log($"This event has occurred {diff.ToString("F4")} seconds before this frame.");
    59.        
    60.         }
    61.  
    62.         _trace.Clear();
    63.     }
    64.  
    65.     private void OnDestroy()
    66.     {
    67.    
    68.         _trace.Disable();
    69.         _trace.Dispose();
    70.     }
    71. }
    72.  
     
  5. HopefulDeveloper

    HopefulDeveloper

    Joined:
    Jan 17, 2022
    Posts:
    10
    Hey, I have not made progress on this issue. I might be working on the problem again in a few weeks. If I ever find anything out I will reply to this thread and tag you.
     
    Arnold_2013 likes this.