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/vr_compositor.h" | 9 #include "chrome/browser/android/vr_shell/vr_compositor.h" |
10 #include "chrome/browser/android/vr_shell/vr_gl_util.h" | 10 #include "chrome/browser/android/vr_shell/vr_gl_util.h" |
(...skipping 20 matching lines...) Expand all Loading... | |
31 | 31 |
32 static constexpr gvr::Vec3f kDesktopPositionDefault = {0.0f, 0.0f, -2.0f}; | 32 static constexpr gvr::Vec3f kDesktopPositionDefault = {0.0f, 0.0f, -2.0f}; |
33 static constexpr float kDesktopHeightDefault = 1.6f; | 33 static constexpr float kDesktopHeightDefault = 1.6f; |
34 | 34 |
35 // Screen angle in degrees. 0 = vertical, positive = top closer. | 35 // Screen angle in degrees. 0 = vertical, positive = top closer. |
36 static constexpr float kDesktopScreenTiltDefault = 0; | 36 static constexpr float kDesktopScreenTiltDefault = 0; |
37 | 37 |
38 static constexpr float kScreenHeightRatio = 1.0f; | 38 static constexpr float kScreenHeightRatio = 1.0f; |
39 static constexpr float kScreenWidthRatio = 16.0f / 9.0f; | 39 static constexpr float kScreenWidthRatio = 16.0f / 9.0f; |
40 | 40 |
41 static constexpr float kReticleWidth = 0.05f; | 41 static constexpr float kReticleWidth = 0.025f; |
42 static constexpr float kReticleHeight = 0.05f; | 42 static constexpr float kReticleHeight = 0.025f; |
43 | 43 |
44 static constexpr float kLaserWidth = 0.01f; | 44 static constexpr float kLaserWidth = 0.01f; |
45 | 45 |
46 // The neutral direction is fixed in world space, this is the | 46 // The neutral direction is fixed in world space, this is the |
47 // reference angle pointing forward towards the horizon when the | 47 // reference angle pointing forward towards the horizon when the |
48 // controller orientation is reset. This should match the yaw angle | 48 // controller orientation is reset. This should match the yaw angle |
49 // where the main screen is placed. | 49 // where the main screen is placed. |
50 static constexpr gvr::Vec3f kNeutralPose = {0.0f, 0.0f, -1.0f}; | 50 static constexpr gvr::Vec3f kNeutralPose = {0.0f, 0.0f, -1.0f}; |
51 | 51 |
52 static constexpr gvr::Vec3f kOrigin = {0.0f, 0.0f, 0.0f}; | |
53 | |
52 // In lieu of an elbow model, we assume a position for the user's hand. | 54 // In lieu of an elbow model, we assume a position for the user's hand. |
53 // TODO(mthiesse): Handedness options. | 55 // TODO(mthiesse): Handedness options. |
54 static constexpr gvr::Vec3f kHandPosition = {0.2f, -0.5f, -0.2f}; | 56 static constexpr gvr::Vec3f kHandPosition = {0.2f, -0.5f, -0.2f}; |
55 | 57 |
56 static constexpr float kReticleZOffset = 0.01f; | 58 // Fraction of the z-distance to the object the cursor is drawn at to avoid |
59 // rounding errors drawing the cursor behind the object. | |
60 static constexpr float kReticleZOffset = 0.99f; | |
57 | 61 |
58 } // namespace | 62 } // namespace |
59 | 63 |
60 namespace vr_shell { | 64 namespace vr_shell { |
61 | 65 |
62 VrShell::VrShell(JNIEnv* env, jobject obj, | 66 VrShell::VrShell(JNIEnv* env, jobject obj, |
63 content::ContentViewCore* content_core, | 67 content::ContentViewCore* content_core, |
64 ui::WindowAndroid* content_window) | 68 ui::WindowAndroid* content_window) |
65 : desktop_screen_tilt_(kDesktopScreenTiltDefault), | 69 : desktop_screen_tilt_(kDesktopScreenTiltDefault), |
66 desktop_height_(kDesktopHeightDefault), | 70 desktop_height_(kDesktopHeightDefault), |
67 desktop_position_(kDesktopPositionDefault), | 71 desktop_position_(kDesktopPositionDefault), |
72 cursor_distance_(-kDesktopPositionDefault.z), | |
68 content_cvc_(content_core) { | 73 content_cvc_(content_core) { |
69 j_vr_shell_.Reset(env, obj); | 74 j_vr_shell_.Reset(env, obj); |
70 content_compositor_view_.reset(new VrCompositor(content_window)); | 75 content_compositor_view_.reset(new VrCompositor(content_window)); |
71 ui_rects_.emplace_back(new ContentRectangle()); | 76 ui_rects_.emplace_back(new ContentRectangle()); |
72 desktop_plane_ = ui_rects_.back().get(); | 77 desktop_plane_ = ui_rects_.back().get(); |
73 desktop_plane_->id = 0; | 78 desktop_plane_->id = 0; |
74 desktop_plane_->copy_rect = {0.0f, 0.0f, 1.0f, 1.0f}; | 79 desktop_plane_->copy_rect = {0.0f, 0.0f, 1.0f, 1.0f}; |
75 // TODO(cjgrant): If we use the native path for content clicks, fix this. | 80 // TODO(cjgrant): If we use the native path for content clicks, fix this. |
76 desktop_plane_->window_rect = {0, 0, 0, 0}; | 81 desktop_plane_->window_rect = {0, 0, 0, 0}; |
77 desktop_plane_->translation = {0.0f, 0.0f, 0.0f}; | 82 desktop_plane_->translation = {0.0f, 0.0f, 0.0f}; |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
162 gvr::Vec3f translation = getTranslation(mat); | 167 gvr::Vec3f translation = getTranslation(mat); |
163 | 168 |
164 // Use the eye midpoint as the origin for Cardboard mode, but apply an offset | 169 // Use the eye midpoint as the origin for Cardboard mode, but apply an offset |
165 // for the controller. | 170 // for the controller. |
166 if (controller_active_) { | 171 if (controller_active_) { |
167 translation.x += kHandPosition.x; | 172 translation.x += kHandPosition.x; |
168 translation.y += kHandPosition.y; | 173 translation.y += kHandPosition.y; |
169 translation.z += kHandPosition.z; | 174 translation.z += kHandPosition.z; |
170 } | 175 } |
171 | 176 |
172 // We can only be intersecting the desktop plane at the moment. | 177 float desktop_dist = ui_rects_[0]->GetRayDistance(translation, forward); |
cjgrant
2016/09/22 18:59:04
Should use desktop_plane_ or scene_.GetUiElementBy
mthiesse
2016/09/22 22:01:33
Done.
| |
173 float distance_to_plane = desktop_plane_->GetRayDistance(translation, | 178 gvr::Vec3f cursor_position = GetRayPoint(translation, forward, desktop_dist); |
cjgrant
2016/09/22 18:59:03
If you want, there's a better way to do this. Sin
mthiesse
2016/09/22 22:01:33
I'll get back to this when we have working control
| |
174 forward); | 179 look_at_vector_ = cursor_position; |
175 look_at_vector_ = GetRayPoint(translation, forward, distance_to_plane); | 180 cursor_distance_ = desktop_dist; |
181 | |
182 // Determine which UI element (if any) the cursor is pointing to. | |
183 float closest_element = std::numeric_limits<float>::infinity(); | |
184 int closest_element_index = -1; | |
185 int pixel_x, pixel_y; | |
186 | |
187 for (std::size_t i = 0; i < ui_rects_.size(); ++i) { | |
188 const ContentRectangle& plane = *ui_rects_[i].get(); | |
189 float distance_to_plane = plane.GetRayDistance(kOrigin, cursor_position); | |
190 gvr::Vec3f plane_intersection_point = | |
191 GetRayPoint(kOrigin, cursor_position, distance_to_plane); | |
192 gvr::Vec3f rect_2d_point = | |
193 MatrixVectorMul(plane.transform.from_world, plane_intersection_point); | |
194 float x = rect_2d_point.x + 0.5f; | |
195 float y = 0.5f - rect_2d_point.y; | |
196 if (distance_to_plane > 0 && distance_to_plane < closest_element) { | |
197 bool is_inside = x >= 0.0f && x < 1.0f && y >= 0.0f && y < 1.0f; | |
198 if (is_inside) { | |
199 closest_element = distance_to_plane; | |
200 cursor_distance_ = desktop_dist * distance_to_plane; | |
201 closest_element_index = i; | |
202 pixel_x = int((plane.copy_rect.width * x) + plane.copy_rect.x); | |
203 pixel_y = int((plane.copy_rect.height * y) + plane.copy_rect.y); | |
204 look_at_vector_ = plane_intersection_point; | |
205 } | |
206 } | |
207 } | |
208 // TODO(mthiesse): Create input events for CVC using pixel_x/y. | |
176 } | 209 } |
177 | 210 |
178 void ApplyNeckModel(gvr::Mat4f& mat_forward) { | 211 void ApplyNeckModel(gvr::Mat4f& mat_forward) { |
179 // This assumes that the input matrix is a pure rotation matrix. The | 212 // This assumes that the input matrix is a pure rotation matrix. The |
180 // input object_from_reference matrix has the inverse rotation of | 213 // input object_from_reference matrix has the inverse rotation of |
181 // the head rotation. Invert it (this is just a transpose). | 214 // the head rotation. Invert it (this is just a transpose). |
182 gvr::Mat4f mat = MatrixTranspose(mat_forward); | 215 gvr::Mat4f mat = MatrixTranspose(mat_forward); |
183 | 216 |
184 // Position of the point between the eyes, relative to the neck pivot: | 217 // Position of the point between the eyes, relative to the neck pivot: |
185 const float kNeckHorizontalOffset = -0.080f; // meters in Z | 218 const float kNeckHorizontalOffset = -0.080f; // meters in Z |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
220 frame.Unbind(); | 253 frame.Unbind(); |
221 frame.Submit(*buffer_viewport_list_, head_pose_); | 254 frame.Submit(*buffer_viewport_list_, head_pose_); |
222 } | 255 } |
223 | 256 |
224 void VrShell::DrawVrShell() { | 257 void VrShell::DrawVrShell() { |
225 float screen_width = kScreenWidthRatio * desktop_height_; | 258 float screen_width = kScreenWidthRatio * desktop_height_; |
226 float screen_height = kScreenHeightRatio * desktop_height_; | 259 float screen_height = kScreenHeightRatio * desktop_height_; |
227 | 260 |
228 float screen_tilt = desktop_screen_tilt_ * M_PI / 180.0f; | 261 float screen_tilt = desktop_screen_tilt_ * M_PI / 180.0f; |
229 | 262 |
230 forward_vector_ = getForwardVector(head_pose_); | |
231 | |
232 gvr::Vec3f headPos = getTranslation(head_pose_); | 263 gvr::Vec3f headPos = getTranslation(head_pose_); |
233 if (headPos.x == 0.0f && headPos.y == 0.0f && headPos.z == 0.0f) { | 264 if (headPos.x == 0.0f && headPos.y == 0.0f && headPos.z == 0.0f) { |
234 // This appears to be a 3DOF pose without a neck model. Add one. | 265 // This appears to be a 3DOF pose without a neck model. Add one. |
235 // The head pose has redundant data. Assume we're only using the | 266 // The head pose has redundant data. Assume we're only using the |
236 // object_from_reference_matrix, we're not updating position_external. | 267 // object_from_reference_matrix, we're not updating position_external. |
237 // TODO: Not sure what object_from_reference_matrix is. The new api removed | 268 // TODO: Not sure what object_from_reference_matrix is. The new api removed |
238 // it. For now, removing it seems working fine. | 269 // it. For now, removing it seems working fine. |
239 ApplyNeckModel(head_pose_); | 270 ApplyNeckModel(head_pose_); |
240 } | 271 } |
241 | 272 |
273 forward_vector_ = getForwardVector(head_pose_); | |
274 | |
242 desktop_plane_->size = {screen_width, screen_height, 1.0f}; | 275 desktop_plane_->size = {screen_width, screen_height, 1.0f}; |
243 desktop_plane_->translation.x = desktop_position_.x; | 276 desktop_plane_->translation.x = desktop_position_.x; |
244 desktop_plane_->translation.y = desktop_position_.y; | 277 desktop_plane_->translation.y = desktop_position_.y; |
245 desktop_plane_->translation.z = desktop_position_.z; | 278 desktop_plane_->translation.z = desktop_position_.z; |
246 | 279 |
247 // Update position of all UI elements (including desktop) | 280 // Update position of all UI elements (including desktop) |
248 UpdateTransforms(screen_width, screen_height, screen_tilt); | 281 UpdateTransforms(screen_width, screen_height, screen_tilt); |
249 | 282 |
250 UpdateController(); | 283 UpdateController(); |
251 | 284 |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
302 combined_matrix = MatrixMul(projection_matrix_, combined_matrix); | 335 combined_matrix = MatrixMul(projection_matrix_, combined_matrix); |
303 vr_shell_renderer_->GetTexturedQuadRenderer()->Draw( | 336 vr_shell_renderer_->GetTexturedQuadRenderer()->Draw( |
304 ui_rects_[i].get()->content_texture_handle, combined_matrix, | 337 ui_rects_[i].get()->content_texture_handle, combined_matrix, |
305 ui_rects_[i].get()->copy_rect); | 338 ui_rects_[i].get()->copy_rect); |
306 } | 339 } |
307 } | 340 } |
308 | 341 |
309 void VrShell::DrawCursor() { | 342 void VrShell::DrawCursor() { |
310 gvr::Mat4f mat; | 343 gvr::Mat4f mat; |
311 SetIdentityM(mat); | 344 SetIdentityM(mat); |
345 | |
312 // Scale the pointer. | 346 // Scale the pointer. |
cjgrant
2016/09/22 18:59:04
... to have a fixed FOV size at any distance. (?)
mthiesse
2016/09/22 22:01:33
Done.
| |
313 ScaleM(mat, mat, kReticleWidth, kReticleHeight, 1.0f); | 347 ScaleM(mat, mat, kReticleWidth * cursor_distance_, |
348 kReticleHeight * cursor_distance_, 1.0f); | |
349 | |
314 // Place the pointer at the screen plane intersection point. | 350 // Place the pointer at the screen plane intersection point. |
315 TranslateM(mat, mat, look_at_vector_.x, look_at_vector_.y, | 351 TranslateM(mat, mat, look_at_vector_.x * kReticleZOffset, |
cjgrant
2016/09/22 18:59:03
Why are x and y also being offset?
mthiesse
2016/09/22 22:01:33
We're moving it slightly towards the viewer while
| |
316 look_at_vector_.z + kReticleZOffset); | 352 look_at_vector_.y * kReticleZOffset, |
353 look_at_vector_.z * kReticleZOffset); | |
317 gvr::Mat4f mv = MatrixMul(view_matrix_, mat); | 354 gvr::Mat4f mv = MatrixMul(view_matrix_, mat); |
318 gvr::Mat4f mvp = MatrixMul(projection_matrix_, mv); | 355 gvr::Mat4f mvp = MatrixMul(projection_matrix_, mv); |
319 vr_shell_renderer_->GetReticleRenderer()->Draw(mvp); | 356 vr_shell_renderer_->GetReticleRenderer()->Draw(mvp); |
320 | 357 |
321 // Draw the laser only for controllers. | 358 // Draw the laser only for controllers. |
322 if (!controller_active_) { | 359 if (!controller_active_) { |
323 return; | 360 return; |
324 } | 361 } |
325 // Find the length of the beam (from hand to target). | 362 // Find the length of the beam (from hand to target). |
326 float xdiff = (kHandPosition.x - look_at_vector_.x); | 363 float xdiff = (kHandPosition.x - look_at_vector_.x); |
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
471 const JavaParamRef<jobject>& content_web_contents, | 508 const JavaParamRef<jobject>& content_web_contents, |
472 jlong content_window_android) { | 509 jlong content_window_android) { |
473 content::ContentViewCore* c_core = content::ContentViewCore::FromWebContents( | 510 content::ContentViewCore* c_core = content::ContentViewCore::FromWebContents( |
474 content::WebContents::FromJavaWebContents(content_web_contents)); | 511 content::WebContents::FromJavaWebContents(content_web_contents)); |
475 return reinterpret_cast<intptr_t>(new VrShell( | 512 return reinterpret_cast<intptr_t>(new VrShell( |
476 env, obj, c_core, | 513 env, obj, c_core, |
477 reinterpret_cast<ui::WindowAndroid*>(content_window_android))); | 514 reinterpret_cast<ui::WindowAndroid*>(content_window_android))); |
478 } | 515 } |
479 | 516 |
480 } // namespace vr_shell | 517 } // namespace vr_shell |
OLD | NEW |