├── LICENSE
├── README.md
├── about
└── screenshot.jpg
├── assets
└── text.png
├── index.html
├── js
├── Maf.js
├── OrbitControls.js
├── THREE.ConstantSpline.js
├── THREE.MeshLine.js
├── isMobile.min.js
└── three.min.js
└── matcap.jpg
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2016 Jaume Sanchez
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 3dwebfest-2016
2 | Ambient effect for 3DWebFest https://www.clicktorelease.com/tmp/threejs/3dwebfest/
3 |
4 |
5 | [](https://www.clicktorelease.com/tmp/threejs/3dwebfest/)
6 |
7 | # License
8 |
9 | MIT licensed
10 |
11 | Copyright (C) 2016 Jaume Sanchez Elias, http://www.clicktorelease.com
12 |
13 |
14 |
--------------------------------------------------------------------------------
/about/screenshot.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/spite/3dwebfest-2016/e738ab53c8ba7b55a1dcaddcbb3a0dff412fd4ed/about/screenshot.jpg
--------------------------------------------------------------------------------
/assets/text.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/spite/3dwebfest-2016/e738ab53c8ba7b55a1dcaddcbb3a0dff412fd4ed/assets/text.png
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 3DWebFest
5 |
6 |
7 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
75 |
76 |
98 |
99 |
124 |
125 |
148 |
149 |
242 |
243 |
278 |
279 |
775 |
776 |
777 |
778 |
--------------------------------------------------------------------------------
/js/Maf.js:
--------------------------------------------------------------------------------
1 | (function() {
2 |
3 | // Module code from underscore.js
4 |
5 | // Establish the root object, `window` (`self`) in the browser, `global`
6 | // on the server, or `this` in some virtual machines. We use `self`
7 | // instead of `window` for `WebWorker` support.
8 | var root = typeof self == 'object' && self.self === self && self ||
9 | typeof global == 'object' && global.global === global && global ||
10 | this;
11 |
12 | var Maf = function(obj) {
13 | if (obj instanceof Maf ) return obj;
14 | if (!(this instanceof Maf )) return new Maf(obj);
15 | this._wrapped = obj;
16 | };
17 |
18 | // Export the Underscore object for **Node.js**, with
19 | // backwards-compatibility for their old module API. If we're in
20 | // the browser, add `Maf` as a global object.
21 | // (`nodeType` is checked to ensure that `module`
22 | // and `exports` are not HTML elements.)
23 | if (typeof exports != 'undefined' && !exports.nodeType) {
24 | if (typeof module != 'undefined' && !module.nodeType && module.exports) {
25 | exports = module.exports = Maf;
26 | }
27 | exports.Maf = Maf;
28 | } else {
29 | root.Maf = Maf;
30 | }
31 |
32 | // Current version.
33 | Maf.VERSION = '1.0.0';
34 |
35 | Maf.PI = Math.PI;
36 |
37 | // https://www.opengl.org/sdk/docs/man/html/clamp.xhtml
38 |
39 | Maf.clamp = function( v, minVal, maxVal ) {
40 | return Math.min( maxVal, Math.max( minVal, v ) );
41 | };
42 |
43 | // https://www.opengl.org/sdk/docs/man/html/step.xhtml
44 |
45 | Maf.step = function( edge, v ) {
46 | return ( v < edge ) ? 0 : 1;
47 | }
48 |
49 | // https://www.opengl.org/sdk/docs/man/html/smoothstep.xhtml
50 |
51 | Maf.smoothStep = function ( edge0, edge1, v ) {
52 | var t = Maf.clamp( ( v - edge0 ) / ( edge1 - edge0 ), 0.0, 1.0 );
53 | return t * t * ( 3.0 - 2.0 * t );
54 | };
55 |
56 | // http://docs.unity3d.com/ScriptReference/Mathf.html
57 | // http://www.shaderific.com/glsl-functions/
58 | // https://www.opengl.org/sdk/docs/man4/html/
59 | // https://msdn.microsoft.com/en-us/library/windows/desktop/ff471376(v=vs.85).aspx
60 | // http://moutjs.com/docs/v0.11/math.html#map
61 | // https://code.google.com/p/kuda/source/browse/public/js/hemi/utils/mathUtils.js?r=8d581c02651077c4ac3f5fc4725323210b6b13cc
62 |
63 | // Converts from degrees to radians.
64 | Maf.deg2Rad = function( degrees ) {
65 | return degrees * Math.PI / 180;
66 | };
67 |
68 | Maf.toRadians = Maf.deg2Rad;
69 |
70 | // Converts from radians to degrees.
71 | Maf.rad2Deg = function(radians) {
72 | return radians * 180 / Math.PI;
73 | };
74 |
75 | Maf.toDegrees = Maf.rad2Deg;
76 |
77 | Maf.clamp01 = function( v ) {
78 | return Maf.clamp( v, 0, 1 );
79 | };
80 |
81 | // https://www.opengl.org/sdk/docs/man/html/mix.xhtml
82 |
83 | Maf.mix = function( x, y, a ) {
84 | if( a <= 0 ) return x;
85 | if( a >= 1 ) return y;
86 | return x + a * (y - x)
87 | };
88 |
89 | Maf.lerp = Maf.mix;
90 |
91 | Maf.inverseMix = function( a, b, v ) {
92 | return ( v - a ) / ( b - a );
93 | };
94 |
95 | Maf.inverseLerp = Maf.inverseMix;
96 |
97 | Maf.mixUnclamped = function( x, y, a ) {
98 | if( a <= 0 ) return x;
99 | if( a >= 1 ) return y;
100 | return x + a * (y - x)
101 | };
102 |
103 | Maf.lerpUnclamped = Maf.mixUnclamped;
104 |
105 | // https://www.opengl.org/sdk/docs/man/html/fract.xhtml
106 |
107 | Maf.fract = function( v ) {
108 | return v - Math.floor( v );
109 | };
110 |
111 | Maf.frac = Maf.fract;
112 |
113 | // http://stackoverflow.com/questions/4965301/finding-if-a-number-is-a-power-of-2
114 |
115 | Maf.isPowerOfTwo = function( v ) {
116 | return ( ( ( v - 1) & v ) == 0 );
117 | };
118 |
119 | // https://bocoup.com/weblog/find-the-closest-power-of-2-with-javascript
120 |
121 | Maf.closestPowerOfTwo = function( v ) {
122 | return Math.pow( 2, Math.round( Math.log( v ) / Math.log( 2 ) ) );
123 | };
124 |
125 | Maf.nextPowerOfTwo = function( v ) {
126 | return Math.pow( 2, Math.ceil( Math.log( v ) / Math.log( 2 ) ) );
127 | }
128 |
129 | // http://stackoverflow.com/questions/1878907/the-smallest-difference-between-2-angles
130 |
131 | //function mod(a, n) { return a - Math.floor(a/n) * n; }
132 | Maf.mod = function(a, n) { return (a % n + n) % n; }
133 |
134 | Maf.deltaAngle = function( a, b ) {
135 | var d = Maf.mod( b - a, 360 );
136 | if( d > 180 ) d = Math.abs( d - 360 );
137 | return d;
138 | };
139 |
140 | Maf.deltaAngleDeg = Maf.deltaAngle;
141 |
142 | Maf.deltaAngleRad = function( a, b ) {
143 | return Maf.toRadians( Maf.deltaAngle( Maf.toDegrees( a ), Maf.toDegrees( b ) ) );
144 | };
145 |
146 | Maf.lerpAngle = function( a, b, t ) {
147 | var angle = Maf.deltaAngle( a, b );
148 | return Maf.mod( a + Maf.lerp( 0, angle, t ), 360 );
149 | };
150 |
151 | Maf.lerpAngleDeg = Maf.lerpAngle;
152 |
153 | Maf.lerpAngleRad = function( a, b, t ) {
154 | return Maf.toRadians( Maf.lerpAngleDeg( Maf.toDegrees( a ), Maf.toDegrees( b ), t ) );
155 | };
156 |
157 | // http://gamedev.stackexchange.com/questions/74324/gamma-space-and-linear-space-with-shader
158 |
159 | Maf.gammaToLinearSpace = function( v ) {
160 | return Math.pow( v, 2.2 );
161 | };
162 |
163 | Maf.linearToGammaSpace = function( v ) {
164 | return Math.pow( v, 1 / 2.2 );
165 | };
166 |
167 | Maf.map = function( from1, to1, from2, to2, v ) {
168 | return from2 + ( v - from1 ) * ( to2 - from2 ) / ( to1 - from1 );
169 | }
170 |
171 | Maf.scale = Maf.map;
172 |
173 | // http://www.iquilezles.org/www/articles/functions/functions.htm
174 |
175 | Maf.almostIdentity = function( x, m, n ) {
176 |
177 | if( x > m ) return x;
178 |
179 | var a = 2 * n - m;
180 | var b = 2 * m - 3 * n;
181 | var t = x / m;
182 |
183 | return ( a * t + b) * t * t + n;
184 | }
185 |
186 | Maf.impulse = function( k, x ) {
187 | var h = k * x;
188 | return h * Math.exp( 1 - h );
189 | };
190 |
191 | Maf.cubicPulse = function( c, w, x ) {
192 | x = Math.abs( x - c );
193 | if( x > w ) return 0;
194 | x /= w;
195 | return 1 - x * x * ( 3 - 2 * x );
196 | }
197 |
198 | Maf.expStep = function( x, k, n ) {
199 | return Math.exp( -k * Math.pow( x, n ) );
200 | }
201 |
202 | Maf.parabola = function( x, k ) {
203 | return Math.pow( 4 * x * ( 1 - x ), k );
204 | }
205 |
206 | Maf.powerCurve = function( x, a, b ) {
207 | var k = Math.pow( a + b, a + b ) / ( Math.pow( a, a ) * Math.pow( b, b ) );
208 | return k * Math.pow( x, a ) * Math.pow( 1 - x, b );
209 | }
210 |
211 | // http://iquilezles.org/www/articles/smin/smin.htm ?
212 |
213 | Maf.latLonToCartesian = function( lat, lon ) {
214 |
215 | lon += 180;
216 | lat = Maf.clamp( lat, -85, 85 );
217 | var phi = Maf.toRadians( 90 - lat );
218 | var theta = Maf.toRadians( 180 - lon );
219 | var x = Math.sin( phi ) * Math.cos( theta );
220 | var y = Math.cos( phi );
221 | var z = Math.sin( phi ) * Math.sin( theta );
222 |
223 | return { x: x, y: y, z: z }
224 |
225 | }
226 |
227 | Maf.cartesianToLatLon = function( x, y, z ) {
228 | var n = Math.sqrt( x * x + y * y + z * z );
229 | return{ lat: Math.asin( z / n ), lon: Math.atan2( y, x ) };
230 | }
231 |
232 | Maf.randomInRange = function( min, max ) {
233 | return min + Math.random() * ( max - min );
234 | }
235 |
236 | Maf.norm = function( v, minVal, maxVal ) {
237 | return ( v - minVal ) / ( maxVal - minVal );
238 | }
239 |
240 | Maf.hash = function( n ) {
241 | return Maf.fract( (1.0 + Math.cos(n)) * 415.92653);
242 | }
243 |
244 | Maf.noise2d = function( x, y ) {
245 | var xhash = Maf.hash( x * 37.0 );
246 | var yhash = Maf.hash( y * 57.0 );
247 | return Maf.fract( xhash + yhash );
248 | }
249 |
250 | // http://iquilezles.org/www/articles/smin/smin.htm
251 |
252 | Maf.smoothMin = function( a, b, k ) {
253 | var res = Math.exp( -k*a ) + Math.exp( -k*b );
254 | return - Math.log( res )/k;
255 | }
256 |
257 | Maf.smoothMax = function( a, b, k ){
258 | return Math.log( Math.exp(a) + Math.exp(b) )/k;
259 | }
260 |
261 |
262 | }());
--------------------------------------------------------------------------------
/js/OrbitControls.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author qiao / https://github.com/qiao
3 | * @author mrdoob / http://mrdoob.com
4 | * @author alteredq / http://alteredqualia.com/
5 | * @author WestLangley / http://github.com/WestLangley
6 | * @author erich666 / http://erichaines.com
7 | */
8 | /*global THREE, console */
9 |
10 | // This set of controls performs orbiting, dollying (zooming), and panning. It maintains
11 | // the "up" direction as +Y, unlike the TrackballControls. Touch on tablet and phones is
12 | // supported.
13 | //
14 | // Orbit - left mouse / touch: one finger move
15 | // Zoom - middle mouse, or mousewheel / touch: two finger spread or squish
16 | // Pan - right mouse, or arrow keys / touch: three finter swipe
17 | //
18 | // This is a drop-in replacement for (most) TrackballControls used in examples.
19 | // That is, include this js file and wherever you see:
20 | // controls = new THREE.TrackballControls( camera );
21 | // controls.target.z = 150;
22 | // Simple substitute "OrbitControls" and the control should work as-is.
23 |
24 | THREE.OrbitControls = function ( object, domElement ) {
25 |
26 | this.object = object;
27 | this.domElement = ( domElement !== undefined ) ? domElement : document;
28 |
29 | // API
30 |
31 | // Set to false to disable this control
32 | this.enabled = true;
33 |
34 | // "target" sets the location of focus, where the control orbits around
35 | // and where it pans with respect to.
36 | this.target = new THREE.Vector3();
37 |
38 | // center is old, deprecated; use "target" instead
39 | this.center = this.target;
40 |
41 | // This option actually enables dollying in and out; left as "zoom" for
42 | // backwards compatibility
43 | this.noZoom = false;
44 | this.zoomSpeed = 1.0;
45 |
46 | // Limits to how far you can dolly in and out
47 | this.minDistance = 0;
48 | this.maxDistance = Infinity;
49 |
50 | // Set to true to disable this control
51 | this.noRotate = false;
52 | this.rotateSpeed = 1.0;
53 |
54 | // Set to true to disable this control
55 | this.noPan = false;
56 | this.keyPanSpeed = 7.0; // pixels moved per arrow key push
57 |
58 | // Set to true to automatically rotate around the target
59 | this.autoRotate = false;
60 | this.autoRotateSpeed = 2.0; // 30 seconds per round when fps is 60
61 |
62 | // How far you can orbit vertically, upper and lower limits.
63 | // Range is 0 to Math.PI radians.
64 | this.minPolarAngle = 0; // radians
65 | this.maxPolarAngle = Math.PI; // radians
66 |
67 | // Set to true to disable use of the keys
68 | this.noKeys = false;
69 |
70 | // The four arrow keys
71 | this.keys = { LEFT: 37, UP: 38, RIGHT: 39, BOTTOM: 40 };
72 |
73 | ////////////
74 | // internals
75 |
76 | var scope = this;
77 |
78 | var EPS = 0.000001;
79 |
80 | var rotateStart = new THREE.Vector2();
81 | var rotateEnd = new THREE.Vector2();
82 | var rotateDelta = new THREE.Vector2();
83 |
84 | var panStart = new THREE.Vector2();
85 | var panEnd = new THREE.Vector2();
86 | var panDelta = new THREE.Vector2();
87 | var panOffset = new THREE.Vector3();
88 |
89 | var offset = new THREE.Vector3();
90 |
91 | var dollyStart = new THREE.Vector2();
92 | var dollyEnd = new THREE.Vector2();
93 | var dollyDelta = new THREE.Vector2();
94 |
95 | var phiDelta = 0;
96 | var thetaDelta = 0;
97 | var scale = 1;
98 | var pan = new THREE.Vector3();
99 |
100 | var lastPosition = new THREE.Vector3();
101 |
102 | var STATE = { NONE : -1, ROTATE : 0, DOLLY : 1, PAN : 2, TOUCH_ROTATE : 3, TOUCH_DOLLY : 4, TOUCH_PAN : 5 };
103 |
104 | var state = STATE.NONE;
105 |
106 | // for reset
107 |
108 | this.target0 = this.target.clone();
109 | this.position0 = this.object.position.clone();
110 |
111 | // so camera.up is the orbit axis
112 |
113 | var quat = new THREE.Quaternion().setFromUnitVectors( object.up, new THREE.Vector3( 0, 1, 0 ) );
114 | var quatInverse = quat.clone().inverse();
115 |
116 | // events
117 |
118 | var changeEvent = { type: 'change' };
119 | var startEvent = { type: 'start'};
120 | var endEvent = { type: 'end'};
121 |
122 | this.rotateLeft = function ( angle ) {
123 |
124 | if ( angle === undefined ) {
125 |
126 | angle = getAutoRotationAngle();
127 |
128 | }
129 |
130 | thetaDelta -= angle;
131 |
132 | };
133 |
134 | this.rotateUp = function ( angle ) {
135 |
136 | if ( angle === undefined ) {
137 |
138 | angle = getAutoRotationAngle();
139 |
140 | }
141 |
142 | phiDelta -= angle;
143 |
144 | };
145 |
146 | // pass in distance in world space to move left
147 | this.panLeft = function ( distance ) {
148 |
149 | var te = this.object.matrix.elements;
150 |
151 | // get X column of matrix
152 | panOffset.set( te[ 0 ], te[ 1 ], te[ 2 ] );
153 | panOffset.multiplyScalar( - distance );
154 |
155 | pan.add( panOffset );
156 |
157 | };
158 |
159 | // pass in distance in world space to move up
160 | this.panUp = function ( distance ) {
161 |
162 | var te = this.object.matrix.elements;
163 |
164 | // get Y column of matrix
165 | panOffset.set( te[ 4 ], te[ 5 ], te[ 6 ] );
166 | panOffset.multiplyScalar( distance );
167 |
168 | pan.add( panOffset );
169 |
170 | };
171 |
172 | // pass in x,y of change desired in pixel space,
173 | // right and down are positive
174 | this.pan = function ( deltaX, deltaY ) {
175 |
176 | var element = scope.domElement === document ? scope.domElement.body : scope.domElement;
177 |
178 | if ( scope.object.fov !== undefined ) {
179 |
180 | // perspective
181 | var position = scope.object.position;
182 | var offset = position.clone().sub( scope.target );
183 | var targetDistance = offset.length();
184 |
185 | // half of the fov is center to top of screen
186 | targetDistance *= Math.tan( ( scope.object.fov / 2 ) * Math.PI / 180.0 );
187 |
188 | // we actually don't use screenWidth, since perspective camera is fixed to screen height
189 | scope.panLeft( 2 * deltaX * targetDistance / element.clientHeight );
190 | scope.panUp( 2 * deltaY * targetDistance / element.clientHeight );
191 |
192 | } else if ( scope.object.top !== undefined ) {
193 |
194 | // orthographic
195 | scope.panLeft( deltaX * (scope.object.right - scope.object.left) / element.clientWidth );
196 | scope.panUp( deltaY * (scope.object.top - scope.object.bottom) / element.clientHeight );
197 |
198 | } else {
199 |
200 | // camera neither orthographic or perspective
201 | console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.' );
202 |
203 | }
204 |
205 | };
206 |
207 | this.dollyIn = function ( dollyScale ) {
208 |
209 | if ( dollyScale === undefined ) {
210 |
211 | dollyScale = getZoomScale();
212 |
213 | }
214 |
215 | scale /= dollyScale;
216 |
217 | };
218 |
219 | this.dollyOut = function ( dollyScale ) {
220 |
221 | if ( dollyScale === undefined ) {
222 |
223 | dollyScale = getZoomScale();
224 |
225 | }
226 |
227 | scale *= dollyScale;
228 |
229 | };
230 |
231 | this.update = function () {
232 |
233 | var position = this.object.position;
234 |
235 | offset.copy( position ).sub( this.target );
236 |
237 | // rotate offset to "y-axis-is-up" space
238 | offset.applyQuaternion( quat );
239 |
240 | // angle from z-axis around y-axis
241 |
242 | var theta = Math.atan2( offset.x, offset.z );
243 |
244 | // angle from y-axis
245 |
246 | var phi = Math.atan2( Math.sqrt( offset.x * offset.x + offset.z * offset.z ), offset.y );
247 |
248 | if ( this.autoRotate ) {
249 |
250 | this.rotateLeft( getAutoRotationAngle() );
251 |
252 | }
253 |
254 | theta += thetaDelta;
255 | phi += phiDelta;
256 |
257 | // restrict phi to be between desired limits
258 | phi = Math.max( this.minPolarAngle, Math.min( this.maxPolarAngle, phi ) );
259 |
260 | // restrict phi to be betwee EPS and PI-EPS
261 | phi = Math.max( EPS, Math.min( Math.PI - EPS, phi ) );
262 |
263 | var radius = offset.length() * scale;
264 |
265 | // restrict radius to be between desired limits
266 | radius = Math.max( this.minDistance, Math.min( this.maxDistance, radius ) );
267 |
268 | // move target to panned location
269 | this.target.add( pan );
270 |
271 | offset.x = radius * Math.sin( phi ) * Math.sin( theta );
272 | offset.y = radius * Math.cos( phi );
273 | offset.z = radius * Math.sin( phi ) * Math.cos( theta );
274 |
275 | // rotate offset back to "camera-up-vector-is-up" space
276 | offset.applyQuaternion( quatInverse );
277 |
278 | position.copy( this.target ).add( offset );
279 |
280 | this.object.lookAt( this.target );
281 |
282 | thetaDelta = 0;
283 | phiDelta = 0;
284 | scale = 1;
285 | pan.set( 0, 0, 0 );
286 |
287 | if ( lastPosition.distanceToSquared( this.object.position ) > EPS ) {
288 |
289 | this.dispatchEvent( changeEvent );
290 |
291 | lastPosition.copy( this.object.position );
292 |
293 | }
294 |
295 | };
296 |
297 |
298 | this.reset = function () {
299 |
300 | state = STATE.NONE;
301 |
302 | this.target.copy( this.target0 );
303 | this.object.position.copy( this.position0 );
304 |
305 | this.update();
306 |
307 | };
308 |
309 | function getAutoRotationAngle() {
310 |
311 | return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed;
312 |
313 | }
314 |
315 | function getZoomScale() {
316 |
317 | return Math.pow( 0.95, scope.zoomSpeed );
318 |
319 | }
320 |
321 | function onMouseDown( event ) {
322 |
323 | if ( scope.enabled === false ) return;
324 | event.preventDefault();
325 |
326 | if ( event.button === 0 ) {
327 | if ( scope.noRotate === true ) return;
328 |
329 | state = STATE.ROTATE;
330 |
331 | rotateStart.set( event.clientX, event.clientY );
332 |
333 | } else if ( event.button === 1 ) {
334 | if ( scope.noZoom === true ) return;
335 |
336 | state = STATE.DOLLY;
337 |
338 | dollyStart.set( event.clientX, event.clientY );
339 |
340 | } else if ( event.button === 2 ) {
341 | if ( scope.noPan === true ) return;
342 |
343 | state = STATE.PAN;
344 |
345 | panStart.set( event.clientX, event.clientY );
346 |
347 | }
348 |
349 | scope.domElement.addEventListener( 'mousemove', onMouseMove, false );
350 | scope.domElement.addEventListener( 'mouseup', onMouseUp, false );
351 | scope.dispatchEvent( startEvent );
352 |
353 | }
354 |
355 | function onMouseMove( event ) {
356 |
357 | if ( scope.enabled === false ) return;
358 |
359 | event.preventDefault();
360 |
361 | var element = scope.domElement === document ? scope.domElement.body : scope.domElement;
362 |
363 | if ( state === STATE.ROTATE ) {
364 |
365 | if ( scope.noRotate === true ) return;
366 |
367 | rotateEnd.set( event.clientX, event.clientY );
368 | rotateDelta.subVectors( rotateEnd, rotateStart );
369 |
370 | // rotating across whole screen goes 360 degrees around
371 | scope.rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth * scope.rotateSpeed );
372 |
373 | // rotating up and down along whole screen attempts to go 360, but limited to 180
374 | scope.rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight * scope.rotateSpeed );
375 |
376 | rotateStart.copy( rotateEnd );
377 |
378 | } else if ( state === STATE.DOLLY ) {
379 |
380 | if ( scope.noZoom === true ) return;
381 |
382 | dollyEnd.set( event.clientX, event.clientY );
383 | dollyDelta.subVectors( dollyEnd, dollyStart );
384 |
385 | if ( dollyDelta.y > 0 ) {
386 |
387 | scope.dollyIn();
388 |
389 | } else {
390 |
391 | scope.dollyOut();
392 |
393 | }
394 |
395 | dollyStart.copy( dollyEnd );
396 |
397 | } else if ( state === STATE.PAN ) {
398 |
399 | if ( scope.noPan === true ) return;
400 |
401 | panEnd.set( event.clientX, event.clientY );
402 | panDelta.subVectors( panEnd, panStart );
403 |
404 | scope.pan( panDelta.x, panDelta.y );
405 |
406 | panStart.copy( panEnd );
407 |
408 | }
409 |
410 | scope.update();
411 |
412 | }
413 |
414 | function onMouseUp( /* event */ ) {
415 |
416 | if ( scope.enabled === false ) return;
417 |
418 | scope.domElement.removeEventListener( 'mousemove', onMouseMove, false );
419 | scope.domElement.removeEventListener( 'mouseup', onMouseUp, false );
420 | scope.dispatchEvent( endEvent );
421 | state = STATE.NONE;
422 |
423 | }
424 |
425 | function onMouseWheel( event ) {
426 |
427 | if ( scope.enabled === false || scope.noZoom === true ) return;
428 |
429 | event.preventDefault();
430 | event.stopPropagation();
431 |
432 | var delta = 0;
433 |
434 | if ( event.wheelDelta !== undefined ) { // WebKit / Opera / Explorer 9
435 |
436 | delta = event.wheelDelta;
437 |
438 | } else if ( event.detail !== undefined ) { // Firefox
439 |
440 | delta = - event.detail;
441 |
442 | }
443 |
444 | if ( delta > 0 ) {
445 |
446 | scope.dollyOut();
447 |
448 | } else {
449 |
450 | scope.dollyIn();
451 |
452 | }
453 |
454 | scope.update();
455 | scope.dispatchEvent( startEvent );
456 | scope.dispatchEvent( changeEvent );
457 | scope.dispatchEvent( endEvent );
458 |
459 | }
460 |
461 | function onKeyDown( event ) {
462 |
463 | if ( scope.enabled === false || scope.noKeys === true || scope.noPan === true ) return;
464 |
465 | switch ( event.keyCode ) {
466 |
467 | case scope.keys.UP:
468 | scope.pan( 0, scope.keyPanSpeed );
469 | scope.update();
470 | break;
471 |
472 | case scope.keys.BOTTOM:
473 | scope.pan( 0, - scope.keyPanSpeed );
474 | scope.update();
475 | break;
476 |
477 | case scope.keys.LEFT:
478 | scope.pan( scope.keyPanSpeed, 0 );
479 | scope.update();
480 | break;
481 |
482 | case scope.keys.RIGHT:
483 | scope.pan( - scope.keyPanSpeed, 0 );
484 | scope.update();
485 | break;
486 |
487 | }
488 |
489 | }
490 |
491 | function touchstart( event ) {
492 |
493 | if ( scope.enabled === false ) return;
494 |
495 | switch ( event.touches.length ) {
496 |
497 | case 1: // one-fingered touch: rotate
498 |
499 | if ( scope.noRotate === true ) return;
500 |
501 | state = STATE.TOUCH_ROTATE;
502 |
503 | rotateStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
504 | break;
505 |
506 | case 2: // two-fingered touch: dolly
507 |
508 | if ( scope.noZoom === true ) return;
509 |
510 | state = STATE.TOUCH_DOLLY;
511 |
512 | var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
513 | var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
514 | var distance = Math.sqrt( dx * dx + dy * dy );
515 | dollyStart.set( 0, distance );
516 | break;
517 |
518 | case 3: // three-fingered touch: pan
519 |
520 | if ( scope.noPan === true ) return;
521 |
522 | state = STATE.TOUCH_PAN;
523 |
524 | panStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
525 | break;
526 |
527 | default:
528 |
529 | state = STATE.NONE;
530 |
531 | }
532 |
533 | scope.dispatchEvent( startEvent );
534 |
535 | }
536 |
537 | function touchmove( event ) {
538 |
539 | if ( scope.enabled === false ) return;
540 |
541 | event.preventDefault();
542 | event.stopPropagation();
543 |
544 | var element = scope.domElement === document ? scope.domElement.body : scope.domElement;
545 |
546 | switch ( event.touches.length ) {
547 |
548 | case 1: // one-fingered touch: rotate
549 |
550 | if ( scope.noRotate === true ) return;
551 | if ( state !== STATE.TOUCH_ROTATE ) return;
552 |
553 | rotateEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
554 | rotateDelta.subVectors( rotateEnd, rotateStart );
555 |
556 | // rotating across whole screen goes 360 degrees around
557 | scope.rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth * scope.rotateSpeed );
558 | // rotating up and down along whole screen attempts to go 360, but limited to 180
559 | scope.rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight * scope.rotateSpeed );
560 |
561 | rotateStart.copy( rotateEnd );
562 |
563 | scope.update();
564 | break;
565 |
566 | case 2: // two-fingered touch: dolly
567 |
568 | if ( scope.noZoom === true ) return;
569 | if ( state !== STATE.TOUCH_DOLLY ) return;
570 |
571 | var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
572 | var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
573 | var distance = Math.sqrt( dx * dx + dy * dy );
574 |
575 | dollyEnd.set( 0, distance );
576 | dollyDelta.subVectors( dollyEnd, dollyStart );
577 |
578 | if ( dollyDelta.y > 0 ) {
579 |
580 | scope.dollyOut();
581 |
582 | } else {
583 |
584 | scope.dollyIn();
585 |
586 | }
587 |
588 | dollyStart.copy( dollyEnd );
589 |
590 | scope.update();
591 | break;
592 |
593 | case 3: // three-fingered touch: pan
594 |
595 | if ( scope.noPan === true ) return;
596 | if ( state !== STATE.TOUCH_PAN ) return;
597 |
598 | panEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
599 | panDelta.subVectors( panEnd, panStart );
600 |
601 | scope.pan( panDelta.x, panDelta.y );
602 |
603 | panStart.copy( panEnd );
604 |
605 | scope.update();
606 | break;
607 |
608 | default:
609 |
610 | state = STATE.NONE;
611 |
612 | }
613 |
614 | }
615 |
616 | function touchend( /* event */ ) {
617 |
618 | if ( scope.enabled === false ) return;
619 |
620 | scope.dispatchEvent( endEvent );
621 | state = STATE.NONE;
622 |
623 | }
624 |
625 | this.domElement.addEventListener( 'contextmenu', function ( event ) { event.preventDefault(); }, false );
626 | this.domElement.addEventListener( 'mousedown', onMouseDown, false );
627 | this.domElement.addEventListener( 'mousewheel', onMouseWheel, false );
628 | this.domElement.addEventListener( 'DOMMouseScroll', onMouseWheel, false ); // firefox
629 |
630 | this.domElement.addEventListener( 'touchstart', touchstart, false );
631 | this.domElement.addEventListener( 'touchend', touchend, false );
632 | this.domElement.addEventListener( 'touchmove', touchmove, false );
633 |
634 | window.addEventListener( 'keydown', onKeyDown, false );
635 |
636 | // force an update at start
637 | this.update();
638 |
639 | };
640 |
641 | THREE.OrbitControls.prototype = Object.create( THREE.EventDispatcher.prototype );
--------------------------------------------------------------------------------
/js/THREE.ConstantSpline.js:
--------------------------------------------------------------------------------
1 | THREE.ConstantSpline = function() {
2 |
3 | this.p0 = new THREE.Vector3();
4 | this.p1 = new THREE.Vector3();
5 | this.p2 = new THREE.Vector3();
6 | this.p3 = new THREE.Vector3();
7 |
8 | this.tmp = new THREE.Vector3();
9 | this.res = new THREE.Vector3();
10 | this.o = new THREE.Vector3();
11 |
12 | this.points = [];
13 | this.lPoints = [];
14 | this.steps = [];
15 |
16 | this.inc = .01;
17 | this.d = 0;
18 |
19 | this.distancesNeedUpdate = false;
20 |
21 | };
22 |
23 | THREE.ConstantSpline.prototype.calculate = function() {
24 |
25 | this.d = 0;
26 | this.points = [];
27 |
28 | this.o.copy( this.p0 );
29 |
30 | for( var j = 0; j <= 1; j += this.inc ) {
31 |
32 | var i = ( 1 - j );
33 | var ii = i * i;
34 | var iii = ii * i;
35 | var jj = j * j;
36 | var jjj = jj * j;
37 |
38 | this.res.set( 0, 0, 0 );
39 |
40 | this.tmp.copy( this.p0 );
41 | this.tmp.multiplyScalar( iii );
42 | this.res.add( this.tmp );
43 |
44 | this.tmp.copy( this.p1 );
45 | this.tmp.multiplyScalar( 3 * j * ii );
46 | this.res.add( this.tmp );
47 |
48 | this.tmp.copy( this.p2 );
49 | this.tmp.multiplyScalar( 3 * jj * i );
50 | this.res.add( this.tmp );
51 |
52 | this.tmp.copy( this.p3 );
53 | this.tmp.multiplyScalar( jjj );
54 | this.res.add( this.tmp );
55 |
56 | this.points.push( this.res.clone() );
57 |
58 | }
59 |
60 | this.points.push( this.p3.clone() );
61 |
62 | this.distancesNeedUpdate = true;
63 |
64 | };
65 |
66 | THREE.ConstantSpline.prototype.calculateDistances = function() {
67 |
68 | this.steps = [];
69 | this.d = 0;
70 |
71 | var from, to, td = 0;
72 |
73 | for( var j = 0; j < this.points.length - 1; j++ ) {
74 |
75 | this.points[ j ].distance = td;
76 | this.points[ j ].ac = this.d;
77 |
78 | from = this.points[ j ],
79 | to = this.points[ j + 1 ],
80 | td = to.distanceTo( from );
81 |
82 | this.d += td;
83 |
84 | }
85 |
86 | this.points[ this.points.length - 1 ].distance = 0;
87 | this.points[ this.points.length - 1 ].ac = this.d;
88 |
89 | }
90 |
91 | THREE.ConstantSpline.prototype.reticulate = function( settings ) {
92 |
93 | if( this.distancesNeedUpdate ) {
94 | this.calculateDistances();
95 | this.distancesNeedUpdate = false;
96 | }
97 |
98 | this.lPoints = [];
99 |
100 | var l = [];
101 |
102 | var steps, distancePerStep;
103 |
104 | if( settings.steps) {
105 | steps = settings.steps;
106 | distancePerStep = this.d / steps;
107 | }
108 |
109 | if( settings.distancePerStep ) {
110 | distancePerStep = settings.distancePerStep;
111 | steps = this.d / distancePerStep;
112 | }
113 |
114 | var d = 0,
115 | p = 0;
116 |
117 | this.lPoints = [];
118 |
119 | var current = new THREE.Vector3();
120 | current.copy( this.points[ 0 ].clone() );
121 | this.lPoints.push( current.clone() );
122 |
123 | function splitSegment( a, b, l ) {
124 |
125 | var t = b.clone();
126 | var d = 0;
127 | t.sub( a );
128 | var rd = t.length();
129 | t.normalize();
130 | t.multiplyScalar( distancePerStep );
131 | var s = Math.floor( rd / distancePerStep );
132 | for( var j = 0; j < s; j++ ) {
133 | a.add( t );
134 | l.push( a.clone() );
135 | d += distancePerStep;
136 | }
137 | return d;
138 | }
139 |
140 | for( var j = 0; j < this.points.length; j++ ) {
141 |
142 | if( this.points[ j ].ac - d > distancePerStep ) {
143 |
144 | d += splitSegment( current, this.points[ j ], this.lPoints );
145 |
146 | }
147 |
148 | }
149 | this.lPoints.push( this.points[ this.points.length - 1 ].clone() );
150 |
151 |
152 | };
--------------------------------------------------------------------------------
/js/THREE.MeshLine.js:
--------------------------------------------------------------------------------
1 | THREE.MeshLine = function() {
2 |
3 | this.positions = [];
4 |
5 | this.previous = [];
6 | this.next = [];
7 | this.side = [];
8 | this.width = [];
9 | this.indices_array = [];
10 | this.uvs = [];
11 |
12 | this.geometry = new THREE.BufferGeometry();
13 |
14 | this.widthCallback = null;
15 |
16 | }
17 |
18 | THREE.MeshLine.prototype.setGeometry = function( g, c ) {
19 |
20 | this.widthCallback = c;
21 |
22 | this.positions = [];
23 |
24 | if( g instanceof THREE.Geometry ) {
25 | for( var j = 0; j < g.vertices.length; j++ ) {
26 | var v = g.vertices[ j ];
27 | this.positions.push( v.x, v.y, v.z );
28 | this.positions.push( v.x, v.y, v.z );
29 | }
30 | }
31 |
32 | if( g instanceof THREE.BufferGeometry ) {
33 | // read attribute positions ?
34 | }
35 |
36 | if( g instanceof Float32Array || g instanceof Array ) {
37 | for( var j = 0; j < g.length; j += 3 ) {
38 | this.positions.push( g[ j ], g[ j + 1 ], g[ j + 2 ] );
39 | this.positions.push( g[ j ], g[ j + 1 ], g[ j + 2 ] );
40 | }
41 | }
42 |
43 | this.process();
44 |
45 | }
46 |
47 | THREE.MeshLine.prototype.compareV3 = function( a, b ) {
48 |
49 | var aa = a * 6;
50 | var ab = b * 6;
51 | return ( this.positions[ aa ] === this.positions[ ab ] ) && ( this.positions[ aa + 1 ] === this.positions[ ab + 1 ] ) && ( this.positions[ aa + 2 ] === this.positions[ ab + 2 ] );
52 |
53 | }
54 |
55 | THREE.MeshLine.prototype.copyV3 = function( a ) {
56 |
57 | var aa = a * 6;
58 | return [ this.positions[ aa ], this.positions[ aa + 1 ], this.positions[ aa + 2 ] ];
59 |
60 | }
61 |
62 | THREE.MeshLine.prototype.process = function() {
63 |
64 | var l = this.positions.length / 6;
65 |
66 | this.previous = [];
67 | this.next = [];
68 | this.side = [];
69 | this.width = [];
70 | this.indices_array = [];
71 | this.uvs = [];
72 |
73 | for( var j = 0; j < l; j++ ) {
74 | this.side.push( 1 );
75 | this.side.push( -1 );
76 | }
77 |
78 | var w;
79 | for( var j = 0; j < l; j++ ) {
80 | if( this.widthCallback ) w = this.widthCallback( j / ( l -1 ) );
81 | else w = 1;
82 | this.width.push( w );
83 | this.width.push( w );
84 | }
85 |
86 | for( var j = 0; j < l; j++ ) {
87 | this.uvs.push( j / ( l - 1 ), 0 );
88 | this.uvs.push( j / ( l - 1 ), 1 );
89 | }
90 |
91 | var v;
92 |
93 | if( this.compareV3( 0, l - 1 ) ){
94 | v = this.copyV3( l - 2 );
95 | } else {
96 | v = this.copyV3( 0 );
97 | }
98 | this.previous.push( v[ 0 ], v[ 1 ], v[ 2 ] );
99 | this.previous.push( v[ 0 ], v[ 1 ], v[ 2 ] );
100 | for( var j = 0; j < l - 1; j++ ) {
101 | v = this.copyV3( j );
102 | this.previous.push( v[ 0 ], v[ 1 ], v[ 2 ] );
103 | this.previous.push( v[ 0 ], v[ 1 ], v[ 2 ] );
104 | }
105 |
106 | for( var j = 1; j < l; j++ ) {
107 | v = this.copyV3( j );
108 | this.next.push( v[ 0 ], v[ 1 ], v[ 2 ] );
109 | this.next.push( v[ 0 ], v[ 1 ], v[ 2 ] );
110 | }
111 |
112 | if( this.compareV3( l - 1, 0 ) ){
113 | v = this.copyV3( 1 );
114 | } else {
115 | v = this.copyV3( l - 1 );
116 | }
117 | this.next.push( v[ 0 ], v[ 1 ], v[ 2 ] );
118 | this.next.push( v[ 0 ], v[ 1 ], v[ 2 ] );
119 |
120 | for( var j = 0; j < l - 1; j++ ) {
121 | var n = j * 2;
122 | this.indices_array.push( n, n + 1, n + 2 );
123 | this.indices_array.push( n + 2, n + 1, n + 3 );
124 | }
125 |
126 | if (!this.attributes) {
127 | this.attributes = {
128 | position: new THREE.BufferAttribute( new Float32Array( this.positions ), 3 ),
129 | previous: new THREE.BufferAttribute( new Float32Array( this.previous ), 3 ),
130 | next: new THREE.BufferAttribute( new Float32Array( this.next ), 3 ),
131 | side: new THREE.BufferAttribute( new Float32Array( this.side ), 1 ),
132 | width: new THREE.BufferAttribute( new Float32Array( this.width ), 1 ),
133 | uv: new THREE.BufferAttribute( new Float32Array( this.uvs ), 2 ),
134 | index: new THREE.BufferAttribute( new Uint16Array( this.indices_array ), 1 )
135 | }
136 | } else {
137 | this.attributes.position.copyArray(new Float32Array(this.positions));
138 | this.attributes.position.needsUpdate = true;
139 | this.attributes.previous.copyArray(new Float32Array(this.previous));
140 | this.attributes.previous.needsUpdate = true;
141 | this.attributes.next.copyArray(new Float32Array(this.next));
142 | this.attributes.next.needsUpdate = true;
143 | this.attributes.side.copyArray(new Float32Array(this.side));
144 | this.attributes.side.needsUpdate = true;
145 | this.attributes.width.copyArray(new Float32Array(this.width));
146 | this.attributes.width.needsUpdate = true;
147 | this.attributes.uv.copyArray(new Float32Array(this.uvs));
148 | this.attributes.uv.needsUpdate = true;
149 | this.attributes.index.copyArray(new Uint16Array(this.index));
150 | this.attributes.index.needsUpdate = true;
151 | }
152 |
153 | this.geometry.addAttribute( 'position', this.attributes.position );
154 | this.geometry.addAttribute( 'previous', this.attributes.previous );
155 | this.geometry.addAttribute( 'next', this.attributes.next );
156 | this.geometry.addAttribute( 'side', this.attributes.side );
157 | this.geometry.addAttribute( 'width', this.attributes.width );
158 | this.geometry.addAttribute( 'uv', this.attributes.uv );
159 |
160 | this.geometry.setIndex( this.attributes.index );
161 |
162 | }
163 |
164 | THREE.MeshLineMaterial = function ( parameters ) {
165 |
166 | var vertexShaderSource = [
167 | 'precision highp float;',
168 | '',
169 | 'attribute vec3 position;',
170 | 'attribute vec3 previous;',
171 | 'attribute vec3 next;',
172 | 'attribute float side;',
173 | 'attribute float width;',
174 | 'attribute vec2 uv;',
175 | '',
176 | 'uniform mat4 projectionMatrix;',
177 | 'uniform mat4 modelViewMatrix;',
178 | 'uniform vec2 resolution;',
179 | 'uniform float lineWidth;',
180 | 'uniform vec3 color;',
181 | 'uniform float opacity;',
182 | 'uniform float near;',
183 | 'uniform float far;',
184 | 'uniform float sizeAttenuation;',
185 | '',
186 | 'varying vec2 vUV;',
187 | 'varying vec4 vColor;',
188 | 'varying float depth;',
189 | '',
190 | 'vec2 fix( vec4 i, float aspect ) {',
191 | '',
192 | ' vec2 res = i.xy / i.w;',
193 | ' res.x *= aspect;',
194 | ' return res;',
195 | '',
196 | '}',
197 | '',
198 | 'void main() {',
199 | '',
200 | ' float aspect = resolution.x / resolution.y;',
201 | ' float pixelWidthRatio = 1. / (resolution.x * projectionMatrix[0][0]);',
202 | '',
203 | ' vColor = vec4( color, opacity );',
204 | ' vUV = uv;',
205 | '',
206 | ' mat4 m = projectionMatrix * modelViewMatrix;',
207 | ' vec4 finalPosition = m * vec4( position, 1.0 );',
208 | ' vec4 prevPos = m * vec4( previous, 1.0 );',
209 | ' vec4 nextPos = m * vec4( next, 1.0 );',
210 | '',
211 | ' vec2 currentP = fix( finalPosition, aspect );',
212 | ' vec2 prevP = fix( prevPos, aspect );',
213 | ' vec2 nextP = fix( nextPos, aspect );',
214 | '',
215 | ' float pixelWidth = finalPosition.w * pixelWidthRatio;',
216 | ' float w = 1.8 * pixelWidth * lineWidth * width;',
217 | '',
218 | ' if( sizeAttenuation == 1. ) {',
219 | ' w = 1.8 * lineWidth * width;',
220 | ' }',
221 | '',
222 | ' vec2 dir;',
223 | ' if( nextP == currentP ) dir = normalize( currentP - prevP );',
224 | ' else if( prevP == currentP ) dir = normalize( nextP - currentP );',
225 | ' else {',
226 | ' vec2 dir1 = normalize( currentP - prevP );',
227 | ' vec2 dir2 = normalize( nextP - currentP );',
228 | ' dir = normalize( dir1 + dir2 );',
229 | '',
230 | ' vec2 perp = vec2( -dir1.y, dir1.x );',
231 | ' vec2 miter = vec2( -dir.y, dir.x );',
232 | ' //w = clamp( w / dot( miter, perp ), 0., 4. * lineWidth * width );',
233 | '',
234 | ' }',
235 | '',
236 | ' //vec2 normal = ( cross( vec3( dir, 0. ), vec3( 0., 0., 1. ) ) ).xy;',
237 | ' vec2 normal = vec2( -dir.y, dir.x );',
238 | ' normal.x /= aspect;',
239 | ' normal *= .5 * w;',
240 | '',
241 | ' vec4 offset = vec4( normal * side, 0.0, 1.0 );',
242 | ' finalPosition.xy += offset.xy;',
243 | '',
244 | ' gl_Position = finalPosition;',
245 | ' depth = gl_Position.z / 1100.;',
246 | '',
247 | '}' ];
248 |
249 | var fragmentShaderSource = [
250 | '#extension GL_OES_standard_derivatives : enable',
251 | 'precision mediump float;',
252 | '',
253 | 'uniform sampler2D map;',
254 | 'uniform float useMap;',
255 | 'uniform float useDash;',
256 | 'uniform vec2 dashArray;',
257 | 'uniform float drawDepth;',
258 | '',
259 | 'varying vec2 vUV;',
260 | 'varying vec4 vColor;',
261 | 'varying float depth;',
262 | '',
263 | 'void main() {',
264 | '',
265 | ' vec4 c = vColor;',
266 | ' if( useMap == 1. ) c *= texture2D( map, vUV );',
267 | ' if( useDash == 1. ){',
268 | ' ',
269 | ' }',
270 | ' if( drawDepth == 0. ) gl_FragColor = c; else gl_FragColor = vec4( vec3( depth ), 1. );',
271 | '',
272 | '}' ];
273 |
274 | function check( v, d ) {
275 | if( v === undefined ) return d;
276 | return v;
277 | }
278 |
279 | THREE.Material.call( this );
280 |
281 | parameters = parameters || {};
282 |
283 | this.lineWidth = check( parameters.lineWidth, 1 );
284 | this.map = check( parameters.map, null );
285 | this.useMap = check( parameters.useMap, 0 );
286 | this.color = check( parameters.color, new THREE.Color( 0xffffff ) );
287 | this.opacity = check( parameters.opacity, 1 );
288 | this.resolution = check( parameters.resolution, new THREE.Vector2( 1, 1 ) );
289 | this.sizeAttenuation = check( parameters.sizeAttenuation, 1 );
290 | this.near = check( parameters.near, 1 );
291 | this.far = check( parameters.far, 1 );
292 | this.dashArray = check( parameters.dashArray, [] );
293 | this.useDash = ( this.dashArray !== [] ) ? 1 : 0;
294 |
295 | var material = new THREE.RawShaderMaterial( {
296 | uniforms:{
297 | lineWidth: { type: 'f', value: this.lineWidth },
298 | map: { type: 't', value: this.map },
299 | useMap: { type: 'f', value: this.useMap },
300 | color: { type: 'c', value: this.color },
301 | opacity: { type: 'f', value: this.opacity },
302 | resolution: { type: 'v2', value: this.resolution },
303 | sizeAttenuation: { type: 'f', value: this.sizeAttenuation },
304 | near: { type: 'f', value: this.near },
305 | far: { type: 'f', value: this.far },
306 | dashArray: { type: 'v2', value: new THREE.Vector2( this.dashArray[ 0 ], this.dashArray[ 1 ] ) },
307 | useDash: { type: 'f', value: this.useDash },
308 | drawDepth: { type: 'f', value: 0 }
309 | },
310 | vertexShader: vertexShaderSource.join( '\r\n' ),
311 | fragmentShader: fragmentShaderSource.join( '\r\n' )
312 | });
313 |
314 | delete parameters.lineWidth;
315 | delete parameters.map;
316 | delete parameters.useMap;
317 | delete parameters.color;
318 | delete parameters.opacity;
319 | delete parameters.resolution;
320 | delete parameters.sizeAttenuation;
321 | delete parameters.near;
322 | delete parameters.far;
323 | delete parameters.dashArray;
324 |
325 | material.type = 'MeshLineMaterial';
326 |
327 | material.setValues( parameters );
328 |
329 | return material;
330 |
331 | };
332 |
333 | THREE.MeshLineMaterial.prototype = Object.create( THREE.Material.prototype );
334 | THREE.MeshLineMaterial.prototype.constructor = THREE.MeshLineMaterial;
335 |
336 | THREE.MeshLineMaterial.prototype.copy = function ( source ) {
337 |
338 | THREE.Material.prototype.copy.call( this, source );
339 |
340 | this.lineWidth = source.lineWidth;
341 | this.map = source.map;
342 | this.useMap = source.useMap;
343 | this.color.copy( source.color );
344 | this.opacity = source.opacity;
345 | this.resolution.copy( source.resolution );
346 | this.sizeAttenuation = source.sizeAttenuation;
347 | this.near = source.near;
348 | this.far = source.far;
349 |
350 | return this;
351 |
352 | };
353 |
--------------------------------------------------------------------------------
/js/isMobile.min.js:
--------------------------------------------------------------------------------
1 | !function(a){var b=/iPhone/i,c=/iPod/i,d=/iPad/i,e=/(?=.*\bAndroid\b)(?=.*\bMobile\b)/i,f=/Android/i,g=/(?=.*\bAndroid\b)(?=.*\bSD4930UR\b)/i,h=/(?=.*\bAndroid\b)(?=.*\b(?:KFOT|KFTT|KFJWI|KFJWA|KFSOWI|KFTHWI|KFTHWA|KFAPWI|KFAPWA|KFARWI|KFASWI|KFSAWI|KFSAWA)\b)/i,i=/IEMobile/i,j=/(?=.*\bWindows\b)(?=.*\bARM\b)/i,k=/BlackBerry/i,l=/BB10/i,m=/Opera Mini/i,n=/(CriOS|Chrome)(?=.*\bMobile\b)/i,o=/(?=.*\bFirefox\b)(?=.*\bMobile\b)/i,p=new RegExp("(?:Nexus 7|BNTV250|Kindle Fire|Silk|GT-P1000)","i"),q=function(a,b){return a.test(b)},r=function(a){var r=a||navigator.userAgent,s=r.split("[FBAN");return"undefined"!=typeof s[1]&&(r=s[0]),this.apple={phone:q(b,r),ipod:q(c,r),tablet:!q(b,r)&&q(d,r),device:q(b,r)||q(c,r)||q(d,r)},this.amazon={phone:q(g,r),tablet:!q(g,r)&&q(h,r),device:q(g,r)||q(h,r)},this.android={phone:q(g,r)||q(e,r),tablet:!q(g,r)&&!q(e,r)&&(q(h,r)||q(f,r)),device:q(g,r)||q(h,r)||q(e,r)||q(f,r)},this.windows={phone:q(i,r),tablet:q(j,r),device:q(i,r)||q(j,r)},this.other={blackberry:q(k,r),blackberry10:q(l,r),opera:q(m,r),firefox:q(o,r),chrome:q(n,r),device:q(k,r)||q(l,r)||q(m,r)||q(o,r)||q(n,r)},this.seven_inch=q(p,r),this.any=this.apple.device||this.android.device||this.windows.device||this.other.device||this.seven_inch,this.phone=this.apple.phone||this.android.phone||this.windows.phone,this.tablet=this.apple.tablet||this.android.tablet||this.windows.tablet,"undefined"==typeof window?this:void 0},s=function(){var a=new r;return a.Class=r,a};"undefined"!=typeof module&&module.exports&&"undefined"==typeof window?module.exports=r:"undefined"!=typeof module&&module.exports&&"undefined"!=typeof window?module.exports=s():"function"==typeof define&&define.amd?define("isMobile",[],a.isMobile=s()):a.isMobile=s()}(this);
2 |
--------------------------------------------------------------------------------
/matcap.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/spite/3dwebfest-2016/e738ab53c8ba7b55a1dcaddcbb3a0dff412fd4ed/matcap.jpg
--------------------------------------------------------------------------------