DISCLAIMER: This software is distributed as-is, without any warranties or conditions of any kind. Use at your own risks!
Version: 0.2.6
This document contains instructions on how to use OpenXR motion compensation API layer.
When using a motion rig in combination with a VR headset (hmd) he movement of the rig causes the in-game camera to change along with your position in the real world. In simulations for example you're basically feel being pushed around inside the cockpit when the motion rig moves.
Motion compensation reduces or ideally removes that effect by locking the in-game world to the pose of the motion rig.
This software aims to provide an API layer for motion compensation to be used with applications and hmds supporting the OpenXR standard.
To be able to do that, the software needs to be informed on the motion rig movement / position. This can be achieved using a tracker, which is either a physical object attached to the motion rig and tracked by the VR runtime (e.g. a motion controller or a vive puck) or a virtual tracker using data from the motion software driving the motion rig.
Limitations:
Feel free to join our Discord community or to send an e-mail to oxrmc@mailbox.org for feedback and assistance.
You can find the source code and the latest release or report issues on github.
If you are (or know someone) willing and able to support the software development (mostly C++, maybe some GUI stuff later on) side of the project, feel free to contact @BuzzteeBear on the Discord server to ask about ways to contribute.
Donations to the project are very welcome and can be made via Paypal.
On explicit user request you can also sponsor the project via GitHub Sponsors
Just double click the installation executable called Install_OpenXR-MotionCompensation_<current_version>.exe
and follow the instructions.
A few hints regarding the installation process:
appdata/local/OpenXR-MotionCompensation
directory that is used from version 0.2.0 onwards.program files
as installation target is recommended, especially for compatibility with WMR based headsets.Setup Log <yyyy-mm-dd xxx>.txt
that is created in the %TEMP%
folder.There may be issues with other OpenXR API layers that are installed on your system. For the most part they can be solved by using the correct order of installation (because that implicitly determines the order in which the layers are loaded).
According to user feedback following constraints seem to be working:
...HKEY_CURRENT_USER/...
while OXRMC uses ...HKEY_LOCAL_MACHINE/...
. So if you're having trouble changing the loading order, try moving the key for OpenKneeboard from Computer\HKEY_CURRENT_USER\SOFTWARE\Khronos\OpenXR\1\ApiLayers\Implicit
to Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Khronos\OpenXR\1\ApiLayers\Implicit
.You can use the application OpenXR Explorer to verify the correct installation:
xrEnumerateApiLayerProperties
(should be in the middle column at the bottom by default)XR_APILAYER_NOVENDOR_motion_compensation
with version v1
existsTo get OXRMC udpated, download and run the latest installation executable from Github. If you want to change the installation directory you have to uninstall the previous version first.
To remove the OpenXR-MotionCompensation layer just use windows settings/control panel as you would do witgh any other application. During uninstallation you can choose to delete your configuration and log files in the appdata directory or to keep them for later use.
Uninstall Log <yyyy-mm-dd xxx>.txt
that is created in the %TEMP%
folder.Configuration files can be found at ...\Users\*<Your_Username>*\AppData\Local\OpenXR-MotionCompensation\OpenXR-MotionCompensation.log
.
After intial installtion this directory contains the default configuration file OpenXR-MotionCompensation.ini
. You can make changes to that file to configure options you want to be the same for all OpenXR applications.
Upon starting an OpenXR application with the API layer active for the first time, a configuration file named after the application is created in the same directory. You can use it to copy (partial) sections from the default configuration file whenever you want to make changes only for that application specifically.
What you can modify in a configuration file:
startup
: You can modify oxrmc's behaviour on application start, e.g. disable a specific feature by setting the corresponding key to 0.
enabled
: you can disable all functionality globally or for a single application. Note that you cannot enable a single application if oxrmc is disabled globally in the default config file. Modifiying this setting requires an applcation restart.physical_enabled
: initialization of physical tracker (motion controller or vive tracker) on startup can be skipped (e.g. if you're using a virtual tracker). Modifiying this setting requires an application restart.overlay_enabled
: enable intitialization of the graphical overlay (for example if it's not required beacuse of using a physical tracker or if the position of the center of rotation is successfully setup and use_cor_pos
= 1 is used). Changing this value requires the VR session to be restarted.physical_early_init
: initialize physical tracker as soon instead of as late as possible. May be required in native OpenXR games / sims that do not support motion controllers input (e.g. iRacing). May avoid conflicts with other open xr layers (e.g. eye tracking in OpenXR toolkit). Modifiying this setting requires an applcation restart.upside_down
: turn in-game coordinate system upside down by rotating it 180 degrees around the 'forward' axis. Necessary for correct orientation of virtual tracker and motion compensation in some games (e.g. iRacing). Changing this value requires the VR session to be restarted.activate
: automatically activate motion compensation on application start and configuration reload.activate_delay
: delay auto-activation by specified number of seconds. The required time for successful activation may vary, depending on application and tracker type used.activate_countdown_
: enable audible countdown for the last 10 seconds before auto-activation. This is supposed to allow getting to neutral postion and timely centering of in-game view.tracker
: The following tracker type
keys are available:
controller
: use either the left or the right motion controller as reference tracker. Valid options for the key side
are left
and right
(Note that changing the side or switching between motion controller and vive tracker requires a restart of the vr session)vive
: use a vive tracker as reference for motion compensation. The key side
has to match the role assigned to the tracker. Valid options for that are:
handheld_object
- which hand (left, right, any) doesn't matter. Having more than one active vive tracker assigned to that role may lead to conflicts, though.left_foot
right_foot
left_shoulder
right_shoulder
left_elbow
right_elbow
left_knee
right_knee
waist
chest
camera
keyboard
.connection_timeout
sets the time (in seconds) the tracker needs to be unresponsive before motion compensation is automatically deactivated. Setting a negative value disables automatic deactivation.connection_check
is only relevant for virtual trackers and determines the period (in seconds) for checking wether the memory mapped file used for data input is actually still actively used. Setting a negative value disables the checksrs
: use the virtual tracker data provided by SRS motion software when using a Witmotion (or similar?) sensor on the motion rig.flypt
use the virtual tracker data provided by FlyPT Mover.yaw
: use the virtual tracker data provided by Yaw VR and Yaw 2. Either while using SRS or Game Engine.offset_...
, use_cor_pos
and cor_...
are used to handle the configuration of the center of rotation (cor) for all available virtual trackers.marker_size
sets the size of the cor / reference tracker marker displayed in the overlay. The value corresponds to the length of one double cone in cm.translational_filter
and rotational_filter
: set the filtering magnitude (key strength
with valid options between 0.0 and 1.0) number of filtering stages (key order
with valid options: 1, 2, 3).vertical_factor
is applied to translational filter strength in vertical/heave direction only (Note that the filter strength is multiplied by the factor and the resulting product of strength * vertical_factor is clamped internally between 0.0 and 1.0).cache
: you can modify th cache used for reverting the motion corrected pose on frame submission:
use_eye_cache
- choose between calcuating eye poses (0 = default) or use cached eye poses (1, was default up until version 0.1.4). Either one might work better with some games or hmds if you encounter jitter with mc activated. You can also modify this setting (and subsequently save it to config file) during runtime with the corresponding shortcut below.tolerance
- modify the time values are kept in cache for before deletion. This may affect eye calculation as well as cached eye positions.shortcuts
: can be used to configure shortcuts for different commands (See List of keyboard bindings for valid values):
activate
- turn motion compensation on or off. Note that this implicitly triggers the calibration action (center
) if that hasn't been executed before.center
- recalibrate the neutral reference pose of the trackertranslation_increase
, translation_decrease
- modify the strength of the translational filter. Changes made during runtime can be saved by using a save command (see below).rotation_increase
, rotation_decrease
= see above, but for rotational filteroffset_forward
, offset_back
, offset_up
, offset_down
, offset_right
, offset_left
- move the center of rotation (cor) for a virtual tracker. The directions are aligned with the forward vector set with the center
command. Changes made during runtime can be saved by using a save command (see below).rotate_right
, rotate_left
- rotate the aforementioned forward vector aroung the gravitational (yaw-)axis. Note that these changes cannot be saved. Therefore changing the offset position AFTER rotating manually and saving the offset values will result in the cor being a different offset position after relaoding those saved values.toggle_overlay
- (de)activate graphical overlay displaying the reference tracker position(s) (See Graphical overlay for details).toggle_cache
- change between calculated and cached eye positions.save_config
- write current filter strength and cor offsets to global config filesave_config_app
- write current filter strength and cor offsets to application specific config file. Note that values in this file will precedent values in the global config file.reload_config
- read in and apply configuration for current app from config files. For technical reasons motion compensation is automatically deactivated and the reference tracker pose is invalidated upon configuration reload.ctrl + shift + alt + i
: logs your current interaction profile, which can be useful when debugging issues with a physical tracker.ctrl + shift + alt + t
: logs the current pose of the reference tracker, can also be used for the purpose of troubleshooting.debug
: For debugging reasons you can check, if the motion compensation functionality generally works on your system without using tracker input from the motion controllers at all by setting testrotation
value to 1
and reloading the configuration. You should be able to see the world rotating around you after pressing the activation shortcut.To use a virtual tracker (as opposed to a physical device) set parameter tracker_type
according to the motion software that is providing the data for motion compensation on your system:
yaw
: Yaw Game Engine (or Sim Racing Studio when using rotational data provided by Yaw VR or Yaw 2)srs
: Sim Racing Studio, using a Witmotion sensorflypt
: FlyPT MoverTo enable OXRMC to correlate translation and rotation of the rig to the virtual space correctly when using a virtual tracker, you have to provide the information where the center of rotation (cor) of your motion rig is positioned and which way is forward. This can be done with the following steps:
center
shortcut. You can also do this implicitly by activating motion compensation if you haven't (re)calibrated since last loading of the configuration.Head Distance
and Height
in its Motion Compensation tab to specify the offset of the cor. Head distance is basically equal to offset_forward
in the configration file. But note that the height parameter is measured upwards from the bottom of your playspace, so you'll need to have that setup correctly in order to use that feature.The current position and orientation of the cor is part of the configuration and can be saved to the (global or app-specific) config file. When your satisfied with the current setting you can set the config key use_cor_pos
to 1
. This causes the cor position to be loaded from the config file when calibrating instead of being determined using the hmd position and the offset values.
Note that this functionality may not work with all HMD vendors. Setting up the playspace in the VR runtime configuration of your hmd might help to get this working correctly. Rumor has it that some HMDs need to be started/initialized at the exact same location for the playspace coordinates to be consistent in between uses.
Feedback on success or failure of this functionality using different VR systems is very welcome and can be made via discord server of the project.
activate
shortcut (CTRL + INSERT by default). This implicitly sets the neutral reference pose for the trackercenter
shortcut (CTRL + DEL by default) while the motion rig is in neutral positionreload_config
shortcut (CTRL + SHIFT + L by default) to restart the OXRMC software with the new values.You can enable/disable the overlay using the toggle_overlay
shortcut. It displays a marker in your headset view for:
upside_down
to 1 in the startup
section of the config file of the corresponding application (or check if it is set to 1 inadvertently).OXRMC can detect if a reference tracker isn't available anymore, if:
After detecting a loss of connection a configurable timeout period is used (connection_timeout
), allopwing two possible outcomes:
Upon activating any shortcut you get audible feedback, corresponding to the performed action (or an error, if something went wrong). If you're getting 'error' or no feedback at all, check for error entries (search for keyword 'error') in the log file at ...\Users<Your_Username>\AppData\Local\OpenXR-MotionCompensation\OpenXR-MotionCompensation.log.
If you recenter the in-app view during a session the reference pose is reset by default. Therefore you should only do that while your motion rig is in neutral position. It is possible (depending on the application) that this automatic recalibration is not triggered, causing the view and reference pose to be out of sync and leading to erroneous motion compensation. You should do the following steps to get this corrected again:
activate
shortcutcenter
shortcutactivate
shortcutWhen using a virtual tracker and the audible feedback says 'motion compensation activated' but you don't get motion compensation as you would expect Use the MmfReader App to make sure oxrmc is actually receiving data from the motion software.
You can always request help on the Discord server
The software package includes a small app called MMF Reader which allows you to display the content of the memory mapped file used for virtual trackers. Just execute it from windows start menu or use the executable in the installation directory and select the kind of tracker you're using from the dropdown menu.
X
.The motion compensation layers logs rudimentary information and errors in a text file located at ...\Users<Your_Username>\AppData\Local\OpenXR-MotionCompensation\OpenXR-MotionCompensation.log. After unexpected behaviour or a crash you can check that file for abormalities or error reports.
If you encounter repeatable bugs or crashes you can use the Windows Performance Recorder Profile (WPRP) tracelogging in combination with the configuration contained within scripts\Trace_OpenXR-MotionCompensation.wprp
to create a more detailed protocol.
Tracelogging can become very useful to investigate user issues.
To capture a trace for the API layer:
wpr -start path\to\Trace_OpenXR-MotionCompensation.wprp -filemode
wpr -stop arbitrary_name_of_file.etl
You can send the trace file to the developer or use an application such as Tabnalysis to inspect the content yourself.
To combine multiple keys for a single shortcut they need to be separated by '+' with no spaces in between the key descriptors.
List of supported shortcut key names:
Name | Key |
---|---|
SHIFT |
shift key |
CTRL |
ctrl key |
ALT |
alt key |
LSHIFT |
left shift key |
RSHIFT |
right shift key |
LCTRL |
left ctrl key |
RCTRL |
right ctrl key |
LALT |
left alt key |
RALT |
right alt key |
0 - 9 |
numerical key |
A - Z |
alphbetical key |
BACKQUOTE |
`~ key (US) |
TAB |
tabulator key |
CAPS |
caps lock key |
PLUS |
+ key (any country) |
MINUS |
- key (any country) |
OPENBRACKET |
[{ key (US) |
CLOSEBRACKET |
]} key (US) |
SEMICOLON |
;: key (US) |
QUOTE |
'" key (US) |
BACKSLASH |
\| key (US) |
COMMA |
, key (any country) |
PERIOD |
. key (any country) |
SLASH |
/? key (US) |
BACK |
backspace key |
CLR |
clr key |
RETURN |
return key |
ESC |
esc key |
SPACE |
space key |
LEFT |
cursor left key |
UP |
cursor up key |
RIGHT |
cursor right key |
DOWN |
cursor down key |
INS |
ins key |
DEL |
del key |
HOME |
home key |
END |
end key |
PGUP |
page up key |
PGDN |
page down key |
NUM0 |
0 key on NUM |
NUM1 |
1 key on NUM |
NUM2 |
2 key on NUM |
NUM3 |
3 key on NUM |
NUM4 |
4 key on NUM |
NUM5 |
5 key on NUM |
NUM6 |
6 key on NUM |
NUM7 |
7 key on NUM |
NUM8 |
8 key on NUM |
NUM9 |
9 key on NUM |
NUMLOCK |
numlock key |
NUMDIVIDE |
/ key on NUM |
NUMMULTIPLY |
* key on NUM |
NUMSUBTRACT |
- key on NUM |
NUMADD |
+ key on NUM |
NUMDECIMAL |
. key on NUM |
NUMSEPARATOR |
separator key on NUM |
F1 |
F1 key |
F2 |
F2 key |
F3 |
F3 key |
F4 |
F4 key |
F5 |
F5 key |
F6 |
F6 key |
F7 |
F7 key |
F8 |
F8 key |
F9 |
F9 key |
F10 |
F10 key |
F11 |
F11 key |
F12 |
F12 key |
PRTSC |
print screen key |
SCROLL |
scroll lock key |
PAUSE |
pause key |
SELECT |
select key |
PRINT |
print key |
HELP |
help key |
EXEC |
execute key |
GAMEPAD_A |
A button on gamepad |
GAMEPAD_B |
B button on gamepad |
GAMEPAD_X |
X button on gamepad |
GAMEPAD_Y |
Y button on gamepad |
GAMEPAD_RIGHT_SHOULDER |
right shoulder button on gamepad |
GAMEPAD_LEFT_SHOULDER |
left shoulder button on gamepad |
GAMEPAD_LEFT_TRIGGER |
left trigger button on gamepad |
GAMEPAD_RIGHT_TRIGGER |
right trigger button on gamepad |
GAMEPAD_DPAD_UP |
digital pad up on gamepad |
GAMEPAD_DPAD_DOWN |
digital pad down on gamepad |
GAMEPAD_DPAD_LEFT |
digital pad left on gamepad |
GAMEPAD_DPAD_RIGHT |
digital pad right on gamepad |
GAMEPAD_START |
start button on gamepad |
GAMEPAD_VIEW |
view button on gamepad |
GAMEPAD_LEFT_THUMBSTICK_BUTTON |
left thumbstick pressed on gamepad |
GAMEPAD_RIGHT_THUMBSTICK_BUTTON |
right thumbstick pressed on gamepad |
GAMEPAD_LEFT_THUMBSTICK_UP |
left thumbstick up on gamepad |
GAMEPAD_LEFT_THUMBSTICK_DOWN |
left thumbstick down on gamepad |
GAMEPAD_LEFT_THUMBSTICK_RIGHT |
left thumbstick left on gamepad |
GAMEPAD_LEFT_THUMBSTICK_LEFT |
left thumbstick right on gamepad |
GAMEPAD_RIGHT_THUMBSTICK_UP |
right thumbstick up on gamepad |
GAMEPAD_RIGHT_THUMBSTICK_DOWN |
right thumbstick down on gamepad |
GAMEPAD_RIGHT_THUMBSTICK_RIGHT |
right thumbstick left on gamepad |
GAMEPAD_RIGHT_THUMBSTICK_LEFT |
right thumbstick right on gamepad |