• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 Google, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <cassert>
18 #include <cmath>
19 #include <array>
20 #include <glm/gtc/matrix_transform.hpp>
21 #include "Simulation.h"
22 
23 namespace {
24 
25 class MeshPicker {
26 public:
MeshPicker()27     MeshPicker() :
28         pattern_({
29                 Meshes::MESH_PYRAMID,
30                 Meshes::MESH_ICOSPHERE,
31                 Meshes::MESH_TEAPOT,
32                 Meshes::MESH_PYRAMID,
33                 Meshes::MESH_ICOSPHERE,
34                 Meshes::MESH_PYRAMID,
35                 Meshes::MESH_PYRAMID,
36                 Meshes::MESH_PYRAMID,
37                 Meshes::MESH_PYRAMID,
38                 Meshes::MESH_PYRAMID,
39                 }), cur_(-1)
40     {
41     }
42 
pick()43     Meshes::Type pick()
44     {
45         cur_ = (cur_ + 1) % pattern_.size();
46         return pattern_[cur_];
47     }
48 
scale(Meshes::Type type) const49     float scale(Meshes::Type type) const
50     {
51         float base = 0.005f;
52 
53         switch (type) {
54         case Meshes::MESH_PYRAMID:
55         default:
56             return base * 1.0f;
57         case Meshes::MESH_ICOSPHERE:
58             return base * 3.0f;
59         case Meshes::MESH_TEAPOT:
60             return base * 10.0f;
61         }
62     }
63 
64 private:
65     const std::array<Meshes::Type, 10> pattern_;
66     int cur_;
67 };
68 
69 class ColorPicker {
70 public:
ColorPicker(unsigned int rng_seed)71     ColorPicker(unsigned int rng_seed) :
72         rng_(rng_seed),
73         red_(0.0f, 1.0f),
74         green_(0.0f, 1.0f),
75         blue_(0.0f, 1.0f)
76     {
77     }
78 
pick()79     glm::vec3 pick()
80     {
81         return glm::vec3{ red_(rng_),
82                           green_(rng_),
83                           blue_(rng_) };
84     }
85 
86 private:
87     std::mt19937 rng_;
88     std::uniform_real_distribution<float> red_;
89     std::uniform_real_distribution<float> green_;
90     std::uniform_real_distribution<float> blue_;
91 };
92 
93 } // namespace
94 
Animation(unsigned int rng_seed,float scale)95 Animation::Animation(unsigned int rng_seed, float scale)
96     : rng_(rng_seed), dir_(-1.0f, 1.0f), speed_(0.1f, 1.0f)
97 {
98     float x = dir_(rng_);
99     float y = dir_(rng_);
100     float z = dir_(rng_);
101     if (std::abs(x) + std::abs(y) + std::abs(z) == 0.0f)
102         x = 1.0f;
103 
104     current_.axis = glm::normalize(glm::vec3(x, y, z));
105 
106     current_.speed = speed_(rng_);
107     current_.scale = scale;
108 
109     current_.matrix = glm::scale(glm::mat4(1.0f), glm::vec3(current_.scale));
110 }
111 
transformation(float t)112 glm::mat4 Animation::transformation(float t)
113 {
114     current_.matrix = glm::rotate(current_.matrix, current_.speed * t, current_.axis);
115 
116     return current_.matrix;
117 }
118 
119 class Curve {
120 public:
~Curve()121     virtual ~Curve() {}
122     virtual glm::vec3 evaluate(float t) = 0;
123 };
124 
125 namespace {
126 
127 enum CurveType {
128     CURVE_RANDOM,
129     CURVE_CIRCLE,
130     CURVE_COUNT,
131 };
132 
133 class RandomCurve : public Curve {
134 public:
RandomCurve(unsigned int rng_seed)135     RandomCurve(unsigned int rng_seed)
136         : rng_(rng_seed), direction_(-0.3f, 0.3f), duration_(1.0f, 5.0f),
137           segment_start_(0.0f), segment_direction_(0.0f),
138           time_start_(0.0f), time_duration_(0.0f)
139     {
140     }
141 
evaluate(float t)142     glm::vec3 evaluate(float t)
143     {
144         if (t >= time_start_ + time_duration_)
145             new_segment(t);
146 
147         pos_ += unit_dir_ * (t - last_);
148         last_ = t;
149 
150         return pos_;
151     }
152 
153 private:
new_segment(float time_start)154     void new_segment(float time_start)
155     {
156         segment_start_ += segment_direction_;
157         segment_direction_ = glm::vec3(direction_(rng_),
158                                        direction_(rng_),
159                                        direction_(rng_));
160 
161         time_start_ = time_start;
162         time_duration_ = duration_(rng_);
163 
164         unit_dir_ = segment_direction_ / time_duration_;
165         pos_ = segment_start_;
166         last_ = time_start_;
167     }
168 
169     std::mt19937 rng_;
170     std::uniform_real_distribution<float> direction_;
171     std::uniform_real_distribution<float> duration_;
172 
173     glm::vec3 segment_start_;
174     glm::vec3 segment_direction_;
175     float time_start_;
176     float time_duration_;
177 
178     glm::vec3 unit_dir_;
179     glm::vec3 pos_;
180     float last_;
181 };
182 
183 class CircleCurve : public Curve {
184 public:
CircleCurve(float radius,glm::vec3 axis)185     CircleCurve(float radius, glm::vec3 axis)
186         : r_(radius)
187     {
188         glm::vec3 a;
189 
190         if (axis.x != 0.0f) {
191             a.x = -axis.z / axis.x;
192             a.y = 0.0f;
193             a.z = 1.0f;
194         } else if (axis.y != 0.0f) {
195             a.x = 1.0f;
196             a.y = -axis.x / axis.y;
197             a.z = 0.0f;
198         } else {
199             a.x = 1.0f;
200             a.y = 0.0f;
201             a.z = -axis.x / axis.z;
202         }
203 
204         a_ = glm::normalize(a);
205         b_ = glm::normalize(glm::cross(a_, axis));
206     }
207 
evaluate(float t)208     glm::vec3 evaluate(float t)
209     {
210         return (a_ * (glm::vec3(std::cos(t)) - glm::vec3(1.0f)) + b_ * glm::vec3(std::sin(t))) *
211             glm::vec3(r_);
212     }
213 
214 private:
215     float r_;
216     glm::vec3 a_;
217     glm::vec3 b_;
218 };
219 
220 } // namespace
221 
Path(unsigned int rng_seed)222 Path::Path(unsigned int rng_seed)
223     : rng_(rng_seed), type_(0, CURVE_COUNT - 1), duration_(5.0f, 20.0f)
224 {
225     // trigger a subpath generation
226     current_.end = -1.0f;
227     current_.now = 0.0f;
228 }
229 
position(float t)230 glm::vec3 Path::position(float t)
231 {
232     current_.now += t;
233 
234     while (current_.now >= current_.end)
235         generate_subpath();
236 
237     return current_.origin + current_.curve->evaluate(current_.now - current_.start);
238 }
239 
generate_subpath()240 void Path::generate_subpath()
241 {
242     float duration = duration_(rng_);
243     CurveType type = static_cast<CurveType>(type_(rng_));
244 
245     if (current_.curve) {
246         current_.origin += current_.curve->evaluate(current_.end - current_.start);
247         current_.start = current_.end;
248     } else {
249         std::uniform_real_distribution<float> origin(0.0f, 2.0f);
250         current_.origin = glm::vec3(origin(rng_), origin(rng_), origin(rng_));
251         current_.start = current_.now;
252     }
253 
254     current_.end = current_.start + duration;
255 
256     Curve *curve;
257 
258     switch (type) {
259     case CURVE_RANDOM:
260         curve = new RandomCurve(rng_());
261         break;
262     case CURVE_CIRCLE:
263         {
264             std::uniform_real_distribution<float> dir(-1.0f, 1.0f);
265             glm::vec3 axis(dir(rng_), dir(rng_), dir(rng_));
266             if (axis.x == 0.0f && axis.y == 0.0f && axis.z == 0.0f)
267                 axis.x = 1.0f;
268 
269             std::uniform_real_distribution<float> radius_(0.02f, 0.2f);
270             curve = new CircleCurve(radius_(rng_), axis);
271         }
272         break;
273     default:
274         assert(!"unreachable");
275         curve = nullptr;
276         break;
277     }
278 
279     current_.curve.reset(curve);
280 }
281 
Simulation(int object_count)282 Simulation::Simulation(int object_count)
283     : random_dev_()
284 {
285     MeshPicker mesh;
286     ColorPicker color(random_dev_());
287 
288     objects_.reserve(object_count);
289     for (int i = 0; i < object_count; i++) {
290         Meshes::Type type = mesh.pick();
291         float scale = mesh.scale(type);
292 
293         objects_.emplace_back(Object{
294             type, glm::vec3(0.5f + 0.5f * (float)i / object_count),
295             color.pick(), Animation(random_dev_(), scale), Path(random_dev_()),
296         });
297     }
298 }
299 
set_frame_data_size(uint32_t size)300 void Simulation::set_frame_data_size(uint32_t size)
301 {
302     uint32_t offset = 0;
303     for (auto &obj : objects_) {
304         obj.frame_data_offset = offset;
305         offset += size;
306     }
307 }
308 
update(float time,int begin,int end)309 void Simulation::update(float time, int begin, int end)
310 {
311     for (int i = begin; i < end; i++) {
312         auto &obj = objects_[i];
313 
314         glm::vec3 pos = obj.path.position(time);
315         glm::mat4 trans = obj.animation.transformation(time);
316         obj.model = glm::translate(glm::mat4(1.0f), pos) * trans;
317     }
318 }
319