blob: b2d2dbd6fea94572e6d32619d6b7a1cdcf8a6e91 [file] [log] [blame]
Ytai Ben-Tsvicbee7d42021-06-15 00:39:31 -07001/*
2 * Copyright (C) 2021 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"){}
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "media/HeadTrackingProcessor.h"
18
19#include "ModeSelector.h"
20#include "PoseDriftCompensator.h"
21#include "QuaternionUtil.h"
22#include "ScreenHeadFusion.h"
Ytai Ben-Tsvi44e7c3d2021-12-15 16:04:01 -080023#include "StillnessDetector.h"
Ytai Ben-Tsvicbee7d42021-06-15 00:39:31 -070024
25namespace android {
26namespace media {
27namespace {
28
29using Eigen::Quaternionf;
30using Eigen::Vector3f;
31
32class HeadTrackingProcessorImpl : public HeadTrackingProcessor {
33 public:
34 HeadTrackingProcessorImpl(const Options& options, HeadTrackingMode initialMode)
35 : mOptions(options),
36 mHeadPoseDriftCompensator(PoseDriftCompensator::Options{
37 .translationalDriftTimeConstant = options.translationalDriftTimeConstant,
38 .rotationalDriftTimeConstant = options.rotationalDriftTimeConstant,
39 }),
40 mScreenPoseDriftCompensator(PoseDriftCompensator::Options{
41 .translationalDriftTimeConstant = options.translationalDriftTimeConstant,
42 .rotationalDriftTimeConstant = options.rotationalDriftTimeConstant,
43 }),
Ytai Ben-Tsvi44e7c3d2021-12-15 16:04:01 -080044 mHeadStillnessDetector(StillnessDetector::Options{
Ytai Ben-Tsvi4cb1e482022-01-06 11:22:05 -080045 .defaultValue = false,
Ytai Ben-Tsvi44e7c3d2021-12-15 16:04:01 -080046 .windowDuration = options.autoRecenterWindowDuration,
47 .translationalThreshold = options.autoRecenterTranslationalThreshold,
48 .rotationalThreshold = options.autoRecenterRotationalThreshold,
49 }),
Ytai Ben-Tsvic7e8a482021-12-20 13:26:34 -080050 mScreenStillnessDetector(StillnessDetector::Options{
Ytai Ben-Tsvi4cb1e482022-01-06 11:22:05 -080051 .defaultValue = true,
Ytai Ben-Tsvic7e8a482021-12-20 13:26:34 -080052 .windowDuration = options.screenStillnessWindowDuration,
53 .translationalThreshold = options.screenStillnessTranslationalThreshold,
54 .rotationalThreshold = options.screenStillnessRotationalThreshold,
55 }),
Ytai Ben-Tsvicbee7d42021-06-15 00:39:31 -070056 mModeSelector(ModeSelector::Options{.freshnessTimeout = options.freshnessTimeout},
57 initialMode),
58 mRateLimiter(PoseRateLimiter::Options{
59 .maxTranslationalVelocity = options.maxTranslationalVelocity,
60 .maxRotationalVelocity = options.maxRotationalVelocity}) {}
61
62 void setDesiredMode(HeadTrackingMode mode) override { mModeSelector.setDesiredMode(mode); }
63
64 void setWorldToHeadPose(int64_t timestamp, const Pose3f& worldToHead,
65 const Twist3f& headTwist) override {
66 Pose3f predictedWorldToHead =
67 worldToHead * integrate(headTwist, mOptions.predictionDuration);
68 mHeadPoseDriftCompensator.setInput(timestamp, predictedWorldToHead);
69 mWorldToHeadTimestamp = timestamp;
70 }
71
72 void setWorldToScreenPose(int64_t timestamp, const Pose3f& worldToScreen) override {
Ytai Ben-Tsvi7901bdd2021-09-08 16:11:07 -070073 if (mPhysicalToLogicalAngle != mPendingPhysicalToLogicalAngle) {
74 // We're introducing an artificial discontinuity. Enable the rate limiter.
75 mRateLimiter.enable();
76 mPhysicalToLogicalAngle = mPendingPhysicalToLogicalAngle;
77 }
78
79 mScreenPoseDriftCompensator.setInput(
80 timestamp, worldToScreen * Pose3f(rotateY(-mPhysicalToLogicalAngle)));
Ytai Ben-Tsvicbee7d42021-06-15 00:39:31 -070081 mWorldToScreenTimestamp = timestamp;
82 }
83
84 void setScreenToStagePose(const Pose3f& screenToStage) override {
85 mModeSelector.setScreenToStagePose(screenToStage);
86 }
87
88 void setDisplayOrientation(float physicalToLogicalAngle) override {
Ytai Ben-Tsvi7901bdd2021-09-08 16:11:07 -070089 mPendingPhysicalToLogicalAngle = physicalToLogicalAngle;
Ytai Ben-Tsvicbee7d42021-06-15 00:39:31 -070090 }
91
92 void calculate(int64_t timestamp) override {
Ytai Ben-Tsvic7e8a482021-12-20 13:26:34 -080093 // Handle the screen first, since it might trigger a recentering of the head.
94 if (mWorldToScreenTimestamp.has_value()) {
95 const Pose3f worldToLogicalScreen = mScreenPoseDriftCompensator.getOutput();
96 mScreenStillnessDetector.setInput(mWorldToScreenTimestamp.value(),
97 worldToLogicalScreen);
98 bool screenStable = mScreenStillnessDetector.calculate(timestamp);
99 mModeSelector.setScreenStable(mWorldToScreenTimestamp.value(), screenStable);
100 // Whenever the screen is unstable, recenter the head pose.
101 if (!screenStable) {
102 recenter(true, false);
103 }
104 mScreenHeadFusion.setWorldToScreenPose(mWorldToScreenTimestamp.value(),
105 worldToLogicalScreen);
106 }
107
108 // Handle head.
Ytai Ben-Tsvicbee7d42021-06-15 00:39:31 -0700109 if (mWorldToHeadTimestamp.has_value()) {
Ytai Ben-Tsvi44e7c3d2021-12-15 16:04:01 -0800110 Pose3f worldToHead = mHeadPoseDriftCompensator.getOutput();
111 mHeadStillnessDetector.setInput(mWorldToHeadTimestamp.value(), worldToHead);
112 // Auto-recenter.
113 if (mHeadStillnessDetector.calculate(timestamp)) {
114 recenter(true, false);
115 worldToHead = mHeadPoseDriftCompensator.getOutput();
116 }
117
Ytai Ben-Tsvicbee7d42021-06-15 00:39:31 -0700118 mScreenHeadFusion.setWorldToHeadPose(mWorldToHeadTimestamp.value(), worldToHead);
119 mModeSelector.setWorldToHeadPose(mWorldToHeadTimestamp.value(), worldToHead);
120 }
121
Ytai Ben-Tsvicbee7d42021-06-15 00:39:31 -0700122 auto maybeScreenToHead = mScreenHeadFusion.calculate();
123 if (maybeScreenToHead.has_value()) {
124 mModeSelector.setScreenToHeadPose(maybeScreenToHead->timestamp,
125 maybeScreenToHead->pose);
126 } else {
127 mModeSelector.setScreenToHeadPose(timestamp, std::nullopt);
128 }
129
130 HeadTrackingMode prevMode = mModeSelector.getActualMode();
131 mModeSelector.calculate(timestamp);
132 if (mModeSelector.getActualMode() != prevMode) {
133 // Mode has changed, enable rate limiting.
134 mRateLimiter.enable();
135 }
136 mRateLimiter.setTarget(mModeSelector.getHeadToStagePose());
137 mHeadToStagePose = mRateLimiter.calculatePose(timestamp);
138 }
139
140 Pose3f getHeadToStagePose() const override { return mHeadToStagePose; }
141
142 HeadTrackingMode getActualMode() const override { return mModeSelector.getActualMode(); }
143
Ytai Ben-Tsvi95b00c82021-08-27 15:27:08 -0700144 void recenter(bool recenterHead, bool recenterScreen) override {
145 if (recenterHead) {
146 mHeadPoseDriftCompensator.recenter();
Ytai Ben-Tsvi44e7c3d2021-12-15 16:04:01 -0800147 mHeadStillnessDetector.reset();
Ytai Ben-Tsvi95b00c82021-08-27 15:27:08 -0700148 }
149 if (recenterScreen) {
150 mScreenPoseDriftCompensator.recenter();
Ytai Ben-Tsvic7e8a482021-12-20 13:26:34 -0800151 mScreenStillnessDetector.reset();
Ytai Ben-Tsvi95b00c82021-08-27 15:27:08 -0700152 }
153
154 // If a sensor being recentered is included in the current mode, apply rate limiting to
155 // avoid discontinuities.
156 HeadTrackingMode mode = mModeSelector.getActualMode();
157 if ((recenterHead && (mode == HeadTrackingMode::WORLD_RELATIVE ||
158 mode == HeadTrackingMode::SCREEN_RELATIVE)) ||
159 (recenterScreen && mode == HeadTrackingMode::SCREEN_RELATIVE)) {
160 mRateLimiter.enable();
161 }
Ytai Ben-Tsvicbee7d42021-06-15 00:39:31 -0700162 }
163
164 private:
165 const Options mOptions;
166 float mPhysicalToLogicalAngle = 0;
Ytai Ben-Tsvi7901bdd2021-09-08 16:11:07 -0700167 // We store the physical to logical angle as "pending" until the next world-to-screen sample it
168 // applies to arrives.
169 float mPendingPhysicalToLogicalAngle = 0;
Ytai Ben-Tsvicbee7d42021-06-15 00:39:31 -0700170 std::optional<int64_t> mWorldToHeadTimestamp;
171 std::optional<int64_t> mWorldToScreenTimestamp;
172 Pose3f mHeadToStagePose;
173 PoseDriftCompensator mHeadPoseDriftCompensator;
174 PoseDriftCompensator mScreenPoseDriftCompensator;
Ytai Ben-Tsvi44e7c3d2021-12-15 16:04:01 -0800175 StillnessDetector mHeadStillnessDetector;
Ytai Ben-Tsvic7e8a482021-12-20 13:26:34 -0800176 StillnessDetector mScreenStillnessDetector;
Ytai Ben-Tsvicbee7d42021-06-15 00:39:31 -0700177 ScreenHeadFusion mScreenHeadFusion;
178 ModeSelector mModeSelector;
179 PoseRateLimiter mRateLimiter;
180};
181
182} // namespace
183
Ytai Ben-Tsviedbab3d2021-08-16 11:27:52 -0700184std::unique_ptr<HeadTrackingProcessor> createHeadTrackingProcessor(
Ytai Ben-Tsvicbee7d42021-06-15 00:39:31 -0700185 const HeadTrackingProcessor::Options& options, HeadTrackingMode initialMode) {
186 return std::make_unique<HeadTrackingProcessorImpl>(options, initialMode);
187}
188
189} // namespace media
190} // namespace android