blob: 1739c6d12eab56da49ce86491fbbc62bb357b535 [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 <gtest/gtest.h>
20
21#include "QuaternionUtil.h"
22#include "TestUtil.h"
23
24namespace android {
25namespace media {
26namespace {
27
28using Eigen::Quaternionf;
29using Eigen::Vector3f;
30using Options = HeadTrackingProcessor::Options;
31
32TEST(HeadTrackingProcessor, Initial) {
33 for (auto mode : {HeadTrackingMode::STATIC, HeadTrackingMode::WORLD_RELATIVE,
34 HeadTrackingMode::SCREEN_RELATIVE}) {
35 std::unique_ptr<HeadTrackingProcessor> processor =
Ytai Ben-Tsviedbab3d2021-08-16 11:27:52 -070036 createHeadTrackingProcessor(Options{}, mode);
Ytai Ben-Tsvicbee7d42021-06-15 00:39:31 -070037 processor->calculate(0);
38 EXPECT_EQ(processor->getActualMode(), HeadTrackingMode::STATIC);
39 EXPECT_EQ(processor->getHeadToStagePose(), Pose3f());
40 }
41}
42
43TEST(HeadTrackingProcessor, BasicComposition) {
44 const Pose3f worldToHead{{1, 2, 3}, Quaternionf::UnitRandom()};
45 const Pose3f worldToScreen{{4, 5, 6}, Quaternionf::UnitRandom()};
46 const Pose3f screenToStage{{7, 8, 9}, Quaternionf::UnitRandom()};
47 const float physicalToLogical = M_PI_2;
48
49 std::unique_ptr<HeadTrackingProcessor> processor =
Ytai Ben-Tsviedbab3d2021-08-16 11:27:52 -070050 createHeadTrackingProcessor(Options{}, HeadTrackingMode::SCREEN_RELATIVE);
Ytai Ben-Tsvib2a87e52021-08-20 10:17:05 -070051
52 // Establish a baseline for the drift compensators.
53 processor->setWorldToHeadPose(0, Pose3f(), Twist3f());
54 processor->setWorldToScreenPose(0, Pose3f());
55
Ytai Ben-Tsvicbee7d42021-06-15 00:39:31 -070056 processor->setWorldToHeadPose(0, worldToHead, Twist3f());
57 processor->setWorldToScreenPose(0, worldToScreen);
58 processor->setScreenToStagePose(screenToStage);
59 processor->setDisplayOrientation(physicalToLogical);
60 processor->calculate(0);
61 ASSERT_EQ(processor->getActualMode(), HeadTrackingMode::SCREEN_RELATIVE);
62 EXPECT_EQ(processor->getHeadToStagePose(), worldToHead.inverse() * worldToScreen *
63 Pose3f(rotateY(-physicalToLogical)) *
64 screenToStage);
65
66 processor->setDesiredMode(HeadTrackingMode::WORLD_RELATIVE);
67 processor->calculate(0);
68 ASSERT_EQ(processor->getActualMode(), HeadTrackingMode::WORLD_RELATIVE);
69 EXPECT_EQ(processor->getHeadToStagePose(), worldToHead.inverse() * screenToStage);
70
71 processor->setDesiredMode(HeadTrackingMode::STATIC);
72 processor->calculate(0);
73 ASSERT_EQ(processor->getActualMode(), HeadTrackingMode::STATIC);
74 EXPECT_EQ(processor->getHeadToStagePose(), screenToStage);
75}
76
77TEST(HeadTrackingProcessor, Prediction) {
78 const Pose3f worldToHead{{1, 2, 3}, Quaternionf::UnitRandom()};
79 const Twist3f headTwist{{4, 5, 6}, quaternionToRotationVector(Quaternionf::UnitRandom()) / 10};
80 const Pose3f worldToScreen{{4, 5, 6}, Quaternionf::UnitRandom()};
81
Ytai Ben-Tsviedbab3d2021-08-16 11:27:52 -070082 std::unique_ptr<HeadTrackingProcessor> processor = createHeadTrackingProcessor(
Ytai Ben-Tsvicbee7d42021-06-15 00:39:31 -070083 Options{.predictionDuration = 2.f}, HeadTrackingMode::WORLD_RELATIVE);
Ytai Ben-Tsvib2a87e52021-08-20 10:17:05 -070084
85 // Establish a baseline for the drift compensators.
86 processor->setWorldToHeadPose(0, Pose3f(), Twist3f());
87 processor->setWorldToScreenPose(0, Pose3f());
88
Ytai Ben-Tsvicbee7d42021-06-15 00:39:31 -070089 processor->setWorldToHeadPose(0, worldToHead, headTwist);
90 processor->setWorldToScreenPose(0, worldToScreen);
91 processor->calculate(0);
92 ASSERT_EQ(processor->getActualMode(), HeadTrackingMode::WORLD_RELATIVE);
93 EXPECT_EQ(processor->getHeadToStagePose(), (worldToHead * integrate(headTwist, 2.f)).inverse());
94
95 processor->setDesiredMode(HeadTrackingMode::SCREEN_RELATIVE);
96 processor->calculate(0);
97 ASSERT_EQ(processor->getActualMode(), HeadTrackingMode::SCREEN_RELATIVE);
98 EXPECT_EQ(processor->getHeadToStagePose(),
99 (worldToHead * integrate(headTwist, 2.f)).inverse() * worldToScreen);
100
101 processor->setDesiredMode(HeadTrackingMode::STATIC);
102 processor->calculate(0);
103 ASSERT_EQ(processor->getActualMode(), HeadTrackingMode::STATIC);
104 EXPECT_EQ(processor->getHeadToStagePose(), Pose3f());
105}
106
107TEST(HeadTrackingProcessor, SmoothModeSwitch) {
108 const Pose3f targetHeadToWorld = Pose3f({4, 0, 0}, rotateZ(M_PI / 2));
109
Ytai Ben-Tsviedbab3d2021-08-16 11:27:52 -0700110 std::unique_ptr<HeadTrackingProcessor> processor = createHeadTrackingProcessor(
Ytai Ben-Tsvicbee7d42021-06-15 00:39:31 -0700111 Options{.maxTranslationalVelocity = 1}, HeadTrackingMode::STATIC);
112
Ytai Ben-Tsvib2a87e52021-08-20 10:17:05 -0700113 // Establish a baseline for the drift compensators.
114 processor->setWorldToHeadPose(0, Pose3f(), Twist3f());
115 processor->setWorldToScreenPose(0, Pose3f());
116
Ytai Ben-Tsvicbee7d42021-06-15 00:39:31 -0700117 processor->calculate(0);
118
119 processor->setDesiredMode(HeadTrackingMode::WORLD_RELATIVE);
120 processor->setWorldToHeadPose(0, targetHeadToWorld.inverse(), Twist3f());
121
122 // We're expecting a gradual move to the target.
123 processor->calculate(0);
124 EXPECT_EQ(HeadTrackingMode::WORLD_RELATIVE, processor->getActualMode());
125 EXPECT_EQ(processor->getHeadToStagePose(), Pose3f());
126
127 processor->calculate(2);
128 EXPECT_EQ(HeadTrackingMode::WORLD_RELATIVE, processor->getActualMode());
129 EXPECT_EQ(processor->getHeadToStagePose(), Pose3f({2, 0, 0}, rotateZ(M_PI / 4)));
130
131 processor->calculate(4);
132 EXPECT_EQ(HeadTrackingMode::WORLD_RELATIVE, processor->getActualMode());
133 EXPECT_EQ(processor->getHeadToStagePose(), targetHeadToWorld);
134
135 // Now that we've reached the target, we should no longer be rate limiting.
136 processor->setWorldToHeadPose(4, Pose3f(), Twist3f());
137 processor->calculate(5);
138 EXPECT_EQ(HeadTrackingMode::WORLD_RELATIVE, processor->getActualMode());
139 EXPECT_EQ(processor->getHeadToStagePose(), Pose3f());
140}
141
142} // namespace
143} // namespace media
144} // namespace android