├── tmp
└── .gitignore
├── online
├── assets
│ ├── data
│ │ └── .gitignore
│ ├── js
│ │ └── .gitignore
│ ├── img
│ │ ├── perlin-512.png
│ │ ├── waternormals.jpg
│ │ ├── star_preview3.png
│ │ ├── skybox3-hr
│ │ │ ├── skybox_0.png
│ │ │ ├── skybox_1.png
│ │ │ ├── skybox_2.png
│ │ │ ├── skybox_3.png
│ │ │ ├── skybox_4.png
│ │ │ └── skybox_5.png
│ │ └── skybox3-lr
│ │ │ ├── skybox_0.png
│ │ │ ├── skybox_1.png
│ │ │ ├── skybox_2.png
│ │ │ ├── skybox_3.png
│ │ │ ├── skybox_4.png
│ │ │ └── skybox_5.png
│ └── src
│ │ ├── config
│ │ └── WebVRConfig.js
│ │ ├── vendor
│ │ ├── modernizr
│ │ │ └── modernizr-custom.js
│ │ ├── three
│ │ │ └── examples
│ │ │ │ └── js
│ │ │ │ └── controls
│ │ │ │ └── MouseControls.js
│ │ ├── zz85
│ │ │ └── SkyShader.js
│ │ └── charliehoey
│ │ │ └── GPUParticleSystem.js
│ │ └── index.js
├── .htaccess
├── bower.json
├── index.html
├── package.json
└── webpack.config.js
├── .gitignore
├── scripts
├── setup.py
└── csv-to-json.py
└── README.md
/tmp/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
--------------------------------------------------------------------------------
/online/assets/data/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
--------------------------------------------------------------------------------
/online/assets/js/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
--------------------------------------------------------------------------------
/online/assets/img/perlin-512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UXVirtual/night-sky/HEAD/online/assets/img/perlin-512.png
--------------------------------------------------------------------------------
/online/assets/img/waternormals.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UXVirtual/night-sky/HEAD/online/assets/img/waternormals.jpg
--------------------------------------------------------------------------------
/online/assets/img/star_preview3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UXVirtual/night-sky/HEAD/online/assets/img/star_preview3.png
--------------------------------------------------------------------------------
/online/assets/img/skybox3-hr/skybox_0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UXVirtual/night-sky/HEAD/online/assets/img/skybox3-hr/skybox_0.png
--------------------------------------------------------------------------------
/online/assets/img/skybox3-hr/skybox_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UXVirtual/night-sky/HEAD/online/assets/img/skybox3-hr/skybox_1.png
--------------------------------------------------------------------------------
/online/assets/img/skybox3-hr/skybox_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UXVirtual/night-sky/HEAD/online/assets/img/skybox3-hr/skybox_2.png
--------------------------------------------------------------------------------
/online/assets/img/skybox3-hr/skybox_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UXVirtual/night-sky/HEAD/online/assets/img/skybox3-hr/skybox_3.png
--------------------------------------------------------------------------------
/online/assets/img/skybox3-hr/skybox_4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UXVirtual/night-sky/HEAD/online/assets/img/skybox3-hr/skybox_4.png
--------------------------------------------------------------------------------
/online/assets/img/skybox3-hr/skybox_5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UXVirtual/night-sky/HEAD/online/assets/img/skybox3-hr/skybox_5.png
--------------------------------------------------------------------------------
/online/assets/img/skybox3-lr/skybox_0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UXVirtual/night-sky/HEAD/online/assets/img/skybox3-lr/skybox_0.png
--------------------------------------------------------------------------------
/online/assets/img/skybox3-lr/skybox_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UXVirtual/night-sky/HEAD/online/assets/img/skybox3-lr/skybox_1.png
--------------------------------------------------------------------------------
/online/assets/img/skybox3-lr/skybox_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UXVirtual/night-sky/HEAD/online/assets/img/skybox3-lr/skybox_2.png
--------------------------------------------------------------------------------
/online/assets/img/skybox3-lr/skybox_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UXVirtual/night-sky/HEAD/online/assets/img/skybox3-lr/skybox_3.png
--------------------------------------------------------------------------------
/online/assets/img/skybox3-lr/skybox_4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UXVirtual/night-sky/HEAD/online/assets/img/skybox3-lr/skybox_4.png
--------------------------------------------------------------------------------
/online/assets/img/skybox3-lr/skybox_5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/UXVirtual/night-sky/HEAD/online/assets/img/skybox3-lr/skybox_5.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | node_modules
3 | scripts/CSVToJSON.egg-info
4 | scripts/dist
5 | online/assets/js/data.json
6 | online/bower_components
7 |
--------------------------------------------------------------------------------
/online/.htaccess:
--------------------------------------------------------------------------------
1 | AddEncoding gzip .gz
2 |
3 | RewriteEngine on
4 | RewriteCond %{HTTP:Accept-encoding} gzip
5 | RewriteCond %{HTTP_USER_AGENT} !Konqueror
6 | RewriteCond %{REQUEST_FILENAME}.gz -f
7 | RewriteRule ^(.*)\.js$ $1.js.gz [QSA,L]
--------------------------------------------------------------------------------
/scripts/setup.py:
--------------------------------------------------------------------------------
1 | #to setup CSV To JSON run: `python setup.py install`
2 |
3 | from setuptools import setup
4 |
5 | setup(
6 | name="CSVToJSON",
7 | version="0.1",
8 | install_requires=[
9 | "pandas"
10 | ]
11 | )
--------------------------------------------------------------------------------
/online/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "olympics-vr-prototype",
3 | "description": "A prototype of the night sky VR functionality.",
4 | "main": "index.js",
5 | "authors": [
6 | "Michael Andrew (michael.andrew@gladeye.co.nz)"
7 | ],
8 | "moduleType": [],
9 | "homepage": "",
10 | "private": true,
11 | "ignore": [
12 | "**/.*",
13 | "node_modules",
14 | "bower_components",
15 | "test",
16 | "tests"
17 | ],
18 | "dependencies": {
19 | "ocean": "https://github.com/jbouny/ocean.git",
20 | "modernizr": "~3.3.1"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/online/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Night Sky Viewer
7 |
8 |
9 |
10 |
11 |
12 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/online/assets/src/config/WebVRConfig.js:
--------------------------------------------------------------------------------
1 | window.WebVRConfig = {
2 | /**
3 | * webvr-polyfill configuration
4 | */
5 |
6 | // Forces availability of VR mode.
7 | FORCE_ENABLE_VR: false, // Default: false.
8 | // Complementary filter coefficient. 0 for accelerometer, 1 for gyro.
9 | K_FILTER: 0.98, // Default: 0.98.
10 | // How far into the future to predict during fast motion.
11 | PREDICTION_TIME_S: 0.040, // Default: 0.040 (in seconds).
12 | // Flag to disable touch panner. In case you have your own touch controls
13 | TOUCH_PANNER_DISABLED: false, // Default: false.
14 | // Enable yaw panning only, disabling roll and pitch. This can be useful for
15 | // panoramas with nothing interesting above or below.
16 | YAW_ONLY: false, // Default: false.
17 | MOUSE_KEYBOARD_CONTROLS_DISABLED: false,
18 |
19 | /**
20 | * webvr-boilerplate configuration
21 | */
22 | // Forces distortion in VR mode.
23 | FORCE_DISTORTION: false, // Default: false.
24 | // Override the distortion background color.
25 | // DISTORTION_BGCOLOR: {x: 1, y: 0, z: 0, w: 1}, // Default: (0,0,0,1).
26 | // Prevent distortion from happening.
27 | PREVENT_DISTORTION: false, // Default: false.
28 | // Show eye centers for debugging.
29 | SHOW_EYE_CENTERS: false, // Default: false.
30 | // Prevent the online DPDB from being fetched.
31 | NO_DPDB_FETCH: true // Default: false.
32 | };
--------------------------------------------------------------------------------
/online/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "olympics-vr-prototype",
3 | "version": "0.1.1",
4 | "description": "A prototype of the night sky VR functionality.",
5 | "main": "index.js",
6 | "dependencies": {
7 | "dat-gui": "^0.5.0",
8 | "exports-loader": "^0.6.3",
9 | "fpsmeter": "git+https://github.com/darsain/fpsmeter.git#v0.3.1",
10 | "imports-loader": "^0.6.5",
11 | "jquery": "^2.2.1",
12 | "jquery-modal": "^0.6.1",
13 | "mobile-detect": "^1.3.1",
14 | "perfnow": "^0.2.0",
15 | "rollup": "^0.25.4",
16 | "stats.js": "^0.0.14",
17 | "three": "^0.75.0",
18 | "three-loaders-collada": "^1.0.1",
19 | "three-text2d": "^0.2.2",
20 | "tiny-popup": "^0.1.11",
21 | "webvr-boilerplate": "^0.3.7",
22 | "webvr-polyfill": "^0.2.7"
23 | },
24 | "devDependencies": {
25 | "babel-core": "^6.6.0",
26 | "babel-loader": "^6.2.4",
27 | "babel-preset-es2015": "^6.6.0",
28 | "babel-preset-react": "^6.5.0",
29 | "css-loader": "^0.23.1",
30 | "expose-loader": "^0.7.1",
31 | "json-loader": "^0.5.4",
32 | "style-loader": "^0.13.0",
33 | "webpack": "^1.13.1",
34 | "webpack-dev-server": "^1.14.1"
35 | },
36 | "scripts": {
37 | "test": "echo \"Error: no test specified\" && exit 1"
38 | },
39 | "repository": {
40 | "type": "git",
41 | "url": "https://git.gladeye.org/michael/olympics-app-prototype.git"
42 | },
43 | "author": "Michael Andrew (michael.andrew@gladeye.co.nz)"
44 | }
45 |
--------------------------------------------------------------------------------
/online/webpack.config.js:
--------------------------------------------------------------------------------
1 | var webpack = require("webpack");
2 | var path = require("path");
3 |
4 | module.exports = {
5 | entry: "./assets/src/index.js",
6 | output: {
7 | path: './assets/js',
8 |
9 | filename: "bundle.js"
10 | },
11 | module: {
12 | loaders: [
13 | {
14 | test: /\.jsx?$/,
15 | exclude: /(node_modules|bower_components)/,
16 | loader: 'babel', // 'babel-loader' is also a legal name to reference
17 | query: {
18 | presets: ['react', 'es2015']
19 | }
20 | },
21 | { test: /\.css$/, loader: "style-loader!css-loader" }
22 | ]
23 | },
24 | resolve: [
25 | {
26 | root: [path.join(__dirname, "bower_components")]
27 | }
28 | ],
29 | plugins: [
30 | new webpack.ProvidePlugin({
31 | THREE: "three",
32 | "window.THREE": "three"
33 | }),
34 | new webpack.ResolverPlugin(
35 | new webpack.ResolverPlugin.DirectoryDescriptionFilePlugin(".bower.json", ["main"])
36 | ),
37 | new webpack.ProvidePlugin({
38 | $: "jquery",
39 | jQuery: "jquery",
40 | "window.jQuery": "jquery"
41 | }),
42 | new webpack.ProvidePlugin({
43 | 'performance': 'imports?this=>global!exports?global.performance!perfnow'
44 | })
45 | ]
46 | };
47 |
48 |
--------------------------------------------------------------------------------
/scripts/csv-to-json.py:
--------------------------------------------------------------------------------
1 | #
2 | # CSV To JSON Converson Script
3 | #
4 | # @author Michael Andrew (michael.andrew@gladeye.co.nz)
5 | # @usage python csv-to-json.py ../tmp/data.csv ../online/assets/data/data.json
6 | #
7 |
8 | import csv
9 | import json
10 | import sys
11 | import urllib2
12 | import gzip
13 | import pandas
14 | import numpy as np
15 |
16 | URL = "https://github.com/astronexus/HYG-Database/raw/master/hygdata_v3.csv" #url to star data csv on GitHub
17 | csvFilePath = sys.argv[1] #destination path of downloaded csv file
18 | jsonFilePath = sys.argv[2] #destination path of converted json file
19 |
20 | print "Downloading star data CSV... This may take a few minutes..."
21 | with open(csvFilePath,'wb') as f:
22 | f.write(urllib2.urlopen(URL).read())
23 | f.close()
24 | print "Download completed. Converting target columns from CSV to GZipped JSON..."
25 |
26 | jsonfileGzipped = gzip.open(jsonFilePath+'.gz', 'wb')
27 | jsonfile = open(jsonFilePath, 'w')
28 |
29 | #pandas.set_option('display.precision', 15)
30 |
31 | colnames = ['id', 'proper', 'mag', 'absmag', 'dist', 'x', 'y', 'z', 'spect', 'con', 'bf', 'gl']
32 | data = pandas.read_csv(csvFilePath, engine='c', usecols=colnames, low_memory=False, delimiter = ',', skip_blank_lines = True, index_col = 0, header = 0, float_precision = 10, dtype={'id': np.int64, 'proper': str, 'dist': np.float64, 'x': np.float64,'y': np.float64, 'z': np.float64, 'spect': str, 'mag': np.float64, 'absmag': np.float64, 'con': str, 'bf': str, 'gl': str})
33 |
34 | print data.dtypes
35 |
36 | myJSON = data.to_json(path_or_buf = None, orient = 'records', date_format = 'epoch', double_precision = 10, force_ascii = False, date_unit = 'ms')
37 |
38 |
39 | jsonfileGzipped.write(myJSON)
40 | jsonfile.write(myJSON)
41 | jsonfile.close()
42 | jsonfileGzipped.close()
43 | print "Done!"
44 |
--------------------------------------------------------------------------------
/online/assets/src/vendor/modernizr/modernizr-custom.js:
--------------------------------------------------------------------------------
1 | /*! modernizr 3.3.1 (Custom Build) | MIT *
2 | * http://modernizr.com/download/?-devicemotion_deviceorientation-geolocation-webgl-webglextensions-addtest-mq-setclasses !*/
3 | !function(e,n,t){function o(e,n){return typeof e===n}function i(){var e,n,t,i,a,s,r;for(var l in c)if(c.hasOwnProperty(l)){if(e=[],n=c[l],n.name&&(e.push(n.name.toLowerCase()),n.options&&n.options.aliases&&n.options.aliases.length))for(t=0;t= 10000000 indicates missing or dubious (e.g., negative) parallax data in Hipparcos.
124 | * `pmra`, `pmdec` - The star's proper motion in right ascension and declination, in milliarcseconds per year.
125 | * `rv` - The star's radial velocity in km/sec, where known.
126 | * `mag` - The star's apparent visual magnitude.
127 | * `absmag` - The star's absolute visual magnitude (its apparent magnitude from a distance of 10 parsecs).
128 | * `spect` - The star's spectral type, if known.
129 | * `ci` - The star's color index (blue magnitude - visual magnitude), where known.
130 | * `x`, `y` ,`z` - The Cartesian coordinates of the star, in a system based on the equatorial coordinates as seen from
131 | Earth. +X is in the direction of the vernal equinox (at epoch 2000), +Z towards the north celestial pole, and +Y in
132 | the direction of R.A. 6 hours, declination 0 degrees.
133 | * `vx`, `vy`, `vz` - The Cartesian velocity components of the star, in the same coordinate system described
134 | immediately above. They are determined from the proper motion and the radial velocity (when known). The velocity
135 | unit is parsecs per year; these are small values (around 1 millionth of a parsec per year), but they enormously
136 | simplify calculations using parsecs as base units for celestial mapping.
137 | * `rarad`, `decrad`, `pmrarad`, `prdecrad` - The positions in radians, and proper motions in radians per year.
138 | * `bayer` - The Bayer designation as a distinct value
139 | * `flam` - The Flamsteed number as a distinct value
140 | * `con` - The standard constellation abbreviation
141 | * `comp`, `comp_primary`, `base` - Identifies a star in a multiple star system. comp = ID of companion star,
142 | comp_primary = ID of primary star for this component, and base = catalog ID or name for this multi-star system.
143 | Currently only used for Gliese stars.
144 | * `lum` - Star's luminosity as a multiple of Solar luminosity.
145 | * `var` - Star's standard variable star designation, when known.
146 | * `var_min`, `var_max`: Star's approximate magnitude range, for variables. This value is based on the Hp magnitudes
147 | for the range in the original Hipparcos catalog, adjusted to the V magnitude scale to match the "mag" field.
148 |
149 | ## Tools
150 |
151 | * [Three.js Inspector](https://chrome.google.com/webstore/detail/threejs-inspector/dnhjfclbfhcbcdfpjaeacomhbdfjbebi/related?hl=en)
152 |
153 | ## Examples
154 |
155 | * [Three JS Point Cloud Experiment](http://codepen.io/seanseansean/pen/EaBZEY)
156 |
157 | * http://www.html5rocks.com/en/tutorials/casestudies/100000stars/
158 |
159 | * http://stars.chromeexperiments.com/
160 |
161 | * https://jbouny.github.io/ocean/demo/
162 |
163 | ## Reference
164 |
165 | * [What Are Celestial Coordinates](http://www.skyandtelescope.com/astronomy-resources/what-are-celestial-coordinates/)
166 | * [Scientific Visualization Studio](http://svs.gsfc.nasa.gov/cgi-bin/details.cgi?aid=3895)
167 | * [Planetary Annihilation Skyboxes](http://www.superouman.net/planetary-annihilation-skyboxes.php)
168 | * [How to Find the Milky Way](http://www.lonelyspeck.com/how-to-find-the-milky-way/)
169 | * [THREE.js VRControls Integration How To Move In The Scene](http://stackoverflow.com/questions/30511524/three-js-vrcontrols-integration-how-to-move-in-the-scene)
170 |
--------------------------------------------------------------------------------
/online/assets/src/vendor/three/examples/js/controls/MouseControls.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author dmarcos / http://github.com/dmarcos
3 | *
4 | * This controls allow to change the orientation of the camera using the mouse
5 | */
6 |
7 | var Util = require('webvr-polyfill/src/util');
8 |
9 | THREE.MouseControls = function ( object, domElement ) {
10 |
11 | var scope = this;
12 |
13 |
14 |
15 | var changeEvent = { type: 'change' };
16 | var startEvent = { type: 'start' };
17 | var endEvent = { type: 'end' };
18 |
19 |
20 | var PI_2 = Math.PI / 2;
21 | var mouseQuat = {
22 | x: new THREE.Quaternion(),
23 | y: new THREE.Quaternion()
24 | };
25 | var object = object;
26 | //var xVector = (Util.isIOS()) ? new THREE.Vector3( 0, 0, 1 ) : new THREE.Vector3( 1, 0, 0 ); //on IOS we have to invert the X axis, so we need to correct it here otherwise it will show up as a Z rotation
27 | //var yVector = new THREE.Vector3( 0, 1, 0 );
28 |
29 | var rotateStart = new THREE.Vector2();
30 | var rotateEnd = new THREE.Vector2();
31 | var rotateDelta = new THREE.Vector2();
32 |
33 | var STATE = { NONE : - 1, ROTATE : 0, TOUCH_ROTATE : 3 };
34 |
35 | var state = STATE.NONE;
36 |
37 | // Set to false to disable rotating
38 | this.enableRotate = true;
39 | this.rotateSpeed = 1.0;
40 |
41 | this.domElement = ( domElement !== undefined ) ? domElement : document;
42 |
43 | // Mouse buttons
44 | this.mouseButtons = { ROTATE: THREE.MOUSE.LEFT };
45 |
46 | this.enabled = true;
47 |
48 | this.orientation = {
49 | x: 0,
50 | y: 0,
51 | };
52 |
53 | function onMouseDown( event ) {
54 |
55 | if ( scope.enabled === false ) return;
56 |
57 | event.preventDefault();
58 |
59 | if ( event.button === scope.mouseButtons.ROTATE ) {
60 |
61 | console.log('mouse down');
62 |
63 | if ( scope.enableRotate === false ) return;
64 |
65 | handleMouseDownRotate( event );
66 |
67 | state = STATE.ROTATE;
68 |
69 | console.log(state)
70 |
71 | }
72 |
73 | if ( state !== STATE.NONE ) {
74 |
75 | scope.domElement.addEventListener( 'mousemove', onMouseMove, false );
76 | scope.domElement.addEventListener( 'mouseup', onMouseUp, false );
77 | scope.domElement.addEventListener( 'mouseout', onMouseUp, false );
78 |
79 | scope.dispatchEvent( startEvent );
80 |
81 | }
82 |
83 | }
84 |
85 | function onMouseMove( event ) {
86 |
87 | if ( scope.enabled === false ) return;
88 |
89 | event.preventDefault();
90 |
91 | if ( state === STATE.ROTATE ) {
92 |
93 | if ( scope.enableRotate === false ) return;
94 |
95 | handleMouseMoveRotate( event );
96 |
97 | }
98 |
99 | }
100 |
101 | function onMouseUp( event ) {
102 |
103 | if ( scope.enabled === false ) return;
104 |
105 | handleMouseUp( event );
106 |
107 | document.removeEventListener( 'mousemove', onMouseMove, false );
108 | document.removeEventListener( 'mouseup', onMouseUp, false );
109 | document.removeEventListener( 'mouseout', onMouseUp, false );
110 |
111 | scope.dispatchEvent( endEvent );
112 |
113 | state = STATE.NONE;
114 |
115 | }
116 |
117 |
118 |
119 | function onTouchStart( event ) {
120 |
121 | if ( scope.enabled === false ) return;
122 |
123 | console.log('touchstart');
124 |
125 | switch ( event.touches.length ) {
126 |
127 | case 1: // one-fingered touch: rotate
128 |
129 | if ( scope.enableRotate === false ) return;
130 |
131 | handleTouchStartRotate( event );
132 |
133 | state = STATE.TOUCH_ROTATE;
134 |
135 | break;
136 |
137 | default:
138 |
139 | state = STATE.NONE;
140 |
141 | }
142 |
143 | if ( state !== STATE.NONE ) {
144 |
145 | scope.dispatchEvent( startEvent );
146 |
147 | }
148 |
149 | }
150 |
151 | function onTouchMove( event ) {
152 |
153 | if ( scope.enabled === false ) return;
154 |
155 | event.preventDefault();
156 | event.stopPropagation();
157 |
158 | switch ( event.touches.length ) {
159 |
160 | case 1: // one-fingered touch: rotate
161 |
162 | if ( scope.enableRotate === false ) return;
163 | if ( state !== STATE.TOUCH_ROTATE ) return; // is this needed?...
164 |
165 | handleTouchMoveRotate( event );
166 |
167 | break;
168 |
169 | default:
170 |
171 | state = STATE.NONE;
172 |
173 | }
174 |
175 | }
176 |
177 | function onTouchEnd( event ) {
178 |
179 | if ( scope.enabled === false ) return;
180 |
181 | handleTouchEnd( event );
182 |
183 | scope.dispatchEvent( endEvent );
184 |
185 | state = STATE.NONE;
186 |
187 | }
188 |
189 | function onContextMenu( event ) {
190 |
191 | event.preventDefault();
192 |
193 | }
194 |
195 | function handleTouchStartRotate( event ) {
196 |
197 | //console.log( 'handleTouchStartRotate' );
198 |
199 | rotateStart.set(event.touches[0].pageX, event.touches[0].pageY);
200 |
201 | }
202 |
203 | function handleTouchEnd( event ) {
204 |
205 | console.log( 'handleTouchEnd' );
206 |
207 | }
208 |
209 | function handleTouchMoveRotate( event ) {
210 |
211 | console.log( 'handleTouchMoveRotate' );
212 |
213 |
214 |
215 | rotateEnd.set(event.touches[0].pageX, event.touches[0].pageY);
216 | rotateDelta.subVectors(rotateEnd, rotateStart);
217 | rotateStart.copy(rotateEnd);
218 |
219 | // On iOS, direction is inverted.
220 | if (Util.isIOS()) {
221 | //rotateDelta.x *= -1;
222 | }
223 |
224 | var orientation = scope.orientation;
225 |
226 | var element = scope.domElement === document ? scope.domElement.body : scope.domElement;
227 | orientation.x += 2 * Math.PI * rotateDelta.y / element.clientWidth * scope.rotateSpeed;
228 |
229 | orientation.y += 2 * Math.PI * rotateDelta.x / element.clientWidth * scope.rotateSpeed;
230 |
231 | //orientation.x = Math.max( - PI_2, Math.min( PI_2, orientation.x ) );
232 |
233 | scope.update();
234 |
235 | }
236 |
237 | function handleMouseMoveRotate( event ) {
238 |
239 | console.log( 'handleMouseMoveRotate' );
240 |
241 | rotateEnd.set( event.clientX, event.clientY );
242 | rotateDelta.subVectors( rotateEnd, rotateStart );
243 |
244 | var element = scope.domElement === document ? scope.domElement.body : scope.domElement;
245 |
246 | // rotating across whole screen goes 360 degrees around
247 | /*rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth * scope.rotateSpeed );
248 |
249 | // rotating up and down along whole screen attempts to go 360, but limited to 180
250 | rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight * scope.rotateSpeed );
251 |
252 | rotateStart.copy( rotateEnd );*/
253 |
254 | rotateStart.copy( rotateEnd );
255 |
256 | var orientation = scope.orientation;
257 |
258 | var movementX = rotateDelta.x;
259 | var movementY = rotateDelta.y;
260 |
261 | orientation.y += movementX * 0.0025;
262 | orientation.x += movementY * 0.0025;
263 |
264 | orientation.x = Math.max( - PI_2, Math.min( PI_2, orientation.x ) );
265 |
266 | scope.update();
267 |
268 | }
269 |
270 | function handleMouseDownRotate( event ) {
271 |
272 | console.log( 'handleMouseDownRotate' );
273 |
274 | rotateStart.set( event.clientX, event.clientY );
275 |
276 | }
277 |
278 | function handleMouseUp( event ) {
279 |
280 | console.log( 'handleMouseUp' );
281 |
282 | }
283 |
284 | this.update = function() {
285 |
286 | if ( scope.enabled === false ) return;
287 |
288 | //TODO: fix this so that rotation is corrected when the parent rotation changes. Currently X and Z axis flip
289 | //when the dollyCamera is rotated in a different direction using the gyro
290 |
291 | mouseQuat.x.setFromEuler(new THREE.Euler(scope.orientation.x, 0, 0));
292 |
293 | mouseQuat.y.setFromEuler(new THREE.Euler(0, scope.orientation.y, 0));
294 |
295 | //mouseQuat.x.setFromAxisAngle( xVector, scope.orientation.x );
296 | //mouseQuat.y.setFromAxisAngle( yVector, scope.orientation.y );
297 | object.quaternion.copy( mouseQuat.y ).multiply( mouseQuat.x );
298 | return;
299 |
300 | };
301 |
302 | this.dispose = function() {
303 |
304 | scope.domElement.removeEventListener( 'mousedown', onMouseDown, false );
305 | scope.domElement.removeEventListener( 'contextmenu', onContextMenu, false );
306 |
307 | document.removeEventListener( 'mousemove', onMouseMove, false );
308 | document.removeEventListener( 'mouseup', onMouseUp, false );
309 | document.removeEventListener( 'mouseout', onMouseUp, false );
310 |
311 |
312 | }
313 |
314 | //scope.domElement.addEventListener( 'mousemove', onMouseMove, false );
315 | scope.domElement.addEventListener( 'mousedown', onMouseDown, false );
316 | scope.domElement.addEventListener( 'touchstart', onTouchStart, false );
317 | scope.domElement.addEventListener( 'touchend', onTouchEnd, false );
318 | scope.domElement.addEventListener( 'touchmove', onTouchMove, false );
319 | scope.domElement.addEventListener( 'contextmenu', onContextMenu, false );
320 |
321 | };
322 |
323 | THREE.MouseControls.prototype = Object.create( THREE.EventDispatcher.prototype );
324 | THREE.MouseControls.prototype.constructor = THREE.MouseControls;
325 |
--------------------------------------------------------------------------------
/online/assets/src/vendor/zz85/SkyShader.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author zz85 / https://github.com/zz85
3 | *
4 | * Based on "A Practical Analytic Model for Daylight"
5 | * aka The Preetham Model, the de facto standard analytic skydome model
6 | * http://www.cs.utah.edu/~shirley/papers/sunsky/sunsky.pdf
7 | *
8 | * First implemented by Simon Wallner
9 | * http://www.simonwallner.at/projects/atmospheric-scattering
10 | *
11 | * Improved by Martin Upitis
12 | * http://blenderartists.org/forum/showthread.php?245954-preethams-sky-impementation-HDR
13 | *
14 | * Three.js integration by zz85 http://twitter.com/blurspline
15 | */
16 |
17 | THREE.ShaderLib[ 'sky' ] = {
18 |
19 | uniforms: {
20 |
21 | luminance: { type: "f", value: 1 },
22 | turbidity: { type: "f", value: 2 },
23 | reileigh: { type: "f", value: 1 },
24 | mieCoefficient: { type: "f", value: 0.005 },
25 | mieDirectionalG: { type: "f", value: 0.8 },
26 | sunPosition: { type: "v3", value: new THREE.Vector3() }
27 |
28 | },
29 |
30 | vertexShader: [
31 |
32 | "varying vec3 vWorldPosition;",
33 |
34 | "void main() {",
35 |
36 | "vec4 worldPosition = modelMatrix * vec4( position, 1.0 );",
37 | "vWorldPosition = worldPosition.xyz;",
38 |
39 | "gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
40 |
41 | "}",
42 |
43 | ].join( "\n" ),
44 |
45 | fragmentShader: [
46 |
47 | "uniform sampler2D skySampler;",
48 | "uniform vec3 sunPosition;",
49 | "varying vec3 vWorldPosition;",
50 |
51 | "vec3 cameraPos = vec3(0., 0., 0.);",
52 | "// uniform sampler2D sDiffuse;",
53 | "// const float turbidity = 10.0; //",
54 | "// const float reileigh = 2.; //",
55 | "// const float luminance = 1.0; //",
56 | "// const float mieCoefficient = 0.005;",
57 | "// const float mieDirectionalG = 0.8;",
58 |
59 | "uniform float luminance;",
60 | "uniform float turbidity;",
61 | "uniform float reileigh;",
62 | "uniform float mieCoefficient;",
63 | "uniform float mieDirectionalG;",
64 |
65 | "// constants for atmospheric scattering",
66 | "const float e = 2.71828182845904523536028747135266249775724709369995957;",
67 | "const float pi = 3.141592653589793238462643383279502884197169;",
68 |
69 | "const float n = 1.0003; // refractive index of air",
70 | "const float N = 2.545E25; // number of molecules per unit volume for air at",
71 | "// 288.15K and 1013mb (sea level -45 celsius)",
72 | "const float pn = 0.035; // depolatization factor for standard air",
73 |
74 | "// wavelength of used primaries, according to preetham",
75 | "const vec3 lambda = vec3(680E-9, 550E-9, 450E-9);",
76 |
77 | "// mie stuff",
78 | "// K coefficient for the primaries",
79 | "const vec3 K = vec3(0.686, 0.678, 0.666);",
80 | "const float v = 4.0;",
81 |
82 | "// optical length at zenith for molecules",
83 | "const float rayleighZenithLength = 8.4E3;",
84 | "const float mieZenithLength = 1.25E3;",
85 | "const vec3 up = vec3(0.0, 1.0, 0.0);",
86 |
87 | "const float EE = 1000.0;",
88 | "const float sunAngularDiameterCos = 0.999956676946448443553574619906976478926848692873900859324;",
89 | "// 66 arc seconds -> degrees, and the cosine of that",
90 |
91 | "// earth shadow hack",
92 | "const float cutoffAngle = pi/1.95;",
93 | "const float steepness = 1.5;",
94 |
95 |
96 | "vec3 totalRayleigh(vec3 lambda)",
97 | "{",
98 | "return (8.0 * pow(pi, 3.0) * pow(pow(n, 2.0) - 1.0, 2.0) * (6.0 + 3.0 * pn)) / (3.0 * N * pow(lambda, vec3(4.0)) * (6.0 - 7.0 * pn));",
99 | "}",
100 |
101 | // see http://blenderartists.org/forum/showthread.php?321110-Shaders-and-Skybox-madness
102 | "// A simplied version of the total Reayleigh scattering to works on browsers that use ANGLE",
103 | "vec3 simplifiedRayleigh()",
104 | "{",
105 | "return 0.0005 / vec3(94, 40, 18);",
106 | // return 0.00054532832366 / (3.0 * 2.545E25 * pow(vec3(680E-9, 550E-9, 450E-9), vec3(4.0)) * 6.245);
107 | "}",
108 |
109 | "float rayleighPhase(float cosTheta)",
110 | "{ ",
111 | "return (3.0 / (16.0*pi)) * (1.0 + pow(cosTheta, 2.0));",
112 | "// return (1.0 / (3.0*pi)) * (1.0 + pow(cosTheta, 2.0));",
113 | "// return (3.0 / 4.0) * (1.0 + pow(cosTheta, 2.0));",
114 | "}",
115 |
116 | "vec3 totalMie(vec3 lambda, vec3 K, float T)",
117 | "{",
118 | "float c = (0.2 * T ) * 10E-18;",
119 | "return 0.434 * c * pi * pow((2.0 * pi) / lambda, vec3(v - 2.0)) * K;",
120 | "}",
121 |
122 | "float hgPhase(float cosTheta, float g)",
123 | "{",
124 | "return (1.0 / (4.0*pi)) * ((1.0 - pow(g, 2.0)) / pow(1.0 - 2.0*g*cosTheta + pow(g, 2.0), 1.5));",
125 | "}",
126 |
127 | "float sunIntensity(float zenithAngleCos)",
128 | "{",
129 | "return EE * max(0.0, 1.0 - exp(-((cutoffAngle - acos(zenithAngleCos))/steepness)));",
130 | "}",
131 |
132 | "// float logLuminance(vec3 c)",
133 | "// {",
134 | "// return log(c.r * 0.2126 + c.g * 0.7152 + c.b * 0.0722);",
135 | "// }",
136 |
137 | "// Filmic ToneMapping http://filmicgames.com/archives/75",
138 | "float A = 0.15;",
139 | "float B = 0.50;",
140 | "float C = 0.10;",
141 | "float D = 0.20;",
142 | "float E = 0.02;",
143 | "float F = 0.30;",
144 | "float W = 1000.0;",
145 |
146 | "vec3 Uncharted2Tonemap(vec3 x)",
147 | "{",
148 | "return ((x*(A*x+C*B)+D*E)/(x*(A*x+B)+D*F))-E/F;",
149 | "}",
150 |
151 |
152 | "void main() ",
153 | "{",
154 | "float sunfade = 1.0-clamp(1.0-exp((sunPosition.y/450000.0)),0.0,1.0);",
155 |
156 | "// luminance = 1.0 ;// vWorldPosition.y / 450000. + 0.5; //sunPosition.y / 450000. * 1. + 0.5;",
157 |
158 | "// gl_FragColor = vec4(sunfade, sunfade, sunfade, 1.0);",
159 |
160 | "float reileighCoefficient = reileigh - (1.0* (1.0-sunfade));",
161 |
162 | "vec3 sunDirection = normalize(sunPosition);",
163 |
164 | "float sunE = sunIntensity(dot(sunDirection, up));",
165 |
166 | "// extinction (absorbtion + out scattering) ",
167 | "// rayleigh coefficients",
168 |
169 | // "vec3 betaR = totalRayleigh(lambda) * reileighCoefficient;",
170 | "vec3 betaR = simplifiedRayleigh() * reileighCoefficient;",
171 |
172 | "// mie coefficients",
173 | "vec3 betaM = totalMie(lambda, K, turbidity) * mieCoefficient;",
174 |
175 | "// optical length",
176 | "// cutoff angle at 90 to avoid singularity in next formula.",
177 | "float zenithAngle = acos(max(0.0, dot(up, normalize(vWorldPosition - cameraPos))));",
178 | "float sR = rayleighZenithLength / (cos(zenithAngle) + 0.15 * pow(93.885 - ((zenithAngle * 180.0) / pi), -1.253));",
179 | "float sM = mieZenithLength / (cos(zenithAngle) + 0.15 * pow(93.885 - ((zenithAngle * 180.0) / pi), -1.253));",
180 |
181 |
182 |
183 | "// combined extinction factor ",
184 | "vec3 Fex = exp(-(betaR * sR + betaM * sM));",
185 |
186 | "// in scattering",
187 | "float cosTheta = dot(normalize(vWorldPosition - cameraPos), sunDirection);",
188 |
189 | "float rPhase = rayleighPhase(cosTheta*0.5+0.5);",
190 | "vec3 betaRTheta = betaR * rPhase;",
191 |
192 | "float mPhase = hgPhase(cosTheta, mieDirectionalG);",
193 | "vec3 betaMTheta = betaM * mPhase;",
194 |
195 |
196 | "vec3 Lin = pow(sunE * ((betaRTheta + betaMTheta) / (betaR + betaM)) * (1.0 - Fex),vec3(1.5));",
197 | "Lin *= mix(vec3(1.0),pow(sunE * ((betaRTheta + betaMTheta) / (betaR + betaM)) * Fex,vec3(1.0/2.0)),clamp(pow(1.0-dot(up, sunDirection),5.0),0.0,1.0));",
198 |
199 | "//nightsky",
200 | "vec3 direction = normalize(vWorldPosition - cameraPos);",
201 | "float theta = acos(direction.y); // elevation --> y-axis, [-pi/2, pi/2]",
202 | "float phi = atan(direction.z, direction.x); // azimuth --> x-axis [-pi/2, pi/2]",
203 | "vec2 uv = vec2(phi, theta) / vec2(2.0*pi, pi) + vec2(0.5, 0.0);",
204 | "// vec3 L0 = texture2D(skySampler, uv).rgb+0.1 * Fex;",
205 | "vec3 L0 = vec3(0.1) * Fex;",
206 |
207 | "// composition + solar disc",
208 | "//if (cosTheta > sunAngularDiameterCos)",
209 | "float sundisk = smoothstep(sunAngularDiameterCos,sunAngularDiameterCos+0.00002,cosTheta);",
210 | "// if (normalize(vWorldPosition - cameraPos).y>0.0)",
211 | "L0 += (sunE * 19000.0 * Fex)*sundisk;",
212 |
213 |
214 | "vec3 whiteScale = 1.0/Uncharted2Tonemap(vec3(W));",
215 |
216 | "vec3 texColor = (Lin+L0); ",
217 | "texColor *= 0.04 ;",
218 | "texColor += vec3(0.0,0.001,0.0025)*0.3;",
219 |
220 | "float g_fMaxLuminance = 1.0;",
221 | "float fLumScaled = 0.1 / luminance; ",
222 | "float fLumCompressed = (fLumScaled * (1.0 + (fLumScaled / (g_fMaxLuminance * g_fMaxLuminance)))) / (1.0 + fLumScaled); ",
223 |
224 | "float ExposureBias = fLumCompressed;",
225 |
226 | "vec3 curr = Uncharted2Tonemap((log2(2.0/pow(luminance,4.0)))*texColor);",
227 | "vec3 color = curr*whiteScale;",
228 |
229 | "vec3 retColor = pow(color,vec3(1.0/(1.2+(1.2*sunfade))));",
230 |
231 |
232 | "gl_FragColor.rgb = retColor;",
233 |
234 | "gl_FragColor.a = 1.0;",
235 | "}",
236 |
237 | ].join( "\n" )
238 |
239 | };
240 |
241 | THREE.Sky = function () {
242 |
243 | var skyShader = THREE.ShaderLib[ "sky" ];
244 | var skyUniforms = THREE.UniformsUtils.clone( skyShader.uniforms );
245 |
246 | var skyMat = new THREE.ShaderMaterial( {
247 | fragmentShader: skyShader.fragmentShader,
248 | vertexShader: skyShader.vertexShader,
249 | uniforms: skyUniforms,
250 | side: THREE.BackSide
251 | } );
252 |
253 | var skyGeo = new THREE.SphereBufferGeometry( 450000, 32, 15 );
254 | var skyMesh = new THREE.Mesh( skyGeo, skyMat );
255 |
256 |
257 | // Expose variables
258 | this.mesh = skyMesh;
259 | this.uniforms = skyUniforms;
260 |
261 | };
262 |
--------------------------------------------------------------------------------
/online/assets/src/vendor/charliehoey/GPUParticleSystem.js:
--------------------------------------------------------------------------------
1 | /*
2 | * GPU Particle System
3 | * @author flimshaw - Charlie Hoey - http://charliehoey.com
4 | *
5 | * A simple to use, general purpose GPU system. Particles are spawn-and-forget with
6 | * several options available, and do not require monitoring or cleanup after spawning.
7 | * Because the paths of all particles are completely deterministic once spawned, the scale
8 | * and direction of time is also variable.
9 | *
10 | * Currently uses a static wrapping perlin noise texture for turbulence, and a small png texture for
11 | * particles, but adding support for a particle texture atlas or changing to a different type of turbulence
12 | * would be a fairly light day's work.
13 | *
14 | * Shader and javascript packing code derrived from several Stack Overflow examples.
15 | *
16 | */
17 |
18 | import THREE from 'three'
19 |
20 | THREE.GPUParticleSystem = function(options) {
21 |
22 | var self = this;
23 | var options = options || {};
24 |
25 | // parse options and use defaults
26 | self.PARTICLE_COUNT = options.maxParticles || 1000000;
27 | self.PARTICLE_CONTAINERS = options.containerCount || 1;
28 | self.PARTICLES_PER_CONTAINER = Math.ceil(self.PARTICLE_COUNT / self.PARTICLE_CONTAINERS);
29 | self.PARTICLE_CURSOR = 0;
30 | self.time = 0;
31 |
32 |
33 | // Custom vertex and fragement shader
34 | var GPUParticleShader = {
35 |
36 | vertexShader: [
37 |
38 | 'precision highp float;',
39 | 'const vec4 bitSh = vec4(256. * 256. * 256., 256. * 256., 256., 1.);',
40 | 'const vec4 bitMsk = vec4(0.,vec3(1./256.0));',
41 | 'const vec4 bitShifts = vec4(1.) / bitSh;',
42 |
43 | '#define FLOAT_MAX 1.70141184e38',
44 | '#define FLOAT_MIN 1.17549435e-38',
45 |
46 | 'lowp vec4 encode_float(highp float v) {',
47 | 'highp float av = abs(v);',
48 |
49 | '//Handle special cases',
50 | 'if(av < FLOAT_MIN) {',
51 | 'return vec4(0.0, 0.0, 0.0, 0.0);',
52 | '} else if(v > FLOAT_MAX) {',
53 | 'return vec4(127.0, 128.0, 0.0, 0.0) / 255.0;',
54 | '} else if(v < -FLOAT_MAX) {',
55 | 'return vec4(255.0, 128.0, 0.0, 0.0) / 255.0;',
56 | '}',
57 |
58 | 'highp vec4 c = vec4(0,0,0,0);',
59 |
60 | '//Compute exponent and mantissa',
61 | 'highp float e = floor(log2(av));',
62 | 'highp float m = av * pow(2.0, -e) - 1.0;',
63 |
64 | //Unpack mantissa
65 | 'c[1] = floor(128.0 * m);',
66 | 'm -= c[1] / 128.0;',
67 | 'c[2] = floor(32768.0 * m);',
68 | 'm -= c[2] / 32768.0;',
69 | 'c[3] = floor(8388608.0 * m);',
70 |
71 | '//Unpack exponent',
72 | 'highp float ebias = e + 127.0;',
73 | 'c[0] = floor(ebias / 2.0);',
74 | 'ebias -= c[0] * 2.0;',
75 | 'c[1] += floor(ebias) * 128.0;',
76 |
77 | '//Unpack sign bit',
78 | 'c[0] += 128.0 * step(0.0, -v);',
79 |
80 | '//Scale back to range',
81 | 'return c / 255.0;',
82 | '}',
83 |
84 | 'vec4 pack(const in float depth)',
85 | '{',
86 | 'const vec4 bit_shift = vec4(256.0*256.0*256.0, 256.0*256.0, 256.0, 1.0);',
87 | 'const vec4 bit_mask = vec4(0.0, 1.0/256.0, 1.0/256.0, 1.0/256.0);',
88 | 'vec4 res = mod(depth*bit_shift*vec4(255), vec4(256))/vec4(255);',
89 | 'res -= res.xxyz * bit_mask;',
90 | 'return res;',
91 | '}',
92 |
93 | 'float unpack(const in vec4 rgba_depth)',
94 | '{',
95 | 'const vec4 bit_shift = vec4(1.0/(256.0*256.0*256.0), 1.0/(256.0*256.0), 1.0/256.0, 1.0);',
96 | 'float depth = dot(rgba_depth, bit_shift);',
97 | 'return depth;',
98 | '}',
99 |
100 | 'uniform float uTime;',
101 | 'uniform float uScale;',
102 | 'uniform sampler2D tNoise;',
103 |
104 | 'attribute vec4 particlePositionsStartTime;',
105 | 'attribute vec4 particleVelColSizeLife;',
106 |
107 | 'varying vec4 vColor;',
108 | 'varying float lifeLeft;',
109 |
110 | 'void main() {',
111 |
112 | '// unpack things from our attributes',
113 | 'vColor = encode_float( particleVelColSizeLife.y );',
114 |
115 | '// convert our velocity back into a value we can use',
116 | 'vec4 velTurb = encode_float( particleVelColSizeLife.x );',
117 | 'vec3 velocity = vec3( velTurb.xyz );',
118 | 'float turbulence = velTurb.w;',
119 |
120 | 'vec3 newPosition;',
121 |
122 | 'float timeElapsed = uTime - particlePositionsStartTime.a;',
123 |
124 | 'lifeLeft = 1. - (timeElapsed / particleVelColSizeLife.w);',
125 |
126 | 'gl_PointSize = ( uScale * particleVelColSizeLife.z ) * lifeLeft;',
127 |
128 | 'velocity.x = ( velocity.x - .5 ) * 3.;',
129 | 'velocity.y = ( velocity.y - .5 ) * 3.;',
130 | 'velocity.z = ( velocity.z - .5 ) * 3.;',
131 |
132 | 'newPosition = particlePositionsStartTime.xyz + ( velocity * 10. ) * ( uTime - particlePositionsStartTime.a );',
133 |
134 | 'vec3 noise = texture2D( tNoise, vec2( newPosition.x * .015 + (uTime * .05), newPosition.y * .02 + (uTime * .015) )).rgb;',
135 | 'vec3 noiseVel = ( noise.rgb - .5 ) * 30.;',
136 |
137 | 'newPosition = mix(newPosition, newPosition + vec3(noiseVel * ( turbulence * 5. ) ), (timeElapsed / particleVelColSizeLife.a) );',
138 |
139 | 'if( velocity.y > 0. && velocity.y < .05 ) {',
140 | 'lifeLeft = 0.;',
141 | '}',
142 |
143 | 'if( velocity.x < -1.45 ) {',
144 | 'lifeLeft = 0.;',
145 | '}',
146 |
147 | 'if( timeElapsed > 0. ) {',
148 | 'gl_Position = projectionMatrix * modelViewMatrix * vec4( newPosition, 1.0 );',
149 | '} else {',
150 | 'gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );',
151 | 'lifeLeft = 0.;',
152 | 'gl_PointSize = 0.;',
153 | '}',
154 | '}'
155 |
156 | ].join("\n"),
157 |
158 | fragmentShader: [
159 |
160 | 'float scaleLinear(float value, vec2 valueDomain) {',
161 | 'return (value - valueDomain.x) / (valueDomain.y - valueDomain.x);',
162 | '}',
163 |
164 | 'float scaleLinear(float value, vec2 valueDomain, vec2 valueRange) {',
165 | 'return mix(valueRange.x, valueRange.y, scaleLinear(value, valueDomain));',
166 | '}',
167 |
168 | 'varying vec4 vColor;',
169 | 'varying float lifeLeft;',
170 |
171 | 'uniform sampler2D tSprite;',
172 |
173 | 'void main() {',
174 |
175 | 'float alpha = 0.;',
176 |
177 | 'if( lifeLeft > .995 ) {',
178 | 'alpha = scaleLinear( lifeLeft, vec2(1., .995), vec2(0., 1.));//mix( 0., 1., ( lifeLeft - .95 ) * 100. ) * .75;',
179 | '} else {',
180 | 'alpha = lifeLeft * .75;',
181 | '}',
182 |
183 | 'vec4 tex = texture2D( tSprite, gl_PointCoord );',
184 |
185 | 'gl_FragColor = vec4( vColor.rgb * tex.a, alpha * tex.a );',
186 | '}'
187 |
188 | ].join("\n")
189 |
190 | };
191 |
192 | // preload a million random numbers
193 | self.rand = [];
194 |
195 | for (var i = 1e5; i > 0; i--) {
196 | self.rand.push(Math.random() - .5);
197 | }
198 |
199 | self.random = function() {
200 | return ++i >= self.rand.length ? self.rand[i = 1] : self.rand[i];
201 | }
202 |
203 | var textureLoader = new THREE.TextureLoader();
204 |
205 | self.particleNoiseTex = textureLoader.load("assets/img/perlin-512.png");
206 | self.particleNoiseTex.wrapS = self.particleNoiseTex.wrapT = THREE.RepeatWrapping;
207 |
208 | self.particleSpriteTex = textureLoader.load("assets/img/particle2.png");
209 | self.particleSpriteTex.wrapS = self.particleSpriteTex.wrapT = THREE.RepeatWrapping;
210 |
211 | self.particleShaderMat = new THREE.ShaderMaterial({
212 | transparent: true,
213 | depthWrite: false,
214 | uniforms: {
215 | "uTime": {
216 | type: "f",
217 | value: 0.0
218 | },
219 | "uScale": {
220 | type: "f",
221 | value: 1.0
222 | },
223 | "tNoise": {
224 | type: "t",
225 | value: self.particleNoiseTex
226 | },
227 | "tSprite": {
228 | type: "t",
229 | value: self.particleSpriteTex
230 | }
231 | },
232 | blending: THREE.AdditiveBlending,
233 | vertexShader: GPUParticleShader.vertexShader,
234 | fragmentShader: GPUParticleShader.fragmentShader
235 | });
236 |
237 | // define defaults for all values
238 | self.particleShaderMat.defaultAttributeValues.particlePositionsStartTime = [0, 0, 0, 0];
239 | self.particleShaderMat.defaultAttributeValues.particleVelColSizeLife = [0, 0, 0, 0];
240 |
241 | self.particleContainers = [];
242 |
243 |
244 | // extend Object3D
245 | THREE.Object3D.apply(this, arguments);
246 |
247 | this.init = function() {
248 |
249 | for (var i = 0; i < self.PARTICLE_CONTAINERS; i++) {
250 |
251 | var c = new THREE.GPUParticleContainer(self.PARTICLES_PER_CONTAINER, self);
252 | self.particleContainers.push(c);
253 | self.add(c);
254 |
255 | }
256 |
257 | }
258 |
259 | this.spawnParticle = function(options) {
260 |
261 | self.PARTICLE_CURSOR++;
262 | if (self.PARTICLE_CURSOR >= self.PARTICLE_COUNT) {
263 | self.PARTICLE_CURSOR = 1;
264 | }
265 |
266 | var currentContainer = self.particleContainers[Math.floor(self.PARTICLE_CURSOR / self.PARTICLES_PER_CONTAINER)];
267 |
268 | currentContainer.spawnParticle(options);
269 |
270 | }
271 |
272 | this.update = function(time) {
273 | for (var i = 0; i < self.PARTICLE_CONTAINERS; i++) {
274 |
275 | self.particleContainers[i].update(time);
276 |
277 | }
278 | };
279 |
280 | this.init();
281 |
282 | }
283 |
284 | THREE.GPUParticleSystem.prototype = Object.create(THREE.Object3D.prototype);
285 | THREE.GPUParticleSystem.prototype.constructor = THREE.GPUParticleSystem;
286 |
287 |
288 | // Subclass for particle containers, allows for very large arrays to be spread out
289 | THREE.GPUParticleContainer = function(maxParticles, particleSystem) {
290 |
291 | var self = this;
292 | self.PARTICLE_COUNT = maxParticles || 100000;
293 | self.PARTICLE_CURSOR = 0;
294 | self.time = 0;
295 | self.DPR = window.devicePixelRatio;
296 | self.GPUParticleSystem = particleSystem;
297 |
298 | var particlesPerArray = Math.floor(self.PARTICLE_COUNT / self.MAX_ATTRIBUTES);
299 |
300 | // extend Object3D
301 | THREE.Object3D.apply(this, arguments);
302 |
303 | // construct a couple small arrays used for packing variables into floats etc
304 | var UINT8_VIEW = new Uint8Array(4)
305 | var FLOAT_VIEW = new Float32Array(UINT8_VIEW.buffer)
306 |
307 | function decodeFloat(x, y, z, w) {
308 | UINT8_VIEW[0] = Math.floor(w)
309 | UINT8_VIEW[1] = Math.floor(z)
310 | UINT8_VIEW[2] = Math.floor(y)
311 | UINT8_VIEW[3] = Math.floor(x)
312 | return FLOAT_VIEW[0]
313 | }
314 |
315 | function componentToHex(c) {
316 | var hex = c.toString(16);
317 | return hex.length == 1 ? "0" + hex : hex;
318 | }
319 |
320 | function rgbToHex(r, g, b) {
321 | return "#" + componentToHex(r) + componentToHex(g) + componentToHex(b);
322 | }
323 |
324 | function hexToRgb(hex) {
325 | var r = hex >> 16;
326 | var g = (hex & 0x00FF00) >> 8;
327 | var b = hex & 0x0000FF;
328 |
329 | if (r > 0) r--;
330 | if (g > 0) g--;
331 | if (b > 0) b--;
332 |
333 | return [r, g, b];
334 | };
335 |
336 | self.particles = [];
337 | self.deadParticles = [];
338 | self.particlesAvailableSlot = [];
339 |
340 | // create a container for particles
341 | self.particleUpdate = false;
342 |
343 | // Shader Based Particle System
344 | self.particleShaderGeo = new THREE.BufferGeometry();
345 |
346 | // new hyper compressed attributes
347 | self.particleVertices = new Float32Array(self.PARTICLE_COUNT * 3); // position
348 | self.particlePositionsStartTime = new Float32Array(self.PARTICLE_COUNT * 4); // position
349 | self.particleVelColSizeLife = new Float32Array(self.PARTICLE_COUNT * 4);
350 |
351 | for (var i = 0; i < self.PARTICLE_COUNT; i++) {
352 | self.particlePositionsStartTime[i * 4 + 0] = 100; //x
353 | self.particlePositionsStartTime[i * 4 + 1] = 0; //y
354 | self.particlePositionsStartTime[i * 4 + 2] = 0.0; //z
355 | self.particlePositionsStartTime[i * 4 + 3] = 0.0; //startTime
356 |
357 | self.particleVertices[i * 3 + 0] = 0; //x
358 | self.particleVertices[i * 3 + 1] = 0; //y
359 | self.particleVertices[i * 3 + 2] = 0.0; //z
360 |
361 | self.particleVelColSizeLife[i * 4 + 0] = decodeFloat(128, 128, 0, 0); //vel
362 | self.particleVelColSizeLife[i * 4 + 1] = decodeFloat(0, 254, 0, 254); //color
363 | self.particleVelColSizeLife[i * 4 + 2] = 1.0; //size
364 | self.particleVelColSizeLife[i * 4 + 3] = 0.0; //lifespan
365 | }
366 |
367 | self.particleShaderGeo.addAttribute('position', new THREE.BufferAttribute(self.particleVertices, 3));
368 | self.particleShaderGeo.addAttribute('particlePositionsStartTime', new THREE.BufferAttribute(self.particlePositionsStartTime, 4).setDynamic(true));
369 | self.particleShaderGeo.addAttribute('particleVelColSizeLife', new THREE.BufferAttribute(self.particleVelColSizeLife, 4).setDynamic(true));
370 |
371 | self.posStart = self.particleShaderGeo.getAttribute('particlePositionsStartTime')
372 | self.velCol = self.particleShaderGeo.getAttribute('particleVelColSizeLife');
373 |
374 | self.particleShaderMat = self.GPUParticleSystem.particleShaderMat;
375 |
376 | this.init = function() {
377 | self.particleSystem = new THREE.Points(self.particleShaderGeo, self.particleShaderMat);
378 | self.particleSystem.frustumCulled = false;
379 | this.add(self.particleSystem);
380 | };
381 |
382 | var options = {},
383 | position = new THREE.Vector3(),
384 | velocity = new THREE.Vector3(),
385 | positionRandomness = 0.,
386 | velocityRandomness = 0.,
387 | color = 0xffffff,
388 | colorRandomness = 0.,
389 | turbulence = 0.,
390 | lifetime = 0.,
391 | size = 0.,
392 | sizeRandomness = 0.,
393 | i;
394 |
395 | var maxVel = 2;
396 | var maxSource = 250;
397 | this.offset = 0;
398 | this.count = 0;
399 |
400 | this.spawnParticle = function(options) {
401 |
402 | options = options || {};
403 |
404 | // setup reasonable default values for all arguments
405 | position = options.position !== undefined ? position.copy(options.position) : position.set(0., 0., 0.);
406 | velocity = options.velocity !== undefined ? velocity.copy(options.velocity) : velocity.set(0., 0., 0.);
407 | positionRandomness = options.positionRandomness !== undefined ? options.positionRandomness : 0.0;
408 | velocityRandomness = options.velocityRandomness !== undefined ? options.velocityRandomness : 0.0;
409 | color = options.color !== undefined ? options.color : 0xffffff;
410 | colorRandomness = options.colorRandomness !== undefined ? options.colorRandomness : 1.0;
411 | turbulence = options.turbulence !== undefined ? options.turbulence : 1.0;
412 | lifetime = options.lifetime !== undefined ? options.lifetime : 5.0;
413 | size = options.size !== undefined ? options.size : 10;
414 | sizeRandomness = options.sizeRandomness !== undefined ? options.sizeRandomness : 0.0,
415 | smoothPosition = options.smoothPosition !== undefined ? options.smoothPosition : false;
416 |
417 | if (self.DPR !== undefined) size *= self.DPR;
418 |
419 | i = self.PARTICLE_CURSOR;
420 |
421 | self.posStart.array[i * 4 + 0] = position.x + ((particleSystem.random()) * positionRandomness); // - ( velocity.x * particleSystem.random() ); //x
422 | self.posStart.array[i * 4 + 1] = position.y + ((particleSystem.random()) * positionRandomness); // - ( velocity.y * particleSystem.random() ); //y
423 | self.posStart.array[i * 4 + 2] = position.z + ((particleSystem.random()) * positionRandomness); // - ( velocity.z * particleSystem.random() ); //z
424 | self.posStart.array[i * 4 + 3] = self.time + (particleSystem.random() * 2e-2); //startTime
425 |
426 | if (smoothPosition === true) {
427 | self.posStart.array[i * 4 + 0] += -(velocity.x * particleSystem.random()); //x
428 | self.posStart.array[i * 4 + 1] += -(velocity.y * particleSystem.random()); //y
429 | self.posStart.array[i * 4 + 2] += -(velocity.z * particleSystem.random()); //z
430 | }
431 |
432 | var velX = velocity.x + (particleSystem.random()) * velocityRandomness;
433 | var velY = velocity.y + (particleSystem.random()) * velocityRandomness;
434 | var velZ = velocity.z + (particleSystem.random()) * velocityRandomness;
435 |
436 | // convert turbulence rating to something we can pack into a vec4
437 | var turbulence = Math.floor(turbulence * 254);
438 |
439 | // clamp our value to between 0. and 1.
440 | velX = Math.floor(maxSource * ((velX - -maxVel) / (maxVel - -maxVel)));
441 | velY = Math.floor(maxSource * ((velY - -maxVel) / (maxVel - -maxVel)));
442 | velZ = Math.floor(maxSource * ((velZ - -maxVel) / (maxVel - -maxVel)));
443 |
444 | self.velCol.array[i * 4 + 0] = decodeFloat(velX, velY, velZ, turbulence); //vel
445 |
446 | var rgb = hexToRgb(color);
447 |
448 | for (var c = 0; c < rgb.length; c++) {
449 | rgb[c] = Math.floor(rgb[c] + ((particleSystem.random()) * colorRandomness) * 254);
450 | if (rgb[c] > 254) rgb[c] = 254;
451 | if (rgb[c] < 0) rgb[c] = 0;
452 | }
453 |
454 | self.velCol.array[i * 4 + 1] = decodeFloat(rgb[0], rgb[1], rgb[2], 254); //color
455 | self.velCol.array[i * 4 + 2] = size + (particleSystem.random()) * sizeRandomness; //size
456 | self.velCol.array[i * 4 + 3] = lifetime; //lifespan
457 |
458 | if (this.offset == 0) {
459 | this.offset = self.PARTICLE_CURSOR;
460 | }
461 |
462 | self.count++;
463 |
464 | self.PARTICLE_CURSOR++;
465 |
466 | if (self.PARTICLE_CURSOR >= self.PARTICLE_COUNT) {
467 | self.PARTICLE_CURSOR = 0;
468 | }
469 |
470 | self.particleUpdate = true;
471 |
472 | }
473 |
474 | this.update = function(time) {
475 |
476 | self.time = time;
477 | self.particleShaderMat.uniforms['uTime'].value = time;
478 |
479 | this.geometryUpdate();
480 |
481 | };
482 |
483 | this.geometryUpdate = function() {
484 | if (self.particleUpdate == true) {
485 | self.particleUpdate = false;
486 |
487 | // if we can get away with a partial buffer update, do so
488 | if (self.offset + self.count < self.PARTICLE_COUNT) {
489 | self.posStart.updateRange.offset = self.velCol.updateRange.offset = self.offset * 4;
490 | self.posStart.updateRange.count = self.velCol.updateRange.count = self.count * 4;
491 | } else {
492 | self.posStart.updateRange.offset = 0;
493 | self.posStart.updateRange.count = self.velCol.updateRange.count = (self.PARTICLE_COUNT * 4);
494 | }
495 |
496 | self.posStart.needsUpdate = true;
497 | self.velCol.needsUpdate = true;
498 |
499 | self.offset = 0;
500 | self.count = 0;
501 | }
502 | }
503 |
504 | this.init();
505 |
506 | }
507 |
508 | THREE.GPUParticleContainer.prototype = Object.create(THREE.Object3D.prototype);
509 | THREE.GPUParticleContainer.prototype.constructor = THREE.GPUParticleContainer;
510 |
--------------------------------------------------------------------------------
/online/assets/src/index.js:
--------------------------------------------------------------------------------
1 | import { SpriteText2D, textAlign } from 'three-text2d'
2 |
3 | import './config/WebVRConfig'
4 |
5 | import 'webvr-polyfill/src/main'
6 |
7 | import 'webvr-boilerplate'
8 | import dat from 'dat-gui'
9 |
10 | import './vendor/three/examples/js/controls/MouseControls'
11 | import 'three/examples/js/controls/VRControls'
12 | import 'three/examples/js/effects/VREffect'
13 |
14 | import './vendor/charliehoey/GPUParticleSystem'
15 |
16 | import 'fpsmeter/dist/fpsmeter'
17 |
18 | import 'jquery-modal'
19 |
20 | import 'jquery-modal/jquery.modal.css'
21 |
22 | import MobileDetect from 'mobile-detect'
23 |
24 | import 'perfnow'
25 |
26 | import Stats from 'stats.js'
27 |
28 | import './vendor/modernizr/modernizr-custom'
29 |
30 | import '../../bower_components/ocean/water-material.js'
31 |
32 |
33 |
34 | var sky, sphere, sphere2, moonLightDebugSphere, sphereContainer, lightDirDebugSphere, cameraContainer, skyboxContainer, skyboxContainer2, scene, renderer, camera, dollyCam;
35 | var starData;
36 | var ms_Water;
37 | var skyBox;
38 | var meter, stats;
39 | var cameraFOV = 45;
40 |
41 | var moonScale = 15;
42 |
43 | var waterTextureSize = 512;
44 |
45 | var aMeshMirror;
46 |
47 | var moonLightDirection = new THREE.Vector3(0,0,0);
48 |
49 | var controls;
50 |
51 | var spriteCount = 0;
52 |
53 |
54 |
55 | var parameters =
56 | {
57 | rotX: 34, //don't touch - defines rotation of star container to skybox!
58 | rotY: 32, //don't touch - defines rotation of star container to skybox!
59 | rotZ: 60, //don't touch - defines rotation of star container to skybox!
60 | lightDirX: 0,
61 | lightDirY: 0,
62 | lightDirZ: -1000,
63 |
64 | moonLightDirX: -50,
65 | moonLightDirY: -500,
66 | moonLightDirZ: 100,
67 |
68 | rotXFloor: 270, //defines rotation of floor to sphereContainer
69 | rotYFloor: 0, //defines rotation of floor to sphereContainer
70 | rotZFloor: 0, //defines rotation of floor to sphereContainer
71 | floorOffset: -10, //defines offset of floor to sphereContainer
72 | cameraContainerRotX: 0, //defines default rotation of camera
73 | cameraContainerRotY: 160, //defines default rotation of camera - linked to compass direction
74 | cameraContainerRotZ: 0, //defines default rotation of camera
75 | cameraOffset: 0, //set to 0 to hide water, set to 1 to show
76 | sphereRotX: 0, //defines default rotation of sphere used to point to north and south celestial poles
77 | sphereRotY: 0, //defines default rotation of sphere used to point to north and south celestial poles - if the camera is added to `sphere` and the Y axis is rotated around the sky will appear to rotate around the north / south points
78 | sphereRotZ: 0, //defines default rotation of sphere used to point to north and south celestial poles
79 | sphere2RotX: 0, //defines default rotation of sphere used to point to north and south celestial poles
80 | sphere2RotY: 0, //defines default rotation of sphere used to point to north and south celestial poles
81 | sphere2RotZ: 0, //defines default rotation of sphere used to point to north and south celestial poles
82 | sphereContainerRotX: 0, //defines default rotation of sphereContainer. Controls global orientation of camera
83 | sphereContainerRotY: 0, //defines default rotation of sphereContainer. Controls global orientation of camera
84 | sphereContainerRotZ: 0, //defines default rotation of sphereContainer. Controls global orientation of camera
85 |
86 | skyboxContainerRotX: 0,
87 | skyboxContainerRotY: 0, //adjust Y value to rotate sky around fixed point - linked to time of day
88 | skyboxContainerRotZ: 0,
89 |
90 | skyboxContainer2RotX: 235, //ajust X value to rotate sky into position according to lat
91 | skyboxContainer2RotY: 0,
92 | skyboxContainer2RotZ: 175, //ajust X value to rotate sky into position according to long
93 |
94 | skyboxRotX: 54,
95 | skyboxRotY: 326,
96 | skyboxRotZ: 347
97 | };
98 |
99 | var defaultWaterSide = THREE.FrontSide;
100 |
101 | var debugOn = false;
102 |
103 | var pointClouds = [];
104 |
105 | var spriteContainer;
106 |
107 | var md = new MobileDetect(window.navigator.userAgent);
108 |
109 | var androidVersion = md.versionStr('Android');
110 |
111 | var iOSVersion = md.versionStr('iOS')
112 |
113 |
114 | var oldAndroid = (androidVersion !== null && cmpVersions(androidVersion,'5', '.') < 0);
115 |
116 | var oldIOS = (iOSVersion !== null && cmpVersions(iOSVersion,'9', '_') < 0);
117 |
118 | var canHandleOrientation = false;
119 |
120 | (function() {
121 |
122 | var originalGetExtensionFunction = WebGLRenderingContext.prototype.getExtension;
123 |
124 | // start with this array empty. Once you know which extensions
125 | // the app is requesting you can then selectively add them here
126 | // to figure out which ones are required.
127 | var extensionToReject = [
128 | "OES_texture_float",
129 | "OES_texture_float_linear",
130 | ];
131 |
132 | WebGLRenderingContext.prototype.getExtension = function() {
133 | var name = arguments[0];
134 | if (extensionToReject.indexOf(name) >= 0) {
135 | return null;
136 | }
137 | var ext = originalGetExtensionFunction.apply(this, arguments);
138 | return ext;
139 | };
140 |
141 | }());
142 |
143 | window.addEventListener("compassneedscalibration", function(event) {
144 |
145 | }, true);
146 |
147 |
148 |
149 | function checkCanHandleOrientation(){
150 |
151 | if (window.DeviceOrientationEvent) {
152 | window.addEventListener("deviceorientation", handleOrientation, false);
153 | }
154 |
155 | function handleOrientation(event){
156 | canHandleOrientation = (event !== null); // event will be either null or with event data
157 | }
158 | }
159 |
160 | function cmpVersions (a, b, delimeter) {
161 | var i, l, diff, segmentsA, segmentsB;
162 |
163 | segmentsA = a.replace(/(\.0+)+$/, '').split(delimeter);
164 | segmentsB = b.replace(/(\.0+)+$/, '').split(delimeter);
165 | l = Math.min(segmentsA.length, segmentsB.length);
166 |
167 | for (i = 0; i < l; i++) {
168 | diff = parseInt(segmentsA[i], 10) - parseInt(segmentsB[i], 10);
169 | if (diff !== 0) {
170 | return diff;
171 | }
172 | }
173 | return segmentsA.length - segmentsB.length;
174 | }
175 |
176 | function initFPSMeter(){
177 | // Meter will be attached to `document.body` with all default options.
178 | meter = new FPSMeter({
179 | interval: 100, // Update interval in milliseconds.
180 | smoothing: 10, // Spike smoothing strength. 1 means no smoothing.
181 | show: 'fps', // Whether to show 'fps', or 'ms' = frame duration in milliseconds.
182 | toggleOn: 'click', // Toggle between show 'fps' and 'ms' on this event.
183 | decimals: 1, // Number of decimals in FPS number. 1 = 59.9, 2 = 59.94, ...
184 | maxFps: 60, // Max expected FPS value.
185 | threshold: 100, // Minimal tick reporting interval in milliseconds.
186 |
187 | // Meter position
188 | position: 'absolute', // Meter position.
189 | zIndex: 10, // Meter Z index.
190 | left: '5px', // Meter left offset.
191 | top: '5px', // Meter top offset.
192 | right: 'auto', // Meter right offset.
193 | bottom: 'auto', // Meter bottom offset.
194 | margin: '0 0 0 0', // Meter margin. Helps with centering the counter when left: 50%;
195 |
196 | // Theme
197 | theme: 'dark', // Meter theme. Build in: 'dark', 'light', 'transparent', 'colorful'.
198 | heat: 1, // Allow themes to use coloring by FPS heat. 0 FPS = red, maxFps = green.
199 |
200 | // Graph
201 | graph: 1, // Whether to show history graph.
202 | history: 20 // How many history states to show in a graph.
203 | });
204 | }
205 |
206 | function loadSkyBox() {
207 | var path = "assets/img/skybox3-hr/";
208 | var format = '.png';
209 | var urls = [
210 | path + 'skybox_0' + format, path + 'skybox_1' + format,
211 | path + 'skybox_2' + format, path + 'skybox_3' + format,
212 | path + 'skybox_4' + format, path + 'skybox_5' + format
213 | ];
214 |
215 | //skybox is now no longer using shaders and has actual geometry instead so we can rotate it
216 | var skyGeometry = new THREE.CubeGeometry( 100000, 100000, 100000 );
217 |
218 | var materialArray = [];
219 | for (var i = 0; i < 6; i++)
220 | materialArray.push( new THREE.MeshBasicMaterial({
221 | map: new THREE.TextureLoader().load(urls[i]),
222 | side: THREE.BackSide
223 | }));
224 | var skyMaterial = new THREE.MeshFaceMaterial( materialArray );
225 | skyBox = new THREE.Mesh( skyGeometry, skyMaterial );
226 |
227 | skyboxContainer = new THREE.Object3D();
228 |
229 | skyboxContainer2 = new THREE.Object3D();
230 |
231 | scene.add(skyboxContainer2);
232 |
233 | skyboxContainer2.add(skyboxContainer);
234 |
235 | skyboxContainer.add(skyBox);
236 |
237 | skyboxContainer2.add( sphere2 );
238 |
239 | skyBox.add(sphereContainer);
240 |
241 | if(debugOn){
242 |
243 |
244 | var gui = new dat.GUI();
245 |
246 | gui.add( parameters, 'rotX' ).min(0).max(359).step(1).name('Stars RotX');
247 | gui.add( parameters, 'rotY' ).min(0).max(359).step(1).name('Stars RotY');
248 | gui.add( parameters, 'rotZ' ).min(0).max(359).step(1).name('Stars RotZ');
249 |
250 | gui.add( parameters, 'lightDirX' ).min(-2000).max(2000).step(50).name('LightDir X');
251 | gui.add( parameters, 'lightDirY' ).min(-2000).max(2000).step(50).name('LightDir Y');
252 | gui.add( parameters, 'lightDirZ' ).min(-2000).max(2000).step(50).name('LightDir Z');
253 |
254 | gui.add( parameters, 'rotXFloor' ).min(0).max(359).step(1).name('Floor RotX');
255 | gui.add( parameters, 'rotYFloor' ).min(0).max(359).step(1).name('Floor RotY');
256 | gui.add( parameters, 'rotZFloor' ).min(0).max(359).step(1).name('Floor RotZ');
257 |
258 | gui.add( parameters, 'floorOffset' ).min(-200).max(200).step(5).name('Floor Offset');
259 |
260 | gui.add( parameters, 'cameraContainerRotX' ).min(0).max(359).step(1).name('Camera RotX');
261 | gui.add( parameters, 'cameraContainerRotY' ).min(0).max(359).step(1).name('Camera RotY');
262 | gui.add( parameters, 'cameraContainerRotZ' ).min(0).max(359).step(1).name('Camera RotZ');
263 |
264 | gui.add( parameters, 'cameraOffset' ).min(-100).max(100).step(1).name('Camera Offset');
265 |
266 |
267 | gui.add( parameters, 'sphereRotX' ).min(0).max(359).step(1).name('Sphere RotX');
268 | gui.add( parameters, 'sphereRotY' ).min(0).max(359).step(1).name('Sphere RotY');
269 | gui.add( parameters, 'sphereRotZ' ).min(0).max(359).step(1).name('Sphere RotZ');
270 |
271 | gui.add( parameters, 'sphere2RotX' ).min(0).max(359).step(1).name('Sphere2 RotX');
272 | gui.add( parameters, 'sphere2RotY' ).min(0).max(359).step(1).name('Sphere2 RotY');
273 | gui.add( parameters, 'sphere2RotZ' ).min(0).max(359).step(1).name('Sphere2 RotZ');
274 |
275 | gui.add( parameters, 'skyboxRotX' ).min(0).max(359).step(1).name('Skybox RotX');
276 | gui.add( parameters, 'skyboxRotY' ).min(0).max(359).step(1).name('Skybox RotY');
277 | gui.add( parameters, 'skyboxRotZ' ).min(0).max(359).step(1).name('Skybox RotZ');
278 |
279 | gui.add( parameters, 'skyboxContainerRotX' ).min(0).max(359).step(1).name('SkyboxCon RotX');
280 | gui.add( parameters, 'skyboxContainerRotY' ).min(0).max(359).step(1).name('SkyboxCon RotY');
281 | gui.add( parameters, 'skyboxContainerRotZ' ).min(0).max(359).step(1).name('SkyboxCon RotZ');
282 |
283 | gui.add( parameters, 'skyboxContainer2RotX' ).min(0).max(359).step(1).name('SkyboxCon2 RotX');
284 | gui.add( parameters, 'skyboxContainer2RotY' ).min(0).max(359).step(1).name('SkyboxCon2 RotY');
285 | gui.add( parameters, 'skyboxContainer2RotZ' ).min(0).max(359).step(1).name('SkyboxCon2 RotZ');
286 |
287 | gui.open();
288 | }
289 |
290 |
291 | }
292 |
293 | function addBasicGroundPlane(){
294 | var geometry = new THREE.PlaneGeometry( 1500, 1500, 1, 1 );
295 | var material = new THREE.MeshBasicMaterial( {color: 0x181818, side: THREE.FrontSide} );
296 | aMeshMirror = new THREE.Mesh( geometry, material );
297 | }
298 |
299 | function initScene(){
300 |
301 | // Setup three.js WebGL renderer. Note: Antialiasing is a big performance hit.
302 | // Only enable it if you actually need to.
303 | renderer = new THREE.WebGLRenderer({antialias: false, alpha: false}); //performance hits if antialias or alpha used
304 | renderer.setPixelRatio(window.devicePixelRatio);
305 |
306 | // Append the canvas element created by the renderer to document body element.
307 | document.body.appendChild(renderer.domElement);
308 |
309 |
310 | //var starCount = 10000;
311 | var normalizeRadius = 500;
312 | var pointCloudCount = 3;
313 | var distanceScale = 1; //keep this at 1 now that we are normalizing star distance
314 | var starMagnitudes = 6; //number of visible star magnitude buckets
315 | var starMagnitudeScaleFactor = 4; //higher number = smaller stars
316 | var starSpriteSize = 5; //scaling factor of star sprites for near stars that make up major constellations
317 |
318 | // Create a three.js scene.
319 | scene = new THREE.Scene();
320 |
321 | window.scene = scene; //export as window.scene so the THREE.js inspector can access it
322 |
323 | cameraContainer = new THREE.Object3D();
324 |
325 | // Create a three.js camera.
326 | camera = new THREE.PerspectiveCamera(cameraFOV, window.innerWidth / window.innerHeight, 0.1, 2000000);
327 | dollyCam = new THREE.PerspectiveCamera();
328 |
329 | dollyCam.add(camera);
330 |
331 | cameraContainer.add(dollyCam);
332 |
333 | // Apply VR headset positional data to camera.
334 |
335 | controls = new THREE.VRControls(camera);
336 |
337 | // Apply VR stereo rendering to renderer.
338 | var effect = new THREE.VREffect(renderer);
339 | effect.setSize(window.innerWidth, window.innerHeight);
340 |
341 | var loader = new THREE.TextureLoader();
342 |
343 | // Add light
344 | var directionalLight = new THREE.DirectionalLight(0xffff55, 1);
345 | directionalLight.position.set(parameters.lightDirX, parameters.lightDirY, parameters.lightDirZ);
346 |
347 |
348 | if(oldAndroid || oldIOS){
349 | addBasicGroundPlane();
350 | }else{
351 | // Load textures
352 | var waterNormals = new THREE.TextureLoader().load('assets/img/waternormals.jpg');
353 | waterNormals.wrapS = waterNormals.wrapT = THREE.RepeatWrapping;
354 |
355 |
356 | // Create the water effect - use THREE.BackSide or THREE.FrontSide depending on the default rotation of the cameraContainer
357 | ms_Water = new THREE.Water(renderer, camera, scene, {
358 | textureWidth: waterTextureSize,
359 | textureHeight: waterTextureSize,
360 | waterNormals: waterNormals,
361 | alpha: 1.0,
362 | sunDirection: directionalLight.position.normalize(),
363 | sunColor: 0xffffff,
364 | waterColor: 0x001e0f,
365 | distortionScale: 50.0,
366 | //side: (parameters.cameraContainerRotY == 180) ? THREE.FrontSide : THREE.BackSide
367 | side: defaultWaterSide
368 | });
369 | aMeshMirror = new THREE.Mesh(
370 | new THREE.PlaneBufferGeometry(1500, 1500, 10, 10),
371 | ms_Water.material
372 | );
373 |
374 | aMeshMirror.add(ms_Water);
375 | }
376 |
377 |
378 | sphereContainer = new THREE.Object3D;
379 |
380 | var geometry = new THREE.SphereGeometry( 5, 32, 32 );
381 |
382 | if(debugOn){
383 | var material = new THREE.MeshBasicMaterial( {color: 0xffff00, wireframe: true, opacity: 0.05, transparent: true} );
384 |
385 | sphere = new THREE.Mesh( geometry, material );
386 | }else{
387 | sphere = new THREE.Object3D;
388 | }
389 |
390 |
391 |
392 | if(debugOn){
393 |
394 | var material2 = new THREE.MeshBasicMaterial( {color: 0xffffff, wireframe: true, opacity: 0.05, transparent: true} );
395 |
396 | sphere2 = new THREE.Mesh( geometry, material2 );
397 | }else{
398 | sphere2 = new THREE.Object3D;
399 | }
400 |
401 | var moonMaterial = new THREE.MeshBasicMaterial( {color: 0xffffff, wireframe: false, opacity: 1, transparent: false/*, map: moonTexture*/} );
402 |
403 | moonLightDebugSphere = new THREE.Mesh( geometry, moonMaterial );
404 |
405 |
406 | moonLightDebugSphere.position.set(parameters.moonLightDirX,parameters.moonLightDirY,parameters.moonLightDirZ);
407 |
408 |
409 | lightDirDebugSphere = new THREE.Mesh( geometry, moonMaterial );
410 |
411 |
412 | lightDirDebugSphere.position.set(parameters.lightDirX,parameters.lightDirY,parameters.lightDirZ);
413 |
414 | lightDirDebugSphere.rotation.set(0,180,0);
415 | lightDirDebugSphere.scale.set(moonScale,moonScale,moonScale);
416 |
417 |
418 | scene.add(lightDirDebugSphere);
419 |
420 | sphereContainer.add( sphere );
421 |
422 | scene.add(aMeshMirror); //reflections don't work correctly unless aMeshMirror added to scene
423 | scene.add(cameraContainer);
424 | aMeshMirror.add(directionalLight); //reflections don't work correctly unless light added to scene
425 |
426 |
427 | loader.load('assets/img/star_preview3.png', onStarTextureLoaded);
428 |
429 | function onStarTextureLoaded(texture){
430 | initStars(texture);
431 | }
432 |
433 | function centerObject(obj){
434 | var box = new THREE.Box3().setFromObject( obj );
435 | box.center( obj.position ); // this re-sets the mesh position
436 | obj.position.multiplyScalar( - 1 );
437 | }
438 |
439 |
440 | // Create a VR manager helper to enter and exit VR mode.
441 | var params = {
442 | hideButton: true, // Default: false.
443 | isUndistorted: true // Default: false.
444 | };
445 | var manager = new WebVRManager(renderer, effect, params);
446 |
447 | function initStars(texture){
448 | var x, y, z;
449 |
450 | //generate point cloud geometry
451 |
452 | var pointCloudGeometries = new Array(pointCloudCount);
453 |
454 | spriteContainer = new THREE.Object3D();
455 | skyBox.add(spriteContainer);
456 |
457 | for(var k = 0; k < pointCloudCount; k++){
458 | pointCloudGeometries[k] = new Array(starMagnitudes);
459 | for(var a = 0; a < starMagnitudes; a++){
460 | pointCloudGeometries[k][a] = new THREE.Geometry();
461 | }
462 | }
463 |
464 | for(var l = 0; l < starData.count; l++){
465 |
466 | x = starData.x[l]*distanceScale;
467 | y = starData.y[l]*distanceScale;
468 | z = starData.z[l]*distanceScale;
469 |
470 | //normalize distance of stars, but keep apparent position in sky - we'll use the mag value to determine size later
471 | x = x * normalizeRadius/starData.dist[l];
472 | y = y * normalizeRadius/starData.dist[l];
473 | z = z * normalizeRadius/starData.dist[l];
474 |
475 | var targetPointCloudGeometry;
476 | var doInsertPoint = true;
477 | var doInsertSprite = false;
478 |
479 | var starLabel = (starData.proper[l] !== null) ? starData.proper[l] : (starData.bf[l] !== null) ? starData.bf[l] : (starData.gl[l] !== null) ? starData.gl[l] : null;
480 |
481 |
482 | if(starLabel !== null && starData.mag[l] < 4){
483 |
484 | doInsertSprite = true;
485 |
486 | if(debugOn){
487 |
488 |
489 | if(starLabel !== null){
490 | var sprite = new SpriteText2D(starLabel, { align: new THREE.Vector2(0, 0), font: '10px Arial', fillStyle: '#ffffff' , antialias: false })
491 | sprite.position.set(x,y,z);
492 | spriteContainer.add(sprite);
493 |
494 | sprite.lookAt(camera.position);
495 |
496 | }
497 |
498 | }
499 | }
500 |
501 | //assign points to geometries with specific colors - use first letter of spect value to define color
502 | //determine which color bucket the star should go into
503 | if(starData.spect[l] !== null){
504 | switch(starData.spect[l].charAt(0)){
505 | case "O":
506 | targetPointCloudGeometry = pointCloudGeometries[0];
507 | break;
508 | case "B":
509 | targetPointCloudGeometry = pointCloudGeometries[1];
510 | break;
511 | case "A":
512 | targetPointCloudGeometry = pointCloudGeometries[2];
513 | break;
514 | case "F":
515 | targetPointCloudGeometry = pointCloudGeometries[3];
516 | break;
517 | case "G":
518 | targetPointCloudGeometry = pointCloudGeometries[4];
519 | break;
520 | case "K":
521 | targetPointCloudGeometry = pointCloudGeometries[5];
522 | break;
523 | case "M":
524 | targetPointCloudGeometry = pointCloudGeometries[6];
525 | break;
526 | }
527 | }else{
528 | targetPointCloudGeometry = pointCloudGeometries[2];
529 | }
530 |
531 | targetPointCloudGeometry = pointCloudGeometries[2];
532 |
533 | //determine which size bucket the star should go into
534 |
535 | var targetSize;
536 |
537 | if (starData.mag[l] < 0) {
538 | targetSize = 0;
539 | } else if (starData.mag[l] >= 0 && starData.mag[l] < 1) {
540 | targetSize = 1;
541 | } else if (starData.mag[l] >= 1 && starData.mag[l] < 2) {
542 | targetSize = 2;
543 | } else if (starData.mag[l] >= 2 && starData.mag[l] < 3) {
544 | targetSize = 3;
545 | } else if (starData.mag[l] >= 3 && starData.mag[l] < 4) {
546 | targetSize = 4;
547 | } else if (starData.mag[l] >= 4 && starData.mag[l] < 5) {
548 | targetSize = 5;
549 | } else if (starData.mag[l] >= 5 && starData.mag[l] < 6) {
550 | targetSize = 6;
551 | doInsertPoint = false;
552 | } else if (starData.mag[l] >= 6 && starData.mag[l] < 7) {
553 | targetSize = 7;
554 | doInsertPoint = false;
555 | } else if (starData.mag[l] >= 7 && starData.mag[l] < 16) {
556 | doInsertPoint = false;
557 | } else {
558 | doInsertPoint = false;
559 | }
560 |
561 | if(doInsertPoint && typeof targetPointCloudGeometry !== 'undefined' && typeof targetPointCloudGeometry[targetSize] !== 'undefined'){
562 | targetPointCloudGeometry[targetSize].vertices.push(new THREE.Vector3(x,y,z));
563 | }
564 |
565 | if(doInsertSprite && doInsertPoint){
566 | var material = new THREE.SpriteMaterial( { map: texture, color: 0xffffff, fog: false, depthTest: true} );
567 |
568 | spriteCount++;
569 |
570 |
571 | var sprite = new THREE.Sprite( material );
572 | sprite.position.set(x,y,z);
573 | spriteContainer.add( sprite );
574 | sprite.lookAt(camera.position);
575 |
576 |
577 | sprite.scale.set((starMagnitudes-starData.mag[l])*starSpriteSize,(starMagnitudes-starData.mag[l])*starSpriteSize,(starMagnitudes-starData.mag[l])*starSpriteSize);
578 |
579 | }
580 | }
581 |
582 | console.log("Stars generated: ",spriteCount);
583 |
584 |
585 | for(var j = 0; j < pointCloudCount; j++){
586 |
587 | var color;
588 |
589 | switch(j){
590 | case 0:
591 | color = 0x0000FF;
592 | break;
593 | case 1:
594 | color = 0xADD8E6;
595 | break;
596 | case 2:
597 | color = 0xFFFFFF;
598 | break;
599 | case 3:
600 | color = 0xFFFFE0;
601 | break;
602 | case 4:
603 | color = 0xFFFF00;
604 | break;
605 | case 5:
606 | color = 0xFFA500;
607 | break;
608 | case 6:
609 | color = 0xFF0000;
610 | break;
611 | case 7:
612 | color = 0x663399;
613 | break;
614 | }
615 |
616 | for(var m = 0; m < starMagnitudes; m++){
617 | var material = new THREE.PointsMaterial({
618 | color: color,
619 | size: (starMagnitudes-m+1)/starMagnitudeScaleFactor,
620 | depthTest: false, transparent : false
621 | //wireframe property not supported on PointsMaterial
622 | });
623 |
624 | var pointCloud = new THREE.Points(pointCloudGeometries[j][m], material);
625 |
626 | pointClouds.push(pointCloud);
627 |
628 | centerObject(pointCloud);
629 | }
630 | }
631 | }
632 |
633 | function onWindowResize() {
634 |
635 | camera.aspect = window.innerWidth / window.innerHeight;
636 | camera.updateProjectionMatrix();
637 |
638 | renderer.setSize( window.innerWidth, window.innerHeight );
639 |
640 | render();
641 |
642 | }
643 |
644 | // Request animation frame loop function
645 | var lastRender = 0;
646 | function animate(timestamp) {
647 |
648 | requestAnimationFrame(animate);
649 |
650 | if(typeof meter !== 'undefined'){
651 | meter.tickStart();
652 | }
653 |
654 | if(typeof stats !== 'undefined'){
655 | stats.begin();
656 | }
657 |
658 | lastRender = timestamp;
659 |
660 | //dont render water if it doesnt exist
661 | if(typeof ms_Water !== 'undefined'){
662 |
663 | if(ms_Water !== null){
664 |
665 | ms_Water.material.uniforms.time.value += 1.0 / 60.0;
666 | ms_Water.render();
667 |
668 | }
669 |
670 | }
671 |
672 | // Update VR headset position and apply to camera.
673 |
674 | if(typeof controls !== 'undefined'/* && typeof dollyControls !== 'undefined'*/){
675 |
676 | controls.update();
677 | }
678 |
679 |
680 |
681 | for(var i = 0; i < pointClouds.length; i++){
682 | // rotate the skybox around its axis
683 |
684 | pointClouds[i].rotation.set(parameters.rotX * Math.PI / 180,parameters.rotY * Math.PI / 180,parameters.rotZ * Math.PI / 180);
685 | }
686 |
687 | if(typeof cameraContainer !== 'undefined'){
688 | cameraContainer.rotation.set(parameters.cameraContainerRotX * Math.PI / 180,parameters.cameraContainerRotY * Math.PI / 180,parameters.cameraContainerRotZ * Math.PI / 180);
689 | camera.position.set(0,parameters.cameraOffset,0);
690 |
691 | }
692 |
693 |
694 | if(typeof spriteContainer !== 'undefined'){
695 | spriteContainer.rotation.set(parameters.rotX * Math.PI / 180,parameters.rotY * Math.PI / 180,parameters.rotZ * Math.PI / 180);
696 | }
697 |
698 | if(typeof aMeshMirror !== 'undefined' && aMeshMirror !== null){
699 | aMeshMirror.rotation.set(parameters.rotXFloor * Math.PI / 180,parameters.rotYFloor * Math.PI / 180,parameters.rotZFloor * Math.PI / 180);
700 |
701 | sphereContainer.rotation.set(parameters.sphereContainerRotX * Math.PI / 180,parameters.sphereContainerRotY * Math.PI / 180,parameters.sphereContainerRotZ * Math.PI / 180);
702 | sphere.rotation.set(parameters.sphereRotX * Math.PI / 180,parameters.sphereRotY * Math.PI / 180,parameters.sphereRotZ * Math.PI / 180);
703 | sphere2.rotation.set(parameters.sphere2RotX * Math.PI / 180,parameters.sphere2RotY * Math.PI / 180,parameters.sphere2RotZ * Math.PI / 180);
704 |
705 |
706 | aMeshMirror.position.set(0,parameters.floorOffset,0);
707 |
708 | sphereContainer.rotation.set(parameters.sphereContainerRotX * Math.PI / 180,parameters.sphereContainerRotY * Math.PI / 180,parameters.sphereContainerRotZ * Math.PI / 180);
709 | sphere.rotation.set(parameters.sphereRotX * Math.PI / 180,parameters.sphereRotY * Math.PI / 180,parameters.sphereRotZ * Math.PI / 180);
710 | sphere2.rotation.set(parameters.sphere2RotX * Math.PI / 180,parameters.sphere2RotY * Math.PI / 180,parameters.sphere2RotZ * Math.PI / 180);
711 |
712 |
713 | }
714 |
715 | if(typeof skyBox !== 'undefined'){
716 | skyBox.rotation.set(parameters.skyboxRotX * Math.PI / 180,parameters.skyboxRotY * Math.PI / 180,parameters.skyboxRotZ * Math.PI / 180);
717 |
718 | skyboxContainer.rotation.set(parameters.skyboxContainerRotX * Math.PI / 180,parameters.skyboxContainerRotY * Math.PI / 180,parameters.skyboxContainerRotZ * Math.PI / 180);
719 |
720 | skyboxContainer2.rotation.set(parameters.skyboxContainer2RotX * Math.PI / 180,parameters.skyboxContainer2RotY * Math.PI / 180,parameters.skyboxContainer2RotZ * Math.PI / 180);
721 | }
722 |
723 | if(typeof ms_Water !== 'undefined' && typeof directionalLight !== 'undefined'){
724 |
725 |
726 | moonLightDirection.set(parameters.moonLightDirX,parameters.moonLightDirY,parameters.moonLightDirZ);
727 |
728 | moonLightDebugSphere.position.set(parameters.moonLightDirX,parameters.moonLightDirY,parameters.moonLightDirZ);
729 |
730 | directionalLight.position.set(parameters.lightDirX,parameters.lightDirY,parameters.lightDirZ);
731 | lightDirDebugSphere.position.set(parameters.lightDirX,parameters.lightDirY,parameters.lightDirZ);
732 | ms_Water.material.uniforms.sunDirection.value = directionalLight.position.normalize();
733 | }
734 |
735 | render(timestamp);
736 |
737 |
738 | if(typeof meter !== 'undefined') {
739 |
740 | meter.tick();
741 |
742 | }
743 |
744 | if(typeof stats !== 'undefined'){
745 | stats.end();
746 | }
747 |
748 | }
749 |
750 | function render(timestamp) {
751 |
752 | manager.render(scene, camera, timestamp);
753 |
754 | }
755 |
756 | // Kick off animation loop
757 | onWindowResize();
758 | animate(performance ? performance.now() : Date.now(),true);
759 |
760 | // Reset the position sensor when 'z' pressed.
761 | function onKey(event) {
762 | if (typeof controls !== 'undefined' && event.keyCode == 90) { // z
763 | controls.resetSensor();
764 | }
765 | }
766 |
767 | window.addEventListener('keydown', onKey, true);
768 | }
769 |
770 |
771 | function loadStarData(){
772 |
773 | $.getJSON( 'assets/data/data.json', {}, function(data){
774 |
775 | //init typed arrays for star data
776 | var n = data.length;
777 |
778 | starData = {
779 | dist: new Float64Array(n),
780 | proper: new Array(n),
781 | x: new Float64Array(n),
782 | y: new Float64Array(n),
783 | z: new Float64Array(n),
784 | spect: new Array(n),
785 | mag: new Float64Array(n),
786 | count: n,
787 | absmag: new Float64Array(n),
788 | con: new Array(n),
789 | bf: new Array(n),
790 | gl: new Array(n)
791 | };
792 |
793 | //populated typed arrays with star data
794 | var i = 0;
795 | while (i < n ) {
796 | starData.dist[i] = data[i].dist;
797 |
798 | starData.proper[i] = data[i].proper;
799 | starData.x[i] = data[i].x;
800 | starData.y[i] = data[i].y;
801 | starData.z[i] = data[i].z;
802 | starData.spect[i] = data[i].spect;
803 | starData.mag[i] = data[i].mag;
804 | starData.absmag[i] = data[i].absmag;
805 | starData.con[i] = data[i].con;
806 | starData.bf[i] = data[i].bf;
807 | starData.gl[i] = data[i].gl;
808 |
809 | i++;
810 | }
811 |
812 | Modernizr.addTest('highres', function() {
813 | // for opera
814 | var ratio = '2.99/2';
815 | // for webkit
816 | var num = '1.499';
817 | var mqs = [
818 | 'only screen and (-o-min-device-pixel-ratio:' + ratio + ')',
819 | 'only screen and (min--moz-device-pixel-ratio:' + num + ')',
820 | 'only screen and (-webkit-min-device-pixel-ratio:' + num + ')',
821 | 'only screen and (min-device-pixel-ratio:' + num + ')'
822 | ];
823 | var isHighRes = false;
824 |
825 | // loop through vendors, checking non-prefixed first
826 | for (var i = mqs.length - 1; i >= 0; i--) {
827 | isHighRes = Modernizr.mq( mqs[i] );
828 | // if found one, return early
829 | if ( isHighRes ) {
830 | return isHighRes;
831 | }
832 | }
833 | // not highres
834 | return isHighRes;
835 | });
836 |
837 | //rendering appears to be partially broken on iOS 8 on latest version of three.js iOS 9 has about 90% market
838 | //share so we can recommend users update to that version
839 | //TODO: add three-orbit-controls library to allow mouse controls to be used by default on devices that don't
840 | //support motion controls
841 |
842 | //TODO: move these checks out into a first-run function along with the FPS test to determin if device is capable
843 | //of running the experience. Magnometer should be optional as it is only required to get the correct
844 | //orientation, but user should be warned that their direction won't be accurate
845 |
846 | checkCanHandleOrientation();
847 |
848 | initScene();
849 |
850 | loadSkyBox();
851 |
852 | initFPSMeter();
853 | });
854 | }
855 |
856 |
857 |
858 | $(document).ready(function(){
859 | loadStarData();
860 | });
861 |
862 |
--------------------------------------------------------------------------------