OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/android/vr_shell/vr_shell.h" | 5 #include "chrome/browser/android/vr_shell/vr_shell.h" |
6 | 6 |
7 #include <thread> | 7 #include <thread> |
8 | 8 |
9 #include "chrome/browser/android/vr_shell/ui_scene.h" | 9 #include "chrome/browser/android/vr_shell/ui_scene.h" |
10 #include "chrome/browser/android/vr_shell/vr_compositor.h" | 10 #include "chrome/browser/android/vr_shell/vr_compositor.h" |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
60 | 60 |
61 // In lieu of an elbow model, we assume a position for the user's hand. | 61 // In lieu of an elbow model, we assume a position for the user's hand. |
62 // TODO(mthiesse): Handedness options. | 62 // TODO(mthiesse): Handedness options. |
63 static constexpr gvr::Vec3f kHandPosition = {0.2f, -0.5f, -0.2f}; | 63 static constexpr gvr::Vec3f kHandPosition = {0.2f, -0.5f, -0.2f}; |
64 | 64 |
65 // Fraction of the distance to the object the cursor is drawn at to avoid | 65 // Fraction of the distance to the object the cursor is drawn at to avoid |
66 // rounding errors drawing the cursor behind the object. | 66 // rounding errors drawing the cursor behind the object. |
67 static constexpr float kReticleOffset = 0.99f; | 67 static constexpr float kReticleOffset = 0.99f; |
68 | 68 |
69 // Limit the rendering distance of the reticle to the distance to a corner of | 69 // Limit the rendering distance of the reticle to the distance to a corner of |
70 // the content quad, times this value. This lets the rendering distance | 70 // the content quad, times this value. This lets the rendering distance |
71 // adjust according to content quad placement. | 71 // adjust according to content quad placement. |
72 static constexpr float kReticleDistanceMultiplier = 1.5f; | 72 static constexpr float kReticleDistanceMultiplier = 1.5f; |
73 | 73 |
74 // UI element 0 is the browser content rectangle. | 74 // UI element 0 is the browser content rectangle. |
75 static constexpr int kBrowserUiElementId = 0; | 75 static constexpr int kBrowserUiElementId = 0; |
76 | 76 |
77 vr_shell::VrShell* g_instance; | 77 vr_shell::VrShell* g_instance; |
78 | 78 |
79 static const char kVrShellUIURL[] = "chrome://vr-shell-ui"; | 79 static const char kVrShellUIURL[] = "chrome://vr-shell-ui"; |
80 | 80 |
81 float Distance(const gvr::Vec3f& vec1, const gvr::Vec3f& vec2) { | 81 float Distance(const gvr::Vec3f& vec1, const gvr::Vec3f& vec2) { |
82 float xdiff = (vec1.x - vec2.x); | 82 float xdiff = (vec1.x - vec2.x); |
83 float ydiff = (vec1.y - vec2.y); | 83 float ydiff = (vec1.y - vec2.y); |
84 float zdiff = (vec1.z - vec2.z); | 84 float zdiff = (vec1.z - vec2.z); |
85 float scale = xdiff * xdiff + ydiff * ydiff + zdiff * zdiff; | 85 float scale = xdiff * xdiff + ydiff * ydiff + zdiff * zdiff; |
86 return std::sqrt(scale); | 86 return std::sqrt(scale); |
87 } | 87 } |
88 | 88 |
89 // Generate a quaternion representing the rotation from the negative Z axis | 89 // Generate a quaternion representing the rotation from the negative Z axis |
90 // (0, 0, -1) to a specified vector. This is an optimized version of a more | 90 // (0, 0, -1) to a specified vector. This is an optimized version of a more |
91 // general vector-to-vector calculation. | 91 // general vector-to-vector calculation. |
92 gvr::Quatf GetRotationFromZAxis(gvr::Vec3f vec) { | 92 gvr::Quatf GetRotationFromZAxis(gvr::Vec3f vec) { |
93 vr_shell::NormalizeVector(vec); | 93 vr_shell::NormalizeVector(vec); |
94 gvr::Quatf quat; | 94 gvr::Quatf quat; |
95 quat.qw = 1.0f - vec.z; | 95 quat.qw = 1.0f - vec.z; |
96 if (quat.qw < 1e-6f) { | 96 if (quat.qw < 1e-6f) { |
97 // Degenerate case: vectors are exactly opposite. Replace by an | 97 // Degenerate case: vectors are exactly opposite. Replace by an |
98 // arbitrary 180 degree rotation to avoid invalid normalization. | 98 // arbitrary 180 degree rotation to avoid invalid normalization. |
99 quat.qx = 1.0f; | 99 quat.qx = 1.0f; |
100 quat.qy = 0.0f; | 100 quat.qy = 0.0f; |
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
233 } | 233 } |
234 | 234 |
235 gvr::Mat4f mat = QuatToMatrix(controller_quat_); | 235 gvr::Mat4f mat = QuatToMatrix(controller_quat_); |
236 gvr::Vec3f forward = MatrixVectorMul(mat, kNeutralPose); | 236 gvr::Vec3f forward = MatrixVectorMul(mat, kNeutralPose); |
237 gvr::Vec3f origin = kHandPosition; | 237 gvr::Vec3f origin = kHandPosition; |
238 | 238 |
239 target_element_ = nullptr; | 239 target_element_ = nullptr; |
240 float distance = scene_.GetUiElementById(kBrowserUiElementId) | 240 float distance = scene_.GetUiElementById(kBrowserUiElementId) |
241 ->GetRayDistance(origin, forward); | 241 ->GetRayDistance(origin, forward); |
242 | 242 |
| 243 // If we place the reticle based on elements intersecting the controller beam, |
| 244 // we can end up with the reticle hiding behind elements, or jumping laterally |
| 245 // in the field of view. This is physically correct, but hard to use. For |
| 246 // usability, do the following instead: |
| 247 // |
| 248 // - Project the controller laser onto an outer surface, which is the |
| 249 // closer of the desktop plane, or a distance-limiting sphere. |
| 250 // - Create a vector between the eyes and the outer surface point. |
| 251 // - If any UI elements intersect this vector, choose the closest to the eyes, |
| 252 // and place the reticle at the intersection point. |
| 253 |
243 // Find distance to a corner of the content quad, and limit the cursor | 254 // Find distance to a corner of the content quad, and limit the cursor |
244 // distance to a multiple of that distance. This lets us keep the reticle on | 255 // distance to a multiple of that distance. This lets us keep the reticle on |
245 // the content plane near the content window, and on the surface of a sphere | 256 // the content plane near the content window, and on the surface of a sphere |
246 // in other directions. | 257 // in other directions. Note that this approach uses distance from controller, |
247 // TODO(cjgrant): Note that this approach uses distance from controller, | 258 // rather than eye, for simplicity. This will make the sphere slightly |
248 // rather than eye, for simplicity. This will make the sphere slightly | |
249 // off-center. | 259 // off-center. |
250 gvr::Vec3f corner = {0.5f, 0.5f, 0.0f}; | 260 gvr::Vec3f corner = {0.5f, 0.5f, 0.0f}; |
251 corner = MatrixVectorMul(desktop_plane_->transform.to_world, corner); | 261 corner = MatrixVectorMul(desktop_plane_->transform.to_world, corner); |
252 float max_distance = Distance(origin, corner) * kReticleDistanceMultiplier; | 262 float max_distance = Distance(origin, corner) * kReticleDistanceMultiplier; |
253 if (distance > max_distance || distance <= 0.0f) { | 263 if (distance > max_distance || distance <= 0.0f) { |
254 distance = max_distance; | 264 distance = max_distance; |
255 } | 265 } |
256 target_point_ = GetRayPoint(origin, forward, distance); | 266 target_point_ = GetRayPoint(origin, forward, distance); |
| 267 gvr::Vec3f eye_to_target = target_point_; |
| 268 NormalizeVector(eye_to_target); |
257 | 269 |
258 // Determine which UI element (if any) the cursor is pointing to. | 270 // Determine which UI element (if any) intersects the line between the eyes |
| 271 // and the controller target position. |
259 float closest_element_distance = std::numeric_limits<float>::infinity(); | 272 float closest_element_distance = std::numeric_limits<float>::infinity(); |
260 int pixel_x = 0; | 273 int pixel_x = 0; |
261 int pixel_y = 0; | 274 int pixel_y = 0; |
262 VrInputManager* input_target = nullptr; | 275 VrInputManager* input_target = nullptr; |
263 | 276 |
264 for (std::size_t i = 0; i < scene_.GetUiElements().size(); ++i) { | 277 for (std::size_t i = 0; i < scene_.GetUiElements().size(); ++i) { |
265 const ContentRectangle& plane = *scene_.GetUiElements()[i].get(); | 278 const ContentRectangle& plane = *scene_.GetUiElements()[i].get(); |
266 if (!plane.visible) { | 279 if (!plane.visible) { |
267 continue; | 280 continue; |
268 } | 281 } |
269 float distance_to_plane = plane.GetRayDistance(origin, forward); | 282 float distance_to_plane = plane.GetRayDistance(kOrigin, eye_to_target); |
270 gvr::Vec3f plane_intersection_point = | 283 gvr::Vec3f plane_intersection_point = |
271 GetRayPoint(origin, forward, distance_to_plane); | 284 GetRayPoint(kOrigin, eye_to_target, distance_to_plane); |
272 | 285 |
273 gvr::Vec3f rect_2d_point = | 286 gvr::Vec3f rect_2d_point = |
274 MatrixVectorMul(plane.transform.from_world, plane_intersection_point); | 287 MatrixVectorMul(plane.transform.from_world, plane_intersection_point); |
275 float x = rect_2d_point.x + 0.5f; | |
276 float y = 0.5f - rect_2d_point.y; | |
277 if (distance_to_plane > 0 && distance_to_plane < closest_element_distance) { | 288 if (distance_to_plane > 0 && distance_to_plane < closest_element_distance) { |
| 289 float x = rect_2d_point.x + 0.5f; |
| 290 float y = 0.5f - rect_2d_point.y; |
278 bool is_inside = x >= 0.0f && x < 1.0f && y >= 0.0f && y < 1.0f; | 291 bool is_inside = x >= 0.0f && x < 1.0f && y >= 0.0f && y < 1.0f; |
279 if (is_inside) { | 292 if (is_inside) { |
280 closest_element_distance = distance_to_plane; | 293 closest_element_distance = distance_to_plane; |
281 pixel_x = | 294 pixel_x = |
282 static_cast<int>(plane.copy_rect.width * x + plane.copy_rect.x); | 295 static_cast<int>(plane.copy_rect.width * x + plane.copy_rect.x); |
283 pixel_y = | 296 pixel_y = |
284 static_cast<int>(plane.copy_rect.height * y + plane.copy_rect.y); | 297 static_cast<int>(plane.copy_rect.height * y + plane.copy_rect.y); |
285 | 298 |
286 target_point_ = plane_intersection_point; | 299 target_point_ = plane_intersection_point; |
287 target_element_ = &plane; | 300 target_element_ = &plane; |
(...skipping 365 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
653 content::WebContents::FromJavaWebContents(content_web_contents)); | 666 content::WebContents::FromJavaWebContents(content_web_contents)); |
654 content::ContentViewCore* ui_core = content::ContentViewCore::FromWebContents( | 667 content::ContentViewCore* ui_core = content::ContentViewCore::FromWebContents( |
655 content::WebContents::FromJavaWebContents(ui_web_contents)); | 668 content::WebContents::FromJavaWebContents(ui_web_contents)); |
656 return reinterpret_cast<intptr_t>(new VrShell( | 669 return reinterpret_cast<intptr_t>(new VrShell( |
657 env, obj, c_core, | 670 env, obj, c_core, |
658 reinterpret_cast<ui::WindowAndroid*>(content_window_android), ui_core, | 671 reinterpret_cast<ui::WindowAndroid*>(content_window_android), ui_core, |
659 reinterpret_cast<ui::WindowAndroid*>(ui_window_android))); | 672 reinterpret_cast<ui::WindowAndroid*>(ui_window_android))); |
660 } | 673 } |
661 | 674 |
662 } // namespace vr_shell | 675 } // namespace vr_shell |
OLD | NEW |