forked from hawksley/eleVR-Web-Player
-
Notifications
You must be signed in to change notification settings - Fork 1
/
index.html
executable file
·320 lines (284 loc) · 13.8 KB
/
index.html
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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
<!--
* eleVR Web Player: A web player for 360 video on the Oculus
* Copyright (C) 2014 Andrea Hawksley and Andrew Lutomirski
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-->
<!DOCTYPE html>
<html>
<head>
<title>eleVR Web Player</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" />
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-touch-fullscreen" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<link rel="icon" sizes="196x196" href="elelogo-square.png">
<!-- Fragment shader program -->
<script id="shader-fs" type="x-shader/x-fragment">
varying mediump vec3 vDirection;
uniform mediump float eye;
uniform mediump float projection;
uniform sampler2D uSampler;
#define PI 3.1415926535897932384626433832795
mediump float sinc(mediump float x) {
if (x == 0.) return 1.;
return sin(x) / x;
}
mediump vec4 directionToColor(mediump vec3 direction, mediump float eye, mediump float projection) {
/*
* Input: a direction. +x = right, +y = up, +z = backward.
* an eye. left = 0, right = 1.
* a projection. see ProjectionEnum in JS file for enum
* Output: a color from the video
*
* Bug alert: the control flow here may screw up texture filtering.
*/
if (projection == 2.) {
// Projection == 2: cube
mediump float scale = 0.99;
mediump float absx = abs(direction.x);
mediump float absy = abs(direction.y);
mediump float absz = abs(direction.z);
if ((absx >= absy) && (absx >= absz)) {
// x is biggest
if (direction.x >= 0.) {
// if +x is right then this is right, which seems to be (0,1)
// but with manualRotation defaulting to [0,1,0,0] this is left
return texture2D(uSampler, vec2((scale*direction.z / (2. * direction.x) + 1.5) / 3., (scale*direction.y / (2. * direction.x) + 1.5) / 2.)); // left
} else {
// if +x is right then this is left, which seems to be (1,1)
// but with manualRotation defaulting to [0,1,0,0] this is right
return texture2D(uSampler, vec2((scale*direction.z / (2. * direction.x) + 0.5) / 3., (scale*-direction.y / (2. * direction.x) + 1.5) / 2.)); // right
}
} else
if (absy >= absz) {
// y is biggest
if (direction.y >= 0.) {
// if +y is up then this is up, which seems to be (2,1)
return texture2D(uSampler, vec2((scale*-direction.x / (2. * direction.y) + 2.5) / 3., (scale*-direction.z / (2. * direction.y) + 1.5) / 2.)); // up
} else {
// if +y is up then this is down, which seems to be (0,0)
return texture2D(uSampler, vec2((scale*direction.x / (2. * direction.y) + 0.5) / 3., (scale*-direction.z / (2. * direction.y) + 0.5) / 2.)); // down
}
} else {
// z is biggest
if (direction.z >= 0.) {
// if +z is backward then this is backward, which seems to be (2,0)
// but with manualRotation defaulting to [0,1,0,0] this is forward
//return vec4(0., 0., 0.25, 0.);
return texture2D(uSampler, vec2((scale*-direction.x / (2. * direction.z) + 1.5) / 3., (scale*direction.y / (2. * direction.z) + 0.5) / 2.)); // forward
} else {
// if +z is backward then this is forward, which seems to be (1,0)
// but with manualRotation defaulting to [0,1,0,0] this is backward
return texture2D(uSampler, vec2((scale*-direction.x / (2. * direction.z) + 2.5) / 3., (scale*-direction.y / (2. * direction.z) + 0.5) / 2.)); // backward
}
}
} else {
mediump float theta = atan(direction.x, -1.0 * direction.z);
mediump float phi = atan(direction.y, length(direction.xz));
/*
* The Nexus 7 and the Moto X (and possibly many others) have
* a buggy atan2 implementation that screws up when the numerator
* (the first argument) is too close to zero. (The 1e-4 is carefully
* chosen: 1e-5 doesn't fix the problem.
*/
if (abs(direction.x) < 1e-4 * abs(direction.z))
theta = 0.5*PI * (1.0 - sign(-1.0 * direction.z));
if (abs(direction.y) < 1e-4 * length(direction.xz))
phi = 0.0;
// Uncomment to debug the transformations.
// return vec4(theta / (2. * PI) + 0.5, phi / (2. * PI) + 0.5, 0., 0.);
if (projection == 4.) {
// try Kavrayskiy VII projection
//mediump float u = 3.*theta/2.*sqrt(1./3.-(phi*phi/(PI*PI)));
//mediump float v = phi;
//mediump float k = -0.15;
// try Wagner VI projection
//mediump float u = theta*sqrt(1.-(3.*phi*phi/(PI*PI)));
//mediump float v = phi;
//mediump float k = -0.2;
// try Winkel tripel projection
mediump float u = min(1.18,0.5*(theta*2./PI+2.*cos(phi)*sin(theta/2.)/sinc(acos(cos(phi)*cos(theta/2.)))));
mediump float v = 0.5*(phi + sin(phi)/sinc(acos(cos(phi)*cos(theta/2.))));
mediump float r = sqrt(u*u + v*v);
//mediump float k = 0.31;
//mediump float d = (0.5 + r * k); //(1. + r * k);
mediump float k = -0.1;
mediump float d = (1. + r * k);
return texture2D(uSampler, vec2((d*u+1.)/2./2.,(d*v/2.)+0.5));
} else
if (projection == 5.) {
// Projection == 5: equirectangular projection, pincushion distortion
mediump float u = mod(theta / (2.0*PI), 1.0) * 2. - 1.; // -1 to 1
mediump float v = phi / PI * 2.; // -1 to 1
mediump float d = sqrt(u*u + v*v) / sqrt(2.) * 2.;
mediump float r = 1.;
if (d != 0.) {
r = atan(d) / d;
}
return texture2D(uSampler, vec2((r*u+1.)/2.,(r*v/2.)+0.5));
} else
if (projection == 6.) {
// Projection == 6: equirectangular projection, barrel distortion
mediump float u = mod(theta / (2.0*PI), 1.0) * 2. - 1.; // -1 to 1
mediump float v = phi / PI * 2.; // -1 to 1
mediump float r = 1. + (u*u + v*v) * 2.; // k
return texture2D(uSampler, vec2((r*u+1.)/2.,(r*v/2.)+0.5));
} else
if (projection == 7.) {
// Projection == 7: cylindrical, top-bottom
mediump float u = mod(theta / (2.0*PI), 1.0) * 2. - 1.; // -1 to 1
mediump float v = phi / PI * 3.; // -1.5 to -1.5
if ((v < -0.5) || (v >= 0.5))
return vec4(0.,0.,0.,0.);
else
if (u < 0.)
return texture2D(uSampler, vec2(u+1., (v/2.)+0.75));
else
return texture2D(uSampler, vec2(u,(v/2.)+0.25));
} else
if (projection == 8.) {
// Projection == 8: Theta S dual fisheye
// FIXME: experimentally determined; manufacturer info may help?
mediump float FOV = PI * 195. / 180.; // FOV of the fisheye
mediump float width = 1.0;
mediump float u, v;
if (direction.z >= 0.) {
theta = atan(-direction.y, direction.x);
phi = atan(length(direction.xy), direction.z);
mediump float r = width * phi / FOV;
v = 0.99999999 - 0.5 * width + r * cos(theta);
u = 0.99999999 - (0.5 * width + r * sin(theta)) * 0.5;
// FIXME: experimentally determined; manufacturer info may help?
u = u * 0.93333333 + 0.050;
v = v * 0.85 + 0.131;
} else {
theta = atan(direction.y, direction.x);
phi = atan(length(direction.xy), -direction.z);
mediump float r = width * phi / FOV;
v = 0.99999999 - 0.5 * width + r * cos(theta);
u = 0.5 - (0.5 * width + r * sin(theta)) * 0.5;
// FIXME: experimentally determined; manufacturer info may help?
u = u * 0.93333333 + 0.0167;
v = v * 0.85 + 0.131;
}
return texture2D(uSampler, vec2(u, v));
} else
if (projection == 0.) {
// Projection == 0: equirectangular projection
return texture2D(uSampler, vec2(mod(theta / (2.0*PI), 1.0), phi / PI + 0.5));
} else
if (projection == 3.) {
// Projection == 3: 180 3D side-by-side
return texture2D(uSampler, vec2((max(0.,min(theta / PI, 1.0)) + eye) / 2., phi / PI + 0.5));
} else {
// Projection == 1: equirectangular top/bottom 3D projection
eye = 1. - eye;
return texture2D(uSampler, vec2(mod(theta / (2.0*PI), 1.0), ((phi / PI + 0.5) + eye)/ 2.));
}
}
}
void main(void) {
gl_FragColor = directionToColor(vDirection, eye, projection);
}
</script>
<!-- Vertex shader program -->
<script id="shader-vs" type="x-shader/x-vertex">
attribute mediump vec2 aVertexPosition;
uniform mediump mat4 proj_inv;
varying mediump vec3 vDirection;
void main(void) {
gl_Position = vec4(aVertexPosition, 1.0, 1.0);
mediump vec4 projective_direction = proj_inv * gl_Position;
vDirection = projective_direction.xyz / projective_direction.w;
}
</script>
<link rel="stylesheet" href="css/font-awesome.css">
<link rel="stylesheet" href="css/elevr-player.css">
<script src="lib/gl-matrix.js" type="text/javascript"></script>
<script src="lib/util.js" type="text/javascript"></script>
<script src="js/controls.js" type="text/javascript"></script>
<script src="js/player-webgl.js" type="text/javascript"></script>
<script src="js/webvr.js" type="text/javascript"></script>
<script src="js/phonevr.js" type="text/javascript"></script>
<script src="js/elevr-player.js" type="text/javascript"></script>
<!-- push a change right before lab week demo? fine, will use my own... script src="http://dailymotion.github.io/hls.js/dist/hls.min.js" type="text/javascript"></script-->
<script src="js/hls.min.js" type="text/javascript"></script>
</head>
<body style="background:#000">
<div id="video-container">
<!-- Loading Message -->
<div id="left-load" class="left">
<div id="title-l" class="title">Loading Video...</div>
<div id="message-l" class="message hidden">Try WASD + Q/E</div>
</div>
<div id="right-load" class="right">
<div id="title-r" class="title">Loading Video...</div>
<div id="message-r" class="message hidden">Try WASD + Q/E</div>
</div>
<div id="left-play" class="left hidden">
<a id="play-l" class="large-play fa fa-play fa-5x"></a>
</div>
<div id="right-play" class="right hidden">
<a id="play-r" class="large-play fa fa-play fa-5x"></a>
</div>
<canvas id="glcanvas">
Your browser doesn't appear to support the HTML5 <code><canvas></code> element.
</canvas>
<video class="hidden" preload="auto" id="video" loop="true" webkit-playsinline crossOrigin="anonymous">
<!--
<source src="therelaxatron2.mp4" type="video/mp4">
<source src="therelaxatron.webm" type="video/webm">
-->
</video>
<!-- Video Controls -->
<div id="video-controls" class="hidden">
<a id="play-pause" class="fa fa-play icon" title="Play"></a>
<input type="range" id="seek-bar" value="0">
<a id="loop" class="fa fa-chain-broken icon" title="Stop Looping"></a>
<a id="mute" class="fa fa-volume-up icon" title="Mute"></a>
<a id="select-local-file" class="fa fa-folder-open icon rfloat" title="Select File"></a>
<select id="projection-select" class="rfloat">
<option value=0>Equirectangular</option>
<option value=1>Equirectangular 3D</option>
<option value=2>Cube</option>
</select>
<select id="video-select" class="rfloat">
<!--
<option value="0therelaxatron2.mp4">The Relaxatron (mp4)</option>
<option value="0therelaxatron.webm">The Relaxatron (webm)</option>
<option value="1Vidcon5.mp4">Vidcon (mp4)</option>
<option value="1Vidcon.webm">Vidcon (webm)</option>
-->
</select>
<a id="full-screen" class="fa fa-expand icon rfloat" title="Full Screen"></a>
</div>
<script>
runEleVRPlayer();
if (typeof window.vrHMD === "undefined") {
document.getElementById("left-load").style.left="0";
document.getElementById("left-play").style.left="0";
document.getElementById("left-load").style.width="100%";
document.getElementById("left-play").style.width="100%";
document.getElementById("right-load").style.right="0";
document.getElementById("right-play").style.right="0";
document.getElementById("right-load").style.width="0";
document.getElementById("right-play").style.width="0";
}
</script>
</div>
</body></html>