Repository: JoanClaret/html5-canvas-animation Branch: master Commit: fb6694507180 Files: 6 Total size: 56.0 KB Directory structure: gitextract_v8arrxzz/ ├── README.md ├── index.html └── js/ ├── 3d-lines-animation.js ├── canvas-renderer.js ├── color.js └── projector.js ================================================ FILE CONTENTS ================================================ ================================================ FILE: README.md ================================================ 3D lines animation with three.js ======================================== ...and an animated background color Tags ----------- HTML5, javascript, canvas, three.js, animation, colors. What is? ----------- 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. Online demo ----------- [Check out the online demo](http://joanclaret.github.io/html5-canvas-animation/) Preview ----------- ![html5 canvas animation preview](http://joanclaret.github.io/html5-canvas-animation/preview.png) How it works? ----------- ### Javascript initialization ```html ``` ### Layout ```html

Hello world

``` ### Options * 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 ### Follow the repository ★ Star and watch [this repo](https://github.com/JoanClaret/html5-canvas-animation) in order to stay updated with news about this plugin License ------- The MIT License (MIT) Copyright (c) 2015 Joan Claret Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Other useful plugins ---------------------- * [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 * [jcSlider](http://joanclaret.github.io/jcSlider): A responsive slider jQuery plugin with CSS animations * [slide and swipe menu](http://joanclaret.github.io/slide-and-swipe-menu): A sliding swipe menu that works with touchSwipe library. * [jquery dynamic max height](http://joanclaret.github.io/jquery-dynamic-max-height) : Dynamic max height plugin for jQuery with CSS animation ================================================ FILE: index.html ================================================ 3D lines animation with three.js

3D lines animation with three.js

================================================ FILE: js/3d-lines-animation.js ================================================ var mouseX = 0, mouseY = 0, windowHalfX = window.innerWidth / 2, windowHalfY = window.innerHeight / 2, SEPARATION = 200, AMOUNTX = 1, AMOUNTY = 1, camera, scene, renderer; init(); animate(); function init() { /* * Define variables */ var container, separation = 1000, amountX = 50, amountY = 50, color = 0xffffff, particles, particle; container = document.getElementById("canvas"); camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 10000 ); camera.position.z = 100; scene = new THREE.Scene(); renderer = new THREE.CanvasRenderer({ alpha: true }); renderer.setPixelRatio( window.devicePixelRatio ); renderer.setClearColor( 0x000000, 0 ); // canvas background color renderer.setSize( window.innerWidth, window.innerHeight ); container.appendChild( renderer.domElement ); var PI2 = Math.PI * 2; var material = new THREE.SpriteCanvasMaterial( { color: color, opacity: 0.5, program: function ( context ) { context.beginPath(); context.arc( 0, 0, 0.5, 0, PI2, true ); context.fill(); } } ); var geometry = new THREE.Geometry(); /* * Number of particles */ for ( var i = 0; i < 150; i ++ ) { particle = new THREE.Sprite( material ); particle.position.x = Math.random() * 2 - 1; particle.position.y = Math.random() * 2 - 1; particle.position.z = Math.random() * 2 - 1; particle.position.normalize(); particle.position.multiplyScalar( Math.random() * 10 + 600 ); particle.scale.x = particle.scale.y = 5; scene.add( particle ); geometry.vertices.push( particle.position ); } /* * Lines */ var line = new THREE.Line( geometry, new THREE.LineBasicMaterial( { color: color, opacity: 0.2 } ) ); scene.add( line ); document.addEventListener( 'mousemove', onDocumentMouseMove, false ); document.addEventListener( 'touchstart', onDocumentTouchStart, false ); document.addEventListener( 'touchmove', onDocumentTouchMove, false ); // window.addEventListener( 'resize', onWindowResize, false ); } function onWindowResize() { windowHalfX = window.innerWidth / 2; windowHalfY = window.innerHeight / 2; camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize( window.innerWidth, window.innerHeight ); } // function onDocumentMouseMove(event) { mouseX = (event.clientX - windowHalfX) * 0.05; mouseY = (event.clientY - windowHalfY) * 0.2; } function onDocumentTouchStart( event ) { if ( event.touches.length > 1 ) { event.preventDefault(); mouseX = (event.touches[ 0 ].pageX - windowHalfX) * 0.7; mouseY = (event.touches[ 0 ].pageY - windowHalfY) * 0.7; } } function onDocumentTouchMove( event ) { if ( event.touches.length == 1 ) { event.preventDefault(); mouseX = event.touches[ 0 ].pageX - windowHalfX; mouseY = event.touches[ 0 ].pageY - windowHalfY; } } // function animate() { requestAnimationFrame( animate ); render(); } function render() { camera.position.x += ( mouseX - camera.position.x ) * 0.1; camera.position.y += ( - mouseY + 200 - camera.position.y ) * 0.05; camera.lookAt( scene.position ); renderer.render( scene, camera ); } ================================================ FILE: js/canvas-renderer.js ================================================ /** * @author mrdoob / http://mrdoob.com/ */ THREE.SpriteCanvasMaterial = function ( parameters ) { THREE.Material.call( this ); this.type = 'SpriteCanvasMaterial'; this.color = new THREE.Color( 0xffffff ); this.program = function ( context, color ) {}; this.setValues( parameters ); }; THREE.SpriteCanvasMaterial.prototype = Object.create( THREE.Material.prototype ); THREE.SpriteCanvasMaterial.prototype.constructor = THREE.SpriteCanvasMaterial; THREE.SpriteCanvasMaterial.prototype.clone = function () { var material = new THREE.SpriteCanvasMaterial(); THREE.Material.prototype.clone.call( this, material ); material.color.copy( this.color ); material.program = this.program; return material; }; // THREE.CanvasRenderer = function ( parameters ) { console.log( 'THREE.CanvasRenderer', THREE.REVISION ); var smoothstep = THREE.Math.smoothstep; parameters = parameters || {}; var _this = this, _renderData, _elements, _lights, _projector = new THREE.Projector(), _canvas = parameters.canvas !== undefined ? parameters.canvas : document.createElement( 'canvas' ), _canvasWidth = _canvas.width, _canvasHeight = _canvas.height, _canvasWidthHalf = Math.floor( _canvasWidth / 2 ), _canvasHeightHalf = Math.floor( _canvasHeight / 2 ), _viewportX = 0, _viewportY = 0, _viewportWidth = _canvasWidth, _viewportHeight = _canvasHeight, pixelRatio = 1, _context = _canvas.getContext( '2d', { alpha: parameters.alpha === true } ), _clearColor = new THREE.Color( 0x000000 ), _clearAlpha = parameters.alpha === true ? 0 : 1, _contextGlobalAlpha = 1, _contextGlobalCompositeOperation = 0, _contextStrokeStyle = null, _contextFillStyle = null, _contextLineWidth = null, _contextLineCap = null, _contextLineJoin = null, _contextLineDash = [], _camera, _v1, _v2, _v3, _v4, _v5 = new THREE.RenderableVertex(), _v6 = new THREE.RenderableVertex(), _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, _v4x, _v4y, _v5x, _v5y, _v6x, _v6y, _color = new THREE.Color(), _color1 = new THREE.Color(), _color2 = new THREE.Color(), _color3 = new THREE.Color(), _color4 = new THREE.Color(), _diffuseColor = new THREE.Color(), _emissiveColor = new THREE.Color(), _lightColor = new THREE.Color(), _patterns = {}, _image, _uvs, _uv1x, _uv1y, _uv2x, _uv2y, _uv3x, _uv3y, _clipBox = new THREE.Box2(), _clearBox = new THREE.Box2(), _elemBox = new THREE.Box2(), _ambientLight = new THREE.Color(), _directionalLights = new THREE.Color(), _pointLights = new THREE.Color(), _vector3 = new THREE.Vector3(), // Needed for PointLight _centroid = new THREE.Vector3(), _normal = new THREE.Vector3(), _normalViewMatrix = new THREE.Matrix3(); // dash+gap fallbacks for Firefox and everything else if ( _context.setLineDash === undefined ) { _context.setLineDash = function () {} } this.domElement = _canvas; this.autoClear = true; this.sortObjects = true; this.sortElements = true; this.info = { render: { vertices: 0, faces: 0 } } // WebGLRenderer compatibility this.supportsVertexTextures = function () {}; this.setFaceCulling = function () {}; // this.getPixelRatio = function () { return pixelRatio; }; this.setPixelRatio = function ( value ) { pixelRatio = value; }; this.setSize = function ( width, height, updateStyle ) { _canvasWidth = width * pixelRatio; _canvasHeight = height * pixelRatio; _canvas.width = _canvasWidth; _canvas.height = _canvasHeight; _canvasWidthHalf = Math.floor( _canvasWidth / 2 ); _canvasHeightHalf = Math.floor( _canvasHeight / 2 ); if ( updateStyle !== false ) { _canvas.style.width = width + 'px'; _canvas.style.height = height + 'px'; } _clipBox.min.set( -_canvasWidthHalf, -_canvasHeightHalf ), _clipBox.max.set( _canvasWidthHalf, _canvasHeightHalf ); _clearBox.min.set( - _canvasWidthHalf, - _canvasHeightHalf ); _clearBox.max.set( _canvasWidthHalf, _canvasHeightHalf ); _contextGlobalAlpha = 1; _contextGlobalCompositeOperation = 0; _contextStrokeStyle = null; _contextFillStyle = null; _contextLineWidth = null; _contextLineCap = null; _contextLineJoin = null; this.setViewport( 0, 0, width, height ); }; this.setViewport = function ( x, y, width, height ) { _viewportX = x * pixelRatio; _viewportY = y * pixelRatio; _viewportWidth = width * pixelRatio; _viewportHeight = height * pixelRatio; }; this.setScissor = function () {}; this.enableScissorTest = function () {}; this.setClearColor = function ( color, alpha ) { _clearColor.set( color ); _clearAlpha = alpha !== undefined ? alpha : 1; _clearBox.min.set( - _canvasWidthHalf, - _canvasHeightHalf ); _clearBox.max.set( _canvasWidthHalf, _canvasHeightHalf ); }; this.setClearColorHex = function ( hex, alpha ) { console.warn( 'THREE.CanvasRenderer: .setClearColorHex() is being removed. Use .setClearColor() instead.' ); this.setClearColor( hex, alpha ); }; this.getClearColor = function () { return _clearColor; }; this.getClearAlpha = function () { return _clearAlpha; }; this.getMaxAnisotropy = function () { return 0; }; this.clear = function () { if ( _clearBox.empty() === false ) { _clearBox.intersect( _clipBox ); _clearBox.expandByScalar( 2 ); _clearBox.min.x = _clearBox.min.x + _canvasWidthHalf; _clearBox.min.y = - _clearBox.min.y + _canvasHeightHalf; // higher y value ! _clearBox.max.x = _clearBox.max.x + _canvasWidthHalf; _clearBox.max.y = - _clearBox.max.y + _canvasHeightHalf; // lower y value ! if ( _clearAlpha < 1 ) { _context.clearRect( _clearBox.min.x | 0, _clearBox.max.y | 0, ( _clearBox.max.x - _clearBox.min.x ) | 0, ( _clearBox.min.y - _clearBox.max.y ) | 0 ); } if ( _clearAlpha > 0 ) { setBlending( THREE.NormalBlending ); setOpacity( 1 ); setFillStyle( 'rgba(' + Math.floor( _clearColor.r * 255 ) + ',' + Math.floor( _clearColor.g * 255 ) + ',' + Math.floor( _clearColor.b * 255 ) + ',' + _clearAlpha + ')' ); _context.fillRect( _clearBox.min.x | 0, _clearBox.max.y | 0, ( _clearBox.max.x - _clearBox.min.x ) | 0, ( _clearBox.min.y - _clearBox.max.y ) | 0 ); } _clearBox.makeEmpty(); } }; // compatibility this.clearColor = function () {}; this.clearDepth = function () {}; this.clearStencil = function () {}; this.render = function ( scene, camera ) { if ( camera instanceof THREE.Camera === false ) { console.error( 'THREE.CanvasRenderer.render: camera is not an instance of THREE.Camera.' ); return; } if ( this.autoClear === true ) this.clear(); _this.info.render.vertices = 0; _this.info.render.faces = 0; _context.setTransform( _viewportWidth / _canvasWidth, 0, 0, - _viewportHeight / _canvasHeight, _viewportX, _canvasHeight - _viewportY ); _context.translate( _canvasWidthHalf, _canvasHeightHalf ); _renderData = _projector.projectScene( scene, camera, this.sortObjects, this.sortElements ); _elements = _renderData.elements; _lights = _renderData.lights; _camera = camera; _normalViewMatrix.getNormalMatrix( camera.matrixWorldInverse ); /* DEBUG setFillStyle( 'rgba( 0, 255, 255, 0.5 )' ); _context.fillRect( _clipBox.min.x, _clipBox.min.y, _clipBox.max.x - _clipBox.min.x, _clipBox.max.y - _clipBox.min.y ); */ calculateLights(); for ( var e = 0, el = _elements.length; e < el; e ++ ) { var element = _elements[ e ]; var material = element.material; if ( material === undefined || material.opacity === 0 ) continue; _elemBox.makeEmpty(); if ( element instanceof THREE.RenderableSprite ) { _v1 = element; _v1.x *= _canvasWidthHalf; _v1.y *= _canvasHeightHalf; renderSprite( _v1, element, material ); } else if ( element instanceof THREE.RenderableLine ) { _v1 = element.v1; _v2 = element.v2; _v1.positionScreen.x *= _canvasWidthHalf; _v1.positionScreen.y *= _canvasHeightHalf; _v2.positionScreen.x *= _canvasWidthHalf; _v2.positionScreen.y *= _canvasHeightHalf; _elemBox.setFromPoints( [ _v1.positionScreen, _v2.positionScreen ] ); if ( _clipBox.isIntersectionBox( _elemBox ) === true ) { renderLine( _v1, _v2, element, material ); } } else if ( element instanceof THREE.RenderableFace ) { _v1 = element.v1; _v2 = element.v2; _v3 = element.v3; if ( _v1.positionScreen.z < - 1 || _v1.positionScreen.z > 1 ) continue; if ( _v2.positionScreen.z < - 1 || _v2.positionScreen.z > 1 ) continue; if ( _v3.positionScreen.z < - 1 || _v3.positionScreen.z > 1 ) continue; _v1.positionScreen.x *= _canvasWidthHalf; _v1.positionScreen.y *= _canvasHeightHalf; _v2.positionScreen.x *= _canvasWidthHalf; _v2.positionScreen.y *= _canvasHeightHalf; _v3.positionScreen.x *= _canvasWidthHalf; _v3.positionScreen.y *= _canvasHeightHalf; if ( material.overdraw > 0 ) { expand( _v1.positionScreen, _v2.positionScreen, material.overdraw ); expand( _v2.positionScreen, _v3.positionScreen, material.overdraw ); expand( _v3.positionScreen, _v1.positionScreen, material.overdraw ); } _elemBox.setFromPoints( [ _v1.positionScreen, _v2.positionScreen, _v3.positionScreen ] ); if ( _clipBox.isIntersectionBox( _elemBox ) === true ) { renderFace3( _v1, _v2, _v3, 0, 1, 2, element, material ); } } /* DEBUG setLineWidth( 1 ); setStrokeStyle( 'rgba( 0, 255, 0, 0.5 )' ); _context.strokeRect( _elemBox.min.x, _elemBox.min.y, _elemBox.max.x - _elemBox.min.x, _elemBox.max.y - _elemBox.min.y ); */ _clearBox.union( _elemBox ); } /* DEBUG setLineWidth( 1 ); setStrokeStyle( 'rgba( 255, 0, 0, 0.5 )' ); _context.strokeRect( _clearBox.min.x, _clearBox.min.y, _clearBox.max.x - _clearBox.min.x, _clearBox.max.y - _clearBox.min.y ); */ _context.setTransform( 1, 0, 0, 1, 0, 0 ); }; // function calculateLights() { _ambientLight.setRGB( 0, 0, 0 ); _directionalLights.setRGB( 0, 0, 0 ); _pointLights.setRGB( 0, 0, 0 ); for ( var l = 0, ll = _lights.length; l < ll; l ++ ) { var light = _lights[ l ]; var lightColor = light.color; if ( light instanceof THREE.AmbientLight ) { _ambientLight.add( lightColor ); } else if ( light instanceof THREE.DirectionalLight ) { // for sprites _directionalLights.add( lightColor ); } else if ( light instanceof THREE.PointLight ) { // for sprites _pointLights.add( lightColor ); } } } function calculateLight( position, normal, color ) { for ( var l = 0, ll = _lights.length; l < ll; l ++ ) { var light = _lights[ l ]; _lightColor.copy( light.color ); if ( light instanceof THREE.DirectionalLight ) { var lightPosition = _vector3.setFromMatrixPosition( light.matrixWorld ).normalize(); var amount = normal.dot( lightPosition ); if ( amount <= 0 ) continue; amount *= light.intensity; color.add( _lightColor.multiplyScalar( amount ) ); } else if ( light instanceof THREE.PointLight ) { var lightPosition = _vector3.setFromMatrixPosition( light.matrixWorld ); var amount = normal.dot( _vector3.subVectors( lightPosition, position ).normalize() ); if ( amount <= 0 ) continue; amount *= light.distance == 0 ? 1 : 1 - Math.min( position.distanceTo( lightPosition ) / light.distance, 1 ); if ( amount == 0 ) continue; amount *= light.intensity; color.add( _lightColor.multiplyScalar( amount ) ); } } } function renderSprite( v1, element, material ) { setOpacity( material.opacity ); setBlending( material.blending ); var scaleX = element.scale.x * _canvasWidthHalf; var scaleY = element.scale.y * _canvasHeightHalf; var dist = 0.5 * Math.sqrt( scaleX * scaleX + scaleY * scaleY ); // allow for rotated sprite _elemBox.min.set( v1.x - dist, v1.y - dist ); _elemBox.max.set( v1.x + dist, v1.y + dist ); if ( material instanceof THREE.SpriteMaterial ) { var texture = material.map; if ( texture !== null && texture.image !== undefined ) { if ( texture.hasEventListener( 'update', onTextureUpdate ) === false ) { if ( texture.image.width > 0 ) { textureToPattern( texture ); } texture.addEventListener( 'update', onTextureUpdate ); } var pattern = _patterns[ texture.id ]; if ( pattern !== undefined ) { setFillStyle( pattern ); } else { setFillStyle( 'rgba( 0, 0, 0, 1 )' ); } // var bitmap = texture.image; var ox = bitmap.width * texture.offset.x; var oy = bitmap.height * texture.offset.y; var sx = bitmap.width * texture.repeat.x; var sy = bitmap.height * texture.repeat.y; var cx = scaleX / sx; var cy = scaleY / sy; _context.save(); _context.translate( v1.x, v1.y ); if ( material.rotation !== 0 ) _context.rotate( material.rotation ); _context.translate( - scaleX / 2, - scaleY / 2 ); _context.scale( cx, cy ); _context.translate( - ox, - oy ); _context.fillRect( ox, oy, sx, sy ); _context.restore(); } else { // no texture setFillStyle( material.color.getStyle() ); _context.save(); _context.translate( v1.x, v1.y ); if ( material.rotation !== 0 ) _context.rotate( material.rotation ); _context.scale( scaleX, - scaleY ); _context.fillRect( - 0.5, - 0.5, 1, 1 ); _context.restore(); } } else if ( material instanceof THREE.SpriteCanvasMaterial ) { setStrokeStyle( material.color.getStyle() ); setFillStyle( material.color.getStyle() ); _context.save(); _context.translate( v1.x, v1.y ); if ( material.rotation !== 0 ) _context.rotate( material.rotation ); _context.scale( scaleX, scaleY ); material.program( _context ); _context.restore(); } /* DEBUG setStrokeStyle( 'rgb(255,255,0)' ); _context.beginPath(); _context.moveTo( v1.x - 10, v1.y ); _context.lineTo( v1.x + 10, v1.y ); _context.moveTo( v1.x, v1.y - 10 ); _context.lineTo( v1.x, v1.y + 10 ); _context.stroke(); */ } function renderLine( v1, v2, element, material ) { setOpacity( material.opacity ); setBlending( material.blending ); _context.beginPath(); _context.moveTo( v1.positionScreen.x, v1.positionScreen.y ); _context.lineTo( v2.positionScreen.x, v2.positionScreen.y ); if ( material instanceof THREE.LineBasicMaterial ) { setLineWidth( material.linewidth ); setLineCap( material.linecap ); setLineJoin( material.linejoin ); if ( material.vertexColors !== THREE.VertexColors ) { setStrokeStyle( material.color.getStyle() ); } else { var colorStyle1 = element.vertexColors[ 0 ].getStyle(); var colorStyle2 = element.vertexColors[ 1 ].getStyle(); if ( colorStyle1 === colorStyle2 ) { setStrokeStyle( colorStyle1 ); } else { try { var grad = _context.createLinearGradient( v1.positionScreen.x, v1.positionScreen.y, v2.positionScreen.x, v2.positionScreen.y ); grad.addColorStop( 0, colorStyle1 ); grad.addColorStop( 1, colorStyle2 ); } catch ( exception ) { grad = colorStyle1; } setStrokeStyle( grad ); } } _context.stroke(); _elemBox.expandByScalar( material.linewidth * 2 ); } else if ( material instanceof THREE.LineDashedMaterial ) { setLineWidth( material.linewidth ); setLineCap( material.linecap ); setLineJoin( material.linejoin ); setStrokeStyle( material.color.getStyle() ); setLineDash( [ material.dashSize, material.gapSize ] ); _context.stroke(); _elemBox.expandByScalar( material.linewidth * 2 ); setLineDash( [] ); } } function renderFace3( v1, v2, v3, uv1, uv2, uv3, element, material ) { _this.info.render.vertices += 3; _this.info.render.faces ++; setOpacity( material.opacity ); setBlending( material.blending ); _v1x = v1.positionScreen.x; _v1y = v1.positionScreen.y; _v2x = v2.positionScreen.x; _v2y = v2.positionScreen.y; _v3x = v3.positionScreen.x; _v3y = v3.positionScreen.y; drawTriangle( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y ); if ( ( material instanceof THREE.MeshLambertMaterial || material instanceof THREE.MeshPhongMaterial ) && material.map === null ) { _diffuseColor.copy( material.color ); _emissiveColor.copy( material.emissive ); if ( material.vertexColors === THREE.FaceColors ) { _diffuseColor.multiply( element.color ); } _color.copy( _ambientLight ); _centroid.copy( v1.positionWorld ).add( v2.positionWorld ).add( v3.positionWorld ).divideScalar( 3 ); calculateLight( _centroid, element.normalModel, _color ); _color.multiply( _diffuseColor ).add( _emissiveColor ); material.wireframe === true ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin ) : fillPath( _color ); } else if ( material instanceof THREE.MeshBasicMaterial || material instanceof THREE.MeshLambertMaterial || material instanceof THREE.MeshPhongMaterial ) { if ( material.map !== null ) { var mapping = material.map.mapping; if ( mapping === THREE.UVMapping ) { _uvs = element.uvs; 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 ); } } else if ( material.envMap !== null ) { if ( material.envMap.mapping === THREE.SphericalReflectionMapping ) { _normal.copy( element.vertexNormalsModel[ uv1 ] ).applyMatrix3( _normalViewMatrix ); _uv1x = 0.5 * _normal.x + 0.5; _uv1y = 0.5 * _normal.y + 0.5; _normal.copy( element.vertexNormalsModel[ uv2 ] ).applyMatrix3( _normalViewMatrix ); _uv2x = 0.5 * _normal.x + 0.5; _uv2y = 0.5 * _normal.y + 0.5; _normal.copy( element.vertexNormalsModel[ uv3 ] ).applyMatrix3( _normalViewMatrix ); _uv3x = 0.5 * _normal.x + 0.5; _uv3y = 0.5 * _normal.y + 0.5; patternPath( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, _uv1x, _uv1y, _uv2x, _uv2y, _uv3x, _uv3y, material.envMap ); } } else { _color.copy( material.color ); if ( material.vertexColors === THREE.FaceColors ) { _color.multiply( element.color ); } material.wireframe === true ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin ) : fillPath( _color ); } } else if ( material instanceof THREE.MeshDepthMaterial ) { _color.r = _color.g = _color.b = 1 - smoothstep( v1.positionScreen.z * v1.positionScreen.w, _camera.near, _camera.far ); material.wireframe === true ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin ) : fillPath( _color ); } else if ( material instanceof THREE.MeshNormalMaterial ) { _normal.copy( element.normalModel ).applyMatrix3( _normalViewMatrix ); _color.setRGB( _normal.x, _normal.y, _normal.z ).multiplyScalar( 0.5 ).addScalar( 0.5 ); material.wireframe === true ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin ) : fillPath( _color ); } else { _color.setRGB( 1, 1, 1 ); material.wireframe === true ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin ) : fillPath( _color ); } } // function drawTriangle( x0, y0, x1, y1, x2, y2 ) { _context.beginPath(); _context.moveTo( x0, y0 ); _context.lineTo( x1, y1 ); _context.lineTo( x2, y2 ); _context.closePath(); } function strokePath( color, linewidth, linecap, linejoin ) { setLineWidth( linewidth ); setLineCap( linecap ); setLineJoin( linejoin ); setStrokeStyle( color.getStyle() ); _context.stroke(); _elemBox.expandByScalar( linewidth * 2 ); } function fillPath( color ) { setFillStyle( color.getStyle() ); _context.fill(); } function onTextureUpdate ( event ) { textureToPattern( event.target ); } function textureToPattern( texture ) { if ( texture instanceof THREE.CompressedTexture ) return; var repeatX = texture.wrapS === THREE.RepeatWrapping; var repeatY = texture.wrapT === THREE.RepeatWrapping; var image = texture.image; var canvas = document.createElement( 'canvas' ); canvas.width = image.width; canvas.height = image.height; var context = canvas.getContext( '2d' ); context.setTransform( 1, 0, 0, - 1, 0, image.height ); context.drawImage( image, 0, 0 ); _patterns[ texture.id ] = _context.createPattern( canvas, repeatX === true && repeatY === true ? 'repeat' : repeatX === true && repeatY === false ? 'repeat-x' : repeatX === false && repeatY === true ? 'repeat-y' : 'no-repeat' ); } function patternPath( x0, y0, x1, y1, x2, y2, u0, v0, u1, v1, u2, v2, texture ) { if ( texture instanceof THREE.DataTexture ) return; if ( texture.hasEventListener( 'update', onTextureUpdate ) === false ) { if ( texture.image !== undefined && texture.image.width > 0 ) { textureToPattern( texture ); } texture.addEventListener( 'update', onTextureUpdate ); } var pattern = _patterns[ texture.id ]; if ( pattern !== undefined ) { setFillStyle( pattern ); } else { setFillStyle( 'rgba(0,0,0,1)' ); _context.fill(); return; } // http://extremelysatisfactorytotalitarianism.com/blog/?p=2120 var a, b, c, d, e, f, det, idet, offsetX = texture.offset.x / texture.repeat.x, offsetY = texture.offset.y / texture.repeat.y, width = texture.image.width * texture.repeat.x, height = texture.image.height * texture.repeat.y; u0 = ( u0 + offsetX ) * width; v0 = ( v0 + offsetY ) * height; u1 = ( u1 + offsetX ) * width; v1 = ( v1 + offsetY ) * height; u2 = ( u2 + offsetX ) * width; v2 = ( v2 + offsetY ) * height; x1 -= x0; y1 -= y0; x2 -= x0; y2 -= y0; u1 -= u0; v1 -= v0; u2 -= u0; v2 -= v0; det = u1 * v2 - u2 * v1; if ( det === 0 ) return; idet = 1 / det; a = ( v2 * x1 - v1 * x2 ) * idet; b = ( v2 * y1 - v1 * y2 ) * idet; c = ( u1 * x2 - u2 * x1 ) * idet; d = ( u1 * y2 - u2 * y1 ) * idet; e = x0 - a * u0 - c * v0; f = y0 - b * u0 - d * v0; _context.save(); _context.transform( a, b, c, d, e, f ); _context.fill(); _context.restore(); } function clipImage( x0, y0, x1, y1, x2, y2, u0, v0, u1, v1, u2, v2, image ) { // http://extremelysatisfactorytotalitarianism.com/blog/?p=2120 var a, b, c, d, e, f, det, idet, width = image.width - 1, height = image.height - 1; u0 *= width; v0 *= height; u1 *= width; v1 *= height; u2 *= width; v2 *= height; x1 -= x0; y1 -= y0; x2 -= x0; y2 -= y0; u1 -= u0; v1 -= v0; u2 -= u0; v2 -= v0; det = u1 * v2 - u2 * v1; idet = 1 / det; a = ( v2 * x1 - v1 * x2 ) * idet; b = ( v2 * y1 - v1 * y2 ) * idet; c = ( u1 * x2 - u2 * x1 ) * idet; d = ( u1 * y2 - u2 * y1 ) * idet; e = x0 - a * u0 - c * v0; f = y0 - b * u0 - d * v0; _context.save(); _context.transform( a, b, c, d, e, f ); _context.clip(); _context.drawImage( image, 0, 0 ); _context.restore(); } // Hide anti-alias gaps function expand( v1, v2, pixels ) { var x = v2.x - v1.x, y = v2.y - v1.y, det = x * x + y * y, idet; if ( det === 0 ) return; idet = pixels / Math.sqrt( det ); x *= idet; y *= idet; v2.x += x; v2.y += y; v1.x -= x; v1.y -= y; } // Context cached methods. function setOpacity( value ) { if ( _contextGlobalAlpha !== value ) { _context.globalAlpha = value; _contextGlobalAlpha = value; } } function setBlending( value ) { if ( _contextGlobalCompositeOperation !== value ) { if ( value === THREE.NormalBlending ) { _context.globalCompositeOperation = 'source-over'; } else if ( value === THREE.AdditiveBlending ) { _context.globalCompositeOperation = 'lighter'; } else if ( value === THREE.SubtractiveBlending ) { _context.globalCompositeOperation = 'darker'; } _contextGlobalCompositeOperation = value; } } function setLineWidth( value ) { if ( _contextLineWidth !== value ) { _context.lineWidth = value; _contextLineWidth = value; } } function setLineCap( value ) { // "butt", "round", "square" if ( _contextLineCap !== value ) { _context.lineCap = value; _contextLineCap = value; } } function setLineJoin( value ) { // "round", "bevel", "miter" if ( _contextLineJoin !== value ) { _context.lineJoin = value; _contextLineJoin = value; } } function setStrokeStyle( value ) { if ( _contextStrokeStyle !== value ) { _context.strokeStyle = value; _contextStrokeStyle = value; } } function setFillStyle( value ) { if ( _contextFillStyle !== value ) { _context.fillStyle = value; _contextFillStyle = value; } } function setLineDash( value ) { if ( _contextLineDash.length !== value.length ) { _context.setLineDash( value ); _contextLineDash = value; } } }; ================================================ FILE: js/color.js ================================================ var colors = new Array( [62,35,255], [60,255,60], [255,35,98], [45,175,230], [255,0,255], [255,128,0]); // var step = 0; //color table indices for: // current color left // next color left // current color right // next color right var colorIndices = [0,1,2,3]; //transition speed var gradientSpeed = 0.002; function updateGradient() { if ( $===undefined ) return; var c0_0 = colors[colorIndices[0]]; var c0_1 = colors[colorIndices[1]]; var c1_0 = colors[colorIndices[2]]; var c1_1 = colors[colorIndices[3]]; var istep = 1 - step; var r1 = Math.round(istep * c0_0[0] + step * c0_1[0]); var g1 = Math.round(istep * c0_0[1] + step * c0_1[1]); var b1 = Math.round(istep * c0_0[2] + step * c0_1[2]); var color1 = "rgb("+r1+","+g1+","+b1+")"; var r2 = Math.round(istep * c1_0[0] + step * c1_1[0]); var g2 = Math.round(istep * c1_0[1] + step * c1_1[1]); var b2 = Math.round(istep * c1_0[2] + step * c1_1[2]); var color2 = "rgb("+r2+","+g2+","+b2+")"; $('.gradient').css({ background: "-webkit-gradient(linear, left top, right top, from("+color1+"), to("+color2+"))"}).css({ background: "-moz-linear-gradient(left, "+color1+" 0%, "+color2+" 100%)"}); step += gradientSpeed; if ( step >= 1 ) { step %= 1; colorIndices[0] = colorIndices[1]; colorIndices[2] = colorIndices[3]; //pick two new target color indices //do not pick the same as the current one colorIndices[1] = ( colorIndices[1] + Math.floor( 1 + Math.random() * (colors.length - 1))) % colors.length; colorIndices[3] = ( colorIndices[3] + Math.floor( 1 + Math.random() * (colors.length - 1))) % colors.length; } } setInterval(updateGradient,10); ================================================ FILE: js/projector.js ================================================ /** * @author mrdoob / http://mrdoob.com/ * @author supereggbert / http://www.paulbrunt.co.uk/ * @author julianwa / https://github.com/julianwa */ THREE.RenderableObject = function () { this.id = 0; this.object = null; this.z = 0; }; // THREE.RenderableFace = function () { this.id = 0; this.v1 = new THREE.RenderableVertex(); this.v2 = new THREE.RenderableVertex(); this.v3 = new THREE.RenderableVertex(); this.normalModel = new THREE.Vector3(); this.vertexNormalsModel = [ new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3() ]; this.vertexNormalsLength = 0; this.color = new THREE.Color(); this.material = null; this.uvs = [ new THREE.Vector2(), new THREE.Vector2(), new THREE.Vector2() ]; this.z = 0; }; // THREE.RenderableVertex = function () { this.position = new THREE.Vector3(); this.positionWorld = new THREE.Vector3(); this.positionScreen = new THREE.Vector4(); this.visible = true; }; THREE.RenderableVertex.prototype.copy = function ( vertex ) { this.positionWorld.copy( vertex.positionWorld ); this.positionScreen.copy( vertex.positionScreen ); }; // THREE.RenderableLine = function () { this.id = 0; this.v1 = new THREE.RenderableVertex(); this.v2 = new THREE.RenderableVertex(); this.vertexColors = [ new THREE.Color(), new THREE.Color() ]; this.material = null; this.z = 0; }; // THREE.RenderableSprite = function () { this.id = 0; this.object = null; this.x = 0; this.y = 0; this.z = 0; this.rotation = 0; this.scale = new THREE.Vector2(); this.material = null; }; // THREE.Projector = function () { var _object, _objectCount, _objectPool = [], _objectPoolLength = 0, _vertex, _vertexCount, _vertexPool = [], _vertexPoolLength = 0, _face, _faceCount, _facePool = [], _facePoolLength = 0, _line, _lineCount, _linePool = [], _linePoolLength = 0, _sprite, _spriteCount, _spritePool = [], _spritePoolLength = 0, _renderData = { objects: [], lights: [], elements: [] }, _vector3 = new THREE.Vector3(), _vector4 = new THREE.Vector4(), _clipBox = new THREE.Box3( new THREE.Vector3( - 1, - 1, - 1 ), new THREE.Vector3( 1, 1, 1 ) ), _boundingBox = new THREE.Box3(), _points3 = new Array( 3 ), _points4 = new Array( 4 ), _viewMatrix = new THREE.Matrix4(), _viewProjectionMatrix = new THREE.Matrix4(), _modelMatrix, _modelViewProjectionMatrix = new THREE.Matrix4(), _normalMatrix = new THREE.Matrix3(), _frustum = new THREE.Frustum(), _clippedVertex1PositionScreen = new THREE.Vector4(), _clippedVertex2PositionScreen = new THREE.Vector4(); // this.projectVector = function ( vector, camera ) { console.warn( 'THREE.Projector: .projectVector() is now vector.project().' ); vector.project( camera ); }; this.unprojectVector = function ( vector, camera ) { console.warn( 'THREE.Projector: .unprojectVector() is now vector.unproject().' ); vector.unproject( camera ); }; this.pickingRay = function ( vector, camera ) { console.error( 'THREE.Projector: .pickingRay() is now raycaster.setFromCamera().' ); }; // var RenderList = function () { var normals = []; var uvs = []; var object = null; var material = null; var normalMatrix = new THREE.Matrix3(); var setObject = function ( value ) { object = value; material = object.material; normalMatrix.getNormalMatrix( object.matrixWorld ); normals.length = 0; uvs.length = 0; }; var projectVertex = function ( vertex ) { var position = vertex.position; var positionWorld = vertex.positionWorld; var positionScreen = vertex.positionScreen; positionWorld.copy( position ).applyMatrix4( _modelMatrix ); positionScreen.copy( positionWorld ).applyMatrix4( _viewProjectionMatrix ); var invW = 1 / positionScreen.w; positionScreen.x *= invW; positionScreen.y *= invW; positionScreen.z *= invW; vertex.visible = positionScreen.x >= - 1 && positionScreen.x <= 1 && positionScreen.y >= - 1 && positionScreen.y <= 1 && positionScreen.z >= - 1 && positionScreen.z <= 1; }; var pushVertex = function ( x, y, z ) { _vertex = getNextVertexInPool(); _vertex.position.set( x, y, z ); projectVertex( _vertex ); }; var pushNormal = function ( x, y, z ) { normals.push( x, y, z ); }; var pushUv = function ( x, y ) { uvs.push( x, y ); }; var checkTriangleVisibility = function ( v1, v2, v3 ) { if ( v1.visible === true || v2.visible === true || v3.visible === true ) return true; _points3[ 0 ] = v1.positionScreen; _points3[ 1 ] = v2.positionScreen; _points3[ 2 ] = v3.positionScreen; return _clipBox.isIntersectionBox( _boundingBox.setFromPoints( _points3 ) ); }; var checkBackfaceCulling = function ( v1, v2, v3 ) { return ( ( v3.positionScreen.x - v1.positionScreen.x ) * ( v2.positionScreen.y - v1.positionScreen.y ) - ( v3.positionScreen.y - v1.positionScreen.y ) * ( v2.positionScreen.x - v1.positionScreen.x ) ) < 0; }; var pushLine = function ( a, b ) { var v1 = _vertexPool[ a ]; var v2 = _vertexPool[ b ]; _line = getNextLineInPool(); _line.id = object.id; _line.v1.copy( v1 ); _line.v2.copy( v2 ); _line.z = ( v1.positionScreen.z + v2.positionScreen.z ) / 2; _line.material = object.material; _renderData.elements.push( _line ); }; var pushTriangle = function ( a, b, c ) { var v1 = _vertexPool[ a ]; var v2 = _vertexPool[ b ]; var v3 = _vertexPool[ c ]; if ( checkTriangleVisibility( v1, v2, v3 ) === false ) return; if ( material.side === THREE.DoubleSide || checkBackfaceCulling( v1, v2, v3 ) === true ) { _face = getNextFaceInPool(); _face.id = object.id; _face.v1.copy( v1 ); _face.v2.copy( v2 ); _face.v3.copy( v3 ); _face.z = ( v1.positionScreen.z + v2.positionScreen.z + v3.positionScreen.z ) / 3; for ( var i = 0; i < 3; i ++ ) { var offset = arguments[ i ] * 3; var normal = _face.vertexNormalsModel[ i ]; normal.set( normals[ offset ], normals[ offset + 1 ], normals[ offset + 2 ] ); normal.applyMatrix3( normalMatrix ).normalize(); var offset2 = arguments[ i ] * 2; var uv = _face.uvs[ i ]; uv.set( uvs[ offset2 ], uvs[ offset2 + 1 ] ); } _face.vertexNormalsLength = 3; _face.material = object.material; _renderData.elements.push( _face ); } }; return { setObject: setObject, projectVertex: projectVertex, checkTriangleVisibility: checkTriangleVisibility, checkBackfaceCulling: checkBackfaceCulling, pushVertex: pushVertex, pushNormal: pushNormal, pushUv: pushUv, pushLine: pushLine, pushTriangle: pushTriangle } }; var renderList = new RenderList(); this.projectScene = function ( scene, camera, sortObjects, sortElements ) { _faceCount = 0; _lineCount = 0; _spriteCount = 0; _renderData.elements.length = 0; if ( scene.autoUpdate === true ) scene.updateMatrixWorld(); if ( camera.parent === undefined ) camera.updateMatrixWorld(); _viewMatrix.copy( camera.matrixWorldInverse.getInverse( camera.matrixWorld ) ); _viewProjectionMatrix.multiplyMatrices( camera.projectionMatrix, _viewMatrix ); _frustum.setFromMatrix( _viewProjectionMatrix ); // _objectCount = 0; _renderData.objects.length = 0; _renderData.lights.length = 0; scene.traverseVisible( function ( object ) { if ( object instanceof THREE.Light ) { _renderData.lights.push( object ); } else if ( object instanceof THREE.Mesh || object instanceof THREE.Line || object instanceof THREE.Sprite ) { if ( object.material.visible === false ) return; if ( object.frustumCulled === false || _frustum.intersectsObject( object ) === true ) { _object = getNextObjectInPool(); _object.id = object.id; _object.object = object; _vector3.setFromMatrixPosition( object.matrixWorld ); _vector3.applyProjection( _viewProjectionMatrix ); _object.z = _vector3.z; _renderData.objects.push( _object ); } } } ); if ( sortObjects === true ) { _renderData.objects.sort( painterSort ); } // for ( var o = 0, ol = _renderData.objects.length; o < ol; o ++ ) { var object = _renderData.objects[ o ].object; var geometry = object.geometry; renderList.setObject( object ); _modelMatrix = object.matrixWorld; _vertexCount = 0; if ( object instanceof THREE.Mesh ) { if ( geometry instanceof THREE.BufferGeometry ) { var attributes = geometry.attributes; var offsets = geometry.offsets; if ( attributes.position === undefined ) continue; var positions = attributes.position.array; for ( var i = 0, l = positions.length; i < l; i += 3 ) { renderList.pushVertex( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] ); } if ( attributes.normal !== undefined ) { var normals = attributes.normal.array; for ( var i = 0, l = normals.length; i < l; i += 3 ) { renderList.pushNormal( normals[ i ], normals[ i + 1 ], normals[ i + 2 ] ); } } if ( attributes.uv !== undefined ) { var uvs = attributes.uv.array; for ( var i = 0, l = uvs.length; i < l; i += 2 ) { renderList.pushUv( uvs[ i ], uvs[ i + 1 ] ); } } if ( attributes.index !== undefined ) { var indices = attributes.index.array; if ( offsets.length > 0 ) { for ( var o = 0; o < offsets.length; o ++ ) { var offset = offsets[ o ]; var index = offset.index; for ( var i = offset.start, l = offset.start + offset.count; i < l; i += 3 ) { renderList.pushTriangle( indices[ i ] + index, indices[ i + 1 ] + index, indices[ i + 2 ] + index ); } } } else { for ( var i = 0, l = indices.length; i < l; i += 3 ) { renderList.pushTriangle( indices[ i ], indices[ i + 1 ], indices[ i + 2 ] ); } } } else { for ( var i = 0, l = positions.length / 3; i < l; i += 3 ) { renderList.pushTriangle( i, i + 1, i + 2 ); } } } else if ( geometry instanceof THREE.Geometry ) { var vertices = geometry.vertices; var faces = geometry.faces; var faceVertexUvs = geometry.faceVertexUvs[ 0 ]; _normalMatrix.getNormalMatrix( _modelMatrix ); var material = object.material; var isFaceMaterial = material instanceof THREE.MeshFaceMaterial; var objectMaterials = isFaceMaterial === true ? object.material : null; for ( var v = 0, vl = vertices.length; v < vl; v ++ ) { var vertex = vertices[ v ]; _vector3.copy( vertex ); if ( material.morphTargets === true ) { var morphTargets = geometry.morphTargets; var morphInfluences = object.morphTargetInfluences; for ( var t = 0, tl = morphTargets.length; t < tl; t ++ ) { var influence = morphInfluences[ t ]; if ( influence === 0 ) continue; var target = morphTargets[ t ]; var targetVertex = target.vertices[ v ]; _vector3.x += ( targetVertex.x - vertex.x ) * influence; _vector3.y += ( targetVertex.y - vertex.y ) * influence; _vector3.z += ( targetVertex.z - vertex.z ) * influence; } } renderList.pushVertex( _vector3.x, _vector3.y, _vector3.z ); } for ( var f = 0, fl = faces.length; f < fl; f ++ ) { var face = faces[ f ]; var material = isFaceMaterial === true ? objectMaterials.materials[ face.materialIndex ] : object.material; if ( material === undefined ) continue; var side = material.side; var v1 = _vertexPool[ face.a ]; var v2 = _vertexPool[ face.b ]; var v3 = _vertexPool[ face.c ]; if ( renderList.checkTriangleVisibility( v1, v2, v3 ) === false ) continue; var visible = renderList.checkBackfaceCulling( v1, v2, v3 ); if ( side !== THREE.DoubleSide ) { if ( side === THREE.FrontSide && visible === false ) continue; if ( side === THREE.BackSide && visible === true ) continue; } _face = getNextFaceInPool(); _face.id = object.id; _face.v1.copy( v1 ); _face.v2.copy( v2 ); _face.v3.copy( v3 ); _face.normalModel.copy( face.normal ); if ( visible === false && ( side === THREE.BackSide || side === THREE.DoubleSide ) ) { _face.normalModel.negate(); } _face.normalModel.applyMatrix3( _normalMatrix ).normalize(); var faceVertexNormals = face.vertexNormals; for ( var n = 0, nl = Math.min( faceVertexNormals.length, 3 ); n < nl; n ++ ) { var normalModel = _face.vertexNormalsModel[ n ]; normalModel.copy( faceVertexNormals[ n ] ); if ( visible === false && ( side === THREE.BackSide || side === THREE.DoubleSide ) ) { normalModel.negate(); } normalModel.applyMatrix3( _normalMatrix ).normalize(); } _face.vertexNormalsLength = faceVertexNormals.length; var vertexUvs = faceVertexUvs[ f ]; if ( vertexUvs !== undefined ) { for ( var u = 0; u < 3; u ++ ) { _face.uvs[ u ].copy( vertexUvs[ u ] ); } } _face.color = face.color; _face.material = material; _face.z = ( v1.positionScreen.z + v2.positionScreen.z + v3.positionScreen.z ) / 3; _renderData.elements.push( _face ); } } } else if ( object instanceof THREE.Line ) { if ( geometry instanceof THREE.BufferGeometry ) { var attributes = geometry.attributes; if ( attributes.position !== undefined ) { var positions = attributes.position.array; for ( var i = 0, l = positions.length; i < l; i += 3 ) { renderList.pushVertex( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] ); } if ( attributes.index !== undefined ) { var indices = attributes.index.array; for ( var i = 0, l = indices.length; i < l; i += 2 ) { renderList.pushLine( indices[ i ], indices[ i + 1 ] ); } } else { var step = object.mode === THREE.LinePieces ? 2 : 1; for ( var i = 0, l = ( positions.length / 3 ) - 1; i < l; i += step ) { renderList.pushLine( i, i + 1 ); } } } } else if ( geometry instanceof THREE.Geometry ) { _modelViewProjectionMatrix.multiplyMatrices( _viewProjectionMatrix, _modelMatrix ); var vertices = object.geometry.vertices; if ( vertices.length === 0 ) continue; v1 = getNextVertexInPool(); v1.positionScreen.copy( vertices[ 0 ] ).applyMatrix4( _modelViewProjectionMatrix ); // Handle LineStrip and LinePieces var step = object.mode === THREE.LinePieces ? 2 : 1; for ( var v = 1, vl = vertices.length; v < vl; v ++ ) { v1 = getNextVertexInPool(); v1.positionScreen.copy( vertices[ v ] ).applyMatrix4( _modelViewProjectionMatrix ); if ( ( v + 1 ) % step > 0 ) continue; v2 = _vertexPool[ _vertexCount - 2 ]; _clippedVertex1PositionScreen.copy( v1.positionScreen ); _clippedVertex2PositionScreen.copy( v2.positionScreen ); if ( clipLine( _clippedVertex1PositionScreen, _clippedVertex2PositionScreen ) === true ) { // Perform the perspective divide _clippedVertex1PositionScreen.multiplyScalar( 1 / _clippedVertex1PositionScreen.w ); _clippedVertex2PositionScreen.multiplyScalar( 1 / _clippedVertex2PositionScreen.w ); _line = getNextLineInPool(); _line.id = object.id; _line.v1.positionScreen.copy( _clippedVertex1PositionScreen ); _line.v2.positionScreen.copy( _clippedVertex2PositionScreen ); _line.z = Math.max( _clippedVertex1PositionScreen.z, _clippedVertex2PositionScreen.z ); _line.material = object.material; if ( object.material.vertexColors === THREE.VertexColors ) { _line.vertexColors[ 0 ].copy( object.geometry.colors[ v ] ); _line.vertexColors[ 1 ].copy( object.geometry.colors[ v - 1 ] ); } _renderData.elements.push( _line ); } } } } else if ( object instanceof THREE.Sprite ) { _vector4.set( _modelMatrix.elements[ 12 ], _modelMatrix.elements[ 13 ], _modelMatrix.elements[ 14 ], 1 ); _vector4.applyMatrix4( _viewProjectionMatrix ); var invW = 1 / _vector4.w; _vector4.z *= invW; if ( _vector4.z >= - 1 && _vector4.z <= 1 ) { _sprite = getNextSpriteInPool(); _sprite.id = object.id; _sprite.x = _vector4.x * invW; _sprite.y = _vector4.y * invW; _sprite.z = _vector4.z; _sprite.object = object; _sprite.rotation = object.rotation; _sprite.scale.x = object.scale.x * Math.abs( _sprite.x - ( _vector4.x + camera.projectionMatrix.elements[ 0 ] ) / ( _vector4.w + camera.projectionMatrix.elements[ 12 ] ) ); _sprite.scale.y = object.scale.y * Math.abs( _sprite.y - ( _vector4.y + camera.projectionMatrix.elements[ 5 ] ) / ( _vector4.w + camera.projectionMatrix.elements[ 13 ] ) ); _sprite.material = object.material; _renderData.elements.push( _sprite ); } } } if ( sortElements === true ) { _renderData.elements.sort( painterSort ); } return _renderData; }; // Pools function getNextObjectInPool() { if ( _objectCount === _objectPoolLength ) { var object = new THREE.RenderableObject(); _objectPool.push( object ); _objectPoolLength ++; _objectCount ++; return object; } return _objectPool[ _objectCount ++ ]; } function getNextVertexInPool() { if ( _vertexCount === _vertexPoolLength ) { var vertex = new THREE.RenderableVertex(); _vertexPool.push( vertex ); _vertexPoolLength ++; _vertexCount ++; return vertex; } return _vertexPool[ _vertexCount ++ ]; } function getNextFaceInPool() { if ( _faceCount === _facePoolLength ) { var face = new THREE.RenderableFace(); _facePool.push( face ); _facePoolLength ++; _faceCount ++; return face; } return _facePool[ _faceCount ++ ]; } function getNextLineInPool() { if ( _lineCount === _linePoolLength ) { var line = new THREE.RenderableLine(); _linePool.push( line ); _linePoolLength ++; _lineCount ++ return line; } return _linePool[ _lineCount ++ ]; } function getNextSpriteInPool() { if ( _spriteCount === _spritePoolLength ) { var sprite = new THREE.RenderableSprite(); _spritePool.push( sprite ); _spritePoolLength ++; _spriteCount ++ return sprite; } return _spritePool[ _spriteCount ++ ]; } // function painterSort( a, b ) { if ( a.z !== b.z ) { return b.z - a.z; } else if ( a.id !== b.id ) { return a.id - b.id; } else { return 0; } } function clipLine( s1, s2 ) { var alpha1 = 0, alpha2 = 1, // Calculate the boundary coordinate of each vertex for the near and far clip planes, // Z = -1 and Z = +1, respectively. bc1near = s1.z + s1.w, bc2near = s2.z + s2.w, bc1far = - s1.z + s1.w, bc2far = - s2.z + s2.w; if ( bc1near >= 0 && bc2near >= 0 && bc1far >= 0 && bc2far >= 0 ) { // Both vertices lie entirely within all clip planes. return true; } else if ( ( bc1near < 0 && bc2near < 0 ) || ( bc1far < 0 && bc2far < 0 ) ) { // Both vertices lie entirely outside one of the clip planes. return false; } else { // The line segment spans at least one clip plane. if ( bc1near < 0 ) { // v1 lies outside the near plane, v2 inside alpha1 = Math.max( alpha1, bc1near / ( bc1near - bc2near ) ); } else if ( bc2near < 0 ) { // v2 lies outside the near plane, v1 inside alpha2 = Math.min( alpha2, bc1near / ( bc1near - bc2near ) ); } if ( bc1far < 0 ) { // v1 lies outside the far plane, v2 inside alpha1 = Math.max( alpha1, bc1far / ( bc1far - bc2far ) ); } else if ( bc2far < 0 ) { // v2 lies outside the far plane, v2 inside alpha2 = Math.min( alpha2, bc1far / ( bc1far - bc2far ) ); } if ( alpha2 < alpha1 ) { // The line segment spans two boundaries, but is outside both of them. // (This can't happen when we're only clipping against just near/far but good // to leave the check here for future usage if other clip planes are added.) return false; } else { // Update the s1 and s2 vertices to match the clipped line segment. s1.lerp( s2, alpha1 ); s2.lerp( s1, 1 - alpha2 ); return true; } } } };