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 22 matching lines...) Expand all Loading... |
33 | 33 |
34 static constexpr gvr::Vec3f kDesktopPositionDefault = {0.0f, 0.0f, -2.0f}; | 34 static constexpr gvr::Vec3f kDesktopPositionDefault = {0.0f, 0.0f, -2.0f}; |
35 static constexpr float kDesktopHeightDefault = 1.6f; | 35 static constexpr float kDesktopHeightDefault = 1.6f; |
36 | 36 |
37 // Screen angle in degrees. 0 = vertical, positive = top closer. | 37 // Screen angle in degrees. 0 = vertical, positive = top closer. |
38 static constexpr float kDesktopScreenTiltDefault = 0; | 38 static constexpr float kDesktopScreenTiltDefault = 0; |
39 | 39 |
40 static constexpr float kScreenHeightRatio = 1.0f; | 40 static constexpr float kScreenHeightRatio = 1.0f; |
41 static constexpr float kScreenWidthRatio = 16.0f / 9.0f; | 41 static constexpr float kScreenWidthRatio = 16.0f / 9.0f; |
42 | 42 |
43 static constexpr float kReticleWidth = 0.05f; | 43 static constexpr float kReticleWidth = 0.025f; |
44 static constexpr float kReticleHeight = 0.05f; | 44 static constexpr float kReticleHeight = 0.025f; |
45 | 45 |
46 static constexpr float kLaserWidth = 0.01f; | 46 static constexpr float kLaserWidth = 0.01f; |
47 | 47 |
48 // The neutral direction is fixed in world space, this is the | 48 // The neutral direction is fixed in world space, this is the |
49 // reference angle pointing forward towards the horizon when the | 49 // reference angle pointing forward towards the horizon when the |
50 // controller orientation is reset. This should match the yaw angle | 50 // controller orientation is reset. This should match the yaw angle |
51 // where the main screen is placed. | 51 // where the main screen is placed. |
52 static constexpr gvr::Vec3f kNeutralPose = {0.0f, 0.0f, -1.0f}; | 52 static constexpr gvr::Vec3f kNeutralPose = {0.0f, 0.0f, -1.0f}; |
53 | 53 |
| 54 static constexpr gvr::Vec3f kOrigin = {0.0f, 0.0f, 0.0f}; |
| 55 |
54 // In lieu of an elbow model, we assume a position for the user's hand. | 56 // In lieu of an elbow model, we assume a position for the user's hand. |
55 // TODO(mthiesse): Handedness options. | 57 // TODO(mthiesse): Handedness options. |
56 static constexpr gvr::Vec3f kHandPosition = {0.2f, -0.5f, -0.2f}; | 58 static constexpr gvr::Vec3f kHandPosition = {0.2f, -0.5f, -0.2f}; |
57 | 59 |
58 static constexpr float kReticleZOffset = 0.01f; | 60 // Fraction of the z-distance to the object the cursor is drawn at to avoid |
| 61 // rounding errors drawing the cursor behind the object. |
| 62 static constexpr float kReticleZOffset = 0.99f; |
59 | 63 |
60 // UI element 0 is the browser content rectangle. | 64 // UI element 0 is the browser content rectangle. |
61 static constexpr int kBrowserUiElementId = 0; | 65 static constexpr int kBrowserUiElementId = 0; |
62 | 66 |
63 vr_shell::VrShell* g_instance; | 67 vr_shell::VrShell* g_instance; |
64 | 68 |
65 } // namespace | 69 } // namespace |
66 | 70 |
67 namespace vr_shell { | 71 namespace vr_shell { |
68 | 72 |
69 VrShell::VrShell(JNIEnv* env, jobject obj, | 73 VrShell::VrShell(JNIEnv* env, jobject obj, |
70 content::ContentViewCore* content_core, | 74 content::ContentViewCore* content_core, |
71 ui::WindowAndroid* content_window) | 75 ui::WindowAndroid* content_window) |
72 : desktop_screen_tilt_(kDesktopScreenTiltDefault), | 76 : desktop_screen_tilt_(kDesktopScreenTiltDefault), |
73 desktop_height_(kDesktopHeightDefault), | 77 desktop_height_(kDesktopHeightDefault), |
74 desktop_position_(kDesktopPositionDefault), | 78 desktop_position_(kDesktopPositionDefault), |
| 79 cursor_distance_(-kDesktopPositionDefault.z), |
75 content_cvc_(content_core), | 80 content_cvc_(content_core), |
76 delegate_(nullptr), | 81 delegate_(nullptr), |
77 weak_ptr_factory_(this) { | 82 weak_ptr_factory_(this) { |
78 g_instance = this; | 83 g_instance = this; |
79 j_vr_shell_.Reset(env, obj); | 84 j_vr_shell_.Reset(env, obj); |
80 content_compositor_view_.reset(new VrCompositor(content_window)); | 85 content_compositor_view_.reset(new VrCompositor(content_window)); |
81 | 86 |
82 float screen_width = kScreenWidthRatio * desktop_height_; | 87 float screen_width = kScreenWidthRatio * desktop_height_; |
83 float screen_height = kScreenHeightRatio * desktop_height_; | 88 float screen_height = kScreenHeightRatio * desktop_height_; |
84 std::unique_ptr<ContentRectangle> rect(new ContentRectangle()); | 89 std::unique_ptr<ContentRectangle> rect(new ContentRectangle()); |
85 rect->id = kBrowserUiElementId; | 90 rect->id = kBrowserUiElementId; |
86 rect->size = {screen_width, screen_height, 1.0f}; | 91 rect->size = {screen_width, screen_height, 1.0f}; |
87 scene_.AddUiElement(rect); | 92 scene_.AddUiElement(rect); |
88 | 93 |
89 desktop_plane_ = scene_.GetUiElementById(kBrowserUiElementId); | 94 desktop_plane_ = scene_.GetUiElementById(kBrowserUiElementId); |
90 | 95 |
91 content_cvc_->GetWebContents()->GetRenderWidgetHostView() | 96 content_cvc_->GetWebContents()->GetRenderWidgetHostView() |
92 ->GetRenderWidgetHost()->WasResized(); | 97 ->GetRenderWidgetHost()->WasResized(); |
93 } | 98 } |
94 | 99 |
95 void VrShell::UpdateCompositorLayers(JNIEnv* env, | 100 void VrShell::UpdateCompositorLayers(JNIEnv* env, |
96 const JavaParamRef<jobject>& obj) { | 101 const JavaParamRef<jobject>& obj) { |
97 content_compositor_view_->SetLayer(content_cvc_); | 102 content_compositor_view_->SetLayer(content_cvc_); |
98 } | 103 } |
99 | 104 |
100 void VrShell::Destroy(JNIEnv* env, const JavaParamRef<jobject>& obj) { | 105 void VrShell::Destroy(JNIEnv* env, const JavaParamRef<jobject>& obj) { |
101 delete this; | 106 delete this; |
102 g_instance = nullptr; | |
103 gl::init::ClearGLBindings(); | |
104 } | 107 } |
105 | 108 |
106 bool RegisterVrShell(JNIEnv* env) { | 109 bool RegisterVrShell(JNIEnv* env) { |
107 return RegisterNativesImpl(env); | 110 return RegisterNativesImpl(env); |
108 } | 111 } |
109 | 112 |
110 VrShell::~VrShell() { | 113 VrShell::~VrShell() { |
| 114 g_instance = nullptr; |
| 115 gl::init::ClearGLBindings(); |
111 } | 116 } |
112 | 117 |
113 void VrShell::SetDelegate(JNIEnv* env, | 118 void VrShell::SetDelegate(JNIEnv* env, |
114 const base::android::JavaParamRef<jobject>& obj, | 119 const base::android::JavaParamRef<jobject>& obj, |
115 const base::android::JavaParamRef<jobject>& delegate) { | 120 const base::android::JavaParamRef<jobject>& delegate) { |
116 delegate_ = VrShellDelegate::getNativeDelegate(env, delegate); | 121 delegate_ = VrShellDelegate::getNativeDelegate(env, delegate); |
117 } | 122 } |
118 | 123 |
119 void VrShell::GvrInit(JNIEnv* env, | 124 void VrShell::GvrInit(JNIEnv* env, |
120 const JavaParamRef<jobject>& obj, | 125 const JavaParamRef<jobject>& obj, |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
175 gvr::Vec3f translation = getTranslation(mat); | 180 gvr::Vec3f translation = getTranslation(mat); |
176 | 181 |
177 // Use the eye midpoint as the origin for Cardboard mode, but apply an offset | 182 // Use the eye midpoint as the origin for Cardboard mode, but apply an offset |
178 // for the controller. | 183 // for the controller. |
179 if (controller_active_) { | 184 if (controller_active_) { |
180 translation.x += kHandPosition.x; | 185 translation.x += kHandPosition.x; |
181 translation.y += kHandPosition.y; | 186 translation.y += kHandPosition.y; |
182 translation.z += kHandPosition.z; | 187 translation.z += kHandPosition.z; |
183 } | 188 } |
184 | 189 |
185 // We can only be intersecting the desktop plane at the moment. | 190 float desktop_dist = scene_.GetUiElementById(kBrowserUiElementId) |
186 float distance_to_plane = desktop_plane_->GetRayDistance(translation, | 191 ->GetRayDistance(translation, forward); |
187 forward); | 192 gvr::Vec3f cursor_position = GetRayPoint(translation, forward, desktop_dist); |
188 look_at_vector_ = GetRayPoint(translation, forward, distance_to_plane); | 193 look_at_vector_ = cursor_position; |
| 194 cursor_distance_ = desktop_dist; |
| 195 |
| 196 // Determine which UI element (if any) the cursor is pointing to. |
| 197 float closest_element = std::numeric_limits<float>::infinity(); |
| 198 int closest_element_index = -1; |
| 199 int pixel_x = 0; |
| 200 int pixel_y = 0; |
| 201 |
| 202 for (std::size_t i = 0; i < scene_.GetUiElements().size(); ++i) { |
| 203 const ContentRectangle& plane = *scene_.GetUiElements()[i].get(); |
| 204 float distance_to_plane = plane.GetRayDistance(kOrigin, cursor_position); |
| 205 gvr::Vec3f plane_intersection_point = |
| 206 GetRayPoint(kOrigin, cursor_position, distance_to_plane); |
| 207 gvr::Vec3f rect_2d_point = |
| 208 MatrixVectorMul(plane.transform.from_world, plane_intersection_point); |
| 209 float x = rect_2d_point.x + 0.5f; |
| 210 float y = 0.5f - rect_2d_point.y; |
| 211 if (distance_to_plane > 0 && distance_to_plane < closest_element) { |
| 212 bool is_inside = x >= 0.0f && x < 1.0f && y >= 0.0f && y < 1.0f; |
| 213 if (is_inside) { |
| 214 closest_element = distance_to_plane; |
| 215 cursor_distance_ = desktop_dist * distance_to_plane; |
| 216 closest_element_index = i; |
| 217 pixel_x = int((plane.copy_rect.width * x) + plane.copy_rect.x); |
| 218 pixel_y = int((plane.copy_rect.height * y) + plane.copy_rect.y); |
| 219 look_at_vector_ = plane_intersection_point; |
| 220 } |
| 221 } |
| 222 } |
| 223 // TODO(mthiesse): Create input events for CVC using pixel_x/y. |
189 } | 224 } |
190 | 225 |
191 void ApplyNeckModel(gvr::Mat4f& mat_forward) { | 226 void ApplyNeckModel(gvr::Mat4f& mat_forward) { |
192 // This assumes that the input matrix is a pure rotation matrix. The | 227 // This assumes that the input matrix is a pure rotation matrix. The |
193 // input object_from_reference matrix has the inverse rotation of | 228 // input object_from_reference matrix has the inverse rotation of |
194 // the head rotation. Invert it (this is just a transpose). | 229 // the head rotation. Invert it (this is just a transpose). |
195 gvr::Mat4f mat = MatrixTranspose(mat_forward); | 230 gvr::Mat4f mat = MatrixTranspose(mat_forward); |
196 | 231 |
197 // Position of the point between the eyes, relative to the neck pivot: | 232 // Position of the point between the eyes, relative to the neck pivot: |
198 const float kNeckHorizontalOffset = -0.080f; // meters in Z | 233 const float kNeckHorizontalOffset = -0.080f; // meters in Z |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
230 DrawVrShell(target_time.monotonic_system_time_nanos); | 265 DrawVrShell(target_time.monotonic_system_time_nanos); |
231 } | 266 } |
232 | 267 |
233 frame.Unbind(); | 268 frame.Unbind(); |
234 frame.Submit(*buffer_viewport_list_, head_pose_); | 269 frame.Submit(*buffer_viewport_list_, head_pose_); |
235 } | 270 } |
236 | 271 |
237 void VrShell::DrawVrShell(int64_t time) { | 272 void VrShell::DrawVrShell(int64_t time) { |
238 float screen_tilt = desktop_screen_tilt_ * M_PI / 180.0f; | 273 float screen_tilt = desktop_screen_tilt_ * M_PI / 180.0f; |
239 | 274 |
240 forward_vector_ = getForwardVector(head_pose_); | |
241 | |
242 gvr::Vec3f headPos = getTranslation(head_pose_); | 275 gvr::Vec3f headPos = getTranslation(head_pose_); |
243 if (headPos.x == 0.0f && headPos.y == 0.0f && headPos.z == 0.0f) { | 276 if (headPos.x == 0.0f && headPos.y == 0.0f && headPos.z == 0.0f) { |
244 // This appears to be a 3DOF pose without a neck model. Add one. | 277 // This appears to be a 3DOF pose without a neck model. Add one. |
245 // The head pose has redundant data. Assume we're only using the | 278 // The head pose has redundant data. Assume we're only using the |
246 // object_from_reference_matrix, we're not updating position_external. | 279 // object_from_reference_matrix, we're not updating position_external. |
247 // TODO: Not sure what object_from_reference_matrix is. The new api removed | 280 // TODO: Not sure what object_from_reference_matrix is. The new api removed |
248 // it. For now, removing it seems working fine. | 281 // it. For now, removing it seems working fine. |
249 ApplyNeckModel(head_pose_); | 282 ApplyNeckModel(head_pose_); |
250 } | 283 } |
251 | 284 |
252 desktop_plane_->translation.x = desktop_position_.x; | 285 forward_vector_ = getForwardVector(head_pose_); |
253 desktop_plane_->translation.y = desktop_position_.y; | 286 |
254 desktop_plane_->translation.z = desktop_position_.z; | 287 desktop_plane_->translation = desktop_position_; |
255 | 288 |
256 // Update the render position of all UI elements (including desktop). | 289 // Update the render position of all UI elements (including desktop). |
257 scene_.UpdateTransforms(screen_tilt, time); | 290 scene_.UpdateTransforms(screen_tilt, time); |
258 | 291 |
259 UpdateController(); | 292 UpdateController(); |
260 | 293 |
261 // Everything should be positioned now, ready for drawing. | 294 // Everything should be positioned now, ready for drawing. |
262 gvr::Mat4f left_eye_view_matrix = | 295 gvr::Mat4f left_eye_view_matrix = |
263 MatrixMul(gvr_api_->GetEyeFromHeadMatrix(GVR_LEFT_EYE), head_pose_); | 296 MatrixMul(gvr_api_->GetEyeFromHeadMatrix(GVR_LEFT_EYE), head_pose_); |
264 gvr::Mat4f right_eye_view_matrix = | 297 gvr::Mat4f right_eye_view_matrix = |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
325 } | 358 } |
326 | 359 |
327 vr_shell_renderer_->GetTexturedQuadRenderer()->Draw( | 360 vr_shell_renderer_->GetTexturedQuadRenderer()->Draw( |
328 texture_handle, combined_matrix, copy_rect); | 361 texture_handle, combined_matrix, copy_rect); |
329 } | 362 } |
330 } | 363 } |
331 | 364 |
332 void VrShell::DrawCursor() { | 365 void VrShell::DrawCursor() { |
333 gvr::Mat4f mat; | 366 gvr::Mat4f mat; |
334 SetIdentityM(mat); | 367 SetIdentityM(mat); |
335 // Scale the pointer. | 368 |
336 ScaleM(mat, mat, kReticleWidth, kReticleHeight, 1.0f); | 369 // Scale the pointer to have a fixed FOV size at any distance. |
| 370 ScaleM(mat, mat, kReticleWidth * cursor_distance_, |
| 371 kReticleHeight * cursor_distance_, 1.0f); |
| 372 |
337 // Place the pointer at the screen plane intersection point. | 373 // Place the pointer at the screen plane intersection point. |
338 TranslateM(mat, mat, look_at_vector_.x, look_at_vector_.y, | 374 TranslateM(mat, mat, look_at_vector_.x * kReticleZOffset, |
339 look_at_vector_.z + kReticleZOffset); | 375 look_at_vector_.y * kReticleZOffset, |
| 376 look_at_vector_.z * kReticleZOffset); |
340 gvr::Mat4f mv = MatrixMul(view_matrix_, mat); | 377 gvr::Mat4f mv = MatrixMul(view_matrix_, mat); |
341 gvr::Mat4f mvp = MatrixMul(projection_matrix_, mv); | 378 gvr::Mat4f mvp = MatrixMul(projection_matrix_, mv); |
342 vr_shell_renderer_->GetReticleRenderer()->Draw(mvp); | 379 vr_shell_renderer_->GetReticleRenderer()->Draw(mvp); |
343 | 380 |
344 // Draw the laser only for controllers. | 381 // Draw the laser only for controllers. |
345 if (!controller_active_) { | 382 if (!controller_active_) { |
346 return; | 383 return; |
347 } | 384 } |
348 // Find the length of the beam (from hand to target). | 385 // Find the length of the beam (from hand to target). |
349 float xdiff = (kHandPosition.x - look_at_vector_.x); | 386 float xdiff = (kHandPosition.x - look_at_vector_.x); |
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
463 const JavaParamRef<jobject>& content_web_contents, | 500 const JavaParamRef<jobject>& content_web_contents, |
464 jlong content_window_android) { | 501 jlong content_window_android) { |
465 content::ContentViewCore* c_core = content::ContentViewCore::FromWebContents( | 502 content::ContentViewCore* c_core = content::ContentViewCore::FromWebContents( |
466 content::WebContents::FromJavaWebContents(content_web_contents)); | 503 content::WebContents::FromJavaWebContents(content_web_contents)); |
467 return reinterpret_cast<intptr_t>(new VrShell( | 504 return reinterpret_cast<intptr_t>(new VrShell( |
468 env, obj, c_core, | 505 env, obj, c_core, |
469 reinterpret_cast<ui::WindowAndroid*>(content_window_android))); | 506 reinterpret_cast<ui::WindowAndroid*>(content_window_android))); |
470 } | 507 } |
471 | 508 |
472 } // namespace vr_shell | 509 } // namespace vr_shell |
OLD | NEW |