Still very much WIP....

This commit is contained in:
Simon 2020-03-07 14:56:45 +00:00
parent 6a1b0a43aa
commit 9fb31d9c5e
8 changed files with 367 additions and 86 deletions

View file

@ -46,7 +46,6 @@ bool qzdoom_initialised;
long long global_time;
float playerHeight;
float playerYaw;
bool showingScreenLayer;
float vrFOV;
vec3_t worldPosition;
vec3_t hmdPosition;
@ -153,8 +152,6 @@ LAMBDA1VR Stuff
//This is now controlled by the engine
static bool useVirtualScreen = true;
//And this is controlled by the user
static bool forceVirtualScreen = false;
void setUseScreenLayer(bool use)
{
@ -163,7 +160,7 @@ void setUseScreenLayer(bool use)
bool useScreenLayer()
{
return useVirtualScreen || showingScreenLayer;
return useVirtualScreen;
}
static void UnEscapeQuotes( char *arg )
@ -885,11 +882,13 @@ void getVROrigins(vec3_t _weaponoffset, vec3_t _weaponangles, vec3_t _hmdPositio
void VR_DoomMain(int argc, char** argv);
void VR_GetMove( float *forward, float *side, float *up, float *yaw, float *pitch, float *roll )
void VR_GetMove( float *joy_forward, float *joy_side, float *hmd_forward, float *hmd_side, float *up, float *yaw, float *pitch, float *roll )
{
*forward = remote_movementForward + positional_movementForward;
*joy_forward = remote_movementForward;
*hmd_forward = positional_movementForward;
*up = remote_movementUp;
*side = remote_movementSideways + positional_movementSideways;
*joy_side = remote_movementSideways;
*hmd_side = positional_movementSideways;
*yaw = hmdorientation[YAW] + snapTurn;
*pitch = hmdorientation[PITCH];
*roll = hmdorientation[ROLL];
@ -1280,7 +1279,6 @@ void VR_Init()
{
//Initialise all our variables
playerYaw = 0.0f;
showingScreenLayer = true;
remote_movementSideways = 0.0f;
remote_movementForward = 0.0f;
remote_movementUp = 0.0f;

View file

@ -34,7 +34,6 @@ extern long long global_time;
extern float playerHeight;
extern float playerYaw;
extern bool showingScreenLayer;
extern float vrFOV;
extern vec3_t worldPosition;

View file

@ -35,7 +35,7 @@ void HandleInput_Default( ovrInputStateTrackedRemote *pDominantTrackedRemoteNew,
(pOffTrackedRemoteOld->Buttons & offButton2)) &&
(pOffTrackedRemoteNew->Buttons & offButton2)) {
showingScreenLayer = !showingScreenLayer;
}
//Menu button
@ -153,13 +153,11 @@ void HandleInput_Default( ovrInputStateTrackedRemote *pDominantTrackedRemoteNew,
//This section corrects for the fact that the controller actually controls direction of movement, but we want to move relative to the direction the
//player is facing for positional tracking
float vr_positional_factor = 1700;
float multiplier = (vr_positional_factor) / (1.0 *
((pOffTrackedRemoteNew->Buttons & ovrButton_Trigger) ? 1.5f : 1.0f));
float vr_positional_factor = 8.5f;
vec2_t v;
rotateAboutOrigin(-positionDeltaThisFrame[0] * multiplier,
positionDeltaThisFrame[2] * multiplier, - hmdorientation[YAW], v);
rotateAboutOrigin(-positionDeltaThisFrame[0] * vr_positional_factor,
positionDeltaThisFrame[2] * vr_positional_factor, - hmdorientation[YAW], v);
positional_movementSideways = v[0];
positional_movementForward = v[1];

View file

@ -99,6 +99,7 @@
#include "d_main.h"
#include <QzDoom/VrInput.h>
#include <cmath>
static FRandom pr_dmspawn ("DMSpawn");
@ -570,7 +571,13 @@ static inline int joyint(double val)
}
extern "C" void VR_GetMove( float *forward, float *side, float *up, float *yaw, float *pitch, float *roll );
extern "C" void VR_GetMove( float *joy_forward, float *joy_side, float *hmd_forward, float *hmd_side, float *up, float *yaw, float *pitch, float *roll );
static int mAngleFromRadians(double radians)
{
double m = std::round(65535.0 * radians / (2.0 * M_PI));
return int(m);
}
//
// G_BuildTiccmd
@ -660,23 +667,20 @@ void G_BuildTiccmd (ticcmd_t *cmd)
forward -= forwardmove[speed];
}
float vrforward=0;
float vrside=0;
float joyforward=0;
float hmdforward=0;
float joyside=0;
float hmdside=0;
float up=0;
float yaw=0;
float pitch=0;
float roll=0;
VR_GetMove(&vrforward, &vrside, &up, &yaw, &pitch, &roll);
if (Button_MoveRight.bDown)
side += sidemove[speed];
if (Button_MoveLeft.bDown)
side -= sidemove[speed];
side += vrside;
forward += vrforward;
// buttons
if (Button_Attack.bDown) cmd->ucmd.buttons |= BT_ATTACK;
if (Button_AltAttack.bDown) cmd->ucmd.buttons |= BT_ALTATTACK;
@ -706,44 +710,44 @@ void G_BuildTiccmd (ticcmd_t *cmd)
if (Button_ShowScores.bDown) cmd->ucmd.buttons |= BT_SHOWSCORES;
// Handle joysticks/game controllers.
float joyaxes[NUM_JOYAXIS];
if (0) {
float joyaxes[NUM_JOYAXIS];
I_GetAxes(joyaxes);
I_GetAxes(joyaxes);
// Remap some axes depending on button state.
if (Button_Strafe.bDown || (Button_Mlook.bDown && lookstrafe)) {
joyaxes[JOYAXIS_Side] = joyaxes[JOYAXIS_Yaw];
joyaxes[JOYAXIS_Yaw] = 0;
}
if (Button_Mlook.bDown) {
joyaxes[JOYAXIS_Pitch] = joyaxes[JOYAXIS_Forward];
joyaxes[JOYAXIS_Forward] = 0;
}
// Remap some axes depending on button state.
if (Button_Strafe.bDown || (Button_Mlook.bDown && lookstrafe))
{
joyaxes[JOYAXIS_Side] = joyaxes[JOYAXIS_Yaw];
joyaxes[JOYAXIS_Yaw] = 0;
}
if (Button_Mlook.bDown)
{
joyaxes[JOYAXIS_Pitch] = joyaxes[JOYAXIS_Forward];
joyaxes[JOYAXIS_Forward] = 0;
if (joyaxes[JOYAXIS_Pitch] != 0) {
G_AddViewPitch(joyint(joyaxes[JOYAXIS_Pitch] * 2048));
}
if (joyaxes[JOYAXIS_Yaw] != 0) {
G_AddViewAngle(joyint(-1280 * joyaxes[JOYAXIS_Yaw]));
}
side -= joyint(sidemove[speed] * joyaxes[JOYAXIS_Side]);
forward += joyint(joyaxes[JOYAXIS_Forward] * forwardmove[speed]);
fly += joyint(joyaxes[JOYAXIS_Up] * 2048);
// Handle mice.
if (!Button_Mlook.bDown && !freelook)
{
forward += (int)((float)mousey * m_forward);
}
}
if (joyaxes[JOYAXIS_Pitch] != 0)
{
G_AddViewPitch(joyint(joyaxes[JOYAXIS_Pitch] * 2048));
}
if (joyaxes[JOYAXIS_Yaw] != 0)
{
G_AddViewAngle(joyint(-1280 * joyaxes[JOYAXIS_Yaw]));
}
VR_GetMove(&joyforward, &joyside, &hmdforward, &hmdside, &up, &yaw, &pitch, &roll);
side += (joyint(sidemove[speed] * joyside) + joyint(sidemove[speed] * hmdside));
forward += (joyint(joyforward * forwardmove[speed]) + joyint(hmdforward * forwardmove[speed]));
side -= joyint(sidemove[speed] * joyaxes[JOYAXIS_Side]);
forward += joyint(joyaxes[JOYAXIS_Forward] * forwardmove[speed]);
fly += joyint(joyaxes[JOYAXIS_Up] * 2048);
// Handle mice.
if (!Button_Mlook.bDown && !freelook)
{
forward += (int)((float)mousey * m_forward);
}
#ifdef __MOBILE__
//Mobile_IN_Move(cmd);
#endif
G_SetViewAngle(mAngleFromRadians(-DEG2RAD(hmdorientation[YAW])));
G_SetViewPitch(mAngleFromRadians(-DEG2RAD(hmdorientation[PITCH])));
cmd->ucmd.pitch = LocalViewPitch >> 16;
@ -896,6 +900,51 @@ void G_AddViewAngle (int yaw, bool mouse)
}
}
void G_SetViewPitch (int look)
{
if (gamestate == GS_TITLELEVEL)
{
return;
}
look = LookAdjust(look);
if (look > 0)
{
// Avoid overflowing
if (LocalViewPitch > INT_MAX - look)
{
LocalViewPitch = 0x78000000;
}
else
{
LocalViewPitch = MIN(look, 0x78000000);
}
}
else if (look < 0)
{
// Avoid overflowing
if (LocalViewPitch < INT_MIN - look)
{
LocalViewPitch = -0x78000000;
}
else
{
LocalViewPitch = MAX(look, -0x78000000);
}
}
}
void G_SetViewAngle (int yaw)
{
if (gamestate == GS_TITLELEVEL)
{
return;
}
yaw = LookAdjust(yaw);
LocalViewAngle = yaw;
}
CVAR (Bool, bot_allowspy, false, 0)

View file

@ -101,6 +101,9 @@ void G_AddViewPitch (int look, bool mouse = false);
// Adds to consoleplayer's viewangle if allowed
void G_AddViewAngle (int yaw, bool mouse = false);
void G_SetViewPitch (int look);
void G_SetViewAngle (int yaw);
extern const AActor *SendItemUse, *SendItemDrop;
extern int SendItemDropAmount;
extern bool doquicksave;

View file

@ -0,0 +1,157 @@
//
//---------------------------------------------------------------------------
//
// Copyright(C) 2016-2017 Christopher Bruns
// All rights reserved.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see http://www.gnu.org/licenses/
//
//--------------------------------------------------------------------------
//
/*
** LSMatrix.h
** less-simple matrix class
*/
#ifndef VR_LS_MATRIX_H_
#define VR_LS_MATRIX_H_
#include "gl/data/gl_matrix.h"
#include "openvr.h"
struct HmdMatrix34_t;
class LSVec3
{
public:
LSVec3(FLOATTYPE x, FLOATTYPE y, FLOATTYPE z, FLOATTYPE w=1.0f)
: x(mVec[0]), y(mVec[1]), z(mVec[2]), w(mVec[3])
{
mVec[0] = x;
mVec[1] = y;
mVec[2] = z;
mVec[3] = w;
}
LSVec3(const LSVec3& rhs)
: x(mVec[0]), y(mVec[1]), z(mVec[2]), w(mVec[3])
{
*this = rhs;
}
LSVec3& operator=(const LSVec3& rhs) {
LSVec3& lhs = *this;
for (int i = 0; i < 4; ++i)
lhs[i] = rhs[i];
return *this;
}
LSVec3& operator+=(const LSVec3& rhs) {
LSVec3& lhs = *this;
for (int i = 0; i < 4; ++i)
lhs[i] += rhs[i];
return *this;
}
const FLOATTYPE& operator[](int i) const {return mVec[i];}
FLOATTYPE& operator[](int i) { return mVec[i]; }
LSVec3 operator-(const LSVec3& rhs) const {
const LSVec3& lhs = *this;
LSVec3 result = *this;
for (int i = 0; i < 4; ++i)
result[i] -= rhs[i];
return result;
}
FLOATTYPE mVec[4];
FLOATTYPE& x;
FLOATTYPE& y;
FLOATTYPE& z;
FLOATTYPE& w;
};
LSVec3 operator*(FLOATTYPE s, const LSVec3& rhs) {
LSVec3 result = rhs;
for (int i = 0; i < 4; ++i)
result[i] *= s;
return result;
}
class LSMatrix44 : public VSMatrix
{
public:
LSMatrix44()
{
loadIdentity();
}
LSMatrix44(const HmdMatrix34_t& m) {
loadIdentity();
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 4; ++j) {
(*this)[i][j] = m.m[i][j];
}
}
}
LSMatrix44(const VSMatrix& m) {
m.copy(mMatrix);
}
// overload bracket operator to return one row of the matrix, so you can invoke, say, m[2][3]
FLOATTYPE* operator[](int i) {return &mMatrix[i*4];}
const FLOATTYPE* operator[](int i) const { return &mMatrix[i * 4]; }
LSMatrix44 operator*(const VSMatrix& rhs) const {
LSMatrix44 result(*this);
result.multMatrix(rhs);
return result;
}
LSVec3 operator*(const LSVec3& rhs) const {
const LSMatrix44& lhs = *this;
LSVec3 result(0, 0, 0, 0);
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
result[i] += lhs[i][j] * rhs[j];
}
}
return result;
}
LSMatrix44 getWithoutTranslation() const {
LSMatrix44 m = *this;
// Remove translation component
m[3][3] = 1.0f;
m[3][2] = m[3][1] = m[3][0] = 0.0f;
m[2][3] = m[1][3] = m[0][3] = 0.0f;
return m;
}
LSMatrix44 transpose() const {
LSMatrix44 result;
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
result[i][j] = (*this)[j][i];
}
}
return result;
}
};
#endif // VR_LS_MATRIX_H_

View file

@ -51,6 +51,7 @@
#include "d_event.h"
#include "QzDoom/VrCommon.h"
#include "LSMatrix.h"
EXTERN_CVAR(Int, screenblocks);
@ -120,6 +121,95 @@ namespace s3d
{
doomYawDegrees = yaw;
outViewShift[0] = outViewShift[1] = outViewShift[2] = 0;
// Pitch and Roll are identical between vr and Doom worlds.
// But yaw can differ, depending on starting state, and controller movement.
float doomYawDegrees = yaw;
deltaYawDegrees = doomYawDegrees - hmdorientation[YAW];
while (deltaYawDegrees > 180)
deltaYawDegrees -= 360;
while (deltaYawDegrees < -180)
deltaYawDegrees += 360;
DAngle vr_to_doom_angle = DAngle(-deltaYawDegrees);
const Stereo3DMode * mode3d = &Stereo3DMode::getCurrentMode();
if (mode3d->IsMono())
return;
const OculusQuestMode * vrMode = static_cast<const OculusQuestMode *>(mode3d);
ovrTracking2 tracking;
vrMode->getTracking(&tracking);
/*
// extract rotation component from hmd transform
LSMatrix44 vr_X_hmd(hmdPose);
LSMatrix44 hmdRot = vr_X_hmd.getWithoutTranslation(); // .transpose();
/// In these eye methods, just get local inter-eye stereoscopic shift, not full position shift ///
// compute local eye shift
LSMatrix44 eyeShift2;
eyeShift2.loadIdentity();
eyeShift2 = eyeShift2 * eyeToHeadTransform; // eye to head
eyeShift2 = eyeShift2 * hmdRot; // head to vr
LSVec3 eye_EyePos = LSVec3(0, 0, 0); // eye position in eye frame
LSVec3 hmd_EyePos = LSMatrix44(eyeToHeadTransform) * eye_EyePos;
LSVec3 hmd_HmdPos = LSVec3(0, 0, 0); // hmd position in hmd frame
LSVec3 vr_EyePos = vr_X_hmd * hmd_EyePos;
LSVec3 vr_HmdPos = vr_X_hmd * hmd_HmdPos;
LSVec3 hmd_OtherEyePos = LSMatrix44(otherEyeToHeadTransform) * eye_EyePos;
LSVec3 vr_OtherEyePos = vr_X_hmd * hmd_OtherEyePos;
LSVec3 vr_EyeOffset = vr_EyePos - vr_HmdPos;
VSMatrix doomInvr = VSMatrix();
doomInvr.loadIdentity();
// permute axes
float permute[] = { // Convert from vr to Doom axis convention, including mirror inversion
-1, 0, 0, 0, // X-right in vr -> X-left in Doom
0, 0, 1, 0, // Z-backward in vr -> Y-backward in Doom
0, 1, 0, 0, // Y-up in vr -> Z-up in Doom
0, 0, 0, 1};
doomInvr.multMatrix(permute);
doomInvr.scale(vr_vunits_per_meter, vr_vunits_per_meter, vr_vunits_per_meter); // Doom units are not meters
double pixelstretch = level.info ? level.info->pixelstretch : 1.2;
doomInvr.scale(pixelstretch, pixelstretch, 1.0); // Doom universe is scaled by 1990s pixel aspect ratio
doomInvr.rotate(deltaYawDegrees, 0, 0, 1);
LSVec3 doom_EyeOffset = LSMatrix44(doomInvr) * vr_EyeOffset;
if (doTrackHmdVerticalPosition) {
// In vr, the real world floor level is at y==0
// In Doom, the virtual player foot level is viewheight below the current viewpoint (on the Z axis)
// We want to align those two heights here
const player_t & player = players[consoleplayer];
double vh = player.viewheight; // Doom thinks this is where you are
double hh = (vr_X_hmd[1][3] - vr_floor_offset) * vr_vunits_per_meter; // HMD is actually here
doom_EyeOffset[2] += hh - vh;
// TODO: optionally allow player to jump and crouch by actually jumping and crouching
}
if (doTrackHmdHorizontalPosition) {
// shift viewpoint when hmd position shifts
static bool is_initial_origin_set = false;
if (! is_initial_origin_set) {
// initialize origin to first noted HMD location
// TODO: implement recentering based on a CCMD
vr_origin = vr_HmdPos;
is_initial_origin_set = true;
}
vr_dpos = vr_HmdPos - vr_origin;
LSVec3 doom_dpos = LSMatrix44(doomInvr) * vr_dpos;
doom_EyeOffset[0] += doom_dpos[0];
doom_EyeOffset[1] += doom_dpos[1];
}
outViewShift[0] = doom_EyeOffset[0];
outViewShift[1] = doom_EyeOffset[1];
outViewShift[2] = doom_EyeOffset[2];
*/
}
/* virtual */
@ -175,12 +265,12 @@ namespace s3d
// Follow HMD orientation, EXCEPT for roll angle (keep weapon upright)
/*if (activeEye->currentPose) {
float openVrRollDegrees = RAD2DEG(-eulerAnglesFromMatrix(activeEye->currentPose->mDeviceToAbsoluteTracking).v[2]);
new_projection.rotate(-openVrRollDegrees, 0, 0, 1);
float vrRollDegrees = RAD2DEG(-eulerAnglesFromMatrix(activeEye->currentPose->mDeviceToAbsoluteTracking).v[2]);
new_projection.rotate(-vrRollDegrees, 0, 0, 1);
if (doFixPitch) {
float openVrPitchDegrees = RAD2DEG(-eulerAnglesFromMatrix(activeEye->currentPose->mDeviceToAbsoluteTracking).v[1]);
new_projection.rotate(-openVrPitchDegrees, 1, 0, 0);
float vrPitchDegrees = RAD2DEG(-eulerAnglesFromMatrix(activeEye->currentPose->mDeviceToAbsoluteTracking).v[1]);
new_projection.rotate(-vrPitchDegrees, 1, 0, 0);
}
if (pitchOffset != 0)
new_projection.rotate(-pitchOffset, 1, 0, 0);
@ -213,24 +303,6 @@ namespace s3d
const Stereo3DMode * mode3d = &Stereo3DMode::getCurrentMode();
if (mode3d->IsMono())
return;
const OculusQuestMode * oculusQuestMode = static_cast<const OculusQuestMode *>(mode3d);
if (oculusQuestMode
&& oculusQuestMode->crossHairDrawer
// Don't draw the crosshair if there is none
&& CrosshairImage != NULL
&& gamestate != GS_TITLELEVEL
&& r_viewpoint.camera->health > 0)
{
const float crosshair_distance_meters = 10.0f; // meters
const float crosshair_width_meters = 0.2f * crosshair_distance_meters;
gl_RenderState.mProjectionMatrix = getQuadInWorld(
crosshair_distance_meters,
crosshair_width_meters,
false,
0.0);
gl_RenderState.ApplyMatrices();
oculusQuestMode->crossHairDrawer->Draw();
}
// Update HUD matrix to render on a separate quad
const float menu_distance_meters = 1.0f;
@ -280,6 +352,11 @@ namespace s3d
crossHairDrawer->Clear();
}
void OculusQuestMode::getTracking(ovrTracking2 *_tracking) const
{
*_tracking = tracking;
}
/* virtual */
// AdjustViewports() is called from within FLGRenderer::SetOutputViewport(...)
void OculusQuestMode::AdjustViewports() const
@ -586,7 +663,7 @@ namespace s3d
gl_multisample = 4;
}
if (gamestate == GS_LEVEL) {
if (gamestate == GS_LEVEL && !isMenuActive()) {
cachedScreenBlocks = screenblocks;
screenblocks = 12; // always be full-screen during 3D scene render
setUseScreenLayer(false);
@ -660,7 +737,11 @@ namespace s3d
//G_AddViewAngle(joyint(-1280 * I_OculusQuestGetYaw() * delta * 30 / 1000));
*/
updateHmdPose();
//Always update roll (as the game tic cmd doesn't support roll
GLRenderer->mAngles.Roll = hmdorientation[ROLL];
//updateHmdPose();
}
@ -682,19 +763,13 @@ namespace s3d
/* */
// Pitch
{
double pixelstretch = level.info ? level.info->pixelstretch : 1.2;
double hmdPitchInDoom = -atan(tan(DEG2RAD(hmdorientation[PITCH])) / pixelstretch);
double viewPitchInDoom = GLRenderer->mAngles.Pitch.Radians();
double dPitch =
// hmdPitchInDoom
- DEG2RAD(hmdorientation[PITCH])
- viewPitchInDoom;
G_AddViewPitch(mAngleFromRadians(dPitch));
}
// Roll can be local, because it doesn't affect gameplay.
GLRenderer->mAngles.Roll = hmdorientation[ROLL];
{
GLRenderer->mAngles.Pitch = hmdorientation[PITCH];

View file

@ -89,6 +89,8 @@ public:
virtual bool RenderPlayerSpritesCrossed() const { return true; }
virtual bool RenderPlayerSpritesInScene() const { return true; }
void getTracking(ovrTracking2 *tracking) const;
protected:
OculusQuestMode();