diff --git a/examples/index.html b/examples/index.html
index 5beca35..1350af8 100644
--- a/examples/index.html
+++ b/examples/index.html
@@ -36,7 +36,7 @@
// if you add renderertype:'Canvas' to the options for ThreejsLayer, you can force the usage of CanvasRenderer
new ThreejsLayer({ map: map }, function(layer){
-
+
if (layer.renderertype=='Canvas' || !Detector.webgl) {
texture = new THREE.Texture(generateSprite());
particles = new THREE.Object3D();
@@ -48,8 +48,8 @@
depthTest: false,
transparent: true
});
-
-
+
+
photos.forEach(function (photo) {
var particle = new THREE.Sprite(material);
var location = new google.maps.LatLng(photo[0], photo[1]),
@@ -74,7 +74,7 @@
texture.needsUpdate = true;
- material = new THREE.ParticleBasicMaterial({
+ material = new THREE.PointCloudMaterial({
size: 20,
map: texture,
opacity: 0.3,
@@ -83,7 +83,7 @@
transparent: true
});
- particles = new THREE.ParticleSystem( geometry, material );
+ particles = new THREE.PointCloud( geometry, material );
}
layer.add( particles );
diff --git a/lib/three.js b/lib/three.js
index b6b1e41..636b15d 100644
--- a/lib/three.js
+++ b/lib/three.js
@@ -4,15 +4,32 @@
* @author mrdoob / http://mrdoob.com/
*/
-var THREE = { REVISION: '68' };
+var THREE = { REVISION: '69' };
// browserify support
+
if ( typeof module === 'object' ) {
module.exports = THREE;
}
+// polyfills
+
+if ( Math.sign === undefined ) {
+
+ Math.sign = function ( x ) {
+
+ return ( x < 0 ) ? - 1 : ( x > 0 ) ? 1 : 0;
+
+ };
+
+}
+
+// https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent.button
+
+THREE.MOUSE = { LEFT: 0, MIDDLE: 1, RIGHT: 2 };
+
// GL STATE CONSTANTS
THREE.CullFaceNone = 0;
@@ -65,6 +82,8 @@ THREE.CustomBlending = 5;
THREE.AddEquation = 100;
THREE.SubtractEquation = 101;
THREE.ReverseSubtractEquation = 102;
+THREE.MinEquation = 103;
+THREE.MaxEquation = 104;
// custom blending destination factors
@@ -146,20 +165,21 @@ THREE.RGBAFormat = 1021;
THREE.LuminanceFormat = 1022;
THREE.LuminanceAlphaFormat = 1023;
-// Compressed texture formats
+// DDS / ST3C Compressed texture formats
THREE.RGB_S3TC_DXT1_Format = 2001;
THREE.RGBA_S3TC_DXT1_Format = 2002;
THREE.RGBA_S3TC_DXT3_Format = 2003;
THREE.RGBA_S3TC_DXT5_Format = 2004;
-/*
-// Potential future PVRTC compressed texture formats
+
+// PVRTC compressed texture formats
+
THREE.RGB_PVRTC_4BPPV1_Format = 2100;
THREE.RGB_PVRTC_2BPPV1_Format = 2101;
THREE.RGBA_PVRTC_4BPPV1_Format = 2102;
THREE.RGBA_PVRTC_2BPPV1_Format = 2103;
-*/
+
// File:src/math/Color.js
@@ -973,6 +993,9 @@ THREE.Quaternion.prototype = {
slerp: function ( qb, t ) {
+ if ( t === 0 ) return this;
+ if ( t === 1 ) return this.copy( qb );
+
var x = this._x, y = this._y, z = this._z, w = this._w;
// http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/
@@ -1039,12 +1062,14 @@ THREE.Quaternion.prototype = {
},
- fromArray: function ( array ) {
+ fromArray: function ( array, offset ) {
- this._x = array[ 0 ];
- this._y = array[ 1 ];
- this._z = array[ 2 ];
- this._w = array[ 3 ];
+ if ( offset === undefined ) offset = 0;
+
+ this._x = array[ offset ];
+ this._y = array[ offset + 1 ];
+ this._z = array[ offset + 2 ];
+ this._w = array[ offset + 3 ];
this.onChangeCallback();
@@ -1052,9 +1077,17 @@ THREE.Quaternion.prototype = {
},
- toArray: function () {
+ toArray: function ( array, offset ) {
- return [ this._x, this._y, this._z, this._w ];
+ if ( array === undefined ) array = [];
+ if ( offset === undefined ) offset = 0;
+
+ array[ offset ] = this._x;
+ array[ offset + 1 ] = this._y;
+ array[ offset + 2 ] = this._z;
+ array[ offset + 3 ] = this._w;
+
+ return array;
},
@@ -1461,18 +1494,26 @@ THREE.Vector2.prototype = {
},
- fromArray: function ( array ) {
+ fromArray: function ( array, offset ) {
- this.x = array[ 0 ];
- this.y = array[ 1 ];
+ if ( offset === undefined ) offset = 0;
+
+ this.x = array[ offset ];
+ this.y = array[ offset + 1 ];
return this;
},
- toArray: function () {
+ toArray: function ( array, offset ) {
+
+ if ( array === undefined ) array = [];
+ if ( offset === undefined ) offset = 0;
+
+ array[ offset ] = this.x;
+ array[ offset + 1 ] = this.y;
- return [ this.x, this.y ];
+ return array;
},
@@ -1793,6 +1834,36 @@ THREE.Vector3.prototype = {
},
+ project: function () {
+
+ var matrix;
+
+ return function ( camera ) {
+
+ if ( matrix === undefined ) matrix = new THREE.Matrix4();
+
+ matrix.multiplyMatrices( camera.projectionMatrix, matrix.getInverse( camera.matrixWorld ) );
+ return this.applyProjection( matrix );
+
+ };
+
+ }(),
+
+ unproject: function () {
+
+ var matrix;
+
+ return function ( camera ) {
+
+ if ( matrix === undefined ) matrix = new THREE.Matrix4();
+
+ matrix.multiplyMatrices( camera.matrixWorld, matrix.getInverse( camera.projectionMatrix ) );
+ return this.applyProjection( matrix );
+
+ };
+
+ }(),
+
transformDirection: function ( m ) {
// input: THREE.Matrix4 affine matrix
@@ -2242,19 +2313,28 @@ THREE.Vector3.prototype = {
},
- fromArray: function ( array ) {
+ fromArray: function ( array, offset ) {
- this.x = array[ 0 ];
- this.y = array[ 1 ];
- this.z = array[ 2 ];
+ if ( offset === undefined ) offset = 0;
+
+ this.x = array[ offset ];
+ this.y = array[ offset + 1 ];
+ this.z = array[ offset + 2 ];
return this;
},
- toArray: function () {
+ toArray: function ( array, offset ) {
- return [ this.x, this.y, this.z ];
+ if ( array === undefined ) array = [];
+ if ( offset === undefined ) offset = 0;
+
+ array[ offset ] = this.x;
+ array[ offset + 1 ] = this.y;
+ array[ offset + 2 ] = this.z;
+
+ return array;
},
@@ -2891,20 +2971,30 @@ THREE.Vector4.prototype = {
},
- fromArray: function ( array ) {
+ fromArray: function ( array, offset ) {
- this.x = array[ 0 ];
- this.y = array[ 1 ];
- this.z = array[ 2 ];
- this.w = array[ 3 ];
+ if ( offset === undefined ) offset = 0;
+
+ this.x = array[ offset ];
+ this.y = array[ offset + 1 ];
+ this.z = array[ offset + 2 ];
+ this.w = array[ offset + 3 ];
return this;
},
- toArray: function () {
+ toArray: function ( array, offset ) {
+
+ if ( array === undefined ) array = [];
+ if ( offset === undefined ) offset = 0;
+
+ array[ offset ] = this.x;
+ array[ offset + 1 ] = this.y;
+ array[ offset + 2 ] = this.z;
+ array[ offset + 3 ] = this.w;
- return [ this.x, this.y, this.z, this.w ];
+ return array;
},
@@ -3708,17 +3798,37 @@ THREE.Box3.prototype = {
object.traverse( function ( node ) {
- if ( node.geometry !== undefined && node.geometry.vertices !== undefined ) {
+ var geometry = node.geometry;
+
+ if ( geometry !== undefined ) {
+
+ if ( geometry instanceof THREE.Geometry ) {
+
+ var vertices = geometry.vertices;
+
+ for ( var i = 0, il = vertices.length; i < il; i ++ ) {
+
+ v1.copy( vertices[ i ] );
+
+ v1.applyMatrix4( node.matrixWorld );
+
+ scope.expandByPoint( v1 );
- var vertices = node.geometry.vertices;
+ }
+
+ } else if ( geometry instanceof THREE.BufferGeometry && geometry.attributes[ 'position' ] !== undefined ) {
+
+ var positions = geometry.attributes[ 'position' ].array;
+
+ for ( var i = 0, il = positions.length; i < il; i += 3 ) {
- for ( var i = 0, il = vertices.length; i < il; i ++ ) {
+ v1.set( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] );
- v1.copy( vertices[ i ] );
+ v1.applyMatrix4( node.matrixWorld );
- v1.applyMatrix4( node.matrixWorld );
+ scope.expandByPoint( v1 );
- scope.expandByPoint( v1 );
+ }
}
@@ -3978,15 +4088,21 @@ THREE.Box3.prototype = {
* @author bhouston / http://exocortex.com
*/
-THREE.Matrix3 = function ( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) {
+THREE.Matrix3 = function () {
+
+ this.elements = new Float32Array( [
+
+ 1, 0, 0,
+ 0, 1, 0,
+ 0, 0, 1
+
+ ] );
- this.elements = new Float32Array( 9 );
+ if ( arguments.length > 0 ) {
- var te = this.elements;
+ console.error( 'THREE.Matrix3: the constructor no longer reads arguments. use .set() instead.' );
- te[ 0 ] = ( n11 !== undefined ) ? n11 : 1; te[ 3 ] = n12 || 0; te[ 6 ] = n13 || 0;
- te[ 1 ] = n21 || 0; te[ 4 ] = ( n22 !== undefined ) ? n22 : 1; te[ 7 ] = n23 || 0;
- te[ 2 ] = n31 || 0; te[ 5 ] = n32 || 0; te[ 8 ] = ( n33 !== undefined ) ? n33 : 1;
+ }
};
@@ -4233,15 +4349,7 @@ THREE.Matrix3.prototype = {
clone: function () {
- var te = this.elements;
-
- return new THREE.Matrix3(
-
- te[ 0 ], te[ 3 ], te[ 6 ],
- te[ 1 ], te[ 4 ], te[ 7 ],
- te[ 2 ], te[ 5 ], te[ 8 ]
-
- );
+ return new THREE.Matrix3().fromArray( this.elements );
}
@@ -4262,20 +4370,22 @@ THREE.Matrix3.prototype = {
* @author WestLangley / http://github.com/WestLangley
*/
+THREE.Matrix4 = function () {
+
+ this.elements = new Float32Array( [
-THREE.Matrix4 = function ( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) {
+ 1, 0, 0, 0,
+ 0, 1, 0, 0,
+ 0, 0, 1, 0,
+ 0, 0, 0, 1
- this.elements = new Float32Array( 16 );
+ ] );
- // TODO: if n11 is undefined, then just set to identity, otherwise copy all other values into matrix
- // we should not support semi specification of Matrix4, it is just weird.
+ if ( arguments.length > 0 ) {
- var te = this.elements;
+ console.error( 'THREE.Matrix4: the constructor no longer reads arguments. use .set() instead.' );
- te[ 0 ] = ( n11 !== undefined ) ? n11 : 1; te[ 4 ] = n12 || 0; te[ 8 ] = n13 || 0; te[ 12 ] = n14 || 0;
- te[ 1 ] = n21 || 0; te[ 5 ] = ( n22 !== undefined ) ? n22 : 1; te[ 9 ] = n23 || 0; te[ 13 ] = n24 || 0;
- te[ 2 ] = n31 || 0; te[ 6 ] = n32 || 0; te[ 10 ] = ( n33 !== undefined ) ? n33 : 1; te[ 14 ] = n34 || 0;
- te[ 3 ] = n41 || 0; te[ 7 ] = n42 || 0; te[ 11 ] = n43 || 0; te[ 15 ] = ( n44 !== undefined ) ? n44 : 1;
+ }
};
@@ -4321,7 +4431,7 @@ THREE.Matrix4.prototype = {
extractPosition: function ( m ) {
- console.warn( 'THREEMatrix4: .extractPosition() has been renamed to .copyPosition().' );
+ console.warn( 'THREE.Matrix4: .extractPosition() has been renamed to .copyPosition().' );
return this.copyPosition( m );
},
@@ -5205,16 +5315,7 @@ THREE.Matrix4.prototype = {
clone: function () {
- var te = this.elements;
-
- return new THREE.Matrix4(
-
- te[ 0 ], te[ 4 ], te[ 8 ], te[ 12 ],
- te[ 1 ], te[ 5 ], te[ 9 ], te[ 13 ],
- te[ 2 ], te[ 6 ], te[ 10 ], te[ 14 ],
- te[ 3 ], te[ 7 ], te[ 11 ], te[ 15 ]
-
- );
+ return new THREE.Matrix4().fromArray( this.elements );
}
@@ -6422,12 +6523,6 @@ THREE.Math = {
},
- sign: function ( x ) {
-
- return ( x < 0 ) ? - 1 : ( x > 0 ) ? 1 : 0;
-
- },
-
degToRad: function () {
var degreeToRadiansFactor = Math.PI / 180;
@@ -7070,7 +7165,7 @@ THREE.EventDispatcher.prototype = {
};
//
-
+
THREE.Raycaster.prototype = {
constructor: THREE.Raycaster,
@@ -7101,6 +7196,13 @@ THREE.EventDispatcher.prototype = {
var intersects = [];
+ if ( objects instanceof Array === false ) {
+
+ console.log( 'THREE.Raycaster.intersectObjects: objects is not an Array.' );
+ return intersects;
+
+ }
+
for ( var i = 0, l = objects.length; i < l; i ++ ) {
intersectObject( objects[ i ], this, intersects, recursive );
@@ -7128,10 +7230,12 @@ THREE.EventDispatcher.prototype = {
THREE.Object3D = function () {
- this.id = THREE.Object3DIdCount ++;
+ Object.defineProperty( this, 'id', { value: THREE.Object3DIdCount ++ } );
+
this.uuid = THREE.Math.generateUUID();
this.name = '';
+ this.type = 'Object3D';
this.parent = undefined;
this.children = [];
@@ -7145,13 +7249,16 @@ THREE.Object3D = function () {
var quaternion = new THREE.Quaternion();
var scale = new THREE.Vector3( 1, 1, 1 );
- rotation.onChange( function () {
+ var onRotationChange = function () {
quaternion.setFromEuler( rotation, false );
- } );
+ };
- quaternion.onChange( function () {
+ var onQuaternionChange = function () {
rotation.setFromQuaternion( quaternion, undefined, false );
- } );
+ };
+
+ rotation.onChange( onRotationChange );
+ quaternion.onChange( onQuaternionChange );
Object.defineProperties( this, {
position: {
@@ -7450,26 +7557,10 @@ THREE.Object3D.prototype = {
this.children.push( object );
- // add to scene
-
- var scene = this;
-
- while ( scene.parent !== undefined ) {
-
- scene = scene.parent;
-
- }
-
- if ( scene !== undefined && scene instanceof THREE.Scene ) {
-
- scene.__addObject( object );
-
- }
-
} else {
-
+
console.error( "THREE.Object3D.add:", object, "is not an instance of THREE.Object3D." );
-
+
}
return this;
@@ -7493,122 +7584,169 @@ THREE.Object3D.prototype = {
if ( index !== - 1 ) {
object.parent = undefined;
+
object.dispatchEvent( { type: 'removed' } );
this.children.splice( index, 1 );
- // remove from scene
+ }
+
+ },
- var scene = this;
+ getChildByName: function ( name, recursive ) {
- while ( scene.parent !== undefined ) {
+ console.warn( 'THREE.Object3D: .getChildByName() has been renamed to .getObjectByName().' );
+ return this.getObjectByName( name, recursive );
- scene = scene.parent;
+ },
- }
+ getObjectById: function ( id, recursive ) {
- if ( scene !== undefined && scene instanceof THREE.Scene ) {
+ if ( this.id === id ) return this;
- scene.__removeObject( object );
+ for ( var i = 0, l = this.children.length; i < l; i ++ ) {
+
+ var child = this.children[ i ];
+ var object = child.getObjectById( id, recursive );
+
+ if ( object !== undefined ) {
+
+ return object;
}
}
- },
+ return undefined;
- raycast: function () {},
+ },
- traverse: function ( callback ) {
+ getObjectByName: function ( name, recursive ) {
- callback( this );
+ if ( this.name === name ) return this;
for ( var i = 0, l = this.children.length; i < l; i ++ ) {
- this.children[ i ].traverse( callback );
+ var child = this.children[ i ];
+ var object = child.getObjectByName( name, recursive );
+
+ if ( object !== undefined ) {
+
+ return object;
+
+ }
}
+ return undefined;
+
},
- traverseVisible: function ( callback ) {
+ getWorldPosition: function ( optionalTarget ) {
- if ( this.visible === false ) return;
+ var result = optionalTarget || new THREE.Vector3();
- callback( this );
+ this.updateMatrixWorld( true );
- for ( var i = 0, l = this.children.length; i < l; i ++ ) {
+ return result.setFromMatrixPosition( this.matrixWorld );
- this.children[ i ].traverseVisible( callback );
+ },
- }
+ getWorldQuaternion: function () {
- },
+ var position = new THREE.Vector3();
+ var scale = new THREE.Vector3();
- getObjectById: function ( id, recursive ) {
+ return function ( optionalTarget ) {
- for ( var i = 0, l = this.children.length; i < l; i ++ ) {
+ var result = optionalTarget || new THREE.Quaternion();
- var child = this.children[ i ];
+ this.updateMatrixWorld( true );
+
+ this.matrixWorld.decompose( position, result, scale );
- if ( child.id === id ) {
+ return result;
- return child;
+ }
- }
+ }(),
- if ( recursive === true ) {
+ getWorldRotation: function () {
- child = child.getObjectById( id, recursive );
+ var quaternion = new THREE.Quaternion();
- if ( child !== undefined ) {
+ return function ( optionalTarget ) {
- return child;
+ var result = optionalTarget || new THREE.Euler();
- }
+ this.getWorldQuaternion( quaternion );
- }
+ return result.setFromQuaternion( quaternion, this.rotation.order, false );
}
- return undefined;
+ }(),
- },
+ getWorldScale: function () {
- getObjectByName: function ( name, recursive ) {
+ var position = new THREE.Vector3();
+ var quaternion = new THREE.Quaternion();
- for ( var i = 0, l = this.children.length; i < l; i ++ ) {
+ return function ( optionalTarget ) {
- var child = this.children[ i ];
+ var result = optionalTarget || new THREE.Vector3();
- if ( child.name === name ) {
+ this.updateMatrixWorld( true );
- return child;
+ this.matrixWorld.decompose( position, quaternion, result );
- }
+ return result;
+
+ }
- if ( recursive === true ) {
+ }(),
- child = child.getObjectByName( name, recursive );
+ getWorldDirection: function () {
- if ( child !== undefined ) {
+ var quaternion = new THREE.Quaternion();
- return child;
+ return function ( optionalTarget ) {
- }
+ var result = optionalTarget || new THREE.Vector3();
- }
+ this.getWorldQuaternion( quaternion );
+
+ return result.set( 0, 0, 1 ).applyQuaternion( quaternion );
}
- return undefined;
+ }(),
+
+ raycast: function () {},
+
+ traverse: function ( callback ) {
+
+ callback( this );
+
+ for ( var i = 0, l = this.children.length; i < l; i ++ ) {
+
+ this.children[ i ].traverse( callback );
+
+ }
},
- getChildByName: function ( name, recursive ) {
+ traverseVisible: function ( callback ) {
- console.warn( 'THREE.Object3D: .getChildByName() has been renamed to .getObjectByName().' );
- return this.getObjectByName( name, recursive );
+ if ( this.visible === false ) return;
+
+ callback( this );
+
+ for ( var i = 0, l = this.children.length; i < l; i ++ ) {
+
+ this.children[ i ].traverseVisible( callback );
+
+ }
},
@@ -7652,1780 +7790,1901 @@ THREE.Object3D.prototype = {
},
- clone: function ( object, recursive ) {
+ toJSON: function () {
- if ( object === undefined ) object = new THREE.Object3D();
- if ( recursive === undefined ) recursive = true;
+ var output = {
+ metadata: {
+ version: 4.3,
+ type: 'Object',
+ generator: 'ObjectExporter'
+ }
+ };
- object.name = this.name;
+ //
- object.up.copy( this.up );
+ var geometries = {};
- object.position.copy( this.position );
- object.quaternion.copy( this.quaternion );
- object.scale.copy( this.scale );
+ var parseGeometry = function ( geometry ) {
- object.renderDepth = this.renderDepth;
+ if ( output.geometries === undefined ) {
- object.rotationAutoUpdate = this.rotationAutoUpdate;
+ output.geometries = [];
- object.matrix.copy( this.matrix );
- object.matrixWorld.copy( this.matrixWorld );
+ }
- object.matrixAutoUpdate = this.matrixAutoUpdate;
- object.matrixWorldNeedsUpdate = this.matrixWorldNeedsUpdate;
+ if ( geometries[ geometry.uuid ] === undefined ) {
- object.visible = this.visible;
+ var json = geometry.toJSON();
- object.castShadow = this.castShadow;
- object.receiveShadow = this.receiveShadow;
+ delete json.metadata;
- object.frustumCulled = this.frustumCulled;
+ geometries[ geometry.uuid ] = json;
- object.userData = JSON.parse( JSON.stringify( this.userData ) );
+ output.geometries.push( json );
- if ( recursive === true ) {
+ }
- for ( var i = 0; i < this.children.length; i ++ ) {
+ return geometry.uuid;
- var child = this.children[ i ];
- object.add( child.clone() );
+ };
- }
+ //
- }
+ var materials = {};
- return object;
+ var parseMaterial = function ( material ) {
- }
+ if ( output.materials === undefined ) {
-};
+ output.materials = [];
-THREE.EventDispatcher.prototype.apply( THREE.Object3D.prototype );
+ }
-THREE.Object3DIdCount = 0;
+ if ( materials[ material.uuid ] === undefined ) {
-// File:src/core/Projector.js
+ var json = material.toJSON();
-/**
- * @author mrdoob / http://mrdoob.com/
- * @author supereggbert / http://www.paulbrunt.co.uk/
- * @author julianwa / https://github.com/julianwa
- */
+ delete json.metadata;
-THREE.Projector = function () {
+ materials[ material.uuid ] = json;
- 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,
+ output.materials.push( json );
- _renderData = { objects: [], lights: [], elements: [] },
+ }
- _vA = new THREE.Vector3(),
- _vB = new THREE.Vector3(),
- _vC = new THREE.Vector3(),
+ return material.uuid;
- _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(),
+ var parseObject = function ( object ) {
- _modelMatrix,
- _modelViewProjectionMatrix = new THREE.Matrix4(),
+ var data = {};
- _normalMatrix = new THREE.Matrix3(),
+ data.uuid = object.uuid;
+ data.type = object.type;
- _frustum = new THREE.Frustum(),
+ if ( object.name !== '' ) data.name = object.name;
+ if ( JSON.stringify( object.userData ) !== '{}' ) data.userData = object.userData;
+ if ( object.visible !== true ) data.visible = object.visible;
- _clippedVertex1PositionScreen = new THREE.Vector4(),
- _clippedVertex2PositionScreen = new THREE.Vector4();
+ if ( object instanceof THREE.PerspectiveCamera ) {
- this.projectVector = function ( vector, camera ) {
+ data.fov = object.fov;
+ data.aspect = object.aspect;
+ data.near = object.near;
+ data.far = object.far;
- camera.matrixWorldInverse.getInverse( camera.matrixWorld );
+ } else if ( object instanceof THREE.OrthographicCamera ) {
- _viewProjectionMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse );
+ data.left = object.left;
+ data.right = object.right;
+ data.top = object.top;
+ data.bottom = object.bottom;
+ data.near = object.near;
+ data.far = object.far;
- return vector.applyProjection( _viewProjectionMatrix );
+ } else if ( object instanceof THREE.AmbientLight ) {
- };
+ data.color = object.color.getHex();
- this.unprojectVector = function () {
+ } else if ( object instanceof THREE.DirectionalLight ) {
- var projectionMatrixInverse = new THREE.Matrix4();
+ data.color = object.color.getHex();
+ data.intensity = object.intensity;
- return function ( vector, camera ) {
+ } else if ( object instanceof THREE.PointLight ) {
- projectionMatrixInverse.getInverse( camera.projectionMatrix );
- _viewProjectionMatrix.multiplyMatrices( camera.matrixWorld, projectionMatrixInverse );
+ data.color = object.color.getHex();
+ data.intensity = object.intensity;
+ data.distance = object.distance;
- return vector.applyProjection( _viewProjectionMatrix );
+ } else if ( object instanceof THREE.SpotLight ) {
- };
+ data.color = object.color.getHex();
+ data.intensity = object.intensity;
+ data.distance = object.distance;
+ data.angle = object.angle;
+ data.exponent = object.exponent;
- }();
+ } else if ( object instanceof THREE.HemisphereLight ) {
- this.pickingRay = function ( vector, camera ) {
+ data.color = object.color.getHex();
+ data.groundColor = object.groundColor.getHex();
- // set two vectors with opposing z values
- vector.z = - 1.0;
- var end = new THREE.Vector3( vector.x, vector.y, 1.0 );
+ } else if ( object instanceof THREE.Mesh ) {
- this.unprojectVector( vector, camera );
- this.unprojectVector( end, camera );
+ data.geometry = parseGeometry( object.geometry );
+ data.material = parseMaterial( object.material );
- // find direction from vector to end
- end.sub( vector ).normalize();
+ } else if ( object instanceof THREE.Line ) {
- return new THREE.Raycaster( vector, end );
+ data.geometry = parseGeometry( object.geometry );
+ data.material = parseMaterial( object.material );
- };
+ } else if ( object instanceof THREE.Sprite ) {
- var RenderList = function () {
+ data.material = parseMaterial( object.material );
- var normals = [];
- var uvs = [];
+ }
- var object = null;
- var material = null;
+ data.matrix = object.matrix.toArray();
- var normalMatrix = new THREE.Matrix3();
+ if ( object.children.length > 0 ) {
- var setObject = function ( value ) {
+ data.children = [];
- object = value;
- material = object.material;
+ for ( var i = 0; i < object.children.length; i ++ ) {
- normalMatrix.getNormalMatrix( object.matrixWorld );
+ data.children.push( parseObject( object.children[ i ] ) );
- normals.length = 0;
- uvs.length = 0;
+ }
- };
+ }
- var projectVertex = function ( vertex ) {
+ return data;
- var position = vertex.position;
- var positionWorld = vertex.positionWorld;
- var positionScreen = vertex.positionScreen;
+ }
- positionWorld.copy( position ).applyMatrix4( _modelMatrix );
- positionScreen.copy( positionWorld ).applyMatrix4( _viewProjectionMatrix );
+ output.object = parseObject( this );
- var invW = 1 / positionScreen.w;
+ return output;
- 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;
+ clone: function ( object, recursive ) {
- };
+ if ( object === undefined ) object = new THREE.Object3D();
+ if ( recursive === undefined ) recursive = true;
- var pushVertex = function ( x, y, z ) {
+ object.name = this.name;
- _vertex = getNextVertexInPool();
- _vertex.position.set( x, y, z );
+ object.up.copy( this.up );
- projectVertex( _vertex );
+ object.position.copy( this.position );
+ object.quaternion.copy( this.quaternion );
+ object.scale.copy( this.scale );
- };
+ object.renderDepth = this.renderDepth;
- var pushNormal = function ( x, y, z ) {
+ object.rotationAutoUpdate = this.rotationAutoUpdate;
- normals.push( x, y, z );
+ object.matrix.copy( this.matrix );
+ object.matrixWorld.copy( this.matrixWorld );
- };
+ object.matrixAutoUpdate = this.matrixAutoUpdate;
+ object.matrixWorldNeedsUpdate = this.matrixWorldNeedsUpdate;
- var pushUv = function ( x, y ) {
+ object.visible = this.visible;
- uvs.push( x, y );
+ object.castShadow = this.castShadow;
+ object.receiveShadow = this.receiveShadow;
- };
+ object.frustumCulled = this.frustumCulled;
- var checkTriangleVisibility = function ( v1, v2, v3 ) {
+ object.userData = JSON.parse( JSON.stringify( this.userData ) );
- if ( v1.visible === true || v2.visible === true || v3.visible === true ) return true;
+ if ( recursive === true ) {
- _points3[ 0 ] = v1.positionScreen;
- _points3[ 1 ] = v2.positionScreen;
- _points3[ 2 ] = v3.positionScreen;
+ for ( var i = 0; i < this.children.length; i ++ ) {
- return _clipBox.isIntersectionBox( _boundingBox.setFromPoints( _points3 ) );
+ var child = this.children[ i ];
+ object.add( child.clone() );
- };
+ }
- 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;
+ return object;
- };
+ }
- var pushLine = function ( a, b ) {
+};
- var v1 = _vertexPool[ a ];
- var v2 = _vertexPool[ b ];
+THREE.EventDispatcher.prototype.apply( THREE.Object3D.prototype );
- _line = getNextLineInPool();
+THREE.Object3DIdCount = 0;
- _line.id = object.id;
- _line.v1.copy( v1 );
- _line.v2.copy( v2 );
- _line.z = ( v1.positionScreen.z + v2.positionScreen.z ) / 2;
+// File:src/core/Projector.js
- _line.material = object.material;
+/**
+ * @author mrdoob / http://mrdoob.com/
+ */
- _renderData.elements.push( _line );
+THREE.Projector = function () {
- };
+ console.warn( 'THREE.Projector has been moved to /examples/renderers/Projector.js.' );
- var pushTriangle = function ( a, b, c ) {
+ this.projectVector = function ( vector, camera ) {
- var v1 = _vertexPool[ a ];
- var v2 = _vertexPool[ b ];
- var v3 = _vertexPool[ c ];
+ console.warn( 'THREE.Projector: .projectVector() is now vector.project().' );
+ vector.project( camera );
- if ( checkTriangleVisibility( v1, v2, v3 ) === false ) return;
+ };
- if ( material.side === THREE.DoubleSide || checkBackfaceCulling( v1, v2, v3 ) === true ) {
+ this.unprojectVector = function ( vector, camera ) {
- _face = getNextFaceInPool();
+ console.warn( 'THREE.Projector: .unprojectVector() is now vector.unproject().' );
+ vector.unproject( camera );
- _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 ++ ) {
+ this.pickingRay = function ( vector, camera ) {
- var offset = arguments[ i ] * 3;
- var normal = _face.vertexNormalsModel[ i ];
+ console.error( 'THREE.Projector: .pickingRay() has been removed.' );
- 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 ] );
+// File:src/core/Face3.js
- }
+/**
+ * @author mrdoob / http://mrdoob.com/
+ * @author alteredq / http://alteredqualia.com/
+ */
- _face.vertexNormalsLength = 3;
+THREE.Face3 = function ( a, b, c, normal, color, materialIndex ) {
- _face.material = object.material;
+ this.a = a;
+ this.b = b;
+ this.c = c;
- _renderData.elements.push( _face );
+ this.normal = normal instanceof THREE.Vector3 ? normal : new THREE.Vector3();
+ this.vertexNormals = normal instanceof Array ? normal : [];
- }
+ this.color = color instanceof THREE.Color ? color : new THREE.Color();
+ this.vertexColors = color instanceof Array ? color : [];
- };
+ this.vertexTangents = [];
- return {
- setObject: setObject,
- projectVertex: projectVertex,
- checkTriangleVisibility: checkTriangleVisibility,
- checkBackfaceCulling: checkBackfaceCulling,
- pushVertex: pushVertex,
- pushNormal: pushNormal,
- pushUv: pushUv,
- pushLine: pushLine,
- pushTriangle: pushTriangle
- }
+ this.materialIndex = materialIndex !== undefined ? materialIndex : 0;
- };
+};
- var renderList = new RenderList();
+THREE.Face3.prototype = {
- this.projectScene = function ( scene, camera, sortObjects, sortElements ) {
+ constructor: THREE.Face3,
- _faceCount = 0;
- _lineCount = 0;
- _spriteCount = 0;
+ clone: function () {
- _renderData.elements.length = 0;
+ var face = new THREE.Face3( this.a, this.b, this.c );
- if ( scene.autoUpdate === true ) scene.updateMatrixWorld();
- if ( camera.parent === undefined ) camera.updateMatrixWorld();
+ face.normal.copy( this.normal );
+ face.color.copy( this.color );
- _viewMatrix.copy( camera.matrixWorldInverse.getInverse( camera.matrixWorld ) );
- _viewProjectionMatrix.multiplyMatrices( camera.projectionMatrix, _viewMatrix );
+ face.materialIndex = this.materialIndex;
- _frustum.setFromMatrix( _viewProjectionMatrix );
+ for ( var i = 0, il = this.vertexNormals.length; i < il; i ++ ) {
- //
+ face.vertexNormals[ i ] = this.vertexNormals[ i ].clone();
- _objectCount = 0;
+ }
- _renderData.objects.length = 0;
- _renderData.lights.length = 0;
+ for ( var i = 0, il = this.vertexColors.length; i < il; i ++ ) {
- scene.traverseVisible( function ( object ) {
+ face.vertexColors[ i ] = this.vertexColors[ i ].clone();
- if ( object instanceof THREE.Light ) {
+ }
- _renderData.lights.push( object );
+ for ( var i = 0, il = this.vertexTangents.length; i < il; i ++ ) {
- } else if ( object instanceof THREE.Mesh || object instanceof THREE.Line || object instanceof THREE.Sprite ) {
+ face.vertexTangents[ i ] = this.vertexTangents[ i ].clone();
- if ( object.frustumCulled === false || _frustum.intersectsObject( object ) === true ) {
+ }
- _object = getNextObjectInPool();
- _object.id = object.id;
- _object.object = object;
+ return face;
- if ( object.renderDepth !== null ) {
+ }
- _object.z = object.renderDepth;
+};
- } else {
+// File:src/core/Face4.js
- _vector3.setFromMatrixPosition( object.matrixWorld );
- _vector3.applyProjection( _viewProjectionMatrix );
- _object.z = _vector3.z;
+/**
+ * @author mrdoob / http://mrdoob.com/
+ */
- }
+THREE.Face4 = function ( a, b, c, d, normal, color, materialIndex ) {
- _renderData.objects.push( _object );
+ console.warn( 'THREE.Face4 has been removed. A THREE.Face3 will be created instead.' )
+ return new THREE.Face3( a, b, c, normal, color, materialIndex );
- }
+};
- }
+// File:src/core/BufferAttribute.js
- } );
+/**
+ * @author mrdoob / http://mrdoob.com/
+ */
- if ( sortObjects === true ) {
+THREE.BufferAttribute = function ( array, itemSize ) {
- _renderData.objects.sort( painterSort );
+ this.array = array;
+ this.itemSize = itemSize;
- }
+ this.needsUpdate = false;
- //
+};
- for ( var o = 0, ol = _renderData.objects.length; o < ol; o ++ ) {
+THREE.BufferAttribute.prototype = {
- var object = _renderData.objects[ o ].object;
- var geometry = object.geometry;
+ constructor: THREE.BufferAttribute,
- renderList.setObject( object );
+ get length () {
- _modelMatrix = object.matrixWorld;
+ return this.array.length;
- _vertexCount = 0;
+ },
- if ( object instanceof THREE.Mesh ) {
+ copyAt: function ( index1, attribute, index2 ) {
- if ( geometry instanceof THREE.BufferGeometry ) {
+ index1 *= this.itemSize;
+ index2 *= attribute.itemSize;
- var attributes = geometry.attributes;
- var offsets = geometry.offsets;
+ for ( var i = 0, l = this.itemSize; i < l; i ++ ) {
- if ( attributes.position === undefined ) continue;
+ this.array[ index1 + i ] = attribute.array[ index2 + i ];
- 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 ] );
+ set: function ( value ) {
- }
+ this.array.set( value );
- if ( attributes.normal !== undefined ) {
+ return this;
- var normals = attributes.normal.array;
+ },
- for ( var i = 0, l = normals.length; i < l; i += 3 ) {
+ setX: function ( index, x ) {
- renderList.pushNormal( normals[ i ], normals[ i + 1 ], normals[ i + 2 ] );
+ this.array[ index * this.itemSize ] = x;
- }
+ return this;
- }
+ },
- if ( attributes.uv !== undefined ) {
+ setY: function ( index, y ) {
- var uvs = attributes.uv.array;
+ this.array[ index * this.itemSize + 1 ] = y;
- for ( var i = 0, l = uvs.length; i < l; i += 2 ) {
+ return this;
- renderList.pushUv( uvs[ i ], uvs[ i + 1 ] );
+ },
- }
+ setZ: function ( index, z ) {
- }
+ this.array[ index * this.itemSize + 2 ] = z;
- if ( attributes.index !== undefined ) {
+ return this;
- var indices = attributes.index.array;
+ },
- if ( offsets.length > 0 ) {
+ setXY: function ( index, x, y ) {
- for ( var o = 0; o < offsets.length; o ++ ) {
+ index *= this.itemSize;
- var offset = offsets[ o ];
- var index = offset.index;
+ this.array[ index ] = x;
+ this.array[ index + 1 ] = y;
- for ( var i = offset.start, l = offset.start + offset.count; i < l; i += 3 ) {
+ return this;
- renderList.pushTriangle( indices[ i ] + index, indices[ i + 1 ] + index, indices[ i + 2 ] + index );
+ },
- }
+ setXYZ: function ( index, x, y, z ) {
- }
+ index *= this.itemSize;
- } else {
+ this.array[ index ] = x;
+ this.array[ index + 1 ] = y;
+ this.array[ index + 2 ] = z;
- for ( var i = 0, l = indices.length; i < l; i += 3 ) {
+ return this;
- renderList.pushTriangle( indices[ i ], indices[ i + 1 ], indices[ i + 2 ] );
+ },
- }
+ setXYZW: function ( index, x, y, z, w ) {
- }
+ index *= this.itemSize;
- } else {
+ this.array[ index ] = x;
+ this.array[ index + 1 ] = y;
+ this.array[ index + 2 ] = z;
+ this.array[ index + 3 ] = w;
- for ( var i = 0, l = positions.length / 3; i < l; i += 3 ) {
+ return this;
- renderList.pushTriangle( i, i + 1, i + 2 );
+ },
- }
+ clone: function () {
- }
+ return new THREE.BufferAttribute( new this.array.constructor( this.array ), this.itemSize );
- } else if ( geometry instanceof THREE.Geometry ) {
+ }
- var vertices = geometry.vertices;
- var faces = geometry.faces;
- var faceVertexUvs = geometry.faceVertexUvs[ 0 ];
+};
- _normalMatrix.getNormalMatrix( _modelMatrix );
+//
- var isFaceMaterial = object.material instanceof THREE.MeshFaceMaterial;
- var objectMaterials = isFaceMaterial === true ? object.material : null;
+THREE.Int8Attribute = function ( data, itemSize ) {
- for ( var v = 0, vl = vertices.length; v < vl; v ++ ) {
+ console.warn( 'THREE.Int8Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' );
+ return new THREE.BufferAttribute( data, itemSize );
- var vertex = vertices[ v ];
- renderList.pushVertex( vertex.x, vertex.y, vertex.z );
+};
- }
+THREE.Uint8Attribute = function ( data, itemSize ) {
- for ( var f = 0, fl = faces.length; f < fl; f ++ ) {
+ console.warn( 'THREE.Uint8Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' );
+ return new THREE.BufferAttribute( data, itemSize );
- var face = faces[ f ];
+};
- var material = isFaceMaterial === true
- ? objectMaterials.materials[ face.materialIndex ]
- : object.material;
+THREE.Uint8ClampedAttribute = function ( data, itemSize ) {
- if ( material === undefined ) continue;
+ console.warn( 'THREE.Uint8ClampedAttribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' );
+ return new THREE.BufferAttribute( data, itemSize );
- var side = material.side;
- var v1 = _vertexPool[ face.a ];
- var v2 = _vertexPool[ face.b ];
- var v3 = _vertexPool[ face.c ];
+};
- if ( material.morphTargets === true ) {
+THREE.Int16Attribute = function ( data, itemSize ) {
- var morphTargets = geometry.morphTargets;
- var morphInfluences = object.morphTargetInfluences;
+ console.warn( 'THREE.Int16Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' );
+ return new THREE.BufferAttribute( data, itemSize );
- var v1p = v1.position;
- var v2p = v2.position;
- var v3p = v3.position;
+};
- _vA.set( 0, 0, 0 );
- _vB.set( 0, 0, 0 );
- _vC.set( 0, 0, 0 );
+THREE.Uint16Attribute = function ( data, itemSize ) {
- for ( var t = 0, tl = morphTargets.length; t < tl; t ++ ) {
+ console.warn( 'THREE.Uint16Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' );
+ return new THREE.BufferAttribute( data, itemSize );
- var influence = morphInfluences[ t ];
+};
- if ( influence === 0 ) continue;
+THREE.Int32Attribute = function ( data, itemSize ) {
- var targets = morphTargets[ t ].vertices;
+ console.warn( 'THREE.Int32Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' );
+ return new THREE.BufferAttribute( data, itemSize );
- _vA.x += ( targets[ face.a ].x - v1p.x ) * influence;
- _vA.y += ( targets[ face.a ].y - v1p.y ) * influence;
- _vA.z += ( targets[ face.a ].z - v1p.z ) * influence;
+};
- _vB.x += ( targets[ face.b ].x - v2p.x ) * influence;
- _vB.y += ( targets[ face.b ].y - v2p.y ) * influence;
- _vB.z += ( targets[ face.b ].z - v2p.z ) * influence;
+THREE.Uint32Attribute = function ( data, itemSize ) {
- _vC.x += ( targets[ face.c ].x - v3p.x ) * influence;
- _vC.y += ( targets[ face.c ].y - v3p.y ) * influence;
- _vC.z += ( targets[ face.c ].z - v3p.z ) * influence;
+ console.warn( 'THREE.Uint32Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' );
+ return new THREE.BufferAttribute( data, itemSize );
- }
+};
- v1.position.add( _vA );
- v2.position.add( _vB );
- v3.position.add( _vC );
+THREE.Float32Attribute = function ( data, itemSize ) {
- renderList.projectVertex( v1 );
- renderList.projectVertex( v2 );
- renderList.projectVertex( v3 );
+ console.warn( 'THREE.Float32Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' );
+ return new THREE.BufferAttribute( data, itemSize );
- }
+};
- if ( renderList.checkTriangleVisibility( v1, v2, v3 ) === false ) continue;
+THREE.Float64Attribute = function ( data, itemSize ) {
- var visible = renderList.checkBackfaceCulling( v1, v2, v3 );
+ console.warn( 'THREE.Float64Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' );
+ return new THREE.BufferAttribute( data, itemSize );
- if ( side !== THREE.DoubleSide ) {
- if ( side === THREE.FrontSide && visible === false ) continue;
- if ( side === THREE.BackSide && visible === true ) continue;
- }
+};
- _face = getNextFaceInPool();
+// File:src/core/BufferGeometry.js
- _face.id = object.id;
- _face.v1.copy( v1 );
- _face.v2.copy( v2 );
- _face.v3.copy( v3 );
+/**
+ * @author alteredq / http://alteredqualia.com/
+ * @author mrdoob / http://mrdoob.com/
+ */
- _face.normalModel.copy( face.normal );
+THREE.BufferGeometry = function () {
- if ( visible === false && ( side === THREE.BackSide || side === THREE.DoubleSide ) ) {
+ Object.defineProperty( this, 'id', { value: THREE.GeometryIdCount ++ } );
- _face.normalModel.negate();
+ this.uuid = THREE.Math.generateUUID();
- }
+ this.name = '';
+ this.type = 'BufferGeometry';
- _face.normalModel.applyMatrix3( _normalMatrix ).normalize();
+ this.attributes = {};
+ this.attributesKeys = [];
- var faceVertexNormals = face.vertexNormals;
+ this.drawcalls = [];
+ this.offsets = this.drawcalls; // backwards compatibility
- for ( var n = 0, nl = Math.min( faceVertexNormals.length, 3 ); n < nl; n ++ ) {
+ this.boundingBox = null;
+ this.boundingSphere = null;
- var normalModel = _face.vertexNormalsModel[ n ];
- normalModel.copy( faceVertexNormals[ n ] );
+};
- if ( visible === false && ( side === THREE.BackSide || side === THREE.DoubleSide ) ) {
+THREE.BufferGeometry.prototype = {
- normalModel.negate();
+ constructor: THREE.BufferGeometry,
- }
+ addAttribute: function ( name, attribute ) {
- normalModel.applyMatrix3( _normalMatrix ).normalize();
+ if ( attribute instanceof THREE.BufferAttribute === false ) {
- }
+ console.warn( 'THREE.BufferGeometry: .addAttribute() now expects ( name, attribute ).' );
- _face.vertexNormalsLength = faceVertexNormals.length;
+ this.attributes[ name ] = { array: arguments[ 1 ], itemSize: arguments[ 2 ] };
- var vertexUvs = faceVertexUvs[ f ];
+ return;
- if ( vertexUvs !== undefined ) {
+ }
- for ( var u = 0; u < 3; u ++ ) {
+ this.attributes[ name ] = attribute;
+ this.attributesKeys = Object.keys( this.attributes );
- _face.uvs[ u ].copy( vertexUvs[ u ] );
+ },
- }
+ getAttribute: function ( name ) {
- }
+ return this.attributes[ name ];
- _face.color = face.color;
- _face.material = material;
+ },
- _face.z = ( v1.positionScreen.z + v2.positionScreen.z + v3.positionScreen.z ) / 3;
+ addDrawCall: function ( start, count, indexOffset ) {
- _renderData.elements.push( _face );
+ this.drawcalls.push( {
- }
+ start: start,
+ count: count,
+ index: indexOffset !== undefined ? indexOffset : 0
- }
+ } );
- } else if ( object instanceof THREE.Line ) {
+ },
- if ( geometry instanceof THREE.BufferGeometry ) {
+ applyMatrix: function ( matrix ) {
- var attributes = geometry.attributes;
+ var position = this.attributes.position;
- if ( attributes.position !== undefined ) {
+ if ( position !== undefined ) {
- var positions = attributes.position.array;
+ matrix.applyToVector3Array( position.array );
+ position.needsUpdate = true;
- for ( var i = 0, l = positions.length; i < l; i += 3 ) {
+ }
- renderList.pushVertex( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] );
+ var normal = this.attributes.normal;
- }
+ if ( normal !== undefined ) {
- if ( attributes.index !== undefined ) {
+ var normalMatrix = new THREE.Matrix3().getNormalMatrix( matrix );
- var indices = attributes.index.array;
+ normalMatrix.applyToVector3Array( normal.array );
+ normal.needsUpdate = true;
- for ( var i = 0, l = indices.length; i < l; i += 2 ) {
+ }
- renderList.pushLine( indices[ i ], indices[ i + 1 ] );
+ },
- }
+ center: function () {
- } else {
+ // TODO
- var step = object.type === THREE.LinePieces ? 2 : 1;
+ },
- for ( var i = 0, l = ( positions.length / 3 ) - 1; i < l; i += step ) {
+ fromGeometry: function ( geometry, settings ) {
- renderList.pushLine( i, i + 1 );
+ settings = settings || { 'vertexColors': THREE.NoColors };
- }
+ var vertices = geometry.vertices;
+ var faces = geometry.faces;
+ var faceVertexUvs = geometry.faceVertexUvs;
+ var vertexColors = settings.vertexColors;
+ var hasFaceVertexUv = faceVertexUvs[ 0 ].length > 0;
+ var hasFaceVertexNormals = faces[ 0 ].vertexNormals.length == 3;
- }
+ var positions = new Float32Array( faces.length * 3 * 3 );
+ this.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );
- }
+ var normals = new Float32Array( faces.length * 3 * 3 );
+ this.addAttribute( 'normal', new THREE.BufferAttribute( normals, 3 ) );
- } else if ( geometry instanceof THREE.Geometry ) {
+ if ( vertexColors !== THREE.NoColors ) {
- _modelViewProjectionMatrix.multiplyMatrices( _viewProjectionMatrix, _modelMatrix );
+ var colors = new Float32Array( faces.length * 3 * 3 );
+ this.addAttribute( 'color', new THREE.BufferAttribute( colors, 3 ) );
- var vertices = object.geometry.vertices;
+ }
- if ( vertices.length === 0 ) continue;
+ if ( hasFaceVertexUv === true ) {
- v1 = getNextVertexInPool();
- v1.positionScreen.copy( vertices[ 0 ] ).applyMatrix4( _modelViewProjectionMatrix );
+ var uvs = new Float32Array( faces.length * 3 * 2 );
+ this.addAttribute( 'uv', new THREE.BufferAttribute( uvs, 2 ) );
- // Handle LineStrip and LinePieces
- var step = object.type === THREE.LinePieces ? 2 : 1;
+ }
- for ( var v = 1, vl = vertices.length; v < vl; v ++ ) {
+ for ( var i = 0, i2 = 0, i3 = 0; i < faces.length; i ++, i2 += 6, i3 += 9 ) {
- v1 = getNextVertexInPool();
- v1.positionScreen.copy( vertices[ v ] ).applyMatrix4( _modelViewProjectionMatrix );
+ var face = faces[ i ];
- if ( ( v + 1 ) % step > 0 ) continue;
+ var a = vertices[ face.a ];
+ var b = vertices[ face.b ];
+ var c = vertices[ face.c ];
- v2 = _vertexPool[ _vertexCount - 2 ];
+ positions[ i3 ] = a.x;
+ positions[ i3 + 1 ] = a.y;
+ positions[ i3 + 2 ] = a.z;
- _clippedVertex1PositionScreen.copy( v1.positionScreen );
- _clippedVertex2PositionScreen.copy( v2.positionScreen );
+ positions[ i3 + 3 ] = b.x;
+ positions[ i3 + 4 ] = b.y;
+ positions[ i3 + 5 ] = b.z;
- if ( clipLine( _clippedVertex1PositionScreen, _clippedVertex2PositionScreen ) === true ) {
+ positions[ i3 + 6 ] = c.x;
+ positions[ i3 + 7 ] = c.y;
+ positions[ i3 + 8 ] = c.z;
- // Perform the perspective divide
- _clippedVertex1PositionScreen.multiplyScalar( 1 / _clippedVertex1PositionScreen.w );
- _clippedVertex2PositionScreen.multiplyScalar( 1 / _clippedVertex2PositionScreen.w );
+ if ( hasFaceVertexNormals === true ) {
- _line = getNextLineInPool();
+ var na = face.vertexNormals[ 0 ];
+ var nb = face.vertexNormals[ 1 ];
+ var nc = face.vertexNormals[ 2 ];
- _line.id = object.id;
- _line.v1.positionScreen.copy( _clippedVertex1PositionScreen );
- _line.v2.positionScreen.copy( _clippedVertex2PositionScreen );
+ normals[ i3 ] = na.x;
+ normals[ i3 + 1 ] = na.y;
+ normals[ i3 + 2 ] = na.z;
- _line.z = Math.max( _clippedVertex1PositionScreen.z, _clippedVertex2PositionScreen.z );
+ normals[ i3 + 3 ] = nb.x;
+ normals[ i3 + 4 ] = nb.y;
+ normals[ i3 + 5 ] = nb.z;
- _line.material = object.material;
+ normals[ i3 + 6 ] = nc.x;
+ normals[ i3 + 7 ] = nc.y;
+ normals[ i3 + 8 ] = nc.z;
- if ( object.material.vertexColors === THREE.VertexColors ) {
+ } else {
- _line.vertexColors[ 0 ].copy( object.geometry.colors[ v ] );
- _line.vertexColors[ 1 ].copy( object.geometry.colors[ v - 1 ] );
+ var n = face.normal;
- }
+ normals[ i3 ] = n.x;
+ normals[ i3 + 1 ] = n.y;
+ normals[ i3 + 2 ] = n.z;
- _renderData.elements.push( _line );
+ normals[ i3 + 3 ] = n.x;
+ normals[ i3 + 4 ] = n.y;
+ normals[ i3 + 5 ] = n.z;
- }
+ normals[ i3 + 6 ] = n.x;
+ normals[ i3 + 7 ] = n.y;
+ normals[ i3 + 8 ] = n.z;
- }
+ }
- }
+ if ( vertexColors === THREE.FaceColors ) {
- } else if ( object instanceof THREE.Sprite ) {
+ var fc = face.color;
- _vector4.set( _modelMatrix.elements[ 12 ], _modelMatrix.elements[ 13 ], _modelMatrix.elements[ 14 ], 1 );
- _vector4.applyMatrix4( _viewProjectionMatrix );
+ colors[ i3 ] = fc.r;
+ colors[ i3 + 1 ] = fc.g;
+ colors[ i3 + 2 ] = fc.b;
- var invW = 1 / _vector4.w;
+ colors[ i3 + 3 ] = fc.r;
+ colors[ i3 + 4 ] = fc.g;
+ colors[ i3 + 5 ] = fc.b;
- _vector4.z *= invW;
+ colors[ i3 + 6 ] = fc.r;
+ colors[ i3 + 7 ] = fc.g;
+ colors[ i3 + 8 ] = fc.b;
- if ( _vector4.z >= - 1 && _vector4.z <= 1 ) {
+ } else if ( vertexColors === THREE.VertexColors ) {
- _sprite = getNextSpriteInPool();
- _sprite.id = object.id;
- _sprite.x = _vector4.x * invW;
- _sprite.y = _vector4.y * invW;
- _sprite.z = _vector4.z;
- _sprite.object = object;
+ var vca = face.vertexColors[ 0 ];
+ var vcb = face.vertexColors[ 1 ];
+ var vcc = face.vertexColors[ 2 ];
- _sprite.rotation = object.rotation;
+ colors[ i3 ] = vca.r;
+ colors[ i3 + 1 ] = vca.g;
+ colors[ i3 + 2 ] = vca.b;
- _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 ] ) );
+ colors[ i3 + 3 ] = vcb.r;
+ colors[ i3 + 4 ] = vcb.g;
+ colors[ i3 + 5 ] = vcb.b;
- _sprite.material = object.material;
+ colors[ i3 + 6 ] = vcc.r;
+ colors[ i3 + 7 ] = vcc.g;
+ colors[ i3 + 8 ] = vcc.b;
- _renderData.elements.push( _sprite );
+ }
- }
+ if ( hasFaceVertexUv === true ) {
- }
+ var uva = faceVertexUvs[ 0 ][ i ][ 0 ];
+ var uvb = faceVertexUvs[ 0 ][ i ][ 1 ];
+ var uvc = faceVertexUvs[ 0 ][ i ][ 2 ];
- }
+ uvs[ i2 ] = uva.x;
+ uvs[ i2 + 1 ] = uva.y;
- if ( sortElements === true ) _renderData.elements.sort( painterSort );
+ uvs[ i2 + 2 ] = uvb.x;
+ uvs[ i2 + 3 ] = uvb.y;
- return _renderData;
+ uvs[ i2 + 4 ] = uvc.x;
+ uvs[ i2 + 5 ] = uvc.y;
- };
+ }
- // Pools
+ }
- function getNextObjectInPool() {
+ this.computeBoundingSphere()
- if ( _objectCount === _objectPoolLength ) {
+ return this;
- var object = new THREE.RenderableObject();
- _objectPool.push( object );
- _objectPoolLength ++;
- _objectCount ++;
- return object;
+ },
- }
+ computeBoundingBox: function () {
- return _objectPool[ _objectCount ++ ];
+ var vector = new THREE.Vector3();
- }
+ return function () {
- function getNextVertexInPool() {
+ if ( this.boundingBox === null ) {
- if ( _vertexCount === _vertexPoolLength ) {
+ this.boundingBox = new THREE.Box3();
- var vertex = new THREE.RenderableVertex();
- _vertexPool.push( vertex );
- _vertexPoolLength ++;
- _vertexCount ++;
- return vertex;
+ }
- }
+ var positions = this.attributes.position.array;
- return _vertexPool[ _vertexCount ++ ];
+ if ( positions ) {
- }
+ var bb = this.boundingBox;
+ bb.makeEmpty();
- function getNextFaceInPool() {
+ for ( var i = 0, il = positions.length; i < il; i += 3 ) {
- if ( _faceCount === _facePoolLength ) {
+ vector.set( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] );
+ bb.expandByPoint( vector );
- var face = new THREE.RenderableFace();
- _facePool.push( face );
- _facePoolLength ++;
- _faceCount ++;
- return face;
+ }
- }
+ }
- return _facePool[ _faceCount ++ ];
+ if ( positions === undefined || positions.length === 0 ) {
+ this.boundingBox.min.set( 0, 0, 0 );
+ this.boundingBox.max.set( 0, 0, 0 );
- }
+ }
- function getNextLineInPool() {
+ if ( isNaN( this.boundingBox.min.x ) || isNaN( this.boundingBox.min.y ) || isNaN( this.boundingBox.min.z ) ) {
- if ( _lineCount === _linePoolLength ) {
+ console.error( 'THREE.BufferGeometry.computeBoundingBox: Computed min/max have NaN values. The "position" attribute is likely to have NaN values.' );
- var line = new THREE.RenderableLine();
- _linePool.push( line );
- _linePoolLength ++;
- _lineCount ++
- return line;
+ }
}
- return _linePool[ _lineCount ++ ];
+ }(),
- }
+ computeBoundingSphere: function () {
- function getNextSpriteInPool() {
+ var box = new THREE.Box3();
+ var vector = new THREE.Vector3();
- if ( _spriteCount === _spritePoolLength ) {
+ return function () {
- var sprite = new THREE.RenderableSprite();
- _spritePool.push( sprite );
- _spritePoolLength ++;
- _spriteCount ++
- return sprite;
+ if ( this.boundingSphere === null ) {
- }
+ this.boundingSphere = new THREE.Sphere();
- return _spritePool[ _spriteCount ++ ];
+ }
- }
+ var positions = this.attributes.position.array;
- //
+ if ( positions ) {
- function painterSort( a, b ) {
+ box.makeEmpty();
- if ( a.z !== b.z ) {
+ var center = this.boundingSphere.center;
- return b.z - a.z;
+ for ( var i = 0, il = positions.length; i < il; i += 3 ) {
- } else if ( a.id !== b.id ) {
+ vector.set( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] );
+ box.expandByPoint( vector );
- return a.id - b.id;
+ }
- } else {
+ box.center( center );
- return 0;
+ // hoping to find a boundingSphere with a radius smaller than the
+ // boundingSphere of the boundingBox: sqrt(3) smaller in the best case
- }
+ var maxRadiusSq = 0;
- }
+ for ( var i = 0, il = positions.length; i < il; i += 3 ) {
- function clipLine( s1, s2 ) {
+ vector.set( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] );
+ maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( vector ) );
- 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;
+ this.boundingSphere.radius = Math.sqrt( maxRadiusSq );
- if ( bc1near >= 0 && bc2near >= 0 && bc1far >= 0 && bc2far >= 0 ) {
+ if ( isNaN( this.boundingSphere.radius ) ) {
- // Both vertices lie entirely within all clip planes.
- return true;
+ console.error( 'THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.' );
- } 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 ) {
+ computeFaceNormals: function () {
- // v1 lies outside the near plane, v2 inside
- alpha1 = Math.max( alpha1, bc1near / ( bc1near - bc2near ) );
+ // backwards compatibility
- } else if ( bc2near < 0 ) {
+ },
- // v2 lies outside the near plane, v1 inside
- alpha2 = Math.min( alpha2, bc1near / ( bc1near - bc2near ) );
+ computeVertexNormals: function () {
- }
+ var attributes = this.attributes;
- if ( bc1far < 0 ) {
+ if ( attributes.position ) {
- // v1 lies outside the far plane, v2 inside
- alpha1 = Math.max( alpha1, bc1far / ( bc1far - bc2far ) );
+ var positions = attributes.position.array;
- } else if ( bc2far < 0 ) {
+ if ( attributes.normal === undefined ) {
- // v2 lies outside the far plane, v2 inside
- alpha2 = Math.min( alpha2, bc1far / ( bc1far - bc2far ) );
+ this.addAttribute( 'normal', new THREE.BufferAttribute( new Float32Array( positions.length ), 3 ) );
- }
+ } else {
- if ( alpha2 < alpha1 ) {
+ // reset existing normals to zero
- // 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;
+ var normals = attributes.normal.array;
- } else {
+ for ( var i = 0, il = normals.length; i < il; i ++ ) {
- // Update the s1 and s2 vertices to match the clipped line segment.
- s1.lerp( s2, alpha1 );
- s2.lerp( s1, 1 - alpha2 );
+ normals[ i ] = 0;
- return true;
+ }
}
- }
+ var normals = attributes.normal.array;
- }
+ var vA, vB, vC,
-};
+ pA = new THREE.Vector3(),
+ pB = new THREE.Vector3(),
+ pC = new THREE.Vector3(),
-// File:src/core/Face3.js
-
-/**
- * @author mrdoob / http://mrdoob.com/
- * @author alteredq / http://alteredqualia.com/
- */
+ cb = new THREE.Vector3(),
+ ab = new THREE.Vector3();
-THREE.Face3 = function ( a, b, c, normal, color, materialIndex ) {
+ // indexed elements
- this.a = a;
- this.b = b;
- this.c = c;
+ if ( attributes.index ) {
- this.normal = normal instanceof THREE.Vector3 ? normal : new THREE.Vector3();
- this.vertexNormals = normal instanceof Array ? normal : [];
+ var indices = attributes.index.array;
- this.color = color instanceof THREE.Color ? color : new THREE.Color();
- this.vertexColors = color instanceof Array ? color : [];
+ var offsets = ( this.offsets.length > 0 ? this.offsets : [ { start: 0, count: indices.length, index: 0 } ] );
- this.vertexTangents = [];
+ for ( var j = 0, jl = offsets.length; j < jl; ++ j ) {
- this.materialIndex = materialIndex !== undefined ? materialIndex : 0;
+ var start = offsets[ j ].start;
+ var count = offsets[ j ].count;
+ var index = offsets[ j ].index;
-};
+ for ( var i = start, il = start + count; i < il; i += 3 ) {
-THREE.Face3.prototype = {
+ vA = ( index + indices[ i ] ) * 3;
+ vB = ( index + indices[ i + 1 ] ) * 3;
+ vC = ( index + indices[ i + 2 ] ) * 3;
- constructor: THREE.Face3,
+ pA.fromArray( positions, vA );
+ pB.fromArray( positions, vB );
+ pC.fromArray( positions, vC );
- clone: function () {
+ cb.subVectors( pC, pB );
+ ab.subVectors( pA, pB );
+ cb.cross( ab );
- var face = new THREE.Face3( this.a, this.b, this.c );
+ normals[ vA ] += cb.x;
+ normals[ vA + 1 ] += cb.y;
+ normals[ vA + 2 ] += cb.z;
- face.normal.copy( this.normal );
- face.color.copy( this.color );
+ normals[ vB ] += cb.x;
+ normals[ vB + 1 ] += cb.y;
+ normals[ vB + 2 ] += cb.z;
- face.materialIndex = this.materialIndex;
+ normals[ vC ] += cb.x;
+ normals[ vC + 1 ] += cb.y;
+ normals[ vC + 2 ] += cb.z;
- for ( var i = 0, il = this.vertexNormals.length; i < il; i ++ ) {
+ }
- face.vertexNormals[ i ] = this.vertexNormals[ i ].clone();
+ }
- }
+ } else {
- for ( var i = 0, il = this.vertexColors.length; i < il; i ++ ) {
+ // non-indexed elements (unconnected triangle soup)
- face.vertexColors[ i ] = this.vertexColors[ i ].clone();
+ for ( var i = 0, il = positions.length; i < il; i += 9 ) {
- }
+ pA.fromArray( positions, i );
+ pB.fromArray( positions, i + 3 );
+ pC.fromArray( positions, i + 6 );
- for ( var i = 0, il = this.vertexTangents.length; i < il; i ++ ) {
+ cb.subVectors( pC, pB );
+ ab.subVectors( pA, pB );
+ cb.cross( ab );
- face.vertexTangents[ i ] = this.vertexTangents[ i ].clone();
+ normals[ i ] = cb.x;
+ normals[ i + 1 ] = cb.y;
+ normals[ i + 2 ] = cb.z;
- }
+ normals[ i + 3 ] = cb.x;
+ normals[ i + 4 ] = cb.y;
+ normals[ i + 5 ] = cb.z;
- return face;
+ normals[ i + 6 ] = cb.x;
+ normals[ i + 7 ] = cb.y;
+ normals[ i + 8 ] = cb.z;
- }
+ }
-};
+ }
-// File:src/core/Face4.js
+ this.normalizeNormals();
-/**
- * @author mrdoob / http://mrdoob.com/
- */
+ attributes.normal.needsUpdate = true;
-THREE.Face4 = function ( a, b, c, d, normal, color, materialIndex ) {
+ }
- console.warn( 'THREE.Face4 has been removed. A THREE.Face3 will be created instead.' )
- return new THREE.Face3( a, b, c, normal, color, materialIndex );
+ },
-};
+ computeTangents: function () {
-// File:src/core/BufferAttribute.js
+ // based on http://www.terathon.com/code/tangent.html
+ // (per vertex tangents)
-/**
- * @author mrdoob / http://mrdoob.com/
- */
+ if ( this.attributes.index === undefined ||
+ this.attributes.position === undefined ||
+ this.attributes.normal === undefined ||
+ this.attributes.uv === undefined ) {
-THREE.BufferAttribute = function ( array, itemSize ) {
+ console.warn( 'Missing required attributes (index, position, normal or uv) in BufferGeometry.computeTangents()' );
+ return;
- this.array = array;
- this.itemSize = itemSize;
+ }
-};
+ var indices = this.attributes.index.array;
+ var positions = this.attributes.position.array;
+ var normals = this.attributes.normal.array;
+ var uvs = this.attributes.uv.array;
-THREE.BufferAttribute.prototype = {
+ var nVertices = positions.length / 3;
- constructor: THREE.BufferAttribute,
+ if ( this.attributes.tangent === undefined ) {
- get length () {
+ this.addAttribute( 'tangent', new THREE.BufferAttribute( new Float32Array( 4 * nVertices ), 4 ) );
- return this.array.length;
+ }
- },
+ var tangents = this.attributes.tangent.array;
- set: function ( value ) {
+ var tan1 = [], tan2 = [];
- this.array.set( value );
+ for ( var k = 0; k < nVertices; k ++ ) {
- return this;
+ tan1[ k ] = new THREE.Vector3();
+ tan2[ k ] = new THREE.Vector3();
- },
+ }
- setX: function ( index, x ) {
+ var vA = new THREE.Vector3(),
+ vB = new THREE.Vector3(),
+ vC = new THREE.Vector3(),
- this.array[ index * this.itemSize ] = x;
+ uvA = new THREE.Vector2(),
+ uvB = new THREE.Vector2(),
+ uvC = new THREE.Vector2(),
- return this;
+ x1, x2, y1, y2, z1, z2,
+ s1, s2, t1, t2, r;
- },
+ var sdir = new THREE.Vector3(), tdir = new THREE.Vector3();
- setY: function ( index, y ) {
+ function handleTriangle( a, b, c ) {
- this.array[ index * this.itemSize + 1 ] = y;
+ vA.fromArray( positions, a * 3 );
+ vB.fromArray( positions, b * 3 );
+ vC.fromArray( positions, c * 3 );
- return this;
+ uvA.fromArray( uvs, a * 2 );
+ uvB.fromArray( uvs, b * 2 );
+ uvC.fromArray( uvs, c * 2 );
- },
+ x1 = vB.x - vA.x;
+ x2 = vC.x - vA.x;
- setZ: function ( index, z ) {
+ y1 = vB.y - vA.y;
+ y2 = vC.y - vA.y;
- this.array[ index * this.itemSize + 2 ] = z;
+ z1 = vB.z - vA.z;
+ z2 = vC.z - vA.z;
- return this;
+ s1 = uvB.x - uvA.x;
+ s2 = uvC.x - uvA.x;
- },
+ t1 = uvB.y - uvA.y;
+ t2 = uvC.y - uvA.y;
- setXY: function ( index, x, y ) {
+ r = 1.0 / ( s1 * t2 - s2 * t1 );
- index *= this.itemSize;
+ sdir.set(
+ ( t2 * x1 - t1 * x2 ) * r,
+ ( t2 * y1 - t1 * y2 ) * r,
+ ( t2 * z1 - t1 * z2 ) * r
+ );
- this.array[ index ] = x;
- this.array[ index + 1 ] = y;
+ tdir.set(
+ ( s1 * x2 - s2 * x1 ) * r,
+ ( s1 * y2 - s2 * y1 ) * r,
+ ( s1 * z2 - s2 * z1 ) * r
+ );
- return this;
+ tan1[ a ].add( sdir );
+ tan1[ b ].add( sdir );
+ tan1[ c ].add( sdir );
- },
+ tan2[ a ].add( tdir );
+ tan2[ b ].add( tdir );
+ tan2[ c ].add( tdir );
- setXYZ: function ( index, x, y, z ) {
+ }
- index *= this.itemSize;
+ var i, il;
+ var j, jl;
+ var iA, iB, iC;
- this.array[ index ] = x;
- this.array[ index + 1 ] = y;
- this.array[ index + 2 ] = z;
+ if ( this.drawcalls.length === 0 ) {
- return this;
+ this.addDrawCall( 0, indices.length, 0 );
- },
+ }
- setXYZW: function ( index, x, y, z, w ) {
+ var drawcalls = this.drawcalls;
- index *= this.itemSize;
+ for ( j = 0, jl = drawcalls.length; j < jl; ++ j ) {
- this.array[ index ] = x;
- this.array[ index + 1 ] = y;
- this.array[ index + 2 ] = z;
- this.array[ index + 3 ] = w;
+ var start = drawcalls[ j ].start;
+ var count = drawcalls[ j ].count;
+ var index = drawcalls[ j ].index;
- return this;
+ for ( i = start, il = start + count; i < il; i += 3 ) {
- }
+ iA = index + indices[ i ];
+ iB = index + indices[ i + 1 ];
+ iC = index + indices[ i + 2 ];
-};
+ handleTriangle( iA, iB, iC );
-//
+ }
-THREE.Int8Attribute = function ( data, itemSize ) {
+ }
- console.warn( 'THREE.Int8Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' );
- return new THREE.BufferAttribute( data, itemSize );
+ var tmp = new THREE.Vector3(), tmp2 = new THREE.Vector3();
+ var n = new THREE.Vector3(), n2 = new THREE.Vector3();
+ var w, t, test;
-};
+ function handleVertex( v ) {
-THREE.Uint8Attribute = function ( data, itemSize ) {
+ n.fromArray( normals, v * 3 );
+ n2.copy( n );
- console.warn( 'THREE.Uint8Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' );
- return new THREE.BufferAttribute( data, itemSize );
+ t = tan1[ v ];
-};
+ // Gram-Schmidt orthogonalize
-THREE.Uint8ClampedAttribute = function ( data, itemSize ) {
+ tmp.copy( t );
+ tmp.sub( n.multiplyScalar( n.dot( t ) ) ).normalize();
- console.warn( 'THREE.Uint8ClampedAttribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' );
- return new THREE.BufferAttribute( data, itemSize );
+ // Calculate handedness
+ tmp2.crossVectors( n2, t );
+ test = tmp2.dot( tan2[ v ] );
+ w = ( test < 0.0 ) ? - 1.0 : 1.0;
-};
+ tangents[ v * 4 ] = tmp.x;
+ tangents[ v * 4 + 1 ] = tmp.y;
+ tangents[ v * 4 + 2 ] = tmp.z;
+ tangents[ v * 4 + 3 ] = w;
-THREE.Int16Attribute = function ( data, itemSize ) {
+ }
- console.warn( 'THREE.Int16Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' );
- return new THREE.BufferAttribute( data, itemSize );
+ for ( j = 0, jl = drawcalls.length; j < jl; ++ j ) {
-};
+ var start = drawcalls[ j ].start;
+ var count = drawcalls[ j ].count;
+ var index = drawcalls[ j ].index;
-THREE.Uint16Attribute = function ( data, itemSize ) {
+ for ( i = start, il = start + count; i < il; i += 3 ) {
- console.warn( 'THREE.Uint16Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' );
- return new THREE.BufferAttribute( data, itemSize );
+ iA = index + indices[ i ];
+ iB = index + indices[ i + 1 ];
+ iC = index + indices[ i + 2 ];
-};
+ handleVertex( iA );
+ handleVertex( iB );
+ handleVertex( iC );
-THREE.Int32Attribute = function ( data, itemSize ) {
+ }
- console.warn( 'THREE.Int32Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' );
- return new THREE.BufferAttribute( data, itemSize );
+ }
-};
+ },
-THREE.Uint32Attribute = function ( data, itemSize ) {
+ /*
+ computeOffsets
+ Compute the draw offset for large models by chunking the index buffer into chunks of 65k addressable vertices.
+ This method will effectively rewrite the index buffer and remap all attributes to match the new indices.
+ WARNING: This method will also expand the vertex count to prevent sprawled triangles across draw offsets.
+ indexBufferSize - Defaults to 65535, but allows for larger or smaller chunks.
+ */
+ computeOffsets: function ( indexBufferSize ) {
- console.warn( 'THREE.Uint32Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' );
- return new THREE.BufferAttribute( data, itemSize );
+ var size = indexBufferSize;
+ if ( indexBufferSize === undefined )
+ size = 65535; //WebGL limits type of index buffer values to 16-bit.
-};
+ var s = Date.now();
-THREE.Float32Attribute = function ( data, itemSize ) {
+ var indices = this.attributes.index.array;
+ var vertices = this.attributes.position.array;
- console.warn( 'THREE.Float32Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' );
- return new THREE.BufferAttribute( data, itemSize );
+ var verticesCount = ( vertices.length / 3 );
+ var facesCount = ( indices.length / 3 );
-};
+ /*
+ console.log("Computing buffers in offsets of "+size+" -> indices:"+indices.length+" vertices:"+vertices.length);
+ console.log("Faces to process: "+(indices.length/3));
+ console.log("Reordering "+verticesCount+" vertices.");
+ */
-THREE.Float64Attribute = function ( data, itemSize ) {
+ var sortedIndices = new Uint16Array( indices.length ); //16-bit buffers
+ var indexPtr = 0;
+ var vertexPtr = 0;
- console.warn( 'THREE.Float64Attribute has been removed. Use THREE.BufferAttribute( array, itemSize ) instead.' );
- return new THREE.BufferAttribute( data, itemSize );
+ var offsets = [ { start:0, count:0, index:0 } ];
+ var offset = offsets[ 0 ];
-};
+ var duplicatedVertices = 0;
+ var newVerticeMaps = 0;
+ var faceVertices = new Int32Array( 6 );
+ var vertexMap = new Int32Array( vertices.length );
+ var revVertexMap = new Int32Array( vertices.length );
+ for ( var j = 0; j < vertices.length; j ++ ) { vertexMap[ j ] = - 1; revVertexMap[ j ] = - 1; }
-// File:src/core/BufferGeometry.js
+ /*
+ Traverse every face and reorder vertices in the proper offsets of 65k.
+ We can have more than 65k entries in the index buffer per offset, but only reference 65k values.
+ */
+ for ( var findex = 0; findex < facesCount; findex ++ ) {
+ newVerticeMaps = 0;
-/**
- * @author alteredq / http://alteredqualia.com/
- */
+ for ( var vo = 0; vo < 3; vo ++ ) {
+ var vid = indices[ findex * 3 + vo ];
+ if ( vertexMap[ vid ] == - 1 ) {
+ //Unmapped vertice
+ faceVertices[ vo * 2 ] = vid;
+ faceVertices[ vo * 2 + 1 ] = - 1;
+ newVerticeMaps ++;
+ } else if ( vertexMap[ vid ] < offset.index ) {
+ //Reused vertices from previous block (duplicate)
+ faceVertices[ vo * 2 ] = vid;
+ faceVertices[ vo * 2 + 1 ] = - 1;
+ duplicatedVertices ++;
+ } else {
+ //Reused vertice in the current block
+ faceVertices[ vo * 2 ] = vid;
+ faceVertices[ vo * 2 + 1 ] = vertexMap[ vid ];
+ }
+ }
-THREE.BufferGeometry = function () {
+ var faceMax = vertexPtr + newVerticeMaps;
+ if ( faceMax > ( offset.index + size ) ) {
+ var new_offset = { start:indexPtr, count:0, index:vertexPtr };
+ offsets.push( new_offset );
+ offset = new_offset;
- this.id = THREE.GeometryIdCount ++;
- this.uuid = THREE.Math.generateUUID();
+ //Re-evaluate reused vertices in light of new offset.
+ for ( var v = 0; v < 6; v += 2 ) {
+ var new_vid = faceVertices[ v + 1 ];
+ if ( new_vid > - 1 && new_vid < offset.index )
+ faceVertices[ v + 1 ] = - 1;
+ }
+ }
- this.name = '';
+ //Reindex the face.
+ for ( var v = 0; v < 6; v += 2 ) {
+ var vid = faceVertices[ v ];
+ var new_vid = faceVertices[ v + 1 ];
- this.attributes = {};
- this.drawcalls = [];
- this.offsets = this.drawcalls; // backwards compatibility
+ if ( new_vid === - 1 )
+ new_vid = vertexPtr ++;
- this.boundingBox = null;
- this.boundingSphere = null;
+ vertexMap[ vid ] = new_vid;
+ revVertexMap[ new_vid ] = vid;
+ sortedIndices[ indexPtr ++ ] = new_vid - offset.index; //XXX overflows at 16bit
+ offset.count ++;
+ }
+ }
-};
+ /* Move all attribute values to map to the new computed indices , also expand the vertice stack to match our new vertexPtr. */
+ this.reorderBuffers( sortedIndices, revVertexMap, vertexPtr );
+ this.offsets = offsets;
-THREE.BufferGeometry.prototype = {
+ /*
+ var orderTime = Date.now();
+ console.log("Reorder time: "+(orderTime-s)+"ms");
+ console.log("Duplicated "+duplicatedVertices+" vertices.");
+ console.log("Compute Buffers time: "+(Date.now()-s)+"ms");
+ console.log("Draw offsets: "+offsets.length);
+ */
- constructor: THREE.BufferGeometry,
+ return offsets;
+ },
- addAttribute: function ( name, attribute ) {
+ merge: function () {
- if ( attribute instanceof THREE.BufferAttribute === false ) {
+ console.log( 'BufferGeometry.merge(): TODO' );
- console.warn( 'THREE.BufferGeometry: .addAttribute() now expects ( name, attribute ).' );
+ },
- this.attributes[ name ] = { array: arguments[ 1 ], itemSize: arguments[ 2 ] };
+ normalizeNormals: function () {
- return;
+ var normals = this.attributes.normal.array;
- }
+ var x, y, z, n;
- this.attributes[ name ] = attribute;
+ for ( var i = 0, il = normals.length; i < il; i += 3 ) {
- },
+ x = normals[ i ];
+ y = normals[ i + 1 ];
+ z = normals[ i + 2 ];
- getAttribute: function ( name ) {
+ n = 1.0 / Math.sqrt( x * x + y * y + z * z );
- return this.attributes[ name ];
+ normals[ i ] *= n;
+ normals[ i + 1 ] *= n;
+ normals[ i + 2 ] *= n;
- },
+ }
- addDrawCall: function ( start, count, indexOffset ) {
+ },
- this.drawcalls.push( {
+ /*
+ reoderBuffers:
+ Reorder attributes based on a new indexBuffer and indexMap.
+ indexBuffer - Uint16Array of the new ordered indices.
+ indexMap - Int32Array where the position is the new vertex ID and the value the old vertex ID for each vertex.
+ vertexCount - Amount of total vertices considered in this reordering (in case you want to grow the vertice stack).
+ */
+ reorderBuffers: function ( indexBuffer, indexMap, vertexCount ) {
- start: start,
- count: count,
- index: indexOffset !== undefined ? indexOffset : 0
+ /* Create a copy of all attributes for reordering. */
+ var sortedAttributes = {};
+ for ( var attr in this.attributes ) {
+ if ( attr == 'index' )
+ continue;
+ var sourceArray = this.attributes[ attr ].array;
+ sortedAttributes[ attr ] = new sourceArray.constructor( this.attributes[ attr ].itemSize * vertexCount );
+ }
- } );
+ /* Move attribute positions based on the new index map */
+ for ( var new_vid = 0; new_vid < vertexCount; new_vid ++ ) {
+ var vid = indexMap[ new_vid ];
+ for ( var attr in this.attributes ) {
+ if ( attr == 'index' )
+ continue;
+ var attrArray = this.attributes[ attr ].array;
+ var attrSize = this.attributes[ attr ].itemSize;
+ var sortedAttr = sortedAttributes[ attr ];
+ for ( var k = 0; k < attrSize; k ++ )
+ sortedAttr[ new_vid * attrSize + k ] = attrArray[ vid * attrSize + k ];
+ }
+ }
+ /* Carry the new sorted buffers locally */
+ this.attributes[ 'index' ].array = indexBuffer;
+ for ( var attr in this.attributes ) {
+ if ( attr == 'index' )
+ continue;
+ this.attributes[ attr ].array = sortedAttributes[ attr ];
+ this.attributes[ attr ].numItems = this.attributes[ attr ].itemSize * vertexCount;
+ }
},
- applyMatrix: function ( matrix ) {
+ toJSON: function () {
- var position = this.attributes.position;
+ var output = {
+ metadata: {
+ version: 4.0,
+ type: 'BufferGeometry',
+ generator: 'BufferGeometryExporter'
+ },
+ uuid: this.uuid,
+ type: this.type,
+ data: {
+ attributes: {}
+ }
+ };
- if ( position !== undefined ) {
+ var attributes = this.attributes;
+ var offsets = this.offsets;
+ var boundingSphere = this.boundingSphere;
- matrix.applyToVector3Array( position.array );
- position.needsUpdate = true;
+ for ( var key in attributes ) {
- }
+ var attribute = attributes[ key ];
- var normal = this.attributes.normal;
+ var array = [], typeArray = attribute.array;
- if ( normal !== undefined ) {
+ for ( var i = 0, l = typeArray.length; i < l; i ++ ) {
- var normalMatrix = new THREE.Matrix3().getNormalMatrix( matrix );
+ array[ i ] = typeArray[ i ];
- normalMatrix.applyToVector3Array( normal.array );
- normal.needsUpdate = true;
+ }
+
+ output.data.attributes[ key ] = {
+ itemSize: attribute.itemSize,
+ type: attribute.array.constructor.name,
+ array: array
+ }
}
- },
+ if ( offsets.length > 0 ) {
- fromGeometry: function ( geometry, settings ) {
+ output.data.offsets = JSON.parse( JSON.stringify( offsets ) );
- settings = settings || { 'vertexColors': THREE.NoColors };
+ }
- var vertices = geometry.vertices;
- var faces = geometry.faces;
- var faceVertexUvs = geometry.faceVertexUvs;
- var vertexColors = settings.vertexColors;
- var hasFaceVertexUv = faceVertexUvs[ 0 ].length > 0;
- var hasFaceVertexNormals = faces[ 0 ].vertexNormals.length == 3;
+ if ( boundingSphere !== null ) {
- var positions = new Float32Array( faces.length * 3 * 3 );
- this.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );
+ output.data.boundingSphere = {
+ center: boundingSphere.center.toArray(),
+ radius: boundingSphere.radius
+ }
- var normals = new Float32Array( faces.length * 3 * 3 );
- this.addAttribute( 'normal', new THREE.BufferAttribute( normals, 3 ) );
+ }
- if ( vertexColors !== THREE.NoColors ) {
+ return output;
- var colors = new Float32Array( faces.length * 3 * 3 );
- this.addAttribute( 'color', new THREE.BufferAttribute( colors, 3 ) );
+ },
- }
+ clone: function () {
- if ( hasFaceVertexUv === true ) {
+ var geometry = new THREE.BufferGeometry();
- var uvs = new Float32Array( faces.length * 3 * 2 );
- this.addAttribute( 'uvs', new THREE.BufferAttribute( uvs, 2 ) );
+ for ( var attr in this.attributes ) {
+
+ var sourceAttr = this.attributes[ attr ];
+ geometry.addAttribute( attr, sourceAttr.clone() );
}
- for ( var i = 0, i2 = 0, i3 = 0; i < faces.length; i ++, i2 += 6, i3 += 9 ) {
+ for ( var i = 0, il = this.offsets.length; i < il; i ++ ) {
- var face = faces[ i ];
+ var offset = this.offsets[ i ];
- var a = vertices[ face.a ];
- var b = vertices[ face.b ];
- var c = vertices[ face.c ];
+ geometry.offsets.push( {
- positions[ i3 ] = a.x;
- positions[ i3 + 1 ] = a.y;
- positions[ i3 + 2 ] = a.z;
+ start: offset.start,
+ index: offset.index,
+ count: offset.count
- positions[ i3 + 3 ] = b.x;
- positions[ i3 + 4 ] = b.y;
- positions[ i3 + 5 ] = b.z;
+ } );
- positions[ i3 + 6 ] = c.x;
- positions[ i3 + 7 ] = c.y;
- positions[ i3 + 8 ] = c.z;
+ }
- if ( hasFaceVertexNormals === true ) {
+ return geometry;
- var na = face.vertexNormals[ 0 ];
- var nb = face.vertexNormals[ 1 ];
- var nc = face.vertexNormals[ 2 ];
+ },
- normals[ i3 ] = na.x;
- normals[ i3 + 1 ] = na.y;
- normals[ i3 + 2 ] = na.z;
+ dispose: function () {
- normals[ i3 + 3 ] = nb.x;
- normals[ i3 + 4 ] = nb.y;
- normals[ i3 + 5 ] = nb.z;
+ this.dispatchEvent( { type: 'dispose' } );
- normals[ i3 + 6 ] = nc.x;
- normals[ i3 + 7 ] = nc.y;
- normals[ i3 + 8 ] = nc.z;
+ }
- } else {
+};
- var n = face.normal;
+THREE.EventDispatcher.prototype.apply( THREE.BufferGeometry.prototype );
- normals[ i3 ] = n.x;
- normals[ i3 + 1 ] = n.y;
- normals[ i3 + 2 ] = n.z;
-
- normals[ i3 + 3 ] = n.x;
- normals[ i3 + 4 ] = n.y;
- normals[ i3 + 5 ] = n.z;
-
- normals[ i3 + 6 ] = n.x;
- normals[ i3 + 7 ] = n.y;
- normals[ i3 + 8 ] = n.z;
-
- }
+// File:src/core/Geometry.js
- if ( vertexColors === THREE.FaceColors ) {
+/**
+ * @author mrdoob / http://mrdoob.com/
+ * @author kile / http://kile.stravaganza.org/
+ * @author alteredq / http://alteredqualia.com/
+ * @author mikael emtinger / http://gomo.se/
+ * @author zz85 / http://www.lab4games.net/zz85/blog
+ * @author bhouston / http://exocortex.com
+ */
- var fc = face.color;
+THREE.Geometry = function () {
- colors[ i3 ] = fc.r;
- colors[ i3 + 1 ] = fc.g;
- colors[ i3 + 2 ] = fc.b;
+ Object.defineProperty( this, 'id', { value: THREE.GeometryIdCount ++ } );
- colors[ i3 + 3 ] = fc.r;
- colors[ i3 + 4 ] = fc.g;
- colors[ i3 + 5 ] = fc.b;
+ this.uuid = THREE.Math.generateUUID();
- colors[ i3 + 6 ] = fc.r;
- colors[ i3 + 7 ] = fc.g;
- colors[ i3 + 8 ] = fc.b;
+ this.name = '';
+ this.type = 'Geometry';
- } else if ( vertexColors === THREE.VertexColors ) {
+ this.vertices = [];
+ this.colors = []; // one-to-one vertex colors, used in Points and Line
- var vca = face.vertexColors[ 0 ];
- var vcb = face.vertexColors[ 1 ];
- var vcc = face.vertexColors[ 2 ];
+ this.faces = [];
- colors[ i3 ] = vca.r;
- colors[ i3 + 1 ] = vca.g;
- colors[ i3 + 2 ] = vca.b;
+ this.faceVertexUvs = [ [] ];
- colors[ i3 + 3 ] = vcb.r;
- colors[ i3 + 4 ] = vcb.g;
- colors[ i3 + 5 ] = vcb.b;
+ this.morphTargets = [];
+ this.morphColors = [];
+ this.morphNormals = [];
- colors[ i3 + 6 ] = vcc.r;
- colors[ i3 + 7 ] = vcc.g;
- colors[ i3 + 8 ] = vcc.b;
+ this.skinWeights = [];
+ this.skinIndices = [];
- }
+ this.lineDistances = [];
- if ( hasFaceVertexUv === true ) {
+ this.boundingBox = null;
+ this.boundingSphere = null;
- var uva = faceVertexUvs[ 0 ][ i ][ 0 ];
- var uvb = faceVertexUvs[ 0 ][ i ][ 1 ];
- var uvc = faceVertexUvs[ 0 ][ i ][ 2 ];
+ this.hasTangents = false;
- uvs[ i2 ] = uva.x;
- uvs[ i2 + 1 ] = uva.y;
+ this.dynamic = true; // the intermediate typed arrays will be deleted when set to false
- uvs[ i2 + 2 ] = uvb.x;
- uvs[ i2 + 3 ] = uvb.y;
+ // update flags
- uvs[ i2 + 4 ] = uvc.x;
- uvs[ i2 + 5 ] = uvc.y;
+ this.verticesNeedUpdate = false;
+ this.elementsNeedUpdate = false;
+ this.uvsNeedUpdate = false;
+ this.normalsNeedUpdate = false;
+ this.tangentsNeedUpdate = false;
+ this.colorsNeedUpdate = false;
+ this.lineDistancesNeedUpdate = false;
- }
+ this.groupsNeedUpdate = false;
- }
+};
- this.computeBoundingSphere()
+THREE.Geometry.prototype = {
- return this;
+ constructor: THREE.Geometry,
- },
+ applyMatrix: function ( matrix ) {
- computeBoundingBox: function () {
+ var normalMatrix = new THREE.Matrix3().getNormalMatrix( matrix );
- if ( this.boundingBox === null ) {
+ for ( var i = 0, il = this.vertices.length; i < il; i ++ ) {
- this.boundingBox = new THREE.Box3();
+ var vertex = this.vertices[ i ];
+ vertex.applyMatrix4( matrix );
}
- var positions = this.attributes[ 'position' ].array;
+ for ( var i = 0, il = this.faces.length; i < il; i ++ ) {
+
+ var face = this.faces[ i ];
+ face.normal.applyMatrix3( normalMatrix ).normalize();
- if ( positions ) {
+ for ( var j = 0, jl = face.vertexNormals.length; j < jl; j ++ ) {
- var bb = this.boundingBox;
+ face.vertexNormals[ j ].applyMatrix3( normalMatrix ).normalize();
- if ( positions.length >= 3 ) {
- bb.min.x = bb.max.x = positions[ 0 ];
- bb.min.y = bb.max.y = positions[ 1 ];
- bb.min.z = bb.max.z = positions[ 2 ];
}
- for ( var i = 3, il = positions.length; i < il; i += 3 ) {
-
- var x = positions[ i ];
- var y = positions[ i + 1 ];
- var z = positions[ i + 2 ];
+ }
- // bounding box
+ if ( this.boundingBox instanceof THREE.Box3 ) {
- if ( x < bb.min.x ) {
+ this.computeBoundingBox();
- bb.min.x = x;
+ }
- } else if ( x > bb.max.x ) {
+ if ( this.boundingSphere instanceof THREE.Sphere ) {
- bb.max.x = x;
+ this.computeBoundingSphere();
- }
+ }
- if ( y < bb.min.y ) {
+ },
- bb.min.y = y;
+ fromBufferGeometry: function ( geometry ) {
- } else if ( y > bb.max.y ) {
+ var scope = this;
- bb.max.y = y;
+ var attributes = geometry.attributes;
- }
+ var vertices = attributes.position.array;
+ var indices = attributes.index !== undefined ? attributes.index.array : undefined;
+ var normals = attributes.normal !== undefined ? attributes.normal.array : undefined;
+ var colors = attributes.color !== undefined ? attributes.color.array : undefined;
+ var uvs = attributes.uv !== undefined ? attributes.uv.array : undefined;
- if ( z < bb.min.z ) {
+ var tempNormals = [];
+ var tempUVs = [];
- bb.min.z = z;
+ for ( var i = 0, j = 0; i < vertices.length; i += 3, j += 2 ) {
- } else if ( z > bb.max.z ) {
+ scope.vertices.push( new THREE.Vector3( vertices[ i ], vertices[ i + 1 ], vertices[ i + 2 ] ) );
- bb.max.z = z;
+ if ( normals !== undefined ) {
- }
+ tempNormals.push( new THREE.Vector3( normals[ i ], normals[ i + 1 ], normals[ i + 2 ] ) );
}
- }
+ if ( colors !== undefined ) {
- if ( positions === undefined || positions.length === 0 ) {
+ scope.colors.push( new THREE.Color( colors[ i ], colors[ i + 1 ], colors[ i + 2 ] ) );
- this.boundingBox.min.set( 0, 0, 0 );
- this.boundingBox.max.set( 0, 0, 0 );
+ }
- }
+ if ( uvs !== undefined ) {
- if ( isNaN( this.boundingBox.min.x ) || isNaN( this.boundingBox.min.y ) || isNaN( this.boundingBox.min.z ) ) {
+ tempUVs.push( new THREE.Vector2( uvs[ j ], uvs[ j + 1 ] ) );
- console.error( 'THREE.BufferGeometry.computeBoundingBox: Computed min/max have NaN values. The "position" attribute is likely to have NaN values.' );
+ }
}
- },
+ var addFace = function ( a, b, c ) {
- computeBoundingSphere: function () {
+ var vertexNormals = normals !== undefined ? [ tempNormals[ a ].clone(), tempNormals[ b ].clone(), tempNormals[ c ].clone() ] : [];
+ var vertexColors = colors !== undefined ? [ scope.colors[ a ].clone(), scope.colors[ b ].clone(), scope.colors[ c ].clone() ] : [];
- var box = new THREE.Box3();
- var vector = new THREE.Vector3();
+ scope.faces.push( new THREE.Face3( a, b, c, vertexNormals, vertexColors ) );
+ scope.faceVertexUvs[ 0 ].push( [ tempUVs[ a ], tempUVs[ b ], tempUVs[ c ] ] );
- return function () {
+ };
- if ( this.boundingSphere === null ) {
+ if ( indices !== undefined ) {
- this.boundingSphere = new THREE.Sphere();
+ for ( var i = 0; i < indices.length; i += 3 ) {
+
+ addFace( indices[ i ], indices[ i + 1 ], indices[ i + 2 ] );
}
- var positions = this.attributes[ 'position' ].array;
+ } else {
- if ( positions ) {
+ for ( var i = 0; i < vertices.length / 3; i += 3 ) {
- box.makeEmpty();
+ addFace( i, i + 1, i + 2 );
- var center = this.boundingSphere.center;
+ }
- for ( var i = 0, il = positions.length; i < il; i += 3 ) {
+ }
+
+ this.computeFaceNormals();
- vector.set( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] );
- box.expandByPoint( vector );
+ if ( geometry.boundingBox !== null ) {
- }
+ this.boundingBox = geometry.boundingBox.clone();
- box.center( center );
+ }
- // hoping to find a boundingSphere with a radius smaller than the
- // boundingSphere of the boundingBox: sqrt(3) smaller in the best case
+ if ( geometry.boundingSphere !== null ) {
- var maxRadiusSq = 0;
+ this.boundingSphere = geometry.boundingSphere.clone();
- for ( var i = 0, il = positions.length; i < il; i += 3 ) {
+ }
- vector.set( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] );
- maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( vector ) );
+ return this;
- }
+ },
- this.boundingSphere.radius = Math.sqrt( maxRadiusSq );
+ center: function () {
- if ( isNaN( this.boundingSphere.radius ) ) {
+ this.computeBoundingBox();
- console.error( 'THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.' );
+ var offset = new THREE.Vector3();
- }
+ offset.addVectors( this.boundingBox.min, this.boundingBox.max );
+ offset.multiplyScalar( - 0.5 );
- }
+ this.applyMatrix( new THREE.Matrix4().makeTranslation( offset.x, offset.y, offset.z ) );
+ this.computeBoundingBox();
- }
+ return offset;
- }(),
+ },
computeFaceNormals: function () {
- // backwards compatibility
+ var cb = new THREE.Vector3(), ab = new THREE.Vector3();
- },
+ for ( var f = 0, fl = this.faces.length; f < fl; f ++ ) {
- computeVertexNormals: function () {
+ var face = this.faces[ f ];
- if ( this.attributes[ 'position' ] ) {
+ var vA = this.vertices[ face.a ];
+ var vB = this.vertices[ face.b ];
+ var vC = this.vertices[ face.c ];
- var i, il;
- var j, jl;
+ cb.subVectors( vC, vB );
+ ab.subVectors( vA, vB );
+ cb.cross( ab );
- var nVertexElements = this.attributes[ 'position' ].array.length;
+ cb.normalize();
- if ( this.attributes[ 'normal' ] === undefined ) {
+ face.normal.copy( cb );
- this.attributes[ 'normal' ] = {
+ }
- itemSize: 3,
- array: new Float32Array( nVertexElements )
+ },
- };
+ computeVertexNormals: function ( areaWeighted ) {
- } else {
+ var v, vl, f, fl, face, vertices;
- // reset existing normals to zero
+ vertices = new Array( this.vertices.length );
- for ( i = 0, il = this.attributes[ 'normal' ].array.length; i < il; i ++ ) {
+ for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) {
- this.attributes[ 'normal' ].array[ i ] = 0;
+ vertices[ v ] = new THREE.Vector3();
- }
+ }
- }
+ if ( areaWeighted ) {
- var positions = this.attributes[ 'position' ].array;
- var normals = this.attributes[ 'normal' ].array;
+ // vertex normals weighted by triangle areas
+ // http://www.iquilezles.org/www/articles/normals/normals.htm
- var vA, vB, vC, x, y, z,
+ var vA, vB, vC, vD;
+ var cb = new THREE.Vector3(), ab = new THREE.Vector3(),
+ db = new THREE.Vector3(), dc = new THREE.Vector3(), bc = new THREE.Vector3();
- pA = new THREE.Vector3(),
- pB = new THREE.Vector3(),
- pC = new THREE.Vector3(),
+ for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
- cb = new THREE.Vector3(),
- ab = new THREE.Vector3();
+ face = this.faces[ f ];
- // indexed elements
+ vA = this.vertices[ face.a ];
+ vB = this.vertices[ face.b ];
+ vC = this.vertices[ face.c ];
- if ( this.attributes[ 'index' ] ) {
+ cb.subVectors( vC, vB );
+ ab.subVectors( vA, vB );
+ cb.cross( ab );
- var indices = this.attributes[ 'index' ].array;
+ vertices[ face.a ].add( cb );
+ vertices[ face.b ].add( cb );
+ vertices[ face.c ].add( cb );
- var offsets = ( this.offsets.length > 0 ? this.offsets : [ { start: 0, count: indices.length, index: 0 } ] );
+ }
- for ( j = 0, jl = offsets.length; j < jl; ++ j ) {
+ } else {
- var start = offsets[ j ].start;
- var count = offsets[ j ].count;
- var index = offsets[ j ].index;
+ for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
- for ( i = start, il = start + count; i < il; i += 3 ) {
+ face = this.faces[ f ];
- vA = index + indices[ i ];
- vB = index + indices[ i + 1 ];
- vC = index + indices[ i + 2 ];
+ vertices[ face.a ].add( face.normal );
+ vertices[ face.b ].add( face.normal );
+ vertices[ face.c ].add( face.normal );
- x = positions[ vA * 3 ];
- y = positions[ vA * 3 + 1 ];
- z = positions[ vA * 3 + 2 ];
- pA.set( x, y, z );
+ }
- x = positions[ vB * 3 ];
- y = positions[ vB * 3 + 1 ];
- z = positions[ vB * 3 + 2 ];
- pB.set( x, y, z );
+ }
- x = positions[ vC * 3 ];
- y = positions[ vC * 3 + 1 ];
- z = positions[ vC * 3 + 2 ];
- pC.set( x, y, z );
+ for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) {
- cb.subVectors( pC, pB );
- ab.subVectors( pA, pB );
- cb.cross( ab );
+ vertices[ v ].normalize();
- normals[ vA * 3 ] += cb.x;
- normals[ vA * 3 + 1 ] += cb.y;
- normals[ vA * 3 + 2 ] += cb.z;
+ }
- normals[ vB * 3 ] += cb.x;
- normals[ vB * 3 + 1 ] += cb.y;
- normals[ vB * 3 + 2 ] += cb.z;
+ for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
- normals[ vC * 3 ] += cb.x;
- normals[ vC * 3 + 1 ] += cb.y;
- normals[ vC * 3 + 2 ] += cb.z;
+ face = this.faces[ f ];
- }
+ face.vertexNormals[ 0 ] = vertices[ face.a ].clone();
+ face.vertexNormals[ 1 ] = vertices[ face.b ].clone();
+ face.vertexNormals[ 2 ] = vertices[ face.c ].clone();
- }
+ }
- // non-indexed elements (unconnected triangle soup)
+ },
- } else {
+ computeMorphNormals: function () {
- for ( i = 0, il = positions.length; i < il; i += 9 ) {
+ var i, il, f, fl, face;
- x = positions[ i ];
- y = positions[ i + 1 ];
- z = positions[ i + 2 ];
- pA.set( x, y, z );
+ // save original normals
+ // - create temp variables on first access
+ // otherwise just copy (for faster repeated calls)
- x = positions[ i + 3 ];
- y = positions[ i + 4 ];
- z = positions[ i + 5 ];
- pB.set( x, y, z );
+ for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
- x = positions[ i + 6 ];
- y = positions[ i + 7 ];
- z = positions[ i + 8 ];
- pC.set( x, y, z );
+ face = this.faces[ f ];
- cb.subVectors( pC, pB );
- ab.subVectors( pA, pB );
- cb.cross( ab );
+ if ( ! face.__originalFaceNormal ) {
- normals[ i ] = cb.x;
- normals[ i + 1 ] = cb.y;
- normals[ i + 2 ] = cb.z;
+ face.__originalFaceNormal = face.normal.clone();
- normals[ i + 3 ] = cb.x;
- normals[ i + 4 ] = cb.y;
- normals[ i + 5 ] = cb.z;
+ } else {
- normals[ i + 6 ] = cb.x;
- normals[ i + 7 ] = cb.y;
- normals[ i + 8 ] = cb.z;
+ face.__originalFaceNormal.copy( face.normal );
+
+ }
+
+ if ( ! face.__originalVertexNormals ) face.__originalVertexNormals = [];
+
+ for ( i = 0, il = face.vertexNormals.length; i < il; i ++ ) {
+
+ if ( ! face.__originalVertexNormals[ i ] ) {
+
+ face.__originalVertexNormals[ i ] = face.vertexNormals[ i ].clone();
+
+ } else {
+
+ face.__originalVertexNormals[ i ].copy( face.vertexNormals[ i ] );
}
}
- this.normalizeNormals();
+ }
- this.normalsNeedUpdate = true;
+ // use temp geometry to compute face and vertex normals for each morph
- }
+ var tmpGeo = new THREE.Geometry();
+ tmpGeo.faces = this.faces;
- },
+ for ( i = 0, il = this.morphTargets.length; i < il; i ++ ) {
- computeTangents: function () {
+ // create on first access
- // based on http://www.terathon.com/code/tangent.html
- // (per vertex tangents)
+ if ( ! this.morphNormals[ i ] ) {
- if ( this.attributes[ 'index' ] === undefined ||
- this.attributes[ 'position' ] === undefined ||
- this.attributes[ 'normal' ] === undefined ||
- this.attributes[ 'uv' ] === undefined ) {
+ this.morphNormals[ i ] = {};
+ this.morphNormals[ i ].faceNormals = [];
+ this.morphNormals[ i ].vertexNormals = [];
- console.warn( 'Missing required attributes (index, position, normal or uv) in BufferGeometry.computeTangents()' );
- return;
+ var dstNormalsFace = this.morphNormals[ i ].faceNormals;
+ var dstNormalsVertex = this.morphNormals[ i ].vertexNormals;
- }
+ var faceNormal, vertexNormals;
- var indices = this.attributes[ 'index' ].array;
- var positions = this.attributes[ 'position' ].array;
- var normals = this.attributes[ 'normal' ].array;
- var uvs = this.attributes[ 'uv' ].array;
+ for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
- var nVertices = positions.length / 3;
+ faceNormal = new THREE.Vector3();
+ vertexNormals = { a: new THREE.Vector3(), b: new THREE.Vector3(), c: new THREE.Vector3() };
- if ( this.attributes[ 'tangent' ] === undefined ) {
+ dstNormalsFace.push( faceNormal );
+ dstNormalsVertex.push( vertexNormals );
- var nTangentElements = 4 * nVertices;
+ }
- this.attributes[ 'tangent' ] = {
+ }
- itemSize: 4,
- array: new Float32Array( nTangentElements )
+ var morphNormals = this.morphNormals[ i ];
- };
+ // set vertices to morph target
- }
+ tmpGeo.vertices = this.morphTargets[ i ].vertices;
- var tangents = this.attributes[ 'tangent' ].array;
+ // compute morph normals
- var tan1 = [], tan2 = [];
+ tmpGeo.computeFaceNormals();
+ tmpGeo.computeVertexNormals();
- for ( var k = 0; k < nVertices; k ++ ) {
+ // store morph normals
- tan1[ k ] = new THREE.Vector3();
- tan2[ k ] = new THREE.Vector3();
+ var faceNormal, vertexNormals;
- }
+ for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
- var xA, yA, zA,
- xB, yB, zB,
- xC, yC, zC,
+ face = this.faces[ f ];
- uA, vA,
- uB, vB,
- uC, vC,
+ faceNormal = morphNormals.faceNormals[ f ];
+ vertexNormals = morphNormals.vertexNormals[ f ];
- x1, x2, y1, y2, z1, z2,
- s1, s2, t1, t2, r;
+ faceNormal.copy( face.normal );
- var sdir = new THREE.Vector3(), tdir = new THREE.Vector3();
+ vertexNormals.a.copy( face.vertexNormals[ 0 ] );
+ vertexNormals.b.copy( face.vertexNormals[ 1 ] );
+ vertexNormals.c.copy( face.vertexNormals[ 2 ] );
- function handleTriangle( a, b, c ) {
+ }
+
+ }
+
+ // restore original normals
- xA = positions[ a * 3 ];
- yA = positions[ a * 3 + 1 ];
- zA = positions[ a * 3 + 2 ];
+ for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
- xB = positions[ b * 3 ];
- yB = positions[ b * 3 + 1 ];
- zB = positions[ b * 3 + 2 ];
+ face = this.faces[ f ];
- xC = positions[ c * 3 ];
- yC = positions[ c * 3 + 1 ];
- zC = positions[ c * 3 + 2 ];
+ face.normal = face.__originalFaceNormal;
+ face.vertexNormals = face.__originalVertexNormals;
- uA = uvs[ a * 2 ];
- vA = uvs[ a * 2 + 1 ];
+ }
- uB = uvs[ b * 2 ];
- vB = uvs[ b * 2 + 1 ];
+ },
- uC = uvs[ c * 2 ];
- vC = uvs[ c * 2 + 1 ];
+ computeTangents: function () {
- x1 = xB - xA;
- x2 = xC - xA;
+ // based on http://www.terathon.com/code/tangent.html
+ // tangents go to vertices
- y1 = yB - yA;
- y2 = yC - yA;
+ var f, fl, v, vl, i, il, vertexIndex,
+ face, uv, vA, vB, vC, uvA, uvB, uvC,
+ x1, x2, y1, y2, z1, z2,
+ s1, s2, t1, t2, r, t, test,
+ tan1 = [], tan2 = [],
+ sdir = new THREE.Vector3(), tdir = new THREE.Vector3(),
+ tmp = new THREE.Vector3(), tmp2 = new THREE.Vector3(),
+ n = new THREE.Vector3(), w;
- z1 = zB - zA;
- z2 = zC - zA;
+ for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) {
- s1 = uB - uA;
- s2 = uC - uA;
+ tan1[ v ] = new THREE.Vector3();
+ tan2[ v ] = new THREE.Vector3();
- t1 = vB - vA;
- t2 = vC - vA;
+ }
- r = 1.0 / ( s1 * t2 - s2 * t1 );
+ function handleTriangle( context, a, b, c, ua, ub, uc ) {
- sdir.set(
- ( t2 * x1 - t1 * x2 ) * r,
- ( t2 * y1 - t1 * y2 ) * r,
- ( t2 * z1 - t1 * z2 ) * r
- );
+ vA = context.vertices[ a ];
+ vB = context.vertices[ b ];
+ vC = context.vertices[ c ];
- tdir.set(
- ( s1 * x2 - s2 * x1 ) * r,
- ( s1 * y2 - s2 * y1 ) * r,
- ( s1 * z2 - s2 * z1 ) * r
- );
+ uvA = uv[ ua ];
+ uvB = uv[ ub ];
+ uvC = uv[ uc ];
+
+ x1 = vB.x - vA.x;
+ x2 = vC.x - vA.x;
+ y1 = vB.y - vA.y;
+ y2 = vC.y - vA.y;
+ z1 = vB.z - vA.z;
+ z2 = vC.z - vA.z;
+
+ s1 = uvB.x - uvA.x;
+ s2 = uvC.x - uvA.x;
+ t1 = uvB.y - uvA.y;
+ t2 = uvC.y - uvA.y;
+
+ r = 1.0 / ( s1 * t2 - s2 * t1 );
+ sdir.set( ( t2 * x1 - t1 * x2 ) * r,
+ ( t2 * y1 - t1 * y2 ) * r,
+ ( t2 * z1 - t1 * z2 ) * r );
+ tdir.set( ( s1 * x2 - s2 * x1 ) * r,
+ ( s1 * y2 - s2 * y1 ) * r,
+ ( s1 * z2 - s2 * z1 ) * r );
tan1[ a ].add( sdir );
tan1[ b ].add( sdir );
@@ -9437,2290 +9696,1771 @@ THREE.BufferGeometry.prototype = {
}
- var i, il;
- var j, jl;
- var iA, iB, iC;
+ for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
- var offsets = this.offsets;
+ face = this.faces[ f ];
+ uv = this.faceVertexUvs[ 0 ][ f ]; // use UV layer 0 for tangents
- for ( j = 0, jl = offsets.length; j < jl; ++ j ) {
+ handleTriangle( this, face.a, face.b, face.c, 0, 1, 2 );
- var start = offsets[ j ].start;
- var count = offsets[ j ].count;
- var index = offsets[ j ].index;
+ }
- for ( i = start, il = start + count; i < il; i += 3 ) {
+ var faceIndex = [ 'a', 'b', 'c', 'd' ];
- iA = index + indices[ i ];
- iB = index + indices[ i + 1 ];
- iC = index + indices[ i + 2 ];
+ for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
- handleTriangle( iA, iB, iC );
+ face = this.faces[ f ];
- }
+ for ( i = 0; i < Math.min( face.vertexNormals.length, 3 ); i ++ ) {
- }
+ n.copy( face.vertexNormals[ i ] );
- var tmp = new THREE.Vector3(), tmp2 = new THREE.Vector3();
- var n = new THREE.Vector3(), n2 = new THREE.Vector3();
- var w, t, test;
+ vertexIndex = face[ faceIndex[ i ] ];
- function handleVertex( v ) {
+ t = tan1[ vertexIndex ];
- n.x = normals[ v * 3 ];
- n.y = normals[ v * 3 + 1 ];
- n.z = normals[ v * 3 + 2 ];
+ // Gram-Schmidt orthogonalize
- n2.copy( n );
+ tmp.copy( t );
+ tmp.sub( n.multiplyScalar( n.dot( t ) ) ).normalize();
- t = tan1[ v ];
+ // Calculate handedness
- // Gram-Schmidt orthogonalize
+ tmp2.crossVectors( face.vertexNormals[ i ], t );
+ test = tmp2.dot( tan2[ vertexIndex ] );
+ w = ( test < 0.0 ) ? - 1.0 : 1.0;
- tmp.copy( t );
- tmp.sub( n.multiplyScalar( n.dot( t ) ) ).normalize();
+ face.vertexTangents[ i ] = new THREE.Vector4( tmp.x, tmp.y, tmp.z, w );
- // Calculate handedness
+ }
- tmp2.crossVectors( n2, t );
- test = tmp2.dot( tan2[ v ] );
- w = ( test < 0.0 ) ? - 1.0 : 1.0;
+ }
- tangents[ v * 4 ] = tmp.x;
- tangents[ v * 4 + 1 ] = tmp.y;
- tangents[ v * 4 + 2 ] = tmp.z;
- tangents[ v * 4 + 3 ] = w;
+ this.hasTangents = true;
- }
+ },
- for ( j = 0, jl = offsets.length; j < jl; ++ j ) {
+ computeLineDistances: function () {
- var start = offsets[ j ].start;
- var count = offsets[ j ].count;
- var index = offsets[ j ].index;
+ var d = 0;
+ var vertices = this.vertices;
- for ( i = start, il = start + count; i < il; i += 3 ) {
+ for ( var i = 0, il = vertices.length; i < il; i ++ ) {
- iA = index + indices[ i ];
- iB = index + indices[ i + 1 ];
- iC = index + indices[ i + 2 ];
+ if ( i > 0 ) {
- handleVertex( iA );
- handleVertex( iB );
- handleVertex( iC );
+ d += vertices[ i ].distanceTo( vertices[ i - 1 ] );
}
+ this.lineDistances[ i ] = d;
+
}
},
- /*
- computeOffsets
- Compute the draw offset for large models by chunking the index buffer into chunks of 65k addressable vertices.
- This method will effectively rewrite the index buffer and remap all attributes to match the new indices.
- WARNING: This method will also expand the vertex count to prevent sprawled triangles across draw offsets.
- indexBufferSize - Defaults to 65535, but allows for larger or smaller chunks.
- */
- computeOffsets: function ( indexBufferSize ) {
+ computeBoundingBox: function () {
- var size = indexBufferSize;
- if ( indexBufferSize === undefined )
- size = 65535; //WebGL limits type of index buffer values to 16-bit.
+ if ( this.boundingBox === null ) {
- var s = Date.now();
+ this.boundingBox = new THREE.Box3();
- var indices = this.attributes[ 'index' ].array;
- var vertices = this.attributes[ 'position' ].array;
+ }
- var verticesCount = ( vertices.length / 3 );
- var facesCount = ( indices.length / 3 );
+ this.boundingBox.setFromPoints( this.vertices );
- /*
- console.log("Computing buffers in offsets of "+size+" -> indices:"+indices.length+" vertices:"+vertices.length);
- console.log("Faces to process: "+(indices.length/3));
- console.log("Reordering "+verticesCount+" vertices.");
- */
+ },
- var sortedIndices = new Uint16Array( indices.length ); //16-bit buffers
- var indexPtr = 0;
- var vertexPtr = 0;
+ computeBoundingSphere: function () {
- var offsets = [ { start:0, count:0, index:0 } ];
- var offset = offsets[ 0 ];
+ if ( this.boundingSphere === null ) {
- var duplicatedVertices = 0;
- var newVerticeMaps = 0;
- var faceVertices = new Int32Array( 6 );
- var vertexMap = new Int32Array( vertices.length );
- var revVertexMap = new Int32Array( vertices.length );
- for ( var j = 0; j < vertices.length; j ++ ) { vertexMap[ j ] = - 1; revVertexMap[ j ] = - 1; }
+ this.boundingSphere = new THREE.Sphere();
- /*
- Traverse every face and reorder vertices in the proper offsets of 65k.
- We can have more than 65k entries in the index buffer per offset, but only reference 65k values.
- */
- for ( var findex = 0; findex < facesCount; findex ++ ) {
- newVerticeMaps = 0;
+ }
- for ( var vo = 0; vo < 3; vo ++ ) {
- var vid = indices[ findex * 3 + vo ];
- if ( vertexMap[ vid ] == - 1 ) {
- //Unmapped vertice
- faceVertices[ vo * 2 ] = vid;
- faceVertices[ vo * 2 + 1 ] = - 1;
- newVerticeMaps ++;
- } else if ( vertexMap[ vid ] < offset.index ) {
- //Reused vertices from previous block (duplicate)
- faceVertices[ vo * 2 ] = vid;
- faceVertices[ vo * 2 + 1 ] = - 1;
- duplicatedVertices ++;
- } else {
- //Reused vertice in the current block
- faceVertices[ vo * 2 ] = vid;
- faceVertices[ vo * 2 + 1 ] = vertexMap[ vid ];
- }
- }
+ this.boundingSphere.setFromPoints( this.vertices );
- var faceMax = vertexPtr + newVerticeMaps;
- if ( faceMax > ( offset.index + size ) ) {
- var new_offset = { start:indexPtr, count:0, index:vertexPtr };
- offsets.push( new_offset );
- offset = new_offset;
+ },
- //Re-evaluate reused vertices in light of new offset.
- for ( var v = 0; v < 6; v += 2 ) {
- var new_vid = faceVertices[ v + 1 ];
- if ( new_vid > - 1 && new_vid < offset.index )
- faceVertices[ v + 1 ] = - 1;
- }
- }
+ merge: function ( geometry, matrix, materialIndexOffset ) {
- //Reindex the face.
- for ( var v = 0; v < 6; v += 2 ) {
- var vid = faceVertices[ v ];
- var new_vid = faceVertices[ v + 1 ];
+ if ( geometry instanceof THREE.Geometry === false ) {
- if ( new_vid === - 1 )
- new_vid = vertexPtr ++;
+ console.error( 'THREE.Geometry.merge(): geometry not an instance of THREE.Geometry.', geometry );
+ return;
- vertexMap[ vid ] = new_vid;
- revVertexMap[ new_vid ] = vid;
- sortedIndices[ indexPtr ++ ] = new_vid - offset.index; //XXX overflows at 16bit
- offset.count ++;
- }
}
- /* Move all attribute values to map to the new computed indices , also expand the vertice stack to match our new vertexPtr. */
- this.reorderBuffers( sortedIndices, revVertexMap, vertexPtr );
- this.offsets = offsets;
-
- /*
- var orderTime = Date.now();
- console.log("Reorder time: "+(orderTime-s)+"ms");
- console.log("Duplicated "+duplicatedVertices+" vertices.");
- console.log("Compute Buffers time: "+(Date.now()-s)+"ms");
- console.log("Draw offsets: "+offsets.length);
- */
-
- return offsets;
- },
+ var normalMatrix,
+ vertexOffset = this.vertices.length,
+ vertices1 = this.vertices,
+ vertices2 = geometry.vertices,
+ faces1 = this.faces,
+ faces2 = geometry.faces,
+ uvs1 = this.faceVertexUvs[ 0 ],
+ uvs2 = geometry.faceVertexUvs[ 0 ];
- merge: function () {
+ if ( materialIndexOffset === undefined ) materialIndexOffset = 0;
- console.log( 'BufferGeometry.merge(): TODO' );
+ if ( matrix !== undefined ) {
- },
+ normalMatrix = new THREE.Matrix3().getNormalMatrix( matrix );
- normalizeNormals: function () {
+ }
- var normals = this.attributes[ 'normal' ].array;
+ // vertices
- var x, y, z, n;
+ for ( var i = 0, il = vertices2.length; i < il; i ++ ) {
- for ( var i = 0, il = normals.length; i < il; i += 3 ) {
+ var vertex = vertices2[ i ];
- x = normals[ i ];
- y = normals[ i + 1 ];
- z = normals[ i + 2 ];
+ var vertexCopy = vertex.clone();
- n = 1.0 / Math.sqrt( x * x + y * y + z * z );
+ if ( matrix !== undefined ) vertexCopy.applyMatrix4( matrix );
- normals[ i ] *= n;
- normals[ i + 1 ] *= n;
- normals[ i + 2 ] *= n;
+ vertices1.push( vertexCopy );
}
- },
-
- /*
- reoderBuffers:
- Reorder attributes based on a new indexBuffer and indexMap.
- indexBuffer - Uint16Array of the new ordered indices.
- indexMap - Int32Array where the position is the new vertex ID and the value the old vertex ID for each vertex.
- vertexCount - Amount of total vertices considered in this reordering (in case you want to grow the vertice stack).
- */
- reorderBuffers: function ( indexBuffer, indexMap, vertexCount ) {
+ // faces
- /* Create a copy of all attributes for reordering. */
- var sortedAttributes = {};
- var types = [ Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64Array ];
- for ( var attr in this.attributes ) {
- if ( attr == 'index' )
- continue;
- var sourceArray = this.attributes[ attr ].array;
- for ( var i = 0, il = types.length; i < il; i ++ ) {
- var type = types[ i ];
- if ( sourceArray instanceof type ) {
- sortedAttributes[ attr ] = new type( this.attributes[ attr ].itemSize * vertexCount );
- break;
- }
- }
- }
+ for ( i = 0, il = faces2.length; i < il; i ++ ) {
- /* Move attribute positions based on the new index map */
- for ( var new_vid = 0; new_vid < vertexCount; new_vid ++ ) {
- var vid = indexMap[ new_vid ];
- for ( var attr in this.attributes ) {
- if ( attr == 'index' )
- continue;
- var attrArray = this.attributes[ attr ].array;
- var attrSize = this.attributes[ attr ].itemSize;
- var sortedAttr = sortedAttributes[ attr ];
- for ( var k = 0; k < attrSize; k ++ )
- sortedAttr[ new_vid * attrSize + k ] = attrArray[ vid * attrSize + k ];
- }
- }
+ var face = faces2[ i ], faceCopy, normal, color,
+ faceVertexNormals = face.vertexNormals,
+ faceVertexColors = face.vertexColors;
- /* Carry the new sorted buffers locally */
- this.attributes[ 'index' ].array = indexBuffer;
- for ( var attr in this.attributes ) {
- if ( attr == 'index' )
- continue;
- this.attributes[ attr ].array = sortedAttributes[ attr ];
- this.attributes[ attr ].numItems = this.attributes[ attr ].itemSize * vertexCount;
- }
- },
+ faceCopy = new THREE.Face3( face.a + vertexOffset, face.b + vertexOffset, face.c + vertexOffset );
+ faceCopy.normal.copy( face.normal );
- clone: function () {
+ if ( normalMatrix !== undefined ) {
- var geometry = new THREE.BufferGeometry();
+ faceCopy.normal.applyMatrix3( normalMatrix ).normalize();
- var types = [ Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64Array ];
+ }
- for ( var attr in this.attributes ) {
+ for ( var j = 0, jl = faceVertexNormals.length; j < jl; j ++ ) {
- var sourceAttr = this.attributes[ attr ];
- var sourceArray = sourceAttr.array;
+ normal = faceVertexNormals[ j ].clone();
- var attribute = {
+ if ( normalMatrix !== undefined ) {
- itemSize: sourceAttr.itemSize,
- array: null
+ normal.applyMatrix3( normalMatrix ).normalize();
- };
+ }
- for ( var i = 0, il = types.length; i < il; i ++ ) {
+ faceCopy.vertexNormals.push( normal );
- var type = types[ i ];
+ }
- if ( sourceArray instanceof type ) {
+ faceCopy.color.copy( face.color );
- attribute.array = new type( sourceArray );
- break;
+ for ( var j = 0, jl = faceVertexColors.length; j < jl; j ++ ) {
- }
+ color = faceVertexColors[ j ];
+ faceCopy.vertexColors.push( color.clone() );
}
- geometry.attributes[ attr ] = attribute;
+ faceCopy.materialIndex = face.materialIndex + materialIndexOffset;
+
+ faces1.push( faceCopy );
}
- for ( var i = 0, il = this.offsets.length; i < il; i ++ ) {
+ // uvs
- var offset = this.offsets[ i ];
+ for ( i = 0, il = uvs2.length; i < il; i ++ ) {
- geometry.offsets.push( {
+ var uv = uvs2[ i ], uvCopy = [];
- start: offset.start,
- index: offset.index,
- count: offset.count
+ if ( uv === undefined ) {
- } );
+ continue;
- }
+ }
- return geometry;
+ for ( var j = 0, jl = uv.length; j < jl; j ++ ) {
- },
+ uvCopy.push( new THREE.Vector2( uv[ j ].x, uv[ j ].y ) );
- dispose: function () {
+ }
- this.dispatchEvent( { type: 'dispose' } );
+ uvs1.push( uvCopy );
- }
+ }
-};
+ },
-THREE.EventDispatcher.prototype.apply( THREE.BufferGeometry.prototype );
+ /*
+ * Checks for duplicate vertices with hashmap.
+ * Duplicated vertices are removed
+ * and faces' vertices are updated.
+ */
-// File:src/core/Geometry.js
+ mergeVertices: function () {
-/**
- * @author mrdoob / http://mrdoob.com/
- * @author kile / http://kile.stravaganza.org/
- * @author alteredq / http://alteredqualia.com/
- * @author mikael emtinger / http://gomo.se/
- * @author zz85 / http://www.lab4games.net/zz85/blog
- * @author bhouston / http://exocortex.com
- */
+ var verticesMap = {}; // Hashmap for looking up vertice by position coordinates (and making sure they are unique)
+ var unique = [], changes = [];
-THREE.Geometry = function () {
+ var v, key;
+ var precisionPoints = 4; // number of decimal points, eg. 4 for epsilon of 0.0001
+ var precision = Math.pow( 10, precisionPoints );
+ var i,il, face;
+ var indices, k, j, jl, u;
- this.id = THREE.GeometryIdCount ++;
- this.uuid = THREE.Math.generateUUID();
+ for ( i = 0, il = this.vertices.length; i < il; i ++ ) {
- this.name = '';
+ v = this.vertices[ i ];
+ key = Math.round( v.x * precision ) + '_' + Math.round( v.y * precision ) + '_' + Math.round( v.z * precision );
- this.vertices = [];
- this.colors = []; // one-to-one vertex colors, used in Points and Line
+ if ( verticesMap[ key ] === undefined ) {
- this.faces = [];
+ verticesMap[ key ] = i;
+ unique.push( this.vertices[ i ] );
+ changes[ i ] = unique.length - 1;
- this.faceVertexUvs = [ [] ];
+ } else {
- this.morphTargets = [];
- this.morphColors = [];
- this.morphNormals = [];
+ //console.log('Duplicate vertex found. ', i, ' could be using ', verticesMap[key]);
+ changes[ i ] = changes[ verticesMap[ key ] ];
- this.skinWeights = [];
- this.skinIndices = [];
+ }
- this.lineDistances = [];
+ };
- this.boundingBox = null;
- this.boundingSphere = null;
- this.hasTangents = false;
+ // if faces are completely degenerate after merging vertices, we
+ // have to remove them from the geometry.
+ var faceIndicesToRemove = [];
- this.dynamic = true; // the intermediate typed arrays will be deleted when set to false
+ for ( i = 0, il = this.faces.length; i < il; i ++ ) {
- // update flags
-
- this.verticesNeedUpdate = false;
- this.elementsNeedUpdate = false;
- this.uvsNeedUpdate = false;
- this.normalsNeedUpdate = false;
- this.tangentsNeedUpdate = false;
- this.colorsNeedUpdate = false;
- this.lineDistancesNeedUpdate = false;
-
- this.buffersNeedUpdate = false;
- this.groupsNeedUpdate = false;
-
-};
+ face = this.faces[ i ];
-THREE.Geometry.prototype = {
+ face.a = changes[ face.a ];
+ face.b = changes[ face.b ];
+ face.c = changes[ face.c ];
- constructor: THREE.Geometry,
+ indices = [ face.a, face.b, face.c ];
- applyMatrix: function ( matrix ) {
+ var dupIndex = - 1;
- var normalMatrix = new THREE.Matrix3().getNormalMatrix( matrix );
+ // if any duplicate vertices are found in a Face3
+ // we have to remove the face as nothing can be saved
+ for ( var n = 0; n < 3; n ++ ) {
+ if ( indices[ n ] == indices[ ( n + 1 ) % 3 ] ) {
- for ( var i = 0, il = this.vertices.length; i < il; i ++ ) {
+ dupIndex = n;
+ faceIndicesToRemove.push( i );
+ break;
- var vertex = this.vertices[ i ];
- vertex.applyMatrix4( matrix );
+ }
+ }
}
- for ( var i = 0, il = this.faces.length; i < il; i ++ ) {
+ for ( i = faceIndicesToRemove.length - 1; i >= 0; i -- ) {
+ var idx = faceIndicesToRemove[ i ];
- var face = this.faces[ i ];
- face.normal.applyMatrix3( normalMatrix ).normalize();
+ this.faces.splice( idx, 1 );
- for ( var j = 0, jl = face.vertexNormals.length; j < jl; j ++ ) {
+ for ( j = 0, jl = this.faceVertexUvs.length; j < jl; j ++ ) {
- face.vertexNormals[ j ].applyMatrix3( normalMatrix ).normalize();
+ this.faceVertexUvs[ j ].splice( idx, 1 );
}
}
- if ( this.boundingBox instanceof THREE.Box3 ) {
+ // Use unique set of vertices
- this.computeBoundingBox();
+ var diff = this.vertices.length - unique.length;
+ this.vertices = unique;
+ return diff;
- }
+ },
- if ( this.boundingSphere instanceof THREE.Sphere ) {
+ toJSON: function () {
- this.computeBoundingSphere();
+ var output = {
+ metadata: {
+ version: 4.0,
+ type: 'BufferGeometry',
+ generator: 'BufferGeometryExporter'
+ },
+ uuid: this.uuid,
+ type: this.type
+ };
- }
+ if ( this.name !== "" ) output.name = this.name;
- },
+ if ( this.parameters !== undefined ) {
- center: function () {
+ var parameters = this.parameters;
- this.computeBoundingBox();
+ for ( var key in parameters ) {
- var offset = new THREE.Vector3();
+ if ( parameters[ key ] !== undefined ) output[ key ] = parameters[ key ];
- offset.addVectors( this.boundingBox.min, this.boundingBox.max );
- offset.multiplyScalar( - 0.5 );
+ }
- this.applyMatrix( new THREE.Matrix4().makeTranslation( offset.x, offset.y, offset.z ) );
- this.computeBoundingBox();
+ return output;
- return offset;
+ }
- },
+ var vertices = [];
- computeFaceNormals: function () {
+ for ( var i = 0; i < this.vertices.length; i ++ ) {
- var cb = new THREE.Vector3(), ab = new THREE.Vector3();
+ var vertex = this.vertices[ i ];
+ vertices.push( vertex.x, vertex.y, vertex.z );
- for ( var f = 0, fl = this.faces.length; f < fl; f ++ ) {
+ }
- var face = this.faces[ f ];
+ var faces = [];
+ var normals = [];
+ var normalsHash = {};
+ var colors = [];
+ var colorsHash = {};
+ var uvs = [];
+ var uvsHash = {};
- var vA = this.vertices[ face.a ];
- var vB = this.vertices[ face.b ];
- var vC = this.vertices[ face.c ];
+ for ( var i = 0; i < this.faces.length; i ++ ) {
- cb.subVectors( vC, vB );
- ab.subVectors( vA, vB );
- cb.cross( ab );
+ var face = this.faces[ i ];
- cb.normalize();
+ var hasMaterial = false; // face.materialIndex !== undefined;
+ var hasFaceUv = false; // deprecated
+ var hasFaceVertexUv = this.faceVertexUvs[ 0 ][ i ] !== undefined;
+ var hasFaceNormal = face.normal.length() > 0;
+ var hasFaceVertexNormal = face.vertexNormals.length > 0;
+ var hasFaceColor = face.color.r !== 1 || face.color.g !== 1 || face.color.b !== 1;
+ var hasFaceVertexColor = face.vertexColors.length > 0;
- face.normal.copy( cb );
+ var faceType = 0;
- }
+ faceType = setBit( faceType, 0, 0 );
+ faceType = setBit( faceType, 1, hasMaterial );
+ faceType = setBit( faceType, 2, hasFaceUv );
+ faceType = setBit( faceType, 3, hasFaceVertexUv );
+ faceType = setBit( faceType, 4, hasFaceNormal );
+ faceType = setBit( faceType, 5, hasFaceVertexNormal );
+ faceType = setBit( faceType, 6, hasFaceColor );
+ faceType = setBit( faceType, 7, hasFaceVertexColor );
- },
+ faces.push( faceType );
+ faces.push( face.a, face.b, face.c );
- computeVertexNormals: function ( areaWeighted ) {
- var v, vl, f, fl, face, vertices;
+ /*
+ if ( hasMaterial ) {
- vertices = new Array( this.vertices.length );
+ faces.push( face.materialIndex );
- for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) {
+ }
+ */
- vertices[ v ] = new THREE.Vector3();
+ if ( hasFaceVertexUv ) {
- }
+ var faceVertexUvs = this.faceVertexUvs[ 0 ][ i ];
- if ( areaWeighted ) {
+ faces.push(
+ getUvIndex( faceVertexUvs[ 0 ] ),
+ getUvIndex( faceVertexUvs[ 1 ] ),
+ getUvIndex( faceVertexUvs[ 2 ] )
+ );
- // vertex normals weighted by triangle areas
- // http://www.iquilezles.org/www/articles/normals/normals.htm
+ }
- var vA, vB, vC, vD;
- var cb = new THREE.Vector3(), ab = new THREE.Vector3(),
- db = new THREE.Vector3(), dc = new THREE.Vector3(), bc = new THREE.Vector3();
+ if ( hasFaceNormal ) {
- for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
+ faces.push( getNormalIndex( face.normal ) );
- face = this.faces[ f ];
+ }
- vA = this.vertices[ face.a ];
- vB = this.vertices[ face.b ];
- vC = this.vertices[ face.c ];
+ if ( hasFaceVertexNormal ) {
- cb.subVectors( vC, vB );
- ab.subVectors( vA, vB );
- cb.cross( ab );
+ var vertexNormals = face.vertexNormals;
- vertices[ face.a ].add( cb );
- vertices[ face.b ].add( cb );
- vertices[ face.c ].add( cb );
+ faces.push(
+ getNormalIndex( vertexNormals[ 0 ] ),
+ getNormalIndex( vertexNormals[ 1 ] ),
+ getNormalIndex( vertexNormals[ 2 ] )
+ );
}
- } else {
+ if ( hasFaceColor ) {
- for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
+ faces.push( getColorIndex( face.color ) );
- face = this.faces[ f ];
+ }
- vertices[ face.a ].add( face.normal );
- vertices[ face.b ].add( face.normal );
- vertices[ face.c ].add( face.normal );
+ if ( hasFaceVertexColor ) {
+
+ var vertexColors = face.vertexColors;
+
+ faces.push(
+ getColorIndex( vertexColors[ 0 ] ),
+ getColorIndex( vertexColors[ 1 ] ),
+ getColorIndex( vertexColors[ 2 ] )
+ );
}
}
- for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) {
+ function setBit( value, position, enabled ) {
- vertices[ v ].normalize();
+ return enabled ? value | ( 1 << position ) : value & ( ~ ( 1 << position) );
}
- for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
-
- face = this.faces[ f ];
-
- face.vertexNormals[ 0 ] = vertices[ face.a ].clone();
- face.vertexNormals[ 1 ] = vertices[ face.b ].clone();
- face.vertexNormals[ 2 ] = vertices[ face.c ].clone();
+ function getNormalIndex( normal ) {
- }
+ var hash = normal.x.toString() + normal.y.toString() + normal.z.toString();
- },
+ if ( normalsHash[ hash ] !== undefined ) {
- computeMorphNormals: function () {
+ return normalsHash[ hash ];
- var i, il, f, fl, face;
+ }
- // save original normals
- // - create temp variables on first access
- // otherwise just copy (for faster repeated calls)
+ normalsHash[ hash ] = normals.length / 3;
+ normals.push( normal.x, normal.y, normal.z );
- for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
+ return normalsHash[ hash ];
- face = this.faces[ f ];
+ }
- if ( ! face.__originalFaceNormal ) {
+ function getColorIndex( color ) {
- face.__originalFaceNormal = face.normal.clone();
+ var hash = color.r.toString() + color.g.toString() + color.b.toString();
- } else {
+ if ( colorsHash[ hash ] !== undefined ) {
- face.__originalFaceNormal.copy( face.normal );
+ return colorsHash[ hash ];
}
- if ( ! face.__originalVertexNormals ) face.__originalVertexNormals = [];
+ colorsHash[ hash ] = colors.length;
+ colors.push( color.getHex() );
- for ( i = 0, il = face.vertexNormals.length; i < il; i ++ ) {
+ return colorsHash[ hash ];
- if ( ! face.__originalVertexNormals[ i ] ) {
+ }
- face.__originalVertexNormals[ i ] = face.vertexNormals[ i ].clone();
+ function getUvIndex( uv ) {
- } else {
+ var hash = uv.x.toString() + uv.y.toString();
- face.__originalVertexNormals[ i ].copy( face.vertexNormals[ i ] );
+ if ( uvsHash[ hash ] !== undefined ) {
- }
+ return uvsHash[ hash ];
}
- }
-
- // use temp geometry to compute face and vertex normals for each morph
-
- var tmpGeo = new THREE.Geometry();
- tmpGeo.faces = this.faces;
+ uvsHash[ hash ] = uvs.length / 2;
+ uvs.push( uv.x, uv.y );
- for ( i = 0, il = this.morphTargets.length; i < il; i ++ ) {
-
- // create on first access
+ return uvsHash[ hash ];
- if ( ! this.morphNormals[ i ] ) {
+ }
- this.morphNormals[ i ] = {};
- this.morphNormals[ i ].faceNormals = [];
- this.morphNormals[ i ].vertexNormals = [];
+ output.data = {};
- var dstNormalsFace = this.morphNormals[ i ].faceNormals;
- var dstNormalsVertex = this.morphNormals[ i ].vertexNormals;
+ output.data.vertices = vertices;
+ output.data.normals = normals;
+ if ( colors.length > 0 ) output.data.colors = colors;
+ if ( uvs.length > 0 ) output.data.uvs = [ uvs ]; // temporal backward compatibility
+ output.data.faces = faces;
- var faceNormal, vertexNormals;
+ //
- for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
+ return output;
- faceNormal = new THREE.Vector3();
- vertexNormals = { a: new THREE.Vector3(), b: new THREE.Vector3(), c: new THREE.Vector3() };
+ },
- dstNormalsFace.push( faceNormal );
- dstNormalsVertex.push( vertexNormals );
+ clone: function () {
- }
+ var geometry = new THREE.Geometry();
- }
+ var vertices = this.vertices;
- var morphNormals = this.morphNormals[ i ];
+ for ( var i = 0, il = vertices.length; i < il; i ++ ) {
- // set vertices to morph target
+ geometry.vertices.push( vertices[ i ].clone() );
- tmpGeo.vertices = this.morphTargets[ i ].vertices;
+ }
- // compute morph normals
+ var faces = this.faces;
- tmpGeo.computeFaceNormals();
- tmpGeo.computeVertexNormals();
+ for ( var i = 0, il = faces.length; i < il; i ++ ) {
- // store morph normals
+ geometry.faces.push( faces[ i ].clone() );
- var faceNormal, vertexNormals;
+ }
- for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
+ var uvs = this.faceVertexUvs[ 0 ];
- face = this.faces[ f ];
+ for ( var i = 0, il = uvs.length; i < il; i ++ ) {
- faceNormal = morphNormals.faceNormals[ f ];
- vertexNormals = morphNormals.vertexNormals[ f ];
+ var uv = uvs[ i ], uvCopy = [];
- faceNormal.copy( face.normal );
+ for ( var j = 0, jl = uv.length; j < jl; j ++ ) {
- vertexNormals.a.copy( face.vertexNormals[ 0 ] );
- vertexNormals.b.copy( face.vertexNormals[ 1 ] );
- vertexNormals.c.copy( face.vertexNormals[ 2 ] );
+ uvCopy.push( new THREE.Vector2( uv[ j ].x, uv[ j ].y ) );
}
+ geometry.faceVertexUvs[ 0 ].push( uvCopy );
+
}
- // restore original normals
+ return geometry;
- for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
+ },
- face = this.faces[ f ];
+ dispose: function () {
- face.normal = face.__originalFaceNormal;
- face.vertexNormals = face.__originalVertexNormals;
+ this.dispatchEvent( { type: 'dispose' } );
- }
+ }
- },
+};
- computeTangents: function () {
+THREE.EventDispatcher.prototype.apply( THREE.Geometry.prototype );
- // based on http://www.terathon.com/code/tangent.html
- // tangents go to vertices
+THREE.GeometryIdCount = 0;
- var f, fl, v, vl, i, il, vertexIndex,
- face, uv, vA, vB, vC, uvA, uvB, uvC,
- x1, x2, y1, y2, z1, z2,
- s1, s2, t1, t2, r, t, test,
- tan1 = [], tan2 = [],
- sdir = new THREE.Vector3(), tdir = new THREE.Vector3(),
- tmp = new THREE.Vector3(), tmp2 = new THREE.Vector3(),
- n = new THREE.Vector3(), w;
+// File:src/cameras/Camera.js
- for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) {
+/**
+ * @author mrdoob / http://mrdoob.com/
+ * @author mikael emtinger / http://gomo.se/
+ * @author WestLangley / http://github.com/WestLangley
+*/
- tan1[ v ] = new THREE.Vector3();
- tan2[ v ] = new THREE.Vector3();
+THREE.Camera = function () {
- }
+ THREE.Object3D.call( this );
- function handleTriangle( context, a, b, c, ua, ub, uc ) {
+ this.type = 'Camera';
- vA = context.vertices[ a ];
- vB = context.vertices[ b ];
- vC = context.vertices[ c ];
+ this.matrixWorldInverse = new THREE.Matrix4();
+ this.projectionMatrix = new THREE.Matrix4();
- uvA = uv[ ua ];
- uvB = uv[ ub ];
- uvC = uv[ uc ];
+};
- x1 = vB.x - vA.x;
- x2 = vC.x - vA.x;
- y1 = vB.y - vA.y;
- y2 = vC.y - vA.y;
- z1 = vB.z - vA.z;
- z2 = vC.z - vA.z;
+THREE.Camera.prototype = Object.create( THREE.Object3D.prototype );
- s1 = uvB.x - uvA.x;
- s2 = uvC.x - uvA.x;
- t1 = uvB.y - uvA.y;
- t2 = uvC.y - uvA.y;
+THREE.Camera.prototype.getWorldDirection = function () {
- r = 1.0 / ( s1 * t2 - s2 * t1 );
- sdir.set( ( t2 * x1 - t1 * x2 ) * r,
- ( t2 * y1 - t1 * y2 ) * r,
- ( t2 * z1 - t1 * z2 ) * r );
- tdir.set( ( s1 * x2 - s2 * x1 ) * r,
- ( s1 * y2 - s2 * y1 ) * r,
- ( s1 * z2 - s2 * z1 ) * r );
+ var quaternion = new THREE.Quaternion();
- tan1[ a ].add( sdir );
- tan1[ b ].add( sdir );
- tan1[ c ].add( sdir );
+ return function ( optionalTarget ) {
- tan2[ a ].add( tdir );
- tan2[ b ].add( tdir );
- tan2[ c ].add( tdir );
+ var result = optionalTarget || new THREE.Vector3();
- }
+ this.getWorldQuaternion( quaternion );
- for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
+ return result.set( 0, 0, - 1 ).applyQuaternion( quaternion );
- face = this.faces[ f ];
- uv = this.faceVertexUvs[ 0 ][ f ]; // use UV layer 0 for tangents
+ }
- handleTriangle( this, face.a, face.b, face.c, 0, 1, 2 );
+}();
- }
+THREE.Camera.prototype.lookAt = function () {
- var faceIndex = [ 'a', 'b', 'c', 'd' ];
+ // This routine does not support cameras with rotated and/or translated parent(s)
- for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
+ var m1 = new THREE.Matrix4();
- face = this.faces[ f ];
+ return function ( vector ) {
- for ( i = 0; i < Math.min( face.vertexNormals.length, 3 ); i ++ ) {
+ m1.lookAt( this.position, vector, this.up );
- n.copy( face.vertexNormals[ i ] );
+ this.quaternion.setFromRotationMatrix( m1 );
- vertexIndex = face[ faceIndex[ i ] ];
+ };
- t = tan1[ vertexIndex ];
+}();
- // Gram-Schmidt orthogonalize
+THREE.Camera.prototype.clone = function ( camera ) {
- tmp.copy( t );
- tmp.sub( n.multiplyScalar( n.dot( t ) ) ).normalize();
+ if ( camera === undefined ) camera = new THREE.Camera();
- // Calculate handedness
+ THREE.Object3D.prototype.clone.call( this, camera );
- tmp2.crossVectors( face.vertexNormals[ i ], t );
- test = tmp2.dot( tan2[ vertexIndex ] );
- w = ( test < 0.0 ) ? - 1.0 : 1.0;
+ camera.matrixWorldInverse.copy( this.matrixWorldInverse );
+ camera.projectionMatrix.copy( this.projectionMatrix );
- face.vertexTangents[ i ] = new THREE.Vector4( tmp.x, tmp.y, tmp.z, w );
+ return camera;
+};
- }
+// File:src/cameras/CubeCamera.js
- }
+/**
+ * Camera for rendering cube maps
+ * - renders scene into axis-aligned cube
+ *
+ * @author alteredq / http://alteredqualia.com/
+ */
- this.hasTangents = true;
+THREE.CubeCamera = function ( near, far, cubeResolution ) {
- },
+ THREE.Object3D.call( this );
- computeLineDistances: function () {
+ this.type = 'CubeCamera';
- var d = 0;
- var vertices = this.vertices;
+ var fov = 90, aspect = 1;
- for ( var i = 0, il = vertices.length; i < il; i ++ ) {
+ var cameraPX = new THREE.PerspectiveCamera( fov, aspect, near, far );
+ cameraPX.up.set( 0, - 1, 0 );
+ cameraPX.lookAt( new THREE.Vector3( 1, 0, 0 ) );
+ this.add( cameraPX );
- if ( i > 0 ) {
+ var cameraNX = new THREE.PerspectiveCamera( fov, aspect, near, far );
+ cameraNX.up.set( 0, - 1, 0 );
+ cameraNX.lookAt( new THREE.Vector3( - 1, 0, 0 ) );
+ this.add( cameraNX );
- d += vertices[ i ].distanceTo( vertices[ i - 1 ] );
+ var cameraPY = new THREE.PerspectiveCamera( fov, aspect, near, far );
+ cameraPY.up.set( 0, 0, 1 );
+ cameraPY.lookAt( new THREE.Vector3( 0, 1, 0 ) );
+ this.add( cameraPY );
- }
+ var cameraNY = new THREE.PerspectiveCamera( fov, aspect, near, far );
+ cameraNY.up.set( 0, 0, - 1 );
+ cameraNY.lookAt( new THREE.Vector3( 0, - 1, 0 ) );
+ this.add( cameraNY );
- this.lineDistances[ i ] = d;
+ var cameraPZ = new THREE.PerspectiveCamera( fov, aspect, near, far );
+ cameraPZ.up.set( 0, - 1, 0 );
+ cameraPZ.lookAt( new THREE.Vector3( 0, 0, 1 ) );
+ this.add( cameraPZ );
- }
+ var cameraNZ = new THREE.PerspectiveCamera( fov, aspect, near, far );
+ cameraNZ.up.set( 0, - 1, 0 );
+ cameraNZ.lookAt( new THREE.Vector3( 0, 0, - 1 ) );
+ this.add( cameraNZ );
- },
+ this.renderTarget = new THREE.WebGLRenderTargetCube( cubeResolution, cubeResolution, { format: THREE.RGBFormat, magFilter: THREE.LinearFilter, minFilter: THREE.LinearFilter } );
- computeBoundingBox: function () {
+ this.updateCubeMap = function ( renderer, scene ) {
- if ( this.boundingBox === null ) {
+ var renderTarget = this.renderTarget;
+ var generateMipmaps = renderTarget.generateMipmaps;
- this.boundingBox = new THREE.Box3();
+ renderTarget.generateMipmaps = false;
- }
+ renderTarget.activeCubeFace = 0;
+ renderer.render( scene, cameraPX, renderTarget );
- this.boundingBox.setFromPoints( this.vertices );
+ renderTarget.activeCubeFace = 1;
+ renderer.render( scene, cameraNX, renderTarget );
- },
+ renderTarget.activeCubeFace = 2;
+ renderer.render( scene, cameraPY, renderTarget );
- computeBoundingSphere: function () {
+ renderTarget.activeCubeFace = 3;
+ renderer.render( scene, cameraNY, renderTarget );
- if ( this.boundingSphere === null ) {
+ renderTarget.activeCubeFace = 4;
+ renderer.render( scene, cameraPZ, renderTarget );
- this.boundingSphere = new THREE.Sphere();
+ renderTarget.generateMipmaps = generateMipmaps;
- }
+ renderTarget.activeCubeFace = 5;
+ renderer.render( scene, cameraNZ, renderTarget );
- this.boundingSphere.setFromPoints( this.vertices );
+ };
- },
+};
- merge: function ( geometry, matrix, materialIndexOffset ) {
+THREE.CubeCamera.prototype = Object.create( THREE.Object3D.prototype );
- if ( geometry instanceof THREE.Geometry === false ) {
+// File:src/cameras/OrthographicCamera.js
- console.error( 'THREE.Geometry.merge(): geometry not an instance of THREE.Geometry.', geometry );
- return;
+/**
+ * @author alteredq / http://alteredqualia.com/
+ */
- }
+THREE.OrthographicCamera = function ( left, right, top, bottom, near, far ) {
- var normalMatrix,
- vertexOffset = this.vertices.length,
- uvPosition = this.faceVertexUvs[ 0 ].length,
- vertices1 = this.vertices,
- vertices2 = geometry.vertices,
- faces1 = this.faces,
- faces2 = geometry.faces,
- uvs1 = this.faceVertexUvs[ 0 ],
- uvs2 = geometry.faceVertexUvs[ 0 ];
+ THREE.Camera.call( this );
- if ( materialIndexOffset === undefined ) materialIndexOffset = 0;
+ this.type = 'OrthographicCamera';
- if ( matrix !== undefined ) {
+ this.zoom = 1;
- normalMatrix = new THREE.Matrix3().getNormalMatrix( matrix );
+ this.left = left;
+ this.right = right;
+ this.top = top;
+ this.bottom = bottom;
- }
+ this.near = ( near !== undefined ) ? near : 0.1;
+ this.far = ( far !== undefined ) ? far : 2000;
- // vertices
+ this.updateProjectionMatrix();
- for ( var i = 0, il = vertices2.length; i < il; i ++ ) {
+};
- var vertex = vertices2[ i ];
+THREE.OrthographicCamera.prototype = Object.create( THREE.Camera.prototype );
- var vertexCopy = vertex.clone();
+THREE.OrthographicCamera.prototype.updateProjectionMatrix = function () {
- if ( matrix !== undefined ) vertexCopy.applyMatrix4( matrix );
+ var dx = ( this.right - this.left ) / ( 2 * this.zoom );
+ var dy = ( this.top - this.bottom ) / ( 2 * this.zoom );
+ var cx = ( this.right + this.left ) / 2;
+ var cy = ( this.top + this.bottom ) / 2;
- vertices1.push( vertexCopy );
+ this.projectionMatrix.makeOrthographic( cx - dx, cx + dx, cy + dy, cy - dy, this.near, this.far );
- }
+};
- // faces
+THREE.OrthographicCamera.prototype.clone = function () {
- for ( i = 0, il = faces2.length; i < il; i ++ ) {
+ var camera = new THREE.OrthographicCamera();
- var face = faces2[ i ], faceCopy, normal, color,
- faceVertexNormals = face.vertexNormals,
- faceVertexColors = face.vertexColors;
+ THREE.Camera.prototype.clone.call( this, camera );
- faceCopy = new THREE.Face3( face.a + vertexOffset, face.b + vertexOffset, face.c + vertexOffset );
- faceCopy.normal.copy( face.normal );
+ camera.zoom = this.zoom;
- if ( normalMatrix !== undefined ) {
+ camera.left = this.left;
+ camera.right = this.right;
+ camera.top = this.top;
+ camera.bottom = this.bottom;
- faceCopy.normal.applyMatrix3( normalMatrix ).normalize();
+ camera.near = this.near;
+ camera.far = this.far;
- }
+ camera.projectionMatrix.copy( this.projectionMatrix );
- for ( var j = 0, jl = faceVertexNormals.length; j < jl; j ++ ) {
+ return camera;
+};
- normal = faceVertexNormals[ j ].clone();
+// File:src/cameras/PerspectiveCamera.js
- if ( normalMatrix !== undefined ) {
+/**
+ * @author mrdoob / http://mrdoob.com/
+ * @author greggman / http://games.greggman.com/
+ * @author zz85 / http://www.lab4games.net/zz85/blog
+ */
- normal.applyMatrix3( normalMatrix ).normalize();
+THREE.PerspectiveCamera = function ( fov, aspect, near, far ) {
- }
+ THREE.Camera.call( this );
- faceCopy.vertexNormals.push( normal );
+ this.type = 'PerspectiveCamera';
- }
+ this.zoom = 1;
- faceCopy.color.copy( face.color );
+ this.fov = fov !== undefined ? fov : 50;
+ this.aspect = aspect !== undefined ? aspect : 1;
+ this.near = near !== undefined ? near : 0.1;
+ this.far = far !== undefined ? far : 2000;
- for ( var j = 0, jl = faceVertexColors.length; j < jl; j ++ ) {
+ this.updateProjectionMatrix();
- color = faceVertexColors[ j ];
- faceCopy.vertexColors.push( color.clone() );
+};
- }
+THREE.PerspectiveCamera.prototype = Object.create( THREE.Camera.prototype );
- faceCopy.materialIndex = face.materialIndex + materialIndexOffset;
- faces1.push( faceCopy );
+/**
+ * Uses Focal Length (in mm) to estimate and set FOV
+ * 35mm (fullframe) camera is used if frame size is not specified;
+ * Formula based on http://www.bobatkins.com/photography/technical/field_of_view.html
+ */
- }
+THREE.PerspectiveCamera.prototype.setLens = function ( focalLength, frameHeight ) {
- // uvs
+ if ( frameHeight === undefined ) frameHeight = 24;
- for ( i = 0, il = uvs2.length; i < il; i ++ ) {
-
- var uv = uvs2[ i ], uvCopy = [];
+ this.fov = 2 * THREE.Math.radToDeg( Math.atan( frameHeight / ( focalLength * 2 ) ) );
+ this.updateProjectionMatrix();
- if ( uv === undefined ) {
+}
- continue;
- }
+/**
+ * Sets an offset in a larger frustum. This is useful for multi-window or
+ * multi-monitor/multi-machine setups.
+ *
+ * For example, if you have 3x2 monitors and each monitor is 1920x1080 and
+ * the monitors are in grid like this
+ *
+ * +---+---+---+
+ * | A | B | C |
+ * +---+---+---+
+ * | D | E | F |
+ * +---+---+---+
+ *
+ * then for each monitor you would call it like this
+ *
+ * var w = 1920;
+ * var h = 1080;
+ * var fullWidth = w * 3;
+ * var fullHeight = h * 2;
+ *
+ * --A--
+ * camera.setOffset( fullWidth, fullHeight, w * 0, h * 0, w, h );
+ * --B--
+ * camera.setOffset( fullWidth, fullHeight, w * 1, h * 0, w, h );
+ * --C--
+ * camera.setOffset( fullWidth, fullHeight, w * 2, h * 0, w, h );
+ * --D--
+ * camera.setOffset( fullWidth, fullHeight, w * 0, h * 1, w, h );
+ * --E--
+ * camera.setOffset( fullWidth, fullHeight, w * 1, h * 1, w, h );
+ * --F--
+ * camera.setOffset( fullWidth, fullHeight, w * 2, h * 1, w, h );
+ *
+ * Note there is no reason monitors have to be the same size or in a grid.
+ */
- for ( var j = 0, jl = uv.length; j < jl; j ++ ) {
+THREE.PerspectiveCamera.prototype.setViewOffset = function ( fullWidth, fullHeight, x, y, width, height ) {
- uvCopy.push( new THREE.Vector2( uv[ j ].x, uv[ j ].y ) );
+ this.fullWidth = fullWidth;
+ this.fullHeight = fullHeight;
+ this.x = x;
+ this.y = y;
+ this.width = width;
+ this.height = height;
- }
+ this.updateProjectionMatrix();
- uvs1.push( uvCopy );
+};
- }
- },
+THREE.PerspectiveCamera.prototype.updateProjectionMatrix = function () {
- /*
- * Checks for duplicate vertices with hashmap.
- * Duplicated vertices are removed
- * and faces' vertices are updated.
- */
+ var fov = THREE.Math.radToDeg( 2 * Math.atan( Math.tan( THREE.Math.degToRad( this.fov ) * 0.5 ) / this.zoom ) );
- mergeVertices: function () {
+ if ( this.fullWidth ) {
- var verticesMap = {}; // Hashmap for looking up vertice by position coordinates (and making sure they are unique)
- var unique = [], changes = [];
+ var aspect = this.fullWidth / this.fullHeight;
+ var top = Math.tan( THREE.Math.degToRad( fov * 0.5 ) ) * this.near;
+ var bottom = - top;
+ var left = aspect * bottom;
+ var right = aspect * top;
+ var width = Math.abs( right - left );
+ var height = Math.abs( top - bottom );
- var v, key;
- var precisionPoints = 4; // number of decimal points, eg. 4 for epsilon of 0.0001
- var precision = Math.pow( 10, precisionPoints );
- var i,il, face;
- var indices, k, j, jl, u;
+ this.projectionMatrix.makeFrustum(
+ left + this.x * width / this.fullWidth,
+ left + ( this.x + this.width ) * width / this.fullWidth,
+ top - ( this.y + this.height ) * height / this.fullHeight,
+ top - this.y * height / this.fullHeight,
+ this.near,
+ this.far
+ );
- for ( i = 0, il = this.vertices.length; i < il; i ++ ) {
+ } else {
- v = this.vertices[ i ];
- key = Math.round( v.x * precision ) + '_' + Math.round( v.y * precision ) + '_' + Math.round( v.z * precision );
+ this.projectionMatrix.makePerspective( fov, this.aspect, this.near, this.far );
- if ( verticesMap[ key ] === undefined ) {
+ }
- verticesMap[ key ] = i;
- unique.push( this.vertices[ i ] );
- changes[ i ] = unique.length - 1;
+};
- } else {
+THREE.PerspectiveCamera.prototype.clone = function () {
- //console.log('Duplicate vertex found. ', i, ' could be using ', verticesMap[key]);
- changes[ i ] = changes[ verticesMap[ key ] ];
+ var camera = new THREE.PerspectiveCamera();
- }
+ THREE.Camera.prototype.clone.call( this, camera );
- };
+ camera.zoom = this.zoom;
+ camera.fov = this.fov;
+ camera.aspect = this.aspect;
+ camera.near = this.near;
+ camera.far = this.far;
- // if faces are completely degenerate after merging vertices, we
- // have to remove them from the geometry.
- var faceIndicesToRemove = [];
+ camera.projectionMatrix.copy( this.projectionMatrix );
- for ( i = 0, il = this.faces.length; i < il; i ++ ) {
+ return camera;
- face = this.faces[ i ];
+};
- face.a = changes[ face.a ];
- face.b = changes[ face.b ];
- face.c = changes[ face.c ];
+// File:src/lights/Light.js
- indices = [ face.a, face.b, face.c ];
+/**
+ * @author mrdoob / http://mrdoob.com/
+ * @author alteredq / http://alteredqualia.com/
+ */
- var dupIndex = - 1;
+THREE.Light = function ( color ) {
- // if any duplicate vertices are found in a Face3
- // we have to remove the face as nothing can be saved
- for ( var n = 0; n < 3; n ++ ) {
- if ( indices[ n ] == indices[ ( n + 1 ) % 3 ] ) {
+ THREE.Object3D.call( this );
- dupIndex = n;
- faceIndicesToRemove.push( i );
- break;
+ this.type = 'Light';
+
+ this.color = new THREE.Color( color );
- }
- }
+};
- }
+THREE.Light.prototype = Object.create( THREE.Object3D.prototype );
- for ( i = faceIndicesToRemove.length - 1; i >= 0; i -- ) {
- var idx = faceIndicesToRemove[ i ];
+THREE.Light.prototype.clone = function ( light ) {
- this.faces.splice( idx, 1 );
+ if ( light === undefined ) light = new THREE.Light();
- for ( j = 0, jl = this.faceVertexUvs.length; j < jl; j ++ ) {
+ THREE.Object3D.prototype.clone.call( this, light );
- this.faceVertexUvs[ j ].splice( idx, 1 );
+ light.color.copy( this.color );
- }
+ return light;
- }
+};
- // Use unique set of vertices
+// File:src/lights/AmbientLight.js
- var diff = this.vertices.length - unique.length;
- this.vertices = unique;
- return diff;
+/**
+ * @author mrdoob / http://mrdoob.com/
+ */
- },
+THREE.AmbientLight = function ( color ) {
- // Geometry splitting
+ THREE.Light.call( this, color );
- makeGroups: ( function () {
+ this.type = 'AmbientLight';
- var geometryGroupCounter = 0;
+};
- return function ( usesFaceMaterial, maxVerticesInGroup ) {
+THREE.AmbientLight.prototype = Object.create( THREE.Light.prototype );
- var f, fl, face, materialIndex,
- groupHash, hash_map = {},geometryGroup;
+THREE.AmbientLight.prototype.clone = function () {
- var numMorphTargets = this.morphTargets.length;
- var numMorphNormals = this.morphNormals.length;
+ var light = new THREE.AmbientLight();
- this.geometryGroups = {};
- this.geometryGroupsList = [];
+ THREE.Light.prototype.clone.call( this, light );
- for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
+ return light;
- face = this.faces[ f ];
- materialIndex = usesFaceMaterial ? face.materialIndex : 0;
+};
- if ( ! ( materialIndex in hash_map ) ) {
+// File:src/lights/AreaLight.js
- hash_map[ materialIndex ] = { 'hash': materialIndex, 'counter': 0 };
+/**
+ * @author MPanknin / http://www.redplant.de/
+ * @author alteredq / http://alteredqualia.com/
+ */
- }
+THREE.AreaLight = function ( color, intensity ) {
- groupHash = hash_map[ materialIndex ].hash + '_' + hash_map[ materialIndex ].counter;
+ THREE.Light.call( this, color );
- if ( ! ( groupHash in this.geometryGroups ) ) {
+ this.type = 'AreaLight';
- geometryGroup = { 'id': geometryGroupCounter++, 'faces3': [], 'materialIndex': materialIndex, 'vertices': 0, 'numMorphTargets': numMorphTargets, 'numMorphNormals': numMorphNormals };
- this.geometryGroups[ groupHash ] = geometryGroup;
- this.geometryGroupsList.push(geometryGroup);
- }
+ this.normal = new THREE.Vector3( 0, - 1, 0 );
+ this.right = new THREE.Vector3( 1, 0, 0 );
- if ( this.geometryGroups[ groupHash ].vertices + 3 > maxVerticesInGroup ) {
+ this.intensity = ( intensity !== undefined ) ? intensity : 1;
- hash_map[ materialIndex ].counter += 1;
- groupHash = hash_map[ materialIndex ].hash + '_' + hash_map[ materialIndex ].counter;
+ this.width = 1.0;
+ this.height = 1.0;
- if ( ! ( groupHash in this.geometryGroups ) ) {
+ this.constantAttenuation = 1.5;
+ this.linearAttenuation = 0.5;
+ this.quadraticAttenuation = 0.1;
- geometryGroup = { 'id': geometryGroupCounter++, 'faces3': [], 'materialIndex': materialIndex, 'vertices': 0, 'numMorphTargets': numMorphTargets, 'numMorphNormals': numMorphNormals };
- this.geometryGroups[ groupHash ] = geometryGroup;
- this.geometryGroupsList.push(geometryGroup);
-
- }
+};
- }
+THREE.AreaLight.prototype = Object.create( THREE.Light.prototype );
- this.geometryGroups[ groupHash ].faces3.push( f );
- this.geometryGroups[ groupHash ].vertices += 3;
- }
+// File:src/lights/DirectionalLight.js
- };
+/**
+ * @author mrdoob / http://mrdoob.com/
+ * @author alteredq / http://alteredqualia.com/
+ */
- } )(),
+THREE.DirectionalLight = function ( color, intensity ) {
- clone: function () {
+ THREE.Light.call( this, color );
- var geometry = new THREE.Geometry();
+ this.type = 'DirectionalLight';
- var vertices = this.vertices;
+ this.position.set( 0, 1, 0 );
+ this.target = new THREE.Object3D();
- for ( var i = 0, il = vertices.length; i < il; i ++ ) {
+ this.intensity = ( intensity !== undefined ) ? intensity : 1;
- geometry.vertices.push( vertices[ i ].clone() );
+ this.castShadow = false;
+ this.onlyShadow = false;
- }
+ //
- var faces = this.faces;
+ this.shadowCameraNear = 50;
+ this.shadowCameraFar = 5000;
- for ( var i = 0, il = faces.length; i < il; i ++ ) {
+ this.shadowCameraLeft = - 500;
+ this.shadowCameraRight = 500;
+ this.shadowCameraTop = 500;
+ this.shadowCameraBottom = - 500;
- geometry.faces.push( faces[ i ].clone() );
+ this.shadowCameraVisible = false;
- }
+ this.shadowBias = 0;
+ this.shadowDarkness = 0.5;
- var uvs = this.faceVertexUvs[ 0 ];
+ this.shadowMapWidth = 512;
+ this.shadowMapHeight = 512;
- for ( var i = 0, il = uvs.length; i < il; i ++ ) {
+ //
- var uv = uvs[ i ], uvCopy = [];
+ this.shadowCascade = false;
- for ( var j = 0, jl = uv.length; j < jl; j ++ ) {
+ this.shadowCascadeOffset = new THREE.Vector3( 0, 0, - 1000 );
+ this.shadowCascadeCount = 2;
- uvCopy.push( new THREE.Vector2( uv[ j ].x, uv[ j ].y ) );
+ this.shadowCascadeBias = [ 0, 0, 0 ];
+ this.shadowCascadeWidth = [ 512, 512, 512 ];
+ this.shadowCascadeHeight = [ 512, 512, 512 ];
- }
+ this.shadowCascadeNearZ = [ - 1.000, 0.990, 0.998 ];
+ this.shadowCascadeFarZ = [ 0.990, 0.998, 1.000 ];
- geometry.faceVertexUvs[ 0 ].push( uvCopy );
+ this.shadowCascadeArray = [];
- }
+ //
- return geometry;
+ this.shadowMap = null;
+ this.shadowMapSize = null;
+ this.shadowCamera = null;
+ this.shadowMatrix = null;
- },
+};
- dispose: function () {
+THREE.DirectionalLight.prototype = Object.create( THREE.Light.prototype );
- this.dispatchEvent( { type: 'dispose' } );
+THREE.DirectionalLight.prototype.clone = function () {
- }
+ var light = new THREE.DirectionalLight();
-};
+ THREE.Light.prototype.clone.call( this, light );
-THREE.EventDispatcher.prototype.apply( THREE.Geometry.prototype );
+ light.target = this.target.clone();
-THREE.GeometryIdCount = 0;
+ light.intensity = this.intensity;
-// File:src/cameras/Camera.js
+ light.castShadow = this.castShadow;
+ light.onlyShadow = this.onlyShadow;
-/**
- * @author mrdoob / http://mrdoob.com/
- * @author mikael emtinger / http://gomo.se/
- * @author WestLangley / http://github.com/WestLangley
-*/
+ //
-THREE.Camera = function () {
+ light.shadowCameraNear = this.shadowCameraNear;
+ light.shadowCameraFar = this.shadowCameraFar;
- THREE.Object3D.call( this );
+ light.shadowCameraLeft = this.shadowCameraLeft;
+ light.shadowCameraRight = this.shadowCameraRight;
+ light.shadowCameraTop = this.shadowCameraTop;
+ light.shadowCameraBottom = this.shadowCameraBottom;
- this.matrixWorldInverse = new THREE.Matrix4();
- this.projectionMatrix = new THREE.Matrix4();
+ light.shadowCameraVisible = this.shadowCameraVisible;
+
+ light.shadowBias = this.shadowBias;
+ light.shadowDarkness = this.shadowDarkness;
+
+ light.shadowMapWidth = this.shadowMapWidth;
+ light.shadowMapHeight = this.shadowMapHeight;
+
+ //
+
+ light.shadowCascade = this.shadowCascade;
+
+ light.shadowCascadeOffset.copy( this.shadowCascadeOffset );
+ light.shadowCascadeCount = this.shadowCascadeCount;
+
+ light.shadowCascadeBias = this.shadowCascadeBias.slice( 0 );
+ light.shadowCascadeWidth = this.shadowCascadeWidth.slice( 0 );
+ light.shadowCascadeHeight = this.shadowCascadeHeight.slice( 0 );
+
+ light.shadowCascadeNearZ = this.shadowCascadeNearZ.slice( 0 );
+ light.shadowCascadeFarZ = this.shadowCascadeFarZ.slice( 0 );
+
+ return light;
};
-THREE.Camera.prototype = Object.create( THREE.Object3D.prototype );
+// File:src/lights/HemisphereLight.js
-THREE.Camera.prototype.lookAt = function () {
+/**
+ * @author alteredq / http://alteredqualia.com/
+ */
- // This routine does not support cameras with rotated and/or translated parent(s)
+THREE.HemisphereLight = function ( skyColor, groundColor, intensity ) {
- var m1 = new THREE.Matrix4();
+ THREE.Light.call( this, skyColor );
- return function ( vector ) {
+ this.type = 'HemisphereLight';
- m1.lookAt( this.position, vector, this.up );
+ this.position.set( 0, 100, 0 );
- this.quaternion.setFromRotationMatrix( m1 );
+ this.groundColor = new THREE.Color( groundColor );
+ this.intensity = ( intensity !== undefined ) ? intensity : 1;
- };
+};
-}();
+THREE.HemisphereLight.prototype = Object.create( THREE.Light.prototype );
-THREE.Camera.prototype.clone = function ( camera ) {
+THREE.HemisphereLight.prototype.clone = function () {
- if ( camera === undefined ) camera = new THREE.Camera();
+ var light = new THREE.HemisphereLight();
- THREE.Object3D.prototype.clone.call( this, camera );
+ THREE.Light.prototype.clone.call( this, light );
- camera.matrixWorldInverse.copy( this.matrixWorldInverse );
- camera.projectionMatrix.copy( this.projectionMatrix );
+ light.groundColor.copy( this.groundColor );
+ light.intensity = this.intensity;
+
+ return light;
- return camera;
};
-// File:src/cameras/CubeCamera.js
+// File:src/lights/PointLight.js
/**
- * Camera for rendering cube maps
- * - renders scene into axis-aligned cube
- *
- * @author alteredq / http://alteredqualia.com/
+ * @author mrdoob / http://mrdoob.com/
*/
-THREE.CubeCamera = function ( near, far, cubeResolution ) {
+THREE.PointLight = function ( color, intensity, distance ) {
- THREE.Object3D.call( this );
+ THREE.Light.call( this, color );
- var fov = 90, aspect = 1;
+ this.type = 'PointLight';
- var cameraPX = new THREE.PerspectiveCamera( fov, aspect, near, far );
- cameraPX.up.set( 0, - 1, 0 );
- cameraPX.lookAt( new THREE.Vector3( 1, 0, 0 ) );
- this.add( cameraPX );
+ this.intensity = ( intensity !== undefined ) ? intensity : 1;
+ this.distance = ( distance !== undefined ) ? distance : 0;
- var cameraNX = new THREE.PerspectiveCamera( fov, aspect, near, far );
- cameraNX.up.set( 0, - 1, 0 );
- cameraNX.lookAt( new THREE.Vector3( - 1, 0, 0 ) );
- this.add( cameraNX );
+};
- var cameraPY = new THREE.PerspectiveCamera( fov, aspect, near, far );
- cameraPY.up.set( 0, 0, 1 );
- cameraPY.lookAt( new THREE.Vector3( 0, 1, 0 ) );
- this.add( cameraPY );
+THREE.PointLight.prototype = Object.create( THREE.Light.prototype );
- var cameraNY = new THREE.PerspectiveCamera( fov, aspect, near, far );
- cameraNY.up.set( 0, 0, - 1 );
- cameraNY.lookAt( new THREE.Vector3( 0, - 1, 0 ) );
- this.add( cameraNY );
+THREE.PointLight.prototype.clone = function () {
- var cameraPZ = new THREE.PerspectiveCamera( fov, aspect, near, far );
- cameraPZ.up.set( 0, - 1, 0 );
- cameraPZ.lookAt( new THREE.Vector3( 0, 0, 1 ) );
- this.add( cameraPZ );
+ var light = new THREE.PointLight();
- var cameraNZ = new THREE.PerspectiveCamera( fov, aspect, near, far );
- cameraNZ.up.set( 0, - 1, 0 );
- cameraNZ.lookAt( new THREE.Vector3( 0, 0, - 1 ) );
- this.add( cameraNZ );
+ THREE.Light.prototype.clone.call( this, light );
- this.renderTarget = new THREE.WebGLRenderTargetCube( cubeResolution, cubeResolution, { format: THREE.RGBFormat, magFilter: THREE.LinearFilter, minFilter: THREE.LinearFilter } );
+ light.intensity = this.intensity;
+ light.distance = this.distance;
- this.updateCubeMap = function ( renderer, scene ) {
+ return light;
- var renderTarget = this.renderTarget;
- var generateMipmaps = renderTarget.generateMipmaps;
+};
- renderTarget.generateMipmaps = false;
+// File:src/lights/SpotLight.js
- renderTarget.activeCubeFace = 0;
- renderer.render( scene, cameraPX, renderTarget );
+/**
+ * @author alteredq / http://alteredqualia.com/
+ */
- renderTarget.activeCubeFace = 1;
- renderer.render( scene, cameraNX, renderTarget );
+THREE.SpotLight = function ( color, intensity, distance, angle, exponent ) {
- renderTarget.activeCubeFace = 2;
- renderer.render( scene, cameraPY, renderTarget );
+ THREE.Light.call( this, color );
- renderTarget.activeCubeFace = 3;
- renderer.render( scene, cameraNY, renderTarget );
+ this.type = 'SpotLight';
- renderTarget.activeCubeFace = 4;
- renderer.render( scene, cameraPZ, renderTarget );
+ this.position.set( 0, 1, 0 );
+ this.target = new THREE.Object3D();
- renderTarget.generateMipmaps = generateMipmaps;
+ this.intensity = ( intensity !== undefined ) ? intensity : 1;
+ this.distance = ( distance !== undefined ) ? distance : 0;
+ this.angle = ( angle !== undefined ) ? angle : Math.PI / 3;
+ this.exponent = ( exponent !== undefined ) ? exponent : 10;
- renderTarget.activeCubeFace = 5;
- renderer.render( scene, cameraNZ, renderTarget );
+ this.castShadow = false;
+ this.onlyShadow = false;
- };
+ //
-};
+ this.shadowCameraNear = 50;
+ this.shadowCameraFar = 5000;
+ this.shadowCameraFov = 50;
-THREE.CubeCamera.prototype = Object.create( THREE.Object3D.prototype );
+ this.shadowCameraVisible = false;
-// File:src/cameras/OrthographicCamera.js
+ this.shadowBias = 0;
+ this.shadowDarkness = 0.5;
-/**
- * @author alteredq / http://alteredqualia.com/
- */
+ this.shadowMapWidth = 512;
+ this.shadowMapHeight = 512;
-THREE.OrthographicCamera = function ( left, right, top, bottom, near, far ) {
+ //
- THREE.Camera.call( this );
+ this.shadowMap = null;
+ this.shadowMapSize = null;
+ this.shadowCamera = null;
+ this.shadowMatrix = null;
- this.left = left;
- this.right = right;
- this.top = top;
- this.bottom = bottom;
+};
- this.near = ( near !== undefined ) ? near : 0.1;
- this.far = ( far !== undefined ) ? far : 2000;
+THREE.SpotLight.prototype = Object.create( THREE.Light.prototype );
- this.updateProjectionMatrix();
+THREE.SpotLight.prototype.clone = function () {
-};
+ var light = new THREE.SpotLight();
-THREE.OrthographicCamera.prototype = Object.create( THREE.Camera.prototype );
+ THREE.Light.prototype.clone.call( this, light );
-THREE.OrthographicCamera.prototype.updateProjectionMatrix = function () {
+ light.target = this.target.clone();
- this.projectionMatrix.makeOrthographic( this.left, this.right, this.top, this.bottom, this.near, this.far );
+ light.intensity = this.intensity;
+ light.distance = this.distance;
+ light.angle = this.angle;
+ light.exponent = this.exponent;
-};
+ light.castShadow = this.castShadow;
+ light.onlyShadow = this.onlyShadow;
-THREE.OrthographicCamera.prototype.clone = function () {
+ //
- var camera = new THREE.OrthographicCamera();
+ light.shadowCameraNear = this.shadowCameraNear;
+ light.shadowCameraFar = this.shadowCameraFar;
+ light.shadowCameraFov = this.shadowCameraFov;
- THREE.Camera.prototype.clone.call( this, camera );
+ light.shadowCameraVisible = this.shadowCameraVisible;
- camera.left = this.left;
- camera.right = this.right;
- camera.top = this.top;
- camera.bottom = this.bottom;
+ light.shadowBias = this.shadowBias;
+ light.shadowDarkness = this.shadowDarkness;
- camera.near = this.near;
- camera.far = this.far;
+ light.shadowMapWidth = this.shadowMapWidth;
+ light.shadowMapHeight = this.shadowMapHeight;
+
+ return light;
- return camera;
};
-// File:src/cameras/PerspectiveCamera.js
+// File:src/loaders/Cache.js
/**
* @author mrdoob / http://mrdoob.com/
- * @author greggman / http://games.greggman.com/
- * @author zz85 / http://www.lab4games.net/zz85/blog
*/
-THREE.PerspectiveCamera = function ( fov, aspect, near, far ) {
+THREE.Cache = function () {
- THREE.Camera.call( this );
+ this.files = {};
- this.fov = fov !== undefined ? fov : 50;
- this.aspect = aspect !== undefined ? aspect : 1;
- this.near = near !== undefined ? near : 0.1;
- this.far = far !== undefined ? far : 2000;
+};
- this.updateProjectionMatrix();
+THREE.Cache.prototype = {
-};
+ constructor: THREE.Cache,
-THREE.PerspectiveCamera.prototype = Object.create( THREE.Camera.prototype );
+ add: function ( key, file ) {
+ // console.log( 'THREE.Cache', 'Adding key:', key );
-/**
- * Uses Focal Length (in mm) to estimate and set FOV
- * 35mm (fullframe) camera is used if frame size is not specified;
- * Formula based on http://www.bobatkins.com/photography/technical/field_of_view.html
- */
+ this.files[ key ] = file;
-THREE.PerspectiveCamera.prototype.setLens = function ( focalLength, frameHeight ) {
+ },
- if ( frameHeight === undefined ) frameHeight = 24;
+ get: function ( key ) {
- this.fov = 2 * THREE.Math.radToDeg( Math.atan( frameHeight / ( focalLength * 2 ) ) );
- this.updateProjectionMatrix();
+ // console.log( 'THREE.Cache', 'Checking key:', key );
-}
+ return this.files[ key ];
+ },
-/**
- * Sets an offset in a larger frustum. This is useful for multi-window or
- * multi-monitor/multi-machine setups.
- *
- * For example, if you have 3x2 monitors and each monitor is 1920x1080 and
- * the monitors are in grid like this
- *
- * +---+---+---+
- * | A | B | C |
- * +---+---+---+
- * | D | E | F |
- * +---+---+---+
- *
- * then for each monitor you would call it like this
- *
- * var w = 1920;
- * var h = 1080;
- * var fullWidth = w * 3;
- * var fullHeight = h * 2;
- *
- * --A--
- * camera.setOffset( fullWidth, fullHeight, w * 0, h * 0, w, h );
- * --B--
- * camera.setOffset( fullWidth, fullHeight, w * 1, h * 0, w, h );
- * --C--
- * camera.setOffset( fullWidth, fullHeight, w * 2, h * 0, w, h );
- * --D--
- * camera.setOffset( fullWidth, fullHeight, w * 0, h * 1, w, h );
- * --E--
- * camera.setOffset( fullWidth, fullHeight, w * 1, h * 1, w, h );
- * --F--
- * camera.setOffset( fullWidth, fullHeight, w * 2, h * 1, w, h );
- *
- * Note there is no reason monitors have to be the same size or in a grid.
- */
+ remove: function ( key ) {
-THREE.PerspectiveCamera.prototype.setViewOffset = function ( fullWidth, fullHeight, x, y, width, height ) {
+ delete this.files[ key ];
- this.fullWidth = fullWidth;
- this.fullHeight = fullHeight;
- this.x = x;
- this.y = y;
- this.width = width;
- this.height = height;
+ },
- this.updateProjectionMatrix();
+ clear: function () {
-};
+ this.files = {}
+ }
-THREE.PerspectiveCamera.prototype.updateProjectionMatrix = function () {
+};
- if ( this.fullWidth ) {
+// File:src/loaders/Loader.js
- var aspect = this.fullWidth / this.fullHeight;
- var top = Math.tan( THREE.Math.degToRad( this.fov * 0.5 ) ) * this.near;
- var bottom = - top;
- var left = aspect * bottom;
- var right = aspect * top;
- var width = Math.abs( right - left );
- var height = Math.abs( top - bottom );
+/**
+ * @author alteredq / http://alteredqualia.com/
+ */
- this.projectionMatrix.makeFrustum(
- left + this.x * width / this.fullWidth,
- left + ( this.x + this.width ) * width / this.fullWidth,
- top - ( this.y + this.height ) * height / this.fullHeight,
- top - this.y * height / this.fullHeight,
- this.near,
- this.far
- );
+THREE.Loader = function ( showStatus ) {
- } else {
+ this.showStatus = showStatus;
+ this.statusDomElement = showStatus ? THREE.Loader.prototype.addStatusElement() : null;
- this.projectionMatrix.makePerspective( this.fov, this.aspect, this.near, this.far );
+ this.imageLoader = new THREE.ImageLoader();
- }
+ this.onLoadStart = function () {};
+ this.onLoadProgress = function () {};
+ this.onLoadComplete = function () {};
};
-THREE.PerspectiveCamera.prototype.clone = function () {
+THREE.Loader.prototype = {
- var camera = new THREE.PerspectiveCamera();
+ constructor: THREE.Loader,
- THREE.Camera.prototype.clone.call( this, camera );
+ crossOrigin: undefined,
- camera.fov = this.fov;
- camera.aspect = this.aspect;
- camera.near = this.near;
- camera.far = this.far;
+ addStatusElement: function () {
- return camera;
-};
+ var e = document.createElement( 'div' );
-// File:src/lights/Light.js
+ e.style.position = 'absolute';
+ e.style.right = '0px';
+ e.style.top = '0px';
+ e.style.fontSize = '0.8em';
+ e.style.textAlign = 'left';
+ e.style.background = 'rgba(0,0,0,0.25)';
+ e.style.color = '#fff';
+ e.style.width = '120px';
+ e.style.padding = '0.5em 0.5em 0.5em 0.5em';
+ e.style.zIndex = 1000;
-/**
- * @author mrdoob / http://mrdoob.com/
- * @author alteredq / http://alteredqualia.com/
- */
+ e.innerHTML = 'Loading ...';
-THREE.Light = function ( color ) {
+ return e;
- THREE.Object3D.call( this );
+ },
- this.color = new THREE.Color( color );
+ updateProgress: function ( progress ) {
-};
+ var message = 'Loaded ';
-THREE.Light.prototype = Object.create( THREE.Object3D.prototype );
+ if ( progress.total ) {
-THREE.Light.prototype.clone = function ( light ) {
+ message += ( 100 * progress.loaded / progress.total ).toFixed( 0 ) + '%';
- if ( light === undefined ) light = new THREE.Light();
- THREE.Object3D.prototype.clone.call( this, light );
+ } else {
- light.color.copy( this.color );
+ message += ( progress.loaded / 1024 ).toFixed( 2 ) + ' KB';
- return light;
+ }
-};
+ this.statusDomElement.innerHTML = message;
-// File:src/lights/AmbientLight.js
+ },
-/**
- * @author mrdoob / http://mrdoob.com/
- */
+ extractUrlBase: function ( url ) {
-THREE.AmbientLight = function ( color ) {
+ var parts = url.split( '/' );
- THREE.Light.call( this, color );
+ if ( parts.length === 1 ) return './';
-};
+ parts.pop();
-THREE.AmbientLight.prototype = Object.create( THREE.Light.prototype );
+ return parts.join( '/' ) + '/';
-THREE.AmbientLight.prototype.clone = function () {
+ },
- var light = new THREE.AmbientLight();
+ initMaterials: function ( materials, texturePath ) {
- THREE.Light.prototype.clone.call( this, light );
+ var array = [];
- return light;
+ for ( var i = 0; i < materials.length; ++ i ) {
-};
+ array[ i ] = this.createMaterial( materials[ i ], texturePath );
-// File:src/lights/AreaLight.js
+ }
-/**
- * @author MPanknin / http://www.redplant.de/
- * @author alteredq / http://alteredqualia.com/
- */
+ return array;
-THREE.AreaLight = function ( color, intensity ) {
+ },
- THREE.Light.call( this, color );
+ needsTangents: function ( materials ) {
- this.normal = new THREE.Vector3( 0, - 1, 0 );
- this.right = new THREE.Vector3( 1, 0, 0 );
+ for ( var i = 0, il = materials.length; i < il; i ++ ) {
- this.intensity = ( intensity !== undefined ) ? intensity : 1;
+ var m = materials[ i ];
- this.width = 1.0;
- this.height = 1.0;
+ if ( m instanceof THREE.ShaderMaterial ) return true;
- this.constantAttenuation = 1.5;
- this.linearAttenuation = 0.5;
- this.quadraticAttenuation = 0.1;
+ }
-};
+ return false;
-THREE.AreaLight.prototype = Object.create( THREE.Light.prototype );
+ },
+ createMaterial: function ( m, texturePath ) {
-// File:src/lights/DirectionalLight.js
+ var scope = this;
-/**
- * @author mrdoob / http://mrdoob.com/
- * @author alteredq / http://alteredqualia.com/
- */
+ function nearest_pow2( n ) {
-THREE.DirectionalLight = function ( color, intensity ) {
+ var l = Math.log( n ) / Math.LN2;
+ return Math.pow( 2, Math.round( l ) );
- THREE.Light.call( this, color );
+ }
- this.position.set( 0, 1, 0 );
- this.target = new THREE.Object3D();
+ function create_texture( where, name, sourceFile, repeat, offset, wrap, anisotropy ) {
- this.intensity = ( intensity !== undefined ) ? intensity : 1;
+ var fullPath = texturePath + sourceFile;
- this.castShadow = false;
- this.onlyShadow = false;
+ var texture;
- //
+ var loader = THREE.Loader.Handlers.get( fullPath );
- this.shadowCameraNear = 50;
- this.shadowCameraFar = 5000;
+ if ( loader !== null ) {
- this.shadowCameraLeft = - 500;
- this.shadowCameraRight = 500;
- this.shadowCameraTop = 500;
- this.shadowCameraBottom = - 500;
+ texture = loader.load( fullPath );
- this.shadowCameraVisible = false;
+ } else {
- this.shadowBias = 0;
- this.shadowDarkness = 0.5;
+ texture = new THREE.Texture();
- this.shadowMapWidth = 512;
- this.shadowMapHeight = 512;
+ loader = scope.imageLoader;
+ loader.crossOrigin = scope.crossOrigin;
+ loader.load( fullPath, function ( image ) {
- //
+ if ( THREE.Math.isPowerOfTwo( image.width ) === false ||
+ THREE.Math.isPowerOfTwo( image.height ) === false ) {
- this.shadowCascade = false;
+ var width = nearest_pow2( image.width );
+ var height = nearest_pow2( image.height );
- this.shadowCascadeOffset = new THREE.Vector3( 0, 0, - 1000 );
- this.shadowCascadeCount = 2;
+ var canvas = document.createElement( 'canvas' );
+ canvas.width = width;
+ canvas.height = height;
- this.shadowCascadeBias = [ 0, 0, 0 ];
- this.shadowCascadeWidth = [ 512, 512, 512 ];
- this.shadowCascadeHeight = [ 512, 512, 512 ];
+ var context = canvas.getContext( '2d' );
+ context.drawImage( image, 0, 0, width, height );
- this.shadowCascadeNearZ = [ - 1.000, 0.990, 0.998 ];
- this.shadowCascadeFarZ = [ 0.990, 0.998, 1.000 ];
+ texture.image = canvas;
- this.shadowCascadeArray = [];
+ } else {
- //
+ texture.image = image;
- this.shadowMap = null;
- this.shadowMapSize = null;
- this.shadowCamera = null;
- this.shadowMatrix = null;
+ }
-};
+ texture.needsUpdate = true;
-THREE.DirectionalLight.prototype = Object.create( THREE.Light.prototype );
+ } );
-THREE.DirectionalLight.prototype.clone = function () {
+ }
- var light = new THREE.DirectionalLight();
+ texture.sourceFile = sourceFile;
- THREE.Light.prototype.clone.call( this, light );
+ if ( repeat ) {
- light.target = this.target.clone();
+ texture.repeat.set( repeat[ 0 ], repeat[ 1 ] );
- light.intensity = this.intensity;
+ if ( repeat[ 0 ] !== 1 ) texture.wrapS = THREE.RepeatWrapping;
+ if ( repeat[ 1 ] !== 1 ) texture.wrapT = THREE.RepeatWrapping;
- light.castShadow = this.castShadow;
- light.onlyShadow = this.onlyShadow;
+ }
- //
+ if ( offset ) {
- light.shadowCameraNear = this.shadowCameraNear;
- light.shadowCameraFar = this.shadowCameraFar;
+ texture.offset.set( offset[ 0 ], offset[ 1 ] );
- light.shadowCameraLeft = this.shadowCameraLeft;
- light.shadowCameraRight = this.shadowCameraRight;
- light.shadowCameraTop = this.shadowCameraTop;
- light.shadowCameraBottom = this.shadowCameraBottom;
+ }
- light.shadowCameraVisible = this.shadowCameraVisible;
+ if ( wrap ) {
- light.shadowBias = this.shadowBias;
- light.shadowDarkness = this.shadowDarkness;
+ var wrapMap = {
+ 'repeat': THREE.RepeatWrapping,
+ 'mirror': THREE.MirroredRepeatWrapping
+ }
- light.shadowMapWidth = this.shadowMapWidth;
- light.shadowMapHeight = this.shadowMapHeight;
+ if ( wrapMap[ wrap[ 0 ] ] !== undefined ) texture.wrapS = wrapMap[ wrap[ 0 ] ];
+ if ( wrapMap[ wrap[ 1 ] ] !== undefined ) texture.wrapT = wrapMap[ wrap[ 1 ] ];
- //
+ }
- light.shadowCascade = this.shadowCascade;
+ if ( anisotropy ) {
- light.shadowCascadeOffset.copy( this.shadowCascadeOffset );
- light.shadowCascadeCount = this.shadowCascadeCount;
+ texture.anisotropy = anisotropy;
- light.shadowCascadeBias = this.shadowCascadeBias.slice( 0 );
- light.shadowCascadeWidth = this.shadowCascadeWidth.slice( 0 );
- light.shadowCascadeHeight = this.shadowCascadeHeight.slice( 0 );
+ }
- light.shadowCascadeNearZ = this.shadowCascadeNearZ.slice( 0 );
- light.shadowCascadeFarZ = this.shadowCascadeFarZ.slice( 0 );
+ where[ name ] = texture;
- return light;
+ }
-};
+ function rgb2hex( rgb ) {
-// File:src/lights/HemisphereLight.js
+ return ( rgb[ 0 ] * 255 << 16 ) + ( rgb[ 1 ] * 255 << 8 ) + rgb[ 2 ] * 255;
-/**
- * @author alteredq / http://alteredqualia.com/
- */
+ }
-THREE.HemisphereLight = function ( skyColor, groundColor, intensity ) {
+ // defaults
- THREE.Light.call( this, skyColor );
+ var mtype = 'MeshLambertMaterial';
+ var mpars = { color: 0xeeeeee, opacity: 1.0, map: null, lightMap: null, normalMap: null, bumpMap: null, wireframe: false };
- this.position.set( 0, 100, 0 );
+ // parameters from model file
- this.groundColor = new THREE.Color( groundColor );
- this.intensity = ( intensity !== undefined ) ? intensity : 1;
+ if ( m.shading ) {
-};
+ var shading = m.shading.toLowerCase();
-THREE.HemisphereLight.prototype = Object.create( THREE.Light.prototype );
+ if ( shading === 'phong' ) mtype = 'MeshPhongMaterial';
+ else if ( shading === 'basic' ) mtype = 'MeshBasicMaterial';
-THREE.HemisphereLight.prototype.clone = function () {
+ }
- var light = new THREE.HemisphereLight();
+ if ( m.blending !== undefined && THREE[ m.blending ] !== undefined ) {
- THREE.Light.prototype.clone.call( this, light );
+ mpars.blending = THREE[ m.blending ];
- light.groundColor.copy( this.groundColor );
- light.intensity = this.intensity;
+ }
- return light;
+ if ( m.transparent !== undefined || m.opacity < 1.0 ) {
-};
+ mpars.transparent = m.transparent;
-// File:src/lights/PointLight.js
+ }
-/**
- * @author mrdoob / http://mrdoob.com/
- */
+ if ( m.depthTest !== undefined ) {
-THREE.PointLight = function ( color, intensity, distance ) {
+ mpars.depthTest = m.depthTest;
- THREE.Light.call( this, color );
+ }
- this.intensity = ( intensity !== undefined ) ? intensity : 1;
- this.distance = ( distance !== undefined ) ? distance : 0;
+ if ( m.depthWrite !== undefined ) {
-};
+ mpars.depthWrite = m.depthWrite;
-THREE.PointLight.prototype = Object.create( THREE.Light.prototype );
+ }
-THREE.PointLight.prototype.clone = function () {
+ if ( m.visible !== undefined ) {
- var light = new THREE.PointLight();
+ mpars.visible = m.visible;
- THREE.Light.prototype.clone.call( this, light );
+ }
- light.intensity = this.intensity;
- light.distance = this.distance;
+ if ( m.flipSided !== undefined ) {
- return light;
+ mpars.side = THREE.BackSide;
-};
+ }
-// File:src/lights/SpotLight.js
+ if ( m.doubleSided !== undefined ) {
-/**
- * @author alteredq / http://alteredqualia.com/
- */
+ mpars.side = THREE.DoubleSide;
-THREE.SpotLight = function ( color, intensity, distance, angle, exponent ) {
+ }
- THREE.Light.call( this, color );
+ if ( m.wireframe !== undefined ) {
- this.position.set( 0, 1, 0 );
- this.target = new THREE.Object3D();
+ mpars.wireframe = m.wireframe;
- this.intensity = ( intensity !== undefined ) ? intensity : 1;
- this.distance = ( distance !== undefined ) ? distance : 0;
- this.angle = ( angle !== undefined ) ? angle : Math.PI / 3;
- this.exponent = ( exponent !== undefined ) ? exponent : 10;
+ }
- this.castShadow = false;
- this.onlyShadow = false;
+ if ( m.vertexColors !== undefined ) {
- //
+ if ( m.vertexColors === 'face' ) {
- this.shadowCameraNear = 50;
- this.shadowCameraFar = 5000;
- this.shadowCameraFov = 50;
+ mpars.vertexColors = THREE.FaceColors;
- this.shadowCameraVisible = false;
+ } else if ( m.vertexColors ) {
- this.shadowBias = 0;
- this.shadowDarkness = 0.5;
+ mpars.vertexColors = THREE.VertexColors;
- this.shadowMapWidth = 512;
- this.shadowMapHeight = 512;
+ }
- //
+ }
- this.shadowMap = null;
- this.shadowMapSize = null;
- this.shadowCamera = null;
- this.shadowMatrix = null;
+ // colors
-};
+ if ( m.colorDiffuse ) {
-THREE.SpotLight.prototype = Object.create( THREE.Light.prototype );
+ mpars.color = rgb2hex( m.colorDiffuse );
-THREE.SpotLight.prototype.clone = function () {
+ } else if ( m.DbgColor ) {
- var light = new THREE.SpotLight();
+ mpars.color = m.DbgColor;
- THREE.Light.prototype.clone.call( this, light );
+ }
- light.target = this.target.clone();
+ if ( m.colorSpecular ) {
- light.intensity = this.intensity;
- light.distance = this.distance;
- light.angle = this.angle;
- light.exponent = this.exponent;
+ mpars.specular = rgb2hex( m.colorSpecular );
- light.castShadow = this.castShadow;
- light.onlyShadow = this.onlyShadow;
+ }
- //
+ if ( m.colorAmbient ) {
- light.shadowCameraNear = this.shadowCameraNear;
- light.shadowCameraFar = this.shadowCameraFar;
- light.shadowCameraFov = this.shadowCameraFov;
+ mpars.ambient = rgb2hex( m.colorAmbient );
- light.shadowCameraVisible = this.shadowCameraVisible;
+ }
- light.shadowBias = this.shadowBias;
- light.shadowDarkness = this.shadowDarkness;
+ if ( m.colorEmissive ) {
- light.shadowMapWidth = this.shadowMapWidth;
- light.shadowMapHeight = this.shadowMapHeight;
+ mpars.emissive = rgb2hex( m.colorEmissive );
- return light;
+ }
+
+ // modifiers
+
+ if ( m.transparency ) {
+
+ mpars.opacity = m.transparency;
+
+ }
+
+ if ( m.specularCoef ) {
+
+ mpars.shininess = m.specularCoef;
+
+ }
+
+ // textures
+
+ if ( m.mapDiffuse && texturePath ) {
+
+ create_texture( mpars, 'map', m.mapDiffuse, m.mapDiffuseRepeat, m.mapDiffuseOffset, m.mapDiffuseWrap, m.mapDiffuseAnisotropy );
+
+ }
+
+ if ( m.mapLight && texturePath ) {
+
+ create_texture( mpars, 'lightMap', m.mapLight, m.mapLightRepeat, m.mapLightOffset, m.mapLightWrap, m.mapLightAnisotropy );
+
+ }
+
+ if ( m.mapBump && texturePath ) {
+
+ create_texture( mpars, 'bumpMap', m.mapBump, m.mapBumpRepeat, m.mapBumpOffset, m.mapBumpWrap, m.mapBumpAnisotropy );
+
+ }
+
+ if ( m.mapNormal && texturePath ) {
+
+ create_texture( mpars, 'normalMap', m.mapNormal, m.mapNormalRepeat, m.mapNormalOffset, m.mapNormalWrap, m.mapNormalAnisotropy );
+
+ }
+
+ if ( m.mapSpecular && texturePath ) {
+
+ create_texture( mpars, 'specularMap', m.mapSpecular, m.mapSpecularRepeat, m.mapSpecularOffset, m.mapSpecularWrap, m.mapSpecularAnisotropy );
+
+ }
+
+ if ( m.mapAlpha && texturePath ) {
+
+ create_texture( mpars, 'alphaMap', m.mapAlpha, m.mapAlphaRepeat, m.mapAlphaOffset, m.mapAlphaWrap, m.mapAlphaAnisotropy );
+
+ }
+
+ //
+
+ if ( m.mapBumpScale ) {
+
+ mpars.bumpScale = m.mapBumpScale;
+
+ }
+
+ // special case for normal mapped material
+
+ if ( m.mapNormal ) {
+
+ var shader = THREE.ShaderLib[ 'normalmap' ];
+ var uniforms = THREE.UniformsUtils.clone( shader.uniforms );
+
+ uniforms[ 'tNormal' ].value = mpars.normalMap;
+
+ if ( m.mapNormalFactor ) {
+
+ uniforms[ 'uNormalScale' ].value.set( m.mapNormalFactor, m.mapNormalFactor );
+
+ }
+
+ if ( mpars.map ) {
+
+ uniforms[ 'tDiffuse' ].value = mpars.map;
+ uniforms[ 'enableDiffuse' ].value = true;
+
+ }
+
+ if ( mpars.specularMap ) {
+
+ uniforms[ 'tSpecular' ].value = mpars.specularMap;
+ uniforms[ 'enableSpecular' ].value = true;
+
+ }
+
+ if ( mpars.lightMap ) {
+
+ uniforms[ 'tAO' ].value = mpars.lightMap;
+ uniforms[ 'enableAO' ].value = true;
+
+ }
+
+ // for the moment don't handle displacement texture
+
+ uniforms[ 'diffuse' ].value.setHex( mpars.color );
+ uniforms[ 'specular' ].value.setHex( mpars.specular );
+ uniforms[ 'ambient' ].value.setHex( mpars.ambient );
+
+ uniforms[ 'shininess' ].value = mpars.shininess;
+
+ if ( mpars.opacity !== undefined ) {
+
+ uniforms[ 'opacity' ].value = mpars.opacity;
+
+ }
+
+ var parameters = { fragmentShader: shader.fragmentShader, vertexShader: shader.vertexShader, uniforms: uniforms, lights: true, fog: true };
+ var material = new THREE.ShaderMaterial( parameters );
+
+ if ( mpars.transparent ) {
+
+ material.transparent = true;
+
+ }
+
+ } else {
+
+ var material = new THREE[ mtype ]( mpars );
+
+ }
+
+ if ( m.DbgName !== undefined ) material.name = m.DbgName;
+
+ return material;
+
+ }
};
-// File:src/loaders/Cache.js
+THREE.Loader.Handlers = {
-/**
- * @author mrdoob / http://mrdoob.com/
- */
-
-THREE.Cache = function () {
-
- this.files = {};
-
-};
-
-THREE.Cache.prototype = {
-
- constructor: THREE.Cache,
-
- add: function ( key, file ) {
-
- // console.log( 'THREE.Cache', 'Adding key:', key );
-
- this.files[ key ] = file;
-
- },
-
- get: function ( key ) {
-
- // console.log( 'THREE.Cache', 'Checking key:', key );
-
- return this.files[ key ];
-
- },
-
- remove: function ( key ) {
-
- delete this.files[ key ];
-
- },
-
- clear: function () {
-
- this.files = {}
-
- }
-
-};
+ handlers: [],
-// File:src/loaders/Loader.js
+ add: function ( regex, loader ) {
+
+ this.handlers.push( regex, loader );
+
+ },
+
+ get: function ( file ) {
+
+ for ( var i = 0, l = this.handlers.length; i < l; i += 2 ) {
+
+ var regex = this.handlers[ i ];
+ var loader = this.handlers[ i + 1 ];
+
+ if ( regex.test( file ) ) {
+
+ return loader;
+
+ }
+
+ }
+
+ return null;
+
+ }
-/**
- * @author alteredq / http://alteredqualia.com/
- */
-
-THREE.Loader = function ( showStatus ) {
-
- this.showStatus = showStatus;
- this.statusDomElement = showStatus ? THREE.Loader.prototype.addStatusElement() : null;
-
- this.imageLoader = new THREE.ImageLoader();
-
- this.onLoadStart = function () {};
- this.onLoadProgress = function () {};
- this.onLoadComplete = function () {};
-
-};
-
-THREE.Loader.prototype = {
-
- constructor: THREE.Loader,
-
- crossOrigin: undefined,
-
- addStatusElement: function () {
-
- var e = document.createElement( 'div' );
-
- e.style.position = 'absolute';
- e.style.right = '0px';
- e.style.top = '0px';
- e.style.fontSize = '0.8em';
- e.style.textAlign = 'left';
- e.style.background = 'rgba(0,0,0,0.25)';
- e.style.color = '#fff';
- e.style.width = '120px';
- e.style.padding = '0.5em 0.5em 0.5em 0.5em';
- e.style.zIndex = 1000;
-
- e.innerHTML = 'Loading ...';
-
- return e;
-
- },
-
- updateProgress: function ( progress ) {
-
- var message = 'Loaded ';
-
- if ( progress.total ) {
-
- message += ( 100 * progress.loaded / progress.total ).toFixed( 0 ) + '%';
-
-
- } else {
-
- message += ( progress.loaded / 1024 ).toFixed( 2 ) + ' KB';
-
- }
-
- this.statusDomElement.innerHTML = message;
-
- },
-
- extractUrlBase: function ( url ) {
-
- var parts = url.split( '/' );
-
- if ( parts.length === 1 ) return './';
-
- parts.pop();
-
- return parts.join( '/' ) + '/';
-
- },
-
- initMaterials: function ( materials, texturePath ) {
-
- var array = [];
-
- for ( var i = 0; i < materials.length; ++ i ) {
-
- array[ i ] = this.createMaterial( materials[ i ], texturePath );
-
- }
-
- return array;
-
- },
-
- needsTangents: function ( materials ) {
-
- for ( var i = 0, il = materials.length; i < il; i ++ ) {
-
- var m = materials[ i ];
-
- if ( m instanceof THREE.ShaderMaterial ) return true;
-
- }
-
- return false;
-
- },
-
- createMaterial: function ( m, texturePath ) {
-
- var scope = this;
-
- function nearest_pow2( n ) {
-
- var l = Math.log( n ) / Math.LN2;
- return Math.pow( 2, Math.round( l ) );
-
- }
-
- function create_texture( where, name, sourceFile, repeat, offset, wrap, anisotropy ) {
-
- var fullPath = texturePath + sourceFile;
-
- var texture;
-
- var loader = THREE.Loader.Handlers.get( fullPath );
-
- if ( loader !== null ) {
-
- texture = loader.load( fullPath );
-
- } else {
-
- texture = new THREE.Texture();
-
- loader = scope.imageLoader;
- loader.crossOrigin = scope.crossOrigin;
- loader.load( fullPath, function ( image ) {
-
- if ( THREE.Math.isPowerOfTwo( image.width ) === false ||
- THREE.Math.isPowerOfTwo( image.height ) === false ) {
-
- var width = nearest_pow2( image.width );
- var height = nearest_pow2( image.height );
-
- var canvas = document.createElement( 'canvas' );
- canvas.width = width;
- canvas.height = height;
-
- var context = canvas.getContext( '2d' );
- context.drawImage( image, 0, 0, width, height );
-
- texture.image = canvas;
-
- } else {
-
- texture.image = image;
-
- }
-
- texture.needsUpdate = true;
-
- } );
-
- }
-
- texture.sourceFile = sourceFile;
-
- if ( repeat ) {
-
- texture.repeat.set( repeat[ 0 ], repeat[ 1 ] );
-
- if ( repeat[ 0 ] !== 1 ) texture.wrapS = THREE.RepeatWrapping;
- if ( repeat[ 1 ] !== 1 ) texture.wrapT = THREE.RepeatWrapping;
-
- }
-
- if ( offset ) {
-
- texture.offset.set( offset[ 0 ], offset[ 1 ] );
-
- }
-
- if ( wrap ) {
-
- var wrapMap = {
- 'repeat': THREE.RepeatWrapping,
- 'mirror': THREE.MirroredRepeatWrapping
- }
-
- if ( wrapMap[ wrap[ 0 ] ] !== undefined ) texture.wrapS = wrapMap[ wrap[ 0 ] ];
- if ( wrapMap[ wrap[ 1 ] ] !== undefined ) texture.wrapT = wrapMap[ wrap[ 1 ] ];
-
- }
-
- if ( anisotropy ) {
-
- texture.anisotropy = anisotropy;
-
- }
-
- where[ name ] = texture;
-
- }
-
- function rgb2hex( rgb ) {
-
- return ( rgb[ 0 ] * 255 << 16 ) + ( rgb[ 1 ] * 255 << 8 ) + rgb[ 2 ] * 255;
-
- }
-
- // defaults
-
- var mtype = 'MeshLambertMaterial';
- var mpars = { color: 0xeeeeee, opacity: 1.0, map: null, lightMap: null, normalMap: null, bumpMap: null, wireframe: false };
-
- // parameters from model file
-
- if ( m.shading ) {
-
- var shading = m.shading.toLowerCase();
-
- if ( shading === 'phong' ) mtype = 'MeshPhongMaterial';
- else if ( shading === 'basic' ) mtype = 'MeshBasicMaterial';
-
- }
-
- if ( m.blending !== undefined && THREE[ m.blending ] !== undefined ) {
-
- mpars.blending = THREE[ m.blending ];
-
- }
-
- if ( m.transparent !== undefined || m.opacity < 1.0 ) {
-
- mpars.transparent = m.transparent;
-
- }
-
- if ( m.depthTest !== undefined ) {
-
- mpars.depthTest = m.depthTest;
-
- }
-
- if ( m.depthWrite !== undefined ) {
-
- mpars.depthWrite = m.depthWrite;
-
- }
-
- if ( m.visible !== undefined ) {
-
- mpars.visible = m.visible;
-
- }
-
- if ( m.flipSided !== undefined ) {
-
- mpars.side = THREE.BackSide;
-
- }
-
- if ( m.doubleSided !== undefined ) {
-
- mpars.side = THREE.DoubleSide;
-
- }
-
- if ( m.wireframe !== undefined ) {
-
- mpars.wireframe = m.wireframe;
-
- }
-
- if ( m.vertexColors !== undefined ) {
-
- if ( m.vertexColors === 'face' ) {
-
- mpars.vertexColors = THREE.FaceColors;
-
- } else if ( m.vertexColors ) {
-
- mpars.vertexColors = THREE.VertexColors;
-
- }
-
- }
-
- // colors
-
- if ( m.colorDiffuse ) {
-
- mpars.color = rgb2hex( m.colorDiffuse );
-
- } else if ( m.DbgColor ) {
-
- mpars.color = m.DbgColor;
-
- }
-
- if ( m.colorSpecular ) {
-
- mpars.specular = rgb2hex( m.colorSpecular );
-
- }
-
- if ( m.colorAmbient ) {
-
- mpars.ambient = rgb2hex( m.colorAmbient );
-
- }
-
- if ( m.colorEmissive ) {
-
- mpars.emissive = rgb2hex( m.colorEmissive );
-
- }
-
- // modifiers
-
- if ( m.transparency ) {
-
- mpars.opacity = m.transparency;
-
- }
-
- if ( m.specularCoef ) {
-
- mpars.shininess = m.specularCoef;
-
- }
-
- // textures
-
- if ( m.mapDiffuse && texturePath ) {
-
- create_texture( mpars, 'map', m.mapDiffuse, m.mapDiffuseRepeat, m.mapDiffuseOffset, m.mapDiffuseWrap, m.mapDiffuseAnisotropy );
-
- }
-
- if ( m.mapLight && texturePath ) {
-
- create_texture( mpars, 'lightMap', m.mapLight, m.mapLightRepeat, m.mapLightOffset, m.mapLightWrap, m.mapLightAnisotropy );
-
- }
-
- if ( m.mapBump && texturePath ) {
-
- create_texture( mpars, 'bumpMap', m.mapBump, m.mapBumpRepeat, m.mapBumpOffset, m.mapBumpWrap, m.mapBumpAnisotropy );
-
- }
-
- if ( m.mapNormal && texturePath ) {
-
- create_texture( mpars, 'normalMap', m.mapNormal, m.mapNormalRepeat, m.mapNormalOffset, m.mapNormalWrap, m.mapNormalAnisotropy );
-
- }
-
- if ( m.mapSpecular && texturePath ) {
-
- create_texture( mpars, 'specularMap', m.mapSpecular, m.mapSpecularRepeat, m.mapSpecularOffset, m.mapSpecularWrap, m.mapSpecularAnisotropy );
-
- }
-
- if ( m.mapAlpha && texturePath ) {
-
- create_texture( mpars, 'alphaMap', m.mapAlpha, m.mapAlphaRepeat, m.mapAlphaOffset, m.mapAlphaWrap, m.mapAlphaAnisotropy );
-
- }
-
- //
-
- if ( m.mapBumpScale ) {
-
- mpars.bumpScale = m.mapBumpScale;
-
- }
-
- // special case for normal mapped material
-
- if ( m.mapNormal ) {
-
- var shader = THREE.ShaderLib[ 'normalmap' ];
- var uniforms = THREE.UniformsUtils.clone( shader.uniforms );
-
- uniforms[ 'tNormal' ].value = mpars.normalMap;
-
- if ( m.mapNormalFactor ) {
-
- uniforms[ 'uNormalScale' ].value.set( m.mapNormalFactor, m.mapNormalFactor );
-
- }
-
- if ( mpars.map ) {
-
- uniforms[ 'tDiffuse' ].value = mpars.map;
- uniforms[ 'enableDiffuse' ].value = true;
-
- }
-
- if ( mpars.specularMap ) {
-
- uniforms[ 'tSpecular' ].value = mpars.specularMap;
- uniforms[ 'enableSpecular' ].value = true;
-
- }
-
- if ( mpars.lightMap ) {
-
- uniforms[ 'tAO' ].value = mpars.lightMap;
- uniforms[ 'enableAO' ].value = true;
-
- }
-
- // for the moment don't handle displacement texture
-
- uniforms[ 'diffuse' ].value.setHex( mpars.color );
- uniforms[ 'specular' ].value.setHex( mpars.specular );
- uniforms[ 'ambient' ].value.setHex( mpars.ambient );
-
- uniforms[ 'shininess' ].value = mpars.shininess;
-
- if ( mpars.opacity !== undefined ) {
-
- uniforms[ 'opacity' ].value = mpars.opacity;
-
- }
-
- var parameters = { fragmentShader: shader.fragmentShader, vertexShader: shader.vertexShader, uniforms: uniforms, lights: true, fog: true };
- var material = new THREE.ShaderMaterial( parameters );
-
- if ( mpars.transparent ) {
-
- material.transparent = true;
-
- }
-
- } else {
-
- var material = new THREE[ mtype ]( mpars );
-
- }
-
- if ( m.DbgName !== undefined ) material.name = m.DbgName;
-
- return material;
-
- }
-
-};
-
-THREE.Loader.Handlers = {
-
- handlers: [],
-
- add: function ( regex, loader ) {
-
- this.handlers.push( regex, loader );
-
- },
-
- get: function ( file ) {
-
- for ( var i = 0, l = this.handlers.length; i < l; i += 2 ) {
-
- var regex = this.handlers[ i ];
- var loader = this.handlers[ i + 1 ];
-
- if ( regex.test( file ) ) {
-
- return loader;
-
- }
-
- }
-
- return null;
-
- }
-
-};
+};
// File:src/loaders/XHRLoader.js
@@ -11893,5140 +11633,4315 @@ THREE.ImageLoader.prototype = {
// File:src/loaders/JSONLoader.js
-/**
- * @author mrdoob / http://mrdoob.com/
- * @author alteredq / http://alteredqualia.com/
- */
-
-THREE.JSONLoader = function ( showStatus ) {
-
- THREE.Loader.call( this, showStatus );
-
- this.withCredentials = false;
-
-};
-
-THREE.JSONLoader.prototype = Object.create( THREE.Loader.prototype );
-
-THREE.JSONLoader.prototype.load = function ( url, callback, texturePath ) {
-
- var scope = this;
-
- // todo: unify load API to for easier SceneLoader use
-
- texturePath = texturePath && ( typeof texturePath === 'string' ) ? texturePath : this.extractUrlBase( url );
-
- this.onLoadStart();
- this.loadAjaxJSON( this, url, callback, texturePath );
-
-};
-
-THREE.JSONLoader.prototype.loadAjaxJSON = function ( context, url, callback, texturePath, callbackProgress ) {
-
- var xhr = new XMLHttpRequest();
-
- var length = 0;
-
- xhr.onreadystatechange = function () {
-
- if ( xhr.readyState === xhr.DONE ) {
-
- if ( xhr.status === 200 || xhr.status === 0 ) {
-
- if ( xhr.responseText ) {
-
- var json = JSON.parse( xhr.responseText );
-
- if ( json.metadata !== undefined && json.metadata.type === 'scene' ) {
-
- console.error( 'THREE.JSONLoader: "' + url + '" seems to be a Scene. Use THREE.SceneLoader instead.' );
- return;
-
- }
-
- var result = context.parse( json, texturePath );
- callback( result.geometry, result.materials );
-
- } else {
-
- console.error( 'THREE.JSONLoader: "' + url + '" seems to be unreachable or the file is empty.' );
-
- }
-
- // in context of more complex asset initialization
- // do not block on single failed file
- // maybe should go even one more level up
-
- context.onLoadComplete();
-
- } else {
-
- console.error( 'THREE.JSONLoader: Couldn\'t load "' + url + '" (' + xhr.status + ')' );
-
- }
-
- } else if ( xhr.readyState === xhr.LOADING ) {
-
- if ( callbackProgress ) {
-
- if ( length === 0 ) {
-
- length = xhr.getResponseHeader( 'Content-Length' );
-
- }
-
- callbackProgress( { total: length, loaded: xhr.responseText.length } );
-
- }
-
- } else if ( xhr.readyState === xhr.HEADERS_RECEIVED ) {
-
- if ( callbackProgress !== undefined ) {
-
- length = xhr.getResponseHeader( 'Content-Length' );
-
- }
-
- }
-
- };
-
- xhr.open( 'GET', url, true );
- xhr.withCredentials = this.withCredentials;
- xhr.send( null );
-
-};
-
-THREE.JSONLoader.prototype.parse = function ( json, texturePath ) {
-
- var scope = this,
- geometry = new THREE.Geometry(),
- scale = ( json.scale !== undefined ) ? 1.0 / json.scale : 1.0;
-
- parseModel( scale );
-
- parseSkin();
- parseMorphing( scale );
-
- geometry.computeFaceNormals();
- geometry.computeBoundingSphere();
-
- function parseModel( scale ) {
-
- function isBitSet( value, position ) {
-
- return value & ( 1 << position );
-
- }
-
- var i, j, fi,
-
- offset, zLength,
-
- colorIndex, normalIndex, uvIndex, materialIndex,
-
- type,
- isQuad,
- hasMaterial,
- hasFaceVertexUv,
- hasFaceNormal, hasFaceVertexNormal,
- hasFaceColor, hasFaceVertexColor,
-
- vertex, face, faceA, faceB, color, hex, normal,
-
- uvLayer, uv, u, v,
-
- faces = json.faces,
- vertices = json.vertices,
- normals = json.normals,
- colors = json.colors,
-
- nUvLayers = 0;
-
- if ( json.uvs !== undefined ) {
-
- // disregard empty arrays
-
- for ( i = 0; i < json.uvs.length; i ++ ) {
-
- if ( json.uvs[ i ].length ) nUvLayers ++;
-
- }
-
- for ( i = 0; i < nUvLayers; i ++ ) {
-
- geometry.faceVertexUvs[ i ] = [];
-
- }
-
- }
-
- offset = 0;
- zLength = vertices.length;
-
- while ( offset < zLength ) {
-
- vertex = new THREE.Vector3();
-
- vertex.x = vertices[ offset ++ ] * scale;
- vertex.y = vertices[ offset ++ ] * scale;
- vertex.z = vertices[ offset ++ ] * scale;
-
- geometry.vertices.push( vertex );
-
- }
-
- offset = 0;
- zLength = faces.length;
-
- while ( offset < zLength ) {
-
- type = faces[ offset ++ ];
-
-
- isQuad = isBitSet( type, 0 );
- hasMaterial = isBitSet( type, 1 );
- hasFaceVertexUv = isBitSet( type, 3 );
- hasFaceNormal = isBitSet( type, 4 );
- hasFaceVertexNormal = isBitSet( type, 5 );
- hasFaceColor = isBitSet( type, 6 );
- hasFaceVertexColor = isBitSet( type, 7 );
-
- // console.log("type", type, "bits", isQuad, hasMaterial, hasFaceVertexUv, hasFaceNormal, hasFaceVertexNormal, hasFaceColor, hasFaceVertexColor);
-
- if ( isQuad ) {
-
- faceA = new THREE.Face3();
- faceA.a = faces[ offset ];
- faceA.b = faces[ offset + 1 ];
- faceA.c = faces[ offset + 3 ];
-
- faceB = new THREE.Face3();
- faceB.a = faces[ offset + 1 ];
- faceB.b = faces[ offset + 2 ];
- faceB.c = faces[ offset + 3 ];
-
- offset += 4;
-
- if ( hasMaterial ) {
-
- materialIndex = faces[ offset ++ ];
- faceA.materialIndex = materialIndex;
- faceB.materialIndex = materialIndex;
-
- }
-
- // to get face <=> uv index correspondence
-
- fi = geometry.faces.length;
-
- if ( hasFaceVertexUv ) {
-
- for ( i = 0; i < nUvLayers; i ++ ) {
-
- uvLayer = json.uvs[ i ];
-
- geometry.faceVertexUvs[ i ][ fi ] = [];
- geometry.faceVertexUvs[ i ][ fi + 1 ] = []
-
- for ( j = 0; j < 4; j ++ ) {
-
- uvIndex = faces[ offset ++ ];
-
- u = uvLayer[ uvIndex * 2 ];
- v = uvLayer[ uvIndex * 2 + 1 ];
-
- uv = new THREE.Vector2( u, v );
-
- if ( j !== 2 ) geometry.faceVertexUvs[ i ][ fi ].push( uv );
- if ( j !== 0 ) geometry.faceVertexUvs[ i ][ fi + 1 ].push( uv );
-
- }
-
- }
-
- }
-
- if ( hasFaceNormal ) {
-
- normalIndex = faces[ offset ++ ] * 3;
-
- faceA.normal.set(
- normals[ normalIndex ++ ],
- normals[ normalIndex ++ ],
- normals[ normalIndex ]
- );
-
- faceB.normal.copy( faceA.normal );
-
- }
-
- if ( hasFaceVertexNormal ) {
-
- for ( i = 0; i < 4; i ++ ) {
-
- normalIndex = faces[ offset ++ ] * 3;
-
- normal = new THREE.Vector3(
- normals[ normalIndex ++ ],
- normals[ normalIndex ++ ],
- normals[ normalIndex ]
- );
-
-
- if ( i !== 2 ) faceA.vertexNormals.push( normal );
- if ( i !== 0 ) faceB.vertexNormals.push( normal );
-
- }
-
- }
-
-
- if ( hasFaceColor ) {
-
- colorIndex = faces[ offset ++ ];
- hex = colors[ colorIndex ];
-
- faceA.color.setHex( hex );
- faceB.color.setHex( hex );
-
- }
-
-
- if ( hasFaceVertexColor ) {
-
- for ( i = 0; i < 4; i ++ ) {
-
- colorIndex = faces[ offset ++ ];
- hex = colors[ colorIndex ];
-
- if ( i !== 2 ) faceA.vertexColors.push( new THREE.Color( hex ) );
- if ( i !== 0 ) faceB.vertexColors.push( new THREE.Color( hex ) );
-
- }
-
- }
-
- geometry.faces.push( faceA );
- geometry.faces.push( faceB );
-
- } else {
-
- face = new THREE.Face3();
- face.a = faces[ offset ++ ];
- face.b = faces[ offset ++ ];
- face.c = faces[ offset ++ ];
-
- if ( hasMaterial ) {
-
- materialIndex = faces[ offset ++ ];
- face.materialIndex = materialIndex;
-
- }
-
- // to get face <=> uv index correspondence
-
- fi = geometry.faces.length;
-
- if ( hasFaceVertexUv ) {
-
- for ( i = 0; i < nUvLayers; i ++ ) {
-
- uvLayer = json.uvs[ i ];
-
- geometry.faceVertexUvs[ i ][ fi ] = [];
-
- for ( j = 0; j < 3; j ++ ) {
-
- uvIndex = faces[ offset ++ ];
-
- u = uvLayer[ uvIndex * 2 ];
- v = uvLayer[ uvIndex * 2 + 1 ];
-
- uv = new THREE.Vector2( u, v );
-
- geometry.faceVertexUvs[ i ][ fi ].push( uv );
-
- }
-
- }
-
- }
-
- if ( hasFaceNormal ) {
-
- normalIndex = faces[ offset ++ ] * 3;
-
- face.normal.set(
- normals[ normalIndex ++ ],
- normals[ normalIndex ++ ],
- normals[ normalIndex ]
- );
-
- }
-
- if ( hasFaceVertexNormal ) {
-
- for ( i = 0; i < 3; i ++ ) {
-
- normalIndex = faces[ offset ++ ] * 3;
-
- normal = new THREE.Vector3(
- normals[ normalIndex ++ ],
- normals[ normalIndex ++ ],
- normals[ normalIndex ]
- );
-
- face.vertexNormals.push( normal );
-
- }
-
- }
-
-
- if ( hasFaceColor ) {
-
- colorIndex = faces[ offset ++ ];
- face.color.setHex( colors[ colorIndex ] );
-
- }
-
-
- if ( hasFaceVertexColor ) {
-
- for ( i = 0; i < 3; i ++ ) {
-
- colorIndex = faces[ offset ++ ];
- face.vertexColors.push( new THREE.Color( colors[ colorIndex ] ) );
-
- }
-
- }
-
- geometry.faces.push( face );
-
- }
-
- }
-
- };
-
- function parseSkin() {
- var influencesPerVertex = ( json.influencesPerVertex !== undefined ) ? json.influencesPerVertex : 2;
-
- if ( json.skinWeights ) {
-
- for ( var i = 0, l = json.skinWeights.length; i < l; i += influencesPerVertex ) {
-
- var x = json.skinWeights[ i ];
- var y = ( influencesPerVertex > 1 ) ? json.skinWeights[ i + 1 ] : 0;
- var z = ( influencesPerVertex > 2 ) ? json.skinWeights[ i + 2 ] : 0;
- var w = ( influencesPerVertex > 3 ) ? json.skinWeights[ i + 3 ] : 0;
-
- geometry.skinWeights.push( new THREE.Vector4( x, y, z, w ) );
-
- }
-
- }
-
- if ( json.skinIndices ) {
-
- for ( var i = 0, l = json.skinIndices.length; i < l; i += influencesPerVertex ) {
-
- var a = json.skinIndices[ i ];
- var b = ( influencesPerVertex > 1 ) ? json.skinIndices[ i + 1 ] : 0;
- var c = ( influencesPerVertex > 2 ) ? json.skinIndices[ i + 2 ] : 0;
- var d = ( influencesPerVertex > 3 ) ? json.skinIndices[ i + 3 ] : 0;
-
- geometry.skinIndices.push( new THREE.Vector4( a, b, c, d ) );
-
- }
-
- }
-
- geometry.bones = json.bones;
-
- if ( geometry.bones && geometry.bones.length > 0 && ( geometry.skinWeights.length !== geometry.skinIndices.length || geometry.skinIndices.length !== geometry.vertices.length ) ) {
-
- console.warn( 'When skinning, number of vertices (' + geometry.vertices.length + '), skinIndices (' +
- geometry.skinIndices.length + '), and skinWeights (' + geometry.skinWeights.length + ') should match.' );
-
- }
-
-
- // could change this to json.animations[0] or remove completely
-
- geometry.animation = json.animation;
- geometry.animations = json.animations;
-
- };
-
- function parseMorphing( scale ) {
-
- if ( json.morphTargets !== undefined ) {
-
- var i, l, v, vl, dstVertices, srcVertices;
-
- for ( i = 0, l = json.morphTargets.length; i < l; i ++ ) {
-
- geometry.morphTargets[ i ] = {};
- geometry.morphTargets[ i ].name = json.morphTargets[ i ].name;
- geometry.morphTargets[ i ].vertices = [];
-
- dstVertices = geometry.morphTargets[ i ].vertices;
- srcVertices = json.morphTargets [ i ].vertices;
-
- for ( v = 0, vl = srcVertices.length; v < vl; v += 3 ) {
-
- var vertex = new THREE.Vector3();
- vertex.x = srcVertices[ v ] * scale;
- vertex.y = srcVertices[ v + 1 ] * scale;
- vertex.z = srcVertices[ v + 2 ] * scale;
-
- dstVertices.push( vertex );
-
- }
-
- }
-
- }
-
- if ( json.morphColors !== undefined ) {
-
- var i, l, c, cl, dstColors, srcColors, color;
-
- for ( i = 0, l = json.morphColors.length; i < l; i ++ ) {
-
- geometry.morphColors[ i ] = {};
- geometry.morphColors[ i ].name = json.morphColors[ i ].name;
- geometry.morphColors[ i ].colors = [];
-
- dstColors = geometry.morphColors[ i ].colors;
- srcColors = json.morphColors [ i ].colors;
-
- for ( c = 0, cl = srcColors.length; c < cl; c += 3 ) {
-
- color = new THREE.Color( 0xffaa00 );
- color.setRGB( srcColors[ c ], srcColors[ c + 1 ], srcColors[ c + 2 ] );
- dstColors.push( color );
-
- }
-
- }
-
- }
-
- };
-
- if ( json.materials === undefined || json.materials.length === 0 ) {
-
- return { geometry: geometry };
-
- } else {
-
- var materials = this.initMaterials( json.materials, texturePath );
-
- if ( this.needsTangents( materials ) ) {
-
- geometry.computeTangents();
-
- }
-
- return { geometry: geometry, materials: materials };
-
- }
-
-};
-
-// File:src/loaders/LoadingManager.js
-
/**
* @author mrdoob / http://mrdoob.com/
+ * @author alteredq / http://alteredqualia.com/
*/
-THREE.LoadingManager = function ( onLoad, onProgress, onError ) {
+THREE.JSONLoader = function ( showStatus ) {
- var scope = this;
+ THREE.Loader.call( this, showStatus );
- var loaded = 0, total = 0;
+ this.withCredentials = false;
- this.onLoad = onLoad;
- this.onProgress = onProgress;
- this.onError = onError;
+};
- this.itemStart = function ( url ) {
+THREE.JSONLoader.prototype = Object.create( THREE.Loader.prototype );
- total ++;
+THREE.JSONLoader.prototype.load = function ( url, callback, texturePath ) {
- };
+ var scope = this;
- this.itemEnd = function ( url ) {
+ // todo: unify load API to for easier SceneLoader use
- loaded ++;
+ texturePath = texturePath && ( typeof texturePath === 'string' ) ? texturePath : this.extractUrlBase( url );
- if ( scope.onProgress !== undefined ) {
+ this.onLoadStart();
+ this.loadAjaxJSON( this, url, callback, texturePath );
- scope.onProgress( url, loaded, total );
+};
- }
+THREE.JSONLoader.prototype.loadAjaxJSON = function ( context, url, callback, texturePath, callbackProgress ) {
- if ( loaded === total && scope.onLoad !== undefined ) {
+ var xhr = new XMLHttpRequest();
- scope.onLoad();
+ var length = 0;
- }
+ xhr.onreadystatechange = function () {
- };
+ if ( xhr.readyState === xhr.DONE ) {
-};
+ if ( xhr.status === 200 || xhr.status === 0 ) {
-THREE.DefaultLoadingManager = new THREE.LoadingManager();
+ if ( xhr.responseText ) {
-// File:src/loaders/BufferGeometryLoader.js
+ var json = JSON.parse( xhr.responseText );
-/**
- * @author mrdoob / http://mrdoob.com/
- */
-
-THREE.BufferGeometryLoader = function ( manager ) {
-
- this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
-
-};
-
-THREE.BufferGeometryLoader.prototype = {
-
- constructor: THREE.BufferGeometryLoader,
-
- load: function ( url, onLoad, onProgress, onError ) {
-
- var scope = this;
-
- var loader = new THREE.XHRLoader();
- loader.setCrossOrigin( this.crossOrigin );
- loader.load( url, function ( text ) {
-
- onLoad( scope.parse( JSON.parse( text ) ) );
-
- }, onProgress, onError );
-
- },
-
- setCrossOrigin: function ( value ) {
-
- this.crossOrigin = value;
-
- },
-
- parse: function ( json ) {
-
- var geometry = new THREE.BufferGeometry();
-
- var attributes = json.attributes;
-
- for ( var key in attributes ) {
-
- var attribute = attributes[ key ];
-
- geometry.attributes[ key ] = {
- itemSize: attribute.itemSize,
- array: new self[ attribute.type ]( attribute.array )
- }
-
- }
-
- var offsets = json.offsets;
-
- if ( offsets !== undefined ) {
-
- geometry.offsets = JSON.parse( JSON.stringify( offsets ) );
-
- }
-
- var boundingSphere = json.boundingSphere;
-
- if ( boundingSphere !== undefined ) {
-
- geometry.boundingSphere = new THREE.Sphere(
- new THREE.Vector3().fromArray( boundingSphere.center !== undefined ? boundingSphere.center : [ 0, 0, 0 ] ),
- boundingSphere.radius
- );
-
- }
-
- return geometry;
-
- }
-
-};
+ if ( json.metadata !== undefined && json.metadata.type === 'scene' ) {
-// File:src/loaders/MaterialLoader.js
+ console.error( 'THREE.JSONLoader: "' + url + '" seems to be a Scene. Use THREE.SceneLoader instead.' );
+ return;
-/**
- * @author mrdoob / http://mrdoob.com/
- */
-
-THREE.MaterialLoader = function ( manager ) {
-
- this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
-
-};
-
-THREE.MaterialLoader.prototype = {
-
- constructor: THREE.MaterialLoader,
-
- load: function ( url, onLoad, onProgress, onError ) {
-
- var scope = this;
-
- var loader = new THREE.XHRLoader();
- loader.setCrossOrigin( this.crossOrigin );
- loader.load( url, function ( text ) {
-
- onLoad( scope.parse( JSON.parse( text ) ) );
-
- }, onProgress, onError );
-
- },
-
- setCrossOrigin: function ( value ) {
-
- this.crossOrigin = value;
-
- },
-
- parse: function ( json ) {
-
- var material = new THREE[ json.type ];
-
- if ( json.color !== undefined ) material.color.setHex( json.color );
- if ( json.ambient !== undefined ) material.ambient.setHex( json.ambient );
- if ( json.emissive !== undefined ) material.emissive.setHex( json.emissive );
- if ( json.specular !== undefined ) material.specular.setHex( json.specular );
- if ( json.shininess !== undefined ) material.shininess = json.shininess;
- if ( json.uniforms !== undefined ) material.uniforms = json.uniforms;
- if ( json.vertexShader !== undefined ) material.vertexShader = json.vertexShader;
- if ( json.fragmentShader !== undefined ) material.fragmentShader = json.fragmentShader;
- if ( json.vertexColors !== undefined ) material.vertexColors = json.vertexColors;
- if ( json.blending !== undefined ) material.blending = json.blending;
- if ( json.side !== undefined ) material.side = json.side;
- if ( json.opacity !== undefined ) material.opacity = json.opacity;
- if ( json.transparent !== undefined ) material.transparent = json.transparent;
- if ( json.wireframe !== undefined ) material.wireframe = json.wireframe;
-
- if ( json.materials !== undefined ) {
-
- for ( var i = 0, l = json.materials.length; i < l; i ++ ) {
-
- material.materials.push( this.parse( json.materials[ i ] ) );
-
- }
-
- }
-
- return material;
-
- }
-
-};
+ }
-// File:src/loaders/ObjectLoader.js
+ var result = context.parse( json, texturePath );
+ callback( result.geometry, result.materials );
-/**
- * @author mrdoob / http://mrdoob.com/
- */
+ } else {
-THREE.ObjectLoader = function ( manager ) {
+ console.error( 'THREE.JSONLoader: "' + url + '" seems to be unreachable or the file is empty.' );
- this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
+ }
-};
+ // in context of more complex asset initialization
+ // do not block on single failed file
+ // maybe should go even one more level up
-THREE.ObjectLoader.prototype = {
+ context.onLoadComplete();
- constructor: THREE.ObjectLoader,
+ } else {
- load: function ( url, onLoad, onProgress, onError ) {
+ console.error( 'THREE.JSONLoader: Couldn\'t load "' + url + '" (' + xhr.status + ')' );
- var scope = this;
+ }
- var loader = new THREE.XHRLoader( scope.manager );
- loader.setCrossOrigin( this.crossOrigin );
- loader.load( url, function ( text ) {
+ } else if ( xhr.readyState === xhr.LOADING ) {
- onLoad( scope.parse( JSON.parse( text ) ) );
+ if ( callbackProgress ) {
- }, onProgress, onError );
+ if ( length === 0 ) {
- },
+ length = xhr.getResponseHeader( 'Content-Length' );
- setCrossOrigin: function ( value ) {
+ }
- this.crossOrigin = value;
+ callbackProgress( { total: length, loaded: xhr.responseText.length } );
- },
+ }
- parse: function ( json ) {
+ } else if ( xhr.readyState === xhr.HEADERS_RECEIVED ) {
- var geometries = this.parseGeometries( json.geometries );
- var materials = this.parseMaterials( json.materials );
- var object = this.parseObject( json.object, geometries, materials );
+ if ( callbackProgress !== undefined ) {
- return object;
+ length = xhr.getResponseHeader( 'Content-Length' );
- },
+ }
- parseGeometries: function ( json ) {
+ }
- var geometries = {};
+ };
- if ( json !== undefined ) {
+ xhr.open( 'GET', url, true );
+ xhr.withCredentials = this.withCredentials;
+ xhr.send( null );
- var geometryLoader = new THREE.JSONLoader();
- var bufferGeometryLoader = new THREE.BufferGeometryLoader();
+};
- for ( var i = 0, l = json.length; i < l; i ++ ) {
+THREE.JSONLoader.prototype.parse = function ( json, texturePath ) {
- var geometry;
- var data = json[ i ];
+ var scope = this,
+ geometry = new THREE.Geometry(),
+ scale = ( json.scale !== undefined ) ? 1.0 / json.scale : 1.0;
- switch ( data.type ) {
+ parseModel( scale );
- case 'PlaneGeometry':
+ parseSkin();
+ parseMorphing( scale );
- geometry = new THREE.PlaneGeometry(
- data.width,
- data.height,
- data.widthSegments,
- data.heightSegments
- );
+ geometry.computeFaceNormals();
+ geometry.computeBoundingSphere();
- break;
+ function parseModel( scale ) {
- case 'BoxGeometry':
- case 'CubeGeometry': // backwards compatible
+ function isBitSet( value, position ) {
- geometry = new THREE.BoxGeometry(
- data.width,
- data.height,
- data.depth,
- data.widthSegments,
- data.heightSegments,
- data.depthSegments
- );
+ return value & ( 1 << position );
- break;
+ }
- case 'CircleGeometry':
+ var i, j, fi,
- geometry = new THREE.CircleGeometry(
- data.radius,
- data.segments
- );
+ offset, zLength,
- break;
+ colorIndex, normalIndex, uvIndex, materialIndex,
- case 'CylinderGeometry':
+ type,
+ isQuad,
+ hasMaterial,
+ hasFaceVertexUv,
+ hasFaceNormal, hasFaceVertexNormal,
+ hasFaceColor, hasFaceVertexColor,
- geometry = new THREE.CylinderGeometry(
- data.radiusTop,
- data.radiusBottom,
- data.height,
- data.radialSegments,
- data.heightSegments,
- data.openEnded
- );
+ vertex, face, faceA, faceB, color, hex, normal,
- break;
+ uvLayer, uv, u, v,
- case 'SphereGeometry':
+ faces = json.faces,
+ vertices = json.vertices,
+ normals = json.normals,
+ colors = json.colors,
- geometry = new THREE.SphereGeometry(
- data.radius,
- data.widthSegments,
- data.heightSegments,
- data.phiStart,
- data.phiLength,
- data.thetaStart,
- data.thetaLength
- );
+ nUvLayers = 0;
- break;
+ if ( json.uvs !== undefined ) {
- case 'IcosahedronGeometry':
+ // disregard empty arrays
- geometry = new THREE.IcosahedronGeometry(
- data.radius,
- data.detail
- );
+ for ( i = 0; i < json.uvs.length; i ++ ) {
- break;
+ if ( json.uvs[ i ].length ) nUvLayers ++;
- case 'TorusGeometry':
+ }
- geometry = new THREE.TorusGeometry(
- data.radius,
- data.tube,
- data.radialSegments,
- data.tubularSegments,
- data.arc
- );
+ for ( i = 0; i < nUvLayers; i ++ ) {
- break;
+ geometry.faceVertexUvs[ i ] = [];
- case 'TorusKnotGeometry':
+ }
- geometry = new THREE.TorusKnotGeometry(
- data.radius,
- data.tube,
- data.radialSegments,
- data.tubularSegments,
- data.p,
- data.q,
- data.heightScale
- );
+ }
- break;
+ offset = 0;
+ zLength = vertices.length;
- case 'BufferGeometry':
+ while ( offset < zLength ) {
- geometry = bufferGeometryLoader.parse( data.data );
+ vertex = new THREE.Vector3();
- break;
+ vertex.x = vertices[ offset ++ ] * scale;
+ vertex.y = vertices[ offset ++ ] * scale;
+ vertex.z = vertices[ offset ++ ] * scale;
- case 'Geometry':
+ geometry.vertices.push( vertex );
- geometry = geometryLoader.parse( data.data ).geometry;
+ }
- break;
+ offset = 0;
+ zLength = faces.length;
- }
+ while ( offset < zLength ) {
- geometry.uuid = data.uuid;
+ type = faces[ offset ++ ];
- if ( data.name !== undefined ) geometry.name = data.name;
- geometries[ data.uuid ] = geometry;
+ isQuad = isBitSet( type, 0 );
+ hasMaterial = isBitSet( type, 1 );
+ hasFaceVertexUv = isBitSet( type, 3 );
+ hasFaceNormal = isBitSet( type, 4 );
+ hasFaceVertexNormal = isBitSet( type, 5 );
+ hasFaceColor = isBitSet( type, 6 );
+ hasFaceVertexColor = isBitSet( type, 7 );
- }
+ // console.log("type", type, "bits", isQuad, hasMaterial, hasFaceVertexUv, hasFaceNormal, hasFaceVertexNormal, hasFaceColor, hasFaceVertexColor);
- }
+ if ( isQuad ) {
- return geometries;
+ faceA = new THREE.Face3();
+ faceA.a = faces[ offset ];
+ faceA.b = faces[ offset + 1 ];
+ faceA.c = faces[ offset + 3 ];
- },
+ faceB = new THREE.Face3();
+ faceB.a = faces[ offset + 1 ];
+ faceB.b = faces[ offset + 2 ];
+ faceB.c = faces[ offset + 3 ];
- parseMaterials: function ( json ) {
+ offset += 4;
- var materials = {};
+ if ( hasMaterial ) {
- if ( json !== undefined ) {
+ materialIndex = faces[ offset ++ ];
+ faceA.materialIndex = materialIndex;
+ faceB.materialIndex = materialIndex;
- var loader = new THREE.MaterialLoader();
+ }
- for ( var i = 0, l = json.length; i < l; i ++ ) {
+ // to get face <=> uv index correspondence
- var data = json[ i ];
- var material = loader.parse( data );
+ fi = geometry.faces.length;
- material.uuid = data.uuid;
+ if ( hasFaceVertexUv ) {
- if ( data.name !== undefined ) material.name = data.name;
+ for ( i = 0; i < nUvLayers; i ++ ) {
- materials[ data.uuid ] = material;
+ uvLayer = json.uvs[ i ];
- }
+ geometry.faceVertexUvs[ i ][ fi ] = [];
+ geometry.faceVertexUvs[ i ][ fi + 1 ] = []
- }
+ for ( j = 0; j < 4; j ++ ) {
- return materials;
+ uvIndex = faces[ offset ++ ];
- },
+ u = uvLayer[ uvIndex * 2 ];
+ v = uvLayer[ uvIndex * 2 + 1 ];
- parseObject: function () {
+ uv = new THREE.Vector2( u, v );
- var matrix = new THREE.Matrix4();
+ if ( j !== 2 ) geometry.faceVertexUvs[ i ][ fi ].push( uv );
+ if ( j !== 0 ) geometry.faceVertexUvs[ i ][ fi + 1 ].push( uv );
- return function ( data, geometries, materials ) {
+ }
- var object;
+ }
- switch ( data.type ) {
+ }
- case 'Scene':
+ if ( hasFaceNormal ) {
- object = new THREE.Scene();
+ normalIndex = faces[ offset ++ ] * 3;
- break;
+ faceA.normal.set(
+ normals[ normalIndex ++ ],
+ normals[ normalIndex ++ ],
+ normals[ normalIndex ]
+ );
- case 'PerspectiveCamera':
+ faceB.normal.copy( faceA.normal );
- object = new THREE.PerspectiveCamera( data.fov, data.aspect, data.near, data.far );
+ }
- break;
+ if ( hasFaceVertexNormal ) {
- case 'OrthographicCamera':
+ for ( i = 0; i < 4; i ++ ) {
- object = new THREE.OrthographicCamera( data.left, data.right, data.top, data.bottom, data.near, data.far );
+ normalIndex = faces[ offset ++ ] * 3;
- break;
+ normal = new THREE.Vector3(
+ normals[ normalIndex ++ ],
+ normals[ normalIndex ++ ],
+ normals[ normalIndex ]
+ );
- case 'AmbientLight':
- object = new THREE.AmbientLight( data.color );
+ if ( i !== 2 ) faceA.vertexNormals.push( normal );
+ if ( i !== 0 ) faceB.vertexNormals.push( normal );
- break;
+ }
- case 'DirectionalLight':
+ }
- object = new THREE.DirectionalLight( data.color, data.intensity );
- break;
+ if ( hasFaceColor ) {
- case 'PointLight':
+ colorIndex = faces[ offset ++ ];
+ hex = colors[ colorIndex ];
- object = new THREE.PointLight( data.color, data.intensity, data.distance );
+ faceA.color.setHex( hex );
+ faceB.color.setHex( hex );
- break;
+ }
- case 'SpotLight':
- object = new THREE.SpotLight( data.color, data.intensity, data.distance, data.angle, data.exponent );
+ if ( hasFaceVertexColor ) {
- break;
+ for ( i = 0; i < 4; i ++ ) {
- case 'HemisphereLight':
+ colorIndex = faces[ offset ++ ];
+ hex = colors[ colorIndex ];
- object = new THREE.HemisphereLight( data.color, data.groundColor, data.intensity );
+ if ( i !== 2 ) faceA.vertexColors.push( new THREE.Color( hex ) );
+ if ( i !== 0 ) faceB.vertexColors.push( new THREE.Color( hex ) );
- break;
+ }
- case 'Mesh':
+ }
- var geometry = geometries[ data.geometry ];
- var material = materials[ data.material ];
+ geometry.faces.push( faceA );
+ geometry.faces.push( faceB );
- if ( geometry === undefined ) {
+ } else {
- console.error( 'THREE.ObjectLoader: Undefined geometry ' + data.geometry );
+ face = new THREE.Face3();
+ face.a = faces[ offset ++ ];
+ face.b = faces[ offset ++ ];
+ face.c = faces[ offset ++ ];
- }
+ if ( hasMaterial ) {
- if ( material === undefined ) {
+ materialIndex = faces[ offset ++ ];
+ face.materialIndex = materialIndex;
- console.error( 'THREE.ObjectLoader: Undefined material ' + data.material );
+ }
- }
+ // to get face <=> uv index correspondence
- object = new THREE.Mesh( geometry, material );
+ fi = geometry.faces.length;
- break;
+ if ( hasFaceVertexUv ) {
- case 'Sprite':
+ for ( i = 0; i < nUvLayers; i ++ ) {
- var material = materials[ data.material ];
+ uvLayer = json.uvs[ i ];
- if ( material === undefined ) {
+ geometry.faceVertexUvs[ i ][ fi ] = [];
- console.error( 'THREE.ObjectLoader: Undefined material ' + data.material );
+ for ( j = 0; j < 3; j ++ ) {
- }
+ uvIndex = faces[ offset ++ ];
- object = new THREE.Sprite( material );
+ u = uvLayer[ uvIndex * 2 ];
+ v = uvLayer[ uvIndex * 2 + 1 ];
- break;
+ uv = new THREE.Vector2( u, v );
- default:
+ geometry.faceVertexUvs[ i ][ fi ].push( uv );
- object = new THREE.Object3D();
+ }
- }
+ }
- object.uuid = data.uuid;
+ }
- if ( data.name !== undefined ) object.name = data.name;
- if ( data.matrix !== undefined ) {
+ if ( hasFaceNormal ) {
- matrix.fromArray( data.matrix );
- matrix.decompose( object.position, object.quaternion, object.scale );
+ normalIndex = faces[ offset ++ ] * 3;
- } else {
+ face.normal.set(
+ normals[ normalIndex ++ ],
+ normals[ normalIndex ++ ],
+ normals[ normalIndex ]
+ );
- if ( data.position !== undefined ) object.position.fromArray( data.position );
- if ( data.rotation !== undefined ) object.rotation.fromArray( data.rotation );
- if ( data.scale !== undefined ) object.scale.fromArray( data.scale );
+ }
- }
+ if ( hasFaceVertexNormal ) {
- if ( data.visible !== undefined ) object.visible = data.visible;
- if ( data.userData !== undefined ) object.userData = data.userData;
+ for ( i = 0; i < 3; i ++ ) {
- if ( data.children !== undefined ) {
+ normalIndex = faces[ offset ++ ] * 3;
- for ( var child in data.children ) {
+ normal = new THREE.Vector3(
+ normals[ normalIndex ++ ],
+ normals[ normalIndex ++ ],
+ normals[ normalIndex ]
+ );
- object.add( this.parseObject( data.children[ child ], geometries, materials ) );
+ face.vertexNormals.push( normal );
+
+ }
}
- }
- return object;
+ if ( hasFaceColor ) {
- }
+ colorIndex = faces[ offset ++ ];
+ face.color.setHex( colors[ colorIndex ] );
- }()
+ }
-};
-// File:src/loaders/TextureLoader.js
+ if ( hasFaceVertexColor ) {
-/**
- * @author mrdoob / http://mrdoob.com/
- */
+ for ( i = 0; i < 3; i ++ ) {
-THREE.TextureLoader = function ( manager ) {
+ colorIndex = faces[ offset ++ ];
+ face.vertexColors.push( new THREE.Color( colors[ colorIndex ] ) );
- this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
+ }
-};
+ }
-THREE.TextureLoader.prototype = {
+ geometry.faces.push( face );
- constructor: THREE.TextureLoader,
+ }
- load: function ( url, onLoad, onProgress, onError ) {
+ }
- var scope = this;
+ };
- var loader = new THREE.ImageLoader( scope.manager );
- loader.setCrossOrigin( this.crossOrigin );
- loader.load( url, function ( image ) {
+ function parseSkin() {
+ var influencesPerVertex = ( json.influencesPerVertex !== undefined ) ? json.influencesPerVertex : 2;
- var texture = new THREE.Texture( image );
- texture.needsUpdate = true;
+ if ( json.skinWeights ) {
- if ( onLoad !== undefined ) {
+ for ( var i = 0, l = json.skinWeights.length; i < l; i += influencesPerVertex ) {
- onLoad( texture );
+ var x = json.skinWeights[ i ];
+ var y = ( influencesPerVertex > 1 ) ? json.skinWeights[ i + 1 ] : 0;
+ var z = ( influencesPerVertex > 2 ) ? json.skinWeights[ i + 2 ] : 0;
+ var w = ( influencesPerVertex > 3 ) ? json.skinWeights[ i + 3 ] : 0;
+
+ geometry.skinWeights.push( new THREE.Vector4( x, y, z, w ) );
}
- }, onProgress, onError );
+ }
- },
+ if ( json.skinIndices ) {
- setCrossOrigin: function ( value ) {
+ for ( var i = 0, l = json.skinIndices.length; i < l; i += influencesPerVertex ) {
- this.crossOrigin = value;
+ var a = json.skinIndices[ i ];
+ var b = ( influencesPerVertex > 1 ) ? json.skinIndices[ i + 1 ] : 0;
+ var c = ( influencesPerVertex > 2 ) ? json.skinIndices[ i + 2 ] : 0;
+ var d = ( influencesPerVertex > 3 ) ? json.skinIndices[ i + 3 ] : 0;
- }
+ geometry.skinIndices.push( new THREE.Vector4( a, b, c, d ) );
-};
+ }
-// File:src/materials/Material.js
+ }
-/**
- * @author mrdoob / http://mrdoob.com/
- * @author alteredq / http://alteredqualia.com/
- */
+ geometry.bones = json.bones;
-THREE.Material = function () {
+ if ( geometry.bones && geometry.bones.length > 0 && ( geometry.skinWeights.length !== geometry.skinIndices.length || geometry.skinIndices.length !== geometry.vertices.length ) ) {
- this.id = THREE.MaterialIdCount ++;
- this.uuid = THREE.Math.generateUUID();
+ console.warn( 'When skinning, number of vertices (' + geometry.vertices.length + '), skinIndices (' +
+ geometry.skinIndices.length + '), and skinWeights (' + geometry.skinWeights.length + ') should match.' );
- this.name = '';
+ }
- this.side = THREE.FrontSide;
- this.opacity = 1;
- this.transparent = false;
+ // could change this to json.animations[0] or remove completely
- this.blending = THREE.NormalBlending;
+ geometry.animation = json.animation;
+ geometry.animations = json.animations;
- this.blendSrc = THREE.SrcAlphaFactor;
- this.blendDst = THREE.OneMinusSrcAlphaFactor;
- this.blendEquation = THREE.AddEquation;
+ };
- this.depthTest = true;
- this.depthWrite = true;
+ function parseMorphing( scale ) {
- this.polygonOffset = false;
- this.polygonOffsetFactor = 0;
- this.polygonOffsetUnits = 0;
+ if ( json.morphTargets !== undefined ) {
- this.alphaTest = 0;
+ var i, l, v, vl, dstVertices, srcVertices;
- this.overdraw = 0; // Overdrawn pixels (typically between 0 and 1) for fixing antialiasing gaps in CanvasRenderer
+ for ( i = 0, l = json.morphTargets.length; i < l; i ++ ) {
- this.visible = true;
+ geometry.morphTargets[ i ] = {};
+ geometry.morphTargets[ i ].name = json.morphTargets[ i ].name;
+ geometry.morphTargets[ i ].vertices = [];
- this.needsUpdate = true;
+ dstVertices = geometry.morphTargets[ i ].vertices;
+ srcVertices = json.morphTargets [ i ].vertices;
-};
+ for ( v = 0, vl = srcVertices.length; v < vl; v += 3 ) {
-THREE.Material.prototype = {
+ var vertex = new THREE.Vector3();
+ vertex.x = srcVertices[ v ] * scale;
+ vertex.y = srcVertices[ v + 1 ] * scale;
+ vertex.z = srcVertices[ v + 2 ] * scale;
- constructor: THREE.Material,
+ dstVertices.push( vertex );
- setValues: function ( values ) {
+ }
- if ( values === undefined ) return;
+ }
- for ( var key in values ) {
+ }
- var newValue = values[ key ];
+ if ( json.morphColors !== undefined ) {
- if ( newValue === undefined ) {
+ var i, l, c, cl, dstColors, srcColors, color;
- console.warn( "THREE.Material: '" + key + "' parameter is undefined." );
- continue;
+ for ( i = 0, l = json.morphColors.length; i < l; i ++ ) {
- }
+ geometry.morphColors[ i ] = {};
+ geometry.morphColors[ i ].name = json.morphColors[ i ].name;
+ geometry.morphColors[ i ].colors = [];
- if ( key in this ) {
+ dstColors = geometry.morphColors[ i ].colors;
+ srcColors = json.morphColors [ i ].colors;
- var currentValue = this[ key ];
+ for ( c = 0, cl = srcColors.length; c < cl; c += 3 ) {
- if ( currentValue instanceof THREE.Color ) {
+ color = new THREE.Color( 0xffaa00 );
+ color.setRGB( srcColors[ c ], srcColors[ c + 1 ], srcColors[ c + 2 ] );
+ dstColors.push( color );
- currentValue.set( newValue );
+ }
- } else if ( currentValue instanceof THREE.Vector3 && newValue instanceof THREE.Vector3 ) {
+ }
- currentValue.copy( newValue );
+ }
- } else if ( key == 'overdraw' ) {
+ };
- // ensure overdraw is backwards-compatable with legacy boolean type
- this[ key ] = Number( newValue );
+ if ( json.materials === undefined || json.materials.length === 0 ) {
- } else {
+ return { geometry: geometry };
- this[ key ] = newValue;
+ } else {
- }
+ var materials = this.initMaterials( json.materials, texturePath );
- }
+ if ( this.needsTangents( materials ) ) {
+
+ geometry.computeTangents();
}
- },
+ return { geometry: geometry, materials: materials };
- clone: function ( material ) {
+ }
- if ( material === undefined ) material = new THREE.Material();
+};
- material.name = this.name;
+// File:src/loaders/LoadingManager.js
- material.side = this.side;
+/**
+ * @author mrdoob / http://mrdoob.com/
+ */
- material.opacity = this.opacity;
- material.transparent = this.transparent;
+THREE.LoadingManager = function ( onLoad, onProgress, onError ) {
- material.blending = this.blending;
+ var scope = this;
- material.blendSrc = this.blendSrc;
- material.blendDst = this.blendDst;
- material.blendEquation = this.blendEquation;
+ var loaded = 0, total = 0;
- material.depthTest = this.depthTest;
- material.depthWrite = this.depthWrite;
+ this.onLoad = onLoad;
+ this.onProgress = onProgress;
+ this.onError = onError;
- material.polygonOffset = this.polygonOffset;
- material.polygonOffsetFactor = this.polygonOffsetFactor;
- material.polygonOffsetUnits = this.polygonOffsetUnits;
+ this.itemStart = function ( url ) {
- material.alphaTest = this.alphaTest;
+ total ++;
- material.overdraw = this.overdraw;
+ };
- material.visible = this.visible;
+ this.itemEnd = function ( url ) {
- return material;
+ loaded ++;
- },
+ if ( scope.onProgress !== undefined ) {
- dispose: function () {
+ scope.onProgress( url, loaded, total );
- this.dispatchEvent( { type: 'dispose' } );
+ }
- }
+ if ( loaded === total && scope.onLoad !== undefined ) {
-};
+ scope.onLoad();
-THREE.EventDispatcher.prototype.apply( THREE.Material.prototype );
+ }
-THREE.MaterialIdCount = 0;
+ };
-// File:src/materials/LineBasicMaterial.js
+};
+
+THREE.DefaultLoadingManager = new THREE.LoadingManager();
+
+// File:src/loaders/BufferGeometryLoader.js
/**
* @author mrdoob / http://mrdoob.com/
- * @author alteredq / http://alteredqualia.com/
- *
- * parameters = {
- * color: ,
- * opacity: ,
- *
- * blending: THREE.NormalBlending,
- * depthTest: ,
- * depthWrite: ,
- *
- * linewidth: ,
- * linecap: "round",
- * linejoin: "round",
- *
- * vertexColors:
- *
- * fog:
- * }
*/
-THREE.LineBasicMaterial = function ( parameters ) {
-
- THREE.Material.call( this );
-
- this.color = new THREE.Color( 0xffffff );
-
- this.linewidth = 1;
- this.linecap = 'round';
- this.linejoin = 'round';
-
- this.vertexColors = THREE.NoColors;
-
- this.fog = true;
+THREE.BufferGeometryLoader = function ( manager ) {
- this.setValues( parameters );
+ this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
};
-THREE.LineBasicMaterial.prototype = Object.create( THREE.Material.prototype );
+THREE.BufferGeometryLoader.prototype = {
-THREE.LineBasicMaterial.prototype.clone = function () {
+ constructor: THREE.BufferGeometryLoader,
- var material = new THREE.LineBasicMaterial();
+ load: function ( url, onLoad, onProgress, onError ) {
- THREE.Material.prototype.clone.call( this, material );
+ var scope = this;
- material.color.copy( this.color );
+ var loader = new THREE.XHRLoader();
+ loader.setCrossOrigin( this.crossOrigin );
+ loader.load( url, function ( text ) {
- material.linewidth = this.linewidth;
- material.linecap = this.linecap;
- material.linejoin = this.linejoin;
+ onLoad( scope.parse( JSON.parse( text ) ) );
- material.vertexColors = this.vertexColors;
+ }, onProgress, onError );
- material.fog = this.fog;
+ },
- return material;
+ setCrossOrigin: function ( value ) {
-};
+ this.crossOrigin = value;
-// File:src/materials/LineDashedMaterial.js
+ },
-/**
- * @author alteredq / http://alteredqualia.com/
- *
- * parameters = {
- * color: ,
- * opacity: ,
- *
- * blending: THREE.NormalBlending,
- * depthTest: ,
- * depthWrite: ,
- *
- * linewidth: ,
- *
- * scale: ,
- * dashSize: ,
- * gapSize: ,
- *
- * vertexColors:
- *
- * fog:
- * }
- */
+ parse: function ( json ) {
-THREE.LineDashedMaterial = function ( parameters ) {
+ var geometry = new THREE.BufferGeometry();
- THREE.Material.call( this );
+ var attributes = json.attributes;
- this.color = new THREE.Color( 0xffffff );
+ for ( var key in attributes ) {
- this.linewidth = 1;
+ var attribute = attributes[ key ];
+ var typedArray = new self[ attribute.type ]( attribute.array );
- this.scale = 1;
- this.dashSize = 3;
- this.gapSize = 1;
+ geometry.addAttribute( key, new THREE.BufferAttribute( typedArray, attribute.itemSize ) );
- this.vertexColors = false;
+ }
- this.fog = true;
+ var offsets = json.offsets;
- this.setValues( parameters );
+ if ( offsets !== undefined ) {
-};
+ geometry.offsets = JSON.parse( JSON.stringify( offsets ) );
-THREE.LineDashedMaterial.prototype = Object.create( THREE.Material.prototype );
+ }
-THREE.LineDashedMaterial.prototype.clone = function () {
+ var boundingSphere = json.boundingSphere;
- var material = new THREE.LineDashedMaterial();
+ if ( boundingSphere !== undefined ) {
- THREE.Material.prototype.clone.call( this, material );
+ var center = new THREE.Vector3();
- material.color.copy( this.color );
+ if ( boundingSphere.center !== undefined ) {
- material.linewidth = this.linewidth;
+ center.fromArray( boundingSphere.center );
- material.scale = this.scale;
- material.dashSize = this.dashSize;
- material.gapSize = this.gapSize;
+ }
- material.vertexColors = this.vertexColors;
+ geometry.boundingSphere = new THREE.Sphere( center, boundingSphere.radius );
- material.fog = this.fog;
+ }
- return material;
+ return geometry;
+
+ }
};
-// File:src/materials/MeshBasicMaterial.js
+// File:src/loaders/MaterialLoader.js
/**
* @author mrdoob / http://mrdoob.com/
- * @author alteredq / http://alteredqualia.com/
- *
- * parameters = {
- * color: ,
- * opacity: ,
- * map: new THREE.Texture( ),
- *
- * lightMap: new THREE.Texture( ),
- *
- * specularMap: new THREE.Texture( ),
- *
- * alphaMap: new THREE.Texture( ),
- *
- * envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ),
- * combine: THREE.Multiply,
- * reflectivity: ,
- * refractionRatio: ,
- *
- * shading: THREE.SmoothShading,
- * blending: THREE.NormalBlending,
- * depthTest: ,
- * depthWrite: ,
- *
- * wireframe: ,
- * wireframeLinewidth: ,
- *
- * vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors,
- *
- * skinning: ,
- * morphTargets: ,
- *
- * fog:
- * }
*/
-THREE.MeshBasicMaterial = function ( parameters ) {
+THREE.MaterialLoader = function ( manager ) {
- THREE.Material.call( this );
+ this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
- this.color = new THREE.Color( 0xffffff ); // emissive
+};
- this.map = null;
+THREE.MaterialLoader.prototype = {
- this.lightMap = null;
+ constructor: THREE.MaterialLoader,
- this.specularMap = null;
+ load: function ( url, onLoad, onProgress, onError ) {
- this.alphaMap = null;
+ var scope = this;
- this.envMap = null;
- this.combine = THREE.MultiplyOperation;
- this.reflectivity = 1;
- this.refractionRatio = 0.98;
+ var loader = new THREE.XHRLoader();
+ loader.setCrossOrigin( this.crossOrigin );
+ loader.load( url, function ( text ) {
- this.fog = true;
+ onLoad( scope.parse( JSON.parse( text ) ) );
- this.shading = THREE.SmoothShading;
+ }, onProgress, onError );
- this.wireframe = false;
- this.wireframeLinewidth = 1;
- this.wireframeLinecap = 'round';
- this.wireframeLinejoin = 'round';
+ },
- this.vertexColors = THREE.NoColors;
+ setCrossOrigin: function ( value ) {
- this.skinning = false;
- this.morphTargets = false;
+ this.crossOrigin = value;
- this.setValues( parameters );
+ },
-};
+ parse: function ( json ) {
-THREE.MeshBasicMaterial.prototype = Object.create( THREE.Material.prototype );
+ var material = new THREE[ json.type ];
-THREE.MeshBasicMaterial.prototype.clone = function () {
+ if ( json.color !== undefined ) material.color.setHex( json.color );
+ if ( json.ambient !== undefined ) material.ambient.setHex( json.ambient );
+ if ( json.emissive !== undefined ) material.emissive.setHex( json.emissive );
+ if ( json.specular !== undefined ) material.specular.setHex( json.specular );
+ if ( json.shininess !== undefined ) material.shininess = json.shininess;
+ if ( json.uniforms !== undefined ) material.uniforms = json.uniforms;
+ if ( json.vertexShader !== undefined ) material.vertexShader = json.vertexShader;
+ if ( json.fragmentShader !== undefined ) material.fragmentShader = json.fragmentShader;
+ if ( json.vertexColors !== undefined ) material.vertexColors = json.vertexColors;
+ if ( json.shading !== undefined ) material.shading = json.shading;
+ if ( json.blending !== undefined ) material.blending = json.blending;
+ if ( json.side !== undefined ) material.side = json.side;
+ if ( json.opacity !== undefined ) material.opacity = json.opacity;
+ if ( json.transparent !== undefined ) material.transparent = json.transparent;
+ if ( json.wireframe !== undefined ) material.wireframe = json.wireframe;
- var material = new THREE.MeshBasicMaterial();
+ if ( json.materials !== undefined ) {
- THREE.Material.prototype.clone.call( this, material );
+ for ( var i = 0, l = json.materials.length; i < l; i ++ ) {
- material.color.copy( this.color );
+ material.materials.push( this.parse( json.materials[ i ] ) );
- material.map = this.map;
+ }
- material.lightMap = this.lightMap;
+ }
- material.specularMap = this.specularMap;
+ return material;
- material.alphaMap = this.alphaMap;
+ }
- material.envMap = this.envMap;
- material.combine = this.combine;
- material.reflectivity = this.reflectivity;
- material.refractionRatio = this.refractionRatio;
+};
- material.fog = this.fog;
+// File:src/loaders/ObjectLoader.js
- material.shading = this.shading;
+/**
+ * @author mrdoob / http://mrdoob.com/
+ */
- material.wireframe = this.wireframe;
- material.wireframeLinewidth = this.wireframeLinewidth;
- material.wireframeLinecap = this.wireframeLinecap;
- material.wireframeLinejoin = this.wireframeLinejoin;
+THREE.ObjectLoader = function ( manager ) {
- material.vertexColors = this.vertexColors;
+ this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
- material.skinning = this.skinning;
- material.morphTargets = this.morphTargets;
+};
- return material;
+THREE.ObjectLoader.prototype = {
-};
+ constructor: THREE.ObjectLoader,
-// File:src/materials/MeshLambertMaterial.js
+ load: function ( url, onLoad, onProgress, onError ) {
-/**
- * @author mrdoob / http://mrdoob.com/
- * @author alteredq / http://alteredqualia.com/
- *
- * parameters = {
- * color: ,
- * ambient: ,
- * emissive: ,
- * opacity: ,
- *
- * map: new THREE.Texture( ),
- *
- * lightMap: new THREE.Texture( ),
- *
- * specularMap: new THREE.Texture( ),
- *
- * alphaMap: new THREE.Texture( ),
- *
- * envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ),
- * combine: THREE.Multiply,
- * reflectivity: ,
- * refractionRatio: ,
- *
- * shading: THREE.SmoothShading,
- * blending: THREE.NormalBlending,
- * depthTest: ,
- * depthWrite: ,
- *
- * wireframe: ,
- * wireframeLinewidth: ,
- *
- * vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors,
- *
- * skinning: ,
- * morphTargets: ,
- * morphNormals: ,
- *
- * fog:
- * }
- */
+ var scope = this;
-THREE.MeshLambertMaterial = function ( parameters ) {
+ var loader = new THREE.XHRLoader( scope.manager );
+ loader.setCrossOrigin( this.crossOrigin );
+ loader.load( url, function ( text ) {
- THREE.Material.call( this );
+ onLoad( scope.parse( JSON.parse( text ) ) );
- this.color = new THREE.Color( 0xffffff ); // diffuse
- this.ambient = new THREE.Color( 0xffffff );
- this.emissive = new THREE.Color( 0x000000 );
+ }, onProgress, onError );
- this.wrapAround = false;
- this.wrapRGB = new THREE.Vector3( 1, 1, 1 );
+ },
- this.map = null;
+ setCrossOrigin: function ( value ) {
- this.lightMap = null;
+ this.crossOrigin = value;
- this.specularMap = null;
+ },
- this.alphaMap = null;
+ parse: function ( json ) {
- this.envMap = null;
- this.combine = THREE.MultiplyOperation;
- this.reflectivity = 1;
- this.refractionRatio = 0.98;
+ var geometries = this.parseGeometries( json.geometries );
+ var materials = this.parseMaterials( json.materials );
+ var object = this.parseObject( json.object, geometries, materials );
- this.fog = true;
+ return object;
- this.shading = THREE.SmoothShading;
+ },
- this.wireframe = false;
- this.wireframeLinewidth = 1;
- this.wireframeLinecap = 'round';
- this.wireframeLinejoin = 'round';
+ parseGeometries: function ( json ) {
- this.vertexColors = THREE.NoColors;
+ var geometries = {};
- this.skinning = false;
- this.morphTargets = false;
- this.morphNormals = false;
+ if ( json !== undefined ) {
- this.setValues( parameters );
+ var geometryLoader = new THREE.JSONLoader();
+ var bufferGeometryLoader = new THREE.BufferGeometryLoader();
-};
+ for ( var i = 0, l = json.length; i < l; i ++ ) {
-THREE.MeshLambertMaterial.prototype = Object.create( THREE.Material.prototype );
+ var geometry;
+ var data = json[ i ];
-THREE.MeshLambertMaterial.prototype.clone = function () {
+ switch ( data.type ) {
- var material = new THREE.MeshLambertMaterial();
+ case 'PlaneGeometry':
- THREE.Material.prototype.clone.call( this, material );
+ geometry = new THREE.PlaneGeometry(
+ data.width,
+ data.height,
+ data.widthSegments,
+ data.heightSegments
+ );
- material.color.copy( this.color );
- material.ambient.copy( this.ambient );
- material.emissive.copy( this.emissive );
+ break;
- material.wrapAround = this.wrapAround;
- material.wrapRGB.copy( this.wrapRGB );
+ case 'BoxGeometry':
+ case 'CubeGeometry': // backwards compatible
- material.map = this.map;
+ geometry = new THREE.BoxGeometry(
+ data.width,
+ data.height,
+ data.depth,
+ data.widthSegments,
+ data.heightSegments,
+ data.depthSegments
+ );
- material.lightMap = this.lightMap;
+ break;
- material.specularMap = this.specularMap;
+ case 'CircleGeometry':
- material.alphaMap = this.alphaMap;
+ geometry = new THREE.CircleGeometry(
+ data.radius,
+ data.segments
+ );
- material.envMap = this.envMap;
- material.combine = this.combine;
- material.reflectivity = this.reflectivity;
- material.refractionRatio = this.refractionRatio;
+ break;
- material.fog = this.fog;
+ case 'CylinderGeometry':
- material.shading = this.shading;
+ geometry = new THREE.CylinderGeometry(
+ data.radiusTop,
+ data.radiusBottom,
+ data.height,
+ data.radialSegments,
+ data.heightSegments,
+ data.openEnded
+ );
- material.wireframe = this.wireframe;
- material.wireframeLinewidth = this.wireframeLinewidth;
- material.wireframeLinecap = this.wireframeLinecap;
- material.wireframeLinejoin = this.wireframeLinejoin;
+ break;
- material.vertexColors = this.vertexColors;
+ case 'SphereGeometry':
- material.skinning = this.skinning;
- material.morphTargets = this.morphTargets;
- material.morphNormals = this.morphNormals;
+ geometry = new THREE.SphereGeometry(
+ data.radius,
+ data.widthSegments,
+ data.heightSegments,
+ data.phiStart,
+ data.phiLength,
+ data.thetaStart,
+ data.thetaLength
+ );
- return material;
+ break;
-};
+ case 'IcosahedronGeometry':
-// File:src/materials/MeshPhongMaterial.js
+ geometry = new THREE.IcosahedronGeometry(
+ data.radius,
+ data.detail
+ );
-/**
- * @author mrdoob / http://mrdoob.com/
- * @author alteredq / http://alteredqualia.com/
- *
- * parameters = {
- * color: ,
- * ambient: ,
- * emissive: ,
- * specular: ,
- * shininess: ,
- * opacity: ,
- *
- * map: new THREE.Texture( ),
- *
- * lightMap: new THREE.Texture( ),
- *
- * bumpMap: new THREE.Texture( ),
- * bumpScale: ,
- *
- * normalMap: new THREE.Texture( ),
- * normalScale: ,
- *
- * specularMap: new THREE.Texture( ),
- *
- * alphaMap: new THREE.Texture( ),
- *
- * envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ),
- * combine: THREE.Multiply,
- * reflectivity: ,
- * refractionRatio: ,
- *
- * shading: THREE.SmoothShading,
- * blending: THREE.NormalBlending,
- * depthTest: ,
- * depthWrite: ,
- *
- * wireframe: ,
- * wireframeLinewidth: ,
- *
- * vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors,
- *
- * skinning: ,
- * morphTargets: ,
- * morphNormals: ,
- *
- * fog:
- * }
- */
+ break;
-THREE.MeshPhongMaterial = function ( parameters ) {
+ case 'TorusGeometry':
- THREE.Material.call( this );
+ geometry = new THREE.TorusGeometry(
+ data.radius,
+ data.tube,
+ data.radialSegments,
+ data.tubularSegments,
+ data.arc
+ );
- this.color = new THREE.Color( 0xffffff ); // diffuse
- this.ambient = new THREE.Color( 0xffffff );
- this.emissive = new THREE.Color( 0x000000 );
- this.specular = new THREE.Color( 0x111111 );
- this.shininess = 30;
+ break;
- this.metal = false;
+ case 'TorusKnotGeometry':
- this.wrapAround = false;
- this.wrapRGB = new THREE.Vector3( 1, 1, 1 );
+ geometry = new THREE.TorusKnotGeometry(
+ data.radius,
+ data.tube,
+ data.radialSegments,
+ data.tubularSegments,
+ data.p,
+ data.q,
+ data.heightScale
+ );
- this.map = null;
+ break;
- this.lightMap = null;
+ case 'BufferGeometry':
- this.bumpMap = null;
- this.bumpScale = 1;
+ geometry = bufferGeometryLoader.parse( data.data );
- this.normalMap = null;
- this.normalScale = new THREE.Vector2( 1, 1 );
+ break;
- this.specularMap = null;
+ case 'Geometry':
- this.alphaMap = null;
+ geometry = geometryLoader.parse( data.data ).geometry;
- this.envMap = null;
- this.combine = THREE.MultiplyOperation;
- this.reflectivity = 1;
- this.refractionRatio = 0.98;
+ break;
- this.fog = true;
+ }
- this.shading = THREE.SmoothShading;
+ geometry.uuid = data.uuid;
- this.wireframe = false;
- this.wireframeLinewidth = 1;
- this.wireframeLinecap = 'round';
- this.wireframeLinejoin = 'round';
+ if ( data.name !== undefined ) geometry.name = data.name;
- this.vertexColors = THREE.NoColors;
+ geometries[ data.uuid ] = geometry;
- this.skinning = false;
- this.morphTargets = false;
- this.morphNormals = false;
+ }
- this.setValues( parameters );
+ }
-};
+ return geometries;
-THREE.MeshPhongMaterial.prototype = Object.create( THREE.Material.prototype );
+ },
-THREE.MeshPhongMaterial.prototype.clone = function () {
+ parseMaterials: function ( json ) {
- var material = new THREE.MeshPhongMaterial();
+ var materials = {};
- THREE.Material.prototype.clone.call( this, material );
+ if ( json !== undefined ) {
- material.color.copy( this.color );
- material.ambient.copy( this.ambient );
- material.emissive.copy( this.emissive );
- material.specular.copy( this.specular );
- material.shininess = this.shininess;
+ var loader = new THREE.MaterialLoader();
- material.metal = this.metal;
+ for ( var i = 0, l = json.length; i < l; i ++ ) {
- material.wrapAround = this.wrapAround;
- material.wrapRGB.copy( this.wrapRGB );
+ var data = json[ i ];
+ var material = loader.parse( data );
- material.map = this.map;
+ material.uuid = data.uuid;
- material.lightMap = this.lightMap;
+ if ( data.name !== undefined ) material.name = data.name;
- material.bumpMap = this.bumpMap;
- material.bumpScale = this.bumpScale;
+ materials[ data.uuid ] = material;
- material.normalMap = this.normalMap;
- material.normalScale.copy( this.normalScale );
+ }
- material.specularMap = this.specularMap;
+ }
- material.alphaMap = this.alphaMap;
+ return materials;
- material.envMap = this.envMap;
- material.combine = this.combine;
- material.reflectivity = this.reflectivity;
- material.refractionRatio = this.refractionRatio;
+ },
- material.fog = this.fog;
+ parseObject: function () {
- material.shading = this.shading;
+ var matrix = new THREE.Matrix4();
- material.wireframe = this.wireframe;
- material.wireframeLinewidth = this.wireframeLinewidth;
- material.wireframeLinecap = this.wireframeLinecap;
- material.wireframeLinejoin = this.wireframeLinejoin;
+ return function ( data, geometries, materials ) {
- material.vertexColors = this.vertexColors;
+ var object;
- material.skinning = this.skinning;
- material.morphTargets = this.morphTargets;
- material.morphNormals = this.morphNormals;
+ switch ( data.type ) {
- return material;
+ case 'Scene':
-};
+ object = new THREE.Scene();
-// File:src/materials/MeshDepthMaterial.js
+ break;
-/**
- * @author mrdoob / http://mrdoob.com/
- * @author alteredq / http://alteredqualia.com/
- *
- * parameters = {
- * opacity: ,
- *
- * blending: THREE.NormalBlending,
- * depthTest: ,
- * depthWrite: ,
- *
- * wireframe: ,
- * wireframeLinewidth:
- * }
- */
+ case 'PerspectiveCamera':
-THREE.MeshDepthMaterial = function ( parameters ) {
+ object = new THREE.PerspectiveCamera( data.fov, data.aspect, data.near, data.far );
- THREE.Material.call( this );
+ break;
- this.morphTargets = false;
- this.wireframe = false;
- this.wireframeLinewidth = 1;
+ case 'OrthographicCamera':
- this.setValues( parameters );
+ object = new THREE.OrthographicCamera( data.left, data.right, data.top, data.bottom, data.near, data.far );
-};
+ break;
-THREE.MeshDepthMaterial.prototype = Object.create( THREE.Material.prototype );
+ case 'AmbientLight':
-THREE.MeshDepthMaterial.prototype.clone = function () {
+ object = new THREE.AmbientLight( data.color );
- var material = new THREE.MeshDepthMaterial();
+ break;
- THREE.Material.prototype.clone.call( this, material );
+ case 'DirectionalLight':
- material.wireframe = this.wireframe;
- material.wireframeLinewidth = this.wireframeLinewidth;
+ object = new THREE.DirectionalLight( data.color, data.intensity );
- return material;
+ break;
-};
+ case 'PointLight':
-// File:src/materials/MeshNormalMaterial.js
+ object = new THREE.PointLight( data.color, data.intensity, data.distance );
-/**
- * @author mrdoob / http://mrdoob.com/
- *
- * parameters = {
- * opacity: ,
- *
- * shading: THREE.FlatShading,
- * blending: THREE.NormalBlending,
- * depthTest: ,
- * depthWrite: ,
- *
- * wireframe: ,
- * wireframeLinewidth:
- * }
- */
+ break;
-THREE.MeshNormalMaterial = function ( parameters ) {
+ case 'SpotLight':
- THREE.Material.call( this, parameters );
+ object = new THREE.SpotLight( data.color, data.intensity, data.distance, data.angle, data.exponent );
- this.shading = THREE.FlatShading;
+ break;
- this.wireframe = false;
- this.wireframeLinewidth = 1;
+ case 'HemisphereLight':
- this.morphTargets = false;
+ object = new THREE.HemisphereLight( data.color, data.groundColor, data.intensity );
- this.setValues( parameters );
+ break;
-};
+ case 'Mesh':
-THREE.MeshNormalMaterial.prototype = Object.create( THREE.Material.prototype );
+ var geometry = geometries[ data.geometry ];
+ var material = materials[ data.material ];
-THREE.MeshNormalMaterial.prototype.clone = function () {
+ if ( geometry === undefined ) {
- var material = new THREE.MeshNormalMaterial();
+ console.warn( 'THREE.ObjectLoader: Undefined geometry', data.geometry );
- THREE.Material.prototype.clone.call( this, material );
+ }
- material.shading = this.shading;
+ if ( material === undefined ) {
- material.wireframe = this.wireframe;
- material.wireframeLinewidth = this.wireframeLinewidth;
+ console.warn( 'THREE.ObjectLoader: Undefined material', data.material );
- return material;
+ }
-};
+ object = new THREE.Mesh( geometry, material );
-// File:src/materials/MeshFaceMaterial.js
+ break;
-/**
- * @author mrdoob / http://mrdoob.com/
- */
+ case 'Line':
-THREE.MeshFaceMaterial = function ( materials ) {
+ var geometry = geometries[ data.geometry ];
+ var material = materials[ data.material ];
- this.materials = materials instanceof Array ? materials : [];
+ if ( geometry === undefined ) {
-};
+ console.warn( 'THREE.ObjectLoader: Undefined geometry', data.geometry );
-THREE.MeshFaceMaterial.prototype.clone = function () {
+ }
- var material = new THREE.MeshFaceMaterial();
+ if ( material === undefined ) {
- for ( var i = 0; i < this.materials.length; i ++ ) {
+ console.warn( 'THREE.ObjectLoader: Undefined material', data.material );
- material.materials.push( this.materials[ i ].clone() );
+ }
- }
+ object = new THREE.Line( geometry, material );
- return material;
+ break;
-};
+ case 'Sprite':
-// File:src/materials/PointCloudMaterial.js
-
-/**
- * @author mrdoob / http://mrdoob.com/
- * @author alteredq / http://alteredqualia.com/
- *
- * parameters = {
- * color: ,
- * opacity: ,
- * map: new THREE.Texture( ),
- *
- * size: ,
- *
- * blending: THREE.NormalBlending,
- * depthTest: ,
- * depthWrite: ,
- *
- * vertexColors: ,
- *
- * fog:
- * }
- */
+ var material = materials[ data.material ];
-THREE.PointCloudMaterial = function ( parameters ) {
+ if ( material === undefined ) {
- THREE.Material.call( this );
+ console.warn( 'THREE.ObjectLoader: Undefined material', data.material );
- this.color = new THREE.Color( 0xffffff );
+ }
- this.map = null;
+ object = new THREE.Sprite( material );
- this.size = 1;
- this.sizeAttenuation = true;
+ break;
- this.vertexColors = THREE.NoColors;
+ case 'Group':
- this.fog = true;
+ object = new THREE.Group();
- this.setValues( parameters );
+ break;
-};
+ default:
-THREE.PointCloudMaterial.prototype = Object.create( THREE.Material.prototype );
+ object = new THREE.Object3D();
-THREE.PointCloudMaterial.prototype.clone = function () {
+ }
- var material = new THREE.PointCloudMaterial();
+ object.uuid = data.uuid;
- THREE.Material.prototype.clone.call( this, material );
+ if ( data.name !== undefined ) object.name = data.name;
+ if ( data.matrix !== undefined ) {
- material.color.copy( this.color );
+ matrix.fromArray( data.matrix );
+ matrix.decompose( object.position, object.quaternion, object.scale );
- material.map = this.map;
+ } else {
- material.size = this.size;
- material.sizeAttenuation = this.sizeAttenuation;
+ if ( data.position !== undefined ) object.position.fromArray( data.position );
+ if ( data.rotation !== undefined ) object.rotation.fromArray( data.rotation );
+ if ( data.scale !== undefined ) object.scale.fromArray( data.scale );
- material.vertexColors = this.vertexColors;
+ }
- material.fog = this.fog;
+ if ( data.visible !== undefined ) object.visible = data.visible;
+ if ( data.userData !== undefined ) object.userData = data.userData;
- return material;
+ if ( data.children !== undefined ) {
-};
+ for ( var child in data.children ) {
-// backwards compatibility
+ object.add( this.parseObject( data.children[ child ], geometries, materials ) );
-THREE.ParticleBasicMaterial = function ( parameters ) {
+ }
- console.warn( 'THREE.ParticleBasicMaterial has been renamed to THREE.PointCloudMaterial.' );
- return new THREE.PointCloudMaterial( parameters );
+ }
-};
+ return object;
-THREE.ParticleSystemMaterial = function ( parameters ) {
+ }
- console.warn( 'THREE.ParticleSystemMaterial has been renamed to THREE.PointCloudMaterial.' );
- return new THREE.PointCloudMaterial( parameters );
+ }()
};
-// File:src/materials/ShaderMaterial.js
+// File:src/loaders/TextureLoader.js
/**
- * @author alteredq / http://alteredqualia.com/
- *
- * parameters = {
- * defines: { "label" : "value" },
- * uniforms: { "parameter1": { type: "f", value: 1.0 }, "parameter2": { type: "i" value2: 2 } },
- *
- * fragmentShader: ,
- * vertexShader: ,
- *
- * shading: THREE.SmoothShading,
- * blending: THREE.NormalBlending,
- * depthTest: ,
- * depthWrite: ,
- *
- * wireframe: ,
- * wireframeLinewidth: ,
- *
- * lights: ,
- *
- * vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors,
- *
- * skinning: ,
- * morphTargets: ,
- * morphNormals: ,
- *
- * fog:
- * }
+ * @author mrdoob / http://mrdoob.com/
*/
-THREE.ShaderMaterial = function ( parameters ) {
+THREE.TextureLoader = function ( manager ) {
- THREE.Material.call( this );
+ this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
- this.defines = {};
- this.uniforms = {};
- this.attributes = null;
+};
- this.vertexShader = 'void main() {\n\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}';
- this.fragmentShader = 'void main() {\n\tgl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );\n}';
+THREE.TextureLoader.prototype = {
- this.shading = THREE.SmoothShading;
+ constructor: THREE.TextureLoader,
- this.linewidth = 1;
+ load: function ( url, onLoad, onProgress, onError ) {
- this.wireframe = false;
- this.wireframeLinewidth = 1;
+ var scope = this;
- this.fog = false; // set to use scene fog
+ var loader = new THREE.ImageLoader( scope.manager );
+ loader.setCrossOrigin( this.crossOrigin );
+ loader.load( url, function ( image ) {
- this.lights = false; // set to use scene lights
+ var texture = new THREE.Texture( image );
+ texture.needsUpdate = true;
- this.vertexColors = THREE.NoColors; // set to use "color" attribute stream
+ if ( onLoad !== undefined ) {
- this.skinning = false; // set to use skinning attribute streams
+ onLoad( texture );
- this.morphTargets = false; // set to use morph targets
- this.morphNormals = false; // set to use morph normals
+ }
- // When rendered geometry doesn't include these attributes but the material does,
- // use these default values in WebGL. This avoids errors when buffer data is missing.
- this.defaultAttributeValues = {
- 'color': [ 1, 1, 1 ],
- 'uv': [ 0, 0 ],
- 'uv2': [ 0, 0 ]
- };
+ }, onProgress, onError );
- this.index0AttributeName = undefined;
+ },
- this.setValues( parameters );
+ setCrossOrigin: function ( value ) {
-};
+ this.crossOrigin = value;
-THREE.ShaderMaterial.prototype = Object.create( THREE.Material.prototype );
+ }
-THREE.ShaderMaterial.prototype.clone = function () {
+};
- var material = new THREE.ShaderMaterial();
+// File:src/loaders/CompressedTextureLoader.js
- THREE.Material.prototype.clone.call( this, material );
+/**
+ * @author mrdoob / http://mrdoob.com/
+ *
+ * Abstract Base class to block based textures loader (dds, pvr, ...)
+ */
- material.fragmentShader = this.fragmentShader;
- material.vertexShader = this.vertexShader;
+THREE.CompressedTextureLoader = function () {
- material.uniforms = THREE.UniformsUtils.clone( this.uniforms );
+ // override in sub classes
+ this._parser = null;
- material.attributes = this.attributes;
- material.defines = this.defines;
+};
- material.shading = this.shading;
- material.wireframe = this.wireframe;
- material.wireframeLinewidth = this.wireframeLinewidth;
+THREE.CompressedTextureLoader.prototype = {
- material.fog = this.fog;
+ constructor: THREE.CompressedTextureLoader,
- material.lights = this.lights;
+ load: function ( url, onLoad, onError ) {
- material.vertexColors = this.vertexColors;
+ var scope = this;
- material.skinning = this.skinning;
+ var images = [];
- material.morphTargets = this.morphTargets;
- material.morphNormals = this.morphNormals;
+ var texture = new THREE.CompressedTexture();
+ texture.image = images;
- return material;
+ var loader = new THREE.XHRLoader();
+ loader.setResponseType( 'arraybuffer' );
-};
+ if ( url instanceof Array ) {
-// File:src/materials/RawShaderMaterial.js
+ var loaded = 0;
-/**
- * @author mrdoob / http://mrdoob.com/
- */
+ var loadTexture = function ( i ) {
-THREE.RawShaderMaterial = function ( parameters ) {
+ loader.load( url[ i ], function ( buffer ) {
- THREE.ShaderMaterial.call( this, parameters );
+ var texDatas = scope._parser( buffer, true );
-};
+ images[ i ] = {
+ width: texDatas.width,
+ height: texDatas.height,
+ format: texDatas.format,
+ mipmaps: texDatas.mipmaps
+ };
-THREE.RawShaderMaterial.prototype = Object.create( THREE.ShaderMaterial.prototype );
+ loaded += 1;
-THREE.RawShaderMaterial.prototype.clone = function () {
+ if ( loaded === 6 ) {
- var material = new THREE.RawShaderMaterial();
+ if (texDatas.mipmapCount == 1)
+ texture.minFilter = THREE.LinearFilter;
- THREE.ShaderMaterial.prototype.clone.call( this, material );
+ texture.format = texDatas.format;
+ texture.needsUpdate = true;
- return material;
+ if ( onLoad ) onLoad( texture );
-};
+ }
-// File:src/materials/SpriteMaterial.js
+ } );
-/**
- * @author alteredq / http://alteredqualia.com/
- *
- * parameters = {
- * color: ,
- * opacity: ,
- * map: new THREE.Texture( ),
- *
- * blending: THREE.NormalBlending,
- * depthTest: ,
- * depthWrite: ,
- *
- * uvOffset: new THREE.Vector2(),
- * uvScale: new THREE.Vector2(),
- *
- * fog:
- * }
- */
+ };
-THREE.SpriteMaterial = function ( parameters ) {
+ for ( var i = 0, il = url.length; i < il; ++ i ) {
- THREE.Material.call( this );
+ loadTexture( i );
- // defaults
+ }
- this.color = new THREE.Color( 0xffffff );
- this.map = null;
+ } else {
- this.rotation = 0;
+ // compressed cubemap texture stored in a single DDS file
- this.fog = false;
+ loader.load( url, function ( buffer ) {
- // set parameters
+ var texDatas = scope._parser( buffer, true );
- this.setValues( parameters );
+ if ( texDatas.isCubemap ) {
-};
+ var faces = texDatas.mipmaps.length / texDatas.mipmapCount;
-THREE.SpriteMaterial.prototype = Object.create( THREE.Material.prototype );
+ for ( var f = 0; f < faces; f ++ ) {
-THREE.SpriteMaterial.prototype.clone = function () {
+ images[ f ] = { mipmaps : [] };
- var material = new THREE.SpriteMaterial();
+ for ( var i = 0; i < texDatas.mipmapCount; i ++ ) {
- THREE.Material.prototype.clone.call( this, material );
+ images[ f ].mipmaps.push( texDatas.mipmaps[ f * texDatas.mipmapCount + i ] );
+ images[ f ].format = texDatas.format;
+ images[ f ].width = texDatas.width;
+ images[ f ].height = texDatas.height;
- material.color.copy( this.color );
- material.map = this.map;
+ }
- material.rotation = this.rotation;
+ }
- material.fog = this.fog;
+ } else {
- return material;
+ texture.image.width = texDatas.width;
+ texture.image.height = texDatas.height;
+ texture.mipmaps = texDatas.mipmaps;
-};
+ }
-// File:src/materials/SpriteCanvasMaterial.js
+ if ( texDatas.mipmapCount === 1 ) {
-/**
- * @author mrdoob / http://mrdoob.com/
- *
- * parameters = {
- * color: ,
- * program: ,
- * opacity: ,
- * blending: THREE.NormalBlending
- * }
- */
+ texture.minFilter = THREE.LinearFilter;
-THREE.SpriteCanvasMaterial = function ( parameters ) {
-
- THREE.Material.call( this );
-
- this.color = new THREE.Color( 0xffffff );
- this.program = function ( context, color ) {};
-
- this.setValues( parameters );
-
-};
+ }
-THREE.SpriteCanvasMaterial.prototype = Object.create( THREE.Material.prototype );
+ texture.format = texDatas.format;
+ texture.needsUpdate = true;
-THREE.SpriteCanvasMaterial.prototype.clone = function () {
+ if ( onLoad ) onLoad( texture );
- var material = new THREE.SpriteCanvasMaterial();
+ } );
- THREE.Material.prototype.clone.call( this, material );
+ }
- material.color.copy( this.color );
- material.program = this.program;
+ return texture;
- return material;
+ }
};
-// backwards compatibility
-
-THREE.ParticleCanvasMaterial = THREE.SpriteCanvasMaterial;
-
-// File:src/textures/Texture.js
+// File:src/materials/Material.js
/**
* @author mrdoob / http://mrdoob.com/
* @author alteredq / http://alteredqualia.com/
- * @author szimek / https://github.com/szimek/
*/
-THREE.Texture = function ( image, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) {
+THREE.Material = function () {
+
+ Object.defineProperty( this, 'id', { value: THREE.MaterialIdCount ++ } );
- this.id = THREE.TextureIdCount ++;
this.uuid = THREE.Math.generateUUID();
this.name = '';
+ this.type = 'Material';
- this.image = image !== undefined ? image : THREE.Texture.DEFAULT_IMAGE;
- this.mipmaps = [];
+ this.side = THREE.FrontSide;
- this.mapping = mapping !== undefined ? mapping : THREE.Texture.DEFAULT_MAPPING;
+ this.opacity = 1;
+ this.transparent = false;
- this.wrapS = wrapS !== undefined ? wrapS : THREE.ClampToEdgeWrapping;
- this.wrapT = wrapT !== undefined ? wrapT : THREE.ClampToEdgeWrapping;
+ this.blending = THREE.NormalBlending;
- this.magFilter = magFilter !== undefined ? magFilter : THREE.LinearFilter;
- this.minFilter = minFilter !== undefined ? minFilter : THREE.LinearMipMapLinearFilter;
+ this.blendSrc = THREE.SrcAlphaFactor;
+ this.blendDst = THREE.OneMinusSrcAlphaFactor;
+ this.blendEquation = THREE.AddEquation;
- this.anisotropy = anisotropy !== undefined ? anisotropy : 1;
+ this.depthTest = true;
+ this.depthWrite = true;
- this.format = format !== undefined ? format : THREE.RGBAFormat;
- this.type = type !== undefined ? type : THREE.UnsignedByteType;
+ this.polygonOffset = false;
+ this.polygonOffsetFactor = 0;
+ this.polygonOffsetUnits = 0;
- this.offset = new THREE.Vector2( 0, 0 );
- this.repeat = new THREE.Vector2( 1, 1 );
+ this.alphaTest = 0;
- this.generateMipmaps = true;
- this.premultiplyAlpha = false;
- this.flipY = true;
- this.unpackAlignment = 4; // valid values: 1, 2, 4, 8 (see http://www.khronos.org/opengles/sdk/docs/man/xhtml/glPixelStorei.xml)
+ this.overdraw = 0; // Overdrawn pixels (typically between 0 and 1) for fixing antialiasing gaps in CanvasRenderer
- this._needsUpdate = false;
- this.onUpdate = null;
+ this.visible = true;
+
+ this.needsUpdate = true;
};
-THREE.Texture.DEFAULT_IMAGE = undefined;
-THREE.Texture.DEFAULT_MAPPING = new THREE.UVMapping();
+THREE.Material.prototype = {
-THREE.Texture.prototype = {
+ constructor: THREE.Material,
- constructor: THREE.Texture,
+ setValues: function ( values ) {
- get needsUpdate () {
+ if ( values === undefined ) return;
- return this._needsUpdate;
+ for ( var key in values ) {
- },
+ var newValue = values[ key ];
- set needsUpdate ( value ) {
+ if ( newValue === undefined ) {
- if ( value === true ) this.update();
+ console.warn( "THREE.Material: '" + key + "' parameter is undefined." );
+ continue;
- this._needsUpdate = value;
+ }
- },
+ if ( key in this ) {
- clone: function ( texture ) {
+ var currentValue = this[ key ];
- if ( texture === undefined ) texture = new THREE.Texture();
+ if ( currentValue instanceof THREE.Color ) {
- texture.image = this.image;
- texture.mipmaps = this.mipmaps.slice( 0 );
+ currentValue.set( newValue );
- texture.mapping = this.mapping;
+ } else if ( currentValue instanceof THREE.Vector3 && newValue instanceof THREE.Vector3 ) {
- texture.wrapS = this.wrapS;
- texture.wrapT = this.wrapT;
+ currentValue.copy( newValue );
- texture.magFilter = this.magFilter;
- texture.minFilter = this.minFilter;
+ } else if ( key == 'overdraw' ) {
- texture.anisotropy = this.anisotropy;
+ // ensure overdraw is backwards-compatable with legacy boolean type
+ this[ key ] = Number( newValue );
- texture.format = this.format;
- texture.type = this.type;
+ } else {
- texture.offset.copy( this.offset );
- texture.repeat.copy( this.repeat );
+ this[ key ] = newValue;
- texture.generateMipmaps = this.generateMipmaps;
- texture.premultiplyAlpha = this.premultiplyAlpha;
- texture.flipY = this.flipY;
- texture.unpackAlignment = this.unpackAlignment;
+ }
- return texture;
+ }
+
+ }
},
- update: function () {
+ toJSON: function () {
- this.dispatchEvent( { type: 'update' } );
+ var output = {
+ metadata: {
+ version: 4.2,
+ type: 'material',
+ generator: 'MaterialExporter'
+ },
+ uuid: this.uuid,
+ type: this.type
+ };
- },
+ if ( this.name !== "" ) output.name = this.name;
- dispose: function () {
+ if ( this instanceof THREE.MeshBasicMaterial ) {
- this.dispatchEvent( { type: 'dispose' } );
+ output.color = this.color.getHex();
+ if ( this.vertexColors !== THREE.NoColors ) output.vertexColors = this.vertexColors;
+ if ( this.blending !== THREE.NormalBlending ) output.blending = this.blending;
+ if ( this.side !== THREE.FrontSide ) output.side = this.side;
- }
+ } else if ( this instanceof THREE.MeshLambertMaterial ) {
-};
+ output.color = this.color.getHex();
+ output.ambient = this.ambient.getHex();
+ output.emissive = this.emissive.getHex();
+ if ( this.vertexColors !== THREE.NoColors ) output.vertexColors = this.vertexColors;
+ if ( this.blending !== THREE.NormalBlending ) output.blending = this.blending;
+ if ( this.side !== THREE.FrontSide ) output.side = this.side;
-THREE.EventDispatcher.prototype.apply( THREE.Texture.prototype );
+ } else if ( this instanceof THREE.MeshPhongMaterial ) {
-THREE.TextureIdCount = 0;
+ output.color = this.color.getHex();
+ output.ambient = this.ambient.getHex();
+ output.emissive = this.emissive.getHex();
+ output.specular = this.specular.getHex();
+ output.shininess = this.shininess;
+ if ( this.vertexColors !== THREE.NoColors ) output.vertexColors = this.vertexColors;
+ if ( this.blending !== THREE.NormalBlending ) output.blending = this.blending;
+ if ( this.side !== THREE.FrontSide ) output.side = this.side;
-// File:src/textures/CubeTexture.js
+ } else if ( this instanceof THREE.MeshNormalMaterial ) {
-/**
- * @author mrdoob / http://mrdoob.com/
- */
+ if ( this.shading !== THREE.FlatShading ) output.shading = this.shading;
+ if ( this.blending !== THREE.NormalBlending ) output.blending = this.blending;
+ if ( this.side !== THREE.FrontSide ) output.side = this.side;
-THREE.CubeTexture = function ( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) {
+ } else if ( this instanceof THREE.MeshDepthMaterial ) {
- THREE.Texture.call( this, images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );
+ if ( this.blending !== THREE.NormalBlending ) output.blending = this.blending;
+ if ( this.side !== THREE.FrontSide ) output.side = this.side;
- this.images = images;
+ } else if ( this instanceof THREE.ShaderMaterial ) {
-};
+ output.uniforms = this.uniforms;
+ output.vertexShader = this.vertexShader;
+ output.fragmentShader = this.fragmentShader;
-THREE.CubeTexture.prototype = Object.create( THREE.Texture.prototype );
+ } else if ( this instanceof THREE.SpriteMaterial ) {
-THREE.CubeTexture.clone = function ( texture ) {
+ output.color = this.color.getHex();
- if ( texture === undefined ) texture = new THREE.CubeTexture();
+ }
- THREE.Texture.prototype.clone.call( this, texture );
+ if ( this.opacity < 1 ) output.opacity = this.opacity;
+ if ( this.transparent !== false ) output.transparent = this.transparent;
+ if ( this.wireframe !== false ) output.wireframe = this.wireframe;
- texture.images = this.images;
+ return output;
- return texture;
+ },
-};
+ clone: function ( material ) {
-// File:src/textures/CompressedTexture.js
+ if ( material === undefined ) material = new THREE.Material();
-/**
- * @author alteredq / http://alteredqualia.com/
- */
+ material.name = this.name;
-THREE.CompressedTexture = function ( mipmaps, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy ) {
+ material.side = this.side;
- THREE.Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );
+ material.opacity = this.opacity;
+ material.transparent = this.transparent;
- this.image = { width: width, height: height };
- this.mipmaps = mipmaps;
+ material.blending = this.blending;
+
+ material.blendSrc = this.blendSrc;
+ material.blendDst = this.blendDst;
+ material.blendEquation = this.blendEquation;
- this.generateMipmaps = false; // WebGL currently can't generate mipmaps for compressed textures, they must be embedded in DDS file
+ material.depthTest = this.depthTest;
+ material.depthWrite = this.depthWrite;
-};
+ material.polygonOffset = this.polygonOffset;
+ material.polygonOffsetFactor = this.polygonOffsetFactor;
+ material.polygonOffsetUnits = this.polygonOffsetUnits;
-THREE.CompressedTexture.prototype = Object.create( THREE.Texture.prototype );
+ material.alphaTest = this.alphaTest;
-THREE.CompressedTexture.prototype.clone = function () {
+ material.overdraw = this.overdraw;
- var texture = new THREE.CompressedTexture();
+ material.visible = this.visible;
- THREE.Texture.prototype.clone.call( this, texture );
+ return material;
- return texture;
+ },
+
+ dispose: function () {
+
+ this.dispatchEvent( { type: 'dispose' } );
+
+ }
};
-// File:src/textures/DataTexture.js
+THREE.EventDispatcher.prototype.apply( THREE.Material.prototype );
+
+THREE.MaterialIdCount = 0;
+
+// File:src/materials/LineBasicMaterial.js
/**
+ * @author mrdoob / http://mrdoob.com/
* @author alteredq / http://alteredqualia.com/
+ *
+ * parameters = {
+ * color: ,
+ * opacity: ,
+ *
+ * blending: THREE.NormalBlending,
+ * depthTest: ,
+ * depthWrite: ,
+ *
+ * linewidth: ,
+ * linecap: "round",
+ * linejoin: "round",
+ *
+ * vertexColors:
+ *
+ * fog:
+ * }
*/
-THREE.DataTexture = function ( data, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy ) {
-
- THREE.Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );
+THREE.LineBasicMaterial = function ( parameters ) {
- this.image = { data: data, width: width, height: height };
+ THREE.Material.call( this );
-};
+ this.type = 'LineBasicMaterial';
-THREE.DataTexture.prototype = Object.create( THREE.Texture.prototype );
+ this.color = new THREE.Color( 0xffffff );
-THREE.DataTexture.prototype.clone = function () {
+ this.linewidth = 1;
+ this.linecap = 'round';
+ this.linejoin = 'round';
- var texture = new THREE.DataTexture();
+ this.vertexColors = THREE.NoColors;
- THREE.Texture.prototype.clone.call( this, texture );
+ this.fog = true;
- return texture;
+ this.setValues( parameters );
};
-// File:src/objects/PointCloud.js
+THREE.LineBasicMaterial.prototype = Object.create( THREE.Material.prototype );
-/**
- * @author alteredq / http://alteredqualia.com/
- */
+THREE.LineBasicMaterial.prototype.clone = function () {
-THREE.PointCloud = function ( geometry, material ) {
+ var material = new THREE.LineBasicMaterial();
- THREE.Object3D.call( this );
+ THREE.Material.prototype.clone.call( this, material );
- this.geometry = geometry !== undefined ? geometry : new THREE.Geometry();
- this.material = material !== undefined ? material : new THREE.PointCloudMaterial( { color: Math.random() * 0xffffff } );
+ material.color.copy( this.color );
- this.sortParticles = false;
+ material.linewidth = this.linewidth;
+ material.linecap = this.linecap;
+ material.linejoin = this.linejoin;
-};
+ material.vertexColors = this.vertexColors;
-THREE.PointCloud.prototype = Object.create( THREE.Object3D.prototype );
+ material.fog = this.fog;
-THREE.PointCloud.prototype.raycast = ( function () {
+ return material;
- var inverseMatrix = new THREE.Matrix4();
- var ray = new THREE.Ray();
+};
- return function ( raycaster, intersects ) {
+// File:src/materials/LineDashedMaterial.js
- var object = this;
- var geometry = object.geometry;
- var threshold = raycaster.params.PointCloud.threshold;
-
- inverseMatrix.getInverse( this.matrixWorld );
- ray.copy( raycaster.ray ).applyMatrix4( inverseMatrix );
-
- if ( geometry.boundingBox !== null ) {
+/**
+ * @author alteredq / http://alteredqualia.com/
+ *
+ * parameters = {
+ * color: ,
+ * opacity: ,
+ *
+ * blending: THREE.NormalBlending,
+ * depthTest: ,
+ * depthWrite: ,
+ *
+ * linewidth: ,
+ *
+ * scale: ,
+ * dashSize: ,
+ * gapSize: ,
+ *
+ * vertexColors:
+ *
+ * fog:
+ * }
+ */
- if ( ray.isIntersectionBox( geometry.boundingBox ) === false ) {
+THREE.LineDashedMaterial = function ( parameters ) {
- return;
+ THREE.Material.call( this );
- }
+ this.type = 'LineDashedMaterial';
- }
+ this.color = new THREE.Color( 0xffffff );
- var localThreshold = threshold / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 );
- var position = new THREE.Vector3();
+ this.linewidth = 1;
- var testPoint = function ( point, index ) {
+ this.scale = 1;
+ this.dashSize = 3;
+ this.gapSize = 1;
- var rayPointDistance = ray.distanceToPoint( point );
+ this.vertexColors = false;
- if ( rayPointDistance < localThreshold ) {
+ this.fog = true;
- var intersectPoint = ray.closestPointToPoint( point );
- intersectPoint.applyMatrix4( object.matrixWorld );
+ this.setValues( parameters );
- var distance = raycaster.ray.origin.distanceTo( intersectPoint );
+};
- intersects.push( {
+THREE.LineDashedMaterial.prototype = Object.create( THREE.Material.prototype );
- distance: distance,
- distanceToRay: rayPointDistance,
- point: intersectPoint.clone(),
- index: index,
- face: null,
- object: object
+THREE.LineDashedMaterial.prototype.clone = function () {
- } );
+ var material = new THREE.LineDashedMaterial();
- }
+ THREE.Material.prototype.clone.call( this, material );
- };
+ material.color.copy( this.color );
- if ( geometry instanceof THREE.BufferGeometry ) {
+ material.linewidth = this.linewidth;
- var attributes = geometry.attributes;
- var positions = attributes.position.array;
+ material.scale = this.scale;
+ material.dashSize = this.dashSize;
+ material.gapSize = this.gapSize;
- if ( attributes.index !== undefined ) {
+ material.vertexColors = this.vertexColors;
- var indices = attributes.index.array;
- var offsets = geometry.offsets;
+ material.fog = this.fog;
- if ( offsets.length === 0 ) {
+ return material;
- var offset = {
- start: 0,
- count: indices.length,
- index: 0
- };
+};
- offsets = [ offset ];
+// File:src/materials/MeshBasicMaterial.js
- }
+/**
+ * @author mrdoob / http://mrdoob.com/
+ * @author alteredq / http://alteredqualia.com/
+ *
+ * parameters = {
+ * color: ,
+ * opacity: ,
+ * map: new THREE.Texture( ),
+ *
+ * lightMap: new THREE.Texture( ),
+ *
+ * specularMap: new THREE.Texture( ),
+ *
+ * alphaMap: new THREE.Texture( ),
+ *
+ * envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ),
+ * combine: THREE.Multiply,
+ * reflectivity: ,
+ * refractionRatio: ,
+ *
+ * shading: THREE.SmoothShading,
+ * blending: THREE.NormalBlending,
+ * depthTest: ,
+ * depthWrite: ,
+ *
+ * wireframe: ,
+ * wireframeLinewidth: ,
+ *
+ * vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors,
+ *
+ * skinning: ,
+ * morphTargets: ,
+ *
+ * fog:
+ * }
+ */
- for ( var oi = 0, ol = offsets.length; oi < ol; ++oi ) {
+THREE.MeshBasicMaterial = function ( parameters ) {
- var start = offsets[ oi ].start;
- var count = offsets[ oi ].count;
- var index = offsets[ oi ].index;
+ THREE.Material.call( this );
- for ( var i = start, il = start + count; i < il; i ++ ) {
+ this.type = 'MeshBasicMaterial';
- var a = index + indices[ i ];
+ this.color = new THREE.Color( 0xffffff ); // emissive
- position.set(
- positions[ a * 3 ],
- positions[ a * 3 + 1 ],
- positions[ a * 3 + 2 ]
- );
+ this.map = null;
- testPoint( position, a );
+ this.lightMap = null;
- }
+ this.specularMap = null;
- }
+ this.alphaMap = null;
- } else {
+ this.envMap = null;
+ this.combine = THREE.MultiplyOperation;
+ this.reflectivity = 1;
+ this.refractionRatio = 0.98;
- var pointCount = positions.length / 3;
+ this.fog = true;
- for ( var i = 0; i < pointCount; i ++ ) {
+ this.shading = THREE.SmoothShading;
- position.set(
- positions[ 3 * i ],
- positions[ 3 * i + 1 ],
- positions[ 3 * i + 2 ]
- );
+ this.wireframe = false;
+ this.wireframeLinewidth = 1;
+ this.wireframeLinecap = 'round';
+ this.wireframeLinejoin = 'round';
- testPoint( position, i );
+ this.vertexColors = THREE.NoColors;
- }
+ this.skinning = false;
+ this.morphTargets = false;
- }
+ this.setValues( parameters );
- } else {
+};
- var vertices = this.geometry.vertices;
+THREE.MeshBasicMaterial.prototype = Object.create( THREE.Material.prototype );
- for ( var i = 0; i < vertices.length; i ++ ) {
+THREE.MeshBasicMaterial.prototype.clone = function () {
- testPoint( vertices[ i ], i );
+ var material = new THREE.MeshBasicMaterial();
- }
+ THREE.Material.prototype.clone.call( this, material );
- }
+ material.color.copy( this.color );
- };
+ material.map = this.map;
-}() );
+ material.lightMap = this.lightMap;
-THREE.PointCloud.prototype.clone = function ( object ) {
+ material.specularMap = this.specularMap;
- if ( object === undefined ) object = new THREE.PointCloud( this.geometry, this.material );
+ material.alphaMap = this.alphaMap;
- object.sortParticles = this.sortParticles;
+ material.envMap = this.envMap;
+ material.combine = this.combine;
+ material.reflectivity = this.reflectivity;
+ material.refractionRatio = this.refractionRatio;
- THREE.Object3D.prototype.clone.call( this, object );
+ material.fog = this.fog;
- return object;
+ material.shading = this.shading;
-};
+ material.wireframe = this.wireframe;
+ material.wireframeLinewidth = this.wireframeLinewidth;
+ material.wireframeLinecap = this.wireframeLinecap;
+ material.wireframeLinejoin = this.wireframeLinejoin;
-// Backwards compatibility
+ material.vertexColors = this.vertexColors;
-THREE.ParticleSystem = function ( geometry, material ) {
+ material.skinning = this.skinning;
+ material.morphTargets = this.morphTargets;
- console.warn( 'THREE.ParticleSystem has been renamed to THREE.PointCloud.' );
- return new THREE.PointCloud( geometry, material );
+ return material;
};
-// File:src/objects/Line.js
+// File:src/materials/MeshLambertMaterial.js
/**
* @author mrdoob / http://mrdoob.com/
+ * @author alteredq / http://alteredqualia.com/
+ *
+ * parameters = {
+ * color: ,
+ * ambient: ,
+ * emissive: ,
+ * opacity: ,
+ *
+ * map: new THREE.Texture( ),
+ *
+ * lightMap: new THREE.Texture( ),
+ *
+ * specularMap: new THREE.Texture( ),
+ *
+ * alphaMap: new THREE.Texture( ),
+ *
+ * envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ),
+ * combine: THREE.Multiply,
+ * reflectivity: ,
+ * refractionRatio: ,
+ *
+ * shading: THREE.SmoothShading,
+ * blending: THREE.NormalBlending,
+ * depthTest: ,
+ * depthWrite: ,
+ *
+ * wireframe: ,
+ * wireframeLinewidth: ,
+ *
+ * vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors,
+ *
+ * skinning: ,
+ * morphTargets: ,
+ * morphNormals: ,
+ *
+ * fog:
+ * }
*/
-THREE.Line = function ( geometry, material, type ) {
+THREE.MeshLambertMaterial = function ( parameters ) {
- THREE.Object3D.call( this );
+ THREE.Material.call( this );
- this.geometry = geometry !== undefined ? geometry : new THREE.Geometry();
- this.material = material !== undefined ? material : new THREE.LineBasicMaterial( { color: Math.random() * 0xffffff } );
+ this.type = 'MeshLambertMaterial';
- this.type = ( type !== undefined ) ? type : THREE.LineStrip;
+ this.color = new THREE.Color( 0xffffff ); // diffuse
+ this.ambient = new THREE.Color( 0xffffff );
+ this.emissive = new THREE.Color( 0x000000 );
-};
-
-THREE.LineStrip = 0;
-THREE.LinePieces = 1;
-
-THREE.Line.prototype = Object.create( THREE.Object3D.prototype );
-
-THREE.Line.prototype.raycast = ( function () {
-
- var inverseMatrix = new THREE.Matrix4();
- var ray = new THREE.Ray();
- var sphere = new THREE.Sphere();
+ this.wrapAround = false;
+ this.wrapRGB = new THREE.Vector3( 1, 1, 1 );
- return function ( raycaster, intersects ) {
+ this.map = null;
- var precision = raycaster.linePrecision;
- var precisionSq = precision * precision;
+ this.lightMap = null;
- var geometry = this.geometry;
+ this.specularMap = null;
- if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();
+ this.alphaMap = null;
- // Checking boundingSphere distance to ray
+ this.envMap = null;
+ this.combine = THREE.MultiplyOperation;
+ this.reflectivity = 1;
+ this.refractionRatio = 0.98;
- sphere.copy( geometry.boundingSphere );
- sphere.applyMatrix4( this.matrixWorld );
+ this.fog = true;
- if ( raycaster.ray.isIntersectionSphere( sphere ) === false ) {
+ this.shading = THREE.SmoothShading;
- return;
+ this.wireframe = false;
+ this.wireframeLinewidth = 1;
+ this.wireframeLinecap = 'round';
+ this.wireframeLinejoin = 'round';
- }
+ this.vertexColors = THREE.NoColors;
- inverseMatrix.getInverse( this.matrixWorld );
- ray.copy( raycaster.ray ).applyMatrix4( inverseMatrix );
+ this.skinning = false;
+ this.morphTargets = false;
+ this.morphNormals = false;
- /* if ( geometry instanceof THREE.BufferGeometry ) {
+ this.setValues( parameters );
- } else */ if ( geometry instanceof THREE.Geometry ) {
+};
- var vertices = geometry.vertices;
- var nbVertices = vertices.length;
- var interSegment = new THREE.Vector3();
- var interRay = new THREE.Vector3();
- var step = this.type === THREE.LineStrip ? 1 : 2;
+THREE.MeshLambertMaterial.prototype = Object.create( THREE.Material.prototype );
- for ( var i = 0; i < nbVertices - 1; i = i + step ) {
+THREE.MeshLambertMaterial.prototype.clone = function () {
- var distSq = ray.distanceSqToSegment( vertices[ i ], vertices[ i + 1 ], interRay, interSegment );
+ var material = new THREE.MeshLambertMaterial();
- if ( distSq > precisionSq ) continue;
+ THREE.Material.prototype.clone.call( this, material );
- var distance = ray.origin.distanceTo( interRay );
+ material.color.copy( this.color );
+ material.ambient.copy( this.ambient );
+ material.emissive.copy( this.emissive );
- if ( distance < raycaster.near || distance > raycaster.far ) continue;
+ material.wrapAround = this.wrapAround;
+ material.wrapRGB.copy( this.wrapRGB );
- intersects.push( {
+ material.map = this.map;
- distance: distance,
- // What do we want? intersection point on the ray or on the segment??
- // point: raycaster.ray.at( distance ),
- point: interSegment.clone().applyMatrix4( this.matrixWorld ),
- face: null,
- faceIndex: null,
- object: this
+ material.lightMap = this.lightMap;
- } );
+ material.specularMap = this.specularMap;
- }
+ material.alphaMap = this.alphaMap;
- }
+ material.envMap = this.envMap;
+ material.combine = this.combine;
+ material.reflectivity = this.reflectivity;
+ material.refractionRatio = this.refractionRatio;
- };
+ material.fog = this.fog;
-}() );
+ material.shading = this.shading;
-THREE.Line.prototype.clone = function ( object ) {
+ material.wireframe = this.wireframe;
+ material.wireframeLinewidth = this.wireframeLinewidth;
+ material.wireframeLinecap = this.wireframeLinecap;
+ material.wireframeLinejoin = this.wireframeLinejoin;
- if ( object === undefined ) object = new THREE.Line( this.geometry, this.material, this.type );
+ material.vertexColors = this.vertexColors;
- THREE.Object3D.prototype.clone.call( this, object );
+ material.skinning = this.skinning;
+ material.morphTargets = this.morphTargets;
+ material.morphNormals = this.morphNormals;
- return object;
+ return material;
};
-// File:src/objects/Mesh.js
+// File:src/materials/MeshPhongMaterial.js
/**
* @author mrdoob / http://mrdoob.com/
* @author alteredq / http://alteredqualia.com/
- * @author mikael emtinger / http://gomo.se/
- * @author jonobr1 / http://jonobr1.com/
+ *
+ * parameters = {
+ * color: ,
+ * ambient: ,
+ * emissive: ,
+ * specular: ,
+ * shininess: ,
+ * opacity: ,
+ *
+ * map: new THREE.Texture( ),
+ *
+ * lightMap: new THREE.Texture( ),
+ *
+ * bumpMap: new THREE.Texture( ),
+ * bumpScale: ,
+ *
+ * normalMap: new THREE.Texture( ),
+ * normalScale: ,
+ *
+ * specularMap: new THREE.Texture( ),
+ *
+ * alphaMap: new THREE.Texture( ),
+ *
+ * envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ),
+ * combine: THREE.Multiply,
+ * reflectivity: ,
+ * refractionRatio: ,
+ *
+ * shading: THREE.SmoothShading,
+ * blending: THREE.NormalBlending,
+ * depthTest: ,
+ * depthWrite: ,
+ *
+ * wireframe: ,
+ * wireframeLinewidth: ,
+ *
+ * vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors,
+ *
+ * skinning: ,
+ * morphTargets: ,
+ * morphNormals: ,
+ *
+ * fog:
+ * }
*/
-THREE.Mesh = function ( geometry, material ) {
-
- THREE.Object3D.call( this );
+THREE.MeshPhongMaterial = function ( parameters ) {
- this.geometry = geometry !== undefined ? geometry : new THREE.Geometry();
- this.material = material !== undefined ? material : new THREE.MeshBasicMaterial( { color: Math.random() * 0xffffff } );
+ THREE.Material.call( this );
- this.updateMorphTargets();
+ this.type = 'MeshPhongMaterial';
-};
+ this.color = new THREE.Color( 0xffffff ); // diffuse
+ this.ambient = new THREE.Color( 0xffffff );
+ this.emissive = new THREE.Color( 0x000000 );
+ this.specular = new THREE.Color( 0x111111 );
+ this.shininess = 30;
-THREE.Mesh.prototype = Object.create( THREE.Object3D.prototype );
+ this.metal = false;
-THREE.Mesh.prototype.updateMorphTargets = function () {
+ this.wrapAround = false;
+ this.wrapRGB = new THREE.Vector3( 1, 1, 1 );
- if ( this.geometry.morphTargets !== undefined && this.geometry.morphTargets.length > 0 ) {
+ this.map = null;
- this.morphTargetBase = - 1;
- this.morphTargetForcedOrder = [];
- this.morphTargetInfluences = [];
- this.morphTargetDictionary = {};
+ this.lightMap = null;
- for ( var m = 0, ml = this.geometry.morphTargets.length; m < ml; m ++ ) {
+ this.bumpMap = null;
+ this.bumpScale = 1;
- this.morphTargetInfluences.push( 0 );
- this.morphTargetDictionary[ this.geometry.morphTargets[ m ].name ] = m;
+ this.normalMap = null;
+ this.normalScale = new THREE.Vector2( 1, 1 );
- }
+ this.specularMap = null;
- }
+ this.alphaMap = null;
-};
+ this.envMap = null;
+ this.combine = THREE.MultiplyOperation;
+ this.reflectivity = 1;
+ this.refractionRatio = 0.98;
-THREE.Mesh.prototype.getMorphTargetIndexByName = function ( name ) {
+ this.fog = true;
- if ( this.morphTargetDictionary[ name ] !== undefined ) {
+ this.shading = THREE.SmoothShading;
- return this.morphTargetDictionary[ name ];
+ this.wireframe = false;
+ this.wireframeLinewidth = 1;
+ this.wireframeLinecap = 'round';
+ this.wireframeLinejoin = 'round';
- }
+ this.vertexColors = THREE.NoColors;
- console.log( 'THREE.Mesh.getMorphTargetIndexByName: morph target ' + name + ' does not exist. Returning 0.' );
+ this.skinning = false;
+ this.morphTargets = false;
+ this.morphNormals = false;
- return 0;
+ this.setValues( parameters );
};
+THREE.MeshPhongMaterial.prototype = Object.create( THREE.Material.prototype );
-THREE.Mesh.prototype.raycast = ( function () {
+THREE.MeshPhongMaterial.prototype.clone = function () {
- var inverseMatrix = new THREE.Matrix4();
- var ray = new THREE.Ray();
- var sphere = new THREE.Sphere();
+ var material = new THREE.MeshPhongMaterial();
- var vA = new THREE.Vector3();
- var vB = new THREE.Vector3();
- var vC = new THREE.Vector3();
+ THREE.Material.prototype.clone.call( this, material );
- return function ( raycaster, intersects ) {
+ material.color.copy( this.color );
+ material.ambient.copy( this.ambient );
+ material.emissive.copy( this.emissive );
+ material.specular.copy( this.specular );
+ material.shininess = this.shininess;
- var geometry = this.geometry;
+ material.metal = this.metal;
- // Checking boundingSphere distance to ray
+ material.wrapAround = this.wrapAround;
+ material.wrapRGB.copy( this.wrapRGB );
- if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();
+ material.map = this.map;
- sphere.copy( geometry.boundingSphere );
- sphere.applyMatrix4( this.matrixWorld );
+ material.lightMap = this.lightMap;
- if ( raycaster.ray.isIntersectionSphere( sphere ) === false ) {
+ material.bumpMap = this.bumpMap;
+ material.bumpScale = this.bumpScale;
- return;
+ material.normalMap = this.normalMap;
+ material.normalScale.copy( this.normalScale );
- }
+ material.specularMap = this.specularMap;
- // Check boundingBox before continuing
+ material.alphaMap = this.alphaMap;
- inverseMatrix.getInverse( this.matrixWorld );
- ray.copy( raycaster.ray ).applyMatrix4( inverseMatrix );
+ material.envMap = this.envMap;
+ material.combine = this.combine;
+ material.reflectivity = this.reflectivity;
+ material.refractionRatio = this.refractionRatio;
- if ( geometry.boundingBox !== null ) {
+ material.fog = this.fog;
- if ( ray.isIntersectionBox( geometry.boundingBox ) === false ) {
+ material.shading = this.shading;
- return;
+ material.wireframe = this.wireframe;
+ material.wireframeLinewidth = this.wireframeLinewidth;
+ material.wireframeLinecap = this.wireframeLinecap;
+ material.wireframeLinejoin = this.wireframeLinejoin;
- }
+ material.vertexColors = this.vertexColors;
- }
+ material.skinning = this.skinning;
+ material.morphTargets = this.morphTargets;
+ material.morphNormals = this.morphNormals;
- if ( geometry instanceof THREE.BufferGeometry ) {
+ return material;
- var material = this.material;
+};
- if ( material === undefined ) return;
+// File:src/materials/MeshDepthMaterial.js
- var attributes = geometry.attributes;
+/**
+ * @author mrdoob / http://mrdoob.com/
+ * @author alteredq / http://alteredqualia.com/
+ *
+ * parameters = {
+ * opacity: ,
+ *
+ * blending: THREE.NormalBlending,
+ * depthTest: ,
+ * depthWrite: ,
+ *
+ * wireframe: ,
+ * wireframeLinewidth:
+ * }
+ */
- var a, b, c;
- var precision = raycaster.precision;
+THREE.MeshDepthMaterial = function ( parameters ) {
- if ( attributes.index !== undefined ) {
+ THREE.Material.call( this );
- var indices = attributes.index.array;
- var positions = attributes.position.array;
- var offsets = geometry.offsets;
+ this.type = 'MeshDepthMaterial';
- if ( offsets.length === 0 ) {
+ this.morphTargets = false;
+ this.wireframe = false;
+ this.wireframeLinewidth = 1;
- offsets = [ { start: 0, count: indices.length, index: 0 } ];
+ this.setValues( parameters );
- }
+};
- for ( var oi = 0, ol = offsets.length; oi < ol; ++oi ) {
+THREE.MeshDepthMaterial.prototype = Object.create( THREE.Material.prototype );
- var start = offsets[ oi ].start;
- var count = offsets[ oi ].count;
- var index = offsets[ oi ].index;
+THREE.MeshDepthMaterial.prototype.clone = function () {
- for ( var i = start, il = start + count; i < il; i += 3 ) {
+ var material = new THREE.MeshDepthMaterial();
- a = index + indices[ i ];
- b = index + indices[ i + 1 ];
- c = index + indices[ i + 2 ];
+ THREE.Material.prototype.clone.call( this, material );
- vA.set(
- positions[ a * 3 ],
- positions[ a * 3 + 1 ],
- positions[ a * 3 + 2 ]
- );
- vB.set(
- positions[ b * 3 ],
- positions[ b * 3 + 1 ],
- positions[ b * 3 + 2 ]
- );
- vC.set(
- positions[ c * 3 ],
- positions[ c * 3 + 1 ],
- positions[ c * 3 + 2 ]
- );
+ material.wireframe = this.wireframe;
+ material.wireframeLinewidth = this.wireframeLinewidth;
+ return material;
- if ( material.side === THREE.BackSide ) {
+};
- var intersectionPoint = ray.intersectTriangle( vC, vB, vA, true );
+// File:src/materials/MeshNormalMaterial.js
- } else {
+/**
+ * @author mrdoob / http://mrdoob.com/
+ *
+ * parameters = {
+ * opacity: ,
+ *
+ * shading: THREE.FlatShading,
+ * blending: THREE.NormalBlending,
+ * depthTest: ,
+ * depthWrite: ,
+ *
+ * wireframe: ,
+ * wireframeLinewidth:
+ * }
+ */
- var intersectionPoint = ray.intersectTriangle( vA, vB, vC, material.side !== THREE.DoubleSide );
+THREE.MeshNormalMaterial = function ( parameters ) {
- }
+ THREE.Material.call( this, parameters );
- if ( intersectionPoint === null ) continue;
+ this.type = 'MeshNormalMaterial';
- intersectionPoint.applyMatrix4( this.matrixWorld );
+ this.shading = THREE.FlatShading;
- var distance = raycaster.ray.origin.distanceTo( intersectionPoint );
+ this.wireframe = false;
+ this.wireframeLinewidth = 1;
- if ( distance < precision || distance < raycaster.near || distance > raycaster.far ) continue;
+ this.morphTargets = false;
- intersects.push( {
+ this.setValues( parameters );
- distance: distance,
- point: intersectionPoint,
- indices: [ a, b, c ],
- face: null,
- faceIndex: null,
- object: this
+};
- } );
+THREE.MeshNormalMaterial.prototype = Object.create( THREE.Material.prototype );
- }
+THREE.MeshNormalMaterial.prototype.clone = function () {
- }
+ var material = new THREE.MeshNormalMaterial();
- } else {
+ THREE.Material.prototype.clone.call( this, material );
- var positions = attributes.position.array;
+ material.shading = this.shading;
- for ( var i = 0, j = 0, il = positions.length; i < il; i += 3, j += 9 ) {
+ material.wireframe = this.wireframe;
+ material.wireframeLinewidth = this.wireframeLinewidth;
- a = i;
- b = i + 1;
- c = i + 2;
+ return material;
- vA.set(
- positions[ j ],
- positions[ j + 1 ],
- positions[ j + 2 ]
- );
- vB.set(
- positions[ j + 3 ],
- positions[ j + 4 ],
- positions[ j + 5 ]
- );
- vC.set(
- positions[ j + 6 ],
- positions[ j + 7 ],
- positions[ j + 8 ]
- );
+};
+// File:src/materials/MeshFaceMaterial.js
- if ( material.side === THREE.BackSide ) {
+/**
+ * @author mrdoob / http://mrdoob.com/
+ */
- var intersectionPoint = ray.intersectTriangle( vC, vB, vA, true );
+THREE.MeshFaceMaterial = function ( materials ) {
- } else {
+ this.uuid = THREE.Math.generateUUID();
- var intersectionPoint = ray.intersectTriangle( vA, vB, vC, material.side !== THREE.DoubleSide );
+ this.type = 'MeshFaceMaterial';
+
+ this.materials = materials instanceof Array ? materials : [];
- }
+};
- if ( intersectionPoint === null ) continue;
+THREE.MeshFaceMaterial.prototype = {
- intersectionPoint.applyMatrix4( this.matrixWorld );
+ constructor: THREE.MeshFaceMaterial,
- var distance = raycaster.ray.origin.distanceTo( intersectionPoint );
+ toJSON: function () {
- if ( distance < precision || distance < raycaster.near || distance > raycaster.far ) continue;
+ var output = {
+ metadata: {
+ version: 4.2,
+ type: 'material',
+ generator: 'MaterialExporter'
+ },
+ uuid: this.uuid,
+ type: this.type,
+ materials: []
+ };
- intersects.push( {
+ for ( var i = 0, l = this.materials.length; i < l; i ++ ) {
- distance: distance,
- point: intersectionPoint,
- indices: [ a, b, c ],
- face: null,
- faceIndex: null,
- object: this
+ output.materials.push( this.materials[ i ].toJSON() );
- } );
+ }
- }
+ return output;
- }
+ },
- } else if ( geometry instanceof THREE.Geometry ) {
+ clone: function () {
- var isFaceMaterial = this.material instanceof THREE.MeshFaceMaterial;
- var objectMaterials = isFaceMaterial === true ? this.material.materials : null;
+ var material = new THREE.MeshFaceMaterial();
- var a, b, c, d;
- var precision = raycaster.precision;
+ for ( var i = 0; i < this.materials.length; i ++ ) {
- var vertices = geometry.vertices;
+ material.materials.push( this.materials[ i ].clone() );
- for ( var f = 0, fl = geometry.faces.length; f < fl; f ++ ) {
+ }
- var face = geometry.faces[ f ];
+ return material;
- var material = isFaceMaterial === true ? objectMaterials[ face.materialIndex ] : this.material;
+ }
- if ( material === undefined ) continue;
+};
- a = vertices[ face.a ];
- b = vertices[ face.b ];
- c = vertices[ face.c ];
+// File:src/materials/PointCloudMaterial.js
- if ( material.morphTargets === true ) {
+/**
+ * @author mrdoob / http://mrdoob.com/
+ * @author alteredq / http://alteredqualia.com/
+ *
+ * parameters = {
+ * color: ,
+ * opacity: ,
+ * map: new THREE.Texture( ),
+ *
+ * size: ,
+ *
+ * blending: THREE.NormalBlending,
+ * depthTest: ,
+ * depthWrite: ,
+ *
+ * vertexColors: ,
+ *
+ * fog:
+ * }
+ */
- var morphTargets = geometry.morphTargets;
- var morphInfluences = this.morphTargetInfluences;
+THREE.PointCloudMaterial = function ( parameters ) {
- vA.set( 0, 0, 0 );
- vB.set( 0, 0, 0 );
- vC.set( 0, 0, 0 );
+ THREE.Material.call( this );
- for ( var t = 0, tl = morphTargets.length; t < tl; t ++ ) {
+ this.type = 'PointCloudMaterial';
- var influence = morphInfluences[ t ];
+ this.color = new THREE.Color( 0xffffff );
- if ( influence === 0 ) continue;
+ this.map = null;
- var targets = morphTargets[ t ].vertices;
+ this.size = 1;
+ this.sizeAttenuation = true;
- vA.x += ( targets[ face.a ].x - a.x ) * influence;
- vA.y += ( targets[ face.a ].y - a.y ) * influence;
- vA.z += ( targets[ face.a ].z - a.z ) * influence;
+ this.vertexColors = THREE.NoColors;
- vB.x += ( targets[ face.b ].x - b.x ) * influence;
- vB.y += ( targets[ face.b ].y - b.y ) * influence;
- vB.z += ( targets[ face.b ].z - b.z ) * influence;
+ this.fog = true;
- vC.x += ( targets[ face.c ].x - c.x ) * influence;
- vC.y += ( targets[ face.c ].y - c.y ) * influence;
- vC.z += ( targets[ face.c ].z - c.z ) * influence;
+ this.setValues( parameters );
- }
+};
- vA.add( a );
- vB.add( b );
- vC.add( c );
+THREE.PointCloudMaterial.prototype = Object.create( THREE.Material.prototype );
- a = vA;
- b = vB;
- c = vC;
+THREE.PointCloudMaterial.prototype.clone = function () {
- }
+ var material = new THREE.PointCloudMaterial();
- if ( material.side === THREE.BackSide ) {
+ THREE.Material.prototype.clone.call( this, material );
- var intersectionPoint = ray.intersectTriangle( c, b, a, true );
+ material.color.copy( this.color );
- } else {
+ material.map = this.map;
- var intersectionPoint = ray.intersectTriangle( a, b, c, material.side !== THREE.DoubleSide );
+ material.size = this.size;
+ material.sizeAttenuation = this.sizeAttenuation;
- }
+ material.vertexColors = this.vertexColors;
- if ( intersectionPoint === null ) continue;
+ material.fog = this.fog;
- intersectionPoint.applyMatrix4( this.matrixWorld );
+ return material;
- var distance = raycaster.ray.origin.distanceTo( intersectionPoint );
+};
- if ( distance < precision || distance < raycaster.near || distance > raycaster.far ) continue;
+// backwards compatibility
- intersects.push( {
+THREE.ParticleBasicMaterial = function ( parameters ) {
- distance: distance,
- point: intersectionPoint,
- face: face,
- faceIndex: f,
- object: this
-
- } );
-
- }
-
- }
-
- };
-
-}() );
-
-THREE.Mesh.prototype.clone = function ( object, recursive ) {
+ console.warn( 'THREE.ParticleBasicMaterial has been renamed to THREE.PointCloudMaterial.' );
+ return new THREE.PointCloudMaterial( parameters );
- if ( object === undefined ) object = new THREE.Mesh( this.geometry, this.material );
+};
- THREE.Object3D.prototype.clone.call( this, object, recursive );
+THREE.ParticleSystemMaterial = function ( parameters ) {
- return object;
+ console.warn( 'THREE.ParticleSystemMaterial has been renamed to THREE.PointCloudMaterial.' );
+ return new THREE.PointCloudMaterial( parameters );
};
-// File:src/objects/Bone.js
+// File:src/materials/ShaderMaterial.js
/**
- * @author mikael emtinger / http://gomo.se/
* @author alteredq / http://alteredqualia.com/
- * @author ikerr / http://verold.com
+ *
+ * parameters = {
+ * defines: { "label" : "value" },
+ * uniforms: { "parameter1": { type: "f", value: 1.0 }, "parameter2": { type: "i" value2: 2 } },
+ *
+ * fragmentShader: ,
+ * vertexShader: ,
+ *
+ * shading: THREE.SmoothShading,
+ * blending: THREE.NormalBlending,
+ * depthTest: ,
+ * depthWrite: ,
+ *
+ * wireframe: ,
+ * wireframeLinewidth: ,
+ *
+ * lights: ,
+ *
+ * vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors,
+ *
+ * skinning: ,
+ * morphTargets: ,
+ * morphNormals: ,
+ *
+ * fog:
+ * }
*/
-THREE.Bone = function ( belongsToSkin ) {
+THREE.ShaderMaterial = function ( parameters ) {
- THREE.Object3D.call( this );
+ THREE.Material.call( this );
- this.skin = belongsToSkin;
+ this.type = 'ShaderMaterial';
- this.accumulatedRotWeight = 0;
- this.accumulatedPosWeight = 0;
- this.accumulatedSclWeight = 0;
+ this.defines = {};
+ this.uniforms = {};
+ this.attributes = null;
-};
+ this.vertexShader = 'void main() {\n\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}';
+ this.fragmentShader = 'void main() {\n\tgl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );\n}';
-THREE.Bone.prototype = Object.create( THREE.Object3D.prototype );
+ this.shading = THREE.SmoothShading;
-THREE.Bone.prototype.updateMatrixWorld = function ( force ) {
+ this.linewidth = 1;
- THREE.Object3D.prototype.updateMatrixWorld.call( this, force );
+ this.wireframe = false;
+ this.wireframeLinewidth = 1;
- // Reset weights to be re-accumulated in the next frame
+ this.fog = false; // set to use scene fog
- this.accumulatedRotWeight = 0;
- this.accumulatedPosWeight = 0;
- this.accumulatedSclWeight = 0;
+ this.lights = false; // set to use scene lights
-};
+ this.vertexColors = THREE.NoColors; // set to use "color" attribute stream
+ this.skinning = false; // set to use skinning attribute streams
-// File:src/objects/Skeleton.js
+ this.morphTargets = false; // set to use morph targets
+ this.morphNormals = false; // set to use morph normals
-/**
- * @author mikael emtinger / http://gomo.se/
- * @author alteredq / http://alteredqualia.com/
- * @author michael guerrero / http://realitymeltdown.com
- * @author ikerr / http://verold.com
- */
+ // When rendered geometry doesn't include these attributes but the material does,
+ // use these default values in WebGL. This avoids errors when buffer data is missing.
+ this.defaultAttributeValues = {
+ 'color': [ 1, 1, 1 ],
+ 'uv': [ 0, 0 ],
+ 'uv2': [ 0, 0 ]
+ };
-THREE.Skeleton = function ( bones, boneInverses, useVertexTexture ) {
+ this.index0AttributeName = undefined;
- this.useVertexTexture = useVertexTexture !== undefined ? useVertexTexture : true;
+ this.setValues( parameters );
- this.identityMatrix = new THREE.Matrix4();
+};
- // copy the bone array
+THREE.ShaderMaterial.prototype = Object.create( THREE.Material.prototype );
- bones = bones || [];
+THREE.ShaderMaterial.prototype.clone = function () {
- this.bones = bones.slice( 0 );
+ var material = new THREE.ShaderMaterial();
- // create a bone texture or an array of floats
+ THREE.Material.prototype.clone.call( this, material );
- if ( this.useVertexTexture ) {
+ material.fragmentShader = this.fragmentShader;
+ material.vertexShader = this.vertexShader;
- // layout (1 matrix = 4 pixels)
- // RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4)
- // with 8x8 pixel texture max 16 bones (8 * 8 / 4)
- // 16x16 pixel texture max 64 bones (16 * 16 / 4)
- // 32x32 pixel texture max 256 bones (32 * 32 / 4)
- // 64x64 pixel texture max 1024 bones (64 * 64 / 4)
+ material.uniforms = THREE.UniformsUtils.clone( this.uniforms );
- var size;
+ material.attributes = this.attributes;
+ material.defines = this.defines;
- if ( this.bones.length > 256 )
- size = 64;
- else if ( this.bones.length > 64 )
- size = 32;
- else if ( this.bones.length > 16 )
- size = 16;
- else
- size = 8;
+ material.shading = this.shading;
- this.boneTextureWidth = size;
- this.boneTextureHeight = size;
+ material.wireframe = this.wireframe;
+ material.wireframeLinewidth = this.wireframeLinewidth;
- this.boneMatrices = new Float32Array( this.boneTextureWidth * this.boneTextureHeight * 4 ); // 4 floats per RGBA pixel
- this.boneTexture = new THREE.DataTexture( this.boneMatrices, this.boneTextureWidth, this.boneTextureHeight, THREE.RGBAFormat, THREE.FloatType );
- this.boneTexture.minFilter = THREE.NearestFilter;
- this.boneTexture.magFilter = THREE.NearestFilter;
- this.boneTexture.generateMipmaps = false;
- this.boneTexture.flipY = false;
+ material.fog = this.fog;
- } else {
+ material.lights = this.lights;
- this.boneMatrices = new Float32Array( 16 * this.bones.length );
+ material.vertexColors = this.vertexColors;
- }
+ material.skinning = this.skinning;
- // use the supplied bone inverses or calculate the inverses
+ material.morphTargets = this.morphTargets;
+ material.morphNormals = this.morphNormals;
- if ( boneInverses === undefined ) {
+ return material;
- this.calculateInverses();
+};
- } else {
+// File:src/materials/RawShaderMaterial.js
- if ( this.bones.length === boneInverses.length ) {
+/**
+ * @author mrdoob / http://mrdoob.com/
+ */
- this.boneInverses = boneInverses.slice( 0 );
+THREE.RawShaderMaterial = function ( parameters ) {
- } else {
+ THREE.ShaderMaterial.call( this, parameters );
- console.warn( 'THREE.Skeleton bonInverses is the wrong length.' );
+ this.type = 'RawShaderMaterial';
- this.boneInverses = [];
+};
- for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) {
+THREE.RawShaderMaterial.prototype = Object.create( THREE.ShaderMaterial.prototype );
- this.boneInverses.push( new THREE.Matrix4() );
+THREE.RawShaderMaterial.prototype.clone = function () {
- }
+ var material = new THREE.RawShaderMaterial();
- }
+ THREE.ShaderMaterial.prototype.clone.call( this, material );
- }
+ return material;
};
-THREE.Skeleton.prototype.calculateInverses = function () {
+// File:src/materials/SpriteMaterial.js
- this.boneInverses = [];
+/**
+ * @author alteredq / http://alteredqualia.com/
+ *
+ * parameters = {
+ * color: ,
+ * opacity: ,
+ * map: new THREE.Texture( ),
+ *
+ * blending: THREE.NormalBlending,
+ * depthTest: ,
+ * depthWrite: ,
+ *
+ * uvOffset: new THREE.Vector2(),
+ * uvScale: new THREE.Vector2(),
+ *
+ * fog:
+ * }
+ */
- for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) {
+THREE.SpriteMaterial = function ( parameters ) {
- var inverse = new THREE.Matrix4();
+ THREE.Material.call( this );
- if ( this.bones[ b ] ) {
+ this.type = 'SpriteMaterial';
- inverse.getInverse( this.bones[ b ].matrixWorld );
+ this.color = new THREE.Color( 0xffffff );
+ this.map = null;
- }
+ this.rotation = 0;
- this.boneInverses.push( inverse );
+ this.fog = false;
- }
+ // set parameters
+
+ this.setValues( parameters );
};
-THREE.Skeleton.prototype.pose = function () {
+THREE.SpriteMaterial.prototype = Object.create( THREE.Material.prototype );
- var bone;
+THREE.SpriteMaterial.prototype.clone = function () {
- // recover the bind-time world matrices
+ var material = new THREE.SpriteMaterial();
- for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) {
+ THREE.Material.prototype.clone.call( this, material );
- bone = this.bones[ b ];
+ material.color.copy( this.color );
+ material.map = this.map;
- if ( bone ) {
+ material.rotation = this.rotation;
- bone.matrixWorld.getInverse( this.boneInverses[ b ] );
+ material.fog = this.fog;
- }
+ return material;
- }
+};
- // compute the local matrices, positions, rotations and scales
+// File:src/textures/Texture.js
- for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) {
+/**
+ * @author mrdoob / http://mrdoob.com/
+ * @author alteredq / http://alteredqualia.com/
+ * @author szimek / https://github.com/szimek/
+ */
- bone = this.bones[ b ];
+THREE.Texture = function ( image, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) {
- if ( bone ) {
+ Object.defineProperty( this, 'id', { value: THREE.TextureIdCount ++ } );
- if ( bone.parent ) {
+ this.uuid = THREE.Math.generateUUID();
- bone.matrix.getInverse( bone.parent.matrixWorld );
- bone.matrix.multiply( bone.matrixWorld );
+ this.name = '';
- }
- else {
+ this.image = image !== undefined ? image : THREE.Texture.DEFAULT_IMAGE;
+ this.mipmaps = [];
- bone.matrix.copy( bone.matrixWorld );
+ this.mapping = mapping !== undefined ? mapping : THREE.Texture.DEFAULT_MAPPING;
- }
+ this.wrapS = wrapS !== undefined ? wrapS : THREE.ClampToEdgeWrapping;
+ this.wrapT = wrapT !== undefined ? wrapT : THREE.ClampToEdgeWrapping;
- bone.matrix.decompose( bone.position, bone.quaternion, bone.scale );
+ this.magFilter = magFilter !== undefined ? magFilter : THREE.LinearFilter;
+ this.minFilter = minFilter !== undefined ? minFilter : THREE.LinearMipMapLinearFilter;
- }
+ this.anisotropy = anisotropy !== undefined ? anisotropy : 1;
- }
+ this.format = format !== undefined ? format : THREE.RGBAFormat;
+ this.type = type !== undefined ? type : THREE.UnsignedByteType;
-};
+ this.offset = new THREE.Vector2( 0, 0 );
+ this.repeat = new THREE.Vector2( 1, 1 );
-THREE.Skeleton.prototype.update = function () {
+ this.generateMipmaps = true;
+ this.premultiplyAlpha = false;
+ this.flipY = true;
+ this.unpackAlignment = 4; // valid values: 1, 2, 4, 8 (see http://www.khronos.org/opengles/sdk/docs/man/xhtml/glPixelStorei.xml)
- var offsetMatrix = new THREE.Matrix4();
+ this._needsUpdate = false;
+ this.onUpdate = null;
- // flatten bone matrices to array
+};
- for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) {
+THREE.Texture.DEFAULT_IMAGE = undefined;
+THREE.Texture.DEFAULT_MAPPING = new THREE.UVMapping();
- // compute the offset between the current and the original transform
+THREE.Texture.prototype = {
- var matrix = this.bones[ b ] ? this.bones[ b ].matrixWorld : this.identityMatrix;
+ constructor: THREE.Texture,
- offsetMatrix.multiplyMatrices( matrix, this.boneInverses[ b ] );
- offsetMatrix.flattenToArrayOffset( this.boneMatrices, b * 16 );
+ get needsUpdate () {
- }
+ return this._needsUpdate;
- if ( this.useVertexTexture ) {
+ },
- this.boneTexture.needsUpdate = true;
+ set needsUpdate ( value ) {
- }
+ if ( value === true ) this.update();
-};
+ this._needsUpdate = value;
+ },
-// File:src/objects/SkinnedMesh.js
+ clone: function ( texture ) {
-/**
- * @author mikael emtinger / http://gomo.se/
- * @author alteredq / http://alteredqualia.com/
- * @author ikerr / http://verold.com
- */
+ if ( texture === undefined ) texture = new THREE.Texture();
-THREE.SkinnedMesh = function ( geometry, material, useVertexTexture ) {
+ texture.image = this.image;
+ texture.mipmaps = this.mipmaps.slice( 0 );
- THREE.Mesh.call( this, geometry, material );
+ texture.mapping = this.mapping;
- this.bindMode = "attached";
- this.bindMatrix = new THREE.Matrix4();
- this.bindMatrixInverse = new THREE.Matrix4();
+ texture.wrapS = this.wrapS;
+ texture.wrapT = this.wrapT;
- // init bones
+ texture.magFilter = this.magFilter;
+ texture.minFilter = this.minFilter;
- // TODO: remove bone creation as there is no reason (other than
- // convenience) for THREE.SkinnedMesh to do this.
+ texture.anisotropy = this.anisotropy;
- var bones = [];
+ texture.format = this.format;
+ texture.type = this.type;
- if ( this.geometry && this.geometry.bones !== undefined ) {
+ texture.offset.copy( this.offset );
+ texture.repeat.copy( this.repeat );
- var bone, gbone, p, q, s;
+ texture.generateMipmaps = this.generateMipmaps;
+ texture.premultiplyAlpha = this.premultiplyAlpha;
+ texture.flipY = this.flipY;
+ texture.unpackAlignment = this.unpackAlignment;
- for ( var b = 0, bl = this.geometry.bones.length; b < bl; ++b ) {
+ return texture;
- gbone = this.geometry.bones[ b ];
+ },
- p = gbone.pos;
- q = gbone.rotq;
- s = gbone.scl;
+ update: function () {
- bone = new THREE.Bone( this );
- bones.push( bone );
+ this.dispatchEvent( { type: 'update' } );
- bone.name = gbone.name;
- bone.position.set( p[ 0 ], p[ 1 ], p[ 2 ] );
- bone.quaternion.set( q[ 0 ], q[ 1 ], q[ 2 ], q[ 3 ] );
+ },
- if ( s !== undefined ) {
+ dispose: function () {
- bone.scale.set( s[ 0 ], s[ 1 ], s[ 2 ] );
+ this.dispatchEvent( { type: 'dispose' } );
- } else {
+ }
- bone.scale.set( 1, 1, 1 );
+};
- }
+THREE.EventDispatcher.prototype.apply( THREE.Texture.prototype );
- }
+THREE.TextureIdCount = 0;
- for ( var b = 0, bl = this.geometry.bones.length; b < bl; ++b ) {
+// File:src/textures/CubeTexture.js
- gbone = this.geometry.bones[ b ];
+/**
+ * @author mrdoob / http://mrdoob.com/
+ */
- if ( gbone.parent !== - 1 ) {
+THREE.CubeTexture = function ( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) {
- bones[ gbone.parent ].add( bones[ b ] );
+ THREE.Texture.call( this, images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );
- } else {
+ this.images = images;
- this.add( bones[ b ] );
+};
- }
+THREE.CubeTexture.prototype = Object.create( THREE.Texture.prototype );
- }
+THREE.CubeTexture.clone = function ( texture ) {
- }
+ if ( texture === undefined ) texture = new THREE.CubeTexture();
- this.normalizeSkinWeights();
+ THREE.Texture.prototype.clone.call( this, texture );
- this.updateMatrixWorld( true );
- this.bind( new THREE.Skeleton( bones, undefined, useVertexTexture ) );
+ texture.images = this.images;
+
+ return texture;
};
+// File:src/textures/CompressedTexture.js
-THREE.SkinnedMesh.prototype = Object.create( THREE.Mesh.prototype );
+/**
+ * @author alteredq / http://alteredqualia.com/
+ */
-THREE.SkinnedMesh.prototype.bind = function( skeleton, bindMatrix ) {
+THREE.CompressedTexture = function ( mipmaps, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy ) {
- this.skeleton = skeleton;
+ THREE.Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );
- if ( bindMatrix === undefined ) {
+ this.image = { width: width, height: height };
+ this.mipmaps = mipmaps;
- this.updateMatrixWorld( true );
+ // no flipping for cube textures
+ // (also flipping doesn't work for compressed textures )
- bindMatrix = this.matrixWorld;
+ this.flipY = false;
- }
+ // can't generate mipmaps for compressed textures
+ // mips must be embedded in DDS files
- this.bindMatrix.copy( bindMatrix );
- this.bindMatrixInverse.getInverse( bindMatrix );
+ this.generateMipmaps = false;
};
-THREE.SkinnedMesh.prototype.pose = function () {
+THREE.CompressedTexture.prototype = Object.create( THREE.Texture.prototype );
- this.skeleton.pose();
+THREE.CompressedTexture.prototype.clone = function () {
-};
+ var texture = new THREE.CompressedTexture();
-THREE.SkinnedMesh.prototype.normalizeSkinWeights = function () {
+ THREE.Texture.prototype.clone.call( this, texture );
- if ( this.geometry instanceof THREE.Geometry ) {
+ return texture;
- for ( var i = 0; i < this.geometry.skinIndices.length; i ++ ) {
+};
- var sw = this.geometry.skinWeights[ i ];
+// File:src/textures/DataTexture.js
- var scale = 1.0 / sw.lengthManhattan();
+/**
+ * @author alteredq / http://alteredqualia.com/
+ */
- if ( scale !== Infinity ) {
+THREE.DataTexture = function ( data, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy ) {
- sw.multiplyScalar( scale );
+ THREE.Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );
- } else {
+ this.image = { data: data, width: width, height: height };
- sw.set( 1 ); // this will be normalized by the shader anyway
+};
- }
+THREE.DataTexture.prototype = Object.create( THREE.Texture.prototype );
- }
+THREE.DataTexture.prototype.clone = function () {
- } else {
+ var texture = new THREE.DataTexture();
- // skinning weights assumed to be normalized for THREE.BufferGeometry
+ THREE.Texture.prototype.clone.call( this, texture );
- }
+ return texture;
};
-THREE.SkinnedMesh.prototype.updateMatrixWorld = function( force ) {
+// File:src/textures/VideoTexture.js
- THREE.Mesh.prototype.updateMatrixWorld.call( this, true );
+/**
+ * @author mrdoob / http://mrdoob.com/
+ */
- if ( this.bindMode === "attached" ) {
+THREE.VideoTexture = function ( video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) {
- this.bindMatrixInverse.getInverse( this.matrixWorld );
+ THREE.Texture.call( this, video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );
- } else if ( this.bindMode === "detached" ) {
+ this.generateMipmaps = false;
- this.bindMatrixInverse.getInverse( this.bindMatrix );
+ var scope = this;
- } else {
+ var update = function () {
- console.warn( 'THREE.SkinnedMesh unreckognized bindMode: ' + this.bindMode );
+ requestAnimationFrame( update );
- }
+ if ( video.readyState === video.HAVE_ENOUGH_DATA ) {
+
+ scope.needsUpdate = true;
+
+ }
+
+ };
+
+ update();
};
-THREE.SkinnedMesh.prototype.clone = function( object ) {
+THREE.VideoTexture.prototype = Object.create( THREE.Texture.prototype );
- if ( object === undefined ) {
+// File:src/objects/Group.js
- object = new THREE.SkinnedMesh( this.geometry, this.material, this.useVertexTexture );
+/**
+ * @author mrdoob / http://mrdoob.com/
+ */
- }
+THREE.Group = function () {
- THREE.Mesh.prototype.clone.call( this, object );
+ THREE.Object3D.call( this );
- return object;
+ this.type = 'Group';
};
+THREE.Group.prototype = Object.create( THREE.Object3D.prototype );
-// File:src/objects/MorphAnimMesh.js
+// File:src/objects/PointCloud.js
/**
* @author alteredq / http://alteredqualia.com/
*/
-THREE.MorphAnimMesh = function ( geometry, material ) {
+THREE.PointCloud = function ( geometry, material ) {
- THREE.Mesh.call( this, geometry, material );
+ THREE.Object3D.call( this );
- // API
+ this.type = 'PointCloud';
- this.duration = 1000; // milliseconds
- this.mirroredLoop = false;
- this.time = 0;
+ this.geometry = geometry !== undefined ? geometry : new THREE.Geometry();
+ this.material = material !== undefined ? material : new THREE.PointCloudMaterial( { color: Math.random() * 0xffffff } );
- // internals
+ this.sortParticles = false;
- this.lastKeyframe = 0;
- this.currentKeyframe = 0;
+};
- this.direction = 1;
- this.directionBackwards = false;
+THREE.PointCloud.prototype = Object.create( THREE.Object3D.prototype );
- this.setFrameRange( 0, this.geometry.morphTargets.length - 1 );
+THREE.PointCloud.prototype.raycast = ( function () {
-};
+ var inverseMatrix = new THREE.Matrix4();
+ var ray = new THREE.Ray();
-THREE.MorphAnimMesh.prototype = Object.create( THREE.Mesh.prototype );
+ return function ( raycaster, intersects ) {
-THREE.MorphAnimMesh.prototype.setFrameRange = function ( start, end ) {
+ var object = this;
+ var geometry = object.geometry;
+ var threshold = raycaster.params.PointCloud.threshold;
- this.startKeyframe = start;
- this.endKeyframe = end;
+ inverseMatrix.getInverse( this.matrixWorld );
+ ray.copy( raycaster.ray ).applyMatrix4( inverseMatrix );
- this.length = this.endKeyframe - this.startKeyframe + 1;
+ if ( geometry.boundingBox !== null ) {
-};
+ if ( ray.isIntersectionBox( geometry.boundingBox ) === false ) {
-THREE.MorphAnimMesh.prototype.setDirectionForward = function () {
+ return;
- this.direction = 1;
- this.directionBackwards = false;
+ }
-};
+ }
-THREE.MorphAnimMesh.prototype.setDirectionBackward = function () {
+ var localThreshold = threshold / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 );
+ var position = new THREE.Vector3();
- this.direction = - 1;
- this.directionBackwards = true;
-
-};
-
-THREE.MorphAnimMesh.prototype.parseAnimations = function () {
+ var testPoint = function ( point, index ) {
- var geometry = this.geometry;
+ var rayPointDistance = ray.distanceToPoint( point );
- if ( ! geometry.animations ) geometry.animations = {};
+ if ( rayPointDistance < localThreshold ) {
- var firstAnimation, animations = geometry.animations;
+ var intersectPoint = ray.closestPointToPoint( point );
+ intersectPoint.applyMatrix4( object.matrixWorld );
- var pattern = /([a-z]+)_?(\d+)/;
+ var distance = raycaster.ray.origin.distanceTo( intersectPoint );
- for ( var i = 0, il = geometry.morphTargets.length; i < il; i ++ ) {
+ intersects.push( {
- var morph = geometry.morphTargets[ i ];
- var parts = morph.name.match( pattern );
+ distance: distance,
+ distanceToRay: rayPointDistance,
+ point: intersectPoint.clone(),
+ index: index,
+ face: null,
+ object: object
- if ( parts && parts.length > 1 ) {
+ } );
- var label = parts[ 1 ];
- var num = parts[ 2 ];
+ }
- if ( ! animations[ label ] ) animations[ label ] = { start: Infinity, end: - Infinity };
+ };
- var animation = animations[ label ];
+ if ( geometry instanceof THREE.BufferGeometry ) {
- if ( i < animation.start ) animation.start = i;
- if ( i > animation.end ) animation.end = i;
+ var attributes = geometry.attributes;
+ var positions = attributes.position.array;
- if ( ! firstAnimation ) firstAnimation = label;
+ if ( attributes.index !== undefined ) {
- }
+ var indices = attributes.index.array;
+ var offsets = geometry.offsets;
- }
+ if ( offsets.length === 0 ) {
- geometry.firstAnimation = firstAnimation;
+ var offset = {
+ start: 0,
+ count: indices.length,
+ index: 0
+ };
-};
+ offsets = [ offset ];
-THREE.MorphAnimMesh.prototype.setAnimationLabel = function ( label, start, end ) {
+ }
- if ( ! this.geometry.animations ) this.geometry.animations = {};
+ for ( var oi = 0, ol = offsets.length; oi < ol; ++oi ) {
- this.geometry.animations[ label ] = { start: start, end: end };
+ var start = offsets[ oi ].start;
+ var count = offsets[ oi ].count;
+ var index = offsets[ oi ].index;
-};
+ for ( var i = start, il = start + count; i < il; i ++ ) {
-THREE.MorphAnimMesh.prototype.playAnimation = function ( label, fps ) {
+ var a = index + indices[ i ];
- var animation = this.geometry.animations[ label ];
+ position.fromArray( positions, a * 3 );
- if ( animation ) {
+ testPoint( position, a );
- this.setFrameRange( animation.start, animation.end );
- this.duration = 1000 * ( ( animation.end - animation.start ) / fps );
- this.time = 0;
+ }
- } else {
+ }
- console.warn( 'animation[' + label + '] undefined' );
+ } else {
- }
+ var pointCount = positions.length / 3;
-};
+ for ( var i = 0; i < pointCount; i ++ ) {
-THREE.MorphAnimMesh.prototype.updateAnimation = function ( delta ) {
+ position.set(
+ positions[ 3 * i ],
+ positions[ 3 * i + 1 ],
+ positions[ 3 * i + 2 ]
+ );
- var frameTime = this.duration / this.length;
+ testPoint( position, i );
- this.time += this.direction * delta;
+ }
- if ( this.mirroredLoop ) {
+ }
- if ( this.time > this.duration || this.time < 0 ) {
+ } else {
- this.direction *= - 1;
+ var vertices = this.geometry.vertices;
- if ( this.time > this.duration ) {
+ for ( var i = 0; i < vertices.length; i ++ ) {
- this.time = this.duration;
- this.directionBackwards = true;
+ testPoint( vertices[ i ], i );
}
- if ( this.time < 0 ) {
+ }
- this.time = 0;
- this.directionBackwards = false;
+ };
- }
+}() );
- }
+THREE.PointCloud.prototype.clone = function ( object ) {
- } else {
+ if ( object === undefined ) object = new THREE.PointCloud( this.geometry, this.material );
- this.time = this.time % this.duration;
+ object.sortParticles = this.sortParticles;
- if ( this.time < 0 ) this.time += this.duration;
+ THREE.Object3D.prototype.clone.call( this, object );
- }
+ return object;
- var keyframe = this.startKeyframe + THREE.Math.clamp( Math.floor( this.time / frameTime ), 0, this.length - 1 );
+};
- if ( keyframe !== this.currentKeyframe ) {
+// Backwards compatibility
- this.morphTargetInfluences[ this.lastKeyframe ] = 0;
- this.morphTargetInfluences[ this.currentKeyframe ] = 1;
+THREE.ParticleSystem = function ( geometry, material ) {
- this.morphTargetInfluences[ keyframe ] = 0;
+ console.warn( 'THREE.ParticleSystem has been renamed to THREE.PointCloud.' );
+ return new THREE.PointCloud( geometry, material );
- this.lastKeyframe = this.currentKeyframe;
- this.currentKeyframe = keyframe;
+};
- }
+// File:src/objects/Line.js
- var mix = ( this.time % frameTime ) / frameTime;
+/**
+ * @author mrdoob / http://mrdoob.com/
+ */
- if ( this.directionBackwards ) {
+THREE.Line = function ( geometry, material, mode ) {
- mix = 1 - mix;
+ THREE.Object3D.call( this );
- }
+ this.type = 'Line';
- this.morphTargetInfluences[ this.currentKeyframe ] = mix;
- this.morphTargetInfluences[ this.lastKeyframe ] = 1 - mix;
+ this.geometry = geometry !== undefined ? geometry : new THREE.Geometry();
+ this.material = material !== undefined ? material : new THREE.LineBasicMaterial( { color: Math.random() * 0xffffff } );
+
+ this.mode = ( mode !== undefined ) ? mode : THREE.LineStrip;
};
-THREE.MorphAnimMesh.prototype.interpolateTargets = function ( a, b, t ) {
+THREE.LineStrip = 0;
+THREE.LinePieces = 1;
- var influences = this.morphTargetInfluences;
+THREE.Line.prototype = Object.create( THREE.Object3D.prototype );
- for ( var i = 0, l = influences.length; i < l; i ++ ) {
+THREE.Line.prototype.raycast = ( function () {
- influences[ i ] = 0;
+ var inverseMatrix = new THREE.Matrix4();
+ var ray = new THREE.Ray();
+ var sphere = new THREE.Sphere();
- }
+ return function ( raycaster, intersects ) {
- if ( a > -1 ) influences[ a ] = 1 - t;
- if ( b > -1 ) influences[ b ] = t;
+ var precision = raycaster.linePrecision;
+ var precisionSq = precision * precision;
-};
+ var geometry = this.geometry;
-THREE.MorphAnimMesh.prototype.clone = function ( object ) {
+ if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();
- if ( object === undefined ) object = new THREE.MorphAnimMesh( this.geometry, this.material );
+ // Checking boundingSphere distance to ray
- object.duration = this.duration;
- object.mirroredLoop = this.mirroredLoop;
- object.time = this.time;
+ sphere.copy( geometry.boundingSphere );
+ sphere.applyMatrix4( this.matrixWorld );
- object.lastKeyframe = this.lastKeyframe;
- object.currentKeyframe = this.currentKeyframe;
+ if ( raycaster.ray.isIntersectionSphere( sphere ) === false ) {
- object.direction = this.direction;
- object.directionBackwards = this.directionBackwards;
+ return;
- THREE.Mesh.prototype.clone.call( this, object );
+ }
- return object;
+ inverseMatrix.getInverse( this.matrixWorld );
+ ray.copy( raycaster.ray ).applyMatrix4( inverseMatrix );
-};
+ /* if ( geometry instanceof THREE.BufferGeometry ) {
-// File:src/objects/LOD.js
+ } else */ if ( geometry instanceof THREE.Geometry ) {
-/**
- * @author mikael emtinger / http://gomo.se/
- * @author alteredq / http://alteredqualia.com/
- * @author mrdoob / http://mrdoob.com/
- */
+ var vertices = geometry.vertices;
+ var nbVertices = vertices.length;
+ var interSegment = new THREE.Vector3();
+ var interRay = new THREE.Vector3();
+ var step = this.mode === THREE.LineStrip ? 1 : 2;
-THREE.LOD = function () {
+ for ( var i = 0; i < nbVertices - 1; i = i + step ) {
- THREE.Object3D.call( this );
+ var distSq = ray.distanceSqToSegment( vertices[ i ], vertices[ i + 1 ], interRay, interSegment );
- this.objects = [];
+ if ( distSq > precisionSq ) continue;
-};
+ var distance = ray.origin.distanceTo( interRay );
+ if ( distance < raycaster.near || distance > raycaster.far ) continue;
-THREE.LOD.prototype = Object.create( THREE.Object3D.prototype );
+ intersects.push( {
-THREE.LOD.prototype.addLevel = function ( object, distance ) {
+ distance: distance,
+ // What do we want? intersection point on the ray or on the segment??
+ // point: raycaster.ray.at( distance ),
+ point: interSegment.clone().applyMatrix4( this.matrixWorld ),
+ face: null,
+ faceIndex: null,
+ object: this
- if ( distance === undefined ) distance = 0;
+ } );
- distance = Math.abs( distance );
+ }
- for ( var l = 0; l < this.objects.length; l ++ ) {
+ }
- if ( distance < this.objects[ l ].distance ) {
+ };
- break;
+}() );
- }
+THREE.Line.prototype.clone = function ( object ) {
- }
+ if ( object === undefined ) object = new THREE.Line( this.geometry, this.material, this.mode );
- this.objects.splice( l, 0, { distance: distance, object: object } );
- this.add( object );
+ THREE.Object3D.prototype.clone.call( this, object );
-};
+ return object;
-THREE.LOD.prototype.getObjectForDistance = function ( distance ) {
+};
- for ( var i = 1, l = this.objects.length; i < l; i ++ ) {
+// File:src/objects/Mesh.js
- if ( distance < this.objects[ i ].distance ) {
+/**
+ * @author mrdoob / http://mrdoob.com/
+ * @author alteredq / http://alteredqualia.com/
+ * @author mikael emtinger / http://gomo.se/
+ * @author jonobr1 / http://jonobr1.com/
+ */
- break;
+THREE.Mesh = function ( geometry, material ) {
- }
+ THREE.Object3D.call( this );
- }
+ this.type = 'Mesh';
+
+ this.geometry = geometry !== undefined ? geometry : new THREE.Geometry();
+ this.material = material !== undefined ? material : new THREE.MeshBasicMaterial( { color: Math.random() * 0xffffff } );
- return this.objects[ i - 1 ].object;
+ this.updateMorphTargets();
};
-THREE.LOD.prototype.raycast = ( function () {
+THREE.Mesh.prototype = Object.create( THREE.Object3D.prototype );
- var matrixPosition = new THREE.Vector3();
+THREE.Mesh.prototype.updateMorphTargets = function () {
- return function ( raycaster, intersects ) {
+ if ( this.geometry.morphTargets !== undefined && this.geometry.morphTargets.length > 0 ) {
- matrixPosition.setFromMatrixPosition( this.matrixWorld );
+ this.morphTargetBase = - 1;
+ this.morphTargetForcedOrder = [];
+ this.morphTargetInfluences = [];
+ this.morphTargetDictionary = {};
- var distance = raycaster.ray.origin.distanceTo( matrixPosition );
+ for ( var m = 0, ml = this.geometry.morphTargets.length; m < ml; m ++ ) {
- this.getObjectForDistance( distance ).raycast( raycaster, intersects );
+ this.morphTargetInfluences.push( 0 );
+ this.morphTargetDictionary[ this.geometry.morphTargets[ m ].name ] = m;
- };
+ }
-}() );
+ }
-THREE.LOD.prototype.update = function () {
+};
- var v1 = new THREE.Vector3();
- var v2 = new THREE.Vector3();
+THREE.Mesh.prototype.getMorphTargetIndexByName = function ( name ) {
- return function ( camera ) {
+ if ( this.morphTargetDictionary[ name ] !== undefined ) {
- if ( this.objects.length > 1 ) {
+ return this.morphTargetDictionary[ name ];
- v1.setFromMatrixPosition( camera.matrixWorld );
- v2.setFromMatrixPosition( this.matrixWorld );
+ }
- var distance = v1.distanceTo( v2 );
+ console.log( 'THREE.Mesh.getMorphTargetIndexByName: morph target ' + name + ' does not exist. Returning 0.' );
- this.objects[ 0 ].object.visible = true;
+ return 0;
- for ( var i = 1, l = this.objects.length; i < l; i ++ ) {
+};
- if ( distance >= this.objects[ i ].distance ) {
- this.objects[ i - 1 ].object.visible = false;
- this.objects[ i ].object.visible = true;
+THREE.Mesh.prototype.raycast = ( function () {
- } else {
+ var inverseMatrix = new THREE.Matrix4();
+ var ray = new THREE.Ray();
+ var sphere = new THREE.Sphere();
- break;
+ var vA = new THREE.Vector3();
+ var vB = new THREE.Vector3();
+ var vC = new THREE.Vector3();
- }
+ return function ( raycaster, intersects ) {
- }
+ var geometry = this.geometry;
- for ( ; i < l; i ++ ) {
+ // Checking boundingSphere distance to ray
- this.objects[ i ].object.visible = false;
+ if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();
- }
+ sphere.copy( geometry.boundingSphere );
+ sphere.applyMatrix4( this.matrixWorld );
- }
+ if ( raycaster.ray.isIntersectionSphere( sphere ) === false ) {
- };
+ return;
-}();
+ }
-THREE.LOD.prototype.clone = function ( object ) {
+ // Check boundingBox before continuing
- if ( object === undefined ) object = new THREE.LOD();
+ inverseMatrix.getInverse( this.matrixWorld );
+ ray.copy( raycaster.ray ).applyMatrix4( inverseMatrix );
- THREE.Object3D.prototype.clone.call( this, object );
+ if ( geometry.boundingBox !== null ) {
- for ( var i = 0, l = this.objects.length; i < l; i ++ ) {
- var x = this.objects[ i ].object.clone();
- x.visible = i === 0;
- object.addLevel( x, this.objects[ i ].distance );
- }
+ if ( ray.isIntersectionBox( geometry.boundingBox ) === false ) {
- return object;
+ return;
-};
+ }
-// File:src/objects/Sprite.js
+ }
-/**
- * @author mikael emtinger / http://gomo.se/
- * @author alteredq / http://alteredqualia.com/
- */
+ if ( geometry instanceof THREE.BufferGeometry ) {
-THREE.Sprite = ( function () {
+ var material = this.material;
- var vertices = new Float32Array( [ - 0.5, - 0.5, 0, 0.5, - 0.5, 0, 0.5, 0.5, 0 ] );
+ if ( material === undefined ) return;
- var geometry = new THREE.BufferGeometry();
- geometry.addAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) );
+ var attributes = geometry.attributes;
- return function ( material ) {
+ var a, b, c;
+ var precision = raycaster.precision;
- THREE.Object3D.call( this );
+ if ( attributes.index !== undefined ) {
- this.geometry = geometry;
- this.material = ( material !== undefined ) ? material : new THREE.SpriteMaterial();
+ var indices = attributes.index.array;
+ var positions = attributes.position.array;
+ var offsets = geometry.offsets;
- };
+ if ( offsets.length === 0 ) {
-} )();
+ offsets = [ { start: 0, count: indices.length, index: 0 } ];
-THREE.Sprite.prototype = Object.create( THREE.Object3D.prototype );
+ }
-THREE.Sprite.prototype.raycast = ( function () {
+ for ( var oi = 0, ol = offsets.length; oi < ol; ++oi ) {
- var matrixPosition = new THREE.Vector3();
+ var start = offsets[ oi ].start;
+ var count = offsets[ oi ].count;
+ var index = offsets[ oi ].index;
- return function ( raycaster, intersects ) {
+ for ( var i = start, il = start + count; i < il; i += 3 ) {
- matrixPosition.setFromMatrixPosition( this.matrixWorld );
+ a = index + indices[ i ];
+ b = index + indices[ i + 1 ];
+ c = index + indices[ i + 2 ];
- var distance = raycaster.ray.distanceToPoint( matrixPosition );
+ vA.fromArray( positions, a * 3 );
+ vB.fromArray( positions, b * 3 );
+ vC.fromArray( positions, c * 3 );
- if ( distance > this.scale.x ) {
+ if ( material.side === THREE.BackSide ) {
- return;
+ var intersectionPoint = ray.intersectTriangle( vC, vB, vA, true );
- }
+ } else {
- intersects.push( {
+ var intersectionPoint = ray.intersectTriangle( vA, vB, vC, material.side !== THREE.DoubleSide );
- distance: distance,
- point: this.position,
- face: null,
- object: this
+ }
- } );
+ if ( intersectionPoint === null ) continue;
- };
+ intersectionPoint.applyMatrix4( this.matrixWorld );
-}() );
+ var distance = raycaster.ray.origin.distanceTo( intersectionPoint );
-THREE.Sprite.prototype.updateMatrix = function () {
+ if ( distance < precision || distance < raycaster.near || distance > raycaster.far ) continue;
- this.matrix.compose( this.position, this.quaternion, this.scale );
+ intersects.push( {
- this.matrixWorldNeedsUpdate = true;
+ distance: distance,
+ point: intersectionPoint,
+ face: new THREE.Face3( a, b, c, THREE.Triangle.normal( vA, vB, vC ) ),
+ faceIndex: null,
+ object: this
-};
+ } );
-THREE.Sprite.prototype.clone = function ( object ) {
+ }
- if ( object === undefined ) object = new THREE.Sprite( this.material );
+ }
- THREE.Object3D.prototype.clone.call( this, object );
+ } else {
- return object;
+ var positions = attributes.position.array;
-};
+ for ( var i = 0, j = 0, il = positions.length; i < il; i += 3, j += 9 ) {
-// Backwards compatibility
+ a = i;
+ b = i + 1;
+ c = i + 2;
-THREE.Particle = THREE.Sprite;
+ vA.fromArray( positions, j );
+ vB.fromArray( positions, j + 3 );
+ vC.fromArray( positions, j + 6 );
-// File:src/scenes/Scene.js
+ if ( material.side === THREE.BackSide ) {
-/**
- * @author mrdoob / http://mrdoob.com/
- */
+ var intersectionPoint = ray.intersectTriangle( vC, vB, vA, true );
-THREE.Scene = function () {
+ } else {
- THREE.Object3D.call( this );
+ var intersectionPoint = ray.intersectTriangle( vA, vB, vC, material.side !== THREE.DoubleSide );
- this.fog = null;
- this.overrideMaterial = null;
+ }
- this.autoUpdate = true; // checked by the renderer
- this.matrixAutoUpdate = false;
+ if ( intersectionPoint === null ) continue;
- this.__lights = [];
+ intersectionPoint.applyMatrix4( this.matrixWorld );
- this.__objectsAdded = [];
- this.__objectsRemoved = [];
+ var distance = raycaster.ray.origin.distanceTo( intersectionPoint );
-};
+ if ( distance < precision || distance < raycaster.near || distance > raycaster.far ) continue;
-THREE.Scene.prototype = Object.create( THREE.Object3D.prototype );
+ intersects.push( {
-THREE.Scene.prototype.__addObject = function ( object ) {
+ distance: distance,
+ point: intersectionPoint,
+ face: new THREE.Face3( a, b, c, THREE.Triangle.normal( vA, vB, vC ) ),
+ faceIndex: null,
+ object: this
- if ( object instanceof THREE.Light ) {
+ } );
- if ( this.__lights.indexOf( object ) === - 1 ) {
+ }
- this.__lights.push( object );
+ }
- }
+ } else if ( geometry instanceof THREE.Geometry ) {
- if ( object.target && object.target.parent === undefined ) {
+ var isFaceMaterial = this.material instanceof THREE.MeshFaceMaterial;
+ var objectMaterials = isFaceMaterial === true ? this.material.materials : null;
- this.add( object.target );
+ var a, b, c, d;
+ var precision = raycaster.precision;
- }
+ var vertices = geometry.vertices;
- } else if ( ! ( object instanceof THREE.Camera || object instanceof THREE.Bone ) ) {
+ for ( var f = 0, fl = geometry.faces.length; f < fl; f ++ ) {
- this.__objectsAdded.push( object );
+ var face = geometry.faces[ f ];
- // check if previously removed
+ var material = isFaceMaterial === true ? objectMaterials[ face.materialIndex ] : this.material;
- var i = this.__objectsRemoved.indexOf( object );
+ if ( material === undefined ) continue;
- if ( i !== - 1 ) {
+ a = vertices[ face.a ];
+ b = vertices[ face.b ];
+ c = vertices[ face.c ];
- this.__objectsRemoved.splice( i, 1 );
+ if ( material.morphTargets === true ) {
- }
+ var morphTargets = geometry.morphTargets;
+ var morphInfluences = this.morphTargetInfluences;
- }
+ vA.set( 0, 0, 0 );
+ vB.set( 0, 0, 0 );
+ vC.set( 0, 0, 0 );
- this.dispatchEvent( { type: 'objectAdded', object: object } );
- object.dispatchEvent( { type: 'addedToScene', scene: this } );
+ for ( var t = 0, tl = morphTargets.length; t < tl; t ++ ) {
- for ( var c = 0; c < object.children.length; c ++ ) {
+ var influence = morphInfluences[ t ];
- this.__addObject( object.children[ c ] );
+ if ( influence === 0 ) continue;
- }
+ var targets = morphTargets[ t ].vertices;
-};
+ vA.x += ( targets[ face.a ].x - a.x ) * influence;
+ vA.y += ( targets[ face.a ].y - a.y ) * influence;
+ vA.z += ( targets[ face.a ].z - a.z ) * influence;
-THREE.Scene.prototype.__removeObject = function ( object ) {
+ vB.x += ( targets[ face.b ].x - b.x ) * influence;
+ vB.y += ( targets[ face.b ].y - b.y ) * influence;
+ vB.z += ( targets[ face.b ].z - b.z ) * influence;
- if ( object instanceof THREE.Light ) {
+ vC.x += ( targets[ face.c ].x - c.x ) * influence;
+ vC.y += ( targets[ face.c ].y - c.y ) * influence;
+ vC.z += ( targets[ face.c ].z - c.z ) * influence;
- var i = this.__lights.indexOf( object );
+ }
- if ( i !== - 1 ) {
+ vA.add( a );
+ vB.add( b );
+ vC.add( c );
- this.__lights.splice( i, 1 );
+ a = vA;
+ b = vB;
+ c = vC;
- }
+ }
- if ( object.shadowCascadeArray ) {
+ if ( material.side === THREE.BackSide ) {
- for ( var x = 0; x < object.shadowCascadeArray.length; x ++ ) {
+ var intersectionPoint = ray.intersectTriangle( c, b, a, true );
- this.__removeObject( object.shadowCascadeArray[ x ] );
+ } else {
- }
+ var intersectionPoint = ray.intersectTriangle( a, b, c, material.side !== THREE.DoubleSide );
- }
+ }
- } else if ( ! ( object instanceof THREE.Camera ) ) {
+ if ( intersectionPoint === null ) continue;
- this.__objectsRemoved.push( object );
+ intersectionPoint.applyMatrix4( this.matrixWorld );
- // check if previously added
+ var distance = raycaster.ray.origin.distanceTo( intersectionPoint );
- var i = this.__objectsAdded.indexOf( object );
+ if ( distance < precision || distance < raycaster.near || distance > raycaster.far ) continue;
- if ( i !== - 1 ) {
+ intersects.push( {
- this.__objectsAdded.splice( i, 1 );
-
- }
-
- }
-
- this.dispatchEvent( { type: 'objectRemoved', object: object } );
- object.dispatchEvent( { type: 'removedFromScene', scene: this } );
-
- for ( var c = 0; c < object.children.length; c ++ ) {
+ distance: distance,
+ point: intersectionPoint,
+ face: face,
+ faceIndex: f,
+ object: this
- this.__removeObject( object.children[ c ] );
+ } );
- }
+ }
-};
+ }
-THREE.Scene.prototype.clone = function ( object ) {
+ };
- if ( object === undefined ) object = new THREE.Scene();
+}() );
- THREE.Object3D.prototype.clone.call( this, object );
+THREE.Mesh.prototype.clone = function ( object, recursive ) {
- if ( this.fog !== null ) object.fog = this.fog.clone();
- if ( this.overrideMaterial !== null ) object.overrideMaterial = this.overrideMaterial.clone();
+ if ( object === undefined ) object = new THREE.Mesh( this.geometry, this.material );
- object.autoUpdate = this.autoUpdate;
- object.matrixAutoUpdate = this.matrixAutoUpdate;
+ THREE.Object3D.prototype.clone.call( this, object, recursive );
return object;
};
-// File:src/scenes/Fog.js
+// File:src/objects/Bone.js
/**
- * @author mrdoob / http://mrdoob.com/
+ * @author mikael emtinger / http://gomo.se/
* @author alteredq / http://alteredqualia.com/
+ * @author ikerr / http://verold.com
*/
-THREE.Fog = function ( color, near, far ) {
-
- this.name = '';
+THREE.Bone = function ( belongsToSkin ) {
- this.color = new THREE.Color( color );
+ THREE.Object3D.call( this );
- this.near = ( near !== undefined ) ? near : 1;
- this.far = ( far !== undefined ) ? far : 1000;
+ this.skin = belongsToSkin;
};
-THREE.Fog.prototype.clone = function () {
-
- return new THREE.Fog( this.color.getHex(), this.near, this.far );
+THREE.Bone.prototype = Object.create( THREE.Object3D.prototype );
-};
-// File:src/scenes/FogExp2.js
+// File:src/objects/Skeleton.js
/**
- * @author mrdoob / http://mrdoob.com/
+ * @author mikael emtinger / http://gomo.se/
* @author alteredq / http://alteredqualia.com/
+ * @author michael guerrero / http://realitymeltdown.com
+ * @author ikerr / http://verold.com
*/
-THREE.FogExp2 = function ( color, density ) {
-
- this.name = '';
-
- this.color = new THREE.Color( color );
- this.density = ( density !== undefined ) ? density : 0.00025;
-
-};
-
-THREE.FogExp2.prototype.clone = function () {
-
- return new THREE.FogExp2( this.color.getHex(), this.density );
+THREE.Skeleton = function ( bones, boneInverses, useVertexTexture ) {
-};
+ this.useVertexTexture = useVertexTexture !== undefined ? useVertexTexture : true;
-// File:src/renderers/CanvasRenderer.js
+ this.identityMatrix = new THREE.Matrix4();
-/**
- * @author mrdoob / http://mrdoob.com/
- */
+ // copy the bone array
-THREE.CanvasRenderer = function ( parameters ) {
+ bones = bones || [];
- console.log( 'THREE.CanvasRenderer', THREE.REVISION );
+ this.bones = bones.slice( 0 );
- var smoothstep = THREE.Math.smoothstep;
+ // create a bone texture or an array of floats
- parameters = parameters || {};
+ if ( this.useVertexTexture ) {
- var _this = this,
- _renderData, _elements, _lights,
- _projector = new THREE.Projector(),
+ // layout (1 matrix = 4 pixels)
+ // RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4)
+ // with 8x8 pixel texture max 16 bones (8 * 8 / 4)
+ // 16x16 pixel texture max 64 bones (16 * 16 / 4)
+ // 32x32 pixel texture max 256 bones (32 * 32 / 4)
+ // 64x64 pixel texture max 1024 bones (64 * 64 / 4)
- _canvas = parameters.canvas !== undefined
- ? parameters.canvas
- : document.createElement( 'canvas' ),
+ var size;
- _canvasWidth = _canvas.width,
- _canvasHeight = _canvas.height,
- _canvasWidthHalf = Math.floor( _canvasWidth / 2 ),
- _canvasHeightHalf = Math.floor( _canvasHeight / 2 ),
+ if ( this.bones.length > 256 )
+ size = 64;
+ else if ( this.bones.length > 64 )
+ size = 32;
+ else if ( this.bones.length > 16 )
+ size = 16;
+ else
+ size = 8;
- _viewportX = 0,
- _viewportY = 0,
- _viewportWidth = _canvasWidth,
- _viewportHeight = _canvasHeight,
+ this.boneTextureWidth = size;
+ this.boneTextureHeight = size;
- _context = _canvas.getContext( '2d', {
- alpha: parameters.alpha === true
- } ),
+ this.boneMatrices = new Float32Array( this.boneTextureWidth * this.boneTextureHeight * 4 ); // 4 floats per RGBA pixel
+ this.boneTexture = new THREE.DataTexture( this.boneMatrices, this.boneTextureWidth, this.boneTextureHeight, THREE.RGBAFormat, THREE.FloatType );
+ this.boneTexture.minFilter = THREE.NearestFilter;
+ this.boneTexture.magFilter = THREE.NearestFilter;
+ this.boneTexture.generateMipmaps = false;
+ this.boneTexture.flipY = false;
- _clearColor = new THREE.Color( 0x000000 ),
- _clearAlpha = 0,
+ } else {
- _contextGlobalAlpha = 1,
- _contextGlobalCompositeOperation = 0,
- _contextStrokeStyle = null,
- _contextFillStyle = null,
- _contextLineWidth = null,
- _contextLineCap = null,
- _contextLineJoin = null,
- _contextLineDash = [],
+ this.boneMatrices = new Float32Array( 16 * this.bones.length );
- _camera,
+ }
- _v1, _v2, _v3, _v4,
- _v5 = new THREE.RenderableVertex(),
- _v6 = new THREE.RenderableVertex(),
+ // use the supplied bone inverses or calculate the inverses
- _v1x, _v1y, _v2x, _v2y, _v3x, _v3y,
- _v4x, _v4y, _v5x, _v5y, _v6x, _v6y,
+ if ( boneInverses === undefined ) {
- _color = new THREE.Color(),
- _color1 = new THREE.Color(),
- _color2 = new THREE.Color(),
- _color3 = new THREE.Color(),
- _color4 = new THREE.Color(),
+ this.calculateInverses();
- _diffuseColor = new THREE.Color(),
- _emissiveColor = new THREE.Color(),
+ } else {
- _lightColor = new THREE.Color(),
+ if ( this.bones.length === boneInverses.length ) {
- _patterns = {},
+ this.boneInverses = boneInverses.slice( 0 );
- _image, _uvs,
- _uv1x, _uv1y, _uv2x, _uv2y, _uv3x, _uv3y,
+ } else {
- _clipBox = new THREE.Box2(),
- _clearBox = new THREE.Box2(),
- _elemBox = new THREE.Box2(),
+ console.warn( 'THREE.Skeleton bonInverses is the wrong length.' );
- _ambientLight = new THREE.Color(),
- _directionalLights = new THREE.Color(),
- _pointLights = new THREE.Color(),
+ this.boneInverses = [];
- _vector3 = new THREE.Vector3(), // Needed for PointLight
- _centroid = new THREE.Vector3(),
- _normal = new THREE.Vector3(),
- _normalViewMatrix = new THREE.Matrix3();
+ for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) {
- // dash+gap fallbacks for Firefox and everything else
+ this.boneInverses.push( new THREE.Matrix4() );
- if ( _context.setLineDash === undefined ) {
+ }
- _context.setLineDash = function () {}
+ }
}
- this.domElement = _canvas;
+};
- this.devicePixelRatio = parameters.devicePixelRatio !== undefined
- ? parameters.devicePixelRatio
- : self.devicePixelRatio !== undefined
- ? self.devicePixelRatio
- : 1;
+THREE.Skeleton.prototype.calculateInverses = function () {
- this.autoClear = true;
- this.sortObjects = true;
- this.sortElements = true;
+ this.boneInverses = [];
- this.info = {
+ for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) {
- render: {
+ var inverse = new THREE.Matrix4();
- vertices: 0,
- faces: 0
+ if ( this.bones[ b ] ) {
+
+ inverse.getInverse( this.bones[ b ].matrixWorld );
}
+ this.boneInverses.push( inverse );
+
}
- // WebGLRenderer compatibility
+};
- this.supportsVertexTextures = function () {};
- this.setFaceCulling = function () {};
+THREE.Skeleton.prototype.pose = function () {
- this.setSize = function ( width, height, updateStyle ) {
+ var bone;
- _canvasWidth = width * this.devicePixelRatio;
- _canvasHeight = height * this.devicePixelRatio;
+ // recover the bind-time world matrices
- _canvas.width = _canvasWidth;
- _canvas.height = _canvasHeight;
+ for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) {
- _canvasWidthHalf = Math.floor( _canvasWidth / 2 );
- _canvasHeightHalf = Math.floor( _canvasHeight / 2 );
+ bone = this.bones[ b ];
- if ( updateStyle !== false ) {
+ if ( bone ) {
- _canvas.style.width = width + 'px';
- _canvas.style.height = height + 'px';
+ bone.matrixWorld.getInverse( this.boneInverses[ b ] );
}
- _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;
+ // compute the local matrices, positions, rotations and scales
- this.setViewport( 0, 0, width, height );
+ for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) {
- };
+ bone = this.bones[ b ];
- this.setViewport = function ( x, y, width, height ) {
+ if ( bone ) {
- _viewportX = x * this.devicePixelRatio;
- _viewportY = y * this.devicePixelRatio;
+ if ( bone.parent ) {
- _viewportWidth = width * this.devicePixelRatio;
- _viewportHeight = height * this.devicePixelRatio;
+ bone.matrix.getInverse( bone.parent.matrixWorld );
+ bone.matrix.multiply( bone.matrixWorld );
- };
+ } else {
- this.setScissor = function () {};
- this.enableScissorTest = function () {};
+ bone.matrix.copy( bone.matrixWorld );
- this.setClearColor = function ( color, alpha ) {
+ }
- _clearColor.set( color );
- _clearAlpha = alpha !== undefined ? alpha : 1;
+ bone.matrix.decompose( bone.position, bone.quaternion, bone.scale );
- _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 );
+THREE.Skeleton.prototype.update = ( function () {
- };
+ var offsetMatrix = new THREE.Matrix4();
- this.getClearColor = function () {
+ return function () {
- return _clearColor;
+ // flatten bone matrices to array
- };
+ for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) {
- this.getClearAlpha = function () {
+ // compute the offset between the current and the original transform
- return _clearAlpha;
+ var matrix = this.bones[ b ] ? this.bones[ b ].matrixWorld : this.identityMatrix;
- };
+ offsetMatrix.multiplyMatrices( matrix, this.boneInverses[ b ] );
+ offsetMatrix.flattenToArrayOffset( this.boneMatrices, b * 16 );
- this.getMaxAnisotropy = function () {
+ }
- return 0;
+ if ( this.useVertexTexture ) {
- };
+ this.boneTexture.needsUpdate = true;
- 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;
- _clearBox.max.x = _clearBox.max.x + _canvasWidthHalf;
- _clearBox.max.y = - _clearBox.max.y + _canvasHeightHalf;
+// File:src/objects/SkinnedMesh.js
- if ( _clearAlpha < 1 ) {
+/**
+ * @author mikael emtinger / http://gomo.se/
+ * @author alteredq / http://alteredqualia.com/
+ * @author ikerr / http://verold.com
+ */
- _context.clearRect(
- _clearBox.min.x | 0,
- _clearBox.min.y | 0,
- ( _clearBox.max.x - _clearBox.min.x ) | 0,
- ( _clearBox.max.y - _clearBox.min.y ) | 0
- );
+THREE.SkinnedMesh = function ( geometry, material, useVertexTexture ) {
- }
+ THREE.Mesh.call( this, geometry, material );
- if ( _clearAlpha > 0 ) {
+ this.type = 'SkinnedMesh';
- setBlending( THREE.NormalBlending );
- setOpacity( 1 );
+ this.bindMode = "attached";
+ this.bindMatrix = new THREE.Matrix4();
+ this.bindMatrixInverse = new THREE.Matrix4();
- setFillStyle( 'rgba(' + Math.floor( _clearColor.r * 255 ) + ',' + Math.floor( _clearColor.g * 255 ) + ',' + Math.floor( _clearColor.b * 255 ) + ',' + _clearAlpha + ')' );
+ // init bones
- _context.fillRect(
- _clearBox.min.x | 0,
- _clearBox.min.y | 0,
- ( _clearBox.max.x - _clearBox.min.x ) | 0,
- ( _clearBox.max.y - _clearBox.min.y ) | 0
- );
+ // TODO: remove bone creation as there is no reason (other than
+ // convenience) for THREE.SkinnedMesh to do this.
- }
+ var bones = [];
- _clearBox.makeEmpty();
+ if ( this.geometry && this.geometry.bones !== undefined ) {
- }
+ var bone, gbone, p, q, s;
- };
+ for ( var b = 0, bl = this.geometry.bones.length; b < bl; ++b ) {
- // compatibility
+ gbone = this.geometry.bones[ b ];
- this.clearColor = function () {};
- this.clearDepth = function () {};
- this.clearStencil = function () {};
+ p = gbone.pos;
+ q = gbone.rotq;
+ s = gbone.scl;
- this.render = function ( scene, camera ) {
+ bone = new THREE.Bone( this );
+ bones.push( bone );
- if ( camera instanceof THREE.Camera === false ) {
+ bone.name = gbone.name;
+ bone.position.set( p[ 0 ], p[ 1 ], p[ 2 ] );
+ bone.quaternion.set( q[ 0 ], q[ 1 ], q[ 2 ], q[ 3 ] );
- console.error( 'THREE.CanvasRenderer.render: camera is not an instance of THREE.Camera.' );
- return;
+ if ( s !== undefined ) {
- }
+ bone.scale.set( s[ 0 ], s[ 1 ], s[ 2 ] );
- if ( this.autoClear === true ) this.clear();
+ } else {
- _this.info.render.vertices = 0;
- _this.info.render.faces = 0;
+ bone.scale.set( 1, 1, 1 );
- _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 );
+ for ( var b = 0, bl = this.geometry.bones.length; b < bl; ++b ) {
- /* 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 );
- */
+ gbone = this.geometry.bones[ b ];
- calculateLights();
+ if ( gbone.parent !== - 1 ) {
- for ( var e = 0, el = _elements.length; e < el; e ++ ) {
+ bones[ gbone.parent ].add( bones[ b ] );
- var element = _elements[ e ];
+ } else {
- var material = element.material;
+ this.add( bones[ b ] );
- if ( material === undefined || material.opacity === 0 ) continue;
+ }
- _elemBox.makeEmpty();
+ }
- if ( element instanceof THREE.RenderableSprite ) {
+ }
- _v1 = element;
- _v1.x *= _canvasWidthHalf; _v1.y *= _canvasHeightHalf;
+ this.normalizeSkinWeights();
- 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;
+ this.updateMatrixWorld( true );
+ this.bind( new THREE.Skeleton( bones, undefined, useVertexTexture ) );
- _elemBox.setFromPoints( [
- _v1.positionScreen,
- _v2.positionScreen
- ] );
+};
- if ( _clipBox.isIntersectionBox( _elemBox ) === true ) {
- renderLine( _v1, _v2, element, material );
+THREE.SkinnedMesh.prototype = Object.create( THREE.Mesh.prototype );
- }
+THREE.SkinnedMesh.prototype.bind = function( skeleton, bindMatrix ) {
- } else if ( element instanceof THREE.RenderableFace ) {
+ this.skeleton = skeleton;
- _v1 = element.v1; _v2 = element.v2; _v3 = element.v3;
+ if ( bindMatrix === undefined ) {
- 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;
+ this.updateMatrixWorld( true );
- _v1.positionScreen.x *= _canvasWidthHalf; _v1.positionScreen.y *= _canvasHeightHalf;
- _v2.positionScreen.x *= _canvasWidthHalf; _v2.positionScreen.y *= _canvasHeightHalf;
- _v3.positionScreen.x *= _canvasWidthHalf; _v3.positionScreen.y *= _canvasHeightHalf;
+ bindMatrix = this.matrixWorld;
- 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 );
+ this.bindMatrix.copy( bindMatrix );
+ this.bindMatrixInverse.getInverse( bindMatrix );
- }
+};
- _elemBox.setFromPoints( [
- _v1.positionScreen,
- _v2.positionScreen,
- _v3.positionScreen
- ] );
+THREE.SkinnedMesh.prototype.pose = function () {
- if ( _clipBox.isIntersectionBox( _elemBox ) === true ) {
+ this.skeleton.pose();
- renderFace3( _v1, _v2, _v3, 0, 1, 2, element, material );
+};
- }
+THREE.SkinnedMesh.prototype.normalizeSkinWeights = function () {
- }
+ if ( this.geometry instanceof THREE.Geometry ) {
- /* 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 );
- */
+ for ( var i = 0; i < this.geometry.skinIndices.length; i ++ ) {
- _clearBox.union( _elemBox );
+ var sw = this.geometry.skinWeights[ i ];
- }
+ var scale = 1.0 / sw.lengthManhattan();
- /* 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 );
- */
+ if ( scale !== Infinity ) {
- _context.setTransform( 1, 0, 0, 1, 0, 0 );
+ sw.multiplyScalar( scale );
- };
+ } else {
- //
+ sw.set( 1 ); // this will be normalized by the shader anyway
- 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 ++ ) {
+ } else {
- var light = _lights[ l ];
- var lightColor = light.color;
+ // skinning weights assumed to be normalized for THREE.BufferGeometry
- if ( light instanceof THREE.AmbientLight ) {
+ }
- _ambientLight.add( lightColor );
+};
- } else if ( light instanceof THREE.DirectionalLight ) {
+THREE.SkinnedMesh.prototype.updateMatrixWorld = function( force ) {
- // for sprites
+ THREE.Mesh.prototype.updateMatrixWorld.call( this, true );
- _directionalLights.add( lightColor );
+ if ( this.bindMode === "attached" ) {
- } else if ( light instanceof THREE.PointLight ) {
+ this.bindMatrixInverse.getInverse( this.matrixWorld );
- // for sprites
+ } else if ( this.bindMode === "detached" ) {
- _pointLights.add( lightColor );
+ this.bindMatrixInverse.getInverse( this.bindMatrix );
- }
+ } else {
- }
+ console.warn( 'THREE.SkinnedMesh unreckognized bindMode: ' + this.bindMode );
}
- function calculateLight( position, normal, color ) {
+};
- for ( var l = 0, ll = _lights.length; l < ll; l ++ ) {
+THREE.SkinnedMesh.prototype.clone = function( object ) {
- var light = _lights[ l ];
+ if ( object === undefined ) {
- _lightColor.copy( light.color );
+ object = new THREE.SkinnedMesh( this.geometry, this.material, this.useVertexTexture );
- if ( light instanceof THREE.DirectionalLight ) {
+ }
- var lightPosition = _vector3.setFromMatrixPosition( light.matrixWorld ).normalize();
+ THREE.Mesh.prototype.clone.call( this, object );
- var amount = normal.dot( lightPosition );
+ return object;
- if ( amount <= 0 ) continue;
+};
- amount *= light.intensity;
- color.add( _lightColor.multiplyScalar( amount ) );
+// File:src/objects/MorphAnimMesh.js
- } else if ( light instanceof THREE.PointLight ) {
+/**
+ * @author alteredq / http://alteredqualia.com/
+ */
- var lightPosition = _vector3.setFromMatrixPosition( light.matrixWorld );
+THREE.MorphAnimMesh = function ( geometry, material ) {
- var amount = normal.dot( _vector3.subVectors( lightPosition, position ).normalize() );
+ THREE.Mesh.call( this, geometry, material );
- if ( amount <= 0 ) continue;
+ this.type = 'MorphAnimMesh';
- amount *= light.distance == 0 ? 1 : 1 - Math.min( position.distanceTo( lightPosition ) / light.distance, 1 );
+ // API
- if ( amount == 0 ) continue;
+ this.duration = 1000; // milliseconds
+ this.mirroredLoop = false;
+ this.time = 0;
- amount *= light.intensity;
+ // internals
- color.add( _lightColor.multiplyScalar( amount ) );
+ this.lastKeyframe = 0;
+ this.currentKeyframe = 0;
- }
+ this.direction = 1;
+ this.directionBackwards = false;
- }
+ this.setFrameRange( 0, this.geometry.morphTargets.length - 1 );
- }
+};
- function renderSprite( v1, element, material ) {
+THREE.MorphAnimMesh.prototype = Object.create( THREE.Mesh.prototype );
- setOpacity( material.opacity );
- setBlending( material.blending );
+THREE.MorphAnimMesh.prototype.setFrameRange = function ( start, end ) {
- var scaleX = element.scale.x * _canvasWidthHalf;
- var scaleY = element.scale.y * _canvasHeightHalf;
+ this.startKeyframe = start;
+ this.endKeyframe = end;
- 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 );
+ this.length = this.endKeyframe - this.startKeyframe + 1;
- if ( material instanceof THREE.SpriteMaterial ) {
+};
- var texture = material.map;
+THREE.MorphAnimMesh.prototype.setDirectionForward = function () {
- if ( texture !== null && texture.image !== undefined ) {
+ this.direction = 1;
+ this.directionBackwards = false;
- if ( texture.hasEventListener( 'update', onTextureUpdate ) === false ) {
+};
- if ( texture.image.width > 0 ) {
+THREE.MorphAnimMesh.prototype.setDirectionBackward = function () {
- textureToPattern( texture );
+ this.direction = - 1;
+ this.directionBackwards = true;
- }
+};
- texture.addEventListener( 'update', onTextureUpdate );
+THREE.MorphAnimMesh.prototype.parseAnimations = function () {
- }
+ var geometry = this.geometry;
- var pattern = _patterns[ texture.id ];
+ if ( ! geometry.animations ) geometry.animations = {};
- if ( pattern !== undefined ) {
+ var firstAnimation, animations = geometry.animations;
- setFillStyle( pattern );
+ var pattern = /([a-z]+)_?(\d+)/;
- } else {
+ for ( var i = 0, il = geometry.morphTargets.length; i < il; i ++ ) {
- setFillStyle( 'rgba( 0, 0, 0, 1 )' );
+ var morph = geometry.morphTargets[ i ];
+ var parts = morph.name.match( pattern );
- }
+ if ( parts && parts.length > 1 ) {
- //
+ var label = parts[ 1 ];
+ var num = parts[ 2 ];
- var bitmap = texture.image;
+ if ( ! animations[ label ] ) animations[ label ] = { start: Infinity, end: - Infinity };
- var ox = bitmap.width * texture.offset.x;
- var oy = bitmap.height * texture.offset.y;
+ var animation = animations[ label ];
- var sx = bitmap.width * texture.repeat.x;
- var sy = bitmap.height * texture.repeat.y;
+ if ( i < animation.start ) animation.start = i;
+ if ( i > animation.end ) animation.end = i;
- var cx = scaleX / sx;
- var cy = scaleY / sy;
+ if ( ! firstAnimation ) firstAnimation = label;
- _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
+ geometry.firstAnimation = firstAnimation;
- 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();
+THREE.MorphAnimMesh.prototype.setAnimationLabel = function ( label, start, end ) {
- }
+ if ( ! this.geometry.animations ) this.geometry.animations = {};
- } else if ( material instanceof THREE.SpriteCanvasMaterial ) {
+ this.geometry.animations[ label ] = { start: start, end: end };
- 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 );
+THREE.MorphAnimMesh.prototype.playAnimation = function ( label, fps ) {
- material.program( _context );
+ var animation = this.geometry.animations[ label ];
- _context.restore();
+ if ( animation ) {
- }
+ this.setFrameRange( animation.start, animation.end );
+ this.duration = 1000 * ( ( animation.end - animation.start ) / fps );
+ this.time = 0;
- /* 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();
- */
+ } else {
+
+ console.warn( 'animation[' + label + '] undefined' );
}
- function renderLine( v1, v2, element, material ) {
+};
- setOpacity( material.opacity );
- setBlending( material.blending );
+THREE.MorphAnimMesh.prototype.updateAnimation = function ( delta ) {
- _context.beginPath();
- _context.moveTo( v1.positionScreen.x, v1.positionScreen.y );
- _context.lineTo( v2.positionScreen.x, v2.positionScreen.y );
+ var frameTime = this.duration / this.length;
- if ( material instanceof THREE.LineBasicMaterial ) {
+ this.time += this.direction * delta;
- setLineWidth( material.linewidth );
- setLineCap( material.linecap );
- setLineJoin( material.linejoin );
+ if ( this.mirroredLoop ) {
- if ( material.vertexColors !== THREE.VertexColors ) {
+ if ( this.time > this.duration || this.time < 0 ) {
- setStrokeStyle( material.color.getStyle() );
+ this.direction *= - 1;
- } else {
+ if ( this.time > this.duration ) {
- var colorStyle1 = element.vertexColors[ 0 ].getStyle();
- var colorStyle2 = element.vertexColors[ 1 ].getStyle();
+ this.time = this.duration;
+ this.directionBackwards = true;
- if ( colorStyle1 === colorStyle2 ) {
+ }
- setStrokeStyle( colorStyle1 );
+ if ( this.time < 0 ) {
- } else {
+ this.time = 0;
+ this.directionBackwards = false;
- 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 ) {
+ } else {
- grad = colorStyle1;
+ this.time = this.time % this.duration;
- }
+ if ( this.time < 0 ) this.time += this.duration;
- setStrokeStyle( grad );
+ }
- }
+ var keyframe = this.startKeyframe + THREE.Math.clamp( Math.floor( this.time / frameTime ), 0, this.length - 1 );
- }
+ if ( keyframe !== this.currentKeyframe ) {
- _context.stroke();
- _elemBox.expandByScalar( material.linewidth * 2 );
+ this.morphTargetInfluences[ this.lastKeyframe ] = 0;
+ this.morphTargetInfluences[ this.currentKeyframe ] = 1;
- } else if ( material instanceof THREE.LineDashedMaterial ) {
+ this.morphTargetInfluences[ keyframe ] = 0;
- setLineWidth( material.linewidth );
- setLineCap( material.linecap );
- setLineJoin( material.linejoin );
- setStrokeStyle( material.color.getStyle() );
- setLineDash( [ material.dashSize, material.gapSize ] );
+ this.lastKeyframe = this.currentKeyframe;
+ this.currentKeyframe = keyframe;
- _context.stroke();
+ }
- _elemBox.expandByScalar( material.linewidth * 2 );
+ var mix = ( this.time % frameTime ) / frameTime;
- setLineDash( [] );
+ if ( this.directionBackwards ) {
- }
+ mix = 1 - mix;
}
- function renderFace3( v1, v2, v3, uv1, uv2, uv3, element, material ) {
+ this.morphTargetInfluences[ this.currentKeyframe ] = mix;
+ this.morphTargetInfluences[ this.lastKeyframe ] = 1 - mix;
- _this.info.render.vertices += 3;
- _this.info.render.faces ++;
+};
- setOpacity( material.opacity );
- setBlending( material.blending );
+THREE.MorphAnimMesh.prototype.interpolateTargets = function ( a, b, t ) {
- _v1x = v1.positionScreen.x; _v1y = v1.positionScreen.y;
- _v2x = v2.positionScreen.x; _v2y = v2.positionScreen.y;
- _v3x = v3.positionScreen.x; _v3y = v3.positionScreen.y;
+ var influences = this.morphTargetInfluences;
- drawTriangle( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y );
+ for ( var i = 0, l = influences.length; i < l; i ++ ) {
- if ( ( material instanceof THREE.MeshLambertMaterial || material instanceof THREE.MeshPhongMaterial ) && material.map === null ) {
+ influences[ i ] = 0;
- _diffuseColor.copy( material.color );
- _emissiveColor.copy( material.emissive );
+ }
- if ( material.vertexColors === THREE.FaceColors ) {
+ if ( a > -1 ) influences[ a ] = 1 - t;
+ if ( b > -1 ) influences[ b ] = t;
- _diffuseColor.multiply( element.color );
+};
- }
+THREE.MorphAnimMesh.prototype.clone = function ( object ) {
- _color.copy( _ambientLight );
+ if ( object === undefined ) object = new THREE.MorphAnimMesh( this.geometry, this.material );
- _centroid.copy( v1.positionWorld ).add( v2.positionWorld ).add( v3.positionWorld ).divideScalar( 3 );
+ object.duration = this.duration;
+ object.mirroredLoop = this.mirroredLoop;
+ object.time = this.time;
- calculateLight( _centroid, element.normalModel, _color );
+ object.lastKeyframe = this.lastKeyframe;
+ object.currentKeyframe = this.currentKeyframe;
- _color.multiply( _diffuseColor ).add( _emissiveColor );
+ object.direction = this.direction;
+ object.directionBackwards = this.directionBackwards;
- material.wireframe === true
- ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin )
- : fillPath( _color );
+ THREE.Mesh.prototype.clone.call( this, object );
- } else if ( material instanceof THREE.MeshBasicMaterial ||
- material instanceof THREE.MeshLambertMaterial ||
- material instanceof THREE.MeshPhongMaterial ) {
+ return object;
- if ( material.map !== null ) {
+};
- if ( material.map.mapping instanceof THREE.UVMapping ) {
+// File:src/objects/LOD.js
- _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 );
+/**
+ * @author mikael emtinger / http://gomo.se/
+ * @author alteredq / http://alteredqualia.com/
+ * @author mrdoob / http://mrdoob.com/
+ */
- }
+THREE.LOD = function () {
- } else if ( material.envMap !== null ) {
+ THREE.Object3D.call( this );
- if ( material.envMap.mapping instanceof THREE.SphericalReflectionMapping ) {
+ this.objects = [];
- _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;
+THREE.LOD.prototype = Object.create( THREE.Object3D.prototype );
- patternPath( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, _uv1x, _uv1y, _uv2x, _uv2y, _uv3x, _uv3y, material.envMap );
+THREE.LOD.prototype.addLevel = function ( object, distance ) {
- } else if ( material.envMap.mapping instanceof THREE.SphericalRefractionMapping ) {
+ if ( distance === undefined ) distance = 0;
- _normal.copy( element.vertexNormalsModel[ uv1 ] ).applyMatrix3( _normalViewMatrix );
- _uv1x = - 0.5 * _normal.x + 0.5;
- _uv1y = - 0.5 * _normal.y + 0.5;
+ distance = Math.abs( distance );
- _normal.copy( element.vertexNormalsModel[ uv2 ] ).applyMatrix3( _normalViewMatrix );
- _uv2x = - 0.5 * _normal.x + 0.5;
- _uv2y = - 0.5 * _normal.y + 0.5;
+ for ( var l = 0; l < this.objects.length; l ++ ) {
- _normal.copy( element.vertexNormalsModel[ uv3 ] ).applyMatrix3( _normalViewMatrix );
- _uv3x = - 0.5 * _normal.x + 0.5;
- _uv3y = - 0.5 * _normal.y + 0.5;
+ if ( distance < this.objects[ l ].distance ) {
- patternPath( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, _uv1x, _uv1y, _uv2x, _uv2y, _uv3x, _uv3y, material.envMap );
+ break;
- }
+ }
+ }
- } else {
+ this.objects.splice( l, 0, { distance: distance, object: object } );
+ this.add( object );
- _color.copy( material.color );
+};
- if ( material.vertexColors === THREE.FaceColors ) {
+THREE.LOD.prototype.getObjectForDistance = function ( distance ) {
- _color.multiply( element.color );
+ for ( var i = 1, l = this.objects.length; i < l; i ++ ) {
- }
+ if ( distance < this.objects[ i ].distance ) {
- material.wireframe === true
- ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin )
- : fillPath( _color );
+ break;
- }
+ }
- } else if ( material instanceof THREE.MeshDepthMaterial ) {
+ }
- _color.r = _color.g = _color.b = 1 - smoothstep( v1.positionScreen.z * v1.positionScreen.w, _camera.near, _camera.far );
+ return this.objects[ i - 1 ].object;
- material.wireframe === true
- ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin )
- : fillPath( _color );
+};
- } else if ( material instanceof THREE.MeshNormalMaterial ) {
+THREE.LOD.prototype.raycast = ( function () {
- _normal.copy( element.normalModel ).applyMatrix3( _normalViewMatrix );
+ var matrixPosition = new THREE.Vector3();
- _color.setRGB( _normal.x, _normal.y, _normal.z ).multiplyScalar( 0.5 ).addScalar( 0.5 );
+ return function ( raycaster, intersects ) {
- material.wireframe === true
- ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin )
- : fillPath( _color );
+ matrixPosition.setFromMatrixPosition( this.matrixWorld );
- } else {
+ var distance = raycaster.ray.origin.distanceTo( matrixPosition );
- _color.setRGB( 1, 1, 1 );
+ this.getObjectForDistance( distance ).raycast( raycaster, intersects );
- material.wireframe === true
- ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin )
- : fillPath( _color );
+ };
- }
+}() );
- }
+THREE.LOD.prototype.update = function () {
- //
+ var v1 = new THREE.Vector3();
+ var v2 = new THREE.Vector3();
- function drawTriangle( x0, y0, x1, y1, x2, y2 ) {
+ return function ( camera ) {
- _context.beginPath();
- _context.moveTo( x0, y0 );
- _context.lineTo( x1, y1 );
- _context.lineTo( x2, y2 );
- _context.closePath();
+ if ( this.objects.length > 1 ) {
- }
+ v1.setFromMatrixPosition( camera.matrixWorld );
+ v2.setFromMatrixPosition( this.matrixWorld );
- function strokePath( color, linewidth, linecap, linejoin ) {
+ var distance = v1.distanceTo( v2 );
- setLineWidth( linewidth );
- setLineCap( linecap );
- setLineJoin( linejoin );
- setStrokeStyle( color.getStyle() );
+ this.objects[ 0 ].object.visible = true;
- _context.stroke();
+ for ( var i = 1, l = this.objects.length; i < l; i ++ ) {
- _elemBox.expandByScalar( linewidth * 2 );
+ if ( distance >= this.objects[ i ].distance ) {
- }
+ this.objects[ i - 1 ].object.visible = false;
+ this.objects[ i ].object.visible = true;
- function fillPath( color ) {
+ } else {
- setFillStyle( color.getStyle() );
- _context.fill();
+ break;
- }
+ }
- function onTextureUpdate ( event ) {
+ }
- textureToPattern( event.target );
+ for ( ; i < l; i ++ ) {
- }
+ this.objects[ i ].object.visible = false;
- 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;
+THREE.LOD.prototype.clone = function ( object ) {
- var context = canvas.getContext( '2d' );
- context.setTransform( 1, 0, 0, - 1, 0, image.height );
- context.drawImage( image, 0, 0 );
+ if ( object === undefined ) object = new THREE.LOD();
- _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'
- );
+ THREE.Object3D.prototype.clone.call( this, object );
+ for ( var i = 0, l = this.objects.length; i < l; i ++ ) {
+ var x = this.objects[ i ].object.clone();
+ x.visible = i === 0;
+ object.addLevel( x, this.objects[ i ].distance );
}
- 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 ) {
+ return object;
- textureToPattern( texture );
+};
- }
+// File:src/objects/Sprite.js
- texture.addEventListener( 'update', onTextureUpdate );
+/**
+ * @author mikael emtinger / http://gomo.se/
+ * @author alteredq / http://alteredqualia.com/
+ */
- }
+THREE.Sprite = ( function () {
- var pattern = _patterns[ texture.id ];
+ var indices = new Uint16Array( [ 0, 1, 2, 0, 2, 3 ] );
+ var vertices = new Float32Array( [ - 0.5, - 0.5, 0, 0.5, - 0.5, 0, 0.5, 0.5, 0, - 0.5, 0.5, 0 ] );
+ var uvs = new Float32Array( [ 0, 0, 1, 0, 1, 1, 0, 1 ] );
- if ( pattern !== undefined ) {
+ var geometry = new THREE.BufferGeometry();
+ geometry.addAttribute( 'index', new THREE.BufferAttribute( indices, 1 ) );
+ geometry.addAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) );
+ geometry.addAttribute( 'uv', new THREE.BufferAttribute( uvs, 2 ) );
- setFillStyle( pattern );
+ return function ( material ) {
- } else {
+ THREE.Object3D.call( this );
- setFillStyle( 'rgba(0,0,0,1)' );
- _context.fill();
+ this.type = 'Sprite';
- return;
+ this.geometry = geometry;
+ this.material = ( material !== undefined ) ? material : new THREE.SpriteMaterial();
- }
+ };
- // 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;
+THREE.Sprite.prototype = Object.create( THREE.Object3D.prototype );
- u0 = ( u0 + offsetX ) * width;
- v0 = ( v0 + offsetY ) * height;
+THREE.Sprite.prototype.raycast = ( function () {
- u1 = ( u1 + offsetX ) * width;
- v1 = ( v1 + offsetY ) * height;
+ var matrixPosition = new THREE.Vector3();
- u2 = ( u2 + offsetX ) * width;
- v2 = ( v2 + offsetY ) * height;
+ return function ( raycaster, intersects ) {
- x1 -= x0; y1 -= y0;
- x2 -= x0; y2 -= y0;
+ matrixPosition.setFromMatrixPosition( this.matrixWorld );
- u1 -= u0; v1 -= v0;
- u2 -= u0; v2 -= v0;
+ var distance = raycaster.ray.distanceToPoint( matrixPosition );
- det = u1 * v2 - u2 * v1;
+ if ( distance > this.scale.x ) {
- if ( det === 0 ) return;
+ 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;
+ intersects.push( {
- e = x0 - a * u0 - c * v0;
- f = y0 - b * u0 - d * v0;
+ distance: distance,
+ point: this.position,
+ face: null,
+ object: this
- _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
+THREE.Sprite.prototype.clone = function ( object ) {
- var a, b, c, d, e, f, det, idet,
- width = image.width - 1,
- height = image.height - 1;
+ if ( object === undefined ) object = new THREE.Sprite( this.material );
- u0 *= width; v0 *= height;
- u1 *= width; v1 *= height;
- u2 *= width; v2 *= height;
+ THREE.Object3D.prototype.clone.call( this, object );
- x1 -= x0; y1 -= y0;
- x2 -= x0; y2 -= y0;
+ return object;
- u1 -= u0; v1 -= v0;
- u2 -= u0; v2 -= v0;
+};
- det = u1 * v2 - u2 * v1;
+// Backwards compatibility
- idet = 1 / det;
+THREE.Particle = THREE.Sprite;
- a = ( v2 * x1 - v1 * x2 ) * idet;
- b = ( v2 * y1 - v1 * y2 ) * idet;
- c = ( u1 * x2 - u2 * x1 ) * idet;
- d = ( u1 * y2 - u2 * y1 ) * idet;
+// File:src/objects/LensFlare.js
- e = x0 - a * u0 - c * v0;
- f = y0 - b * u0 - d * v0;
+/**
+ * @author mikael emtinger / http://gomo.se/
+ * @author alteredq / http://alteredqualia.com/
+ */
- _context.save();
- _context.transform( a, b, c, d, e, f );
- _context.clip();
- _context.drawImage( image, 0, 0 );
- _context.restore();
+THREE.LensFlare = function ( texture, size, distance, blending, color ) {
- }
+ THREE.Object3D.call( this );
- // Hide anti-alias gaps
+ this.lensFlares = [];
- function expand( v1, v2, pixels ) {
+ this.positionScreen = new THREE.Vector3();
+ this.customUpdateCallback = undefined;
- var x = v2.x - v1.x, y = v2.y - v1.y,
- det = x * x + y * y, idet;
+ if( texture !== undefined ) {
- if ( det === 0 ) return;
+ this.add( texture, size, distance, blending, color );
- idet = pixels / Math.sqrt( det );
+ }
- x *= idet; y *= idet;
+};
- v2.x += x; v2.y += y;
- v1.x -= x; v1.y -= y;
+THREE.LensFlare.prototype = Object.create( THREE.Object3D.prototype );
- }
- // Context cached methods.
+/*
+ * Add: adds another flare
+ */
- function setOpacity( value ) {
+THREE.LensFlare.prototype.add = function ( texture, size, distance, blending, color, opacity ) {
- if ( _contextGlobalAlpha !== value ) {
+ if ( size === undefined ) size = - 1;
+ if ( distance === undefined ) distance = 0;
+ if ( opacity === undefined ) opacity = 1;
+ if ( color === undefined ) color = new THREE.Color( 0xffffff );
+ if ( blending === undefined ) blending = THREE.NormalBlending;
- _context.globalAlpha = value;
- _contextGlobalAlpha = value;
+ distance = Math.min( distance, Math.max( 0, distance ) );
- }
+ this.lensFlares.push( {
+ texture: texture, // THREE.Texture
+ size: size, // size in pixels (-1 = use texture.width)
+ distance: distance, // distance (0-1) from light source (0=at light source)
+ x: 0, y: 0, z: 0, // screen position (-1 => 1) z = 0 is ontop z = 1 is back
+ scale: 1, // scale
+ rotation: 1, // rotation
+ opacity: opacity, // opacity
+ color: color, // color
+ blending: blending // blending
+ } );
- }
+};
- function setBlending( value ) {
+/*
+ * Update lens flares update positions on all flares based on the screen position
+ * Set myLensFlare.customUpdateCallback to alter the flares in your project specific way.
+ */
- if ( _contextGlobalCompositeOperation !== value ) {
+THREE.LensFlare.prototype.updateLensFlares = function () {
- if ( value === THREE.NormalBlending ) {
+ var f, fl = this.lensFlares.length;
+ var flare;
+ var vecX = - this.positionScreen.x * 2;
+ var vecY = - this.positionScreen.y * 2;
- _context.globalCompositeOperation = 'source-over';
+ for( f = 0; f < fl; f ++ ) {
- } else if ( value === THREE.AdditiveBlending ) {
+ flare = this.lensFlares[ f ];
- _context.globalCompositeOperation = 'lighter';
+ flare.x = this.positionScreen.x + vecX * flare.distance;
+ flare.y = this.positionScreen.y + vecY * flare.distance;
- } else if ( value === THREE.SubtractiveBlending ) {
+ flare.wantedRotation = flare.x * Math.PI * 0.25;
+ flare.rotation += ( flare.wantedRotation - flare.rotation ) * 0.25;
- _context.globalCompositeOperation = 'darker';
+ }
- }
+};
- _contextGlobalCompositeOperation = value;
- }
+// File:src/scenes/Scene.js
- }
+/**
+ * @author mrdoob / http://mrdoob.com/
+ */
- function setLineWidth( value ) {
+THREE.Scene = function () {
- if ( _contextLineWidth !== value ) {
+ THREE.Object3D.call( this );
- _context.lineWidth = value;
- _contextLineWidth = value;
+ this.type = 'Scene';
- }
+ this.fog = null;
+ this.overrideMaterial = null;
- }
+ this.autoUpdate = true; // checked by the renderer
- function setLineCap( value ) {
+};
- // "butt", "round", "square"
+THREE.Scene.prototype = Object.create( THREE.Object3D.prototype );
- if ( _contextLineCap !== value ) {
+THREE.Scene.prototype.clone = function ( object ) {
- _context.lineCap = value;
- _contextLineCap = value;
+ if ( object === undefined ) object = new THREE.Scene();
- }
+ THREE.Object3D.prototype.clone.call( this, object );
- }
+ if ( this.fog !== null ) object.fog = this.fog.clone();
+ if ( this.overrideMaterial !== null ) object.overrideMaterial = this.overrideMaterial.clone();
- function setLineJoin( value ) {
+ object.autoUpdate = this.autoUpdate;
+ object.matrixAutoUpdate = this.matrixAutoUpdate;
- // "round", "bevel", "miter"
+ return object;
- if ( _contextLineJoin !== value ) {
+};
- _context.lineJoin = value;
- _contextLineJoin = value;
+// File:src/scenes/Fog.js
- }
+/**
+ * @author mrdoob / http://mrdoob.com/
+ * @author alteredq / http://alteredqualia.com/
+ */
- }
+THREE.Fog = function ( color, near, far ) {
- function setStrokeStyle( value ) {
+ this.name = '';
- if ( _contextStrokeStyle !== value ) {
+ this.color = new THREE.Color( color );
- _context.strokeStyle = value;
- _contextStrokeStyle = value;
+ this.near = ( near !== undefined ) ? near : 1;
+ this.far = ( far !== undefined ) ? far : 1000;
- }
+};
- }
+THREE.Fog.prototype.clone = function () {
- function setFillStyle( value ) {
+ return new THREE.Fog( this.color.getHex(), this.near, this.far );
- if ( _contextFillStyle !== value ) {
+};
- _context.fillStyle = value;
- _contextFillStyle = value;
+// File:src/scenes/FogExp2.js
- }
+/**
+ * @author mrdoob / http://mrdoob.com/
+ * @author alteredq / http://alteredqualia.com/
+ */
- }
+THREE.FogExp2 = function ( color, density ) {
- function setLineDash( value ) {
+ this.name = '';
- if ( _contextLineDash.length !== value.length ) {
+ this.color = new THREE.Color( color );
+ this.density = ( density !== undefined ) ? density : 0.00025;
- _context.setLineDash( value );
- _contextLineDash = value;
+};
- }
+THREE.FogExp2.prototype.clone = function () {
- }
+ return new THREE.FogExp2( this.color.getHex(), this.density );
};
@@ -17080,7 +15995,7 @@ THREE.ShaderChunk[ 'morphnormal_vertex'] = "#ifdef USE_MORPHNORMALS\n\n vec3 mor
// File:src/renderers/shaders/ShaderChunk/envmap_pars_fragment.glsl
-THREE.ShaderChunk[ 'envmap_pars_fragment'] = "#ifdef USE_ENVMAP\n\n uniform float reflectivity;\n uniform samplerCube envMap;\n uniform float flipEnvMap;\n uniform int combine;\n\n #if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )\n\n uniform bool useRefract;\n uniform float refractionRatio;\n\n #else\n\n varying vec3 vReflect;\n\n #endif\n\n#endif";
+THREE.ShaderChunk[ 'envmap_pars_fragment'] = "#ifdef USE_ENVMAP\n\n uniform float reflectivity;\n uniform samplerCube envMap;\n uniform float flipEnvMap;\n uniform int combine;\n\n #if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\n uniform bool useRefract;\n uniform float refractionRatio;\n\n #else\n\n varying vec3 vReflect;\n\n #endif\n\n#endif";
// File:src/renderers/shaders/ShaderChunk/logdepthbuf_fragment.glsl
@@ -17132,7 +16047,7 @@ THREE.ShaderChunk[ 'skinning_vertex'] = "#ifdef USE_SKINNING\n\n #ifdef USE_MORP
// File:src/renderers/shaders/ShaderChunk/envmap_pars_vertex.glsl
-THREE.ShaderChunk[ 'envmap_pars_vertex'] = "#if defined( USE_ENVMAP ) && ! defined( USE_BUMPMAP ) && ! defined( USE_NORMALMAP )\n\n varying vec3 vReflect;\n\n uniform float refractionRatio;\n uniform bool useRefract;\n\n#endif\n";
+THREE.ShaderChunk[ 'envmap_pars_vertex'] = "#if defined( USE_ENVMAP ) && ! defined( USE_BUMPMAP ) && ! defined( USE_NORMALMAP ) && ! defined( PHONG )\n\n varying vec3 vReflect;\n\n uniform float refractionRatio;\n uniform bool useRefract;\n\n#endif\n";
// File:src/renderers/shaders/ShaderChunk/linear_to_gamma_fragment.glsl
@@ -17152,7 +16067,7 @@ THREE.ShaderChunk[ 'map_pars_vertex'] = "#if defined( USE_MAP ) || defined( USE_
// File:src/renderers/shaders/ShaderChunk/envmap_fragment.glsl
-THREE.ShaderChunk[ 'envmap_fragment'] = "#ifdef USE_ENVMAP\n\n vec3 reflectVec;\n\n #if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )\n\n vec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );\n\n // http://en.wikibooks.org/wiki/GLSL_Programming/Applying_Matrix_Transformations\n // Transforming Normal Vectors with the Inverse Transformation\n\n vec3 worldNormal = normalize( vec3( vec4( normal, 0.0 ) * viewMatrix ) );\n\n if ( useRefract ) {\n\n reflectVec = refract( cameraToVertex, worldNormal, refractionRatio );\n\n } else { \n\n reflectVec = reflect( cameraToVertex, worldNormal );\n\n }\n\n #else\n\n reflectVec = vReflect;\n\n #endif\n\n #ifdef DOUBLE_SIDED\n\n float flipNormal = ( -1.0 + 2.0 * float( gl_FrontFacing ) );\n vec4 cubeColor = textureCube( envMap, flipNormal * vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );\n\n #else\n\n vec4 cubeColor = textureCube( envMap, vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );\n\n #endif\n\n #ifdef GAMMA_INPUT\n\n cubeColor.xyz *= cubeColor.xyz;\n\n #endif\n\n if ( combine == 1 ) {\n\n gl_FragColor.xyz = mix( gl_FragColor.xyz, cubeColor.xyz, specularStrength * reflectivity );\n\n } else if ( combine == 2 ) {\n\n gl_FragColor.xyz += cubeColor.xyz * specularStrength * reflectivity;\n\n } else {\n\n gl_FragColor.xyz = mix( gl_FragColor.xyz, gl_FragColor.xyz * cubeColor.xyz, specularStrength * reflectivity );\n\n }\n\n#endif";
+THREE.ShaderChunk[ 'envmap_fragment'] = "#ifdef USE_ENVMAP\n\n vec3 reflectVec;\n\n #if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\n vec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );\n\n // http://en.wikibooks.org/wiki/GLSL_Programming/Applying_Matrix_Transformations\n // Transforming Normal Vectors with the Inverse Transformation\n\n vec3 worldNormal = normalize( vec3( vec4( normal, 0.0 ) * viewMatrix ) );\n\n if ( useRefract ) {\n\n reflectVec = refract( cameraToVertex, worldNormal, refractionRatio );\n\n } else { \n\n reflectVec = reflect( cameraToVertex, worldNormal );\n\n }\n\n #else\n\n reflectVec = vReflect;\n\n #endif\n\n #ifdef DOUBLE_SIDED\n\n float flipNormal = ( -1.0 + 2.0 * float( gl_FrontFacing ) );\n vec4 cubeColor = textureCube( envMap, flipNormal * vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );\n\n #else\n\n vec4 cubeColor = textureCube( envMap, vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );\n\n #endif\n\n #ifdef GAMMA_INPUT\n\n cubeColor.xyz *= cubeColor.xyz;\n\n #endif\n\n if ( combine == 1 ) {\n\n gl_FragColor.xyz = mix( gl_FragColor.xyz, cubeColor.xyz, specularStrength * reflectivity );\n\n } else if ( combine == 2 ) {\n\n gl_FragColor.xyz += cubeColor.xyz * specularStrength * reflectivity;\n\n } else {\n\n gl_FragColor.xyz = mix( gl_FragColor.xyz, gl_FragColor.xyz * cubeColor.xyz, specularStrength * reflectivity );\n\n }\n\n#endif";
// File:src/renderers/shaders/ShaderChunk/specularmap_pars_fragment.glsl
@@ -17212,7 +16127,7 @@ THREE.ShaderChunk[ 'morphtarget_vertex'] = "#ifdef USE_MORPHTARGETS\n\n vec3 mor
// File:src/renderers/shaders/ShaderChunk/envmap_vertex.glsl
-THREE.ShaderChunk[ 'envmap_vertex'] = "#if defined( USE_ENVMAP ) && ! defined( USE_BUMPMAP ) && ! defined( USE_NORMALMAP )\n\n vec3 worldNormal = mat3( modelMatrix[ 0 ].xyz, modelMatrix[ 1 ].xyz, modelMatrix[ 2 ].xyz ) * objectNormal;\n worldNormal = normalize( worldNormal );\n\n vec3 cameraToVertex = normalize( worldPosition.xyz - cameraPosition );\n\n if ( useRefract ) {\n\n vReflect = refract( cameraToVertex, worldNormal, refractionRatio );\n\n } else {\n\n vReflect = reflect( cameraToVertex, worldNormal );\n\n }\n\n#endif";
+THREE.ShaderChunk[ 'envmap_vertex'] = "#if defined( USE_ENVMAP ) && ! defined( USE_BUMPMAP ) && ! defined( USE_NORMALMAP ) && ! defined( PHONG )\n\n vec3 worldNormal = mat3( modelMatrix[ 0 ].xyz, modelMatrix[ 1 ].xyz, modelMatrix[ 2 ].xyz ) * objectNormal;\n worldNormal = normalize( worldNormal );\n\n vec3 cameraToVertex = normalize( worldPosition.xyz - cameraPosition );\n\n if ( useRefract ) {\n\n vReflect = refract( cameraToVertex, worldNormal, refractionRatio );\n\n } else {\n\n vReflect = reflect( cameraToVertex, worldNormal );\n\n }\n\n#endif";
// File:src/renderers/shaders/ShaderChunk/shadowmap_fragment.glsl
@@ -17252,13 +16167,13 @@ THREE.UniformsUtils = {
merge: function ( uniforms ) {
- var u, p, tmp, merged = {};
+ var merged = {};
- for ( u = 0; u < uniforms.length; u ++ ) {
+ for ( var u = 0; u < uniforms.length; u ++ ) {
- tmp = this.clone( uniforms[ u ] );
+ var tmp = this.clone( uniforms[ u ] );
- for ( p in tmp ) {
+ for ( var p in tmp ) {
merged[ p ] = tmp[ p ];
@@ -17272,15 +16187,15 @@ THREE.UniformsUtils = {
clone: function ( uniforms_src ) {
- var u, p, parameter, parameter_src, uniforms_dst = {};
+ var uniforms_dst = {};
- for ( u in uniforms_src ) {
+ for ( var u in uniforms_src ) {
uniforms_dst[ u ] = {};
- for ( p in uniforms_src[ u ] ) {
+ for ( var p in uniforms_src[ u ] ) {
- parameter_src = uniforms_src[ u ][ p ];
+ var parameter_src = uniforms_src[ u ][ p ];
if ( parameter_src instanceof THREE.Color ||
parameter_src instanceof THREE.Vector2 ||
@@ -17714,6 +16629,8 @@ THREE.ShaderLib = {
fragmentShader: [
+ "#define PHONG",
+
"uniform vec3 diffuse;",
"uniform float opacity;",
@@ -18778,10 +17695,18 @@ THREE.WebGLRenderer = function ( parameters ) {
_clearColor = new THREE.Color( 0x000000 ),
_clearAlpha = 0;
-
+
+ var lights = [];
+
+ var _webglObjects = {};
+ var _webglObjectsImmediate = [];
+
var opaqueObjects = [];
var transparentObjects = [];
+ var sprites = [];
+ var lensFlares = [];
+
// public properties
this.domElement = _canvas;
@@ -18811,7 +17736,6 @@ THREE.WebGLRenderer = function ( parameters ) {
// shadow map
this.shadowMapEnabled = false;
- this.shadowMapAutoUpdate = true;
this.shadowMapType = THREE.PCFShadowMap;
this.shadowMapCullFace = THREE.CullFaceFront;
this.shadowMapDebug = false;
@@ -18826,11 +17750,6 @@ THREE.WebGLRenderer = function ( parameters ) {
this.autoScaleCubemaps = true;
- // custom render plugins
-
- this.renderPluginsPre = [];
- this.renderPluginsPost = [];
-
// info
this.info = {
@@ -18865,7 +17784,7 @@ THREE.WebGLRenderer = function ( parameters ) {
_currentProgram = null,
_currentFramebuffer = null,
_currentMaterialId = - 1,
- _currentGeometryGroupHash = null,
+ _currentGeometryGroupHash = - 1,
_currentCamera = null,
_usedTextureUnits = 0,
@@ -18931,111 +17850,247 @@ THREE.WebGLRenderer = function ( parameters ) {
var _gl;
- var _glExtensionTextureFloat;
- var _glExtensionTextureFloatLinear;
- var _glExtensionStandardDerivatives;
- var _glExtensionTextureFilterAnisotropic;
- var _glExtensionCompressedTextureS3TC;
- var _glExtensionElementIndexUint;
- var _glExtensionFragDepth;
+ try {
+ var attributes = {
+ alpha: _alpha,
+ depth: _depth,
+ stencil: _stencil,
+ antialias: _antialias,
+ premultipliedAlpha: _premultipliedAlpha,
+ preserveDrawingBuffer: _preserveDrawingBuffer
+ };
- initGL();
-
- setDefaultGLState();
-
- this.context = _gl;
-
- // GPU capabilities
-
- var _maxTextures = _gl.getParameter( _gl.MAX_TEXTURE_IMAGE_UNITS );
- var _maxVertexTextures = _gl.getParameter( _gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS );
- var _maxTextureSize = _gl.getParameter( _gl.MAX_TEXTURE_SIZE );
- var _maxCubemapSize = _gl.getParameter( _gl.MAX_CUBE_MAP_TEXTURE_SIZE );
+ _gl = _context || _canvas.getContext( 'webgl', attributes ) || _canvas.getContext( 'experimental-webgl', attributes );
- var _maxAnisotropy = _glExtensionTextureFilterAnisotropic ? _gl.getParameter( _glExtensionTextureFilterAnisotropic.MAX_TEXTURE_MAX_ANISOTROPY_EXT ) : 0;
+ if ( _gl === null ) {
- var _supportsVertexTextures = ( _maxVertexTextures > 0 );
- var _supportsBoneTextures = _supportsVertexTextures && _glExtensionTextureFloat;
+ if ( _canvas.getContext( 'webgl') !== null ) {
- var _compressedTextureFormats = _glExtensionCompressedTextureS3TC ? _gl.getParameter( _gl.COMPRESSED_TEXTURE_FORMATS ) : [];
+ throw 'Error creating WebGL context with your selected attributes.';
- //
+ } else {
- var _vertexShaderPrecisionHighpFloat = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.HIGH_FLOAT );
- var _vertexShaderPrecisionMediumpFloat = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.MEDIUM_FLOAT );
- var _vertexShaderPrecisionLowpFloat = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.LOW_FLOAT );
+ throw 'Error creating WebGL context.';
- var _fragmentShaderPrecisionHighpFloat = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.HIGH_FLOAT );
- var _fragmentShaderPrecisionMediumpFloat = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.MEDIUM_FLOAT );
- var _fragmentShaderPrecisionLowpFloat = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.LOW_FLOAT );
+ }
- // clamp precision to maximum available
+ }
- var highpAvailable = _vertexShaderPrecisionHighpFloat.precision > 0 && _fragmentShaderPrecisionHighpFloat.precision > 0;
- var mediumpAvailable = _vertexShaderPrecisionMediumpFloat.precision > 0 && _fragmentShaderPrecisionMediumpFloat.precision > 0;
+ } catch ( error ) {
- if ( _precision === 'highp' && ! highpAvailable ) {
+ console.error( error );
- if ( mediumpAvailable ) {
+ }
- _precision = 'mediump';
- console.warn( 'THREE.WebGLRenderer: highp not supported, using mediump.' );
+ if ( _gl.getShaderPrecisionFormat === undefined ) {
- } else {
+ _gl.getShaderPrecisionFormat = function () {
- _precision = 'lowp';
- console.warn( 'THREE.WebGLRenderer: highp and mediump not supported, using lowp.' );
+ return {
+ 'rangeMin': 1,
+ 'rangeMax': 1,
+ 'precision': 1
+ };
}
}
- if ( _precision === 'mediump' && ! mediumpAvailable ) {
+ var extensions = new THREE.WebGLExtensions( _gl );
- _precision = 'lowp';
- console.warn( 'THREE.WebGLRenderer: mediump not supported, using lowp.' );
+ extensions.get( 'OES_texture_float' );
+ extensions.get( 'OES_texture_float_linear' );
+ extensions.get( 'OES_standard_derivatives' );
- }
+ if ( _logarithmicDepthBuffer ) {
- // API
+ extensions.get( 'EXT_frag_depth' );
- this.getContext = function () {
+ }
- return _gl;
+ //
- };
+ function setDefaultGLState() {
- this.supportsVertexTextures = function () {
+ _gl.clearColor( 0, 0, 0, 1 );
+ _gl.clearDepth( 1 );
+ _gl.clearStencil( 0 );
- return _supportsVertexTextures;
+ _gl.enable( _gl.DEPTH_TEST );
+ _gl.depthFunc( _gl.LEQUAL );
- };
+ _gl.frontFace( _gl.CCW );
+ _gl.cullFace( _gl.BACK );
+ _gl.enable( _gl.CULL_FACE );
+
+ _gl.enable( _gl.BLEND );
+ _gl.blendEquation( _gl.FUNC_ADD );
+ _gl.blendFunc( _gl.SRC_ALPHA, _gl.ONE_MINUS_SRC_ALPHA );
+
+ _gl.viewport( _viewportX, _viewportY, _viewportWidth, _viewportHeight );
+
+ _gl.clearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha );
+
+ }
+
+ setDefaultGLState();
+
+ this.context = _gl;
+
+ // GPU capabilities
+
+ var _maxTextures = _gl.getParameter( _gl.MAX_TEXTURE_IMAGE_UNITS );
+ var _maxVertexTextures = _gl.getParameter( _gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS );
+ var _maxTextureSize = _gl.getParameter( _gl.MAX_TEXTURE_SIZE );
+ var _maxCubemapSize = _gl.getParameter( _gl.MAX_CUBE_MAP_TEXTURE_SIZE );
+
+ var _supportsVertexTextures = _maxVertexTextures > 0;
+ var _supportsBoneTextures = _supportsVertexTextures && extensions.get( 'OES_texture_float' );
+
+ //
+
+ var _vertexShaderPrecisionHighpFloat = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.HIGH_FLOAT );
+ var _vertexShaderPrecisionMediumpFloat = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.MEDIUM_FLOAT );
+ var _vertexShaderPrecisionLowpFloat = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.LOW_FLOAT );
+
+ var _fragmentShaderPrecisionHighpFloat = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.HIGH_FLOAT );
+ var _fragmentShaderPrecisionMediumpFloat = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.MEDIUM_FLOAT );
+ var _fragmentShaderPrecisionLowpFloat = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.LOW_FLOAT );
+
+ var getCompressedTextureFormats = ( function () {
+
+ var array;
+
+ return function () {
+
+ if ( array !== undefined ) {
+
+ return array;
+
+ }
+
+ array = [];
+
+ if ( extensions.get( 'WEBGL_compressed_texture_pvrtc' ) || extensions.get( 'WEBGL_compressed_texture_s3tc' ) ) {
+
+ var formats = _gl.getParameter( _gl.COMPRESSED_TEXTURE_FORMATS );
+
+ for ( var i = 0; i < formats.length; i ++ ){
+
+ array.push( formats[ i ] );
+
+ }
+
+ }
+
+ return array;
+
+ };
+
+ } )();
+
+ // clamp precision to maximum available
+
+ var highpAvailable = _vertexShaderPrecisionHighpFloat.precision > 0 && _fragmentShaderPrecisionHighpFloat.precision > 0;
+ var mediumpAvailable = _vertexShaderPrecisionMediumpFloat.precision > 0 && _fragmentShaderPrecisionMediumpFloat.precision > 0;
+
+ if ( _precision === 'highp' && ! highpAvailable ) {
+
+ if ( mediumpAvailable ) {
+
+ _precision = 'mediump';
+ console.warn( 'THREE.WebGLRenderer: highp not supported, using mediump.' );
+
+ } else {
+
+ _precision = 'lowp';
+ console.warn( 'THREE.WebGLRenderer: highp and mediump not supported, using lowp.' );
+
+ }
+
+ }
+
+ if ( _precision === 'mediump' && ! mediumpAvailable ) {
+
+ _precision = 'lowp';
+ console.warn( 'THREE.WebGLRenderer: mediump not supported, using lowp.' );
+
+ }
+
+ // Plugins
+
+ var shadowMapPlugin = new THREE.ShadowMapPlugin( this, lights, _webglObjects, _webglObjectsImmediate );
+
+ var spritePlugin = new THREE.SpritePlugin( this, sprites );
+ var lensFlarePlugin = new THREE.LensFlarePlugin( this, lensFlares );
+
+ // API
+
+ this.getContext = function () {
+
+ return _gl;
+
+ };
+
+ this.supportsVertexTextures = function () {
+
+ return _supportsVertexTextures;
+
+ };
this.supportsFloatTextures = function () {
- return _glExtensionTextureFloat;
+ return extensions.get( 'OES_texture_float' );
};
this.supportsStandardDerivatives = function () {
- return _glExtensionStandardDerivatives;
+ return extensions.get( 'OES_standard_derivatives' );
};
this.supportsCompressedTextureS3TC = function () {
- return _glExtensionCompressedTextureS3TC;
+ return extensions.get( 'WEBGL_compressed_texture_s3tc' );
+
+ };
+
+ this.supportsCompressedTexturePVRTC = function () {
+
+ return extensions.get( 'WEBGL_compressed_texture_pvrtc' );
};
- this.getMaxAnisotropy = function () {
+ this.supportsBlendMinMax = function () {
- return _maxAnisotropy;
+ return extensions.get( 'EXT_blend_minmax' );
};
+ this.getMaxAnisotropy = ( function () {
+
+ var value;
+
+ return function () {
+
+ if ( value !== undefined ) {
+
+ return value;
+
+ }
+
+ var extension = extensions.get( 'EXT_texture_filter_anisotropic' );
+
+ value = extension !== null ? _gl.getParameter( extension.MAX_TEXTURE_MAX_ANISOTROPY_EXT ) : 0;
+
+ return value;
+
+ }
+
+ } )();
+
this.getPrecision = function () {
return _precision;
@@ -19154,44 +18209,25 @@ THREE.WebGLRenderer = function ( parameters ) {
};
- // Plugins
-
- this.addPostPlugin = function ( plugin ) {
-
- plugin.init( this );
- this.renderPluginsPost.push( plugin );
-
- };
-
- this.addPrePlugin = function ( plugin ) {
-
- plugin.init( this );
- this.renderPluginsPre.push( plugin );
-
- };
-
- // Rendering
+ // Reset
- this.updateShadowMap = function ( scene, camera ) {
+ this.resetGLState = function () {
_currentProgram = null;
+ _currentCamera = null;
+
_oldBlending = - 1;
_oldDepthTest = - 1;
_oldDepthWrite = - 1;
- _currentGeometryGroupHash = - 1;
- _currentMaterialId = - 1;
- _lightsNeedUpdate = true;
_oldDoubleSided = - 1;
_oldFlipSided = - 1;
+ _currentGeometryGroupHash = - 1;
+ _currentMaterialId = - 1;
- initObjects( scene );
-
- this.shadowMapPlugin.update( scene, camera );
+ _lightsNeedUpdate = true;
};
- // Internal functions
-
// Buffer allocation
function createParticleBuffers ( geometry ) {
@@ -19260,6 +18296,20 @@ THREE.WebGLRenderer = function ( parameters ) {
// Events
+ var onObjectRemoved = function ( event ) {
+
+ var object = event.target;
+
+ object.traverse( function ( child ) {
+
+ child.removeEventListener( 'remove', onObjectRemoved );
+
+ removeObject( child );
+
+ } );
+
+ };
+
var onGeometryDispose = function ( event ) {
var geometry = event.target;
@@ -19308,31 +18358,50 @@ THREE.WebGLRenderer = function ( parameters ) {
// Buffer deallocation
var deleteBuffers = function ( geometry ) {
+
+ var buffers = [
+ '__webglVertexBuffer',
+ '__webglNormalBuffer',
+ '__webglTangentBuffer',
+ '__webglColorBuffer',
+ '__webglUVBuffer',
+ '__webglUV2Buffer',
+
+ '__webglSkinIndicesBuffer',
+ '__webglSkinWeightsBuffer',
+
+ '__webglFaceBuffer',
+ '__webglLineBuffer',
+
+ '__webglLineDistanceBuffer'
+ ];
+
+ for ( var i = 0, l = buffers.length; i < l; i ++ ) {
+
+ var name = buffers[ i ];
+
+ if ( geometry[ name ] !== undefined ) {
- if ( geometry.__webglVertexBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglVertexBuffer );
- if ( geometry.__webglNormalBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglNormalBuffer );
- if ( geometry.__webglTangentBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglTangentBuffer );
- if ( geometry.__webglColorBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglColorBuffer );
- if ( geometry.__webglUVBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglUVBuffer );
- if ( geometry.__webglUV2Buffer !== undefined ) _gl.deleteBuffer( geometry.__webglUV2Buffer );
+ _gl.deleteBuffer( geometry[ name ] );
- if ( geometry.__webglSkinIndicesBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglSkinIndicesBuffer );
- if ( geometry.__webglSkinWeightsBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglSkinWeightsBuffer );
+ delete geometry[ name ];
- if ( geometry.__webglFaceBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglFaceBuffer );
- if ( geometry.__webglLineBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglLineBuffer );
+ }
+
+ }
- if ( geometry.__webglLineDistanceBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglLineDistanceBuffer );
// custom attributes
if ( geometry.__webglCustomAttributesList !== undefined ) {
- for ( var id in geometry.__webglCustomAttributesList ) {
+ for ( var name in geometry.__webglCustomAttributesList ) {
- _gl.deleteBuffer( geometry.__webglCustomAttributesList[ id ].buffer );
+ _gl.deleteBuffer( geometry.__webglCustomAttributesList[ name ].buffer );
}
+ delete geometry.__webglCustomAttributesList;
+
}
_this.info.memory.geometries --;
@@ -19341,17 +18410,19 @@ THREE.WebGLRenderer = function ( parameters ) {
var deallocateGeometry = function ( geometry ) {
- geometry.__webglInit = undefined;
+ delete geometry.__webglInit;
if ( geometry instanceof THREE.BufferGeometry ) {
- var attributes = geometry.attributes;
+ for ( var name in geometry.attributes ) {
+
+ var attribute = geometry.attributes[ name ];
- for ( var key in attributes ) {
+ if ( attribute.buffer !== undefined ) {
- if ( attributes[ key ].buffer !== undefined ) {
+ _gl.deleteBuffer( attribute.buffer );
- _gl.deleteBuffer( attributes[ key ].buffer );
+ delete attribute.buffer;
}
@@ -19361,11 +18432,13 @@ THREE.WebGLRenderer = function ( parameters ) {
} else {
- if ( geometry.geometryGroups !== undefined ) {
+ var geometryGroupsList = geometryGroups[ geometry.id ];
- for ( var i = 0,l = geometry.geometryGroupsList.length; i 1 ) {
- geometryGroup.__normalArray = new Float32Array( nvertices * 3 );
+ geometryGroup.__uv2Array = new Float32Array( nvertices * 2 );
}
@@ -19619,28 +18709,6 @@ THREE.WebGLRenderer = function ( parameters ) {
}
- if ( vertexColorType ) {
-
- geometryGroup.__colorArray = new Float32Array( nvertices * 3 );
-
- }
-
- if ( uvType ) {
-
- if ( geometry.faceVertexUvs.length > 0 ) {
-
- geometryGroup.__uvArray = new Float32Array( nvertices * 2 );
-
- }
-
- if ( geometry.faceVertexUvs.length > 1 ) {
-
- geometryGroup.__uv2Array = new Float32Array( nvertices * 2 );
-
- }
-
- }
-
if ( object.geometry.skinWeights.length && object.geometry.skinIndices.length ) {
geometryGroup.__skinIndexArray = new Float32Array( nvertices * 4 );
@@ -19648,7 +18716,7 @@ THREE.WebGLRenderer = function ( parameters ) {
}
- var UintArray = _glExtensionElementIndexUint !== null && ntris > 21845 ? Uint32Array : Uint16Array; // 65535 / 3
+ var UintArray = extensions.get( 'OES_element_index_uint' ) !== null && ntris > 21845 ? Uint32Array : Uint16Array; // 65535 / 3
geometryGroup.__typeArray = UintArray;
geometryGroup.__faceArray = new UintArray( ntris * 3 );
@@ -19694,12 +18762,12 @@ THREE.WebGLRenderer = function ( parameters ) {
}
- for ( var a in material.attributes ) {
+ for ( var name in material.attributes ) {
// Do a shallow copy of the attribute object so different geometryGroup chunks use different
// attribute buffers which are correctly indexed in the setMeshBuffers function
- var originalAttribute = material.attributes[ a ];
+ var originalAttribute = material.attributes[ name ];
var attribute = {};
@@ -19725,7 +18793,7 @@ THREE.WebGLRenderer = function ( parameters ) {
attribute.array = new Float32Array( nvertices * size );
attribute.buffer = _gl.createBuffer();
- attribute.buffer.belongsToAttribute = a;
+ attribute.buffer.belongsToAttribute = name;
originalAttribute.needsUpdate = true;
attribute.__original = originalAttribute;
@@ -19756,78 +18824,6 @@ THREE.WebGLRenderer = function ( parameters ) {
};
- function bufferGuessNormalType ( material ) {
-
- // only MeshBasicMaterial and MeshDepthMaterial don't need normals
-
- if ( ( material instanceof THREE.MeshBasicMaterial && ! material.envMap ) || material instanceof THREE.MeshDepthMaterial ) {
-
- return false;
-
- }
-
- if ( materialNeedsSmoothNormals( material ) ) {
-
- return THREE.SmoothShading;
-
- } else {
-
- return THREE.FlatShading;
-
- }
-
- };
-
- function bufferGuessVertexColorType( material ) {
-
- if ( material.vertexColors ) {
-
- return material.vertexColors;
-
- }
-
- return false;
-
- };
-
- function bufferGuessUVType( material ) {
-
- // material must use some texture to require uvs
-
- if ( material.map ||
- material.lightMap ||
- material.bumpMap ||
- material.normalMap ||
- material.specularMap ||
- material.alphaMap ||
- material instanceof THREE.ShaderMaterial ) {
-
- return true;
-
- }
-
- return false;
-
- };
-
- //
-
- function initDirectBuffers( geometry ) {
-
- for ( var name in geometry.attributes ) {
-
- var bufferType = ( name === 'index' ) ? _gl.ELEMENT_ARRAY_BUFFER : _gl.ARRAY_BUFFER;
-
- var attribute = geometry.attributes[ name ];
- attribute.buffer = _gl.createBuffer();
-
- _gl.bindBuffer( bufferType, attribute.buffer );
- _gl.bufferData( bufferType, attribute.array, _gl.STATIC_DRAW );
-
- }
-
- }
-
// Buffer setting
function setParticleBuffers ( geometry, hint, object ) {
@@ -20331,11 +19327,7 @@ THREE.WebGLRenderer = function ( parameters ) {
}
- var normalType = bufferGuessNormalType( material ),
- vertexColorType = bufferGuessVertexColorType( material ),
- uvType = bufferGuessUVType( material ),
-
- needsSmoothNormals = ( normalType === THREE.SmoothShading );
+ var needsSmoothNormals = materialNeedsSmoothNormals( material );
var f, fl, fi, face,
vertexNormals, faceNormal, normal,
@@ -20596,7 +19588,7 @@ THREE.WebGLRenderer = function ( parameters ) {
}
- if ( dirtyColors && vertexColorType ) {
+ if ( dirtyColors ) {
for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
@@ -20605,7 +19597,7 @@ THREE.WebGLRenderer = function ( parameters ) {
vertexColors = face.vertexColors;
faceColor = face.color;
- if ( vertexColors.length === 3 && vertexColorType === THREE.VertexColors ) {
+ if ( vertexColors.length === 3 && material.vertexColors === THREE.VertexColors ) {
c1 = vertexColors[ 0 ];
c2 = vertexColors[ 1 ];
@@ -20680,7 +19672,7 @@ THREE.WebGLRenderer = function ( parameters ) {
}
- if ( dirtyNormals && normalType ) {
+ if ( dirtyNormals ) {
for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
@@ -20724,7 +19716,7 @@ THREE.WebGLRenderer = function ( parameters ) {
}
- if ( dirtyUvs && obj_uvs && uvType ) {
+ if ( dirtyUvs && obj_uvs ) {
for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
@@ -20756,7 +19748,7 @@ THREE.WebGLRenderer = function ( parameters ) {
}
- if ( dirtyUvs && obj_uvs2 && uvType ) {
+ if ( dirtyUvs && obj_uvs2 ) {
for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) {
@@ -21126,31 +20118,31 @@ THREE.WebGLRenderer = function ( parameters ) {
};
- function setDirectBuffers( geometry, hint ) {
+ function setDirectBuffers( geometry ) {
var attributes = geometry.attributes;
+ var attributesKeys = geometry.attributesKeys;
- var attributeName, attributeItem;
+ for ( var i = 0, l = attributesKeys.length; i < l; i ++ ) {
- for ( attributeName in attributes ) {
+ var key = attributesKeys[ i ];
+ var attribute = attributes[ key ];
- attributeItem = attributes[ attributeName ];
+ if ( attribute.buffer === undefined ) {
- if ( attributeItem.needsUpdate ) {
+ attribute.buffer = _gl.createBuffer();
+ attribute.needsUpdate = true;
- if ( attributeName === 'index' ) {
-
- _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, attributeItem.buffer );
- _gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, attributeItem.array, hint );
+ }
- } else {
+ if ( attribute.needsUpdate === true ) {
- _gl.bindBuffer( _gl.ARRAY_BUFFER, attributeItem.buffer );
- _gl.bufferData( _gl.ARRAY_BUFFER, attributeItem.array, hint );
+ var bufferType = ( key === 'index' ) ? _gl.ELEMENT_ARRAY_BUFFER : _gl.ARRAY_BUFFER;
- }
+ _gl.bindBuffer( bufferType, attribute.buffer );
+ _gl.bufferData( bufferType, attribute.array, _gl.STATIC_DRAW );
- attributeItem.needsUpdate = false;
+ attribute.needsUpdate = false;
}
@@ -21257,32 +20249,41 @@ THREE.WebGLRenderer = function ( parameters ) {
};
- function setupVertexAttributes( material, programAttributes, geometryAttributes, startIndex ) {
+ function setupVertexAttributes( material, program, geometry, startIndex ) {
- for ( var attributeName in programAttributes ) {
+ var geometryAttributes = geometry.attributes;
+
+ var programAttributes = program.attributes;
+ var programAttributesKeys = program.attributesKeys;
+
+ for ( var i = 0, l = programAttributesKeys.length; i < l; i ++ ) {
- var attributePointer = programAttributes[ attributeName ];
- var attributeItem = geometryAttributes[ attributeName ];
+ var key = programAttributesKeys[ i ];
+ var programAttribute = programAttributes[ key ];
- if ( attributePointer >= 0 ) {
+ if ( programAttribute >= 0 ) {
- if ( attributeItem ) {
+ var geometryAttribute = geometryAttributes[ key ];
- var attributeSize = attributeItem.itemSize;
+ if ( geometryAttribute !== undefined ) {
- _gl.bindBuffer( _gl.ARRAY_BUFFER, attributeItem.buffer );
- enableAttribute( attributePointer );
- _gl.vertexAttribPointer( attributePointer, attributeSize, _gl.FLOAT, false, 0, startIndex * attributeSize * 4 ); // 4 bytes per Float32
+ var size = geometryAttribute.itemSize;
- } else if ( material.defaultAttributeValues ) {
+ _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryAttribute.buffer );
- if ( material.defaultAttributeValues[ attributeName ].length === 2 ) {
+ enableAttribute( programAttribute );
- _gl.vertexAttrib2fv( attributePointer, material.defaultAttributeValues[ attributeName ] );
+ _gl.vertexAttribPointer( programAttribute, size, _gl.FLOAT, false, 0, startIndex * size * 4 ); // 4 bytes per Float32
- } else if ( material.defaultAttributeValues[ attributeName ].length === 3 ) {
+ } else if ( material.defaultAttributeValues !== undefined ) {
- _gl.vertexAttrib3fv( attributePointer, material.defaultAttributeValues[ attributeName ] );
+ if ( material.defaultAttributeValues[ key ].length === 2 ) {
+
+ _gl.vertexAttrib2fv( programAttribute, material.defaultAttributeValues[ key ] );
+
+ } else if ( material.defaultAttributeValues[ key ].length === 3 ) {
+
+ _gl.vertexAttrib3fv( programAttribute, material.defaultAttributeValues[ key ] );
}
@@ -21300,14 +20301,8 @@ THREE.WebGLRenderer = function ( parameters ) {
if ( material.visible === false ) return;
- var linewidth, a, attribute;
- var attributeItem, attributeName, attributePointer, attributeSize;
-
var program = setProgram( camera, lights, fog, material, object );
- var programAttributes = program.attributes;
- var geometryAttributes = geometry.attributes;
-
var updateBuffers = false,
wireframeBit = material.wireframe ? 1 : 0,
geometryHash = ( geometry.id * 0xffffff ) + ( program.id * 2 ) + wireframeBit;
@@ -21329,7 +20324,9 @@ THREE.WebGLRenderer = function ( parameters ) {
if ( object instanceof THREE.Mesh ) {
- var index = geometryAttributes[ 'index' ];
+ var mode = material.wireframe === true ? _gl.LINES : _gl.TRIANGLES;
+
+ var index = geometry.attributes.index;
if ( index ) {
@@ -21337,7 +20334,7 @@ THREE.WebGLRenderer = function ( parameters ) {
var type, size;
- if ( index.array instanceof Uint32Array ) {
+ if ( index.array instanceof Uint32Array && extensions.get( 'OES_element_index_uint' ) ) {
type = _gl.UNSIGNED_INT;
size = 4;
@@ -21355,12 +20352,12 @@ THREE.WebGLRenderer = function ( parameters ) {
if ( updateBuffers ) {
- setupVertexAttributes( material, programAttributes, geometryAttributes, 0 );
+ setupVertexAttributes( material, program, geometry, 0 );
_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer );
}
- _gl.drawElements( _gl.TRIANGLES, index.array.length, type, 0 );
+ _gl.drawElements( mode, index.array.length, type, 0 );
_this.info.render.calls ++;
_this.info.render.vertices += index.array.length; // not really true, here vertices can be shared
@@ -21380,14 +20377,14 @@ THREE.WebGLRenderer = function ( parameters ) {
if ( updateBuffers ) {
- setupVertexAttributes( material, programAttributes, geometryAttributes, startIndex );
+ setupVertexAttributes( material, program, geometry, startIndex );
_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer );
}
// render indexed triangles
- _gl.drawElements( _gl.TRIANGLES, offsets[ i ].count, type, offsets[ i ].start * size );
+ _gl.drawElements( mode, offsets[ i ].count, type, offsets[ i ].start * size );
_this.info.render.calls ++;
_this.info.render.vertices += offsets[ i ].count; // not really true, here vertices can be shared
@@ -21403,7 +20400,7 @@ THREE.WebGLRenderer = function ( parameters ) {
if ( updateBuffers ) {
- setupVertexAttributes( material, programAttributes, geometryAttributes, 0 );
+ setupVertexAttributes( material, program, geometry, 0 );
}
@@ -21411,7 +20408,7 @@ THREE.WebGLRenderer = function ( parameters ) {
// render non-indexed triangles
- _gl.drawArrays( _gl.TRIANGLES, 0, position.array.length / 3 );
+ _gl.drawArrays( mode, 0, position.array.length / 3 );
_this.info.render.calls ++;
_this.info.render.vertices += position.array.length / 3;
@@ -21425,11 +20422,11 @@ THREE.WebGLRenderer = function ( parameters ) {
if ( updateBuffers ) {
- setupVertexAttributes( material, programAttributes, geometryAttributes, 0 );
+ setupVertexAttributes( material, program, geometry, 0 );
}
- var position = geometryAttributes[ 'position' ];
+ var position = geometry.attributes.position;
// render particles
@@ -21440,11 +20437,11 @@ THREE.WebGLRenderer = function ( parameters ) {
} else if ( object instanceof THREE.Line ) {
- var mode = ( object.type === THREE.LineStrip ) ? _gl.LINE_STRIP : _gl.LINES;
+ var mode = ( object.mode === THREE.LineStrip ) ? _gl.LINE_STRIP : _gl.LINES;
setLineWidth( material.linewidth );
- var index = geometryAttributes[ 'index' ];
+ var index = geometry.attributes.index;
if ( index ) {
@@ -21470,7 +20467,7 @@ THREE.WebGLRenderer = function ( parameters ) {
if ( updateBuffers ) {
- setupVertexAttributes( material, programAttributes, geometryAttributes, 0 );
+ setupVertexAttributes( material, program, geometry, 0 );
_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer );
}
@@ -21494,7 +20491,7 @@ THREE.WebGLRenderer = function ( parameters ) {
if ( updateBuffers ) {
- setupVertexAttributes( material, programAttributes, geometryAttributes, startIndex );
+ setupVertexAttributes( material, program, geometry, startIndex );
_gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer );
}
@@ -21516,11 +20513,11 @@ THREE.WebGLRenderer = function ( parameters ) {
if ( updateBuffers ) {
- setupVertexAttributes( material, programAttributes, geometryAttributes, 0 );
+ setupVertexAttributes( material, program, geometry, 0 );
}
- var position = geometryAttributes[ 'position' ];
+ var position = geometry.attributes.position;
_gl.drawArrays( mode, 0, position.array.length / 3 );
@@ -21537,8 +20534,6 @@ THREE.WebGLRenderer = function ( parameters ) {
if ( material.visible === false ) return;
- var linewidth, a, attribute, i, il;
-
var program = setProgram( camera, lights, fog, material, object );
var attributes = program.attributes;
@@ -21591,9 +20586,9 @@ THREE.WebGLRenderer = function ( parameters ) {
if ( geometryGroup.__webglCustomAttributesList ) {
- for ( i = 0, il = geometryGroup.__webglCustomAttributesList.length; i < il; i ++ ) {
+ for ( var i = 0, il = geometryGroup.__webglCustomAttributesList.length; i < il; i ++ ) {
- attribute = geometryGroup.__webglCustomAttributesList[ i ];
+ var attribute = geometryGroup.__webglCustomAttributesList[ i ];
if ( attributes[ attribute.buffer.belongsToAttribute ] >= 0 ) {
@@ -21618,7 +20613,7 @@ THREE.WebGLRenderer = function ( parameters ) {
enableAttribute( attributes.color );
_gl.vertexAttribPointer( attributes.color, 3, _gl.FLOAT, false, 0, 0 );
- } else if ( material.defaultAttributeValues ) {
+ } else if ( material.defaultAttributeValues !== undefined ) {
_gl.vertexAttrib3fv( attributes.color, material.defaultAttributeValues.color );
@@ -21657,7 +20652,7 @@ THREE.WebGLRenderer = function ( parameters ) {
enableAttribute( attributes.uv );
_gl.vertexAttribPointer( attributes.uv, 2, _gl.FLOAT, false, 0, 0 );
- } else if ( material.defaultAttributeValues ) {
+ } else if ( material.defaultAttributeValues !== undefined ) {
_gl.vertexAttrib2fv( attributes.uv, material.defaultAttributeValues.uv );
@@ -21674,7 +20669,7 @@ THREE.WebGLRenderer = function ( parameters ) {
enableAttribute( attributes.uv2 );
_gl.vertexAttribPointer( attributes.uv2, 2, _gl.FLOAT, false, 0, 0 );
- } else if ( material.defaultAttributeValues ) {
+ } else if ( material.defaultAttributeValues !== undefined ) {
_gl.vertexAttrib2fv( attributes.uv2, material.defaultAttributeValues.uv2 );
@@ -21741,7 +20736,7 @@ THREE.WebGLRenderer = function ( parameters ) {
} else if ( object instanceof THREE.Line ) {
- var mode = ( object.type === THREE.LineStrip ) ? _gl.LINE_STRIP : _gl.LINES;
+ var mode = ( object.mode === THREE.LineStrip ) ? _gl.LINE_STRIP : _gl.LINES;
setLineWidth( material.linewidth );
@@ -21943,13 +20938,17 @@ THREE.WebGLRenderer = function ( parameters ) {
}
- };
+ }
// Sorting
function painterSortStable ( a, b ) {
- if ( a.z !== b.z ) {
+ if ( a.material.id !== b.material.id ) {
+
+ return b.material.id - a.material.id;
+
+ } else if ( a.z !== b.z ) {
return b.z - a.z;
@@ -21959,7 +20958,7 @@ THREE.WebGLRenderer = function ( parameters ) {
}
- };
+ }
function reversePainterSortStable ( a, b ) {
@@ -21973,14 +20972,13 @@ THREE.WebGLRenderer = function ( parameters ) {
}
- };
+ }
function numericalSort ( a, b ) {
return b[ 0 ] - a[ 0 ];
- };
-
+ }
// Rendering
@@ -21993,16 +20991,11 @@ THREE.WebGLRenderer = function ( parameters ) {
}
- var i, il,
-
- webglObject, object,
- renderList,
-
- lights = scene.__lights,
- fog = scene.fog;
+ var fog = scene.fog;
// reset caching for this frame
+ _currentGeometryGroupHash = - 1;
_currentMaterialId = - 1;
_currentCamera = null;
_lightsNeedUpdate = true;
@@ -22016,7 +21009,8 @@ THREE.WebGLRenderer = function ( parameters ) {
if ( camera.parent === undefined ) camera.updateMatrixWorld();
// update Skeleton objects
- function updateSkeletons( object ) {
+
+ scene.traverse( function ( object ) {
if ( object instanceof THREE.SkinnedMesh ) {
@@ -22024,27 +21018,21 @@ THREE.WebGLRenderer = function ( parameters ) {
}
- for ( var i = 0, l = object.children.length; i < l; i ++ ) {
-
- updateSkeletons( object.children[ i ] );
-
- }
-
- }
-
- updateSkeletons( scene );
+ } );
camera.matrixWorldInverse.getInverse( camera.matrixWorld );
_projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse );
_frustum.setFromMatrix( _projScreenMatrix );
- initObjects( scene );
-
+ lights.length = 0;
opaqueObjects.length = 0;
transparentObjects.length = 0;
-
- projectObject( scene, scene, camera );
+
+ sprites.length = 0;
+ lensFlares.length = 0;
+
+ projectObject( scene, scene );
if ( _this.sortObjects === true ) {
@@ -22054,8 +21042,8 @@ THREE.WebGLRenderer = function ( parameters ) {
}
// custom render plugins (pre pass)
-
- renderPlugins( this.renderPluginsPre, scene, camera );
+
+ shadowMapPlugin.render( scene, camera );
//
@@ -22072,19 +21060,12 @@ THREE.WebGLRenderer = function ( parameters ) {
}
- // set matrices for regular objects (frustum culled)
-
-
-
-
// set matrices for immediate objects
- renderList = scene.__webglObjectsImmediate;
-
- for ( i = 0, il = renderList.length; i < il; i ++ ) {
+ for ( var i = 0, il = _webglObjectsImmediate.length; i < il; i ++ ) {
- webglObject = renderList[ i ];
- object = webglObject.object;
+ var webglObject = _webglObjectsImmediate[ i ];
+ var object = webglObject.object;
if ( object.visible ) {
@@ -22107,7 +21088,7 @@ THREE.WebGLRenderer = function ( parameters ) {
renderObjects( opaqueObjects, camera, lights, fog, true, material );
renderObjects( transparentObjects, camera, lights, fog, true, material );
- renderObjectsImmediate( scene.__webglObjectsImmediate, '', camera, lights, fog, false, material );
+ renderObjectsImmediate( _webglObjectsImmediate, '', camera, lights, fog, false, material );
} else {
@@ -22118,19 +21099,19 @@ THREE.WebGLRenderer = function ( parameters ) {
this.setBlending( THREE.NoBlending );
renderObjects( opaqueObjects, camera, lights, fog, false, material );
- renderObjectsImmediate( scene.__webglObjectsImmediate, 'opaque', camera, lights, fog, false, material );
+ renderObjectsImmediate( _webglObjectsImmediate, 'opaque', camera, lights, fog, false, material );
// transparent pass (back-to-front order)
renderObjects( transparentObjects, camera, lights, fog, true, material );
- renderObjectsImmediate( scene.__webglObjectsImmediate, 'transparent', camera, lights, fog, true, material );
+ renderObjectsImmediate( _webglObjectsImmediate, 'transparent', camera, lights, fog, true, material );
}
// custom render plugins (post pass)
- renderPlugins( this.renderPluginsPost, scene, camera );
-
+ spritePlugin.render( scene, camera );
+ lensFlarePlugin.render( scene, camera, _currentWidth, _currentHeight );
// Generate mipmap if we're using any kind of mipmap filtering
@@ -22148,107 +21129,91 @@ THREE.WebGLRenderer = function ( parameters ) {
// _gl.finish();
};
-
- function projectObject(scene, object,camera){
-
+
+ function projectObject( scene, object ) {
+
if ( object.visible === false ) return;
-
- var webglObjects = scene.__webglObjects[ object.id ];
-
- if ( webglObjects && ( object.frustumCulled === false || _frustum.intersectsObject( object ) === true ) ) {
-
- updateObject( scene, object );
-
- for ( var i = 0, l = webglObjects.length; i < l; i ++ ) {
-
- var webglObject = webglObjects[i];
-
- unrollBufferMaterial( webglObject );
- webglObject.render = true;
+ if ( object instanceof THREE.Scene || object instanceof THREE.Group ) {
- if ( _this.sortObjects === true ) {
+ // skip
- if ( object.renderDepth !== null ) {
+ } else {
- webglObject.z = object.renderDepth;
+ initObject( object, scene );
- } else {
+ if ( object instanceof THREE.Light ) {
- _vector3.setFromMatrixPosition( object.matrixWorld );
- _vector3.applyProjection( _projScreenMatrix );
+ lights.push( object );
- webglObject.z = _vector3.z;
+ } else if ( object instanceof THREE.Sprite ) {
- }
+ sprites.push( object );
- }
+ } else if ( object instanceof THREE.LensFlare ) {
- }
+ lensFlares.push( object );
- }
-
- for ( var i = 0, l = object.children.length; i < l; i ++ ) {
+ } else {
- projectObject( scene, object.children[ i ], camera );
+ var webglObjects = _webglObjects[ object.id ];
- }
-
- }
+ if ( webglObjects && ( object.frustumCulled === false || _frustum.intersectsObject( object ) === true ) ) {
+
+ updateObject( object, scene );
+
+ for ( var i = 0, l = webglObjects.length; i < l; i ++ ) {
+
+ var webglObject = webglObjects[i];
- function renderPlugins( plugins, scene, camera ) {
+ unrollBufferMaterial( webglObject );
- if ( plugins.length === 0 ) return;
+ webglObject.render = true;
- for ( var i = 0, il = plugins.length; i < il; i ++ ) {
+ if ( _this.sortObjects === true ) {
- // reset state for plugin (to start from clean slate)
+ if ( object.renderDepth !== null ) {
- _currentProgram = null;
- _currentCamera = null;
+ webglObject.z = object.renderDepth;
- _oldBlending = - 1;
- _oldDepthTest = - 1;
- _oldDepthWrite = - 1;
- _oldDoubleSided = - 1;
- _oldFlipSided = - 1;
- _currentGeometryGroupHash = - 1;
- _currentMaterialId = - 1;
+ } else {
+
+ _vector3.setFromMatrixPosition( object.matrixWorld );
+ _vector3.applyProjection( _projScreenMatrix );
- _lightsNeedUpdate = true;
+ webglObject.z = _vector3.z;
- plugins[ i ].render( scene, camera, _currentWidth, _currentHeight );
+ }
- // reset state after plugin (anything could have changed)
+ }
- _currentProgram = null;
- _currentCamera = null;
+ }
- _oldBlending = - 1;
- _oldDepthTest = - 1;
- _oldDepthWrite = - 1;
- _oldDoubleSided = - 1;
- _oldFlipSided = - 1;
- _currentGeometryGroupHash = - 1;
- _currentMaterialId = - 1;
+ }
- _lightsNeedUpdate = true;
+ }
}
- };
+ for ( var i = 0, l = object.children.length; i < l; i ++ ) {
+
+ projectObject( scene, object.children[ i ] );
+
+ }
+
+ }
function renderObjects( renderList, camera, lights, fog, useBlending, overrideMaterial ) {
- var webglObject, object, buffer, material;
+ var material;
for ( var i = renderList.length - 1; i !== - 1; i -- ) {
- webglObject = renderList[ i ];
+ var webglObject = renderList[ i ];
+
+ var object = webglObject.object;
+ var buffer = webglObject.buffer;
- object = webglObject.object;
- buffer = webglObject.buffer;
-
setupMatrices( object, camera );
if ( overrideMaterial ) {
@@ -22283,16 +21248,16 @@ THREE.WebGLRenderer = function ( parameters ) {
}
- };
+ }
function renderObjectsImmediate ( renderList, materialType, camera, lights, fog, useBlending, overrideMaterial ) {
- var webglObject, object, material, program;
+ var material;
for ( var i = 0, il = renderList.length; i < il; i ++ ) {
- webglObject = renderList[ i ];
- object = webglObject.object;
+ var webglObject = renderList[ i ];
+ var object = webglObject.object;
if ( object.visible ) {
@@ -22320,7 +21285,7 @@ THREE.WebGLRenderer = function ( parameters ) {
}
- };
+ }
this.renderImmediateObject = function ( camera, lights, fog, material, object ) {
@@ -22359,7 +21324,7 @@ THREE.WebGLRenderer = function ( parameters ) {
}
- };
+ }
function unrollBufferMaterial ( globject ) {
@@ -22375,84 +21340,50 @@ THREE.WebGLRenderer = function ( parameters ) {
material = material.materials[ materialIndex ];
+ globject.material = material;
+
if ( material.transparent ) {
- globject.material = material;
transparentObjects.push( globject );
} else {
- globject.material = material;
opaqueObjects.push( globject );
}
- } else {
-
- if ( material ) {
+ } else if ( material ) {
- if ( material.transparent ) {
+ globject.material = material;
- globject.material = material;
- transparentObjects.push( globject );
+ if ( material.transparent ) {
- } else {
+ transparentObjects.push( globject );
- globject.material = material;
- opaqueObjects.push( globject );
+ } else {
- }
+ opaqueObjects.push( globject );
}
}
- };
-
- // Objects refresh
-
- var initObjects = function ( scene ) {
-
- if ( ! scene.__webglObjects ) {
-
- scene.__webglObjects = {};
- scene.__webglObjectsImmediate = [];
-
- }
-
- while ( scene.__objectsAdded.length ) {
-
- addObject( scene.__objectsAdded[ 0 ], scene );
- scene.__objectsAdded.splice( 0, 1 );
-
- }
-
- while ( scene.__objectsRemoved.length ) {
-
- removeObject( scene.__objectsRemoved[ 0 ], scene );
- scene.__objectsRemoved.splice( 0, 1 );
-
- }
-
- };
-
- // Objects adding
-
- function addObject( object, scene ) {
+ }
- var g, geometry, geometryGroup;
+ function initObject( object, scene ) {
if ( object.__webglInit === undefined ) {
object.__webglInit = true;
-
object._modelViewMatrix = new THREE.Matrix4();
object._normalMatrix = new THREE.Matrix3();
+ object.addEventListener( 'removed', onObjectRemoved );
+
}
-
- geometry = object.geometry;
-
+
+ var geometry = object.geometry;
+
if ( geometry === undefined ) {
// ImmediateRenderObject
@@ -22464,21 +21395,15 @@ THREE.WebGLRenderer = function ( parameters ) {
if ( geometry instanceof THREE.BufferGeometry ) {
- initDirectBuffers( geometry );
+ //
} else if ( object instanceof THREE.Mesh ) {
-
- if ( object.__webglActive !== undefined ) {
-
- removeObject( object, scene );
- }
-
- initGeometryGroups(scene, object, geometry);
+ initGeometryGroups( scene, object, geometry );
} else if ( object instanceof THREE.Line ) {
- if ( ! geometry.__webglVertexBuffer ) {
+ if ( geometry.__webglVertexBuffer === undefined ) {
createLineBuffers( geometry );
initLineBuffers( geometry, object );
@@ -22491,7 +21416,7 @@ THREE.WebGLRenderer = function ( parameters ) {
} else if ( object instanceof THREE.PointCloud ) {
- if ( ! geometry.__webglVertexBuffer ) {
+ if ( geometry.__webglVertexBuffer === undefined ) {
createParticleBuffers( geometry );
initParticleBuffers( geometry, object );
@@ -22507,64 +21432,144 @@ THREE.WebGLRenderer = function ( parameters ) {
if ( object.__webglActive === undefined) {
- if ( object instanceof THREE.Mesh ) {
+ object.__webglActive = true;
- geometry = object.geometry;
+ if ( object instanceof THREE.Mesh ) {
if ( geometry instanceof THREE.BufferGeometry ) {
- addBuffer( scene.__webglObjects, geometry, object );
+ addBuffer( _webglObjects, geometry, object );
} else if ( geometry instanceof THREE.Geometry ) {
- for ( var i = 0,l = geometry.geometryGroupsList.length; i maxVerticesInGroup ) {
+
+ hash_map[ materialIndex ].counter += 1;
+ groupHash = hash_map[ materialIndex ].hash + '_' + hash_map[ materialIndex ].counter;
+
+ if ( ! ( groupHash in groups ) ) {
+
+ group = {
+ id: geometryGroupCounter ++,
+ faces3: [],
+ materialIndex: materialIndex,
+ vertices: 0,
+ numMorphTargets: numMorphTargets,
+ numMorphNormals: numMorphNormals
+ };
+
+ groups[ groupHash ] = group;
+ groupsList.push( group );
+
+ }
+
+ }
+
+ groups[ groupHash ].faces3.push( f );
+ groups[ groupHash ].vertices += 3;
}
- };
-
+ return groupsList;
+
+ }
+
function initGeometryGroups( scene, object, geometry ) {
-
- var g, geometryGroup, material,addBuffers = false;
- material = object.material;
- if ( geometry.geometryGroups === undefined || geometry.groupsNeedUpdate ) {
-
- delete scene.__webglObjects[object.id];
- geometry.makeGroups( material instanceof THREE.MeshFaceMaterial, _glExtensionElementIndexUint ? 4294967296 : 65535 );
+ var material = object.material, addBuffers = false;
+
+ if ( geometryGroups[ geometry.id ] === undefined || geometry.groupsNeedUpdate === true ) {
+
+ delete _webglObjects[ object.id ];
+
+ geometryGroups[ geometry.id ] = makeGroups( geometry, material instanceof THREE.MeshFaceMaterial );
+
geometry.groupsNeedUpdate = false;
}
+ var geometryGroupsList = geometryGroups[ geometry.id ];
+
// create separate VBOs per geometry chunk
- for ( var i = 0, il = geometry.geometryGroupsList.length; i < il; i ++ ) {
+ for ( var i = 0, il = geometryGroupsList.length; i < il; i ++ ) {
- geometryGroup = geometry.geometryGroupsList[ i ];
+ var geometryGroup = geometryGroupsList[ i ];
// initialise VBO on the first access
- if ( ! geometryGroup.__webglVertexBuffer ) {
+ if ( geometryGroup.__webglVertexBuffer === undefined ) {
createMeshBuffers( geometryGroup );
initMeshBuffers( geometryGroup, object );
@@ -22576,17 +21581,19 @@ THREE.WebGLRenderer = function ( parameters ) {
geometry.normalsNeedUpdate = true;
geometry.tangentsNeedUpdate = true;
geometry.colorsNeedUpdate = true;
-
+
addBuffers = true;
-
+
} else {
-
+
addBuffers = false;
-
+
}
-
+
if ( addBuffers || object.__webglActive === undefined ) {
- addBuffer( scene.__webglObjects, geometryGroup, object );
+
+ addBuffer( _webglObjects, geometryGroup, object );
+
}
}
@@ -22594,7 +21601,7 @@ THREE.WebGLRenderer = function ( parameters ) {
object.__webglActive = true;
}
-
+
function addBuffer( objlist, buffer, object ) {
var id = object.id;
@@ -22627,39 +21634,33 @@ THREE.WebGLRenderer = function ( parameters ) {
// Objects updates
- function updateObject(scene, object ) {
+ function updateObject( object, scene ) {
- var geometry = object.geometry,
- geometryGroup, customAttributesDirty, material;
+ var geometry = object.geometry, customAttributesDirty, material;
if ( geometry instanceof THREE.BufferGeometry ) {
- setDirectBuffers( geometry, _gl.DYNAMIC_DRAW );
+ setDirectBuffers( geometry );
} else if ( object instanceof THREE.Mesh ) {
// check all geometry groups
- if ( geometry.buffersNeedUpdate || geometry.groupsNeedUpdate ) {
-
- if ( geometry instanceof THREE.BufferGeometry ) {
- initDirectBuffers( geometry );
+ if ( geometry.groupsNeedUpdate === true ) {
+
+ initGeometryGroups( scene, object, geometry );
- } else if ( object instanceof THREE.Mesh ) {
-
- initGeometryGroups(scene, object,geometry);
-
- }
-
}
- for ( var i = 0, il = geometry.geometryGroupsList.length; i < il; i ++ ) {
+ var geometryGroupsList = geometryGroups[ geometry.id ];
- geometryGroup = geometry.geometryGroupsList[ i ];
+ for ( var i = 0, il = geometryGroupsList.length; i < il; i ++ ) {
+
+ var geometryGroup = geometryGroupsList[ i ];
material = getBufferMaterial( object, geometryGroup );
- if ( geometry.buffersNeedUpdate || geometry.groupsNeedUpdate) {
+ if ( geometry.groupsNeedUpdate === true ) {
initMeshBuffers( geometryGroup, object );
@@ -22685,8 +21686,6 @@ THREE.WebGLRenderer = function ( parameters ) {
geometry.colorsNeedUpdate = false;
geometry.tangentsNeedUpdate = false;
- geometry.buffersNeedUpdate = false;
-
material.attributes && clearCustomAttributes( material );
} else if ( object instanceof THREE.Line ) {
@@ -22727,59 +21726,55 @@ THREE.WebGLRenderer = function ( parameters ) {
}
- };
+ }
// Objects updates - custom attributes check
function areCustomAttributesDirty( material ) {
- for ( var a in material.attributes ) {
+ for ( var name in material.attributes ) {
- if ( material.attributes[ a ].needsUpdate ) return true;
+ if ( material.attributes[ name ].needsUpdate ) return true;
}
return false;
- };
+ }
function clearCustomAttributes( material ) {
- for ( var a in material.attributes ) {
+ for ( var name in material.attributes ) {
- material.attributes[ a ].needsUpdate = false;
+ material.attributes[ name ].needsUpdate = false;
}
- };
+ }
// Objects removal
- function removeObject( object, scene ) {
+ function removeObject( object ) {
if ( object instanceof THREE.Mesh ||
object instanceof THREE.PointCloud ||
object instanceof THREE.Line ) {
- removeInstancesWebglObjects( scene.__webglObjects, object );
+ delete _webglObjects[ object.id ];
} else if ( object instanceof THREE.ImmediateRenderObject || object.immediateRenderCallback ) {
- removeInstances( scene.__webglObjectsImmediate, object );
+ removeInstances( _webglObjectsImmediate, object );
}
- delete object.__webglActive;
-
- };
-
-
-
- function removeInstancesWebglObjects( objlist, object ) {
+ delete object.__webglInit;
+ delete object._modelViewMatrix;
+ delete object._normalMatrix;
- delete objlist[ object.id ];
+ delete object.__webglActive;
- };
+ }
function removeInstances( objlist, object ) {
@@ -22793,15 +21788,15 @@ THREE.WebGLRenderer = function ( parameters ) {
}
- };
+ }
// Materials
- this.initMaterial = function ( material, lights, fog, object ) {
+ function initMaterial( material, lights, fog, object ) {
material.addEventListener( 'dispose', onMaterialDispose );
- var u, a, identifiers, i, parameters, maxLightCount, maxBones, maxShadows, shaderID;
+ var shaderID;
if ( material instanceof THREE.MeshDepthMaterial ) {
@@ -22860,13 +21855,11 @@ THREE.WebGLRenderer = function ( parameters ) {
// heuristics to create shader parameters according to lights in the scene
// (not to blow over maxLights budget)
- maxLightCount = allocateLights( lights );
-
- maxShadows = allocateShadows( lights );
+ var maxLightCount = allocateLights( lights );
+ var maxShadows = allocateShadows( lights );
+ var maxBones = allocateBones( object );
- maxBones = allocateBones( object );
-
- parameters = {
+ var parameters = {
precision: _precision,
supportsVertexTextures: _supportsVertexTextures,
@@ -22894,8 +21887,8 @@ THREE.WebGLRenderer = function ( parameters ) {
morphTargets: material.morphTargets,
morphNormals: material.morphNormals,
- maxMorphTargets: this.maxMorphTargets,
- maxMorphNormals: this.maxMorphNormals,
+ maxMorphTargets: _this.maxMorphTargets,
+ maxMorphNormals: _this.maxMorphNormals,
maxDirLights: maxLightCount.directional,
maxPointLights: maxLightCount.point,
@@ -22903,10 +21896,10 @@ THREE.WebGLRenderer = function ( parameters ) {
maxHemiLights: maxLightCount.hemi,
maxShadows: maxShadows,
- shadowMapEnabled: this.shadowMapEnabled && object.receiveShadow && maxShadows > 0,
- shadowMapType: this.shadowMapType,
- shadowMapDebug: this.shadowMapDebug,
- shadowMapCascade: this.shadowMapCascade,
+ shadowMapEnabled: _this.shadowMapEnabled && object.receiveShadow && maxShadows > 0,
+ shadowMapType: _this.shadowMapType,
+ shadowMapDebug: _this.shadowMapDebug,
+ shadowMapCascade: _this.shadowMapCascade,
alphaTest: material.alphaTest,
metal: material.metal,
@@ -22931,17 +21924,21 @@ THREE.WebGLRenderer = function ( parameters ) {
}
- for ( var d in material.defines ) {
+ if ( material.defines !== undefined ) {
+
+ for ( var name in material.defines ) {
- chunks.push( d );
- chunks.push( material.defines[ d ] );
+ chunks.push( name );
+ chunks.push( material.defines[ name ] );
+
+ }
}
- for ( var p in parameters ) {
+ for ( var name in parameters ) {
- chunks.push( p );
- chunks.push( parameters[ p ] );
+ chunks.push( name );
+ chunks.push( parameters[ name ] );
}
@@ -22968,7 +21965,7 @@ THREE.WebGLRenderer = function ( parameters ) {
if ( program === undefined ) {
- program = new THREE.WebGLProgram( this, code, material, parameters );
+ program = new THREE.WebGLProgram( _this, code, material, parameters );
_programs.push( program );
_this.info.memory.programs = _programs.length;
@@ -22977,7 +21974,7 @@ THREE.WebGLRenderer = function ( parameters ) {
material.program = program;
- var attributes = material.program.attributes;
+ var attributes = program.attributes;
if ( material.morphTargets ) {
@@ -22985,7 +21982,7 @@ THREE.WebGLRenderer = function ( parameters ) {
var id, base = 'morphTarget';
- for ( i = 0; i < this.maxMorphTargets; i ++ ) {
+ for ( var i = 0; i < _this.maxMorphTargets; i ++ ) {
id = base + i;
@@ -23005,7 +22002,7 @@ THREE.WebGLRenderer = function ( parameters ) {
var id, base = 'morphNormal';
- for ( i = 0; i < this.maxMorphNormals; i ++ ) {
+ for ( i = 0; i < _this.maxMorphNormals; i ++ ) {
id = base + i;
@@ -23021,7 +22018,7 @@ THREE.WebGLRenderer = function ( parameters ) {
material.uniformsList = [];
- for ( u in material.__webglShader.uniforms ) {
+ for ( var u in material.__webglShader.uniforms ) {
var location = material.program.uniforms[ u ];
@@ -23031,7 +22028,7 @@ THREE.WebGLRenderer = function ( parameters ) {
}
- };
+ }
function setProgram( camera, lights, fog, material, object ) {
@@ -23041,7 +22038,7 @@ THREE.WebGLRenderer = function ( parameters ) {
if ( material.program ) deallocateMaterial( material );
- _this.initMaterial( material, lights, fog, object );
+ initMaterial( material, lights, fog, object );
material.needsUpdate = false;
}
@@ -23276,7 +22273,7 @@ THREE.WebGLRenderer = function ( parameters ) {
return program;
- };
+ }
// Uniforms (refresh uniforms objects)
@@ -23371,14 +22368,14 @@ THREE.WebGLRenderer = function ( parameters ) {
uniforms.combine.value = material.combine;
uniforms.useRefract.value = material.envMap && material.envMap.mapping instanceof THREE.CubeRefractionMapping;
- };
+ }
function refreshUniformsLine ( uniforms, material ) {
uniforms.diffuse.value = material.color;
uniforms.opacity.value = material.opacity;
- };
+ }
function refreshUniformsDash ( uniforms, material ) {
@@ -23386,7 +22383,7 @@ THREE.WebGLRenderer = function ( parameters ) {
uniforms.totalSize.value = material.dashSize + material.gapSize;
uniforms.scale.value = material.scale;
- };
+ }
function refreshUniformsParticle ( uniforms, material ) {
@@ -23397,7 +22394,7 @@ THREE.WebGLRenderer = function ( parameters ) {
uniforms.map.value = material.map;
- };
+ }
function refreshUniformsFog ( uniforms, fog ) {
@@ -23414,7 +22411,7 @@ THREE.WebGLRenderer = function ( parameters ) {
}
- };
+ }
function refreshUniformsPhong ( uniforms, material ) {
@@ -23440,7 +22437,7 @@ THREE.WebGLRenderer = function ( parameters ) {
}
- };
+ }
function refreshUniformsLambert ( uniforms, material ) {
@@ -23462,7 +22459,7 @@ THREE.WebGLRenderer = function ( parameters ) {
}
- };
+ }
function refreshUniformsLights ( uniforms, lights ) {
@@ -23486,7 +22483,7 @@ THREE.WebGLRenderer = function ( parameters ) {
uniforms.hemisphereLightGroundColor.value = lights.hemi.groundColors;
uniforms.hemisphereLightDirection.value = lights.hemi.positions;
- };
+ }
// If uniforms are marked as clean, they don't need to be loaded to the GPU.
@@ -23512,7 +22509,7 @@ THREE.WebGLRenderer = function ( parameters ) {
uniforms.hemisphereLightGroundColor.needsUpdate = boolean;
uniforms.hemisphereLightDirection.needsUpdate = boolean;
- };
+ }
function refreshUniformsShadow ( uniforms, lights ) {
@@ -23544,7 +22541,7 @@ THREE.WebGLRenderer = function ( parameters ) {
}
- };
+ }
// Uniforms (load to GPU)
@@ -23558,7 +22555,7 @@ THREE.WebGLRenderer = function ( parameters ) {
}
- };
+ }
function getTextureUnit() {
@@ -23574,7 +22571,7 @@ THREE.WebGLRenderer = function ( parameters ) {
return textureUnit;
- };
+ }
function loadUniformsGeneric ( uniforms ) {
@@ -23647,7 +22644,7 @@ THREE.WebGLRenderer = function ( parameters ) {
//
- case 'i':
+ case 'i':
// single integer
_gl.uniform1i( location, value );
@@ -23675,7 +22672,7 @@ THREE.WebGLRenderer = function ( parameters ) {
break;
- case 'v4':
+ case 'v4':
// single THREE.Vector4
_gl.uniform4f( location, value.x, value.y, value.z, value.w );
@@ -23910,14 +22907,14 @@ THREE.WebGLRenderer = function ( parameters ) {
}
- };
+ }
function setupMatrices ( object, camera ) {
object._modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld );
object._normalMatrix.getNormalMatrix( object._modelViewMatrix );
- };
+ }
//
@@ -23927,7 +22924,7 @@ THREE.WebGLRenderer = function ( parameters ) {
array[ offset + 1 ] = color.g * color.g * intensitySq;
array[ offset + 2 ] = color.b * color.b * intensitySq;
- };
+ }
function setColorLinear( array, offset, color, intensity ) {
@@ -23935,7 +22932,7 @@ THREE.WebGLRenderer = function ( parameters ) {
array[ offset + 1 ] = color.g * intensity;
array[ offset + 2 ] = color.b * intensity;
- };
+ }
function setupLights ( lights ) {
@@ -24084,15 +23081,14 @@ THREE.WebGLRenderer = function ( parameters ) {
}
- _vector3.setFromMatrixPosition( light.matrixWorld );
+ _direction.setFromMatrixPosition( light.matrixWorld );
- spotPositions[ spotOffset ] = _vector3.x;
- spotPositions[ spotOffset + 1 ] = _vector3.y;
- spotPositions[ spotOffset + 2 ] = _vector3.z;
+ spotPositions[ spotOffset ] = _direction.x;
+ spotPositions[ spotOffset + 1 ] = _direction.y;
+ spotPositions[ spotOffset + 2 ] = _direction.z;
spotDistances[ spotLength ] = distance;
- _direction.copy( _vector3 );
_vector3.setFromMatrixPosition( light.target.matrixWorld );
_direction.sub( _vector3 );
_direction.normalize();
@@ -24162,7 +23158,7 @@ THREE.WebGLRenderer = function ( parameters ) {
zlights.ambient[ 1 ] = g;
zlights.ambient[ 2 ] = b;
- };
+ }
// GL state setting
@@ -24284,7 +23280,7 @@ THREE.WebGLRenderer = function ( parameters ) {
}
- };
+ }
function setPolygonOffset ( polygonoffset, factor, units ) {
@@ -24313,7 +23309,7 @@ THREE.WebGLRenderer = function ( parameters ) {
}
- };
+ }
this.setBlending = function ( blending, blendEquation, blendSrc, blendDst ) {
@@ -24392,6 +23388,8 @@ THREE.WebGLRenderer = function ( parameters ) {
function setTextureParameters ( textureType, texture, isImagePowerOfTwo ) {
+ var extension;
+
if ( isImagePowerOfTwo ) {
_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, paramThreeToGL( texture.wrapS ) );
@@ -24410,121 +23408,144 @@ THREE.WebGLRenderer = function ( parameters ) {
}
- if ( _glExtensionTextureFilterAnisotropic && texture.type !== THREE.FloatType ) {
+ extension = extensions.get( 'EXT_texture_filter_anisotropic' );
+
+ if ( extension && texture.type !== THREE.FloatType ) {
if ( texture.anisotropy > 1 || texture.__oldAnisotropy ) {
- _gl.texParameterf( textureType, _glExtensionTextureFilterAnisotropic.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, _maxAnisotropy ) );
+ _gl.texParameterf( textureType, extension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, _this.getMaxAnisotropy() ) );
texture.__oldAnisotropy = texture.anisotropy;
}
}
- };
+ }
- this.setTexture = function ( texture, slot ) {
+ this.uploadTexture = function ( texture ) {
- if ( texture.needsUpdate ) {
+ if ( texture.__webglInit === undefined ) {
- if ( ! texture.__webglInit ) {
+ texture.__webglInit = true;
- texture.__webglInit = true;
+ texture.addEventListener( 'dispose', onTextureDispose );
- texture.addEventListener( 'dispose', onTextureDispose );
+ texture.__webglTexture = _gl.createTexture();
- texture.__webglTexture = _gl.createTexture();
+ _this.info.memory.textures ++;
- _this.info.memory.textures ++;
+ }
- }
+ _gl.bindTexture( _gl.TEXTURE_2D, texture.__webglTexture );
- _gl.activeTexture( _gl.TEXTURE0 + slot );
- _gl.bindTexture( _gl.TEXTURE_2D, texture.__webglTexture );
+ _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY );
+ _gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha );
+ _gl.pixelStorei( _gl.UNPACK_ALIGNMENT, texture.unpackAlignment );
- _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY );
- _gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha );
- _gl.pixelStorei( _gl.UNPACK_ALIGNMENT, texture.unpackAlignment );
+ texture.image = clampToMaxSize( texture.image, _maxTextureSize );
- var image = texture.image,
- isImagePowerOfTwo = THREE.Math.isPowerOfTwo( image.width ) && THREE.Math.isPowerOfTwo( image.height ),
- glFormat = paramThreeToGL( texture.format ),
- glType = paramThreeToGL( texture.type );
+ var image = texture.image,
+ isImagePowerOfTwo = THREE.Math.isPowerOfTwo( image.width ) && THREE.Math.isPowerOfTwo( image.height ),
+ glFormat = paramThreeToGL( texture.format ),
+ glType = paramThreeToGL( texture.type );
- setTextureParameters( _gl.TEXTURE_2D, texture, isImagePowerOfTwo );
+ setTextureParameters( _gl.TEXTURE_2D, texture, isImagePowerOfTwo );
- var mipmap, mipmaps = texture.mipmaps;
+ var mipmap, mipmaps = texture.mipmaps;
- if ( texture instanceof THREE.DataTexture ) {
+ if ( texture instanceof THREE.DataTexture ) {
- // use manually created mipmaps if available
- // if there are no manual mipmaps
- // set 0 level mipmap and then use GL to generate other mipmap levels
+ // use manually created mipmaps if available
+ // if there are no manual mipmaps
+ // set 0 level mipmap and then use GL to generate other mipmap levels
- if ( mipmaps.length > 0 && isImagePowerOfTwo ) {
+ if ( mipmaps.length > 0 && isImagePowerOfTwo ) {
- for ( var i = 0, il = mipmaps.length; i < il; i ++ ) {
+ for ( var i = 0, il = mipmaps.length; i < il; i ++ ) {
- mipmap = mipmaps[ i ];
- _gl.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
+ mipmap = mipmaps[ i ];
+ _gl.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
- }
+ }
- texture.generateMipmaps = false;
+ texture.generateMipmaps = false;
- } else {
+ } else {
- _gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, image.width, image.height, 0, glFormat, glType, image.data );
+ _gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, image.width, image.height, 0, glFormat, glType, image.data );
- }
+ }
- } else if ( texture instanceof THREE.CompressedTexture ) {
+ } else if ( texture instanceof THREE.CompressedTexture ) {
- for ( var i = 0, il = mipmaps.length; i < il; i ++ ) {
+ for ( var i = 0, il = mipmaps.length; i < il; i ++ ) {
+
+ mipmap = mipmaps[ i ];
+
+ if ( texture.format !== THREE.RGBAFormat && texture.format !== THREE.RGBFormat ) {
+
+ if ( getCompressedTextureFormats().indexOf( glFormat ) > -1 ) {
- mipmap = mipmaps[ i ];
- if ( texture.format !== THREE.RGBAFormat ) {
_gl.compressedTexImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, mipmap.data );
+
} else {
- _gl.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
+
+ console.warn( "Attempt to load unsupported compressed texture format" );
+
}
+ } else {
+
+ _gl.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
+
}
- } else { // regular Texture (image, video, canvas)
+ }
- // use manually created mipmaps if available
- // if there are no manual mipmaps
- // set 0 level mipmap and then use GL to generate other mipmap levels
+ } else { // regular Texture (image, video, canvas)
- if ( mipmaps.length > 0 && isImagePowerOfTwo ) {
+ // use manually created mipmaps if available
+ // if there are no manual mipmaps
+ // set 0 level mipmap and then use GL to generate other mipmap levels
- for ( var i = 0, il = mipmaps.length; i < il; i ++ ) {
+ if ( mipmaps.length > 0 && isImagePowerOfTwo ) {
- mipmap = mipmaps[ i ];
- _gl.texImage2D( _gl.TEXTURE_2D, i, glFormat, glFormat, glType, mipmap );
+ for ( var i = 0, il = mipmaps.length; i < il; i ++ ) {
- }
+ mipmap = mipmaps[ i ];
+ _gl.texImage2D( _gl.TEXTURE_2D, i, glFormat, glFormat, glType, mipmap );
- texture.generateMipmaps = false;
+ }
- } else {
+ texture.generateMipmaps = false;
- _gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, glFormat, glType, texture.image );
+ } else {
- }
+ _gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, glFormat, glType, texture.image );
}
- if ( texture.generateMipmaps && isImagePowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_2D );
+ }
+
+ if ( texture.generateMipmaps && isImagePowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_2D );
+
+ texture.needsUpdate = false;
+
+ if ( texture.onUpdate ) texture.onUpdate();
+
+ };
+
+ this.setTexture = function ( texture, slot ) {
+
+ _gl.activeTexture( _gl.TEXTURE0 + slot );
- texture.needsUpdate = false;
+ if ( texture.needsUpdate ) {
- if ( texture.onUpdate ) texture.onUpdate();
+ _this.uploadTexture( texture );
} else {
- _gl.activeTexture( _gl.TEXTURE0 + slot );
_gl.bindTexture( _gl.TEXTURE_2D, texture.__webglTexture );
}
@@ -24533,27 +23554,27 @@ THREE.WebGLRenderer = function ( parameters ) {
function clampToMaxSize ( image, maxSize ) {
- if ( image.width <= maxSize && image.height <= maxSize ) {
+ if ( image.width > maxSize || image.height > maxSize ) {
- return image;
+ // Warning: Scaling through the canvas will only work with images that use
+ // premultiplied alpha.
- }
+ var scale = maxSize / Math.max( image.width, image.height );
- // Warning: Scaling through the canvas will only work with images that use
- // premultiplied alpha.
+ var canvas = document.createElement( 'canvas' );
+ canvas.width = Math.floor( image.width * scale );
+ canvas.height = Math.floor( image.height * scale );
- var maxDimension = Math.max( image.width, image.height );
- var newWidth = Math.floor( image.width * maxSize / maxDimension );
- var newHeight = Math.floor( image.height * maxSize / maxDimension );
+ var context = canvas.getContext( '2d' );
+ context.drawImage( image, 0, 0, image.width, image.height, 0, 0, canvas.width, canvas.height );
- var canvas = document.createElement( 'canvas' );
- canvas.width = newWidth;
- canvas.height = newHeight;
+ console.log( 'THREE.WebGLRenderer:', image, 'is too big (' + image.width + 'x' + image.height + '). Resized to ' + canvas.width + 'x' + canvas.height + '.' );
- var ctx = canvas.getContext( '2d' );
- ctx.drawImage( image, 0, 0, image.width, image.height, 0, 0, newWidth, newHeight );
+ return canvas;
- return canvas;
+ }
+
+ return image;
}
@@ -24579,18 +23600,19 @@ THREE.WebGLRenderer = function ( parameters ) {
_gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY );
var isCompressed = texture instanceof THREE.CompressedTexture;
+ var isDataTexture = texture.image[ 0 ] instanceof THREE.DataTexture;
var cubeImage = [];
for ( var i = 0; i < 6; i ++ ) {
- if ( _this.autoScaleCubemaps && ! isCompressed ) {
+ if ( _this.autoScaleCubemaps && ! isCompressed && ! isDataTexture ) {
cubeImage[ i ] = clampToMaxSize( texture.image[ i ], _maxCubemapSize );
} else {
- cubeImage[ i ] = texture.image[ i ];
+ cubeImage[ i ] = isDataTexture ? texture.image[ i ].image : texture.image[ i ];
}
@@ -24607,7 +23629,15 @@ THREE.WebGLRenderer = function ( parameters ) {
if ( ! isCompressed ) {
- _gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, glFormat, glType, cubeImage[ i ] );
+ if ( isDataTexture ) {
+
+ _gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, cubeImage[ i ].width, cubeImage[ i ].height, 0, glFormat, glType, cubeImage[ i ].data );
+
+ } else {
+
+ _gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, glFormat, glType, cubeImage[ i ] );
+
+ }
} else {
@@ -24616,16 +23646,29 @@ THREE.WebGLRenderer = function ( parameters ) {
for ( var j = 0, jl = mipmaps.length; j < jl; j ++ ) {
mipmap = mipmaps[ j ];
- if ( texture.format !== THREE.RGBAFormat ) {
- _gl.compressedTexImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, mipmap.data );
+ if ( texture.format !== THREE.RGBAFormat && texture.format !== THREE.RGBFormat ) {
+
+ if ( getCompressedTextureFormats().indexOf( glFormat ) > -1 ) {
+
+ _gl.compressedTexImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, mipmap.data );
+
+ } else {
+
+ console.warn( "Attempt to load unsupported compressed texture format" );
+
+ }
} else {
+
_gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
+
}
}
+
}
+
}
if ( texture.generateMipmaps && isImagePowerOfTwo ) {
@@ -24647,14 +23690,14 @@ THREE.WebGLRenderer = function ( parameters ) {
}
- };
+ }
function setCubeTextureDynamic ( texture, slot ) {
_gl.activeTexture( _gl.TEXTURE0 + slot );
_gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.__webglTexture );
- };
+ }
// Render targets
@@ -24663,7 +23706,7 @@ THREE.WebGLRenderer = function ( parameters ) {
_gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
_gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, textureTarget, renderTarget.__webglTexture, 0 );
- };
+ }
function setupRenderBuffer ( renderbuffer, renderTarget ) {
@@ -24691,13 +23734,13 @@ THREE.WebGLRenderer = function ( parameters ) {
}
- };
+ }
this.setRenderTarget = function ( renderTarget ) {
var isCube = ( renderTarget instanceof THREE.WebGLRenderTargetCube );
- if ( renderTarget && ! renderTarget.__webglFramebuffer ) {
+ if ( renderTarget && renderTarget.__webglFramebuffer === undefined ) {
if ( renderTarget.depthBuffer === undefined ) renderTarget.depthBuffer = true;
if ( renderTarget.stencilBuffer === undefined ) renderTarget.stencilBuffer = true;
@@ -24858,7 +23901,7 @@ THREE.WebGLRenderer = function ( parameters ) {
}
- };
+ }
// Fallback filters for non-power-of-2 textures
@@ -24872,12 +23915,14 @@ THREE.WebGLRenderer = function ( parameters ) {
return _gl.LINEAR;
- };
+ }
// Map three.js constants to WebGL constants
function paramThreeToGL ( p ) {
+ var extension;
+
if ( p === THREE.RepeatWrapping ) return _gl.REPEAT;
if ( p === THREE.ClampToEdgeWrapping ) return _gl.CLAMP_TO_EDGE;
if ( p === THREE.MirroredRepeatWrapping ) return _gl.MIRRORED_REPEAT;
@@ -24925,18 +23970,40 @@ THREE.WebGLRenderer = function ( parameters ) {
if ( p === THREE.OneMinusDstColorFactor ) return _gl.ONE_MINUS_DST_COLOR;
if ( p === THREE.SrcAlphaSaturateFactor ) return _gl.SRC_ALPHA_SATURATE;
- if ( _glExtensionCompressedTextureS3TC !== undefined ) {
+ extension = extensions.get( 'WEBGL_compressed_texture_s3tc' );
+
+ if ( extension !== null ) {
- if ( p === THREE.RGB_S3TC_DXT1_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGB_S3TC_DXT1_EXT;
- if ( p === THREE.RGBA_S3TC_DXT1_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGBA_S3TC_DXT1_EXT;
- if ( p === THREE.RGBA_S3TC_DXT3_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGBA_S3TC_DXT3_EXT;
- if ( p === THREE.RGBA_S3TC_DXT5_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGBA_S3TC_DXT5_EXT;
+ if ( p === THREE.RGB_S3TC_DXT1_Format ) return extension.COMPRESSED_RGB_S3TC_DXT1_EXT;
+ if ( p === THREE.RGBA_S3TC_DXT1_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT1_EXT;
+ if ( p === THREE.RGBA_S3TC_DXT3_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT3_EXT;
+ if ( p === THREE.RGBA_S3TC_DXT5_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT5_EXT;
+
+ }
+
+ extension = extensions.get( 'WEBGL_compressed_texture_pvrtc' );
+
+ if ( extension !== null ) {
+
+ if ( p === THREE.RGB_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_4BPPV1_IMG;
+ if ( p === THREE.RGB_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_2BPPV1_IMG;
+ if ( p === THREE.RGBA_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;
+ if ( p === THREE.RGBA_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;
+
+ }
+
+ extension = extensions.get( 'EXT_blend_minmax' );
+
+ if ( extension !== null ) {
+
+ if ( p === THREE.MinEquation ) return extension.MIN_EXT;
+ if ( p === THREE.MaxEquation ) return extension.MAX_EXT;
}
return 0;
- };
+ }
// Allocations
@@ -24977,7 +24044,7 @@ THREE.WebGLRenderer = function ( parameters ) {
}
- };
+ }
function allocateLights( lights ) {
@@ -25001,7 +24068,7 @@ THREE.WebGLRenderer = function ( parameters ) {
return { 'directional': dirLights, 'point': pointLights, 'spot': spotLights, 'hemi': hemiLights };
- };
+ }
function allocateShadows( lights ) {
@@ -25020,129 +24087,33 @@ THREE.WebGLRenderer = function ( parameters ) {
return maxShadows;
- };
-
- // Initialization
-
- function initGL() {
-
- try {
-
- var attributes = {
- alpha: _alpha,
- depth: _depth,
- stencil: _stencil,
- antialias: _antialias,
- premultipliedAlpha: _premultipliedAlpha,
- preserveDrawingBuffer: _preserveDrawingBuffer
- };
-
- _gl = _context || _canvas.getContext( 'webgl', attributes ) || _canvas.getContext( 'experimental-webgl', attributes );
-
- if ( _gl === null ) {
-
- throw 'Error creating WebGL context.';
-
- }
-
- } catch ( error ) {
-
- console.error( error );
-
- }
-
- _glExtensionTextureFloat = _gl.getExtension( 'OES_texture_float' );
- _glExtensionTextureFloatLinear = _gl.getExtension( 'OES_texture_float_linear' );
- _glExtensionStandardDerivatives = _gl.getExtension( 'OES_standard_derivatives' );
-
- _glExtensionTextureFilterAnisotropic = _gl.getExtension( 'EXT_texture_filter_anisotropic' ) || _gl.getExtension( 'MOZ_EXT_texture_filter_anisotropic' ) || _gl.getExtension( 'WEBKIT_EXT_texture_filter_anisotropic' );
-
- _glExtensionCompressedTextureS3TC = _gl.getExtension( 'WEBGL_compressed_texture_s3tc' ) || _gl.getExtension( 'MOZ_WEBGL_compressed_texture_s3tc' ) || _gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_s3tc' );
-
- _glExtensionElementIndexUint = _gl.getExtension( 'OES_element_index_uint' );
-
-
- if ( _glExtensionTextureFloat === null ) {
-
- console.log( 'THREE.WebGLRenderer: Float textures not supported.' );
-
- }
-
- if ( _glExtensionStandardDerivatives === null ) {
-
- console.log( 'THREE.WebGLRenderer: Standard derivatives not supported.' );
-
- }
-
- if ( _glExtensionTextureFilterAnisotropic === null ) {
-
- console.log( 'THREE.WebGLRenderer: Anisotropic texture filtering not supported.' );
-
- }
-
- if ( _glExtensionCompressedTextureS3TC === null ) {
-
- console.log( 'THREE.WebGLRenderer: S3TC compressed textures not supported.' );
-
- }
-
- if ( _glExtensionElementIndexUint === null ) {
-
- console.log( 'THREE.WebGLRenderer: elementindex as unsigned integer not supported.' );
-
- }
-
- if ( _gl.getShaderPrecisionFormat === undefined ) {
-
- _gl.getShaderPrecisionFormat = function () {
-
- return {
- 'rangeMin': 1,
- 'rangeMax': 1,
- 'precision': 1
- };
-
- }
- }
-
- if ( _logarithmicDepthBuffer ) {
+ }
- _glExtensionFragDepth = _gl.getExtension( 'EXT_frag_depth' );
+ // DEPRECATED
+
+ this.initMaterial = function () {
- }
+ console.warn( 'THREE.WebGLRenderer: .initMaterial() has been removed.' );
};
- function setDefaultGLState () {
-
- _gl.clearColor( 0, 0, 0, 1 );
- _gl.clearDepth( 1 );
- _gl.clearStencil( 0 );
-
- _gl.enable( _gl.DEPTH_TEST );
- _gl.depthFunc( _gl.LEQUAL );
+ this.addPrePlugin = function () {
- _gl.frontFace( _gl.CCW );
- _gl.cullFace( _gl.BACK );
- _gl.enable( _gl.CULL_FACE );
+ console.warn( 'THREE.WebGLRenderer: .addPrePlugin() has been removed.' );
- _gl.enable( _gl.BLEND );
- _gl.blendEquation( _gl.FUNC_ADD );
- _gl.blendFunc( _gl.SRC_ALPHA, _gl.ONE_MINUS_SRC_ALPHA );
+ };
- _gl.viewport( _viewportX, _viewportY, _viewportWidth, _viewportHeight );
+ this.addPostPlugin = function () {
- _gl.clearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha );
+ console.warn( 'THREE.WebGLRenderer: .addPostPlugin() has been removed.' );
};
- // default plugins (order is important)
+ this.updateShadowMap = function () {
- this.shadowMapPlugin = new THREE.ShadowMapPlugin();
- this.addPrePlugin( this.shadowMapPlugin );
+ console.warn( 'THREE.WebGLRenderer: .updateShadowMap() has been removed.' );
- this.addPostPlugin( new THREE.SpritePlugin() );
- this.addPostPlugin( new THREE.LensFlarePlugin() );
+ };
};
@@ -25249,6 +24220,76 @@ THREE.WebGLRenderTargetCube = function ( width, height, options ) {
THREE.WebGLRenderTargetCube.prototype = Object.create( THREE.WebGLRenderTarget.prototype );
+// File:src/renderers/webgl/WebGLExtensions.js
+
+THREE.WebGLExtensions = function ( gl ) {
+
+ var extensions = {};
+
+ this.get = function ( name ) {
+
+ if ( extensions[ name ] !== undefined ) {
+
+ return extensions[ name ];
+
+ }
+
+ var extension;
+
+ switch ( name ) {
+
+ case 'OES_texture_float':
+ extension = gl.getExtension( 'OES_texture_float' );
+ break;
+
+ case 'OES_texture_float_linear':
+ extension = gl.getExtension( 'OES_texture_float_linear' );
+ break;
+
+ case 'OES_standard_derivatives':
+ extension = gl.getExtension( 'OES_standard_derivatives' );
+ break;
+
+ case 'EXT_texture_filter_anisotropic':
+ extension = gl.getExtension( 'EXT_texture_filter_anisotropic' ) || gl.getExtension( 'MOZ_EXT_texture_filter_anisotropic' ) || gl.getExtension( 'WEBKIT_EXT_texture_filter_anisotropic' );
+ break;
+
+ case 'WEBGL_compressed_texture_s3tc':
+ extension = gl.getExtension( 'WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'MOZ_WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_s3tc' );
+ break;
+
+ case 'WEBGL_compressed_texture_pvrtc':
+ extension = gl.getExtension( 'WEBGL_compressed_texture_pvrtc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_pvrtc' );
+ break;
+
+ case 'OES_element_index_uint':
+ extension = gl.getExtension( 'OES_element_index_uint' );
+ break;
+
+ case 'EXT_blend_minmax':
+ extension = gl.getExtension( 'EXT_blend_minmax' );
+ break;
+
+ case 'EXT_frag_depth':
+ extension = gl.getExtension( 'EXT_frag_depth' );
+ break;
+
+ }
+
+ if ( extension === null ) {
+
+ console.log( 'THREE.WebGLRenderer: ' + name + ' extension not supported.' );
+
+ }
+
+ extensions[ name ] = extension;
+
+ return extension;
+
+ };
+
+};
+
// File:src/renderers/webgl/WebGLProgram.js
THREE.WebGLProgram = ( function () {
@@ -25614,6 +24655,7 @@ THREE.WebGLProgram = ( function () {
}
this.attributes = cacheAttributeLocations( _gl, program, identifiers );
+ this.attributesKeys = Object.keys( this.attributes );
//
@@ -25677,5071 +24719,5210 @@ THREE.WebGLShader = ( function () {
} )();
-// File:src/renderers/renderables/RenderableVertex.js
+// File:src/renderers/webgl/plugins/LensFlarePlugin.js
/**
- * @author mrdoob / http://mrdoob.com/
+ * @author mikael emtinger / http://gomo.se/
+ * @author alteredq / http://alteredqualia.com/
*/
-THREE.RenderableVertex = function () {
+THREE.LensFlarePlugin = function ( renderer, flares ) {
- this.position = new THREE.Vector3();
- this.positionWorld = new THREE.Vector3();
- this.positionScreen = new THREE.Vector4();
+ var gl = renderer.context;
- this.visible = true;
+ var vertexBuffer, elementBuffer;
+ var program, attributes, uniforms;
+ var hasVertexTexture;
-};
+ var tempTexture, occlusionTexture;
-THREE.RenderableVertex.prototype.copy = function ( vertex ) {
+ var init = function () {
- this.positionWorld.copy( vertex.positionWorld );
- this.positionScreen.copy( vertex.positionScreen );
+ var vertices = new Float32Array( [
+ -1, -1, 0, 0,
+ 1, -1, 1, 0,
+ 1, 1, 1, 1,
+ -1, 1, 0, 1
+ ] );
-};
+ var faces = new Uint16Array( [
+ 0, 1, 2,
+ 0, 2, 3
+ ] );
-// File:src/renderers/renderables/RenderableFace.js
+ // buffers
-/**
- * @author mrdoob / http://mrdoob.com/
- */
+ vertexBuffer = gl.createBuffer();
+ elementBuffer = gl.createBuffer();
-THREE.RenderableFace = function () {
+ gl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer );
+ gl.bufferData( gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW );
- this.id = 0;
+ gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer );
+ gl.bufferData( gl.ELEMENT_ARRAY_BUFFER, faces, gl.STATIC_DRAW );
- this.v1 = new THREE.RenderableVertex();
- this.v2 = new THREE.RenderableVertex();
- this.v3 = new THREE.RenderableVertex();
+ // textures
- this.normalModel = new THREE.Vector3();
+ tempTexture = gl.createTexture();
+ occlusionTexture = gl.createTexture();
- this.vertexNormalsModel = [ new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3() ];
- this.vertexNormalsLength = 0;
+ gl.bindTexture( gl.TEXTURE_2D, tempTexture );
+ gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGB, 16, 16, 0, gl.RGB, gl.UNSIGNED_BYTE, null );
+ gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE );
+ gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE );
+ gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST );
+ gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST );
- this.color = new THREE.Color();
- this.material = null;
- this.uvs = [ new THREE.Vector2(), new THREE.Vector2(), new THREE.Vector2() ];
+ gl.bindTexture( gl.TEXTURE_2D, occlusionTexture );
+ gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGBA, 16, 16, 0, gl.RGBA, gl.UNSIGNED_BYTE, null );
+ gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE );
+ gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE );
+ gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST );
+ gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST );
- this.z = 0;
+ hasVertexTexture = gl.getParameter( gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS ) > 0;
-};
+ var shader;
-// File:src/renderers/renderables/RenderableObject.js
+ if ( hasVertexTexture ) {
-/**
- * @author mrdoob / http://mrdoob.com/
- */
+ shader = {
-THREE.RenderableObject = function () {
+ vertexShader: [
- this.id = 0;
+ "uniform lowp int renderType;",
- this.object = null;
- this.z = 0;
-
-};
+ "uniform vec3 screenPosition;",
+ "uniform vec2 scale;",
+ "uniform float rotation;",
-// File:src/renderers/renderables/RenderableSprite.js
+ "uniform sampler2D occlusionMap;",
-/**
- * @author mrdoob / http://mrdoob.com/
- */
+ "attribute vec2 position;",
+ "attribute vec2 uv;",
-THREE.RenderableSprite = function () {
+ "varying vec2 vUV;",
+ "varying float vVisibility;",
- this.id = 0;
+ "void main() {",
- this.object = null;
+ "vUV = uv;",
- this.x = 0;
- this.y = 0;
- this.z = 0;
+ "vec2 pos = position;",
- this.rotation = 0;
- this.scale = new THREE.Vector2();
+ "if( renderType == 2 ) {",
- this.material = null;
+ "vec4 visibility = texture2D( occlusionMap, vec2( 0.1, 0.1 ) );",
+ "visibility += texture2D( occlusionMap, vec2( 0.5, 0.1 ) );",
+ "visibility += texture2D( occlusionMap, vec2( 0.9, 0.1 ) );",
+ "visibility += texture2D( occlusionMap, vec2( 0.9, 0.5 ) );",
+ "visibility += texture2D( occlusionMap, vec2( 0.9, 0.9 ) );",
+ "visibility += texture2D( occlusionMap, vec2( 0.5, 0.9 ) );",
+ "visibility += texture2D( occlusionMap, vec2( 0.1, 0.9 ) );",
+ "visibility += texture2D( occlusionMap, vec2( 0.1, 0.5 ) );",
+ "visibility += texture2D( occlusionMap, vec2( 0.5, 0.5 ) );",
-};
+ "vVisibility = visibility.r / 9.0;",
+ "vVisibility *= 1.0 - visibility.g / 9.0;",
+ "vVisibility *= visibility.b / 9.0;",
+ "vVisibility *= 1.0 - visibility.a / 9.0;",
-// File:src/renderers/renderables/RenderableLine.js
+ "pos.x = cos( rotation ) * position.x - sin( rotation ) * position.y;",
+ "pos.y = sin( rotation ) * position.x + cos( rotation ) * position.y;",
-/**
- * @author mrdoob / http://mrdoob.com/
- */
+ "}",
-THREE.RenderableLine = function () {
+ "gl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );",
- this.id = 0;
+ "}"
- this.v1 = new THREE.RenderableVertex();
- this.v2 = new THREE.RenderableVertex();
+ ].join( "\n" ),
- this.vertexColors = [ new THREE.Color(), new THREE.Color() ];
- this.material = null;
+ fragmentShader: [
- this.z = 0;
+ "uniform lowp int renderType;",
-};
+ "uniform sampler2D map;",
+ "uniform float opacity;",
+ "uniform vec3 color;",
-// File:src/extras/GeometryUtils.js
+ "varying vec2 vUV;",
+ "varying float vVisibility;",
-/**
- * @author mrdoob / http://mrdoob.com/
- */
+ "void main() {",
-THREE.GeometryUtils = {
+ // pink square
- merge: function ( geometry1, geometry2, materialIndexOffset ) {
+ "if( renderType == 0 ) {",
- console.warn( 'THREE.GeometryUtils: .merge() has been moved to Geometry. Use geometry.merge( geometry2, matrix, materialIndexOffset ) instead.' );
+ "gl_FragColor = vec4( 1.0, 0.0, 1.0, 0.0 );",
- var matrix;
+ // restore
- if ( geometry2 instanceof THREE.Mesh ) {
+ "} else if( renderType == 1 ) {",
- geometry2.matrixAutoUpdate && geometry2.updateMatrix();
+ "gl_FragColor = texture2D( map, vUV );",
- matrix = geometry2.matrix;
- geometry2 = geometry2.geometry;
+ // flare
- }
+ "} else {",
- geometry1.merge( geometry2, matrix, materialIndexOffset );
+ "vec4 texture = texture2D( map, vUV );",
+ "texture.a *= opacity * vVisibility;",
+ "gl_FragColor = texture;",
+ "gl_FragColor.rgb *= color;",
- },
+ "}",
- center: function ( geometry ) {
+ "}"
- console.warn( 'THREE.GeometryUtils: .center() has been moved to Geometry. Use geometry.center() instead.' );
- return geometry.center();
+ ].join( "\n" )
- }
+ };
-};
+ } else {
-// File:src/extras/ImageUtils.js
+ shader = {
-/**
- * @author alteredq / http://alteredqualia.com/
- * @author mrdoob / http://mrdoob.com/
- * @author Daosheng Mu / https://github.com/DaoshengMu/
- */
+ vertexShader: [
-THREE.ImageUtils = {
+ "uniform lowp int renderType;",
- crossOrigin: undefined,
+ "uniform vec3 screenPosition;",
+ "uniform vec2 scale;",
+ "uniform float rotation;",
- loadTexture: function ( url, mapping, onLoad, onError ) {
+ "attribute vec2 position;",
+ "attribute vec2 uv;",
- var loader = new THREE.ImageLoader();
- loader.crossOrigin = this.crossOrigin;
+ "varying vec2 vUV;",
- var texture = new THREE.Texture( undefined, mapping );
+ "void main() {",
- loader.load( url, function ( image ) {
+ "vUV = uv;",
- texture.image = image;
- texture.needsUpdate = true;
+ "vec2 pos = position;",
- if ( onLoad ) onLoad( texture );
+ "if( renderType == 2 ) {",
- }, undefined, function ( event ) {
+ "pos.x = cos( rotation ) * position.x - sin( rotation ) * position.y;",
+ "pos.y = sin( rotation ) * position.x + cos( rotation ) * position.y;",
- if ( onError ) onError( event );
+ "}",
- } );
+ "gl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );",
- texture.sourceFile = url;
+ "}"
- return texture;
+ ].join( "\n" ),
- },
+ fragmentShader: [
- loadTextureCube: function ( array, mapping, onLoad, onError ) {
+ "precision mediump float;",
- var images = [];
+ "uniform lowp int renderType;",
- var loader = new THREE.ImageLoader();
- loader.crossOrigin = this.crossOrigin;
+ "uniform sampler2D map;",
+ "uniform sampler2D occlusionMap;",
+ "uniform float opacity;",
+ "uniform vec3 color;",
- var texture = new THREE.CubeTexture( images, mapping );
+ "varying vec2 vUV;",
- // no flipping needed for cube textures
+ "void main() {",
- texture.flipY = false;
+ // pink square
- var loaded = 0;
+ "if( renderType == 0 ) {",
- var loadTexture = function ( i ) {
+ "gl_FragColor = vec4( texture2D( map, vUV ).rgb, 0.0 );",
- loader.load( array[ i ], function ( image ) {
+ // restore
- texture.images[ i ] = image;
+ "} else if( renderType == 1 ) {",
- loaded += 1;
+ "gl_FragColor = texture2D( map, vUV );",
- if ( loaded === 6 ) {
+ // flare
- texture.needsUpdate = true;
+ "} else {",
- if ( onLoad ) onLoad( texture );
+ "float visibility = texture2D( occlusionMap, vec2( 0.5, 0.1 ) ).a;",
+ "visibility += texture2D( occlusionMap, vec2( 0.9, 0.5 ) ).a;",
+ "visibility += texture2D( occlusionMap, vec2( 0.5, 0.9 ) ).a;",
+ "visibility += texture2D( occlusionMap, vec2( 0.1, 0.5 ) ).a;",
+ "visibility = ( 1.0 - visibility / 4.0 );",
- }
+ "vec4 texture = texture2D( map, vUV );",
+ "texture.a *= opacity * visibility;",
+ "gl_FragColor = texture;",
+ "gl_FragColor.rgb *= color;",
- } );
+ "}",
- }
+ "}"
- for ( var i = 0, il = array.length; i < il; ++ i ) {
+ ].join( "\n" )
- loadTexture( i );
+ };
}
- return texture;
+ program = createProgram( shader );
- },
+ attributes = {
+ vertex: gl.getAttribLocation ( program, "position" ),
+ uv: gl.getAttribLocation ( program, "uv" )
+ }
- loadCompressedTexture: function () {
+ uniforms = {
+ renderType: gl.getUniformLocation( program, "renderType" ),
+ map: gl.getUniformLocation( program, "map" ),
+ occlusionMap: gl.getUniformLocation( program, "occlusionMap" ),
+ opacity: gl.getUniformLocation( program, "opacity" ),
+ color: gl.getUniformLocation( program, "color" ),
+ scale: gl.getUniformLocation( program, "scale" ),
+ rotation: gl.getUniformLocation( program, "rotation" ),
+ screenPosition: gl.getUniformLocation( program, "screenPosition" )
+ };
- console.error( 'THREE.ImageUtils.loadCompressedTexture has been removed. Use THREE.DDSLoader instead.' )
+ };
- },
+ /*
+ * Render lens flares
+ * Method: renders 16x16 0xff00ff-colored points scattered over the light source area,
+ * reads these back and calculates occlusion.
+ */
- loadCompressedTextureCube: function () {
+ this.render = function ( scene, camera, viewportWidth, viewportHeight ) {
- console.error( 'THREE.ImageUtils.loadCompressedTextureCube has been removed. Use THREE.DDSLoader instead.' )
+ if ( flares.length === 0 ) return;
- },
+ var tempPosition = new THREE.Vector3();
- getNormalMap: function ( image, depth ) {
+ var invAspect = viewportHeight / viewportWidth,
+ halfViewportWidth = viewportWidth * 0.5,
+ halfViewportHeight = viewportHeight * 0.5;
- // Adapted from http://www.paulbrunt.co.uk/lab/heightnormal/
+ var size = 16 / viewportHeight,
+ scale = new THREE.Vector2( size * invAspect, size );
- var cross = function ( a, b ) {
+ var screenPosition = new THREE.Vector3( 1, 1, 0 ),
+ screenPositionPixels = new THREE.Vector2( 1, 1 );
- return [ a[ 1 ] * b[ 2 ] - a[ 2 ] * b[ 1 ], a[ 2 ] * b[ 0 ] - a[ 0 ] * b[ 2 ], a[ 0 ] * b[ 1 ] - a[ 1 ] * b[ 0 ] ];
+ if ( program === undefined ) {
+
+ init();
}
- var subtract = function ( a, b ) {
+ gl.useProgram( program );
- return [ a[ 0 ] - b[ 0 ], a[ 1 ] - b[ 1 ], a[ 2 ] - b[ 2 ] ];
+ gl.enableVertexAttribArray( attributes.vertex );
+ gl.enableVertexAttribArray( attributes.uv );
- }
+ // loop through all lens flares to update their occlusion and positions
+ // setup gl and common used attribs/unforms
- var normalize = function ( a ) {
+ gl.uniform1i( uniforms.occlusionMap, 0 );
+ gl.uniform1i( uniforms.map, 1 );
- var l = Math.sqrt( a[ 0 ] * a[ 0 ] + a[ 1 ] * a[ 1 ] + a[ 2 ] * a[ 2 ] );
- return [ a[ 0 ] / l, a[ 1 ] / l, a[ 2 ] / l ];
+ gl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer );
+ gl.vertexAttribPointer( attributes.vertex, 2, gl.FLOAT, false, 2 * 8, 0 );
+ gl.vertexAttribPointer( attributes.uv, 2, gl.FLOAT, false, 2 * 8, 8 );
- }
+ gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer );
- depth = depth | 1;
+ gl.disable( gl.CULL_FACE );
+ gl.depthMask( false );
- var width = image.width;
- var height = image.height;
+ for ( var i = 0, l = flares.length; i < l; i ++ ) {
- var canvas = document.createElement( 'canvas' );
- canvas.width = width;
- canvas.height = height;
+ size = 16 / viewportHeight;
+ scale.set( size * invAspect, size );
- var context = canvas.getContext( '2d' );
- context.drawImage( image, 0, 0 );
+ // calc object screen position
- var data = context.getImageData( 0, 0, width, height ).data;
- var imageData = context.createImageData( width, height );
- var output = imageData.data;
+ var flare = flares[ i ];
+
+ tempPosition.set( flare.matrixWorld.elements[12], flare.matrixWorld.elements[13], flare.matrixWorld.elements[14] );
- for ( var x = 0; x < width; x ++ ) {
+ tempPosition.applyMatrix4( camera.matrixWorldInverse );
+ tempPosition.applyProjection( camera.projectionMatrix );
- for ( var y = 0; y < height; y ++ ) {
+ // setup arrays for gl programs
- var ly = y - 1 < 0 ? 0 : y - 1;
- var uy = y + 1 > height - 1 ? height - 1 : y + 1;
- var lx = x - 1 < 0 ? 0 : x - 1;
- var ux = x + 1 > width - 1 ? width - 1 : x + 1;
+ screenPosition.copy( tempPosition )
- var points = [];
- var origin = [ 0, 0, data[ ( y * width + x ) * 4 ] / 255 * depth ];
- points.push( [ - 1, 0, data[ ( y * width + lx ) * 4 ] / 255 * depth ] );
- points.push( [ - 1, - 1, data[ ( ly * width + lx ) * 4 ] / 255 * depth ] );
- points.push( [ 0, - 1, data[ ( ly * width + x ) * 4 ] / 255 * depth ] );
- points.push( [ 1, - 1, data[ ( ly * width + ux ) * 4 ] / 255 * depth ] );
- points.push( [ 1, 0, data[ ( y * width + ux ) * 4 ] / 255 * depth ] );
- points.push( [ 1, 1, data[ ( uy * width + ux ) * 4 ] / 255 * depth ] );
- points.push( [ 0, 1, data[ ( uy * width + x ) * 4 ] / 255 * depth ] );
- points.push( [ - 1, 1, data[ ( uy * width + lx ) * 4 ] / 255 * depth ] );
+ screenPositionPixels.x = screenPosition.x * halfViewportWidth + halfViewportWidth;
+ screenPositionPixels.y = screenPosition.y * halfViewportHeight + halfViewportHeight;
- var normals = [];
- var num_points = points.length;
+ // screen cull
- for ( var i = 0; i < num_points; i ++ ) {
+ if ( hasVertexTexture || (
+ screenPositionPixels.x > 0 &&
+ screenPositionPixels.x < viewportWidth &&
+ screenPositionPixels.y > 0 &&
+ screenPositionPixels.y < viewportHeight ) ) {
- var v1 = points[ i ];
- var v2 = points[ ( i + 1 ) % num_points ];
- v1 = subtract( v1, origin );
- v2 = subtract( v2, origin );
- normals.push( normalize( cross( v1, v2 ) ) );
+ // save current RGB to temp texture
- }
+ gl.activeTexture( gl.TEXTURE1 );
+ gl.bindTexture( gl.TEXTURE_2D, tempTexture );
+ gl.copyTexImage2D( gl.TEXTURE_2D, 0, gl.RGB, screenPositionPixels.x - 8, screenPositionPixels.y - 8, 16, 16, 0 );
- var normal = [ 0, 0, 0 ];
- for ( var i = 0; i < normals.length; i ++ ) {
+ // render pink quad
- normal[ 0 ] += normals[ i ][ 0 ];
- normal[ 1 ] += normals[ i ][ 1 ];
- normal[ 2 ] += normals[ i ][ 2 ];
+ gl.uniform1i( uniforms.renderType, 0 );
+ gl.uniform2f( uniforms.scale, scale.x, scale.y );
+ gl.uniform3f( uniforms.screenPosition, screenPosition.x, screenPosition.y, screenPosition.z );
- }
+ gl.disable( gl.BLEND );
+ gl.enable( gl.DEPTH_TEST );
- normal[ 0 ] /= normals.length;
- normal[ 1 ] /= normals.length;
- normal[ 2 ] /= normals.length;
+ gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 );
- var idx = ( y * width + x ) * 4;
- output[ idx ] = ( ( normal[ 0 ] + 1.0 ) / 2.0 * 255 ) | 0;
- output[ idx + 1 ] = ( ( normal[ 1 ] + 1.0 ) / 2.0 * 255 ) | 0;
- output[ idx + 2 ] = ( normal[ 2 ] * 255 ) | 0;
- output[ idx + 3 ] = 255;
+ // copy result to occlusionMap
- }
+ gl.activeTexture( gl.TEXTURE0 );
+ gl.bindTexture( gl.TEXTURE_2D, occlusionTexture );
+ gl.copyTexImage2D( gl.TEXTURE_2D, 0, gl.RGBA, screenPositionPixels.x - 8, screenPositionPixels.y - 8, 16, 16, 0 );
- }
- context.putImageData( imageData, 0, 0 );
+ // restore graphics
- return canvas;
+ gl.uniform1i( uniforms.renderType, 1 );
+ gl.disable( gl.DEPTH_TEST );
- },
+ gl.activeTexture( gl.TEXTURE1 );
+ gl.bindTexture( gl.TEXTURE_2D, tempTexture );
+ gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 );
- generateDataTexture: function ( width, height, color ) {
- var size = width * height;
- var data = new Uint8Array( 3 * size );
+ // update object positions
- var r = Math.floor( color.r * 255 );
- var g = Math.floor( color.g * 255 );
- var b = Math.floor( color.b * 255 );
+ flare.positionScreen.copy( screenPosition )
- for ( var i = 0; i < size; i ++ ) {
+ if ( flare.customUpdateCallback ) {
- data[ i * 3 ] = r;
- data[ i * 3 + 1 ] = g;
- data[ i * 3 + 2 ] = b;
+ flare.customUpdateCallback( flare );
- }
+ } else {
- var texture = new THREE.DataTexture( data, width, height, THREE.RGBFormat );
- texture.needsUpdate = true;
+ flare.updateLensFlares();
- return texture;
+ }
- }
+ // render flares
-};
+ gl.uniform1i( uniforms.renderType, 2 );
+ gl.enable( gl.BLEND );
-// File:src/extras/SceneUtils.js
+ for ( var j = 0, jl = flare.lensFlares.length; j < jl; j ++ ) {
-/**
- * @author alteredq / http://alteredqualia.com/
- */
+ var sprite = flare.lensFlares[ j ];
-THREE.SceneUtils = {
+ if ( sprite.opacity > 0.001 && sprite.scale > 0.001 ) {
- createMultiMaterialObject: function ( geometry, materials ) {
+ screenPosition.x = sprite.x;
+ screenPosition.y = sprite.y;
+ screenPosition.z = sprite.z;
- var group = new THREE.Object3D();
+ size = sprite.size * sprite.scale / viewportHeight;
- for ( var i = 0, l = materials.length; i < l; i ++ ) {
+ scale.x = size * invAspect;
+ scale.y = size;
- group.add( new THREE.Mesh( geometry, materials[ i ] ) );
+ gl.uniform3f( uniforms.screenPosition, screenPosition.x, screenPosition.y, screenPosition.z );
+ gl.uniform2f( uniforms.scale, scale.x, scale.y );
+ gl.uniform1f( uniforms.rotation, sprite.rotation );
- }
+ gl.uniform1f( uniforms.opacity, sprite.opacity );
+ gl.uniform3f( uniforms.color, sprite.color.r, sprite.color.g, sprite.color.b );
- return group;
+ renderer.setBlending( sprite.blending, sprite.blendEquation, sprite.blendSrc, sprite.blendDst );
+ renderer.setTexture( sprite.texture, 1 );
- },
+ gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 );
- detach: function ( child, parent, scene ) {
+ }
- child.applyMatrix( parent.matrixWorld );
- parent.remove( child );
- scene.add( child );
+ }
- },
+ }
- attach: function ( child, scene, parent ) {
+ }
- var matrixWorldInverse = new THREE.Matrix4();
- matrixWorldInverse.getInverse( parent.matrixWorld );
- child.applyMatrix( matrixWorldInverse );
+ // restore gl
- scene.remove( child );
- parent.add( child );
+ gl.enable( gl.CULL_FACE );
+ gl.enable( gl.DEPTH_TEST );
+ gl.depthMask( true );
- }
+ renderer.resetGLState();
-};
+ };
-// File:src/extras/FontUtils.js
+ function createProgram ( shader ) {
-/**
- * @author zz85 / http://www.lab4games.net/zz85/blog
- * @author alteredq / http://alteredqualia.com/
- *
- * For Text operations in three.js (See TextGeometry)
- *
- * It uses techniques used in:
- *
- * typeface.js and canvastext
- * For converting fonts and rendering with javascript
- * http://typeface.neocracy.org
- *
- * Triangulation ported from AS3
- * Simple Polygon Triangulation
- * http://actionsnippet.com/?p=1462
- *
- * A Method to triangulate shapes with holes
- * http://www.sakri.net/blog/2009/06/12/an-approach-to-triangulating-polygons-with-holes/
- *
- */
+ var program = gl.createProgram();
-THREE.FontUtils = {
+ var fragmentShader = gl.createShader( gl.FRAGMENT_SHADER );
+ var vertexShader = gl.createShader( gl.VERTEX_SHADER );
- faces: {},
+ var prefix = "precision " + renderer.getPrecision() + " float;\n";
- // Just for now. face[weight][style]
+ gl.shaderSource( fragmentShader, prefix + shader.fragmentShader );
+ gl.shaderSource( vertexShader, prefix + shader.vertexShader );
- face: 'helvetiker',
- weight: 'normal',
- style: 'normal',
- size: 150,
- divisions: 10,
+ gl.compileShader( fragmentShader );
+ gl.compileShader( vertexShader );
- getFace: function () {
+ gl.attachShader( program, fragmentShader );
+ gl.attachShader( program, vertexShader );
- try {
+ gl.linkProgram( program );
- return this.faces[ this.face ][ this.weight ][ this.style ];
+ return program;
- } catch (e) {
+ }
- throw "The font " + this.face + " with " + this.weight + " weight and " + this.style + " style is missing."
+};
- };
+// File:src/renderers/webgl/plugins/ShadowMapPlugin.js
- },
+/**
+ * @author alteredq / http://alteredqualia.com/
+ */
- loadFace: function ( data ) {
+THREE.ShadowMapPlugin = function ( _renderer, _lights, _webglObjects, _webglObjectsImmediate ) {
- var family = data.familyName.toLowerCase();
+ var _gl = _renderer.context;
- var ThreeFont = this;
+ var _depthMaterial, _depthMaterialMorph, _depthMaterialSkin, _depthMaterialMorphSkin,
- ThreeFont.faces[ family ] = ThreeFont.faces[ family ] || {};
+ _frustum = new THREE.Frustum(),
+ _projScreenMatrix = new THREE.Matrix4(),
- ThreeFont.faces[ family ][ data.cssFontWeight ] = ThreeFont.faces[ family ][ data.cssFontWeight ] || {};
- ThreeFont.faces[ family ][ data.cssFontWeight ][ data.cssFontStyle ] = data;
+ _min = new THREE.Vector3(),
+ _max = new THREE.Vector3(),
- var face = ThreeFont.faces[ family ][ data.cssFontWeight ][ data.cssFontStyle ] = data;
+ _matrixPosition = new THREE.Vector3(),
+
+ _renderList = [];
- return data;
+ // init
- },
+ var depthShader = THREE.ShaderLib[ "depthRGBA" ];
+ var depthUniforms = THREE.UniformsUtils.clone( depthShader.uniforms );
- drawText: function ( text ) {
+ _depthMaterial = new THREE.ShaderMaterial( {
+ uniforms: depthUniforms,
+ vertexShader: depthShader.vertexShader,
+ fragmentShader: depthShader.fragmentShader
+ } );
- var characterPts = [], allPts = [];
+ _depthMaterialMorph = new THREE.ShaderMaterial( {
+ uniforms: depthUniforms,
+ vertexShader: depthShader.vertexShader,
+ fragmentShader: depthShader.fragmentShader,
+ morphTargets: true
+ } );
- // RenderText
+ _depthMaterialSkin = new THREE.ShaderMaterial( {
+ uniforms: depthUniforms,
+ vertexShader: depthShader.vertexShader,
+ fragmentShader: depthShader.fragmentShader,
+ skinning: true
+ } );
- var i, p,
- face = this.getFace(),
- scale = this.size / face.resolution,
- offset = 0,
- chars = String( text ).split( '' ),
- length = chars.length;
+ _depthMaterialMorphSkin = new THREE.ShaderMaterial( {
+ uniforms: depthUniforms,
+ vertexShader: depthShader.vertexShader,
+ fragmentShader: depthShader.fragmentShader,
+ morphTargets: true,
+ skinning: true
+ } );
- var fontPaths = [];
+ _depthMaterial._shadowPass = true;
+ _depthMaterialMorph._shadowPass = true;
+ _depthMaterialSkin._shadowPass = true;
+ _depthMaterialMorphSkin._shadowPass = true;
- for ( i = 0; i < length; i ++ ) {
+ this.render = function ( scene, camera ) {
- var path = new THREE.Path();
+ if ( _renderer.shadowMapEnabled === false ) return;
- var ret = this.extractGlyphPoints( chars[ i ], face, scale, offset, path );
- offset += ret.offset;
+ var i, il, j, jl, n,
- fontPaths.push( ret.path );
+ shadowMap, shadowMatrix, shadowCamera,
+ program, buffer, material,
+ webglObject, object, light,
- }
+ lights = [],
+ k = 0,
- // get the width
+ fog = null;
- var width = offset / 2;
- //
- // for ( p = 0; p < allPts.length; p++ ) {
- //
- // allPts[ p ].x -= width;
- //
- // }
+ // set GL state for depth map
- //var extract = this.extractPoints( allPts, characterPts );
- //extract.contour = allPts;
+ _gl.clearColor( 1, 1, 1, 1 );
+ _gl.disable( _gl.BLEND );
- //extract.paths = fontPaths;
- //extract.offset = width;
+ _gl.enable( _gl.CULL_FACE );
+ _gl.frontFace( _gl.CCW );
- return { paths: fontPaths, offset: width };
+ if ( _renderer.shadowMapCullFace === THREE.CullFaceFront ) {
- },
+ _gl.cullFace( _gl.FRONT );
+ } else {
+ _gl.cullFace( _gl.BACK );
+ }
- extractGlyphPoints: function ( c, face, scale, offset, path ) {
+ _renderer.setDepthTest( true );
- var pts = [];
+ // preprocess lights
+ // - skip lights that are not casting shadows
+ // - create virtual lights for cascaded shadow maps
- var i, i2, divisions,
- outline, action, length,
- scaleX, scaleY,
- x, y, cpx, cpy, cpx0, cpy0, cpx1, cpy1, cpx2, cpy2,
- laste,
- glyph = face.glyphs[ c ] || face.glyphs[ '?' ];
+ for ( i = 0, il = _lights.length; i < il; i ++ ) {
- if ( ! glyph ) return;
+ light = _lights[ i ];
- if ( glyph.o ) {
+ if ( ! light.castShadow ) continue;
- outline = glyph._cachedOutline || ( glyph._cachedOutline = glyph.o.split( ' ' ) );
- length = outline.length;
+ if ( ( light instanceof THREE.DirectionalLight ) && light.shadowCascade ) {
- scaleX = scale;
- scaleY = scale;
+ for ( n = 0; n < light.shadowCascadeCount; n ++ ) {
- for ( i = 0; i < length; ) {
+ var virtualLight;
- action = outline[ i ++ ];
+ if ( ! light.shadowCascadeArray[ n ] ) {
- //console.log( action );
+ virtualLight = createVirtualLight( light, n );
+ virtualLight.originalCamera = camera;
- switch ( action ) {
+ var gyro = new THREE.Gyroscope();
+ gyro.position.copy( light.shadowCascadeOffset );
- case 'm':
+ gyro.add( virtualLight );
+ gyro.add( virtualLight.target );
- // Move To
+ camera.add( gyro );
- x = outline[ i ++ ] * scaleX + offset;
- y = outline[ i ++ ] * scaleY;
+ light.shadowCascadeArray[ n ] = virtualLight;
- path.moveTo( x, y );
- break;
+ console.log( "Created virtualLight", virtualLight );
- case 'l':
+ } else {
- // Line To
+ virtualLight = light.shadowCascadeArray[ n ];
- x = outline[ i ++ ] * scaleX + offset;
- y = outline[ i ++ ] * scaleY;
- path.lineTo( x,y );
- break;
+ }
- case 'q':
+ updateVirtualLight( light, n );
- // QuadraticCurveTo
+ lights[ k ] = virtualLight;
+ k ++;
- cpx = outline[ i ++ ] * scaleX + offset;
- cpy = outline[ i ++ ] * scaleY;
- cpx1 = outline[ i ++ ] * scaleX + offset;
- cpy1 = outline[ i ++ ] * scaleY;
+ }
- path.quadraticCurveTo( cpx1, cpy1, cpx, cpy );
+ } else {
- laste = pts[ pts.length - 1 ];
+ lights[ k ] = light;
+ k ++;
- if ( laste ) {
+ }
- cpx0 = laste.x;
- cpy0 = laste.y;
+ }
- for ( i2 = 1, divisions = this.divisions; i2 <= divisions; i2 ++ ) {
+ // render depth map
- var t = i2 / divisions;
- var tx = THREE.Shape.Utils.b2( t, cpx0, cpx1, cpx );
- var ty = THREE.Shape.Utils.b2( t, cpy0, cpy1, cpy );
- }
+ for ( i = 0, il = lights.length; i < il; i ++ ) {
- }
+ light = lights[ i ];
- break;
+ if ( ! light.shadowMap ) {
- case 'b':
+ var shadowFilter = THREE.LinearFilter;
- // Cubic Bezier Curve
+ if ( _renderer.shadowMapType === THREE.PCFSoftShadowMap ) {
- cpx = outline[ i ++ ] * scaleX + offset;
- cpy = outline[ i ++ ] * scaleY;
- cpx1 = outline[ i ++ ] * scaleX + offset;
- cpy1 = outline[ i ++ ] * scaleY;
- cpx2 = outline[ i ++ ] * scaleX + offset;
- cpy2 = outline[ i ++ ] * scaleY;
+ shadowFilter = THREE.NearestFilter;
- path.bezierCurveTo( cpx1, cpy1, cpx2, cpy2, cpx, cpy );
+ }
- laste = pts[ pts.length - 1 ];
+ var pars = { minFilter: shadowFilter, magFilter: shadowFilter, format: THREE.RGBAFormat };
- if ( laste ) {
+ light.shadowMap = new THREE.WebGLRenderTarget( light.shadowMapWidth, light.shadowMapHeight, pars );
+ light.shadowMapSize = new THREE.Vector2( light.shadowMapWidth, light.shadowMapHeight );
- cpx0 = laste.x;
- cpy0 = laste.y;
+ light.shadowMatrix = new THREE.Matrix4();
- for ( i2 = 1, divisions = this.divisions; i2 <= divisions; i2 ++ ) {
+ }
- var t = i2 / divisions;
- var tx = THREE.Shape.Utils.b3( t, cpx0, cpx1, cpx2, cpx );
- var ty = THREE.Shape.Utils.b3( t, cpy0, cpy1, cpy2, cpy );
+ if ( ! light.shadowCamera ) {
- }
+ if ( light instanceof THREE.SpotLight ) {
- }
+ light.shadowCamera = new THREE.PerspectiveCamera( light.shadowCameraFov, light.shadowMapWidth / light.shadowMapHeight, light.shadowCameraNear, light.shadowCameraFar );
- break;
+ } else if ( light instanceof THREE.DirectionalLight ) {
- }
+ light.shadowCamera = new THREE.OrthographicCamera( light.shadowCameraLeft, light.shadowCameraRight, light.shadowCameraTop, light.shadowCameraBottom, light.shadowCameraNear, light.shadowCameraFar );
- }
- }
+ } else {
+ console.error( "Unsupported light type for shadow" );
+ continue;
+ }
- return { offset: glyph.ha * scale, path:path };
- }
+ scene.add( light.shadowCamera );
-};
+ if ( scene.autoUpdate === true ) scene.updateMatrixWorld();
+ }
-THREE.FontUtils.generateShapes = function ( text, parameters ) {
+ if ( light.shadowCameraVisible && ! light.cameraHelper ) {
- // Parameters
+ light.cameraHelper = new THREE.CameraHelper( light.shadowCamera );
+ scene.add( light.cameraHelper );
- parameters = parameters || {};
+ }
- var size = parameters.size !== undefined ? parameters.size : 100;
- var curveSegments = parameters.curveSegments !== undefined ? parameters.curveSegments : 4;
+ if ( light.isVirtual && virtualLight.originalCamera == camera ) {
- var font = parameters.font !== undefined ? parameters.font : 'helvetiker';
- var weight = parameters.weight !== undefined ? parameters.weight : 'normal';
- var style = parameters.style !== undefined ? parameters.style : 'normal';
-
- THREE.FontUtils.size = size;
- THREE.FontUtils.divisions = curveSegments;
+ updateShadowCamera( camera, light );
- THREE.FontUtils.face = font;
- THREE.FontUtils.weight = weight;
- THREE.FontUtils.style = style;
+ }
- // Get a Font data json object
+ shadowMap = light.shadowMap;
+ shadowMatrix = light.shadowMatrix;
+ shadowCamera = light.shadowCamera;
- var data = THREE.FontUtils.drawText( text );
+ //
- var paths = data.paths;
- var shapes = [];
+ shadowCamera.position.setFromMatrixPosition( light.matrixWorld );
+ _matrixPosition.setFromMatrixPosition( light.target.matrixWorld );
+ shadowCamera.lookAt( _matrixPosition );
+ shadowCamera.updateMatrixWorld();
- for ( var p = 0, pl = paths.length; p < pl; p ++ ) {
+ shadowCamera.matrixWorldInverse.getInverse( shadowCamera.matrixWorld );
- Array.prototype.push.apply( shapes, paths[ p ].toShapes() );
+ //
- }
+ if ( light.cameraHelper ) light.cameraHelper.visible = light.shadowCameraVisible;
+ if ( light.shadowCameraVisible ) light.cameraHelper.update();
- return shapes;
+ // compute shadow matrix
-};
+ shadowMatrix.set(
+ 0.5, 0.0, 0.0, 0.5,
+ 0.0, 0.5, 0.0, 0.5,
+ 0.0, 0.0, 0.5, 0.5,
+ 0.0, 0.0, 0.0, 1.0
+ );
+ shadowMatrix.multiply( shadowCamera.projectionMatrix );
+ shadowMatrix.multiply( shadowCamera.matrixWorldInverse );
-/**
- * This code is a quick port of code written in C++ which was submitted to
- * flipcode.com by John W. Ratcliff // July 22, 2000
- * See original code and more information here:
- * http://www.flipcode.com/archives/Efficient_Polygon_Triangulation.shtml
- *
- * ported to actionscript by Zevan Rosser
- * www.actionsnippet.com
- *
- * ported to javascript by Joshua Koo
- * http://www.lab4games.net/zz85/blog
- *
- */
+ // update camera matrices and frustum
+ _projScreenMatrix.multiplyMatrices( shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse );
+ _frustum.setFromMatrix( _projScreenMatrix );
-( function ( namespace ) {
+ // render shadow map
- var EPSILON = 0.0000000001;
+ _renderer.setRenderTarget( shadowMap );
+ _renderer.clear();
- // takes in an contour array and returns
+ // set object matrices & frustum culling
- var process = function ( contour, indices ) {
+ _renderList.length = 0;
- var n = contour.length;
+ projectObject( scene, scene, shadowCamera );
- if ( n < 3 ) return null;
- var result = [],
- verts = [],
- vertIndices = [];
+ // render regular objects
- /* we want a counter-clockwise polygon in verts */
+ var objectMaterial, useMorphing, useSkinning;
- var u, v, w;
+ for ( j = 0, jl = _renderList.length; j < jl; j ++ ) {
- if ( area( contour ) > 0.0 ) {
+ webglObject = _renderList[ j ];
- for ( v = 0; v < n; v ++ ) verts[ v ] = v;
+ object = webglObject.object;
+ buffer = webglObject.buffer;
- } else {
+ // culling is overriden globally for all objects
+ // while rendering depth map
- for ( v = 0; v < n; v ++ ) verts[ v ] = ( n - 1 ) - v;
+ // need to deal with MeshFaceMaterial somehow
+ // in that case just use the first of material.materials for now
+ // (proper solution would require to break objects by materials
+ // similarly to regular rendering and then set corresponding
+ // depth materials per each chunk instead of just once per object)
- }
+ objectMaterial = getObjectMaterial( object );
- var nv = n;
+ useMorphing = object.geometry.morphTargets !== undefined && object.geometry.morphTargets.length > 0 && objectMaterial.morphTargets;
+ useSkinning = object instanceof THREE.SkinnedMesh && objectMaterial.skinning;
- /* remove nv - 2 vertices, creating 1 triangle every time */
+ if ( object.customDepthMaterial ) {
- var count = 2 * nv; /* error detection */
+ material = object.customDepthMaterial;
- for ( v = nv - 1; nv > 2; ) {
+ } else if ( useSkinning ) {
- /* if we loop, it is probably a non-simple polygon */
+ material = useMorphing ? _depthMaterialMorphSkin : _depthMaterialSkin;
- if ( ( count -- ) <= 0 ) {
+ } else if ( useMorphing ) {
- //** Triangulate: ERROR - probable bad polygon!
+ material = _depthMaterialMorph;
- //throw ( "Warning, unable to triangulate polygon!" );
- //return null;
- // Sometimes warning is fine, especially polygons are triangulated in reverse.
- console.log( 'Warning, unable to triangulate polygon!' );
+ } else {
- if ( indices ) return vertIndices;
- return result;
+ material = _depthMaterial;
- }
+ }
- /* three consecutive vertices in current polygon, */
+ _renderer.setMaterialFaces( objectMaterial );
- u = v; if ( nv <= u ) u = 0; /* previous */
- v = u + 1; if ( nv <= v ) v = 0; /* new v */
- w = v + 1; if ( nv <= w ) w = 0; /* next */
+ if ( buffer instanceof THREE.BufferGeometry ) {
- if ( snip( contour, u, v, w, nv, verts ) ) {
+ _renderer.renderBufferDirect( shadowCamera, _lights, fog, material, buffer, object );
- var a, b, c, s, t;
+ } else {
- /* true names of the vertices */
+ _renderer.renderBuffer( shadowCamera, _lights, fog, material, buffer, object );
- a = verts[ u ];
- b = verts[ v ];
- c = verts[ w ];
+ }
- /* output Triangle */
+ }
- result.push( [ contour[ a ],
- contour[ b ],
- contour[ c ] ] );
+ // set matrices and render immediate objects
+ for ( j = 0, jl = _webglObjectsImmediate.length; j < jl; j ++ ) {
- vertIndices.push( [ verts[ u ], verts[ v ], verts[ w ] ] );
+ webglObject = _webglObjectsImmediate[ j ];
+ object = webglObject.object;
- /* remove v from the remaining polygon */
+ if ( object.visible && object.castShadow ) {
- for ( s = v, t = v + 1; t < nv; s++, t++ ) {
+ object._modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld );
- verts[ s ] = verts[ t ];
+ _renderer.renderImmediateObject( shadowCamera, _lights, fog, _depthMaterial, object );
}
- nv --;
+ }
- /* reset error detection counter */
+ }
- count = 2 * nv;
+ // restore GL state
- }
+ var clearColor = _renderer.getClearColor(),
+ clearAlpha = _renderer.getClearAlpha();
+
+ _gl.clearColor( clearColor.r, clearColor.g, clearColor.b, clearAlpha );
+ _gl.enable( _gl.BLEND );
+
+ if ( _renderer.shadowMapCullFace === THREE.CullFaceFront ) {
+
+ _gl.cullFace( _gl.BACK );
}
- if ( indices ) return vertIndices;
- return result;
+ _renderer.resetGLState();
};
- // calculate area of the contour polygon
+ function projectObject( scene, object, shadowCamera ){
- var area = function ( contour ) {
+ if ( object.visible ) {
- var n = contour.length;
- var a = 0.0;
+ var webglObjects = _webglObjects[ object.id ];
- for ( var p = n - 1, q = 0; q < n; p = q ++ ) {
+ if ( webglObjects && object.castShadow && (object.frustumCulled === false || _frustum.intersectsObject( object ) === true) ) {
- a += contour[ p ].x * contour[ q ].y - contour[ q ].x * contour[ p ].y;
+ for ( var i = 0, l = webglObjects.length; i < l; i ++ ) {
- }
+ var webglObject = webglObjects[ i ];
- return a * 0.5;
+ object._modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld );
+ _renderList.push( webglObject );
- };
+ }
- var snip = function ( contour, u, v, w, n, verts ) {
+ }
- var p;
- var ax, ay, bx, by;
- var cx, cy, px, py;
+ for ( var i = 0, l = object.children.length; i < l; i ++ ) {
- ax = contour[ verts[ u ] ].x;
- ay = contour[ verts[ u ] ].y;
+ projectObject( scene, object.children[ i ], shadowCamera );
- bx = contour[ verts[ v ] ].x;
- by = contour[ verts[ v ] ].y;
+ }
- cx = contour[ verts[ w ] ].x;
- cy = contour[ verts[ w ] ].y;
+ }
- if ( EPSILON > ( ( ( bx - ax ) * ( cy - ay ) ) - ( ( by - ay ) * ( cx - ax ) ) ) ) return false;
+ }
- var aX, aY, bX, bY, cX, cY;
- var apx, apy, bpx, bpy, cpx, cpy;
- var cCROSSap, bCROSScp, aCROSSbp;
+ function createVirtualLight( light, cascade ) {
- aX = cx - bx; aY = cy - by;
- bX = ax - cx; bY = ay - cy;
- cX = bx - ax; cY = by - ay;
+ var virtualLight = new THREE.DirectionalLight();
- for ( p = 0; p < n; p ++ ) {
+ virtualLight.isVirtual = true;
- px = contour[ verts[ p ] ].x
- py = contour[ verts[ p ] ].y
+ virtualLight.onlyShadow = true;
+ virtualLight.castShadow = true;
- if ( ( ( px === ax ) && ( py === ay ) ) ||
- ( ( px === bx ) && ( py === by ) ) ||
- ( ( px === cx ) && ( py === cy ) ) ) continue;
+ virtualLight.shadowCameraNear = light.shadowCameraNear;
+ virtualLight.shadowCameraFar = light.shadowCameraFar;
- apx = px - ax; apy = py - ay;
- bpx = px - bx; bpy = py - by;
- cpx = px - cx; cpy = py - cy;
+ virtualLight.shadowCameraLeft = light.shadowCameraLeft;
+ virtualLight.shadowCameraRight = light.shadowCameraRight;
+ virtualLight.shadowCameraBottom = light.shadowCameraBottom;
+ virtualLight.shadowCameraTop = light.shadowCameraTop;
- // see if p is inside triangle abc
+ virtualLight.shadowCameraVisible = light.shadowCameraVisible;
- aCROSSbp = aX * bpy - aY * bpx;
- cCROSSap = cX * apy - cY * apx;
- bCROSScp = bX * cpy - bY * cpx;
+ virtualLight.shadowDarkness = light.shadowDarkness;
- if ( ( aCROSSbp >= - EPSILON ) && ( bCROSScp >= - EPSILON ) && ( cCROSSap >= - EPSILON ) ) return false;
+ virtualLight.shadowBias = light.shadowCascadeBias[ cascade ];
+ virtualLight.shadowMapWidth = light.shadowCascadeWidth[ cascade ];
+ virtualLight.shadowMapHeight = light.shadowCascadeHeight[ cascade ];
+
+ virtualLight.pointsWorld = [];
+ virtualLight.pointsFrustum = [];
+
+ var pointsWorld = virtualLight.pointsWorld,
+ pointsFrustum = virtualLight.pointsFrustum;
+
+ for ( var i = 0; i < 8; i ++ ) {
+
+ pointsWorld[ i ] = new THREE.Vector3();
+ pointsFrustum[ i ] = new THREE.Vector3();
}
- return true;
+ var nearZ = light.shadowCascadeNearZ[ cascade ];
+ var farZ = light.shadowCascadeFarZ[ cascade ];
- };
+ pointsFrustum[ 0 ].set( - 1, - 1, nearZ );
+ pointsFrustum[ 1 ].set( 1, - 1, nearZ );
+ pointsFrustum[ 2 ].set( - 1, 1, nearZ );
+ pointsFrustum[ 3 ].set( 1, 1, nearZ );
+ pointsFrustum[ 4 ].set( - 1, - 1, farZ );
+ pointsFrustum[ 5 ].set( 1, - 1, farZ );
+ pointsFrustum[ 6 ].set( - 1, 1, farZ );
+ pointsFrustum[ 7 ].set( 1, 1, farZ );
- namespace.Triangulate = process;
- namespace.Triangulate.area = area;
+ return virtualLight;
- return namespace;
+ }
-} )( THREE.FontUtils );
+ // Synchronize virtual light with the original light
-// To use the typeface.js face files, hook up the API
-self._typeface_js = { faces: THREE.FontUtils.faces, loadFace: THREE.FontUtils.loadFace };
-THREE.typeface_js = self._typeface_js;
+ function updateVirtualLight( light, cascade ) {
-// File:src/extras/core/Curve.js
+ var virtualLight = light.shadowCascadeArray[ cascade ];
-/**
- * @author zz85 / http://www.lab4games.net/zz85/blog
- * Extensible curve object
- *
- * Some common of Curve methods
- * .getPoint(t), getTangent(t)
- * .getPointAt(u), getTagentAt(u)
- * .getPoints(), .getSpacedPoints()
- * .getLength()
- * .updateArcLengths()
- *
- * This following classes subclasses THREE.Curve:
- *
- * -- 2d classes --
- * THREE.LineCurve
- * THREE.QuadraticBezierCurve
- * THREE.CubicBezierCurve
- * THREE.SplineCurve
- * THREE.ArcCurve
- * THREE.EllipseCurve
- *
- * -- 3d classes --
- * THREE.LineCurve3
- * THREE.QuadraticBezierCurve3
- * THREE.CubicBezierCurve3
- * THREE.SplineCurve3
- * THREE.ClosedSplineCurve3
- *
- * A series of curves can be represented as a THREE.CurvePath
- *
- **/
-
-/**************************************************************
- * Abstract Curve base class
- **************************************************************/
+ virtualLight.position.copy( light.position );
+ virtualLight.target.position.copy( light.target.position );
+ virtualLight.lookAt( virtualLight.target );
-THREE.Curve = function () {
+ virtualLight.shadowCameraVisible = light.shadowCameraVisible;
+ virtualLight.shadowDarkness = light.shadowDarkness;
-};
+ virtualLight.shadowBias = light.shadowCascadeBias[ cascade ];
-// Virtual base class method to overwrite and implement in subclasses
-// - t [0 .. 1]
+ var nearZ = light.shadowCascadeNearZ[ cascade ];
+ var farZ = light.shadowCascadeFarZ[ cascade ];
-THREE.Curve.prototype.getPoint = function ( t ) {
+ var pointsFrustum = virtualLight.pointsFrustum;
- console.log( "Warning, getPoint() not implemented!" );
- return null;
+ pointsFrustum[ 0 ].z = nearZ;
+ pointsFrustum[ 1 ].z = nearZ;
+ pointsFrustum[ 2 ].z = nearZ;
+ pointsFrustum[ 3 ].z = nearZ;
-};
+ pointsFrustum[ 4 ].z = farZ;
+ pointsFrustum[ 5 ].z = farZ;
+ pointsFrustum[ 6 ].z = farZ;
+ pointsFrustum[ 7 ].z = farZ;
-// Get point at relative position in curve according to arc length
-// - u [0 .. 1]
+ }
-THREE.Curve.prototype.getPointAt = function ( u ) {
+ // Fit shadow camera's ortho frustum to camera frustum
- var t = this.getUtoTmapping( u );
- return this.getPoint( t );
+ function updateShadowCamera( camera, light ) {
-};
+ var shadowCamera = light.shadowCamera,
+ pointsFrustum = light.pointsFrustum,
+ pointsWorld = light.pointsWorld;
-// Get sequence of points using getPoint( t )
+ _min.set( Infinity, Infinity, Infinity );
+ _max.set( - Infinity, - Infinity, - Infinity );
-THREE.Curve.prototype.getPoints = function ( divisions ) {
+ for ( var i = 0; i < 8; i ++ ) {
- if ( ! divisions ) divisions = 5;
+ var p = pointsWorld[ i ];
- var d, pts = [];
+ p.copy( pointsFrustum[ i ] );
+ p.unproject( camera );
- for ( d = 0; d <= divisions; d ++ ) {
+ p.applyMatrix4( shadowCamera.matrixWorldInverse );
- pts.push( this.getPoint( d / divisions ) );
+ if ( p.x < _min.x ) _min.x = p.x;
+ if ( p.x > _max.x ) _max.x = p.x;
- }
+ if ( p.y < _min.y ) _min.y = p.y;
+ if ( p.y > _max.y ) _max.y = p.y;
- return pts;
+ if ( p.z < _min.z ) _min.z = p.z;
+ if ( p.z > _max.z ) _max.z = p.z;
-};
+ }
-// Get sequence of points using getPointAt( u )
+ shadowCamera.left = _min.x;
+ shadowCamera.right = _max.x;
+ shadowCamera.top = _max.y;
+ shadowCamera.bottom = _min.y;
-THREE.Curve.prototype.getSpacedPoints = function ( divisions ) {
+ // can't really fit near/far
+ //shadowCamera.near = _min.z;
+ //shadowCamera.far = _max.z;
- if ( ! divisions ) divisions = 5;
+ shadowCamera.updateProjectionMatrix();
- var d, pts = [];
+ }
- for ( d = 0; d <= divisions; d ++ ) {
+ // For the moment just ignore objects that have multiple materials with different animation methods
+ // Only the first material will be taken into account for deciding which depth material to use for shadow maps
- pts.push( this.getPointAt( d / divisions ) );
+ function getObjectMaterial( object ) {
- }
+ return object.material instanceof THREE.MeshFaceMaterial
+ ? object.material.materials[ 0 ]
+ : object.material;
- return pts;
+ };
};
-// Get total curve arc length
+// File:src/renderers/webgl/plugins/SpritePlugin.js
-THREE.Curve.prototype.getLength = function () {
+/**
+ * @author mikael emtinger / http://gomo.se/
+ * @author alteredq / http://alteredqualia.com/
+ */
- var lengths = this.getLengths();
- return lengths[ lengths.length - 1 ];
+THREE.SpritePlugin = function ( renderer, sprites ) {
-};
+ var gl = renderer.context;
-// Get list of cumulative segment lengths
+ var vertexBuffer, elementBuffer;
+ var program, attributes, uniforms;
-THREE.Curve.prototype.getLengths = function ( divisions ) {
+ var texture;
+
+ var init = function () {
- if ( ! divisions ) divisions = (this.__arcLengthDivisions) ? (this.__arcLengthDivisions): 200;
+ var vertices = new Float32Array( [
+ - 0.5, - 0.5, 0, 0,
+ 0.5, - 0.5, 1, 0,
+ 0.5, 0.5, 1, 1,
+ - 0.5, 0.5, 0, 1
+ ] );
- if ( this.cacheArcLengths
- && ( this.cacheArcLengths.length == divisions + 1 )
- && ! this.needsUpdate) {
+ var faces = new Uint16Array( [
+ 0, 1, 2,
+ 0, 2, 3
+ ] );
- //console.log( "cached", this.cacheArcLengths );
- return this.cacheArcLengths;
+ vertexBuffer = gl.createBuffer();
+ elementBuffer = gl.createBuffer();
- }
+ gl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer );
+ gl.bufferData( gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW );
- this.needsUpdate = false;
+ gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer );
+ gl.bufferData( gl.ELEMENT_ARRAY_BUFFER, faces, gl.STATIC_DRAW );
- var cache = [];
- var current, last = this.getPoint( 0 );
- var p, sum = 0;
+ program = createProgram();
- cache.push( 0 );
+ attributes = {
+ position: gl.getAttribLocation ( program, 'position' ),
+ uv: gl.getAttribLocation ( program, 'uv' )
+ };
- for ( p = 1; p <= divisions; p ++ ) {
+ uniforms = {
+ uvOffset: gl.getUniformLocation( program, 'uvOffset' ),
+ uvScale: gl.getUniformLocation( program, 'uvScale' ),
- current = this.getPoint ( p / divisions );
- sum += current.distanceTo( last );
- cache.push( sum );
- last = current;
+ rotation: gl.getUniformLocation( program, 'rotation' ),
+ scale: gl.getUniformLocation( program, 'scale' ),
- }
+ color: gl.getUniformLocation( program, 'color' ),
+ map: gl.getUniformLocation( program, 'map' ),
+ opacity: gl.getUniformLocation( program, 'opacity' ),
- this.cacheArcLengths = cache;
+ modelViewMatrix: gl.getUniformLocation( program, 'modelViewMatrix' ),
+ projectionMatrix: gl.getUniformLocation( program, 'projectionMatrix' ),
- return cache; // { sums: cache, sum:sum }; Sum is in the last element.
+ fogType: gl.getUniformLocation( program, 'fogType' ),
+ fogDensity: gl.getUniformLocation( program, 'fogDensity' ),
+ fogNear: gl.getUniformLocation( program, 'fogNear' ),
+ fogFar: gl.getUniformLocation( program, 'fogFar' ),
+ fogColor: gl.getUniformLocation( program, 'fogColor' ),
-};
+ alphaTest: gl.getUniformLocation( program, 'alphaTest' )
+ };
+ var canvas = document.createElement( 'canvas' );
+ canvas.width = 8;
+ canvas.height = 8;
-THREE.Curve.prototype.updateArcLengths = function() {
- this.needsUpdate = true;
- this.getLengths();
-};
+ var context = canvas.getContext( '2d' );
+ context.fillStyle = 'white';
+ context.fillRect( 0, 0, 8, 8 );
-// Given u ( 0 .. 1 ), get a t to find p. This gives you points which are equi distance
+ texture = new THREE.Texture( canvas );
+ texture.needsUpdate = true;
-THREE.Curve.prototype.getUtoTmapping = function ( u, distance ) {
+ };
- var arcLengths = this.getLengths();
+ this.render = function ( scene, camera ) {
- var i = 0, il = arcLengths.length;
+ if ( sprites.length === 0 ) return;
- var targetArcLength; // The targeted u distance value to get
+ // setup gl
- if ( distance ) {
+ if ( program === undefined ) {
- targetArcLength = distance;
+ init();
- } else {
+ }
- targetArcLength = u * arcLengths[ il - 1 ];
+ gl.useProgram( program );
- }
+ gl.enableVertexAttribArray( attributes.position );
+ gl.enableVertexAttribArray( attributes.uv );
- //var time = Date.now();
+ gl.disable( gl.CULL_FACE );
+ gl.enable( gl.BLEND );
- // binary search for the index with largest value smaller than target u distance
+ gl.bindBuffer( gl.ARRAY_BUFFER, vertexBuffer );
+ gl.vertexAttribPointer( attributes.position, 2, gl.FLOAT, false, 2 * 8, 0 );
+ gl.vertexAttribPointer( attributes.uv, 2, gl.FLOAT, false, 2 * 8, 8 );
- var low = 0, high = il - 1, comparison;
+ gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, elementBuffer );
- while ( low <= high ) {
+ gl.uniformMatrix4fv( uniforms.projectionMatrix, false, camera.projectionMatrix.elements );
- i = Math.floor( low + ( high - low ) / 2 ); // less likely to overflow, though probably not issue here, JS doesn't really have integers, all numbers are floats
+ gl.activeTexture( gl.TEXTURE0 );
+ gl.uniform1i( uniforms.map, 0 );
- comparison = arcLengths[ i ] - targetArcLength;
+ var oldFogType = 0;
+ var sceneFogType = 0;
+ var fog = scene.fog;
- if ( comparison < 0 ) {
+ if ( fog ) {
- low = i + 1;
- continue;
+ gl.uniform3f( uniforms.fogColor, fog.color.r, fog.color.g, fog.color.b );
- } else if ( comparison > 0 ) {
+ if ( fog instanceof THREE.Fog ) {
- high = i - 1;
- continue;
+ gl.uniform1f( uniforms.fogNear, fog.near );
+ gl.uniform1f( uniforms.fogFar, fog.far );
- } else {
+ gl.uniform1i( uniforms.fogType, 1 );
+ oldFogType = 1;
+ sceneFogType = 1;
- high = i;
- break;
+ } else if ( fog instanceof THREE.FogExp2 ) {
- // DONE
+ gl.uniform1f( uniforms.fogDensity, fog.density );
- }
+ gl.uniform1i( uniforms.fogType, 2 );
+ oldFogType = 2;
+ sceneFogType = 2;
- }
+ }
- i = high;
+ } else {
- //console.log('b' , i, low, high, Date.now()- time);
+ gl.uniform1i( uniforms.fogType, 0 );
+ oldFogType = 0;
+ sceneFogType = 0;
- if ( arcLengths[ i ] == targetArcLength ) {
+ }
- var t = i / ( il - 1 );
- return t;
- }
+ // update positions and sort
- // we could get finer grain at lengths, or use simple interpolatation between two points
+ for ( var i = 0, l = sprites.length; i < l; i ++ ) {
- var lengthBefore = arcLengths[ i ];
- var lengthAfter = arcLengths[ i + 1 ];
+ var sprite = sprites[ i ];
- var segmentLength = lengthAfter - lengthBefore;
+ sprite._modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, sprite.matrixWorld );
- // determine where we are between the 'before' and 'after' points
+ if ( sprite.renderDepth === null ) {
- var segmentFraction = ( targetArcLength - lengthBefore ) / segmentLength;
+ sprite.z = - sprite._modelViewMatrix.elements[ 14 ];
- // add that fractional amount to t
+ } else {
- var t = ( i + segmentFraction ) / ( il -1 );
+ sprite.z = sprite.renderDepth;
- return t;
+ }
-};
+ }
-// Returns a unit vector tangent at t
-// In case any sub curve does not implement its tangent derivation,
-// 2 points a small delta apart will be used to find its gradient
-// which seems to give a reasonable approximation
+ sprites.sort( painterSortStable );
-THREE.Curve.prototype.getTangent = function( t ) {
+ // render all sprites
- var delta = 0.0001;
- var t1 = t - delta;
- var t2 = t + delta;
+ var scale = [];
- // Capping in case of danger
+ for ( var i = 0, l = sprites.length; i < l; i ++ ) {
- if ( t1 < 0 ) t1 = 0;
- if ( t2 > 1 ) t2 = 1;
-
- var pt1 = this.getPoint( t1 );
- var pt2 = this.getPoint( t2 );
+ var sprite = sprites[ i ];
+ var material = sprite.material;
- var vec = pt2.clone().sub(pt1);
- return vec.normalize();
+ gl.uniform1f( uniforms.alphaTest, material.alphaTest );
+ gl.uniformMatrix4fv( uniforms.modelViewMatrix, false, sprite._modelViewMatrix.elements );
-};
+ scale[ 0 ] = sprite.scale.x;
+ scale[ 1 ] = sprite.scale.y;
+ var fogType = 0;
-THREE.Curve.prototype.getTangentAt = function ( u ) {
+ if ( scene.fog && material.fog ) {
- var t = this.getUtoTmapping( u );
- return this.getTangent( t );
+ fogType = sceneFogType;
-};
+ }
+ if ( oldFogType !== fogType ) {
+ gl.uniform1i( uniforms.fogType, fogType );
+ oldFogType = fogType;
+ }
+ if ( material.map !== null ) {
-/**************************************************************
- * Utils
- **************************************************************/
+ gl.uniform2f( uniforms.uvOffset, material.map.offset.x, material.map.offset.y );
+ gl.uniform2f( uniforms.uvScale, material.map.repeat.x, material.map.repeat.y );
-THREE.Curve.Utils = {
+ } else {
- tangentQuadraticBezier: function ( t, p0, p1, p2 ) {
+ gl.uniform2f( uniforms.uvOffset, 0, 0 );
+ gl.uniform2f( uniforms.uvScale, 1, 1 );
- return 2 * ( 1 - t ) * ( p1 - p0 ) + 2 * t * ( p2 - p1 );
+ }
- },
+ gl.uniform1f( uniforms.opacity, material.opacity );
+ gl.uniform3f( uniforms.color, material.color.r, material.color.g, material.color.b );
- // Puay Bing, thanks for helping with this derivative!
+ gl.uniform1f( uniforms.rotation, material.rotation );
+ gl.uniform2fv( uniforms.scale, scale );
- tangentCubicBezier: function (t, p0, p1, p2, p3 ) {
+ renderer.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst );
+ renderer.setDepthTest( material.depthTest );
+ renderer.setDepthWrite( material.depthWrite );
- return - 3 * p0 * (1 - t) * (1 - t) +
- 3 * p1 * (1 - t) * (1-t) - 6 *t *p1 * (1-t) +
- 6 * t * p2 * (1-t) - 3 * t * t * p2 +
- 3 * t * t * p3;
- },
+ if ( material.map && material.map.image && material.map.image.width ) {
+ renderer.setTexture( material.map, 0 );
- tangentSpline: function ( t, p0, p1, p2, p3 ) {
+ } else {
- // To check if my formulas are correct
+ renderer.setTexture( texture, 0 );
- var h00 = 6 * t * t - 6 * t; // derived from 2t^3 − 3t^2 + 1
- var h10 = 3 * t * t - 4 * t + 1; // t^3 − 2t^2 + t
- var h01 = - 6 * t * t + 6 * t; // − 2t3 + 3t2
- var h11 = 3 * t * t - 2 * t; // t3 − t2
+ }
- return h00 + h10 + h01 + h11;
+ gl.drawElements( gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0 );
- },
+ }
- // Catmull-Rom
+ // restore gl
- interpolate: function( p0, p1, p2, p3, t ) {
+ gl.enable( gl.CULL_FACE );
+
+ renderer.resetGLState();
- var v0 = ( p2 - p0 ) * 0.5;
- var v1 = ( p3 - p1 ) * 0.5;
- var t2 = t * t;
- var t3 = t * t2;
- return ( 2 * p1 - 2 * p2 + v0 + v1 ) * t3 + ( - 3 * p1 + 3 * p2 - 2 * v0 - v1 ) * t2 + v0 * t + p1;
+ };
- }
+ function createProgram () {
-};
+ var program = gl.createProgram();
+ var vertexShader = gl.createShader( gl.VERTEX_SHADER );
+ var fragmentShader = gl.createShader( gl.FRAGMENT_SHADER );
-// TODO: Transformation for Curves?
+ gl.shaderSource( vertexShader, [
-/**************************************************************
- * 3D Curves
- **************************************************************/
+ 'precision ' + renderer.getPrecision() + ' float;',
-// A Factory method for creating new curve subclasses
+ 'uniform mat4 modelViewMatrix;',
+ 'uniform mat4 projectionMatrix;',
+ 'uniform float rotation;',
+ 'uniform vec2 scale;',
+ 'uniform vec2 uvOffset;',
+ 'uniform vec2 uvScale;',
-THREE.Curve.create = function ( constructor, getPointFunc ) {
+ 'attribute vec2 position;',
+ 'attribute vec2 uv;',
- constructor.prototype = Object.create( THREE.Curve.prototype );
- constructor.prototype.getPoint = getPointFunc;
+ 'varying vec2 vUV;',
- return constructor;
+ 'void main() {',
-};
+ 'vUV = uvOffset + uv * uvScale;',
-// File:src/extras/core/CurvePath.js
+ 'vec2 alignedPosition = position * scale;',
-/**
- * @author zz85 / http://www.lab4games.net/zz85/blog
- *
- **/
+ 'vec2 rotatedPosition;',
+ 'rotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;',
+ 'rotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;',
-/**************************************************************
- * Curved Path - a curve path is simply a array of connected
- * curves, but retains the api of a curve
- **************************************************************/
+ 'vec4 finalPosition;',
-THREE.CurvePath = function () {
+ 'finalPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );',
+ 'finalPosition.xy += rotatedPosition;',
+ 'finalPosition = projectionMatrix * finalPosition;',
- this.curves = [];
- this.bends = [];
-
- this.autoClose = false; // Automatically closes the path
-};
+ 'gl_Position = finalPosition;',
-THREE.CurvePath.prototype = Object.create( THREE.Curve.prototype );
+ '}'
-THREE.CurvePath.prototype.add = function ( curve ) {
+ ].join( '\n' ) );
- this.curves.push( curve );
+ gl.shaderSource( fragmentShader, [
-};
+ 'precision ' + renderer.getPrecision() + ' float;',
-THREE.CurvePath.prototype.checkConnection = function() {
- // TODO
- // If the ending of curve is not connected to the starting
- // or the next curve, then, this is not a real path
-};
+ 'uniform vec3 color;',
+ 'uniform sampler2D map;',
+ 'uniform float opacity;',
-THREE.CurvePath.prototype.closePath = function() {
- // TODO Test
- // and verify for vector3 (needs to implement equals)
- // Add a line curve if start and end of lines are not connected
- var startPoint = this.curves[0].getPoint(0);
- var endPoint = this.curves[this.curves.length-1].getPoint(1);
-
- if (! startPoint.equals(endPoint)) {
- this.curves.push( new THREE.LineCurve(endPoint, startPoint) );
- }
-
-};
+ 'uniform int fogType;',
+ 'uniform vec3 fogColor;',
+ 'uniform float fogDensity;',
+ 'uniform float fogNear;',
+ 'uniform float fogFar;',
+ 'uniform float alphaTest;',
-// To get accurate point with reference to
-// entire path distance at time t,
-// following has to be done:
+ 'varying vec2 vUV;',
-// 1. Length of each sub path have to be known
-// 2. Locate and identify type of curve
-// 3. Get t for the curve
-// 4. Return curve.getPointAt(t')
+ 'void main() {',
-THREE.CurvePath.prototype.getPoint = function( t ) {
+ 'vec4 texture = texture2D( map, vUV );',
- var d = t * this.getLength();
- var curveLengths = this.getCurveLengths();
- var i = 0, diff, curve;
+ 'if ( texture.a < alphaTest ) discard;',
- // To think about boundaries points.
+ 'gl_FragColor = vec4( color * texture.xyz, texture.a * opacity );',
- while ( i < curveLengths.length ) {
+ 'if ( fogType > 0 ) {',
- if ( curveLengths[ i ] >= d ) {
+ 'float depth = gl_FragCoord.z / gl_FragCoord.w;',
+ 'float fogFactor = 0.0;',
- diff = curveLengths[ i ] - d;
- curve = this.curves[ i ];
+ 'if ( fogType == 1 ) {',
- var u = 1 - diff / curve.getLength();
+ 'fogFactor = smoothstep( fogNear, fogFar, depth );',
- return curve.getPointAt( u );
+ '} else {',
- break;
- }
+ 'const float LOG2 = 1.442695;',
+ 'float fogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );',
+ 'fogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );',
- i ++;
+ '}',
- }
+ 'gl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );',
- return null;
+ '}',
- // loop where sum != 0, sum > d , sum+1 maxX ) maxX = p.x;
- else if ( p.x < minX ) minX = p.x;
+/**
+ * @author alteredq / http://alteredqualia.com/
+ * @author mrdoob / http://mrdoob.com/
+ * @author Daosheng Mu / https://github.com/DaoshengMu/
+ */
- if ( p.y > maxY ) maxY = p.y;
- else if ( p.y < minY ) minY = p.y;
+THREE.ImageUtils = {
- if ( v3 ) {
+ crossOrigin: undefined,
- if ( p.z > maxZ ) maxZ = p.z;
- else if ( p.z < minZ ) minZ = p.z;
+ loadTexture: function ( url, mapping, onLoad, onError ) {
- }
+ var loader = new THREE.ImageLoader();
+ loader.crossOrigin = this.crossOrigin;
- sum.add( p );
+ var texture = new THREE.Texture( undefined, mapping );
- }
+ loader.load( url, function ( image ) {
- var ret = {
+ texture.image = image;
+ texture.needsUpdate = true;
- minX: minX,
- minY: minY,
- maxX: maxX,
- maxY: maxY
+ if ( onLoad ) onLoad( texture );
- };
+ }, undefined, function ( event ) {
- if ( v3 ) {
+ if ( onError ) onError( event );
- ret.maxZ = maxZ;
- ret.minZ = minZ;
+ } );
- }
+ texture.sourceFile = url;
- return ret;
+ return texture;
-};
+ },
-/**************************************************************
- * Create Geometries Helpers
- **************************************************************/
+ loadTextureCube: function ( array, mapping, onLoad, onError ) {
-/// Generate geometry from path points (for Line or Points objects)
+ var images = [];
-THREE.CurvePath.prototype.createPointsGeometry = function( divisions ) {
+ var loader = new THREE.ImageLoader();
+ loader.crossOrigin = this.crossOrigin;
- var pts = this.getPoints( divisions, true );
- return this.createGeometry( pts );
+ var texture = new THREE.CubeTexture( images, mapping );
-};
+ // no flipping needed for cube textures
-// Generate geometry from equidistance sampling along the path
+ texture.flipY = false;
-THREE.CurvePath.prototype.createSpacedPointsGeometry = function( divisions ) {
+ var loaded = 0;
- var pts = this.getSpacedPoints( divisions, true );
- return this.createGeometry( pts );
+ var loadTexture = function ( i ) {
-};
+ loader.load( array[ i ], function ( image ) {
-THREE.CurvePath.prototype.createGeometry = function( points ) {
+ texture.images[ i ] = image;
- var geometry = new THREE.Geometry();
+ loaded += 1;
- for ( var i = 0; i < points.length; i ++ ) {
+ if ( loaded === 6 ) {
- geometry.vertices.push( new THREE.Vector3( points[ i ].x, points[ i ].y, points[ i ].z || 0) );
+ texture.needsUpdate = true;
- }
+ if ( onLoad ) onLoad( texture );
- return geometry;
+ }
-};
+ } );
+ }
-/**************************************************************
- * Bend / Wrap Helper Methods
- **************************************************************/
+ for ( var i = 0, il = array.length; i < il; ++ i ) {
-// Wrap path / Bend modifiers?
+ loadTexture( i );
-THREE.CurvePath.prototype.addWrapPath = function ( bendpath ) {
+ }
- this.bends.push( bendpath );
+ return texture;
-};
+ },
-THREE.CurvePath.prototype.getTransformedPoints = function( segments, bends ) {
+ loadCompressedTexture: function () {
- var oldPts = this.getPoints( segments ); // getPoints getSpacedPoints
- var i, il;
+ console.error( 'THREE.ImageUtils.loadCompressedTexture has been removed. Use THREE.DDSLoader instead.' )
- if ( ! bends ) {
+ },
- bends = this.bends;
+ loadCompressedTextureCube: function () {
- }
+ console.error( 'THREE.ImageUtils.loadCompressedTextureCube has been removed. Use THREE.DDSLoader instead.' )
- for ( i = 0, il = bends.length; i < il; i ++ ) {
+ },
- oldPts = this.getWrapPoints( oldPts, bends[ i ] );
+ getNormalMap: function ( image, depth ) {
- }
+ // Adapted from http://www.paulbrunt.co.uk/lab/heightnormal/
- return oldPts;
+ var cross = function ( a, b ) {
-};
+ return [ a[ 1 ] * b[ 2 ] - a[ 2 ] * b[ 1 ], a[ 2 ] * b[ 0 ] - a[ 0 ] * b[ 2 ], a[ 0 ] * b[ 1 ] - a[ 1 ] * b[ 0 ] ];
-THREE.CurvePath.prototype.getTransformedSpacedPoints = function( segments, bends ) {
+ }
- var oldPts = this.getSpacedPoints( segments );
+ var subtract = function ( a, b ) {
- var i, il;
+ return [ a[ 0 ] - b[ 0 ], a[ 1 ] - b[ 1 ], a[ 2 ] - b[ 2 ] ];
- if ( ! bends ) {
+ }
- bends = this.bends;
+ var normalize = function ( a ) {
- }
+ var l = Math.sqrt( a[ 0 ] * a[ 0 ] + a[ 1 ] * a[ 1 ] + a[ 2 ] * a[ 2 ] );
+ return [ a[ 0 ] / l, a[ 1 ] / l, a[ 2 ] / l ];
- for ( i = 0, il = bends.length; i < il; i ++ ) {
+ }
- oldPts = this.getWrapPoints( oldPts, bends[ i ] );
+ depth = depth | 1;
- }
+ var width = image.width;
+ var height = image.height;
- return oldPts;
+ var canvas = document.createElement( 'canvas' );
+ canvas.width = width;
+ canvas.height = height;
-};
+ var context = canvas.getContext( '2d' );
+ context.drawImage( image, 0, 0 );
-// This returns getPoints() bend/wrapped around the contour of a path.
-// Read http://www.planetclegg.com/projects/WarpingTextToSplines.html
+ var data = context.getImageData( 0, 0, width, height ).data;
+ var imageData = context.createImageData( width, height );
+ var output = imageData.data;
-THREE.CurvePath.prototype.getWrapPoints = function ( oldPts, path ) {
+ for ( var x = 0; x < width; x ++ ) {
- var bounds = this.getBoundingBox();
+ for ( var y = 0; y < height; y ++ ) {
- var i, il, p, oldX, oldY, xNorm;
+ var ly = y - 1 < 0 ? 0 : y - 1;
+ var uy = y + 1 > height - 1 ? height - 1 : y + 1;
+ var lx = x - 1 < 0 ? 0 : x - 1;
+ var ux = x + 1 > width - 1 ? width - 1 : x + 1;
- for ( i = 0, il = oldPts.length; i < il; i ++ ) {
+ var points = [];
+ var origin = [ 0, 0, data[ ( y * width + x ) * 4 ] / 255 * depth ];
+ points.push( [ - 1, 0, data[ ( y * width + lx ) * 4 ] / 255 * depth ] );
+ points.push( [ - 1, - 1, data[ ( ly * width + lx ) * 4 ] / 255 * depth ] );
+ points.push( [ 0, - 1, data[ ( ly * width + x ) * 4 ] / 255 * depth ] );
+ points.push( [ 1, - 1, data[ ( ly * width + ux ) * 4 ] / 255 * depth ] );
+ points.push( [ 1, 0, data[ ( y * width + ux ) * 4 ] / 255 * depth ] );
+ points.push( [ 1, 1, data[ ( uy * width + ux ) * 4 ] / 255 * depth ] );
+ points.push( [ 0, 1, data[ ( uy * width + x ) * 4 ] / 255 * depth ] );
+ points.push( [ - 1, 1, data[ ( uy * width + lx ) * 4 ] / 255 * depth ] );
- p = oldPts[ i ];
+ var normals = [];
+ var num_points = points.length;
- oldX = p.x;
- oldY = p.y;
+ for ( var i = 0; i < num_points; i ++ ) {
- xNorm = oldX / bounds.maxX;
+ var v1 = points[ i ];
+ var v2 = points[ ( i + 1 ) % num_points ];
+ v1 = subtract( v1, origin );
+ v2 = subtract( v2, origin );
+ normals.push( normalize( cross( v1, v2 ) ) );
- // If using actual distance, for length > path, requires line extrusions
- //xNorm = path.getUtoTmapping(xNorm, oldX); // 3 styles. 1) wrap stretched. 2) wrap stretch by arc length 3) warp by actual distance
+ }
- xNorm = path.getUtoTmapping( xNorm, oldX );
+ var normal = [ 0, 0, 0 ];
- // check for out of bounds?
+ for ( var i = 0; i < normals.length; i ++ ) {
- var pathPt = path.getPoint( xNorm );
- var normal = path.getTangent( xNorm );
- normal.set( - normal.y, normal.x ).multiplyScalar( oldY );
+ normal[ 0 ] += normals[ i ][ 0 ];
+ normal[ 1 ] += normals[ i ][ 1 ];
+ normal[ 2 ] += normals[ i ][ 2 ];
- p.x = pathPt.x + normal.x;
- p.y = pathPt.y + normal.y;
+ }
- }
+ normal[ 0 ] /= normals.length;
+ normal[ 1 ] /= normals.length;
+ normal[ 2 ] /= normals.length;
- return oldPts;
+ var idx = ( y * width + x ) * 4;
-};
+ output[ idx ] = ( ( normal[ 0 ] + 1.0 ) / 2.0 * 255 ) | 0;
+ output[ idx + 1 ] = ( ( normal[ 1 ] + 1.0 ) / 2.0 * 255 ) | 0;
+ output[ idx + 2 ] = ( normal[ 2 ] * 255 ) | 0;
+ output[ idx + 3 ] = 255;
+ }
-// File:src/extras/core/Gyroscope.js
+ }
-/**
- * @author alteredq / http://alteredqualia.com/
- */
-
-THREE.Gyroscope = function () {
-
- THREE.Object3D.call( this );
-
-};
-
-THREE.Gyroscope.prototype = Object.create( THREE.Object3D.prototype );
-
-THREE.Gyroscope.prototype.updateMatrixWorld = function ( force ) {
-
- this.matrixAutoUpdate && this.updateMatrix();
-
- // update matrixWorld
-
- if ( this.matrixWorldNeedsUpdate || force ) {
-
- if ( this.parent ) {
-
- this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix );
-
- this.matrixWorld.decompose( this.translationWorld, this.quaternionWorld, this.scaleWorld );
- this.matrix.decompose( this.translationObject, this.quaternionObject, this.scaleObject );
-
- this.matrixWorld.compose( this.translationWorld, this.quaternionObject, this.scaleWorld );
-
-
- } else {
-
- this.matrixWorld.copy( this.matrix );
-
- }
-
-
- this.matrixWorldNeedsUpdate = false;
-
- force = true;
-
- }
-
- // update children
-
- for ( var i = 0, l = this.children.length; i < l; i ++ ) {
-
- this.children[ i ].updateMatrixWorld( force );
-
- }
-
-};
-
-THREE.Gyroscope.prototype.translationWorld = new THREE.Vector3();
-THREE.Gyroscope.prototype.translationObject = new THREE.Vector3();
-THREE.Gyroscope.prototype.quaternionWorld = new THREE.Quaternion();
-THREE.Gyroscope.prototype.quaternionObject = new THREE.Quaternion();
-THREE.Gyroscope.prototype.scaleWorld = new THREE.Vector3();
-THREE.Gyroscope.prototype.scaleObject = new THREE.Vector3();
-
+ context.putImageData( imageData, 0, 0 );
-// File:src/extras/core/Path.js
+ return canvas;
-/**
- * @author zz85 / http://www.lab4games.net/zz85/blog
- * Creates free form 2d path using series of points, lines or curves.
- *
- **/
+ },
-THREE.Path = function ( points ) {
+ generateDataTexture: function ( width, height, color ) {
- THREE.CurvePath.call(this);
+ var size = width * height;
+ var data = new Uint8Array( 3 * size );
- this.actions = [];
+ var r = Math.floor( color.r * 255 );
+ var g = Math.floor( color.g * 255 );
+ var b = Math.floor( color.b * 255 );
- if ( points ) {
+ for ( var i = 0; i < size; i ++ ) {
- this.fromPoints( points );
+ data[ i * 3 ] = r;
+ data[ i * 3 + 1 ] = g;
+ data[ i * 3 + 2 ] = b;
- }
+ }
-};
+ var texture = new THREE.DataTexture( data, width, height, THREE.RGBFormat );
+ texture.needsUpdate = true;
-THREE.Path.prototype = Object.create( THREE.CurvePath.prototype );
+ return texture;
-THREE.PathActions = {
+ }
- MOVE_TO: 'moveTo',
- LINE_TO: 'lineTo',
- QUADRATIC_CURVE_TO: 'quadraticCurveTo', // Bezier quadratic curve
- BEZIER_CURVE_TO: 'bezierCurveTo', // Bezier cubic curve
- CSPLINE_THRU: 'splineThru', // Catmull-rom spline
- ARC: 'arc', // Circle
- ELLIPSE: 'ellipse'
};
-// TODO Clean up PATH API
+// File:src/extras/SceneUtils.js
-// Create path using straight lines to connect all points
-// - vectors: array of Vector2
+/**
+ * @author alteredq / http://alteredqualia.com/
+ */
-THREE.Path.prototype.fromPoints = function ( vectors ) {
-
- this.moveTo( vectors[ 0 ].x, vectors[ 0 ].y );
+THREE.SceneUtils = {
- for ( var v = 1, vlen = vectors.length; v < vlen; v ++ ) {
+ createMultiMaterialObject: function ( geometry, materials ) {
- this.lineTo( vectors[ v ].x, vectors[ v ].y );
+ var group = new THREE.Object3D();
- };
+ for ( var i = 0, l = materials.length; i < l; i ++ ) {
-};
+ group.add( new THREE.Mesh( geometry, materials[ i ] ) );
-// startPath() endPath()?
+ }
-THREE.Path.prototype.moveTo = function ( x, y ) {
+ return group;
- var args = Array.prototype.slice.call( arguments );
- this.actions.push( { action: THREE.PathActions.MOVE_TO, args: args } );
+ },
-};
+ detach: function ( child, parent, scene ) {
-THREE.Path.prototype.lineTo = function ( x, y ) {
+ child.applyMatrix( parent.matrixWorld );
+ parent.remove( child );
+ scene.add( child );
- var args = Array.prototype.slice.call( arguments );
+ },
- var lastargs = this.actions[ this.actions.length - 1 ].args;
+ attach: function ( child, scene, parent ) {
- var x0 = lastargs[ lastargs.length - 2 ];
- var y0 = lastargs[ lastargs.length - 1 ];
+ var matrixWorldInverse = new THREE.Matrix4();
+ matrixWorldInverse.getInverse( parent.matrixWorld );
+ child.applyMatrix( matrixWorldInverse );
- var curve = new THREE.LineCurve( new THREE.Vector2( x0, y0 ), new THREE.Vector2( x, y ) );
- this.curves.push( curve );
+ scene.remove( child );
+ parent.add( child );
- this.actions.push( { action: THREE.PathActions.LINE_TO, args: args } );
+ }
};
-THREE.Path.prototype.quadraticCurveTo = function( aCPx, aCPy, aX, aY ) {
+// File:src/extras/FontUtils.js
- var args = Array.prototype.slice.call( arguments );
+/**
+ * @author zz85 / http://www.lab4games.net/zz85/blog
+ * @author alteredq / http://alteredqualia.com/
+ *
+ * For Text operations in three.js (See TextGeometry)
+ *
+ * It uses techniques used in:
+ *
+ * typeface.js and canvastext
+ * For converting fonts and rendering with javascript
+ * http://typeface.neocracy.org
+ *
+ * Triangulation ported from AS3
+ * Simple Polygon Triangulation
+ * http://actionsnippet.com/?p=1462
+ *
+ * A Method to triangulate shapes with holes
+ * http://www.sakri.net/blog/2009/06/12/an-approach-to-triangulating-polygons-with-holes/
+ *
+ */
- var lastargs = this.actions[ this.actions.length - 1 ].args;
+THREE.FontUtils = {
- var x0 = lastargs[ lastargs.length - 2 ];
- var y0 = lastargs[ lastargs.length - 1 ];
+ faces: {},
- var curve = new THREE.QuadraticBezierCurve( new THREE.Vector2( x0, y0 ),
- new THREE.Vector2( aCPx, aCPy ),
- new THREE.Vector2( aX, aY ) );
- this.curves.push( curve );
+ // Just for now. face[weight][style]
- this.actions.push( { action: THREE.PathActions.QUADRATIC_CURVE_TO, args: args } );
+ face: 'helvetiker',
+ weight: 'normal',
+ style: 'normal',
+ size: 150,
+ divisions: 10,
-};
+ getFace: function () {
-THREE.Path.prototype.bezierCurveTo = function( aCP1x, aCP1y,
- aCP2x, aCP2y,
- aX, aY ) {
+ try {
- var args = Array.prototype.slice.call( arguments );
+ return this.faces[ this.face ][ this.weight ][ this.style ];
- var lastargs = this.actions[ this.actions.length - 1 ].args;
+ } catch (e) {
- var x0 = lastargs[ lastargs.length - 2 ];
- var y0 = lastargs[ lastargs.length - 1 ];
+ throw "The font " + this.face + " with " + this.weight + " weight and " + this.style + " style is missing."
- var curve = new THREE.CubicBezierCurve( new THREE.Vector2( x0, y0 ),
- new THREE.Vector2( aCP1x, aCP1y ),
- new THREE.Vector2( aCP2x, aCP2y ),
- new THREE.Vector2( aX, aY ) );
- this.curves.push( curve );
+ };
- this.actions.push( { action: THREE.PathActions.BEZIER_CURVE_TO, args: args } );
+ },
-};
+ loadFace: function ( data ) {
-THREE.Path.prototype.splineThru = function( pts /*Array of Vector*/ ) {
+ var family = data.familyName.toLowerCase();
- var args = Array.prototype.slice.call( arguments );
- var lastargs = this.actions[ this.actions.length - 1 ].args;
+ var ThreeFont = this;
- var x0 = lastargs[ lastargs.length - 2 ];
- var y0 = lastargs[ lastargs.length - 1 ];
-//---
- var npts = [ new THREE.Vector2( x0, y0 ) ];
- Array.prototype.push.apply( npts, pts );
+ ThreeFont.faces[ family ] = ThreeFont.faces[ family ] || {};
- var curve = new THREE.SplineCurve( npts );
- this.curves.push( curve );
+ ThreeFont.faces[ family ][ data.cssFontWeight ] = ThreeFont.faces[ family ][ data.cssFontWeight ] || {};
+ ThreeFont.faces[ family ][ data.cssFontWeight ][ data.cssFontStyle ] = data;
- this.actions.push( { action: THREE.PathActions.CSPLINE_THRU, args: args } );
+ var face = ThreeFont.faces[ family ][ data.cssFontWeight ][ data.cssFontStyle ] = data;
-};
+ return data;
-// FUTURE: Change the API or follow canvas API?
+ },
-THREE.Path.prototype.arc = function ( aX, aY, aRadius,
- aStartAngle, aEndAngle, aClockwise ) {
+ drawText: function ( text ) {
- var lastargs = this.actions[ this.actions.length - 1].args;
- var x0 = lastargs[ lastargs.length - 2 ];
- var y0 = lastargs[ lastargs.length - 1 ];
+ var characterPts = [], allPts = [];
- this.absarc(aX + x0, aY + y0, aRadius,
- aStartAngle, aEndAngle, aClockwise );
+ // RenderText
- };
+ var i, p,
+ face = this.getFace(),
+ scale = this.size / face.resolution,
+ offset = 0,
+ chars = String( text ).split( '' ),
+ length = chars.length;
- THREE.Path.prototype.absarc = function ( aX, aY, aRadius,
- aStartAngle, aEndAngle, aClockwise ) {
- this.absellipse(aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise);
- };
+ var fontPaths = [];
-THREE.Path.prototype.ellipse = function ( aX, aY, xRadius, yRadius,
- aStartAngle, aEndAngle, aClockwise ) {
+ for ( i = 0; i < length; i ++ ) {
- var lastargs = this.actions[ this.actions.length - 1].args;
- var x0 = lastargs[ lastargs.length - 2 ];
- var y0 = lastargs[ lastargs.length - 1 ];
+ var path = new THREE.Path();
- this.absellipse(aX + x0, aY + y0, xRadius, yRadius,
- aStartAngle, aEndAngle, aClockwise );
+ var ret = this.extractGlyphPoints( chars[ i ], face, scale, offset, path );
+ offset += ret.offset;
- };
+ fontPaths.push( ret.path );
+ }
-THREE.Path.prototype.absellipse = function ( aX, aY, xRadius, yRadius,
- aStartAngle, aEndAngle, aClockwise ) {
+ // get the width
- var args = Array.prototype.slice.call( arguments );
- var curve = new THREE.EllipseCurve( aX, aY, xRadius, yRadius,
- aStartAngle, aEndAngle, aClockwise );
- this.curves.push( curve );
+ var width = offset / 2;
+ //
+ // for ( p = 0; p < allPts.length; p++ ) {
+ //
+ // allPts[ p ].x -= width;
+ //
+ // }
- var lastPoint = curve.getPoint(1);
- args.push(lastPoint.x);
- args.push(lastPoint.y);
+ //var extract = this.extractPoints( allPts, characterPts );
+ //extract.contour = allPts;
- this.actions.push( { action: THREE.PathActions.ELLIPSE, args: args } );
+ //extract.paths = fontPaths;
+ //extract.offset = width;
- };
+ return { paths: fontPaths, offset: width };
-THREE.Path.prototype.getSpacedPoints = function ( divisions, closedPath ) {
+ },
- if ( ! divisions ) divisions = 40;
- var points = [];
- for ( var i = 0; i < divisions; i ++ ) {
- points.push( this.getPoint( i / divisions ) );
+ extractGlyphPoints: function ( c, face, scale, offset, path ) {
- //if( !this.getPoint( i / divisions ) ) throw "DIE";
+ var pts = [];
- }
+ var i, i2, divisions,
+ outline, action, length,
+ scaleX, scaleY,
+ x, y, cpx, cpy, cpx0, cpy0, cpx1, cpy1, cpx2, cpy2,
+ laste,
+ glyph = face.glyphs[ c ] || face.glyphs[ '?' ];
- // if ( closedPath ) {
- //
- // points.push( points[ 0 ] );
- //
- // }
+ if ( ! glyph ) return;
- return points;
+ if ( glyph.o ) {
-};
+ outline = glyph._cachedOutline || ( glyph._cachedOutline = glyph.o.split( ' ' ) );
+ length = outline.length;
-/* Return an array of vectors based on contour of the path */
+ scaleX = scale;
+ scaleY = scale;
-THREE.Path.prototype.getPoints = function( divisions, closedPath ) {
+ for ( i = 0; i < length; ) {
- if (this.useSpacedPoints) {
- console.log('tata');
- return this.getSpacedPoints( divisions, closedPath );
- }
+ action = outline[ i ++ ];
- divisions = divisions || 12;
+ //console.log( action );
- var points = [];
+ switch ( action ) {
- var i, il, item, action, args;
- var cpx, cpy, cpx2, cpy2, cpx1, cpy1, cpx0, cpy0,
- laste, j,
- t, tx, ty;
+ case 'm':
- for ( i = 0, il = this.actions.length; i < il; i ++ ) {
+ // Move To
- item = this.actions[ i ];
+ x = outline[ i ++ ] * scaleX + offset;
+ y = outline[ i ++ ] * scaleY;
- action = item.action;
- args = item.args;
+ path.moveTo( x, y );
+ break;
- switch( action ) {
+ case 'l':
- case THREE.PathActions.MOVE_TO:
+ // Line To
- points.push( new THREE.Vector2( args[ 0 ], args[ 1 ] ) );
+ x = outline[ i ++ ] * scaleX + offset;
+ y = outline[ i ++ ] * scaleY;
+ path.lineTo( x,y );
+ break;
- break;
+ case 'q':
- case THREE.PathActions.LINE_TO:
+ // QuadraticCurveTo
- points.push( new THREE.Vector2( args[ 0 ], args[ 1 ] ) );
+ cpx = outline[ i ++ ] * scaleX + offset;
+ cpy = outline[ i ++ ] * scaleY;
+ cpx1 = outline[ i ++ ] * scaleX + offset;
+ cpy1 = outline[ i ++ ] * scaleY;
- break;
+ path.quadraticCurveTo( cpx1, cpy1, cpx, cpy );
- case THREE.PathActions.QUADRATIC_CURVE_TO:
+ laste = pts[ pts.length - 1 ];
- cpx = args[ 2 ];
- cpy = args[ 3 ];
+ if ( laste ) {
- cpx1 = args[ 0 ];
- cpy1 = args[ 1 ];
+ cpx0 = laste.x;
+ cpy0 = laste.y;
- if ( points.length > 0 ) {
+ for ( i2 = 1, divisions = this.divisions; i2 <= divisions; i2 ++ ) {
- laste = points[ points.length - 1 ];
+ var t = i2 / divisions;
+ var tx = THREE.Shape.Utils.b2( t, cpx0, cpx1, cpx );
+ var ty = THREE.Shape.Utils.b2( t, cpy0, cpy1, cpy );
+ }
- cpx0 = laste.x;
- cpy0 = laste.y;
+ }
- } else {
+ break;
- laste = this.actions[ i - 1 ].args;
+ case 'b':
- cpx0 = laste[ laste.length - 2 ];
- cpy0 = laste[ laste.length - 1 ];
+ // Cubic Bezier Curve
- }
+ cpx = outline[ i ++ ] * scaleX + offset;
+ cpy = outline[ i ++ ] * scaleY;
+ cpx1 = outline[ i ++ ] * scaleX + offset;
+ cpy1 = outline[ i ++ ] * scaleY;
+ cpx2 = outline[ i ++ ] * scaleX + offset;
+ cpy2 = outline[ i ++ ] * scaleY;
- for ( j = 1; j <= divisions; j ++ ) {
+ path.bezierCurveTo( cpx1, cpy1, cpx2, cpy2, cpx, cpy );
- t = j / divisions;
+ laste = pts[ pts.length - 1 ];
- tx = THREE.Shape.Utils.b2( t, cpx0, cpx1, cpx );
- ty = THREE.Shape.Utils.b2( t, cpy0, cpy1, cpy );
+ if ( laste ) {
- points.push( new THREE.Vector2( tx, ty ) );
+ cpx0 = laste.x;
+ cpy0 = laste.y;
- }
+ for ( i2 = 1, divisions = this.divisions; i2 <= divisions; i2 ++ ) {
- break;
+ var t = i2 / divisions;
+ var tx = THREE.Shape.Utils.b3( t, cpx0, cpx1, cpx2, cpx );
+ var ty = THREE.Shape.Utils.b3( t, cpy0, cpy1, cpy2, cpy );
- case THREE.PathActions.BEZIER_CURVE_TO:
+ }
- cpx = args[ 4 ];
- cpy = args[ 5 ];
+ }
- cpx1 = args[ 0 ];
- cpy1 = args[ 1 ];
+ break;
- cpx2 = args[ 2 ];
- cpy2 = args[ 3 ];
+ }
- if ( points.length > 0 ) {
+ }
+ }
- laste = points[ points.length - 1 ];
- cpx0 = laste.x;
- cpy0 = laste.y;
- } else {
+ return { offset: glyph.ha * scale, path:path };
+ }
- laste = this.actions[ i - 1 ].args;
+};
- cpx0 = laste[ laste.length - 2 ];
- cpy0 = laste[ laste.length - 1 ];
- }
+THREE.FontUtils.generateShapes = function ( text, parameters ) {
+ // Parameters
- for ( j = 1; j <= divisions; j ++ ) {
+ parameters = parameters || {};
- t = j / divisions;
+ var size = parameters.size !== undefined ? parameters.size : 100;
+ var curveSegments = parameters.curveSegments !== undefined ? parameters.curveSegments : 4;
- tx = THREE.Shape.Utils.b3( t, cpx0, cpx1, cpx2, cpx );
- ty = THREE.Shape.Utils.b3( t, cpy0, cpy1, cpy2, cpy );
+ var font = parameters.font !== undefined ? parameters.font : 'helvetiker';
+ var weight = parameters.weight !== undefined ? parameters.weight : 'normal';
+ var style = parameters.style !== undefined ? parameters.style : 'normal';
- points.push( new THREE.Vector2( tx, ty ) );
+ THREE.FontUtils.size = size;
+ THREE.FontUtils.divisions = curveSegments;
- }
+ THREE.FontUtils.face = font;
+ THREE.FontUtils.weight = weight;
+ THREE.FontUtils.style = style;
- break;
+ // Get a Font data json object
- case THREE.PathActions.CSPLINE_THRU:
+ var data = THREE.FontUtils.drawText( text );
- laste = this.actions[ i - 1 ].args;
+ var paths = data.paths;
+ var shapes = [];
- var last = new THREE.Vector2( laste[ laste.length - 2 ], laste[ laste.length - 1 ] );
- var spts = [ last ];
+ for ( var p = 0, pl = paths.length; p < pl; p ++ ) {
- var n = divisions * args[ 0 ].length;
+ Array.prototype.push.apply( shapes, paths[ p ].toShapes() );
- spts = spts.concat( args[ 0 ] );
+ }
- var spline = new THREE.SplineCurve( spts );
+ return shapes;
- for ( j = 1; j <= n; j ++ ) {
+};
- points.push( spline.getPointAt( j / n ) ) ;
- }
+/**
+ * This code is a quick port of code written in C++ which was submitted to
+ * flipcode.com by John W. Ratcliff // July 22, 2000
+ * See original code and more information here:
+ * http://www.flipcode.com/archives/Efficient_Polygon_Triangulation.shtml
+ *
+ * ported to actionscript by Zevan Rosser
+ * www.actionsnippet.com
+ *
+ * ported to javascript by Joshua Koo
+ * http://www.lab4games.net/zz85/blog
+ *
+ */
- break;
- case THREE.PathActions.ARC:
+( function ( namespace ) {
- var aX = args[ 0 ], aY = args[ 1 ],
- aRadius = args[ 2 ],
- aStartAngle = args[ 3 ], aEndAngle = args[ 4 ],
- aClockwise = !! args[ 5 ];
+ var EPSILON = 0.0000000001;
- var deltaAngle = aEndAngle - aStartAngle;
- var angle;
- var tdivisions = divisions * 2;
+ // takes in an contour array and returns
- for ( j = 1; j <= tdivisions; j ++ ) {
+ var process = function ( contour, indices ) {
- t = j / tdivisions;
+ var n = contour.length;
- if ( ! aClockwise ) {
+ if ( n < 3 ) return null;
- t = 1 - t;
+ var result = [],
+ verts = [],
+ vertIndices = [];
- }
+ /* we want a counter-clockwise polygon in verts */
- angle = aStartAngle + t * deltaAngle;
+ var u, v, w;
- tx = aX + aRadius * Math.cos( angle );
- ty = aY + aRadius * Math.sin( angle );
+ if ( area( contour ) > 0.0 ) {
- //console.log('t', t, 'angle', angle, 'tx', tx, 'ty', ty);
+ for ( v = 0; v < n; v ++ ) verts[ v ] = v;
- points.push( new THREE.Vector2( tx, ty ) );
+ } else {
- }
+ for ( v = 0; v < n; v ++ ) verts[ v ] = ( n - 1 ) - v;
- //console.log(points);
+ }
- break;
-
- case THREE.PathActions.ELLIPSE:
+ var nv = n;
- var aX = args[ 0 ], aY = args[ 1 ],
- xRadius = args[ 2 ],
- yRadius = args[ 3 ],
- aStartAngle = args[ 4 ], aEndAngle = args[ 5 ],
- aClockwise = !! args[ 6 ];
+ /* remove nv - 2 vertices, creating 1 triangle every time */
+ var count = 2 * nv; /* error detection */
- var deltaAngle = aEndAngle - aStartAngle;
- var angle;
- var tdivisions = divisions * 2;
+ for ( v = nv - 1; nv > 2; ) {
- for ( j = 1; j <= tdivisions; j ++ ) {
+ /* if we loop, it is probably a non-simple polygon */
- t = j / tdivisions;
+ if ( ( count -- ) <= 0 ) {
- if ( ! aClockwise ) {
+ //** Triangulate: ERROR - probable bad polygon!
- t = 1 - t;
+ //throw ( "Warning, unable to triangulate polygon!" );
+ //return null;
+ // Sometimes warning is fine, especially polygons are triangulated in reverse.
+ console.log( 'Warning, unable to triangulate polygon!' );
- }
+ if ( indices ) return vertIndices;
+ return result;
- angle = aStartAngle + t * deltaAngle;
+ }
- tx = aX + xRadius * Math.cos( angle );
- ty = aY + yRadius * Math.sin( angle );
+ /* three consecutive vertices in current polygon, */
- //console.log('t', t, 'angle', angle, 'tx', tx, 'ty', ty);
+ u = v; if ( nv <= u ) u = 0; /* previous */
+ v = u + 1; if ( nv <= v ) v = 0; /* new v */
+ w = v + 1; if ( nv <= w ) w = 0; /* next */
- points.push( new THREE.Vector2( tx, ty ) );
+ if ( snip( contour, u, v, w, nv, verts ) ) {
- }
+ var a, b, c, s, t;
- //console.log(points);
+ /* true names of the vertices */
- break;
+ a = verts[ u ];
+ b = verts[ v ];
+ c = verts[ w ];
- } // end switch
+ /* output Triangle */
- }
+ result.push( [ contour[ a ],
+ contour[ b ],
+ contour[ c ] ] );
+ vertIndices.push( [ verts[ u ], verts[ v ], verts[ w ] ] );
- // Normalize to remove the closing point by default.
- var lastPoint = points[ points.length - 1];
- var EPSILON = 0.0000000001;
- if ( Math.abs(lastPoint.x - points[ 0 ].x) < EPSILON &&
- Math.abs(lastPoint.y - points[ 0 ].y) < EPSILON)
- points.splice( points.length - 1, 1);
- if ( closedPath ) {
+ /* remove v from the remaining polygon */
- points.push( points[ 0 ] );
+ for ( s = v, t = v + 1; t < nv; s++, t++ ) {
- }
+ verts[ s ] = verts[ t ];
- return points;
+ }
-};
+ nv --;
-//
-// Breaks path into shapes
-//
-// Assumptions (if parameter isCCW==true the opposite holds):
-// - solid shapes are defined clockwise (CW)
-// - holes are defined counterclockwise (CCW)
-//
-// If parameter noHoles==true:
-// - all subPaths are regarded as solid shapes
-// - definition order CW/CCW has no relevance
-//
+ /* reset error detection counter */
-THREE.Path.prototype.toShapes = function( isCCW, noHoles ) {
+ count = 2 * nv;
- function extractSubpaths( inActions ) {
+ }
- var i, il, item, action, args;
+ }
- var subPaths = [], lastPath = new THREE.Path();
+ if ( indices ) return vertIndices;
+ return result;
- for ( i = 0, il = inActions.length; i < il; i ++ ) {
-
- item = inActions[ i ];
+ };
- args = item.args;
- action = item.action;
+ // calculate area of the contour polygon
- if ( action == THREE.PathActions.MOVE_TO ) {
+ var area = function ( contour ) {
- if ( lastPath.actions.length != 0 ) {
+ var n = contour.length;
+ var a = 0.0;
- subPaths.push( lastPath );
- lastPath = new THREE.Path();
+ for ( var p = n - 1, q = 0; q < n; p = q ++ ) {
- }
+ a += contour[ p ].x * contour[ q ].y - contour[ q ].x * contour[ p ].y;
- }
+ }
- lastPath[ action ].apply( lastPath, args );
+ return a * 0.5;
- }
+ };
- if ( lastPath.actions.length != 0 ) {
+ var snip = function ( contour, u, v, w, n, verts ) {
- subPaths.push( lastPath );
+ var p;
+ var ax, ay, bx, by;
+ var cx, cy, px, py;
- }
+ ax = contour[ verts[ u ] ].x;
+ ay = contour[ verts[ u ] ].y;
- // console.log(subPaths);
+ bx = contour[ verts[ v ] ].x;
+ by = contour[ verts[ v ] ].y;
- return subPaths;
- }
+ cx = contour[ verts[ w ] ].x;
+ cy = contour[ verts[ w ] ].y;
- function toShapesNoHoles( inSubpaths ) {
+ if ( EPSILON > ( ( ( bx - ax ) * ( cy - ay ) ) - ( ( by - ay ) * ( cx - ax ) ) ) ) return false;
- var shapes = [];
+ var aX, aY, bX, bY, cX, cY;
+ var apx, apy, bpx, bpy, cpx, cpy;
+ var cCROSSap, bCROSScp, aCROSSbp;
- for ( var i = 0, il = inSubpaths.length; i < il; i ++ ) {
+ aX = cx - bx; aY = cy - by;
+ bX = ax - cx; bY = ay - cy;
+ cX = bx - ax; cY = by - ay;
- var tmpPath = inSubpaths[ i ];
+ for ( p = 0; p < n; p ++ ) {
- var tmpShape = new THREE.Shape();
- tmpShape.actions = tmpPath.actions;
- tmpShape.curves = tmpPath.curves;
+ px = contour[ verts[ p ] ].x
+ py = contour[ verts[ p ] ].y
- shapes.push( tmpShape );
- }
+ if ( ( ( px === ax ) && ( py === ay ) ) ||
+ ( ( px === bx ) && ( py === by ) ) ||
+ ( ( px === cx ) && ( py === cy ) ) ) continue;
- //console.log("shape", shapes);
+ apx = px - ax; apy = py - ay;
+ bpx = px - bx; bpy = py - by;
+ cpx = px - cx; cpy = py - cy;
- return shapes;
- };
+ // see if p is inside triangle abc
- function isPointInsidePolygon( inPt, inPolygon ) {
- var EPSILON = 0.0000000001;
+ aCROSSbp = aX * bpy - aY * bpx;
+ cCROSSap = cX * apy - cY * apx;
+ bCROSScp = bX * cpy - bY * cpx;
- var polyLen = inPolygon.length;
+ if ( ( aCROSSbp >= - EPSILON ) && ( bCROSScp >= - EPSILON ) && ( cCROSSap >= - EPSILON ) ) return false;
- // inPt on polygon contour => immediate success or
- // toggling of inside/outside at every single! intersection point of an edge
- // with the horizontal line through inPt, left of inPt
- // not counting lowerY endpoints of edges and whole edges on that line
- var inside = false;
- for( var p = polyLen - 1, q = 0; q < polyLen; p = q ++ ) {
- var edgeLowPt = inPolygon[ p ];
- var edgeHighPt = inPolygon[ q ];
+ }
- var edgeDx = edgeHighPt.x - edgeLowPt.x;
- var edgeDy = edgeHighPt.y - edgeLowPt.y;
+ return true;
- if ( Math.abs(edgeDy) > EPSILON ) { // not parallel
- if ( edgeDy < 0 ) {
- edgeLowPt = inPolygon[ q ]; edgeDx = - edgeDx;
- edgeHighPt = inPolygon[ p ]; edgeDy = - edgeDy;
- }
- if ( ( inPt.y < edgeLowPt.y ) || ( inPt.y > edgeHighPt.y ) ) continue;
+ };
- if ( inPt.y == edgeLowPt.y ) {
- if ( inPt.x == edgeLowPt.x ) return true; // inPt is on contour ?
- // continue; // no intersection or edgeLowPt => doesn't count !!!
- } else {
- var perpEdge = edgeDy * (inPt.x - edgeLowPt.x) - edgeDx * (inPt.y - edgeLowPt.y);
- if ( perpEdge == 0 ) return true; // inPt is on contour ?
- if ( perpEdge < 0 ) continue;
- inside = ! inside; // true intersection left of inPt
- }
- } else { // parallel or colinear
- if ( inPt.y != edgeLowPt.y ) continue; // parallel
- // egde lies on the same horizontal line as inPt
- if ( ( ( edgeHighPt.x <= inPt.x ) && ( inPt.x <= edgeLowPt.x ) ) ||
- ( ( edgeLowPt.x <= inPt.x ) && ( inPt.x <= edgeHighPt.x ) ) ) return true; // inPt: Point on contour !
- // continue;
- }
- }
- return inside;
- }
+ namespace.Triangulate = process;
+ namespace.Triangulate.area = area;
+ return namespace;
- var subPaths = extractSubpaths( this.actions );
- if ( subPaths.length == 0 ) return [];
+} )( THREE.FontUtils );
- if ( noHoles === true ) return toShapesNoHoles( subPaths );
+// To use the typeface.js face files, hook up the API
+self._typeface_js = { faces: THREE.FontUtils.faces, loadFace: THREE.FontUtils.loadFace };
+THREE.typeface_js = self._typeface_js;
+// File:src/extras/audio/Audio.js
- var solid, tmpPath, tmpShape, shapes = [];
+/**
+ * @author mrdoob / http://mrdoob.com/
+ */
- if ( subPaths.length == 1) {
+THREE.Audio = function ( listener ) {
- tmpPath = subPaths[0];
- tmpShape = new THREE.Shape();
- tmpShape.actions = tmpPath.actions;
- tmpShape.curves = tmpPath.curves;
- shapes.push( tmpShape );
- return shapes;
+ THREE.Object3D.call( this );
- }
+ this.type = 'Audio';
- var holesFirst = ! THREE.Shape.Utils.isClockWise( subPaths[ 0 ].getPoints() );
- holesFirst = isCCW ? ! holesFirst : holesFirst;
+ this.context = listener.context;
+ this.source = this.context.createBufferSource();
- // console.log("Holes first", holesFirst);
-
- var betterShapeHoles = [];
- var newShapes = [];
- var newShapeHoles = [];
- var mainIdx = 0;
- var tmpPoints;
+ this.gain = this.context.createGain();
+ this.gain.connect( this.context.destination );
- newShapes[mainIdx] = undefined;
- newShapeHoles[mainIdx] = [];
+ this.panner = this.context.createPanner();
+ this.panner.connect( this.gain );
- var i, il;
+};
- for ( i = 0, il = subPaths.length; i < il; i ++ ) {
+THREE.Audio.prototype = Object.create( THREE.Object3D.prototype );
- tmpPath = subPaths[ i ];
- tmpPoints = tmpPath.getPoints();
- solid = THREE.Shape.Utils.isClockWise( tmpPoints );
- solid = isCCW ? ! solid : solid;
+THREE.Audio.prototype.load = function ( file ) {
- if ( solid ) {
+ var scope = this;
- if ( (! holesFirst ) && ( newShapes[mainIdx] ) ) mainIdx ++;
+ var request = new XMLHttpRequest();
+ request.open( 'GET', file, true );
+ request.responseType = 'arraybuffer';
+ request.onload = function ( e ) {
- newShapes[mainIdx] = { s: new THREE.Shape(), p: tmpPoints };
- newShapes[mainIdx].s.actions = tmpPath.actions;
- newShapes[mainIdx].s.curves = tmpPath.curves;
-
- if ( holesFirst ) mainIdx ++;
- newShapeHoles[mainIdx] = [];
+ scope.context.decodeAudioData( this.response, function ( buffer ) {
- //console.log('cw', i);
+ scope.source.buffer = buffer;
+ scope.source.connect( scope.panner );
+ scope.source.start( 0 );
- } else {
+ } );
- newShapeHoles[mainIdx].push( { h: tmpPath, p: tmpPoints[0] } );
+ };
+ request.send();
- //console.log('ccw', i);
+ return this;
- }
+};
- }
+THREE.Audio.prototype.setLoop = function ( value ) {
- // only Holes? -> probably all Shapes with wrong orientation
- if ( ! newShapes[0] ) return toShapesNoHoles( subPaths );
+ this.source.loop = value;
+};
- if ( newShapes.length > 1 ) {
- var ambigious = false;
- var toChange = [];
+THREE.Audio.prototype.setRefDistance = function ( value ) {
- for (var sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) {
- betterShapeHoles[sIdx] = [];
- }
- for (var sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) {
- var sh = newShapes[sIdx];
- var sho = newShapeHoles[sIdx];
- for (var hIdx = 0; hIdx < sho.length; hIdx ++ ) {
- var ho = sho[hIdx];
- var hole_unassigned = true;
- for (var s2Idx = 0; s2Idx < newShapes.length; s2Idx ++ ) {
- if ( isPointInsidePolygon( ho.p, newShapes[s2Idx].p ) ) {
- if ( sIdx != s2Idx ) toChange.push( { froms: sIdx, tos: s2Idx, hole: hIdx } );
- if ( hole_unassigned ) {
- hole_unassigned = false;
- betterShapeHoles[s2Idx].push( ho );
- } else {
- ambigious = true;
- }
- }
- }
- if ( hole_unassigned ) { betterShapeHoles[sIdx].push( ho ); }
- }
- }
- // console.log("ambigious: ", ambigious);
- if ( toChange.length > 0 ) {
- // console.log("to change: ", toChange);
- if (! ambigious) newShapeHoles = betterShapeHoles;
- }
- }
+ this.panner.refDistance = value;
- var tmpHoles, j, jl;
- for ( i = 0, il = newShapes.length; i < il; i ++ ) {
- tmpShape = newShapes[i].s;
- shapes.push( tmpShape );
- tmpHoles = newShapeHoles[i];
- for ( j = 0, jl = tmpHoles.length; j < jl; j ++ ) {
- tmpShape.holes.push( tmpHoles[j].h );
- }
- }
+};
- //console.log("shape", shapes);
+THREE.Audio.prototype.setRolloffFactor = function ( value ) {
- return shapes;
+ this.panner.rolloffFactor = value;
};
-// File:src/extras/core/Shape.js
+THREE.Audio.prototype.updateMatrixWorld = ( function () {
-/**
- * @author zz85 / http://www.lab4games.net/zz85/blog
- * Defines a 2d shape plane using paths.
- **/
+ var position = new THREE.Vector3();
-// STEP 1 Create a path.
-// STEP 2 Turn path into shape.
-// STEP 3 ExtrudeGeometry takes in Shape/Shapes
-// STEP 3a - Extract points from each shape, turn to vertices
-// STEP 3b - Triangulate each shape, add faces.
+ return function ( force ) {
-THREE.Shape = function () {
+ THREE.Object3D.prototype.updateMatrixWorld.call( this, force );
- THREE.Path.apply( this, arguments );
- this.holes = [];
+ position.setFromMatrixPosition( this.matrixWorld );
-};
+ this.panner.setPosition( position.x, position.y, position.z );
-THREE.Shape.prototype = Object.create( THREE.Path.prototype );
+ };
-// Convenience method to return ExtrudeGeometry
+} )();
-THREE.Shape.prototype.extrude = function ( options ) {
+// File:src/extras/audio/AudioListener.js
- var extruded = new THREE.ExtrudeGeometry( this, options );
- return extruded;
+/**
+ * @author mrdoob / http://mrdoob.com/
+ */
-};
+THREE.AudioListener = function () {
-// Convenience method to return ShapeGeometry
+ THREE.Object3D.call( this );
-THREE.Shape.prototype.makeGeometry = function ( options ) {
+ this.type = 'AudioListener';
- var geometry = new THREE.ShapeGeometry( this, options );
- return geometry;
+ this.context = new ( window.AudioContext || window.webkitAudioContext )();
};
-// Get points of holes
+THREE.AudioListener.prototype = Object.create( THREE.Object3D.prototype );
-THREE.Shape.prototype.getPointsHoles = function ( divisions ) {
+THREE.AudioListener.prototype.updateMatrixWorld = ( function () {
- var i, il = this.holes.length, holesPts = [];
+ var position = new THREE.Vector3();
+ var quaternion = new THREE.Quaternion();
+ var scale = new THREE.Vector3();
- for ( i = 0; i < il; i ++ ) {
+ var orientation = new THREE.Vector3();
+ var velocity = new THREE.Vector3();
- holesPts[ i ] = this.holes[ i ].getTransformedPoints( divisions, this.bends );
+ var positionPrev = new THREE.Vector3();
- }
+ return function ( force ) {
- return holesPts;
+ THREE.Object3D.prototype.updateMatrixWorld.call( this, force );
+
+ var listener = this.context.listener;
+
+ this.matrixWorld.decompose( position, quaternion, scale );
+
+ orientation.set( 0, 0, -1 ).applyQuaternion( quaternion );
+ velocity.subVectors( position, positionPrev );
+
+ listener.setPosition( position.x, position.y, position.z );
+ listener.setOrientation( orientation.x, orientation.y, orientation.z, this.up.x, this.up.y, this.up.z );
+ listener.setVelocity( velocity.x, velocity.y, velocity.z );
+
+ positionPrev.copy( position );
+
+ };
+
+} )();
+
+// File:src/extras/core/Curve.js
+
+/**
+ * @author zz85 / http://www.lab4games.net/zz85/blog
+ * Extensible curve object
+ *
+ * Some common of Curve methods
+ * .getPoint(t), getTangent(t)
+ * .getPointAt(u), getTagentAt(u)
+ * .getPoints(), .getSpacedPoints()
+ * .getLength()
+ * .updateArcLengths()
+ *
+ * This following classes subclasses THREE.Curve:
+ *
+ * -- 2d classes --
+ * THREE.LineCurve
+ * THREE.QuadraticBezierCurve
+ * THREE.CubicBezierCurve
+ * THREE.SplineCurve
+ * THREE.ArcCurve
+ * THREE.EllipseCurve
+ *
+ * -- 3d classes --
+ * THREE.LineCurve3
+ * THREE.QuadraticBezierCurve3
+ * THREE.CubicBezierCurve3
+ * THREE.SplineCurve3
+ * THREE.ClosedSplineCurve3
+ *
+ * A series of curves can be represented as a THREE.CurvePath
+ *
+ **/
+
+/**************************************************************
+ * Abstract Curve base class
+ **************************************************************/
+
+THREE.Curve = function () {
};
-// Get points of holes (spaced by regular distance)
+// Virtual base class method to overwrite and implement in subclasses
+// - t [0 .. 1]
-THREE.Shape.prototype.getSpacedPointsHoles = function ( divisions ) {
+THREE.Curve.prototype.getPoint = function ( t ) {
- var i, il = this.holes.length, holesPts = [];
+ console.log( "Warning, getPoint() not implemented!" );
+ return null;
- for ( i = 0; i < il; i ++ ) {
+};
- holesPts[ i ] = this.holes[ i ].getTransformedSpacedPoints( divisions, this.bends );
+// Get point at relative position in curve according to arc length
+// - u [0 .. 1]
- }
+THREE.Curve.prototype.getPointAt = function ( u ) {
- return holesPts;
+ var t = this.getUtoTmapping( u );
+ return this.getPoint( t );
};
+// Get sequence of points using getPoint( t )
-// Get points of shape and holes (keypoints based on segments parameter)
+THREE.Curve.prototype.getPoints = function ( divisions ) {
-THREE.Shape.prototype.extractAllPoints = function ( divisions ) {
+ if ( ! divisions ) divisions = 5;
- return {
+ var d, pts = [];
- shape: this.getTransformedPoints( divisions ),
- holes: this.getPointsHoles( divisions )
+ for ( d = 0; d <= divisions; d ++ ) {
- };
+ pts.push( this.getPoint( d / divisions ) );
+
+ }
+
+ return pts;
};
-THREE.Shape.prototype.extractPoints = function ( divisions ) {
+// Get sequence of points using getPointAt( u )
+
+THREE.Curve.prototype.getSpacedPoints = function ( divisions ) {
+
+ if ( ! divisions ) divisions = 5;
+
+ var d, pts = [];
+
+ for ( d = 0; d <= divisions; d ++ ) {
+
+ pts.push( this.getPointAt( d / divisions ) );
- if (this.useSpacedPoints) {
- return this.extractAllSpacedPoints(divisions);
}
- return this.extractAllPoints(divisions);
+ return pts;
};
-//
-// THREE.Shape.prototype.extractAllPointsWithBend = function ( divisions, bend ) {
-//
-// return {
-//
-// shape: this.transform( bend, divisions ),
-// holes: this.getPointsHoles( divisions, bend )
-//
-// };
-//
-// };
+// Get total curve arc length
-// Get points of shape and holes (spaced by regular distance)
+THREE.Curve.prototype.getLength = function () {
-THREE.Shape.prototype.extractAllSpacedPoints = function ( divisions ) {
+ var lengths = this.getLengths();
+ return lengths[ lengths.length - 1 ];
- return {
+};
- shape: this.getTransformedSpacedPoints( divisions ),
- holes: this.getSpacedPointsHoles( divisions )
+// Get list of cumulative segment lengths
- };
+THREE.Curve.prototype.getLengths = function ( divisions ) {
+
+ if ( ! divisions ) divisions = (this.__arcLengthDivisions) ? (this.__arcLengthDivisions): 200;
+
+ if ( this.cacheArcLengths
+ && ( this.cacheArcLengths.length == divisions + 1 )
+ && ! this.needsUpdate) {
+
+ //console.log( "cached", this.cacheArcLengths );
+ return this.cacheArcLengths;
+
+ }
+
+ this.needsUpdate = false;
+
+ var cache = [];
+ var current, last = this.getPoint( 0 );
+ var p, sum = 0;
+
+ cache.push( 0 );
+
+ for ( p = 1; p <= divisions; p ++ ) {
+
+ current = this.getPoint ( p / divisions );
+ sum += current.distanceTo( last );
+ cache.push( sum );
+ last = current;
+
+ }
+
+ this.cacheArcLengths = cache;
+
+ return cache; // { sums: cache, sum:sum }; Sum is in the last element.
};
-/**************************************************************
- * Utils
- **************************************************************/
-THREE.Shape.Utils = {
+THREE.Curve.prototype.updateArcLengths = function() {
+ this.needsUpdate = true;
+ this.getLengths();
+};
- triangulateShape: function ( contour, holes ) {
+// Given u ( 0 .. 1 ), get a t to find p. This gives you points which are equi distance
- function point_in_segment_2D_colin( inSegPt1, inSegPt2, inOtherPt ) {
- // inOtherPt needs to be colinear to the inSegment
- if ( inSegPt1.x != inSegPt2.x ) {
- if ( inSegPt1.x < inSegPt2.x ) {
- return ( ( inSegPt1.x <= inOtherPt.x ) && ( inOtherPt.x <= inSegPt2.x ) );
- } else {
- return ( ( inSegPt2.x <= inOtherPt.x ) && ( inOtherPt.x <= inSegPt1.x ) );
- }
- } else {
- if ( inSegPt1.y < inSegPt2.y ) {
- return ( ( inSegPt1.y <= inOtherPt.y ) && ( inOtherPt.y <= inSegPt2.y ) );
- } else {
- return ( ( inSegPt2.y <= inOtherPt.y ) && ( inOtherPt.y <= inSegPt1.y ) );
- }
- }
- }
+THREE.Curve.prototype.getUtoTmapping = function ( u, distance ) {
- function intersect_segments_2D( inSeg1Pt1, inSeg1Pt2, inSeg2Pt1, inSeg2Pt2, inExcludeAdjacentSegs ) {
- var EPSILON = 0.0000000001;
+ var arcLengths = this.getLengths();
- var seg1dx = inSeg1Pt2.x - inSeg1Pt1.x, seg1dy = inSeg1Pt2.y - inSeg1Pt1.y;
- var seg2dx = inSeg2Pt2.x - inSeg2Pt1.x, seg2dy = inSeg2Pt2.y - inSeg2Pt1.y;
+ var i = 0, il = arcLengths.length;
- var seg1seg2dx = inSeg1Pt1.x - inSeg2Pt1.x;
- var seg1seg2dy = inSeg1Pt1.y - inSeg2Pt1.y;
+ var targetArcLength; // The targeted u distance value to get
- var limit = seg1dy * seg2dx - seg1dx * seg2dy;
- var perpSeg1 = seg1dy * seg1seg2dx - seg1dx * seg1seg2dy;
+ if ( distance ) {
- if ( Math.abs(limit) > EPSILON ) { // not parallel
+ targetArcLength = distance;
- var perpSeg2;
- if ( limit > 0 ) {
- if ( ( perpSeg1 < 0 ) || ( perpSeg1 > limit ) ) return [];
- perpSeg2 = seg2dy * seg1seg2dx - seg2dx * seg1seg2dy;
- if ( ( perpSeg2 < 0 ) || ( perpSeg2 > limit ) ) return [];
- } else {
- if ( ( perpSeg1 > 0 ) || ( perpSeg1 < limit ) ) return [];
- perpSeg2 = seg2dy * seg1seg2dx - seg2dx * seg1seg2dy;
- if ( ( perpSeg2 > 0 ) || ( perpSeg2 < limit ) ) return [];
- }
+ } else {
- // i.e. to reduce rounding errors
- // intersection at endpoint of segment#1?
- if ( perpSeg2 == 0 ) {
- if ( ( inExcludeAdjacentSegs ) &&
- ( ( perpSeg1 == 0 ) || ( perpSeg1 == limit ) ) ) return [];
- return [ inSeg1Pt1 ];
- }
- if ( perpSeg2 == limit ) {
- if ( ( inExcludeAdjacentSegs ) &&
- ( ( perpSeg1 == 0 ) || ( perpSeg1 == limit ) ) ) return [];
- return [ inSeg1Pt2 ];
- }
- // intersection at endpoint of segment#2?
- if ( perpSeg1 == 0 ) return [ inSeg2Pt1 ];
- if ( perpSeg1 == limit ) return [ inSeg2Pt2 ];
+ targetArcLength = u * arcLengths[ il - 1 ];
- // return real intersection point
- var factorSeg1 = perpSeg2 / limit;
- return [ { x: inSeg1Pt1.x + factorSeg1 * seg1dx,
- y: inSeg1Pt1.y + factorSeg1 * seg1dy } ];
+ }
- } else { // parallel or colinear
- if ( ( perpSeg1 != 0 ) ||
- ( seg2dy * seg1seg2dx != seg2dx * seg1seg2dy ) ) return [];
+ //var time = Date.now();
- // they are collinear or degenerate
- var seg1Pt = ( (seg1dx == 0) && (seg1dy == 0) ); // segment1 ist just a point?
- var seg2Pt = ( (seg2dx == 0) && (seg2dy == 0) ); // segment2 ist just a point?
- // both segments are points
- if ( seg1Pt && seg2Pt ) {
- if ( (inSeg1Pt1.x != inSeg2Pt1.x) ||
- (inSeg1Pt1.y != inSeg2Pt1.y) ) return []; // they are distinct points
- return [ inSeg1Pt1 ]; // they are the same point
- }
- // segment#1 is a single point
- if ( seg1Pt ) {
- if (! point_in_segment_2D_colin( inSeg2Pt1, inSeg2Pt2, inSeg1Pt1 ) ) return []; // but not in segment#2
- return [ inSeg1Pt1 ];
- }
- // segment#2 is a single point
- if ( seg2Pt ) {
- if (! point_in_segment_2D_colin( inSeg1Pt1, inSeg1Pt2, inSeg2Pt1 ) ) return []; // but not in segment#1
- return [ inSeg2Pt1 ];
- }
+ // binary search for the index with largest value smaller than target u distance
- // they are collinear segments, which might overlap
- var seg1min, seg1max, seg1minVal, seg1maxVal;
- var seg2min, seg2max, seg2minVal, seg2maxVal;
- if (seg1dx != 0) { // the segments are NOT on a vertical line
- if ( inSeg1Pt1.x < inSeg1Pt2.x ) {
- seg1min = inSeg1Pt1; seg1minVal = inSeg1Pt1.x;
- seg1max = inSeg1Pt2; seg1maxVal = inSeg1Pt2.x;
- } else {
- seg1min = inSeg1Pt2; seg1minVal = inSeg1Pt2.x;
- seg1max = inSeg1Pt1; seg1maxVal = inSeg1Pt1.x;
- }
- if ( inSeg2Pt1.x < inSeg2Pt2.x ) {
- seg2min = inSeg2Pt1; seg2minVal = inSeg2Pt1.x;
- seg2max = inSeg2Pt2; seg2maxVal = inSeg2Pt2.x;
- } else {
- seg2min = inSeg2Pt2; seg2minVal = inSeg2Pt2.x;
- seg2max = inSeg2Pt1; seg2maxVal = inSeg2Pt1.x;
- }
- } else { // the segments are on a vertical line
- if ( inSeg1Pt1.y < inSeg1Pt2.y ) {
- seg1min = inSeg1Pt1; seg1minVal = inSeg1Pt1.y;
- seg1max = inSeg1Pt2; seg1maxVal = inSeg1Pt2.y;
- } else {
- seg1min = inSeg1Pt2; seg1minVal = inSeg1Pt2.y;
- seg1max = inSeg1Pt1; seg1maxVal = inSeg1Pt1.y;
- }
- if ( inSeg2Pt1.y < inSeg2Pt2.y ) {
- seg2min = inSeg2Pt1; seg2minVal = inSeg2Pt1.y;
- seg2max = inSeg2Pt2; seg2maxVal = inSeg2Pt2.y;
- } else {
- seg2min = inSeg2Pt2; seg2minVal = inSeg2Pt2.y;
- seg2max = inSeg2Pt1; seg2maxVal = inSeg2Pt1.y;
- }
- }
- if ( seg1minVal <= seg2minVal ) {
- if ( seg1maxVal < seg2minVal ) return [];
- if ( seg1maxVal == seg2minVal ) {
- if ( inExcludeAdjacentSegs ) return [];
- return [ seg2min ];
- }
- if ( seg1maxVal <= seg2maxVal ) return [ seg2min, seg1max ];
- return [ seg2min, seg2max ];
- } else {
- if ( seg1minVal > seg2maxVal ) return [];
- if ( seg1minVal == seg2maxVal ) {
- if ( inExcludeAdjacentSegs ) return [];
- return [ seg1min ];
- }
- if ( seg1maxVal <= seg2maxVal ) return [ seg1min, seg1max ];
- return [ seg1min, seg2max ];
- }
- }
- }
+ var low = 0, high = il - 1, comparison;
- function isPointInsideAngle( inVertex, inLegFromPt, inLegToPt, inOtherPt ) {
- // The order of legs is important
+ while ( low <= high ) {
- var EPSILON = 0.0000000001;
+ i = Math.floor( low + ( high - low ) / 2 ); // less likely to overflow, though probably not issue here, JS doesn't really have integers, all numbers are floats
- // translation of all points, so that Vertex is at (0,0)
- var legFromPtX = inLegFromPt.x - inVertex.x, legFromPtY = inLegFromPt.y - inVertex.y;
- var legToPtX = inLegToPt.x - inVertex.x, legToPtY = inLegToPt.y - inVertex.y;
- var otherPtX = inOtherPt.x - inVertex.x, otherPtY = inOtherPt.y - inVertex.y;
+ comparison = arcLengths[ i ] - targetArcLength;
- // main angle >0: < 180 deg.; 0: 180 deg.; <0: > 180 deg.
- var from2toAngle = legFromPtX * legToPtY - legFromPtY * legToPtX;
- var from2otherAngle = legFromPtX * otherPtY - legFromPtY * otherPtX;
+ if ( comparison < 0 ) {
- if ( Math.abs(from2toAngle) > EPSILON ) { // angle != 180 deg.
+ low = i + 1;
+ continue;
- var other2toAngle = otherPtX * legToPtY - otherPtY * legToPtX;
- // console.log( "from2to: " + from2toAngle + ", from2other: " + from2otherAngle + ", other2to: " + other2toAngle );
+ } else if ( comparison > 0 ) {
+
+ high = i - 1;
+ continue;
+
+ } else {
+
+ high = i;
+ break;
+
+ // DONE
- if ( from2toAngle > 0 ) { // main angle < 180 deg.
- return ( ( from2otherAngle >= 0 ) && ( other2toAngle >= 0 ) );
- } else { // main angle > 180 deg.
- return ( ( from2otherAngle >= 0 ) || ( other2toAngle >= 0 ) );
- }
- } else { // angle == 180 deg.
- // console.log( "from2to: 180 deg., from2other: " + from2otherAngle );
- return ( from2otherAngle > 0 );
- }
}
+ }
- function removeHoles( contour, holes ) {
+ i = high;
- var shape = contour.concat(); // work on this shape
- var hole;
+ //console.log('b' , i, low, high, Date.now()- time);
- function isCutLineInsideAngles( inShapeIdx, inHoleIdx ) {
- // Check if hole point lies within angle around shape point
- var lastShapeIdx = shape.length - 1;
+ if ( arcLengths[ i ] == targetArcLength ) {
- var prevShapeIdx = inShapeIdx - 1;
- if ( prevShapeIdx < 0 ) prevShapeIdx = lastShapeIdx;
+ var t = i / ( il - 1 );
+ return t;
- var nextShapeIdx = inShapeIdx + 1;
- if ( nextShapeIdx > lastShapeIdx ) nextShapeIdx = 0;
+ }
- var insideAngle = isPointInsideAngle( shape[inShapeIdx], shape[ prevShapeIdx ], shape[ nextShapeIdx ], hole[inHoleIdx] );
- if (! insideAngle ) {
- // console.log( "Vertex (Shape): " + inShapeIdx + ", Point: " + hole[inHoleIdx].x + "/" + hole[inHoleIdx].y );
- return false;
- }
+ // we could get finer grain at lengths, or use simple interpolatation between two points
- // Check if shape point lies within angle around hole point
- var lastHoleIdx = hole.length - 1;
+ var lengthBefore = arcLengths[ i ];
+ var lengthAfter = arcLengths[ i + 1 ];
- var prevHoleIdx = inHoleIdx - 1;
- if ( prevHoleIdx < 0 ) prevHoleIdx = lastHoleIdx;
+ var segmentLength = lengthAfter - lengthBefore;
- var nextHoleIdx = inHoleIdx + 1;
- if ( nextHoleIdx > lastHoleIdx ) nextHoleIdx = 0;
+ // determine where we are between the 'before' and 'after' points
- insideAngle = isPointInsideAngle( hole[inHoleIdx], hole[ prevHoleIdx ], hole[ nextHoleIdx ], shape[inShapeIdx] );
- if (! insideAngle ) {
- // console.log( "Vertex (Hole): " + inHoleIdx + ", Point: " + shape[inShapeIdx].x + "/" + shape[inShapeIdx].y );
- return false;
- }
+ var segmentFraction = ( targetArcLength - lengthBefore ) / segmentLength;
- return true;
- }
+ // add that fractional amount to t
- function intersectsShapeEdge( inShapePt, inHolePt ) {
- // checks for intersections with shape edges
- var sIdx, nextIdx, intersection;
- for ( sIdx = 0; sIdx < shape.length; sIdx ++ ) {
- nextIdx = sIdx+1; nextIdx %= shape.length;
- intersection = intersect_segments_2D( inShapePt, inHolePt, shape[sIdx], shape[nextIdx], true );
- if ( intersection.length > 0 ) return true;
- }
+ var t = ( i + segmentFraction ) / ( il -1 );
- return false;
- }
+ return t;
- var indepHoles = [];
+};
- function intersectsHoleEdge( inShapePt, inHolePt ) {
- // checks for intersections with hole edges
- var ihIdx, chkHole,
- hIdx, nextIdx, intersection;
- for ( ihIdx = 0; ihIdx < indepHoles.length; ihIdx ++ ) {
- chkHole = holes[indepHoles[ihIdx]];
- for ( hIdx = 0; hIdx < chkHole.length; hIdx ++ ) {
- nextIdx = hIdx+1; nextIdx %= chkHole.length;
- intersection = intersect_segments_2D( inShapePt, inHolePt, chkHole[hIdx], chkHole[nextIdx], true );
- if ( intersection.length > 0 ) return true;
- }
- }
- return false;
- }
+// Returns a unit vector tangent at t
+// In case any sub curve does not implement its tangent derivation,
+// 2 points a small delta apart will be used to find its gradient
+// which seems to give a reasonable approximation
- var holeIndex, shapeIndex,
- shapePt, holePt,
- holeIdx, cutKey, failedCuts = [],
- tmpShape1, tmpShape2,
- tmpHole1, tmpHole2;
+THREE.Curve.prototype.getTangent = function( t ) {
- for ( var h = 0, hl = holes.length; h < hl; h ++ ) {
+ var delta = 0.0001;
+ var t1 = t - delta;
+ var t2 = t + delta;
- indepHoles.push( h );
+ // Capping in case of danger
- }
+ if ( t1 < 0 ) t1 = 0;
+ if ( t2 > 1 ) t2 = 1;
- var minShapeIndex = 0;
- var counter = indepHoles.length * 2;
- while ( indepHoles.length > 0 ) {
- counter --;
- if ( counter < 0 ) {
- console.log( "Infinite Loop! Holes left:" + indepHoles.length + ", Probably Hole outside Shape!" );
- break;
- }
+ var pt1 = this.getPoint( t1 );
+ var pt2 = this.getPoint( t2 );
- // search for shape-vertex and hole-vertex,
- // which can be connected without intersections
- for ( shapeIndex = minShapeIndex; shapeIndex < shape.length; shapeIndex ++ ) {
+ var vec = pt2.clone().sub(pt1);
+ return vec.normalize();
- shapePt = shape[ shapeIndex ];
- holeIndex = - 1;
+};
- // search for hole which can be reached without intersections
- for ( var h = 0; h < indepHoles.length; h ++ ) {
- holeIdx = indepHoles[h];
- // prevent multiple checks
- cutKey = shapePt.x + ":" + shapePt.y + ":" + holeIdx;
- if ( failedCuts[cutKey] !== undefined ) continue;
+THREE.Curve.prototype.getTangentAt = function ( u ) {
- hole = holes[holeIdx];
- for ( var h2 = 0; h2 < hole.length; h2 ++ ) {
- holePt = hole[ h2 ];
- if (! isCutLineInsideAngles( shapeIndex, h2 ) ) continue;
- if ( intersectsShapeEdge( shapePt, holePt ) ) continue;
- if ( intersectsHoleEdge( shapePt, holePt ) ) continue;
+ var t = this.getUtoTmapping( u );
+ return this.getTangent( t );
- holeIndex = h2;
- indepHoles.splice(h,1);
+};
- tmpShape1 = shape.slice( 0, shapeIndex+1 );
- tmpShape2 = shape.slice( shapeIndex );
- tmpHole1 = hole.slice( holeIndex );
- tmpHole2 = hole.slice( 0, holeIndex+1 );
- shape = tmpShape1.concat( tmpHole1 ).concat( tmpHole2 ).concat( tmpShape2 );
- minShapeIndex = shapeIndex;
- // Debug only, to show the selected cuts
- // glob_CutLines.push( [ shapePt, holePt ] );
- break;
- }
- if ( holeIndex >= 0 ) break; // hole-vertex found
+/**************************************************************
+ * Utils
+ **************************************************************/
- failedCuts[cutKey] = true; // remember failure
- }
- if ( holeIndex >= 0 ) break; // hole-vertex found
- }
- }
+THREE.Curve.Utils = {
+
+ tangentQuadraticBezier: function ( t, p0, p1, p2 ) {
+
+ return 2 * ( 1 - t ) * ( p1 - p0 ) + 2 * t * ( p2 - p1 );
+
+ },
+
+ // Puay Bing, thanks for helping with this derivative!
+
+ tangentCubicBezier: function (t, p0, p1, p2, p3 ) {
+
+ return - 3 * p0 * (1 - t) * (1 - t) +
+ 3 * p1 * (1 - t) * (1-t) - 6 *t *p1 * (1-t) +
+ 6 * t * p2 * (1-t) - 3 * t * t * p2 +
+ 3 * t * t * p3;
+
+ },
+
+ tangentSpline: function ( t, p0, p1, p2, p3 ) {
+
+ // To check if my formulas are correct
+
+ var h00 = 6 * t * t - 6 * t; // derived from 2t^3 − 3t^2 + 1
+ var h10 = 3 * t * t - 4 * t + 1; // t^3 − 2t^2 + t
+ var h01 = - 6 * t * t + 6 * t; // − 2t3 + 3t2
+ var h11 = 3 * t * t - 2 * t; // t3 − t2
+
+ return h00 + h10 + h01 + h11;
+
+ },
+
+ // Catmull-Rom
+
+ interpolate: function( p0, p1, p2, p3, t ) {
+
+ var v0 = ( p2 - p0 ) * 0.5;
+ var v1 = ( p3 - p1 ) * 0.5;
+ var t2 = t * t;
+ var t3 = t * t2;
+ return ( 2 * p1 - 2 * p2 + v0 + v1 ) * t3 + ( - 3 * p1 + 3 * p2 - 2 * v0 - v1 ) * t2 + v0 * t + p1;
+
+ }
+
+};
+
+
+// TODO: Transformation for Curves?
+
+/**************************************************************
+ * 3D Curves
+ **************************************************************/
+
+// A Factory method for creating new curve subclasses
+
+THREE.Curve.create = function ( constructor, getPointFunc ) {
+
+ constructor.prototype = Object.create( THREE.Curve.prototype );
+ constructor.prototype.getPoint = getPointFunc;
+
+ return constructor;
+
+};
+
+// File:src/extras/core/CurvePath.js
+
+/**
+ * @author zz85 / http://www.lab4games.net/zz85/blog
+ *
+ **/
+
+/**************************************************************
+ * Curved Path - a curve path is simply a array of connected
+ * curves, but retains the api of a curve
+ **************************************************************/
+
+THREE.CurvePath = function () {
+
+ this.curves = [];
+ this.bends = [];
+
+ this.autoClose = false; // Automatically closes the path
+};
+
+THREE.CurvePath.prototype = Object.create( THREE.Curve.prototype );
+
+THREE.CurvePath.prototype.add = function ( curve ) {
+
+ this.curves.push( curve );
+
+};
+
+THREE.CurvePath.prototype.checkConnection = function() {
+ // TODO
+ // If the ending of curve is not connected to the starting
+ // or the next curve, then, this is not a real path
+};
+
+THREE.CurvePath.prototype.closePath = function() {
+ // TODO Test
+ // and verify for vector3 (needs to implement equals)
+ // Add a line curve if start and end of lines are not connected
+ var startPoint = this.curves[0].getPoint(0);
+ var endPoint = this.curves[this.curves.length-1].getPoint(1);
+
+ if (! startPoint.equals(endPoint)) {
+ this.curves.push( new THREE.LineCurve(endPoint, startPoint) );
+ }
+
+};
+
+// To get accurate point with reference to
+// entire path distance at time t,
+// following has to be done:
+
+// 1. Length of each sub path have to be known
+// 2. Locate and identify type of curve
+// 3. Get t for the curve
+// 4. Return curve.getPointAt(t')
+
+THREE.CurvePath.prototype.getPoint = function( t ) {
+
+ var d = t * this.getLength();
+ var curveLengths = this.getCurveLengths();
+ var i = 0, diff, curve;
+
+ // To think about boundaries points.
+
+ while ( i < curveLengths.length ) {
+
+ if ( curveLengths[ i ] >= d ) {
+
+ diff = curveLengths[ i ] - d;
+ curve = this.curves[ i ];
+
+ var u = 1 - diff / curve.getLength();
- return shape; /* shape with no holes */
+ return curve.getPointAt( u );
+
+ break;
}
+ i ++;
- var i, il, f, face,
- key, index,
- allPointsMap = {};
+ }
- // To maintain reference to old shape, one must match coordinates, or offset the indices from original arrays. It's probably easier to do the first.
+ return null;
- var allpoints = contour.concat();
+ // loop where sum != 0, sum > d , sum+1 maxX ) maxX = p.x;
+ else if ( p.x < minX ) minX = p.x;
- },
+ if ( p.y > maxY ) maxY = p.y;
+ else if ( p.y < minY ) minY = p.y;
- b2p1: function ( t, p ) {
+ if ( v3 ) {
- return 2 * ( 1 - t ) * t * p;
+ if ( p.z > maxZ ) maxZ = p.z;
+ else if ( p.z < minZ ) minZ = p.z;
- },
+ }
- b2p2: function ( t, p ) {
+ sum.add( p );
- return t * t * p;
+ }
- },
+ var ret = {
- b2: function ( t, p0, p1, p2 ) {
+ minX: minX,
+ minY: minY,
+ maxX: maxX,
+ maxY: maxY
- return this.b2p0( t, p0 ) + this.b2p1( t, p1 ) + this.b2p2( t, p2 );
+ };
- },
+ if ( v3 ) {
- // Cubic Bezier Functions
+ ret.maxZ = maxZ;
+ ret.minZ = minZ;
- b3p0: function ( t, p ) {
+ }
- var k = 1 - t;
- return k * k * k * p;
+ return ret;
- },
+};
- b3p1: function ( t, p ) {
+/**************************************************************
+ * Create Geometries Helpers
+ **************************************************************/
- var k = 1 - t;
- return 3 * k * k * t * p;
+/// Generate geometry from path points (for Line or Points objects)
- },
+THREE.CurvePath.prototype.createPointsGeometry = function( divisions ) {
- b3p2: function ( t, p ) {
+ var pts = this.getPoints( divisions, true );
+ return this.createGeometry( pts );
- var k = 1 - t;
- return 3 * k * t * t * p;
+};
- },
+// Generate geometry from equidistance sampling along the path
- b3p3: function ( t, p ) {
+THREE.CurvePath.prototype.createSpacedPointsGeometry = function( divisions ) {
- return t * t * t * p;
+ var pts = this.getSpacedPoints( divisions, true );
+ return this.createGeometry( pts );
- },
+};
- b3: function ( t, p0, p1, p2, p3 ) {
+THREE.CurvePath.prototype.createGeometry = function( points ) {
- return this.b3p0( t, p0 ) + this.b3p1( t, p1 ) + this.b3p2( t, p2 ) + this.b3p3( t, p3 );
+ var geometry = new THREE.Geometry();
+
+ for ( var i = 0; i < points.length; i ++ ) {
+
+ geometry.vertices.push( new THREE.Vector3( points[ i ].x, points[ i ].y, points[ i ].z || 0) );
}
-};
+ return geometry;
+};
-// File:src/extras/curves/LineCurve.js
/**************************************************************
- * Line
+ * Bend / Wrap Helper Methods
**************************************************************/
-THREE.LineCurve = function ( v1, v2 ) {
-
- this.v1 = v1;
- this.v2 = v2;
-
-};
+// Wrap path / Bend modifiers?
-THREE.LineCurve.prototype = Object.create( THREE.Curve.prototype );
+THREE.CurvePath.prototype.addWrapPath = function ( bendpath ) {
-THREE.LineCurve.prototype.getPoint = function ( t ) {
+ this.bends.push( bendpath );
- var point = this.v2.clone().sub(this.v1);
- point.multiplyScalar( t ).add( this.v1 );
+};
- return point;
+THREE.CurvePath.prototype.getTransformedPoints = function( segments, bends ) {
-};
+ var oldPts = this.getPoints( segments ); // getPoints getSpacedPoints
+ var i, il;
-// Line curve is linear, so we can overwrite default getPointAt
+ if ( ! bends ) {
-THREE.LineCurve.prototype.getPointAt = function ( u ) {
+ bends = this.bends;
- return this.getPoint( u );
+ }
-};
+ for ( i = 0, il = bends.length; i < il; i ++ ) {
-THREE.LineCurve.prototype.getTangent = function( t ) {
+ oldPts = this.getWrapPoints( oldPts, bends[ i ] );
- var tangent = this.v2.clone().sub(this.v1);
+ }
- return tangent.normalize();
+ return oldPts;
};
-// File:src/extras/curves/QuadraticBezierCurve.js
+THREE.CurvePath.prototype.getTransformedSpacedPoints = function( segments, bends ) {
-/**************************************************************
- * Quadratic Bezier curve
- **************************************************************/
+ var oldPts = this.getSpacedPoints( segments );
+
+ var i, il;
+ if ( ! bends ) {
-THREE.QuadraticBezierCurve = function ( v0, v1, v2 ) {
+ bends = this.bends;
- this.v0 = v0;
- this.v1 = v1;
- this.v2 = v2;
+ }
-};
+ for ( i = 0, il = bends.length; i < il; i ++ ) {
-THREE.QuadraticBezierCurve.prototype = Object.create( THREE.Curve.prototype );
+ oldPts = this.getWrapPoints( oldPts, bends[ i ] );
+ }
-THREE.QuadraticBezierCurve.prototype.getPoint = function ( t ) {
+ return oldPts;
- var tx, ty;
+};
- tx = THREE.Shape.Utils.b2( t, this.v0.x, this.v1.x, this.v2.x );
- ty = THREE.Shape.Utils.b2( t, this.v0.y, this.v1.y, this.v2.y );
+// This returns getPoints() bend/wrapped around the contour of a path.
+// Read http://www.planetclegg.com/projects/WarpingTextToSplines.html
- return new THREE.Vector2( tx, ty );
+THREE.CurvePath.prototype.getWrapPoints = function ( oldPts, path ) {
-};
+ var bounds = this.getBoundingBox();
+ var i, il, p, oldX, oldY, xNorm;
-THREE.QuadraticBezierCurve.prototype.getTangent = function( t ) {
+ for ( i = 0, il = oldPts.length; i < il; i ++ ) {
- var tx, ty;
+ p = oldPts[ i ];
- tx = THREE.Curve.Utils.tangentQuadraticBezier( t, this.v0.x, this.v1.x, this.v2.x );
- ty = THREE.Curve.Utils.tangentQuadraticBezier( t, this.v0.y, this.v1.y, this.v2.y );
+ oldX = p.x;
+ oldY = p.y;
- // returns unit vector
+ xNorm = oldX / bounds.maxX;
- var tangent = new THREE.Vector2( tx, ty );
- tangent.normalize();
+ // If using actual distance, for length > path, requires line extrusions
+ //xNorm = path.getUtoTmapping(xNorm, oldX); // 3 styles. 1) wrap stretched. 2) wrap stretch by arc length 3) warp by actual distance
- return tangent;
+ xNorm = path.getUtoTmapping( xNorm, oldX );
-};
+ // check for out of bounds?
-// File:src/extras/curves/CubicBezierCurve.js
+ var pathPt = path.getPoint( xNorm );
+ var normal = path.getTangent( xNorm );
+ normal.set( - normal.y, normal.x ).multiplyScalar( oldY );
-/**************************************************************
- * Cubic Bezier curve
- **************************************************************/
+ p.x = pathPt.x + normal.x;
+ p.y = pathPt.y + normal.y;
-THREE.CubicBezierCurve = function ( v0, v1, v2, v3 ) {
+ }
- this.v0 = v0;
- this.v1 = v1;
- this.v2 = v2;
- this.v3 = v3;
+ return oldPts;
};
-THREE.CubicBezierCurve.prototype = Object.create( THREE.Curve.prototype );
-THREE.CubicBezierCurve.prototype.getPoint = function ( t ) {
+// File:src/extras/core/Gyroscope.js
- var tx, ty;
+/**
+ * @author alteredq / http://alteredqualia.com/
+ */
- tx = THREE.Shape.Utils.b3( t, this.v0.x, this.v1.x, this.v2.x, this.v3.x );
- ty = THREE.Shape.Utils.b3( t, this.v0.y, this.v1.y, this.v2.y, this.v3.y );
+THREE.Gyroscope = function () {
- return new THREE.Vector2( tx, ty );
+ THREE.Object3D.call( this );
};
-THREE.CubicBezierCurve.prototype.getTangent = function( t ) {
+THREE.Gyroscope.prototype = Object.create( THREE.Object3D.prototype );
- var tx, ty;
+THREE.Gyroscope.prototype.updateMatrixWorld = ( function () {
- tx = THREE.Curve.Utils.tangentCubicBezier( t, this.v0.x, this.v1.x, this.v2.x, this.v3.x );
- ty = THREE.Curve.Utils.tangentCubicBezier( t, this.v0.y, this.v1.y, this.v2.y, this.v3.y );
+ var translationObject = new THREE.Vector3();
+ var quaternionObject = new THREE.Quaternion();
+ var scaleObject = new THREE.Vector3();
- var tangent = new THREE.Vector2( tx, ty );
- tangent.normalize();
+ var translationWorld = new THREE.Vector3();
+ var quaternionWorld = new THREE.Quaternion();
+ var scaleWorld = new THREE.Vector3();
- return tangent;
+ return function ( force ) {
-};
+ this.matrixAutoUpdate && this.updateMatrix();
-// File:src/extras/curves/SplineCurve.js
+ // update matrixWorld
-/**************************************************************
- * Spline curve
- **************************************************************/
+ if ( this.matrixWorldNeedsUpdate || force ) {
-THREE.SplineCurve = function ( points /* array of Vector2 */ ) {
+ if ( this.parent ) {
- this.points = (points == undefined) ? [] : points;
+ this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix );
-};
+ this.matrixWorld.decompose( translationWorld, quaternionWorld, scaleWorld );
+ this.matrix.decompose( translationObject, quaternionObject, scaleObject );
-THREE.SplineCurve.prototype = Object.create( THREE.Curve.prototype );
+ this.matrixWorld.compose( translationWorld, quaternionObject, scaleWorld );
-THREE.SplineCurve.prototype.getPoint = function ( t ) {
- var v = new THREE.Vector2();
- var c = [];
- var points = this.points, point, intPoint, weight;
- point = ( points.length - 1 ) * t;
+ } else {
- intPoint = Math.floor( point );
- weight = point - intPoint;
+ this.matrixWorld.copy( this.matrix );
- c[ 0 ] = intPoint == 0 ? intPoint : intPoint - 1;
- c[ 1 ] = intPoint;
- c[ 2 ] = intPoint > points.length - 2 ? points.length -1 : intPoint + 1;
- c[ 3 ] = intPoint > points.length - 3 ? points.length -1 : intPoint + 2;
+ }
- v.x = THREE.Curve.Utils.interpolate( points[ c[ 0 ] ].x, points[ c[ 1 ] ].x, points[ c[ 2 ] ].x, points[ c[ 3 ] ].x, weight );
- v.y = THREE.Curve.Utils.interpolate( points[ c[ 0 ] ].y, points[ c[ 1 ] ].y, points[ c[ 2 ] ].y, points[ c[ 3 ] ].y, weight );
- return v;
+ this.matrixWorldNeedsUpdate = false;
-};
+ force = true;
-// File:src/extras/curves/EllipseCurve.js
+ }
-/**************************************************************
- * Ellipse curve
- **************************************************************/
+ // update children
-THREE.EllipseCurve = function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise ) {
+ for ( var i = 0, l = this.children.length; i < l; i ++ ) {
- this.aX = aX;
- this.aY = aY;
+ this.children[ i ].updateMatrixWorld( force );
- this.xRadius = xRadius;
- this.yRadius = yRadius;
+ }
- this.aStartAngle = aStartAngle;
- this.aEndAngle = aEndAngle;
+ };
+
+}() );
- this.aClockwise = aClockwise;
+// File:src/extras/core/Path.js
-};
+/**
+ * @author zz85 / http://www.lab4games.net/zz85/blog
+ * Creates free form 2d path using series of points, lines or curves.
+ *
+ **/
-THREE.EllipseCurve.prototype = Object.create( THREE.Curve.prototype );
+THREE.Path = function ( points ) {
-THREE.EllipseCurve.prototype.getPoint = function ( t ) {
+ THREE.CurvePath.call(this);
- var angle;
- var deltaAngle = this.aEndAngle - this.aStartAngle;
+ this.actions = [];
- if ( deltaAngle < 0 ) deltaAngle += Math.PI * 2;
- if ( deltaAngle > Math.PI * 2 ) deltaAngle -= Math.PI * 2;
+ if ( points ) {
- if ( this.aClockwise === true ) {
+ this.fromPoints( points );
- angle = this.aEndAngle + ( 1 - t ) * ( Math.PI * 2 - deltaAngle );
+ }
- } else {
+};
- angle = this.aStartAngle + t * deltaAngle;
+THREE.Path.prototype = Object.create( THREE.CurvePath.prototype );
- }
+THREE.PathActions = {
+
+ MOVE_TO: 'moveTo',
+ LINE_TO: 'lineTo',
+ QUADRATIC_CURVE_TO: 'quadraticCurveTo', // Bezier quadratic curve
+ BEZIER_CURVE_TO: 'bezierCurveTo', // Bezier cubic curve
+ CSPLINE_THRU: 'splineThru', // Catmull-rom spline
+ ARC: 'arc', // Circle
+ ELLIPSE: 'ellipse'
+};
- var tx = this.aX + this.xRadius * Math.cos( angle );
- var ty = this.aY + this.yRadius * Math.sin( angle );
+// TODO Clean up PATH API
- return new THREE.Vector2( tx, ty );
+// Create path using straight lines to connect all points
+// - vectors: array of Vector2
-};
+THREE.Path.prototype.fromPoints = function ( vectors ) {
-// File:src/extras/curves/ArcCurve.js
+ this.moveTo( vectors[ 0 ].x, vectors[ 0 ].y );
-/**************************************************************
- * Arc curve
- **************************************************************/
+ for ( var v = 1, vlen = vectors.length; v < vlen; v ++ ) {
-THREE.ArcCurve = function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) {
+ this.lineTo( vectors[ v ].x, vectors[ v ].y );
+
+ };
- THREE.EllipseCurve.call( this, aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise );
};
-THREE.ArcCurve.prototype = Object.create( THREE.EllipseCurve.prototype );
+// startPath() endPath()?
-// File:src/extras/curves/LineCurve3.js
+THREE.Path.prototype.moveTo = function ( x, y ) {
-/**************************************************************
- * Line3D
- **************************************************************/
+ var args = Array.prototype.slice.call( arguments );
+ this.actions.push( { action: THREE.PathActions.MOVE_TO, args: args } );
-THREE.LineCurve3 = THREE.Curve.create(
+};
- function ( v1, v2 ) {
+THREE.Path.prototype.lineTo = function ( x, y ) {
- this.v1 = v1;
- this.v2 = v2;
+ var args = Array.prototype.slice.call( arguments );
- },
+ var lastargs = this.actions[ this.actions.length - 1 ].args;
- function ( t ) {
+ var x0 = lastargs[ lastargs.length - 2 ];
+ var y0 = lastargs[ lastargs.length - 1 ];
- var r = new THREE.Vector3();
+ var curve = new THREE.LineCurve( new THREE.Vector2( x0, y0 ), new THREE.Vector2( x, y ) );
+ this.curves.push( curve );
+ this.actions.push( { action: THREE.PathActions.LINE_TO, args: args } );
- r.subVectors( this.v2, this.v1 ); // diff
- r.multiplyScalar( t );
- r.add( this.v1 );
+};
- return r;
+THREE.Path.prototype.quadraticCurveTo = function( aCPx, aCPy, aX, aY ) {
- }
+ var args = Array.prototype.slice.call( arguments );
-);
+ var lastargs = this.actions[ this.actions.length - 1 ].args;
-// File:src/extras/curves/QuadraticBezierCurve3.js
+ var x0 = lastargs[ lastargs.length - 2 ];
+ var y0 = lastargs[ lastargs.length - 1 ];
-/**************************************************************
- * Quadratic Bezier 3D curve
- **************************************************************/
+ var curve = new THREE.QuadraticBezierCurve( new THREE.Vector2( x0, y0 ),
+ new THREE.Vector2( aCPx, aCPy ),
+ new THREE.Vector2( aX, aY ) );
+ this.curves.push( curve );
-THREE.QuadraticBezierCurve3 = THREE.Curve.create(
+ this.actions.push( { action: THREE.PathActions.QUADRATIC_CURVE_TO, args: args } );
- function ( v0, v1, v2 ) {
+};
- this.v0 = v0;
- this.v1 = v1;
- this.v2 = v2;
+THREE.Path.prototype.bezierCurveTo = function( aCP1x, aCP1y,
+ aCP2x, aCP2y,
+ aX, aY ) {
- },
+ var args = Array.prototype.slice.call( arguments );
- function ( t ) {
+ var lastargs = this.actions[ this.actions.length - 1 ].args;
- var tx, ty, tz;
+ var x0 = lastargs[ lastargs.length - 2 ];
+ var y0 = lastargs[ lastargs.length - 1 ];
- tx = THREE.Shape.Utils.b2( t, this.v0.x, this.v1.x, this.v2.x );
- ty = THREE.Shape.Utils.b2( t, this.v0.y, this.v1.y, this.v2.y );
- tz = THREE.Shape.Utils.b2( t, this.v0.z, this.v1.z, this.v2.z );
+ var curve = new THREE.CubicBezierCurve( new THREE.Vector2( x0, y0 ),
+ new THREE.Vector2( aCP1x, aCP1y ),
+ new THREE.Vector2( aCP2x, aCP2y ),
+ new THREE.Vector2( aX, aY ) );
+ this.curves.push( curve );
- return new THREE.Vector3( tx, ty, tz );
+ this.actions.push( { action: THREE.PathActions.BEZIER_CURVE_TO, args: args } );
- }
+};
-);
+THREE.Path.prototype.splineThru = function( pts /*Array of Vector*/ ) {
-// File:src/extras/curves/CubicBezierCurve3.js
+ var args = Array.prototype.slice.call( arguments );
+ var lastargs = this.actions[ this.actions.length - 1 ].args;
-/**************************************************************
- * Cubic Bezier 3D curve
- **************************************************************/
+ var x0 = lastargs[ lastargs.length - 2 ];
+ var y0 = lastargs[ lastargs.length - 1 ];
+//---
+ var npts = [ new THREE.Vector2( x0, y0 ) ];
+ Array.prototype.push.apply( npts, pts );
-THREE.CubicBezierCurve3 = THREE.Curve.create(
+ var curve = new THREE.SplineCurve( npts );
+ this.curves.push( curve );
- function ( v0, v1, v2, v3 ) {
+ this.actions.push( { action: THREE.PathActions.CSPLINE_THRU, args: args } );
- this.v0 = v0;
- this.v1 = v1;
- this.v2 = v2;
- this.v3 = v3;
+};
- },
+// FUTURE: Change the API or follow canvas API?
- function ( t ) {
+THREE.Path.prototype.arc = function ( aX, aY, aRadius,
+ aStartAngle, aEndAngle, aClockwise ) {
- var tx, ty, tz;
+ var lastargs = this.actions[ this.actions.length - 1].args;
+ var x0 = lastargs[ lastargs.length - 2 ];
+ var y0 = lastargs[ lastargs.length - 1 ];
- tx = THREE.Shape.Utils.b3( t, this.v0.x, this.v1.x, this.v2.x, this.v3.x );
- ty = THREE.Shape.Utils.b3( t, this.v0.y, this.v1.y, this.v2.y, this.v3.y );
- tz = THREE.Shape.Utils.b3( t, this.v0.z, this.v1.z, this.v2.z, this.v3.z );
+ this.absarc(aX + x0, aY + y0, aRadius,
+ aStartAngle, aEndAngle, aClockwise );
- return new THREE.Vector3( tx, ty, tz );
+ };
- }
+ THREE.Path.prototype.absarc = function ( aX, aY, aRadius,
+ aStartAngle, aEndAngle, aClockwise ) {
+ this.absellipse(aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise);
+ };
-);
+THREE.Path.prototype.ellipse = function ( aX, aY, xRadius, yRadius,
+ aStartAngle, aEndAngle, aClockwise ) {
-// File:src/extras/curves/SplineCurve3.js
+ var lastargs = this.actions[ this.actions.length - 1].args;
+ var x0 = lastargs[ lastargs.length - 2 ];
+ var y0 = lastargs[ lastargs.length - 1 ];
-/**************************************************************
- * Spline 3D curve
- **************************************************************/
+ this.absellipse(aX + x0, aY + y0, xRadius, yRadius,
+ aStartAngle, aEndAngle, aClockwise );
+ };
-THREE.SplineCurve3 = THREE.Curve.create(
- function ( points /* array of Vector3 */) {
+THREE.Path.prototype.absellipse = function ( aX, aY, xRadius, yRadius,
+ aStartAngle, aEndAngle, aClockwise ) {
+
+ var args = Array.prototype.slice.call( arguments );
+ var curve = new THREE.EllipseCurve( aX, aY, xRadius, yRadius,
+ aStartAngle, aEndAngle, aClockwise );
+ this.curves.push( curve );
- this.points = (points == undefined) ? [] : points;
+ var lastPoint = curve.getPoint(1);
+ args.push(lastPoint.x);
+ args.push(lastPoint.y);
- },
+ this.actions.push( { action: THREE.PathActions.ELLIPSE, args: args } );
- function ( t ) {
+ };
- var v = new THREE.Vector3();
- var c = [];
- var points = this.points, point, intPoint, weight;
- point = ( points.length - 1 ) * t;
+THREE.Path.prototype.getSpacedPoints = function ( divisions, closedPath ) {
- intPoint = Math.floor( point );
- weight = point - intPoint;
+ if ( ! divisions ) divisions = 40;
- c[ 0 ] = intPoint == 0 ? intPoint : intPoint - 1;
- c[ 1 ] = intPoint;
- c[ 2 ] = intPoint > points.length - 2 ? points.length - 1 : intPoint + 1;
- c[ 3 ] = intPoint > points.length - 3 ? points.length - 1 : intPoint + 2;
+ var points = [];
- var pt0 = points[ c[0] ],
- pt1 = points[ c[1] ],
- pt2 = points[ c[2] ],
- pt3 = points[ c[3] ];
+ for ( var i = 0; i < divisions; i ++ ) {
- v.x = THREE.Curve.Utils.interpolate(pt0.x, pt1.x, pt2.x, pt3.x, weight);
- v.y = THREE.Curve.Utils.interpolate(pt0.y, pt1.y, pt2.y, pt3.y, weight);
- v.z = THREE.Curve.Utils.interpolate(pt0.z, pt1.z, pt2.z, pt3.z, weight);
+ points.push( this.getPoint( i / divisions ) );
- return v;
+ //if( !this.getPoint( i / divisions ) ) throw "DIE";
}
-);
+ // if ( closedPath ) {
+ //
+ // points.push( points[ 0 ] );
+ //
+ // }
+ return points;
-// THREE.SplineCurve3.prototype.getTangent = function(t) {
-// var v = new THREE.Vector3();
-// var c = [];
-// var points = this.points, point, intPoint, weight;
-// point = ( points.length - 1 ) * t;
+};
-// intPoint = Math.floor( point );
-// weight = point - intPoint;
+/* Return an array of vectors based on contour of the path */
-// c[ 0 ] = intPoint == 0 ? intPoint : intPoint - 1;
-// c[ 1 ] = intPoint;
-// c[ 2 ] = intPoint > points.length - 2 ? points.length - 1 : intPoint + 1;
-// c[ 3 ] = intPoint > points.length - 3 ? points.length - 1 : intPoint + 2;
+THREE.Path.prototype.getPoints = function( divisions, closedPath ) {
-// var pt0 = points[ c[0] ],
-// pt1 = points[ c[1] ],
-// pt2 = points[ c[2] ],
-// pt3 = points[ c[3] ];
+ if (this.useSpacedPoints) {
+ console.log('tata');
+ return this.getSpacedPoints( divisions, closedPath );
+ }
-// // t = weight;
-// v.x = THREE.Curve.Utils.tangentSpline( t, pt0.x, pt1.x, pt2.x, pt3.x );
-// v.y = THREE.Curve.Utils.tangentSpline( t, pt0.y, pt1.y, pt2.y, pt3.y );
-// v.z = THREE.Curve.Utils.tangentSpline( t, pt0.z, pt1.z, pt2.z, pt3.z );
+ divisions = divisions || 12;
-// return v;
+ var points = [];
-// }
+ var i, il, item, action, args;
+ var cpx, cpy, cpx2, cpy2, cpx1, cpy1, cpx0, cpy0,
+ laste, j,
+ t, tx, ty;
-// File:src/extras/curves/ClosedSplineCurve3.js
+ for ( i = 0, il = this.actions.length; i < il; i ++ ) {
-/**************************************************************
- * Closed Spline 3D curve
- **************************************************************/
+ item = this.actions[ i ];
+ action = item.action;
+ args = item.args;
-THREE.ClosedSplineCurve3 = THREE.Curve.create(
+ switch( action ) {
- function ( points /* array of Vector3 */) {
+ case THREE.PathActions.MOVE_TO:
- this.points = (points == undefined) ? [] : points;
+ points.push( new THREE.Vector2( args[ 0 ], args[ 1 ] ) );
- },
+ break;
- function ( t ) {
+ case THREE.PathActions.LINE_TO:
- var v = new THREE.Vector3();
- var c = [];
- var points = this.points, point, intPoint, weight;
- point = ( points.length - 0 ) * t;
- // This needs to be from 0-length +1
+ points.push( new THREE.Vector2( args[ 0 ], args[ 1 ] ) );
- intPoint = Math.floor( point );
- weight = point - intPoint;
+ break;
- intPoint += intPoint > 0 ? 0 : ( Math.floor( Math.abs( intPoint ) / points.length ) + 1 ) * points.length;
- c[ 0 ] = ( intPoint - 1 ) % points.length;
- c[ 1 ] = ( intPoint ) % points.length;
- c[ 2 ] = ( intPoint + 1 ) % points.length;
- c[ 3 ] = ( intPoint + 2 ) % points.length;
+ case THREE.PathActions.QUADRATIC_CURVE_TO:
- v.x = THREE.Curve.Utils.interpolate( points[ c[ 0 ] ].x, points[ c[ 1 ] ].x, points[ c[ 2 ] ].x, points[ c[ 3 ] ].x, weight );
- v.y = THREE.Curve.Utils.interpolate( points[ c[ 0 ] ].y, points[ c[ 1 ] ].y, points[ c[ 2 ] ].y, points[ c[ 3 ] ].y, weight );
- v.z = THREE.Curve.Utils.interpolate( points[ c[ 0 ] ].z, points[ c[ 1 ] ].z, points[ c[ 2 ] ].z, points[ c[ 3 ] ].z, weight );
+ cpx = args[ 2 ];
+ cpy = args[ 3 ];
- return v;
+ cpx1 = args[ 0 ];
+ cpy1 = args[ 1 ];
- }
+ if ( points.length > 0 ) {
-);
+ laste = points[ points.length - 1 ];
-// File:src/extras/animation/AnimationHandler.js
+ cpx0 = laste.x;
+ cpy0 = laste.y;
-/**
- * @author mikael emtinger / http://gomo.se/
- */
+ } else {
-THREE.AnimationHandler = {
+ laste = this.actions[ i - 1 ].args;
- LINEAR: 0,
- CATMULLROM: 1,
- CATMULLROM_FORWARD: 2,
+ cpx0 = laste[ laste.length - 2 ];
+ cpy0 = laste[ laste.length - 1 ];
- //
+ }
- add: function () { console.warn( 'THREE.AnimationHandler.add() has been deprecated.' ); },
- get: function () { console.warn( 'THREE.AnimationHandler.get() has been deprecated.' ); },
- remove: function () { console.warn( 'THREE.AnimationHandler.remove() has been deprecated.' ); },
+ for ( j = 1; j <= divisions; j ++ ) {
- //
+ t = j / divisions;
- animations: [],
+ tx = THREE.Shape.Utils.b2( t, cpx0, cpx1, cpx );
+ ty = THREE.Shape.Utils.b2( t, cpy0, cpy1, cpy );
- init: function ( data ) {
+ points.push( new THREE.Vector2( tx, ty ) );
- if ( data.initialized === true ) return;
+ }
- // loop through all keys
+ break;
- for ( var h = 0; h < data.hierarchy.length; h ++ ) {
+ case THREE.PathActions.BEZIER_CURVE_TO:
- for ( var k = 0; k < data.hierarchy[ h ].keys.length; k ++ ) {
+ cpx = args[ 4 ];
+ cpy = args[ 5 ];
- // remove minus times
+ cpx1 = args[ 0 ];
+ cpy1 = args[ 1 ];
- if ( data.hierarchy[ h ].keys[ k ].time < 0 ) {
+ cpx2 = args[ 2 ];
+ cpy2 = args[ 3 ];
- data.hierarchy[ h ].keys[ k ].time = 0;
+ if ( points.length > 0 ) {
- }
+ laste = points[ points.length - 1 ];
- // create quaternions
+ cpx0 = laste.x;
+ cpy0 = laste.y;
- if ( data.hierarchy[ h ].keys[ k ].rot !== undefined &&
- ! ( data.hierarchy[ h ].keys[ k ].rot instanceof THREE.Quaternion ) ) {
+ } else {
- var quat = data.hierarchy[ h ].keys[ k ].rot;
- data.hierarchy[ h ].keys[ k ].rot = new THREE.Quaternion().fromArray( quat );
+ laste = this.actions[ i - 1 ].args;
- }
+ cpx0 = laste[ laste.length - 2 ];
+ cpy0 = laste[ laste.length - 1 ];
}
- // prepare morph target keys
-
- if ( data.hierarchy[ h ].keys.length && data.hierarchy[ h ].keys[ 0 ].morphTargets !== undefined ) {
- // get all used
+ for ( j = 1; j <= divisions; j ++ ) {
- var usedMorphTargets = {};
+ t = j / divisions;
- for ( var k = 0; k < data.hierarchy[ h ].keys.length; k ++ ) {
+ tx = THREE.Shape.Utils.b3( t, cpx0, cpx1, cpx2, cpx );
+ ty = THREE.Shape.Utils.b3( t, cpy0, cpy1, cpy2, cpy );
- for ( var m = 0; m < data.hierarchy[ h ].keys[ k ].morphTargets.length; m ++ ) {
+ points.push( new THREE.Vector2( tx, ty ) );
- var morphTargetName = data.hierarchy[ h ].keys[ k ].morphTargets[ m ];
- usedMorphTargets[ morphTargetName ] = - 1;
+ }
- }
+ break;
- }
+ case THREE.PathActions.CSPLINE_THRU:
- data.hierarchy[ h ].usedMorphTargets = usedMorphTargets;
+ laste = this.actions[ i - 1 ].args;
+ var last = new THREE.Vector2( laste[ laste.length - 2 ], laste[ laste.length - 1 ] );
+ var spts = [ last ];
- // set all used on all frames
+ var n = divisions * args[ 0 ].length;
- for ( var k = 0; k < data.hierarchy[ h ].keys.length; k ++ ) {
+ spts = spts.concat( args[ 0 ] );
- var influences = {};
+ var spline = new THREE.SplineCurve( spts );
- for ( var morphTargetName in usedMorphTargets ) {
+ for ( j = 1; j <= n; j ++ ) {
- for ( var m = 0; m < data.hierarchy[ h ].keys[ k ].morphTargets.length; m ++ ) {
+ points.push( spline.getPointAt( j / n ) ) ;
- if ( data.hierarchy[ h ].keys[ k ].morphTargets[ m ] === morphTargetName ) {
+ }
- influences[ morphTargetName ] = data.hierarchy[ h ].keys[ k ].morphTargetsInfluences[ m ];
- break;
+ break;
- }
+ case THREE.PathActions.ARC:
- }
+ var aX = args[ 0 ], aY = args[ 1 ],
+ aRadius = args[ 2 ],
+ aStartAngle = args[ 3 ], aEndAngle = args[ 4 ],
+ aClockwise = !! args[ 5 ];
- if ( m === data.hierarchy[ h ].keys[ k ].morphTargets.length ) {
+ var deltaAngle = aEndAngle - aStartAngle;
+ var angle;
+ var tdivisions = divisions * 2;
- influences[ morphTargetName ] = 0;
+ for ( j = 1; j <= tdivisions; j ++ ) {
- }
+ t = j / tdivisions;
- }
+ if ( ! aClockwise ) {
- data.hierarchy[ h ].keys[ k ].morphTargetsInfluences = influences;
+ t = 1 - t;
}
- }
+ angle = aStartAngle + t * deltaAngle;
+ tx = aX + aRadius * Math.cos( angle );
+ ty = aY + aRadius * Math.sin( angle );
- // remove all keys that are on the same time
+ //console.log('t', t, 'angle', angle, 'tx', tx, 'ty', ty);
- for ( var k = 1; k < data.hierarchy[ h ].keys.length; k ++ ) {
+ points.push( new THREE.Vector2( tx, ty ) );
- if ( data.hierarchy[ h ].keys[ k ].time === data.hierarchy[ h ].keys[ k - 1 ].time ) {
+ }
- data.hierarchy[ h ].keys.splice( k, 1 );
- k --;
+ //console.log(points);
- }
+ break;
+
+ case THREE.PathActions.ELLIPSE:
- }
+ var aX = args[ 0 ], aY = args[ 1 ],
+ xRadius = args[ 2 ],
+ yRadius = args[ 3 ],
+ aStartAngle = args[ 4 ], aEndAngle = args[ 5 ],
+ aClockwise = !! args[ 6 ];
- // set index
+ var deltaAngle = aEndAngle - aStartAngle;
+ var angle;
+ var tdivisions = divisions * 2;
- for ( var k = 0; k < data.hierarchy[ h ].keys.length; k ++ ) {
+ for ( j = 1; j <= tdivisions; j ++ ) {
- data.hierarchy[ h ].keys[ k ].index = k;
+ t = j / tdivisions;
- }
+ if ( ! aClockwise ) {
- }
+ t = 1 - t;
- data.initialized = true;
+ }
- return data;
+ angle = aStartAngle + t * deltaAngle;
- },
+ tx = aX + xRadius * Math.cos( angle );
+ ty = aY + yRadius * Math.sin( angle );
- parse: function ( root ) {
+ //console.log('t', t, 'angle', angle, 'tx', tx, 'ty', ty);
- var parseRecurseHierarchy = function ( root, hierarchy ) {
+ points.push( new THREE.Vector2( tx, ty ) );
- hierarchy.push( root );
+ }
- for ( var c = 0; c < root.children.length; c ++ )
- parseRecurseHierarchy( root.children[ c ], hierarchy );
+ //console.log(points);
- };
+ break;
- // setup hierarchy
+ } // end switch
- var hierarchy = [];
+ }
- if ( root instanceof THREE.SkinnedMesh ) {
- for ( var b = 0; b < root.skeleton.bones.length; b ++ ) {
- hierarchy.push( root.skeleton.bones[ b ] );
+ // Normalize to remove the closing point by default.
+ var lastPoint = points[ points.length - 1];
+ var EPSILON = 0.0000000001;
+ if ( Math.abs(lastPoint.x - points[ 0 ].x) < EPSILON &&
+ Math.abs(lastPoint.y - points[ 0 ].y) < EPSILON)
+ points.splice( points.length - 1, 1);
+ if ( closedPath ) {
- }
+ points.push( points[ 0 ] );
- } else {
+ }
- parseRecurseHierarchy( root, hierarchy );
+ return points;
- }
+};
- return hierarchy;
+//
+// Breaks path into shapes
+//
+// Assumptions (if parameter isCCW==true the opposite holds):
+// - solid shapes are defined clockwise (CW)
+// - holes are defined counterclockwise (CCW)
+//
+// If parameter noHoles==true:
+// - all subPaths are regarded as solid shapes
+// - definition order CW/CCW has no relevance
+//
- },
+THREE.Path.prototype.toShapes = function( isCCW, noHoles ) {
- play: function ( animation ) {
+ function extractSubpaths( inActions ) {
+
+ var i, il, item, action, args;
- if ( this.animations.indexOf( animation ) === - 1 ) {
+ var subPaths = [], lastPath = new THREE.Path();
- this.animations.push( animation );
+ for ( i = 0, il = inActions.length; i < il; i ++ ) {
- }
+ item = inActions[ i ];
- },
+ args = item.args;
+ action = item.action;
- stop: function ( animation ) {
+ if ( action == THREE.PathActions.MOVE_TO ) {
- var index = this.animations.indexOf( animation );
+ if ( lastPath.actions.length != 0 ) {
- if ( index !== - 1 ) {
+ subPaths.push( lastPath );
+ lastPath = new THREE.Path();
- this.animations.splice( index, 1 );
+ }
- }
+ }
- },
+ lastPath[ action ].apply( lastPath, args );
- update: function ( deltaTimeMS ) {
+ }
- for ( var i = 0; i < this.animations.length; i ++ ) {
+ if ( lastPath.actions.length != 0 ) {
- this.animations[ i ].update( deltaTimeMS );
+ subPaths.push( lastPath );
}
- }
+ // console.log(subPaths);
-};
+ return subPaths;
+ }
-// File:src/extras/animation/Animation.js
+ function toShapesNoHoles( inSubpaths ) {
-/**
- * @author mikael emtinger / http://gomo.se/
- * @author mrdoob / http://mrdoob.com/
- * @author alteredq / http://alteredqualia.com/
- */
+ var shapes = [];
-THREE.Animation = function ( root, data ) {
+ for ( var i = 0, il = inSubpaths.length; i < il; i ++ ) {
- this.root = root;
- this.data = THREE.AnimationHandler.init( data );
- this.hierarchy = THREE.AnimationHandler.parse( root );
+ var tmpPath = inSubpaths[ i ];
- this.currentTime = 0;
- this.timeScale = 1;
+ var tmpShape = new THREE.Shape();
+ tmpShape.actions = tmpPath.actions;
+ tmpShape.curves = tmpPath.curves;
- this.isPlaying = false;
- this.loop = true;
- this.weight = 0;
+ shapes.push( tmpShape );
+ }
- this.interpolationType = THREE.AnimationHandler.LINEAR;
+ //console.log("shape", shapes);
-};
+ return shapes;
+ };
+ function isPointInsidePolygon( inPt, inPolygon ) {
+ var EPSILON = 0.0000000001;
-THREE.Animation.prototype.keyTypes = [ "pos", "rot", "scl" ];
+ var polyLen = inPolygon.length;
+ // inPt on polygon contour => immediate success or
+ // toggling of inside/outside at every single! intersection point of an edge
+ // with the horizontal line through inPt, left of inPt
+ // not counting lowerY endpoints of edges and whole edges on that line
+ var inside = false;
+ for( var p = polyLen - 1, q = 0; q < polyLen; p = q ++ ) {
+ var edgeLowPt = inPolygon[ p ];
+ var edgeHighPt = inPolygon[ q ];
-THREE.Animation.prototype.play = function ( startTime, weight ) {
+ var edgeDx = edgeHighPt.x - edgeLowPt.x;
+ var edgeDy = edgeHighPt.y - edgeLowPt.y;
- this.currentTime = startTime !== undefined ? startTime : 0;
- this.weight = weight !== undefined ? weight: 1;
+ if ( Math.abs(edgeDy) > EPSILON ) { // not parallel
+ if ( edgeDy < 0 ) {
+ edgeLowPt = inPolygon[ q ]; edgeDx = - edgeDx;
+ edgeHighPt = inPolygon[ p ]; edgeDy = - edgeDy;
+ }
+ if ( ( inPt.y < edgeLowPt.y ) || ( inPt.y > edgeHighPt.y ) ) continue;
- this.isPlaying = true;
+ if ( inPt.y == edgeLowPt.y ) {
+ if ( inPt.x == edgeLowPt.x ) return true; // inPt is on contour ?
+ // continue; // no intersection or edgeLowPt => doesn't count !!!
+ } else {
+ var perpEdge = edgeDy * (inPt.x - edgeLowPt.x) - edgeDx * (inPt.y - edgeLowPt.y);
+ if ( perpEdge == 0 ) return true; // inPt is on contour ?
+ if ( perpEdge < 0 ) continue;
+ inside = ! inside; // true intersection left of inPt
+ }
+ } else { // parallel or colinear
+ if ( inPt.y != edgeLowPt.y ) continue; // parallel
+ // egde lies on the same horizontal line as inPt
+ if ( ( ( edgeHighPt.x <= inPt.x ) && ( inPt.x <= edgeLowPt.x ) ) ||
+ ( ( edgeLowPt.x <= inPt.x ) && ( inPt.x <= edgeHighPt.x ) ) ) return true; // inPt: Point on contour !
+ // continue;
+ }
+ }
- this.reset();
+ return inside;
+ }
- THREE.AnimationHandler.play( this );
-};
+ var subPaths = extractSubpaths( this.actions );
+ if ( subPaths.length == 0 ) return [];
+ if ( noHoles === true ) return toShapesNoHoles( subPaths );
-THREE.Animation.prototype.stop = function() {
- this.isPlaying = false;
+ var solid, tmpPath, tmpShape, shapes = [];
- THREE.AnimationHandler.stop( this );
+ if ( subPaths.length == 1) {
-};
+ tmpPath = subPaths[0];
+ tmpShape = new THREE.Shape();
+ tmpShape.actions = tmpPath.actions;
+ tmpShape.curves = tmpPath.curves;
+ shapes.push( tmpShape );
+ return shapes;
-THREE.Animation.prototype.reset = function () {
+ }
- for ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) {
+ var holesFirst = ! THREE.Shape.Utils.isClockWise( subPaths[ 0 ].getPoints() );
+ holesFirst = isCCW ? ! holesFirst : holesFirst;
- var object = this.hierarchy[ h ];
+ // console.log("Holes first", holesFirst);
+
+ var betterShapeHoles = [];
+ var newShapes = [];
+ var newShapeHoles = [];
+ var mainIdx = 0;
+ var tmpPoints;
- object.matrixAutoUpdate = true;
+ newShapes[mainIdx] = undefined;
+ newShapeHoles[mainIdx] = [];
- if ( object.animationCache === undefined ) {
+ var i, il;
- object.animationCache = {};
+ for ( i = 0, il = subPaths.length; i < il; i ++ ) {
- }
+ tmpPath = subPaths[ i ];
+ tmpPoints = tmpPath.getPoints();
+ solid = THREE.Shape.Utils.isClockWise( tmpPoints );
+ solid = isCCW ? ! solid : solid;
- if ( object.animationCache[this.data.name] === undefined ) {
+ if ( solid ) {
- object.animationCache[this.data.name] = {};
- object.animationCache[this.data.name].prevKey = { pos: 0, rot: 0, scl: 0 };
- object.animationCache[this.data.name].nextKey = { pos: 0, rot: 0, scl: 0 };
- object.animationCache[this.data.name].originalMatrix = object.matrix;
+ if ( (! holesFirst ) && ( newShapes[mainIdx] ) ) mainIdx ++;
- }
+ newShapes[mainIdx] = { s: new THREE.Shape(), p: tmpPoints };
+ newShapes[mainIdx].s.actions = tmpPath.actions;
+ newShapes[mainIdx].s.curves = tmpPath.curves;
+
+ if ( holesFirst ) mainIdx ++;
+ newShapeHoles[mainIdx] = [];
- var animationCache = object.animationCache[this.data.name];
+ //console.log('cw', i);
- // Get keys to match our current time
+ } else {
- for ( var t = 0; t < 3; t ++ ) {
+ newShapeHoles[mainIdx].push( { h: tmpPath, p: tmpPoints[0] } );
- var type = this.keyTypes[ t ];
+ //console.log('ccw', i);
- var prevKey = this.data.hierarchy[ h ].keys[ 0 ];
- var nextKey = this.getNextKeyWith( type, h, 1 );
+ }
- while ( nextKey.time < this.currentTime && nextKey.index > prevKey.index ) {
+ }
- prevKey = nextKey;
- nextKey = this.getNextKeyWith( type, h, nextKey.index + 1 );
+ // only Holes? -> probably all Shapes with wrong orientation
+ if ( ! newShapes[0] ) return toShapesNoHoles( subPaths );
- }
- animationCache.prevKey[ type ] = prevKey;
- animationCache.nextKey[ type ] = nextKey;
+ if ( newShapes.length > 1 ) {
+ var ambigious = false;
+ var toChange = [];
+ for (var sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) {
+ betterShapeHoles[sIdx] = [];
+ }
+ for (var sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) {
+ var sh = newShapes[sIdx];
+ var sho = newShapeHoles[sIdx];
+ for (var hIdx = 0; hIdx < sho.length; hIdx ++ ) {
+ var ho = sho[hIdx];
+ var hole_unassigned = true;
+ for (var s2Idx = 0; s2Idx < newShapes.length; s2Idx ++ ) {
+ if ( isPointInsidePolygon( ho.p, newShapes[s2Idx].p ) ) {
+ if ( sIdx != s2Idx ) toChange.push( { froms: sIdx, tos: s2Idx, hole: hIdx } );
+ if ( hole_unassigned ) {
+ hole_unassigned = false;
+ betterShapeHoles[s2Idx].push( ho );
+ } else {
+ ambigious = true;
+ }
+ }
+ }
+ if ( hole_unassigned ) { betterShapeHoles[sIdx].push( ho ); }
+ }
+ }
+ // console.log("ambigious: ", ambigious);
+ if ( toChange.length > 0 ) {
+ // console.log("to change: ", toChange);
+ if (! ambigious) newShapeHoles = betterShapeHoles;
}
+ }
+ var tmpHoles, j, jl;
+ for ( i = 0, il = newShapes.length; i < il; i ++ ) {
+ tmpShape = newShapes[i].s;
+ shapes.push( tmpShape );
+ tmpHoles = newShapeHoles[i];
+ for ( j = 0, jl = tmpHoles.length; j < jl; j ++ ) {
+ tmpShape.holes.push( tmpHoles[j].h );
+ }
}
+ //console.log("shape", shapes);
+
+ return shapes;
+
};
+// File:src/extras/core/Shape.js
-THREE.Animation.prototype.update = (function(){
+/**
+ * @author zz85 / http://www.lab4games.net/zz85/blog
+ * Defines a 2d shape plane using paths.
+ **/
- var points = [];
- var target = new THREE.Vector3();
- var newVector = new THREE.Vector3();
- var newQuat = new THREE.Quaternion();
+// STEP 1 Create a path.
+// STEP 2 Turn path into shape.
+// STEP 3 ExtrudeGeometry takes in Shape/Shapes
+// STEP 3a - Extract points from each shape, turn to vertices
+// STEP 3b - Triangulate each shape, add faces.
- // Catmull-Rom spline
+THREE.Shape = function () {
- var interpolateCatmullRom = function ( points, scale ) {
+ THREE.Path.apply( this, arguments );
+ this.holes = [];
- var c = [], v3 = [],
- point, intPoint, weight, w2, w3,
- pa, pb, pc, pd;
+};
- point = ( points.length - 1 ) * scale;
- intPoint = Math.floor( point );
- weight = point - intPoint;
+THREE.Shape.prototype = Object.create( THREE.Path.prototype );
- c[ 0 ] = intPoint === 0 ? intPoint : intPoint - 1;
- c[ 1 ] = intPoint;
- c[ 2 ] = intPoint > points.length - 2 ? intPoint : intPoint + 1;
- c[ 3 ] = intPoint > points.length - 3 ? intPoint : intPoint + 2;
+// Convenience method to return ExtrudeGeometry
+
+THREE.Shape.prototype.extrude = function ( options ) {
+
+ var extruded = new THREE.ExtrudeGeometry( this, options );
+ return extruded;
- pa = points[ c[ 0 ] ];
- pb = points[ c[ 1 ] ];
- pc = points[ c[ 2 ] ];
- pd = points[ c[ 3 ] ];
+};
- w2 = weight * weight;
- w3 = weight * w2;
+// Convenience method to return ShapeGeometry
- v3[ 0 ] = interpolate( pa[ 0 ], pb[ 0 ], pc[ 0 ], pd[ 0 ], weight, w2, w3 );
- v3[ 1 ] = interpolate( pa[ 1 ], pb[ 1 ], pc[ 1 ], pd[ 1 ], weight, w2, w3 );
- v3[ 2 ] = interpolate( pa[ 2 ], pb[ 2 ], pc[ 2 ], pd[ 2 ], weight, w2, w3 );
+THREE.Shape.prototype.makeGeometry = function ( options ) {
- return v3;
+ var geometry = new THREE.ShapeGeometry( this, options );
+ return geometry;
- };
+};
- var interpolate = function ( p0, p1, p2, p3, t, t2, t3 ) {
+// Get points of holes
- var v0 = ( p2 - p0 ) * 0.5,
- v1 = ( p3 - p1 ) * 0.5;
+THREE.Shape.prototype.getPointsHoles = function ( divisions ) {
- return ( 2 * ( p1 - p2 ) + v0 + v1 ) * t3 + ( - 3 * ( p1 - p2 ) - 2 * v0 - v1 ) * t2 + v0 * t + p1;
+ var i, il = this.holes.length, holesPts = [];
- };
+ for ( i = 0; i < il; i ++ ) {
- return function ( delta ) {
+ holesPts[ i ] = this.holes[ i ].getTransformedPoints( divisions, this.bends );
- if ( this.isPlaying === false ) return;
+ }
- this.currentTime += delta * this.timeScale;
+ return holesPts;
- if ( this.weight === 0 )
- return;
+};
- //
+// Get points of holes (spaced by regular distance)
- var duration = this.data.length;
+THREE.Shape.prototype.getSpacedPointsHoles = function ( divisions ) {
- if ( this.loop === true && this.currentTime > duration ) {
+ var i, il = this.holes.length, holesPts = [];
- this.currentTime %= duration;
- this.reset();
+ for ( i = 0; i < il; i ++ ) {
- } else if ( this.loop === false && this.currentTime > duration ) {
+ holesPts[ i ] = this.holes[ i ].getTransformedSpacedPoints( divisions, this.bends );
- this.stop();
- return;
+ }
- }
+ return holesPts;
- for ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) {
+};
- var object = this.hierarchy[ h ];
- var animationCache = object.animationCache[this.data.name];
- // loop through pos/rot/scl
+// Get points of shape and holes (keypoints based on segments parameter)
- for ( var t = 0; t < 3; t ++ ) {
+THREE.Shape.prototype.extractAllPoints = function ( divisions ) {
- // get keys
+ return {
- var type = this.keyTypes[ t ];
- var prevKey = animationCache.prevKey[ type ];
- var nextKey = animationCache.nextKey[ type ];
+ shape: this.getTransformedPoints( divisions ),
+ holes: this.getPointsHoles( divisions )
- if ( nextKey.time <= this.currentTime ) {
+ };
- prevKey = this.data.hierarchy[ h ].keys[ 0 ];
- nextKey = this.getNextKeyWith( type, h, 1 );
+};
- while ( nextKey.time < this.currentTime && nextKey.index > prevKey.index ) {
+THREE.Shape.prototype.extractPoints = function ( divisions ) {
- prevKey = nextKey;
- nextKey = this.getNextKeyWith( type, h, nextKey.index + 1 );
+ if (this.useSpacedPoints) {
+ return this.extractAllSpacedPoints(divisions);
+ }
- }
+ return this.extractAllPoints(divisions);
- animationCache.prevKey[ type ] = prevKey;
- animationCache.nextKey[ type ] = nextKey;
+};
- }
+//
+// THREE.Shape.prototype.extractAllPointsWithBend = function ( divisions, bend ) {
+//
+// return {
+//
+// shape: this.transform( bend, divisions ),
+// holes: this.getPointsHoles( divisions, bend )
+//
+// };
+//
+// };
- object.matrixAutoUpdate = true;
- object.matrixWorldNeedsUpdate = true;
+// Get points of shape and holes (spaced by regular distance)
- var scale = ( this.currentTime - prevKey.time ) / ( nextKey.time - prevKey.time );
+THREE.Shape.prototype.extractAllSpacedPoints = function ( divisions ) {
- var prevXYZ = prevKey[ type ];
- var nextXYZ = nextKey[ type ];
+ return {
- if ( scale < 0 ) scale = 0;
- if ( scale > 1 ) scale = 1;
+ shape: this.getTransformedSpacedPoints( divisions ),
+ holes: this.getSpacedPointsHoles( divisions )
- // interpolate
+ };
- if ( type === "pos" ) {
+};
- if ( this.interpolationType === THREE.AnimationHandler.LINEAR ) {
+/**************************************************************
+ * Utils
+ **************************************************************/
- newVector.x = prevXYZ[ 0 ] + ( nextXYZ[ 0 ] - prevXYZ[ 0 ] ) * scale;
- newVector.y = prevXYZ[ 1 ] + ( nextXYZ[ 1 ] - prevXYZ[ 1 ] ) * scale;
- newVector.z = prevXYZ[ 2 ] + ( nextXYZ[ 2 ] - prevXYZ[ 2 ] ) * scale;
+THREE.Shape.Utils = {
- // blend
- if ( object instanceof THREE.Bone ) {
+ triangulateShape: function ( contour, holes ) {
+
+ function point_in_segment_2D_colin( inSegPt1, inSegPt2, inOtherPt ) {
+ // inOtherPt needs to be colinear to the inSegment
+ if ( inSegPt1.x != inSegPt2.x ) {
+ if ( inSegPt1.x < inSegPt2.x ) {
+ return ( ( inSegPt1.x <= inOtherPt.x ) && ( inOtherPt.x <= inSegPt2.x ) );
+ } else {
+ return ( ( inSegPt2.x <= inOtherPt.x ) && ( inOtherPt.x <= inSegPt1.x ) );
+ }
+ } else {
+ if ( inSegPt1.y < inSegPt2.y ) {
+ return ( ( inSegPt1.y <= inOtherPt.y ) && ( inOtherPt.y <= inSegPt2.y ) );
+ } else {
+ return ( ( inSegPt2.y <= inOtherPt.y ) && ( inOtherPt.y <= inSegPt1.y ) );
+ }
+ }
+ }
- var proportionalWeight = this.weight / ( this.weight + object.accumulatedPosWeight );
- object.position.lerp( newVector, proportionalWeight );
- object.accumulatedPosWeight += this.weight;
+ function intersect_segments_2D( inSeg1Pt1, inSeg1Pt2, inSeg2Pt1, inSeg2Pt2, inExcludeAdjacentSegs ) {
+ var EPSILON = 0.0000000001;
- } else {
+ var seg1dx = inSeg1Pt2.x - inSeg1Pt1.x, seg1dy = inSeg1Pt2.y - inSeg1Pt1.y;
+ var seg2dx = inSeg2Pt2.x - inSeg2Pt1.x, seg2dy = inSeg2Pt2.y - inSeg2Pt1.y;
- object.position.copy( newVector );
+ var seg1seg2dx = inSeg1Pt1.x - inSeg2Pt1.x;
+ var seg1seg2dy = inSeg1Pt1.y - inSeg2Pt1.y;
- }
+ var limit = seg1dy * seg2dx - seg1dx * seg2dy;
+ var perpSeg1 = seg1dy * seg1seg2dx - seg1dx * seg1seg2dy;
- } else if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM ||
- this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) {
+ if ( Math.abs(limit) > EPSILON ) { // not parallel
- points[ 0 ] = this.getPrevKeyWith( "pos", h, prevKey.index - 1 )[ "pos" ];
- points[ 1 ] = prevXYZ;
- points[ 2 ] = nextXYZ;
- points[ 3 ] = this.getNextKeyWith( "pos", h, nextKey.index + 1 )[ "pos" ];
+ var perpSeg2;
+ if ( limit > 0 ) {
+ if ( ( perpSeg1 < 0 ) || ( perpSeg1 > limit ) ) return [];
+ perpSeg2 = seg2dy * seg1seg2dx - seg2dx * seg1seg2dy;
+ if ( ( perpSeg2 < 0 ) || ( perpSeg2 > limit ) ) return [];
+ } else {
+ if ( ( perpSeg1 > 0 ) || ( perpSeg1 < limit ) ) return [];
+ perpSeg2 = seg2dy * seg1seg2dx - seg2dx * seg1seg2dy;
+ if ( ( perpSeg2 > 0 ) || ( perpSeg2 < limit ) ) return [];
+ }
- scale = scale * 0.33 + 0.33;
+ // i.e. to reduce rounding errors
+ // intersection at endpoint of segment#1?
+ if ( perpSeg2 == 0 ) {
+ if ( ( inExcludeAdjacentSegs ) &&
+ ( ( perpSeg1 == 0 ) || ( perpSeg1 == limit ) ) ) return [];
+ return [ inSeg1Pt1 ];
+ }
+ if ( perpSeg2 == limit ) {
+ if ( ( inExcludeAdjacentSegs ) &&
+ ( ( perpSeg1 == 0 ) || ( perpSeg1 == limit ) ) ) return [];
+ return [ inSeg1Pt2 ];
+ }
+ // intersection at endpoint of segment#2?
+ if ( perpSeg1 == 0 ) return [ inSeg2Pt1 ];
+ if ( perpSeg1 == limit ) return [ inSeg2Pt2 ];
- var currentPoint = interpolateCatmullRom( points, scale );
- var proportionalWeight = 1;
-
- if ( object instanceof THREE.Bone ) {
+ // return real intersection point
+ var factorSeg1 = perpSeg2 / limit;
+ return [ { x: inSeg1Pt1.x + factorSeg1 * seg1dx,
+ y: inSeg1Pt1.y + factorSeg1 * seg1dy } ];
- proportionalWeight = this.weight / ( this.weight + object.accumulatedPosWeight );
- object.accumulatedPosWeight += this.weight;
+ } else { // parallel or colinear
+ if ( ( perpSeg1 != 0 ) ||
+ ( seg2dy * seg1seg2dx != seg2dx * seg1seg2dy ) ) return [];
- }
+ // they are collinear or degenerate
+ var seg1Pt = ( (seg1dx == 0) && (seg1dy == 0) ); // segment1 ist just a point?
+ var seg2Pt = ( (seg2dx == 0) && (seg2dy == 0) ); // segment2 ist just a point?
+ // both segments are points
+ if ( seg1Pt && seg2Pt ) {
+ if ( (inSeg1Pt1.x != inSeg2Pt1.x) ||
+ (inSeg1Pt1.y != inSeg2Pt1.y) ) return []; // they are distinct points
+ return [ inSeg1Pt1 ]; // they are the same point
+ }
+ // segment#1 is a single point
+ if ( seg1Pt ) {
+ if (! point_in_segment_2D_colin( inSeg2Pt1, inSeg2Pt2, inSeg1Pt1 ) ) return []; // but not in segment#2
+ return [ inSeg1Pt1 ];
+ }
+ // segment#2 is a single point
+ if ( seg2Pt ) {
+ if (! point_in_segment_2D_colin( inSeg1Pt1, inSeg1Pt2, inSeg2Pt1 ) ) return []; // but not in segment#1
+ return [ inSeg2Pt1 ];
+ }
- // blend
+ // they are collinear segments, which might overlap
+ var seg1min, seg1max, seg1minVal, seg1maxVal;
+ var seg2min, seg2max, seg2minVal, seg2maxVal;
+ if (seg1dx != 0) { // the segments are NOT on a vertical line
+ if ( inSeg1Pt1.x < inSeg1Pt2.x ) {
+ seg1min = inSeg1Pt1; seg1minVal = inSeg1Pt1.x;
+ seg1max = inSeg1Pt2; seg1maxVal = inSeg1Pt2.x;
+ } else {
+ seg1min = inSeg1Pt2; seg1minVal = inSeg1Pt2.x;
+ seg1max = inSeg1Pt1; seg1maxVal = inSeg1Pt1.x;
+ }
+ if ( inSeg2Pt1.x < inSeg2Pt2.x ) {
+ seg2min = inSeg2Pt1; seg2minVal = inSeg2Pt1.x;
+ seg2max = inSeg2Pt2; seg2maxVal = inSeg2Pt2.x;
+ } else {
+ seg2min = inSeg2Pt2; seg2minVal = inSeg2Pt2.x;
+ seg2max = inSeg2Pt1; seg2maxVal = inSeg2Pt1.x;
+ }
+ } else { // the segments are on a vertical line
+ if ( inSeg1Pt1.y < inSeg1Pt2.y ) {
+ seg1min = inSeg1Pt1; seg1minVal = inSeg1Pt1.y;
+ seg1max = inSeg1Pt2; seg1maxVal = inSeg1Pt2.y;
+ } else {
+ seg1min = inSeg1Pt2; seg1minVal = inSeg1Pt2.y;
+ seg1max = inSeg1Pt1; seg1maxVal = inSeg1Pt1.y;
+ }
+ if ( inSeg2Pt1.y < inSeg2Pt2.y ) {
+ seg2min = inSeg2Pt1; seg2minVal = inSeg2Pt1.y;
+ seg2max = inSeg2Pt2; seg2maxVal = inSeg2Pt2.y;
+ } else {
+ seg2min = inSeg2Pt2; seg2minVal = inSeg2Pt2.y;
+ seg2max = inSeg2Pt1; seg2maxVal = inSeg2Pt1.y;
+ }
+ }
+ if ( seg1minVal <= seg2minVal ) {
+ if ( seg1maxVal < seg2minVal ) return [];
+ if ( seg1maxVal == seg2minVal ) {
+ if ( inExcludeAdjacentSegs ) return [];
+ return [ seg2min ];
+ }
+ if ( seg1maxVal <= seg2maxVal ) return [ seg2min, seg1max ];
+ return [ seg2min, seg2max ];
+ } else {
+ if ( seg1minVal > seg2maxVal ) return [];
+ if ( seg1minVal == seg2maxVal ) {
+ if ( inExcludeAdjacentSegs ) return [];
+ return [ seg1min ];
+ }
+ if ( seg1maxVal <= seg2maxVal ) return [ seg1min, seg1max ];
+ return [ seg1min, seg2max ];
+ }
+ }
+ }
- var vector = object.position;
-
- vector.x = vector.x + ( currentPoint[ 0 ] - vector.x ) * proportionalWeight;
- vector.y = vector.y + ( currentPoint[ 1 ] - vector.y ) * proportionalWeight;
- vector.z = vector.z + ( currentPoint[ 2 ] - vector.z ) * proportionalWeight;
+ function isPointInsideAngle( inVertex, inLegFromPt, inLegToPt, inOtherPt ) {
+ // The order of legs is important
- if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) {
+ var EPSILON = 0.0000000001;
- var forwardPoint = interpolateCatmullRom( points, scale * 1.01 );
+ // translation of all points, so that Vertex is at (0,0)
+ var legFromPtX = inLegFromPt.x - inVertex.x, legFromPtY = inLegFromPt.y - inVertex.y;
+ var legToPtX = inLegToPt.x - inVertex.x, legToPtY = inLegToPt.y - inVertex.y;
+ var otherPtX = inOtherPt.x - inVertex.x, otherPtY = inOtherPt.y - inVertex.y;
- target.set( forwardPoint[ 0 ], forwardPoint[ 1 ], forwardPoint[ 2 ] );
- target.sub( vector );
- target.y = 0;
- target.normalize();
+ // main angle >0: < 180 deg.; 0: 180 deg.; <0: > 180 deg.
+ var from2toAngle = legFromPtX * legToPtY - legFromPtY * legToPtX;
+ var from2otherAngle = legFromPtX * otherPtY - legFromPtY * otherPtX;
- var angle = Math.atan2( target.x, target.z );
- object.rotation.set( 0, angle, 0 );
+ if ( Math.abs(from2toAngle) > EPSILON ) { // angle != 180 deg.
- }
+ var other2toAngle = otherPtX * legToPtY - otherPtY * legToPtX;
+ // console.log( "from2to: " + from2toAngle + ", from2other: " + from2otherAngle + ", other2to: " + other2toAngle );
- }
+ if ( from2toAngle > 0 ) { // main angle < 180 deg.
+ return ( ( from2otherAngle >= 0 ) && ( other2toAngle >= 0 ) );
+ } else { // main angle > 180 deg.
+ return ( ( from2otherAngle >= 0 ) || ( other2toAngle >= 0 ) );
+ }
+ } else { // angle == 180 deg.
+ // console.log( "from2to: 180 deg., from2other: " + from2otherAngle );
+ return ( from2otherAngle > 0 );
+ }
+ }
- } else if ( type === "rot" ) {
- THREE.Quaternion.slerp( prevXYZ, nextXYZ, newQuat, scale );
+ function removeHoles( contour, holes ) {
- // Avoid paying the cost of an additional slerp if we don't have to
- if ( ! ( object instanceof THREE.Bone ) ) {
+ var shape = contour.concat(); // work on this shape
+ var hole;
- object.quaternion.copy(newQuat);
+ function isCutLineInsideAngles( inShapeIdx, inHoleIdx ) {
+ // Check if hole point lies within angle around shape point
+ var lastShapeIdx = shape.length - 1;
- } else if ( object.accumulatedRotWeight === 0 ) {
+ var prevShapeIdx = inShapeIdx - 1;
+ if ( prevShapeIdx < 0 ) prevShapeIdx = lastShapeIdx;
- object.quaternion.copy(newQuat);
- object.accumulatedRotWeight = this.weight;
+ var nextShapeIdx = inShapeIdx + 1;
+ if ( nextShapeIdx > lastShapeIdx ) nextShapeIdx = 0;
- } else {
+ var insideAngle = isPointInsideAngle( shape[inShapeIdx], shape[ prevShapeIdx ], shape[ nextShapeIdx ], hole[inHoleIdx] );
+ if (! insideAngle ) {
+ // console.log( "Vertex (Shape): " + inShapeIdx + ", Point: " + hole[inHoleIdx].x + "/" + hole[inHoleIdx].y );
+ return false;
+ }
- var proportionalWeight = this.weight / ( this.weight + object.accumulatedRotWeight );
- THREE.Quaternion.slerp( object.quaternion, newQuat, object.quaternion, proportionalWeight );
- object.accumulatedRotWeight += this.weight;
+ // Check if shape point lies within angle around hole point
+ var lastHoleIdx = hole.length - 1;
- }
+ var prevHoleIdx = inHoleIdx - 1;
+ if ( prevHoleIdx < 0 ) prevHoleIdx = lastHoleIdx;
- } else if ( type === "scl" ) {
+ var nextHoleIdx = inHoleIdx + 1;
+ if ( nextHoleIdx > lastHoleIdx ) nextHoleIdx = 0;
- newVector.x = prevXYZ[ 0 ] + ( nextXYZ[ 0 ] - prevXYZ[ 0 ] ) * scale;
- newVector.y = prevXYZ[ 1 ] + ( nextXYZ[ 1 ] - prevXYZ[ 1 ] ) * scale;
- newVector.z = prevXYZ[ 2 ] + ( nextXYZ[ 2 ] - prevXYZ[ 2 ] ) * scale;
+ insideAngle = isPointInsideAngle( hole[inHoleIdx], hole[ prevHoleIdx ], hole[ nextHoleIdx ], shape[inShapeIdx] );
+ if (! insideAngle ) {
+ // console.log( "Vertex (Hole): " + inHoleIdx + ", Point: " + shape[inShapeIdx].x + "/" + shape[inShapeIdx].y );
+ return false;
+ }
- if ( object instanceof THREE.Bone ) {
+ return true;
+ }
- var proportionalWeight = this.weight / ( this.weight + object.accumulatedSclWeight);
- object.scale.lerp( newVector, proportionalWeight );
- object.accumulatedSclWeight += this.weight;
+ function intersectsShapeEdge( inShapePt, inHolePt ) {
+ // checks for intersections with shape edges
+ var sIdx, nextIdx, intersection;
+ for ( sIdx = 0; sIdx < shape.length; sIdx ++ ) {
+ nextIdx = sIdx+1; nextIdx %= shape.length;
+ intersection = intersect_segments_2D( inShapePt, inHolePt, shape[sIdx], shape[nextIdx], true );
+ if ( intersection.length > 0 ) return true;
+ }
- } else {
+ return false;
+ }
- object.scale.copy( newVector );
+ var indepHoles = [];
+ function intersectsHoleEdge( inShapePt, inHolePt ) {
+ // checks for intersections with hole edges
+ var ihIdx, chkHole,
+ hIdx, nextIdx, intersection;
+ for ( ihIdx = 0; ihIdx < indepHoles.length; ihIdx ++ ) {
+ chkHole = holes[indepHoles[ihIdx]];
+ for ( hIdx = 0; hIdx < chkHole.length; hIdx ++ ) {
+ nextIdx = hIdx+1; nextIdx %= chkHole.length;
+ intersection = intersect_segments_2D( inShapePt, inHolePt, chkHole[hIdx], chkHole[nextIdx], true );
+ if ( intersection.length > 0 ) return true;
}
-
}
-
+ return false;
}
- }
-
- return true;
-
- };
+ var holeIndex, shapeIndex,
+ shapePt, holePt,
+ holeIdx, cutKey, failedCuts = [],
+ tmpShape1, tmpShape2,
+ tmpHole1, tmpHole2;
-})();
+ for ( var h = 0, hl = holes.length; h < hl; h ++ ) {
+ indepHoles.push( h );
+ }
+ var minShapeIndex = 0;
+ var counter = indepHoles.length * 2;
+ while ( indepHoles.length > 0 ) {
+ counter --;
+ if ( counter < 0 ) {
+ console.log( "Infinite Loop! Holes left:" + indepHoles.length + ", Probably Hole outside Shape!" );
+ break;
+ }
+ // search for shape-vertex and hole-vertex,
+ // which can be connected without intersections
+ for ( shapeIndex = minShapeIndex; shapeIndex < shape.length; shapeIndex ++ ) {
-// Get next key with
+ shapePt = shape[ shapeIndex ];
+ holeIndex = - 1;
-THREE.Animation.prototype.getNextKeyWith = function ( type, h, key ) {
+ // search for hole which can be reached without intersections
+ for ( var h = 0; h < indepHoles.length; h ++ ) {
+ holeIdx = indepHoles[h];
- var keys = this.data.hierarchy[ h ].keys;
+ // prevent multiple checks
+ cutKey = shapePt.x + ":" + shapePt.y + ":" + holeIdx;
+ if ( failedCuts[cutKey] !== undefined ) continue;
- if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM ||
- this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) {
+ hole = holes[holeIdx];
+ for ( var h2 = 0; h2 < hole.length; h2 ++ ) {
+ holePt = hole[ h2 ];
+ if (! isCutLineInsideAngles( shapeIndex, h2 ) ) continue;
+ if ( intersectsShapeEdge( shapePt, holePt ) ) continue;
+ if ( intersectsHoleEdge( shapePt, holePt ) ) continue;
- key = key < keys.length - 1 ? key : keys.length - 1;
+ holeIndex = h2;
+ indepHoles.splice(h,1);
- } else {
+ tmpShape1 = shape.slice( 0, shapeIndex+1 );
+ tmpShape2 = shape.slice( shapeIndex );
+ tmpHole1 = hole.slice( holeIndex );
+ tmpHole2 = hole.slice( 0, holeIndex+1 );
- key = key % keys.length;
+ shape = tmpShape1.concat( tmpHole1 ).concat( tmpHole2 ).concat( tmpShape2 );
- }
+ minShapeIndex = shapeIndex;
- for ( ; key < keys.length; key ++ ) {
+ // Debug only, to show the selected cuts
+ // glob_CutLines.push( [ shapePt, holePt ] );
- if ( keys[ key ][ type ] !== undefined ) {
+ break;
+ }
+ if ( holeIndex >= 0 ) break; // hole-vertex found
- return keys[ key ];
+ failedCuts[cutKey] = true; // remember failure
+ }
+ if ( holeIndex >= 0 ) break; // hole-vertex found
+ }
+ }
+ return shape; /* shape with no holes */
}
- }
- return this.data.hierarchy[ h ].keys[ 0 ];
+ var i, il, f, face,
+ key, index,
+ allPointsMap = {};
-};
+ // To maintain reference to old shape, one must match coordinates, or offset the indices from original arrays. It's probably easier to do the first.
-// Get previous key with
+ var allpoints = contour.concat();
-THREE.Animation.prototype.getPrevKeyWith = function ( type, h, key ) {
+ for ( var h = 0, hl = holes.length; h < hl; h ++ ) {
- var keys = this.data.hierarchy[ h ].keys;
+ Array.prototype.push.apply( allpoints, holes[h] );
- if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM ||
- this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) {
+ }
- key = key > 0 ? key : 0;
+ //console.log( "allpoints",allpoints, allpoints.length );
- } else {
+ // prepare all points map
- key = key >= 0 ? key : key + keys.length;
+ for ( i = 0, il = allpoints.length; i < il; i ++ ) {
- }
+ key = allpoints[ i ].x + ":" + allpoints[ i ].y;
+ if ( allPointsMap[ key ] !== undefined ) {
- for ( ; key >= 0; key -- ) {
+ console.log( "Duplicate point", key );
- if ( keys[ key ][ type ] !== undefined ) {
+ }
- return keys[ key ];
+ allPointsMap[ key ] = i;
}
- }
+ // remove holes by cutting paths to holes and adding them to the shape
+ var shapeWithoutHoles = removeHoles( contour, holes );
- return this.data.hierarchy[ h ].keys[ keys.length - 1 ];
+ var triangles = THREE.FontUtils.Triangulate( shapeWithoutHoles, false ); // True returns indices for points of spooled shape
+ //console.log( "triangles",triangles, triangles.length );
-};
+ // check all face vertices against all points map
-// File:src/extras/animation/KeyFrameAnimation.js
+ for ( i = 0, il = triangles.length; i < il; i ++ ) {
-/**
- * @author mikael emtinger / http://gomo.se/
- * @author mrdoob / http://mrdoob.com/
- * @author alteredq / http://alteredqualia.com/
- * @author khang duong
- * @author erik kitson
- */
+ face = triangles[ i ];
-THREE.KeyFrameAnimation = function ( data ) {
+ for ( f = 0; f < 3; f ++ ) {
- this.root = data.node;
- this.data = THREE.AnimationHandler.init( data );
- this.hierarchy = THREE.AnimationHandler.parse( this.root );
- this.currentTime = 0;
- this.timeScale = 0.001;
- this.isPlaying = false;
- this.isPaused = true;
- this.loop = true;
+ key = face[ f ].x + ":" + face[ f ].y;
- // initialize to first keyframes
+ index = allPointsMap[ key ];
- for ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) {
+ if ( index !== undefined ) {
- var keys = this.data.hierarchy[h].keys,
- sids = this.data.hierarchy[h].sids,
- obj = this.hierarchy[h];
+ face[ f ] = index;
- if ( keys.length && sids ) {
+ }
- for ( var s = 0; s < sids.length; s ++ ) {
+ }
- var sid = sids[ s ],
- next = this.getNextKeyWith( sid, h, 0 );
+ }
+
+ return triangles.concat();
+
+ },
+
+ isClockWise: function ( pts ) {
- if ( next ) {
+ return THREE.FontUtils.Triangulate.area( pts ) < 0;
- next.apply( sid );
+ },
- }
+ // Bezier Curves formulas obtained from
+ // http://en.wikipedia.org/wiki/B%C3%A9zier_curve
- }
+ // Quad Bezier Functions
- obj.matrixAutoUpdate = false;
- this.data.hierarchy[h].node.updateMatrix();
- obj.matrixWorldNeedsUpdate = true;
+ b2p0: function ( t, p ) {
- }
+ var k = 1 - t;
+ return k * k * p;
- }
+ },
-};
+ b2p1: function ( t, p ) {
+ return 2 * ( 1 - t ) * t * p;
-THREE.KeyFrameAnimation.prototype.play = function ( startTime ) {
+ },
- this.currentTime = startTime !== undefined ? startTime : 0;
+ b2p2: function ( t, p ) {
- if ( this.isPlaying === false ) {
+ return t * t * p;
- this.isPlaying = true;
+ },
- // reset key cache
+ b2: function ( t, p0, p1, p2 ) {
- var h, hl = this.hierarchy.length,
- object,
- node;
+ return this.b2p0( t, p0 ) + this.b2p1( t, p1 ) + this.b2p2( t, p2 );
- for ( h = 0; h < hl; h ++ ) {
+ },
- object = this.hierarchy[ h ];
- node = this.data.hierarchy[ h ];
+ // Cubic Bezier Functions
- if ( node.animationCache === undefined ) {
+ b3p0: function ( t, p ) {
- node.animationCache = {};
- node.animationCache.prevKey = null;
- node.animationCache.nextKey = null;
- node.animationCache.originalMatrix = object.matrix;
+ var k = 1 - t;
+ return k * k * k * p;
- }
+ },
- var keys = this.data.hierarchy[h].keys;
+ b3p1: function ( t, p ) {
- if (keys.length) {
+ var k = 1 - t;
+ return 3 * k * k * t * p;
- node.animationCache.prevKey = keys[ 0 ];
- node.animationCache.nextKey = keys[ 1 ];
+ },
- this.startTime = Math.min( keys[0].time, this.startTime );
- this.endTime = Math.max( keys[keys.length - 1].time, this.endTime );
+ b3p2: function ( t, p ) {
- }
+ var k = 1 - t;
+ return 3 * k * t * t * p;
- }
+ },
- this.update( 0 );
+ b3p3: function ( t, p ) {
- }
+ return t * t * t * p;
- this.isPaused = false;
+ },
- THREE.AnimationHandler.play( this );
+ b3: function ( t, p0, p1, p2, p3 ) {
-};
+ return this.b3p0( t, p0 ) + this.b3p1( t, p1 ) + this.b3p2( t, p2 ) + this.b3p3( t, p3 );
+ }
-THREE.KeyFrameAnimation.prototype.stop = function() {
+};
- this.isPlaying = false;
- this.isPaused = false;
- THREE.AnimationHandler.stop( this );
+// File:src/extras/curves/LineCurve.js
- // reset JIT matrix and remove cache
+/**************************************************************
+ * Line
+ **************************************************************/
- for ( var h = 0; h < this.data.hierarchy.length; h ++ ) {
-
- var obj = this.hierarchy[ h ];
- var node = this.data.hierarchy[ h ];
+THREE.LineCurve = function ( v1, v2 ) {
- if ( node.animationCache !== undefined ) {
+ this.v1 = v1;
+ this.v2 = v2;
- var original = node.animationCache.originalMatrix;
+};
- original.copy( obj.matrix );
- obj.matrix = original;
+THREE.LineCurve.prototype = Object.create( THREE.Curve.prototype );
- delete node.animationCache;
+THREE.LineCurve.prototype.getPoint = function ( t ) {
- }
+ var point = this.v2.clone().sub(this.v1);
+ point.multiplyScalar( t ).add( this.v1 );
- }
+ return point;
};
+// Line curve is linear, so we can overwrite default getPointAt
-// Update
+THREE.LineCurve.prototype.getPointAt = function ( u ) {
-THREE.KeyFrameAnimation.prototype.update = function ( delta ) {
+ return this.getPoint( u );
- if ( this.isPlaying === false ) return;
+};
- this.currentTime += delta * this.timeScale;
+THREE.LineCurve.prototype.getTangent = function( t ) {
- //
+ var tangent = this.v2.clone().sub(this.v1);
- var duration = this.data.length;
+ return tangent.normalize();
- if ( this.loop === true && this.currentTime > duration ) {
+};
- this.currentTime %= duration;
+// File:src/extras/curves/QuadraticBezierCurve.js
- }
+/**************************************************************
+ * Quadratic Bezier curve
+ **************************************************************/
- this.currentTime = Math.min( this.currentTime, duration );
- for ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) {
+THREE.QuadraticBezierCurve = function ( v0, v1, v2 ) {
- var object = this.hierarchy[ h ];
- var node = this.data.hierarchy[ h ];
+ this.v0 = v0;
+ this.v1 = v1;
+ this.v2 = v2;
- var keys = node.keys,
- animationCache = node.animationCache;
+};
+THREE.QuadraticBezierCurve.prototype = Object.create( THREE.Curve.prototype );
- if ( keys.length ) {
- var prevKey = animationCache.prevKey;
- var nextKey = animationCache.nextKey;
+THREE.QuadraticBezierCurve.prototype.getPoint = function ( t ) {
- if ( nextKey.time <= this.currentTime ) {
+ var vector = new THREE.Vector2();
- while ( nextKey.time < this.currentTime && nextKey.index > prevKey.index ) {
+ vector.x = THREE.Shape.Utils.b2( t, this.v0.x, this.v1.x, this.v2.x );
+ vector.y = THREE.Shape.Utils.b2( t, this.v0.y, this.v1.y, this.v2.y );
- prevKey = nextKey;
- nextKey = keys[ prevKey.index + 1 ];
+ return vector;
- }
+};
- animationCache.prevKey = prevKey;
- animationCache.nextKey = nextKey;
- }
+THREE.QuadraticBezierCurve.prototype.getTangent = function( t ) {
- if ( nextKey.time >= this.currentTime ) {
+ var vector = new THREE.Vector2();
- prevKey.interpolate( nextKey, this.currentTime );
+ vector.x = THREE.Curve.Utils.tangentQuadraticBezier( t, this.v0.x, this.v1.x, this.v2.x );
+ vector.y = THREE.Curve.Utils.tangentQuadraticBezier( t, this.v0.y, this.v1.y, this.v2.y );
- } else {
+ // returns unit vector
- prevKey.interpolate( nextKey, nextKey.time );
+ return vector.normalize();
- }
+};
- this.data.hierarchy[ h ].node.updateMatrix();
- object.matrixWorldNeedsUpdate = true;
+// File:src/extras/curves/CubicBezierCurve.js
- }
+/**************************************************************
+ * Cubic Bezier curve
+ **************************************************************/
- }
+THREE.CubicBezierCurve = function ( v0, v1, v2, v3 ) {
+
+ this.v0 = v0;
+ this.v1 = v1;
+ this.v2 = v2;
+ this.v3 = v3;
};
-// Get next key with
+THREE.CubicBezierCurve.prototype = Object.create( THREE.Curve.prototype );
-THREE.KeyFrameAnimation.prototype.getNextKeyWith = function( sid, h, key ) {
+THREE.CubicBezierCurve.prototype.getPoint = function ( t ) {
- var keys = this.data.hierarchy[ h ].keys;
- key = key % keys.length;
+ var tx, ty;
- for ( ; key < keys.length; key ++ ) {
+ tx = THREE.Shape.Utils.b3( t, this.v0.x, this.v1.x, this.v2.x, this.v3.x );
+ ty = THREE.Shape.Utils.b3( t, this.v0.y, this.v1.y, this.v2.y, this.v3.y );
- if ( keys[ key ].hasTarget( sid ) ) {
+ return new THREE.Vector2( tx, ty );
- return keys[ key ];
+};
- }
+THREE.CubicBezierCurve.prototype.getTangent = function( t ) {
- }
+ var tx, ty;
- return keys[ 0 ];
+ tx = THREE.Curve.Utils.tangentCubicBezier( t, this.v0.x, this.v1.x, this.v2.x, this.v3.x );
+ ty = THREE.Curve.Utils.tangentCubicBezier( t, this.v0.y, this.v1.y, this.v2.y, this.v3.y );
-};
+ var tangent = new THREE.Vector2( tx, ty );
+ tangent.normalize();
-// Get previous key with
+ return tangent;
-THREE.KeyFrameAnimation.prototype.getPrevKeyWith = function( sid, h, key ) {
+};
- var keys = this.data.hierarchy[ h ].keys;
- key = key >= 0 ? key : key + keys.length;
+// File:src/extras/curves/SplineCurve.js
- for ( ; key >= 0; key -- ) {
+/**************************************************************
+ * Spline curve
+ **************************************************************/
- if ( keys[ key ].hasTarget( sid ) ) {
+THREE.SplineCurve = function ( points /* array of Vector2 */ ) {
- return keys[ key ];
+ this.points = ( points == undefined ) ? [] : points;
- }
+};
- }
+THREE.SplineCurve.prototype = Object.create( THREE.Curve.prototype );
- return keys[ keys.length - 1 ];
+THREE.SplineCurve.prototype.getPoint = function ( t ) {
-};
+ var points = this.points;
+ var point = ( points.length - 1 ) * t;
-// File:src/extras/animation/MorphAnimation.js
+ var intPoint = Math.floor( point );
+ var weight = point - intPoint;
-/**
- * @author mrdoob / http://mrdoob.com
- */
+ var point0 = points[ intPoint == 0 ? intPoint : intPoint - 1 ]
+ var point1 = points[ intPoint ]
+ var point2 = points[ intPoint > points.length - 2 ? points.length -1 : intPoint + 1 ]
+ var point3 = points[ intPoint > points.length - 3 ? points.length -1 : intPoint + 2 ]
-THREE.MorphAnimation = function ( mesh ) {
+ var vector = new THREE.Vector2();
- this.mesh = mesh;
- this.frames = mesh.morphTargetInfluences.length;
- this.currentTime = 0;
- this.duration = 1000;
- this.loop = true;
+ vector.x = THREE.Curve.Utils.interpolate( point0.x, point1.x, point2.x, point3.x, weight );
+ vector.y = THREE.Curve.Utils.interpolate( point0.y, point1.y, point2.y, point3.y, weight );
- this.isPlaying = false;
+ return vector;
};
-THREE.MorphAnimation.prototype = {
+// File:src/extras/curves/EllipseCurve.js
- play: function () {
+/**************************************************************
+ * Ellipse curve
+ **************************************************************/
- this.isPlaying = true;
+THREE.EllipseCurve = function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise ) {
- },
+ this.aX = aX;
+ this.aY = aY;
- pause: function () {
+ this.xRadius = xRadius;
+ this.yRadius = yRadius;
- this.isPlaying = false;
+ this.aStartAngle = aStartAngle;
+ this.aEndAngle = aEndAngle;
- },
+ this.aClockwise = aClockwise;
- update: ( function () {
+};
- var lastFrame = 0;
- var currentFrame = 0;
+THREE.EllipseCurve.prototype = Object.create( THREE.Curve.prototype );
- return function ( delta ) {
+THREE.EllipseCurve.prototype.getPoint = function ( t ) {
- if ( this.isPlaying === false ) return;
+ var deltaAngle = this.aEndAngle - this.aStartAngle;
- this.currentTime += delta;
+ if ( deltaAngle < 0 ) deltaAngle += Math.PI * 2;
+ if ( deltaAngle > Math.PI * 2 ) deltaAngle -= Math.PI * 2;
- if ( this.loop === true && this.currentTime > this.duration ) {
+ var angle;
- this.currentTime %= this.duration;
+ if ( this.aClockwise === true ) {
- }
+ angle = this.aEndAngle + ( 1 - t ) * ( Math.PI * 2 - deltaAngle );
- this.currentTime = Math.min( this.currentTime, this.duration );
+ } else {
- var interpolation = this.duration / this.frames;
- var frame = Math.floor( this.currentTime / interpolation );
+ angle = this.aStartAngle + t * deltaAngle;
- if ( frame != currentFrame ) {
+ }
+
+ var vector = new THREE.Vector2();
- this.mesh.morphTargetInfluences[ lastFrame ] = 0;
- this.mesh.morphTargetInfluences[ currentFrame ] = 1;
- this.mesh.morphTargetInfluences[ frame ] = 0;
+ vector.x = this.aX + this.xRadius * Math.cos( angle );
+ vector.y = this.aY + this.yRadius * Math.sin( angle );
- lastFrame = currentFrame;
- currentFrame = frame;
+ return vector;
- }
+};
- this.mesh.morphTargetInfluences[ frame ] = ( this.currentTime % interpolation ) / interpolation;
- this.mesh.morphTargetInfluences[ lastFrame ] = 1 - this.mesh.morphTargetInfluences[ frame ];
+// File:src/extras/curves/ArcCurve.js
- }
+/**************************************************************
+ * Arc curve
+ **************************************************************/
- } )()
+THREE.ArcCurve = function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) {
+ THREE.EllipseCurve.call( this, aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise );
};
-// File:src/extras/geometries/BoxGeometry.js
-
-/**
- * @author mrdoob / http://mrdoob.com/
- * based on http://papervision3d.googlecode.com/svn/trunk/as3/trunk/src/org/papervision3d/objects/primitives/Cube.as
- */
+THREE.ArcCurve.prototype = Object.create( THREE.EllipseCurve.prototype );
-THREE.BoxGeometry = function ( width, height, depth, widthSegments, heightSegments, depthSegments ) {
+// File:src/extras/curves/LineCurve3.js
- THREE.Geometry.call( this );
+/**************************************************************
+ * Line3D
+ **************************************************************/
- this.parameters = {
- width: width,
- height: height,
- depth: depth,
- widthSegments: widthSegments,
- heightSegments: heightSegments,
- depthSegments: depthSegments
- };
+THREE.LineCurve3 = THREE.Curve.create(
- this.widthSegments = widthSegments || 1;
- this.heightSegments = heightSegments || 1;
- this.depthSegments = depthSegments || 1;
+ function ( v1, v2 ) {
- var scope = this;
+ this.v1 = v1;
+ this.v2 = v2;
- var width_half = width / 2;
- var height_half = height / 2;
- var depth_half = depth / 2;
+ },
- buildPlane( 'z', 'y', - 1, - 1, depth, height, width_half, 0 ); // px
- buildPlane( 'z', 'y', 1, - 1, depth, height, - width_half, 1 ); // nx
- buildPlane( 'x', 'z', 1, 1, width, depth, height_half, 2 ); // py
- buildPlane( 'x', 'z', 1, - 1, width, depth, - height_half, 3 ); // ny
- buildPlane( 'x', 'y', 1, - 1, width, height, depth_half, 4 ); // pz
- buildPlane( 'x', 'y', - 1, - 1, width, height, - depth_half, 5 ); // nz
+ function ( t ) {
- function buildPlane( u, v, udir, vdir, width, height, depth, materialIndex ) {
+ var vector = new THREE.Vector3();
- var w, ix, iy,
- gridX = scope.widthSegments,
- gridY = scope.heightSegments,
- width_half = width / 2,
- height_half = height / 2,
- offset = scope.vertices.length;
+ vector.subVectors( this.v2, this.v1 ); // diff
+ vector.multiplyScalar( t );
+ vector.add( this.v1 );
- if ( ( u === 'x' && v === 'y' ) || ( u === 'y' && v === 'x' ) ) {
+ return vector;
- w = 'z';
+ }
- } else if ( ( u === 'x' && v === 'z' ) || ( u === 'z' && v === 'x' ) ) {
+);
- w = 'y';
- gridY = scope.depthSegments;
+// File:src/extras/curves/QuadraticBezierCurve3.js
- } else if ( ( u === 'z' && v === 'y' ) || ( u === 'y' && v === 'z' ) ) {
+/**************************************************************
+ * Quadratic Bezier 3D curve
+ **************************************************************/
- w = 'x';
- gridX = scope.depthSegments;
+THREE.QuadraticBezierCurve3 = THREE.Curve.create(
- }
+ function ( v0, v1, v2 ) {
- var gridX1 = gridX + 1,
- gridY1 = gridY + 1,
- segment_width = width / gridX,
- segment_height = height / gridY,
- normal = new THREE.Vector3();
+ this.v0 = v0;
+ this.v1 = v1;
+ this.v2 = v2;
- normal[ w ] = depth > 0 ? 1 : - 1;
+ },
- for ( iy = 0; iy < gridY1; iy ++ ) {
+ function ( t ) {
- for ( ix = 0; ix < gridX1; ix ++ ) {
+ var vector = new THREE.Vector3();
- var vector = new THREE.Vector3();
- vector[ u ] = ( ix * segment_width - width_half ) * udir;
- vector[ v ] = ( iy * segment_height - height_half ) * vdir;
- vector[ w ] = depth;
+ vector.x = THREE.Shape.Utils.b2( t, this.v0.x, this.v1.x, this.v2.x );
+ vector.y = THREE.Shape.Utils.b2( t, this.v0.y, this.v1.y, this.v2.y );
+ vector.z = THREE.Shape.Utils.b2( t, this.v0.z, this.v1.z, this.v2.z );
- scope.vertices.push( vector );
+ return vector;
- }
+ }
- }
+);
- for ( iy = 0; iy < gridY; iy ++ ) {
+// File:src/extras/curves/CubicBezierCurve3.js
- for ( ix = 0; ix < gridX; ix ++ ) {
+/**************************************************************
+ * Cubic Bezier 3D curve
+ **************************************************************/
- var a = ix + gridX1 * iy;
- var b = ix + gridX1 * ( iy + 1 );
- var c = ( ix + 1 ) + gridX1 * ( iy + 1 );
- var d = ( ix + 1 ) + gridX1 * iy;
+THREE.CubicBezierCurve3 = THREE.Curve.create(
- var uva = new THREE.Vector2( ix / gridX, 1 - iy / gridY );
- var uvb = new THREE.Vector2( ix / gridX, 1 - ( iy + 1 ) / gridY );
- var uvc = new THREE.Vector2( ( ix + 1 ) / gridX, 1 - ( iy + 1 ) / gridY );
- var uvd = new THREE.Vector2( ( ix + 1 ) / gridX, 1 - iy / gridY );
+ function ( v0, v1, v2, v3 ) {
- var face = new THREE.Face3( a + offset, b + offset, d + offset );
- face.normal.copy( normal );
- face.vertexNormals.push( normal.clone(), normal.clone(), normal.clone() );
- face.materialIndex = materialIndex;
+ this.v0 = v0;
+ this.v1 = v1;
+ this.v2 = v2;
+ this.v3 = v3;
- scope.faces.push( face );
- scope.faceVertexUvs[ 0 ].push( [ uva, uvb, uvd ] );
+ },
- face = new THREE.Face3( b + offset, c + offset, d + offset );
- face.normal.copy( normal );
- face.vertexNormals.push( normal.clone(), normal.clone(), normal.clone() );
- face.materialIndex = materialIndex;
+ function ( t ) {
- scope.faces.push( face );
- scope.faceVertexUvs[ 0 ].push( [ uvb.clone(), uvc, uvd.clone() ] );
+ var vector = new THREE.Vector3();
- }
+ vector.x = THREE.Shape.Utils.b3( t, this.v0.x, this.v1.x, this.v2.x, this.v3.x );
+ vector.y = THREE.Shape.Utils.b3( t, this.v0.y, this.v1.y, this.v2.y, this.v3.y );
+ vector.z = THREE.Shape.Utils.b3( t, this.v0.z, this.v1.z, this.v2.z, this.v3.z );
- }
+ return vector;
}
- this.mergeVertices();
-
-};
+);
-THREE.BoxGeometry.prototype = Object.create( THREE.Geometry.prototype );
+// File:src/extras/curves/SplineCurve3.js
-// File:src/extras/geometries/CircleGeometry.js
+/**************************************************************
+ * Spline 3D curve
+ **************************************************************/
-/**
- * @author hughes
- */
-THREE.CircleGeometry = function ( radius, segments, thetaStart, thetaLength ) {
+THREE.SplineCurve3 = THREE.Curve.create(
- THREE.Geometry.call( this );
+ function ( points /* array of Vector3 */) {
- this.parameters = {
- radius: radius,
- segments: segments,
- thetaStart: thetaStart,
- thetaLength: thetaLength
- };
+ this.points = ( points == undefined ) ? [] : points;
- radius = radius || 50;
- segments = segments !== undefined ? Math.max( 3, segments ) : 8;
+ },
- thetaStart = thetaStart !== undefined ? thetaStart : 0;
- thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2;
+ function ( t ) {
- var i, uvs = [],
- center = new THREE.Vector3(), centerUV = new THREE.Vector2( 0.5, 0.5 );
+ var points = this.points;
+ var point = ( points.length - 1 ) * t;
- this.vertices.push(center);
- uvs.push( centerUV );
+ var intPoint = Math.floor( point );
+ var weight = point - intPoint;
- for ( i = 0; i <= segments; i ++ ) {
+ var point0 = points[ intPoint == 0 ? intPoint : intPoint - 1 ];
+ var point1 = points[ intPoint ];
+ var point2 = points[ intPoint > points.length - 2 ? points.length - 1 : intPoint + 1 ];
+ var point3 = points[ intPoint > points.length - 3 ? points.length - 1 : intPoint + 2 ];
- var vertex = new THREE.Vector3();
- var segment = thetaStart + i / segments * thetaLength;
+ var vector = new THREE.Vector3();
- vertex.x = radius * Math.cos( segment );
- vertex.y = radius * Math.sin( segment );
+ vector.x = THREE.Curve.Utils.interpolate( point0.x, point1.x, point2.x, point3.x, weight );
+ vector.y = THREE.Curve.Utils.interpolate( point0.y, point1.y, point2.y, point3.y, weight );
+ vector.z = THREE.Curve.Utils.interpolate( point0.z, point1.z, point2.z, point3.z, weight );
- this.vertices.push( vertex );
- uvs.push( new THREE.Vector2( ( vertex.x / radius + 1 ) / 2, ( vertex.y / radius + 1 ) / 2 ) );
+ return vector;
}
- var n = new THREE.Vector3( 0, 0, 1 );
+);
- for ( i = 1; i <= segments; i ++ ) {
+// File:src/extras/curves/ClosedSplineCurve3.js
- this.faces.push( new THREE.Face3( i, i + 1, 0, [ n.clone(), n.clone(), n.clone() ] ) );
- this.faceVertexUvs[ 0 ].push( [ uvs[ i ].clone(), uvs[ i + 1 ].clone(), centerUV.clone() ] );
+/**************************************************************
+ * Closed Spline 3D curve
+ **************************************************************/
- }
- this.computeFaceNormals();
+THREE.ClosedSplineCurve3 = THREE.Curve.create(
- this.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius );
+ function ( points /* array of Vector3 */) {
-};
+ this.points = ( points == undefined ) ? [] : points;
-THREE.CircleGeometry.prototype = Object.create( THREE.Geometry.prototype );
+ },
-// File:src/extras/geometries/CubeGeometry.js
+ function ( t ) {
-/**
- * @author mrdoob / http://mrdoob.com/
- */
+ var points = this.points;
+ var point = ( points.length - 0 ) * t; // This needs to be from 0-length +1
+ var intPoint = Math.floor( point );
+ var weight = point - intPoint;
-THREE.CubeGeometry = function ( width, height, depth, widthSegments, heightSegments, depthSegments ) {
+ intPoint += intPoint > 0 ? 0 : ( Math.floor( Math.abs( intPoint ) / points.length ) + 1 ) * points.length;
- console.warn( 'THEE.CubeGeometry has been renamed to THREE.BoxGeometry.' );
- return new THREE.BoxGeometry( width, height, depth, widthSegments, heightSegments, depthSegments );
+ var point0 = points[ ( intPoint - 1 ) % points.length ];
+ var point1 = points[ ( intPoint ) % points.length ];
+ var point2 = points[ ( intPoint + 1 ) % points.length ];
+ var point3 = points[ ( intPoint + 2 ) % points.length ];
- };
+ var vector = new THREE.Vector3();
-// File:src/extras/geometries/CylinderGeometry.js
+ vector.x = THREE.Curve.Utils.interpolate( point0.x, point1.x, point2.x, point3.x, weight );
+ vector.y = THREE.Curve.Utils.interpolate( point0.y, point1.y, point2.y, point3.y, weight );
+ vector.z = THREE.Curve.Utils.interpolate( point0.z, point1.z, point2.z, point3.z, weight );
+
+ return vector;
+
+ }
+
+);
+
+// File:src/extras/animation/AnimationHandler.js
/**
- * @author mrdoob / http://mrdoob.com/
+ * @author mikael emtinger / http://gomo.se/
*/
-THREE.CylinderGeometry = function ( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded ) {
+THREE.AnimationHandler = {
- THREE.Geometry.call( this );
+ LINEAR: 0,
+ CATMULLROM: 1,
+ CATMULLROM_FORWARD: 2,
- this.parameters = {
- radiusTop: radiusTop,
- radiusBottom: radiusBottom,
- height: height,
- radialSegments: radialSegments,
- heightSegments: heightSegments,
- openEnded: openEnded
- };
+ //
+
+ add: function () { console.warn( 'THREE.AnimationHandler.add() has been deprecated.' ); },
+ get: function () { console.warn( 'THREE.AnimationHandler.get() has been deprecated.' ); },
+ remove: function () { console.warn( 'THREE.AnimationHandler.remove() has been deprecated.' ); },
- radiusTop = radiusTop !== undefined ? radiusTop : 20;
- radiusBottom = radiusBottom !== undefined ? radiusBottom : 20;
- height = height !== undefined ? height : 100;
+ //
- radialSegments = radialSegments || 8;
- heightSegments = heightSegments || 1;
+ animations: [],
- openEnded = openEnded !== undefined ? openEnded : false;
+ init: function ( data ) {
- var heightHalf = height / 2;
+ if ( data.initialized === true ) return;
- var x, y, vertices = [], uvs = [];
+ // loop through all keys
- for ( y = 0; y <= heightSegments; y ++ ) {
+ for ( var h = 0; h < data.hierarchy.length; h ++ ) {
- var verticesRow = [];
- var uvsRow = [];
+ for ( var k = 0; k < data.hierarchy[ h ].keys.length; k ++ ) {
- var v = y / heightSegments;
- var radius = v * ( radiusBottom - radiusTop ) + radiusTop;
+ // remove minus times
- for ( x = 0; x <= radialSegments; x ++ ) {
+ if ( data.hierarchy[ h ].keys[ k ].time < 0 ) {
- var u = x / radialSegments;
+ data.hierarchy[ h ].keys[ k ].time = 0;
- var vertex = new THREE.Vector3();
- vertex.x = radius * Math.sin( u * Math.PI * 2 );
- vertex.y = - v * height + heightHalf;
- vertex.z = radius * Math.cos( u * Math.PI * 2 );
+ }
- this.vertices.push( vertex );
+ // create quaternions
- verticesRow.push( this.vertices.length - 1 );
- uvsRow.push( new THREE.Vector2( u, 1 - v ) );
+ if ( data.hierarchy[ h ].keys[ k ].rot !== undefined &&
+ ! ( data.hierarchy[ h ].keys[ k ].rot instanceof THREE.Quaternion ) ) {
- }
+ var quat = data.hierarchy[ h ].keys[ k ].rot;
+ data.hierarchy[ h ].keys[ k ].rot = new THREE.Quaternion().fromArray( quat );
- vertices.push( verticesRow );
- uvs.push( uvsRow );
+ }
- }
+ }
- var tanTheta = ( radiusBottom - radiusTop ) / height;
- var na, nb;
+ // prepare morph target keys
- for ( x = 0; x < radialSegments; x ++ ) {
+ if ( data.hierarchy[ h ].keys.length && data.hierarchy[ h ].keys[ 0 ].morphTargets !== undefined ) {
- if ( radiusTop !== 0 ) {
+ // get all used
- na = this.vertices[ vertices[ 0 ][ x ] ].clone();
- nb = this.vertices[ vertices[ 0 ][ x + 1 ] ].clone();
+ var usedMorphTargets = {};
- } else {
+ for ( var k = 0; k < data.hierarchy[ h ].keys.length; k ++ ) {
- na = this.vertices[ vertices[ 1 ][ x ] ].clone();
- nb = this.vertices[ vertices[ 1 ][ x + 1 ] ].clone();
+ for ( var m = 0; m < data.hierarchy[ h ].keys[ k ].morphTargets.length; m ++ ) {
- }
+ var morphTargetName = data.hierarchy[ h ].keys[ k ].morphTargets[ m ];
+ usedMorphTargets[ morphTargetName ] = - 1;
- na.setY( Math.sqrt( na.x * na.x + na.z * na.z ) * tanTheta ).normalize();
- nb.setY( Math.sqrt( nb.x * nb.x + nb.z * nb.z ) * tanTheta ).normalize();
+ }
- for ( y = 0; y < heightSegments; y ++ ) {
+ }
- var v1 = vertices[ y ][ x ];
- var v2 = vertices[ y + 1 ][ x ];
- var v3 = vertices[ y + 1 ][ x + 1 ];
- var v4 = vertices[ y ][ x + 1 ];
+ data.hierarchy[ h ].usedMorphTargets = usedMorphTargets;
- var n1 = na.clone();
- var n2 = na.clone();
- var n3 = nb.clone();
- var n4 = nb.clone();
- var uv1 = uvs[ y ][ x ].clone();
- var uv2 = uvs[ y + 1 ][ x ].clone();
- var uv3 = uvs[ y + 1 ][ x + 1 ].clone();
- var uv4 = uvs[ y ][ x + 1 ].clone();
+ // set all used on all frames
- this.faces.push( new THREE.Face3( v1, v2, v4, [ n1, n2, n4 ] ) );
- this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv4 ] );
+ for ( var k = 0; k < data.hierarchy[ h ].keys.length; k ++ ) {
- this.faces.push( new THREE.Face3( v2, v3, v4, [ n2.clone(), n3, n4.clone() ] ) );
- this.faceVertexUvs[ 0 ].push( [ uv2.clone(), uv3, uv4.clone() ] );
+ var influences = {};
- }
+ for ( var morphTargetName in usedMorphTargets ) {
- }
+ for ( var m = 0; m < data.hierarchy[ h ].keys[ k ].morphTargets.length; m ++ ) {
- // top cap
+ if ( data.hierarchy[ h ].keys[ k ].morphTargets[ m ] === morphTargetName ) {
- if ( openEnded === false && radiusTop > 0 ) {
+ influences[ morphTargetName ] = data.hierarchy[ h ].keys[ k ].morphTargetsInfluences[ m ];
+ break;
- this.vertices.push( new THREE.Vector3( 0, heightHalf, 0 ) );
+ }
- for ( x = 0; x < radialSegments; x ++ ) {
+ }
- var v1 = vertices[ 0 ][ x ];
- var v2 = vertices[ 0 ][ x + 1 ];
- var v3 = this.vertices.length - 1;
+ if ( m === data.hierarchy[ h ].keys[ k ].morphTargets.length ) {
- var n1 = new THREE.Vector3( 0, 1, 0 );
- var n2 = new THREE.Vector3( 0, 1, 0 );
- var n3 = new THREE.Vector3( 0, 1, 0 );
+ influences[ morphTargetName ] = 0;
- var uv1 = uvs[ 0 ][ x ].clone();
- var uv2 = uvs[ 0 ][ x + 1 ].clone();
- var uv3 = new THREE.Vector2( uv2.x, 0 );
+ }
- this.faces.push( new THREE.Face3( v1, v2, v3, [ n1, n2, n3 ] ) );
- this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv3 ] );
+ }
- }
+ data.hierarchy[ h ].keys[ k ].morphTargetsInfluences = influences;
- }
+ }
- // bottom cap
+ }
- if ( openEnded === false && radiusBottom > 0 ) {
- this.vertices.push( new THREE.Vector3( 0, - heightHalf, 0 ) );
+ // remove all keys that are on the same time
- for ( x = 0; x < radialSegments; x ++ ) {
+ for ( var k = 1; k < data.hierarchy[ h ].keys.length; k ++ ) {
- var v1 = vertices[ y ][ x + 1 ];
- var v2 = vertices[ y ][ x ];
- var v3 = this.vertices.length - 1;
+ if ( data.hierarchy[ h ].keys[ k ].time === data.hierarchy[ h ].keys[ k - 1 ].time ) {
- var n1 = new THREE.Vector3( 0, - 1, 0 );
- var n2 = new THREE.Vector3( 0, - 1, 0 );
- var n3 = new THREE.Vector3( 0, - 1, 0 );
+ data.hierarchy[ h ].keys.splice( k, 1 );
+ k --;
- var uv1 = uvs[ y ][ x + 1 ].clone();
- var uv2 = uvs[ y ][ x ].clone();
- var uv3 = new THREE.Vector2( uv2.x, 1 );
+ }
- this.faces.push( new THREE.Face3( v1, v2, v3, [ n1, n2, n3 ] ) );
- this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv3 ] );
+ }
- }
- }
+ // set index
- this.computeFaceNormals();
+ for ( var k = 0; k < data.hierarchy[ h ].keys.length; k ++ ) {
-}
+ data.hierarchy[ h ].keys[ k ].index = k;
-THREE.CylinderGeometry.prototype = Object.create( THREE.Geometry.prototype );
+ }
-// File:src/extras/geometries/ExtrudeGeometry.js
+ }
-/**
- * @author zz85 / http://www.lab4games.net/zz85/blog
- *
- * Creates extruded geometry from a path shape.
- *
- * parameters = {
- *
- * curveSegments: , // number of points on the curves
- * steps: , // number of points for z-side extrusions / used for subdividing segements of extrude spline too
- * amount: , // Depth to extrude the shape
- *
- * bevelEnabled: , // turn on bevel
- * bevelThickness: , // how deep into the original shape bevel goes
- * bevelSize: , // how far from shape outline is bevel
- * bevelSegments: , // number of bevel layers
- *
- * extrudePath: // 3d spline path to extrude shape along. (creates Frames if .frames aren't defined)
- * frames: // containing arrays of tangents, normals, binormals
- *
- * material: // material index for front and back faces
- * extrudeMaterial: // material index for extrusion and beveled faces
- * uvGenerator: