blob: 26ef20b433788ec1dc0939e0f480167c746f11ad [file] [log] [blame]
// Copyright 2018 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/environment/stars.h"
#include "base/numerics/math_constants.h"
#include "base/rand_util.h"
#include "base/stl_util.h"
#include "chrome/browser/vr/ui_element_renderer.h"
#include "chrome/browser/vr/ui_scene_constants.h"
#include "chrome/browser/vr/vr_gl_util.h"
#include "ui/gfx/animation/tween.h"
namespace vr {
namespace {
constexpr size_t kNumStars = 500lu;
// Position & opacity.
constexpr size_t kFloatsPerStarVertex = 5lu;
constexpr size_t kDataStride = kFloatsPerStarVertex * sizeof(float);
constexpr size_t kOpacityDataOffset = 3 * sizeof(float);
constexpr size_t kPhaseDataOffset = 4 * sizeof(float);
constexpr size_t kVerticesPerStar = 6lu;
constexpr size_t kTrianglesPerStar = kVerticesPerStar - 1lu;
constexpr float kMinStarWidth = 0.002f;
constexpr float kMaxStarWidth = 0.007f;
constexpr float kMaxStarDegrees = 70.0f;
constexpr float kOpacityNoiseScale = 5.0f;
float g_vertices[kNumStars * kFloatsPerStarVertex * kVerticesPerStar];
GLushort g_indices[kNumStars * kTrianglesPerStar * 3lu];
// clang-format off
static constexpr char const* kVertexShader = SHADER(
precision mediump float;
uniform mat4 u_ModelViewProjMatrix;
uniform float u_Time;
attribute vec4 a_Position;
attribute float a_Opacity;
attribute float a_Phase;
varying mediump float v_Opacity;
float Twinkle(float t) {
return sin(t + 5.0 * cos(t + 3.0)) * 0.25 + 0.75;
}
void main() {
float twinkle = 1.0;
v_Opacity = a_Opacity * Twinkle(u_Time + a_Phase);
gl_Position = u_ModelViewProjMatrix * a_Position;
}
);
static constexpr char const* kFragmentShader = SHADER(
precision highp float;
varying mediump float v_Opacity;
void main() {
mediump vec4 color = vec4(1.0, 1.0, 1.0, 1.0);
// This is somewhat arbitrary, but makes the bright part of the star larger.
gl_FragColor = color * v_Opacity * v_Opacity;
}
);
// clang-format on
} // namespace
Stars::Stars() = default;
Stars::~Stars() = default;
void Stars::Render(UiElementRenderer* renderer,
const CameraModel& camera) const {
renderer->DrawStars((last_frame_time() - start_time_).InSecondsF(),
camera.view_proj_matrix * world_space_transform());
}
void Stars::Initialize(SkiaSurfaceProvider* provider) {
start_time_ = base::TimeTicks::Now();
}
Stars::Renderer::Renderer() : BaseRenderer(kVertexShader, kFragmentShader) {
model_view_proj_matrix_handle_ =
glGetUniformLocation(program_handle_, "u_ModelViewProjMatrix");
time_handle_ = glGetUniformLocation(program_handle_, "u_Time");
opacity_handle_ = glGetAttribLocation(program_handle_, "a_Opacity");
phase_handle_ = glGetAttribLocation(program_handle_, "a_Phase");
}
Stars::Renderer::~Renderer() {}
// TODO(vollick): use time |t| to animate the stars.
void Stars::Renderer::Draw(float t, const gfx::Transform& view_proj_matrix) {
glUseProgram(program_handle_);
// Pass in model view project matrix.
glUniformMatrix4fv(model_view_proj_matrix_handle_, 1, false,
MatrixToGLArray(view_proj_matrix).data());
glUniform1f(time_handle_, t * 0.5);
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_);
// Set up position attribute.
glVertexAttribPointer(position_handle_, 3, GL_FLOAT, false, kDataStride,
VOID_OFFSET(0));
glEnableVertexAttribArray(position_handle_);
// Set up opacity attribute.
glVertexAttribPointer(opacity_handle_, 1, GL_FLOAT, false, kDataStride,
VOID_OFFSET(kOpacityDataOffset));
glEnableVertexAttribArray(opacity_handle_);
// Set up phase attribute
glVertexAttribPointer(phase_handle_, 1, GL_FLOAT, false, kDataStride,
VOID_OFFSET(kPhaseDataOffset));
glEnableVertexAttribArray(phase_handle_);
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer_);
glDrawElements(GL_TRIANGLES, base::size(g_indices), GL_UNSIGNED_SHORT, 0);
glDisableVertexAttribArray(position_handle_);
glDisableVertexAttribArray(opacity_handle_);
glDisableVertexAttribArray(phase_handle_);
}
GLuint Stars::Renderer::vertex_buffer_ = 0;
GLuint Stars::Renderer::index_buffer_ = 0;
void Stars::Renderer::CreateBuffers() {
gfx::Point3F local_star_geometry[kVerticesPerStar];
for (size_t i = 1; i < kVerticesPerStar; ++i) {
float k = 2.0f / (kVerticesPerStar - 1.0f);
k *= i - 1;
local_star_geometry[i].set_x(cos(base::kPiFloat * k));
local_star_geometry[i].set_y(sin(base::kPiFloat * k));
}
size_t cur_vertex = 0;
size_t cur_index = 0;
for (size_t i = 0; i < kNumStars; ++i) {
float x_rot = gfx::Tween::FloatValueBetween(
base::RandDouble(), -kMaxStarDegrees, kMaxStarDegrees);
float y_rot = gfx::Tween::FloatValueBetween(
base::RandDouble(), -kMaxStarDegrees, kMaxStarDegrees);
float size = gfx::Tween::FloatValueBetween(base::RandDouble(),
kMinStarWidth, kMaxStarWidth);
float phase = gfx::Tween::FloatValueBetween(base::RandDouble(), 0.0f,
2.0f * base::kPiFloat);
float opacity =
1.0 - gfx::Vector2dF(x_rot, y_rot).Length() / kMaxStarDegrees;
float opacity_noise = (base::RandDouble() - 0.5);
opacity_noise *= opacity_noise * opacity_noise * kOpacityNoiseScale;
opacity += opacity_noise;
opacity = std::min(1.0f, std::max(0.0f, opacity));
gfx::Transform local;
local.RotateAboutYAxis(x_rot);
local.RotateAboutXAxis(y_rot);
local.Translate3d({0, 0, -kSkyDistance});
local.Scale3d(size * kSkyDistance, size * kSkyDistance, 1.0f);
for (size_t j = 0; j < kVerticesPerStar - 1; j++, cur_index += 3) {
size_t j_next = (j + 1) % (kVerticesPerStar - 1);
g_indices[cur_index] = cur_vertex;
g_indices[cur_index + 1] = cur_vertex + j + 1;
g_indices[cur_index + 2] = cur_vertex + j_next + 1;
}
for (size_t j = 0; j < kVerticesPerStar; j++, cur_vertex++) {
gfx::Point3F p = local_star_geometry[j];
local.TransformPoint(&p);
g_vertices[cur_vertex * kFloatsPerStarVertex] = p.x();
g_vertices[cur_vertex * kFloatsPerStarVertex + 1] = p.y();
g_vertices[cur_vertex * kFloatsPerStarVertex + 2] = p.z();
g_vertices[cur_vertex * kFloatsPerStarVertex + 3] = j ? 0 : opacity;
g_vertices[cur_vertex * kFloatsPerStarVertex + 4] = phase;
}
}
GLuint buffers[2];
glGenBuffers(2, buffers);
vertex_buffer_ = buffers[0];
index_buffer_ = buffers[1];
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_);
glBufferData(GL_ARRAY_BUFFER, base::size(g_vertices) * sizeof(float),
g_vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer_);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
base::size(g_indices) * sizeof(GLushort), g_indices,
GL_STATIC_DRAW);
}
} // namespace vr