add openvr support, switch to 8.1 sdk, prepare for vr ui

This commit is contained in:
2018-10-28 00:29:09 +02:00
parent 4c41be1336
commit 0fff9f2010
19 changed files with 506 additions and 23 deletions

231
src/hmd.cpp Normal file
View File

@@ -0,0 +1,231 @@
#include "pch.h"
#include "hmd.h"
#include "log.h"
#include <array>
Vive::Vive()
{
for (int i = 0; i < 2; i++)
controllers[i].active = true;
}
bool Vive::Initialize()
{
vr::EVRInitError error;
hmd = vr::VR_Init(&error, vr::EVRApplicationType::VRApplication_Scene);
if (error != vr::EVRInitError::VRInitError_None)
return false;
comp = vr::VRCompositor();
if (!comp)
return false;
hmd->GetRecommendedRenderTargetSize(&eyeWidth, &eyeHeight);
LOG("Eye target resolution: %dx%d\n", eyeWidth, eyeHeight);
for (int eye = 0; eye < 2; ++eye)
{
eyes[eye].create(eyeWidth, eyeHeight);
eyes[eye].bindFramebuffer();
eyes[eye].clear({ 1, 0, 0, 1 });
eyes[eye].unbindFramebuffer();
}
int attempts = 50;
do
{
int nc = 0;
for (int nDevice = 0; nDevice < vr::k_unMaxTrackedDeviceCount; ++nDevice)
{
if (hmd->GetTrackedDeviceClass(nDevice) == vr::TrackedDeviceClass_HMD)
{
auto read_string = [nDevice, this](vr::ETrackedDeviceProperty p) -> std::string {
size_t len = hmd->GetStringTrackedDeviceProperty(nDevice, p, nullptr, 0);
std::string str(len, '\0');
hmd->GetStringTrackedDeviceProperty(nDevice, p, (char*)str.data(), len);
return str;
};
dev_tracksys = read_string(vr::Prop_TrackingSystemName_String);
dev_serial = read_string(vr::Prop_SerialNumber_String);
dev_model = read_string(vr::Prop_ModelNumber_String);
dev_manufacturer = read_string(vr::Prop_ManufacturerName_String);
}
}
std::this_thread::sleep_for(std::chrono::milliseconds(100));
attempts--;
} while (attempts > 0 && dev_serial.empty());
return true;
}
void Vive::Terminate()
{
vr::VR_Shutdown();
}
void Vive::ResetYaw()
{
yaw_offset = euler.y;
}
void Vive::Draw()
{
if (!(hmd && comp && comp_attempts < 10))
return;
vr::TrackedDevicePose_t poses[vr::k_unMaxTrackedDeviceCount];
comp->WaitGetPoses(poses, vr::k_unMaxTrackedDeviceCount, NULL, 0);
auto& hmdPose = poses[vr::k_unTrackedDeviceIndex_Hmd];
for (int eye = 0; eye < 2; ++eye)
{
eyes[eye].bindFramebuffer();
eyes[eye].clear(background);
glViewport(0, 0, eyes[eye].getWidth(), eyes[eye].getHeight());
// Get view and projection matrices
vr::HmdMatrix44_t p = hmd->GetProjectionMatrix((vr::EVREye)eye, 0.2f, 1000.f);
float eyeProj[4][4] = {
p.m[0][0], p.m[1][0], p.m[2][0], p.m[3][0],
p.m[0][1], p.m[1][1], p.m[2][1], p.m[3][1],
p.m[0][2], p.m[1][2], p.m[2][2], p.m[3][2],
p.m[0][3], p.m[1][3], p.m[2][3], p.m[3][3],
};
vr::HmdMatrix34_t e = hmd->GetEyeToHeadTransform((vr::EVREye)eye);
float eyePose[4][4] = {
e.m[0][0], e.m[1][0], e.m[2][0], 0,
e.m[0][1], e.m[1][1], e.m[2][1], 0,
e.m[0][2], e.m[1][2], e.m[2][2], 0,
e.m[0][3], e.m[1][3], e.m[2][3], 1,
};
vr::HmdMatrix34_t h = hmdPose.mDeviceToAbsoluteTracking;
float hmdPose[4][4] = {
h.m[0][0], h.m[1][0], h.m[2][0], 0,
h.m[0][1], h.m[1][1], h.m[2][1], 0,
h.m[0][2], h.m[1][2], h.m[2][2], 0,
h.m[0][3], h.m[1][3], h.m[2][3], 1,
};
auto mat_proj = glm::make_mat4((float*)eyeProj);
auto mat_pose = glm::inverse(glm::make_mat4((float*)hmdPose));
auto mat_eye = glm::inverse(glm::make_mat4((float*)eyePose));
proj[eye] = mat_proj;
view[eye] = mat_eye * mat_pose;
pose = glm::make_mat4((float*)hmdPose);
for (auto& c : controllers)
c.valid = false;
for (auto& c : trackers)
c.valid = false;
int nc = 0;
int nt = 0;
for (int nDevice = 0; nDevice < vr::k_unMaxTrackedDeviceCount; ++nDevice)
{
if (poses[nDevice].bPoseIsValid)
{
vr::HmdMatrix34_t p = poses[nDevice].mDeviceToAbsoluteTracking;
float mat[4][4] = {
p.m[0][0], p.m[1][0], p.m[2][0], 0,
p.m[0][1], p.m[1][1], p.m[2][1], 0,
p.m[0][2], p.m[1][2], p.m[2][2], 0,
p.m[0][3], p.m[1][3], p.m[2][3], 1,
};
switch (hmd->GetTrackedDeviceClass(nDevice))
{
case vr::TrackedDeviceClass_Controller:
{
vr::EVRInitError error;
vr::ETrackedControllerRole controllerRole = (vr::ETrackedControllerRole)
hmd->GetInt32TrackedDeviceProperty(nDevice, vr::ETrackedDeviceProperty::Prop_ControllerRoleHint_Int32);
auto& c = controllers[nc];
c.index = nc;
c.active = true;
c.valid = true;
hmd->GetControllerState(nDevice, &c.state, sizeof(vr::VRControllerState_t));
c.update(glm::make_mat4((float*)mat));
c.buttons_bits = c.state.ulButtonPressed;
c.role = controllerRole;
for (int axi = 0; axi < 5; axi++)
{
c.axis[axi].x = c.state.rAxis[axi].x;
c.axis[axi].y = c.state.rAxis[axi].y;
}
auto btn = c.state.ulButtonPressed;
for (auto b : { Controller::Button::Trigger, Controller::Button::Grip })
{
if ((btn & (uint64_t)b) != 0 && !c.buttons[(uint64_t)b])
{
c.buttons[(uint64_t)b] = true;
if (on_button)
on_button(c, b, Controller::Action::Press);
}
if ((btn & (uint64_t)b) == 0 && c.buttons[(uint64_t)b])
{
c.buttons[(uint64_t)b] = false;
if (on_button)
on_button(c, b, Controller::Action::Release);
}
}
nc++;
}
break;
case vr::TrackedDeviceClass_HMD:
break;
case vr::TrackedDeviceClass_Invalid:
break;
case vr::TrackedDeviceClass_GenericTracker:
{
auto& c = trackers[nt];
c.index = nt;
c.active = true;
c.valid = true;
c.update(glm::make_mat4((float*)mat));
}
break;
case vr::TrackedDeviceClass_TrackingReference:
break;
default:
break;
}
}
}
if (nc > 1 && swap_controllers)
{
std::swap(controllers[0], controllers[1]);
}
if (on_draw)
on_draw(proj[eye], view[eye]);
eyes[eye].unbindFramebuffer();
}
vr::Texture_t eyeTexture0 = { (void*)eyes[0].getTextureID(), vr::ETextureType::TextureType_OpenGL, vr::ColorSpace_Linear };
if (auto err = comp->Submit(vr::EVREye::Eye_Left, &eyeTexture0) != vr::EVRCompositorError::VRCompositorError_None)
{
LOG("Compositor error %d", err);
comp_attempts++;
return;
}
vr::Texture_t eyeTexture1 = { (void*)eyes[1].getTextureID(), vr::ETextureType::TextureType_OpenGL, vr::ColorSpace_Linear };
if (auto err = comp->Submit(vr::EVREye::Eye_Right, &eyeTexture1) != vr::EVRCompositorError::VRCompositorError_None)
{
LOG("Compositor error %d", err);
comp_attempts++;
return;
}
comp_attempts = 0;
glFlush();
// glFinish();
// glBindTexture(GL_TEXTURE_2D, 0);
}
bool Vive::Valid()
{
return comp && comp_attempts < 10;
}