1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
|
/* Logic for levels, where each level contains all the objects that a scene needs */
/* Global variables */
stars = [];
blackHoles = [];
animations = [];
starsBuf = [];
blackHolesBuf = [];
levels = [];
var startT = -1;
/* Star "class" */
Star = function(center, size, starsBuf) {
if (starsBuf.length == STAR_MAX_COUNT)
throw 'Error: cannot add more stars, limit of ' + STAR_MAX_COUNT + ' reached!'
this.sphere = new Sphere(center, size);
this.sphere.color = STAR_COLOR;
this.index = starsBuf.push([]) - 1;
this.center = center;
this.sphere.center = center;
starsBuf[this.index] = center.concat(this.sphere.size);
}
Star.prototype.moveTo = function(newCenter, starsBuf) {
this.sphere.center = newCenter;
starsBuf[this.index] = newCenter.concat(this.sphere.size);
gl.uniform4fv(gl.getUniformLocation(glprog, 'uStars[' + this.index + ']'), starsBuf[this.index]);
}
Star.prototype.draw = function() {
this.sphere.draw();
}
/* BlackHole "class" */
BlackHole = function(center, size, blackHolesBuf) {
if (blackHolesBuf.length == BLACKHOLE_MAX_COUNT)
throw 'Error: cannot add more black holes, limit of ' + BLACKHOLE_MAX_COUNT + ' reached!'
this.rs = size / 3;
this.index = blackHolesBuf.push([]) - 1;
this.center = center;
blackHolesBuf[this.index] = center.concat(this.rs);
}
BlackHole.prototype.moveTo = function(newCenter, blackHolesBuf) {
blackHolesBuf[this.index] = newCenter.concat(this.rs);
gl.uniform4fv(gl.getUniformLocation(glprog, 'uBH[' + this.index + ']'), blackHolesBuf[this.index]);
}
BlackHole.prototype.draw = function() {
// Black holes are not "drawn"
// But I'm keeping that function in case I put blackHole.draw() by accident
}
/* Level "class" */
Level = function(name, description, cameraCoords) {
this.name = name;
this.description = description;
this.cameraCoords = cameraCoords;
this.stars = [];
this.blackHoles = [];
this.animations = [];
this.starsBuf = [];
this.blackHolesBuf = [];
levels.push(this);
}
Level.prototype.addStar = function(center, size, animation) {
var star = new Star(center, size, this.starsBuf);
this.stars.push(star);
if (animation) this.animations.push((t) => star.moveTo(animation(t, star), this.starsBuf));
}
Level.prototype.addBlackHole = function(center, size, animation) {
var bh = new BlackHole(center, size, this.blackHolesBuf);
this.blackHoles.push(bh);
if (animation) this.animations.push((t) => bh.moveTo(animation(t, bh), this.blackHolesBuf));
}
Level.prototype.load = function() {
stars = this.stars;
blackHoles = this.blackHoles;
starsBuf = this.starsBuf;
blackHolesBuf = this.blackHolesBuf;
animations = this.animations;
pos = this.cameraCoords;
initCameraVectors();
for (var i = 0; i < STAR_MAX_COUNT; i++) {
var val = (i < starsBuf.length) ? starsBuf[i] : [0,0,0,0];
gl.uniform4fv(gl.getUniformLocation(glprog, 'uStars[' + i + ']'), val);
}
for (var i = 0; i < BLACKHOLE_MAX_COUNT; i++) {
var val = (i < blackHolesBuf.length) ? blackHolesBuf[i] : [0,0,0,0];
gl.uniform4fv(gl.getUniformLocation(glprog, 'uBH[' + i + ']'), val);
}
startT = -1;
}
/* Our levels, this is ran in init() */
function createLevels() {
var l1 = new Level(
"Star passing behind black hole",
"You can see how the black hole (correctly) warps the light of the star, when it passes from behind.",
[1000,0,650]);
l1.addStar([1100,0,1000], 10, (t, star) => vecSum(star.center, [-100 * (1 + Math.sin(t/30 + 1.5 * Math.PI)),0,0]));
l1.addBlackHole([1000,0,900], 30, undefined);
var l2 = new Level(
"Star gets closer to event horizon",
"Now the camera is very close to the event horizon, looking at the same direction as the previous level. As the star passes behind the black hole, we can see it approaching the event horizon, however, it will never pass it and will continue becoming thinner and taller (at least until we can calculate and show it).",
[1014,0,892]);
l2.addStar([1070,0,1000], 10, (t, star) => vecSum(star.center, [-t,0,0]));
l2.addBlackHole([1000,0,900], 30, undefined);
var l3 = new Level(
"Star behind black hole",
"The star is behind the black hole and it's going fruther away from the camera and then closer. The star itself is always much smaller than the center of the black hole (that swallows all light), but we can still see parts of it thanks to the gravitational lensing.",
[1000,0,650]);
l3.addStar([1000,0,1000], 10, (t, star) => vecSum(star.center, [0,0,-36 * (1 + Math.sin(t/10 + 1.5 * Math.PI))]));
l3.addBlackHole([1000,0,900], 30, undefined);
var l4 = new Level(
"Star, orbiting a black hole",
"We can see how if we look at a star, orbiting the black hole, from an angle, we'll see the bottom and top part of the distorted light be disjoint and how the bottom part moves in the opposite direction to the orbit.",
[1000,0,650]);
var speed = Math.PI / 20, rad = 40;
l4.addStar([1000+rad,0,900], 3,
(t, star) => vecSum([1000,0,900], [Math.cos(t*speed) * rad,
Math.sin(t*speed) * 5,
Math.sin(t*speed) * rad]));
l4.addBlackHole([1000,0,900], 35, undefined);
var l5 = new Level(
"Star ring, orbiting around the black hole",
"Similarly to a black hole with an accretion disk, like the one in the movie Interstellar, we can see how it looks as if the stars in the back warp and hop over the black hole, and how there is something of a half-circle on the bottom of the black hole, that starts from behind it.",
[1000,0,650]);
speed = Math.PI / 10;
for (var i = 0; i < 2 * Math.PI; i += Math.PI / 7) {
// I'm kinda cheating here, since I use the star's coordinates to store i
// but passing i to the lambda function always passes by refrence, no matter what I do
l5.addStar([1000,i,900], 3,
(t, star) => vecSum([1000,0,900], [Math.cos(star.center[1] + t*speed) * rad,
Math.sin(star.center[1] + t*speed) * 5,
Math.sin(star.center[1] + t*speed) * rad]));
}
l5.addBlackHole([1000,0,900], 35, undefined);
}
|