Merge pull request #75 from lvonasek/OpenXR

OpenXR menuyaw and recenter support added
This commit is contained in:
Simon 2022-05-05 16:30:07 +01:00 committed by GitHub
commit 325641f90e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 96 additions and 67 deletions

View file

@ -294,12 +294,18 @@ void VR_EnterVR( engine_t* engine, ovrJava java ) {
ALOGE("Failed to create XR session: %d.", initResult); ALOGE("Failed to create XR session: %d.", initResult);
exit(1); exit(1);
} }
// Create a space to the first path
XrReferenceSpaceCreateInfo spaceCreateInfo = {};
spaceCreateInfo.type = XR_TYPE_REFERENCE_SPACE_CREATE_INFO;
spaceCreateInfo.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_VIEW;
spaceCreateInfo.poseInReferenceSpace.orientation.w = 1.0f;
OXR(xrCreateReferenceSpace(engine->appState.Session, &spaceCreateInfo, &engine->appState.HeadSpace));
} }
void VR_LeaveVR( engine_t* engine ) { void VR_LeaveVR( engine_t* engine ) {
if (engine->appState.Session) { if (engine->appState.Session) {
OXR(xrDestroySpace(engine->appState.HeadSpace)); OXR(xrDestroySpace(engine->appState.HeadSpace));
OXR(xrDestroySpace(engine->appState.LocalSpace));
// StageSpace is optional. // StageSpace is optional.
if (engine->appState.StageSpace != XR_NULL_HANDLE) { if (engine->appState.StageSpace != XR_NULL_HANDLE) {
OXR(xrDestroySpace(engine->appState.StageSpace)); OXR(xrDestroySpace(engine->appState.StageSpace));
@ -307,7 +313,6 @@ void VR_LeaveVR( engine_t* engine ) {
OXR(xrDestroySpace(engine->appState.FakeStageSpace)); OXR(xrDestroySpace(engine->appState.FakeStageSpace));
engine->appState.CurrentSpace = XR_NULL_HANDLE; engine->appState.CurrentSpace = XR_NULL_HANDLE;
OXR(xrDestroySession(engine->appState.Session)); OXR(xrDestroySession(engine->appState.Session));
OXR(xrDestroyInstance(engine->appState.Instance));
engine->appState.Session = NULL; engine->appState.Session = NULL;
} }
} }

View file

@ -63,6 +63,8 @@ typedef struct {
int *menuCursorX; int *menuCursorX;
int *menuCursorY; int *menuCursorY;
qboolean menuLeftHanded; qboolean menuLeftHanded;
float recenterYaw;
} vr_clientinfo_t; } vr_clientinfo_t;
#endif //vr_clientinfo_h #endif //vr_clientinfo_h

View file

@ -23,6 +23,7 @@ extern vr_clientinfo_t vr;
extern cvar_t *vr_heightAdjust; extern cvar_t *vr_heightAdjust;
XrView* projections; XrView* projections;
GLboolean stageSupported = GL_FALSE;
void VR_UpdateStageBounds(ovrApp* pappState) { void VR_UpdateStageBounds(ovrApp* pappState) {
XrExtent2Df stageBounds = {}; XrExtent2Df stageBounds = {};
@ -161,6 +162,54 @@ void VR_GetResolution(engine_t* engine, int *pWidth, int *pHeight)
} }
} }
void VR_Recenter(engine_t* engine) {
// Calculate recenter reference
XrReferenceSpaceCreateInfo spaceCreateInfo = {};
spaceCreateInfo.type = XR_TYPE_REFERENCE_SPACE_CREATE_INFO;
spaceCreateInfo.poseInReferenceSpace.orientation.w = 1.0f;
if (engine->appState.CurrentSpace != XR_NULL_HANDLE) {
vec3_t rotation = {0, 0, 0};
XrSpaceLocation loc = {};
loc.type = XR_TYPE_SPACE_LOCATION;
OXR(xrLocateSpace(engine->appState.HeadSpace, engine->appState.CurrentSpace, engine->predictedDisplayTime, &loc));
QuatToYawPitchRoll(loc.pose.orientation, rotation, vr.hmdorientation);
vr.recenterYaw += radians(vr.hmdorientation[YAW]);
spaceCreateInfo.poseInReferenceSpace.orientation.x = 0;
spaceCreateInfo.poseInReferenceSpace.orientation.y = sin(vr.recenterYaw / 2);
spaceCreateInfo.poseInReferenceSpace.orientation.z = 0;
spaceCreateInfo.poseInReferenceSpace.orientation.w = cos(vr.recenterYaw / 2);
}
// Delete previous space instances
if (engine->appState.StageSpace != XR_NULL_HANDLE) {
OXR(xrDestroySpace(engine->appState.StageSpace));
}
if (engine->appState.FakeStageSpace != XR_NULL_HANDLE) {
OXR(xrDestroySpace(engine->appState.FakeStageSpace));
}
// Create a default stage space to use if SPACE_TYPE_STAGE is not
// supported, or calls to xrGetReferenceSpaceBoundsRect fail.
spaceCreateInfo.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_LOCAL;
spaceCreateInfo.poseInReferenceSpace.position.y = -1.6750f;
OXR(xrCreateReferenceSpace(engine->appState.Session, &spaceCreateInfo, &engine->appState.FakeStageSpace));
ALOGV("Created fake stage space from local space with offset");
engine->appState.CurrentSpace = engine->appState.FakeStageSpace;
if (stageSupported) {
spaceCreateInfo.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_STAGE;
spaceCreateInfo.poseInReferenceSpace.position.y = 0.0f;
OXR(xrCreateReferenceSpace(engine->appState.Session, &spaceCreateInfo, &engine->appState.StageSpace));
ALOGV("Created stage space");
engine->appState.CurrentSpace = engine->appState.StageSpace;
}
// Update menu orientation
vr.menuYaw = 0;
}
void VR_InitRenderer( engine_t* engine ) { void VR_InitRenderer( engine_t* engine ) {
#if ENABLE_GL_DEBUG #if ENABLE_GL_DEBUG
glEnable(GL_DEBUG_OUTPUT); glEnable(GL_DEBUG_OUTPUT);
@ -227,7 +276,6 @@ void VR_InitRenderer( engine_t* engine ) {
OXR(xrEnumerateReferenceSpaces( OXR(xrEnumerateReferenceSpaces(
engine->appState.Session, numOutputSpaces, &numOutputSpaces, referenceSpaces)); engine->appState.Session, numOutputSpaces, &numOutputSpaces, referenceSpaces));
GLboolean stageSupported = GL_FALSE;
for (uint32_t i = 0; i < numOutputSpaces; i++) { for (uint32_t i = 0; i < numOutputSpaces; i++) {
if (referenceSpaces[i] == XR_REFERENCE_SPACE_TYPE_STAGE) { if (referenceSpaces[i] == XR_REFERENCE_SPACE_TYPE_STAGE) {
stageSupported = GL_TRUE; stageSupported = GL_TRUE;
@ -237,32 +285,8 @@ void VR_InitRenderer( engine_t* engine ) {
free(referenceSpaces); free(referenceSpaces);
// Create a space to the first path if (engine->appState.CurrentSpace == XR_NULL_HANDLE) {
XrReferenceSpaceCreateInfo spaceCreateInfo = {}; VR_Recenter(engine);
spaceCreateInfo.type = XR_TYPE_REFERENCE_SPACE_CREATE_INFO;
spaceCreateInfo.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_VIEW;
spaceCreateInfo.poseInReferenceSpace.orientation.w = 1.0f;
OXR(xrCreateReferenceSpace(engine->appState.Session, &spaceCreateInfo, &engine->appState.HeadSpace));
spaceCreateInfo.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_LOCAL;
OXR(xrCreateReferenceSpace(engine->appState.Session, &spaceCreateInfo, &engine->appState.LocalSpace));
// Create a default stage space to use if SPACE_TYPE_STAGE is not
// supported, or calls to xrGetReferenceSpaceBoundsRect fail.
{
spaceCreateInfo.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_LOCAL;
spaceCreateInfo.poseInReferenceSpace.position.y = -1.6750f;
OXR(xrCreateReferenceSpace(engine->appState.Session, &spaceCreateInfo, &engine->appState.FakeStageSpace));
ALOGV("Created fake stage space from local space with offset");
engine->appState.CurrentSpace = engine->appState.FakeStageSpace;
}
if (stageSupported) {
spaceCreateInfo.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_STAGE;
spaceCreateInfo.poseInReferenceSpace.position.y = 0.0f;
OXR(xrCreateReferenceSpace(engine->appState.Session, &spaceCreateInfo, &engine->appState.StageSpace));
ALOGV("Created stage space");
engine->appState.CurrentSpace = engine->appState.StageSpace;
} }
projections = (XrView*)(malloc(ovrMaxNumEyes * sizeof(XrView))); projections = (XrView*)(malloc(ovrMaxNumEyes * sizeof(XrView)));
@ -323,7 +347,9 @@ void VR_DrawFrame( engine_t* engine ) {
} }
GLboolean stageBoundsDirty = GL_TRUE; GLboolean stageBoundsDirty = GL_TRUE;
ovrApp_HandleXrEvents(&engine->appState); if (ovrApp_HandleXrEvents(&engine->appState)) {
VR_Recenter(engine);
}
if (engine->appState.SessionActive == GL_FALSE) { if (engine->appState.SessionActive == GL_FALSE) {
return; return;
} }
@ -358,44 +384,34 @@ void VR_DrawFrame( engine_t* engine ) {
beginFrameDesc.next = NULL; beginFrameDesc.next = NULL;
OXR(xrBeginFrame(engine->appState.Session, &beginFrameDesc)); OXR(xrBeginFrame(engine->appState.Session, &beginFrameDesc));
// We extract Yaw, Pitch, Roll instead of directly using the orientation
// to allow "additional" yaw manipulation with mouse/controller.
XrSpaceLocation loc = {}; XrSpaceLocation loc = {};
loc.type = XR_TYPE_SPACE_LOCATION; loc.type = XR_TYPE_SPACE_LOCATION;
OXR(xrLocateSpace( OXR(xrLocateSpace(engine->appState.HeadSpace, engine->appState.CurrentSpace, frameState.predictedDisplayTime, &loc));
engine->appState.HeadSpace, engine->appState.CurrentSpace, frameState.predictedDisplayTime, &loc));
XrPosef xfStageFromHead = loc.pose; XrPosef xfStageFromHead = loc.pose;
OXR(xrLocateSpace( const XrQuaternionf quatHmd = xfStageFromHead.orientation;
engine->appState.HeadSpace, engine->appState.LocalSpace, frameState.predictedDisplayTime, &loc)); const XrVector3f positionHmd = xfStageFromHead.position;
vec3_t rotation = {0, 0, 0};
QuatToYawPitchRoll(quatHmd, rotation, vr.hmdorientation);
VectorSet(vr.hmdposition, positionHmd.x, positionHmd.y + vr_heightAdjust->value, positionHmd.z);
{ //Position
// We extract Yaw, Pitch, Roll instead of directly using the orientation VectorSubtract(vr.hmdposition_last, vr.hmdposition, vr.hmdposition_delta);
// to allow "additional" yaw manipulation with mouse/controller.
XrSpaceLocation loc = {};
loc.type = XR_TYPE_SPACE_LOCATION;
OXR(xrLocateSpace(engine->appState.HeadSpace, engine->appState.CurrentSpace, frameState.predictedDisplayTime, &loc));
XrPosef xfStageFromHead = loc.pose;
const XrQuaternionf quatHmd = xfStageFromHead.orientation;
const XrVector3f positionHmd = xfStageFromHead.position;
vec3_t rotation = {0, 0, 0};
QuatToYawPitchRoll(quatHmd, rotation, vr.hmdorientation);
VectorSet(vr.hmdposition, positionHmd.x, positionHmd.y + vr_heightAdjust->value, positionHmd.z);
//Position //Keep this for our records
VectorSubtract(vr.hmdposition_last, vr.hmdposition, vr.hmdposition_delta); VectorCopy(vr.hmdposition, vr.hmdposition_last);
//Keep this for our records //Orientation
VectorCopy(vr.hmdposition, vr.hmdposition_last); VectorSubtract(vr.hmdorientation_last, vr.hmdorientation, vr.hmdorientation_delta);
//Orientation //Keep this for our records
VectorSubtract(vr.hmdorientation_last, vr.hmdorientation, vr.hmdorientation_delta); VectorCopy(vr.hmdorientation, vr.hmdorientation_last);
//Keep this for our records // View yaw delta
VectorCopy(vr.hmdorientation, vr.hmdorientation_last); const float clientview_yaw = vr.clientviewangles[YAW] - vr.hmdorientation[YAW];
vr.clientview_yaw_delta = vr.clientview_yaw_last - clientview_yaw;
// View yaw delta vr.clientview_yaw_last = clientview_yaw;
const float clientview_yaw = vr.clientviewangles[YAW] - vr.hmdorientation[YAW];
vr.clientview_yaw_delta = vr.clientview_yaw_last - clientview_yaw;
vr.clientview_yaw_last = clientview_yaw;
}
XrViewLocateInfo projectionInfo = {}; XrViewLocateInfo projectionInfo = {};
projectionInfo.type = XR_TYPE_VIEW_LOCATE_INFO; projectionInfo.type = XR_TYPE_VIEW_LOCATE_INFO;
@ -465,6 +481,7 @@ void VR_DrawFrame( engine_t* engine ) {
XrCompositionLayerProjectionView projection_layer_elements[2] = {}; XrCompositionLayerProjectionView projection_layer_elements[2] = {};
if (!VR_useScreenLayer() && !(cl.snap.ps.pm_flags & PMF_FOLLOW && vr.follow_mode == VRFM_FIRSTPERSON)) { if (!VR_useScreenLayer() && !(cl.snap.ps.pm_flags & PMF_FOLLOW && vr.follow_mode == VRFM_FIRSTPERSON)) {
vr.menuYaw = vr.hmdorientation[YAW];
for (int eye = 0; eye < ovrMaxNumEyes; eye++) { for (int eye = 0; eye < ovrMaxNumEyes; eye++) {
ovrFramebuffer* frameBuffer = &engine->appState.Renderer.FrameBuffer; ovrFramebuffer* frameBuffer = &engine->appState.Renderer.FrameBuffer;
@ -500,7 +517,7 @@ void VR_DrawFrame( engine_t* engine ) {
XrCompositionLayerCylinderKHR cylinder_layer = {}; XrCompositionLayerCylinderKHR cylinder_layer = {};
cylinder_layer.type = XR_TYPE_COMPOSITION_LAYER_CYLINDER_KHR; cylinder_layer.type = XR_TYPE_COMPOSITION_LAYER_CYLINDER_KHR;
cylinder_layer.layerFlags = XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT; cylinder_layer.layerFlags = XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT;
cylinder_layer.space = engine->appState.LocalSpace; cylinder_layer.space = engine->appState.CurrentSpace;
cylinder_layer.eyeVisibility = XR_EYE_VISIBILITY_BOTH; cylinder_layer.eyeVisibility = XR_EYE_VISIBILITY_BOTH;
memset(&cylinder_layer.subImage, 0, sizeof(XrSwapchainSubImage)); memset(&cylinder_layer.subImage, 0, sizeof(XrSwapchainSubImage));
cylinder_layer.subImage.swapchain = engine->appState.Renderer.FrameBuffer.ColorSwapChain.Handle; cylinder_layer.subImage.swapchain = engine->appState.Renderer.FrameBuffer.ColorSwapChain.Handle;
@ -510,8 +527,12 @@ void VR_DrawFrame( engine_t* engine ) {
cylinder_layer.subImage.imageRect.extent.height = height; cylinder_layer.subImage.imageRect.extent.height = height;
cylinder_layer.subImage.imageArrayIndex = 0; cylinder_layer.subImage.imageArrayIndex = 0;
const XrVector3f axis = {0.0f, 1.0f, 0.0f}; const XrVector3f axis = {0.0f, 1.0f, 0.0f};
const XrVector3f pos = {xfStageFromHead.position.x, -0.25f, xfStageFromHead.position.z - 4.0f}; XrVector3f pos = {
cylinder_layer.pose.orientation = XrQuaternionf_CreateFromVectorAngle(axis, 0); xfStageFromHead.position.x - sin(radians(vr.menuYaw)) * 4.0f,
-0.25f,
xfStageFromHead.position.z - cos(radians(vr.menuYaw)) * 4.0f
};
cylinder_layer.pose.orientation = XrQuaternionf_CreateFromVectorAngle(axis, radians(vr.menuYaw));
cylinder_layer.pose.position = pos; cylinder_layer.pose.position = pos;
cylinder_layer.radius = 12.0f; cylinder_layer.radius = 12.0f;
cylinder_layer.centralAngle = MATH_PI * 0.5f; cylinder_layer.centralAngle = MATH_PI * 0.5f;

View file

@ -236,7 +236,6 @@ void ovrApp_Clear(ovrApp* app) {
memset(&app->ViewConfigurationView, 0, ovrMaxNumEyes * sizeof(XrViewConfigurationView)); memset(&app->ViewConfigurationView, 0, ovrMaxNumEyes * sizeof(XrViewConfigurationView));
app->SystemId = XR_NULL_SYSTEM_ID; app->SystemId = XR_NULL_SYSTEM_ID;
app->HeadSpace = XR_NULL_HANDLE; app->HeadSpace = XR_NULL_HANDLE;
app->LocalSpace = XR_NULL_HANDLE;
app->StageSpace = XR_NULL_HANDLE; app->StageSpace = XR_NULL_HANDLE;
app->FakeStageSpace = XR_NULL_HANDLE; app->FakeStageSpace = XR_NULL_HANDLE;
app->CurrentSpace = XR_NULL_HANDLE; app->CurrentSpace = XR_NULL_HANDLE;
@ -314,8 +313,9 @@ void ovrApp_HandleSessionStateChanges(ovrApp* app, XrSessionState state) {
} }
} }
void ovrApp_HandleXrEvents(ovrApp* app) { GLboolean ovrApp_HandleXrEvents(ovrApp* app) {
XrEventDataBuffer eventDataBuffer = {}; XrEventDataBuffer eventDataBuffer = {};
GLboolean recenter = GL_FALSE;
// Poll for events // Poll for events
for (;;) { for (;;) {
@ -368,6 +368,7 @@ void ovrApp_HandleXrEvents(ovrApp* app) {
ref_space_change_event->referenceSpaceType, ref_space_change_event->referenceSpaceType,
(void*)ref_space_change_event->session, (void*)ref_space_change_event->session,
FromXrTime(ref_space_change_event->changeTime)); FromXrTime(ref_space_change_event->changeTime));
recenter = GL_TRUE;
} break; } break;
case XR_TYPE_EVENT_DATA_SESSION_STATE_CHANGED: { case XR_TYPE_EVENT_DATA_SESSION_STATE_CHANGED: {
const XrEventDataSessionStateChanged* session_state_changed_event = const XrEventDataSessionStateChanged* session_state_changed_event =
@ -398,6 +399,7 @@ void ovrApp_HandleXrEvents(ovrApp* app) {
break; break;
} }
} }
return recenter;
} }
/* /*

View file

@ -79,7 +79,6 @@ typedef struct {
XrViewConfigurationView ViewConfigurationView[ovrMaxNumEyes]; XrViewConfigurationView ViewConfigurationView[ovrMaxNumEyes];
XrSystemId SystemId; XrSystemId SystemId;
XrSpace HeadSpace; XrSpace HeadSpace;
XrSpace LocalSpace;
XrSpace StageSpace; XrSpace StageSpace;
XrSpace FakeStageSpace; XrSpace FakeStageSpace;
XrSpace CurrentSpace; XrSpace CurrentSpace;
@ -159,7 +158,7 @@ typedef enum {
void ovrApp_Clear(ovrApp* app); void ovrApp_Clear(ovrApp* app);
void ovrApp_Destroy(ovrApp* app); void ovrApp_Destroy(ovrApp* app);
void ovrApp_HandleXrEvents(ovrApp* app); GLboolean ovrApp_HandleXrEvents(ovrApp* app);
void ovrFramebuffer_Acquire(ovrFramebuffer* frameBuffer); void ovrFramebuffer_Acquire(ovrFramebuffer* frameBuffer);
void ovrFramebuffer_Resolve(ovrFramebuffer* frameBuffer); void ovrFramebuffer_Resolve(ovrFramebuffer* frameBuffer);