Page MenuHome

VR: OpenXR Action Support
AbandonedPublic

Authored by Peter Kim (muxed-reality) on Oct 6 2020, 2:57 PM.
Tokens
"Love" token, awarded by Jefftml."Love" token, awarded by tintwotin."Love" token, awarded by joe_daniels."Love" token, awarded by Mike.Bailey."Like" token, awarded by Fracture128."Love" token, awarded by slumber."Love" token, awarded by PatrickWilson."Love" token, awarded by Baga."Love" token, awarded by burkules."Love" token, awarded by Robonnet."Love" token, awarded by Jaydead."Love" token, awarded by aliasguru."Like" token, awarded by ankitm."Love" token, awarded by noemis."Like" token, awarded by Pipeliner."Love" token, awarded by jar091."Love" token, awarded by Alaska."Love" token, awarded by madminstrel.

Details

Summary

This addresses T77137 VR: Python API for Controller Interaction.

This patch allows users to create custom OpenXR input / output actions via the Python API. It also adds basic VR controller visualization and an OpenGL selection method for VR (partially fulfilling T77127 and T77128, respectively).
Changes are implemented at the GHOST, WM, and RNA / Python layers.

User-created actions can be used to execute a Python operator, retrieve state from a button or pose, or send a haptic pulse when performed during a VR session. Bindings for actions, using OpenXR paths are entirely defined by the user to allow the API to extend to any hardware supported by OpenXR.

The "VR Scene Inspection" add-on has also been extended to use the new VR action functions. This way, users can create and customize actions via the add-on sidebar if they prefer.

Visualization of VR controllers is first achieved by reading the state of a user-specified VR pose action. Then, custom drawing via the add-on (for screen visualization) as well as offscreen rendering from within Blender (for in-headset display) is performed to portray the controller axes. This basic visualization can later be replaced with more appropriate controller geometry.

Finally, invoke_3d() and modal_3d() functions were added to the basic select and transform operators, allowing them to be controlled via XR inputs. Implementation-wise, a VR controller's 3D location is first projected to 2D mouse coordinates using the perspective of the user's preferred eye and then the result is passed to the regular invoke() / modal() functions. Using this approach, controller-based OpenGL picking was implemented.

You can test out the XR actions functionality using the sample file below and the xr-actions-D9124 experimental build. Special thanks to blendFX for creating the sample.

Diff Detail

Repository
rB Blender
Branch
xr-actions-D9124
Build Status
Buildable 10979
Build 10979: arc lint + arc unit

Event Timeline

There are a very large number of changes, so older changes are hidden. Show Older Changes
Peter Kim (muxed-reality) retitled this revision from Add patch changes. to VR: OpenXR Action Support.Oct 6 2020, 3:54 PM
Peter Kim (muxed-reality) edited the summary of this revision. (Show Details)
Peter Kim (muxed-reality) changed the visibility from "No One" to "All Users".

Hey, I'm so happy to see you working on this :)

I didn't have time yet to dig too deep, but wanted to give some first feedback at least:
From a few brief looks, the way things are done here makes a lot of sense to me. They are pretty much how I imagined how things could/should look. I'm myself a bit unsure still how the event system integration should work. What you did here seems quite reasonable, but I haven't fully made up my mind on the most future proof approach yet.
I'm also a bit unsure if we should expose a UI for customizing actions yet. As a first step I think we should let add-ons define action sets for their tools/workflows, user-customization could be added later.

But these things we can discuss together. I'd love to chat a bit more directly - this came out of nowhere so I have many questions ;)
Are you on blender.chat? We can discuss in the #blender-coders or #xr channel there.

Also, if you plan to further work on this or other features, we can give you commit access so you can work in a public branch on git.blender.org. That's JFYI, we can discuss this better in the chat.

Peter Kim (muxed-reality) updated this revision to Diff 30502.EditedOct 29 2020, 4:38 PM
Peter Kim (muxed-reality) edited the summary of this revision. (Show Details)

Expanded XR operator functionality.

Added invoke_3d() and modal_3d() functions to the basic select and
transform operators, allowing them to be controlled via XR inputs.
As a prerequisite, implemented an OpenGL selection method for VR
(addresses T77128), achieved by projecting a VR controller's 3D
location to 2D mouse coordinates.

Also added support for calling operators with properties via XR
inputs. To accomplish this, added new "XR" and "XR Session" keymaps
to the blender default keyconfig and added XR action set and action
identifiers to key map items. In this way, an operator and its
properties can be connected to a user-defined XR action and executed
during a VR session.

Peter Kim (muxed-reality) updated this revision to Diff 31119.EditedNov 16 2020, 1:09 PM

Implemented remaining features for 1.5 milestone.

Added XR raycast select and grab (location/rotation transform)
operators. These are far more limited than the existing select and
transform operators but are more natural to use in VR and may be
preferred for some basic workflows. In addition to object
manipulation, these operators also support mesh editing.

Also added an "absolute tracking" session option that allows users to
define the tracking origin in a way that is not linked to the headset
position. This is particularly useful for motion capture, in which
only the controllers may be necessary, as well as applications that
use external tracking systems.

Finally, enabled switching between action sets during a session,
allowing users to quickly transition to different workflows (e.g.
scene inspection, scene setup, animation) in VR.

Made adjustments based on user feedback.

Enabled import/export of operator properties for scene action sets.
This uses the existing keymap I/O logic to create a ".xrkey.py" file
that will automatically be loaded on blend file load and saved on
blend file save.

Added an option for the raycast select operator to ignore
non-selectable objects and adjusted its selection behavior to match
view3d.select.

Headset/controller objects will now have their original transforms
restored at the end of the session (and also when they are toggled),
preventing unwanted changes to the scene.

Finally, added an alternate controller visualization that draws the
forward ray of the controller and made "controller draw style" a
session setting that can be extended in the future.

Julian Eisel (Severin) requested changes to this revision.EditedJan 18 2021, 1:40 AM

Hey, very sorry this has taken so long! I'm enthusiastic about this. The review process can be tedious, but let's get through it!

Just a first quick glance over the code. Here are some general points:

  • My earlier proposal wasn't to make VR actions part of the normal keymap, but to register action-set configs like normal keymap-configs in a .py file. So, for example, there could be a vr_default_action_maps.py as part of the scene inspection add-on. Plus (optionally, don't think it's needed yet), a UI for editing the action set mapping via the Add-on's preferences.
  • We should provide default action sets, so the system is ready to go for common devices.
  • I don't think there should be a UI for editing actions. At least not by default. We could show this if "Developer Extras" are enabled but it's not something we should expose to regular users.
  • The UI shouldn't contain names like "Controller 0"/"Controller 1". Just name it "Controller Left"/"Controller Right".
  • Same for the code, I don't see a point in calling something 0/1 that is just left/right. Is there a case where 0/1 is more appropriate? (Other than if the view is upside-down, looking backwards or arms are crossed.)
  • Can we find out ourselves which action set to use? So the user doesn't have to select between "oculus"/"wmr"/...
  • Is the auto-key design really a good idea? AFAICS the recording framerate will be limited by the drawing framerate. So if the frame rate is poor, the tracking will be really poor as well. I'd expect the tracking to be on an own thread dedicated to purely to the tracking.
build_files/utils/make_update.py
172

Better add a TODO note here, as a reminder to change this back, easy to miss when doing the merge.

intern/ghost/GHOST_Types.h
687

Do we need to have these priorities? Usually we just use order based priorities.

717–719

This should not be done. We shouldn't pass any such Blender data through Ghost like this, it could be wrapped into a type that is passed as customdata.

intern/ghost/intern/GHOST_XrSession.cpp
96–98

There should be types like GHOST_XrActionSet with all cleanup handled by the destructor.
Think there should also be GHOST_XrAction. Types should generally be small and focused.

source/blender/draw/intern/draw_manager.c
1411–1430

Why can't we just register a regular View3D drawing callback? Why this XR specific handling here?

Jeroen suggested we have batch at WM level, that the XR view can fill and the draw-manager will draw. Longer term that's the solution we should go for I think.

I'd also be fine with a new region call-back type REGION_DRAW_XR_POST_VIEW as a temporary-ish solution. But the special handling to check for XR drawing-flags should happen outside of the draw-manager.

1450

See above, this kind of special code for XR shouldn't be needed.

Maybe View3D.flag should have a V3D_ALWAYS_CALL_DRAW_CB, so the draw-callbacks are executed even if there's no context.

source/blender/windowmanager/xr/intern/wm_xr_operators.c
1028

What is the reason for adding this, as opposed to extending the dedicated transform operators in transform_ops.c?

An operator doing vertex manipulations shouldn't be at WM level. I think there should simply be a TRANSFORM_OT_3d_grab or so.

This revision now requires changes to proceed.Jan 18 2021, 1:40 AM
source/blender/editors/space_view3d/view3d_select.c
2538–2542

These invoke_3d callbacks all seem to-do some of the same things. That means we should probably generalize them somehow.

source/blender/makesdna/DNA_screen_types.h
640

Region types shouldn't be used like that I think. But if the drawing callback is done differently, this isn't needed.

source/blender/makesrna/intern/rna_xr.c
372–376

Setting Ghost data here doesn't seem right. I'd expect an equivalent to wmKeyMapItem (maybe wmActionMapItem?) here that stores that stuff.

source/blender/windowmanager/intern/wm_event_system.c
3202

We should look into how much of the regular even queue and event handling we can use. It should be as much as possible. I'm unsure how this should be done to be honest.
Think queuing the events in the surface seems fine. All action specific handling can happen through a specific handler type like wmEventHandler_XrAction.

Brecht also suggested to me that we use the regular event queue, as not doing so caused issues in the past.

Hey, very sorry this has taken so long! I'm enthusiastic about this. The review process can be tedious, but let's get through it!

Just a first quick glance over the code. Here are some general points:

  • My earlier proposal wasn't to make VR actions part of the normal keymap, but to register action-set configs like normal keymap-configs in a .py file. So, for example, there could be a vr_default_action_maps.py as part of the scene inspection add-on. Plus (optionally, don't think it's needed yet), a UI for editing the action set mapping via the Add-on's preferences.
  • We should provide default action sets, so the system is ready to go for common devices.
  • I don't think there should be a UI for editing actions. At least not by default. We could show this if "Developer Extras" are enabled but it's not something we should expose to regular users.
  • The UI shouldn't contain names like "Controller 0"/"Controller 1". Just name it "Controller Left"/"Controller Right".
  • Same for the code, I don't see a point in calling something 0/1 that is just left/right. Is there a case where 0/1 is more appropriate? (Other than if the view is upside-down, looking backwards or arms are crossed.)
  • Can we find out ourselves which action set to use? So the user doesn't have to select between "oculus"/"wmr"/...
  • Is the auto-key design really a good idea? AFAICS the recording framerate will be limited by the drawing framerate. So if the frame rate is poor, the tracking will be really poor as well. I'd expect the tracking to be on an own thread dedicated to purely to the tracking.

Hey, no problem and thanks for your feedback. I'll work on making adjustments over the coming weeks.

In response to your general points:

  • VR actions in normal keymap: I actually understood your earlier proposal to register VR actions in a similar, but separate, way to keymap configs. However, I found that I would need to duplicate a lot of the work already done by the keymaps (for example, generating diffs against default configs and visualizing operator properties). Furthermore, it seemed consistent to group XR inputs together with the other types of input mappings (NDOF, Text Input, Timer, etc.). That being said, a separate system for VR actions also seems reasonable.
  • Default action sets: I agree that we should provide default action sets. I didn't add any at first in order to make the interface as generic as possible but realize now that they will be necessary for regular users.
  • UI for editing actions: Hmm I'd like to give all users the option to modify input mappings for default actions (since they may find a different mapping more preferable/ergonomic) as well as the ability to add their own custom actions (since they may have workflows not covered by the default action sets). Hiding this behind "Developer Extras" seems reasonable though.
  • "0/1" vs "left/right": Although in most cases "left/right" will be most appropriate for identifying controllers, I decided to use "0/1" because there may be some cases where a controller or other tracked device may not be strictly left or right (such as a Vive tracker). However, excluding these special cases, I do think that "left/right" is more easily understood.
  • Determining device-appropriate action set: In theory, the XR runtime is supposed to automatically select the most appropriate action set (from a list of provided action sets) for the identified device. However, in practice this hasn't worked well for me, so (unless we want to compare known device strings/IDs) I think we should still give users the option to select a specific action set.
  • Auto-keying: I agree that the auto-keying has its downfalls as is and should be performed on a separate thread. Even in its current state though, I believe some people (e.g. blendFX) have found it useful for production.

Hi @Peter Kim (muxed-reality) I'm trying to create an own action using this system just to see if I understood how this works correctly. I can make it work with a button which I assign to the screen.animation_play command just fine:


What I'd desire to add however is a binding that would allow me to move in 3D space by using the thumbsticks on my Oculus controllers. Would you have a suggestion on how this can be achieved? Is it possible with the current system at all?
Alternatively, is it possible to create a teleporter function somehow?

Thanks for all the great efforts here!

@Rainer Trummer (aliasguru) VR navigation is not really supported at the moment, but it is planned for the future (probably in a later patch).

What you can do for now is create a VR landmark of "Custom Object" type and adjust the object's position via a custom operator. If the operator is assigned to a VR action, it will receive events of type XR_ACTION so you can then listen for this input to move the object (and thus the viewer's position).

In addition, the event will have an "xr_state" property, which gives the float value (-1.0 to 1.0) of the input, as well as "xr_controller_location" (xyz) and "xr_controller_rotation" (quaternion) properties that give the corresponding controller pose (same left/right side as the input) at the time the event occurred.

Some people have tried this approach with some success. However, it may be best to wait until VR navigation is properly supported (i.e. once there is a navigation/world matrix that can be applied to VR poses and is accessible via the Python API) .

  • VR actions in normal keymap: I actually understood your earlier proposal to register VR actions in a similar, but separate, way to keymap configs. However, I found that I would need to duplicate a lot of the work already done by the keymaps (for example, generating diffs against default configs and visualizing operator properties). Furthermore, it seemed consistent to group XR inputs together with the other types of input mappings (NDOF, Text Input, Timer, etc.). That being said, a separate system for VR actions also seems reasonable.

I think we can keep this much simpler.
First, like I said I don't think we need customizable action-sets yet. For now having a default action set defined in an editable Python file should be enough. Let's see how this part works first, before doubling down on it.

If in future we want to add customizable action-sets we can indeed do it with a UI like the keymaps and I think we can actually reuse the code for that. E.g. you can call draw_kmi() in rna_keymap_ui.py and either adjust that so it works for action sets too or create temporary "fake" keymap items for the UI drawing. Both should be simple to do. These layout functions do simple things anyway.

Further I don't think we need complex diffing. For keymaps it's only needed because a number of keymaps have to be merged into one, and compatibility is very important. For action sets we can do something simpler since there will be less "layers" involved (2? One base action-set from an add-on or otherwise imported + changes by the user?).

Basically my advice is to not add complexity that isn't clearly needed at this early stage. We can still add such non-core stuff - or we might also end up deciding to go for a different design when we evaluate things later. This is typical for agile development: do just enough to learn enough for the next steps, focus on the essentials at first. It's fine if things will be limited, as long as we deliver something that gets the user from A to B and we didn't design ourselve into a corner.

(Maybe we should call our abstraction of action-sets action-maps? To keep it consistent with key-maps.)

  • "0/1" vs "left/right": Although in most cases "left/right" will be most appropriate for identifying controllers, I decided to use "0/1" because there may be some cases where a controller or other tracked device may not be strictly left or right (such as a Vive tracker). However, excluding these special cases, I do think that "left/right" is more easily understood.

Yeah, think so too. I guess left/right would relate to the resting pose, which could be noted clearly in the code/API-docs.

  • Determining device-appropriate action set: In theory, the XR runtime is supposed to automatically select the most appropriate action set (from a list of provided action sets) for the identified device. However, in practice this hasn't worked well for me, so (unless we want to compare known device strings/IDs) I think we should still give users the option to select a specific action set.

There's a lot to be said about adding options because it seems like the easiest/safest way forward. It's better to come up with designs that don't need such options.

So the runtime just fails to select the correct action set? Is that only a specific runtime? Maybe it's fixed by now?
I'd say temporarily having a map of known device IDs is fine, until the runtimes handle it properly. If there are issues we might want to report them upstream.

  • Auto-keying: I agree that the auto-keying has its downfalls as is and should be performed on a separate thread. Even in its current state though, I believe some people (e.g. blendFX) have found it useful for production.

I think so too but I'd make it a feature that is disabled by default. It could be an add-on preference that somehow notes that it's of limited use.

In general it's good to differentiate between core functionality for the milestone, and features we add just because it's useful to some of our stakeholders (e.g. the autokeying). The latter needs less polish/design and can be moved into a separate add-on or behind a preference of the scene inspection one.

On another note, we may want to consider renaming the add-on once it becomes more than just scene inspection.

There are a number of things we could review in separate patches and move into master already/soon.

For example the Ghost-XR and WM-XR code doesn't need to follow high standards, it's internal, runtime only code. We can always change things in master as needed.
Other things that could be split off:

  • Improvements to reference spaces.
  • Autokeying from VR session (experimental feature of the add-on?).
  • Headset object.
  • The changes to support wmOperatorType.modal_3d/.invoke_3d (doesn't have to include the usages, like transform_invoke_3d(), I just want to see if other devs agree on this approach).
  • Surface event handling.

Typically I'd create a bunch of branches for this, which is quite a hassle to deal with. But I think it's the fastest way forward.

Refactor internal XR API (remove Blender data from GHOST, remove
GHOST types from RNA).

Use common functions for modal_3d operators.

Move XR actions from keymaps to separate actionmaps system.

Peter Kim (muxed-reality) marked 4 inline comments as done.Mar 14 2021, 2:13 PM
Peter Kim (muxed-reality) added inline comments.
intern/ghost/GHOST_Types.h
687

Removed explicit action set priorities.

717–719

Removed Blender data from Ghost_XrActionInfo.

source/blender/editors/space_view3d/view3d_select.c
2538–2542

Generalized invoke_3d logic with ED_view3d_view_params_get/set().

source/blender/makesrna/intern/rna_xr.c
372–376

Removed Ghost data, but instead of passing individual arguments it might be better to pass XrActionMap/XrActionMapItem now.

Peter Kim (muxed-reality) updated this revision to Diff 36037.EditedApr 10 2021, 7:06 AM
Peter Kim (muxed-reality) marked 3 inline comments as done.
Peter Kim (muxed-reality) edited the summary of this revision. (Show Details)

Last update before patch splitting.

Peter Kim (muxed-reality) changed the visibility from "All Users" to "Public (No Login Required)".May 18 2021, 11:05 AM

I created a task to keep track of the patches: T88367: Review & Merge Controller Support Patches. Is there any particular reason to keep this patch open? Guess the fact that the branch is named xr-actions-D9124, but we can simply rename that (suggest xr-controller-support or such).

I created a task to keep track of the patches: T88367: Review & Merge Controller Support Patches. Is there any particular reason to keep this patch open? Guess the fact that the branch is named xr-actions-D9124, but we can simply rename that (suggest xr-controller-support or such).

Ok, I renamed the branch to xr-controller-support and updated it with the latest changes from master. Guess there's no need to keep this patch open anymore.

Julian Eisel (Severin) abandoned this revision.EditedMay 18 2021, 4:21 PM

Seems we can not simply close the patch, only abandon it... Rest assured this is not abandoned!

The patch is now split up into multiple ones, which allows us to review and merge them one by one. See T88367: Review & Merge Controller Support Patches for the individual patches.