mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-07-10 05:50:28 +02:00
Merge pull request #6009 from jherico/homer
Enabling programmatic access to the IPD scale
This commit is contained in:
commit
05fd62ac51
22 changed files with 291 additions and 108 deletions
42
examples/example/hmd/ipdScalingTest.js
Normal file
42
examples/example/hmd/ipdScalingTest.js
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
//
|
||||||
|
// Created by Bradley Austin Davis on 2015/10/04
|
||||||
|
// Copyright 2013-2015 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
IPDScalingTest = function() {
|
||||||
|
// Switch every 5 seconds between normal IPD and 0 IPD (in seconds)
|
||||||
|
this.UPDATE_INTERVAL = 10.0;
|
||||||
|
this.lastUpdateInterval = 0;
|
||||||
|
this.scaled = false;
|
||||||
|
|
||||||
|
var that = this;
|
||||||
|
Script.scriptEnding.connect(function() {
|
||||||
|
that.onCleanup();
|
||||||
|
});
|
||||||
|
|
||||||
|
Script.update.connect(function(deltaTime) {
|
||||||
|
that.lastUpdateInterval += deltaTime;
|
||||||
|
if (that.lastUpdateInterval >= that.UPDATE_INTERVAL) {
|
||||||
|
that.onUpdate(that.lastUpdateInterval);
|
||||||
|
that.lastUpdateInterval = 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
IPDScalingTest.prototype.onCleanup = function() {
|
||||||
|
HMD.setIPDScale(1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
IPDScalingTest.prototype.onUpdate = function(deltaTime) {
|
||||||
|
this.scaled = !this.scaled;
|
||||||
|
if (this.scaled) {
|
||||||
|
HMD.ipdScale = 0.0;
|
||||||
|
} else {
|
||||||
|
HMD.ipdScale = 1.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
new IPDScalingTest();
|
|
@ -306,6 +306,7 @@ bool setupEssentials(int& argc, char** argv) {
|
||||||
DependencyManager::set<DesktopScriptingInterface>();
|
DependencyManager::set<DesktopScriptingInterface>();
|
||||||
DependencyManager::set<EntityScriptingInterface>();
|
DependencyManager::set<EntityScriptingInterface>();
|
||||||
DependencyManager::set<WindowScriptingInterface>();
|
DependencyManager::set<WindowScriptingInterface>();
|
||||||
|
DependencyManager::set<HMDScriptingInterface>();
|
||||||
#if defined(Q_OS_MAC) || defined(Q_OS_WIN)
|
#if defined(Q_OS_MAC) || defined(Q_OS_WIN)
|
||||||
DependencyManager::set<SpeechRecognizer>();
|
DependencyManager::set<SpeechRecognizer>();
|
||||||
#endif
|
#endif
|
||||||
|
@ -1166,9 +1167,11 @@ void Application::paintGL() {
|
||||||
// right eye. There are FIXMEs in the relevant plugins
|
// right eye. There are FIXMEs in the relevant plugins
|
||||||
_myCamera.setProjection(displayPlugin->getProjection(Mono, _myCamera.getProjection()));
|
_myCamera.setProjection(displayPlugin->getProjection(Mono, _myCamera.getProjection()));
|
||||||
renderArgs._context->enableStereo(true);
|
renderArgs._context->enableStereo(true);
|
||||||
mat4 eyeViews[2];
|
mat4 eyeOffsets[2];
|
||||||
mat4 eyeProjections[2];
|
mat4 eyeProjections[2];
|
||||||
auto baseProjection = renderArgs._viewFrustum->getProjection();
|
auto baseProjection = renderArgs._viewFrustum->getProjection();
|
||||||
|
auto hmdInterface = DependencyManager::get<HMDScriptingInterface>();
|
||||||
|
float IPDScale = hmdInterface->getIPDScale();
|
||||||
// FIXME we probably don't need to set the projection matrix every frame,
|
// FIXME we probably don't need to set the projection matrix every frame,
|
||||||
// only when the display plugin changes (or in non-HMD modes when the user
|
// only when the display plugin changes (or in non-HMD modes when the user
|
||||||
// changes the FOV manually, which right now I don't think they can.
|
// changes the FOV manually, which right now I don't think they can.
|
||||||
|
@ -1177,14 +1180,24 @@ void Application::paintGL() {
|
||||||
// applied to the avatar, so we need to get the difference between the head
|
// applied to the avatar, so we need to get the difference between the head
|
||||||
// pose applied to the avatar and the per eye pose, and use THAT as
|
// pose applied to the avatar and the per eye pose, and use THAT as
|
||||||
// the per-eye stereo matrix adjustment.
|
// the per-eye stereo matrix adjustment.
|
||||||
mat4 eyePose = displayPlugin->getEyePose(eye);
|
mat4 eyeToHead = displayPlugin->getEyeToHeadTransform(eye);
|
||||||
|
// Grab the translation
|
||||||
|
vec3 eyeOffset = glm::vec3(eyeToHead[3]);
|
||||||
|
// Apply IPD scaling
|
||||||
|
mat4 eyeOffsetTransform = glm::translate(mat4(), eyeOffset * -1.0f * IPDScale);
|
||||||
|
eyeOffsets[eye] = eyeOffsetTransform;
|
||||||
|
|
||||||
|
// Tell the plugin what pose we're using to render. In this case we're just using the
|
||||||
|
// unmodified head pose because the only plugin that cares (the Oculus plugin) uses it
|
||||||
|
// for rotational timewarp. If we move to support positonal timewarp, we need to
|
||||||
|
// ensure this contains the full pose composed with the eye offsets.
|
||||||
mat4 headPose = displayPlugin->getHeadPose();
|
mat4 headPose = displayPlugin->getHeadPose();
|
||||||
mat4 eyeView = glm::inverse(eyePose) * headPose;
|
displayPlugin->setEyeRenderPose(eye, headPose);
|
||||||
eyeViews[eye] = eyeView;
|
|
||||||
eyeProjections[eye] = displayPlugin->getProjection(eye, baseProjection);
|
eyeProjections[eye] = displayPlugin->getProjection(eye, baseProjection);
|
||||||
});
|
});
|
||||||
renderArgs._context->setStereoProjections(eyeProjections);
|
renderArgs._context->setStereoProjections(eyeProjections);
|
||||||
renderArgs._context->setStereoViews(eyeViews);
|
renderArgs._context->setStereoViews(eyeOffsets);
|
||||||
}
|
}
|
||||||
displaySide(&renderArgs, _myCamera);
|
displaySide(&renderArgs, _myCamera);
|
||||||
renderArgs._context->enableStereo(false);
|
renderArgs._context->enableStereo(false);
|
||||||
|
@ -3929,7 +3942,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri
|
||||||
|
|
||||||
scriptEngine->registerGlobalObject("Paths", DependencyManager::get<PathUtils>().data());
|
scriptEngine->registerGlobalObject("Paths", DependencyManager::get<PathUtils>().data());
|
||||||
|
|
||||||
scriptEngine->registerGlobalObject("HMD", &HMDScriptingInterface::getInstance());
|
scriptEngine->registerGlobalObject("HMD", DependencyManager::get<HMDScriptingInterface>().data());
|
||||||
scriptEngine->registerFunction("HMD", "getHUDLookAtPosition2D", HMDScriptingInterface::getHUDLookAtPosition2D, 0);
|
scriptEngine->registerFunction("HMD", "getHUDLookAtPosition2D", HMDScriptingInterface::getHUDLookAtPosition2D, 0);
|
||||||
scriptEngine->registerFunction("HMD", "getHUDLookAtPosition3D", HMDScriptingInterface::getHUDLookAtPosition3D, 0);
|
scriptEngine->registerFunction("HMD", "getHUDLookAtPosition3D", HMDScriptingInterface::getHUDLookAtPosition3D, 0);
|
||||||
|
|
||||||
|
@ -4739,19 +4752,25 @@ mat4 Application::getEyeProjection(int eye) const {
|
||||||
|
|
||||||
mat4 Application::getEyePose(int eye) const {
|
mat4 Application::getEyePose(int eye) const {
|
||||||
if (isHMDMode()) {
|
if (isHMDMode()) {
|
||||||
return getActiveDisplayPlugin()->getEyePose((Eye)eye);
|
auto hmdInterface = DependencyManager::get<HMDScriptingInterface>();
|
||||||
|
float IPDScale = hmdInterface->getIPDScale();
|
||||||
|
auto displayPlugin = getActiveDisplayPlugin();
|
||||||
|
mat4 headPose = displayPlugin->getHeadPose();
|
||||||
|
mat4 eyeToHead = displayPlugin->getEyeToHeadTransform((Eye)eye);
|
||||||
|
{
|
||||||
|
vec3 eyeOffset = glm::vec3(eyeToHead[3]);
|
||||||
|
// Apply IPD scaling
|
||||||
|
mat4 eyeOffsetTransform = glm::translate(mat4(), eyeOffset * -1.0f * IPDScale);
|
||||||
|
eyeToHead[3] = vec4(eyeOffset, 1.0);
|
||||||
|
}
|
||||||
|
return eyeToHead * headPose;
|
||||||
}
|
}
|
||||||
|
|
||||||
return mat4();
|
return mat4();
|
||||||
}
|
}
|
||||||
|
|
||||||
mat4 Application::getEyeOffset(int eye) const {
|
mat4 Application::getEyeOffset(int eye) const {
|
||||||
if (isHMDMode()) {
|
// FIXME invert?
|
||||||
mat4 identity;
|
return getActiveDisplayPlugin()->getEyeToHeadTransform((Eye)eye);
|
||||||
return getActiveDisplayPlugin()->getView((Eye)eye, identity);
|
|
||||||
}
|
|
||||||
|
|
||||||
return mat4();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mat4 Application::getHMDSensorPose() const {
|
mat4 Application::getHMDSensorPose() const {
|
||||||
|
|
|
@ -16,6 +16,9 @@ PluginContainerProxy::PluginContainerProxy() {
|
||||||
Plugin::setContainer(this);
|
Plugin::setContainer(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PluginContainerProxy::~PluginContainerProxy() {
|
||||||
|
}
|
||||||
|
|
||||||
bool PluginContainerProxy::isForeground() {
|
bool PluginContainerProxy::isForeground() {
|
||||||
return qApp->isForeground() && !qApp->getWindow()->isMinimized();
|
return qApp->isForeground() && !qApp->getWindow()->isMinimized();
|
||||||
}
|
}
|
||||||
|
@ -151,3 +154,7 @@ void PluginContainerProxy::showDisplayPluginsTools() {
|
||||||
QGLWidget* PluginContainerProxy::getPrimarySurface() {
|
QGLWidget* PluginContainerProxy::getPrimarySurface() {
|
||||||
return qApp->_glWidget;
|
return qApp->_glWidget;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const DisplayPlugin* PluginContainerProxy::getActiveDisplayPlugin() const {
|
||||||
|
return qApp->getActiveDisplayPlugin();
|
||||||
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
class PluginContainerProxy : public QObject, PluginContainer {
|
class PluginContainerProxy : public QObject, PluginContainer {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
PluginContainerProxy();
|
PluginContainerProxy();
|
||||||
|
virtual ~PluginContainerProxy();
|
||||||
virtual void addMenu(const QString& menuName) override;
|
virtual void addMenu(const QString& menuName) override;
|
||||||
virtual void removeMenu(const QString& menuName) override;
|
virtual void removeMenu(const QString& menuName) override;
|
||||||
virtual QAction* addMenuItem(const QString& path, const QString& name, std::function<void(bool)> onClicked, bool checkable = false, bool checked = false, const QString& groupName = "") override;
|
virtual QAction* addMenuItem(const QString& path, const QString& name, std::function<void(bool)> onClicked, bool checkable = false, bool checked = false, const QString& groupName = "") override;
|
||||||
|
@ -23,6 +24,8 @@ class PluginContainerProxy : public QObject, PluginContainer {
|
||||||
virtual void requestReset() override;
|
virtual void requestReset() override;
|
||||||
virtual QGLWidget* getPrimarySurface() override;
|
virtual QGLWidget* getPrimarySurface() override;
|
||||||
virtual bool isForeground() override;
|
virtual bool isForeground() override;
|
||||||
|
virtual const DisplayPlugin* getActiveDisplayPlugin() const override;
|
||||||
|
|
||||||
QRect _savedGeometry{ 10, 120, 800, 600 };
|
QRect _savedGeometry{ 10, 120, 800, 600 };
|
||||||
|
|
||||||
friend class Application;
|
friend class Application;
|
||||||
|
|
|
@ -1342,11 +1342,13 @@ void MyAvatar::renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, fl
|
||||||
if (qApp->isHMDMode()) {
|
if (qApp->isHMDMode()) {
|
||||||
glm::vec3 cameraPosition = qApp->getCamera()->getPosition();
|
glm::vec3 cameraPosition = qApp->getCamera()->getPosition();
|
||||||
|
|
||||||
glm::mat4 leftEyePose = qApp->getActiveDisplayPlugin()->getEyePose(Eye::Left);
|
|
||||||
glm::vec3 leftEyePosition = glm::vec3(leftEyePose[3]);
|
|
||||||
glm::mat4 rightEyePose = qApp->getActiveDisplayPlugin()->getEyePose(Eye::Right);
|
|
||||||
glm::vec3 rightEyePosition = glm::vec3(rightEyePose[3]);
|
|
||||||
glm::mat4 headPose = qApp->getActiveDisplayPlugin()->getHeadPose();
|
glm::mat4 headPose = qApp->getActiveDisplayPlugin()->getHeadPose();
|
||||||
|
glm::mat4 leftEyePose = qApp->getActiveDisplayPlugin()->getEyeToHeadTransform(Eye::Left);
|
||||||
|
leftEyePose = leftEyePose * headPose;
|
||||||
|
glm::vec3 leftEyePosition = glm::vec3(leftEyePose[3]);
|
||||||
|
glm::mat4 rightEyePose = qApp->getActiveDisplayPlugin()->getEyeToHeadTransform(Eye::Right);
|
||||||
|
rightEyePose = rightEyePose * headPose;
|
||||||
|
glm::vec3 rightEyePosition = glm::vec3(rightEyePose[3]);
|
||||||
glm::vec3 headPosition = glm::vec3(headPose[3]);
|
glm::vec3 headPosition = glm::vec3(headPose[3]);
|
||||||
|
|
||||||
getHead()->renderLookAts(renderArgs,
|
getHead()->renderLookAts(renderArgs,
|
||||||
|
|
|
@ -13,33 +13,17 @@
|
||||||
|
|
||||||
#include <QtScript/QScriptContext>
|
#include <QtScript/QScriptContext>
|
||||||
|
|
||||||
#include <avatar/AvatarManager.h>
|
|
||||||
|
|
||||||
#include "Application.h"
|
|
||||||
#include "display-plugins/DisplayPlugin.h"
|
#include "display-plugins/DisplayPlugin.h"
|
||||||
|
#include <avatar/AvatarManager.h>
|
||||||
|
#include "Application.h"
|
||||||
|
|
||||||
HMDScriptingInterface& HMDScriptingInterface::getInstance() {
|
HMDScriptingInterface::HMDScriptingInterface() {
|
||||||
static HMDScriptingInterface sharedInstance;
|
|
||||||
return sharedInstance;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HMDScriptingInterface::getHUDLookAtPosition3D(glm::vec3& result) const {
|
|
||||||
Camera* camera = qApp->getCamera();
|
|
||||||
glm::vec3 position = camera->getPosition();
|
|
||||||
glm::quat orientation = camera->getOrientation();
|
|
||||||
|
|
||||||
glm::vec3 direction = orientation * glm::vec3(0.0f, 0.0f, -1.0f);
|
|
||||||
|
|
||||||
const auto& compositor = qApp->getApplicationCompositor();
|
|
||||||
|
|
||||||
return compositor.calculateRayUICollisionPoint(position, direction, result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QScriptValue HMDScriptingInterface::getHUDLookAtPosition2D(QScriptContext* context, QScriptEngine* engine) {
|
QScriptValue HMDScriptingInterface::getHUDLookAtPosition2D(QScriptContext* context, QScriptEngine* engine) {
|
||||||
|
|
||||||
glm::vec3 hudIntersection;
|
glm::vec3 hudIntersection;
|
||||||
|
auto instance = DependencyManager::get<HMDScriptingInterface>();
|
||||||
if ((&HMDScriptingInterface::getInstance())->getHUDLookAtPosition3D(hudIntersection)) {
|
if (instance->getHUDLookAtPosition3D(hudIntersection)) {
|
||||||
MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||||
glm::vec3 sphereCenter = myAvatar->getDefaultEyePosition();
|
glm::vec3 sphereCenter = myAvatar->getDefaultEyePosition();
|
||||||
glm::vec3 direction = glm::inverse(myAvatar->getOrientation()) * (hudIntersection - sphereCenter);
|
glm::vec3 direction = glm::inverse(myAvatar->getOrientation()) * (hudIntersection - sphereCenter);
|
||||||
|
@ -53,16 +37,13 @@ QScriptValue HMDScriptingInterface::getHUDLookAtPosition2D(QScriptContext* conte
|
||||||
|
|
||||||
QScriptValue HMDScriptingInterface::getHUDLookAtPosition3D(QScriptContext* context, QScriptEngine* engine) {
|
QScriptValue HMDScriptingInterface::getHUDLookAtPosition3D(QScriptContext* context, QScriptEngine* engine) {
|
||||||
glm::vec3 result;
|
glm::vec3 result;
|
||||||
if ((&HMDScriptingInterface::getInstance())->getHUDLookAtPosition3D(result)) {
|
auto instance = DependencyManager::get<HMDScriptingInterface>();
|
||||||
|
if (instance->getHUDLookAtPosition3D(result)) {
|
||||||
return qScriptValueFromValue<glm::vec3>(engine, result);
|
return qScriptValueFromValue<glm::vec3>(engine, result);
|
||||||
}
|
}
|
||||||
return QScriptValue::NullValue;
|
return QScriptValue::NullValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
float HMDScriptingInterface::getIPD() const {
|
|
||||||
return qApp->getActiveDisplayPlugin()->getIPD();
|
|
||||||
}
|
|
||||||
|
|
||||||
void HMDScriptingInterface::toggleMagnifier() {
|
void HMDScriptingInterface::toggleMagnifier() {
|
||||||
qApp->getApplicationCompositor().toggleMagnifier();
|
qApp->getApplicationCompositor().toggleMagnifier();
|
||||||
}
|
}
|
||||||
|
@ -71,6 +52,14 @@ bool HMDScriptingInterface::getMagnifier() const {
|
||||||
return qApp->getApplicationCompositor().hasMagnifier();
|
return qApp->getApplicationCompositor().hasMagnifier();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HMDScriptingInterface::isHMDMode() const {
|
bool HMDScriptingInterface::getHUDLookAtPosition3D(glm::vec3& result) const {
|
||||||
return qApp->isHMDMode();
|
Camera* camera = qApp->getCamera();
|
||||||
|
glm::vec3 position = camera->getPosition();
|
||||||
|
glm::quat orientation = camera->getOrientation();
|
||||||
|
|
||||||
|
glm::vec3 direction = orientation * glm::vec3(0.0f, 0.0f, -1.0f);
|
||||||
|
|
||||||
|
const auto& compositor = qApp->getApplicationCompositor();
|
||||||
|
|
||||||
|
return compositor.calculateRayUICollisionPoint(position, direction, result);
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,22 +13,19 @@
|
||||||
#define hifi_HMDScriptingInterface_h
|
#define hifi_HMDScriptingInterface_h
|
||||||
|
|
||||||
#include <QtScript/QScriptValue>
|
#include <QtScript/QScriptValue>
|
||||||
|
|
||||||
#include <GLMHelpers.h>
|
|
||||||
|
|
||||||
class QScriptContext;
|
class QScriptContext;
|
||||||
class QScriptEngine;
|
class QScriptEngine;
|
||||||
|
|
||||||
|
#include <GLMHelpers.h>
|
||||||
|
#include <DependencyManager.h>
|
||||||
|
#include <display-plugins/AbstractHMDScriptingInterface.h>
|
||||||
|
|
||||||
class HMDScriptingInterface : public QObject {
|
|
||||||
|
class HMDScriptingInterface : public AbstractHMDScriptingInterface, public Dependency {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
Q_PROPERTY(bool magnifier READ getMagnifier)
|
Q_PROPERTY(bool magnifier READ getMagnifier)
|
||||||
Q_PROPERTY(bool active READ isHMDMode)
|
|
||||||
Q_PROPERTY(float ipd READ getIPD)
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static HMDScriptingInterface& getInstance();
|
HMDScriptingInterface();
|
||||||
|
|
||||||
static QScriptValue getHUDLookAtPosition2D(QScriptContext* context, QScriptEngine* engine);
|
static QScriptValue getHUDLookAtPosition2D(QScriptContext* context, QScriptEngine* engine);
|
||||||
static QScriptValue getHUDLookAtPosition3D(QScriptContext* context, QScriptEngine* engine);
|
static QScriptValue getHUDLookAtPosition3D(QScriptContext* context, QScriptEngine* engine);
|
||||||
|
|
||||||
|
@ -36,11 +33,7 @@ public slots:
|
||||||
void toggleMagnifier();
|
void toggleMagnifier();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
HMDScriptingInterface() = default;
|
|
||||||
bool getMagnifier() const;
|
bool getMagnifier() const;
|
||||||
bool isHMDMode() const;
|
|
||||||
float getIPD() const;
|
|
||||||
|
|
||||||
bool getHUDLookAtPosition3D(glm::vec3& result) const;
|
bool getHUDLookAtPosition3D(glm::vec3& result) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
#include <glm/gtc/type_ptr.hpp>
|
#include <glm/gtc/type_ptr.hpp>
|
||||||
|
|
||||||
|
#include <display-plugins/DisplayPlugin.h>
|
||||||
#include <avatar/AvatarManager.h>
|
#include <avatar/AvatarManager.h>
|
||||||
#include <gpu/GLBackend.h>
|
#include <gpu/GLBackend.h>
|
||||||
#include <NumericalConstants.h>
|
#include <NumericalConstants.h>
|
||||||
|
@ -285,7 +286,10 @@ void ApplicationCompositor::displayOverlayTextureHmd(RenderArgs* renderArgs, int
|
||||||
|
|
||||||
mat4 camMat;
|
mat4 camMat;
|
||||||
_cameraBaseTransform.getMatrix(camMat);
|
_cameraBaseTransform.getMatrix(camMat);
|
||||||
camMat = camMat * qApp->getEyePose(eye);
|
auto displayPlugin = qApp->getActiveDisplayPlugin();
|
||||||
|
auto headPose = displayPlugin->getHeadPose();
|
||||||
|
auto eyeToHead = displayPlugin->getEyeToHeadTransform((Eye)eye);
|
||||||
|
camMat = (headPose * eyeToHead) * camMat;
|
||||||
batch.setViewportTransform(renderArgs->_viewport);
|
batch.setViewportTransform(renderArgs->_viewport);
|
||||||
batch.setViewTransform(camMat);
|
batch.setViewTransform(camMat);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
//
|
||||||
|
// Created by Bradley Austin Davis on 2015/10/04
|
||||||
|
// Copyright 2013-2015 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "AbstractHMDScriptingInterface.h"
|
||||||
|
|
||||||
|
#include <SettingHandle.h>
|
||||||
|
|
||||||
|
#include "DisplayPlugin.h"
|
||||||
|
#include <plugins/PluginContainer.h>
|
||||||
|
#include <OVR_CAPI_Keys.h>
|
||||||
|
|
||||||
|
static Setting::Handle<float> IPD_SCALE_HANDLE("hmd.ipdScale", 1.0f);
|
||||||
|
|
||||||
|
AbstractHMDScriptingInterface::AbstractHMDScriptingInterface() {
|
||||||
|
_IPDScale = IPD_SCALE_HANDLE.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
float AbstractHMDScriptingInterface::getIPD() const {
|
||||||
|
return PluginContainer::getInstance().getActiveDisplayPlugin()->getIPD();
|
||||||
|
}
|
||||||
|
|
||||||
|
float AbstractHMDScriptingInterface::getEyeHeight() const {
|
||||||
|
// FIXME update the display plugin interface to expose per-plugin settings
|
||||||
|
return OVR_DEFAULT_EYE_HEIGHT;
|
||||||
|
}
|
||||||
|
|
||||||
|
float AbstractHMDScriptingInterface::getPlayerHeight() const {
|
||||||
|
// FIXME update the display plugin interface to expose per-plugin settings
|
||||||
|
return OVR_DEFAULT_PLAYER_HEIGHT;
|
||||||
|
}
|
||||||
|
|
||||||
|
float AbstractHMDScriptingInterface::getIPDScale() const {
|
||||||
|
return _IPDScale;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AbstractHMDScriptingInterface::setIPDScale(float IPDScale) {
|
||||||
|
IPDScale = glm::clamp(IPDScale, -1.0f, 3.0f);
|
||||||
|
if (IPDScale != _IPDScale) {
|
||||||
|
_IPDScale = IPDScale;
|
||||||
|
IPD_SCALE_HANDLE.set(IPDScale);
|
||||||
|
emit IPDScaleChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AbstractHMDScriptingInterface::isHMDMode() const {
|
||||||
|
return PluginContainer::getInstance().getActiveDisplayPlugin()->isHmd();
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
//
|
||||||
|
// Created by Bradley Austin Davis on 2015/10/04
|
||||||
|
// Copyright 2013-2015 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifndef hifi_AbstractHMDScriptingInterface_h
|
||||||
|
#define hifi_AbstractHMDScriptingInterface_h
|
||||||
|
|
||||||
|
#include <GLMHelpers.h>
|
||||||
|
|
||||||
|
class AbstractHMDScriptingInterface : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
Q_PROPERTY(bool active READ isHMDMode)
|
||||||
|
Q_PROPERTY(float ipd READ getIPD)
|
||||||
|
Q_PROPERTY(float eyeHeight READ getEyeHeight)
|
||||||
|
Q_PROPERTY(float playerHeight READ getPlayerHeight)
|
||||||
|
Q_PROPERTY(float ipdScale READ getIPDScale WRITE setIPDScale NOTIFY IPDScaleChanged)
|
||||||
|
|
||||||
|
public:
|
||||||
|
AbstractHMDScriptingInterface();
|
||||||
|
float getIPD() const;
|
||||||
|
float getEyeHeight() const;
|
||||||
|
float getPlayerHeight() const;
|
||||||
|
float getIPDScale() const;
|
||||||
|
void setIPDScale(float ipdScale);
|
||||||
|
bool isHMDMode() const;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void IPDScaleChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
float _IPDScale{ 1.0 };
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // hifi_AbstractHMDScriptingInterface_h
|
|
@ -46,6 +46,8 @@ void for_each_eye(F f, FF ff) {
|
||||||
|
|
||||||
class QWindow;
|
class QWindow;
|
||||||
|
|
||||||
|
#define AVERAGE_HUMAN_IPD 0.064f
|
||||||
|
|
||||||
class DisplayPlugin : public Plugin {
|
class DisplayPlugin : public Plugin {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
|
@ -107,21 +109,22 @@ public:
|
||||||
return baseProjection;
|
return baseProjection;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual glm::mat4 getView(Eye eye, const glm::mat4& baseView) const {
|
|
||||||
return glm::inverse(getEyePose(eye)) * baseView;
|
|
||||||
}
|
|
||||||
|
|
||||||
// HMD specific methods
|
// HMD specific methods
|
||||||
// TODO move these into another class?
|
// TODO move these into another class?
|
||||||
virtual glm::mat4 getEyePose(Eye eye) const {
|
virtual glm::mat4 getEyeToHeadTransform(Eye eye) const {
|
||||||
static const glm::mat4 pose; return pose;
|
static const glm::mat4 transform; return transform;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual glm::mat4 getHeadPose() const {
|
virtual glm::mat4 getHeadPose() const {
|
||||||
static const glm::mat4 pose; return pose;
|
static const glm::mat4 pose; return pose;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual float getIPD() const { return 0.0f; }
|
// Needed for timewarp style features
|
||||||
|
virtual void setEyeRenderPose(Eye eye, const glm::mat4& pose) {
|
||||||
|
// NOOP
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual float getIPD() const { return AVERAGE_HUMAN_IPD; }
|
||||||
|
|
||||||
virtual void abandonCalibration() {}
|
virtual void abandonCalibration() {}
|
||||||
virtual void resetSensors() {}
|
virtual void resetSensors() {}
|
||||||
|
|
|
@ -19,7 +19,6 @@ void OculusBaseDisplayPlugin::preRender() {
|
||||||
#if (OVR_MAJOR_VERSION >= 6)
|
#if (OVR_MAJOR_VERSION >= 6)
|
||||||
ovrFrameTiming ftiming = ovr_GetFrameTiming(_hmd, _frameIndex);
|
ovrFrameTiming ftiming = ovr_GetFrameTiming(_hmd, _frameIndex);
|
||||||
_trackingState = ovr_GetTrackingState(_hmd, ftiming.DisplayMidpointSeconds);
|
_trackingState = ovr_GetTrackingState(_hmd, ftiming.DisplayMidpointSeconds);
|
||||||
ovr_CalcEyePoses(_trackingState.HeadPose.ThePose, _eyeOffsets, _eyePoses);
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,14 +32,19 @@ void OculusBaseDisplayPlugin::resetSensors() {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::mat4 OculusBaseDisplayPlugin::getEyePose(Eye eye) const {
|
glm::mat4 OculusBaseDisplayPlugin::getEyeToHeadTransform(Eye eye) const {
|
||||||
return toGlm(_eyePoses[eye]);
|
return glm::translate(mat4(), toGlm(_eyeOffsets[eye]));
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::mat4 OculusBaseDisplayPlugin::getHeadPose() const {
|
glm::mat4 OculusBaseDisplayPlugin::getHeadPose() const {
|
||||||
return toGlm(_trackingState.HeadPose.ThePose);
|
return toGlm(_trackingState.HeadPose.ThePose);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OculusBaseDisplayPlugin::setEyeRenderPose(Eye eye, const glm::mat4& pose) {
|
||||||
|
_eyePoses[eye] = ovrPoseFromGlm(pose);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool OculusBaseDisplayPlugin::isSupported() const {
|
bool OculusBaseDisplayPlugin::isSupported() const {
|
||||||
#if (OVR_MAJOR_VERSION >= 6)
|
#if (OVR_MAJOR_VERSION >= 6)
|
||||||
if (!OVR_SUCCESS(ovr_Initialize(nullptr))) {
|
if (!OVR_SUCCESS(ovr_Initialize(nullptr))) {
|
||||||
|
@ -151,9 +155,9 @@ void OculusBaseDisplayPlugin::display(GLuint finalTexture, const glm::uvec2& sce
|
||||||
}
|
}
|
||||||
|
|
||||||
float OculusBaseDisplayPlugin::getIPD() const {
|
float OculusBaseDisplayPlugin::getIPD() const {
|
||||||
float result = 0.0f;
|
float result = OVR_DEFAULT_IPD;
|
||||||
#if (OVR_MAJOR_VERSION >= 6)
|
#if (OVR_MAJOR_VERSION >= 6)
|
||||||
result = ovr_GetFloat(_hmd, OVR_KEY_IPD, OVR_DEFAULT_IPD);
|
result = ovr_GetFloat(_hmd, OVR_KEY_IPD, result);
|
||||||
#endif
|
#endif
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
|
@ -29,8 +29,9 @@ public:
|
||||||
virtual glm::uvec2 getRecommendedRenderSize() const override final;
|
virtual glm::uvec2 getRecommendedRenderSize() const override final;
|
||||||
virtual glm::uvec2 getRecommendedUiSize() const override final { return uvec2(1920, 1080); }
|
virtual glm::uvec2 getRecommendedUiSize() const override final { return uvec2(1920, 1080); }
|
||||||
virtual void resetSensors() override final;
|
virtual void resetSensors() override final;
|
||||||
virtual glm::mat4 getEyePose(Eye eye) const override final;
|
virtual glm::mat4 getEyeToHeadTransform(Eye eye) const override final;
|
||||||
virtual glm::mat4 getHeadPose() const override final;
|
virtual glm::mat4 getHeadPose() const override final;
|
||||||
|
virtual void setEyeRenderPose(Eye eye, const glm::mat4& pose) override final;
|
||||||
virtual float getIPD() const override final;
|
virtual float getIPD() const override final;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -39,6 +40,7 @@ protected:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ovrPosef _eyePoses[2];
|
ovrPosef _eyePoses[2];
|
||||||
|
ovrVector3f _eyeOffsets[2];
|
||||||
|
|
||||||
mat4 _eyeProjections[3];
|
mat4 _eyeProjections[3];
|
||||||
mat4 _compositeEyeProjections[2];
|
mat4 _compositeEyeProjections[2];
|
||||||
|
@ -50,7 +52,6 @@ protected:
|
||||||
ovrHmd _hmd;
|
ovrHmd _hmd;
|
||||||
float _ipd{ OVR_DEFAULT_IPD };
|
float _ipd{ OVR_DEFAULT_IPD };
|
||||||
ovrEyeRenderDesc _eyeRenderDescs[2];
|
ovrEyeRenderDesc _eyeRenderDescs[2];
|
||||||
ovrVector3f _eyeOffsets[2];
|
|
||||||
ovrFovPort _eyeFovs[2];
|
ovrFovPort _eyeFovs[2];
|
||||||
ovrHmdDesc _hmdDesc;
|
ovrHmdDesc _hmdDesc;
|
||||||
ovrLayerEyeFov _sceneLayer;
|
ovrLayerEyeFov _sceneLayer;
|
||||||
|
|
|
@ -79,3 +79,11 @@ inline ovrQuatf ovrFromGlm(const glm::quat & q) {
|
||||||
return{ q.x, q.y, q.z, q.w };
|
return{ q.x, q.y, q.z, q.w };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline ovrPosef ovrPoseFromGlm(const glm::mat4 & m) {
|
||||||
|
glm::vec3 translation = glm::vec3(m[3]) / m[3].w;
|
||||||
|
glm::quat orientation = glm::quat_cast(m);
|
||||||
|
ovrPosef result;
|
||||||
|
result.Orientation = ovrFromGlm(orientation);
|
||||||
|
result.Position = ovrFromGlm(translation);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
|
@ -59,11 +59,11 @@ void OculusLegacyDisplayPlugin::resetSensors() {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::mat4 OculusLegacyDisplayPlugin::getEyePose(Eye eye) const {
|
glm::mat4 OculusLegacyDisplayPlugin::getEyeToHeadTransform(Eye eye) const {
|
||||||
#if (OVR_MAJOR_VERSION == 5)
|
#if (OVR_MAJOR_VERSION == 5)
|
||||||
return toGlm(_eyePoses[eye]);
|
return toGlm(_eyePoses[eye]);
|
||||||
#else
|
#else
|
||||||
return WindowOpenGLDisplayPlugin::getEyePose(eye);
|
return WindowOpenGLDisplayPlugin::getEyeToHeadTransform(eye);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ public:
|
||||||
virtual glm::uvec2 getRecommendedRenderSize() const override;
|
virtual glm::uvec2 getRecommendedRenderSize() const override;
|
||||||
virtual glm::uvec2 getRecommendedUiSize() const override { return uvec2(1920, 1080); }
|
virtual glm::uvec2 getRecommendedUiSize() const override { return uvec2(1920, 1080); }
|
||||||
virtual void resetSensors() override;
|
virtual void resetSensors() override;
|
||||||
virtual glm::mat4 getEyePose(Eye eye) const override;
|
virtual glm::mat4 getEyeToHeadTransform(Eye eye) const override;
|
||||||
virtual glm::mat4 getHeadPose() const override;
|
virtual glm::mat4 getHeadPose() const override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -160,8 +160,8 @@ void OpenVrDisplayPlugin::resetSensors() {
|
||||||
_sensorResetMat = glm::inverse(cancelOutRollAndPitch(_trackedDevicePoseMat4[0]));
|
_sensorResetMat = glm::inverse(cancelOutRollAndPitch(_trackedDevicePoseMat4[0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::mat4 OpenVrDisplayPlugin::getEyePose(Eye eye) const {
|
glm::mat4 OpenVrDisplayPlugin::getEyeToHeadTransform(Eye eye) const {
|
||||||
return getHeadPose() * _eyesData[eye]._eyeOffset;
|
return _eyesData[eye]._eyeOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::mat4 OpenVrDisplayPlugin::getHeadPose() const {
|
glm::mat4 OpenVrDisplayPlugin::getHeadPose() const {
|
||||||
|
|
|
@ -29,7 +29,7 @@ public:
|
||||||
virtual glm::mat4 getProjection(Eye eye, const glm::mat4& baseProjection) const override;
|
virtual glm::mat4 getProjection(Eye eye, const glm::mat4& baseProjection) const override;
|
||||||
virtual void resetSensors() override;
|
virtual void resetSensors() override;
|
||||||
|
|
||||||
virtual glm::mat4 getEyePose(Eye eye) const override;
|
virtual glm::mat4 getEyeToHeadTransform(Eye eye) const override;
|
||||||
virtual glm::mat4 getHeadPose() const override;
|
virtual glm::mat4 getHeadPose() const override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -61,10 +61,6 @@ glm::mat4 StereoDisplayPlugin::getProjection(Eye eye, const glm::mat4& baseProje
|
||||||
return eyeProjection;
|
return eyeProjection;
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::mat4 StereoDisplayPlugin::getEyePose(Eye eye) const {
|
|
||||||
return mat4();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<QAction*> _screenActions;
|
std::vector<QAction*> _screenActions;
|
||||||
void StereoDisplayPlugin::activate() {
|
void StereoDisplayPlugin::activate() {
|
||||||
auto screens = qApp->screens();
|
auto screens = qApp->screens();
|
||||||
|
|
|
@ -21,7 +21,14 @@ public:
|
||||||
|
|
||||||
virtual float getRecommendedAspectRatio() const override;
|
virtual float getRecommendedAspectRatio() const override;
|
||||||
virtual glm::mat4 getProjection(Eye eye, const glm::mat4& baseProjection) const override;
|
virtual glm::mat4 getProjection(Eye eye, const glm::mat4& baseProjection) const override;
|
||||||
virtual glm::mat4 getEyePose(Eye eye) const override;
|
|
||||||
|
// NOTE, because Stereo displays don't include head tracking, and therefore
|
||||||
|
// can't include roll or pitch, the eye separation is embedded into the projection
|
||||||
|
// matrix. However, this eliminates the possibility of easily mainpulating
|
||||||
|
// the IPD at the Application level, the way we now allow with HMDs.
|
||||||
|
// If that becomes an issue then we'll need to break up the functionality similar
|
||||||
|
// to the HMD plugins.
|
||||||
|
// virtual glm::mat4 getEyeToHeadTransform(Eye eye) const override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void updateScreen();
|
void updateScreen();
|
||||||
|
|
|
@ -9,7 +9,17 @@
|
||||||
|
|
||||||
static PluginContainer* INSTANCE{ nullptr };
|
static PluginContainer* INSTANCE{ nullptr };
|
||||||
|
|
||||||
|
PluginContainer& PluginContainer::getInstance() {
|
||||||
|
Q_ASSERT(INSTANCE);
|
||||||
|
return *INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
PluginContainer::PluginContainer() {
|
PluginContainer::PluginContainer() {
|
||||||
Q_ASSERT(!INSTANCE);
|
Q_ASSERT(!INSTANCE);
|
||||||
INSTANCE = this;
|
INSTANCE = this;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
PluginContainer::~PluginContainer() {
|
||||||
|
Q_ASSERT(INSTANCE == this);
|
||||||
|
INSTANCE = nullptr;
|
||||||
|
};
|
||||||
|
|
|
@ -13,10 +13,13 @@
|
||||||
class QAction;
|
class QAction;
|
||||||
class QGLWidget;
|
class QGLWidget;
|
||||||
class QScreen;
|
class QScreen;
|
||||||
|
class DisplayPlugin;
|
||||||
|
|
||||||
class PluginContainer {
|
class PluginContainer {
|
||||||
public:
|
public:
|
||||||
|
static PluginContainer& getInstance();
|
||||||
PluginContainer();
|
PluginContainer();
|
||||||
|
virtual ~PluginContainer();
|
||||||
virtual void addMenu(const QString& menuName) = 0;
|
virtual void addMenu(const QString& menuName) = 0;
|
||||||
virtual void removeMenu(const QString& menuName) = 0;
|
virtual void removeMenu(const QString& menuName) = 0;
|
||||||
virtual QAction* addMenuItem(const QString& path, const QString& name, std::function<void(bool)> onClicked, bool checkable = false, bool checked = false, const QString& groupName = "") = 0;
|
virtual QAction* addMenuItem(const QString& path, const QString& name, std::function<void(bool)> onClicked, bool checkable = false, bool checked = false, const QString& groupName = "") = 0;
|
||||||
|
@ -29,4 +32,5 @@ public:
|
||||||
virtual void requestReset() = 0;
|
virtual void requestReset() = 0;
|
||||||
virtual QGLWidget* getPrimarySurface() = 0;
|
virtual QGLWidget* getPrimarySurface() = 0;
|
||||||
virtual bool isForeground() = 0;
|
virtual bool isForeground() = 0;
|
||||||
|
virtual const DisplayPlugin* getActiveDisplayPlugin() const = 0;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue