blob: ee60fa55ddc741a23b0ccc8b79ed39788b848585 [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"
23
24namespace android {
25namespace media {
26namespace {
27
28using Eigen::Quaternionf;
29using Eigen::Vector3f;
30
31class HeadTrackingProcessorImpl : public HeadTrackingProcessor {
32 public:
33 HeadTrackingProcessorImpl(const Options& options, HeadTrackingMode initialMode)
34 : mOptions(options),
35 mHeadPoseDriftCompensator(PoseDriftCompensator::Options{
36 .translationalDriftTimeConstant = options.translationalDriftTimeConstant,
37 .rotationalDriftTimeConstant = options.rotationalDriftTimeConstant,
38 }),
39 mScreenPoseDriftCompensator(PoseDriftCompensator::Options{
40 .translationalDriftTimeConstant = options.translationalDriftTimeConstant,
41 .rotationalDriftTimeConstant = options.rotationalDriftTimeConstant,
42 }),
43 mModeSelector(ModeSelector::Options{.freshnessTimeout = options.freshnessTimeout},
44 initialMode),
45 mRateLimiter(PoseRateLimiter::Options{
46 .maxTranslationalVelocity = options.maxTranslationalVelocity,
47 .maxRotationalVelocity = options.maxRotationalVelocity}) {}
48
49 void setDesiredMode(HeadTrackingMode mode) override { mModeSelector.setDesiredMode(mode); }
50
51 void setWorldToHeadPose(int64_t timestamp, const Pose3f& worldToHead,
52 const Twist3f& headTwist) override {
53 Pose3f predictedWorldToHead =
54 worldToHead * integrate(headTwist, mOptions.predictionDuration);
55 mHeadPoseDriftCompensator.setInput(timestamp, predictedWorldToHead);
56 mWorldToHeadTimestamp = timestamp;
57 }
58
59 void setWorldToScreenPose(int64_t timestamp, const Pose3f& worldToScreen) override {
60 mScreenPoseDriftCompensator.setInput(timestamp, worldToScreen);
61 mWorldToScreenTimestamp = timestamp;
62 }
63
64 void setScreenToStagePose(const Pose3f& screenToStage) override {
65 mModeSelector.setScreenToStagePose(screenToStage);
66 }
67
68 void setDisplayOrientation(float physicalToLogicalAngle) override {
69 if (mPhysicalToLogicalAngle != physicalToLogicalAngle) {
70 mRateLimiter.enable();
71 }
72 mPhysicalToLogicalAngle = physicalToLogicalAngle;
73 }
74
75 void calculate(int64_t timestamp) override {
76 if (mWorldToHeadTimestamp.has_value()) {
77 const Pose3f worldToHead = mHeadPoseDriftCompensator.getOutput();
78 mScreenHeadFusion.setWorldToHeadPose(mWorldToHeadTimestamp.value(), worldToHead);
79 mModeSelector.setWorldToHeadPose(mWorldToHeadTimestamp.value(), worldToHead);
80 }
81
82 if (mWorldToScreenTimestamp.has_value()) {
83 const Pose3f worldToLogicalScreen = mScreenPoseDriftCompensator.getOutput() *
84 Pose3f(rotateY(-mPhysicalToLogicalAngle));
85 mScreenHeadFusion.setWorldToScreenPose(mWorldToScreenTimestamp.value(),
86 worldToLogicalScreen);
87 }
88
89 auto maybeScreenToHead = mScreenHeadFusion.calculate();
90 if (maybeScreenToHead.has_value()) {
91 mModeSelector.setScreenToHeadPose(maybeScreenToHead->timestamp,
92 maybeScreenToHead->pose);
93 } else {
94 mModeSelector.setScreenToHeadPose(timestamp, std::nullopt);
95 }
96
97 HeadTrackingMode prevMode = mModeSelector.getActualMode();
98 mModeSelector.calculate(timestamp);
99 if (mModeSelector.getActualMode() != prevMode) {
100 // Mode has changed, enable rate limiting.
101 mRateLimiter.enable();
102 }
103 mRateLimiter.setTarget(mModeSelector.getHeadToStagePose());
104 mHeadToStagePose = mRateLimiter.calculatePose(timestamp);
105 }
106
107 Pose3f getHeadToStagePose() const override { return mHeadToStagePose; }
108
109 HeadTrackingMode getActualMode() const override { return mModeSelector.getActualMode(); }
110
111 void recenter() override {
112 mHeadPoseDriftCompensator.recenter();
113 mScreenPoseDriftCompensator.recenter();
114 mRateLimiter.enable();
115 }
116
117 private:
118 const Options mOptions;
119 float mPhysicalToLogicalAngle = 0;
120 std::optional<int64_t> mWorldToHeadTimestamp;
121 std::optional<int64_t> mWorldToScreenTimestamp;
122 Pose3f mHeadToStagePose;
123 PoseDriftCompensator mHeadPoseDriftCompensator;
124 PoseDriftCompensator mScreenPoseDriftCompensator;
125 ScreenHeadFusion mScreenHeadFusion;
126 ModeSelector mModeSelector;
127 PoseRateLimiter mRateLimiter;
128};
129
130} // namespace
131
Ytai Ben-Tsviedbab3d2021-08-16 11:27:52 -0700132std::unique_ptr<HeadTrackingProcessor> createHeadTrackingProcessor(
Ytai Ben-Tsvicbee7d42021-06-15 00:39:31 -0700133 const HeadTrackingProcessor::Options& options, HeadTrackingMode initialMode) {
134 return std::make_unique<HeadTrackingProcessorImpl>(options, initialMode);
135}
136
137} // namespace media
138} // namespace android