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