浏览代码

OculusVR: Add basic camera positioning

Campbell Suter 8 年之前
父节点
当前提交
601ba1cfda

+ 4 - 4
jme3-vr/src/main/java/com/jme3/app/VRAppState.java

@@ -399,14 +399,14 @@ public class VRAppState extends AbstractAppState {
         
         //FIXME: check if this code is necessary.
         // Updates scene and gui states.
-        Iterator<Spatial> spatialIter = application.getViewPort().getScenes().iterator();
+        Iterator<Spatial> spatialIter = getLeftViewPort().getScenes().iterator();
         Spatial spatial = null;
         while(spatialIter.hasNext()){
         	spatial = spatialIter.next();
         	spatial.updateLogicalState(tpf);
         	spatial.updateGeometricState();
-        }        
-        
+        }
+
         if( environment.isInVR() == false || environment.getVRGUIManager().getPositioningMode() == VRGUIPositioningMode.MANUAL ) {
             // only update geometric state here if GUI is in manual mode, or not in VR
             // it will get updated automatically in the viewmanager update otherwise
@@ -419,7 +419,7 @@ public class VRAppState extends AbstractAppState {
         }
         
         // use the analog control on the first tracked controller to push around the mouse
-        environment.getVRMouseManager().updateAnalogAsMouse(0, null, null, null, tpf);
+        // environment.getVRMouseManager().updateAnalogAsMouse(0, null, null, null, tpf);
     }
 
     @Override

+ 29 - 0
jme3-vr/src/main/java/com/jme3/input/vr/OculusVR.java

@@ -87,6 +87,11 @@ public class OculusVR implements VRAPI {
      */
     private final Matrix4f[] eyePoses = new Matrix4f[2];
 
+    /**
+     * The eye poses, as used during rendering.
+     */
+    private final OVRPosef eyePosesPtr[] = new OVRPosef[2];
+
     // The size of the texture drawn onto the HMD
     private int textureW;
     private int textureH;
@@ -240,6 +245,22 @@ public class OculusVR implements VRAPI {
         OVRTrackingState hmdState = OVRTrackingState.malloc();
         ovr_GetTrackingState(session, ftiming, true, hmdState);
 
+        //get head pose
+        OVRPosef headPose = hmdState.HeadPose().ThePose();
+        hmdState.free();
+
+        //build view offsets struct
+        OVRPosef.Buffer hmdToEyeOffsets = OVRPosef.calloc(2);
+        hmdToEyeOffsets.put(0, eyeRenderDesc[ovrEye_Left].HmdToEyePose());
+        hmdToEyeOffsets.put(1, eyeRenderDesc[ovrEye_Right].HmdToEyePose());
+
+        //calculate eye poses
+        OVRPosef.Buffer outEyePoses = OVRPosef.create(2);
+        OVRUtil.ovr_CalcEyePoses(headPose, hmdToEyeOffsets, outEyePoses);
+        hmdToEyeOffsets.free();
+        eyePosesPtr[ovrEye_Left] = outEyePoses.get(0);
+        eyePosesPtr[ovrEye_Right] = outEyePoses.get(1);
+
         // TODO
     }
 
@@ -559,6 +580,14 @@ public class OculusVR implements VRAPI {
     public PointerBuffer getLayers() {
         return layers;
     }
+
+    public OVRLayerEyeFov getLayer0() {
+        return layer0;
+    }
+
+    public OVRPosef[] getEyePosesPtr() {
+        return eyePosesPtr;
+    }
 }
 
 /* vim: set ts=4 softtabstop=0 sw=4 expandtab: */

+ 76 - 7
jme3-vr/src/main/java/com/jme3/util/VRViewManagerOculus.java

@@ -35,7 +35,9 @@ import com.jme3.app.VREnvironment;
 import com.jme3.input.vr.OculusVR;
 import com.jme3.input.vr.VRAPI;
 import com.jme3.math.ColorRGBA;
+import com.jme3.math.Quaternion;
 import com.jme3.math.Vector2f;
+import com.jme3.math.Vector3f;
 import com.jme3.renderer.Camera;
 import com.jme3.renderer.ViewPort;
 import com.jme3.scene.Spatial;
@@ -45,11 +47,8 @@ import java.nio.IntBuffer;
 import java.util.Iterator;
 import java.util.logging.Logger;
 
-import org.lwjgl.PointerBuffer;
-
 import org.lwjgl.ovr.*;
 
-import static org.lwjgl.BufferUtils.*;
 import static org.lwjgl.ovr.OVR.*;
 import static org.lwjgl.ovr.OVRErrorCode.*;
 
@@ -65,6 +64,13 @@ public class VRViewManagerOculus extends AbstractVRViewManager {
     private final VREnvironment environment;
     private final OculusVR hardware;
 
+    // Copied from OSVR
+    //final & temp values for camera calculations
+    private final Vector3f finalPosition = new Vector3f();
+    private final Quaternion finalRotation = new Quaternion();
+    private final Vector3f hmdPos = new Vector3f();
+    private final Quaternion hmdRot = new Quaternion();
+
     public VRViewManagerOculus(VREnvironment environment) {
         this.environment = environment;
 
@@ -94,20 +100,83 @@ public class VRViewManagerOculus extends AbstractVRViewManager {
         // TODO
 
         hardware.updatePose();
+
+        // TODO deduplicate
+        if (environment != null) {
+            // grab the observer
+            Object obs = environment.getObserver();
+            Quaternion objRot;
+            Vector3f objPos;
+            if (obs instanceof Camera) {
+                objRot = ((Camera) obs).getRotation();
+                objPos = ((Camera) obs).getLocation();
+            } else {
+                objRot = ((Spatial) obs).getWorldRotation();
+                objPos = ((Spatial) obs).getWorldTranslation();
+            }
+            // grab the hardware handle
+            VRAPI dev = environment.getVRHardware();
+            if (dev != null) {
+                // update the HMD's position & orientation
+                dev.getPositionAndOrientation(hmdPos, hmdRot);
+                if (obs != null) {
+                    // update hmdPos based on obs rotation
+                    finalRotation.set(objRot);
+                    finalRotation.mult(hmdPos, hmdPos);
+                    finalRotation.multLocal(hmdRot);
+                }
+
+                finalizeCamera(dev.getHMDVectorPoseLeftEye(), objPos, leftCamera);
+                finalizeCamera(dev.getHMDVectorPoseRightEye(), objPos, rightCamera);
+            } else {
+                leftCamera.setFrame(objPos, objRot);
+                rightCamera.setFrame(objPos, objRot);
+            }
+
+            if (environment.hasTraditionalGUIOverlay()) {
+                // update the mouse?
+                environment.getVRMouseManager().update(tpf);
+
+                // update GUI position?
+                if (environment.getVRGUIManager().wantsReposition || environment.getVRGUIManager().getPositioningMode() != VRGUIPositioningMode.MANUAL) {
+                    environment.getVRGUIManager().positionGuiNow(tpf);
+                    environment.getVRGUIManager().updateGuiQuadGeometricState();
+                }
+            }
+        } else {
+            throw new IllegalStateException("This VR view manager is not attached to any VR environment.");
+        }
+    }
+
+    /**
+     * Place the camera within the scene.
+     *
+     * @param eyePos      the eye position.
+     * @param obsPosition the observer position.
+     * @param cam         the camera to place.
+     */
+    private void finalizeCamera(Vector3f eyePos, Vector3f obsPosition, Camera cam) {
+        finalRotation.mult(eyePos, finalPosition);
+        finalPosition.addLocal(hmdPos);
+        if (obsPosition != null) {
+            finalPosition.addLocal(obsPosition);
+        }
+        finalPosition.y += getHeightAdjustment();
+        cam.setFrame(finalPosition, finalRotation);
     }
 
     @Override
     public void render() {
         for (int eye = 0; eye < 2; eye++) {
-            // TODO add eyePoses
-//            OVRPosef eyePose = eyePoses[eye];
-//            layer0.RenderPose(eye, eyePose);
+            // TODO do we need this? Don't we set the camera positions ourselves?
+            OVRPosef eyePose = hardware.getEyePosesPtr()[eye];
+            hardware.getLayer0().RenderPose(eye, eyePose);
 
             IntBuffer currentIndexB = BufferUtils.createIntBuffer(1);
             ovr_GetTextureSwapChainCurrentIndex(session(), hardware.getChain(), currentIndexB);
             int index = currentIndexB.get();
 
-            (eye == 0 ? leftViewPort : rightViewPort).setOutputFrameBuffer(hardware.getFramebuffers()[index]);
+            (eye == ovrEye_Left ? leftViewPort : rightViewPort).setOutputFrameBuffer(hardware.getFramebuffers()[index]);
         }
 
         // Now the game will render into the buffers given to us by LibOVR