Official VR module

Yes, VRApplication should not be used. As asked by the JMonkey contributors, I’'ve now switched to VRAppState. I will remove the VRApplication on next commit.

1 Like

@seinturier thanks for the great work.

If i can access the JMonkey wiki, i will provide a simple tutorial for using VR capabilities within JMonkey environment.

You are welcome to add your PR to JME wiki here : GitHub - jMonkeyEngine/wiki: The official wiki for jMonkeyEngine.
I can merge it for you.

And it would be cool if you can also add the test example to jme3-examples

1 Like

Hello,

I’m aware that there is a jme3-example module but my problem is that this project has a dependency to jm3-lwjgl and i need jme3-lwjgl3 in order the use the VR. So it’s difficult to integrate a VR example within the jme3-exampls module.

1 Like

Question: Is it possible to change the size of the mirrored window?

1 Like

Hello Rickard, Yes it is possible but i will commit some changes today in order to refactor and separate the VR specific stuff and the JMonkey one. Il will also make settings update and you will be able to set the mirror windows witdh, height and position from the AppSettings.

3 Likes

Hello to all,

I’ve committed the new version of the jme3-vr module and I’ve made a new pull request to the master branch.

This new version now provide a VREnvironment class that gather all VR related stuff. This class can be instantiated and initialized before any call to JMonkey and it is so possible now to know if the system can handle VR rendering before starting JMonkey application and attaching the VRAppState.

I’ve also refactored some classes so the old example should not work anymore. Here is a new version of the VR sample that deal with the new VREnvironment class:
package sample;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.logging.Filter;
import java.util.logging.Formatter;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;

import com.jme3.app.Application;
import com.jme3.app.SimpleApplication;
import com.jme3.app.VRAppState;
import com.jme3.app.VRConstants;
import com.jme3.app.VREnvironment;
import com.jme3.app.state.AppState;
import com.jme3.asset.plugins.FileLocator;
import com.jme3.input.InputManager;
import com.jme3.input.KeyInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.input.vr.VRInputType;
import com.jme3.input.vr.openvr.OpenVR;
import com.jme3.material.Material;
import com.jme3.math.FastMath;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.post.CartoonSSAO;
import com.jme3.post.FilterPostProcessor;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.Spatial.CullHint;
import com.jme3.scene.shape.Box;
import com.jme3.system.AppSettings;
import com.jme3.texture.Texture;
import com.jme3.texture.Texture.MagFilter;
import com.jme3.texture.Texture.MinFilter;
import com.jme3.ui.Picture;
import com.jme3.util.SkyFactory;
import com.jme3.util.VRGUIPositioningMode;

/**
 * A Jmonkey sample that show the use of VR rendering with a JMonkey Application.
 * @author Julien Seinturier
 */
public class VRAppStateSample extends SimpleApplication {

	private static final Logger logger = Logger.getLogger(VRAppStateSample.class.getName());
    
    // general objects for scene management
    Node boxes = new Node("");
    Spatial observer;
    boolean moveForward, moveBackwards, rotateLeft, rotateRight;
    Material mat;
    Node mainScene;
    Geometry leftHand, rightHand;

    private float distance  = 100f;
    private float prod      = 0f;
    private float placeRate = 0f;
    
    VRAppState vrAppState = null;
    
    public VRAppStateSample(AppState... initialStates) {
        super(initialStates);
        
        vrAppState = getStateManager().getState(VRAppState.class);
    }
    
    
    @Override
    public void simpleInitApp() {    
    	
    	logger.info("Updating asset manager with "+System.getProperty("user.dir"));
    	getAssetManager().registerLocator(System.getProperty("user.dir")+File.separator+"assets", FileLocator.class);
    	
        mainScene = new Node("scene");
        observer = new Node("observer");
        
        Spatial sky = SkyFactory.createSky(getAssetManager(), "Textures/Sky/Bright/spheremap.png", SkyFactory.EnvMapType.EquirectMap);
        rootNode.attachChild(sky);
        
        Geometry box = new Geometry("", new Box(5,5,5));
        mat = new Material(getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
        Texture noise = getAssetManager().loadTexture("Textures/noise.png");
        noise.setMagFilter(MagFilter.Nearest);
        noise.setMinFilter(MinFilter.Trilinear);
        noise.setAnisotropicFilter(16);
        mat.setTexture("ColorMap", noise);
                     
        // make the floor according to the size of our play area
        Geometry floor = new Geometry("floor", new Box(1f, 1f, 1f));
        
        Vector2f playArea = vrAppState.getVREnvironment().getVRBounds().getPlaySize();
        if( playArea == null ) {
            // no play area, use default size & height
            floor.setLocalScale(2f, 0.5f, 2f);
            floor.move(0f, -1.5f, 0f);
        } else {
            // cube model is actually 2x as big, cut it down to proper playArea size with * 0.5
            floor.setLocalScale(playArea.x * 0.5f, 0.5f, playArea.y * 0.5f);
            floor.move(0f, -0.5f, 0f);
        }
        floor.setMaterial(mat);
        rootNode.attachChild(floor);
        
        // hand wands
        leftHand = (Geometry)getAssetManager().loadModel("Models/vive_controller.j3o");
        rightHand = leftHand.clone();
        Material handMat = new Material(getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
        handMat.setTexture("ColorMap", getAssetManager().loadTexture("Textures/vive_controller.png"));
        leftHand.setMaterial(handMat);
        rightHand.setMaterial(handMat);
        rootNode.attachChild(rightHand);
        rootNode.attachChild(leftHand);
        
        // gui element
        Vector2f guiCanvasSize = vrAppState.getVRGUIManager().getCanvasSize();
        Picture test = new Picture("testpic");
        test.setImage(getAssetManager(), "Textures/crosshair.png", true);
        test.setWidth(192f);
        test.setHeight(128f);
        test.setPosition(guiCanvasSize.x * 0.5f - 192f * 0.5f, guiCanvasSize.y * 0.5f - 128f * 0.5f);
        guiNode.attachChild(test);
        
        
        // test any positioning mode here (defaults to AUTO_CAM_ALL)
        vrAppState.getVRGUIManager().setPositioningMode(VRGUIPositioningMode.AUTO_OBSERVER_ALL);
        vrAppState.getVRGUIManager().setGuiScale(0.4f);
        
        box.setMaterial(mat);
        
        Geometry box2 = box.clone();
        box2.move(15, 0, 0);
        box2.setMaterial(mat);
        Geometry box3 = box.clone();
        box3.move(-15, 0, 0);
        box3.setMaterial(mat);        
        
        boxes.attachChild(box);
        boxes.attachChild(box2);
        boxes.attachChild(box3);
        rootNode.attachChild(boxes);
        
        observer.setLocalTranslation(new Vector3f(0.0f, 0.0f, 0.0f));
        
        vrAppState.setObserver(observer);
        mainScene.attachChild(observer);
        rootNode.attachChild(mainScene);
        
        addAllBoxes();

        initInputs();
        
        // use magic VR mouse cusor (same usage as non-VR mouse cursor)
        getInputManager().setCursorVisible(true);
      
        // filter test (can be added here like this)
        // but we are going to save them for the F key during runtime
        /*
        CartoonSSAO cartfilt = new CartoonSSAO();
        FilterPostProcessor fpp = new FilterPostProcessor(assetManager);
        fpp.addFilter(cartfilt);
        viewPort.addProcessor(fpp);        
        */
    }


     private void initInputs() {
        InputManager inputManager = getInputManager();
        inputManager.addMapping("toggle", new KeyTrigger(KeyInput.KEY_SPACE));
        inputManager.addMapping("incShift", new KeyTrigger(KeyInput.KEY_Q));
        inputManager.addMapping("decShift", new KeyTrigger(KeyInput.KEY_E));
        inputManager.addMapping("forward", new KeyTrigger(KeyInput.KEY_W));
        inputManager.addMapping("back", new KeyTrigger(KeyInput.KEY_S));
        inputManager.addMapping("left", new KeyTrigger(KeyInput.KEY_A));
        inputManager.addMapping("right", new KeyTrigger(KeyInput.KEY_D));
        inputManager.addMapping("filter", new KeyTrigger(KeyInput.KEY_F));
        inputManager.addMapping("dumpImages", new KeyTrigger(KeyInput.KEY_I));
        inputManager.addMapping("exit", new KeyTrigger(KeyInput.KEY_ESCAPE));
        
        ActionListener acl = new ActionListener() {

            public void onAction(String name, boolean keyPressed, float tpf) {
                if(name.equals("incShift") && keyPressed){
                	vrAppState.getVRGUIManager().adjustGuiDistance(-0.1f);
                }else if(name.equals("decShift") && keyPressed){
                	vrAppState.getVRGUIManager().adjustGuiDistance(0.1f);
                }else if(name.equals("filter") && keyPressed){
                    // adding filters in realtime
                    CartoonSSAO cartfilt = new CartoonSSAO(vrAppState.isInstanceRendering());
                    FilterPostProcessor fpp = new FilterPostProcessor(getAssetManager());
                    fpp.addFilter(cartfilt);
                    getViewPort().addProcessor(fpp);
                    // filters added to main viewport during runtime,
                    // move them into VR processing
                    // (won't do anything if not in VR mode)
                    vrAppState.moveScreenProcessingToVR();
                }
                if( name.equals("toggle") ) {
                	vrAppState.getVRGUIManager().positionGui();
                }                
                if(name.equals("forward")){
                    if(keyPressed){
                        moveForward = true;
                    } else {
                        moveForward = false;
                    }
                } else if(name.equals("back")){
                    if(keyPressed){
                        moveBackwards = true;
                    } else {
                        moveBackwards = false;
                    }
                } else if( name.equals("dumpImages") ) {
                    ((OpenVR)vrAppState.getVRHardware()).getCompositor().CompositorDumpImages.apply();
                }else if(name.equals("left")){
                    if(keyPressed){
                        rotateLeft = true;
                    } else {
                        rotateLeft = false;
                    }
                } else if(name.equals("right")){
                    if(keyPressed){
                        rotateRight = true;
                    } else {
                        rotateRight = false;
                    }
                } else if( name.equals("exit") ) {
                    stop(true);
                    System.exit(0);
                }
                
                
            }
        };
        inputManager.addListener(acl, "forward");
        inputManager.addListener(acl, "back");
        inputManager.addListener(acl, "left");
        inputManager.addListener(acl, "right");
        inputManager.addListener(acl, "toggle");
        inputManager.addListener(acl, "incShift");
        inputManager.addListener(acl, "decShift");
        inputManager.addListener(acl, "filter");
        inputManager.addListener(acl, "dumpImages");
        inputManager.addListener(acl, "exit");
    }
     
     @Override
     public void simpleUpdate(float tpf){

         //FPS test
         /*tpfAdder += tpf;
         tpfCount++;
         if( tpfCount == 60 ) {
             System.out.println("FPS: " + Float.toString(1f / (tpfAdder / tpfCount)));
             tpfCount = 0;
             tpfAdder = 0f;
         }*/
         
         prod+=tpf;
         distance = 100f * FastMath.sin(prod);
         boxes.setLocalTranslation(0, 0, 200f+ distance);
         
         if(moveForward){
             observer.move(vrAppState.getFinalObserverRotation().getRotationColumn(2).mult(tpf*8f));
         }
         if(moveBackwards){
             observer.move(vrAppState.getFinalObserverRotation().getRotationColumn(2).mult(-tpf*8f));
         }
         if(rotateLeft){
             observer.rotate(0, 0.75f*tpf, 0);
         }
         if(rotateRight){
             observer.rotate(0, -0.75f*tpf, 0);
         }
         
         handleWandInput(0, leftHand);
         handleWandInput(1, rightHand);
         if( placeRate > 0f ) placeRate -= tpf;
     }
     
     private void handleWandInput(int index, Geometry geo) {
    	 
         Quaternion q = vrAppState.getVRinput().getFinalObserverRotation(index);
         Vector3f v = vrAppState.getVRinput().getFinalObserverPosition(index);
         if( q != null && v != null ) {
             geo.setCullHint(CullHint.Dynamic); // make sure we see it
             geo.setLocalTranslation(v);
             geo.setLocalRotation(q);
             // place boxes when holding down trigger
             if( vrAppState.getVRinput().getAxis(index, VRInputType.ViveTriggerAxis).x >= 1f &&
                 placeRate <= 0f ) {
                 placeRate = 0.5f;
                 addBox(v, q, 0.1f);
                 vrAppState.getVRinput().triggerHapticPulse(index, 0.1f);
             }
             // print out all of the known information about the controllers here
             /*for(int i=0;i<VRInput.getRawControllerState(index).rAxis.length;i++) {
                 VRControllerAxis_t cs = VRInput.getRawControllerState(index).rAxis[i];
                 System.out.println("Controller#" + Integer.toString(index) + ", Axis#" + Integer.toString(i) + " X: " + Float.toString(cs.x) + ", Y: " + Float.toString(cs.y));
             }
             System.out.println("Button press: " + Long.toString(VRInput.getRawControllerState(index).ulButtonPressed.longValue()) + ", touch: " + Long.toString(VRInput.getRawControllerState(index).ulButtonTouched.longValue()));
             */
         } else {
             geo.setCullHint(CullHint.Always); // hide it             
         }
     }
     
     private void addAllBoxes() {
        float distance = 8;
        for (int x = 0; x < 35; x++) {
            float cos = FastMath.cos(x * FastMath.PI / 16f) * distance;
            float sin = FastMath.sin(x * FastMath.PI / 16f) * distance;
            Vector3f loc = new Vector3f(cos, 0, sin);
            addBox(loc, null, 1f);
            loc = new Vector3f(0, cos, sin);
            addBox(loc, null, 1f);
        }

    }

    private void addBox(Vector3f location, Quaternion rot, float scale) {
        Box b = new Box(0.3f, 0.3f, 0.3f);

        Geometry leftQuad = new Geometry("Box", b);
        if( rot != null ) {
            leftQuad.setLocalRotation(rot);
        } else {
            leftQuad.rotate(0.5f, 0f, 0f);
        }
        leftQuad.setLocalScale(scale);
        leftQuad.setMaterial(mat);
        leftQuad.setLocalTranslation(location);
        mainScene.attachChild(leftQuad);
    }
    
    private static void initLog(){
    	// Set the logger to display config messages.
    	Logger log = Logger.getLogger("");
    	log.setLevel(Level.FINE);
    	
    	// Disable Nifty µGUI logs
    	Logger.getLogger("de.lessvoid.nifty").setLevel(Level.SEVERE); 
    	Logger.getLogger("NiftyInputEventHandlingLog").setLevel(Level.SEVERE); 
        
        Filter filter = new Filter(){
			public boolean isLoggable(LogRecord record) {
				return true;
			}
        };
      
        Formatter formatter = new Formatter(){

          private final String lineSeparator = System.getProperty("line.separator");
          
          SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd-HH:mm:ss");
          
          @Override
          public String format(LogRecord record) {
            
            if (record != null){
              
              String simpleClassName = record.getSourceClassName();
              
              if (simpleClassName != null){
                int index = simpleClassName.lastIndexOf(".");
                if ((index > -1)&&(index < (simpleClassName.length() - 1))){
                  simpleClassName = simpleClassName.substring(index+1);
                }
              } else {
                simpleClassName = "Unknow,";
              }
              
              String level =  "";
              if (record.getLevel().equals(Level.FINEST)){
                level = "FINEST ";
              } else if (record.getLevel().equals(Level.FINER)){
                level = "FINER  ";
              } else if (record.getLevel().equals(Level.FINE)){
                level = "FINE   ";
              } else if (record.getLevel().equals(Level.CONFIG)){
                level = "CONFIG ";
              } else if (record.getLevel().equals(Level.INFO)){
                level = "INFO   ";
              } else if (record.getLevel().equals(Level.WARNING)){
                level = "WARNING";
              } else if (record.getLevel().equals(Level.SEVERE)){
                level = "SEVERE ";
              } else {
                level = "???????";
              }
              
              // Use record parameters
              String message = record.getMessage();
              if (record.getParameters() != null){
                for(int i = 0; i < record.getParameters().length; i++){
                  message = message.replace("{"+i+"}", ""+record.getParameters()[i]);
                }
              }
              
              if (record.getThrown() == null){
                return "("+sdf.format(new Date(record.getMillis()))+") "+level+" ["+simpleClassName+"] ["+record.getSourceMethodName()+"] "+message+lineSeparator;
              } else {
                String str = "("+sdf.format(new Date(record.getMillis()))+") "+level+" ["+simpleClassName+"] ["+record.getSourceMethodName()+"] caused by "+message+lineSeparator;
                
                StackTraceElement[] elements = record.getThrown().getStackTrace();
                for(int i = 0; i < elements.length; i++){
                  str += "("+sdf.format(new Date(record.getMillis()))+") "+level+" ["+simpleClassName+"] ["+record.getSourceMethodName()+"] at "+elements[i]+lineSeparator;
                }
                return "("+sdf.format(new Date(record.getMillis()))+") "+level+" ["+record.getSourceClassName()+"] ["+record.getSourceMethodName()+"] "+message+lineSeparator+str;
              }
            } else {
              return null;
            }
        }};  

    	// If the init is forced from a previous configuration, we remove the older handlers.
    	if (log != null){
          if (log.getHandlers() != null){
            for(int i = log.getHandlers().length - 1; i >= 0; i--){
              log.getHandlers()[i].setFilter(filter);
              log.getHandlers()[i].setFormatter(formatter);
              log.getHandlers()[i].setLevel(Level.CONFIG);
            }
          }
        }
    }
    
    /**
     * Create a {@link VRAppState VR app state} and use a Simple application that use it.<br>
     * The recommended procedure is:<br>
     * <ul>
     * <li>Create some {@link AppSettings AppSettings} with VR related parameters.
     * <li>Instanciate the {@link VRAppState VRAppState} attached to the settings.
     * <li>Instanciate your {@link Application Application}.
     * <li>Attach the settings to the application.
     * <li>Start the application.
     * </ul>
     * @param args not used
     */
    public static void main(String[] args){
    	
    	// Init the log to display all the configuration informations.
    	// This is not needed within final application.
    	initLog();
    	
    	// Prepare settings for VR rendering. 
    	// It is recommended to share same settings between the VR app state and the application.
    	AppSettings settings = new AppSettings(true);
    	
    	settings.put(VRConstants.SETTING_VRAPI, VRConstants.SETTING_VRAPI_OPENVR_VALUE); // The VR api to use (need to be present on the system)
    	settings.put(VRConstants.SETTING_DISABLE_VR, false);          // Enable VR
    	settings.put(VRConstants.SETTING_ENABLE_MIRROR_WINDOW, true); // Enable Mirror rendering oh the screen (disable to be faster)
    	settings.put(VRConstants.SETTING_VR_FORCE, false);            // Not forcing VR rendering if no VR system is found.
    	settings.put(VRConstants.SETTING_GUI_CURVED_SURFACE, true);   // Curve the mesh that is displaying the GUI
    	settings.put(VRConstants.SETTING_FLIP_EYES, false);           // Is the HMD eyes have to be inverted.
    	settings.put(VRConstants.SETTING_NO_GUI, false);              // enable gui.
    	settings.put(VRConstants.SETTING_GUI_OVERDRAW, true);         // show gui even if it is behind things.
    	
    	settings.put(VRConstants.SETTING_DEFAULT_FOV, 108f);          // The default ield Of View (FOV)
    	settings.put(VRConstants.SETTING_DEFAULT_ASPECT_RATIO, 1f);   // The default aspect ratio.
    	
    	settings.setRenderer(AppSettings.LWJGL_OPENGL3); // Setting the renderer. OpenGL 3 is needed if you're using Instance Rendering.
    	
        // The VR Environment.
        // This object is the interface between the JMonkey world (Application, AppState, ...) and the VR specific stuff.
    	VREnvironment environment = new VREnvironment(settings);
    	environment.initialize();
    	
    	// Checking if the VR environment is well initialized 
    	// (access to the underlying VR system is effective, VR devices are detected).
    	if (environment.isInitialized()){
        	
        	// Initialise VR AppState with the VR environment.
            VRAppState vrAppState = new VRAppState(settings, environment);
        	
        	// Create the sample application with the VRAppState attached.
            // There is no constraint on the Application type.
            SimpleApplication test = new VRAppStateSample(vrAppState);
            test.setShowSettings(false);

            // Sharing settings between app state and application is recommended.
            test.setSettings(settings);   
            
            // Starting the application.
            test.start();
    	} else {
    		logger.severe("Cannot start VR sample application as VR system is not initialized (see log for details)");
    	}
    }
}
7 Likes

Hey.
I’ve tried updating to the latest.
There’s a crash I can’t get past:

java.lang.NullPointerException
	at com.jme3.renderer.Camera.clone(Camera.java:270)
	at com.jme3.util.VRViewManagerOpenVR.setupMirrorBuffers(VRViewManagerOpenVR.java:539)
	at com.jme3.util.VRViewManagerOpenVR.setupVRScene(VRViewManagerOpenVR.java:389)
	at com.jme3.util.VRViewManagerOpenVR.initialize(VRViewManagerOpenVR.java:263)
	at com.jme3.app.VRAppState.initialize(VRAppState.java:470)

It seems the camera isn’t initialized, so when it tries to clone the location there’s an NPE. I haven’t been able to determine if it’s a race condition or not. I guess AppStates won’t ever be initialized before the application?

This happens when “VREnableMirrorWindow” and “SwapBuffers” are true. However, I haven’t been able to turn either of them off by changing settings…

Edit: As expected, commenting out “setupMirrorBuffers(environment.getCamera(), leftEyeTexture, false);” gets me past this, but doesn’t show anything in the mirror view

1 Like

No… but eventually, Application won’t initialize anything either (only app states will). Something to keep in mind as you cast about for solutions.

1 Like

Which branch do you recommend building from? I built
master and no jme3-vr.jar ended up in my dist folder.

1 Like

After adding jme3-vr-3.2.0-SNAPSHOT.jar from the jme3-vr/build/libs folder, the sample code posted above complains about missing VREnvironment and VRGUIPositioningMode.

Help? Thanks!

1 Like

Forgot to mention, I built master pulled from GitHub - jseinturier/jmonkeyengine: A complete 3D game development suite written purely in Java.. I had even worse luck with GitHub - jMonkeyEngine/jmonkeyengine: A complete 3D game development suite written purely in Java..

1 Like

Hello.

I’m actually away from my computer and i can’t check your problem.

The last version of jme-vr has been pulled to jmonkey master branch a week ago. However, in order to build the module, you have to enable java 1.8 compatibility and jme3-lwjgl3.

I’ll give you more information by next week.

2 Likes

Hello.

It is curious as the classes you mention are visible within the sources of the jmonkey master branch. You can even unzip the jar to check the classes inside.

Be also sure to use jme3-lwjgl3 and java 1.8

1 Like

Not sure whether that check works. I had the same problem and added an include manually, even though I run Java 8.

From settings.gradle:

if (JavaVersion.current().isJava8Compatible()) {
    include 'jme3-lwjgl3'
    include 'jme3-vr'
}

@sduensin remove the if statement, or add “include ‘jme3-vr’” outside of it in your jmonkeyengine/settings.gradle and it should build

2 Likes

Yes i made this correction myself… I think that is a bug of graddle that can’t determine the running java version properly.

1 Like

Thanks for the follow-up. After pulling master from the main JME repo I was able to make it work…

I had to build JME, then add the VR JAR manually. I also had to download and add the JNA JARs.

Very excited to play with this. :slight_smile:

1 Like

While playing with the sample code above, I can’t seem to get SETTING_DISABLE_VR or SETTING_VR_FORCE to allow me to run the code without my headset. Is this a possibility? I’d like to be able to run with and without VR.

Thanks again!

1 Like

LWJGL v3.1.2 Brings OpenVR Bindings, Tiny OpenEXR

2 Likes

Hello,

I know that LWJGL now handles OpenVR bindings. I will integrate the LWJGL binding as an underlying VR wrapper for the next release of JMonkey. However, my aims its to provide a VR module that is as independant as possible from the native VR systems (as it was aimed with LWJGL/JOGL for JMonkey). So the integration of the LWGJL / OpenVR wrapping should not affect the VR AppState and the other high level VR functionalities.

5 Likes

I’ve been able to get your VRAppStateSample.java to run in Linux (Ubuntu 16.04 NVidia GeForce GTX 950) using OSVR on an HDK 2 using the extended mode json config file. I had to remove the places where you explicitly prevent 64 bit Linux from running. It looks great, and the headset works, but for some reason the keyboard input stops working. Do you have any idea why this might be the case? Does OSVR try to grab the keyboard before JME3 gets to it? It also seems to create 2 windows, a JMonkeyEngine window and a second window called OSVR0. I have to alt-tab to set focus to the new window before it starts rendering, it initially displays a blank window with nothing in it until I alt-tab specifically into the OSVR0 window. Regular JME3 windows don’t exhibit this behavior. Anyone have any ideas why? I’ve pasted the debug output from the console below:

(2017.10.15-00:18:56) CONFIG [VREnvironment] [initialize] Initializing VR environment.
(2017.10.15-00:18:56) CONFIG [VREnvironment] [initialize] Creating OSVR wrapper [SUCCESS]
(2017.10.15-00:18:56) CONFIG [OSVR] [initialize] Initialize OSVR system.
e[1mOct 15 00:18:57.105 info [OSVR]: Logging for /usr/lib/jvm/java-8-oracle/bin/java
e[00me[1mOct 15 00:18:57.105 info [OSVR: j]: OSVR client context initialized for j
e[00me[1mOct 15 00:18:57.125 info [OSVR: j]: Got connection to main OSVR server
e[00me[1mOct 15 00:18:57.458 info [OSVR: j]: Connected 0 of 0 unconnected paths successfully
e[00me[1mOct 15 00:18:57.459 info [OSVR: j]: Connection process took 334ms: have connection to server, have path tree
e[00m(2017.10.15-00:18:57) CONFIG [OSVRInput] [init] Initialize OSVR input.
e[1mOct 15 00:18:57.464 info [OSVR]: /home/silicon-admin/osvr_linux/OSVR-Core/src/osvr/Common/ClientInterface.cpp:38: Interface initialized for /me/hands/left
e[00me[1mOct 15 00:18:57.464 info [OSVR: j]: Could not resolve source for /me/hands/left
e[00me[1mOct 15 00:18:57.464 info [OSVR]: /home/silicon-admin/osvr_linux/OSVR-Core/src/osvr/Common/ClientInterface.cpp:38: Interface initialized for /me/hands/right
e[00me[1mOct 15 00:18:57.464 info [OSVR: j]: Could not resolve source for /me/hands/right
e[00me[1mOct 15 00:18:57.467 info [OSVR]: /home/silicon-admin/osvr_linux/OSVR-Core/src/osvr/Common/ClientInterface.cpp:38: Interface initialized for /controller/left/0
e[00me[1mOct 15 00:18:57.467 info [OSVR: j]: Could not resolve source for /controller/left/0
e[00me[1mOct 15 00:18:57.469 info [OSVR]: /home/silicon-admin/osvr_linux/OSVR-Core/src/osvr/Common/ClientInterface.cpp:38: Interface initialized for /controller/left/1
e[00me[1mOct 15 00:18:57.469 info [OSVR: j]: Could not resolve source for /controller/left/1
e[00me[1mOct 15 00:18:57.469 info [OSVR]: /home/silicon-admin/osvr_linux/OSVR-Core/src/osvr/Common/ClientInterface.cpp:38: Interface initialized for /controller/left/2
e[00me[1mOct 15 00:18:57.469 info [OSVR: j]: Could not resolve source for /controller/left/2
e[00me[1mOct 15 00:18:57.469 info [OSVR]: /home/silicon-admin/osvr_linux/OSVR-Core/src/osvr/Common/ClientInterface.cpp:38: Interface initialized for /controller/left/3
e[00me[1mOct 15 00:18:57.469 info [OSVR: j]: Could not resolve source for /controller/left/3
e[00me[1mOct 15 00:18:57.469 info [OSVR]: /home/silicon-admin/osvr_linux/OSVR-Core/src/osvr/Common/ClientInterface.cpp:38: Interface initialized for /controller/left/4
e[00me[1mOct 15 00:18:57.469 info [OSVR: j]: Could not resolve source for /controller/left/4
e[00me[1mOct 15 00:18:57.469 info [OSVR]: /home/silicon-admin/osvr_linux/OSVR-Core/src/osvr/Common/ClientInterface.cpp:38: Interface initialized for /controller/right/0
e[00me[1mOct 15 00:18:57.469 info [OSVR: j]: Could not resolve source for /controller/right/0
e[00me[1mOct 15 00:18:57.469 info [OSVR]: /home/silicon-admin/osvr_linux/OSVR-Core/src/osvr/Common/ClientInterface.cpp:38: Interface initialized for /controller/right/1
e[00me[1mOct 15 00:18:57.469 info [OSVR: j]: Could not resolve source for /controller/right/1
e[00me[1mOct 15 00:18:57.469 info [OSVR]: /home/silicon-admin/osvr_linux/OSVR-Core/src/osvr/Common/ClientInterface.cpp:38: Interface initialized for /controller/right/2
e[00me[1mOct 15 00:18:57.469 info [OSVR: j]: Could not resolve source for /controller/right/2
e[00me[1mOct 15 00:18:57.469 info [OSVR]: /home/silicon-admin/osvr_linux/OSVR-Core/src/osvr/Common/ClientInterface.cpp:38: Interface initialized for /controller/right/3
e[00me[1mOct 15 00:18:57.469 info [OSVR: j]: Could not resolve source for /controller/right/3
e[00me[1mOct 15 00:18:57.469 info [OSVR]: /home/silicon-admin/osvr_linux/OSVR-Core/src/osvr/Common/ClientInterface.cpp:38: Interface initialized for /controller/right/4
e[00me[1mOct 15 00:18:57.469 info [OSVR: j]: Could not resolve source for /controller/right/4
e[00me[1mOct 15 00:18:57.469 info [OSVR]: /home/silicon-admin/osvr_linux/OSVR-Core/src/osvr/Common/ClientInterface.cpp:38: Interface initialized for /controller/left/bumper
e[00me[1mOct 15 00:18:57.470 info [OSVR: j]: Could not resolve source for /controller/left/bumper
e[00me[1mOct 15 00:18:57.470 info [OSVR]: /home/silicon-admin/osvr_linux/OSVR-Core/src/osvr/Common/ClientInterface.cpp:38: Interface initialized for /controller/right/bumper
e[00me[1mOct 15 00:18:57.470 info [OSVR: j]: Could not resolve source for /controller/right/bumper
e[00me[1mOct 15 00:18:57.470 info [OSVR]: /home/silicon-admin/osvr_linux/OSVR-Core/src/osvr/Common/ClientInterface.cpp:38: Interface initialized for /controller/left/joystick/button
e[00me[1mOct 15 00:18:57.470 info [OSVR: j]: Could not resolve source for /controller/left/joystick/button
e[00me[1mOct 15 00:18:57.470 info [OSVR]: /home/silicon-admin/osvr_linux/OSVR-Core/src/osvr/Common/ClientInterface.cpp:38: Interface initialized for /controller/right/joystick/button
e[00me[1mOct 15 00:18:57.470 info [OSVR: j]: Could not resolve source for /controller/right/joystick/button
e[00me[1mOct 15 00:18:57.470 info [OSVR]: /home/silicon-admin/osvr_linux/OSVR-Core/src/osvr/Common/ClientInterface.cpp:38: Interface initialized for /controller/left/trigger
e[00me[1mOct 15 00:18:57.470 info [OSVR: j]: Could not resolve source for /controller/left/trigger
e[00me[1mOct 15 00:18:57.470 info [OSVR]: /home/silicon-admin/osvr_linux/OSVR-Core/src/osvr/Common/ClientInterface.cpp:38: Interface initialized for /controller/right/trigger
e[00me[1mOct 15 00:18:57.470 info [OSVR: j]: Could not resolve source for /controller/right/trigger
e[00me[1mOct 15 00:18:57.471 info [OSVR]: /home/silicon-admin/osvr_linux/OSVR-Core/src/osvr/Common/ClientInterface.cpp:38: Interface initialized for /controller/left/joystick/x
e[00me[1mOct 15 00:18:57.471 info [OSVR: j]: Could not resolve source for /controller/left/joystick/x
e[00me[1mOct 15 00:18:57.471 info [OSVR]: /home/silicon-admin/osvr_linux/OSVR-Core/src/osvr/Common/ClientInterface.cpp:38: Interface initialized for /controller/left/joystick/y
e[00me[1mOct 15 00:18:57.471 info [OSVR: j]: Could not resolve source for /controller/left/joystick/y
e[00me[1mOct 15 00:18:57.471 info [OSVR]: /home/silicon-admin/osvr_linux/OSVR-Core/src/osvr/Common/ClientInterface.cpp:38: Interface initialized for /controller/right/joystick/x
e[00me[1mOct 15 00:18:57.471 info [OSVR: j]: Could not resolve source for /controller/right/joystick/x
e[00me[1mOct 15 00:18:57.471 info [OSVR]: /home/silicon-admin/osvr_linux/OSVR-Core/src/osvr/Common/ClientInterface.cpp:38: Interface initialized for /controller/right/joystick/y
e[00me[1mOct 15 00:18:57.471 info [OSVR: j]: Could not resolve source for /controller/right/joystick/y
e[00me[1mOct 15 00:18:57.479 info [OSVR]: /home/silicon-admin/osvr_linux/OSVR-Core/src/osvr/Common/ClientInterface.cpp:38: Interface initialized for /me/head
e[00me[1mOct 15 00:18:57.542 info [OSVR]: /home/silicon-admin/osvr_linux/OSVR-Core/src/osvr/Client/TrackerRemoteFactory.cpp:93: Constructed a TrackerHandler for com_osvr_Multiserver/OSVRHackerDevKit0@localhost:3883 sensor 0
e[00me[1mOct 15 00:18:57.542 info [OSVR: j]: Successfully produced handler for /me/head
e[00me[1mOct 15 00:18:57.542 info [OSVR]: /home/silicon-admin/osvr_linux/OSVR-Core/src/osvr/Common/ClientInterface.cpp:38: Interface initialized for /me/head
e[00me[1mOct 15 00:18:57.542 info [OSVR]: /home/silicon-admin/osvr_linux/OSVR-Core/src/osvr/Common/ClientInterface.cpp:38: Interface initialized for /me/head
e[00me[1mOct 15 00:18:57.542 info [OSVR]: /home/silicon-admin/osvr_linux/OSVR-Core/src/osvr/Client/DisplayConfig.cpp:195: Display:
e[00me[1mOct 15 00:18:57.542 info [OSVR]: /home/silicon-admin/osvr_linux/OSVR-Core/src/osvr/ClientKit/DisplayC.cpp:47: Created an OSVR_DisplayConfigObject!
e[00mWaiting for the display to fully start up, including receiving initial pose update…
OK, display startup status is good!
(2017.10.15-00:18:57) CONFIG [VREnvironment] [initialize] VR native wrapper initialized [SUCCESS]
(2017.10.15-00:18:57) CONFIG [VRAppState] [stateAttached] Using given settings.
(2017.10.15-00:18:57) SEVERE [com.jme3.app.VRAppState] [stateAttached] null
(2017.10.15-00:18:57) SEVERE [VRAppState] [stateAttached] caused by null
(2017.10.15-00:18:57) SEVERE [VRAppState] [stateAttached] at com.jme3.app.VRAppState.stateAttached(VRAppState.java:527)
(2017.10.15-00:18:57) SEVERE [VRAppState] [stateAttached] at com.jme3.app.state.AppStateManager.attach(AppStateManager.java:133)
(2017.10.15-00:18:57) SEVERE [VRAppState] [stateAttached] at com.jme3.app.LegacyApplication.(LegacyApplication.java:118)
(2017.10.15-00:18:57) SEVERE [VRAppState] [stateAttached] at com.jme3.app.SimpleApplication.(SimpleApplication.java:104)
(2017.10.15-00:18:57) SEVERE [VRAppState] [stateAttached] at sample.VRAppStateSample.(VRAppStateSample.java:70)
(2017.10.15-00:18:57) SEVERE [VRAppState] [stateAttached] at sample.VRAppStateSample.main(VRAppStateSample.java:510)
(2017.10.15-00:18:57) CONFIG [VRAppState] [stateAttached] Updated underlying application settings.
(2017.10.15-00:18:57) INFO [JmeDesktopSystem] [initialize] Running on jMonkeyEngine 3.2-16

  • Branch: master
  • Git Hash: 556e3de
  • Build Date: 2017-10-03
    (2017.10.15-00:18:58) INFO [LwjglContext] [printContextInitInfo] LWJGL 3.1.2 build 29 context running on thread main
  • Graphics Adapter: GLFW 3.3.0 X11 GLX EGL clock_gettime /dev/js shared
    (2017.10.15-00:18:58) INFO [GLRenderer] [loadCapabilitiesCommon] OpenGL Renderer Information
  • Vendor: NVIDIA Corporation
  • Renderer: GeForce GTX 950/PCIe/SSE2
  • OpenGL Version: 3.2.0 NVIDIA 375.66
  • GLSL Version: 1.50 NVIDIA via Cg compiler
  • Profile: Core
    (2017.10.15-00:18:58) WARNING [AssetConfig] [loadText] Cannot find loader com.jme3.scene.plugins.blender.BlenderModelLoader
    (2017.10.15-00:18:58) INFO [ALAudioRenderer] [initOpenAL] Audio Renderer Information
  • Device: OpenAL Soft
  • Vendor: OpenAL Community
  • Renderer: OpenAL Soft
  • Version: 1.1 ALSOFT 1.17.2
  • 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_SOFTX_device_clock ALC_SOFT_HRTF ALC_SOFT_loopback ALC_SOFTX_output_limiter ALC_SOFT_pause_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_block_alignment AL_SOFT_deferred_updates AL_SOFT_direct_channels AL_SOFT_gain_clamp_ex AL_SOFT_loop_points AL_SOFT_MSADPCM AL_SOFT_source_latency AL_SOFT_source_length AL_SOFT_source_resampler AL_SOFT_source_spatialize
    (2017.10.15-00:18:58) INFO [ALAudioRenderer] [initOpenAL] Audio effect extension version: 1.0
    (2017.10.15-00:18:58) INFO [ALAudioRenderer] [initOpenAL] Audio max auxiliary sends: 2
    (2017.10.15-00:18:58) INFO [VRAppStateSample] [simpleInitApp] Updating asset manager with /home/silicon-admin/workspace3/jme3test
    (2017.10.15-00:18:58) WARNING [Material] [checkSetParam] Material parameter being set: Texture with type Texture2D doesn’'t match definition types TextureCubeMap
    e[1mOct 15 00:18:58.698 info [OSVR]: /home/silicon-admin/osvr_linux/OSVR-Core/src/osvr/Common/ClientInterface.cpp:38: Interface initialized for /me/head
    e[00me[1mOct 15 00:18:58.698 info [OSVR]: /home/silicon-admin/osvr_linux/OSVR-Core/src/osvr/Common/ClientInterface.cpp:38: Interface initialized for /me/head
    e[00me[1mOct 15 00:18:58.698 info [OSVR]: /home/silicon-admin/osvr_linux/OSVR-Core/src/osvr/Common/ClientInterface.cpp:38: Interface initialized for /me/head
    e[00me[1mOct 15 00:18:58.698 info [OSVR]: /home/silicon-admin/osvr_linux/OSVR-Core/src/osvr/Client/DisplayConfig.cpp:195: Display:
    e[00me[1mOct 15 00:18:58.698 info [OSVR]: /home/silicon-admin/osvr_linux/OSVR-Core/src/osvr/ClientKit/DisplayC.cpp:47: Created an OSVR_DisplayConfigObject!
    e[00me[31me[1mOct 15 00:18:58.899 error [createRenderManager]: Got Display info from server (ignore earlier errors that occured while we were waiting to connect)
    e[00mOSVRDisplayConfiguration::parse(): WARNING: Your display descriptor is outdated (using an outdated schema) and may not work with all applications. Please check with your vendor or the OSVR community to get an updated one matching the most recent JSON Schema for display descriptors.
    OSVRDisplayConfiguration::parse(): Using mono point sample distortion.
    OSVRDisplayConfiguration::parse(): Processing JSON data into mono point samples description structure.
    OSVRDisplayConfiguration::parse(): Initial processing complete. Loaded mono point samples data with 1581 and 1581 samples per eye, respectively.
    OSVRDisplayConfiguration::parse(): Using distortion method “mono_point_samples_built_in”: “OSVR_HDK_20_V1”
    e[1mOct 15 00:18:58.929 info [createRenderManager]: Display descriptor reports vendor as OSVR
    e[00me[1mOct 15 00:18:58.929 info [createRenderManager]: Adding direct mode candidate PNPID SEN described as Some OSVR HDK units with early firmware/EDID data
    e[00me[1mOct 15 00:18:58.929 info [createRenderManager]: Adding direct mode candidate PNPID SVR described as Most OSVR HDK units
    e[00me[1mOct 15 00:18:58.929 info [createRenderManager]: Adding direct mode candidate PNPID AUO described as Some OSVR HDK2 firmware versions
    e[00me[1mOct 15 00:18:58.930 info [OSVR: com.osvr.renderManager]: OSVR client context initialized for com.osvr.renderManager
    e[00me[1mOct 15 00:18:58.970 info [OSVR: com.osvr.renderManager]: Got connection to main OSVR server
    e[00me[1mOct 15 00:18:59.303 info [OSVR: com.osvr.renderManager]: Connected 0 of 0 unconnected paths successfully
    e[00me[1mOct 15 00:18:59.304 info [OSVR: com.osvr.renderManager]: Connection process took 334ms: have connection to server, have path tree
    e[00me[1mOct 15 00:18:59.305 info [OSVR]: /home/silicon-admin/osvr_linux/OSVR-Core/src/osvr/Common/ClientInterface.cpp:38: Interface initialized for /me/head
    e[00me[1mOct 15 00:18:59.389 info [OSVR]: /home/silicon-admin/osvr_linux/OSVR-Core/src/osvr/Client/TrackerRemoteFactory.cpp:93: Constructed a TrackerHandler for com_osvr_Multiserver/OSVRHackerDevKit0@localhost:3883 sensor 0
    e[00me[1mOct 15 00:18:59.389 info [OSVR: com.osvr.renderManager]: Successfully produced handler for /me/head
    e[00me[1mOct 15 00:18:59.389 info [OSVR]: /home/silicon-admin/osvr_linux/OSVR-Core/src/osvr/Common/ClientInterface.cpp:38: Interface initialized for /me/head
    e[00mContext sharing success!
1 Like