Explorar el Código

Add initialization logic to OculusVR input

Campbell Suter hace 8 años
padre
commit
3ac7888dc0
Se han modificado 1 ficheros con 240 adiciones y 13 borrados
  1. 240 13
      jme3-vr/src/main/java/com/jme3/input/vr/OculusVR.java

+ 240 - 13
jme3-vr/src/main/java/com/jme3/input/vr/OculusVR.java

@@ -8,10 +8,24 @@ package com.jme3.input.vr;
 import com.jme3.app.VREnvironment;
 import com.jme3.math.*;
 import com.jme3.renderer.Camera;
+import com.jme3.util.VRUtil;
+
+import java.nio.IntBuffer;
+import java.util.Locale;
+import java.util.concurrent.TimeUnit;
+import java.util.logging.Level;
 import java.util.logging.Logger;
 
+import static org.lwjgl.opengl.GL11.*;
+import static org.lwjgl.ovr.OVR.*;
+
+import static org.lwjgl.ovr.OVRErrorCode.*;
+import static org.lwjgl.system.MemoryUtil.*;
 import static org.lwjgl.ovr.OVRUtil.ovr_Detect;
 
+import org.lwjgl.BufferUtils;
+import org.lwjgl.PointerBuffer;
+
 import org.lwjgl.ovr.*;
 
 /**
@@ -26,6 +40,57 @@ public class OculusVR implements VRAPI {
     private final VREnvironment environment;
     private boolean initialized;
 
+    /**
+     * Pointer to the HMD object
+     */
+    private long session;
+
+    /**
+     * Information about the VR session (should the app quit, is
+     * it visible or is the universal menu open, etc)
+     */
+    private OVRSessionStatus sessionStatus;
+
+    /**
+     * HMD information, such as product name and manufacturer.
+     */
+    private OVRHmdDesc hmdDesc;
+
+    /**
+     * The horizontal resolution of the HMD
+     */
+    private int resolutionW;
+
+    /**
+     * The vertical resolution of the HMD
+     */
+    private int resolutionH;
+
+    /**
+     * Field-of-view data for each eye (how many degrees from the
+     * center can the user see).
+     */
+    private final OVRFovPort fovPorts[] = new OVRFovPort[2];
+
+    /**
+     * Data about each eye to be rendered - in particular, the
+     * offset from the center of the HMD to the eye.
+     */
+    private final OVREyeRenderDesc eyeRenderDesc[] = new OVREyeRenderDesc[2];
+
+    /**
+     * Store the projections for each eye, so we don't have to malloc
+     * and recalculate them each frame.
+     */
+    private final OVRMatrix4f[] projections = new OVRMatrix4f[2];
+
+    /**
+     * Store the poses for each eye.
+     *
+     * @see #getHMDMatrixPoseLeftEye()
+     */
+    private final Matrix4f[] eyePoses = new Matrix4f[2];
+
     public OculusVR(VREnvironment environment) {
         this.environment = environment;
     }
@@ -42,23 +107,117 @@ public class OculusVR implements VRAPI {
 
     @Override
     public int getDisplayFrequency() {
-        throw new UnsupportedOperationException();
+        // TODO find correct frequency. I'm not sure
+        // if LibOVR has a way to do that, though.
+        return 60;
     }
 
     @Override
     public boolean initialize() {
         OVRDetectResult detect = OVRDetectResult.calloc();
         ovr_Detect(0, detect);
-        System.out.println("OVRDetectResult.IsOculusHMDConnected = " + detect.IsOculusHMDConnected());
-        System.out.println("OVRDetectResult.IsOculusServiceRunning = " + detect.IsOculusServiceRunning());
+        boolean connected = detect.IsOculusHMDConnected();
+        LOGGER.info("OVRDetectResult.IsOculusHMDConnected = " + connected);
+        LOGGER.info("OVRDetectResult.IsOculusServiceRunning = " + detect.IsOculusServiceRunning());
         detect.free();
-        if (detect.IsOculusHMDConnected() == false) {
+
+        if (!connected) {
             return false;
         }
 
         initialized = true;
 
-        throw new UnsupportedOperationException("Not yet implemented!");
+        // step 1 - hmd init
+        System.out.println("step 1 - hmd init");
+        OVRLogCallback callback = new OVRLogCallback() {
+            @Override
+            public void invoke(long userData, int level, long message) {
+                System.out.println("LibOVR [" + userData + "] [" + level + "] " + memASCII(message));
+            }
+        };
+        OVRInitParams initParams = OVRInitParams.calloc();
+        initParams.LogCallback(callback);
+        //initParams.Flags(ovrInit_Debug);
+        if (ovr_Initialize(initParams) != ovrSuccess) {
+            System.out.println("init failed");
+        }
+        System.out.println("OVR SDK " + ovr_GetVersionString());
+        initParams.free();
+
+        // step 2 - hmd create
+        System.out.println("step 2 - hmd create");
+        PointerBuffer pHmd = memAllocPointer(1);
+        OVRGraphicsLuid luid = OVRGraphicsLuid.calloc();
+        if (ovr_Create(pHmd, luid) != ovrSuccess) {
+            System.out.println("create failed, try debug");
+            //debug headset is now enabled via the Oculus Configuration util . tools -> Service -> Configure
+            return false;
+        }
+        session = pHmd.get(0);
+        memFree(pHmd);
+        luid.free();
+        sessionStatus = OVRSessionStatus.calloc();
+
+        // step 3 - hmdDesc queries
+        System.out.println("step 3 - hmdDesc queries");
+        hmdDesc = OVRHmdDesc.malloc();
+        ovr_GetHmdDesc(session, hmdDesc);
+        System.out.println("ovr_GetHmdDesc = " + hmdDesc.ManufacturerString() + " " + hmdDesc.ProductNameString() + " " + hmdDesc.SerialNumberString() + " " + hmdDesc.Type());
+        if (hmdDesc.Type() == ovrHmd_None) {
+            System.out.println("missing init");
+            return false;
+        }
+
+        resolutionW = hmdDesc.Resolution().w();
+        resolutionH = hmdDesc.Resolution().h();
+        System.out.println("resolution W=" + resolutionW + ", H=" + resolutionH);
+        if (resolutionW == 0) {
+            System.out.println("Huh - width=0");
+            return false;
+        }
+
+        // FOV
+        for (int eye = 0; eye < 2; eye++) {
+            fovPorts[eye] = hmdDesc.DefaultEyeFov(eye);
+            System.out.println("eye " + eye + " = " + fovPorts[eye].UpTan() + ", " + fovPorts[eye].DownTan() + ", " + fovPorts[eye].LeftTan() + ", " + fovPorts[eye].RightTan());
+        }
+        // TODO what does this do? I think it might be the height of the player, for correct floor heights?
+        // playerEyePos = new Vector3f(0.0f, -ovr_GetFloat(session, OVR_KEY_EYE_HEIGHT, 1.65f), 0.0f);
+
+        // step 4 - tracking - no longer needed as of 0.8.0.0
+
+        // step 5 - projections
+        System.out.println("step 5 - projections");
+        for (int eye = 0; eye < 2; eye++) {
+            projections[eye] = OVRMatrix4f.malloc();
+            OVRUtil.ovrMatrix4f_Projection(fovPorts[eye], 0.5f, 500f, OVRUtil.ovrProjection_None, projections[eye]);
+            //1.3 was right handed, now none flag
+        }
+
+        // step 6 - render desc
+        System.out.println("step 6 - render desc");
+        for (int eye = 0; eye < 2; eye++) {
+            eyeRenderDesc[eye] = OVREyeRenderDesc.malloc();
+            ovr_GetRenderDesc(session, eye, fovPorts[eye], eyeRenderDesc[eye]);
+
+            // Changed from an offset to a pose, so there is also a rotation.
+            System.out.println("ipd eye " + eye + " = " + eyeRenderDesc[eye].HmdToEyePose().Position().x());
+
+            OVRPosef pose = eyeRenderDesc[eye].HmdToEyePose();
+
+            Matrix4f jPose = new Matrix4f();
+            jPose.setTranslation(vecO2J(pose.Position(), new Vector3f()));
+            jPose.setRotationQuaternion(quatO2J(pose.Orientation(), new Quaternion()));
+
+            eyePoses[eye] = jPose;
+        }
+
+        // step 7 - recenter
+        System.out.println("step 7 - recenter");
+        ovr_RecenterTrackingOrigin(session);
+
+        // throw new UnsupportedOperationException("Not yet implemented!");
+        return true;
     }
 
     @Override
@@ -68,14 +227,18 @@ public class OculusVR implements VRAPI {
 
     @Override
     public void destroy() {
+        throw new UnsupportedOperationException();
     }
 
     @Override
     public void reset() {
+        throw new UnsupportedOperationException();
     }
 
     @Override
     public void getRenderSize(Vector2f store) {
+        store.x = resolutionW;
+        store.y = resolutionH;
     }
 
     @Override
@@ -105,12 +268,12 @@ public class OculusVR implements VRAPI {
 
     @Override
     public Matrix4f getHMDMatrixProjectionLeftEye(Camera cam) {
-        throw new UnsupportedOperationException();
+        return matrixO2J(projections[ovrEye_Left], new Matrix4f());
     }
 
     @Override
     public Matrix4f getHMDMatrixProjectionRightEye(Camera cam) {
-        throw new UnsupportedOperationException();
+        return matrixO2J(projections[ovrEye_Right], new Matrix4f());
     }
 
     @Override
@@ -130,19 +293,28 @@ public class OculusVR implements VRAPI {
 
     @Override
     public Matrix4f getHMDMatrixPoseLeftEye() {
-        throw new UnsupportedOperationException();
+        return eyePoses[ovrEye_Left];
     }
 
     @Override
-    public HmdType getType() {
-        throw new UnsupportedOperationException();
+    public Matrix4f getHMDMatrixPoseRightEye() {
+        return eyePoses[ovrEye_Left];
     }
 
     @Override
-    public Matrix4f getHMDMatrixPoseRightEye() {
+    public HmdType getType() {
         throw new UnsupportedOperationException();
     }
 
+    public boolean initVRCompositor(boolean set) {
+        if (!set) {
+            throw new UnsupportedOperationException("Cannot use LibOVR without compositor!");
+        }
+
+        // TODO move initialization code here from VRViewManagerOculus
+        return true;
+    }
+
     public void printLatencyInfoToConsole(boolean set) {
         throw new UnsupportedOperationException("Not yet implemented!");
     }
@@ -159,7 +331,62 @@ public class OculusVR implements VRAPI {
         throw new UnsupportedOperationException("Not yet implemented!");
     }
 
-    public boolean initVRCompositor(boolean set) {
-        throw new UnsupportedOperationException("Not yet implemented!");
+    // UTILITIES
+    // TODO move to helper class
+
+    /**
+     * Copy the values from a LibOVR matrix into a jMonkeyEngine matrix.
+     *
+     * @param from The matrix to copy from.
+     * @param to   The matrix to copy to.
+     * @return The {@code to} argument.
+     */
+    public static Matrix4f matrixO2J(OVRMatrix4f from, Matrix4f to) {
+        for (int x = 0; x < 4; x++) {
+            for (int y = 0; y < 4; y++) {
+                float val = from.M(x + y * 4); // TODO verify this
+                to.set(x, y, val);
+            }
+        }
+
+        return to;
+    }
+
+    /**
+     * Copy the values from a LibOVR quaternion into a jMonkeyEngine quaternion.
+     *
+     * @param from The quaternion to copy from.
+     * @param to   The quaternion to copy to.
+     * @return The {@code to} argument.
+     */
+    public static Quaternion quatO2J(OVRQuatf from, Quaternion to) {
+        to.set(
+                from.x(),
+                from.y(),
+                from.z(),
+                from.w()
+        );
+
+        return to;
+    }
+
+    /**
+     * Copy the values from a LibOVR vector into a jMonkeyEngine vector.
+     *
+     * @param from The vector to copy from.
+     * @param to   The vector to copy to.
+     * @return The {@code to} argument.
+     */
+    public static Vector3f vecO2J(OVRVector3f from, Vector3f to) {
+        to.set(
+                from.x(),
+                from.y(),
+                from.z()
+        );
+
+        return to;
     }
 }
+
+/* vim: set ts=4 softtabstop=0 sw=4 expandtab: */
+