I’m trying to use the OpenXR dpad binding modifier in a project but can’t get it to work. I’ve done the following:
Enabled the “Dpad Binding” option in the project’s OpenXR modifiers settings
Added actions to my action set as booleans
Added the new actions to the “Thumbstick Dpad” in my controller’s profile
I’ve also tried adding the dpad binding modifier to the input profile to see if that changed anything (it did not).
In the script, I’m listening to the XRController.button_pressed signal for this action, but it appears to never emit when pressing either thumbstick in any direction. Assigning the action to a physical button, however, does emit the signal. Is button_pressed the signal I should be subscribing to for dpad binding actions?
For reference, I’m attempting this using Valve Index controllers, and my OpenXR runtime is Monado (via Envision). According to the OpenXR documentation Monado does support the required “XR_EXT_dpad_binding” extension, so my guess I’m missing something simple in my project. Any ideas as to what I might be doing wrong?
In theory that should indeed work, I’ve only ever tested it with steamVR. I don’t know what limits Monados implementation has, but you’d think it would work.
I know this demo works with SteamVR so maybe you can check if there are any differences between it and what you’re doing:
Else we need to see if we can get some feedback from Monado.
Thanks! Unfortunately not only did the bindings also not work in that project, but the project wouldn’t even launch until I switched from “Compatibility” to “Mobile”. Here’s what I get when attempting to launch the demo project without making any changes:
Godot Engine v4.6.stable.arch_linux - https://godotengine.org
OpenXR: Created instance for OpenXR 1.1.54
OpenXR: Running on OpenXR runtime: Monado(XRT) by Collabora et al 'v25.1.0-207-g69834fe93' 25.1.0
OpenGL API 3.3.0 NVIDIA 590.48.01 - Compatibility - Using Device: NVIDIA - NVIDIA GeForce RTX 2080 SUPER
OpenXR: Failed to create session [ XR_ERROR_GRAPHICS_DEVICE_INVALID ]
OpenXR not instantiated!
After switching to “Mobile”, the project launches:
OpenXR: Created instance for OpenXR 1.1.54
OpenXR: Running on OpenXR runtime: Monado(XRT) by Collabora et al 'v25.1.0-207-g69834fe93' 25.1.0
OpenXR: XrGraphicsRequirementsVulkan2KHR:
- minApiVersionSupported: 1.0.0
- maxApiVersionSupported: 1023.1023.1023
Vulkan 1.4.325 - Forward Mobile - Using Device #0: NVIDIA - NVIDIA GeForce RTX 2080 SUPER
OpenXR instantiated successfully.
OpenXR: Refresh rate reported as 144.000015258789
OpenXR gained focus
Not sure if this is a bug or Nvidia drivers just being dumb on Linux. I’m trying to run the demo project using SteamVR instead, but that’s giving me a whole different error (“OpenXR was requested but failed to start”), but I think that’s a system configuration issue on my end.
Just a quick follow-up: I can confirm SteamVR on Linux does support the dpad binding extension (issue with launching Godot VR projects with SteamVR was configuration error on my end). I’m still investigating issues with Monado, will post here if I learn anything.
Hmm interesting. There is no rule that OpenXR runtimes must support all graphics APIs.
WMR famously only supported DirectX, which was a PITA for many developers and confusion to many users.
Monado obviously doesn’t support OpenGL on your system, which is weird because the OpenXR Runtime Support matrix reports it as supported. Could be a limitation with the Linux distro you’re running.
In the end, that’s not something Godot can do much about.
I’ll poke a contact I have with Monado to see if I can find anything out about their d-pad support.
Yeah, the OpenGL think I’m not worried about, likely just a driver issue on my end.
As for the dpad issue, appreciate the help! Not sure if it’s of any assistance to your contact, but I did talk with some folks over on the Linux VR Adventures Discord, where they recommended I capture the debug output with environment variable OXR_DEBUG_BINDINGS=true, which I’ve included below. The dpad bound actions are locomotion/snap_turn_left, locomotion/snap_turn_right, and locomotion/teleport. I confirmed they do work with SteamVR, so it’s a safe bet it’s a Monado issue.
Monado debug output:
OpenXR: Running on OpenXR runtime: Monado(XRT) by Collabora et al 'v25.1.0-218-g7aa33fcea' 25.1.0
LOG in xrGetSystem: Selected devices
Head: 'Valve Index'
Eyes: '<none>'
Left: 'Valve Knuckles Left'
Right: 'Valve Knuckles Right'
Gamepad: '<none>'
Hand-Tracking Left (unobstructed): '<none>'
Hand-Tracking Right (unobstructed): '<none>'
Hand-Tracking Left (conforming): 'Valve Knuckles Left'
Hand-Tracking Right (conforming): 'Valve Knuckles Right'
OpenXR: XrGraphicsRequirementsVulkan2KHR:
- minApiVersionSupported: 1.0.0
- maxApiVersionSupported: 1023.1023.1023
LOG in xrCreateVulkanInstanceKHR: Creation of VkInstance:
result: VK_SUCCESS
vulkanInstance: 0x556e02ca4740
extensions:
VK_KHR_external_fence_capabilities
VK_KHR_external_memory_capabilities
VK_KHR_external_semaphore_capabilities
VK_KHR_get_physical_device_properties2
VK_EXT_debug_utils
VK_KHR_surface
VK_KHR_xlib_surface
LOG in xrGetVulkanGraphicsDeviceKHR: Creation of VkDevice:
result: VK_SUCCESS
vulkanDevice: 0x556e02dffed0
vulkanInstance: 0x556e02ca4740
external_fence_fd: true
external_semaphore_fd: true
timelineSemaphore: true
extensions:
VK_KHR_dedicated_allocation
VK_KHR_external_fence
VK_KHR_external_memory
VK_KHR_external_semaphore
VK_KHR_get_memory_requirements2
VK_KHR_external_memory_fd
VK_KHR_16bit_storage
VK_KHR_buffer_device_address
VK_KHR_create_renderpass2
VK_KHR_depth_stencil_resolve
VK_KHR_fragment_shading_rate
VK_KHR_image_format_list
VK_KHR_maintenance2
VK_KHR_multiview
VK_KHR_shader_float16_int8
VK_KHR_storage_buffer_storage_class
VK_KHR_swapchain
VK_KHR_vulkan_memory_model
VK_EXT_device_fault
VK_EXT_pipeline_creation_cache_control
VK_EXT_subgroup_size_control
VK_KHR_external_semaphore_fd
VK_KHR_external_fence_fd
VK_KHR_timeline_semaphore
Vulkan 1.4.325 - Forward Mobile - Using Device #0: NVIDIA - NVIDIA GeForce RTX 2080 SUPER
XR_ERROR_VALIDATION_FAILURE: xrSuggestInteractionProfileBindings(suggestedBindings->countSuggestedBindings == 0) cannot suggest 0 bindings
OpenXR: failed to suggest bindings for /interaction_profiles/khr/simple_controller ! [ XR_ERROR_VALIDATION_FAILURE ]
Action trigger isn't part of an action set!
Action trigger isn't part of an action set!
XR_ERROR_VALIDATION_FAILURE: xrSuggestInteractionProfileBindings(suggestedBindings->countSuggestedBindings == 0) cannot suggest 0 bindings
OpenXR: failed to suggest bindings for /interaction_profiles/htc/vive_controller ! [ XR_ERROR_VALIDATION_FAILURE ]
Action trigger isn't part of an action set!
Action trigger isn't part of an action set!
XR_ERROR_VALIDATION_FAILURE: xrSuggestInteractionProfileBindings(suggestedBindings->countSuggestedBindings == 0) cannot suggest 0 bindings
OpenXR: failed to suggest bindings for /interaction_profiles/microsoft/motion_controller ! [ XR_ERROR_VALIDATION_FAILURE ]
Action trigger isn't part of an action set!
Action trigger isn't part of an action set!
XR_ERROR_VALIDATION_FAILURE: xrSuggestInteractionProfileBindings(suggestedBindings->countSuggestedBindings == 0) cannot suggest 0 bindings
OpenXR: failed to suggest bindings for /interaction_profiles/oculus/touch_controller ! [ XR_ERROR_VALIDATION_FAILURE ]
Action trigger isn't part of an action set!
Action trigger isn't part of an action set!
XR_ERROR_VALIDATION_FAILURE: xrSuggestInteractionProfileBindings(suggestedBindings->countSuggestedBindings == 0) cannot suggest 0 bindings
OpenXR: failed to suggest bindings for /interaction_profiles/bytedance/pico4_controller ! [ XR_ERROR_VALIDATION_FAILURE ]
Action trigger isn't part of an action set!
Action trigger isn't part of an action set!
WARNING: Analog threshold extension is not enabled or available.
at: get_ip_modification (modules/openxr/extensions/openxr_valve_analog_threshold_extension.cpp:148)
WARNING: Analog threshold extension is not enabled or available.
at: get_ip_modification (modules/openxr/extensions/openxr_valve_analog_threshold_extension.cpp:148)
Action trigger isn't part of an action set!
Action trigger isn't part of an action set!
XR_ERROR_VALIDATION_FAILURE: xrSuggestInteractionProfileBindings(suggestedBindings->countSuggestedBindings == 0) cannot suggest 0 bindings
OpenXR: failed to suggest bindings for /interaction_profiles/hp/mixed_reality_controller ! [ XR_ERROR_VALIDATION_FAILURE ]
Action trigger isn't part of an action set!
Action trigger isn't part of an action set!
XR_ERROR_VALIDATION_FAILURE: xrSuggestInteractionProfileBindings(suggestedBindings->countSuggestedBindings == 0) cannot suggest 0 bindings
OpenXR: failed to suggest bindings for /interaction_profiles/samsung/odyssey_controller ! [ XR_ERROR_VALIDATION_FAILURE ]
Action trigger isn't part of an action set!
Action trigger isn't part of an action set!
XR_ERROR_VALIDATION_FAILURE: xrSuggestInteractionProfileBindings(suggestedBindings->countSuggestedBindings == 0) cannot suggest 0 bindings
OpenXR: failed to suggest bindings for /interaction_profiles/htc/vive_cosmos_controller ! [ XR_ERROR_VALIDATION_FAILURE ]
Action trigger isn't part of an action set!
Action trigger isn't part of an action set!
XR_ERROR_VALIDATION_FAILURE: xrSuggestInteractionProfileBindings(suggestedBindings->countSuggestedBindings == 0) cannot suggest 0 bindings
OpenXR: failed to suggest bindings for /interaction_profiles/htc/vive_focus3_controller ! [ XR_ERROR_VALIDATION_FAILURE ]
OpenXR initialized successfully
Load level initiated: uid://4xpyddojuqse
At: res://scenes/main/main.gd:20:load_level()
Pausing tree
At: res://scenes/main/main.gd:21:load_level()
Awaiting ready to load signal...
At: res://scenes/main/main.gd:25:load_level()
OpenXR: Refresh rate reported as 144.000015258789
OpenXR: Gained focus
LOG in xrSyncActions: : Binding poses/aim_pose
For: /user/hand/left
Profile: /interaction_profiles/valve/index_controller
Binding: /user/hand/left/input/aim/pose
Bound (xdev 'Valve Knuckles Left'): XRT_INPUT_INDEX_AIM_POSE!
Binding: /user/hand/right/input/aim/pose
Rejected! (SUB PATH)
Finding transforms for 'XRT_INPUT_INDEX_AIM_POSE' to action 'aim_pose' of type 'XR_ACTION_TYPE_POSE_INPUT'
Adding transform from 'XR_ACTION_TYPE_POSE_INPUT' to 'XRT_INPUT_TYPE_POSE'
Using identity transform for input.
Bound to:
'XRT_INPUT_INDEX_AIM_POSE' ('XRT_INPUT_TYPE_POSE') on 'Valve Knuckles Left' (inactive)
For: /user/hand/right
Profile: /interaction_profiles/valve/index_controller
Binding: /user/hand/left/input/aim/pose
Rejected! (SUB PATH)
Binding: /user/hand/right/input/aim/pose
Bound (xdev 'Valve Knuckles Right'): XRT_INPUT_INDEX_AIM_POSE!
Finding transforms for 'XRT_INPUT_INDEX_AIM_POSE' to action 'aim_pose' of type 'XR_ACTION_TYPE_POSE_INPUT'
Adding transform from 'XR_ACTION_TYPE_POSE_INPUT' to 'XRT_INPUT_TYPE_POSE'
Using identity transform for input.
Bound to:
'XRT_INPUT_INDEX_AIM_POSE' ('XRT_INPUT_TYPE_POSE') on 'Valve Knuckles Right' (inactive)
For: <any>
Binding any pose to left.
Done
LOG in xrSyncActions: : Binding poses/grip_pose
For: /user/hand/left
Profile: /interaction_profiles/valve/index_controller
Binding: /user/hand/left/input/grip/pose
Bound (xdev 'Valve Knuckles Left'): XRT_INPUT_INDEX_GRIP_POSE!
Binding: /user/hand/right/input/grip/pose
Rejected! (SUB PATH)
Finding transforms for 'XRT_INPUT_INDEX_GRIP_POSE' to action 'grip_pose' of type 'XR_ACTION_TYPE_POSE_INPUT'
Adding transform from 'XR_ACTION_TYPE_POSE_INPUT' to 'XRT_INPUT_TYPE_POSE'
Using identity transform for input.
Bound to:
'XRT_INPUT_INDEX_GRIP_POSE' ('XRT_INPUT_TYPE_POSE') on 'Valve Knuckles Left' (inactive)
For: /user/hand/right
Profile: /interaction_profiles/valve/index_controller
Binding: /user/hand/left/input/grip/pose
Rejected! (SUB PATH)
Binding: /user/hand/right/input/grip/pose
Bound (xdev 'Valve Knuckles Right'): XRT_INPUT_INDEX_GRIP_POSE!
Finding transforms for 'XRT_INPUT_INDEX_GRIP_POSE' to action 'grip_pose' of type 'XR_ACTION_TYPE_POSE_INPUT'
Adding transform from 'XR_ACTION_TYPE_POSE_INPUT' to 'XRT_INPUT_TYPE_POSE'
Using identity transform for input.
Bound to:
'XRT_INPUT_INDEX_GRIP_POSE' ('XRT_INPUT_TYPE_POSE') on 'Valve Knuckles Right' (inactive)
For: <any>
Binding any pose to left.
Done
LOG in xrSyncActions: : Binding poses/default_pose
For: /user/hand/left
Profile: /interaction_profiles/valve/index_controller
Binding: /user/hand/left/input/grip/pose
Bound (xdev 'Valve Knuckles Left'): XRT_INPUT_INDEX_GRIP_POSE!
Binding: /user/hand/right/input/grip/pose
Rejected! (SUB PATH)
Finding transforms for 'XRT_INPUT_INDEX_GRIP_POSE' to action 'default_pose' of type 'XR_ACTION_TYPE_POSE_INPUT'
Adding transform from 'XR_ACTION_TYPE_POSE_INPUT' to 'XRT_INPUT_TYPE_POSE'
Using identity transform for input.
Bound to:
'XRT_INPUT_INDEX_GRIP_POSE' ('XRT_INPUT_TYPE_POSE') on 'Valve Knuckles Left' (inactive)
For: /user/hand/right
Profile: /interaction_profiles/valve/index_controller
Binding: /user/hand/left/input/grip/pose
Rejected! (SUB PATH)
Binding: /user/hand/right/input/grip/pose
Bound (xdev 'Valve Knuckles Right'): XRT_INPUT_INDEX_GRIP_POSE!
Finding transforms for 'XRT_INPUT_INDEX_GRIP_POSE' to action 'default_pose' of type 'XR_ACTION_TYPE_POSE_INPUT'
Adding transform from 'XR_ACTION_TYPE_POSE_INPUT' to 'XRT_INPUT_TYPE_POSE'
Using identity transform for input.
Bound to:
'XRT_INPUT_INDEX_GRIP_POSE' ('XRT_INPUT_TYPE_POSE') on 'Valve Knuckles Right' (inactive)
For: <any>
Binding any pose to left.
Done
LOG in xrSyncActions: : Binding haptics/haptics
For: /user/hand/left
Profile: /interaction_profiles/valve/index_controller
Binding: /user/hand/left/output/haptic
Bound (xdev 'Valve Knuckles Left'): UNKNOWN!
Binding: /user/hand/right/output/haptic
Rejected! (SUB PATH)
For: /user/hand/right
Profile: /interaction_profiles/valve/index_controller
Binding: /user/hand/left/output/haptic
Rejected! (SUB PATH)
Binding: /user/hand/right/output/haptic
Bound (xdev 'Valve Knuckles Right'): UNKNOWN!
Done
LOG in xrSyncActions: : Binding grabbing/grab
For: /user/hand/left
Profile: /interaction_profiles/valve/index_controller
Binding: /user/hand/left/input/squeeze/value
Bound (xdev 'Valve Knuckles Left'): XRT_INPUT_INDEX_SQUEEZE_VALUE!
Binding: /user/hand/right/input/squeeze/force
Rejected! (SUB PATH)
Finding transforms for 'XRT_INPUT_INDEX_SQUEEZE_VALUE' to action 'grab' of type 'XR_ACTION_TYPE_FLOAT_INPUT'
Adding transform from 'XR_ACTION_TYPE_FLOAT_INPUT' to 'XRT_INPUT_TYPE_VEC1_ZERO_TO_ONE'
Using identity transform for input.
Bound to:
'XRT_INPUT_INDEX_SQUEEZE_VALUE' ('XRT_INPUT_TYPE_VEC1_ZERO_TO_ONE') on 'Valve Knuckles Left' (inactive)
For: /user/hand/right
Profile: /interaction_profiles/valve/index_controller
Binding: /user/hand/left/input/squeeze/value
Rejected! (SUB PATH)
Binding: /user/hand/right/input/squeeze/force
Bound (xdev 'Valve Knuckles Right'): XRT_INPUT_INDEX_SQUEEZE_FORCE!
Finding transforms for 'XRT_INPUT_INDEX_SQUEEZE_FORCE' to action 'grab' of type 'XR_ACTION_TYPE_FLOAT_INPUT'
Adding transform from 'XR_ACTION_TYPE_FLOAT_INPUT' to 'XRT_INPUT_TYPE_VEC1_ZERO_TO_ONE'
Using identity transform for input.
Bound to:
'XRT_INPUT_INDEX_SQUEEZE_FORCE' ('XRT_INPUT_TYPE_VEC1_ZERO_TO_ONE') on 'Valve Knuckles Right' (inactive)
Done
LOG in xrSyncActions: : Binding locomotion/teleport
For: /user/hand/right
Profile: /interaction_profiles/valve/index_controller
No bindings!
Done
LOG in xrSyncActions: : Binding locomotion/movement
For: /user/hand/left
Profile: /interaction_profiles/valve/index_controller
Binding: /user/hand/left/input/thumbstick
Bound (xdev 'Valve Knuckles Left'): XRT_INPUT_INDEX_THUMBSTICK_CLICK!
Binding: /user/hand/left/input/thumbstick
Bound (xdev 'Valve Knuckles Left'): XRT_INPUT_INDEX_THUMBSTICK_TOUCH!
Binding: /user/hand/left/input/thumbstick
Bound (xdev 'Valve Knuckles Left'): XRT_INPUT_INDEX_THUMBSTICK!
Finding transforms for 'XRT_INPUT_INDEX_THUMBSTICK_CLICK' to action 'movement' of type 'XR_ACTION_TYPE_VECTOR2F_INPUT'
Adding transform from 'XR_ACTION_TYPE_VECTOR2F_INPUT' to 'XRT_INPUT_TYPE_BOOLEAN'
Could not transform!
Rejected! (NO TRANSFORM)
Finding transforms for 'XRT_INPUT_INDEX_THUMBSTICK_TOUCH' to action 'movement' of type 'XR_ACTION_TYPE_VECTOR2F_INPUT'
Adding transform from 'XR_ACTION_TYPE_VECTOR2F_INPUT' to 'XRT_INPUT_TYPE_BOOLEAN'
Could not transform!
Rejected! (NO TRANSFORM)
Finding transforms for 'XRT_INPUT_INDEX_THUMBSTICK' to action 'movement' of type 'XR_ACTION_TYPE_VECTOR2F_INPUT'
Adding transform from 'XR_ACTION_TYPE_VECTOR2F_INPUT' to 'XRT_INPUT_TYPE_VEC2_MINUS_ONE_TO_ONE'
Using identity transform for input.
Bound to:
'XRT_INPUT_INDEX_THUMBSTICK' ('XRT_INPUT_TYPE_VEC2_MINUS_ONE_TO_ONE') on 'Valve Knuckles Left' (inactive)
Done
LOG in xrSyncActions: : Binding locomotion/snap_turn_left
For: /user/hand/right
Profile: /interaction_profiles/valve/index_controller
No bindings!
Done
LOG in xrSyncActions: : Binding locomotion/snap_turn_right
For: /user/hand/right
Profile: /interaction_profiles/valve/index_controller
No bindings!
Done
LOG in xrSyncActions: : Binding locomotion/teleport_pose
For: /user/hand/left
Profile: /interaction_profiles/valve/index_controller
Binding: /user/hand/left/input/aim/pose
Bound (xdev 'Valve Knuckles Left'): XRT_INPUT_INDEX_AIM_POSE!
Binding: /user/hand/right/input/aim/pose
Rejected! (SUB PATH)
Finding transforms for 'XRT_INPUT_INDEX_AIM_POSE' to action 'teleport_pose' of type 'XR_ACTION_TYPE_POSE_INPUT'
Adding transform from 'XR_ACTION_TYPE_POSE_INPUT' to 'XRT_INPUT_TYPE_POSE'
Using identity transform for input.
Bound to:
'XRT_INPUT_INDEX_AIM_POSE' ('XRT_INPUT_TYPE_POSE') on 'Valve Knuckles Left' (inactive)
For: /user/hand/right
Profile: /interaction_profiles/valve/index_controller
Binding: /user/hand/left/input/aim/pose
Rejected! (SUB PATH)
Binding: /user/hand/right/input/aim/pose
Bound (xdev 'Valve Knuckles Right'): XRT_INPUT_INDEX_AIM_POSE!
Finding transforms for 'XRT_INPUT_INDEX_AIM_POSE' to action 'teleport_pose' of type 'XR_ACTION_TYPE_POSE_INPUT'
Adding transform from 'XR_ACTION_TYPE_POSE_INPUT' to 'XRT_INPUT_TYPE_POSE'
Using identity transform for input.
Bound to:
'XRT_INPUT_INDEX_AIM_POSE' ('XRT_INPUT_TYPE_POSE') on 'Valve Knuckles Right' (inactive)
For: <any>
Binding any pose to left.
Done
ok thanks. I’ve already implemented a basic system for it but I’m often wondering if there’s specific notes for what works/doesn’t for the quest version. I still keep trying to drag and drop from the res: browser.