| 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 |