History

HMD re-centering while driving improvements.

Previously the HUD fading in/out would also recenter the hmd sensor and the avatar, which caused many problems including: * The user's view could shift vertically. * Your avatar would briefly go into t-pose * other users would see your avatar go into t-pose. Now we now move the UI sphere instead, which results in a much smoother experience. MyAvatar: added hasDriveInput method. OverlayConductor: * removed avatar and sensor reset, instead the overlay's modelTransform is changed. * revived STANDING mode, which is active if myAvatar->getClearOverlayWhenDriving() is true and you are wearing an HMD. * SITTING & FLAT mode should be unchanged. * Instead of using avatar velocity to fade out/fade in the hud, We use the presense or absanse of avatar drive input. * Additionally, we check distance to the UI sphere, and quickly recenter the hud if the users head is too close to the actual hud sphere. CompositorHelper: * Bug fixes for ray picks not using the modelTransform.

Anthony J. Thibault committed 10 years ago

Commit 5ef68471 parent b21fbe56 files · +65 −63Browse files

Showing the changes to interface/src/ui/OverlayConductor.cpp (1 of 6 files). Show all

Unified · Split

interface/src/ui/OverlayConductor.cpp+52−59
@@ -22,10 +22,31 @@ OverlayConductor::OverlayConductor() { · 21 unmodified lines
22OverlayConductor::~OverlayConductor() {22OverlayConductor::~OverlayConductor() {
23}23}
24 24
25bool OverlayConductor::shouldCenterUI() const {
26
27 glm::mat4 hmdMat = qApp->getHMDSensorPose();
28 glm::vec3 hmdPos = extractTranslation(hmdMat);
29 glm::vec3 hmdForward = transformVectorFast(hmdMat, glm::vec3(0.0f, 0.0f, -1.0f));
30
31 Transform uiTransform = qApp->getApplicationCompositor().getModelTransform();
32 glm::vec3 uiPos = uiTransform.getTranslation();
33 glm::vec3 uiForward = uiTransform.getRotation() * glm::vec3(0.0f, 0.0f, -1.0f);
34
35 const float MAX_COMPOSITOR_DISTANCE = 0.6f;
36 const float MAX_COMPOSITOR_ANGLE = 180.0f; // rotation check is effectively disabled
37 if (glm::distance(uiPos, hmdPos) > MAX_COMPOSITOR_DISTANCE ||
38 glm::dot(uiForward, hmdForward) < cosf(glm::radians(MAX_COMPOSITOR_ANGLE))) {
39 return true;
40 }
41 return false;
42}
43
25void OverlayConductor::update(float dt) {44void OverlayConductor::update(float dt) {
26 45
27 updateMode();46 updateMode();
28 47
48 MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
49
29 switch (_mode) {50 switch (_mode) {
30 case SITTING: {51 case SITTING: {
31 // when sitting, the overlay is at the origin, facing down the -z axis.52 // when sitting, the overlay is at the origin, facing down the -z axis.
@@ -36,75 +57,49 @@ void OverlayConductor::update(float dt) { · 4 unmodified lines
36 break;57 break;
37 }58 }
38 case STANDING: {59 case STANDING: {
39 // when standing, the overlay is at a reference position, which is set when the overlay is
40 // enabled. The camera is taken directly from the HMD, but in world space.
41 // So the sensorToWorldMatrix must be applied.
42 MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
43 Transform t;
44 t.evalFromRawMatrix(myAvatar->getSensorToWorldMatrix());
45 qApp->getApplicationCompositor().setCameraBaseTransform(t);
46
47 // detect when head moves out side of sweet spot, or looks away.
48 mat4 headMat = myAvatar->getSensorToWorldMatrix() * qApp->getHMDSensorPose();
49 vec3 headWorldPos = extractTranslation(headMat);
50 vec3 headForward = glm::quat_cast(headMat) * glm::vec3(0.0f, 0.0f, -1.0f);
51 Transform modelXform = qApp->getApplicationCompositor().getModelTransform();
52 vec3 compositorWorldPos = modelXform.getTranslation();
53 vec3 compositorForward = modelXform.getRotation() * glm::vec3(0.0f, 0.0f, -1.0f);
54 const float MAX_COMPOSITOR_DISTANCE = 0.6f;
55 const float MAX_COMPOSITOR_ANGLE = 110.0f;
56 if (_enabled && (glm::distance(headWorldPos, compositorWorldPos) > MAX_COMPOSITOR_DISTANCE ||
57 glm::dot(headForward, compositorForward) < cosf(glm::radians(MAX_COMPOSITOR_ANGLE)))) {
58 // fade out the overlay
59 setEnabled(false);
60 }
61 break;
62 }
63 case FLAT:
64 // do nothing
65 break;
66 }
67}
68 60
69void OverlayConductor::updateMode() {
70 MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
71 if (myAvatar->getClearOverlayWhenDriving()) {
72 float speed = glm::length(myAvatar->getVelocity());
73 const float MIN_DRIVING = 0.2f;
74 const float MAX_NOT_DRIVING = 0.01f;
75 const quint64 REQUIRED_USECS_IN_NEW_MODE_BEFORE_INVISIBLE = 200 * 1000;61 const quint64 REQUIRED_USECS_IN_NEW_MODE_BEFORE_INVISIBLE = 200 * 1000;
76 const quint64 REQUIRED_USECS_IN_NEW_MODE_BEFORE_VISIBLE = 1000 * 1000;62 const quint64 REQUIRED_USECS_IN_NEW_MODE_BEFORE_VISIBLE = 1000 * 1000;
77 bool nowDriving = _driving; // Assume current _driving mode unless...63
78 if (speed > MIN_DRIVING) { // ... we're definitely moving...64 // fade in or out the overlay, based on driving.
79 nowDriving = true;65 bool nowDriving = myAvatar->hasDriveInput();
80 } else if (speed < MAX_NOT_DRIVING) { // ... or definitely not.
81 nowDriving = false;
82 }
83 // Check that we're in this new mode for long enough to really trigger a transition.66 // Check that we're in this new mode for long enough to really trigger a transition.
84 if (nowDriving == _driving) { // If there's no change in state, clear any attepted timer.67 if (nowDriving == _driving) { // If there's no change in state, clear any attepted timer.
85 _timeInPotentialMode = 0;68 _timeInPotentialMode = 0;
86 } else if (_timeInPotentialMode == 0) { // We've just changed with no timer, so start timing now.69 } else if (_timeInPotentialMode == 0) { // We've just changed with no timer, so start timing now.
87 _timeInPotentialMode = usecTimestampNow();70 _timeInPotentialMode = usecTimestampNow();
88 } else if ((usecTimestampNow() - _timeInPotentialMode) > (nowDriving ? REQUIRED_USECS_IN_NEW_MODE_BEFORE_INVISIBLE : REQUIRED_USECS_IN_NEW_MODE_BEFORE_VISIBLE)) {71 } else if ((usecTimestampNow() - _timeInPotentialMode) > (nowDriving ? REQUIRED_USECS_IN_NEW_MODE_BEFORE_INVISIBLE : REQUIRED_USECS_IN_NEW_MODE_BEFORE_VISIBLE)) {
89 _timeInPotentialMode = 0; // a real transition72 _timeInPotentialMode = 0; // a real transition
90 if (nowDriving) {73 bool wantsOverlays = Menu::getInstance()->isOptionChecked(MenuOption::Overlays);
91 _wantsOverlays = Menu::getInstance()->isOptionChecked(MenuOption::Overlays);74 if (wantsOverlays) {
92 } else { // reset when coming out of driving
93 _mode = FLAT; // Seems appropriate to let things reset, below, after the following.
94 // All reset of, e.g., room-scale location as though by apostrophe key, without all the other adjustments.
95 qApp->getActiveDisplayPlugin()->resetSensors();
96 myAvatar->reset(true, false, false);
97 }
98 if (_wantsOverlays) {
99 setEnabled(!nowDriving);75 setEnabled(!nowDriving);
100 }76 }
101 _driving = nowDriving;77 _driving = nowDriving;
102 } // Else haven't accumulated enough time in new mode, but keep timing.78 }
79
80 // center the UI
81 if (shouldCenterUI()) {
82 Transform hmdTransform(cancelOutRollAndPitch(qApp->getHMDSensorPose()));
83 qApp->getApplicationCompositor().setModelTransform(hmdTransform);
84 }
85 break;
86 }
87 case FLAT:
88 // do nothing
89 break;
103 }90 }
91}
92
93void OverlayConductor::updateMode() {
94 MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
104 95
105 Mode newMode;96 Mode newMode;
106 if (qApp->isHMDMode()) {97 if (qApp->isHMDMode()) {
107 newMode = SITTING;98 if (myAvatar->getClearOverlayWhenDriving()) {
99 newMode = STANDING;
100 } else {
101 newMode = SITTING;
102 }
108 } else {103 } else {
109 newMode = FLAT;104 newMode = FLAT;
110 }105 }
@@ -117,11 +112,10 @@ void OverlayConductor::updateMode() { · 6 unmodified lines
117 qApp->getApplicationCompositor().setModelTransform(Transform());112 qApp->getApplicationCompositor().setModelTransform(Transform());
118 break;113 break;
119 }114 }
120 case STANDING: { // STANDING mode is not currently used.115 case STANDING: {
121 // enter the STANDING state116 // enter the STANDING state
122 // place the overlay at the current hmd position in world space117 Transform hmdTransform(cancelOutRollAndPitch(qApp->getHMDSensorPose()));
123 auto camMat = cancelOutRollAndPitch(myAvatar->getSensorToWorldMatrix() * qApp->getHMDSensorPose());118 qApp->getApplicationCompositor().setModelTransform(hmdTransform);
124 qApp->getApplicationCompositor().setModelTransform(Transform(camMat));
125 break;119 break;
126 }120 }
127 121
@@ -132,7 +126,6 @@ void OverlayConductor::updateMode() { · 4 unmodified lines
132 }126 }
133 127
134 _mode = newMode;128 _mode = newMode;
135
136}129}
137 130
138void OverlayConductor::setEnabled(bool enabled) {131void OverlayConductor::setEnabled(bool enabled) {
@@ -149,7 +142,7 @@ void OverlayConductor::setEnabled(bool enabled) { · 10 unmodified lines
149 MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();142 MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
150 auto camMat = cancelOutRollAndPitch(myAvatar->getSensorToWorldMatrix() * qApp->getHMDSensorPose());143 auto camMat = cancelOutRollAndPitch(myAvatar->getSensorToWorldMatrix() * qApp->getHMDSensorPose());
151 qApp->getApplicationCompositor().setModelTransform(Transform(camMat));144 qApp->getApplicationCompositor().setModelTransform(Transform(camMat));
152 } 145 }
153}146}
154 147
155bool OverlayConductor::getEnabled() const {148bool OverlayConductor::getEnabled() const {

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t