Tamarin 2: OpenXR for Virtual realily

Tamarin 2

I’ve just release a new version of Tamarin (2.0.0) that replaces the OpenVR of Tamarin 1 / jme3-vr with OpenXR. OpenXR is the new industry standard for Virtual and Augmented reality so applications running with OpenXR should have better support and a longer life.

Thank you to @starcommander for kicking off the OpenXR effort and to @zzuegg for helping me with a more efficient OpenGL render (apparently saving 700Mb of copying textures around per second)

It’s obviously filled with breaking changes from Tamarin 1 but the API is very similar so while it’s breaking it should be relatively obvious how to migrate an application. In particular the 3 main AppStates map like this

Tamarin 1 Tamarin 2 Purpose
VrAppState (from JMonkey) XrAppState (from Tamarin) The eyes and overall system boot up
ActionBasedOpenVrState OpenXrActionState Low level calls to get actions (aka button presses and hand positions
VRHandsAppState VRHandsAppState Optionated hand model binding and high level APIs (barely changed from Tamarin 1)

Some of the hand coordinate systems are a little different (I took the opportunity to standardise them a bit)

Tamarin 2 completely replaces jme3-vr so that should not be included in build.gradle. Instead jme3-desktop (and other standard jme3 dependencies) should be included.

Minimal Example

public class Main extends SimpleApplication{

    public static void main(String[] args) {
        AppSettings settings = new AppSettings(true);
        settings.put("Renderer", AppSettings.LWJGL_OPENGL45); // OpenXR only supports relatively modern OpenGL
        settings.setTitle("Tamarin OpenXR Example");
        settings.setVSync(false); // don't want to VSync to the monitor refresh rate, we want to sync to the headset refresh rate

        Main app = new Main();
        app.setSettings(settings);
        app.start();
    }

    @Override
    public void simpleInitApp(){
            getStateManager().attach(new XrAppState());
           //optionally add OpenXrActionState and VRHandsAppState 
    }
}

A more extensive example can be found in TamarinTestBed

What does Tamarin 2 / OpenXR have over OpenVR

VR & AR

OpenXR supports both VR (i.e. fully immersive) and Augmented reality (virtual objects layered over the real world). I don’t have a headset that supports it so I haven’t tested it but I think enabling AR should be as easy as:

  • Making sure the viewports background is transparent

  • Setting Tamarin to boot in AR mode

      XrSettings xrSettings = new XrSettings();
      xrSettings.setXrVrMode(XrVrMode.ENVIRONMENT_BLEND_MODE_ALPHA_BLEND);
      getStateManager().attach(new XrAppState(xrSettings));
    

Go into and out of VR at will

Unlike jme3-vr; Tamarin 2 adopts the running OpenGL context and does not need to be running before JME starts, this means that an application can start as a desktop application and then move over into VR when the XrAppState is added. Additionally its possible to remove and re-add the state at will, with VR binding and unbinding (This is experimental, it works but I want to smooth it out a bit. The test bed has an example of doing this). This is something that was requested previously by @RaffaeleRagni .

Similarly, by default it adopts the main camera (makes the desktop view track the VR view) but it can be configured to not do that and leave the main view alone.

Nicer action manifest

In OpenXR the action manifest was defined in XML (and that XML could not be packed with the application, it had to be a raw file just lying about), in OpenXR it can be provided by code which means I can provide a nice API for it

    Action openHandMenu = Action.builder()
            .actionHandle(ActionHandles.OPEN_HAND_MENU)
            .translatedName("Open Hand Menu")
            .actionType(ActionType.BOOLEAN)
            .withSuggestedBinding(OculusTouchController.PROFILE, OculusTouchController.pathBuilder().leftHand().thumbStickClick())
            .withSuggestedBinding(OculusTouchController.PROFILE, OculusTouchController.pathBuilder().rightHand().thumbStickClick())
            // other controllers suggested bindings
            .build();

    return ActionManifest.builder()
            .withActionSet(ActionSet
                    .builder()
                    .name("main")
                    .translatedName("Main Actions")
                    .priority(1)
                    .withAction(openHandMenu)
                    // other actions
                    .build()
            ).build();

Gamma correction

As a side effect of adopting the existing OpenGL context rather than spinning up my own I believe that Tamarin 2 doesn’t have the long standing no gamma correction bug as reported by @marcelfalliere

Xr Extensions

OpenXR is made of a bunch of extensions, a small number of which are used in Tamarin. Tamarin makes it possible to request more if you require them

    XrSettings xrSettings = new XrSettings();
    xrSettings.addRequiredXrExtension("XR_EXT_DPAD_BINDING_EXTENSION_NAME");
    getStateManager().attach(new XrAppState(xrSettings));

But of course that will probably mean you’ll need to write direct calls to LWJGL to exercise those extensions.

The observer

No one seemed to like the observer from jme3-vr. It still exists in Tamarin 2 (because it’s actually an essential concept; to map the VR world to the real world) but its prominence is much reduced; you can ask Tamarin to move the player’s feet to a location or turn them to face something and Tamarin will figure out what that actually means for the observer

DPads?

So often you want to treat a thumbpad as a DPad (i.e. left is a “button”, right is a “button” etc). That is supported in OpenXR but requires LWJGL 3.3.3 while JMonkeyEngine is on 3.3.1. In the meantime Tamarin includes a class SyntheticDPad that can give the same functionality (albeit in a less clean and configurable way)

What about OpenVR

If your current project uses Tamarin 1 and/or pure JME3-vr then it isn’t super urgent to move. OpenVR continues to be well supported (and steam have recently committed to continuing support - although I can’t find where I read that) so “don’t panic” but in my opinion new projects probably should be targeting OpenXR.

Hand models

Hand models are unfortunately completely incompatible between OpenXR and OpenVR. This is because the bones have changed (OpenVR has bones parented naturally, OpenXR has them all as independent). Tamarin 2 comes with a new set of hands so if you were using Tamarin default hands before just use them, if not you’ll need to update your bones.

Testing

I have only tested this on one system with one OS and one graphics card. If anyone else is able to test (the TamarinTestBed is great for that) and let me know if it either does or doesn’t work for you that would be most appreciated.

I tested this on:
Windows 10, Oculus Quest 2 (SteamVR via Virtual Desktop), NVIDIA GeForce RTX 3070

16 Likes

Thanks Richtea and everyone :slight_smile:

As i understand into JME there were included OpenXR in package: jme3-desktop

thats Tamarin 2 is using now.

Also Tamarin 2 is still same repo as Tamarin 1: GitHub - oneMillionWorlds/Tamarin at 2.x

is that correct?

I still didnt tried use VR, but want to confirm for later purpose of using.

Hi,

As i understand into JME there were included OpenXR in package: jme3-desktop

I don’t believe that jme3-desktop provides the openXR bindings. Tamarin adds dependencies lwjgl-openxr and lwjgl-egl in order to provide OpenXR (but I think these build on the core LWJGL so need to be the same version as JME’s LWJGL

Also Tamarin 2 is still same repo as Tamarin 1: GitHub - oneMillionWorlds/Tamarin at 2.x

Sort of, that 2.x branch was from when it was experimental, I’ve now merged all of that into the main branch at GitHub - oneMillionWorlds/Tamarin: A VR utilities library for JMonkeyEngine. I’ve kept a seperate 1.x branch in case Tamarin 1 needs any bug fixes

Similarly its the same gradle dependency, so

implementation 'com.onemillionworlds:tamarin:2.0.0'

(However, I realised I was being stupid with the DPad thing, LWJGL 3.3.3 contains a string constant for the DPad extension, but I can just type that in myself without the constant. So a Tamarin 2.0.1 will be hot on the heals of 2.0.0 that includes dpad functionality, so keep an eye on https://mvnrepository.com/artifact/com.onemillionworlds/tamarin for the most recent version)

1 Like

ok thanks :slight_smile:

So just Master branch or linked maven artifact is 2.x

main git branch (for Tamarin 2) and 2.x.x maven artifacts.

Ive deleted the old 2.x branches to be less confusing

1 Like

Thanks for doing this!

Only now had a chance to try it.
Testing with Oculus Rift CV1 results in an exception at start:
java.lang.IllegalStateException: OpenXR library does not provide required extension: XR_EXT_hand_tracking
at com.onemillionworlds.tamarin.openxr.OpenXrSessionManager.createOpenXRInstance(OpenXrSessionManager.java:199)
at com.onemillionworlds.tamarin.openxr.OpenXrSessionManager.createOpenXrSession(OpenXrSessionManager.java:164)
at com.onemillionworlds.tamarin.openxr.XrAppState.initialize(XrAppState.java:93)

it doesn’t support hand tracking.

Thanks for testing. Is that rift launched via steam or another way?

Edit; I think my previous assumption of “all the runtimes will have XR_EXT_hand_tracking, it’ll be fine!” was clearly incorrect. I’ll do some work to make it optional and degrade gracefully if its not available

Yeah, not having handtracking is getting rare I guess, but still a few of us out there.

(Started via cmd. Oculus software starts automatically, as does Steam. Closing Steam didn’t make a difference.)

@rnk Could you try version 2.1.0? I’ve made the XR_EXT_hand_tracking extension optional and made it gracefully degrade like this:

  • If hand tracking extension is available use it to render high fidelity hand bone positions (as in 2.0.2)
  • If hand tracking extension is not available but a grabAction has been registered on the hand (BoundHand#setGrabAction) then use the grab strength to approximate the bone position. This means fist clench and unclench only, approximated by the button controlling the grab. An example of this can be seen in the Tamarin Test Bed > Block Moving example
  • If hand tracking extension is not available and a grabAction is not set then the hand is always in an open position. (The Tamarin Test Bed main menu is an example where this is the case)

(Incidentally the XR_EXT_hand_tracking extension isn’t for what I would consider hand tracking - hands without controllers; it’s for determining the bone positions based on the controllers; I had assumed this extension would be runtime dependent but is apparently controller dependent)

after git pull for TamarinTestBed:

Nov. 08, 2023 12:26:45 AM com.jme3.system.JmeDesktopSystem initialize
INFORMATION: Running on jMonkeyEngine 3.6.1-stable
 * Branch: HEAD
 * Git Hash: 4de10c3
 * Build Date: 2023-06-23
Nov. 08, 2023 12:26:45 AM com.jme3.system.lwjgl.LwjglContext printContextInitInfo
INFORMATION: LWJGL 3.3.2-snapshot context running on thread jME3 Main
 * Graphics Adapter: GLFW 3.4.0 Win32 WGL Null EGL OSMesa VisualC DLL
Nov. 08, 2023 12:26:46 AM com.jme3.renderer.opengl.GLRenderer loadCapabilitiesCommon
INFORMATION: OpenGL Renderer Information
 * Vendor: NVIDIA Corporation
 * Renderer: NVIDIA GeForce GTX 1070/PCIe/SSE2
 * OpenGL Version: 4.5.0 NVIDIA 536.23
 * GLSL Version: 4.50 NVIDIA
 * Profile: Core
Nov. 08, 2023 12:26:46 AM com.jme3.audio.openal.ALAudioRenderer initOpenAL
INFORMATION: Audio Renderer Information
 * Device: OpenAL Soft
 * Vendor: OpenAL Community
 * Renderer: OpenAL Soft
 * Version: 1.1 ALSOFT 1.23.0
 * Supported channels: 64
 * ALC extensions: ALC_ENUMERATE_ALL_EXT ALC_ENUMERATION_EXT ALC_EXT_CAPTURE ALC_EXT_DEDICATED ALC_EXT_disconnect ALC_EXT_EFX ALC_EXT_thread_local_context ALC_SOFT_device_clock ALC_SOFT_HRTF ALC_SOFT_loopback ALC_SOFT_loopback_bformat ALC_SOFT_output_limiter ALC_SOFT_output_mode ALC_SOFT_pause_device ALC_SOFT_reopen_device
 * AL extensions: AL_EXT_ALAW AL_EXT_BFORMAT AL_EXT_DOUBLE AL_EXT_EXPONENT_DISTANCE AL_EXT_FLOAT32 AL_EXT_IMA4 AL_EXT_LINEAR_DISTANCE AL_EXT_MCFORMATS AL_EXT_MULAW AL_EXT_MULAW_BFORMAT AL_EXT_MULAW_MCFORMATS AL_EXT_OFFSET AL_EXT_source_distance_model AL_EXT_SOURCE_RADIUS AL_EXT_STEREO_ANGLES AL_LOKI_quadriphonic AL_SOFT_bformat_ex AL_SOFTX_bformat_hoa AL_SOFT_block_alignment AL_SOFT_callback_buffer AL_SOFTX_convolution_reverb AL_SOFT_deferred_updates AL_SOFT_direct_channels AL_SOFT_direct_channels_remix AL_SOFT_effect_target AL_SOFT_events AL_SOFT_gain_clamp_ex AL_SOFTX_hold_on_disconnect AL_SOFT_loop_points AL_SOFTX_map_buffer AL_SOFT_MSADPCM AL_SOFT_source_latency AL_SOFT_source_length AL_SOFT_source_resampler AL_SOFT_source_spatialize AL_SOFTX_source_start_delay AL_SOFT_UHJ
Nov. 08, 2023 12:26:46 AM com.jme3.audio.openal.ALAudioRenderer initOpenAL
INFORMATION: Audio effect extension version: 1.0
Nov. 08, 2023 12:26:46 AM com.jme3.audio.openal.ALAudioRenderer initOpenAL
INFORMATION: Audio max auxiliary sends: 2
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
Nov. 08, 2023 12:26:48 AM com.onemillionworlds.tamarin.openxr.OpenXrSessionManager makeLayersCheck
INFORMATION: XR core validation not available
Nov. 08, 2023 12:26:48 AM com.onemillionworlds.tamarin.openxr.OpenXrSessionManager createOpenXRInstance
WARNUNG: OpenXR extension XR_EXT_hand_tracking NOT loaded
Nov. 08, 2023 12:26:48 AM com.onemillionworlds.tamarin.openxr.OpenXrSessionManager createOpenXRInstance
WARNUNG: OpenXR extension XR_KHR_binding_modification NOT loaded
Nov. 08, 2023 12:26:48 AM com.onemillionworlds.tamarin.openxr.OpenXrSessionManager createOpenXRInstance
WARNUNG: OpenXR extension XR_MNDX_egl_enable NOT loaded
Nov. 08, 2023 12:26:48 AM com.onemillionworlds.tamarin.openxr.OpenXrSessionManager createOpenXRInstance
WARNUNG: OpenXR extension XR_EXT_dpad_binding NOT loaded
Nov. 08, 2023 12:26:48 AM com.onemillionworlds.tamarin.openxr.OpenXrSessionManager initializeAndBindOpenGL
INFORMATION: The OpenXR runtime supports OpenGL 4.0 to OpenGL 4.6
Using XrGraphicsBindingOpenGLWin32KHR to create the session
Nov. 08, 2023 12:26:48 AM com.onemillionworlds.tamarin.openxr.OpenXrSessionManager initializeAndBindOpenGL
INFORMATION: OpenXR debug utils enabled
Headset name:Oculus Rift CV1 vendor:14
Headset orientationTracking:true positionTracking:true
Headset MaxWidth:4096 MaxHeight:4096 MaxLayerCount:16
Nov. 08, 2023 12:26:48 AM com.jme3.app.LegacyApplication handleError
SCHWERWIEGEND: Uncaught exception thrown in Thread[jME3 Main,5,main]
java.lang.IllegalStateException: No compatable swapchain / framebuffer format availible
        at com.onemillionworlds.tamarin.openxr.OpenXrSessionManager.createXRSwapchains(OpenXrSessionManager.java:428)
        at com.onemillionworlds.tamarin.openxr.OpenXrSessionManager.createOpenXrSession(OpenXrSessionManager.java:171)
        at com.onemillionworlds.tamarin.openxr.XrAppState.initialize(XrAppState.java:93)
        at com.jme3.app.state.BaseAppState.initialize(BaseAppState.java:129)
        at com.jme3.app.state.AppStateManager.initializePending(AppStateManager.java:332)
        at com.jme3.app.state.AppStateManager.update(AppStateManager.java:362)
        at com.jme3.app.SimpleApplication.update(SimpleApplication.java:258)
        at com.jme3.system.lwjgl.LwjglWindow.runLoop(LwjglWindow.java:628)
        at com.jme3.system.lwjgl.LwjglWindow.run(LwjglWindow.java:717)
        at java.base/java.lang.Thread.run(Thread.java:833)

Nov. 08, 2023 12:26:48 AM com.jme3.system.JmeSystemDelegate lambda$new$0
WARNUNG: JmeDialogsFactory implementation not found.
Uncaught exception thrown in Thread[jME3 Main,5,main]
IllegalStateException: No compatable swapchain / framebuffer format availible

Exception: java.lang.NullPointerException thrown from the UncaughtExceptionHandler in thread "jME3 Main"

Ok, progress at least.

I’ve expanded the list of formats to choose from and also made the error list the available formats (I’m slightly worried there may be visual artefacts as I didn’t originally include the others as they aren’t as good)

To avoid adding a bunch of versions to maven central as we work through these issues I’m using a staging repository.

Would you be able to add this to your list of repositories in your build.gradle

maven {
    url "https://s01.oss.sonatype.org/content/repositories/comonemillionworlds-1022"
}

E.g.

repositories {
    jcenter()
    mavenCentral()
    maven {
        url "https://s01.oss.sonatype.org/content/repositories/comonemillionworlds-1022"
    }
}

And use version 2.1.1-rc.2.

rc2 gave me:

Could not find com.onemillionworlds:tamarin:2.1.1-rc.2.

I tried with
implementation ‘com.onemillionworlds:tamarin:2.1.1-rc.1’

which gave me this:

Nov. 09, 2023 2:48:15 AM com.jme3.system.JmeDesktopSystem initialize
INFORMATION: Running on jMonkeyEngine 3.6.1-stable
 * Branch: HEAD
 * Git Hash: 4de10c3
 * Build Date: 2023-06-23
Nov. 09, 2023 2:48:16 AM com.jme3.system.lwjgl.LwjglContext printContextInitInfo
INFORMATION: LWJGL 3.3.2-snapshot context running on thread jME3 Main
 * Graphics Adapter: GLFW 3.4.0 Win32 WGL Null EGL OSMesa VisualC DLL
Nov. 09, 2023 2:48:16 AM com.jme3.renderer.opengl.GLRenderer loadCapabilitiesCommon
INFORMATION: OpenGL Renderer Information
 * Vendor: NVIDIA Corporation
 * Renderer: NVIDIA GeForce GTX 1070/PCIe/SSE2
 * OpenGL Version: 4.5.0 NVIDIA 536.23
 * GLSL Version: 4.50 NVIDIA
 * Profile: Core
Nov. 09, 2023 2:48:16 AM com.jme3.audio.openal.ALAudioRenderer initOpenAL
INFORMATION: Audio Renderer Information
 * Device: OpenAL Soft
 * Vendor: OpenAL Community
 * Renderer: OpenAL Soft
 * Version: 1.1 ALSOFT 1.23.0
 * Supported channels: 64
 * ALC extensions: ALC_ENUMERATE_ALL_EXT ALC_ENUMERATION_EXT ALC_EXT_CAPTURE ALC_EXT_DEDICATED ALC_EXT_disconnect ALC_EXT_EFX ALC_EXT_thread_local_context ALC_SOFT_device_clock ALC_SOFT_HRTF ALC_SOFT_loopback ALC_SOFT_loopback_bformat ALC_SOFT_output_limiter ALC_SOFT_output_mode ALC_SOFT_pause_device ALC_SOFT_reopen_device
 * AL extensions: AL_EXT_ALAW AL_EXT_BFORMAT AL_EXT_DOUBLE AL_EXT_EXPONENT_DISTANCE AL_EXT_FLOAT32 AL_EXT_IMA4 AL_EXT_LINEAR_DISTANCE AL_EXT_MCFORMATS AL_EXT_MULAW AL_EXT_MULAW_BFORMAT AL_EXT_MULAW_MCFORMATS AL_EXT_OFFSET AL_EXT_source_distance_model AL_EXT_SOURCE_RADIUS AL_EXT_STEREO_ANGLES AL_LOKI_quadriphonic AL_SOFT_bformat_ex AL_SOFTX_bformat_hoa AL_SOFT_block_alignment AL_SOFT_callback_buffer AL_SOFTX_convolution_reverb AL_SOFT_deferred_updates AL_SOFT_direct_channels AL_SOFT_direct_channels_remix AL_SOFT_effect_target AL_SOFT_events AL_SOFT_gain_clamp_ex AL_SOFTX_hold_on_disconnect AL_SOFT_loop_points AL_SOFTX_map_buffer AL_SOFT_MSADPCM AL_SOFT_source_latency AL_SOFT_source_length AL_SOFT_source_resampler AL_SOFT_source_spatialize AL_SOFTX_source_start_delay AL_SOFT_UHJ
Nov. 09, 2023 2:48:16 AM com.jme3.audio.openal.ALAudioRenderer initOpenAL
INFORMATION: Audio effect extension version: 1.0
Nov. 09, 2023 2:48:16 AM com.jme3.audio.openal.ALAudioRenderer initOpenAL
INFORMATION: Audio max auxiliary sends: 2
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
Nov. 09, 2023 2:48:18 AM com.onemillionworlds.tamarin.openxr.OpenXrSessionManager makeLayersCheck
INFORMATION: XR core validation not available
Nov. 09, 2023 2:48:18 AM com.onemillionworlds.tamarin.openxr.OpenXrSessionManager createOpenXRInstance
WARNUNG: OpenXR extension XR_EXT_hand_tracking NOT loaded
Nov. 09, 2023 2:48:18 AM com.onemillionworlds.tamarin.openxr.OpenXrSessionManager createOpenXRInstance
WARNUNG: OpenXR extension XR_KHR_binding_modification NOT loaded
Nov. 09, 2023 2:48:18 AM com.onemillionworlds.tamarin.openxr.OpenXrSessionManager createOpenXRInstance
WARNUNG: OpenXR extension XR_MNDX_egl_enable NOT loaded
Nov. 09, 2023 2:48:18 AM com.onemillionworlds.tamarin.openxr.OpenXrSessionManager createOpenXRInstance
WARNUNG: OpenXR extension XR_EXT_dpad_binding NOT loaded
Nov. 09, 2023 2:48:18 AM com.onemillionworlds.tamarin.openxr.OpenXrSessionManager initializeAndBindOpenGL
INFORMATION: The OpenXR runtime supports OpenGL 4.0 to OpenGL 4.6
Using XrGraphicsBindingOpenGLWin32KHR to create the session
Nov. 09, 2023 2:48:18 AM com.onemillionworlds.tamarin.openxr.OpenXrSessionManager initializeAndBindOpenGL
INFORMATION: OpenXR debug utils enabled
Headset name:Oculus Rift CV1 vendor:14
Headset orientationTracking:true positionTracking:true
Headset MaxWidth:4096 MaxHeight:4096 MaxLayerCount:16
Nov. 09, 2023 2:48:18 AM com.onemillionworlds.tamarin.openxr.OpenXrSessionManager createXRSwapchains
INFORMATION: Selected colour format 32856 from options [32856, 33189, 34843, 35056, 35898, 35907, 36012, 36013]
XrEventDataSessionStateChanged: state null->IDLE session=72061768746139649 time=171048150281199
Nov. 09, 2023 2:48:18 AM com.jme3.app.LegacyApplication handleError
SCHWERWIEGEND: Uncaught exception thrown in Thread[jME3 Main,5,main]
java.lang.RuntimeException: No action found for ActionHandle[actionSetName=main, actionName=trigger]. Have you registered it in the manifest?
        at com.onemillionworlds.tamarin.actions.OpenXrActionState.obtainActionHandle(OpenXrActionState.java:579)
        at com.onemillionworlds.tamarin.actions.OpenXrActionState.getFloatActionState(OpenXrActionState.java:762)
        at com.onemillionworlds.tamarin.vrhands.functions.LemurClickFunction.getClickActionPressure(LemurClickFunction.java:187)
        at com.onemillionworlds.tamarin.vrhands.functions.LemurClickFunction.update(LemurClickFunction.java:122)
        at com.onemillionworlds.tamarin.vrhands.BoundHand.lambda$update$6(BoundHand.java:339)
        at java.base/java.util.concurrent.CopyOnWriteArrayList.forEach(CopyOnWriteArrayList.java:807)
        at com.onemillionworlds.tamarin.vrhands.BoundHand.update(BoundHand.java:339)
        at com.onemillionworlds.tamarin.vrhands.VRHandsAppState.lambda$update$2(VRHandsAppState.java:140)
        at java.base/java.util.Optional.ifPresent(Optional.java:178)
        at com.onemillionworlds.tamarin.vrhands.VRHandsAppState.update(VRHandsAppState.java:139)
        at com.jme3.app.state.AppStateManager.update(AppStateManager.java:371)
        at com.jme3.app.SimpleApplication.update(SimpleApplication.java:258)
        at com.jme3.system.lwjgl.LwjglWindow.runLoop(LwjglWindow.java:628)
        at com.jme3.system.lwjgl.LwjglWindow.run(LwjglWindow.java:717)
        at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: java.lang.NullPointerException: Cannot invoke "java.util.Map.get(Object)" because "this.actions" is null
        at com.onemillionworlds.tamarin.actions.OpenXrActionState.obtainActionHandle(OpenXrActionState.java:577)
        ... 14 more

Nov. 09, 2023 2:48:18 AM com.jme3.system.JmeSystemDelegate lambda$new$0
WARNUNG: JmeDialogsFactory implementation not found.
Uncaught exception thrown in Thread[jME3 Main,5,main]
RuntimeException: No action found for ActionHandle[actionSetName=main, actionName=trigger]. Have you registered it in the manifest?

progress again I hope.

1 Like

Progress indeed!

Yes, that version was a typo, sorry

I think I see what’s happening. I think the session doesn’t quite start quickly enough, meaning the action manifest doesn’t load and then it crashes when the action is subsequently used. I’ve tried to make it more forgiving of that

Could you try

maven {
    url "https://s01.oss.sonatype.org/content/repositories/comonemillionworlds-1025"
}

And version 2.1.1-rc.3

I can see from your logs that the dpad extension (XR_EXT_dpad_binding ) also failed to load. I think it should just issue a warning “-22 XR_ERROR_PATH_UNSUPPORTED occurred during xrSuggestInteractionProfileBindings. The semantic path is unsupported” and limp on. But it won’t work properly. You might want to remap the dpad suggested bindings in Main#manifest() in TamarinTestBed

A real application would probably want to test if that extension was available before requesting dpad paths

(It’s one slightly frustrating thing about openXR; so much of what feels like core functionality is provided as extensions that may or may not be present)

I had deprecated the SyntheticDpad (which provides dpad behavior from joysticks in java rather than asking the runtime to do it) but seeing this maybe ill bring it back to non deprecated to give better cross platform support

now a window pops up and for a moment something happens in the hmd
more progress!

Nov. 09, 2023 5:06:44 PM com.jme3.system.JmeDesktopSystem initialize
INFORMATION: Running on jMonkeyEngine 3.6.1-stable
 * Branch: HEAD
 * Git Hash: 4de10c3
 * Build Date: 2023-06-23
Nov. 09, 2023 5:06:44 PM com.jme3.system.lwjgl.LwjglContext printContextInitInfo
INFORMATION: LWJGL 3.3.2-snapshot context running on thread jME3 Main
 * Graphics Adapter: GLFW 3.4.0 Win32 WGL Null EGL OSMesa VisualC DLL
Nov. 09, 2023 5:06:44 PM com.jme3.renderer.opengl.GLRenderer loadCapabilitiesCommon
INFORMATION: OpenGL Renderer Information
 * Vendor: NVIDIA Corporation
 * Renderer: NVIDIA GeForce GTX 1070/PCIe/SSE2
 * OpenGL Version: 4.5.0 NVIDIA 536.23
 * GLSL Version: 4.50 NVIDIA
 * Profile: Core
Nov. 09, 2023 5:06:45 PM com.jme3.audio.openal.ALAudioRenderer initOpenAL
INFORMATION: Audio Renderer Information
 * Device: OpenAL Soft
 * Vendor: OpenAL Community
 * Renderer: OpenAL Soft
 * Version: 1.1 ALSOFT 1.23.0
 * Supported channels: 64
 * ALC extensions: ALC_ENUMERATE_ALL_EXT ALC_ENUMERATION_EXT ALC_EXT_CAPTURE ALC_EXT_DEDICATED ALC_EXT_disconnect ALC_EXT_EFX ALC_EXT_thread_local_context ALC_SOFT_device_clock ALC_SOFT_HRTF ALC_SOFT_loopback ALC_SOFT_loopback_bformat ALC_SOFT_output_limiter ALC_SOFT_output_mode ALC_SOFT_pause_device ALC_SOFT_reopen_device
 * AL extensions: AL_EXT_ALAW AL_EXT_BFORMAT AL_EXT_DOUBLE AL_EXT_EXPONENT_DISTANCE AL_EXT_FLOAT32 AL_EXT_IMA4 AL_EXT_LINEAR_DISTANCE AL_EXT_MCFORMATS AL_EXT_MULAW AL_EXT_MULAW_BFORMAT AL_EXT_MULAW_MCFORMATS AL_EXT_OFFSET AL_EXT_source_distance_model AL_EXT_SOURCE_RADIUS AL_EXT_STEREO_ANGLES AL_LOKI_quadriphonic AL_SOFT_bformat_ex AL_SOFTX_bformat_hoa AL_SOFT_block_alignment AL_SOFT_callback_buffer AL_SOFTX_convolution_reverb AL_SOFT_deferred_updates AL_SOFT_direct_channels AL_SOFT_direct_channels_remix AL_SOFT_effect_target AL_SOFT_events AL_SOFT_gain_clamp_ex AL_SOFTX_hold_on_disconnect AL_SOFT_loop_points AL_SOFTX_map_buffer AL_SOFT_MSADPCM AL_SOFT_source_latency AL_SOFT_source_length AL_SOFT_source_resampler AL_SOFT_source_spatialize AL_SOFTX_source_start_delay AL_SOFT_UHJ
Nov. 09, 2023 5:06:45 PM com.jme3.audio.openal.ALAudioRenderer initOpenAL
INFORMATION: Audio effect extension version: 1.0
Nov. 09, 2023 5:06:45 PM com.jme3.audio.openal.ALAudioRenderer initOpenAL
INFORMATION: Audio max auxiliary sends: 2
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
Nov. 09, 2023 5:06:47 PM com.onemillionworlds.tamarin.openxr.OpenXrSessionManager makeLayersCheck
INFORMATION: XR core validation not available
Nov. 09, 2023 5:06:47 PM com.onemillionworlds.tamarin.openxr.OpenXrSessionManager createOpenXRInstance
WARNUNG: OpenXR extension XR_EXT_hand_tracking NOT loaded
Nov. 09, 2023 5:06:47 PM com.onemillionworlds.tamarin.openxr.OpenXrSessionManager createOpenXRInstance
WARNUNG: OpenXR extension XR_KHR_binding_modification NOT loaded
Nov. 09, 2023 5:06:47 PM com.onemillionworlds.tamarin.openxr.OpenXrSessionManager createOpenXRInstance
WARNUNG: OpenXR extension XR_MNDX_egl_enable NOT loaded
Nov. 09, 2023 5:06:47 PM com.onemillionworlds.tamarin.openxr.OpenXrSessionManager createOpenXRInstance
WARNUNG: OpenXR extension XR_EXT_dpad_binding NOT loaded
Nov. 09, 2023 5:06:47 PM com.onemillionworlds.tamarin.openxr.OpenXrSessionManager initializeAndBindOpenGL
INFORMATION: The OpenXR runtime supports OpenGL 4.0 to OpenGL 4.6
Using XrGraphicsBindingOpenGLWin32KHR to create the session
Nov. 09, 2023 5:06:47 PM com.onemillionworlds.tamarin.openxr.OpenXrSessionManager initializeAndBindOpenGL
INFORMATION: OpenXR debug utils enabled
Headset name:Oculus Rift CV1 vendor:14
Headset orientationTracking:true positionTracking:true
Headset MaxWidth:4096 MaxHeight:4096 MaxLayerCount:16
Nov. 09, 2023 5:06:47 PM com.onemillionworlds.tamarin.openxr.OpenXrSessionManager createXRSwapchains
INFORMATION: Selected colour format 32856 from options [32856, 33189, 34843, 35056, 35898, 35907, 36012, 36013]
XrEventDataSessionStateChanged: state null->IDLE session=72087383931092993 time=222557875212500
Nov. 09, 2023 5:06:47 PM com.jme3.anim.SkinningControl controlRender
INFORMATION: Hardware skinning engaged for Armature (Node)
Nov. 09, 2023 5:06:47 PM com.jme3.anim.SkinningControl controlRender
INFORMATION: Hardware skinning engaged for Armature (Node)
XrEventDataSessionStateChanged: state IDLE->READY session=72087383931092993 time=222608447009800
Nov. 09, 2023 5:07:37 PM com.jme3.app.LegacyApplication handleError
SCHWERWIEGEND: Uncaught exception thrown in Thread[jME3 Main,5,main]
com.onemillionworlds.tamarin.openxr.OpenXrSessionManager$OpenXrException: XR_ERROR_VALIDATION_FAILURE
        at com.onemillionworlds.tamarin.openxr.OpenXrSessionManager.checkResponseCode(OpenXrSessionManager.java:880)
        at com.onemillionworlds.tamarin.actions.OpenXrActionState.checkResponseCode(OpenXrActionState.java:522)
        at com.onemillionworlds.tamarin.actions.OpenXrActionState.registerActions(OpenXrActionState.java:326)
        at com.onemillionworlds.tamarin.actions.OpenXrActionState.update(OpenXrActionState.java:894)
        at com.jme3.app.state.AppStateManager.update(AppStateManager.java:371)
        at com.jme3.app.SimpleApplication.update(SimpleApplication.java:258)
        at com.jme3.system.lwjgl.LwjglWindow.runLoop(LwjglWindow.java:628)
        at com.jme3.system.lwjgl.LwjglWindow.run(LwjglWindow.java:717)
        at java.base/java.lang.Thread.run(Thread.java:833)

Nov. 09, 2023 5:07:37 PM com.jme3.system.JmeSystemDelegate lambda$new$0
WARNUNG: JmeDialogsFactory implementation not found.
Uncaught exception thrown in Thread[jME3 Main,5,main]
OpenXrException: XR_ERROR_VALIDATION_FAILURE

the following part didn’t show up when I ran it again:

Nov. 09, 2023 5:06:47 PM com.jme3.anim.SkinningControl controlRender
INFORMATION: Hardware skinning engaged for Armature (Node)
Nov. 09, 2023 5:06:47 PM com.jme3.anim.SkinningControl controlRender
INFORMATION: Hardware skinning engaged for Armature (Node)

Interesting, I have a theory but I’m less certain about that one. It waits for the XR state to be “READY” before it registers the manifest but I myself get some warnings about it not being focused. I’ve changed it to wait till its focused before registering, lets see if that helps

Could you try these?

maven {
    url "https://s01.oss.sonatype.org/content/repositories/comonemillionworlds-1026"
}

Version: 2.1.1-rc.4

Nov. 09, 2023 7:26:04 PM com.jme3.system.JmeDesktopSystem initialize
INFORMATION: Running on jMonkeyEngine 3.6.1-stable
 * Branch: HEAD
 * Git Hash: 4de10c3
 * Build Date: 2023-06-23
Nov. 09, 2023 7:26:04 PM com.jme3.system.lwjgl.LwjglContext printContextInitInfo
INFORMATION: LWJGL 3.3.2-snapshot context running on thread jME3 Main
 * Graphics Adapter: GLFW 3.4.0 Win32 WGL Null EGL OSMesa VisualC DLL
Nov. 09, 2023 7:26:05 PM com.jme3.renderer.opengl.GLRenderer loadCapabilitiesCommon
INFORMATION: OpenGL Renderer Information
 * Vendor: NVIDIA Corporation
 * Renderer: NVIDIA GeForce GTX 1070/PCIe/SSE2
 * OpenGL Version: 4.5.0 NVIDIA 536.23
 * GLSL Version: 4.50 NVIDIA
 * Profile: Core
Nov. 09, 2023 7:26:05 PM com.jme3.audio.openal.ALAudioRenderer initOpenAL
INFORMATION: Audio Renderer Information
 * Device: OpenAL Soft
 * Vendor: OpenAL Community
 * Renderer: OpenAL Soft
 * Version: 1.1 ALSOFT 1.23.0
 * Supported channels: 64
 * ALC extensions: ALC_ENUMERATE_ALL_EXT ALC_ENUMERATION_EXT ALC_EXT_CAPTURE ALC_EXT_DEDICATED ALC_EXT_disconnect ALC_EXT_EFX ALC_EXT_thread_local_context ALC_SOFT_device_clock ALC_SOFT_HRTF ALC_SOFT_loopback ALC_SOFT_loopback_bformat ALC_SOFT_output_limiter ALC_SOFT_output_mode ALC_SOFT_pause_device ALC_SOFT_reopen_device
 * AL extensions: AL_EXT_ALAW AL_EXT_BFORMAT AL_EXT_DOUBLE AL_EXT_EXPONENT_DISTANCE AL_EXT_FLOAT32 AL_EXT_IMA4 AL_EXT_LINEAR_DISTANCE AL_EXT_MCFORMATS AL_EXT_MULAW AL_EXT_MULAW_BFORMAT AL_EXT_MULAW_MCFORMATS AL_EXT_OFFSET AL_EXT_source_distance_model AL_EXT_SOURCE_RADIUS AL_EXT_STEREO_ANGLES AL_LOKI_quadriphonic AL_SOFT_bformat_ex AL_SOFTX_bformat_hoa AL_SOFT_block_alignment AL_SOFT_callback_buffer AL_SOFTX_convolution_reverb AL_SOFT_deferred_updates AL_SOFT_direct_channels AL_SOFT_direct_channels_remix AL_SOFT_effect_target AL_SOFT_events AL_SOFT_gain_clamp_ex AL_SOFTX_hold_on_disconnect AL_SOFT_loop_points AL_SOFTX_map_buffer AL_SOFT_MSADPCM AL_SOFT_source_latency AL_SOFT_source_length AL_SOFT_source_resampler AL_SOFT_source_spatialize AL_SOFTX_source_start_delay AL_SOFT_UHJ
Nov. 09, 2023 7:26:05 PM com.jme3.audio.openal.ALAudioRenderer initOpenAL
INFORMATION: Audio effect extension version: 1.0
Nov. 09, 2023 7:26:05 PM com.jme3.audio.openal.ALAudioRenderer initOpenAL
INFORMATION: Audio max auxiliary sends: 2
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
Nov. 09, 2023 7:26:07 PM com.onemillionworlds.tamarin.openxr.OpenXrSessionManager makeLayersCheck
INFORMATION: XR core validation not available
Nov. 09, 2023 7:26:07 PM com.onemillionworlds.tamarin.openxr.OpenXrSessionManager createOpenXRInstance
WARNUNG: OpenXR extension XR_EXT_hand_tracking NOT loaded
Nov. 09, 2023 7:26:07 PM com.onemillionworlds.tamarin.openxr.OpenXrSessionManager createOpenXRInstance
WARNUNG: OpenXR extension XR_KHR_binding_modification NOT loaded
Nov. 09, 2023 7:26:07 PM com.onemillionworlds.tamarin.openxr.OpenXrSessionManager createOpenXRInstance
WARNUNG: OpenXR extension XR_MNDX_egl_enable NOT loaded
Nov. 09, 2023 7:26:07 PM com.onemillionworlds.tamarin.openxr.OpenXrSessionManager createOpenXRInstance
WARNUNG: OpenXR extension XR_EXT_dpad_binding NOT loaded
Nov. 09, 2023 7:26:07 PM com.onemillionworlds.tamarin.openxr.OpenXrSessionManager initializeAndBindOpenGL
INFORMATION: The OpenXR runtime supports OpenGL 4.0 to OpenGL 4.6
Using XrGraphicsBindingOpenGLWin32KHR to create the session
Nov. 09, 2023 7:26:07 PM com.onemillionworlds.tamarin.openxr.OpenXrSessionManager initializeAndBindOpenGL
INFORMATION: OpenXR debug utils enabled
Headset name:Oculus Rift CV1 vendor:14
Headset orientationTracking:true positionTracking:true
Headset MaxWidth:4096 MaxHeight:4096 MaxLayerCount:16
Nov. 09, 2023 7:26:07 PM com.onemillionworlds.tamarin.openxr.OpenXrSessionManager createXRSwapchains
INFORMATION: Selected colour format 32856 from options [32856, 33189, 34843, 35056, 35898, 35907, 36012, 36013]
XrEventDataSessionStateChanged: state null->IDLE session=72077900643303425 time=230917911503800
XrEventDataSessionStateChanged: state IDLE->READY session=72077900643303425 time=230917911528600
Nov. 09, 2023 7:26:07 PM com.jme3.anim.SkinningControl controlRender
INFORMATION: Hardware skinning engaged for Armature (Node)
Nov. 09, 2023 7:26:07 PM com.jme3.anim.SkinningControl controlRender
INFORMATION: Hardware skinning engaged for Armature (Node)
Shouldn't render
XrEventDataSessionStateChanged: state READY->SYNCHRONIZED session=72077900643303425 time=230918430505500
Shouldn't render
Shouldn't render
Shouldn't render
Shouldn't render
Shouldn't render
Shouldn't render
Shouldn't render
Shouldn't render
Shouldn't render
Shouldn't render
Shouldn't render
Shouldn't render
Shouldn't render
Shouldn't render
Shouldn't render
Shouldn't render
Shouldn't render
Shouldn't render
Shouldn't render
Shouldn't render
Shouldn't render
Shouldn't render
Shouldn't render
Shouldn't render
Shouldn't render
Shouldn't render
Shouldn't render
Shouldn't render
Shouldn't render
Shouldn't render
Shouldn't render
Shouldn't render
Shouldn't render
Shouldn't render
Shouldn't render
Shouldn't render
Shouldn't render
Shouldn't render
Shouldn't render
Shouldn't render
Shouldn't render
Shouldn't render
Shouldn't render
Shouldn't render
Shouldn't render
Shouldn't render
Shouldn't render
Shouldn't render
Shouldn't render
Shouldn't render
Shouldn't render
Shouldn't render
Shouldn't render
Shouldn't render
Shouldn't render
Shouldn't render
Shouldn't render
Shouldn't render
Shouldn't render
XrEventDataSessionStateChanged: state SYNCHRONIZED->VISIBLE session=72077900643303425 time=230919165506900
Nov. 09, 2023 7:26:08 PM example.Main lambda$simpleInitApp$1
INFORMATION: System is: Oculus Rift CV1
XrEventDataSessionStateChanged: state VISIBLE->FOCUSED session=72077900643303425 time=230919165519499
Nov. 09, 2023 7:26:08 PM com.onemillionworlds.tamarin.actions.OpenXrActionState registerActions
INFORMATION: Registering manifest
Nov. 09, 2023 7:26:08 PM com.jme3.app.LegacyApplication handleError
SCHWERWIEGEND: Uncaught exception thrown in Thread[jME3 Main,5,main]
com.onemillionworlds.tamarin.openxr.OpenXrSessionManager$OpenXrException: XR_ERROR_VALIDATION_FAILURE Context: Creating action set main (Main Actions) p:1
        at com.onemillionworlds.tamarin.openxr.OpenXrSessionManager.checkResponseCode(OpenXrSessionManager.java:891)
        at com.onemillionworlds.tamarin.actions.OpenXrActionState.checkResponseCode(OpenXrActionState.java:519)
        at com.onemillionworlds.tamarin.actions.OpenXrActionState.registerActions(OpenXrActionState.java:323)
        at com.onemillionworlds.tamarin.actions.OpenXrActionState.update(OpenXrActionState.java:899)
        at com.jme3.app.state.AppStateManager.update(AppStateManager.java:371)
        at com.jme3.app.SimpleApplication.update(SimpleApplication.java:258)
        at com.jme3.system.lwjgl.LwjglWindow.runLoop(LwjglWindow.java:628)
        at com.jme3.system.lwjgl.LwjglWindow.run(LwjglWindow.java:717)
        at java.base/java.lang.Thread.run(Thread.java:833)

Nov. 09, 2023 7:26:08 PM com.jme3.system.JmeSystemDelegate lambda$new$0
WARNUNG: JmeDialogsFactory implementation not found.
Uncaught exception thrown in Thread[jME3 Main,5,main]
OpenXrException: XR_ERROR_VALIDATION_FAILURE Context: Creating action set main (Main Actions) p:1

it opens a window that stays open until I put on the hmd.

Shame, just to see if this is purely a hand control problem could you comment out these lines

In Main

    //getStateManager().attach(new OpenXrActionState(manifest(), ActionSets.MAIN));
    //getStateManager().attach(new VRHandsAppState(handSpec()));

In MenuExampleState

    /*vrHands.getHandControls().forEach(h -> {
        functionRegistrations.add(h.attachPickLine(pickLine()));
        functionRegistrations.add(h.setPickMarkerContinuous(rootNodeDelegate));
        functionRegistrations.add(h.setClickAction_lemurSupport(ActionHandles.TRIGGER, rootNodeDelegate));
    });*/

That should turn off all the hand interaction and if the headset part is working it would show you a menu floating in VR space (Which obviously you won’t be able to interact with without the hands)

Also; what sort of runtime are you using? If you aren’t already could you try using steamVR?

that helped. I see floating text and it doesn’t crash.

Runtime: standard oculus rift (win10)
how would I ensure that steamVR is used ? add the testbed as a non steam game to steam, open the steamVR environment and run it from there?

if I readd the hand control lines and run the testbed via the SteamVR home it crashes again right away.
not sure yet how I’d best save console output running it like that.