Baseline working openvr code

This commit is contained in:
James Urquhart 2016-04-17 22:19:42 +01:00
parent e239d106f5
commit ba91478fad
23 changed files with 1463 additions and 457 deletions

View file

@ -27,6 +27,7 @@
#include "core/stringTable.h"
#include "platform/platformInput.h"
#include "math/mQuat.h"
#include "math/mAngAxis.h"
MODULE_BEGIN( InputEventManager )
@ -546,3 +547,21 @@ void InputEventManager::buildInputEvent(U32 deviceType, U32 deviceInst, InputEve
newEvent.postToSignal(Input::smInputEvent);
}
void InputEventManager::buildInputEvent(U32 deviceType, U32 deviceInst, InputEventType objType, InputObjectInstances objInst, InputActionType action, AngAxisF& aValue)
{
InputEventInfo newEvent;
newEvent.deviceType = deviceType;
newEvent.deviceInst = deviceInst;
newEvent.objType = objType;
newEvent.objInst = objInst;
newEvent.action = action;
newEvent.fValue = aValue.axis.x;
newEvent.fValue2 = aValue.axis.y;
newEvent.fValue3 = aValue.axis.z;
newEvent.fValue4 = aValue.angle;
newEvent.postToSignal(Input::smInputEvent);
}

View file

@ -504,6 +504,9 @@ public:
/// Build an input event based on a QuatF
void buildInputEvent(U32 deviceType, U32 deviceInst, InputEventType objType, InputObjectInstances objInst, InputActionType action, QuatF& qValue);
/// Build an input event based on a AngAxisF
void buildInputEvent(U32 deviceType, U32 deviceInst, InputEventType objType, InputObjectInstances objInst, InputActionType action, AngAxisF& qValue);
protected:
U32 mNextDeviceTypeCode;
U32 mNextDeviceCode;

View file

@ -62,7 +62,7 @@ MODULE_END;
// OculusVRDevice
//-----------------------------------------------------------------------------
bool OculusVRDevice::smEnableDevice = true;
bool OculusVRDevice::smEnableDevice = false;
bool OculusVRDevice::smSimulateHMD = true;
@ -318,17 +318,6 @@ void OculusVRDevice::getEyeOffsets(Point3F *dest) const
hmd->getEyeOffsets(dest);
}
bool OculusVRDevice::providesFovPorts() const
{
if(!mHMDDevices.size())
return false;
const OculusVRHMDDevice* hmd = getHMDDevice(mActiveDeviceId);
if(!hmd)
return Point3F::Zero;
return true;
}
void OculusVRDevice::getFovPorts(FovPort *out) const
{
@ -562,6 +551,20 @@ GameConnection* OculusVRDevice::getCurrentConnection()
//-----------------------------------------------------------------------------
GFXTexHandle OculusVRDevice::getPreviewTexture()
{
if (!mHMDDevices.size())
return NULL;
OculusVRHMDDevice* hmd = getHMDDevice(mActiveDeviceId);
if (!hmd)
return NULL;
return hmd->getPreviewTexture();
}
//-----------------------------------------------------------------------------
DefineEngineFunction(isOculusVRDeviceActive, bool, (),,
"@brief Used to determine if the Oculus VR input device is active\n\n"

View file

@ -115,8 +115,8 @@ public:
virtual bool providesFrameEyePose() const;
virtual void getFrameEyePose(DisplayPose *outPose, U32 eyeId) const;
virtual bool providesEyeOffsets() const;
virtual bool providesFovPorts() const { return true; }
virtual void getEyeOffsets(Point3F *dest) const;
virtual bool providesFovPorts() const;
virtual void getFovPorts(FovPort *out) const;
virtual bool providesProjectionOffset() const;
virtual const Point2F& getProjectionOffset() const;
@ -154,6 +154,8 @@ public:
virtual void setCurrentConnection(GameConnection *connection);
virtual GameConnection* getCurrentConnection();
GFXTexHandle getPreviewTexture();
bool _handleDeviceEvent( GFXDevice::GFXDeviceEventType evt );
public:

View file

@ -43,7 +43,6 @@
#include "OVR_CAPI_GL.h"
#define OCULUS_USE_GL
#endif
extern GFXTextureObject *gLastStereoTexture;
struct OculusTexture
{
@ -317,6 +316,14 @@ void OculusVRHMDDevice::dismissWarning()
//ovr_DismissHSWDisplay(mDevice);
}
GFXTexHandle OculusVRHMDDevice::getPreviewTexture()
{
if (!mIsValid || !mDevice)
return NULL;
return mDebugMirrorTextureHandle;
}
bool OculusVRHMDDevice::setupTargets()
{
// Create eye render buffers
@ -381,9 +388,6 @@ bool OculusVRHMDDevice::setupTargets()
mEyeRT[1] = mStereoRT;
mEyeViewport[1] = RectI(Point2I(mRenderLayer.Viewport[1].Pos.x, mRenderLayer.Viewport[1].Pos.y), Point2I(mRenderLayer.Viewport[1].Size.w, mRenderLayer.Viewport[1].Size.h));
gLastStereoTexture = NULL;
GFXD3D11Device* device = static_cast<GFXD3D11Device*>(GFX);
D3D11_TEXTURE2D_DESC dsDesc;
@ -453,7 +457,6 @@ bool OculusVRHMDDevice::setupTargets()
}
mDebugMirrorTextureHandle = object;
gLastStereoTexture = mDebugMirrorTextureHandle;
}
else
{
@ -673,10 +676,11 @@ void OculusVRHMDDevice::getFrameEyePose(DisplayPose *outPose, U32 eyeId) const
OVR::Quatf orientation = pose.Orientation;
const OVR::Vector3f position = pose.Position;
EulerF rotEuler;
OculusVRUtil::convertRotation(orientation, rotEuler);
MatrixF torqueMat(1);
OVR::Matrix4f mat(orientation);
OculusVRUtil::convertRotation(mat.M, torqueMat);
outPose->orientation = rotEuler;
outPose->orientation = QuatF(torqueMat);
outPose->position = Point3F(-position.x, position.z, -position.y);
}

View file

@ -185,6 +185,8 @@ public:
virtual void setCurrentConnection(GameConnection *connection) { mConnection = connection; }
virtual GameConnection* getCurrentConnection() { return mConnection; }
GFXTexHandle getPreviewTexture();
String dumpMetrics();
// Stereo RT

View file

@ -26,6 +26,7 @@
#include "platform/platformInput.h"
#include "console/simBase.h"
#include "console/engineAPI.h"
#include "math/mAngAxis.h"
#include "OVR_CAPI_0_8_0.h"
U32 OculusVRSensorDevice::OVR_SENSORROT[OculusVRConstants::MaxSensors] = {0};
@ -184,7 +185,8 @@ bool OculusVRSensorDevice::process(U32 deviceType, bool generateRotAsAngAxis, bo
{
if(generateRotAsAngAxis)
{
INPUTMGR->buildInputEvent(deviceType, OculusVRConstants::DefaultOVRBase, SI_ROT, OVR_SENSORROT[mActionCodeIndex], SI_MOVE, currentBuffer->mRotQuat);
AngAxisF axisAA(currentBuffer->mRotQuat);
INPUTMGR->buildInputEvent(deviceType, OculusVRConstants::DefaultOVRBase, SI_ROT, OVR_SENSORROT[mActionCodeIndex], SI_MOVE, axisAA);
}
if(generateRotAsEuler)

View file

@ -44,10 +44,7 @@ void convertRotation(const F32 inRotMat[4][4], MatrixF& outRotation)
void convertRotation(OVR::Quatf& inRotation, EulerF& outRotation)
{
F32 yaw, pitch, roll;
inRotation.GetEulerAngles<OVR::Axis_Y, OVR::Axis_X, OVR::Axis_Z>(&yaw, &pitch, &roll);
outRotation.x = -pitch;
outRotation.y = roll;
outRotation.z = -yaw;
inRotation.GetEulerAngles<OVR::Axis_X, OVR::Axis_Z, OVR::Axis_Y, OVR::Rotate_CW, OVR::Handed_R>(&outRotation.x, &outRotation.y, &outRotation.z);
}
void calculateAxisRotation(const MatrixF& inRotation, const F32& maxAxisRadius, Point2F& outRotation)

View file

@ -0,0 +1,886 @@
#include "platform/input/openVR/openVRProvider.h"
#include "platform/platformInput.h"
#include "core/module.h"
#include "console/engineAPI.h"
#include "T3D/gameBase/gameConnection.h"
#include "gui/core/guiCanvas.h"
#include "postFx/postEffectCommon.h"
#include "gfx/D3D11/gfxD3D11Device.h"
#include "gfx/D3D11/gfxD3D11TextureObject.h"
#include "gfx/D3D11/gfxD3D11EnumTranslate.h"
#include "gfx/gfxStringEnumTranslate.h"
/*
#include "gfx/gl/gfxGLDevice.h"
#include "gfx/gl/gfxGLTextureObject.h"
#include "gfx/gl/gfxGLEnumTranslate.h"
*/
#include "platform/input/oculusVR/oculusVRUtil.h"
U32 OpenVRProvider::OVR_SENSORROT[vr::k_unMaxTrackedDeviceCount] = { 0 };
U32 OpenVRProvider::OVR_SENSORROTANG[vr::k_unMaxTrackedDeviceCount] = { 0 };
U32 OpenVRProvider::OVR_SENSORVELOCITY[vr::k_unMaxTrackedDeviceCount] = { 0 };
U32 OpenVRProvider::OVR_SENSORANGVEL[vr::k_unMaxTrackedDeviceCount] = { 0 };
U32 OpenVRProvider::OVR_SENSORMAGNETOMETER[vr::k_unMaxTrackedDeviceCount] = { 0 };
U32 OpenVRProvider::OVR_SENSORPOSITION[vr::k_unMaxTrackedDeviceCount] = { 0 };
U32 OpenVRProvider::OVR_BUTTONPRESSED[vr::k_unMaxTrackedDeviceCount];
U32 OpenVRProvider::OVR_BUTTONTOUCHED[vr::k_unMaxTrackedDeviceCount];
U32 OpenVRProvider::OVR_AXISNONE[vr::k_unMaxTrackedDeviceCount] = { 0 };
U32 OpenVRProvider::OVR_AXISTRACKPAD[vr::k_unMaxTrackedDeviceCount] = { 0 };
U32 OpenVRProvider::OVR_AXISJOYSTICK[vr::k_unMaxTrackedDeviceCount] = { 0 };
U32 OpenVRProvider::OVR_AXISTRIGGER[vr::k_unMaxTrackedDeviceCount] = { 0 };
static String GetTrackedDeviceString(vr::IVRSystem *pHmd, vr::TrackedDeviceIndex_t unDevice, vr::TrackedDeviceProperty prop, vr::TrackedPropertyError *peError = NULL)
{
uint32_t unRequiredBufferLen = pHmd->GetStringTrackedDeviceProperty(unDevice, prop, NULL, 0, peError);
if (unRequiredBufferLen == 0)
return "";
char *pchBuffer = new char[unRequiredBufferLen];
unRequiredBufferLen = pHmd->GetStringTrackedDeviceProperty(unDevice, prop, pchBuffer, unRequiredBufferLen, peError);
String sResult = pchBuffer;
delete[] pchBuffer;
return sResult;
}
static MatrixF ConvertSteamVRAffineMatrixToMatrixFPlain(const vr::HmdMatrix34_t &mat)
{
MatrixF outMat(1);
outMat.setColumn(0, Point4F(mat.m[0][0], mat.m[1][0], mat.m[2][0], 0.0));
outMat.setColumn(1, Point4F(mat.m[0][1], mat.m[1][1], mat.m[2][1], 0.0));
outMat.setColumn(2, Point4F(mat.m[0][2], mat.m[1][2], mat.m[2][2], 0.0));
outMat.setColumn(3, Point4F(mat.m[0][3], mat.m[1][3], mat.m[2][3], 1.0f)); // pos
return outMat;
}
MODULE_BEGIN(OpenVRProvider)
MODULE_INIT_AFTER(InputEventManager)
MODULE_SHUTDOWN_BEFORE(InputEventManager)
MODULE_INIT
{
OpenVRProvider::staticInit();
ManagedSingleton< OpenVRProvider >::createSingleton();
}
MODULE_SHUTDOWN
{
ManagedSingleton< OpenVRProvider >::deleteSingleton();
}
MODULE_END;
bool OpenVRRenderState::setupRenderTargets(U32 mode)
{
if (!mHMD)
return false;
U32 sizeX, sizeY;
Point2I newRTSize;
mHMD->GetRecommendedRenderTargetSize(&sizeX, &sizeY);
mEyeViewport[0] = RectI(Point2I(0, 0), Point2I(sizeX, sizeY));
mEyeViewport[1] = RectI(Point2I(0, 0), Point2I(sizeX, sizeY));
newRTSize.x = sizeX;
newRTSize.y = sizeY;
GFXTexHandle stereoTexture;
stereoTexture.set(newRTSize.x, newRTSize.y, GFXFormatR8G8B8A8, &VRTextureProfile, "OpenVR Stereo RT Color");
mStereoRenderTextures[0] = mStereoRenderTextures[1] = stereoTexture;
GFXTexHandle stereoDepthTexture;
stereoDepthTexture.set(newRTSize.x, newRTSize.y, GFXFormatD24S8, &VRDepthProfile, "OpenVR Depth");
mStereoDepthTextures[0] = mStereoDepthTextures[1] = stereoDepthTexture;
mStereoRT = GFX->allocRenderToTextureTarget();
mStereoRT->attachTexture(GFXTextureTarget::Color0, stereoTexture);
mStereoRT->attachTexture(GFXTextureTarget::DepthStencil, stereoDepthTexture);
mEyeRT[0] = mEyeRT[1] = mStereoRT;
return true;
}
void OpenVRRenderState::setupDistortion()
{
if (!mHMD)
return;
U16 m_iLensGridSegmentCountH = 43;
U16 m_iLensGridSegmentCountV = 43;
float w = (float)(1.0 / float(m_iLensGridSegmentCountH - 1));
float h = (float)(1.0 / float(m_iLensGridSegmentCountV - 1));
float u, v = 0;
Vector<GFXVertexPTTT> vVerts(0);
GFXVertexPTTT *vert;
vVerts.reserve((m_iLensGridSegmentCountV * m_iLensGridSegmentCountH) * 2);
mDistortionVerts.set(GFX, (m_iLensGridSegmentCountV * m_iLensGridSegmentCountH) * 2, GFXBufferTypeStatic);
vert = mDistortionVerts.lock();
//left eye distortion verts
float Xoffset = -1;
for (int y = 0; y < m_iLensGridSegmentCountV; y++)
{
for (int x = 0; x < m_iLensGridSegmentCountH; x++)
{
u = x*w; v = 1 - y*h;
vert->point = Point3F(Xoffset + u, -1 + 2 * y*h, 0.0f);
vr::DistortionCoordinates_t dc0 = mHMD->ComputeDistortion(vr::Eye_Left, u, v);
vert->texCoord1 = Point2F(dc0.rfRed[0], 1 - dc0.rfRed[1]); // r
vert->texCoord2 = Point2F(dc0.rfGreen[0], 1 - dc0.rfGreen[1]); // g
vert->texCoord3 = Point2F(dc0.rfBlue[0], 1 - dc0.rfBlue[1]); // b
vert++;
}
}
//right eye distortion verts
Xoffset = 0;
for (int y = 0; y < m_iLensGridSegmentCountV; y++)
{
for (int x = 0; x < m_iLensGridSegmentCountH; x++)
{
u = x*w; v = 1 - y*h;
vert->point = Point3F(Xoffset + u, -1 + 2 * y*h, 0.0f);
vr::DistortionCoordinates_t dc0 = mHMD->ComputeDistortion(vr::Eye_Right, u, v);
vert->texCoord1 = Point2F(dc0.rfRed[0], 1 - dc0.rfRed[1]);
vert->texCoord2 = Point2F(dc0.rfGreen[0], 1 - dc0.rfGreen[1]);
vert->texCoord3 = Point2F(dc0.rfBlue[0], 1 - dc0.rfBlue[1]);
vert++;
}
}
mDistortionVerts.unlock();
mDistortionInds.set(GFX, m_iLensGridSegmentCountV * m_iLensGridSegmentCountH * 6 * 2, 0, GFXBufferTypeStatic);
GFXPrimitive *prim;
U16 *index;
mDistortionInds.lock(&index, &prim);
U16 a, b, c, d;
U16 offset = 0;
for (U16 y = 0; y < m_iLensGridSegmentCountV - 1; y++)
{
for (U16 x = 0; x < m_iLensGridSegmentCountH - 1; x++)
{
a = m_iLensGridSegmentCountH*y + x + offset;
b = m_iLensGridSegmentCountH*y + x + 1 + offset;
c = (y + 1)*m_iLensGridSegmentCountH + x + 1 + offset;
d = (y + 1)*m_iLensGridSegmentCountH + x + offset;
*index++ = a;
*index++ = b;
*index++ = c;
*index++ = a;
*index++ = c;
*index++ = d;
}
}
offset = (m_iLensGridSegmentCountH)*(m_iLensGridSegmentCountV);
for (U16 y = 0; y < m_iLensGridSegmentCountV - 1; y++)
{
for (U16 x = 0; x < m_iLensGridSegmentCountH - 1; x++)
{
a = m_iLensGridSegmentCountH*y + x + offset;
b = m_iLensGridSegmentCountH*y + x + 1 + offset;
c = (y + 1)*m_iLensGridSegmentCountH + x + 1 + offset;
d = (y + 1)*m_iLensGridSegmentCountH + x + offset;
*index++ = a;
*index++ = b;
*index++ = c;
*index++ = a;
*index++ = c;
*index++ = d;
}
}
mDistortionInds.unlock();
}
void OpenVRRenderState::renderDistortion(U32 eye)
{
// Updates distortion for an eye (this should only be the case for backend APIS where image should be predistorted)
/*
glDisable(GL_DEPTH_TEST);
glViewport( 0, 0, m_nWindowWidth, m_nWindowHeight );
glBindVertexArray( m_unLensVAO );
glUseProgram( m_unLensProgramID );
//render left lens (first half of index array )
glBindTexture(GL_TEXTURE_2D, leftEyeDesc.m_nResolveTextureId );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
glDrawElements( GL_TRIANGLES, m_uiIndexSize/2, GL_UNSIGNED_SHORT, 0 );
//render right lens (second half of index array )
glBindTexture(GL_TEXTURE_2D, rightEyeDesc.m_nResolveTextureId );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
glDrawElements( GL_TRIANGLES, m_uiIndexSize/2, GL_UNSIGNED_SHORT, (const void *)(m_uiIndexSize) );
glBindVertexArray( 0 );
glUseProgram( 0 );
*/
}
void OpenVRRenderState::renderPreview()
{
}
void OpenVRRenderState::reset(vr::IVRSystem* hmd)
{
mHMD = hmd;
mStereoRT = NULL;
mEyeRT[0] = mEyeRT[1] = NULL;
mStereoRenderTextures[0] = mStereoRenderTextures[1] = NULL;
mStereoDepthTextures[0] = mStereoDepthTextures[1] = NULL;
mDistortionVerts = NULL;
mDistortionInds = NULL;
if (!mHMD)
return;
vr::HmdMatrix34_t mat = mHMD->GetEyeToHeadTransform(vr::Eye_Left);
mEyePose[0] = ConvertSteamVRAffineMatrixToMatrixFPlain(mat);
mEyePose[0].inverse();
mat = mHMD->GetEyeToHeadTransform(vr::Eye_Right);
mEyePose[1] = ConvertSteamVRAffineMatrixToMatrixFPlain(mat);
mEyePose[1].inverse();
mHMD->GetProjectionRaw(vr::Eye_Left, &mEyeFov[0].leftTan, &mEyeFov[0].rightTan, &mEyeFov[0].upTan, &mEyeFov[0].downTan);
mHMD->GetProjectionRaw(vr::Eye_Right, &mEyeFov[1].leftTan, &mEyeFov[1].rightTan, &mEyeFov[1].upTan, &mEyeFov[1].downTan);
mEyeFov[0].upTan = -mEyeFov[0].upTan;
mEyeFov[0].leftTan = -mEyeFov[0].leftTan;
mEyeFov[1].upTan = -mEyeFov[1].upTan;
mEyeFov[1].leftTan = -mEyeFov[1].leftTan;
}
OpenVRProvider::OpenVRProvider() :
mHMD(NULL),
mRenderModels(NULL),
mDrawCanvas(NULL),
mGameConnection(NULL)
{
dStrcpy(mName, "openvr");
mDeviceType = INPUTMGR->getNextDeviceType();
buildInputCodeTable();
GFXDevice::getDeviceEventSignal().notify(this, &OpenVRProvider::_handleDeviceEvent);
INPUTMGR->registerDevice(this);
}
OpenVRProvider::~OpenVRProvider()
{
}
void OpenVRProvider::staticInit()
{
// TODO: Add console vars
}
bool OpenVRProvider::enable()
{
disable();
// Load openvr runtime
vr::EVRInitError eError = vr::VRInitError_None;
mHMD = vr::VR_Init(&eError, vr::VRApplication_Scene);
dMemset(mDeviceClassChar, '\0', sizeof(mDeviceClassChar));
if (eError != vr::VRInitError_None)
{
mHMD = NULL;
char buf[1024];
sprintf_s(buf, sizeof(buf), "Unable to init VR runtime: %s", vr::VR_GetVRInitErrorAsEnglishDescription(eError));
Con::printf(buf);
return false;
}
mRenderModels = (vr::IVRRenderModels *)vr::VR_GetGenericInterface(vr::IVRRenderModels_Version, &eError);
if (!mRenderModels)
{
mHMD = NULL;
vr::VR_Shutdown();
char buf[1024];
sprintf_s(buf, sizeof(buf), "Unable to get render model interface: %s", vr::VR_GetVRInitErrorAsEnglishDescription(eError));
Con::printf(buf);
return false;
}
mDriver = GetTrackedDeviceString(mHMD, vr::k_unTrackedDeviceIndex_Hmd, vr::Prop_TrackingSystemName_String);
mDisplay = GetTrackedDeviceString(mHMD, vr::k_unTrackedDeviceIndex_Hmd, vr::Prop_SerialNumber_String);
mHMDRenderState.reset(mHMD);
mHMD->ResetSeatedZeroPose();
dMemset(mPreviousInputTrackedDevicePose, '\0', sizeof(mPreviousInputTrackedDevicePose));
mEnabled = true;
return true;
}
bool OpenVRProvider::disable()
{
if (mHMD)
{
mHMD = NULL;
mRenderModels = NULL;
mHMDRenderState.reset(NULL);
vr::VR_Shutdown();
}
mEnabled = false;
return true;
}
void OpenVRProvider::buildInputCodeTable()
{
// Obtain all of the device codes
for (U32 i = 0; i < vr::k_unMaxTrackedDeviceCount; ++i)
{
OVR_SENSORROT[i] = INPUTMGR->getNextDeviceCode();
OVR_SENSORROTANG[i] = INPUTMGR->getNextDeviceCode();
OVR_SENSORVELOCITY[i] = INPUTMGR->getNextDeviceCode();
OVR_SENSORANGVEL[i] = INPUTMGR->getNextDeviceCode();
OVR_SENSORMAGNETOMETER[i] = INPUTMGR->getNextDeviceCode();
OVR_SENSORPOSITION[i] = INPUTMGR->getNextDeviceCode();
OVR_BUTTONPRESSED[i] = INPUTMGR->getNextDeviceCode();
OVR_BUTTONTOUCHED[i] = INPUTMGR->getNextDeviceCode();
OVR_AXISNONE[i] = INPUTMGR->getNextDeviceCode();
OVR_AXISTRACKPAD[i] = INPUTMGR->getNextDeviceCode();
OVR_AXISJOYSTICK[i] = INPUTMGR->getNextDeviceCode();
OVR_AXISTRIGGER[i] = INPUTMGR->getNextDeviceCode();
}
// Build out the virtual map
char buffer[64];
for (U32 i = 0; i < vr::k_unMaxTrackedDeviceCount; ++i)
{
dSprintf(buffer, 64, "opvr_sensorrot%d", i);
INPUTMGR->addVirtualMap(buffer, SI_ROT, OVR_SENSORROT[i]);
dSprintf(buffer, 64, "opvr_sensorrotang%d", i);
INPUTMGR->addVirtualMap(buffer, SI_POS, OVR_SENSORROTANG[i]);
dSprintf(buffer, 64, "opvr_sensorvelocity%d", i);
INPUTMGR->addVirtualMap(buffer, SI_POS, OVR_SENSORVELOCITY[i]);
dSprintf(buffer, 64, "opvr_sensorangvel%d", i);
INPUTMGR->addVirtualMap(buffer, SI_POS, OVR_SENSORANGVEL[i]);
dSprintf(buffer, 64, "opvr_sensormagnetometer%d", i);
INPUTMGR->addVirtualMap(buffer, SI_POS, OVR_SENSORMAGNETOMETER[i]);
dSprintf(buffer, 64, "opvr_sensorpos%d", i);
INPUTMGR->addVirtualMap(buffer, SI_POS, OVR_SENSORPOSITION[i]);
dSprintf(buffer, 64, "opvr_buttonpressed%d", i);
INPUTMGR->addVirtualMap(buffer, SI_INT, OVR_BUTTONPRESSED[i]);
dSprintf(buffer, 64, "opvr_buttontouched%d", i);
INPUTMGR->addVirtualMap(buffer, SI_INT, OVR_BUTTONTOUCHED[i]);
dSprintf(buffer, 64, "opvr_axis_none%d", i);
INPUTMGR->addVirtualMap(buffer, SI_POS, OVR_AXISNONE[i]);
dSprintf(buffer, 64, "opvr_axis_trackpad%d", i);
INPUTMGR->addVirtualMap(buffer, SI_POS, OVR_AXISTRACKPAD[i]);
dSprintf(buffer, 64, "opvr_axis_joystick%d", i);
INPUTMGR->addVirtualMap(buffer, SI_POS, OVR_AXISJOYSTICK[i]);
dSprintf(buffer, 64, "opvr_axis_trigger%d", i);
INPUTMGR->addVirtualMap(buffer, SI_INT, OVR_AXISTRIGGER[i]);
}
}
bool OpenVRProvider::process()
{
if (!mHMD)
return true;
// Process SteamVR events
vr::VREvent_t event;
while (mHMD->PollNextEvent(&event, sizeof(event)))
{
processVREvent(event);
}
// Process SteamVR controller state
for (vr::TrackedDeviceIndex_t unDevice = 0; unDevice < vr::k_unMaxTrackedDeviceCount; unDevice++)
{
vr::VRControllerState_t state;
if (mHMD->GetControllerState(unDevice, &state))
{
// TODO
}
}
// Update input poses
updateTrackedPoses();
submitInputChanges();
return true;
}
bool OpenVRProvider::providesFrameEyePose() const
{
return mHMD != NULL;
}
inline Point3F OpenVRVecToTorqueVec(vr::HmdVector3_t vec)
{
return Point3F(-vec.v[0], vec.v[2], -vec.v[1]);
}
void OpenVRTransformToRotPos(MatrixF mat, QuatF &outRot, Point3F &outPos)
{
// Directly set the rotation and position from the eye transforms
MatrixF torqueMat(1);
F32 inRotMat[4][4];
Point4F col0; mat.getColumn(0, &col0);
Point4F col1; mat.getColumn(1, &col1);
Point4F col2; mat.getColumn(2, &col2);
Point4F col3; mat.getColumn(3, &col3);
inRotMat[0][0] = col0.x;
inRotMat[0][1] = col0.y;
inRotMat[0][2] = col0.z;
inRotMat[0][3] = col0.w;
inRotMat[1][0] = col1.x;
inRotMat[1][1] = col1.y;
inRotMat[1][2] = col1.z;
inRotMat[1][3] = col1.w;
inRotMat[2][0] = col2.x;
inRotMat[2][1] = col2.y;
inRotMat[2][2] = col2.z;
inRotMat[2][3] = col2.w;
inRotMat[3][0] = col3.x;
inRotMat[3][1] = col3.y;
inRotMat[3][2] = col3.z;
inRotMat[3][3] = col3.w;
OculusVRUtil::convertRotation(inRotMat, torqueMat);
Point3F pos = torqueMat.getPosition();
outRot = QuatF(torqueMat);
outPos = Point3F(-pos.x, pos.z, -pos.y);
}
void OpenVRProvider::getFrameEyePose(IDevicePose *pose, U32 eye) const
{
AssertFatal(eye >= 0 && eye < 2, "Out of bounds eye");
MatrixF mat = mHMDRenderState.mHMDPose * mHMDRenderState.mEyePose[eye];
OpenVRTransformToRotPos(mat, pose->orientation, pose->position);
pose->velocity = Point3F(0);
pose->angularVelocity = Point3F(0);
}
bool OpenVRProvider::providesEyeOffsets() const
{
return mHMD != NULL;
}
/// Returns eye offset not taking into account any position tracking info
void OpenVRProvider::getEyeOffsets(Point3F *dest) const
{
dest[0] = mHMDRenderState.mEyePose[0].getPosition();
dest[1] = mHMDRenderState.mEyePose[1].getPosition();
}
bool OpenVRProvider::providesFovPorts() const
{
return mHMD != NULL;
}
void OpenVRProvider::getFovPorts(FovPort *out) const
{
dMemcpy(out, mHMDRenderState.mEyeFov, sizeof(mHMDRenderState.mEyeFov));
}
bool OpenVRProvider::providesProjectionOffset() const
{
return mHMD != NULL;
}
const Point2F& OpenVRProvider::getProjectionOffset() const
{
return Point2F(0, 0);
}
void OpenVRProvider::getStereoViewports(RectI *out) const
{
out[0] = mHMDRenderState.mEyeViewport[0];
out[1] = mHMDRenderState.mEyeViewport[1];
}
void OpenVRProvider::getStereoTargets(GFXTextureTarget **out) const
{
out[0] = mHMDRenderState.mEyeRT[0];
out[1] = mHMDRenderState.mEyeRT[1];
}
void OpenVRProvider::setDrawCanvas(GuiCanvas *canvas)
{
vr::EVRInitError peError = vr::VRInitError_None;
if (!vr::VRCompositor())
{
printf("Compositor initialization failed. See log file for details\n");
return;
}
if (mDrawCanvas != canvas || mHMDRenderState.mHMD == NULL)
{
mHMDRenderState.setupRenderTargets(0);
}
mDrawCanvas = canvas;
}
void OpenVRProvider::setCurrentConnection(GameConnection *connection)
{
mGameConnection = connection;
}
GameConnection* OpenVRProvider::getCurrentConnection()
{
return mGameConnection;
}
GFXTexHandle OpenVRProvider::getPreviewTexture()
{
return mHMDRenderState.mStereoRenderTextures[0]; // TODO: render distortion preview
}
void OpenVRProvider::onStartFrame()
{
if (!mHMD)
return;
}
void OpenVRProvider::onEndFrame()
{
if (!mHMD)
return;
}
void OpenVRProvider::onEyeRendered(U32 index)
{
if (!mHMD)
return;
if (GFX->getAdapterType() == Direct3D11)
{
vr::Texture_t eyeTexture = { (void*)static_cast<GFXD3D11TextureObject*>(mHMDRenderState.mStereoRenderTextures[index].getPointer())->get2DTex(), vr::API_DirectX, vr::ColorSpace_Gamma };
vr::VRCompositor()->Submit((vr::EVREye)(vr::Eye_Left + index), &eyeTexture);
}
else if (GFX->getAdapterType() == OpenGL)
{/*
vr::Texture_t eyeTexture = { (void*)static_cast<GFXGLTextureObject*>(mHMDRenderState.mStereoRenderTextures[index].getPointer())->getHandle(), vr::API_OpenGL, vr::ColorSpace_Gamma };
vr::VRCompositor()->Submit((vr::EVREye)(vr::Eye_Left + index), &eyeTexture);*/
}
}
bool OpenVRProvider::_handleDeviceEvent(GFXDevice::GFXDeviceEventType evt)
{
if (!ManagedSingleton<OpenVRProvider>::instanceOrNull())
{
return true;
}
switch (evt)
{
case GFXDevice::deStartOfFrame:
// Start of frame
onStartFrame();
break;
case GFXDevice::dePostFrame:
// End of frame
onEndFrame();
break;
case GFXDevice::deDestroy:
// Need to reinit rendering
break;
case GFXDevice::deLeftStereoFrameRendered:
//
onEyeRendered(0);
break;
case GFXDevice::deRightStereoFrameRendered:
//
onEyeRendered(1);
break;
default:
break;
}
return true;
}
void OpenVRProvider::processVREvent(const vr::VREvent_t & event)
{
switch (event.eventType)
{
case vr::VREvent_TrackedDeviceActivated:
{
// Setup render model
}
break;
case vr::VREvent_TrackedDeviceDeactivated:
{
// Deactivated
}
break;
case vr::VREvent_TrackedDeviceUpdated:
{
// Updated
}
break;
}
}
void OpenVRProvider::updateTrackedPoses()
{
if (!mHMD)
return;
vr::VRCompositor()->WaitGetPoses(mTrackedDevicePose, vr::k_unMaxTrackedDeviceCount, NULL, 0);
mValidPoseCount = 0;
for (int nDevice = 0; nDevice < vr::k_unMaxTrackedDeviceCount; ++nDevice)
{
IDevicePose &inPose = mCurrentDevicePose[nDevice];
if (mTrackedDevicePose[nDevice].bPoseIsValid)
{
mValidPoseCount++;
MatrixF mat = ConvertSteamVRAffineMatrixToMatrixFPlain(mTrackedDevicePose[nDevice].mDeviceToAbsoluteTracking);
mat.inverse();
if (nDevice == vr::k_unTrackedDeviceIndex_Hmd)
{
mHMDRenderState.mHMDPose = mat;
}
vr::TrackedDevicePose_t &outPose = mTrackedDevicePose[nDevice];
OpenVRTransformToRotPos(mat, inPose.orientation, inPose.position);
inPose.state = outPose.eTrackingResult;
inPose.valid = outPose.bPoseIsValid;
inPose.connected = outPose.bDeviceIsConnected;
inPose.velocity = OpenVRVecToTorqueVec(outPose.vVelocity);
inPose.angularVelocity = OpenVRVecToTorqueVec(outPose.vAngularVelocity);
}
else
{
inPose.valid = false;
}
}
}
void OpenVRProvider::submitInputChanges()
{
// Diff current frame with previous frame
for (U32 i = 0; i < vr::k_unMaxTrackedDeviceCount; i++)
{
IDevicePose curPose = mCurrentDevicePose[i];
IDevicePose prevPose = mPreviousInputTrackedDevicePose[i];
if (!curPose.valid || !curPose.connected)
continue;
if (curPose.orientation != prevPose.orientation)
{
AngAxisF axisAA(curPose.orientation);
INPUTMGR->buildInputEvent(mDeviceType, 0, SI_ROT, OVR_SENSORROT[i], SI_MOVE, axisAA);
}
if (curPose.position != prevPose.position)
{
INPUTMGR->buildInputEvent(mDeviceType, 0, SI_POS, OVR_SENSORPOSITION[i], SI_MOVE, curPose.position);
}
if (curPose.velocity != prevPose.velocity)
{
// Convert angles to degrees
VectorF angles;
angles.x = curPose.velocity.x;
angles.y = curPose.velocity.y;
angles.z = curPose.velocity.z;
INPUTMGR->buildInputEvent(mDeviceType, 0, SI_POS, OVR_SENSORVELOCITY[i], SI_MOVE, angles);
}
if (curPose.angularVelocity != prevPose.angularVelocity)
{
// Convert angles to degrees
VectorF angles;
angles[0] = mRadToDeg(curPose.velocity.x);
angles[1] = mRadToDeg(curPose.velocity.y);
angles[2] = mRadToDeg(curPose.velocity.z);
INPUTMGR->buildInputEvent(mDeviceType, 0, SI_POS, OVR_SENSORANGVEL[i], SI_MOVE, angles);
}
/*
if (curPose.connected != prevPose.connected)
{
if (Con::isFunction("onOVRConnectionChanged"))
{
Con::executef("onOVRConnectionStatus", curPose.connected);
}
}*/
if (curPose.state != prevPose.state)
{
if (Con::isFunction("onOVRStateChanged"))
{
Con::executef("onOVRStateChanged", curPose.state);
}
}
}
dMemcpy(mPreviousInputTrackedDevicePose, mCurrentDevicePose, sizeof(mPreviousInputTrackedDevicePose));
}
void OpenVRProvider::resetSensors()
{
if (mHMD)
{
mHMD->ResetSeatedZeroPose();
}
}
DefineEngineFunction(isOpenVRDeviceActive, bool, (), ,
"@brief Used to determine if the OpenVR input device is active\n\n"
"The OpenVR device is considered active when the library has been "
"initialized and either a real of simulated HMD is present.\n\n"
"@return True if the OpenVR input device is active.\n"
"@ingroup Game")
{
if (!ManagedSingleton<OpenVRProvider>::instanceOrNull())
{
return false;
}
return OCULUSVRDEV->getActive();
}
DefineEngineFunction(OpenVRSetEnabled, bool, (bool value), ,
"@brief Used to determine if the OpenVR input device is active\n\n"
"The OpenVR device is considered active when the library has been "
"initialized and either a real of simulated HMD is present.\n\n"
"@return True if the OpenVR input device is active.\n"
"@ingroup Game")
{
if (!ManagedSingleton<OpenVRProvider>::instanceOrNull())
{
return false;
}
return value ? ManagedSingleton<OpenVRProvider>::instance()->enable() : ManagedSingleton<OpenVRProvider>::instance()->disable();
}
DefineEngineFunction(setOpenVRHMDAsGameConnectionDisplayDevice, bool, (GameConnection* conn), ,
"@brief Sets the first HMD to be a GameConnection's display device\n\n"
"@param conn The GameConnection to set.\n"
"@return True if the GameConnection display device was set.\n"
"@ingroup Game")
{
if (!ManagedSingleton<OpenVRProvider>::instanceOrNull())
{
Con::errorf("setOVRHMDAsGameConnectionDisplayDevice(): No Oculus VR Device present.");
return false;
}
if (!conn)
{
Con::errorf("setOVRHMDAsGameConnectionDisplayDevice(): Invalid GameConnection.");
return false;
}
conn->setDisplayDevice(ManagedSingleton<OpenVRProvider>::instance());
return true;
}
DefineEngineFunction(OpenVRResetSensors, void, (), ,
"@brief Resets all Oculus VR sensors.\n\n"
"This resets all sensor orientations such that their 'normal' rotation "
"is defined when this function is called. This defines an HMD's forwards "
"and up direction, for example."
"@ingroup Game")
{
if (!ManagedSingleton<OpenVRProvider>::instanceOrNull())
{
return;
}
ManagedSingleton<OpenVRProvider>::instance()->resetSensors();
}

View file

@ -0,0 +1,172 @@
#ifndef _OPENVRDEVICE_H_
#define _OPENVRDEVICE_H_
#include "math/mQuat.h"
#include "math/mPoint4.h"
#include "math/util/frustum.h"
#include "core/util/tSingleton.h"
#include "gfx/gfxDevice.h"
#include "gfx/gfxVertexBuffer.h"
#include "gfx/gfxPrimitiveBuffer.h"
#include "gfx/gfxTarget.h"
#include "platform/input/IInputDevice.h"
#include "platform/input/event.h"
#include "platform/output/IDisplayDevice.h"
#include <openvr.h>
class OpenVRHMDDevice;
struct OpenVRRenderState
{
vr::IVRSystem *mHMD;
FovPort mEyeFov[2];
MatrixF mEyePose[2];
MatrixF mHMDPose;
RectI mEyeViewport[2];
GFXTextureTargetRef mStereoRT;
GFXTextureTargetRef mEyeRT[2];
GFXTexHandle mStereoRenderTextures[2];
GFXTexHandle mStereoDepthTextures[2];
GFXVertexBufferHandle<GFXVertexPTTT> mDistortionVerts;
GFXPrimitiveBufferHandle mDistortionInds;
bool setupRenderTargets(U32 mode);
void setupDistortion();
void renderDistortion(U32 eye);
void renderPreview();
void reset(vr::IVRSystem* hmd);
};
class OpenVRProvider : public IDisplayDevice, public IInputDevice
{
public:
enum DataDifferences {
DIFF_NONE = 0,
DIFF_ROT = (1 << 0),
DIFF_ROTAXISX = (1 << 1),
DIFF_ROTAXISY = (1 << 2),
DIFF_ACCEL = (1 << 3),
DIFF_ANGVEL = (1 << 4),
DIFF_MAG = (1 << 5),
DIFF_POS = (1 << 6),
DIFF_STATUS = (1 << 7),
DIFF_ROTAXIS = (DIFF_ROTAXISX | DIFF_ROTAXISY),
DIFF_RAW = (DIFF_ACCEL | DIFF_ANGVEL | DIFF_MAG),
};
OpenVRProvider();
~OpenVRProvider();
static void staticInit();
bool enable();
bool disable();
bool getActive() { return mHMD != NULL; }
/// @name Input handling
/// {
void buildInputCodeTable();
virtual bool process();
/// }
/// @name Display handling
/// {
virtual bool providesFrameEyePose() const;
virtual void getFrameEyePose(IDevicePose *pose, U32 eye) const;
virtual bool providesEyeOffsets() const;
/// Returns eye offset not taking into account any position tracking info
virtual void getEyeOffsets(Point3F *dest) const;
virtual bool providesFovPorts() const;
virtual void getFovPorts(FovPort *out) const;
virtual bool providesProjectionOffset() const;
virtual const Point2F& getProjectionOffset() const;
virtual void getStereoViewports(RectI *out) const;
virtual void getStereoTargets(GFXTextureTarget **out) const;
virtual void setDrawCanvas(GuiCanvas *canvas);
virtual void setCurrentConnection(GameConnection *connection);
virtual GameConnection* getCurrentConnection();
virtual GFXTexHandle getPreviewTexture();
virtual void onStartFrame();
virtual void onEndFrame();
virtual void onEyeRendered(U32 index);
bool _handleDeviceEvent(GFXDevice::GFXDeviceEventType evt);
/// }
/// @name OpenVR handling
/// {
void processVREvent(const vr::VREvent_t & event);
void updateTrackedPoses();
void submitInputChanges();
void resetSensors();
/// }
/// @name OpenVR state
/// {
vr::IVRSystem *mHMD;
vr::IVRRenderModels *mRenderModels;
String mDriver;
String mDisplay;
vr::TrackedDevicePose_t mTrackedDevicePose[vr::k_unMaxTrackedDeviceCount];
IDevicePose mCurrentDevicePose[vr::k_unMaxTrackedDeviceCount];
IDevicePose mPreviousInputTrackedDevicePose[vr::k_unMaxTrackedDeviceCount];
U32 mValidPoseCount;
char mDeviceClassChar[vr::k_unMaxTrackedDeviceCount];
OpenVRRenderState mHMDRenderState;
/// }
GuiCanvas* mDrawCanvas;
GameConnection* mGameConnection;
static U32 OVR_SENSORROT[vr::k_unMaxTrackedDeviceCount];
static U32 OVR_SENSORROTANG[vr::k_unMaxTrackedDeviceCount];
static U32 OVR_SENSORVELOCITY[vr::k_unMaxTrackedDeviceCount];
static U32 OVR_SENSORANGVEL[vr::k_unMaxTrackedDeviceCount];
static U32 OVR_SENSORMAGNETOMETER[vr::k_unMaxTrackedDeviceCount];
static U32 OVR_SENSORPOSITION[vr::k_unMaxTrackedDeviceCount];
static U32 OVR_BUTTONPRESSED[vr::k_unMaxTrackedDeviceCount];
static U32 OVR_BUTTONTOUCHED[vr::k_unMaxTrackedDeviceCount];
static U32 OVR_AXISNONE[vr::k_unMaxTrackedDeviceCount];
static U32 OVR_AXISTRACKPAD[vr::k_unMaxTrackedDeviceCount];
static U32 OVR_AXISJOYSTICK[vr::k_unMaxTrackedDeviceCount];
static U32 OVR_AXISTRIGGER[vr::k_unMaxTrackedDeviceCount];
public:
// For ManagedSingleton.
static const char* getSingletonName() { return "OpenVRProvider"; }
};
/// Returns the OculusVRDevice singleton.
#define OCULUSVRDEV ManagedSingleton<OpenVRProvider>::instance()
#endif // _OCULUSVRDEVICE_H_