├── README.md
├── index.html
└── js
├── 3d-lines-animation.js
├── canvas-renderer.js
├── color.js
├── projector.js
└── three.min.js
/README.md:
--------------------------------------------------------------------------------
1 | 3D lines animation with three.js
2 | ========================================
3 | ...and an animated background color
4 |
5 |
6 | Tags
7 | -----------
8 | HTML5, javascript, canvas, three.js, animation, colors.
9 |
10 |
11 | What is?
12 | -----------
13 |
14 | I took a prebuild three.js [example](http://threejs.org/examples/#canvas_lines) and put a fancy animated background color, adjusted some parameters like number of lines, perspective and colors. Now is ready to use for everyone.
15 |
16 | Online demo
17 | -----------
18 | [Check out the online demo](http://joanclaret.github.io/html5-canvas-animation/)
19 |
20 |
21 | Preview
22 | -----------
23 |
24 | 
25 |
26 |
27 |
28 | How it works?
29 | -----------
30 |
31 | ### Javascript initialization
32 |
33 | ```html
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | ```
48 |
49 | ### Layout
50 |
51 | ```html
52 |
53 |
54 |
Hello world
55 |
56 |
57 |
58 | ```
59 |
60 | ### Options
61 |
62 | * The script is fully configurable (colors, lines, opacities, perspectives...) but you'll need to dive in to the code to adjust them. Download the files and start checking out the file 3d-lines-animation.js
63 |
64 | ### Follow the repository
65 | ★ Star and watch [this repo](https://github.com/JoanClaret/html5-canvas-animation) in order to stay updated with news about this plugin
66 |
67 |
68 | License
69 | -------
70 |
71 | The MIT License (MIT)
72 |
73 | Copyright (c) 2015 Joan Claret
74 |
75 | Permission is hereby granted, free of charge, to any person obtaining a copy
76 | of this software and associated documentation files (the "Software"), to deal
77 | in the Software without restriction, including without limitation the rights
78 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
79 | copies of the Software, and to permit persons to whom the Software is
80 | furnished to do so, subject to the following conditions:
81 |
82 | The above copyright notice and this permission notice shall be included in
83 | all copies or substantial portions of the Software.
84 |
85 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
86 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
87 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
88 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
89 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
90 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
91 | THE SOFTWARE.
92 |
93 | Other useful plugins
94 | ----------------------
95 | * [Maximum Characters limit warning](https://github.com/JoanClaret/max-char-limit-warning): Get a warning when the max char limit has been exceeded with a jQuery plugin
96 | * [jcSlider](http://joanclaret.github.io/jcSlider): A responsive slider jQuery plugin with CSS animations
97 | * [slide and swipe menu](http://joanclaret.github.io/slide-and-swipe-menu): A sliding swipe menu that works with touchSwipe library.
98 | * [jquery dynamic max height](http://joanclaret.github.io/jquery-dynamic-max-height) : Dynamic max height plugin for jQuery with CSS animation
99 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 3D lines animation with three.js
6 |
7 |
8 |
44 |
45 |
46 |
47 |
48 |
3D lines animation with three.js
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/js/3d-lines-animation.js:
--------------------------------------------------------------------------------
1 | var mouseX = 0, mouseY = 0,
2 |
3 | windowHalfX = window.innerWidth / 2,
4 | windowHalfY = window.innerHeight / 2,
5 |
6 | SEPARATION = 200,
7 | AMOUNTX = 1,
8 | AMOUNTY = 1,
9 |
10 | camera, scene, renderer;
11 |
12 | init();
13 | animate();
14 |
15 |
16 |
17 | function init() {
18 |
19 |
20 | /*
21 | * Define variables
22 | */
23 | var container, separation = 1000, amountX = 50, amountY = 50, color = 0xffffff,
24 | particles, particle;
25 |
26 | container = document.getElementById("canvas");
27 |
28 |
29 | camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 10000 );
30 | camera.position.z = 100;
31 |
32 | scene = new THREE.Scene();
33 |
34 | renderer = new THREE.CanvasRenderer({ alpha: true });
35 | renderer.setPixelRatio( window.devicePixelRatio );
36 | renderer.setClearColor( 0x000000, 0 ); // canvas background color
37 | renderer.setSize( window.innerWidth, window.innerHeight );
38 | container.appendChild( renderer.domElement );
39 |
40 |
41 |
42 | var PI2 = Math.PI * 2;
43 | var material = new THREE.SpriteCanvasMaterial( {
44 |
45 | color: color,
46 | opacity: 0.5,
47 | program: function ( context ) {
48 |
49 | context.beginPath();
50 | context.arc( 0, 0, 0.5, 0, PI2, true );
51 | context.fill();
52 |
53 | }
54 |
55 | } );
56 |
57 | var geometry = new THREE.Geometry();
58 |
59 | /*
60 | * Number of particles
61 | */
62 | for ( var i = 0; i < 150; i ++ ) {
63 |
64 | particle = new THREE.Sprite( material );
65 | particle.position.x = Math.random() * 2 - 1;
66 | particle.position.y = Math.random() * 2 - 1;
67 | particle.position.z = Math.random() * 2 - 1;
68 | particle.position.normalize();
69 | particle.position.multiplyScalar( Math.random() * 10 + 600 );
70 | particle.scale.x = particle.scale.y = 5;
71 |
72 | scene.add( particle );
73 |
74 | geometry.vertices.push( particle.position );
75 |
76 | }
77 |
78 | /*
79 | * Lines
80 | */
81 |
82 | var line = new THREE.Line( geometry, new THREE.LineBasicMaterial( { color: color, opacity: 0.2 } ) );
83 | scene.add( line );
84 |
85 | document.addEventListener( 'mousemove', onDocumentMouseMove, false );
86 | document.addEventListener( 'touchstart', onDocumentTouchStart, false );
87 | document.addEventListener( 'touchmove', onDocumentTouchMove, false );
88 |
89 | //
90 |
91 | window.addEventListener( 'resize', onWindowResize, false );
92 |
93 | }
94 |
95 | function onWindowResize() {
96 |
97 | windowHalfX = window.innerWidth / 2;
98 | windowHalfY = window.innerHeight / 2;
99 |
100 | camera.aspect = window.innerWidth / window.innerHeight;
101 | camera.updateProjectionMatrix();
102 |
103 | renderer.setSize( window.innerWidth, window.innerHeight );
104 |
105 | }
106 |
107 | //
108 |
109 | function onDocumentMouseMove(event) {
110 |
111 | mouseX = (event.clientX - windowHalfX) * 0.05;
112 | mouseY = (event.clientY - windowHalfY) * 0.2;
113 |
114 | }
115 |
116 | function onDocumentTouchStart( event ) {
117 |
118 | if ( event.touches.length > 1 ) {
119 |
120 | event.preventDefault();
121 |
122 | mouseX = (event.touches[ 0 ].pageX - windowHalfX) * 0.7;
123 | mouseY = (event.touches[ 0 ].pageY - windowHalfY) * 0.7;
124 |
125 | }
126 |
127 | }
128 |
129 | function onDocumentTouchMove( event ) {
130 |
131 | if ( event.touches.length == 1 ) {
132 |
133 | event.preventDefault();
134 |
135 | mouseX = event.touches[ 0 ].pageX - windowHalfX;
136 | mouseY = event.touches[ 0 ].pageY - windowHalfY;
137 |
138 | }
139 |
140 | }
141 |
142 | //
143 |
144 | function animate() {
145 |
146 | requestAnimationFrame( animate );
147 |
148 | render();
149 |
150 | }
151 |
152 | function render() {
153 |
154 | camera.position.x += ( mouseX - camera.position.x ) * 0.1;
155 | camera.position.y += ( - mouseY + 200 - camera.position.y ) * 0.05;
156 | camera.lookAt( scene.position );
157 |
158 | renderer.render( scene, camera );
159 |
160 | }
--------------------------------------------------------------------------------
/js/canvas-renderer.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author mrdoob / http://mrdoob.com/
3 | */
4 |
5 | THREE.SpriteCanvasMaterial = function ( parameters ) {
6 |
7 | THREE.Material.call( this );
8 |
9 | this.type = 'SpriteCanvasMaterial';
10 |
11 | this.color = new THREE.Color( 0xffffff );
12 | this.program = function ( context, color ) {};
13 |
14 | this.setValues( parameters );
15 |
16 | };
17 |
18 | THREE.SpriteCanvasMaterial.prototype = Object.create( THREE.Material.prototype );
19 | THREE.SpriteCanvasMaterial.prototype.constructor = THREE.SpriteCanvasMaterial;
20 |
21 | THREE.SpriteCanvasMaterial.prototype.clone = function () {
22 |
23 | var material = new THREE.SpriteCanvasMaterial();
24 |
25 | THREE.Material.prototype.clone.call( this, material );
26 |
27 | material.color.copy( this.color );
28 | material.program = this.program;
29 |
30 | return material;
31 |
32 | };
33 |
34 | //
35 |
36 | THREE.CanvasRenderer = function ( parameters ) {
37 |
38 | console.log( 'THREE.CanvasRenderer', THREE.REVISION );
39 |
40 | var smoothstep = THREE.Math.smoothstep;
41 |
42 | parameters = parameters || {};
43 |
44 | var _this = this,
45 | _renderData, _elements, _lights,
46 | _projector = new THREE.Projector(),
47 |
48 | _canvas = parameters.canvas !== undefined
49 | ? parameters.canvas
50 | : document.createElement( 'canvas' ),
51 |
52 | _canvasWidth = _canvas.width,
53 | _canvasHeight = _canvas.height,
54 | _canvasWidthHalf = Math.floor( _canvasWidth / 2 ),
55 | _canvasHeightHalf = Math.floor( _canvasHeight / 2 ),
56 |
57 | _viewportX = 0,
58 | _viewportY = 0,
59 | _viewportWidth = _canvasWidth,
60 | _viewportHeight = _canvasHeight,
61 |
62 | pixelRatio = 1,
63 |
64 | _context = _canvas.getContext( '2d', {
65 | alpha: parameters.alpha === true
66 | } ),
67 |
68 | _clearColor = new THREE.Color( 0x000000 ),
69 | _clearAlpha = parameters.alpha === true ? 0 : 1,
70 |
71 | _contextGlobalAlpha = 1,
72 | _contextGlobalCompositeOperation = 0,
73 | _contextStrokeStyle = null,
74 | _contextFillStyle = null,
75 | _contextLineWidth = null,
76 | _contextLineCap = null,
77 | _contextLineJoin = null,
78 | _contextLineDash = [],
79 |
80 | _camera,
81 |
82 | _v1, _v2, _v3, _v4,
83 | _v5 = new THREE.RenderableVertex(),
84 | _v6 = new THREE.RenderableVertex(),
85 |
86 | _v1x, _v1y, _v2x, _v2y, _v3x, _v3y,
87 | _v4x, _v4y, _v5x, _v5y, _v6x, _v6y,
88 |
89 | _color = new THREE.Color(),
90 | _color1 = new THREE.Color(),
91 | _color2 = new THREE.Color(),
92 | _color3 = new THREE.Color(),
93 | _color4 = new THREE.Color(),
94 |
95 | _diffuseColor = new THREE.Color(),
96 | _emissiveColor = new THREE.Color(),
97 |
98 | _lightColor = new THREE.Color(),
99 |
100 | _patterns = {},
101 |
102 | _image, _uvs,
103 | _uv1x, _uv1y, _uv2x, _uv2y, _uv3x, _uv3y,
104 |
105 | _clipBox = new THREE.Box2(),
106 | _clearBox = new THREE.Box2(),
107 | _elemBox = new THREE.Box2(),
108 |
109 | _ambientLight = new THREE.Color(),
110 | _directionalLights = new THREE.Color(),
111 | _pointLights = new THREE.Color(),
112 |
113 | _vector3 = new THREE.Vector3(), // Needed for PointLight
114 | _centroid = new THREE.Vector3(),
115 | _normal = new THREE.Vector3(),
116 | _normalViewMatrix = new THREE.Matrix3();
117 |
118 | // dash+gap fallbacks for Firefox and everything else
119 |
120 | if ( _context.setLineDash === undefined ) {
121 |
122 | _context.setLineDash = function () {}
123 |
124 | }
125 |
126 | this.domElement = _canvas;
127 |
128 | this.autoClear = true;
129 | this.sortObjects = true;
130 | this.sortElements = true;
131 |
132 | this.info = {
133 |
134 | render: {
135 |
136 | vertices: 0,
137 | faces: 0
138 |
139 | }
140 |
141 | }
142 |
143 | // WebGLRenderer compatibility
144 |
145 | this.supportsVertexTextures = function () {};
146 | this.setFaceCulling = function () {};
147 |
148 | //
149 |
150 | this.getPixelRatio = function () {
151 |
152 | return pixelRatio;
153 |
154 | };
155 |
156 | this.setPixelRatio = function ( value ) {
157 |
158 | pixelRatio = value;
159 |
160 | };
161 |
162 | this.setSize = function ( width, height, updateStyle ) {
163 |
164 | _canvasWidth = width * pixelRatio;
165 | _canvasHeight = height * pixelRatio;
166 |
167 | _canvas.width = _canvasWidth;
168 | _canvas.height = _canvasHeight;
169 |
170 | _canvasWidthHalf = Math.floor( _canvasWidth / 2 );
171 | _canvasHeightHalf = Math.floor( _canvasHeight / 2 );
172 |
173 | if ( updateStyle !== false ) {
174 |
175 | _canvas.style.width = width + 'px';
176 | _canvas.style.height = height + 'px';
177 |
178 | }
179 |
180 | _clipBox.min.set( -_canvasWidthHalf, -_canvasHeightHalf ),
181 | _clipBox.max.set( _canvasWidthHalf, _canvasHeightHalf );
182 |
183 | _clearBox.min.set( - _canvasWidthHalf, - _canvasHeightHalf );
184 | _clearBox.max.set( _canvasWidthHalf, _canvasHeightHalf );
185 |
186 | _contextGlobalAlpha = 1;
187 | _contextGlobalCompositeOperation = 0;
188 | _contextStrokeStyle = null;
189 | _contextFillStyle = null;
190 | _contextLineWidth = null;
191 | _contextLineCap = null;
192 | _contextLineJoin = null;
193 |
194 | this.setViewport( 0, 0, width, height );
195 |
196 | };
197 |
198 | this.setViewport = function ( x, y, width, height ) {
199 |
200 | _viewportX = x * pixelRatio;
201 | _viewportY = y * pixelRatio;
202 |
203 | _viewportWidth = width * pixelRatio;
204 | _viewportHeight = height * pixelRatio;
205 |
206 | };
207 |
208 | this.setScissor = function () {};
209 | this.enableScissorTest = function () {};
210 |
211 | this.setClearColor = function ( color, alpha ) {
212 |
213 | _clearColor.set( color );
214 | _clearAlpha = alpha !== undefined ? alpha : 1;
215 |
216 | _clearBox.min.set( - _canvasWidthHalf, - _canvasHeightHalf );
217 | _clearBox.max.set( _canvasWidthHalf, _canvasHeightHalf );
218 |
219 | };
220 |
221 | this.setClearColorHex = function ( hex, alpha ) {
222 |
223 | console.warn( 'THREE.CanvasRenderer: .setClearColorHex() is being removed. Use .setClearColor() instead.' );
224 | this.setClearColor( hex, alpha );
225 |
226 | };
227 |
228 | this.getClearColor = function () {
229 |
230 | return _clearColor;
231 |
232 | };
233 |
234 | this.getClearAlpha = function () {
235 |
236 | return _clearAlpha;
237 |
238 | };
239 |
240 | this.getMaxAnisotropy = function () {
241 |
242 | return 0;
243 |
244 | };
245 |
246 | this.clear = function () {
247 |
248 | if ( _clearBox.empty() === false ) {
249 |
250 | _clearBox.intersect( _clipBox );
251 | _clearBox.expandByScalar( 2 );
252 |
253 | _clearBox.min.x = _clearBox.min.x + _canvasWidthHalf;
254 | _clearBox.min.y = - _clearBox.min.y + _canvasHeightHalf; // higher y value !
255 | _clearBox.max.x = _clearBox.max.x + _canvasWidthHalf;
256 | _clearBox.max.y = - _clearBox.max.y + _canvasHeightHalf; // lower y value !
257 |
258 | if ( _clearAlpha < 1 ) {
259 |
260 | _context.clearRect(
261 | _clearBox.min.x | 0,
262 | _clearBox.max.y | 0,
263 | ( _clearBox.max.x - _clearBox.min.x ) | 0,
264 | ( _clearBox.min.y - _clearBox.max.y ) | 0
265 | );
266 |
267 | }
268 |
269 | if ( _clearAlpha > 0 ) {
270 |
271 | setBlending( THREE.NormalBlending );
272 | setOpacity( 1 );
273 |
274 | setFillStyle( 'rgba(' + Math.floor( _clearColor.r * 255 ) + ',' + Math.floor( _clearColor.g * 255 ) + ',' + Math.floor( _clearColor.b * 255 ) + ',' + _clearAlpha + ')' );
275 |
276 | _context.fillRect(
277 | _clearBox.min.x | 0,
278 | _clearBox.max.y | 0,
279 | ( _clearBox.max.x - _clearBox.min.x ) | 0,
280 | ( _clearBox.min.y - _clearBox.max.y ) | 0
281 | );
282 |
283 | }
284 |
285 | _clearBox.makeEmpty();
286 |
287 | }
288 |
289 | };
290 |
291 | // compatibility
292 |
293 | this.clearColor = function () {};
294 | this.clearDepth = function () {};
295 | this.clearStencil = function () {};
296 |
297 | this.render = function ( scene, camera ) {
298 |
299 | if ( camera instanceof THREE.Camera === false ) {
300 |
301 | console.error( 'THREE.CanvasRenderer.render: camera is not an instance of THREE.Camera.' );
302 | return;
303 |
304 | }
305 |
306 | if ( this.autoClear === true ) this.clear();
307 |
308 | _this.info.render.vertices = 0;
309 | _this.info.render.faces = 0;
310 |
311 | _context.setTransform( _viewportWidth / _canvasWidth, 0, 0, - _viewportHeight / _canvasHeight, _viewportX, _canvasHeight - _viewportY );
312 | _context.translate( _canvasWidthHalf, _canvasHeightHalf );
313 |
314 | _renderData = _projector.projectScene( scene, camera, this.sortObjects, this.sortElements );
315 | _elements = _renderData.elements;
316 | _lights = _renderData.lights;
317 | _camera = camera;
318 |
319 | _normalViewMatrix.getNormalMatrix( camera.matrixWorldInverse );
320 |
321 | /* DEBUG
322 | setFillStyle( 'rgba( 0, 255, 255, 0.5 )' );
323 | _context.fillRect( _clipBox.min.x, _clipBox.min.y, _clipBox.max.x - _clipBox.min.x, _clipBox.max.y - _clipBox.min.y );
324 | */
325 |
326 | calculateLights();
327 |
328 | for ( var e = 0, el = _elements.length; e < el; e ++ ) {
329 |
330 | var element = _elements[ e ];
331 |
332 | var material = element.material;
333 |
334 | if ( material === undefined || material.opacity === 0 ) continue;
335 |
336 | _elemBox.makeEmpty();
337 |
338 | if ( element instanceof THREE.RenderableSprite ) {
339 |
340 | _v1 = element;
341 | _v1.x *= _canvasWidthHalf; _v1.y *= _canvasHeightHalf;
342 |
343 | renderSprite( _v1, element, material );
344 |
345 | } else if ( element instanceof THREE.RenderableLine ) {
346 |
347 | _v1 = element.v1; _v2 = element.v2;
348 |
349 | _v1.positionScreen.x *= _canvasWidthHalf; _v1.positionScreen.y *= _canvasHeightHalf;
350 | _v2.positionScreen.x *= _canvasWidthHalf; _v2.positionScreen.y *= _canvasHeightHalf;
351 |
352 | _elemBox.setFromPoints( [
353 | _v1.positionScreen,
354 | _v2.positionScreen
355 | ] );
356 |
357 | if ( _clipBox.isIntersectionBox( _elemBox ) === true ) {
358 |
359 | renderLine( _v1, _v2, element, material );
360 |
361 | }
362 |
363 | } else if ( element instanceof THREE.RenderableFace ) {
364 |
365 | _v1 = element.v1; _v2 = element.v2; _v3 = element.v3;
366 |
367 | if ( _v1.positionScreen.z < - 1 || _v1.positionScreen.z > 1 ) continue;
368 | if ( _v2.positionScreen.z < - 1 || _v2.positionScreen.z > 1 ) continue;
369 | if ( _v3.positionScreen.z < - 1 || _v3.positionScreen.z > 1 ) continue;
370 |
371 | _v1.positionScreen.x *= _canvasWidthHalf; _v1.positionScreen.y *= _canvasHeightHalf;
372 | _v2.positionScreen.x *= _canvasWidthHalf; _v2.positionScreen.y *= _canvasHeightHalf;
373 | _v3.positionScreen.x *= _canvasWidthHalf; _v3.positionScreen.y *= _canvasHeightHalf;
374 |
375 | if ( material.overdraw > 0 ) {
376 |
377 | expand( _v1.positionScreen, _v2.positionScreen, material.overdraw );
378 | expand( _v2.positionScreen, _v3.positionScreen, material.overdraw );
379 | expand( _v3.positionScreen, _v1.positionScreen, material.overdraw );
380 |
381 | }
382 |
383 | _elemBox.setFromPoints( [
384 | _v1.positionScreen,
385 | _v2.positionScreen,
386 | _v3.positionScreen
387 | ] );
388 |
389 | if ( _clipBox.isIntersectionBox( _elemBox ) === true ) {
390 |
391 | renderFace3( _v1, _v2, _v3, 0, 1, 2, element, material );
392 |
393 | }
394 |
395 | }
396 |
397 | /* DEBUG
398 | setLineWidth( 1 );
399 | setStrokeStyle( 'rgba( 0, 255, 0, 0.5 )' );
400 | _context.strokeRect( _elemBox.min.x, _elemBox.min.y, _elemBox.max.x - _elemBox.min.x, _elemBox.max.y - _elemBox.min.y );
401 | */
402 |
403 | _clearBox.union( _elemBox );
404 |
405 | }
406 |
407 | /* DEBUG
408 | setLineWidth( 1 );
409 | setStrokeStyle( 'rgba( 255, 0, 0, 0.5 )' );
410 | _context.strokeRect( _clearBox.min.x, _clearBox.min.y, _clearBox.max.x - _clearBox.min.x, _clearBox.max.y - _clearBox.min.y );
411 | */
412 |
413 | _context.setTransform( 1, 0, 0, 1, 0, 0 );
414 |
415 | };
416 |
417 | //
418 |
419 | function calculateLights() {
420 |
421 | _ambientLight.setRGB( 0, 0, 0 );
422 | _directionalLights.setRGB( 0, 0, 0 );
423 | _pointLights.setRGB( 0, 0, 0 );
424 |
425 | for ( var l = 0, ll = _lights.length; l < ll; l ++ ) {
426 |
427 | var light = _lights[ l ];
428 | var lightColor = light.color;
429 |
430 | if ( light instanceof THREE.AmbientLight ) {
431 |
432 | _ambientLight.add( lightColor );
433 |
434 | } else if ( light instanceof THREE.DirectionalLight ) {
435 |
436 | // for sprites
437 |
438 | _directionalLights.add( lightColor );
439 |
440 | } else if ( light instanceof THREE.PointLight ) {
441 |
442 | // for sprites
443 |
444 | _pointLights.add( lightColor );
445 |
446 | }
447 |
448 | }
449 |
450 | }
451 |
452 | function calculateLight( position, normal, color ) {
453 |
454 | for ( var l = 0, ll = _lights.length; l < ll; l ++ ) {
455 |
456 | var light = _lights[ l ];
457 |
458 | _lightColor.copy( light.color );
459 |
460 | if ( light instanceof THREE.DirectionalLight ) {
461 |
462 | var lightPosition = _vector3.setFromMatrixPosition( light.matrixWorld ).normalize();
463 |
464 | var amount = normal.dot( lightPosition );
465 |
466 | if ( amount <= 0 ) continue;
467 |
468 | amount *= light.intensity;
469 |
470 | color.add( _lightColor.multiplyScalar( amount ) );
471 |
472 | } else if ( light instanceof THREE.PointLight ) {
473 |
474 | var lightPosition = _vector3.setFromMatrixPosition( light.matrixWorld );
475 |
476 | var amount = normal.dot( _vector3.subVectors( lightPosition, position ).normalize() );
477 |
478 | if ( amount <= 0 ) continue;
479 |
480 | amount *= light.distance == 0 ? 1 : 1 - Math.min( position.distanceTo( lightPosition ) / light.distance, 1 );
481 |
482 | if ( amount == 0 ) continue;
483 |
484 | amount *= light.intensity;
485 |
486 | color.add( _lightColor.multiplyScalar( amount ) );
487 |
488 | }
489 |
490 | }
491 |
492 | }
493 |
494 | function renderSprite( v1, element, material ) {
495 |
496 | setOpacity( material.opacity );
497 | setBlending( material.blending );
498 |
499 | var scaleX = element.scale.x * _canvasWidthHalf;
500 | var scaleY = element.scale.y * _canvasHeightHalf;
501 |
502 | var dist = 0.5 * Math.sqrt( scaleX * scaleX + scaleY * scaleY ); // allow for rotated sprite
503 | _elemBox.min.set( v1.x - dist, v1.y - dist );
504 | _elemBox.max.set( v1.x + dist, v1.y + dist );
505 |
506 | if ( material instanceof THREE.SpriteMaterial ) {
507 |
508 | var texture = material.map;
509 |
510 | if ( texture !== null && texture.image !== undefined ) {
511 |
512 | if ( texture.hasEventListener( 'update', onTextureUpdate ) === false ) {
513 |
514 | if ( texture.image.width > 0 ) {
515 |
516 | textureToPattern( texture );
517 |
518 | }
519 |
520 | texture.addEventListener( 'update', onTextureUpdate );
521 |
522 | }
523 |
524 | var pattern = _patterns[ texture.id ];
525 |
526 | if ( pattern !== undefined ) {
527 |
528 | setFillStyle( pattern );
529 |
530 | } else {
531 |
532 | setFillStyle( 'rgba( 0, 0, 0, 1 )' );
533 |
534 | }
535 |
536 | //
537 |
538 | var bitmap = texture.image;
539 |
540 | var ox = bitmap.width * texture.offset.x;
541 | var oy = bitmap.height * texture.offset.y;
542 |
543 | var sx = bitmap.width * texture.repeat.x;
544 | var sy = bitmap.height * texture.repeat.y;
545 |
546 | var cx = scaleX / sx;
547 | var cy = scaleY / sy;
548 |
549 | _context.save();
550 | _context.translate( v1.x, v1.y );
551 | if ( material.rotation !== 0 ) _context.rotate( material.rotation );
552 | _context.translate( - scaleX / 2, - scaleY / 2 );
553 | _context.scale( cx, cy );
554 | _context.translate( - ox, - oy );
555 | _context.fillRect( ox, oy, sx, sy );
556 | _context.restore();
557 |
558 | } else {
559 |
560 | // no texture
561 |
562 | setFillStyle( material.color.getStyle() );
563 |
564 | _context.save();
565 | _context.translate( v1.x, v1.y );
566 | if ( material.rotation !== 0 ) _context.rotate( material.rotation );
567 | _context.scale( scaleX, - scaleY );
568 | _context.fillRect( - 0.5, - 0.5, 1, 1 );
569 | _context.restore();
570 |
571 | }
572 |
573 | } else if ( material instanceof THREE.SpriteCanvasMaterial ) {
574 |
575 | setStrokeStyle( material.color.getStyle() );
576 | setFillStyle( material.color.getStyle() );
577 |
578 | _context.save();
579 | _context.translate( v1.x, v1.y );
580 | if ( material.rotation !== 0 ) _context.rotate( material.rotation );
581 | _context.scale( scaleX, scaleY );
582 |
583 | material.program( _context );
584 |
585 | _context.restore();
586 |
587 | }
588 |
589 | /* DEBUG
590 | setStrokeStyle( 'rgb(255,255,0)' );
591 | _context.beginPath();
592 | _context.moveTo( v1.x - 10, v1.y );
593 | _context.lineTo( v1.x + 10, v1.y );
594 | _context.moveTo( v1.x, v1.y - 10 );
595 | _context.lineTo( v1.x, v1.y + 10 );
596 | _context.stroke();
597 | */
598 |
599 | }
600 |
601 | function renderLine( v1, v2, element, material ) {
602 |
603 | setOpacity( material.opacity );
604 | setBlending( material.blending );
605 |
606 | _context.beginPath();
607 | _context.moveTo( v1.positionScreen.x, v1.positionScreen.y );
608 | _context.lineTo( v2.positionScreen.x, v2.positionScreen.y );
609 |
610 | if ( material instanceof THREE.LineBasicMaterial ) {
611 |
612 | setLineWidth( material.linewidth );
613 | setLineCap( material.linecap );
614 | setLineJoin( material.linejoin );
615 |
616 | if ( material.vertexColors !== THREE.VertexColors ) {
617 |
618 | setStrokeStyle( material.color.getStyle() );
619 |
620 | } else {
621 |
622 | var colorStyle1 = element.vertexColors[ 0 ].getStyle();
623 | var colorStyle2 = element.vertexColors[ 1 ].getStyle();
624 |
625 | if ( colorStyle1 === colorStyle2 ) {
626 |
627 | setStrokeStyle( colorStyle1 );
628 |
629 | } else {
630 |
631 | try {
632 |
633 | var grad = _context.createLinearGradient(
634 | v1.positionScreen.x,
635 | v1.positionScreen.y,
636 | v2.positionScreen.x,
637 | v2.positionScreen.y
638 | );
639 | grad.addColorStop( 0, colorStyle1 );
640 | grad.addColorStop( 1, colorStyle2 );
641 |
642 | } catch ( exception ) {
643 |
644 | grad = colorStyle1;
645 |
646 | }
647 |
648 | setStrokeStyle( grad );
649 |
650 | }
651 |
652 | }
653 |
654 | _context.stroke();
655 | _elemBox.expandByScalar( material.linewidth * 2 );
656 |
657 | } else if ( material instanceof THREE.LineDashedMaterial ) {
658 |
659 | setLineWidth( material.linewidth );
660 | setLineCap( material.linecap );
661 | setLineJoin( material.linejoin );
662 | setStrokeStyle( material.color.getStyle() );
663 | setLineDash( [ material.dashSize, material.gapSize ] );
664 |
665 | _context.stroke();
666 |
667 | _elemBox.expandByScalar( material.linewidth * 2 );
668 |
669 | setLineDash( [] );
670 |
671 | }
672 |
673 | }
674 |
675 | function renderFace3( v1, v2, v3, uv1, uv2, uv3, element, material ) {
676 |
677 | _this.info.render.vertices += 3;
678 | _this.info.render.faces ++;
679 |
680 | setOpacity( material.opacity );
681 | setBlending( material.blending );
682 |
683 | _v1x = v1.positionScreen.x; _v1y = v1.positionScreen.y;
684 | _v2x = v2.positionScreen.x; _v2y = v2.positionScreen.y;
685 | _v3x = v3.positionScreen.x; _v3y = v3.positionScreen.y;
686 |
687 | drawTriangle( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y );
688 |
689 | if ( ( material instanceof THREE.MeshLambertMaterial || material instanceof THREE.MeshPhongMaterial ) && material.map === null ) {
690 |
691 | _diffuseColor.copy( material.color );
692 | _emissiveColor.copy( material.emissive );
693 |
694 | if ( material.vertexColors === THREE.FaceColors ) {
695 |
696 | _diffuseColor.multiply( element.color );
697 |
698 | }
699 |
700 | _color.copy( _ambientLight );
701 |
702 | _centroid.copy( v1.positionWorld ).add( v2.positionWorld ).add( v3.positionWorld ).divideScalar( 3 );
703 |
704 | calculateLight( _centroid, element.normalModel, _color );
705 |
706 | _color.multiply( _diffuseColor ).add( _emissiveColor );
707 |
708 | material.wireframe === true
709 | ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin )
710 | : fillPath( _color );
711 |
712 | } else if ( material instanceof THREE.MeshBasicMaterial ||
713 | material instanceof THREE.MeshLambertMaterial ||
714 | material instanceof THREE.MeshPhongMaterial ) {
715 |
716 | if ( material.map !== null ) {
717 |
718 | var mapping = material.map.mapping;
719 |
720 | if ( mapping === THREE.UVMapping ) {
721 |
722 | _uvs = element.uvs;
723 | patternPath( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, _uvs[ uv1 ].x, _uvs[ uv1 ].y, _uvs[ uv2 ].x, _uvs[ uv2 ].y, _uvs[ uv3 ].x, _uvs[ uv3 ].y, material.map );
724 |
725 | }
726 |
727 | } else if ( material.envMap !== null ) {
728 |
729 | if ( material.envMap.mapping === THREE.SphericalReflectionMapping ) {
730 |
731 | _normal.copy( element.vertexNormalsModel[ uv1 ] ).applyMatrix3( _normalViewMatrix );
732 | _uv1x = 0.5 * _normal.x + 0.5;
733 | _uv1y = 0.5 * _normal.y + 0.5;
734 |
735 | _normal.copy( element.vertexNormalsModel[ uv2 ] ).applyMatrix3( _normalViewMatrix );
736 | _uv2x = 0.5 * _normal.x + 0.5;
737 | _uv2y = 0.5 * _normal.y + 0.5;
738 |
739 | _normal.copy( element.vertexNormalsModel[ uv3 ] ).applyMatrix3( _normalViewMatrix );
740 | _uv3x = 0.5 * _normal.x + 0.5;
741 | _uv3y = 0.5 * _normal.y + 0.5;
742 |
743 | patternPath( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, _uv1x, _uv1y, _uv2x, _uv2y, _uv3x, _uv3y, material.envMap );
744 |
745 | }
746 |
747 | } else {
748 |
749 | _color.copy( material.color );
750 |
751 | if ( material.vertexColors === THREE.FaceColors ) {
752 |
753 | _color.multiply( element.color );
754 |
755 | }
756 |
757 | material.wireframe === true
758 | ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin )
759 | : fillPath( _color );
760 |
761 | }
762 |
763 | } else if ( material instanceof THREE.MeshDepthMaterial ) {
764 |
765 | _color.r = _color.g = _color.b = 1 - smoothstep( v1.positionScreen.z * v1.positionScreen.w, _camera.near, _camera.far );
766 |
767 | material.wireframe === true
768 | ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin )
769 | : fillPath( _color );
770 |
771 | } else if ( material instanceof THREE.MeshNormalMaterial ) {
772 |
773 | _normal.copy( element.normalModel ).applyMatrix3( _normalViewMatrix );
774 |
775 | _color.setRGB( _normal.x, _normal.y, _normal.z ).multiplyScalar( 0.5 ).addScalar( 0.5 );
776 |
777 | material.wireframe === true
778 | ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin )
779 | : fillPath( _color );
780 |
781 | } else {
782 |
783 | _color.setRGB( 1, 1, 1 );
784 |
785 | material.wireframe === true
786 | ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin )
787 | : fillPath( _color );
788 |
789 | }
790 |
791 | }
792 |
793 | //
794 |
795 | function drawTriangle( x0, y0, x1, y1, x2, y2 ) {
796 |
797 | _context.beginPath();
798 | _context.moveTo( x0, y0 );
799 | _context.lineTo( x1, y1 );
800 | _context.lineTo( x2, y2 );
801 | _context.closePath();
802 |
803 | }
804 |
805 | function strokePath( color, linewidth, linecap, linejoin ) {
806 |
807 | setLineWidth( linewidth );
808 | setLineCap( linecap );
809 | setLineJoin( linejoin );
810 | setStrokeStyle( color.getStyle() );
811 |
812 | _context.stroke();
813 |
814 | _elemBox.expandByScalar( linewidth * 2 );
815 |
816 | }
817 |
818 | function fillPath( color ) {
819 |
820 | setFillStyle( color.getStyle() );
821 | _context.fill();
822 |
823 | }
824 |
825 | function onTextureUpdate ( event ) {
826 |
827 | textureToPattern( event.target );
828 |
829 | }
830 |
831 | function textureToPattern( texture ) {
832 |
833 | if ( texture instanceof THREE.CompressedTexture ) return;
834 |
835 | var repeatX = texture.wrapS === THREE.RepeatWrapping;
836 | var repeatY = texture.wrapT === THREE.RepeatWrapping;
837 |
838 | var image = texture.image;
839 |
840 | var canvas = document.createElement( 'canvas' );
841 | canvas.width = image.width;
842 | canvas.height = image.height;
843 |
844 | var context = canvas.getContext( '2d' );
845 | context.setTransform( 1, 0, 0, - 1, 0, image.height );
846 | context.drawImage( image, 0, 0 );
847 |
848 | _patterns[ texture.id ] = _context.createPattern(
849 | canvas, repeatX === true && repeatY === true
850 | ? 'repeat'
851 | : repeatX === true && repeatY === false
852 | ? 'repeat-x'
853 | : repeatX === false && repeatY === true
854 | ? 'repeat-y'
855 | : 'no-repeat'
856 | );
857 |
858 | }
859 |
860 | function patternPath( x0, y0, x1, y1, x2, y2, u0, v0, u1, v1, u2, v2, texture ) {
861 |
862 | if ( texture instanceof THREE.DataTexture ) return;
863 |
864 | if ( texture.hasEventListener( 'update', onTextureUpdate ) === false ) {
865 |
866 | if ( texture.image !== undefined && texture.image.width > 0 ) {
867 |
868 | textureToPattern( texture );
869 |
870 | }
871 |
872 | texture.addEventListener( 'update', onTextureUpdate );
873 |
874 | }
875 |
876 | var pattern = _patterns[ texture.id ];
877 |
878 | if ( pattern !== undefined ) {
879 |
880 | setFillStyle( pattern );
881 |
882 | } else {
883 |
884 | setFillStyle( 'rgba(0,0,0,1)' );
885 | _context.fill();
886 |
887 | return;
888 |
889 | }
890 |
891 | // http://extremelysatisfactorytotalitarianism.com/blog/?p=2120
892 |
893 | var a, b, c, d, e, f, det, idet,
894 | offsetX = texture.offset.x / texture.repeat.x,
895 | offsetY = texture.offset.y / texture.repeat.y,
896 | width = texture.image.width * texture.repeat.x,
897 | height = texture.image.height * texture.repeat.y;
898 |
899 | u0 = ( u0 + offsetX ) * width;
900 | v0 = ( v0 + offsetY ) * height;
901 |
902 | u1 = ( u1 + offsetX ) * width;
903 | v1 = ( v1 + offsetY ) * height;
904 |
905 | u2 = ( u2 + offsetX ) * width;
906 | v2 = ( v2 + offsetY ) * height;
907 |
908 | x1 -= x0; y1 -= y0;
909 | x2 -= x0; y2 -= y0;
910 |
911 | u1 -= u0; v1 -= v0;
912 | u2 -= u0; v2 -= v0;
913 |
914 | det = u1 * v2 - u2 * v1;
915 |
916 | if ( det === 0 ) return;
917 |
918 | idet = 1 / det;
919 |
920 | a = ( v2 * x1 - v1 * x2 ) * idet;
921 | b = ( v2 * y1 - v1 * y2 ) * idet;
922 | c = ( u1 * x2 - u2 * x1 ) * idet;
923 | d = ( u1 * y2 - u2 * y1 ) * idet;
924 |
925 | e = x0 - a * u0 - c * v0;
926 | f = y0 - b * u0 - d * v0;
927 |
928 | _context.save();
929 | _context.transform( a, b, c, d, e, f );
930 | _context.fill();
931 | _context.restore();
932 |
933 | }
934 |
935 | function clipImage( x0, y0, x1, y1, x2, y2, u0, v0, u1, v1, u2, v2, image ) {
936 |
937 | // http://extremelysatisfactorytotalitarianism.com/blog/?p=2120
938 |
939 | var a, b, c, d, e, f, det, idet,
940 | width = image.width - 1,
941 | height = image.height - 1;
942 |
943 | u0 *= width; v0 *= height;
944 | u1 *= width; v1 *= height;
945 | u2 *= width; v2 *= height;
946 |
947 | x1 -= x0; y1 -= y0;
948 | x2 -= x0; y2 -= y0;
949 |
950 | u1 -= u0; v1 -= v0;
951 | u2 -= u0; v2 -= v0;
952 |
953 | det = u1 * v2 - u2 * v1;
954 |
955 | idet = 1 / det;
956 |
957 | a = ( v2 * x1 - v1 * x2 ) * idet;
958 | b = ( v2 * y1 - v1 * y2 ) * idet;
959 | c = ( u1 * x2 - u2 * x1 ) * idet;
960 | d = ( u1 * y2 - u2 * y1 ) * idet;
961 |
962 | e = x0 - a * u0 - c * v0;
963 | f = y0 - b * u0 - d * v0;
964 |
965 | _context.save();
966 | _context.transform( a, b, c, d, e, f );
967 | _context.clip();
968 | _context.drawImage( image, 0, 0 );
969 | _context.restore();
970 |
971 | }
972 |
973 | // Hide anti-alias gaps
974 |
975 | function expand( v1, v2, pixels ) {
976 |
977 | var x = v2.x - v1.x, y = v2.y - v1.y,
978 | det = x * x + y * y, idet;
979 |
980 | if ( det === 0 ) return;
981 |
982 | idet = pixels / Math.sqrt( det );
983 |
984 | x *= idet; y *= idet;
985 |
986 | v2.x += x; v2.y += y;
987 | v1.x -= x; v1.y -= y;
988 |
989 | }
990 |
991 | // Context cached methods.
992 |
993 | function setOpacity( value ) {
994 |
995 | if ( _contextGlobalAlpha !== value ) {
996 |
997 | _context.globalAlpha = value;
998 | _contextGlobalAlpha = value;
999 |
1000 | }
1001 |
1002 | }
1003 |
1004 | function setBlending( value ) {
1005 |
1006 | if ( _contextGlobalCompositeOperation !== value ) {
1007 |
1008 | if ( value === THREE.NormalBlending ) {
1009 |
1010 | _context.globalCompositeOperation = 'source-over';
1011 |
1012 | } else if ( value === THREE.AdditiveBlending ) {
1013 |
1014 | _context.globalCompositeOperation = 'lighter';
1015 |
1016 | } else if ( value === THREE.SubtractiveBlending ) {
1017 |
1018 | _context.globalCompositeOperation = 'darker';
1019 |
1020 | }
1021 |
1022 | _contextGlobalCompositeOperation = value;
1023 |
1024 | }
1025 |
1026 | }
1027 |
1028 | function setLineWidth( value ) {
1029 |
1030 | if ( _contextLineWidth !== value ) {
1031 |
1032 | _context.lineWidth = value;
1033 | _contextLineWidth = value;
1034 |
1035 | }
1036 |
1037 | }
1038 |
1039 | function setLineCap( value ) {
1040 |
1041 | // "butt", "round", "square"
1042 |
1043 | if ( _contextLineCap !== value ) {
1044 |
1045 | _context.lineCap = value;
1046 | _contextLineCap = value;
1047 |
1048 | }
1049 |
1050 | }
1051 |
1052 | function setLineJoin( value ) {
1053 |
1054 | // "round", "bevel", "miter"
1055 |
1056 | if ( _contextLineJoin !== value ) {
1057 |
1058 | _context.lineJoin = value;
1059 | _contextLineJoin = value;
1060 |
1061 | }
1062 |
1063 | }
1064 |
1065 | function setStrokeStyle( value ) {
1066 |
1067 | if ( _contextStrokeStyle !== value ) {
1068 |
1069 | _context.strokeStyle = value;
1070 | _contextStrokeStyle = value;
1071 |
1072 | }
1073 |
1074 | }
1075 |
1076 | function setFillStyle( value ) {
1077 |
1078 | if ( _contextFillStyle !== value ) {
1079 |
1080 | _context.fillStyle = value;
1081 | _contextFillStyle = value;
1082 |
1083 | }
1084 |
1085 | }
1086 |
1087 | function setLineDash( value ) {
1088 |
1089 | if ( _contextLineDash.length !== value.length ) {
1090 |
1091 | _context.setLineDash( value );
1092 | _contextLineDash = value;
1093 |
1094 | }
1095 |
1096 | }
1097 |
1098 | };
1099 |
--------------------------------------------------------------------------------
/js/color.js:
--------------------------------------------------------------------------------
1 |
2 | var colors = new Array(
3 | [62,35,255],
4 | [60,255,60],
5 | [255,35,98],
6 | [45,175,230],
7 | [255,0,255],
8 | [255,128,0]);
9 |
10 |
11 | //
12 |
13 | var step = 0;
14 | //color table indices for:
15 | // current color left
16 | // next color left
17 | // current color right
18 | // next color right
19 | var colorIndices = [0,1,2,3];
20 |
21 | //transition speed
22 | var gradientSpeed = 0.002;
23 |
24 | function updateGradient()
25 | {
26 |
27 | if ( $===undefined ) return;
28 |
29 | var c0_0 = colors[colorIndices[0]];
30 | var c0_1 = colors[colorIndices[1]];
31 | var c1_0 = colors[colorIndices[2]];
32 | var c1_1 = colors[colorIndices[3]];
33 |
34 | var istep = 1 - step;
35 | var r1 = Math.round(istep * c0_0[0] + step * c0_1[0]);
36 | var g1 = Math.round(istep * c0_0[1] + step * c0_1[1]);
37 | var b1 = Math.round(istep * c0_0[2] + step * c0_1[2]);
38 | var color1 = "rgb("+r1+","+g1+","+b1+")";
39 |
40 | var r2 = Math.round(istep * c1_0[0] + step * c1_1[0]);
41 | var g2 = Math.round(istep * c1_0[1] + step * c1_1[1]);
42 | var b2 = Math.round(istep * c1_0[2] + step * c1_1[2]);
43 | var color2 = "rgb("+r2+","+g2+","+b2+")";
44 |
45 | $('.gradient').css({
46 | background: "-webkit-gradient(linear, left top, right top, from("+color1+"), to("+color2+"))"}).css({
47 | background: "-moz-linear-gradient(left, "+color1+" 0%, "+color2+" 100%)"});
48 |
49 | step += gradientSpeed;
50 | if ( step >= 1 )
51 | {
52 | step %= 1;
53 | colorIndices[0] = colorIndices[1];
54 | colorIndices[2] = colorIndices[3];
55 |
56 | //pick two new target color indices
57 | //do not pick the same as the current one
58 | colorIndices[1] = ( colorIndices[1] + Math.floor( 1 + Math.random() * (colors.length - 1))) % colors.length;
59 | colorIndices[3] = ( colorIndices[3] + Math.floor( 1 + Math.random() * (colors.length - 1))) % colors.length;
60 |
61 | }
62 | }
63 |
64 | setInterval(updateGradient,10);
--------------------------------------------------------------------------------
/js/projector.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author mrdoob / http://mrdoob.com/
3 | * @author supereggbert / http://www.paulbrunt.co.uk/
4 | * @author julianwa / https://github.com/julianwa
5 | */
6 |
7 | THREE.RenderableObject = function () {
8 |
9 | this.id = 0;
10 |
11 | this.object = null;
12 | this.z = 0;
13 |
14 | };
15 |
16 | //
17 |
18 | THREE.RenderableFace = function () {
19 |
20 | this.id = 0;
21 |
22 | this.v1 = new THREE.RenderableVertex();
23 | this.v2 = new THREE.RenderableVertex();
24 | this.v3 = new THREE.RenderableVertex();
25 |
26 | this.normalModel = new THREE.Vector3();
27 |
28 | this.vertexNormalsModel = [ new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3() ];
29 | this.vertexNormalsLength = 0;
30 |
31 | this.color = new THREE.Color();
32 | this.material = null;
33 | this.uvs = [ new THREE.Vector2(), new THREE.Vector2(), new THREE.Vector2() ];
34 |
35 | this.z = 0;
36 |
37 | };
38 |
39 | //
40 |
41 | THREE.RenderableVertex = function () {
42 |
43 | this.position = new THREE.Vector3();
44 | this.positionWorld = new THREE.Vector3();
45 | this.positionScreen = new THREE.Vector4();
46 |
47 | this.visible = true;
48 |
49 | };
50 |
51 | THREE.RenderableVertex.prototype.copy = function ( vertex ) {
52 |
53 | this.positionWorld.copy( vertex.positionWorld );
54 | this.positionScreen.copy( vertex.positionScreen );
55 |
56 | };
57 |
58 | //
59 |
60 | THREE.RenderableLine = function () {
61 |
62 | this.id = 0;
63 |
64 | this.v1 = new THREE.RenderableVertex();
65 | this.v2 = new THREE.RenderableVertex();
66 |
67 | this.vertexColors = [ new THREE.Color(), new THREE.Color() ];
68 | this.material = null;
69 |
70 | this.z = 0;
71 |
72 | };
73 |
74 | //
75 |
76 | THREE.RenderableSprite = function () {
77 |
78 | this.id = 0;
79 |
80 | this.object = null;
81 |
82 | this.x = 0;
83 | this.y = 0;
84 | this.z = 0;
85 |
86 | this.rotation = 0;
87 | this.scale = new THREE.Vector2();
88 |
89 | this.material = null;
90 |
91 | };
92 |
93 | //
94 |
95 | THREE.Projector = function () {
96 |
97 | var _object, _objectCount, _objectPool = [], _objectPoolLength = 0,
98 | _vertex, _vertexCount, _vertexPool = [], _vertexPoolLength = 0,
99 | _face, _faceCount, _facePool = [], _facePoolLength = 0,
100 | _line, _lineCount, _linePool = [], _linePoolLength = 0,
101 | _sprite, _spriteCount, _spritePool = [], _spritePoolLength = 0,
102 |
103 | _renderData = { objects: [], lights: [], elements: [] },
104 |
105 | _vector3 = new THREE.Vector3(),
106 | _vector4 = new THREE.Vector4(),
107 |
108 | _clipBox = new THREE.Box3( new THREE.Vector3( - 1, - 1, - 1 ), new THREE.Vector3( 1, 1, 1 ) ),
109 | _boundingBox = new THREE.Box3(),
110 | _points3 = new Array( 3 ),
111 | _points4 = new Array( 4 ),
112 |
113 | _viewMatrix = new THREE.Matrix4(),
114 | _viewProjectionMatrix = new THREE.Matrix4(),
115 |
116 | _modelMatrix,
117 | _modelViewProjectionMatrix = new THREE.Matrix4(),
118 |
119 | _normalMatrix = new THREE.Matrix3(),
120 |
121 | _frustum = new THREE.Frustum(),
122 |
123 | _clippedVertex1PositionScreen = new THREE.Vector4(),
124 | _clippedVertex2PositionScreen = new THREE.Vector4();
125 |
126 | //
127 |
128 | this.projectVector = function ( vector, camera ) {
129 |
130 | console.warn( 'THREE.Projector: .projectVector() is now vector.project().' );
131 | vector.project( camera );
132 |
133 | };
134 |
135 | this.unprojectVector = function ( vector, camera ) {
136 |
137 | console.warn( 'THREE.Projector: .unprojectVector() is now vector.unproject().' );
138 | vector.unproject( camera );
139 |
140 | };
141 |
142 | this.pickingRay = function ( vector, camera ) {
143 |
144 | console.error( 'THREE.Projector: .pickingRay() is now raycaster.setFromCamera().' );
145 |
146 | };
147 |
148 | //
149 |
150 | var RenderList = function () {
151 |
152 | var normals = [];
153 | var uvs = [];
154 |
155 | var object = null;
156 | var material = null;
157 |
158 | var normalMatrix = new THREE.Matrix3();
159 |
160 | var setObject = function ( value ) {
161 |
162 | object = value;
163 | material = object.material;
164 |
165 | normalMatrix.getNormalMatrix( object.matrixWorld );
166 |
167 | normals.length = 0;
168 | uvs.length = 0;
169 |
170 | };
171 |
172 | var projectVertex = function ( vertex ) {
173 |
174 | var position = vertex.position;
175 | var positionWorld = vertex.positionWorld;
176 | var positionScreen = vertex.positionScreen;
177 |
178 | positionWorld.copy( position ).applyMatrix4( _modelMatrix );
179 | positionScreen.copy( positionWorld ).applyMatrix4( _viewProjectionMatrix );
180 |
181 | var invW = 1 / positionScreen.w;
182 |
183 | positionScreen.x *= invW;
184 | positionScreen.y *= invW;
185 | positionScreen.z *= invW;
186 |
187 | vertex.visible = positionScreen.x >= - 1 && positionScreen.x <= 1 &&
188 | positionScreen.y >= - 1 && positionScreen.y <= 1 &&
189 | positionScreen.z >= - 1 && positionScreen.z <= 1;
190 |
191 | };
192 |
193 | var pushVertex = function ( x, y, z ) {
194 |
195 | _vertex = getNextVertexInPool();
196 | _vertex.position.set( x, y, z );
197 |
198 | projectVertex( _vertex );
199 |
200 | };
201 |
202 | var pushNormal = function ( x, y, z ) {
203 |
204 | normals.push( x, y, z );
205 |
206 | };
207 |
208 | var pushUv = function ( x, y ) {
209 |
210 | uvs.push( x, y );
211 |
212 | };
213 |
214 | var checkTriangleVisibility = function ( v1, v2, v3 ) {
215 |
216 | if ( v1.visible === true || v2.visible === true || v3.visible === true ) return true;
217 |
218 | _points3[ 0 ] = v1.positionScreen;
219 | _points3[ 1 ] = v2.positionScreen;
220 | _points3[ 2 ] = v3.positionScreen;
221 |
222 | return _clipBox.isIntersectionBox( _boundingBox.setFromPoints( _points3 ) );
223 |
224 | };
225 |
226 | var checkBackfaceCulling = function ( v1, v2, v3 ) {
227 |
228 | return ( ( v3.positionScreen.x - v1.positionScreen.x ) *
229 | ( v2.positionScreen.y - v1.positionScreen.y ) -
230 | ( v3.positionScreen.y - v1.positionScreen.y ) *
231 | ( v2.positionScreen.x - v1.positionScreen.x ) ) < 0;
232 |
233 | };
234 |
235 | var pushLine = function ( a, b ) {
236 |
237 | var v1 = _vertexPool[ a ];
238 | var v2 = _vertexPool[ b ];
239 |
240 | _line = getNextLineInPool();
241 |
242 | _line.id = object.id;
243 | _line.v1.copy( v1 );
244 | _line.v2.copy( v2 );
245 | _line.z = ( v1.positionScreen.z + v2.positionScreen.z ) / 2;
246 |
247 | _line.material = object.material;
248 |
249 | _renderData.elements.push( _line );
250 |
251 | };
252 |
253 | var pushTriangle = function ( a, b, c ) {
254 |
255 | var v1 = _vertexPool[ a ];
256 | var v2 = _vertexPool[ b ];
257 | var v3 = _vertexPool[ c ];
258 |
259 | if ( checkTriangleVisibility( v1, v2, v3 ) === false ) return;
260 |
261 | if ( material.side === THREE.DoubleSide || checkBackfaceCulling( v1, v2, v3 ) === true ) {
262 |
263 | _face = getNextFaceInPool();
264 |
265 | _face.id = object.id;
266 | _face.v1.copy( v1 );
267 | _face.v2.copy( v2 );
268 | _face.v3.copy( v3 );
269 | _face.z = ( v1.positionScreen.z + v2.positionScreen.z + v3.positionScreen.z ) / 3;
270 |
271 | for ( var i = 0; i < 3; i ++ ) {
272 |
273 | var offset = arguments[ i ] * 3;
274 | var normal = _face.vertexNormalsModel[ i ];
275 |
276 | normal.set( normals[ offset ], normals[ offset + 1 ], normals[ offset + 2 ] );
277 | normal.applyMatrix3( normalMatrix ).normalize();
278 |
279 | var offset2 = arguments[ i ] * 2;
280 |
281 | var uv = _face.uvs[ i ];
282 | uv.set( uvs[ offset2 ], uvs[ offset2 + 1 ] );
283 |
284 | }
285 |
286 | _face.vertexNormalsLength = 3;
287 |
288 | _face.material = object.material;
289 |
290 | _renderData.elements.push( _face );
291 |
292 | }
293 |
294 | };
295 |
296 | return {
297 | setObject: setObject,
298 | projectVertex: projectVertex,
299 | checkTriangleVisibility: checkTriangleVisibility,
300 | checkBackfaceCulling: checkBackfaceCulling,
301 | pushVertex: pushVertex,
302 | pushNormal: pushNormal,
303 | pushUv: pushUv,
304 | pushLine: pushLine,
305 | pushTriangle: pushTriangle
306 | }
307 |
308 | };
309 |
310 | var renderList = new RenderList();
311 |
312 | this.projectScene = function ( scene, camera, sortObjects, sortElements ) {
313 |
314 | _faceCount = 0;
315 | _lineCount = 0;
316 | _spriteCount = 0;
317 |
318 | _renderData.elements.length = 0;
319 |
320 | if ( scene.autoUpdate === true ) scene.updateMatrixWorld();
321 | if ( camera.parent === undefined ) camera.updateMatrixWorld();
322 |
323 | _viewMatrix.copy( camera.matrixWorldInverse.getInverse( camera.matrixWorld ) );
324 | _viewProjectionMatrix.multiplyMatrices( camera.projectionMatrix, _viewMatrix );
325 |
326 | _frustum.setFromMatrix( _viewProjectionMatrix );
327 |
328 | //
329 |
330 | _objectCount = 0;
331 |
332 | _renderData.objects.length = 0;
333 | _renderData.lights.length = 0;
334 |
335 | scene.traverseVisible( function ( object ) {
336 |
337 | if ( object instanceof THREE.Light ) {
338 |
339 | _renderData.lights.push( object );
340 |
341 | } else if ( object instanceof THREE.Mesh || object instanceof THREE.Line || object instanceof THREE.Sprite ) {
342 |
343 | if ( object.material.visible === false ) return;
344 |
345 | if ( object.frustumCulled === false || _frustum.intersectsObject( object ) === true ) {
346 |
347 | _object = getNextObjectInPool();
348 | _object.id = object.id;
349 | _object.object = object;
350 |
351 | _vector3.setFromMatrixPosition( object.matrixWorld );
352 | _vector3.applyProjection( _viewProjectionMatrix );
353 | _object.z = _vector3.z;
354 |
355 | _renderData.objects.push( _object );
356 |
357 | }
358 |
359 | }
360 |
361 | } );
362 |
363 | if ( sortObjects === true ) {
364 |
365 | _renderData.objects.sort( painterSort );
366 |
367 | }
368 |
369 | //
370 |
371 | for ( var o = 0, ol = _renderData.objects.length; o < ol; o ++ ) {
372 |
373 | var object = _renderData.objects[ o ].object;
374 | var geometry = object.geometry;
375 |
376 | renderList.setObject( object );
377 |
378 | _modelMatrix = object.matrixWorld;
379 |
380 | _vertexCount = 0;
381 |
382 | if ( object instanceof THREE.Mesh ) {
383 |
384 | if ( geometry instanceof THREE.BufferGeometry ) {
385 |
386 | var attributes = geometry.attributes;
387 | var offsets = geometry.offsets;
388 |
389 | if ( attributes.position === undefined ) continue;
390 |
391 | var positions = attributes.position.array;
392 |
393 | for ( var i = 0, l = positions.length; i < l; i += 3 ) {
394 |
395 | renderList.pushVertex( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] );
396 |
397 | }
398 |
399 | if ( attributes.normal !== undefined ) {
400 |
401 | var normals = attributes.normal.array;
402 |
403 | for ( var i = 0, l = normals.length; i < l; i += 3 ) {
404 |
405 | renderList.pushNormal( normals[ i ], normals[ i + 1 ], normals[ i + 2 ] );
406 |
407 | }
408 |
409 | }
410 |
411 | if ( attributes.uv !== undefined ) {
412 |
413 | var uvs = attributes.uv.array;
414 |
415 | for ( var i = 0, l = uvs.length; i < l; i += 2 ) {
416 |
417 | renderList.pushUv( uvs[ i ], uvs[ i + 1 ] );
418 |
419 | }
420 |
421 | }
422 |
423 | if ( attributes.index !== undefined ) {
424 |
425 | var indices = attributes.index.array;
426 |
427 | if ( offsets.length > 0 ) {
428 |
429 | for ( var o = 0; o < offsets.length; o ++ ) {
430 |
431 | var offset = offsets[ o ];
432 | var index = offset.index;
433 |
434 | for ( var i = offset.start, l = offset.start + offset.count; i < l; i += 3 ) {
435 |
436 | renderList.pushTriangle( indices[ i ] + index, indices[ i + 1 ] + index, indices[ i + 2 ] + index );
437 |
438 | }
439 |
440 | }
441 |
442 | } else {
443 |
444 | for ( var i = 0, l = indices.length; i < l; i += 3 ) {
445 |
446 | renderList.pushTriangle( indices[ i ], indices[ i + 1 ], indices[ i + 2 ] );
447 |
448 | }
449 |
450 | }
451 |
452 | } else {
453 |
454 | for ( var i = 0, l = positions.length / 3; i < l; i += 3 ) {
455 |
456 | renderList.pushTriangle( i, i + 1, i + 2 );
457 |
458 | }
459 |
460 | }
461 |
462 | } else if ( geometry instanceof THREE.Geometry ) {
463 |
464 | var vertices = geometry.vertices;
465 | var faces = geometry.faces;
466 | var faceVertexUvs = geometry.faceVertexUvs[ 0 ];
467 |
468 | _normalMatrix.getNormalMatrix( _modelMatrix );
469 |
470 | var material = object.material;
471 |
472 | var isFaceMaterial = material instanceof THREE.MeshFaceMaterial;
473 | var objectMaterials = isFaceMaterial === true ? object.material : null;
474 |
475 | for ( var v = 0, vl = vertices.length; v < vl; v ++ ) {
476 |
477 | var vertex = vertices[ v ];
478 |
479 | _vector3.copy( vertex );
480 |
481 | if ( material.morphTargets === true ) {
482 |
483 | var morphTargets = geometry.morphTargets;
484 | var morphInfluences = object.morphTargetInfluences;
485 |
486 | for ( var t = 0, tl = morphTargets.length; t < tl; t ++ ) {
487 |
488 | var influence = morphInfluences[ t ];
489 |
490 | if ( influence === 0 ) continue;
491 |
492 | var target = morphTargets[ t ];
493 | var targetVertex = target.vertices[ v ];
494 |
495 | _vector3.x += ( targetVertex.x - vertex.x ) * influence;
496 | _vector3.y += ( targetVertex.y - vertex.y ) * influence;
497 | _vector3.z += ( targetVertex.z - vertex.z ) * influence;
498 |
499 | }
500 |
501 | }
502 |
503 | renderList.pushVertex( _vector3.x, _vector3.y, _vector3.z );
504 |
505 | }
506 |
507 | for ( var f = 0, fl = faces.length; f < fl; f ++ ) {
508 |
509 | var face = faces[ f ];
510 |
511 | var material = isFaceMaterial === true
512 | ? objectMaterials.materials[ face.materialIndex ]
513 | : object.material;
514 |
515 | if ( material === undefined ) continue;
516 |
517 | var side = material.side;
518 |
519 | var v1 = _vertexPool[ face.a ];
520 | var v2 = _vertexPool[ face.b ];
521 | var v3 = _vertexPool[ face.c ];
522 |
523 | if ( renderList.checkTriangleVisibility( v1, v2, v3 ) === false ) continue;
524 |
525 | var visible = renderList.checkBackfaceCulling( v1, v2, v3 );
526 |
527 | if ( side !== THREE.DoubleSide ) {
528 | if ( side === THREE.FrontSide && visible === false ) continue;
529 | if ( side === THREE.BackSide && visible === true ) continue;
530 | }
531 |
532 | _face = getNextFaceInPool();
533 |
534 | _face.id = object.id;
535 | _face.v1.copy( v1 );
536 | _face.v2.copy( v2 );
537 | _face.v3.copy( v3 );
538 |
539 | _face.normalModel.copy( face.normal );
540 |
541 | if ( visible === false && ( side === THREE.BackSide || side === THREE.DoubleSide ) ) {
542 |
543 | _face.normalModel.negate();
544 |
545 | }
546 |
547 | _face.normalModel.applyMatrix3( _normalMatrix ).normalize();
548 |
549 | var faceVertexNormals = face.vertexNormals;
550 |
551 | for ( var n = 0, nl = Math.min( faceVertexNormals.length, 3 ); n < nl; n ++ ) {
552 |
553 | var normalModel = _face.vertexNormalsModel[ n ];
554 | normalModel.copy( faceVertexNormals[ n ] );
555 |
556 | if ( visible === false && ( side === THREE.BackSide || side === THREE.DoubleSide ) ) {
557 |
558 | normalModel.negate();
559 |
560 | }
561 |
562 | normalModel.applyMatrix3( _normalMatrix ).normalize();
563 |
564 | }
565 |
566 | _face.vertexNormalsLength = faceVertexNormals.length;
567 |
568 | var vertexUvs = faceVertexUvs[ f ];
569 |
570 | if ( vertexUvs !== undefined ) {
571 |
572 | for ( var u = 0; u < 3; u ++ ) {
573 |
574 | _face.uvs[ u ].copy( vertexUvs[ u ] );
575 |
576 | }
577 |
578 | }
579 |
580 | _face.color = face.color;
581 | _face.material = material;
582 |
583 | _face.z = ( v1.positionScreen.z + v2.positionScreen.z + v3.positionScreen.z ) / 3;
584 |
585 | _renderData.elements.push( _face );
586 |
587 | }
588 |
589 | }
590 |
591 | } else if ( object instanceof THREE.Line ) {
592 |
593 | if ( geometry instanceof THREE.BufferGeometry ) {
594 |
595 | var attributes = geometry.attributes;
596 |
597 | if ( attributes.position !== undefined ) {
598 |
599 | var positions = attributes.position.array;
600 |
601 | for ( var i = 0, l = positions.length; i < l; i += 3 ) {
602 |
603 | renderList.pushVertex( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] );
604 |
605 | }
606 |
607 | if ( attributes.index !== undefined ) {
608 |
609 | var indices = attributes.index.array;
610 |
611 | for ( var i = 0, l = indices.length; i < l; i += 2 ) {
612 |
613 | renderList.pushLine( indices[ i ], indices[ i + 1 ] );
614 |
615 | }
616 |
617 | } else {
618 |
619 | var step = object.mode === THREE.LinePieces ? 2 : 1;
620 |
621 | for ( var i = 0, l = ( positions.length / 3 ) - 1; i < l; i += step ) {
622 |
623 | renderList.pushLine( i, i + 1 );
624 |
625 | }
626 |
627 | }
628 |
629 | }
630 |
631 | } else if ( geometry instanceof THREE.Geometry ) {
632 |
633 | _modelViewProjectionMatrix.multiplyMatrices( _viewProjectionMatrix, _modelMatrix );
634 |
635 | var vertices = object.geometry.vertices;
636 |
637 | if ( vertices.length === 0 ) continue;
638 |
639 | v1 = getNextVertexInPool();
640 | v1.positionScreen.copy( vertices[ 0 ] ).applyMatrix4( _modelViewProjectionMatrix );
641 |
642 | // Handle LineStrip and LinePieces
643 | var step = object.mode === THREE.LinePieces ? 2 : 1;
644 |
645 | for ( var v = 1, vl = vertices.length; v < vl; v ++ ) {
646 |
647 | v1 = getNextVertexInPool();
648 | v1.positionScreen.copy( vertices[ v ] ).applyMatrix4( _modelViewProjectionMatrix );
649 |
650 | if ( ( v + 1 ) % step > 0 ) continue;
651 |
652 | v2 = _vertexPool[ _vertexCount - 2 ];
653 |
654 | _clippedVertex1PositionScreen.copy( v1.positionScreen );
655 | _clippedVertex2PositionScreen.copy( v2.positionScreen );
656 |
657 | if ( clipLine( _clippedVertex1PositionScreen, _clippedVertex2PositionScreen ) === true ) {
658 |
659 | // Perform the perspective divide
660 | _clippedVertex1PositionScreen.multiplyScalar( 1 / _clippedVertex1PositionScreen.w );
661 | _clippedVertex2PositionScreen.multiplyScalar( 1 / _clippedVertex2PositionScreen.w );
662 |
663 | _line = getNextLineInPool();
664 |
665 | _line.id = object.id;
666 | _line.v1.positionScreen.copy( _clippedVertex1PositionScreen );
667 | _line.v2.positionScreen.copy( _clippedVertex2PositionScreen );
668 |
669 | _line.z = Math.max( _clippedVertex1PositionScreen.z, _clippedVertex2PositionScreen.z );
670 |
671 | _line.material = object.material;
672 |
673 | if ( object.material.vertexColors === THREE.VertexColors ) {
674 |
675 | _line.vertexColors[ 0 ].copy( object.geometry.colors[ v ] );
676 | _line.vertexColors[ 1 ].copy( object.geometry.colors[ v - 1 ] );
677 |
678 | }
679 |
680 | _renderData.elements.push( _line );
681 |
682 | }
683 |
684 | }
685 |
686 | }
687 |
688 | } else if ( object instanceof THREE.Sprite ) {
689 |
690 | _vector4.set( _modelMatrix.elements[ 12 ], _modelMatrix.elements[ 13 ], _modelMatrix.elements[ 14 ], 1 );
691 | _vector4.applyMatrix4( _viewProjectionMatrix );
692 |
693 | var invW = 1 / _vector4.w;
694 |
695 | _vector4.z *= invW;
696 |
697 | if ( _vector4.z >= - 1 && _vector4.z <= 1 ) {
698 |
699 | _sprite = getNextSpriteInPool();
700 | _sprite.id = object.id;
701 | _sprite.x = _vector4.x * invW;
702 | _sprite.y = _vector4.y * invW;
703 | _sprite.z = _vector4.z;
704 | _sprite.object = object;
705 |
706 | _sprite.rotation = object.rotation;
707 |
708 | _sprite.scale.x = object.scale.x * Math.abs( _sprite.x - ( _vector4.x + camera.projectionMatrix.elements[ 0 ] ) / ( _vector4.w + camera.projectionMatrix.elements[ 12 ] ) );
709 | _sprite.scale.y = object.scale.y * Math.abs( _sprite.y - ( _vector4.y + camera.projectionMatrix.elements[ 5 ] ) / ( _vector4.w + camera.projectionMatrix.elements[ 13 ] ) );
710 |
711 | _sprite.material = object.material;
712 |
713 | _renderData.elements.push( _sprite );
714 |
715 | }
716 |
717 | }
718 |
719 | }
720 |
721 | if ( sortElements === true ) {
722 |
723 | _renderData.elements.sort( painterSort );
724 |
725 | }
726 |
727 | return _renderData;
728 |
729 | };
730 |
731 | // Pools
732 |
733 | function getNextObjectInPool() {
734 |
735 | if ( _objectCount === _objectPoolLength ) {
736 |
737 | var object = new THREE.RenderableObject();
738 | _objectPool.push( object );
739 | _objectPoolLength ++;
740 | _objectCount ++;
741 | return object;
742 |
743 | }
744 |
745 | return _objectPool[ _objectCount ++ ];
746 |
747 | }
748 |
749 | function getNextVertexInPool() {
750 |
751 | if ( _vertexCount === _vertexPoolLength ) {
752 |
753 | var vertex = new THREE.RenderableVertex();
754 | _vertexPool.push( vertex );
755 | _vertexPoolLength ++;
756 | _vertexCount ++;
757 | return vertex;
758 |
759 | }
760 |
761 | return _vertexPool[ _vertexCount ++ ];
762 |
763 | }
764 |
765 | function getNextFaceInPool() {
766 |
767 | if ( _faceCount === _facePoolLength ) {
768 |
769 | var face = new THREE.RenderableFace();
770 | _facePool.push( face );
771 | _facePoolLength ++;
772 | _faceCount ++;
773 | return face;
774 |
775 | }
776 |
777 | return _facePool[ _faceCount ++ ];
778 |
779 |
780 | }
781 |
782 | function getNextLineInPool() {
783 |
784 | if ( _lineCount === _linePoolLength ) {
785 |
786 | var line = new THREE.RenderableLine();
787 | _linePool.push( line );
788 | _linePoolLength ++;
789 | _lineCount ++
790 | return line;
791 |
792 | }
793 |
794 | return _linePool[ _lineCount ++ ];
795 |
796 | }
797 |
798 | function getNextSpriteInPool() {
799 |
800 | if ( _spriteCount === _spritePoolLength ) {
801 |
802 | var sprite = new THREE.RenderableSprite();
803 | _spritePool.push( sprite );
804 | _spritePoolLength ++;
805 | _spriteCount ++
806 | return sprite;
807 |
808 | }
809 |
810 | return _spritePool[ _spriteCount ++ ];
811 |
812 | }
813 |
814 | //
815 |
816 | function painterSort( a, b ) {
817 |
818 | if ( a.z !== b.z ) {
819 |
820 | return b.z - a.z;
821 |
822 | } else if ( a.id !== b.id ) {
823 |
824 | return a.id - b.id;
825 |
826 | } else {
827 |
828 | return 0;
829 |
830 | }
831 |
832 | }
833 |
834 | function clipLine( s1, s2 ) {
835 |
836 | var alpha1 = 0, alpha2 = 1,
837 |
838 | // Calculate the boundary coordinate of each vertex for the near and far clip planes,
839 | // Z = -1 and Z = +1, respectively.
840 | bc1near = s1.z + s1.w,
841 | bc2near = s2.z + s2.w,
842 | bc1far = - s1.z + s1.w,
843 | bc2far = - s2.z + s2.w;
844 |
845 | if ( bc1near >= 0 && bc2near >= 0 && bc1far >= 0 && bc2far >= 0 ) {
846 |
847 | // Both vertices lie entirely within all clip planes.
848 | return true;
849 |
850 | } else if ( ( bc1near < 0 && bc2near < 0 ) || ( bc1far < 0 && bc2far < 0 ) ) {
851 |
852 | // Both vertices lie entirely outside one of the clip planes.
853 | return false;
854 |
855 | } else {
856 |
857 | // The line segment spans at least one clip plane.
858 |
859 | if ( bc1near < 0 ) {
860 |
861 | // v1 lies outside the near plane, v2 inside
862 | alpha1 = Math.max( alpha1, bc1near / ( bc1near - bc2near ) );
863 |
864 | } else if ( bc2near < 0 ) {
865 |
866 | // v2 lies outside the near plane, v1 inside
867 | alpha2 = Math.min( alpha2, bc1near / ( bc1near - bc2near ) );
868 |
869 | }
870 |
871 | if ( bc1far < 0 ) {
872 |
873 | // v1 lies outside the far plane, v2 inside
874 | alpha1 = Math.max( alpha1, bc1far / ( bc1far - bc2far ) );
875 |
876 | } else if ( bc2far < 0 ) {
877 |
878 | // v2 lies outside the far plane, v2 inside
879 | alpha2 = Math.min( alpha2, bc1far / ( bc1far - bc2far ) );
880 |
881 | }
882 |
883 | if ( alpha2 < alpha1 ) {
884 |
885 | // The line segment spans two boundaries, but is outside both of them.
886 | // (This can't happen when we're only clipping against just near/far but good
887 | // to leave the check here for future usage if other clip planes are added.)
888 | return false;
889 |
890 | } else {
891 |
892 | // Update the s1 and s2 vertices to match the clipped line segment.
893 | s1.lerp( s2, alpha1 );
894 | s2.lerp( s1, 1 - alpha2 );
895 |
896 | return true;
897 |
898 | }
899 |
900 | }
901 |
902 | }
903 |
904 | };
905 |
--------------------------------------------------------------------------------