Introduce 'View ratchetting', cleanup/improve vestibular motion (#510)
* vestibular motion cleanup * Fix environment jumping when autoturn is enabled * Restrict vestibular motion to forward movement * Revert "vestibular motion cleanup" This reverts commit 3d6b293ad2d6a0df41756c67f7e80c4b2be8b6fd. * Experimental: dynamic redirection. very subtle effect * formatting... * swap centidegrees for millidegrees * Experimental: introduce view ratchetting * more cleanup * Revert "Experimental: dynamic redirection. very subtle effect" This reverts commit d6c8e5cdedf1b11013f25340c2e9be64ec1359b8. * vestibular motion cleanup * view ratchetting settings * cleanup and formatting * Resolve drift, improve accuracy of vestibular motion/autoturn * updated UI first pass * UI first pass * Hide Unset Errors After encountering one * fix synch issue add ratchet box * moved view ratchet ui to own file * minor format changes to fit * fixed REALLY 3% minimum * fixed vestib motion default Co-authored-by: ykeara <ykeara1@gmail.com>
This commit is contained in:
@@ -60,6 +60,7 @@ DISTFILES += \
|
|||||||
src/res/qml/rotation_page/redirected/* \
|
src/res/qml/rotation_page/redirected/* \
|
||||||
src/res/qml/rotation_page/snap_turn/* \
|
src/res/qml/rotation_page/snap_turn/* \
|
||||||
src/res/qml/rotation_page/space_turn/* \
|
src/res/qml/rotation_page/space_turn/* \
|
||||||
|
src/res/qml/rotation_page/view_ratchet/* \
|
||||||
src/res/qml/common/*
|
src/res/qml/common/*
|
||||||
|
|
||||||
win32:RC_ICONS += src/res/img/icons/advicon256px.ico
|
win32:RC_ICONS += src/res/img/icons/advicon256px.ico
|
||||||
|
|||||||
@@ -2,15 +2,31 @@
|
|||||||
|
|
||||||
namespace ovr_settings_wrapper
|
namespace ovr_settings_wrapper
|
||||||
{
|
{
|
||||||
|
// cludgey solution, long term solution we should apply defaults that make sense
|
||||||
|
// (most likely false)
|
||||||
|
bool unsetSettingErrorEnabled = true;
|
||||||
|
|
||||||
SettingsError handleErrors( std::string settingsKey,
|
SettingsError handleErrors( std::string settingsKey,
|
||||||
vr::EVRSettingsError error,
|
vr::EVRSettingsError error,
|
||||||
std::string customErrorMsg )
|
std::string customErrorMsg )
|
||||||
{
|
{
|
||||||
if ( error != vr::VRSettingsError_None )
|
if ( error != vr::VRSettingsError_None )
|
||||||
{
|
{
|
||||||
|
if ( !unsetSettingErrorEnabled
|
||||||
|
&& error
|
||||||
|
== vr::EVRSettingsError::
|
||||||
|
VRSettingsError_UnsetSettingHasNoDefault )
|
||||||
|
{
|
||||||
|
return SettingsError::UndefinedError;
|
||||||
|
}
|
||||||
LOG( ERROR ) << "Could not access \"" << settingsKey << "\" setting: "
|
LOG( ERROR ) << "Could not access \"" << settingsKey << "\" setting: "
|
||||||
<< vr::VRSettings()->GetSettingsErrorNameFromEnum( error )
|
<< vr::VRSettings()->GetSettingsErrorNameFromEnum( error )
|
||||||
<< " " << customErrorMsg;
|
<< " " << customErrorMsg;
|
||||||
|
if ( error
|
||||||
|
== vr::EVRSettingsError::VRSettingsError_UnsetSettingHasNoDefault )
|
||||||
|
{
|
||||||
|
unsetSettingErrorEnabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
return SettingsError::UndefinedError;
|
return SettingsError::UndefinedError;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,5 +64,7 @@ SettingsError handleErrors( std::string settingsKey,
|
|||||||
vr::EVRSettingsError,
|
vr::EVRSettingsError,
|
||||||
std::string customErrorMsg );
|
std::string customErrorMsg );
|
||||||
|
|
||||||
|
extern bool unsetSettingErrorEnabled;
|
||||||
|
|
||||||
void resetAllSettings();
|
void resetAllSettings();
|
||||||
} // namespace ovr_settings_wrapper
|
} // namespace ovr_settings_wrapper
|
||||||
|
|||||||
@@ -6,13 +6,14 @@ import "../common"
|
|||||||
import "redirected"
|
import "redirected"
|
||||||
import "space_turn"
|
import "space_turn"
|
||||||
import "snap_turn"
|
import "snap_turn"
|
||||||
|
import "view_ratchet"
|
||||||
|
|
||||||
|
|
||||||
MyStackViewPage {
|
MyStackViewPage {
|
||||||
width: 1200
|
width: 1200
|
||||||
headerText: "Rotation Settings"
|
headerText: "Rotation Settings"
|
||||||
content: ColumnLayout {
|
content: ColumnLayout {
|
||||||
spacing: 10
|
spacing: 8
|
||||||
AutoTurnGroupBox{
|
AutoTurnGroupBox{
|
||||||
id: autoTurnGroupBox
|
id: autoTurnGroupBox
|
||||||
}
|
}
|
||||||
@@ -20,7 +21,9 @@ MyStackViewPage {
|
|||||||
RedirectedGroupBox{
|
RedirectedGroupBox{
|
||||||
id: redirectedGroupBox
|
id: redirectedGroupBox
|
||||||
}
|
}
|
||||||
|
ViewRatchetGroupBox{
|
||||||
|
id: vgiiewRatchetGroupBox
|
||||||
|
}
|
||||||
SpaceTurnGroupBox{
|
SpaceTurnGroupBox{
|
||||||
id:spaceTurnGroupBox
|
id:spaceTurnGroupBox
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ GroupBox {
|
|||||||
label: MyText {
|
label: MyText {
|
||||||
leftPadding: 10
|
leftPadding: 10
|
||||||
text: "Auto-Turn (for discrete redirected walking)"
|
text: "Auto-Turn (for discrete redirected walking)"
|
||||||
bottomPadding: -10
|
bottomPadding: -12
|
||||||
}
|
}
|
||||||
background: Rectangle {
|
background: Rectangle {
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
@@ -26,7 +26,7 @@ GroupBox {
|
|||||||
color: "#ffffff"
|
color: "#ffffff"
|
||||||
height: 1
|
height: 1
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.bottomMargin: 5
|
Layout.bottomMargin: 3
|
||||||
}
|
}
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ GroupBox {
|
|||||||
label: MyText {
|
label: MyText {
|
||||||
leftPadding: 10
|
leftPadding: 10
|
||||||
text: "Vestibular Motion (for continuous redirected walking)"
|
text: "Vestibular Motion (for continuous redirected walking)"
|
||||||
bottomPadding: -10
|
bottomPadding: -12
|
||||||
}
|
}
|
||||||
background: Rectangle {
|
background: Rectangle {
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
@@ -26,13 +26,13 @@ GroupBox {
|
|||||||
color: "#ffffff"
|
color: "#ffffff"
|
||||||
height: 1
|
height: 1
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.bottomMargin: 5
|
Layout.bottomMargin: 3
|
||||||
}
|
}
|
||||||
|
|
||||||
RowLayout{
|
RowLayout{
|
||||||
MyToggleButton {
|
MyToggleButton {
|
||||||
id: redirectedModeToggle
|
id: redirectedModeToggle
|
||||||
text: "On"
|
text: "Toggle On/Off"
|
||||||
Layout.preferredWidth: 225
|
Layout.preferredWidth: 225
|
||||||
onCheckedChanged: {
|
onCheckedChanged: {
|
||||||
RotationTabController.setVestibularMotionEnabled(this.checked, true);
|
RotationTabController.setVestibularMotionEnabled(this.checked, true);
|
||||||
@@ -106,6 +106,7 @@ GroupBox {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
redirectedWalkingRadiusText.text = ((RotationTabController.vestibularMotionRadius).toFixed(2))
|
redirectedWalkingRadiusText.text = ((RotationTabController.vestibularMotionRadius).toFixed(2))
|
||||||
redirectedModeToggle.checked = RotationTabController.vestibularMotionEnabled
|
redirectedModeToggle.checked = RotationTabController.vestibularMotionEnabled
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ GroupBox {
|
|||||||
label: MyText {
|
label: MyText {
|
||||||
leftPadding: 10
|
leftPadding: 10
|
||||||
text: "Space Turn (for manual redirected walking)"
|
text: "Space Turn (for manual redirected walking)"
|
||||||
bottomPadding: -10
|
bottomPadding: -12
|
||||||
}
|
}
|
||||||
background: Rectangle {
|
background: Rectangle {
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
@@ -26,7 +26,7 @@ GroupBox {
|
|||||||
color: "#ffffff"
|
color: "#ffffff"
|
||||||
height: 1
|
height: 1
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.bottomMargin: 5
|
Layout.bottomMargin: 3
|
||||||
}
|
}
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
|
|||||||
@@ -0,0 +1,88 @@
|
|||||||
|
import QtQuick 2.7
|
||||||
|
import QtQuick.Controls 2.0
|
||||||
|
import QtQuick.Layouts 1.3
|
||||||
|
import ovras.advsettings 1.0
|
||||||
|
import "../../common"
|
||||||
|
|
||||||
|
GroupBox {
|
||||||
|
id: viewRatchetGroupBox
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
MyToggleButton{
|
||||||
|
id: viewRatchetToggleBtn
|
||||||
|
text: "View Ratchetting"
|
||||||
|
Layout.preferredWidth: 275
|
||||||
|
onCheckedChanged: {
|
||||||
|
RotationTabController.setViewRatchettingEnabled(this.checked, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Item{
|
||||||
|
Layout.preferredWidth: 25
|
||||||
|
}
|
||||||
|
|
||||||
|
MySlider {
|
||||||
|
id: viewRatchetSlider
|
||||||
|
from: 0.00
|
||||||
|
to: 0.1
|
||||||
|
stepSize: 0.01
|
||||||
|
Layout.fillWidth: true
|
||||||
|
onMoved: {
|
||||||
|
viewRatchetText.text = this.value.toFixed(2)
|
||||||
|
RotationTabController.setViewRatchettingPercent(this.value, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
MyTextField {
|
||||||
|
id: viewRatchetText
|
||||||
|
text: "0.05"
|
||||||
|
keyBoardUID: 1007
|
||||||
|
Layout.preferredWidth: 100
|
||||||
|
Layout.leftMargin: 10
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
function onInputEvent(input) {
|
||||||
|
var val = parseFloat(input)
|
||||||
|
if (!isNaN(val)) {
|
||||||
|
if (val < 0) {
|
||||||
|
val = 0
|
||||||
|
} else if (val > 1) {
|
||||||
|
val = 1
|
||||||
|
}
|
||||||
|
RotationTabController.setViewRatchettingPercent(val.toFixed(2), true)
|
||||||
|
if(val > 0.1){
|
||||||
|
viewRatchetSlider.value = 0.1
|
||||||
|
}else{
|
||||||
|
viewRatchetSlider.value = val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
text = RotationTabController.viewRatchettingPercent.toFixed(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
viewRatchetToggleBtn.checked = RotationTabController.viewRatchettingEnabled
|
||||||
|
var ratchetPercVal = RotationTabController.viewRatchettingPercent
|
||||||
|
viewRatchetSlider.value = ratchetPercVal
|
||||||
|
viewRatchetText.text = ratchetPercVal.toFixed(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: RotationTabController
|
||||||
|
|
||||||
|
onViewRatchettingEnabledChanged:{
|
||||||
|
viewRatchetToggleBtn.checked = RotationTabController.viewRatchettingEnabled
|
||||||
|
}
|
||||||
|
onViewRatchettingPercentChanged:{
|
||||||
|
var ratchetPercVal = RotationTabController.viewRatchettingPercent
|
||||||
|
viewRatchetSlider.value = ratchetPercVal
|
||||||
|
viewRatchetText.text = ratchetPercVal.toFixed(2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -56,7 +56,7 @@ GroupBox {
|
|||||||
stepSize: 0.01
|
stepSize: 0.01
|
||||||
value: 1.0
|
value: 1.0
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
onPositionChanged: {
|
onMoved: {
|
||||||
var val = (this.value * 100)
|
var val = (this.value * 100)
|
||||||
brightnessValueText.text = Math.round(val) + "%"
|
brightnessValueText.text = Math.round(val) + "%"
|
||||||
VideoTabController.setBrightnessOpacityValue(value.toFixed(2), true)
|
VideoTabController.setBrightnessOpacityValue(value.toFixed(2), true)
|
||||||
@@ -80,6 +80,9 @@ GroupBox {
|
|||||||
}
|
}
|
||||||
var v = (val/100)
|
var v = (val/100)
|
||||||
VideoTabController.setBrightnessOpacityValue(v.toFixed(2), true)
|
VideoTabController.setBrightnessOpacityValue(v.toFixed(2), true)
|
||||||
|
if(v<.05){
|
||||||
|
v = .05
|
||||||
|
}
|
||||||
brightnessSlider.value = v
|
brightnessSlider.value = v
|
||||||
}
|
}
|
||||||
text = Math.round(VideoTabController.brightnessOpacityValue * 100) + "%"
|
text = Math.round(VideoTabController.brightnessOpacityValue * 100) + "%"
|
||||||
|
|||||||
@@ -396,6 +396,10 @@ private:
|
|||||||
SettingCategory::Rotation,
|
SettingCategory::Rotation,
|
||||||
QtInfo{ "autoturnVestibularMotionEnabled" },
|
QtInfo{ "autoturnVestibularMotionEnabled" },
|
||||||
false },
|
false },
|
||||||
|
BoolSettingValue{ BoolSetting::ROTATION_autoturnViewRatchettingEnabled,
|
||||||
|
SettingCategory::Rotation,
|
||||||
|
QtInfo{ "autoturnViewRatchettingEnabled" },
|
||||||
|
false },
|
||||||
BoolSettingValue{ BoolSetting::ROTATION_autoturnShowNotification,
|
BoolSettingValue{ BoolSetting::ROTATION_autoturnShowNotification,
|
||||||
SettingCategory::Rotation,
|
SettingCategory::Rotation,
|
||||||
QtInfo{ "autoturnShowNotification" },
|
QtInfo{ "autoturnShowNotification" },
|
||||||
@@ -488,7 +492,11 @@ private:
|
|||||||
SettingCategory::Rotation,
|
SettingCategory::Rotation,
|
||||||
QtInfo{ "autoturnVestibularMotionRadius" },
|
QtInfo{ "autoturnVestibularMotionRadius" },
|
||||||
22.0 },
|
22.0 },
|
||||||
|
DoubleSettingValue{
|
||||||
|
DoubleSetting::ROTATION_autoturnViewRatchettingPercent,
|
||||||
|
SettingCategory::Rotation,
|
||||||
|
QtInfo{ "autoturnViewRatchettingPercent" },
|
||||||
|
0.05 },
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr static auto stringSettingsSize
|
constexpr static auto stringSettingsSize
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ enum class BoolSetting
|
|||||||
ROTATION_autoturnEnabled,
|
ROTATION_autoturnEnabled,
|
||||||
ROTATION_autoturnUseCornerAngle,
|
ROTATION_autoturnUseCornerAngle,
|
||||||
ROTATION_autoturnVestibularMotionEnabled,
|
ROTATION_autoturnVestibularMotionEnabled,
|
||||||
|
ROTATION_autoturnViewRatchettingEnabled,
|
||||||
ROTATION_autoturnShowNotification,
|
ROTATION_autoturnShowNotification,
|
||||||
// LAST_ENUMERATOR must always be set to the last value
|
// LAST_ENUMERATOR must always be set to the last value
|
||||||
LAST_ENUMERATOR = ROTATION_autoturnShowNotification,
|
LAST_ENUMERATOR = ROTATION_autoturnShowNotification,
|
||||||
@@ -84,8 +85,9 @@ enum class DoubleSetting
|
|||||||
ROTATION_cordDetanglingAngle,
|
ROTATION_cordDetanglingAngle,
|
||||||
ROTATION_autoturnMinCordTangle,
|
ROTATION_autoturnMinCordTangle,
|
||||||
ROTATION_autoturnVestibularMotionRadius,
|
ROTATION_autoturnVestibularMotionRadius,
|
||||||
|
ROTATION_autoturnViewRatchettingPercent,
|
||||||
// LAST_ENUMERATOR must always be set to the last value
|
// LAST_ENUMERATOR must always be set to the last value
|
||||||
LAST_ENUMERATOR = ROTATION_autoturnVestibularMotionRadius,
|
LAST_ENUMERATOR = ROTATION_autoturnViewRatchettingPercent,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class StringSetting
|
enum class StringSetting
|
||||||
|
|||||||
@@ -94,7 +94,6 @@ void RotationTabController::eventLoopTick(
|
|||||||
{
|
{
|
||||||
m_isHMDActive = true;
|
m_isHMDActive = true;
|
||||||
}
|
}
|
||||||
// TODO: this doesn't need to run if both are off
|
|
||||||
if ( poseHmd.bPoseIsValid && poseHmd.bDeviceIsConnected
|
if ( poseHmd.bPoseIsValid && poseHmd.bDeviceIsConnected
|
||||||
&& poseHmd.eTrackingResult == vr::TrackingResult_Running_OK )
|
&& poseHmd.eTrackingResult == vr::TrackingResult_Running_OK )
|
||||||
{
|
{
|
||||||
@@ -116,6 +115,12 @@ void RotationTabController::eventLoopTick(
|
|||||||
doVestibularMotion( poseHmd, chaperoneDistances );
|
doVestibularMotion( poseHmd, chaperoneDistances );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( RotationTabController::viewRatchettingEnabled() )
|
||||||
|
{
|
||||||
|
doViewRatchetting( poseHmd, chaperoneDistances );
|
||||||
|
}
|
||||||
|
|
||||||
|
m_autoTurnLastHmdUpdate = poseHmd.mDeviceToAbsoluteTracking;
|
||||||
m_autoTurnChaperoneDistancesLast = std::move( chaperoneDistances );
|
m_autoTurnChaperoneDistancesLast = std::move( chaperoneDistances );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -144,6 +149,85 @@ void RotationTabController::eventLoopTick(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RotationTabController::doViewRatchetting(
|
||||||
|
const vr::TrackedDevicePose_t& poseHmd,
|
||||||
|
const std::vector<utils::ChaperoneQuadData>& chaperoneDistances )
|
||||||
|
{
|
||||||
|
if ( m_isHMDActive && poseHmd.bPoseIsValid && poseHmd.bDeviceIsConnected
|
||||||
|
&& poseHmd.eTrackingResult == vr::TrackingResult_Running_OK
|
||||||
|
&& !chaperoneDistances.empty() )
|
||||||
|
{
|
||||||
|
if ( chaperoneDistances.size()
|
||||||
|
!= m_autoTurnChaperoneDistancesLast.size() )
|
||||||
|
{
|
||||||
|
m_autoTurnChaperoneDistancesLast = chaperoneDistances;
|
||||||
|
m_autoTurnLastHmdUpdate = poseHmd.mDeviceToAbsoluteTracking;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the (index of the) nearest wall
|
||||||
|
size_t nearestWallIdx = 0;
|
||||||
|
for ( size_t i = 0; i < chaperoneDistances.size(); i++ )
|
||||||
|
{
|
||||||
|
if ( chaperoneDistances[i].distance
|
||||||
|
< chaperoneDistances[nearestWallIdx].distance )
|
||||||
|
{
|
||||||
|
nearestWallIdx = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const auto& nearestWall = chaperoneDistances[nearestWallIdx];
|
||||||
|
|
||||||
|
// Convert pose matrix to quaternion
|
||||||
|
auto hmdQuaternion
|
||||||
|
= quaternion::fromHmdMatrix34( poseHmd.mDeviceToAbsoluteTracking );
|
||||||
|
|
||||||
|
// Get HMD raw yaw
|
||||||
|
double hmdYaw = quaternion::getYaw( hmdQuaternion );
|
||||||
|
|
||||||
|
// Get angle between HMD position and nearest point on
|
||||||
|
// wall
|
||||||
|
double hmdPositionToWallYaw = static_cast<double>(
|
||||||
|
std::atan2( nearestWall.nearestPoint.v[0]
|
||||||
|
- poseHmd.mDeviceToAbsoluteTracking.m[0][3],
|
||||||
|
nearestWall.nearestPoint.v[2]
|
||||||
|
- poseHmd.mDeviceToAbsoluteTracking.m[2][3] ) );
|
||||||
|
|
||||||
|
// Get angle between HMD and wall
|
||||||
|
double hmdToWallYaw
|
||||||
|
= reduceAngle<>( hmdYaw - hmdPositionToWallYaw, -M_PI, M_PI );
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
// if we change walls, ignore
|
||||||
|
if ( nearestWallIdx != m_ratchettingLastWall )
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Facing away from the wall is 0, |facing towards the wall| is M_PI
|
||||||
|
// Ignore turning towards the wall (e.g. change in magnitude is
|
||||||
|
// greater than 0)
|
||||||
|
if ( std::abs( hmdToWallYaw )
|
||||||
|
- std::abs( m_ratchettingLastHmdRotation )
|
||||||
|
> 0.0 )
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Magnify that change
|
||||||
|
double delta_degrees
|
||||||
|
= reduceAngle<>(
|
||||||
|
hmdToWallYaw - m_ratchettingLastHmdRotation, -M_PI, M_PI )
|
||||||
|
* viewRatchettingPercent();
|
||||||
|
|
||||||
|
parent->m_moveCenterTabController.setRotation(
|
||||||
|
parent->m_moveCenterTabController.rotation()
|
||||||
|
+ static_cast<int>( delta_degrees * k_radiansToCentidegrees ) );
|
||||||
|
} while ( false );
|
||||||
|
|
||||||
|
m_ratchettingLastHmdRotation = hmdToWallYaw;
|
||||||
|
m_ratchettingLastWall = nearestWallIdx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void RotationTabController::doVestibularMotion(
|
void RotationTabController::doVestibularMotion(
|
||||||
const vr::TrackedDevicePose_t& poseHmd,
|
const vr::TrackedDevicePose_t& poseHmd,
|
||||||
const std::vector<utils::ChaperoneQuadData>& chaperoneDistances )
|
const std::vector<utils::ChaperoneQuadData>& chaperoneDistances )
|
||||||
@@ -158,37 +242,20 @@ void RotationTabController::doVestibularMotion(
|
|||||||
m_autoTurnChaperoneDistancesLast = chaperoneDistances;
|
m_autoTurnChaperoneDistancesLast = chaperoneDistances;
|
||||||
m_autoTurnLastHmdUpdate = poseHmd.mDeviceToAbsoluteTracking;
|
m_autoTurnLastHmdUpdate = poseHmd.mDeviceToAbsoluteTracking;
|
||||||
}
|
}
|
||||||
// Find the nearest wall we're moving TOWARDS and rotate
|
// Rotate dist/(2*pi*r) where r is
|
||||||
// away from it Rotate dist/(2*pi*r) where r is
|
|
||||||
// m_autoTurnVestibularMotionRadius, as if we had walked
|
// m_autoTurnVestibularMotionRadius, as if we had walked
|
||||||
// however many inches along a circle and the world was
|
// however many inches along a circle and the world was
|
||||||
// turning to compensate
|
// turning to compensate
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
// find nearest wall we're moving towards
|
// Find the nearest wall
|
||||||
auto nearestWall = chaperoneDistances.end();
|
const auto& nearestWall
|
||||||
auto itrLast = m_autoTurnChaperoneDistancesLast.begin();
|
= std::min_element( chaperoneDistances.begin(),
|
||||||
for ( auto itr = chaperoneDistances.begin();
|
chaperoneDistances.end(),
|
||||||
itr != chaperoneDistances.end();
|
[]( const auto& quadA, const auto& quadB ) {
|
||||||
itr++ )
|
return quadA.distance < quadB.distance;
|
||||||
{
|
} );
|
||||||
itrLast++;
|
|
||||||
// if ( itr->distance > itrLast->distance )
|
|
||||||
//{
|
|
||||||
// continue;
|
|
||||||
//}
|
|
||||||
|
|
||||||
if ( nearestWall == chaperoneDistances.end()
|
|
||||||
|| itr->distance < nearestWall->distance )
|
|
||||||
{
|
|
||||||
nearestWall = itr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ( nearestWall == chaperoneDistances.end() )
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert pose matrix to quaternion
|
// Convert pose matrix to quaternion
|
||||||
auto hmdQuaternion = quaternion::fromHmdMatrix34(
|
auto hmdQuaternion = quaternion::fromHmdMatrix34(
|
||||||
@@ -210,6 +277,19 @@ void RotationTabController::doVestibularMotion(
|
|||||||
= reduceAngle<>( hmdYaw - hmdPositionToWallYaw, -M_PI, M_PI );
|
= reduceAngle<>( hmdYaw - hmdPositionToWallYaw, -M_PI, M_PI );
|
||||||
bool turnLeft = hmdToWallYaw > 0.0;
|
bool turnLeft = hmdToWallYaw > 0.0;
|
||||||
|
|
||||||
|
// Only turn if moving forward
|
||||||
|
double hmdMovementDirection = static_cast<double>(
|
||||||
|
std::atan2( m_autoTurnLastHmdUpdate.m[0][3]
|
||||||
|
- poseHmd.mDeviceToAbsoluteTracking.m[0][3],
|
||||||
|
m_autoTurnLastHmdUpdate.m[2][3]
|
||||||
|
- poseHmd.mDeviceToAbsoluteTracking.m[2][3] ) );
|
||||||
|
if ( std::abs( hmdYaw - hmdMovementDirection )
|
||||||
|
* k_radiansToCentidegrees
|
||||||
|
>= 7000 )
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// Get the distance between previous and current
|
// Get the distance between previous and current
|
||||||
// position
|
// position
|
||||||
double distanceChange = static_cast<double>(
|
double distanceChange = static_cast<double>(
|
||||||
@@ -229,20 +309,16 @@ void RotationTabController::doVestibularMotion(
|
|||||||
}
|
}
|
||||||
|
|
||||||
double rotationAmount = arcLength * ( turnLeft ? 1 : -1 );
|
double rotationAmount = arcLength * ( turnLeft ? 1 : -1 );
|
||||||
|
int newRotationAngle = reduceAngle<>(
|
||||||
|
parent->m_moveCenterTabController.rotation()
|
||||||
|
+ static_cast<int>( rotationAmount
|
||||||
|
* k_radiansToCentidegrees ),
|
||||||
|
0,
|
||||||
|
36000 );
|
||||||
|
|
||||||
double newRotationAngleDeg
|
parent->m_moveCenterTabController.setRotation( newRotationAngle );
|
||||||
= std::fmod( parent->m_moveCenterTabController.rotation()
|
|
||||||
+ ( rotationAmount * k_radiansToCentidegrees )
|
|
||||||
+ m_autoTurnRoundingError,
|
|
||||||
360000.0 );
|
|
||||||
int newRotationAngleInt = static_cast<int>( newRotationAngleDeg );
|
|
||||||
m_autoTurnRoundingError = newRotationAngleDeg - newRotationAngleInt;
|
|
||||||
|
|
||||||
parent->m_moveCenterTabController.setRotation(
|
|
||||||
newRotationAngleInt );
|
|
||||||
|
|
||||||
} while ( false );
|
} while ( false );
|
||||||
m_autoTurnLastHmdUpdate = poseHmd.mDeviceToAbsoluteTracking;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -272,7 +348,6 @@ void RotationTabController::doAutoTurn(
|
|||||||
== AutoTurnModes::LINEAR_SMOOTH_TURN
|
== AutoTurnModes::LINEAR_SMOOTH_TURN
|
||||||
&& m_autoTurnLinearSmoothTurnRemaining != 0 )
|
&& m_autoTurnLinearSmoothTurnRemaining != 0 )
|
||||||
{
|
{
|
||||||
// TODO: implement angular acceleration max?
|
|
||||||
double deltaSeconds
|
double deltaSeconds
|
||||||
= FrameRates::toDoubleSeconds( m_estimatedFrameRate );
|
= FrameRates::toDoubleSeconds( m_estimatedFrameRate );
|
||||||
auto miniDeltaAngle = static_cast<int>(
|
auto miniDeltaAngle = static_cast<int>(
|
||||||
@@ -284,11 +359,11 @@ void RotationTabController::doAutoTurn(
|
|||||||
{
|
{
|
||||||
miniDeltaAngle = m_autoTurnLinearSmoothTurnRemaining;
|
miniDeltaAngle = m_autoTurnLinearSmoothTurnRemaining;
|
||||||
}
|
}
|
||||||
int newRotationAngleDeg = reduceAngle<>(
|
int newRotationAngleDeg
|
||||||
static_cast<int>( parent->m_moveCenterTabController.rotation()
|
= reduceAngle<>( parent->m_moveCenterTabController.rotation()
|
||||||
+ miniDeltaAngle ),
|
+ static_cast<int>( miniDeltaAngle ),
|
||||||
0,
|
0,
|
||||||
36000 );
|
36000 );
|
||||||
|
|
||||||
parent->m_moveCenterTabController.setRotation(
|
parent->m_moveCenterTabController.setRotation(
|
||||||
newRotationAngleDeg );
|
newRotationAngleDeg );
|
||||||
@@ -428,9 +503,8 @@ void RotationTabController::doAutoTurn(
|
|||||||
{
|
{
|
||||||
case AutoTurnModes::SNAP:
|
case AutoTurnModes::SNAP:
|
||||||
parent->m_moveCenterTabController.setRotation(
|
parent->m_moveCenterTabController.setRotation(
|
||||||
static_cast<int>(
|
parent->m_moveCenterTabController.rotation()
|
||||||
parent->m_moveCenterTabController.rotation()
|
+ static_cast<int>( delta_degrees ) );
|
||||||
+ delta_degrees ) );
|
|
||||||
break;
|
break;
|
||||||
case AutoTurnModes::LINEAR_SMOOTH_TURN:
|
case AutoTurnModes::LINEAR_SMOOTH_TURN:
|
||||||
m_autoTurnLinearSmoothTurnRemaining
|
m_autoTurnLinearSmoothTurnRemaining
|
||||||
@@ -577,6 +651,18 @@ double RotationTabController::vestibularMotionRadius() const
|
|||||||
settings::DoubleSetting::ROTATION_autoturnVestibularMotionRadius );
|
settings::DoubleSetting::ROTATION_autoturnVestibularMotionRadius );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool RotationTabController::viewRatchettingEnabled() const
|
||||||
|
{
|
||||||
|
return settings::getSetting(
|
||||||
|
settings::BoolSetting::ROTATION_autoturnViewRatchettingEnabled );
|
||||||
|
}
|
||||||
|
|
||||||
|
double RotationTabController::viewRatchettingPercent() const
|
||||||
|
{
|
||||||
|
return settings::getSetting(
|
||||||
|
settings::DoubleSetting::ROTATION_autoturnViewRatchettingPercent );
|
||||||
|
}
|
||||||
|
|
||||||
// Setters
|
// Setters
|
||||||
|
|
||||||
void RotationTabController::setAutoTurnEnabled( bool value, bool notify )
|
void RotationTabController::setAutoTurnEnabled( bool value, bool notify )
|
||||||
@@ -711,5 +797,25 @@ void RotationTabController::setVestibularMotionRadius( double value,
|
|||||||
emit vestibularMotionRadiusChanged( value );
|
emit vestibularMotionRadiusChanged( value );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
void RotationTabController::setViewRatchettingEnabled( bool value, bool notify )
|
||||||
|
{
|
||||||
|
settings::setSetting(
|
||||||
|
settings::BoolSetting::ROTATION_autoturnViewRatchettingEnabled, value );
|
||||||
|
if ( notify )
|
||||||
|
{
|
||||||
|
emit viewRatchettingEnabledChanged( value );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void RotationTabController::setViewRatchettingPercent( double value,
|
||||||
|
bool notify )
|
||||||
|
{
|
||||||
|
settings::setSetting(
|
||||||
|
settings::DoubleSetting::ROTATION_autoturnViewRatchettingPercent,
|
||||||
|
value );
|
||||||
|
if ( notify )
|
||||||
|
{
|
||||||
|
emit viewRatchettingPercentChanged( value );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace advsettings
|
} // namespace advsettings
|
||||||
|
|||||||
@@ -83,6 +83,12 @@ class RotationTabController : public QObject
|
|||||||
Q_PROPERTY(
|
Q_PROPERTY(
|
||||||
double vestibularMotionRadius READ vestibularMotionRadius WRITE
|
double vestibularMotionRadius READ vestibularMotionRadius WRITE
|
||||||
setVestibularMotionRadius NOTIFY vestibularMotionRadiusChanged )
|
setVestibularMotionRadius NOTIFY vestibularMotionRadiusChanged )
|
||||||
|
Q_PROPERTY(
|
||||||
|
bool viewRatchettingEnabled READ viewRatchettingEnabled WRITE
|
||||||
|
setViewRatchettingEnabled NOTIFY viewRatchettingEnabledChanged )
|
||||||
|
Q_PROPERTY(
|
||||||
|
double viewRatchettingPercent READ viewRatchettingPercent WRITE
|
||||||
|
setViewRatchettingPercent NOTIFY viewRatchettingPercentChanged )
|
||||||
Q_PROPERTY(
|
Q_PROPERTY(
|
||||||
bool autoTurnShowNotification READ autoTurnShowNotification WRITE
|
bool autoTurnShowNotification READ autoTurnShowNotification WRITE
|
||||||
setAutoTurnShowNotification NOTIFY autoTurnShowNotificationChanged )
|
setAutoTurnShowNotification NOTIFY autoTurnShowNotificationChanged )
|
||||||
@@ -108,8 +114,9 @@ private:
|
|||||||
std::vector<bool> m_autoTurnWallActive;
|
std::vector<bool> m_autoTurnWallActive;
|
||||||
vr::HmdMatrix34_t m_autoTurnLastHmdUpdate;
|
vr::HmdMatrix34_t m_autoTurnLastHmdUpdate;
|
||||||
std::vector<utils::ChaperoneQuadData> m_autoTurnChaperoneDistancesLast;
|
std::vector<utils::ChaperoneQuadData> m_autoTurnChaperoneDistancesLast;
|
||||||
double m_autoTurnRoundingError = 0.0;
|
|
||||||
std::chrono::steady_clock::time_point::duration m_estimatedFrameRate;
|
std::chrono::steady_clock::time_point::duration m_estimatedFrameRate;
|
||||||
|
double m_ratchettingLastHmdRotation = 0.0;
|
||||||
|
size_t m_ratchettingLastWall = 0;
|
||||||
|
|
||||||
std::optional<std::chrono::steady_clock::time_point>
|
std::optional<std::chrono::steady_clock::time_point>
|
||||||
m_autoTurnNotificationTimestamp;
|
m_autoTurnNotificationTimestamp;
|
||||||
@@ -122,6 +129,9 @@ private:
|
|||||||
void doVestibularMotion(
|
void doVestibularMotion(
|
||||||
const vr::TrackedDevicePose_t& poseHmd,
|
const vr::TrackedDevicePose_t& poseHmd,
|
||||||
const std::vector<utils::ChaperoneQuadData>& chaperoneDistances );
|
const std::vector<utils::ChaperoneQuadData>& chaperoneDistances );
|
||||||
|
void doViewRatchetting(
|
||||||
|
const vr::TrackedDevicePose_t& poseHmd,
|
||||||
|
const std::vector<utils::ChaperoneQuadData>& chaperoneDistances );
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void initStage1();
|
void initStage1();
|
||||||
@@ -143,6 +153,8 @@ public:
|
|||||||
int autoTurnMode() const;
|
int autoTurnMode() const;
|
||||||
bool vestibularMotionEnabled() const;
|
bool vestibularMotionEnabled() const;
|
||||||
double vestibularMotionRadius() const;
|
double vestibularMotionRadius() const;
|
||||||
|
bool viewRatchettingEnabled() const;
|
||||||
|
double viewRatchettingPercent() const;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void setAutoTurnEnabled( bool value, bool notify = true );
|
void setAutoTurnEnabled( bool value, bool notify = true );
|
||||||
@@ -156,6 +168,8 @@ public slots:
|
|||||||
void setAutoTurnMode( int value, bool notify = true );
|
void setAutoTurnMode( int value, bool notify = true );
|
||||||
void setVestibularMotionEnabled( bool value, bool notify = true );
|
void setVestibularMotionEnabled( bool value, bool notify = true );
|
||||||
void setVestibularMotionRadius( double value, bool notify = true );
|
void setVestibularMotionRadius( double value, bool notify = true );
|
||||||
|
void setViewRatchettingEnabled( bool value, bool notify = true );
|
||||||
|
void setViewRatchettingPercent( double value, bool notify = true );
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
||||||
@@ -171,6 +185,8 @@ signals:
|
|||||||
void autoTurnModeChanged( int value );
|
void autoTurnModeChanged( int value );
|
||||||
void vestibularMotionEnabledChanged( bool value );
|
void vestibularMotionEnabledChanged( bool value );
|
||||||
void vestibularMotionRadiusChanged( double value );
|
void vestibularMotionRadiusChanged( double value );
|
||||||
|
void viewRatchettingEnabledChanged( bool value );
|
||||||
|
void viewRatchettingPercentChanged( double value );
|
||||||
};
|
};
|
||||||
|
|
||||||
// Would be nice to do <typename T, T min, T max> but the standard doesn't allow
|
// Would be nice to do <typename T, T min, T max> but the standard doesn't allow
|
||||||
|
|||||||
Reference in New Issue
Block a user