Add initialization logic to OculusVR input
This commit is contained in:
parent
7313abf58d
commit
3ac7888dc0
@ -8,10 +8,24 @@ package com.jme3.input.vr;
|
|||||||
import com.jme3.app.VREnvironment;
|
import com.jme3.app.VREnvironment;
|
||||||
import com.jme3.math.*;
|
import com.jme3.math.*;
|
||||||
import com.jme3.renderer.Camera;
|
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 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 static org.lwjgl.ovr.OVRUtil.ovr_Detect;
|
||||||
|
|
||||||
|
import org.lwjgl.BufferUtils;
|
||||||
|
import org.lwjgl.PointerBuffer;
|
||||||
|
|
||||||
import org.lwjgl.ovr.*;
|
import org.lwjgl.ovr.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -26,6 +40,57 @@ public class OculusVR implements VRAPI {
|
|||||||
private final VREnvironment environment;
|
private final VREnvironment environment;
|
||||||
private boolean initialized;
|
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) {
|
public OculusVR(VREnvironment environment) {
|
||||||
this.environment = environment;
|
this.environment = environment;
|
||||||
}
|
}
|
||||||
@ -42,23 +107,117 @@ public class OculusVR implements VRAPI {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getDisplayFrequency() {
|
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
|
@Override
|
||||||
public boolean initialize() {
|
public boolean initialize() {
|
||||||
OVRDetectResult detect = OVRDetectResult.calloc();
|
OVRDetectResult detect = OVRDetectResult.calloc();
|
||||||
ovr_Detect(0, detect);
|
ovr_Detect(0, detect);
|
||||||
System.out.println("OVRDetectResult.IsOculusHMDConnected = " + detect.IsOculusHMDConnected());
|
boolean connected = detect.IsOculusHMDConnected();
|
||||||
System.out.println("OVRDetectResult.IsOculusServiceRunning = " + detect.IsOculusServiceRunning());
|
LOGGER.info("OVRDetectResult.IsOculusHMDConnected = " + connected);
|
||||||
|
LOGGER.info("OVRDetectResult.IsOculusServiceRunning = " + detect.IsOculusServiceRunning());
|
||||||
detect.free();
|
detect.free();
|
||||||
if (detect.IsOculusHMDConnected() == false) {
|
|
||||||
|
if (!connected) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
initialized = true;
|
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
|
@Override
|
||||||
@ -68,14 +227,18 @@ public class OculusVR implements VRAPI {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void destroy() {
|
public void destroy() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void reset() {
|
public void reset() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void getRenderSize(Vector2f store) {
|
public void getRenderSize(Vector2f store) {
|
||||||
|
store.x = resolutionW;
|
||||||
|
store.y = resolutionH;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -105,12 +268,12 @@ public class OculusVR implements VRAPI {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Matrix4f getHMDMatrixProjectionLeftEye(Camera cam) {
|
public Matrix4f getHMDMatrixProjectionLeftEye(Camera cam) {
|
||||||
throw new UnsupportedOperationException();
|
return matrixO2J(projections[ovrEye_Left], new Matrix4f());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Matrix4f getHMDMatrixProjectionRightEye(Camera cam) {
|
public Matrix4f getHMDMatrixProjectionRightEye(Camera cam) {
|
||||||
throw new UnsupportedOperationException();
|
return matrixO2J(projections[ovrEye_Right], new Matrix4f());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -130,7 +293,12 @@ public class OculusVR implements VRAPI {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Matrix4f getHMDMatrixPoseLeftEye() {
|
public Matrix4f getHMDMatrixPoseLeftEye() {
|
||||||
throw new UnsupportedOperationException();
|
return eyePoses[ovrEye_Left];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Matrix4f getHMDMatrixPoseRightEye() {
|
||||||
|
return eyePoses[ovrEye_Left];
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -138,9 +306,13 @@ public class OculusVR implements VRAPI {
|
|||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public boolean initVRCompositor(boolean set) {
|
||||||
public Matrix4f getHMDMatrixPoseRightEye() {
|
if (!set) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException("Cannot use LibOVR without compositor!");
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO move initialization code here from VRViewManagerOculus
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void printLatencyInfoToConsole(boolean set) {
|
public void printLatencyInfoToConsole(boolean set) {
|
||||||
@ -159,7 +331,62 @@ public class OculusVR implements VRAPI {
|
|||||||
throw new UnsupportedOperationException("Not yet implemented!");
|
throw new UnsupportedOperationException("Not yet implemented!");
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean initVRCompositor(boolean set) {
|
// UTILITIES
|
||||||
throw new UnsupportedOperationException("Not yet implemented!");
|
// 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: */
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user