mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-25 18:55:01 +02:00
Merge pull request #3579 from ctrlaltdavid/20073
CR for Job #20073 - Automatically calibrate the Oculus Rift after startup
This commit is contained in:
commit
ad64ea62a1
8 changed files with 208 additions and 53 deletions
|
@ -1089,6 +1089,9 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
|||
case Qt::Key_Equal:
|
||||
_myAvatar->resetSize();
|
||||
break;
|
||||
case Qt::Key_Escape:
|
||||
OculusManager::abandonCalibration();
|
||||
break;
|
||||
default:
|
||||
event->ignore();
|
||||
break;
|
||||
|
@ -1481,6 +1484,9 @@ void Application::setEnableVRMode(bool enableVRMode) {
|
|||
OculusManager::disconnect();
|
||||
OculusManager::connect();
|
||||
}
|
||||
OculusManager::recalibrate();
|
||||
} else {
|
||||
OculusManager::abandonCalibration();
|
||||
}
|
||||
|
||||
resizeGL(_glWidget->getDeviceWidth(), _glWidget->getDeviceHeight());
|
||||
|
|
|
@ -365,6 +365,8 @@ public slots:
|
|||
|
||||
void domainSettingsReceived(const QJsonObject& domainSettingsObject);
|
||||
|
||||
void resetSensors();
|
||||
|
||||
private slots:
|
||||
void timer();
|
||||
void idle();
|
||||
|
@ -381,7 +383,6 @@ private slots:
|
|||
void closeMirrorView();
|
||||
void restoreMirrorView();
|
||||
void shrinkMirrorView();
|
||||
void resetSensors();
|
||||
|
||||
void parseVersionXml();
|
||||
|
||||
|
|
|
@ -55,6 +55,20 @@ bool OculusManager::_programInitialized = false;
|
|||
Camera* OculusManager::_camera = NULL;
|
||||
int OculusManager::_activeEyeIndex = -1;
|
||||
|
||||
float OculusManager::CALIBRATION_DELTA_MINIMUM_LENGTH = 0.02f;
|
||||
float OculusManager::CALIBRATION_DELTA_MINIMUM_ANGLE = 5.f * RADIANS_PER_DEGREE;
|
||||
float OculusManager::CALIBRATION_ZERO_MAXIMUM_LENGTH = 0.01f;
|
||||
float OculusManager::CALIBRATION_ZERO_MAXIMUM_ANGLE = 2.0f * RADIANS_PER_DEGREE;
|
||||
quint64 OculusManager::CALIBRATION_ZERO_HOLD_TIME = 3000000; // usec
|
||||
float OculusManager::CALIBRATION_MESSAGE_DISTANCE = 2.5f;
|
||||
OculusManager::CalibrationState OculusManager::_calibrationState;
|
||||
glm::vec3 OculusManager::_calibrationPosition;
|
||||
glm::quat OculusManager::_calibrationOrientation;
|
||||
quint64 OculusManager::_calibrationStartTime;
|
||||
int OculusManager::_calibrationMessage = NULL;
|
||||
QString OculusManager::CALIBRATION_BILLBOARD_URL = "http://hifi-public.s3.amazonaws.com/images/hold-to-calibrate.svg";
|
||||
float OculusManager::CALIBRATION_BILLBOARD_SCALE = 2.f;
|
||||
|
||||
#endif
|
||||
|
||||
glm::vec3 OculusManager::_leftEyePosition = glm::vec3();
|
||||
|
@ -62,6 +76,8 @@ glm::vec3 OculusManager::_rightEyePosition = glm::vec3();
|
|||
|
||||
void OculusManager::connect() {
|
||||
#ifdef HAVE_LIBOVR
|
||||
_calibrationState = UNCALIBRATED;
|
||||
|
||||
ovr_Initialize();
|
||||
|
||||
_ovrHmd = ovrHmd_Create(0);
|
||||
|
@ -172,6 +188,121 @@ void OculusManager::disconnect() {
|
|||
#endif
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBOVR
|
||||
void OculusManager::positionCalibrationBillboard(BillboardOverlay* billboard) {
|
||||
glm::quat headOrientation = Application::getInstance()->getAvatar()->getHeadOrientation();
|
||||
headOrientation.x = 0;
|
||||
headOrientation.z = 0;
|
||||
glm::normalize(headOrientation);
|
||||
billboard->setPosition(Application::getInstance()->getAvatar()->getHeadPosition()
|
||||
+ headOrientation * glm::vec3(0.f, 0.f, -CALIBRATION_MESSAGE_DISTANCE));
|
||||
billboard->setRotation(headOrientation);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LIBOVR
|
||||
void OculusManager::calibrate(glm::vec3 position, glm::quat orientation) {
|
||||
static QString progressMessage;
|
||||
static BillboardOverlay* billboard;
|
||||
|
||||
switch (_calibrationState) {
|
||||
|
||||
case UNCALIBRATED:
|
||||
if (position != glm::vec3() && orientation != glm::quat()) { // Handle zero values at start-up.
|
||||
_calibrationPosition = position;
|
||||
_calibrationOrientation = orientation;
|
||||
_calibrationState = WAITING_FOR_DELTA;
|
||||
}
|
||||
break;
|
||||
|
||||
case WAITING_FOR_DELTA:
|
||||
if (glm::length(position - _calibrationPosition) > CALIBRATION_DELTA_MINIMUM_LENGTH
|
||||
|| glm::angle(orientation * glm::inverse(_calibrationOrientation)) > CALIBRATION_DELTA_MINIMUM_ANGLE) {
|
||||
_calibrationPosition = position;
|
||||
_calibrationOrientation = orientation;
|
||||
_calibrationState = WAITING_FOR_ZERO;
|
||||
}
|
||||
break;
|
||||
|
||||
case WAITING_FOR_ZERO:
|
||||
if (glm::length(position - _calibrationPosition) < CALIBRATION_ZERO_MAXIMUM_LENGTH
|
||||
&& glm::angle(orientation * glm::inverse(_calibrationOrientation)) < CALIBRATION_ZERO_MAXIMUM_ANGLE) {
|
||||
_calibrationStartTime = usecTimestampNow();
|
||||
_calibrationState = WAITING_FOR_ZERO_HELD;
|
||||
|
||||
if (!_calibrationMessage) {
|
||||
qDebug() << "Hold still to calibrate HMD";
|
||||
|
||||
billboard = new BillboardOverlay();
|
||||
billboard->setURL(CALIBRATION_BILLBOARD_URL);
|
||||
billboard->setScale(CALIBRATION_BILLBOARD_SCALE);
|
||||
billboard->setIsFacingAvatar(false);
|
||||
positionCalibrationBillboard(billboard);
|
||||
|
||||
_calibrationMessage = Application::getInstance()->getOverlays().addOverlay(billboard);
|
||||
}
|
||||
|
||||
progressMessage = "";
|
||||
} else {
|
||||
_calibrationPosition = position;
|
||||
_calibrationOrientation = orientation;
|
||||
}
|
||||
break;
|
||||
|
||||
case WAITING_FOR_ZERO_HELD:
|
||||
if (glm::length(position - _calibrationPosition) < CALIBRATION_ZERO_MAXIMUM_LENGTH
|
||||
&& glm::angle(orientation * glm::inverse(_calibrationOrientation)) < CALIBRATION_ZERO_MAXIMUM_ANGLE) {
|
||||
if ((usecTimestampNow() - _calibrationStartTime) > CALIBRATION_ZERO_HOLD_TIME) {
|
||||
_calibrationState = CALIBRATED;
|
||||
qDebug() << "HMD calibrated";
|
||||
Application::getInstance()->getOverlays().deleteOverlay(_calibrationMessage);
|
||||
_calibrationMessage = NULL;
|
||||
Application::getInstance()->resetSensors();
|
||||
} else {
|
||||
quint64 quarterSeconds = (usecTimestampNow() - _calibrationStartTime) / 250000;
|
||||
if (quarterSeconds + 1 > progressMessage.length()) {
|
||||
// 3...2...1...
|
||||
if (quarterSeconds == 4 * (quarterSeconds / 4)) {
|
||||
quint64 wholeSeconds = CALIBRATION_ZERO_HOLD_TIME / 1000000 - quarterSeconds / 4;
|
||||
|
||||
if (wholeSeconds == 3) {
|
||||
positionCalibrationBillboard(billboard);
|
||||
}
|
||||
|
||||
progressMessage += QString::number(wholeSeconds);
|
||||
} else {
|
||||
progressMessage += ".";
|
||||
}
|
||||
//qDebug() << progressMessage; // Progress message ready for 3D text overlays.
|
||||
}
|
||||
}
|
||||
} else {
|
||||
_calibrationPosition = position;
|
||||
_calibrationOrientation = orientation;
|
||||
_calibrationState = WAITING_FOR_ZERO;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void OculusManager::recalibrate() {
|
||||
#ifdef HAVE_LIBOVR
|
||||
_calibrationState = UNCALIBRATED;
|
||||
#endif
|
||||
}
|
||||
|
||||
void OculusManager::abandonCalibration() {
|
||||
#ifdef HAVE_LIBOVR
|
||||
_calibrationState = CALIBRATED;
|
||||
if (_calibrationMessage) {
|
||||
qDebug() << "Abandoned HMD calibration";
|
||||
Application::getInstance()->getOverlays().deleteOverlay(_calibrationMessage);
|
||||
_calibrationMessage = NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBOVR
|
||||
void OculusManager::generateDistortionMesh() {
|
||||
|
||||
|
@ -325,6 +456,13 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p
|
|||
ovrVector3f ovrHeadPosition = ts.HeadPose.ThePose.Position;
|
||||
|
||||
trackerPosition = glm::vec3(ovrHeadPosition.x, ovrHeadPosition.y, ovrHeadPosition.z);
|
||||
|
||||
if (_calibrationState != CALIBRATED) {
|
||||
ovrQuatf ovrHeadOrientation = ts.HeadPose.ThePose.Orientation;
|
||||
orientation = glm::quat(ovrHeadOrientation.w, ovrHeadOrientation.x, ovrHeadOrientation.y, ovrHeadOrientation.z);
|
||||
calibrate(trackerPosition, orientation);
|
||||
}
|
||||
|
||||
trackerPosition = bodyOrientation * trackerPosition;
|
||||
#endif
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#endif
|
||||
|
||||
#include "renderer/ProgramObject.h"
|
||||
#include "ui/overlays/BillboardOverlay.h"
|
||||
|
||||
const float DEFAULT_OCULUS_UI_ANGULAR_SIZE = 72.0f;
|
||||
|
||||
|
@ -30,6 +31,8 @@ public:
|
|||
static void connect();
|
||||
static void disconnect();
|
||||
static bool isConnected();
|
||||
static void recalibrate();
|
||||
static void abandonCalibration();
|
||||
static void beginFrameTiming();
|
||||
static void endFrameTiming();
|
||||
static void configureCamera(Camera& camera, int screenWidth, int screenHeight);
|
||||
|
@ -99,6 +102,30 @@ private:
|
|||
static bool _programInitialized;
|
||||
static Camera* _camera;
|
||||
static int _activeEyeIndex;
|
||||
|
||||
static void calibrate(const glm::vec3 position, const glm::quat orientation);
|
||||
enum CalibrationState {
|
||||
UNCALIBRATED,
|
||||
WAITING_FOR_DELTA,
|
||||
WAITING_FOR_ZERO,
|
||||
WAITING_FOR_ZERO_HELD,
|
||||
CALIBRATED
|
||||
};
|
||||
static void positionCalibrationBillboard(BillboardOverlay* billboard);
|
||||
static float CALIBRATION_DELTA_MINIMUM_LENGTH;
|
||||
static float CALIBRATION_DELTA_MINIMUM_ANGLE;
|
||||
static float CALIBRATION_ZERO_MAXIMUM_LENGTH;
|
||||
static float CALIBRATION_ZERO_MAXIMUM_ANGLE;
|
||||
static quint64 CALIBRATION_ZERO_HOLD_TIME;
|
||||
static float CALIBRATION_MESSAGE_DISTANCE;
|
||||
static CalibrationState _calibrationState;
|
||||
static glm::vec3 _calibrationPosition;
|
||||
static glm::quat _calibrationOrientation;
|
||||
static quint64 _calibrationStartTime;
|
||||
static int _calibrationMessage;
|
||||
static QString CALIBRATION_BILLBOARD_URL;
|
||||
static float CALIBRATION_BILLBOARD_SCALE;
|
||||
|
||||
#endif
|
||||
|
||||
static glm::vec3 _leftEyePosition;
|
||||
|
|
|
@ -156,9 +156,14 @@ void BillboardOverlay::setProperties(const QScriptValue &properties) {
|
|||
}
|
||||
}
|
||||
|
||||
void BillboardOverlay::setURL(const QString& url) {
|
||||
setBillboardURL(url);
|
||||
}
|
||||
|
||||
void BillboardOverlay::setBillboardURL(const QString& url) {
|
||||
_url = url;
|
||||
QUrl actualURL = url;
|
||||
|
||||
_isLoaded = false;
|
||||
|
||||
// clear the billboard if previously set
|
||||
|
|
|
@ -24,6 +24,12 @@ public:
|
|||
BillboardOverlay();
|
||||
|
||||
virtual void render();
|
||||
|
||||
// setters
|
||||
void setURL(const QString& url);
|
||||
void setScale(float scale) { _scale = scale; }
|
||||
void setIsFacingAvatar(bool isFacingAvatar) { _isFacingAvatar = isFacingAvatar; }
|
||||
|
||||
virtual void setProperties(const QScriptValue& properties);
|
||||
void setClipFromSource(const QRect& bounds) { _fromImage = bounds; }
|
||||
|
||||
|
|
|
@ -124,90 +124,59 @@ void Overlays::render3D() {
|
|||
|
||||
unsigned int Overlays::addOverlay(const QString& type, const QScriptValue& properties) {
|
||||
unsigned int thisID = 0;
|
||||
bool created = false;
|
||||
bool is3D = false;
|
||||
Overlay* thisOverlay = NULL;
|
||||
|
||||
bool created = true;
|
||||
if (type == "image") {
|
||||
thisOverlay = new ImageOverlay();
|
||||
thisOverlay->init(_parent);
|
||||
thisOverlay->setProperties(properties);
|
||||
created = true;
|
||||
} else if (type == "text") {
|
||||
thisOverlay = new TextOverlay();
|
||||
thisOverlay->init(_parent);
|
||||
thisOverlay->setProperties(properties);
|
||||
created = true;
|
||||
} else if (type == "cube") {
|
||||
thisOverlay = new Cube3DOverlay();
|
||||
thisOverlay->init(_parent);
|
||||
thisOverlay->setProperties(properties);
|
||||
created = true;
|
||||
is3D = true;
|
||||
} else if (type == "sphere") {
|
||||
thisOverlay = new Sphere3DOverlay();
|
||||
thisOverlay->init(_parent);
|
||||
thisOverlay->setProperties(properties);
|
||||
created = true;
|
||||
is3D = true;
|
||||
} else if (type == "circle3d") {
|
||||
thisOverlay = new Circle3DOverlay();
|
||||
thisOverlay->init(_parent);
|
||||
thisOverlay->setProperties(properties);
|
||||
created = true;
|
||||
is3D = true;
|
||||
} else if (type == "rectangle3d") {
|
||||
thisOverlay = new Rectangle3DOverlay();
|
||||
thisOverlay->init(_parent);
|
||||
thisOverlay->setProperties(properties);
|
||||
created = true;
|
||||
is3D = true;
|
||||
} else if (type == "line3d") {
|
||||
thisOverlay = new Line3DOverlay();
|
||||
thisOverlay->init(_parent);
|
||||
thisOverlay->setProperties(properties);
|
||||
created = true;
|
||||
is3D = true;
|
||||
} else if (type == "localvoxels") {
|
||||
thisOverlay = new LocalVoxelsOverlay();
|
||||
thisOverlay->init(_parent);
|
||||
thisOverlay->setProperties(properties);
|
||||
created = true;
|
||||
is3D = true;
|
||||
} else if (type == "localmodels") {
|
||||
thisOverlay = new LocalModelsOverlay(Application::getInstance()->getEntityClipboardRenderer());
|
||||
thisOverlay->init(_parent);
|
||||
thisOverlay->setProperties(properties);
|
||||
created = true;
|
||||
is3D = true;
|
||||
} else if (type == "model") {
|
||||
thisOverlay = new ModelOverlay();
|
||||
thisOverlay->init(_parent);
|
||||
thisOverlay->setProperties(properties);
|
||||
created = true;
|
||||
is3D = true;
|
||||
} else if (type == "billboard") {
|
||||
thisOverlay = new BillboardOverlay();
|
||||
thisOverlay->init(_parent);
|
||||
thisOverlay->setProperties(properties);
|
||||
created = true;
|
||||
is3D = true;
|
||||
} else {
|
||||
created = false;
|
||||
}
|
||||
|
||||
if (created) {
|
||||
QWriteLocker lock(&_lock);
|
||||
thisID = _nextOverlayID;
|
||||
_nextOverlayID++;
|
||||
if (is3D) {
|
||||
_overlays3D[thisID] = thisOverlay;
|
||||
} else {
|
||||
_overlays2D[thisID] = thisOverlay;
|
||||
}
|
||||
thisOverlay->setProperties(properties);
|
||||
thisID = addOverlay(thisOverlay);
|
||||
}
|
||||
|
||||
return thisID;
|
||||
}
|
||||
|
||||
unsigned int Overlays::addOverlay(Overlay* overlay) {
|
||||
overlay->init(_parent);
|
||||
|
||||
QWriteLocker lock(&_lock);
|
||||
unsigned int thisID = _nextOverlayID;
|
||||
_nextOverlayID++;
|
||||
bool is3D = typeid(*overlay) != typeid(ImageOverlay) && typeid(*overlay) != typeid(TextOverlay);
|
||||
if (is3D) {
|
||||
_overlays3D[thisID] = overlay;
|
||||
} else {
|
||||
_overlays2D[thisID] = overlay;
|
||||
}
|
||||
|
||||
return thisID;
|
||||
}
|
||||
|
||||
bool Overlays::editOverlay(unsigned int id, const QScriptValue& properties) {
|
||||
Overlay* thisOverlay = NULL;
|
||||
QWriteLocker lock(&_lock);
|
||||
|
|
|
@ -44,6 +44,9 @@ public slots:
|
|||
/// adds an overlay with the specific properties
|
||||
unsigned int addOverlay(const QString& type, const QScriptValue& properties);
|
||||
|
||||
/// adds an overlay that's already been created
|
||||
unsigned int addOverlay(Overlay* overlay);
|
||||
|
||||
/// edits an overlay updating only the included properties, will return the identified OverlayID in case of
|
||||
/// successful edit, if the input id is for an unknown overlay this function will have no effect
|
||||
bool editOverlay(unsigned int id, const QScriptValue& properties);
|
||||
|
|
Loading…
Reference in a new issue