Browse Source

Merge branch 'dev' of https://github.com/mrdoob/three.js into dev

hena-3 10 years ago
parent
commit
73524eabfe

File diff suppressed because it is too large
+ 260 - 84
build/three.js


File diff suppressed because it is too large
+ 77 - 71
build/three.min.js


+ 20 - 2
docs/api/core/Geometry.html

@@ -102,12 +102,30 @@
 
 		<h3>[property:Array skinWeights]</h3>
 		<div>
-		Array of skinning weights, matching number and order of vertices.
+		Array of [page:Vector4 Vector4s] representing the skinning weights as used in a [page:SkinnedMesh],
+		The weights match the number and order of vertices in the geometry. The weighted values
+		are typically between the values of 0 and 1 and affect the amount that the individuals bones affect
+		a given vertex.
 		</div>
 
 		<h3>[property:Array skinIndices]</h3>
 		<div>
-		Array of skinning indices, matching number and order of vertices.
+		Array of [page:Vector4 Vector4s] representing the indices of individual bones in the [page:Skeleton.bones] array,
+		The indices match the number and order of vertices in the geometry.
+		<code>
+		// e.g.
+		geometry.skinIndices[15] = new THREE.Vector4(   0,   5,   9, 0 );
+		geometry.skinWeights[15] = new THREE.Vector4( 0.2, 0.5, 0.3, 0 );
+		
+		// corresponds with the following vertex
+		geometry.vertices[15];
+		
+		// these bones will be used like so:
+		skeleton.bones[0]; // weight of 0.2
+		skeleton.bones[5]; // weight of 0.5
+		skeleton.bones[9]; // weight of 0.3
+		skeleton.bones[0]; // weight of 0
+		</code>
 		</div>
 
 		<h3>[property:Object boundingBox]</h3>

+ 17 - 8
docs/api/objects/Bone.html

@@ -11,25 +11,34 @@
 
 		<h1>[name]</h1>
 
-		<div class="desc">A bone which is part of a [page:SkinnedMesh].</div>
-
+		<div class="desc">
+		A bone which is part of a [page:Skeleton]. The skeleton in turn is used by the [page:SkinnedMesh].
+		Bones are almost identical to a blank [page:Object3D].
+		</div>
+		
+		<h3>Example</h3>
+		
+		<code>
+		var root = new THREE.Bone();
+		var child = new THREE.Bone();
+		
+		root.add( child );
+		child.position.y = 5;
+		</code>
 
 		<h2>Constructor</h2>
 
 
-		<h3>[name]([page:SkinnedMesh belongsToSkin])</h3>
-		<div>
-		belongsToSkin -- An instance of [page:SkinnedMesh].
-		</div>
+		<h3>[name]([page:SkinnedMesh skin])</h3>
 		<div>
-		This creates a new instance of a bone from the skin.
+		skin — (optional) The [page:SkinnedMesh] to which the bone belongs.
 		</div>
 
 		<h2>Properties</h2>
 
 		<h3>[property:SkinnedMesh skin]</h3>
 		<div>
-		The skin that contains this bone.
+		An optional reference to the [page:SkinnedMesh].
 		</div>
 
 

+ 128 - 0
docs/api/objects/Skeleton.html

@@ -0,0 +1,128 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<meta charset="utf-8" />
+		<script src="../../list.js"></script>
+		<script src="../../page.js"></script>
+		<link type="text/css" rel="stylesheet" href="../../page.css" />
+	</head>
+	<body>
+		
+		<h1>[name]</h1>
+
+		<div class="desc">
+		Use an array of [page:Bone bones] to create a skeleton that can be used by a [page:SkinnedMesh].
+		WebGL only.
+		</div>
+
+		<h2>Example</h2>
+
+		<code>
+		// Create a simple "arm"
+		
+		var bones = [];
+		
+		var shoulder = new THREE.Bone();
+		var elbow = new THREE.Bone();
+		var hand = new THREE.Bone();
+		
+		shoulder.add( elbow );
+		elbow.add( hand );
+
+		bones.push( shoulder );
+		bones.push( elbow );
+		bones.push( hand );
+		
+		shoulder.position.y = -5;
+		elbow.position.y = 0;
+		hand.position.y = 5;
+		
+		var armSkeleton = THREE.Skeleton( bones );
+		
+		// See THREE.SkinnedMesh for an example of usage with a mesh
+		</code>
+
+		<h2>Constructor</h2>
+
+
+		<h3>[name]( [page:Array bones], [page:Array boneInverses], [page:Boolean useVertexTexture]  )</h3>
+		<div>
+		bones — The array of [page:bone bones]<br/>
+		boneInverses — (optional) An array of [page:Matrix4 Matrix4s]<br/>
+		useVertexTexture — (optional) Whether or not to use a vertex texture in the shader.
+		</div>
+		<div>
+		The constructor automatically sets up all of the properties below.
+		</div>
+
+
+		<h2>Properties</h2>
+		
+		<h3>[property:Array bones]</h3>
+		<div>
+		The array of [page:bone bones]
+		</div>
+		
+		
+		<h3>[property:Boolean useVertexTexture]</h3>
+		<div>
+		Whether or not to use a vertex texture in the shader, set in the constructor. Not all devices
+		support floating point pixel textures. If this option is set then the bone matrices will be packed into
+		a texture and sent to the shader. This method allows a much larger set of bones to be used. Otherwise
+		the vertex shader will use uniforms, which do not allow for as many bones to be used. The exact
+		numbers vary between devices.
+		</div>
+		
+		
+		<h3>[property:Array boneInverses]</h3>
+		<div>
+		An array of [page:Matrix4 Matrix4s] that represent the inverse of the matrixWorld of the individual bones.
+		</div>
+		
+		
+		<h3>[property:Integer boneTextureWidth]</h3>
+		<div>
+		The width of the vertex data texture.
+		</div>
+		
+		
+		<h3>[property:Integer boneTextureHeight]</h3>
+		<div>
+		The height of the vertex data texture.
+		</div>
+		
+		
+		<h3>[property:Float32Array boneMatrices]</h3>
+		<div>
+		The array buffer holding the bone data when using a vertex texture.
+		</div>
+		
+		
+		<h3>[property:DataTexture boneTexture]</h3>
+		<div>
+		The [page:DataTexture] holding the bone data when using a vertex texture.
+		</div>
+		
+
+		<h2>Methods</h2>
+
+		<h3>[method:null calculateInverses]()</h3>
+		<div>Generates the boneInverses.</div>
+		
+		
+		<h3>[method:null pose]()</h3>
+		<div>Returns the skeleton to the base pose.</div>
+		
+		
+		<h3>[method:null update]()</h3>
+		<div>
+		Updates the [page:Float32Array boneMatrices] and [page:DataTexture boneTexture] after changing the bones.
+		This is called automatically by the [page:WebGLRenderer] if the skeleton is used with a [page:SkinnedMesh].
+		</div>
+		
+		
+		<h2>Source</h2>
+
+		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
+	</body>
+</html>

+ 76 - 12
docs/api/objects/SkinnedMesh.html

@@ -11,27 +11,60 @@
 
 		<h1>[name]</h1>
 
-		<div class="desc">An 3d object that has bones data. These Bones can then be used to animate the vertices of the object.</div>
-
+		<div class="desc">A mesh that has a [page:Skeleton] with [page:Bone bones] that can then be used to animate the vertices of the geometry.</div>
+
+		<h2>Example</h2>
+		
+		<iframe src='../../scenes/bones-browser.html'></iframe>
+		
+		<code>
+		var geometry = new THREE.CylinderGeometry( 5, 5, 5, 5, 15, 5, 30 );
+		
+		//Create the skin indices and skin weights
+		for ( var i = 0; i < geometry.vertices.length; i ++ ) {
+			
+			// Imaginary functions to calculate the indices and weights
+			var skinIndex = calculateSkinIndex( geometry.vertices, i );
+			var skinWeight = calculateSkinWeight( geometry.vertices, i );
+			
+			// Ease between each bone
+			geometry.skinIndices.push( new THREE.Vector4( skinIndex, skinIndex + 1, 0, 0 ) );
+			geometry.skinWeights.push( new THREE.Vector4( 1 - skinWeight, skinWeight, 0, 0 ) );		
+			
+		}
+		
+		var mesh = THREE.SkinnedMesh( geometry, material );
+
+		// See example from THREE.Skeleton for the armSkeleton
+		var rootBone = armSkeleton.bones[ 0 ];
+		mesh.add( rootBone );
+		
+		// Bind the skeleton to the mesh
+		mesh.bind( armSkeleton );
+		
+		// Update the inverse matrices in the skeleton to reflect the newly bound skeleton
+		armSkeleton.calculateInverses();
+		
+		// Move the bones and manipulate the model
+		armSkeleton.bones[ 0 ].rotation.x = -0.1;
+		armSkeleton.bones[ 1 ].rotation.x = 0.2;
+		</code>
+		
 
 		<h2>Constructor</h2>
 
 
 		<h3>[name]([page:Geometry geometry], [page:Material material], [page:boolean useVertexTexture])</h3>
 		<div>
-                geometry — An instance of [page:Geometry].<br />
-                material — An instance of [page:Material] (optional).<br />
-		useVertexTexture -- Defines wether a vertex texture can be used (optional).
-		</div>
-		<div>
-		This Creates a new instance of skinnedMesh.
+        geometry — An instance of [page:Geometry]. [page:Geometry.skinIndices] and [page:Geometry.skinWeights] should be set.<br />
+        material — An instance of [page:Material] (optional).<br />
+		useVertexTexture -- Defines whether a vertex texture can be used (optional).
 		</div>
 
 
 		<h2>Properties</h2>
 
 
-
 		<h3>[property:array bones]</h3>
 		<div>
 		This contains the array of bones for this mesh. These should be set in the constructor.
@@ -52,19 +85,50 @@
 		This array of matrices contains the matrices of the bones. These get calculated in the constructor.
 		</div>
 
+		<h3>[property:string bindMode]</h3>
+		<div>
+		Either "attached" or "detached". "attached" uses the [page:SkinnedMesh.matrixWorld] property for the base transform
+		matrix of the bones. "detached" uses the [page:SkinnedMesh.bindMatrix].
+		</div>
+		
+		<h3>[property:Matrix4 bindMatrix]</h3>
+		<div>
+		The base matrix that is used for the bound bone transforms.
+		</div>
+
+		<h3>[property:Matrix4 inverseBindMatrix]</h3>
+		<div>
+		The inverse of the bindMatrix.
+		</div>
+
 		<h2>Methods</h2>
 
+		<h3>[method:null bind]([page:Skeleton skeleton], [page:Matrix4 bindMatrix])</h3>
+		<div>
+		skeleton — [page:Skeleton]<br/>
+		bindMatrix — [page:Matrix4] that represents the base transform of the skeleton
+		</div>
+		<div>
+		Bind a skeleton to the skinned mesh. The bindMatrix gets saved to .bindMatrix property and the .bindMatrixInverse
+		gets calculated.
+		</div>
+		
+		<h3>[method:null normalizeSkinWeights]()</h3>
+		<div>
+		Normalizes the [page:Geometry.skinWeights] vectors. Does not affect [page:BufferGeometry].
+		</div>
+
 		<h3>[method:null pose]()</h3>
 		<div>
-		This method sets the skinnedmesh in the rest pose.
+		This method sets the skinned mesh in the rest pose.
 		</div>
 
 		<h3>[method:Bone addBone]([page:Bone bone])</h3>
 		<div>
-		bone -- This is the bone that needs to be added. (optional)
+		bone  This is the bone that needs to be added. (optional)
 		</div>
 		<div>
-		This method adds the bone to the skinnedmesh when it is provided. It creates a new bone and adds that when no bone is given.
+		This method adds the bone to the skinned mesh when it is provided. It creates a new bone and adds that when no bone is given.
 		</div>
 
 		<h2>Source</h2>

+ 1 - 0
docs/list.js

@@ -116,6 +116,7 @@ var list = {
 			[ "MorphAnimMesh", "api/objects/MorphAnimMesh" ],
 			[ "PointCloud", "api/objects/PointCloud" ],
 			[ "SkinnedMesh", "api/objects/SkinnedMesh" ],
+			[ "Skeleton", "api/objects/Skeleton" ],
 			[ "Sprite", "api/objects/Sprite" ]
 		],
 

+ 2 - 0
docs/manual/introduction/Creating-a-scene.html

@@ -21,8 +21,10 @@
 		<div>Before you can use Three.js, you need somewhere to display it. Save the following HTML to a file on your computer, along with a copy of <a href="http://threejs.org/build/three.min.js">three.min.js</a> in the js/ directory, and open it in your browser.</div>
 
 		<code>
+		&lt;!DOCTYPE html&gt;
 		&lt;html&gt;
 			&lt;head&gt;
+				&lt;meta charset=utf-8&gt;
 				&lt;title&gt;My first Three.js app&lt;/title&gt;
 				&lt;style&gt;
 					body { margin: 0; }

+ 272 - 0
docs/scenes/bones-browser.html

@@ -0,0 +1,272 @@
+<!doctype html>
+<html lang="en">
+	<head>
+		<meta charset="utf-8">
+		<title>Three.js Bones Browser</title>
+		<style>
+			@font-face {
+				font-family: 'inconsolata';
+				src: url('../files/inconsolata.woff') format('woff');
+				font-weight: normal;
+				font-style: normal;
+			}
+			
+			body {
+				margin:0;
+				font-family: 'inconsolata';
+				font-size: 15px;
+				line-height: 18px;
+				overflow: hidden;
+			}
+			
+			canvas { width: 100%; height: 100% }
+			
+			#newWindow {
+				display: block;
+				position: absolute;
+				bottom: 0.3em;
+				left: 0.5em;
+				color: #fff;
+			}
+		</style>
+	</head>
+	<body>
+		
+		<a id='newWindow' href='./bones-browser.html' target='_blank'>Open in New Window</a>
+		
+		<script src="../../build/three.min.js"></script>
+		<script src='../../examples/js/libs/dat.gui.min.js'></script>
+		<script src="../../examples/js/controls/OrbitControls.js"></script>
+		
+		<script>
+
+			var gui, scene, camera, renderer, orbit, ambientLight, lights, mesh, bones, skeletonHelper;
+
+			var state = {
+
+				animateBones : false
+
+			};
+
+			function initScene () {
+
+				gui = new dat.GUI();
+				scene = new THREE.Scene();
+				camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 200 );
+				camera.position.z = 30;
+				camera.position.y = 30;
+
+				renderer = new THREE.WebGLRenderer( { antialias: true } );
+				renderer.setSize( window.innerWidth, window.innerHeight );
+				document.body.appendChild( renderer.domElement );
+
+				orbit = new THREE.OrbitControls( camera, renderer.domElement );
+				orbit.noZoom = true;
+
+				ambientLight = new THREE.AmbientLight( 0x000000 );
+				scene.add( ambientLight );
+
+				lights = [];
+				lights[ 0 ] = new THREE.PointLight( 0xffffff, 1, 0 );
+				lights[ 1 ] = new THREE.PointLight( 0xffffff, 1, 0 );
+				lights[ 2 ] = new THREE.PointLight( 0xffffff, 1, 0 );
+
+				lights[ 0 ].position.set( 0, 200, 0 );
+				lights[ 1 ].position.set( 100, 200, 100 );
+				lights[ 2 ].position.set( -100, -200, -100 );
+
+				scene.add( lights[ 0 ] );
+				scene.add( lights[ 1 ] );
+				scene.add( lights[ 2 ] );
+
+				window.addEventListener( 'resize', function () {
+
+					camera.aspect = window.innerWidth / window.innerHeight;
+					camera.updateProjectionMatrix();
+
+					renderer.setSize( window.innerWidth, window.innerHeight );
+
+				}, false );
+
+				initBones();
+				setupDatGui();
+
+			}
+
+			function createGeometry ( sizing ) {
+
+				var geometry = new THREE.CylinderGeometry(
+					5,                       // radiusTop
+					5,                       // radiusBottom
+					sizing.height,           // height
+					8,                       // radiusSegments
+					sizing.segmentCount * 3, // heightSegments
+					true                     // openEnded
+				);
+
+				for ( var i = 0; i < geometry.vertices.length; i ++ ) {
+
+					var vertex = geometry.vertices[ i ];
+					var y = ( vertex.y + sizing.halfHeight );
+
+					var skinIndex = Math.floor( y / sizing.segmentHeight );
+					var skinWeight = ( y % sizing.segmentHeight ) / sizing.segmentHeight;
+
+					geometry.skinIndices.push( new THREE.Vector4( skinIndex, skinIndex + 1, 0, 0 ) );
+					geometry.skinWeights.push( new THREE.Vector4( 1 - skinWeight, skinWeight, 0, 0 ) );
+
+				}
+
+				return geometry;
+
+			};
+
+			function createBones ( sizing ) {
+
+				bones = [];
+
+				var prevBone = new THREE.Bone();
+				bones.push( prevBone );
+				prevBone.position.y = -sizing.halfHeight;
+
+				for ( var i = 0; i < sizing.segmentCount; i ++ ) {
+
+					var bone = new THREE.Bone();
+					bone.position.y = sizing.segmentHeight;
+					bones.push( bone );
+					prevBone.add( bone );
+					prevBone = bone;
+
+				}
+
+				return bones;
+
+			};
+
+			function createMesh ( geometry, bones ) {
+
+				var material = new THREE.MeshPhongMaterial( {
+					skinning : true,
+					color: 0x156289,
+					emissive: 0x072534,
+					side: THREE.DoubleSide,
+					shading: THREE.FlatShading
+				} );
+
+				var mesh = new THREE.SkinnedMesh( geometry,	material );
+				var skeleton = new THREE.Skeleton( bones );
+	
+				mesh.add( bones[ 0 ] );
+	
+				mesh.bind( skeleton );
+				skeleton.calculateInverses();
+
+				skeletonHelper = new THREE.SkeletonHelper( mesh );
+				skeletonHelper.material.linewidth = 2;
+				scene.add( skeletonHelper );
+
+				return mesh;
+	
+			};
+
+			function setupDatGui () {
+	
+				var folder = gui.addFolder( "General Options" );
+	
+				folder.add( state, "animateBones" );
+				folder.__controllers[ 0 ].name( "Animate Bones" );
+
+				folder.add( mesh, "pose" );
+				folder.__controllers[ 1 ].name( ".pose()" );
+	
+				var bones = mesh.skeleton.bones;
+	
+				for ( var i = 0; i < bones.length; i ++ ) {
+		
+					var bone = bones[ i ];
+		
+					folder = gui.addFolder( "Bone " + i );
+	
+					folder.add( bone.position, 'x', -10 + bone.position.x, 10 + bone.position.x );
+					folder.add( bone.position, 'y', -10 + bone.position.y, 10 + bone.position.y );
+					folder.add( bone.position, 'z', -10 + bone.position.z, 10 + bone.position.z );
+
+					folder.add( bone.rotation, 'x', -Math.PI * 0.5, Math.PI * 0.5 );
+					folder.add( bone.rotation, 'y', -Math.PI * 0.5, Math.PI * 0.5 );
+					folder.add( bone.rotation, 'z', -Math.PI * 0.5, Math.PI * 0.5 );
+		
+					folder.add( bone.scale, 'x', 0, 2 );
+					folder.add( bone.scale, 'y', 0, 2 );
+					folder.add( bone.scale, 'z', 0, 2 );
+
+					folder.__controllers[ 0 ].name( "position.x" );
+					folder.__controllers[ 1 ].name( "position.y" );
+					folder.__controllers[ 2 ].name( "position.z" );
+		
+					folder.__controllers[ 3 ].name( "rotation.x" );
+					folder.__controllers[ 4 ].name( "rotation.y" );
+					folder.__controllers[ 5 ].name( "rotation.z" );
+		
+					folder.__controllers[ 6 ].name( "scale.x" );
+					folder.__controllers[ 7 ].name( "scale.y" );
+					folder.__controllers[ 8 ].name( "scale.z" );
+		
+				}
+				
+			}
+
+			function initBones () {
+	
+				var segmentHeight = 8;
+				var segmentCount = 4;
+				var height = segmentHeight * segmentCount;
+				var halfHeight = height * 0.5;
+
+				var sizing = {
+					segmentHeight : segmentHeight,
+					segmentCount : segmentCount,
+					height : height,
+					halfHeight : halfHeight
+				};
+
+				var geometry = createGeometry( sizing );
+				var bones = createBones( sizing );
+				mesh = createMesh( geometry, bones );
+
+				mesh.scale.multiplyScalar( 1 );
+				scene.add( mesh );
+
+			};
+
+			function render () {
+	
+				requestAnimationFrame( render );
+
+				var time = Date.now() * 0.001;
+	
+				var bone = mesh;
+
+	
+				//Wiggle the bones
+				if ( state.animateBones ) {
+		
+					for ( var i = 0; i < mesh.skeleton.bones.length; i ++ ) {
+		
+						mesh.skeleton.bones[ i ].rotation.z = Math.sin( time ) * 2 / mesh.skeleton.bones.length;
+		
+					}
+		
+				}
+
+				skeletonHelper.update();
+	
+				renderer.render( scene, camera );
+	
+			};
+
+			initScene();
+			render();
+			
+		</script>
+	</body>
+</html>

+ 1 - 14
examples/js/BlendCharacterGui.js

@@ -7,7 +7,6 @@ function BlendCharacterGui(animations) {
 	var controls = {
 
 		gui: null,
-		"Lock Camera": false,
 		"Show Model": true,
 		"Show Skeleton": false,
 		"Time Scale": 1.0,
@@ -55,7 +54,6 @@ function BlendCharacterGui(animations) {
 		var playback = controls.gui.addFolder( 'Playback' );
 		var blending = controls.gui.addFolder( 'Blend Tuning' );
 
-		settings.add( controls, "Lock Camera" ).onChange( controls.lockCameraChanged );
 		settings.add( controls, "Show Model" ).onChange( controls.showModelChanged );
 		settings.add( controls, "Show Skeleton" ).onChange( controls.showSkeletonChanged );
 		settings.add( controls, "Time Scale", 0, 1, 0.01 );
@@ -174,17 +172,6 @@ function BlendCharacterGui(animations) {
 
 	};
 
-	controls.lockCameraChanged = function() {
-
-		var data = {
-			detail: {
-				shouldLock: controls['Lock Camera']
-			}
-		};
-
-		window.dispatchEvent( new CustomEvent( 'toggle-lock-camera', data ) );
-	};
-
 	controls.showSkeletonChanged = function() {
 
 		var data = {
@@ -211,4 +198,4 @@ function BlendCharacterGui(animations) {
 
 	init.call(this);
 
-}
+}

+ 3 - 3
examples/js/libs/stats.min.js

@@ -1,5 +1,5 @@
 // stats.js - http://github.com/mrdoob/stats.js
 var Stats=function(){function f(a,e,b){a=document.createElement(a);a.id=e;a.style.cssText=b;return a}function l(a,e,b){var c=f("div",a,"padding:0 0 3px 3px;text-align:left;background:"+b),d=f("div",a+"Text","font-family:Helvetica,Arial,sans-serif;font-size:9px;font-weight:bold;line-height:15px;color:"+e);d.innerHTML=a.toUpperCase();c.appendChild(d);a=f("div",a+"Graph","width:74px;height:30px;background:"+e);c.appendChild(a);for(e=0;74>e;e++)a.appendChild(f("span","","width:1px;height:30px;float:left;opacity:0.9;background:"+
-b));return c}function m(a){for(var b=c.children,d=0;d<b.length;d++)b[d].style.display=d===a?"block":"none";n=a}function p(a,b){a.appendChild(a.firstChild).style.height=Math.min(30,30-30*b)+"px"}var q=performance&&performance.now?performance.now.bind(performance):Date.now,k=q(),r=k,t=0,n=0,c=f("div","stats","width:80px;opacity:0.9;cursor:pointer");c.addEventListener("mousedown",function(a){a.preventDefault();m(++n%c.children.length)},!1);var d=0,u=Infinity,v=0,b=l("fps","#0ff","#002"),A=b.children[0],
-B=b.children[1];c.appendChild(b);var g=0,w=Infinity,x=0,b=l("ms","#0f0","#020"),C=b.children[0],D=b.children[1];c.appendChild(b);if(performance&&performance.memory){var h=0,y=Infinity,z=0,b=l("mb","#f08","#201"),E=b.children[0],F=b.children[1];c.appendChild(b)}m(n);return{REVISION:14,domElement:c,setMode:m,begin:function(){k=q()},end:function(){var a=q();g=a-k;w=Math.min(w,g);x=Math.max(x,g);C.textContent=(g|0)+" MS ("+(w|0)+"-"+(x|0)+")";p(D,g/200);t++;if(a>r+1E3&&(d=Math.round(1E3*t/(a-r)),u=Math.min(u,
-d),v=Math.max(v,d),A.textContent=d+" FPS ("+u+"-"+v+")",p(B,d/100),r=a,t=0,void 0!==h)){var b=performance.memory.usedJSHeapSize,c=performance.memory.jsHeapSizeLimit;h=Math.round(9.54E-7*b);y=Math.min(y,h);z=Math.max(z,h);E.textContent=h+" MB ("+y+"-"+z+")";p(F,b/c)}return a},update:function(){k=this.end()}}};"object"===typeof module&&(module.exports=Stats);
+b));return c}function m(a){for(var b=c.children,d=0;d<b.length;d++)b[d].style.display=d===a?"block":"none";n=a}function p(a,b){a.appendChild(a.firstChild).style.height=Math.min(30,30-30*b)+"px"}var q=self.performance&&self.performance.now?self.performance.now.bind(performance):Date.now,k=q(),r=k,t=0,n=0,c=f("div","stats","width:80px;opacity:0.9;cursor:pointer");c.addEventListener("mousedown",function(a){a.preventDefault();m(++n%c.children.length)},!1);var d=0,u=Infinity,v=0,b=l("fps","#0ff","#002"),
+A=b.children[0],B=b.children[1];c.appendChild(b);var g=0,w=Infinity,x=0,b=l("ms","#0f0","#020"),C=b.children[0],D=b.children[1];c.appendChild(b);if(self.performance&&self.performance.memory){var h=0,y=Infinity,z=0,b=l("mb","#f08","#201"),E=b.children[0],F=b.children[1];c.appendChild(b)}m(n);return{REVISION:14,domElement:c,setMode:m,begin:function(){k=q()},end:function(){var a=q();g=a-k;w=Math.min(w,g);x=Math.max(x,g);C.textContent=(g|0)+" MS ("+(w|0)+"-"+(x|0)+")";p(D,g/200);t++;if(a>r+1E3&&(d=Math.round(1E3*
+t/(a-r)),u=Math.min(u,d),v=Math.max(v,d),A.textContent=d+" FPS ("+u+"-"+v+")",p(B,d/100),r=a,t=0,void 0!==h)){var b=performance.memory.usedJSHeapSize,c=performance.memory.jsHeapSizeLimit;h=Math.round(9.54E-7*b);y=Math.min(y,h);z=Math.max(z,h);E.textContent=h+" MB ("+y+"-"+z+")";p(F,b/c)}return a},update:function(){k=this.end()}}};"object"===typeof module&&(module.exports=Stats);

+ 1 - 1
examples/js/renderers/Projector.js

@@ -516,7 +516,7 @@ THREE.Projector = function () {
 
 						var face = faces[ f ];
 
-						var material = isFaceMaterial === true
+						material = isFaceMaterial === true
 							 ? objectMaterials.materials[ face.materialIndex ]
 							 : object.material;
 

+ 0 - 9
examples/webgl_animation_skinning_blending.html

@@ -94,7 +94,6 @@
 				window.addEventListener( 'weight-animation', onWeightAnimation );
 				window.addEventListener( 'crossfade', onCrossfade );
 				window.addEventListener( 'warp', onWarp );
-				window.addEventListener( 'toggle-lock-camera', onLockCameraToggle );
 				window.addEventListener( 'toggle-show-skeleton', onShowSkeleton );
 				window.addEventListener( 'toggle-show-model', onShowModel );
 
@@ -184,14 +183,6 @@
 
 			}
 
-
-			function onLockCameraToggle( event ) {
-
-				var shouldLock = event.detail.shouldLock;
-				controls.enabled = !shouldLock;
-
-			}
-
 			function onShowSkeleton( event ) {
 
 				var shouldShow = event.detail.shouldShow;

+ 46 - 61
examples/webgl_modifier_tessellation.html

@@ -64,7 +64,7 @@
 				vNormal = normal;
 				vColor = customColor;
 
-				vec3 newPosition = position + amplitude * displacement;
+				vec3 newPosition = position + normal * amplitude * displacement;
 				gl_Position = projectionMatrix * modelViewMatrix * vec4( newPosition, 1.0 );
 
 			}
@@ -78,7 +78,7 @@
 
 			void main() {
 
-				const float ambient = 0.005;
+				const float ambient = 0.4;
 
 				vec3 light = vec3( 1.0 );
 				light = normalize( light );
@@ -86,7 +86,6 @@
 				float directional = max( dot( vNormal, light ), 0.0 );
 
 				gl_FragColor = vec4( ( directional + ambient ) * vColor, 1.0 );
-				gl_FragColor.xyz = sqrt( gl_FragColor.xyz );
 
 			}
 
@@ -109,8 +108,8 @@
 
 		function init() {
 
-			camera = new THREE.PerspectiveCamera( 25, WIDTH / HEIGHT, 1, 10000 );
-			camera.position.z = 350;
+			camera = new THREE.PerspectiveCamera( 40, WIDTH / HEIGHT, 1, 10000 );
+			camera.position.set( -100, 100, 200 );
 
 			controls = new THREE.TrackballControls( camera );
 
@@ -118,31 +117,6 @@
 
 			//
 
-			attributes = {
-
-				displacement: {	type: 'v3', value: [] },
-				customColor:  {	type: 'c', value: [] }
-
-			};
-
-			uniforms = {
-
-				amplitude: { type: "f", value: 0.0 }
-
-			};
-
-			var shaderMaterial = new THREE.ShaderMaterial( {
-
-				uniforms: 		uniforms,
-				attributes:     attributes,
-				vertexShader:   document.getElementById( 'vertexshader' ).textContent,
-				fragmentShader: document.getElementById( 'fragmentshader' ).textContent,
-				shading: 		THREE.FlatShading,
-				side: 			THREE.DoubleSide
-
-			});
-
-
 			var geometry = new THREE.TextGeometry( "THREE.JS", {
 
 				size: 40,
@@ -159,8 +133,6 @@
 
 			});
 
-			geometry.dynamic = true;
-
 			geometry.center();
 
 			var tessellateModifier = new THREE.TessellateModifier( 8 );
@@ -174,57 +146,68 @@
 			var explodeModifier = new THREE.ExplodeModifier();
 			explodeModifier.modify( geometry );
 
-			var vertices = geometry.vertices;
+			var numFaces = geometry.faces.length;
+
+			//
+
+			geometry = new THREE.BufferGeometry().fromGeometry( geometry );
 
-			var colors = attributes.customColor.value;
-			var displacement = attributes.displacement.value;
+			var colors = new Float32Array( numFaces * 3 * 3 );
+			var displacement = new Float32Array( numFaces * 3 * 3 );
 
-			var nv, v = 0;
+			var color = new THREE.Color();
 
-			for ( var f = 0; f < geometry.faces.length; f ++ ) {
+			for ( var f = 0; f < numFaces; f ++ ) {
 
-				var face = geometry.faces[ f ];
+				var index = 9 * f;
 
-				if ( face instanceof THREE.Face3 ) {
+				var h = 0.2 * Math.random();
+				var s = 0.5 + 0.5 * Math.random();
+				var l = 0.5 + 0.5 * Math.random();
+
+				color.setHSL( h, s, l );
 
-					nv = 3;
+				var d = 10 * ( 0.5 - Math.random() );
+
+				for ( var i = 0; i < 3; i ++ ) {
 
-				} else {
+					colors[ index + ( 3 * i )     ] = color.r;
+					colors[ index + ( 3 * i ) + 1 ] = color.g;
+					colors[ index + ( 3 * i ) + 2 ] = color.b;
 
-					nv = 4;
+					displacement[ index + ( 3 * i )     ] = d;
+					displacement[ index + ( 3 * i ) + 1 ] = d;
+					displacement[ index + ( 3 * i ) + 2 ] = d;
 
 				}
 
-				var h = 0.15 * Math.random();
-				var s = 0.5 + 0.5 * Math.random();
-				var l = 0.5 + 0.5 * Math.random();
+			}
 
-				var d = 10 * ( 0.5 - Math.random() );
+			geometry.addAttribute( 'customColor', new THREE.BufferAttribute( colors, 3 ) );
+			geometry.addAttribute( 'displacement', new THREE.BufferAttribute( displacement, 3 ) );
 
-				var x = 2 * ( 0.5 - Math.random() );
-				var y = 2 * ( 0.5 - Math.random() );
-				var z = 2 * ( 0.5 - Math.random() );
+			//
 
-				for ( var i = 0; i < nv; i ++ ) {
+			attributes = [ `displacement`, `customColor` ];
 
-					colors[ v ] = new THREE.Color();
-					displacement[ v ] = new THREE.Vector3();
+			uniforms = {
 
-					colors[ v ].setHSL( h, s, l );
-					colors[ v ].convertGammaToLinear();
+				amplitude: { type: "f", value: 0.0 }
 
-					displacement[ v ].set( x, y, z );
+			};
 
-					v += 1;
+			var shaderMaterial = new THREE.ShaderMaterial( {
 
-				}
+				uniforms: 		uniforms,
+				attributes:     attributes,
+				vertexShader:   document.getElementById( 'vertexshader' ).textContent,
+				fragmentShader: document.getElementById( 'fragmentshader' ).textContent
 
-			}
+			});
 
-			console.log( "faces", geometry.faces.length );
+			//
 
 			mesh = new THREE.Mesh( geometry, shaderMaterial );
-			mesh.rotation.set( 0.5, 0.5, 0 );
 
 			scene.add( mesh );
 
@@ -259,6 +242,7 @@
 			requestAnimationFrame( animate );
 
 			render();
+
 			stats.update();
 
 		}
@@ -267,9 +251,10 @@
 
 			var time = Date.now() * 0.001;
 
-			uniforms.amplitude.value = Math.sin( time * 0.5 );
+			uniforms.amplitude.value = 1.0 + Math.sin( time * 0.5 );
 
 			controls.update();
+
 			renderer.render( scene, camera );
 
 		}

+ 31 - 0
src/core/BufferGeometry.js

@@ -194,11 +194,13 @@ THREE.BufferGeometry.prototype = {
 			direct.normalsNeedUpdate = geometry.normalsNeedUpdate;
 			direct.colorsNeedUpdate = geometry.colorsNeedUpdate;
 			direct.uvsNeedUpdate = geometry.uvsNeedUpdate;
+			direct.tangentsNeedUpdate = geometry.tangentsNeedUpdate;
 
 			geometry.verticesNeedUpdate = false;
 			geometry.normalsNeedUpdate = false;
 			geometry.colorsNeedUpdate = false;
 			geometry.uvsNeedUpdate = false;
+			geometry.tangentsNeedUpdate = false;
 
 			geometry = direct;
 
@@ -249,6 +251,21 @@ THREE.BufferGeometry.prototype = {
 
 		}
 
+		if ( geometry.tangentsNeedUpdate === true ) {
+
+			var attribute = this.attributes.tangent;
+
+			if ( attribute !== undefined ) {
+
+				attribute.copyVector4sArray( geometry.tangents );
+				attribute.needsUpdate = true;
+
+			}
+
+			geometry.tangentsNeedUpdate = false;
+
+		}
+
 		return this;
 
 	},
@@ -298,6 +315,20 @@ THREE.BufferGeometry.prototype = {
 
 		}
 
+		if ( geometry.uvs2.length > 0 ) {
+
+			var uvs2 = new Float32Array( geometry.uvs2.length * 2 );
+			this.addAttribute( 'uv2', new THREE.BufferAttribute( uvs2, 2 ).copyVector2sArray( geometry.uvs2 ) );
+
+		}
+
+		if ( geometry.tangents.length > 0 ) {
+
+			var tangents = new Float32Array( geometry.tangents.length * 4 );
+			this.addAttribute( 'tangent', new THREE.BufferAttribute( tangents, 4 ).copyVector4sArray( geometry.tangents ) );
+
+		}
+
 		// morphs
 
 		if ( geometry.morphTargets.length > 0 ) {

+ 33 - 2
src/core/DirectGeometry.js

@@ -18,6 +18,7 @@ THREE.DirectGeometry = function () {
 	this.colors = [];
 	this.uvs = [];
 	this.uvs2 = [];
+	this.tangents = [];
 
 	this.morphTargets = [];
 	this.morphColors = [];
@@ -37,6 +38,7 @@ THREE.DirectGeometry = function () {
 	this.normalsNeedUpdate = false;
 	this.colorsNeedUpdate = false;
 	this.uvsNeedUpdate = false;
+	this.tangentsNeedUpdate = false;
 
 };
 
@@ -61,6 +63,14 @@ THREE.DirectGeometry.prototype = {
 
 	},
 
+	computeTangents: function () {
+
+		console.warn( 'THREE.DirectGeometry: computeTangents() is not a method of this type of geometry.' );
+		return this;
+
+	},
+
+
 	fromGeometry: function ( geometry ) {
 
 		var faces = geometry.faces;
@@ -70,6 +80,8 @@ THREE.DirectGeometry.prototype = {
 		var hasFaceVertexUv = faceVertexUvs[ 0 ] && faceVertexUvs[ 0 ].length > 0;
 		var hasFaceVertexUv2 = faceVertexUvs[ 1 ] && faceVertexUvs[ 1 ].length > 0;
 
+		var hasTangents = geometry.hasTangents;
+
 		// morphs
 
 		var morphTargets = geometry.morphTargets;
@@ -153,7 +165,7 @@ THREE.DirectGeometry.prototype = {
 
 				} else {
 
-					console.warn( 'THREE.BufferGeometry.fromGeometry(): Undefined vertexUv', i );
+					console.warn( 'THREE.DirectGeometry.fromGeometry(): Undefined vertexUv ', i );
 
 					this.uvs.push( new THREE.Vector2(), new THREE.Vector2(), new THREE.Vector2() );
 
@@ -171,7 +183,7 @@ THREE.DirectGeometry.prototype = {
 
 				} else {
 
-					console.warn( 'THREE.BufferGeometry.fromGeometry(): Undefined vertexUv2', i );
+					console.warn( 'THREE.DirectGeometry.fromGeometry(): Undefined vertexUv2 ', i );
 
 					this.uvs2.push( new THREE.Vector2(), new THREE.Vector2(), new THREE.Vector2() );
 
@@ -179,6 +191,24 @@ THREE.DirectGeometry.prototype = {
 
 			}
 
+			if ( hasTangents === true ) {
+
+				var vertexTangents = face.vertexTangents;
+
+				if ( vertexTangents.length === 3 ) {
+
+					this.tangents.push( vertexTangents[ 0 ], vertexTangents[ 1 ], vertexTangents[ 2 ] );
+
+				} else {
+
+					console.warn( 'THREE.DirectGeometry.fromGeometry(): Undefined tangents ', i );
+
+					this.tangents.push( new THREE.Vector4(), new THREE.Vector4(), new THREE.Vector4() );
+
+				}
+
+			}
+
 			// morphs
 
 			for ( var j = 0; j < morphTargetsLength; j ++ ) {
@@ -226,6 +256,7 @@ THREE.DirectGeometry.prototype = {
 		this.normalsNeedUpdate = geometry.normalsNeedUpdate;
 		this.colorsNeedUpdate = geometry.colorsNeedUpdate;
 		this.uvsNeedUpdate = geometry.uvsNeedUpdate;
+		this.tangentsNeedUpdate = geometry.tangentsNeedUpdate;
 
 		return this;
 

+ 43 - 4
src/core/Geometry.js

@@ -45,8 +45,6 @@ THREE.Geometry = function () {
 	this.colorsNeedUpdate = false;
 	this.lineDistancesNeedUpdate = false;
 
-	this.groupsNeedUpdate = false;
-
 };
 
 THREE.Geometry.prototype = {
@@ -105,11 +103,18 @@ THREE.Geometry.prototype = {
 		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;
+		var uvs2 = attributes.uv2 !== undefined ? attributes.uv2.array : undefined;
+		var tangents = attributes.tangent !== undefined ? attributes.tangent.array : undefined;
+
+		if ( uvs2 !== undefined ) this.faceVertexUvs[ 1 ] = [];
+		if ( tangents !== undefined ) this.hasTangents = true;
 
 		var tempNormals = [];
 		var tempUVs = [];
+		var tempUVs2 = [];
+		var tempTangents = [];
 
-		for ( var i = 0, j = 0; i < vertices.length; i += 3, j += 2 ) {
+		for ( var i = 0, j = 0, k = 0; i < vertices.length; i += 3, j += 2, k += 4 ) {
 
 			scope.vertices.push( new THREE.Vector3( vertices[ i ], vertices[ i + 1 ], vertices[ i + 2 ] ) );
 
@@ -131,6 +136,18 @@ THREE.Geometry.prototype = {
 
 			}
 
+			if ( uvs2 !== undefined ) {
+
+				tempUVs2.push( new THREE.Vector2( uvs2[ j ], uvs2[ j + 1 ] ) );
+
+			}
+
+			if ( tangents !== undefined ) {
+
+				tempTangents.push( new THREE.Vector4( tangents[ k ], tangents[ k + 1 ], tangents[ k + 2 ], tangents[ k + 3 ] ) );
+
+			}
+
 		}
 
 		var addFace = function ( a, b, c ) {
@@ -138,7 +155,9 @@ THREE.Geometry.prototype = {
 			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() ] : [];
 
-			scope.faces.push( new THREE.Face3( a, b, c, vertexNormals, vertexColors ) );
+			var face = new THREE.Face3( a, b, c, vertexNormals, vertexColors );
+
+			scope.faces.push( face );
 
 			if ( uvs !== undefined ) {
 
@@ -146,6 +165,18 @@ THREE.Geometry.prototype = {
 
 			}
 
+			if ( uvs2 !== undefined ) {
+
+				scope.faceVertexUvs[ 1 ].push( [ tempUVs2[ a ].clone(), tempUVs2[ b ].clone(), tempUVs2[ c ].clone() ] );
+
+			}
+
+			if ( tangents !== undefined ) {
+
+				face.vertexTangents.push( tempTangents[ a ].clone(), tempTangents[ b ].clone(), tempTangents[ c ].clone() );
+
+			}
+
 		};
 
 		if ( indices !== undefined ) {
@@ -1071,6 +1102,14 @@ THREE.Geometry.prototype = {
 
 		this.dispatchEvent( { type: 'dispose' } );
 
+	},
+
+	// Backwards compatibility
+
+	set groupsNeedUpdate ( value ) {
+
+		if ( value === true ) this.dispose();
+
 	}
 
 };

+ 1 - 1
src/extras/FontUtils.js

@@ -31,7 +31,7 @@ THREE.FontUtils = {
 
 		try {
 
-			return this.faces[ this.face ][ this.weight ][ this.style ];
+			return this.faces[ this.face.toLowerCase() ][ this.weight ][ this.style ];
 
 		} catch (e) {
 

+ 29 - 0
src/lights/AreaLight.js

@@ -1,6 +1,7 @@
 /**
  * @author MPanknin / http://www.redplant.de/
  * @author alteredq / http://alteredqualia.com/
+ * @author prafullit
  */
 
 THREE.AreaLight = function ( color, intensity ) {
@@ -26,3 +27,31 @@ THREE.AreaLight = function ( color, intensity ) {
 THREE.AreaLight.prototype = Object.create( THREE.Light.prototype );
 THREE.AreaLight.prototype.constructor = THREE.AreaLight;
 
+THREE.AreaLight.prototype.clone = function () {
+
+	var light = new THREE.AreaLight();
+
+	THREE.Light.prototype.clone.call( this, light );
+
+	light.normal.copy(this.normal);
+	light.right.copy(this.right);
+	light.intensity = this.intensity;
+	light.width = this.width;
+	light.height = this.height;
+	light.constantAttenuation = this.constantAttenuation;
+	light.linearAttenuation = this.linearAttenuation;
+	light.quadraticAttenuation = this.quadraticAttenuation
+
+	return light;
+
+};
+
+THREE.AreaLight.prototype.toJSON = function ( meta ) {
+
+	var data = THREE.Object3D.prototype.toJSON.call( this, meta );
+
+	data.object.color = this.color.getHex();
+	data.object.intensity = this.intensity;
+
+	return data;
+};

+ 46 - 4
src/materials/MeshFaceMaterial.js

@@ -4,11 +4,53 @@
 
 THREE.MeshFaceMaterial = function ( materials ) {
 
-	console.error( 'THREE.MeshFaceMaterial has been removed.' );
+	this.uuid = THREE.Math.generateUUID();
 
-	var material = Array.isArray( materials ) ? materials[ 0 ] : new THREE.MeshBasicMaterial();
-	material.materials = []; // temporal workaround
+	this.type = 'MeshFaceMaterial';
 
-	return material;
+	this.materials = materials instanceof Array ? materials : [];
+
+};
+
+THREE.MeshFaceMaterial.prototype = {
+
+	constructor: THREE.MeshFaceMaterial,
+
+	toJSON: function () {
+
+		var output = {
+			metadata: {
+				version: 4.2,
+				type: 'material',
+				generator: 'MaterialExporter'
+			},
+			uuid: this.uuid,
+			type: this.type,
+			materials: []
+		};
+
+		for ( var i = 0, l = this.materials.length; i < l; i ++ ) {
+
+			output.materials.push( this.materials[ i ].toJSON() );
+
+		}
+
+		return output;
+
+	},
+
+	clone: function () {
+
+		var material = new THREE.MeshFaceMaterial();
+
+		for ( var i = 0; i < this.materials.length; i ++ ) {
+
+			material.materials.push( this.materials[ i ].clone() );
+
+		}
+
+		return material;
+
+	}
 
 };

+ 41 - 19
src/objects/LOD.js

@@ -8,7 +8,18 @@ THREE.LOD = function () {
 
 	THREE.Object3D.call( this );
 
-	this.objects = [];
+	Object.defineProperties( this, {
+		levels: {
+			enumerable: true,
+			value: []
+		},
+		objects: {
+			get: function () {
+				console.warn( 'THREE.LOD: .objects has been renamed to .levels.' );
+				return this.levels;
+			}
+		}
+	} );
 
 };
 
@@ -22,9 +33,11 @@ THREE.LOD.prototype.addLevel = function ( object, distance ) {
 
 	distance = Math.abs( distance );
 
-	for ( var l = 0; l < this.objects.length; l ++ ) {
+	var levels = this.levels;
+
+	for ( var l = 0; l < levels.length; l ++ ) {
 
-		if ( distance < this.objects[ l ].distance ) {
+		if ( distance < levels[ l ].distance ) {
 
 			break;
 
@@ -32,16 +45,19 @@ THREE.LOD.prototype.addLevel = function ( object, distance ) {
 
 	}
 
-	this.objects.splice( l, 0, { distance: distance, object: object } );
+	levels.splice( l, 0, { distance: distance, object: object } );
+
 	this.add( object );
 
 };
 
 THREE.LOD.prototype.getObjectForDistance = function ( distance ) {
 
-	for ( var i = 1, l = this.objects.length; i < l; i ++ ) {
+	var levels = this.levels;
+
+	for ( var i = 1, l = levels.length; i < l; i ++ ) {
 
-		if ( distance < this.objects[ i ].distance ) {
+		if ( distance < levels[ i ].distance ) {
 
 			break;
 
@@ -49,7 +65,7 @@ THREE.LOD.prototype.getObjectForDistance = function ( distance ) {
 
 	}
 
-	return this.objects[ i - 1 ].object;
+	return levels[ i - 1 ].object;
 
 };
 
@@ -76,21 +92,23 @@ THREE.LOD.prototype.update = function () {
 
 	return function ( camera ) {
 
-		if ( this.objects.length > 1 ) {
+		var levels = this.levels;
+
+		if ( levels.length > 1 ) {
 
 			v1.setFromMatrixPosition( camera.matrixWorld );
 			v2.setFromMatrixPosition( this.matrixWorld );
 
 			var distance = v1.distanceTo( v2 );
 
-			this.objects[ 0 ].object.visible = true;
+			levels[ 0 ].object.visible = true;
 
-			for ( var i = 1, l = this.objects.length; i < l; i ++ ) {
+			for ( var i = 1, l = levels.length; i < l; i ++ ) {
 
-				if ( distance >= this.objects[ i ].distance ) {
+				if ( distance >= levels[ i ].distance ) {
 
-					this.objects[ i - 1 ].object.visible = false;
-					this.objects[ i     ].object.visible = true;
+					levels[ i - 1 ].object.visible = false;
+					levels[ i     ].object.visible = true;
 
 				} else {
 
@@ -102,7 +120,7 @@ THREE.LOD.prototype.update = function () {
 
 			for ( ; i < l; i ++ ) {
 
-				this.objects[ i ].object.visible = false;
+				levels[ i ].object.visible = false;
 
 			}
 
@@ -116,12 +134,16 @@ THREE.LOD.prototype.clone = function ( object ) {
 
 	if ( object === undefined ) object = new THREE.LOD();
 
-	THREE.Object3D.prototype.clone.call( this, object );
+	THREE.Object3D.prototype.clone.call( this, object, false );
+
+	var levels = this.levels;
+
+	for ( var i = 0, l = levels.length; i < l; i ++ ) {
+
+		var level = levels[ i ];
+
+		object.addLevel( level.object.clone(), level.distance );
 
-	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 );
 	}
 
 	return object;

+ 17 - 20
src/objects/Mesh.js

@@ -69,6 +69,9 @@ THREE.Mesh.prototype.raycast = ( function () {
 	return function ( raycaster, intersects ) {
 
 		var geometry = this.geometry;
+		var material = this.material;
+
+		if ( material === undefined ) return;
 
 		// Checking boundingSphere distance to ray
 
@@ -98,16 +101,12 @@ THREE.Mesh.prototype.raycast = ( function () {
 
 		}
 
-		if ( geometry instanceof THREE.BufferGeometry ) {
-
-			var material = this.material;
+		var a, b, c;
 
-			if ( material === undefined ) return;
+		if ( geometry instanceof THREE.BufferGeometry ) {
 
 			var attributes = geometry.attributes;
 
-			var a, b, c;
-
 			if ( attributes.index !== undefined ) {
 
 				var indices = attributes.index.array;
@@ -159,9 +158,9 @@ THREE.Mesh.prototype.raycast = ( function () {
 							distance: distance,
 							point: intersectionPoint,
 							face: new THREE.Face3( a, b, c, THREE.Triangle.normal( vA, vB, vC ) ),
-							faceIndex: Math.floor(i/3), // triangle number in indices buffer semantics
+							faceIndex: Math.floor( i / 3 ), // triangle number in indices buffer semantics
 							object: this
-							
+
 						} );
 
 					}
@@ -216,26 +215,24 @@ THREE.Mesh.prototype.raycast = ( function () {
 
 		} else if ( geometry instanceof THREE.Geometry ) {
 
-			var isFaceMaterial = this.material instanceof THREE.MeshFaceMaterial;
-			var objectMaterials = isFaceMaterial === true ? this.material.materials : null;
-
-			var a, b, c;
+			var isFaceMaterial = material instanceof THREE.MeshFaceMaterial;
+			var materials = isFaceMaterial === true ? material.materials : null;
 
 			var vertices = geometry.vertices;
+			var faces = geometry.faces;
 
-			for ( var f = 0, fl = geometry.faces.length; f < fl; f ++ ) {
-
-				var face = geometry.faces[ f ];
+			for ( var f = 0, fl = faces.length; f < fl; f ++ ) {
 
-				var material = isFaceMaterial === true ? objectMaterials[ face.materialIndex ] : this.material;
+				var face = faces[ f ];
+				var faceMaterial = isFaceMaterial === true ? materials[ face.materialIndex ] : material;
 
-				if ( material === undefined ) continue;
+				if ( faceMaterial === undefined ) continue;
 
 				a = vertices[ face.a ];
 				b = vertices[ face.b ];
 				c = vertices[ face.c ];
 
-				if ( material.morphTargets === true ) {
+				if ( faceMaterial.morphTargets === true ) {
 
 					var morphTargets = geometry.morphTargets;
 					var morphInfluences = this.morphTargetInfluences;
@@ -276,13 +273,13 @@ THREE.Mesh.prototype.raycast = ( function () {
 
 				}
 
-				if ( material.side === THREE.BackSide ) {
+				if ( faceMaterial.side === THREE.BackSide ) {
 
 					var intersectionPoint = ray.intersectTriangle( c, b, a, true );
 
 				} else {
 
-					var intersectionPoint = ray.intersectTriangle( a, b, c, material.side !== THREE.DoubleSide );
+					var intersectionPoint = ray.intersectTriangle( a, b, c, faceMaterial.side !== THREE.DoubleSide );
 
 				}
 

+ 11 - 17
src/objects/PointCloud.js

@@ -83,21 +83,21 @@ THREE.PointCloud.prototype.raycast = ( function () {
 
 				if ( offsets.length === 0 ) {
 
-					var offset = {
+					offsets.push( {
 						start: 0,
 						count: indices.length,
 						index: 0
-					};
-
-					offsets = [ offset ];
+					} );
 
 				}
 
 				for ( var oi = 0, ol = offsets.length; oi < ol; ++ oi ) {
 
-					var start = offsets[ oi ].start;
-					var count = offsets[ oi ].count;
-					var index = offsets[ oi ].index;
+					var offset = offsets[ oi ];
+
+					var start = offset.start;
+					var count = offset.count;
+					var index = offset.index;
 
 					for ( var i = start, il = start + count; i < il; i ++ ) {
 
@@ -113,15 +113,9 @@ THREE.PointCloud.prototype.raycast = ( function () {
 
 			} else {
 
-				var pointCount = positions.length / 3;
-
-				for ( var i = 0; i < pointCount; i ++ ) {
+				for ( var i = 0, l = positions.length / 3; i < l; i ++ ) {
 
-					position.set(
-						positions[ 3 * i ],
-						positions[ 3 * i + 1 ],
-						positions[ 3 * i + 2 ]
-					);
+					position.fromArray( positions, i * 3 );
 
 					testPoint( position, i );
 
@@ -131,9 +125,9 @@ THREE.PointCloud.prototype.raycast = ( function () {
 
 		} else {
 
-			var vertices = this.geometry.vertices;
+			var vertices = geometry.vertices;
 
-			for ( var i = 0; i < vertices.length; i ++ ) {
+			for ( var i = 0, l = vertices.length; i < l; i ++ ) {
 
 				testPoint( vertices[ i ], i );
 

+ 8 - 17
src/objects/Skeleton.js

@@ -20,25 +20,16 @@ THREE.Skeleton = function ( bones, boneInverses, useVertexTexture ) {
 	// create a bone texture or an array of floats
 
 	if ( this.useVertexTexture ) {
-
+		
 		// 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)
-
-		var size;
-
-		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;
-
+		//  with  8x8  pixel texture max   16 bones * 4 pixels =  (8 * 8)
+		//       16x16 pixel texture max   64 bones * 4 pixels = (16 * 16)
+		//       32x32 pixel texture max  256 bones * 4 pixels = (32 * 32)
+		//       64x64 pixel texture max 1024 bones * 4 pixels = (64 * 64)
+		
+		var size = THREE.Math.nextPowerOfTwo( Math.sqrt( this.bones.length * 4 ) ); // 4 pixels needed for 1 matrix
+		
 		this.boneTextureWidth = size;
 		this.boneTextureHeight = size;
 

+ 25 - 32
src/renderers/WebGLRenderer.js

@@ -1006,6 +1006,8 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 		if ( material.visible === false ) return;
 
+		setMaterial( material );
+
 		var geometry = objects.geometries.get( object );
 		var program = setProgram( camera, lights, fog, material, object );
 
@@ -1606,8 +1608,6 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 			var overrideMaterial = scene.overrideMaterial;
 
-			setMaterial( overrideMaterial );
-
 			renderObjects( opaqueObjects, camera, lights, fog, overrideMaterial );
 			renderObjects( transparentObjects, camera, lights, fog, overrideMaterial );
 			renderObjectsImmediate( objects.objectsImmediate, '', camera, lights, fog, overrideMaterial );
@@ -1727,7 +1727,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 	function renderObjects( renderList, camera, lights, fog, overrideMaterial ) {
 
-		var material;
+		var material = overrideMaterial;
 
 		for ( var i = 0, l = renderList.length; i < l; i ++ ) {
 
@@ -1737,21 +1737,22 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 			setupMatrices( object, camera );
 
-			if ( overrideMaterial ) {
+			if ( overrideMaterial === null ) material = object.material;
 
-				material = overrideMaterial;
+			if ( material instanceof THREE.MeshFaceMaterial ) {
 
-			} else {
+				var materials = material.materials;
 
-				material = object.material;
+				for ( var j = 0, jl = materials.length; j < jl; j ++ ) {
 
-				if ( ! material ) continue;
+					_this.renderBufferDirect( camera, lights, fog, materials[ j ], object );
 
-				setMaterial( material );
+				}
+
+				continue;
 
 			}
 
-			_this.setMaterialFaces( material );
 			_this.renderBufferDirect( camera, lights, fog, material, object );
 
 		}
@@ -1760,7 +1761,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 	function renderObjectsImmediate ( renderList, materialType, camera, lights, fog, overrideMaterial ) {
 
-		var material;
+		var material = overrideMaterial;
 
 		for ( var i = 0, l = renderList.length; i < l; i ++ ) {
 
@@ -1769,19 +1770,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 			if ( object.visible === true ) {
 
-				if ( overrideMaterial ) {
-
-					material = overrideMaterial;
-
-				} else {
-
-					material = webglObject[ materialType ];
-
-					if ( ! material ) continue;
-
-					setMaterial( material );
-
-				}
+				if ( overrideMaterial === null ) material = webglObject[ materialType ];
 
 				_this.renderImmediateObject( camera, lights, fog, material, object );
 
@@ -1793,12 +1782,12 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 	this.renderImmediateObject = function ( camera, lights, fog, material, object ) {
 
+		setMaterial( material );
+
 		var program = setProgram( camera, lights, fog, material, object );
 
 		_currentGeometryProgram = '';
 
-		_this.setMaterialFaces( material );
-
 		if ( object.immediateRenderCallback ) {
 
 			object.immediateRenderCallback( program, _gl, _frustum );
@@ -2048,6 +2037,8 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 	function setMaterial( material ) {
 
+		setMaterialFaces( material );
+
 		if ( material.transparent === true ) {
 
 			state.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha );
@@ -2066,6 +2057,13 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 	}
 
+	function setMaterialFaces( material ) {
+
+		state.setDoubleSided( material.side === THREE.DoubleSide );
+		state.setFlipSided( material.side === THREE.BackSide );
+
+	}
+
 	function setProgram( camera, lights, fog, material, object ) {
 
 		_usedTextureUnits = 0;
@@ -3150,12 +3148,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 	};
 
-	this.setMaterialFaces = function ( material ) {
-
-		state.setDoubleSided( material.side === THREE.DoubleSide );
-		state.setFlipSided( material.side === THREE.BackSide );
-
-	};
+	this.setMaterialFaces = setMaterialFaces;
 
 	// Textures
 

+ 1 - 1
src/renderers/shaders/ShaderChunk/color_vertex.glsl

@@ -1,5 +1,5 @@
 #ifdef USE_COLOR
 
-	vColor.xyz = inputToLinear( color.xyz );
+	vColor.xyz = color.xyz;
 
 #endif

+ 0 - 3
src/renderers/shaders/ShaderChunk/shadowmap_fragment.glsl

@@ -209,9 +209,6 @@
 
 	}
 
-	// NOTE: I am unsure if this is correct in linear space.  -bhouston, Dec 29, 2014
-	shadowColor = inputToLinear( shadowColor );
-
 	outgoingLight = outgoingLight * shadowColor;
 
 #endif

+ 7 - 6
src/renderers/webgl/WebGLGeometries.js

@@ -37,14 +37,11 @@ THREE.WebGLGeometries = function ( gl, info ) {
 	function onGeometryDispose( event ) {
 
 		var geometry = event.target;
+		var buffergeometry = geometries[ geometry.id ];
 
-		geometry.removeEventListener( 'dispose', onGeometryDispose );
-
-		geometry = geometries[ geometry.id ];
-
-		for ( var name in geometry.attributes ) {
+		for ( var name in buffergeometry.attributes ) {
 
-			var attribute = geometry.attributes[ name ];
+			var attribute = buffergeometry.attributes[ name ];
 
 			if ( attribute.buffer !== undefined ) {
 
@@ -56,6 +53,10 @@ THREE.WebGLGeometries = function ( gl, info ) {
 
 		}
 
+		geometry.removeEventListener( 'dispose', onGeometryDispose );
+
+		delete geometries[ geometry.id ];
+
 		info.memory.geometries --;
 
 	}

+ 8 - 7
utils/build/includes/canvas.json

@@ -21,7 +21,9 @@
 	"src/core/Object3D.js",
 	"src/core/Face3.js",
 	"src/core/Face4.js",
+	"src/core/BufferAttribute.js",
 	"src/core/Geometry.js",
+	"src/core/BufferGeometry.js",
 	"src/cameras/Camera.js",
 	"src/cameras/OrthographicCamera.js",
 	"src/cameras/PerspectiveCamera.js",
@@ -29,9 +31,11 @@
 	"src/lights/AmbientLight.js",
 	"src/lights/DirectionalLight.js",
 	"src/lights/PointLight.js",
+	"src/loaders/Cache.js",
 	"src/loaders/Loader.js",
 	"src/loaders/ImageLoader.js",
 	"src/loaders/JSONLoader.js",
+	"src/loaders/LoadingManager.js",
 	"src/loaders/MaterialLoader.js",
 	"src/loaders/TextureLoader.js",
 	"src/materials/Material.js",
@@ -43,21 +47,18 @@
 	"src/materials/MeshNormalMaterial.js",
 	"src/materials/MeshFaceMaterial.js",
 	"src/materials/SpriteMaterial.js",
-	"src/materials/SpriteCanvasMaterial.js",
 	"src/textures/Texture.js",
+	"src/textures/CompressedTexture.js",
 	"src/textures/DataTexture.js",
 	"src/textures/VideoTexture.js",
 	"src/objects/Group.js",
 	"src/objects/Line.js",
+	"src/objects/LineSegments.js",
 	"src/objects/Mesh.js",
 	"src/objects/Bone.js",
 	"src/objects/Skeleton.js",
 	"src/objects/Sprite.js",
 	"src/scenes/Scene.js",
-	"src/renderers/CanvasRenderer.js",
-	"src/renderers/renderables/RenderableVertex.js",
-	"src/renderers/renderables/RenderableFace.js",
-	"src/renderers/renderables/RenderableObject.js",
-	"src/renderers/renderables/RenderableSprite.js",
-	"src/renderers/renderables/RenderableLine.js"
+	"examples/js/renderers/Projector.js",
+	"examples/js/renderers/CanvasRenderer.js"
 ]

Some files were not shown because too many files changed in this diff