1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "chrome/browser/vr/elements/environment/stars.h"
6 
7 #include "base/numerics/math_constants.h"
8 #include "base/numerics/ranges.h"
9 #include "base/rand_util.h"
10 #include "base/stl_util.h"
11 #include "chrome/browser/vr/ui_element_renderer.h"
12 #include "chrome/browser/vr/ui_scene_constants.h"
13 #include "device/vr/vr_gl_util.h"
14 #include "ui/gfx/animation/tween.h"
15 
16 namespace vr {
17 
18 namespace {
19 constexpr size_t kNumStars = 500lu;
20 
21 // Position & opacity.
22 constexpr size_t kFloatsPerStarVertex = 5lu;
23 constexpr size_t kDataStride = kFloatsPerStarVertex * sizeof(float);
24 constexpr size_t kOpacityDataOffset = 3 * sizeof(float);
25 constexpr size_t kPhaseDataOffset = 4 * sizeof(float);
26 constexpr size_t kVerticesPerStar = 6lu;
27 constexpr size_t kTrianglesPerStar = kVerticesPerStar - 1lu;
28 
29 constexpr float kMinStarWidth = 0.002f;
30 constexpr float kMaxStarWidth = 0.007f;
31 
32 constexpr float kMaxStarDegrees = 70.0f;
33 constexpr float kOpacityNoiseScale = 5.0f;
34 
35 float g_vertices[kNumStars * kFloatsPerStarVertex * kVerticesPerStar];
36 GLushort g_indices[kNumStars * kTrianglesPerStar * 3lu];
37 
38 // clang-format off
39 static constexpr char const* kVertexShader = SHADER(
40   precision mediump float;
41   uniform mat4 u_ModelViewProjMatrix;
42   uniform float u_Time;
43   attribute vec4 a_Position;
44   attribute float a_Opacity;
45   attribute float a_Phase;
46   varying mediump float v_Opacity;
47 
48   float Twinkle(float t) {
49     return sin(t + 5.0 * cos(t + 3.0)) * 0.25 + 0.75;
50   }
51 
52   void main() {
53     float twinkle = 1.0;
54     v_Opacity = a_Opacity * Twinkle(u_Time + a_Phase);
55     gl_Position = u_ModelViewProjMatrix * a_Position;
56   }
57 );
58 
59 static constexpr char const* kFragmentShader = SHADER(
60   precision highp float;
61   varying mediump float v_Opacity;
62   void main() {
63     mediump vec4 color = vec4(1.0, 1.0, 1.0, 1.0);
64     // This is somewhat arbitrary, but makes the bright part of the star larger.
65     gl_FragColor = color * v_Opacity * v_Opacity;
66   }
67 );
68 // clang-format on
69 
70 }  // namespace
71 
72 Stars::Stars() = default;
73 Stars::~Stars() = default;
74 
Render(UiElementRenderer * renderer,const CameraModel & camera) const75 void Stars::Render(UiElementRenderer* renderer,
76                    const CameraModel& camera) const {
77   renderer->DrawStars((last_frame_time() - start_time_).InSecondsF(),
78                       camera.view_proj_matrix * world_space_transform());
79 }
80 
Initialize(SkiaSurfaceProvider * provider)81 void Stars::Initialize(SkiaSurfaceProvider* provider) {
82   start_time_ = base::TimeTicks::Now();
83 }
84 
Renderer()85 Stars::Renderer::Renderer() : BaseRenderer(kVertexShader, kFragmentShader) {
86   model_view_proj_matrix_handle_ =
87       glGetUniformLocation(program_handle_, "u_ModelViewProjMatrix");
88   time_handle_ = glGetUniformLocation(program_handle_, "u_Time");
89   opacity_handle_ = glGetAttribLocation(program_handle_, "a_Opacity");
90   phase_handle_ = glGetAttribLocation(program_handle_, "a_Phase");
91 }
92 
~Renderer()93 Stars::Renderer::~Renderer() {}
94 
95 // TODO(vollick): use time |t| to animate the stars.
Draw(float t,const gfx::Transform & view_proj_matrix)96 void Stars::Renderer::Draw(float t, const gfx::Transform& view_proj_matrix) {
97   glUseProgram(program_handle_);
98 
99   // Pass in model view project matrix.
100   glUniformMatrix4fv(model_view_proj_matrix_handle_, 1, false,
101                      MatrixToGLArray(view_proj_matrix).data());
102 
103   glUniform1f(time_handle_, t * 0.5);
104 
105   glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_);
106 
107   // Set up position attribute.
108   glVertexAttribPointer(position_handle_, 3, GL_FLOAT, false, kDataStride,
109                         VOID_OFFSET(0));
110   glEnableVertexAttribArray(position_handle_);
111 
112   // Set up opacity attribute.
113   glVertexAttribPointer(opacity_handle_, 1, GL_FLOAT, false, kDataStride,
114                         VOID_OFFSET(kOpacityDataOffset));
115   glEnableVertexAttribArray(opacity_handle_);
116 
117   // Set up phase attribute
118   glVertexAttribPointer(phase_handle_, 1, GL_FLOAT, false, kDataStride,
119                         VOID_OFFSET(kPhaseDataOffset));
120   glEnableVertexAttribArray(phase_handle_);
121 
122   glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_);
123   glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer_);
124 
125   glDrawElements(GL_TRIANGLES, base::size(g_indices), GL_UNSIGNED_SHORT, 0);
126 
127   glDisableVertexAttribArray(position_handle_);
128   glDisableVertexAttribArray(opacity_handle_);
129   glDisableVertexAttribArray(phase_handle_);
130 }
131 
132 GLuint Stars::Renderer::vertex_buffer_ = 0;
133 GLuint Stars::Renderer::index_buffer_ = 0;
134 
CreateBuffers()135 void Stars::Renderer::CreateBuffers() {
136   gfx::Point3F local_star_geometry[kVerticesPerStar];
137   for (size_t i = 1; i < kVerticesPerStar; ++i) {
138     float k = 2.0f / (kVerticesPerStar - 1.0f);
139     k *= i - 1;
140     local_star_geometry[i].set_x(cos(base::kPiFloat * k));
141     local_star_geometry[i].set_y(sin(base::kPiFloat * k));
142   }
143   size_t cur_vertex = 0;
144   size_t cur_index = 0;
145   for (size_t i = 0; i < kNumStars; ++i) {
146     float x_rot = gfx::Tween::FloatValueBetween(
147         base::RandDouble(), -kMaxStarDegrees, kMaxStarDegrees);
148     float y_rot = gfx::Tween::FloatValueBetween(
149         base::RandDouble(), -kMaxStarDegrees, kMaxStarDegrees);
150     float size = gfx::Tween::FloatValueBetween(base::RandDouble(),
151                                                kMinStarWidth, kMaxStarWidth);
152     float phase = gfx::Tween::FloatValueBetween(base::RandDouble(), 0.0f,
153                                                 2.0f * base::kPiFloat);
154     float opacity =
155         1.0 - gfx::Vector2dF(x_rot, y_rot).Length() / kMaxStarDegrees;
156 
157     float opacity_noise = (base::RandDouble() - 0.5);
158     opacity_noise *= opacity_noise * opacity_noise * kOpacityNoiseScale;
159     opacity = base::ClampToRange(opacity + opacity_noise, 0.0f, 1.0f);
160 
161     gfx::Transform local;
162     local.RotateAboutYAxis(x_rot);
163     local.RotateAboutXAxis(y_rot);
164     local.Translate3d({0, 0, -kSkyDistance});
165     local.Scale3d(size * kSkyDistance, size * kSkyDistance, 1.0f);
166     for (size_t j = 0; j < kVerticesPerStar - 1; j++, cur_index += 3) {
167       size_t j_next = (j + 1) % (kVerticesPerStar - 1);
168       g_indices[cur_index] = cur_vertex;
169       g_indices[cur_index + 1] = cur_vertex + j + 1;
170       g_indices[cur_index + 2] = cur_vertex + j_next + 1;
171     }
172     for (size_t j = 0; j < kVerticesPerStar; j++, cur_vertex++) {
173       gfx::Point3F p = local_star_geometry[j];
174       local.TransformPoint(&p);
175       g_vertices[cur_vertex * kFloatsPerStarVertex] = p.x();
176       g_vertices[cur_vertex * kFloatsPerStarVertex + 1] = p.y();
177       g_vertices[cur_vertex * kFloatsPerStarVertex + 2] = p.z();
178       g_vertices[cur_vertex * kFloatsPerStarVertex + 3] = j ? 0 : opacity;
179       g_vertices[cur_vertex * kFloatsPerStarVertex + 4] = phase;
180     }
181   }
182 
183   GLuint buffers[2];
184   glGenBuffers(2, buffers);
185   vertex_buffer_ = buffers[0];
186   index_buffer_ = buffers[1];
187 
188   glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_);
189   glBufferData(GL_ARRAY_BUFFER, base::size(g_vertices) * sizeof(float),
190                g_vertices, GL_STATIC_DRAW);
191 
192   glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer_);
193   glBufferData(GL_ELEMENT_ARRAY_BUFFER,
194                base::size(g_indices) * sizeof(GLushort), g_indices,
195                GL_STATIC_DRAW);
196 }
197 
198 }  // namespace vr
199