From 601ba1cfda0314e44862da389ce86e83cc2ecbaa Mon Sep 17 00:00:00 2001 From: Campbell Suter Date: Fri, 29 Sep 2017 09:13:57 +1300 Subject: [PATCH] OculusVR: Add basic camera positioning --- .../main/java/com/jme3/app/VRAppState.java | 8 +- .../main/java/com/jme3/input/vr/OculusVR.java | 29 +++++++ .../com/jme3/util/VRViewManagerOculus.java | 83 +++++++++++++++++-- 3 files changed, 109 insertions(+), 11 deletions(-) diff --git a/jme3-vr/src/main/java/com/jme3/app/VRAppState.java b/jme3-vr/src/main/java/com/jme3/app/VRAppState.java index 39df3884b..806f2cc42 100644 --- a/jme3-vr/src/main/java/com/jme3/app/VRAppState.java +++ b/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 spatialIter = application.getViewPort().getScenes().iterator(); + Iterator 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 diff --git a/jme3-vr/src/main/java/com/jme3/input/vr/OculusVR.java b/jme3-vr/src/main/java/com/jme3/input/vr/OculusVR.java index c10a23d89..3ba52e481 100644 --- a/jme3-vr/src/main/java/com/jme3/input/vr/OculusVR.java +++ b/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: */ diff --git a/jme3-vr/src/main/java/com/jme3/util/VRViewManagerOculus.java b/jme3-vr/src/main/java/com/jme3/util/VRViewManagerOculus.java index fb442be32..64fffa988 100644 --- a/jme3-vr/src/main/java/com/jme3/util/VRViewManagerOculus.java +++ b/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