blob: 71fae8a3bc7e92eb88e572c22fab08599cd2603b [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"
Ytai Ben-Tsvi09ad8c92022-01-28 14:19:08 -080020#include "PoseBias.h"
Ytai Ben-Tsvicbee7d42021-06-15 00:39:31 -070021#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),
Ytai Ben-Tsvi44e7c3d2021-12-15 16:04:01 -080036 mHeadStillnessDetector(StillnessDetector::Options{
Ytai Ben-Tsvi4cb1e482022-01-06 11:22:05 -080037 .defaultValue = false,
Ytai Ben-Tsvi44e7c3d2021-12-15 16:04:01 -080038 .windowDuration = options.autoRecenterWindowDuration,
39 .translationalThreshold = options.autoRecenterTranslationalThreshold,
40 .rotationalThreshold = options.autoRecenterRotationalThreshold,
41 }),
Ytai Ben-Tsvic7e8a482021-12-20 13:26:34 -080042 mScreenStillnessDetector(StillnessDetector::Options{
Ytai Ben-Tsvi4cb1e482022-01-06 11:22:05 -080043 .defaultValue = true,
Ytai Ben-Tsvic7e8a482021-12-20 13:26:34 -080044 .windowDuration = options.screenStillnessWindowDuration,
45 .translationalThreshold = options.screenStillnessTranslationalThreshold,
46 .rotationalThreshold = options.screenStillnessRotationalThreshold,
47 }),
Ytai Ben-Tsvicbee7d42021-06-15 00:39:31 -070048 mModeSelector(ModeSelector::Options{.freshnessTimeout = options.freshnessTimeout},
49 initialMode),
50 mRateLimiter(PoseRateLimiter::Options{
51 .maxTranslationalVelocity = options.maxTranslationalVelocity,
52 .maxRotationalVelocity = options.maxRotationalVelocity}) {}
53
54 void setDesiredMode(HeadTrackingMode mode) override { mModeSelector.setDesiredMode(mode); }
55
56 void setWorldToHeadPose(int64_t timestamp, const Pose3f& worldToHead,
57 const Twist3f& headTwist) override {
58 Pose3f predictedWorldToHead =
59 worldToHead * integrate(headTwist, mOptions.predictionDuration);
Ytai Ben-Tsvi09ad8c92022-01-28 14:19:08 -080060 mHeadPoseBias.setInput(predictedWorldToHead);
Ytai Ben-Tsvi5e6c0f32022-01-19 08:20:39 -080061 mHeadStillnessDetector.setInput(timestamp, predictedWorldToHead);
Ytai Ben-Tsvicbee7d42021-06-15 00:39:31 -070062 mWorldToHeadTimestamp = timestamp;
63 }
64
65 void setWorldToScreenPose(int64_t timestamp, const Pose3f& worldToScreen) override {
Ytai Ben-Tsvi7901bdd2021-09-08 16:11:07 -070066 if (mPhysicalToLogicalAngle != mPendingPhysicalToLogicalAngle) {
67 // We're introducing an artificial discontinuity. Enable the rate limiter.
68 mRateLimiter.enable();
69 mPhysicalToLogicalAngle = mPendingPhysicalToLogicalAngle;
70 }
71
Ytai Ben-Tsvi5e6c0f32022-01-19 08:20:39 -080072 Pose3f worldToLogicalScreen = worldToScreen * Pose3f(rotateY(-mPhysicalToLogicalAngle));
Ytai Ben-Tsvi09ad8c92022-01-28 14:19:08 -080073 mScreenPoseBias.setInput(worldToLogicalScreen);
Ytai Ben-Tsvi5e6c0f32022-01-19 08:20:39 -080074 mScreenStillnessDetector.setInput(timestamp, worldToLogicalScreen);
Ytai Ben-Tsvicbee7d42021-06-15 00:39:31 -070075 mWorldToScreenTimestamp = timestamp;
76 }
77
78 void setScreenToStagePose(const Pose3f& screenToStage) override {
79 mModeSelector.setScreenToStagePose(screenToStage);
80 }
81
82 void setDisplayOrientation(float physicalToLogicalAngle) override {
Ytai Ben-Tsvi7901bdd2021-09-08 16:11:07 -070083 mPendingPhysicalToLogicalAngle = physicalToLogicalAngle;
Ytai Ben-Tsvicbee7d42021-06-15 00:39:31 -070084 }
85
86 void calculate(int64_t timestamp) override {
Ytai Ben-Tsvic7e8a482021-12-20 13:26:34 -080087 // Handle the screen first, since it might trigger a recentering of the head.
88 if (mWorldToScreenTimestamp.has_value()) {
Ytai Ben-Tsvi09ad8c92022-01-28 14:19:08 -080089 const Pose3f worldToLogicalScreen = mScreenPoseBias.getOutput();
Ytai Ben-Tsvic7e8a482021-12-20 13:26:34 -080090 bool screenStable = mScreenStillnessDetector.calculate(timestamp);
91 mModeSelector.setScreenStable(mWorldToScreenTimestamp.value(), screenStable);
92 // Whenever the screen is unstable, recenter the head pose.
93 if (!screenStable) {
94 recenter(true, false);
95 }
96 mScreenHeadFusion.setWorldToScreenPose(mWorldToScreenTimestamp.value(),
97 worldToLogicalScreen);
98 }
99
100 // Handle head.
Ytai Ben-Tsvicbee7d42021-06-15 00:39:31 -0700101 if (mWorldToHeadTimestamp.has_value()) {
Ytai Ben-Tsvi09ad8c92022-01-28 14:19:08 -0800102 Pose3f worldToHead = mHeadPoseBias.getOutput();
Ytai Ben-Tsvi44e7c3d2021-12-15 16:04:01 -0800103 // Auto-recenter.
104 if (mHeadStillnessDetector.calculate(timestamp)) {
105 recenter(true, false);
Ytai Ben-Tsvi09ad8c92022-01-28 14:19:08 -0800106 worldToHead = mHeadPoseBias.getOutput();
Ytai Ben-Tsvi44e7c3d2021-12-15 16:04:01 -0800107 }
108
Ytai Ben-Tsvicbee7d42021-06-15 00:39:31 -0700109 mScreenHeadFusion.setWorldToHeadPose(mWorldToHeadTimestamp.value(), worldToHead);
110 mModeSelector.setWorldToHeadPose(mWorldToHeadTimestamp.value(), worldToHead);
111 }
112
Ytai Ben-Tsvicbee7d42021-06-15 00:39:31 -0700113 auto maybeScreenToHead = mScreenHeadFusion.calculate();
114 if (maybeScreenToHead.has_value()) {
115 mModeSelector.setScreenToHeadPose(maybeScreenToHead->timestamp,
116 maybeScreenToHead->pose);
117 } else {
118 mModeSelector.setScreenToHeadPose(timestamp, std::nullopt);
119 }
120
121 HeadTrackingMode prevMode = mModeSelector.getActualMode();
122 mModeSelector.calculate(timestamp);
123 if (mModeSelector.getActualMode() != prevMode) {
124 // Mode has changed, enable rate limiting.
125 mRateLimiter.enable();
126 }
127 mRateLimiter.setTarget(mModeSelector.getHeadToStagePose());
128 mHeadToStagePose = mRateLimiter.calculatePose(timestamp);
129 }
130
131 Pose3f getHeadToStagePose() const override { return mHeadToStagePose; }
132
133 HeadTrackingMode getActualMode() const override { return mModeSelector.getActualMode(); }
134
Ytai Ben-Tsvi95b00c82021-08-27 15:27:08 -0700135 void recenter(bool recenterHead, bool recenterScreen) override {
136 if (recenterHead) {
Ytai Ben-Tsvi09ad8c92022-01-28 14:19:08 -0800137 mHeadPoseBias.recenter();
Ytai Ben-Tsvi44e7c3d2021-12-15 16:04:01 -0800138 mHeadStillnessDetector.reset();
Ytai Ben-Tsvi95b00c82021-08-27 15:27:08 -0700139 }
140 if (recenterScreen) {
Ytai Ben-Tsvi09ad8c92022-01-28 14:19:08 -0800141 mScreenPoseBias.recenter();
Ytai Ben-Tsvic7e8a482021-12-20 13:26:34 -0800142 mScreenStillnessDetector.reset();
Ytai Ben-Tsvi95b00c82021-08-27 15:27:08 -0700143 }
144
145 // If a sensor being recentered is included in the current mode, apply rate limiting to
146 // avoid discontinuities.
147 HeadTrackingMode mode = mModeSelector.getActualMode();
148 if ((recenterHead && (mode == HeadTrackingMode::WORLD_RELATIVE ||
149 mode == HeadTrackingMode::SCREEN_RELATIVE)) ||
150 (recenterScreen && mode == HeadTrackingMode::SCREEN_RELATIVE)) {
151 mRateLimiter.enable();
152 }
Ytai Ben-Tsvicbee7d42021-06-15 00:39:31 -0700153 }
154
155 private:
156 const Options mOptions;
157 float mPhysicalToLogicalAngle = 0;
Ytai Ben-Tsvi7901bdd2021-09-08 16:11:07 -0700158 // We store the physical to logical angle as "pending" until the next world-to-screen sample it
159 // applies to arrives.
160 float mPendingPhysicalToLogicalAngle = 0;
Ytai Ben-Tsvicbee7d42021-06-15 00:39:31 -0700161 std::optional<int64_t> mWorldToHeadTimestamp;
162 std::optional<int64_t> mWorldToScreenTimestamp;
163 Pose3f mHeadToStagePose;
Ytai Ben-Tsvi09ad8c92022-01-28 14:19:08 -0800164 PoseBias mHeadPoseBias;
165 PoseBias mScreenPoseBias;
Ytai Ben-Tsvi44e7c3d2021-12-15 16:04:01 -0800166 StillnessDetector mHeadStillnessDetector;
Ytai Ben-Tsvic7e8a482021-12-20 13:26:34 -0800167 StillnessDetector mScreenStillnessDetector;
Ytai Ben-Tsvicbee7d42021-06-15 00:39:31 -0700168 ScreenHeadFusion mScreenHeadFusion;
169 ModeSelector mModeSelector;
170 PoseRateLimiter mRateLimiter;
171};
172
173} // namespace
174
Ytai Ben-Tsviedbab3d2021-08-16 11:27:52 -0700175std::unique_ptr<HeadTrackingProcessor> createHeadTrackingProcessor(
Ytai Ben-Tsvicbee7d42021-06-15 00:39:31 -0700176 const HeadTrackingProcessor::Options& options, HeadTrackingMode initialMode) {
177 return std::make_unique<HeadTrackingProcessorImpl>(options, initialMode);
178}
179
180} // namespace media
181} // namespace android