| // Copyright 2017 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/vr/elements/reticle.h" |
| |
| #include "base/numerics/math_constants.h" |
| #include "chrome/browser/vr/model/model.h" |
| #include "chrome/browser/vr/ui_element_renderer.h" |
| #include "chrome/browser/vr/ui_scene.h" |
| #include "chrome/browser/vr/ui_scene_constants.h" |
| #include "chrome/browser/vr/vr_gl_util.h" |
| |
| namespace vr { |
| |
| namespace { |
| |
| // clang-format off |
| static constexpr char const* kVertexShader = SHADER( |
| precision mediump float; |
| uniform mat4 u_ModelViewProjMatrix; |
| attribute vec4 a_Position; |
| varying vec2 v_TexCoordinate; |
| |
| void main() { |
| v_TexCoordinate = vec2(0.5 + a_Position[0], 0.5 - a_Position[1]); |
| gl_Position = u_ModelViewProjMatrix * a_Position; |
| } |
| ); |
| |
| static constexpr char const* kFragmentShader = SHADER( |
| precision mediump float; |
| varying mediump vec2 v_TexCoordinate; |
| uniform lowp vec4 color; |
| uniform mediump float ring_diameter; |
| uniform mediump float inner_hole; |
| uniform mediump float inner_ring_end; |
| uniform mediump float inner_ring_thickness; |
| uniform mediump float mid_ring_end; |
| uniform mediump float mid_ring_opacity; |
| uniform mediump float opacity; |
| |
| void main() { |
| mediump float r = length(v_TexCoordinate - vec2(0.5, 0.5)); |
| mediump float color_radius = inner_ring_end * ring_diameter; |
| mediump float color_feather_radius = inner_ring_thickness * ring_diameter; |
| mediump float hole_radius = |
| inner_hole * ring_diameter - color_feather_radius; |
| mediump float color1 = clamp( |
| 1.0 - (r - color_radius) / color_feather_radius, 0.0, 1.0); |
| mediump float hole_alpha = |
| clamp((r - hole_radius) / color_feather_radius, 0.0, 1.0); |
| |
| mediump float black_radius = mid_ring_end * ring_diameter; |
| mediump float black_feather = |
| 1.0 / (ring_diameter * 0.5 - black_radius); |
| mediump float black_alpha_factor = |
| mid_ring_opacity * (1.0 - (r - black_radius) * black_feather); |
| mediump float alpha = clamp( |
| min(hole_alpha, max(color1, black_alpha_factor)) * opacity, 0.0, 1.0); |
| lowp vec3 color_rgb = color1 * color.xyz; |
| gl_FragColor = vec4(color_rgb * color.w * alpha, color.w * alpha); |
| } |
| ); |
| // clang-format on |
| |
| static constexpr float kRingDiameter = 1.0f; |
| static constexpr float kInnerHole = 0.0f; |
| static constexpr float kInnerRingEnd = 0.177f; |
| static constexpr float kInnerRingThickness = 0.14f; |
| static constexpr float kMidRingEnd = 0.177f; |
| static constexpr float kMidRingOpacity = 0.22f; |
| static constexpr float kReticleColor[] = {1.0f, 1.0f, 1.0f, 1.0f}; |
| |
| } // namespace |
| |
| Reticle::Reticle(UiScene* scene, Model* model) : scene_(scene), model_(model) { |
| SetName(kReticle); |
| SetDrawPhase(kPhaseForeground); |
| set_hit_testable(false); |
| SetVisible(true); |
| } |
| |
| Reticle::~Reticle() = default; |
| |
| UiElement* Reticle::TargetElement() const { |
| return scene_->GetUiElementById(model_->reticle.target_element_id); |
| } |
| |
| void Reticle::Render(UiElementRenderer* renderer, |
| const CameraModel& model) const { |
| // Scale the reticle to have a fixed FOV size at any distance. |
| const float eye_to_target = |
| std::sqrt(model_->reticle.target_point.SquaredDistanceTo(kOrigin)); |
| |
| gfx::Transform mat; |
| mat.Scale3d(kReticleWidth * eye_to_target, kReticleHeight * eye_to_target, 1); |
| |
| gfx::Quaternion rotation; |
| |
| UiElement* target = TargetElement(); |
| if (target) { |
| // Make the reticle planar to the element it's hitting. |
| rotation = gfx::Quaternion(gfx::Vector3dF(0.0f, 0.0f, -1.0f), |
| -target->GetNormal()); |
| } else { |
| // Rotate the reticle to directly face the eyes. |
| rotation = gfx::Quaternion(gfx::Vector3dF(0.0f, 0.0f, -1.0f), |
| model_->reticle.target_point - kOrigin); |
| } |
| gfx::Transform rotation_mat(rotation); |
| mat = rotation_mat * mat; |
| |
| mat.matrix().postTranslate(model_->reticle.target_point.x(), |
| model_->reticle.target_point.y(), |
| model_->reticle.target_point.z()); |
| gfx::Transform transform = |
| model.view_proj_matrix * world_space_transform() * mat; |
| renderer->DrawReticle(computed_opacity(), transform); |
| } |
| |
| Reticle::Renderer::Renderer() |
| : BaseQuadRenderer(kVertexShader, kFragmentShader) { |
| model_view_proj_matrix_handle_ = |
| glGetUniformLocation(program_handle_, "u_ModelViewProjMatrix"); |
| color_handle_ = glGetUniformLocation(program_handle_, "color"); |
| ring_diameter_handle_ = |
| glGetUniformLocation(program_handle_, "ring_diameter"); |
| inner_hole_handle_ = glGetUniformLocation(program_handle_, "inner_hole"); |
| inner_ring_end_handle_ = |
| glGetUniformLocation(program_handle_, "inner_ring_end"); |
| inner_ring_thickness_handle_ = |
| glGetUniformLocation(program_handle_, "inner_ring_thickness"); |
| mid_ring_end_handle_ = glGetUniformLocation(program_handle_, "mid_ring_end"); |
| mid_ring_opacity_handle_ = |
| glGetUniformLocation(program_handle_, "mid_ring_opacity"); |
| opacity_handle_ = glGetUniformLocation(program_handle_, "opacity"); |
| } |
| |
| Reticle::Renderer::~Renderer() = default; |
| |
| void Reticle::Renderer::Draw(float opacity, |
| const gfx::Transform& view_proj_matrix) { |
| PrepareToDraw(model_view_proj_matrix_handle_, view_proj_matrix); |
| |
| glUniform4f(color_handle_, kReticleColor[0], kReticleColor[1], |
| kReticleColor[2], kReticleColor[3]); |
| glUniform1f(ring_diameter_handle_, kRingDiameter); |
| glUniform1f(inner_hole_handle_, kInnerHole); |
| glUniform1f(inner_ring_end_handle_, kInnerRingEnd); |
| glUniform1f(inner_ring_thickness_handle_, kInnerRingThickness); |
| glUniform1f(mid_ring_end_handle_, kMidRingEnd); |
| glUniform1f(mid_ring_opacity_handle_, kMidRingOpacity); |
| glUniform1f(opacity_handle_, opacity); |
| |
| glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer_); |
| glDrawElements(GL_TRIANGLES, BaseQuadRenderer::NumQuadIndices(), |
| GL_UNSIGNED_SHORT, 0); |
| |
| glDisableVertexAttribArray(position_handle_); |
| } |
| |
| const char* Reticle::Renderer::VertexShader() { |
| return kVertexShader; |
| } |
| |
| } // namespace vr |