comfort mode -- squeeze vision to avoid sickness

This commit is contained in:
Seth Alves 2019-01-31 11:22:26 -08:00
parent dd9b4a8143
commit 9baf4c7078
21 changed files with 846 additions and 8 deletions

View file

@ -6755,6 +6755,12 @@ void Application::update(float deltaTime) {
if (!getActiveDisplayPlugin()->isActive()) {
getMain3DScene()->processTransactionQueue();
}
// decide if the sensorToWorldMatrix is changing in a way that warrents squeezing the edges of the view down
if (getActiveDisplayPlugin()->isHmd()) {
PerformanceTimer perfTimer("squeezeVision");
_visionSqueeze.updateVisionSqueeze(myAvatar->getSensorToWorldMatrix(), deltaTime);
}
}
void Application::updateRenderArgs(float deltaTime) {

View file

@ -78,6 +78,7 @@
#include <ModelScriptingInterface.h>
#include "Sound.h"
#include "VisionSqueeze.h"
class GLCanvas;
class FaceTracker;
@ -364,6 +365,9 @@ public:
void forceLoginWithTokens(const QString& tokens);
void setConfigFileURL(const QString& fileUrl);
// used by preferences and HMDScriptingInterface...
VisionSqueeze& getVisionSqueeze() { return _visionSqueeze; }
signals:
void svoImportRequested(const QString& url);
@ -731,6 +735,7 @@ private:
bool _loginDialogPoppedUp{ false };
bool _desktopRootItemCreated{ false };
bool _developerMenuVisible{ false };
QString _previousAvatarSkeletonModel;
float _previousAvatarTargetScale;
@ -837,5 +842,7 @@ private:
bool _resumeAfterLoginDialogActionTaken_SafeToRun { false };
bool _startUpFinished { false };
bool _overrideEntry { false };
VisionSqueeze _visionSqueeze;
};
#endif // hifi_Application_h

View file

@ -0,0 +1,213 @@
//
// VisionSqueeze.cpp
// interface/src
//
// Created by Seth Alves on 2019-3-13.
// Copyright 2019 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 "VisionSqueeze.h"
#include <glm/gtx/matrix_decompose.hpp>
#include <glm/gtc/epsilon.hpp>
#include <display-plugins/hmd/HmdDisplayPlugin.h>
#include "Application.h"
VisionSqueeze::VisionSqueeze() :
_visionSqueezeEnabled(_visionSqueezeEnabledSetting.get()),
_visionSqueezeRatioX(_visionSqueezeRatioXSetting.get()),
_visionSqueezeRatioY(_visionSqueezeRatioYSetting.get()),
_visionSqueezeUnSqueezeDelay(_visionSqueezeUnSqueezeDelaySetting.get()),
_visionSqueezeUnSqueezeSpeed(_visionSqueezeUnSqueezeSpeedSetting.get()),
_visionSqueezeTransition(_visionSqueezeTransitionSetting.get()),
_visionSqueezePerEye(_visionSqueezePerEyeSetting.get()),
_visionSqueezeGroundPlaneY(_visionSqueezeGroundPlaneYSetting.get()),
_visionSqueezeSpotlightSize(_visionSqueezeSpotlightSizeSetting.get()),
_visionSqueezeTurningXFactor(_visionSqueezeTurningXFactorSetting.get()),
_visionSqueezeTurningYFactor(_visionSqueezeTurningYFactorSetting.get()) {
}
void VisionSqueeze::setVisionSqueezeEnabled(bool value) {
if (value != _visionSqueezeEnabled) {
_visionSqueezeEnabled = value;
_visionSqueezeEnabledSetting.set(_visionSqueezeEnabled);
}
}
void VisionSqueeze::setVisionSqueezeRatioX(float value) {
if (value != _visionSqueezeRatioX) {
_visionSqueezeRatioX = value;
_visionSqueezeRatioXSetting.set(_visionSqueezeRatioX);
}
}
void VisionSqueeze::setVisionSqueezeRatioY(float value) {
if (value != _visionSqueezeRatioY) {
_visionSqueezeRatioY = value;
_visionSqueezeRatioYSetting.set(_visionSqueezeRatioY);
}
}
void VisionSqueeze::setVisionSqueezeUnSqueezeDelay(float value) {
if (value != _visionSqueezeUnSqueezeDelay) {
_visionSqueezeUnSqueezeDelay = value;
_visionSqueezeUnSqueezeDelaySetting.set(_visionSqueezeUnSqueezeDelay);
}
}
void VisionSqueeze::setVisionSqueezeUnSqueezeSpeed(float value) {
if (value != _visionSqueezeUnSqueezeSpeed) {
_visionSqueezeUnSqueezeSpeed = value;
_visionSqueezeUnSqueezeSpeedSetting.set(_visionSqueezeUnSqueezeSpeed);
}
}
void VisionSqueeze::setVisionSqueezeTransition(float value) {
if (value != _visionSqueezeTransition) {
_visionSqueezeTransition = value;
_visionSqueezeTransitionSetting.set(_visionSqueezeTransition);
}
}
void VisionSqueeze::setVisionSqueezePerEye(int value) {
if (value != _visionSqueezePerEye) {
_visionSqueezePerEye = value;
_visionSqueezePerEyeSetting.set(_visionSqueezePerEye);
}
}
void VisionSqueeze::setVisionSqueezeGroundPlaneY(float value) {
if (value != _visionSqueezeGroundPlaneY) {
_visionSqueezeGroundPlaneY = value;
_visionSqueezeGroundPlaneYSetting.set(_visionSqueezeGroundPlaneY);
}
}
void VisionSqueeze::setVisionSqueezeSpotlightSize(float value) {
if (value != _visionSqueezeSpotlightSize) {
_visionSqueezeSpotlightSize = value;
_visionSqueezeSpotlightSizeSetting.set(_visionSqueezeSpotlightSize);
}
}
void VisionSqueeze::setVisionSqueezeTurningXFactor(float value) {
if (value != _visionSqueezeTurningXFactor) {
_visionSqueezeTurningXFactor = value;
_visionSqueezeTurningXFactorSetting.set(_visionSqueezeTurningXFactor);
}
}
void VisionSqueeze::setVisionSqueezeTurningYFactor(float value) {
if (value != _visionSqueezeTurningYFactor) {
_visionSqueezeTurningYFactor = value;
_visionSqueezeTurningYFactorSetting.set(_visionSqueezeTurningYFactor);
}
}
void VisionSqueeze::updateVisionSqueeze(const glm::mat4& sensorToWorldMatrix, float deltaTime) {
const float SENSOR_TO_WORLD_TRANS_EPSILON = 0.0001f;
const float SENSOR_TO_WORLD_TRANS_Y_EPSILON = 0.01f;
const float SENSOR_TO_WORLD_TRANS_ITS_A_TELEPORT_SQUARED = 2.0f;
const float SENSOR_TO_WORLD_ROT_EPSILON = 0.000005f;
const float SENSOR_TO_WORLD_ROT_ITS_A_SNAP_TURN = 0.99f;
const float VISION_SQUEEZE_TP_LOCKOUT = 0.1f; // seconds
glm::vec3 scale;
glm::quat rotation;
glm::vec3 translation;
glm::vec3 skew;
glm::vec4 perspective;
glm::decompose(sensorToWorldMatrix, scale, rotation, translation, skew, perspective);
if (!_visionSqueezeEnabled) {
_squeezeVision = false;
_squeezeVisionTurning = false;
} else if (_visionSqueezeLockout > 0.0f) {
_visionSqueezeLockout -= deltaTime;
} else {
_squeezeVision = false;
_squeezeVisionTurning = false;
glm::vec3 absTransDelta = glm::abs(translation - _prevTranslation);
float rotDot = fabsf(glm::dot(rotation, _prevRotation));
// if the avatar has just teleported or snap-turned, briefly disable triggering of vision-squeeze
if (glm::length2(translation - _prevTranslation) > SENSOR_TO_WORLD_TRANS_ITS_A_TELEPORT_SQUARED ||
rotDot < SENSOR_TO_WORLD_ROT_ITS_A_SNAP_TURN) {
_visionSqueezeLockout = VISION_SQUEEZE_TP_LOCKOUT;
_squeezeVision = true;
_squeezeVisionTurning = true;
} else if (rotDot < 1.0f - SENSOR_TO_WORLD_ROT_EPSILON) {
_squeezeVision = true;
_squeezeVisionTurning = true;
} else if (absTransDelta.x > SENSOR_TO_WORLD_TRANS_EPSILON ||
absTransDelta.y > SENSOR_TO_WORLD_TRANS_Y_EPSILON ||
absTransDelta.z > SENSOR_TO_WORLD_TRANS_EPSILON) {
_squeezeVision = true;
_squeezeVisionTurning = false;
}
}
_prevTranslation = translation;
_prevRotation = rotation;
static quint64 lastSqueezeTime = 0;
quint64 now = usecTimestampNow();
static float visionSqueezeX = 0.0f; // 0.0 -- unobstructed, 1.0 -- fully blocked
static float visionSqueezeY = 0.0f; // 0.0 -- unobstructed, 1.0 -- fully blocked
if (_squeezeVision) {
float ratioX = getVisionSqueezeRatioX();
float ratioY = getVisionSqueezeRatioY();
if (ratioX >= 0.0f) {
if (_squeezeVisionTurning) {
ratioX += (1.0f - ratioX) * getVisionSqueezeTurningXFactor();
}
float newVisionSqueezeX = ratioX;
if (newVisionSqueezeX >= visionSqueezeX) {
lastSqueezeTime = now;
visionSqueezeX = newVisionSqueezeX;
}
} else {
visionSqueezeX = -1.0f;
}
if (ratioY >= 0.0f) {
float newVisionSqueezeY = ratioY;
if (newVisionSqueezeY >= visionSqueezeY) {
lastSqueezeTime = now;
visionSqueezeY = newVisionSqueezeY;
}
} else {
visionSqueezeY = -1.0f;
}
}
float unsqueezeAmount = deltaTime * getVisionSqueezeUnSqueezeSpeed();
if (now - lastSqueezeTime > getVisionSqueezeUnSqueezeDelay() * USECS_PER_SECOND) {
visionSqueezeX -= unsqueezeAmount;
if (visionSqueezeX < 0.0f) {
visionSqueezeX = -1.0f;
}
visionSqueezeY -= unsqueezeAmount;
if (visionSqueezeY < 0.0f) {
visionSqueezeY = -1.0f;
}
}
std::shared_ptr<HmdDisplayPlugin> hmdDisplayPlugin =
std::dynamic_pointer_cast<HmdDisplayPlugin>(qApp->getActiveDisplayPlugin());
if (hmdDisplayPlugin) {
hmdDisplayPlugin->updateVisionSqueezeParameters(visionSqueezeX, visionSqueezeY,
getVisionSqueezeTransition(),
getVisionSqueezePerEye(),
getVisionSqueezeGroundPlaneY(),
getVisionSqueezeSpotlightSize());
}
}

View file

@ -0,0 +1,108 @@
//
// VisionSqueeze.h
// interface/src
//
// Created by Seth Alves on 2019-3-13.
// Copyright 2019 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
//
#ifndef hifi_VisionSqueeze_h
#define hifi_VisionSqueeze_h
#include <memory>
#include <glm/glm.hpp>
#include <SettingHandle.h>
static const float DEFAULT_VISION_SQUEEZE_TURNING_X_FACTOR = 0.51f;
static const float DEFAULT_VISION_SQUEEZE_TURNING_Y_FACTOR = 0.36f;
static const float DEFAULT_VISION_SQUEEZE_UNSQUEEZE_DELAY = 0.2f; // seconds
static const float DEFAULT_VISION_SQUEEZE_UNSQUEEZE_SPEED = 3.0f;
static const float DEFAULT_VISION_SQUEEZE_TRANSITION = 0.25f;
static const int DEFAULT_VISION_SQUEEZE_PER_EYE = 1;
static const float DEFAULT_VISION_SQUEEZE_GROUND_PLANE_Y = 0.0f;
static const float DEFAULT_VISION_SQUEEZE_SPOTLIGHT_SIZE = 6.0f;
class VisionSqueeze {
public:
VisionSqueeze();
bool getVisionSqueezeEnabled() const { return _visionSqueezeEnabled; }
void setVisionSqueezeEnabled(bool value);
float getVisionSqueezeRatioX() const { return _visionSqueezeRatioX; }
float getVisionSqueezeRatioY() const { return _visionSqueezeRatioY; }
void setVisionSqueezeRatioX(float value);
void setVisionSqueezeRatioY(float value);
float getVisionSqueezeUnSqueezeDelay() const { return _visionSqueezeUnSqueezeDelay; }
void setVisionSqueezeUnSqueezeDelay(float value);
float getVisionSqueezeUnSqueezeSpeed() const { return _visionSqueezeUnSqueezeSpeed; }
void setVisionSqueezeUnSqueezeSpeed(float value);
float getVisionSqueezeTransition() const { return _visionSqueezeTransition; }
void setVisionSqueezeTransition(float value);
int getVisionSqueezePerEye() const { return _visionSqueezePerEye; }
void setVisionSqueezePerEye(int value);
float getVisionSqueezeGroundPlaneY() const { return _visionSqueezeGroundPlaneY; }
void setVisionSqueezeGroundPlaneY(float value);
float getVisionSqueezeSpotlightSize() const { return _visionSqueezeSpotlightSize; }
void setVisionSqueezeSpotlightSize(float value);
float getVisionSqueezeTurningXFactor() const { return _visionSqueezeTurningXFactor; }
void setVisionSqueezeTurningXFactor(float value);
float getVisionSqueezeTurningYFactor() const { return _visionSqueezeTurningYFactor; }
void setVisionSqueezeTurningYFactor(float value);
void updateVisionSqueeze(const glm::mat4& sensorToWorldMatrix, float deltaTime);
// state variable accessors used by Application.cpp...
bool getSqueezeVision() const { return _squeezeVision; }
void setSqueezeVision(bool value) { _squeezeVision = value; }
bool getSqueezeVisionTurning() const { return _squeezeVisionTurning; }
void setSqueezeVisionTurning(bool value) { _squeezeVisionTurning = value; }
private:
Setting::Handle<bool> _visionSqueezeEnabledSetting {"visionSqueezeEnabled", false};
Setting::Handle<float> _visionSqueezeRatioXSetting {"visionSqueezeRatioX", 0.0f};
Setting::Handle<float> _visionSqueezeRatioYSetting {"visionSqueezeRatioY", 0.0f};
Setting::Handle<float> _visionSqueezeUnSqueezeDelaySetting {"visionSqueezeUnSqueezeDelay",
DEFAULT_VISION_SQUEEZE_UNSQUEEZE_DELAY};
Setting::Handle<float> _visionSqueezeUnSqueezeSpeedSetting {"visionSqueezeUnSqueezeSpeed",
DEFAULT_VISION_SQUEEZE_UNSQUEEZE_SPEED};
Setting::Handle<float> _visionSqueezeTransitionSetting {"visionSqueezeTransition", DEFAULT_VISION_SQUEEZE_TRANSITION};
Setting::Handle<float> _visionSqueezePerEyeSetting {"visionSqueezePerEye", DEFAULT_VISION_SQUEEZE_PER_EYE};
Setting::Handle<float> _visionSqueezeGroundPlaneYSetting {"visionSqueezeGroundPlaneY",
DEFAULT_VISION_SQUEEZE_GROUND_PLANE_Y};
Setting::Handle<float> _visionSqueezeSpotlightSizeSetting {"visionSqueezeSpotlightSize",
DEFAULT_VISION_SQUEEZE_SPOTLIGHT_SIZE};
Setting::Handle<float> _visionSqueezeTurningXFactorSetting {"visionSqueezeTurningXFactor",
DEFAULT_VISION_SQUEEZE_TURNING_X_FACTOR};
Setting::Handle<float> _visionSqueezeTurningYFactorSetting {"visionSqueezeTurningYFactor",
DEFAULT_VISION_SQUEEZE_TURNING_Y_FACTOR};
// these are readable and writable from the scripting interface (on a different thread), so make them atomic
std::atomic<bool> _visionSqueezeEnabled { false };
std::atomic<float> _visionSqueezeRatioX { 0.0f };
std::atomic<float> _visionSqueezeRatioY { 0.0f };
std::atomic<float> _visionSqueezeUnSqueezeDelay { DEFAULT_VISION_SQUEEZE_UNSQUEEZE_DELAY }; // seconds
std::atomic<float> _visionSqueezeUnSqueezeSpeed { DEFAULT_VISION_SQUEEZE_UNSQUEEZE_SPEED };
std::atomic<float> _visionSqueezeTransition { DEFAULT_VISION_SQUEEZE_TRANSITION };
std::atomic<int> _visionSqueezePerEye { DEFAULT_VISION_SQUEEZE_PER_EYE };
std::atomic<float> _visionSqueezeGroundPlaneY { DEFAULT_VISION_SQUEEZE_GROUND_PLANE_Y };
std::atomic<float> _visionSqueezeSpotlightSize { DEFAULT_VISION_SQUEEZE_SPOTLIGHT_SIZE };
std::atomic<float> _visionSqueezeTurningXFactor { DEFAULT_VISION_SQUEEZE_TURNING_X_FACTOR };
std::atomic<float> _visionSqueezeTurningYFactor { DEFAULT_VISION_SQUEEZE_TURNING_Y_FACTOR };
bool _squeezeVision { false };
bool _squeezeVisionTurning { false };
float _visionSqueezeLockout { 0.0 };
glm::vec3 _prevTranslation;
glm::quat _prevRotation;
};
#endif // hifi_VisionSqueeze_h

View file

@ -6144,4 +6144,3 @@ void MyAvatar::sendPacket(const QUuid& entityID) const {
});
}
}

View file

@ -236,3 +236,83 @@ QVariant HMDScriptingInterface::getPlayAreaRect() {
QVector<glm::vec3> HMDScriptingInterface::getSensorPositions() {
return qApp->getActiveDisplayPlugin()->getSensorPositions();
}
float HMDScriptingInterface::getVisionSqueezeRatioX() const {
return qApp->getVisionSqueeze().getVisionSqueezeRatioX();
}
float HMDScriptingInterface::getVisionSqueezeRatioY() const {
return qApp->getVisionSqueeze().getVisionSqueezeRatioY();
}
void HMDScriptingInterface::setVisionSqueezeRatioX(float value) {
qApp->getVisionSqueeze().setVisionSqueezeRatioX(value);
}
void HMDScriptingInterface::setVisionSqueezeRatioY(float value) {
qApp->getVisionSqueeze().setVisionSqueezeRatioY(value);
}
float HMDScriptingInterface::getVisionSqueezeUnSqueezeDelay() const {
return qApp->getVisionSqueeze().getVisionSqueezeUnSqueezeDelay();
}
void HMDScriptingInterface::setVisionSqueezeUnSqueezeDelay(float value) {
qApp->getVisionSqueeze().setVisionSqueezeUnSqueezeDelay(value);
}
float HMDScriptingInterface::getVisionSqueezeUnSqueezeSpeed() const {
return qApp->getVisionSqueeze().getVisionSqueezeUnSqueezeSpeed();
}
void HMDScriptingInterface::setVisionSqueezeUnSqueezeSpeed(float value) {
qApp->getVisionSqueeze().setVisionSqueezeUnSqueezeSpeed(value);
}
float HMDScriptingInterface::getVisionSqueezeTransition() const {
return qApp->getVisionSqueeze().getVisionSqueezeTransition();
}
void HMDScriptingInterface::setVisionSqueezeTransition(float value) {
qApp->getVisionSqueeze().setVisionSqueezeTransition(value);
}
int HMDScriptingInterface::getVisionSqueezePerEye() const {
return qApp->getVisionSqueeze().getVisionSqueezePerEye();
}
void HMDScriptingInterface::setVisionSqueezePerEye(int value) {
qApp->getVisionSqueeze().setVisionSqueezePerEye(value);
}
float HMDScriptingInterface::getVisionSqueezeGroundPlaneY() const {
return qApp->getVisionSqueeze().getVisionSqueezeGroundPlaneY();
}
void HMDScriptingInterface::setVisionSqueezeGroundPlaneY(float value) {
qApp->getVisionSqueeze().setVisionSqueezeGroundPlaneY(value);
}
float HMDScriptingInterface::getVisionSqueezeSpotlightSize() const {
return qApp->getVisionSqueeze().getVisionSqueezeSpotlightSize();
}
void HMDScriptingInterface::setVisionSqueezeSpotlightSize(float value) {
qApp->getVisionSqueeze().setVisionSqueezeSpotlightSize(value);
}
float HMDScriptingInterface::getVisionSqueezeTurningXFactor() const {
return qApp->getVisionSqueeze().getVisionSqueezeTurningXFactor();
}
void HMDScriptingInterface::setVisionSqueezeTurningXFactor(float value) {
qApp->getVisionSqueeze().setVisionSqueezeTurningXFactor(value);
}
float HMDScriptingInterface::getVisionSqueezeTurningYFactor() const {
return qApp->getVisionSqueeze().getVisionSqueezeTurningYFactor();
}
void HMDScriptingInterface::setVisionSqueezeTurningYFactor(float value) {
qApp->getVisionSqueeze().setVisionSqueezeTurningYFactor(value);
}

View file

@ -84,6 +84,17 @@ class HMDScriptingInterface : public AbstractHMDScriptingInterface, public Depen
Q_PROPERTY(QVariant playArea READ getPlayAreaRect);
Q_PROPERTY(QVector<glm::vec3> sensorPositions READ getSensorPositions);
Q_PROPERTY(float visionSqueezeRatioX READ getVisionSqueezeRatioX WRITE setVisionSqueezeRatioX);
Q_PROPERTY(float visionSqueezeRatioY READ getVisionSqueezeRatioY WRITE setVisionSqueezeRatioY);
Q_PROPERTY(float visionSqueezeUnSqueezeDelay READ getVisionSqueezeUnSqueezeDelay WRITE setVisionSqueezeUnSqueezeDelay);
Q_PROPERTY(float visionSqueezeUnSqueezeSpeed READ getVisionSqueezeUnSqueezeSpeed WRITE setVisionSqueezeUnSqueezeSpeed);
Q_PROPERTY(float visionSqueezeTransition READ getVisionSqueezeTransition WRITE setVisionSqueezeTransition);
Q_PROPERTY(int visionSqueezePerEye READ getVisionSqueezePerEye WRITE setVisionSqueezePerEye);
Q_PROPERTY(float visionSqueezeGroundPlaneY READ getVisionSqueezeGroundPlaneY WRITE setVisionSqueezeGroundPlaneY);
Q_PROPERTY(float visionSqueezeSpotlightSize READ getVisionSqueezeSpotlightSize WRITE setVisionSqueezeSpotlightSize);
Q_PROPERTY(float visionSqueezeTurningXFactor READ getVisionSqueezeTurningXFactor WRITE setVisionSqueezeTurningXFactor);
Q_PROPERTY(float visionSqueezeTurningYFactor READ getVisionSqueezeTurningYFactor WRITE setVisionSqueezeTurningYFactor);
public:
/**jsdoc
@ -339,6 +350,27 @@ public:
*/
Q_INVOKABLE void openTablet(bool contextualMode = false);
float getVisionSqueezeRatioX() const;
float getVisionSqueezeRatioY() const;
void setVisionSqueezeRatioX(float value);
void setVisionSqueezeRatioY(float value);
float getVisionSqueezeUnSqueezeDelay() const;
void setVisionSqueezeUnSqueezeDelay(float value);
float getVisionSqueezeUnSqueezeSpeed() const;
void setVisionSqueezeUnSqueezeSpeed(float value);
float getVisionSqueezeTransition() const;
void setVisionSqueezeTransition(float value);
int getVisionSqueezePerEye() const;
void setVisionSqueezePerEye(int value);
float getVisionSqueezeGroundPlaneY() const;
void setVisionSqueezeGroundPlaneY(float value);
float getVisionSqueezeSpotlightSize() const;
void setVisionSqueezeSpotlightSize(float value);
float getVisionSqueezeTurningXFactor() const;
void setVisionSqueezeTurningXFactor(float value);
float getVisionSqueezeTurningYFactor() const;
void setVisionSqueezeTurningYFactor(float value);
signals:
/**jsdoc
* Triggered when a request to show or hide models of the HMD hand controllers is made using

View file

@ -16,6 +16,7 @@
#include <Preferences.h>
#include <plugins/PluginUtils.h>
#include <display-plugins/CompositorHelper.h>
#include <display-plugins/hmd/HmdDisplayPlugin.h>
#include "scripting/RenderScriptingInterface.h"
#include "Application.h"
#include "DialogsManager.h"
@ -377,6 +378,33 @@ void setupPreferences() {
preference->setDecimals(2);
preferences->addPreference(preference);
}
{
auto getter = []()->bool {
return qApp->getVisionSqueeze().getVisionSqueezeEnabled();
};
auto setter = [](bool value) {
qApp->getVisionSqueeze().setVisionSqueezeEnabled(value);
};
auto preference = new CheckPreference(VR_MOVEMENT, "Enable HMD Comfort Mode", getter, setter);
preferences->addPreference(preference);
}
{
const float sliderPositions = 5.0f;
auto getter = [sliderPositions]()->float {
return roundf(sliderPositions * qApp->getVisionSqueeze().getVisionSqueezeRatioX());
};
auto setter = [sliderPositions](float value) {
float ratio = value / sliderPositions;
qApp->getVisionSqueeze().setVisionSqueezeRatioX(ratio);
qApp->getVisionSqueeze().setVisionSqueezeRatioY(ratio);
};
auto preference = new SpinnerSliderPreference(VR_MOVEMENT, "Comfort Mode", getter, setter);
preference->setMin(0.0f);
preference->setMax(sliderPositions);
preference->setStep(1.0f);
preference->setDecimals(0);
preferences->addPreference(preference);
}
{
auto getter = [myAvatar]()->bool { return myAvatar->getShowPlayArea(); };
auto setter = [myAvatar](bool value) { myAvatar->setShowPlayArea(value); };

View file

@ -0,0 +1,104 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
//
// DrawTextureWithVisionSqueeze.frag
//
// Draw texture 0 fetched at texcoord.xy
//
// Created by Seth Alves on 2019-2-15
// Copyright 2019 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 display-plugins/VisionSqueeze.slh@>
struct DrawTextureWithVisionSqueezeParams {
float _visionSqueezeX;
float _visionSqueezeY;
float _spareA;
float _spareB;
mat4 _leftProjection;
mat4 _rightProjection;
mat4 _hmdSensorMatrix;
float _visionSqueezeTransition;
int _visionSqueezePerEye;
float _visionSqueezeGroundPlaneY;
float _visionSqueezeSpotlightSize;
};
LAYOUT(binding=0) uniform sampler2D colorMap;
// binding=1 must match drawTextureWithSqueezeParamsSlot in OpenGLDisplayPlugin.h
LAYOUT(binding=1) uniform drawTextureWithSqueezeMappingParamsBuffer {
DrawTextureWithVisionSqueezeParams params;
};
layout(location=0) in vec2 varTexCoord0;
layout(location=0) out vec4 outFragColor;
float getVisionSqueezeX() {
return params._visionSqueezeX;
}
float getVisionSqueezeY() {
return params._visionSqueezeY;
}
float getVisionSqueezeTransitionRatio() {
return params._visionSqueezeTransition;
}
int getVisionSqueezePerEye() {
return params._visionSqueezePerEye;
}
float getVisionSqueezeGroundPlaneY() {
return params._visionSqueezeGroundPlaneY;
}
float getVisionSqueezeSpotlightSize() {
return params._visionSqueezeSpotlightSize;
}
mat4 getProjectionMatrix(float eye) {
if (eye == 0.0) {
return params._leftProjection;
} else {
return params._rightProjection;
}
}
mat4 getHMDSensorMatrix() {
return params._hmdSensorMatrix;
}
void main(void) {
float side = float(varTexCoord0.x > 0.5);
mat4 leftProjectionMatrix = getProjectionMatrix(0.0);
vec4 fovTan = extractFovTan(leftProjectionMatrix);
vec2 focalPointNDC = extractFocalPoint(fovTan);
focalPointNDC.x -= 2.0 * focalPointNDC.x * (1.0 - side);
vec2 focalPointUV = 0.5 * (focalPointNDC + vec2(1.0));
// block edges of vision to avoid sickness
vec2 visionSqueezeRatios = vec2(getVisionSqueezeX(), getVisionSqueezeY());
bool perEye = getVisionSqueezePerEye() > 0;
float frac = squeezeVision(perEye, varTexCoord0, visionSqueezeRatios, getVisionSqueezeTransitionRatio(), focalPointUV);
if (frac == 0.0) {
// world only
outFragColor = texture(colorMap, varTexCoord0);
} else {
// grid on the floor only or mixed
mat4 hmdSensorMatrix = getHMDSensorMatrix();
mat4 projectionMatrix = getProjectionMatrix(side);
mat4 projectionInverse = inverse(projectionMatrix);
float groundPlaneY = getVisionSqueezeGroundPlaneY();
float spotLightSize = getVisionSqueezeSpotlightSize();
vec4 gridColor = vec4(gridFloor(varTexCoord0, hmdSensorMatrix, projectionInverse, groundPlaneY, spotLightSize), 1.0);
vec4 preSqueezeColor = texture(colorMap, varTexCoord0);
// mix between grid and world
outFragColor = mix(preSqueezeColor, gridColor, frac);
}
}

View file

@ -0,0 +1 @@
VERTEX gpu::vertex::DrawUnitQuadTexcoord

View file

@ -392,6 +392,9 @@ void OpenGLDisplayPlugin::customizeContext() {
_drawTexturePipeline = gpu::Pipeline::create(gpu::Shader::createProgram(DrawTexture), scissorState);
_drawTextureSqueezePipeline =
gpu::Pipeline::create(gpu::Shader::createProgram(shader::display_plugins::program::DrawTextureWithVisionSqueeze), scissorState);
_linearToSRGBPipeline = gpu::Pipeline::create(gpu::Shader::createProgram(DrawTextureLinearToSRGB), scissorState);
_SRGBToLinearPipeline = gpu::Pipeline::create(gpu::Shader::createProgram(DrawTextureSRGBToLinear), scissorState);
@ -407,6 +410,7 @@ void OpenGLDisplayPlugin::customizeContext() {
void OpenGLDisplayPlugin::uncustomizeContext() {
_drawTexturePipeline.reset();
_drawTextureSqueezePipeline.reset();
_linearToSRGBPipeline.reset();
_SRGBToLinearPipeline.reset();
_cursorPipeline.reset();
@ -629,6 +633,10 @@ void OpenGLDisplayPlugin::compositePointer() {
});
}
void OpenGLDisplayPlugin::setupCompositeScenePipeline(gpu::Batch& batch) {
batch.setPipeline(_drawTexturePipeline);
}
void OpenGLDisplayPlugin::compositeScene() {
render([&](gpu::Batch& batch) {
batch.enableStereo(false);
@ -637,8 +645,8 @@ void OpenGLDisplayPlugin::compositeScene() {
batch.setStateScissorRect(ivec4(uvec2(), _compositeFramebuffer->getSize()));
batch.resetViewTransform();
batch.setProjectionTransform(mat4());
batch.setPipeline(_drawTexturePipeline);
batch.setResourceTexture(0, _currentFrame->framebuffer->getRenderBuffer(0));
setupCompositeScenePipeline(batch);
batch.draw(gpu::TRIANGLE_STRIP, 4);
});
}
@ -958,4 +966,3 @@ void OpenGLDisplayPlugin::copyTextureToQuickFramebuffer(NetworkTexturePointer ne
gpu::PipelinePointer OpenGLDisplayPlugin::getRenderTexturePipeline() {
return _drawTexturePipeline;
}

View file

@ -100,6 +100,7 @@ protected:
virtual QThread::Priority getPresentPriority() { return QThread::HighPriority; }
virtual void compositeLayers();
virtual void setupCompositeScenePipeline(gpu::Batch& batch);
virtual void compositeScene();
virtual void compositePointer();
virtual void compositeExtra(){};
@ -155,6 +156,7 @@ protected:
gpu::PipelinePointer _mirrorHUDPipeline;
gpu::ShaderPointer _mirrorHUDPS;
gpu::PipelinePointer _drawTexturePipeline;
gpu::PipelinePointer _drawTextureSqueezePipeline;
gpu::PipelinePointer _linearToSRGBPipeline;
gpu::PipelinePointer _SRGBToLinearPipeline;
gpu::PipelinePointer _cursorPipeline;

View file

@ -0,0 +1,106 @@
// Generated on <$_SCRIBE_DATE$>
//
// Created by Seth Alves on 2019-2-13.
// Copyright 2019 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
//
<@if not VISION_SQUEEZE_SLH@>
<@def VISION_SQUEEZE_SLH@>
float ellipse(vec2 coord, vec2 centerUV, vec2 semiAxis) {
return pow(coord.x - centerUV.x, 2.0) / semiAxis.x + pow(coord.y - centerUV.y, 2.0) / semiAxis.y;
}
vec4 extractFovTan(mat4 m) {
mat4 mt = transpose(m);
vec4 v;
vec4 result;
// x -- Left
v = mt * vec4(1.0, 0.0, 0.0, 1.0);
result.x = -(v.z / v.x);
// y -- Right
v = mt * vec4(-1.0, 0.0, 0.0, 1.0);
result.y = (v.z / v.x);
// z -- Down
v = mt * vec4(0.0, 1.0, 0.0, 1.0);
result.z = -(v.z / v.y);
// w -- Up
v = mt * vec4(0.0, -1.0, 0.0, 1.0);
result.w = v.z / v.y;
return result;
}
// takes left-side projection matrix, returns NDC for right eye. to get left, invert sign on x coord of result.
vec2 extractFocalPoint(vec4 fovTan) {
float fovwidth = fovTan.x + fovTan.y;
float fovheight = fovTan.z + fovTan.w;
vec2 focalPoint = vec2(fovTan.y / fovwidth, (fovTan.z / fovheight) - 0.5f);
return focalPoint;
}
float squeezeVision(bool perEye, vec2 varTexCoord0, vec2 visionSqueezeRatios, float transitionRatio, vec2 focalPointUV) {
if (visionSqueezeRatios.x == 0.0 && visionSqueezeRatios.y == 0.0) {
return 0.0;
}
vec2 centerUV;
vec2 semiAxis;
if (perEye) {
// tubes in front of each eye
centerUV = focalPointUV;
semiAxis = vec2(0.25) - visionSqueezeRatios * 0.25;
} else {
// one tube in front of face
centerUV = vec2(0.5, focalPointUV.y);
semiAxis = vec2(0.5) - visionSqueezeRatios * 0.5;
}
float ellipseValue = ellipse(varTexCoord0, centerUV, semiAxis);
float frac = clamp((ellipseValue - 1.0) / clamp(transitionRatio, 0.01, 0.7), 0.0, 1.0);
return frac;
}
vec3 gridFloor(vec2 varTexCoord0, mat4 hmdSensorMatrix, mat4 projectionInverse, float groundPlaneY, float spotLightSize) {
vec4 ndc = vec4(varTexCoord0.x * 4.0 - 1.0 - 2.0 * float(varTexCoord0.x > 0.5), varTexCoord0.y * 2.0 - 1.0, -1.0, 1.0);
vec4 fragmentEyeCoords = hmdSensorMatrix * projectionInverse * ndc;
vec4 near4 = hmdSensorMatrix * vec4(0.0, 0.0, 0.0, 1.0);
vec3 near = (near4 / near4.w).xyz;
vec3 far = fragmentEyeCoords.xyz / fragmentEyeCoords.w;
// intersect a line from near to far with the plane y = groundPlaneY
float t = -(near.y - groundPlaneY) / (far.y - near.y);
vec2 R = (near + t * (far - near)).xz;
float lineThickness = 1.5 / length(R);
vec4 gridColor = vec4(0.35);
vec4 baseColor = vec4(0.1);
vec4 skyColor = vec4(0.0, 0.0, 0.0, 0.0);
vec2 wrapped = fract(R) - 0.5f;
vec2 range = abs(wrapped);
vec2 speeds = fwidth(R);
vec2 pixelRange = range/speeds;
float lineWeight = clamp(min(pixelRange.x, pixelRange.y) - lineThickness, 0.0, 1.0);
float horizonFuzz = 0.02;
if (t < 0.0) {
return mix(gridColor, skyColor, clamp(0.0, 1.0, -t)).xyz;
} else if (t < horizonFuzz) {
lineWeight = lineWeight * max(0.0, t);
}
vec4 c = mix(gridColor, baseColor, lineWeight);
// fade out grid to avoid shimmer
float fadeVal = 0.7;
return mix(c, baseColor * fadeVal + gridColor * (1.0 - fadeVal),
0.1 * clamp((length(R) - spotLightSize), 0.0, 1.0)).xyz;
}
<@endif@>

View file

@ -1,4 +1,4 @@
//
//
// Created by Bradley Austin Davis on 2016/02/15
// Copyright 2016 High Fidelity, Inc.
//
@ -113,6 +113,11 @@ void HmdDisplayPlugin::internalDeactivate() {
}
void HmdDisplayPlugin::customizeContext() {
VisionSqueezeParameters parameters;
_visionSqueezeParametersBuffer =
gpu::BufferView(std::make_shared<gpu::Buffer>(sizeof(VisionSqueezeParameters), (const gpu::Byte*) &parameters));
Parent::customizeContext();
_hudRenderer.build();
}
@ -478,3 +483,57 @@ HmdDisplayPlugin::~HmdDisplayPlugin() {
float HmdDisplayPlugin::stutterRate() const {
return _stutterRate.rate();
}
float adjustVisionSqueezeRatioForDevice(float visionSqueezeRatio, float visionSqueezeDeviceLow, float visionSqueezeDeviceHigh) {
const float SETTINGS_STEP = 0.2f; // adjusting the slider in preferences changes the ratio by this much
if (visionSqueezeRatio == 0.0f) {
return 0.0f;
}
float deviceRange = visionSqueezeDeviceHigh - visionSqueezeDeviceLow;
if (visionSqueezeRatio <= SETTINGS_STEP) {
// lowest "enabled" setting -- without this special case the user doesn't see anything on the lowest setting
float scaleFactor = (visionSqueezeRatio == SETTINGS_STEP) ? 0.24f : 0.18f; // these magic values were picked through experimentation
return deviceRange * scaleFactor + visionSqueezeDeviceLow;
} else {
const float SQUEEZE_ADJUSTMENT = 0.75f; // magic number picked through experimentation
return deviceRange * (SQUEEZE_ADJUSTMENT * visionSqueezeRatio) + visionSqueezeDeviceLow;
}
}
void HmdDisplayPlugin::updateVisionSqueezeParameters(float visionSqueezeX, float visionSqueezeY,
float visionSqueezeTransition,
int visionSqueezePerEye, float visionSqueezeGroundPlaneY,
float visionSqueezeSpotlightSize) {
visionSqueezeX = adjustVisionSqueezeRatioForDevice(visionSqueezeX, _visionSqueezeDeviceLowX, _visionSqueezeDeviceHighX);
visionSqueezeY = adjustVisionSqueezeRatioForDevice(visionSqueezeY, _visionSqueezeDeviceLowY, _visionSqueezeDeviceHighY);
auto& params = _visionSqueezeParametersBuffer.get<VisionSqueezeParameters>();
if (params._visionSqueezeX != visionSqueezeX) {
_visionSqueezeParametersBuffer.edit<VisionSqueezeParameters>()._visionSqueezeX = visionSqueezeX;
}
if (params._visionSqueezeY != visionSqueezeY) {
_visionSqueezeParametersBuffer.edit<VisionSqueezeParameters>()._visionSqueezeY = visionSqueezeY;
}
if (params._visionSqueezeTransition != visionSqueezeTransition) {
_visionSqueezeParametersBuffer.edit<VisionSqueezeParameters>()._visionSqueezeTransition = visionSqueezeTransition;
}
if (params._visionSqueezePerEye != visionSqueezePerEye) {
_visionSqueezeParametersBuffer.edit<VisionSqueezeParameters>()._visionSqueezePerEye = visionSqueezePerEye;
}
if (params._visionSqueezeGroundPlaneY != visionSqueezeGroundPlaneY) {
_visionSqueezeParametersBuffer.edit<VisionSqueezeParameters>()._visionSqueezeGroundPlaneY = visionSqueezeGroundPlaneY;
}
if (params._visionSqueezeSpotlightSize != visionSqueezeSpotlightSize) {
_visionSqueezeParametersBuffer.edit<VisionSqueezeParameters>()._visionSqueezeSpotlightSize = visionSqueezeSpotlightSize;
}
}
void HmdDisplayPlugin::setupCompositeScenePipeline(gpu::Batch& batch) {
batch.setPipeline(_drawTextureSqueezePipeline);
_visionSqueezeParametersBuffer.edit<VisionSqueezeParameters>()._hmdSensorMatrix = _currentPresentFrameInfo.presentPose;
batch.setUniformBuffer(drawTextureWithVisionSqueezeParamsSlot, _visionSqueezeParametersBuffer);
}

View file

@ -50,6 +50,9 @@ public:
std::function<void(gpu::Batch&, const gpu::TexturePointer&)> getHUDOperator() override;
virtual StencilMaskMode getStencilMaskMode() const override { return StencilMaskMode::PAINT; }
void updateVisionSqueezeParameters(float visionSqueezeX, float visionSqueezeY, float visionSqueezeTransition,
int visionSqueezePerEye, float visionSqueezeGroundPlaneY,
float visionSqueezeSpotlightSize);
signals:
void hmdMountedChanged();
@ -91,6 +94,33 @@ protected:
RateCounter<> _stutterRate;
bool _disablePreview { true };
class VisionSqueezeParameters {
public:
float _visionSqueezeX { 0.0f };
float _visionSqueezeY { 0.0f };
float _spareA { 0.0f };
float _spareB { 0.0f };
glm::mat4 _leftProjection;
glm::mat4 _rightProjection;
glm::mat4 _hmdSensorMatrix;
float _visionSqueezeTransition { 0.15f };
int _visionSqueezePerEye { 0 };
float _visionSqueezeGroundPlaneY { 0.0f };
float _visionSqueezeSpotlightSize { 0.0f };
VisionSqueezeParameters() {}
};
typedef gpu::BufferView UniformBufferView;
gpu::BufferView _visionSqueezeParametersBuffer;
virtual void setupCompositeScenePipeline(gpu::Batch& batch) override;
float _visionSqueezeDeviceLowX { 0.0f };
float _visionSqueezeDeviceHighX { 1.0f };
float _visionSqueezeDeviceLowY { 0.0f };
float _visionSqueezeDeviceHighY { 1.0f };
private:
ivec4 getViewportForSourceSize(const uvec2& size) const;
float getLeftCenterPixel() const;
@ -112,7 +142,7 @@ private:
struct Uniforms {
float alpha { 1.0f };
} uniforms;
struct Vertex {
vec3 pos;
vec2 uv;
@ -126,3 +156,5 @@ private:
std::function<void(gpu::Batch&, const gpu::TexturePointer&)> render();
} _hudRenderer;
};
const int drawTextureWithVisionSqueezeParamsSlot = 1; // must match binding in DrawTextureWithVisionSqueeze.slf

View file

@ -220,7 +220,7 @@ double Context::getFrameTimerBatchAverage() const {
const Backend::TransformCamera& Backend::TransformCamera::recomputeDerived(const Transform& xformView) const {
_projectionInverse = glm::inverse(_projection);
// Get the viewEyeToWorld matrix form the transformView as passed to the gpu::Batch
// Get the viewEyeToWorld matrix from the transformView as passed to the gpu::Batch
// this is the "_viewInverse" fed to the shader
// Genetrate the "_view" matrix as well from the xform
xformView.getMatrix(_viewInverse);

View file

@ -214,6 +214,9 @@ public:
virtual StencilMaskMode getStencilMaskMode() const { return StencilMaskMode::NONE; }
using StencilMaskMeshOperator = std::function<void(gpu::Batch&)>;
virtual StencilMaskMeshOperator getStencilMaskMeshOperator() { return nullptr; }
virtual void updateParameters(float visionSqueezeX, float visionSqueezeY, float visionSqueezeTransition,
int visionSqueezePerEye, float visionSqueezeGroundPlaneY,
float visionSqueezeSpotlightSize) {}
signals:
void recommendedFramebufferSizeChanged(const QSize& size);

View file

@ -142,6 +142,13 @@ namespace render {
bool _takingSnapshot { false };
StencilMaskMode _stencilMaskMode { StencilMaskMode::NONE };
std::function<void(gpu::Batch&)> _stencilMaskOperator;
float _visionSqueezeX { 0.0f };
float _visionSqueezeY { 0.0f };
float _visionSqueezeTransition { 0.15f };
int _visionSqueezePerEye { 0 };
float _visionSqueezeGroundPlaneY { 0.0f };
float _visionSqueezeSpotlightSize { 0.02f };
};
}

View file

@ -53,6 +53,13 @@ bool OculusDisplayPlugin::internalActivate() {
void OculusDisplayPlugin::init() {
Plugin::init();
// Different HMDs end up showing the squeezed-vision egg as different sizes. These values
// attempt to make them appear the same.
_visionSqueezeDeviceLowX = 0.8f;
_visionSqueezeDeviceHighX = 0.98f;
_visionSqueezeDeviceLowY = 0.8f;
_visionSqueezeDeviceHighY = 0.9f;
emit deviceConnected(getName());
}
@ -151,8 +158,11 @@ void OculusDisplayPlugin::hmdPresent() {
GLuint curTexId;
ovr_GetTextureSwapChainBufferGL(_session, _textureSwapChain, curIndex, &curTexId);
_visionSqueezeParametersBuffer.edit<VisionSqueezeParameters>()._leftProjection = _eyeProjections[0];
_visionSqueezeParametersBuffer.edit<VisionSqueezeParameters>()._rightProjection = _eyeProjections[1];
// Manually bind the texture to the FBO
// FIXME we should have a way of wrapping raw GL ids in GPU objects without
// FIXME we should have a way of wrapping raw GL ids in GPU objects without
// taking ownership of the object
auto fbo = getGLBackend()->getFramebufferID(_outputFramebuffer);
glNamedFramebufferTexture(fbo, GL_COLOR_ATTACHMENT0, curTexId, 0);

View file

@ -396,6 +396,13 @@ void OpenVrDisplayPlugin::init() {
_lastGoodHMDPose.m[2][2] = 1.0f;
_lastGoodHMDPose.m[2][3] = 0.0f;
// Different HMDs end up showing the squeezed-vision egg as different sizes. These values
// attempt to make them appear the same.
_visionSqueezeDeviceLowX = 0.8f;
_visionSqueezeDeviceHighX = 0.98f;
_visionSqueezeDeviceLowY = 0.8f;
_visionSqueezeDeviceHighY = 0.9f;
emit deviceConnected(getName());
}
@ -651,6 +658,11 @@ void OpenVrDisplayPlugin::hmdPresent() {
if (_threadedSubmit) {
_submitThread->waitForPresent();
} else {
_visionSqueezeParametersBuffer.edit<VisionSqueezeParameters>()._leftProjection = _eyeProjections[0];
_visionSqueezeParametersBuffer.edit<VisionSqueezeParameters>()._rightProjection = _eyeProjections[1];
_visionSqueezeParametersBuffer.edit<VisionSqueezeParameters>()._hmdSensorMatrix = _currentPresentFrameInfo.presentPose;
GLuint glTexId = getGLBackend()->getTextureID(_compositeFramebuffer->getRenderBuffer(0));
vr::Texture_t vrTexture{ (void*)(uintptr_t)glTexId, vr::TextureType_OpenGL, vr::ColorSpace_Auto };
vr::VRCompositor()->Submit(vr::Eye_Left, &vrTexture, &OPENVR_TEXTURE_BOUNDS_LEFT);
@ -828,4 +840,15 @@ DisplayPlugin::StencilMaskMeshOperator OpenVrDisplayPlugin::getStencilMaskMeshOp
}
}
return nullptr;
}
}
void OpenVrDisplayPlugin::updateParameters(float visionSqueezeX, float visionSqueezeY, float visionSqueezeTransition,
int visionSqueezePerEye, float visionSqueezeGroundPlaneY,
float visionSqueezeSpotlightSize) {
_visionSqueezeX = visionSqueezeX;
_visionSqueezeY = visionSqueezeY;
_visionSqueezeTransition = visionSqueezeTransition;
_visionSqueezePerEye = visionSqueezePerEye;
_visionSqueezeGroundPlaneY = visionSqueezeGroundPlaneY;
_visionSqueezeSpotlightSize = visionSqueezeSpotlightSize;
}

View file

@ -72,6 +72,10 @@ public:
virtual StencilMaskMode getStencilMaskMode() const override { return StencilMaskMode::MESH; }
virtual StencilMaskMeshOperator getStencilMaskMeshOperator() override;
virtual void updateParameters(float visionSqueezeX, float visionSqueezeY, float visionSqueezeTransition,
int visionSqueezePerEye, float visionSqueezeGroundPlaneY,
float visionSqueezeSpotlightSize) override;
protected:
bool internalActivate() override;
void internalDeactivate() override;
@ -102,4 +106,11 @@ private:
std::array<graphics::MeshPointer, 2> _stencilMeshes;
bool _stencilMeshesInitialized { false };
float _visionSqueezeX;
float _visionSqueezeY;
float _visionSqueezeTransition;
int _visionSqueezePerEye;
float _visionSqueezeGroundPlaneY;
float _visionSqueezeSpotlightSize;
};