浏览代码

Merge pull request #2 from mrdoob/dev

mrdoob/three.js dev into Lowfab/three.js dev
Arthur Silber 10 年之前
父节点
当前提交
e0a515a4b7
共有 95 个文件被更改,包括 1520 次插入1415 次删除
  1. 1 1
      bower.json
  2. 123 75
      build/three.js
  3. 87 88
      build/three.min.js
  4. 4 2
      docs/api/extras/helpers/EdgesHelper.html
  5. 1 2
      docs/api/math/Matrix4.html
  6. 2 4
      editor/js/Script.js
  7. 19 9
      editor/js/Sidebar.Geometry.js
  8. 0 6
      editor/js/Viewport.js
  9. 3 1
      examples/index.html
  10. 8 5
      examples/js/ShaderDeferred.js
  11. 36 66
      examples/js/ShaderSkin.js
  12. 17 41
      examples/js/ShaderTerrain.js
  13. 16 23
      examples/js/SkyShader.js
  14. 19 4
      examples/js/effects/VREffect.js
  15. 2 2
      examples/js/math/Lut.js
  16. 11 11
      examples/js/postprocessing/AdaptiveToneMappingPass.js
  17. 26 63
      examples/js/shaders/NormalDisplacementShader.js
  18. 6 5
      examples/misc_fps.html
  19. 3 0
      examples/models/json/pressure.json
  20. 二进制
      examples/textures/MaryOculus.webm
  21. 1 0
      examples/textures/MaryOculus.webm.nfo
  22. 5 0
      examples/textures/decal/LICENSE.TXT
  23. 二进制
      examples/textures/decal/decal-diffuse.png
  24. 二进制
      examples/textures/decal/decal-normal.jpg
  25. 168 0
      examples/vr_video.html
  26. 1 1
      examples/webgl_animation_skinning_morph.html
  27. 1 1
      examples/webgl_decals.html
  28. 2 2
      examples/webgl_effects_parallaxbarrier.html
  29. 1 0
      examples/webgl_interactive_cubes_gpu.html
  30. 10 32
      examples/webgl_loader_scene.html
  31. 3 4
      examples/webgl_materials_lightmap.html
  32. 3 0
      examples/webgl_materials_normaldisplacementmap.html
  33. 1 1
      examples/webgl_mirror.html
  34. 13 24
      examples/webgl_shaders_sky.html
  35. 30 16
      examples/webgl_shaders_tonemapping.html
  36. 1 1
      examples/webgl_terrain_dynamic.html
  37. 2 2
      src/Three.js
  38. 17 16
      src/core/BufferGeometry.js
  39. 38 16
      src/core/Geometry.js
  40. 1 3
      src/core/Object3D.js
  41. 6 8
      src/extras/FontUtils.js
  42. 223 220
      src/extras/animation/Animation.js
  43. 98 101
      src/extras/animation/KeyFrameAnimation.js
  44. 7 5
      src/extras/animation/MorphAnimation.js
  45. 57 2
      src/extras/audio/Audio.js
  46. 0 7
      src/extras/audio/AudioListener.js
  47. 0 1
      src/extras/core/Path.js
  48. 1 9
      src/extras/geometries/ExtrudeGeometry.js
  49. 0 1
      src/extras/geometries/ParametricGeometry.js
  50. 1 2
      src/extras/geometries/PolyhedronGeometry.js
  51. 1 2
      src/extras/geometries/ShapeGeometry.js
  52. 2 6
      src/extras/geometries/TubeGeometry.js
  53. 11 2
      src/extras/helpers/EdgesHelper.js
  54. 0 2
      src/extras/helpers/VertexNormalsHelper.js
  55. 0 2
      src/extras/helpers/VertexTangentsHelper.js
  56. 0 1
      src/extras/objects/MorphBlendMesh.js
  57. 3 3
      src/loaders/BufferGeometryLoader.js
  58. 16 14
      src/loaders/JSONLoader.js
  59. 3 2
      src/loaders/ObjectLoader.js
  60. 1 1
      src/math/Matrix3.js
  61. 1 1
      src/math/Matrix4.js
  62. 1 1
      src/math/Spline.js
  63. 15 6
      src/math/Vector2.js
  64. 10 0
      src/math/Vector3.js
  65. 11 0
      src/math/Vector4.js
  66. 1 1
      src/objects/Mesh.js
  67. 0 1
      src/objects/MorphAnimMesh.js
  68. 29 45
      src/renderers/WebGLRenderer.js
  69. 1 1
      src/renderers/shaders/ShaderChunk/alphamap_fragment.glsl
  70. 1 1
      src/renderers/shaders/ShaderChunk/alphatest_fragment.glsl
  71. 1 1
      src/renderers/shaders/ShaderChunk/color_fragment.glsl
  72. 4 4
      src/renderers/shaders/ShaderChunk/envmap_fragment.glsl
  73. 1 1
      src/renderers/shaders/ShaderChunk/fog_fragment.glsl
  74. 1 1
      src/renderers/shaders/ShaderChunk/lightmap_fragment.glsl
  75. 0 3
      src/renderers/shaders/ShaderChunk/lights_lambert_pars_vertex.glsl
  76. 2 2
      src/renderers/shaders/ShaderChunk/lights_lambert_vertex.glsl
  77. 17 57
      src/renderers/shaders/ShaderChunk/lights_phong_fragment.glsl
  78. 1 1
      src/renderers/shaders/ShaderChunk/linear_to_gamma_fragment.glsl
  79. 1 1
      src/renderers/shaders/ShaderChunk/map_fragment.glsl
  80. 1 1
      src/renderers/shaders/ShaderChunk/map_particle_fragment.glsl
  81. 3 3
      src/renderers/shaders/ShaderChunk/shadowmap_fragment.glsl
  82. 43 18
      src/renderers/shaders/ShaderLib.js
  83. 1 1
      src/renderers/webgl/plugins/ShadowMapPlugin.js
  84. 1 0
      src/textures/Texture.js
  85. 64 18
      utils/build/build.js
  86. 2 2
      utils/build/package.json
  87. 87 79
      utils/exporters/blender/addons/io_three/__init__.py
  88. 1 0
      utils/exporters/blender/addons/io_three/constants.py
  89. 4 12
      utils/exporters/blender/addons/io_three/exporter/_json.py
  90. 27 55
      utils/exporters/blender/addons/io_three/exporter/api/animation.py
  91. 7 3
      utils/exporters/blender/addons/io_three/exporter/api/material.py
  92. 58 123
      utils/exporters/blender/addons/io_three/exporter/api/mesh.py
  93. 9 11
      utils/exporters/blender/addons/io_three/exporter/geometry.py
  94. 0 43
      utils/exporters/blender/addons/io_three/exporter/utilities.py
  95. 2 0
      utils/exporters/blender/tests/scripts/exporter.py

+ 1 - 1
bower.json

@@ -1,6 +1,6 @@
 {
 	"name": "three.js",
-	"version": "0.0.70",
+	"version": "0.0.71",
 	"homepage": "http://threejs.org/",
 	"description": "JavaScript 3D library",
 	"main": "build/three.js",

文件差异内容过多而无法显示
+ 123 - 75
build/three.js


文件差异内容过多而无法显示
+ 87 - 88
build/three.min.js


+ 4 - 2
docs/api/extras/helpers/EdgesHelper.html

@@ -27,10 +27,12 @@
 		</code>
 
 		<h2>Constructor</h2>
-		<h3>[name]( [page:Object3D object], [page:Color color] )</h3>
+		<h3>[name]( [page:Object3D object], [page:Color color], [page:Float thresholdAngle] )</h3>
 		<div>
 		object -- Object of which to draw edges <br />
-		color -- Color of the edges.
+		color -- Color of the edges.<br />
+		thresholdAngle -- the minimim angle (in degrees), between the face normals of adjacent faces, that is required to render an edge. Default is 0.1.
+
 		</div>
 		<div>
 		Creates a [page:Line], showing only the "hard" edges of the passed object; specifically, no edge will be drawn between faces which are adjacent and coplanar (or nearly coplanar).

+ 1 - 2
docs/api/math/Matrix4.html

@@ -165,8 +165,7 @@
 
 		<h3>[method:Array decompose]( [page:Vector3 translation], [page:Quaternion quaternion], [page:Vector3 scale] )</h3>
 		<div>
-		Decomposes this matrix into the *translation*, *quaternion* and *scale* components.<br />
-		If parameters are not passed, new instances will be created.
+		Decomposes this matrix into the *translation*, *quaternion* and *scale* components.
 		</div>
 
 		<h3>[method:Matrix4 makeTranslation]( [page:Float x], [page:Float y], [page:Float z] ) [page:Matrix4 this]</h3>

+ 2 - 4
editor/js/Script.js

@@ -89,14 +89,12 @@ var Script = function ( editor ) {
 
 			}
 
-			for ( var i = 0; i < widgets.length; i ++ ) {
+			while ( widgets.length > 0 ) {
 
-				codemirror.removeLineWidget( widgets[ i ] );
+				codemirror.removeLineWidget( widgets.shift() );
 
 			}
 
-			widgets.length = 0;
-
 			//
 
 			try {

+ 19 - 9
editor/js/Sidebar.Geometry.js

@@ -17,13 +17,14 @@ Sidebar.Geometry = function ( editor ) {
 
 	var geometryType = new UI.Text().setTextTransform( 'uppercase' );
 	container.addStatic( geometryType );
-	
+
 	// Actions
-	
+
 	var objectActions = new UI.Select().setPosition('absolute').setRight( '8px' ).setFontSize( '11px' );
 	objectActions.setOptions( {
 
 		'Actions': 'Actions',
+		'Center': 'Center',
 		'Flatten': 'Flatten'
 
 	} );
@@ -34,26 +35,35 @@ Sidebar.Geometry = function ( editor ) {
 	} );
 	objectActions.onChange( function ( event ) {
 
+		var action = this.getValue();
+
 		var object = editor.selected;
+		var geometry = object.geometry;
 
-		switch ( this.getValue() ) {
+		if ( confirm( action + ' ' + object.name + '?' ) === false ) return;
 
-			case 'Flatten':
+		switch ( action ) {
+
+			case 'Center':
 
-				var object = editor.selected;
+				var offset = geometry.center();
 
-				if ( confirm( 'Flatten ' + object.name + '?' ) === false ) return;
+				object.position.sub( offset );
 
-				var geometry = object.geometry;
+				editor.signals.geometryChanged.dispatch( geometry );
+				editor.signals.objectChanged.dispatch( object );
+
+				break;
+
+			case 'Flatten':
 
 				geometry.applyMatrix( object.matrix );
-				geometry.verticesNeedUpdate = true;
-				geometry.normalsNeedUpdate = true;
 
 				object.position.set( 0, 0, 0 );
 				object.rotation.set( 0, 0, 0 );
 				object.scale.set( 1, 1, 1 );
 
+				editor.signals.geometryChanged.dispatch( geometry );
 				editor.signals.objectChanged.dispatch( object );
 
 				break;

+ 0 - 6
editor/js/Viewport.js

@@ -370,12 +370,6 @@ var Viewport = function ( editor ) {
 
 		transformControls.update();
 
-		if ( object.geometry !== undefined ) {
-
-			selectionBox.update( object );
-
-		}
-
 		if ( object instanceof THREE.PerspectiveCamera ) {
 
 			object.updateProjectionMatrix();

+ 3 - 1
examples/index.html

@@ -358,6 +358,7 @@
 				"webgl_shadowmap",
 				"webgl_shadowmap_performance",
 				"webgl_shadowmap_viewer",
+				"webgl_shadowmesh",
 				"webgl_sprites",
 				"webgl_terrain_dynamic",
 				"webgl_test_memory",
@@ -371,7 +372,8 @@
 				"webgldeferred_pointlights"
 			],
 			"vr": [
-				"vr_cubes"
+				"vr_cubes",
+				"vr_video"
 			],
 			"css3d": [
 				"css3d_molecules",

+ 8 - 5
examples/js/ShaderDeferred.js

@@ -187,7 +187,8 @@ THREE.ShaderDeferred = {
 
 				"const float opacity = 1.0;",
 
-				"gl_FragColor = vec4( diffuse, opacity );",
+				"vec3 outgoingLight = vec3( 0.0 );",	// outgoing light does not have an alpha, the surface does
+				"vec4 diffuseColor = vec4( diffuse, opacity );",
 
 				THREE.ShaderChunk[ "map_fragment" ],
 				THREE.ShaderChunk[ "alphatest_fragment" ],
@@ -195,6 +196,8 @@ THREE.ShaderDeferred = {
 				THREE.ShaderChunk[ "lightmap_fragment" ],
 				THREE.ShaderChunk[ "color_fragment" ],
 
+				"outgoingLight = diffuseColor.rgb;",
+
 				"#ifdef USE_ENVMAP",
 
 					"vec2 texCoord = gl_FragCoord.xy / vec2( viewWidth, viewHeight );",
@@ -230,15 +233,15 @@ THREE.ShaderDeferred = {
 
 					"if ( combine == 1 ) {",
 
-						"gl_FragColor.xyz = mix( gl_FragColor.xyz, cubeColor.xyz, specularStrength * reflectivity );",
+						"outgoingLight = mix( outgoingLight, cubeColor.xyz, specularStrength * reflectivity );",
 
 					"} else if ( combine == 2 ) {",
 
-						"gl_FragColor.xyz += cubeColor.xyz * specularStrength * reflectivity;",
+						"outgoingLight += cubeColor.xyz * specularStrength * reflectivity;",
 
 					"} else {",
 
-						"gl_FragColor.xyz = mix( gl_FragColor.xyz, gl_FragColor.xyz * cubeColor.xyz, specularStrength * reflectivity );",
+						"outgoingLight = mix( outgoingLight, diffuseColor.xyz * cubeColor.xyz, specularStrength * reflectivity );",
 
 					"}",
 
@@ -267,7 +270,7 @@ THREE.ShaderDeferred = {
 
 				// diffuse color
 
-				"gl_FragColor.x = vec3_to_float( compressionScale * gl_FragColor.xyz );",
+				"gl_FragColor.x = vec3_to_float( compressionScale * outgoingLight );",
 
 				// specular color
 

+ 36 - 66
examples/js/ShaderSkin.js

@@ -159,12 +159,13 @@ THREE.ShaderSkin = {
 
 			"void main() {",
 
-				"gl_FragColor = vec4( vec3( 1.0 ), opacity );",
+				"vec3 outgoingLight = vec3( 0.0 );",	// outgoing light does not have an alpha, the surface does
+				"vec4 diffuseColor = vec4( diffuse, opacity );",
 
 				"vec4 colDiffuse = texture2D( tDiffuse, vUv );",
 				"colDiffuse.rgb *= colDiffuse.rgb;",
 
-				"gl_FragColor = gl_FragColor * colDiffuse;",
+				"diffuseColor = diffuseColor * colDiffuse;",
 
 				"vec3 normal = normalize( vNormal );",
 				"vec3 viewPosition = normalize( vViewPosition );",
@@ -190,12 +191,11 @@ THREE.ShaderSkin = {
 
 				// point lights
 
-				"vec3 specularTotal = vec3( 0.0 );",
+				"vec3 totalSpecularLight = vec3( 0.0 );",
+				"vec3 totalDiffuseLight = vec3( 0.0 );",
 
 				"#if MAX_POINT_LIGHTS > 0",
 
-					"vec3 pointTotal = vec3( 0.0 );",
-
 					"for ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {",
 
 						"vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );",
@@ -212,8 +212,8 @@ THREE.ShaderSkin = {
 
 						"float pointSpecularWeight = KS_Skin_Specular( normal, lVector, viewPosition, uRoughness, uSpecularBrightness );",
 
-						"pointTotal    += attenuation * diffuse * pointLightColor[ i ] * pointDiffuseWeight;",
-						"specularTotal += attenuation * specular * pointLightColor[ i ] * pointSpecularWeight * specularStrength;",
+						"totalDiffuseLight += attenuation * pointLightColor[ i ] * pointDiffuseWeight;",
+						"totalSpecularLight += attenuation * specular * pointLightColor[ i ] * pointSpecularWeight * specularStrength;",
 
 					"}",
 
@@ -223,8 +223,6 @@ THREE.ShaderSkin = {
 
 				"#if MAX_DIR_LIGHTS > 0",
 
-					"vec3 dirTotal = vec3( 0.0 );",
-
 					"for( int i = 0; i < MAX_DIR_LIGHTS; i++ ) {",
 
 						"vec3 dirVector = transformDirection( directionalLightDirection[ i ], viewMatrix );",
@@ -233,10 +231,10 @@ THREE.ShaderSkin = {
 						"float dirDiffuseWeightHalf = max( 0.5 * dot( normal, dirVector ) + 0.5, 0.0 );",
 						"vec3 dirDiffuseWeight = mix( vec3 ( dirDiffuseWeightFull ), vec3( dirDiffuseWeightHalf ), uWrapRGB );",
 
-						"float dirSpecularWeight =  KS_Skin_Specular( normal, dirVector, viewPosition, uRoughness, uSpecularBrightness );",
+						"float dirSpecularWeight = KS_Skin_Specular( normal, dirVector, viewPosition, uRoughness, uSpecularBrightness );",
 
-						"dirTotal 	   += diffuse * directionalLightColor[ i ] * dirDiffuseWeight;",
-						"specularTotal += specular * directionalLightColor[ i ] * dirSpecularWeight * specularStrength;",
+						"totalDiffuseLight += directionalLightColor[ i ] * dirDiffuseWeight;",
+						"totalSpecularLight += specular * directionalLightColor[ i ] * dirSpecularWeight * specularStrength;",
 
 					"}",
 
@@ -246,8 +244,6 @@ THREE.ShaderSkin = {
 
 				"#if MAX_HEMI_LIGHTS > 0",
 
-					"vec3 hemiTotal = vec3( 0.0 );",
-
 					"for ( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {",
 
 						"vec3 lVector = transformDirection( hemisphereLightDirection[ i ], viewMatrix );",
@@ -255,7 +251,7 @@ THREE.ShaderSkin = {
 						"float dotProduct = dot( normal, lVector );",
 						"float hemiDiffuseWeight = 0.5 * dotProduct + 0.5;",
 
-						"hemiTotal += diffuse * mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );",
+						"totalDiffuseLight += mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );",
 
 						// specular (sky light)
 
@@ -267,34 +263,21 @@ THREE.ShaderSkin = {
 						"vec3 lVectorGround = -lVector;",
 						"hemiSpecularWeight += KS_Skin_Specular( normal, lVectorGround, viewPosition, uRoughness, uSpecularBrightness );",
 
-						"specularTotal += specular * mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight ) * hemiSpecularWeight * specularStrength;",
+						"totalSpecularLight += specular * mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight ) * hemiSpecularWeight * specularStrength;",
 
 					"}",
 
 				"#endif",
 
-				// all lights contribution summation
-
-				"vec3 totalLight = vec3( 0.0 );",
-
-				"#if MAX_DIR_LIGHTS > 0",
-					"totalLight += dirTotal;",
-				"#endif",
-
-				"#if MAX_POINT_LIGHTS > 0",
-					"totalLight += pointTotal;",
-				"#endif",
-
-				"#if MAX_HEMI_LIGHTS > 0",
-					"totalLight += hemiTotal;",
-				"#endif",
-
-				"gl_FragColor.xyz = gl_FragColor.xyz * ( totalLight + ambientLightColor * diffuse ) + specularTotal;",
+				"outgoingLight += diffuseColor.xyz * ( totalDiffuseLight + ambientLightColor * diffuse ) + totalSpecularLight;",
 
 				THREE.ShaderChunk[ "shadowmap_fragment" ],
 				THREE.ShaderChunk[ "linear_to_gamma_fragment" ],
 				THREE.ShaderChunk[ "fog_fragment" ],
 
+				"gl_FragColor = vec4( outgoingLight, diffuseColor.a );",	// TODO, this should be pre-multiplied to allow for bright highlights on very transparent objects
+
+
 			"}"
 
 		].join("\n"),
@@ -468,9 +451,9 @@ THREE.ShaderSkin = {
 
 			"void main() {",
 
-				"gl_FragColor = vec4( 1.0 );",
+				"vec3 outgoingLight = vec3( 0.0 );",	// outgoing light does not have an alpha, the surface does
+				"vec4 diffuseColor = vec4( diffuse, opacity );",
 
-				"vec4 mColor = vec4( diffuse, opacity );",
 				"vec4 mSpecular = vec4( specular, opacity );",
 
 				"vec3 normalTex = texture2D( tNormal, vUv ).xyz * 2.0 - 1.0;",
@@ -480,7 +463,7 @@ THREE.ShaderSkin = {
 				"vec4 colDiffuse = texture2D( tDiffuse, vUv );",
 				"colDiffuse *= colDiffuse;",
 
-				"gl_FragColor = gl_FragColor * colDiffuse;",
+				"diffuseColor *= colDiffuse;",
 
 				"mat3 tsb = mat3( vTangent, vBinormal, vNormal );",
 				"vec3 finalNormal = tsb * normalTex;",
@@ -490,12 +473,11 @@ THREE.ShaderSkin = {
 
 				// point lights
 
-				"vec3 specularTotal = vec3( 0.0 );",
+				"vec3 totalDiffuseLight = vec3( 0.0 );",
+				"vec3 totalSpecularLight = vec3( 0.0 );",
 
 				"#if MAX_POINT_LIGHTS > 0",
 
-					"vec4 pointTotal = vec4( vec3( 0.0 ), 1.0 );",
-
 					"for ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {",
 
 						"vec3 pointVector = normalize( vPointLight[ i ].xyz );",
@@ -503,10 +485,10 @@ THREE.ShaderSkin = {
 
 						"float pointDiffuseWeight = max( dot( normal, pointVector ), 0.0 );",
 
-						"pointTotal  += pointDistance * vec4( pointLightColor[ i ], 1.0 ) * ( mColor * pointDiffuseWeight );",
+						"totalDiffuseLight += pointDistance * pointLightColor[ i ] * pointDiffuseWeight;",
 
 						"if ( passID == 1 )",
-							"specularTotal += pointDistance * mSpecular.xyz * pointLightColor[ i ] * KS_Skin_Specular( normal, pointVector, viewPosition, uRoughness, uSpecularBrightness );",
+							"totalSpecularLight += pointDistance * mSpecular.xyz * pointLightColor[ i ] * KS_Skin_Specular( normal, pointVector, viewPosition, uRoughness, uSpecularBrightness );",
 
 					"}",
 
@@ -516,40 +498,27 @@ THREE.ShaderSkin = {
 
 				"#if MAX_DIR_LIGHTS > 0",
 
-					"vec4 dirTotal = vec4( vec3( 0.0 ), 1.0 );",
-
 					"for( int i = 0; i < MAX_DIR_LIGHTS; i++ ) {",
 
 						"vec3 dirVector = transformDirection( directionalLightDirection[ i ], viewMatrix );",
 
 						"float dirDiffuseWeight = max( dot( normal, dirVector ), 0.0 );",
 
-						"dirTotal  += vec4( directionalLightColor[ i ], 1.0 ) * ( mColor * dirDiffuseWeight );",
+						"totalDiffuseLight += directionalLightColor[ i ] * dirDiffuseWeight;",
 
 						"if ( passID == 1 )",
-							"specularTotal += mSpecular.xyz * directionalLightColor[ i ] * KS_Skin_Specular( normal, dirVector, viewPosition, uRoughness, uSpecularBrightness );",
+							"totalSpecularLight += mSpecular.xyz * directionalLightColor[ i ] * KS_Skin_Specular( normal, dirVector, viewPosition, uRoughness, uSpecularBrightness );",
 
 					"}",
 
 				"#endif",
 
-				// all lights contribution summation
 
-				"vec4 totalLight = vec4( vec3( 0.0 ), opacity );",
-
-				"#if MAX_DIR_LIGHTS > 0",
-					"totalLight += dirTotal;",
-				"#endif",
-
-				"#if MAX_POINT_LIGHTS > 0",
-					"totalLight += pointTotal;",
-				"#endif",
-
-				"gl_FragColor = gl_FragColor * totalLight;",
+				"outgoingLight += diffuseColor.rgb * ( totalDiffuseLight + totalSpecularLight );",
 
 				"if ( passID == 0 ) {",
 
-					"gl_FragColor = vec4( sqrt( gl_FragColor.xyz ), gl_FragColor.w );",
+					"outgoingLight = sqrt( outgoingLight );",
 
 				"} else if ( passID == 1 ) {",
 
@@ -557,11 +526,11 @@ THREE.ShaderSkin = {
 
 					"#ifdef VERSION1",
 
-						"vec3 nonblurColor = sqrt( gl_FragColor.xyz );",
+						"vec3 nonblurColor = sqrt(outgoingLight );",
 
 					"#else",
 
-						"vec3 nonblurColor = gl_FragColor.xyz;",
+						"vec3 nonblurColor = outgoingLight;",
 
 					"#endif",
 
@@ -578,20 +547,19 @@ THREE.ShaderSkin = {
 					//"gl_FragColor = vec4( vec3( 0.25, 0.6, 0.8 ) * nonblurColor + vec3( 0.15, 0.25, 0.2 ) * blur1Color + vec3( 0.15, 0.15, 0.0 ) * blur2Color + vec3( 0.45, 0.0, 0.0 ) * blur3Color, gl_FragColor.w );",
 
 
-					"gl_FragColor = vec4( vec3( 0.22,  0.437, 0.635 ) * nonblurColor + ",
+					"outgoingLight = vec3( vec3( 0.22,  0.437, 0.635 ) * nonblurColor + ",
 										 "vec3( 0.101, 0.355, 0.365 ) * blur1Color + ",
 										 "vec3( 0.119, 0.208, 0.0 )   * blur2Color + ",
 										 "vec3( 0.114, 0.0,   0.0 )   * blur3Color + ",
-										 "vec3( 0.444, 0.0,   0.0 )   * blur4Color",
-										 ", gl_FragColor.w );",
+										 "vec3( 0.444, 0.0,   0.0 )   * blur4Color );",
 
-					"gl_FragColor.xyz *= pow( colDiffuse.xyz, vec3( 0.5 ) );",
+					"outgoingLight *= sqrt( colDiffuse.xyz );",
 
-					"gl_FragColor.xyz += ambientLightColor * diffuse * colDiffuse.xyz + specularTotal;",
+					"outgoingLight += ambientLightColor * diffuse * colDiffuse.xyz + totalSpecularLight;",
 
 					"#ifndef VERSION1",
 
-						"gl_FragColor.xyz = sqrt( gl_FragColor.xyz );",
+						"outgoingLight = sqrt( outgoingLight );",
 
 					"#endif",
 
@@ -599,6 +567,8 @@ THREE.ShaderSkin = {
 
 				THREE.ShaderChunk[ "fog_fragment" ],
 
+				"gl_FragColor = vec4( outgoingLight, diffuseColor.a );",	// TODO, this should be pre-multiplied to allow for bright highlights on very transparent objects
+
 			"}"
 
 		].join("\n"),

+ 17 - 41
examples/js/ShaderTerrain.js

@@ -118,7 +118,8 @@ THREE.ShaderTerrain = {
 
 			"void main() {",
 
-				"gl_FragColor = vec4( vec3( 1.0 ), opacity );",
+				"vec3 outgoingLight = vec3( 0.0 );",	// outgoing light does not have an alpha, the surface does
+				"vec4 diffuseColor = vec4( diffuse, opacity );",
 
 				"vec3 specularTex = vec3( 1.0 );",
 
@@ -137,15 +138,15 @@ THREE.ShaderTerrain = {
 					"colDiffuse1.xyz = inputToLinear( colDiffuse1.xyz );",
 					"colDiffuse2.xyz = inputToLinear( colDiffuse2.xyz );",
 
-					"gl_FragColor = gl_FragColor * mix ( colDiffuse1, colDiffuse2, 1.0 - texture2D( tDisplacement, uvBase ) );",
+					"diffuseColor *= mix ( colDiffuse1, colDiffuse2, 1.0 - texture2D( tDisplacement, uvBase ) );",
 
 				" } else if( enableDiffuse1 ) {",
 
-					"gl_FragColor = gl_FragColor * texture2D( tDiffuse1, uvOverlay );",
+					"diffuseColor *= texture2D( tDiffuse1, uvOverlay );",
 
 				"} else if( enableDiffuse2 ) {",
 
-					"gl_FragColor = gl_FragColor * texture2D( tDiffuse2, uvOverlay );",
+					"diffuseColor *= texture2D( tDiffuse2, uvOverlay );",
 
 				"}",
 
@@ -158,13 +159,13 @@ THREE.ShaderTerrain = {
 				"vec3 normal = normalize( finalNormal );",
 				"vec3 viewPosition = normalize( vViewPosition );",
 
+				"vec3 totalDiffuseLight = vec3( 0.0 );",
+				"vec3 totalSpecularLight = vec3( 0.0 );",
+
 				// point lights
 
 				"#if MAX_POINT_LIGHTS > 0",
 
-					"vec3 pointDiffuse = vec3( 0.0 );",
-					"vec3 pointSpecular = vec3( 0.0 );",
-
 					"for ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {",
 
 						"vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );",
@@ -181,8 +182,8 @@ THREE.ShaderTerrain = {
 
 						"float pointSpecularWeight = specularTex.r * max( pow( pointDotNormalHalf, shininess ), 0.0 );",
 
-						"pointDiffuse += attenuation * pointLightColor[ i ] * diffuse * pointDiffuseWeight;",
-						"pointSpecular += attenuation * pointLightColor[ i ] * specular * pointSpecularWeight * pointDiffuseWeight;",
+						"totalDiffuseLight += attenuation * pointLightColor[ i ] * pointDiffuseWeight;",
+						"totalSpecularLight += attenuation * pointLightColor[ i ] * specular * pointSpecularWeight * pointDiffuseWeight;",
 
 					"}",
 
@@ -205,8 +206,8 @@ THREE.ShaderTerrain = {
 
 						"float dirSpecularWeight = specularTex.r * max( pow( dirDotNormalHalf, shininess ), 0.0 );",
 
-						"dirDiffuse += directionalLightColor[ i ] * diffuse * dirDiffuseWeight;",
-						"dirSpecular += directionalLightColor[ i ] * specular * dirSpecularWeight * dirDiffuseWeight;",
+						"totalDiffuseLight += directionalLightColor[ i ] * dirDiffuseWeight;",
+						"totalSpecularLight += directionalLightColor[ i ] * specular * dirSpecularWeight * dirDiffuseWeight;",
 
 					"}",
 
@@ -228,7 +229,7 @@ THREE.ShaderTerrain = {
 						"float dotProduct = dot( normal, lVector );",
 						"float hemiDiffuseWeight = 0.5 * dotProduct + 0.5;",
 
-						"hemiDiffuse += diffuse * mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );",
+						"totalDiffuseLight += mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );",
 
 						// specular (sky light)
 
@@ -246,45 +247,20 @@ THREE.ShaderTerrain = {
 						"float hemiDotNormalHalfGround = 0.5 * dot( normal, hemiHalfVectorGround ) + 0.5;",
 						"hemiSpecularWeight += specularTex.r * max( pow( hemiDotNormalHalfGround, shininess ), 0.0 );",
 
-						"hemiSpecular += specular * mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight ) * hemiSpecularWeight * hemiDiffuseWeight;",
+						"totalSpecularLight += specular * mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight ) * hemiSpecularWeight * hemiDiffuseWeight;",
 
 					"}",
 
 				"#endif",
 
-				// all lights contribution summation
-
-				"vec3 totalDiffuse = vec3( 0.0 );",
-				"vec3 totalSpecular = vec3( 0.0 );",
-
-				"#if MAX_DIR_LIGHTS > 0",
-
-					"totalDiffuse += dirDiffuse;",
-					"totalSpecular += dirSpecular;",
-
-				"#endif",
-
-				"#if MAX_HEMI_LIGHTS > 0",
-
-					"totalDiffuse += hemiDiffuse;",
-					"totalSpecular += hemiSpecular;",
-
-				"#endif",
-
-				"#if MAX_POINT_LIGHTS > 0",
-
-					"totalDiffuse += pointDiffuse;",
-					"totalSpecular += pointSpecular;",
-
-				"#endif",
-
-				//"gl_FragColor.xyz = gl_FragColor.xyz * ( totalDiffuse + ambientLightColor * diffuse ) + totalSpecular;",
-				"gl_FragColor.xyz = gl_FragColor.xyz * ( totalDiffuse + ambientLightColor * diffuse + totalSpecular );",
+				"outgoingLight += diffuseColor.xyz * ( totalDiffuseLight + ambientLightColor + totalSpecularLight );",
 
 				THREE.ShaderChunk[ "shadowmap_fragment" ],
 				THREE.ShaderChunk[ "linear_to_gamma_fragment" ],
 				THREE.ShaderChunk[ "fog_fragment" ],
 
+				"gl_FragColor = vec4( outgoingLight, diffuseColor.a );",	// TODO, this should be pre-multiplied to allow for bright highlights on very transparent objects
+
 			"}"
 
 		].join("\n"),

+ 16 - 23
examples/js/SkyShader.js

@@ -1,16 +1,16 @@
 /**
  * @author zz85 / https://github.com/zz85
- * 
- * Based on "A Practical Analytic Model for Daylight" 
+ *
+ * Based on "A Practical Analytic Model for Daylight"
  * aka The Preetham Model, the de facto standard analytic skydome model
  * http://www.cs.utah.edu/~shirley/papers/sunsky/sunsky.pdf
- * 
+ *
  * First implemented by Simon Wallner
  * http://www.simonwallner.at/projects/atmospheric-scattering
- * 
+ *
  * Improved by Martin Upitis
  * http://blenderartists.org/forum/showthread.php?245954-preethams-sky-impementation-HDR
- * 
+ *
  * Three.js integration by zz85 http://twitter.com/blurspline
 */
 
@@ -30,13 +30,11 @@ THREE.ShaderLib['sky'] = {
 	vertexShader: [
 
 		"varying vec3 vWorldPosition;",
-		"varying vec2 vUv;",
 
 		"void main() {",
 
 			"vec4 worldPosition = modelMatrix * vec4( position, 1.0 );",
 			"vWorldPosition = worldPosition.xyz;",
-			"vUv = uv;",
 
 			"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
 
@@ -46,12 +44,9 @@ THREE.ShaderLib['sky'] = {
 
 	fragmentShader: [
 
-
 		"uniform sampler2D skySampler;",
 		"uniform vec3 sunPosition;",
 		"varying vec3 vWorldPosition;",
-		"varying vec2 vUv;",
-
 
 		"vec3 cameraPos = vec3(0., 0., 0.);",
 		"// uniform sampler2D sDiffuse;",
@@ -67,7 +62,6 @@ THREE.ShaderLib['sky'] = {
 		"uniform float mieCoefficient;",
 		"uniform float mieDirectionalG;",
 
-
 		"vec3 sunDirection = normalize(sunPosition);",
 		"float reileighCoefficient = reileigh;",
 
@@ -165,9 +159,9 @@ THREE.ShaderLib['sky'] = {
 			"// luminance =  1.0 ;// vWorldPosition.y / 450000. + 0.5; //sunPosition.y / 450000. * 1. + 0.5;",
 
 			 "// gl_FragColor = vec4(sunfade, sunfade, sunfade, 1.0);",
-			
+
 			"reileighCoefficient = reileighCoefficient - (1.0* (1.0-sunfade));",
-			
+
 			"float sunE = sunIntensity(dot(sunDirection, up));",
 
 			"// extinction (absorbtion + out scattering) ",
@@ -210,7 +204,7 @@ THREE.ShaderLib['sky'] = {
 			"vec2 uv = vec2(phi, theta) / vec2(2.0*pi, pi) + vec2(0.5, 0.0);",
 			"// vec3 L0 = texture2D(skySampler, uv).rgb+0.1 * Fex;",
 			"vec3 L0 = vec3(0.1) * Fex;",
-			
+
 			"// composition + solar disc",
 			"//if (cosTheta > sunAngularDiameterCos)",
 			"float sundisk = smoothstep(sunAngularDiameterCos,sunAngularDiameterCos+0.00002,cosTheta);",
@@ -219,25 +213,25 @@ THREE.ShaderLib['sky'] = {
 
 
 			"vec3 whiteScale = 1.0/Uncharted2Tonemap(vec3(W));",
-			
+
 			"vec3 texColor = (Lin+L0);   ",
 			"texColor *= 0.04 ;",
 			"texColor += vec3(0.0,0.001,0.0025)*0.3;",
-			
+
 			"float g_fMaxLuminance = 1.0;",
 			"float fLumScaled = 0.1 / luminance;     ",
 			"float fLumCompressed = (fLumScaled * (1.0 + (fLumScaled / (g_fMaxLuminance * g_fMaxLuminance)))) / (1.0 + fLumScaled); ",
 
 			"float ExposureBias = fLumCompressed;",
-		   
+
 			"vec3 curr = Uncharted2Tonemap((log2(2.0/pow(luminance,4.0)))*texColor);",
 			"vec3 color = curr*whiteScale;",
 
 			"vec3 retColor = pow(color,vec3(1.0/(1.2+(1.2*sunfade))));",
 
-			
+
 			"gl_FragColor.rgb = retColor;",
-				
+
 			"gl_FragColor.a = 1.0;",
 		"}",
 
@@ -250,9 +244,9 @@ THREE.Sky = function () {
 	var skyShader = THREE.ShaderLib[ "sky" ];
 	var skyUniforms = THREE.UniformsUtils.clone( skyShader.uniforms );
 
-	var skyMat = new THREE.ShaderMaterial( { 
-		fragmentShader: skyShader.fragmentShader, 
-		vertexShader: skyShader.vertexShader, 
+	var skyMat = new THREE.ShaderMaterial( {
+		fragmentShader: skyShader.fragmentShader,
+		vertexShader: skyShader.vertexShader,
 		uniforms: skyUniforms,
 		side: THREE.BackSide
 	} );
@@ -265,5 +259,4 @@ THREE.Sky = function () {
 	this.mesh = skyMesh;
 	this.uniforms = skyUniforms;
 
-
 };

+ 19 - 4
examples/js/effects/VREffect.js

@@ -74,16 +74,31 @@ THREE.VREffect = function ( renderer, done ) {
 			return;
 		}
 		// Regular render mode if not HMD
+		if ( scene instanceof Array ) scene = scene[ 0 ];
 		renderer.render.apply( this._renderer, arguments );
 	};
 
 	this.renderStereo = function( scene, camera, renderTarget, forceClear ) {
 
+		var sceneLeft, sceneRight;
+
+		if ( scene instanceof Array ) {
+
+			sceneLeft = scene[ 0 ];
+			sceneRight = scene[ 1 ];
+
+		} else {
+
+			sceneLeft = scene;
+			sceneRight = scene;
+
+		}
+
 		var leftEyeTranslation = this.leftEyeTranslation;
 		var rightEyeTranslation = this.rightEyeTranslation;
 		var renderer = this._renderer;
-		var rendererWidth = renderer.context.drawingBufferWidth;
-		var rendererHeight = renderer.context.drawingBufferHeight;
+		var rendererWidth = renderer.context.drawingBufferWidth / renderer.getPixelRatio();
+		var rendererHeight = renderer.context.drawingBufferHeight / renderer.getPixelRatio();
 		var eyeDivisionLine = rendererWidth / 2;
 
 		renderer.enableScissorTest( true );
@@ -105,12 +120,12 @@ THREE.VREffect = function ( renderer, done ) {
 		// render left eye
 		renderer.setViewport( 0, 0, eyeDivisionLine, rendererHeight );
 		renderer.setScissor( 0, 0, eyeDivisionLine, rendererHeight );
-		renderer.render( scene, cameraLeft );
+		renderer.render( sceneLeft, cameraLeft );
 
 		// render right eye
 		renderer.setViewport( eyeDivisionLine, 0, eyeDivisionLine, rendererHeight );
 		renderer.setScissor( eyeDivisionLine, 0, eyeDivisionLine, rendererHeight );
-		renderer.render( scene, cameraRight );
+		renderer.render( sceneRight, cameraRight );
 
 		renderer.enableScissorTest( false );
 

+ 2 - 2
examples/js/math/Lut.js

@@ -300,7 +300,7 @@ THREE.Lut.prototype = {
 		contextTitle.fillText( this.legend.labels.title.toString() + this.legend.labels.um.toString(), borderThickness, this.legend.labels.fontsize + borderThickness );
 
 		var txtTitle = new THREE.Texture( canvasTitle );
-
+		txtTitle.minFilter = THREE.LinearFilter;
 		txtTitle.needsUpdate = true;
 
 		var spriteMaterialTitle = new THREE.SpriteMaterial( { map: txtTitle, useScreenCoordinates: false } );
@@ -385,7 +385,7 @@ THREE.Lut.prototype = {
 				contextTick.fillText( value.toString(), borderThickness, this.legend.labels.fontsize + borderThickness );
 
 				var txtTick = new THREE.Texture( canvasTick );
-
+				txtTick.minFilter = THREE.LinearFilter;
 				txtTick.needsUpdate = true;
 
 				var spriteMaterialTick = new THREE.SpriteMaterial( { map: txtTick, useScreenCoordinates: false } );

+ 11 - 11
examples/js/postprocessing/AdaptiveToneMappingPass.js

@@ -16,7 +16,7 @@ THREE.AdaptiveToneMappingPass = function ( adaptive, resolution ) {
 	this.luminanceRT = null;
 	this.previousLuminanceRT = null;
 	this.currentLuminanceRT = null;
-	
+
 	if ( THREE.CopyShader === undefined )
 		console.error( "THREE.AdaptiveToneMappingPass relies on THREE.CopyShader" );
 
@@ -39,7 +39,7 @@ THREE.AdaptiveToneMappingPass = function ( adaptive, resolution ) {
 
 	this.materialLuminance = new THREE.ShaderMaterial( {
 
-		uniforms: THREE.LuminosityShader.uniforms,
+		uniforms: THREE.UniformsUtils.clone( THREE.LuminosityShader.uniforms ),
 		vertexShader: THREE.LuminosityShader.vertexShader,
 		fragmentShader: THREE.LuminosityShader.fragmentShader,
 		blending: THREE.NoBlending,
@@ -72,15 +72,15 @@ THREE.AdaptiveToneMappingPass = function ( adaptive, resolution ) {
 			"uniform sampler2D currentLum;",
 			"uniform float delta;",
 			"uniform float tau;",
-			
+
 			"void main() {",
 
 				"vec4 lastLum = texture2D( lastLum, vUv, MIP_LEVEL_1X1 );",
 				"vec4 currentLum = texture2D( currentLum, vUv, MIP_LEVEL_1X1 );",
-				
+
 				"float fLastLum = lastLum.r;",
 				"float fCurrentLum = currentLum.r;",
-				
+
 				//The adaption seems to work better in extreme lighting differences
 				//if the input luminance is squared.
 				"fCurrentLum *= fCurrentLum;",
@@ -95,7 +95,7 @@ THREE.AdaptiveToneMappingPass = function ( adaptive, resolution ) {
 
 	this.materialAdaptiveLum = new THREE.ShaderMaterial( {
 
-		uniforms: this.adaptLuminanceShader.uniforms,
+		uniforms: THREE.UniformsUtils.clone( this.adaptLuminanceShader.uniforms ),
 		vertexShader: this.adaptLuminanceShader.vertexShader,
 		fragmentShader: this.adaptLuminanceShader.fragmentShader,
 		defines: this.adaptLuminanceShader.defines,
@@ -107,7 +107,7 @@ THREE.AdaptiveToneMappingPass = function ( adaptive, resolution ) {
 
 	this.materialToneMap = new THREE.ShaderMaterial( {
 
-		uniforms: THREE.ToneMapShader.uniforms,
+		uniforms: THREE.UniformsUtils.clone( THREE.ToneMapShader.uniforms ),
 		vertexShader: THREE.ToneMapShader.vertexShader,
 		fragmentShader: THREE.ToneMapShader.fragmentShader,
 		blending: THREE.NoBlending
@@ -120,7 +120,7 @@ THREE.AdaptiveToneMappingPass = function ( adaptive, resolution ) {
 	this.camera = new THREE.OrthographicCamera( -1, 1, 1, -1, 0, 1 );
 	this.scene  = new THREE.Scene();
 
-	this.quad = new THREE.Mesh( new THREE.PlaneGeometry( 2, 2 ), null );
+	this.quad = new THREE.Mesh( new THREE.PlaneBufferGeometry( 2, 2 ), null );
 	this.scene.add( this.quad );
 
 };
@@ -160,7 +160,7 @@ THREE.AdaptiveToneMappingPass.prototype = {
 		this.quad.material = this.materialToneMap;
 		this.materialToneMap.uniforms.tDiffuse.value = readBuffer;
 		renderer.render( this.scene, this.camera, writeBuffer, this.clear );
-		
+
 	},
 
 	reset: function( renderer ) {
@@ -184,7 +184,7 @@ THREE.AdaptiveToneMappingPass.prototype = {
 		//We only need mipmapping for the current luminosity because we want a down-sampled version to sample in our adaptive shader
 		pars.minFilter = THREE.LinearMipMapLinearFilter;
 		this.currentLuminanceRT = new THREE.WebGLRenderTarget( this.resolution, this.resolution, pars );
-		
+
 		if ( this.adaptive ) {
 			this.materialToneMap.defines["ADAPTED_LUMINANCE"] = "";
 			this.materialToneMap.uniforms.luminanceMap.value = this.luminanceRT;
@@ -261,4 +261,4 @@ THREE.AdaptiveToneMappingPass.prototype = {
 		}
 	}
 
-};
+};

+ 26 - 63
examples/js/shaders/NormalDisplacementShader.js

@@ -134,7 +134,8 @@ THREE.NormalDisplacementShader = {
 		"void main() {",
 			THREE.ShaderChunk[ "logdepthbuf_fragment" ],
 
-		"	gl_FragColor = vec4( vec3( 1.0 ), opacity );",
+		"	vec3 outgoingLight = vec3( 0.0 );",	// outgoing light does not have an alpha, the surface does
+		"	vec4 diffuseColor = vec4( diffuse, opacity );",
 
 		"	vec3 specularTex = vec3( 1.0 );",
 
@@ -149,11 +150,11 @@ THREE.NormalDisplacementShader = {
 		"			vec4 texelColor = texture2D( tDiffuse, vUv );",
 		"			texelColor.xyz *= texelColor.xyz;",
 
-		"			gl_FragColor = gl_FragColor * texelColor;",
+		"			diffuseColor *= texelColor;",
 
 		"		#else",
 
-		"			gl_FragColor = gl_FragColor * texture2D( tDiffuse, vUv );",
+		"			diffuseColor *= texture2D( tDiffuse, vUv );",
 
 		"		#endif",
 
@@ -166,11 +167,11 @@ THREE.NormalDisplacementShader = {
 		"			vec4 aoColor = texture2D( tAO, vUv );",
 		"			aoColor.xyz *= aoColor.xyz;",
 
-		"			gl_FragColor.xyz = gl_FragColor.xyz * aoColor.xyz;",
+		"			diffuseColor.rgb *= aoColor.xyz;",
 
 		"		#else",
 
-		"			gl_FragColor.xyz = gl_FragColor.xyz * texture2D( tAO, vUv ).xyz;",
+		"			diffuseColor.rgb *= texture2D( tAO, vUv ).xyz;",
 
 		"		#endif",
 
@@ -193,13 +194,13 @@ THREE.NormalDisplacementShader = {
 		"	vec3 normal = normalize( finalNormal );",
 		"	vec3 viewPosition = normalize( vViewPosition );",
 
+		"	vec3 totalDiffuseLight = vec3( 0.0 );",
+		"	vec3 totalSpecularLight = vec3( 0.0 );",
+
 			// point lights
 
 		"	#if MAX_POINT_LIGHTS > 0",
 
-		"		vec3 pointDiffuse = vec3( 0.0 );",
-		"		vec3 pointSpecular = vec3( 0.0 );",
-
 		"		for ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {",
 
 		"			vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );",
@@ -226,7 +227,7 @@ THREE.NormalDisplacementShader = {
 
 		"			#endif",
 
-		"			pointDiffuse += pointDistance * pointLightColor[ i ] * diffuse * pointDiffuseWeight;",
+		"			totalDiffuseLight += pointDistance * pointLightColor[ i ] * pointDiffuseWeight;",
 
 					// specular
 
@@ -237,7 +238,7 @@ THREE.NormalDisplacementShader = {
 		"			float specularNormalization = ( shininess + 2.0 ) / 8.0;",
 
 		"			vec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( pointVector, pointHalfVector ), 0.0 ), 5.0 );",
-		"			pointSpecular += schlick * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * pointDistance * specularNormalization;",
+		"			totalSpecularLight += schlick * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * pointDistance * specularNormalization;",
 
 		"		}",
 
@@ -247,9 +248,6 @@ THREE.NormalDisplacementShader = {
 
 		"	#if MAX_SPOT_LIGHTS > 0",
 
-		"		vec3 spotDiffuse = vec3( 0.0 );",
-		"		vec3 spotSpecular = vec3( 0.0 );",
-
 		"		for ( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {",
 
 		"			vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );",
@@ -282,7 +280,7 @@ THREE.NormalDisplacementShader = {
 
 		"				#endif",
 
-		"				spotDiffuse += spotDistance * spotLightColor[ i ] * diffuse * spotDiffuseWeight * spotEffect;",
+		"				totalDiffuseLight += spotDistance * spotLightColor[ i ] * spotDiffuseWeight * spotEffect;",
 
 						// specular
 
@@ -293,7 +291,7 @@ THREE.NormalDisplacementShader = {
 		"				float specularNormalization = ( shininess + 2.0 ) / 8.0;",
 
 		"				vec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( spotVector, spotHalfVector ), 0.0 ), 5.0 );",
-		"				spotSpecular += schlick * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * spotDistance * specularNormalization * spotEffect;",
+		"				totalSpecularLight += schlick * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * spotDistance * specularNormalization * spotEffect;",
 
 		"			}",
 
@@ -305,9 +303,6 @@ THREE.NormalDisplacementShader = {
 
 		"	#if MAX_DIR_LIGHTS > 0",
 
-		"		vec3 dirDiffuse = vec3( 0.0 );",
-		"		vec3 dirSpecular = vec3( 0.0 );",
-
 		"		for( int i = 0; i < MAX_DIR_LIGHTS; i++ ) {",
 
 		"			vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );",
@@ -328,7 +323,7 @@ THREE.NormalDisplacementShader = {
 
 		"			#endif",
 
-		"			dirDiffuse += directionalLightColor[ i ] * diffuse * dirDiffuseWeight;",
+		"			totalDiffuseLight += directionalLightColor[ i ] * dirDiffuseWeight;",
 
 					// specular
 
@@ -339,7 +334,7 @@ THREE.NormalDisplacementShader = {
 		"			float specularNormalization = ( shininess + 2.0 ) / 8.0;",
 
 		"			vec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( dirVector, dirHalfVector ), 0.0 ), 5.0 );",
-		"			dirSpecular += schlick * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization;",
+		"			totalSpecularLight += schlick * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization;",
 
 		"		}",
 
@@ -349,9 +344,6 @@ THREE.NormalDisplacementShader = {
 
 		"	#if MAX_HEMI_LIGHTS > 0",
 
-		"		vec3 hemiDiffuse = vec3( 0.0 );",
-		"		vec3 hemiSpecular = vec3( 0.0 );",
-
 		"		for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {",
 
 		"			vec4 lDirection = viewMatrix * vec4( hemisphereLightDirection[ i ], 0.0 );",
@@ -364,7 +356,7 @@ THREE.NormalDisplacementShader = {
 
 		"			vec3 hemiColor = mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );",
 
-		"			hemiDiffuse += diffuse * hemiColor;",
+		"			totalDiffuseLight += hemiColor;",
 
 					// specular (sky light)
 
@@ -387,52 +379,19 @@ THREE.NormalDisplacementShader = {
 
 		"			vec3 schlickSky = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, hemiHalfVectorSky ), 0.0 ), 5.0 );",
 		"			vec3 schlickGround = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVectorGround, hemiHalfVectorGround ), 0.0 ), 5.0 );",
-		"			hemiSpecular += hemiColor * specularNormalization * ( schlickSky * hemiSpecularWeightSky * max( dotProduct, 0.0 ) + schlickGround * hemiSpecularWeightGround * max( dotProductGround, 0.0 ) );",
+		"			totalSpecularLight += hemiColor * specularNormalization * ( schlickSky * hemiSpecularWeightSky * max( dotProduct, 0.0 ) + schlickGround * hemiSpecularWeightGround * max( dotProductGround, 0.0 ) );",
 
 		"		}",
 
-		"	#endif",
-
-			// all lights contribution summation
-
-		"	vec3 totalDiffuse = vec3( 0.0 );",
-		"	vec3 totalSpecular = vec3( 0.0 );",
-
-		"	#if MAX_DIR_LIGHTS > 0",
-
-		"		totalDiffuse += dirDiffuse;",
-		"		totalSpecular += dirSpecular;",
-
-		"	#endif",
-
-		"	#if MAX_HEMI_LIGHTS > 0",
-
-		"		totalDiffuse += hemiDiffuse;",
-		"		totalSpecular += hemiSpecular;",
-
-		"	#endif",
-
-		"	#if MAX_POINT_LIGHTS > 0",
-
-		"		totalDiffuse += pointDiffuse;",
-		"		totalSpecular += pointSpecular;",
-
-		"	#endif",
-
-		"	#if MAX_SPOT_LIGHTS > 0",
-
-		"		totalDiffuse += spotDiffuse;",
-		"		totalSpecular += spotSpecular;",
-
 		"	#endif",
 
 		"	#ifdef METAL",
 
-		"		gl_FragColor.xyz = gl_FragColor.xyz * ( totalDiffuse + ambientLightColor * diffuse + totalSpecular );",
+		"		outgoingLight += diffuseColor.xyz * ( totalDiffuseLight + ambientLightColor + totalSpecularLight );",
 
 		"	#else",
 
-		"		gl_FragColor.xyz = gl_FragColor.xyz * ( totalDiffuse + ambientLightColor * diffuse ) + totalSpecular;",
+		"		outgoingLight += diffuseColor.xyz * ( totalDiffuseLight + ambientLightColor ) + totalSpecularLight;",
 
 		"	#endif",
 
@@ -440,13 +399,15 @@ THREE.NormalDisplacementShader = {
 
 		"		vec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );",
 
+		"		vec3 worldNormal = inverseTransformDirection( normal, viewMatrix );",
+
 		"		#ifdef ENVMAP_MODE_REFLECTION",
 
-		"			vec3 vReflect = reflect( cameraToVertex, normal );",
+		"			vec3 vReflect = reflect( cameraToVertex, worldNormal );",
 
 		"		#else",
 
-		"			vec3 vReflect = refract( cameraToVertex, normal, refractionRatio );",
+		"			vec3 vReflect = refract( cameraToVertex, worldNormal, refractionRatio );",
 
 		"		#endif",
 
@@ -458,7 +419,7 @@ THREE.NormalDisplacementShader = {
 
 		"		#endif",
 
-		"		gl_FragColor.xyz = mix( gl_FragColor.xyz, cubeColor.xyz, specularTex.r * reflectivity );",
+		"		outgoingLight = mix( outgoingLight, cubeColor.xyz, specularTex.r * reflectivity );",
 
 		"	}",
 
@@ -466,6 +427,8 @@ THREE.NormalDisplacementShader = {
 			THREE.ShaderChunk[ "linear_to_gamma_fragment" ],
 			THREE.ShaderChunk[ "fog_fragment" ],
 
+		"	gl_FragColor = vec4( outgoingLight, diffuseColor.a );",	// TODO, this should be pre-multiplied to allow for bright highlights on very transparent objects
+
 		"}"
 
 	].join("\n"),

+ 6 - 5
examples/misc_fps.html

@@ -163,7 +163,7 @@
 								var actualHeight = hits[0].distance - birdsEye;
 
 								// collision: stick to the surface if landing on it
-								
+
 								if( ( motion.velocity.y <= 0 ) && ( Math.abs( actualHeight ) < kneeDeep ) ) {
 									motion.position.y -= actualHeight;
 									motion.velocity.y = 0;
@@ -185,9 +185,9 @@
 							// limit the tilt at ±0.4 radians
 
 							motion.rotation.x = Math.max( -0.4, Math.min ( +0.4, motion.rotation.x ) );
-							
+
 							// wrap horizontal rotation to 0...2π
-							
+
 							motion.rotation.y += tau; motion.rotation.y %= tau;
 
 							timeLeft -= dt;
@@ -233,6 +233,7 @@
 				var placeholder = new THREE.Object3D();
 
 				var texture = THREE.ImageUtils.loadTexture( textureUrl );
+				texture.minFilter = THREE.LinearFilter;
 				texture.anisotropy = textureQuality;
 
 				var loader = new THREE.JSONLoader();
@@ -256,7 +257,7 @@
 			var camera = new THREE.PerspectiveCamera( 60, 1, 0.1, 9000 );
 
 			var scene = new THREE.Scene();
-			
+
 			scene.add( camera );
 
 			scene.add( makeSkybox( [
@@ -294,7 +295,7 @@
 
 					// call our game loop with the time elapsed since last rendering, in ms
 					gameLoop( timeElapsed );
-					
+
 					renderer.render( scene, camera );
 					requestAnimationFrame( render );
 				};

文件差异内容过多而无法显示
+ 3 - 0
examples/models/json/pressure.json


二进制
examples/textures/MaryOculus.webm


+ 1 - 0
examples/textures/MaryOculus.webm.nfo

@@ -0,0 +1 @@
+ffmpeg -i MaryOculus.mp4 -vf scale=2048:1024 -b:v 20M -threads 4 -an MaryOculus7.webm

+ 5 - 0
examples/textures/decal/LICENSE.TXT

@@ -0,0 +1,5 @@
+decal-diffuse.png
+decal-normal.jpg
+
+Licensed under a CC0 1.0 Universal (CC0 1.0) Public Domain Dedication License:
+http://creativecommons.org/publicdomain/zero/1.0/

二进制
examples/textures/decal/decal-diffuse.png


二进制
examples/textures/decal/decal-normal.jpg


+ 168 - 0
examples/vr_video.html

@@ -0,0 +1,168 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<title>three.js webgl - vr video</title>
+		<meta charset="utf-8">
+		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
+		<style>
+			body {
+				font-family: Monospace;
+				background-color: #f0f0f0;
+				margin: 0px;
+				overflow: hidden;
+			}
+			#info {
+				position: absolute;
+				top: 10px;
+				width: 100%;
+				color: #fff;
+				text-align: center;
+			}
+			a {
+				color: #ff0
+			}
+		</style>
+	</head>
+	<body>
+		<div id="container"></div>
+		<div id="info">
+			<a href="http://threejs.org" target="_blank">three.js</a> webgl - vr video<br />
+			stereoscopic panoramic render by <a href="http://pedrofe.com/rendering-for-oculus-rift-with-arnold/" target="_blank">pedrofe</a>. scene from <a href="http://www.meryproject.com/" target="_blank">mery project</a>.
+		</div>
+
+		<script src="../build/three.min.js"></script>
+		<script src="js/effects/VREffect.js"></script>
+		<script src="js/controls/VRControls.js"></script>
+
+		<script>
+
+			var camera, sceneLeft, sceneRight, renderer;
+			var video, texture;
+
+			var controls, effect;
+
+			init();
+			animate();
+
+			function init() {
+
+				var container = document.getElementById( 'container' );
+				container.addEventListener( 'click', function () {
+
+					video.play();
+					effect.setFullScreen( true );
+
+				} );
+
+				camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 2000 );
+
+				// video
+
+				video = document.createElement( 'video' );
+				video.loop = true;
+				video.src = 'textures/MaryOculus.webm';
+				video.play();
+
+				texture = new THREE.VideoTexture( video );
+				texture.minFilter = THREE.LinearFilter;
+				texture.format = THREE.RGBFormat;
+				texture.generateMipmaps = false;
+
+				// left
+
+				sceneLeft = new THREE.Scene();
+
+				var geometry = new THREE.SphereGeometry( 500, 60, 40 );
+				geometry.applyMatrix( new THREE.Matrix4().makeScale( -1, 1, 1 ) );
+
+				var uvs = geometry.faceVertexUvs[ 0 ];
+
+				for ( var i = 0; i < uvs.length; i ++ ) {
+
+					for ( var j = 0; j < 3; j ++ ) {
+
+						uvs[ i ][ j ].x *= 0.5;
+
+					}
+
+				}
+
+				var material = new THREE.MeshBasicMaterial( { map: texture } );
+
+				var mesh = new THREE.Mesh( geometry, material );
+				mesh.rotation.y = - Math.PI / 2;
+				sceneLeft.add( mesh );
+
+				// right
+
+				sceneRight = new THREE.Scene();
+
+				var geometry = new THREE.SphereGeometry( 500, 60, 40 );
+				geometry.applyMatrix( new THREE.Matrix4().makeScale( -1, 1, 1 ) );
+
+				var uvs = geometry.faceVertexUvs[ 0 ];
+
+				for ( var i = 0; i < uvs.length; i ++ ) {
+
+					for ( var j = 0; j < 3; j ++ ) {
+
+						uvs[ i ][ j ].x *= 0.5;
+						uvs[ i ][ j ].x += 0.5;
+
+					}
+
+				}
+
+				var material = new THREE.MeshBasicMaterial( { map: texture } );
+
+				var mesh = new THREE.Mesh( geometry, material );
+				mesh.rotation.y = - Math.PI / 2;
+				sceneRight.add( mesh );
+
+				//
+
+				renderer = new THREE.WebGLRenderer();
+				renderer.setClearColor( 0x101010 );
+				renderer.setSize( window.innerWidth, window.innerHeight );
+				container.appendChild( renderer.domElement );
+
+				//
+
+				controls = new THREE.VRControls( camera );
+
+				effect = new THREE.VREffect( renderer );
+				effect.setSize( window.innerWidth, window.innerHeight );
+
+				//
+
+				window.addEventListener( 'resize', onWindowResize, false );
+
+			}
+
+			function onWindowResize() {
+
+				camera.aspect = window.innerWidth / window.innerHeight;
+				camera.updateProjectionMatrix();
+
+				effect.setSize( window.innerWidth, window.innerHeight );
+
+			}
+
+			function animate() {
+
+				requestAnimationFrame( animate );
+				render();
+
+			}
+
+			function render() {
+
+				controls.update();
+
+				effect.render( [ sceneLeft, sceneRight ], camera );
+
+			}
+
+		</script>
+	</body>
+</html>

+ 1 - 1
examples/webgl_animation_skinning_morph.html

@@ -127,7 +127,7 @@
 
 				//
 
-				var light = new THREE.DirectionalLight( 0x497f13, 1 );
+				var light = new THREE.DirectionalLight( 0x493f13, 1 );
 				light.position.set( 0, -1, 0 );
 				scene.add( light );
 

+ 1 - 1
examples/webgl_decals.html

@@ -53,7 +53,7 @@
 			specular: 0x444444,
 			map: decalDiffuse,
 			normalMap: decalNormal,
-			normalScale: new THREE.Vector2( .15, .15 ),
+			normalScale: new THREE.Vector2( 1, 1 ),
 			shininess: 30,
 			transparent: true,
 			depthTest: true,

+ 2 - 2
examples/webgl_effects_parallaxbarrier.html

@@ -36,7 +36,7 @@
 	<body>
 		<div id="d">
 			<div id="info">
-				<a href="http://threejs.org" target="_blank">three.js</a> webgl - effects - parallax barrier. 
+				<a href="http://threejs.org" target="_blank">three.js</a> webgl - effects - parallax barrier.
 				texture by <a href="http://www.humus.name/index.php?page=Textures" target="_blank">Humus</a> :
 				<span id="car_info">
 					<span id="car_name">Bugatti Veyron model</span>
@@ -245,7 +245,7 @@
 				"Carmine": 	new THREE.MeshPhongMaterial( { color: 0x770000, specular:0xffaaaa, envMap: textureCube, combine: THREE.MultiplyOperation } ),
 				"Gold": 	new THREE.MeshPhongMaterial( { color: 0xaa9944, specular:0xbbaa99, shininess:50, envMap: textureCube, combine: THREE.MultiplyOperation } ),
 				"Bronze":	new THREE.MeshPhongMaterial( { color: 0x150505, specular:0xee6600, shininess:10, envMap: textureCube, combine: THREE.MixOperation, reflectivity: 0.25 } ),
-				"Chrome": 	new THREE.MeshPhongMaterial( { color: 0xffffff, specular:0xffffff, envMap: textureCube, combine: THREE.Multiply } ),
+				"Chrome": 	new THREE.MeshPhongMaterial( { color: 0xffffff, specular:0xffffff, envMap: textureCube, combine: THREE.MultiplyOperation } ),
 
 				"Orange metal": new THREE.MeshLambertMaterial( { color: 0xff6600, envMap: textureCube, combine: THREE.MultiplyOperation } ),
 				"Blue metal": 	new THREE.MeshLambertMaterial( { color: 0x001133, envMap: textureCube, combine: THREE.MultiplyOperation  } ),

+ 1 - 0
examples/webgl_interactive_cubes_gpu.html

@@ -75,6 +75,7 @@
 
 				pickingScene = new THREE.Scene();
 				pickingTexture = new THREE.WebGLRenderTarget( window.innerWidth, window.innerHeight );
+				pickingTexture.minFilter = THREE.LinearFilter;
 				pickingTexture.generateMipmaps = false;
 
 				scene.add( new THREE.AmbientLight( 0x555555 ) );

+ 10 - 32
examples/webgl_loader_scene.html

@@ -39,15 +39,6 @@
 				display:none;
 			}
 
-			#start {
-				color:#fff;
-				text-shadow: #000 0px 0px 2px;
-				padding:0.1em 0.3em;
-				width:3em;
-				text-align: center;
-				display:none;
-			}
-
 			.shadow {
 				-moz-box-shadow: 0px 0px 5px #000;
 				-webkit-box-shadow: 0px 0px 5px #000;
@@ -97,7 +88,6 @@
 
 			<center>
 				<div id="progressbar" class="shadow"><div id="bar" class="shadow"></div></div>
-				<div id="start" class="disabled">Start</div>
 			</center>
 		</div>
 
@@ -186,8 +176,6 @@
 				stats.domElement.style.zIndex = 100;
 				container.appendChild( stats.domElement );
 
-				$( "start" ).addEventListener( 'click', onStartClick, false );
-
 				var callbackProgress = function( progress, result ) {
 
 					var bar = 250,
@@ -207,8 +195,6 @@
 
 					$( "message" ).style.display = "none";
 					$( "progressbar" ).style.display = "none";
-					$( "start" ).style.display = "block";
-					$( "start" ).className = "enabled";
 
 					result.scene.traverse( function ( object ) {
 
@@ -237,6 +223,16 @@
 
 					} );
 
+					//
+
+					$( "progress" ).style.display = "none";
+
+					camera = loaded.currentCamera;
+					camera.aspect = window.innerWidth / window.innerHeight;
+					camera.updateProjectionMatrix();
+
+					scene = loaded.scene;
+
 				}
 
 				$( "progress" ).style.display = "block";
@@ -276,24 +272,6 @@
 
 			}
 
-			function setButtonActive( id ) {
-
-				$( "start" ).style.backgroundColor = "green";
-
-			}
-
-			function onStartClick() {
-
-				$( "progress" ).style.display = "none";
-
-				camera = loaded.currentCamera;
-				camera.aspect = window.innerWidth / window.innerHeight;
-				camera.updateProjectionMatrix();
-
-				scene = loaded.scene;
-
-			}
-
 			function onDocumentMouseMove( event ) {
 
 				mouseX = ( event.clientX - windowHalfX );

+ 3 - 4
examples/webgl_materials_lightmap.html

@@ -100,14 +100,13 @@
 
 				// LIGHTS
 
-				var directionalLight = new THREE.DirectionalLight( 0xffffff, 1.475 );
+				var directionalLight = new THREE.DirectionalLight( 0x333333, 2 );
 				directionalLight.position.set( 100, 100, -100 );
 				scene.add( directionalLight );
 
 
-				var hemiLight = new THREE.HemisphereLight( 0xffffff, 0xffffff, 1.25 );
-				hemiLight.color.setHSL( 0.6, 1, 0.75 );
-				hemiLight.groundColor.setHSL( 0.1, 0.8, 0.7 );
+				var hemiLight = new THREE.HemisphereLight( 0xaabbff, 0x040404, 1 );
+
 				hemiLight.position.y = 500;
 				scene.add( hemiLight );
 

+ 3 - 0
examples/webgl_materials_normaldisplacementmap.html

@@ -185,6 +185,9 @@
 				var parameters = { fragmentShader: shader.fragmentShader, vertexShader: shader.vertexShader, uniforms: uniforms, lights: true, fog: false };
 				var material1 = new THREE.ShaderMaterial( parameters );
 
+				// Ensure that ENVMAP_MODE_REFLECTION is defined in shader
+				material1.envMap = reflectionCube;
+
 				var material2 = new THREE.MeshPhongMaterial( {
 					color: diffuse,
 					specular: specular,

+ 1 - 1
examples/webgl_mirror.html

@@ -86,7 +86,7 @@
 
 				var planeGeo = new THREE.PlaneBufferGeometry( 100.1, 100.1 );
 				
-				// MIRORR planes
+				// MIRROR planes
 				groundMirror = new THREE.Mirror( renderer, camera, { clipBias: 0.003, textureWidth: WIDTH, textureHeight: HEIGHT, color: 0x777777 } );
 				
 				var mirrorMesh = new THREE.Mesh( planeGeo, groundMirror.material );

+ 13 - 24
examples/webgl_shaders_sky.html

@@ -20,8 +20,8 @@
 			}
 
 			#info {
-				color:#333;
-				text-shadow: 1px 1px #fff;
+				color:#ccc;
+				text-shadow: 1px 1px rgba(0,0,0,0.25);
 				position: absolute;
 				top: 0px; width: 100%;
 				padding: 5px;
@@ -29,7 +29,7 @@
 			}
 
 			a {
-				color: #333;
+				color: #fff;
 			}
 
 		</style>
@@ -90,7 +90,7 @@
 					mieDirectionalG: 0.8,
 					luminance: 1,
 					inclination: 0.49, // elevation / inclination
-					azimuth: 0.25, // Facing front,					
+					azimuth: 0.25, // Facing front,
 					sun: !true
 				}
 
@@ -108,8 +108,8 @@
 					var phi = 2 * Math.PI * (effectController.azimuth - 0.5);
 
 					sunSphere.position.x = distance * Math.cos(phi);
-					sunSphere.position.y = distance * Math.sin(phi) * Math.sin(theta); 
-					sunSphere.position.z = distance * Math.sin(phi) * Math.cos(theta); 
+					sunSphere.position.y = distance * Math.sin(phi) * Math.sin(theta);
+					sunSphere.position.z = distance * Math.sin(phi) * Math.cos(theta);
 
 					sunSphere.visible = effectController.sun;
 
@@ -129,14 +129,14 @@
 				gui.add( effectController, "inclination", 0, 1, 0.0001).onChange( guiChanged );
 				gui.add( effectController, "azimuth", 0, 1, 0.0001).onChange( guiChanged );
 				gui.add( effectController, "sun").onChange( guiChanged );
-				
+
 
 				guiChanged();
 
 
 				camera.lookAt(sunSphere.position)
 
-	
+
 			}
 
 
@@ -150,21 +150,10 @@
 
 				scene = new THREE.Scene();
 
-				var size = 500;
-
-				var geometryLines = new THREE.BoxGeometry( size, size, size );
-	
-				var geometryPlane = new THREE.PlaneGeometry( size * 10, size * 10, 1, 1);
-				geometryPlane.applyMatrix( new THREE.Matrix4().makeRotationX( - Math.PI / 2 ) );
-	
-
-				var materialLines = new THREE.MeshBasicMaterial( { wireframe: true } );
-
-				meshLines = new THREE.Mesh( geometryLines, materialLines );
-
-				// scene.add( meshLines );
-
-				scene.add( new THREE.Mesh( geometryPlane, materialLines ) );
+				var helper = new THREE.GridHelper( 5000, 5000 );
+				helper.color1.setHex( 0xffffff );
+				helper.color2.setHex( 0xffffff );
+				scene.add( helper );
 
 				initSky();
 
@@ -206,7 +195,7 @@
 				time = Date.now();
 
 				requestAnimationFrame( animate );
-				
+
 				controls.update();
 
 				render();

+ 30 - 16
examples/webgl_shaders_tonemapping.html

@@ -85,12 +85,15 @@
 			function init() {
 
 				params = {
-					"Average Luminosity": 0.7,
+					bloomAmount: 1.0,
+					sunLight: 4.0,
+
+					enabled: true,
+					avgLuminance: 0.7,
 					middleGrey: 0.04,
 					maxLuminance: 16,
-					bloomAmount: 1.0,
+
 					adaptionRate: 2.0,
-					sunLight: 4.0,
 				};
 
 				container = document.createElement( 'div' );
@@ -395,22 +398,24 @@
 				// ldrEffectComposer.addPass( gammaPass );
 
 
-				var dynamicHdrGui = new dat.GUI();
+				var gui = new dat.GUI();
 
 				// dynamicHdrGui.add( params, 'projection', { 'From cam to mesh': 'camera', 'Normal to mesh': 'normal' } );
-				dynamicHdrGui.add( params, 'middleGrey', 0, 12 );
-				dynamicHdrGui.add( params, 'maxLuminance', 1, 30 );
-				dynamicHdrGui.add( params, 'adaptionRate', 0.0, 10.0 );
-				dynamicHdrGui.add( params, 'bloomAmount', 0.0, 10.0 );
-				dynamicHdrGui.add( params, 'sunLight', 0.1, 12.0 );
-				// dynamicHdrGui.add( params, 'clear' );
-				dynamicHdrGui.open();
+				var sceneGui = gui.addFolder( 'Scenes' );
+				var toneMappingGui = gui.addFolder( 'ToneMapping' );
+				var adaptiveToneMappingGui = gui.addFolder( 'AdaptiveOnly' );
+
+				sceneGui.add( params, 'bloomAmount', 0.0, 10.0 );
+				sceneGui.add( params, 'sunLight', 0.1, 12.0 );
+
+				toneMappingGui.add( params, 'enabled' );
+				toneMappingGui.add( params, 'middleGrey', 0, 12 );
+				toneMappingGui.add( params, 'avgLuminance', 0.001, 2.0 );
+				toneMappingGui.add( params, 'maxLuminance', 1, 30 );
 
-				var ldrGui = new dat.GUI();
-				ldrGui.domElement.style.position = 'absolute';
-				ldrGui.add( params, 'Average Luminosity', 0.001, 2.0 );
-				ldrGui.open();
+				adaptiveToneMappingGui.add( params, 'adaptionRate', 0.0, 10.0 );
 
+				gui.open();
 
 				window.addEventListener( 'resize', onWindowResize, false );
 
@@ -445,10 +450,19 @@
 					adaptiveLuminanceMat.uniforms.map.value = adaptToneMappingPass.luminanceRT;
 					currentLuminanceMat.uniforms.map.value = adaptToneMappingPass.currentLuminanceRT;
 					if ( adaptToneMappingPass.setAverageLuminance ) {
-						adaptToneMappingPass.setAverageLuminance( params["Average Luminosity"] );
+						adaptToneMappingPass.setAverageLuminance( params.avgLuminance );
 					}
+					adaptToneMappingPass.enabled = params.enabled;
 					adaptToneMappingPass.setMaxLuminance( params.maxLuminance );
 					adaptToneMappingPass.setMiddleGrey( params.middleGrey );
+
+					hdrToneMappingPass.enabled = params.enabled;
+					hdrToneMappingPass.setMaxLuminance( params.maxLuminance );
+					hdrToneMappingPass.setMiddleGrey( params.middleGrey );
+				
+					ldrToneMappingPass.enabled = params.enabled;
+					ldrToneMappingPass.setMaxLuminance( params.maxLuminance );
+					ldrToneMappingPass.setMiddleGrey( params.middleGrey );
 				}
 
 				directionalLight.intensity = params.sunLight;

+ 1 - 1
examples/webgl_terrain_dynamic.html

@@ -606,7 +606,7 @@
 
 				var sceneTmp = new THREE.Scene();
 
-				var meshTmp = new THREE.Mesh( new THREE.PlaneGeometry( SCREEN_WIDTH, SCREEN_HEIGHT ), shaderMaterial );
+				var meshTmp = new THREE.Mesh( new THREE.PlaneBufferGeometry( SCREEN_WIDTH, SCREEN_HEIGHT ), shaderMaterial );
 				meshTmp.position.z = -500;
 
 				sceneTmp.add( meshTmp );

+ 2 - 2
src/Three.js

@@ -2,7 +2,7 @@
  * @author mrdoob / http://mrdoob.com/
  */
 
-var THREE = { REVISION: '71dev' };
+var THREE = { REVISION: '72dev' };
 
 // browserify support
 
@@ -16,7 +16,7 @@ if ( typeof module === 'object' ) {
 
 if ( Math.sign === undefined ) {
 
-	// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sign 
+	// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sign
 
 	Math.sign = function ( x ) {
 

+ 17 - 16
src/core/BufferGeometry.js

@@ -84,13 +84,13 @@ THREE.BufferGeometry.prototype = {
 
 		}
 
-		if ( this.boundingBox instanceof THREE.Box3 ) {
+		if ( this.boundingBox !== null ) {
 
 			this.computeBoundingBox();
 
 		}
 
-		if ( this.boundingSphere instanceof THREE.Sphere ) {
+		if ( this.boundingSphere !== null ) {
 
 			this.computeBoundingSphere();
 
@@ -100,7 +100,13 @@ THREE.BufferGeometry.prototype = {
 
 	center: function () {
 
-		// TODO
+		this.computeBoundingBox();
+
+		var offset = this.boundingBox.center().negate();
+
+		this.applyMatrix( new THREE.Matrix4().setPosition( offset ) );
+
+		return offset;
 
 	},
 
@@ -661,24 +667,18 @@ THREE.BufferGeometry.prototype = {
 	},
 
 	/*
-		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.
+	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.
+	size - Defaults to 65535, but allows for larger or smaller chunks.
 	*/
-	computeOffsets: function ( indexBufferSize ) {
-
-		var size = indexBufferSize;
-		if ( indexBufferSize === undefined )
-			size = 65535; //WebGL limits type of index buffer values to 16-bit.
+	computeOffsets: function ( size ) {
 
-		var s = Date.now();
+		if ( size === undefined ) size = 65535; // WebGL limits type of index buffer values to 16-bit.
 
 		var indices = this.attributes.index.array;
 		var vertices = this.attributes.position.array;
 
-		var verticesCount = ( vertices.length / 3 );
 		var facesCount = ( indices.length / 3 );
 
 		/*
@@ -758,7 +758,8 @@ THREE.BufferGeometry.prototype = {
 
 		/* 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;
+		this.offsets = offsets; // TODO: Deprecate
+		this.drawcalls = offsets;
 
 		/*
 		var orderTime = Date.now();

+ 38 - 16
src/core/Geometry.js

@@ -81,18 +81,21 @@ THREE.Geometry.prototype = {
 
 		}
 
-		if ( this.boundingBox instanceof THREE.Box3 ) {
+		if ( this.boundingBox !== null ) {
 
 			this.computeBoundingBox();
 
 		}
 
-		if ( this.boundingSphere instanceof THREE.Sphere ) {
+		if ( this.boundingSphere !== null ) {
 
 			this.computeBoundingSphere();
 
 		}
 
+		this.verticesNeedUpdate = true;
+		this.normalsNeedUpdate = true;
+
 	},
 
 	fromBufferGeometry: function ( geometry ) {
@@ -151,9 +154,33 @@ THREE.Geometry.prototype = {
 
 		if ( indices !== undefined ) {
 
-			for ( var i = 0; i < indices.length; i += 3 ) {
+			var drawcalls = geometry.drawcalls;
+
+			if ( drawcalls.length > 0 ) {
+
+				for ( var i = 0; i < drawcalls.length; i ++ ) {
+
+					var drawcall = drawcalls[ i ];
+
+					var start = drawcall.start;
+					var count = drawcall.count;
+					var index = drawcall.index;
 
-				addFace( indices[ i ], indices[ i + 1 ], indices[ i + 2 ] );
+					for ( var j = start, jl = start + count; j < jl; j += 3 ) {
+
+						addFace( index + indices[ j ], index + indices[ j + 1 ], index + indices[ j + 2 ] );
+
+					}
+
+				}
+
+			} else {
+
+				for ( var i = 0; i < indices.length; i += 3 ) {
+
+					addFace( indices[ i ], indices[ i + 1 ], indices[ i + 2 ] );
+
+				}
 
 			}
 
@@ -189,13 +216,9 @@ THREE.Geometry.prototype = {
 
 		this.computeBoundingBox();
 
-		var offset = new THREE.Vector3();
+		var offset = this.boundingBox.center().negate();
 
-		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();
+		this.applyMatrix( new THREE.Matrix4().setPosition( offset ) );
 
 		return offset;
 
@@ -242,9 +265,8 @@ THREE.Geometry.prototype = {
 			// 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();
+			var vA, vB, vC;
+			var cb = new THREE.Vector3(), ab = new THREE.Vector3();
 
 			for ( f = 0, fl = this.faces.length; f < fl; f ++ ) {
 
@@ -418,7 +440,7 @@ THREE.Geometry.prototype = {
 		// based on http://www.terathon.com/code/tangent.html
 		// tangents go to vertices
 
-		var f, fl, v, vl, i, il, vertexIndex,
+		var f, fl, v, vl, i, vertexIndex,
 			face, uv, vA, vB, vC, uvA, uvB, uvC,
 			x1, x2, y1, y2, z1, z2,
 			s1, s2, t1, t2, r, t, test,
@@ -700,8 +722,8 @@ THREE.Geometry.prototype = {
 		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;
+		var i, il, face;
+		var indices, j, jl;
 
 		for ( i = 0, il = this.vertices.length; i < il; i ++ ) {
 

+ 1 - 3
src/core/Object3D.js

@@ -19,8 +19,6 @@ THREE.Object3D = function () {
 
 	this.up = THREE.Object3D.DefaultUp.clone();
 
-	var scope = this;
-
 	var position = new THREE.Vector3();
 	var rotation = new THREE.Euler();
 	var quaternion = new THREE.Quaternion();
@@ -53,7 +51,7 @@ THREE.Object3D = function () {
 		scale: {
 			enumerable: true,
 			value: scale
-		},
+		}
 	} );
 
 	this.rotationAutoUpdate = true;

+ 6 - 8
src/extras/FontUtils.js

@@ -56,7 +56,7 @@ THREE.FontUtils = {
 		ThreeFont.faces[ family ][ data.cssFontWeight ] = ThreeFont.faces[ family ][ data.cssFontWeight ] || {};
 		ThreeFont.faces[ family ][ data.cssFontWeight ][ data.cssFontStyle ] = data;
 
-		var face = ThreeFont.faces[ family ][ data.cssFontWeight ][ data.cssFontStyle ] = data;
+		ThreeFont.faces[ family ][ data.cssFontWeight ][ data.cssFontStyle ] = data;
 
 		return data;
 
@@ -64,11 +64,9 @@ THREE.FontUtils = {
 
 	drawText: function ( text ) {
 
-		var characterPts = [], allPts = [];
-
 		// RenderText
 
-		var i, p,
+		var i,
 			face = this.getFace(),
 			scale = this.size / face.resolution,
 			offset = 0,
@@ -180,8 +178,8 @@ THREE.FontUtils = {
 						for ( i2 = 1, divisions = this.divisions; i2 <= divisions; i2 ++ ) {
 
 							var t = i2 / divisions;
-							var tx = THREE.Shape.Utils.b2( t, cpx0, cpx1, cpx );
-							var ty = THREE.Shape.Utils.b2( t, cpy0, cpy1, cpy );
+							THREE.Shape.Utils.b2( t, cpx0, cpx1, cpx );
+							THREE.Shape.Utils.b2( t, cpy0, cpy1, cpy );
 						}
 
 					}
@@ -211,8 +209,8 @@ THREE.FontUtils = {
 						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 );
+							THREE.Shape.Utils.b3( t, cpx0, cpx1, cpx2, cpx );
+							THREE.Shape.Utils.b3( t, cpy0, cpy1, cpy2, cpy );
 
 						}
 

+ 223 - 220
src/extras/animation/Animation.js

@@ -21,383 +21,386 @@ THREE.Animation = function ( root, data ) {
 
 };
 
+THREE.Animation.prototype = {
 
-THREE.Animation.prototype.keyTypes = [ "pos", "rot", "scl" ];
+	constructor: THREE.Animation,
 
+	keyTypes:  [ "pos", "rot", "scl" ],
 
-THREE.Animation.prototype.play = function ( startTime, weight ) {
+	play: function ( startTime, weight ) {
 
-	this.currentTime = startTime !== undefined ? startTime : 0;
-	this.weight = weight !== undefined ? weight : 1;
+		this.currentTime = startTime !== undefined ? startTime : 0;
+		this.weight = weight !== undefined ? weight : 1;
 
-	this.isPlaying = true;
+		this.isPlaying = true;
 
-	this.reset();
+		this.reset();
 
-	THREE.AnimationHandler.play( this );
+		THREE.AnimationHandler.play( this );
 
-};
+	},
 
+	stop: function() {
 
-THREE.Animation.prototype.stop = function() {
+		this.isPlaying = false;
 
-	this.isPlaying = false;
+		THREE.AnimationHandler.stop( this );
 
-	THREE.AnimationHandler.stop( this );
+	},
 
-};
+	reset: function () {
 
-THREE.Animation.prototype.reset = function () {
+		for ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) {
 
-	for ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) {
+			var object = this.hierarchy[ h ];
 
-		var object = this.hierarchy[ h ];
+			if ( object.animationCache === undefined ) {
 
-		if ( object.animationCache === undefined ) {
+				object.animationCache = {
+					animations: {},
+					blending: {
+						positionWeight: 0.0,
+						quaternionWeight: 0.0,
+						scaleWeight: 0.0
+					}
+				};
+			}
 
-			object.animationCache = {
-				animations: {},
-				blending: {
-					positionWeight: 0.0,
-					quaternionWeight: 0.0,
-					scaleWeight: 0.0
-				}
-			};
-		}
+			var name = this.data.name;
+			var animations = object.animationCache.animations;
+			var animationCache = animations[ name ];
 
-		if ( object.animationCache.animations[this.data.name] === undefined ) {
+			if ( animationCache === undefined ) {
 
-			object.animationCache.animations[this.data.name] = {};
-			object.animationCache.animations[this.data.name].prevKey = { pos: 0, rot: 0, scl: 0 };
-			object.animationCache.animations[this.data.name].nextKey = { pos: 0, rot: 0, scl: 0 };
-			object.animationCache.animations[this.data.name].originalMatrix = object.matrix;
+				animationCache = {
+					prevKey: { pos: 0, rot: 0, scl: 0 },
+					nextKey: { pos: 0, rot: 0, scl: 0 },
+					originalMatrix: object.matrix
+				};
 
-		}
+				animations[ name ] = animationCache;
 
-		var animationCache = object.animationCache.animations[this.data.name];
+			}
 
-		// Get keys to match our current time
+			// Get keys to match our current time
 
-		for ( var t = 0; t < 3; t ++ ) {
+			for ( var t = 0; t < 3; t ++ ) {
 
-			var type = this.keyTypes[ t ];
+				var type = this.keyTypes[ t ];
 
-			var prevKey = this.data.hierarchy[ h ].keys[ 0 ];
-			var nextKey = this.getNextKeyWith( type, h, 1 );
+				var prevKey = this.data.hierarchy[ h ].keys[ 0 ];
+				var nextKey = this.getNextKeyWith( type, h, 1 );
 
-			while ( nextKey.time < this.currentTime && nextKey.index > prevKey.index ) {
+				while ( nextKey.time < this.currentTime && nextKey.index > prevKey.index ) {
 
-				prevKey = nextKey;
-				nextKey = this.getNextKeyWith( type, h, nextKey.index + 1 );
+					prevKey = nextKey;
+					nextKey = this.getNextKeyWith( type, h, nextKey.index + 1 );
 
-			}
+				}
+
+				animationCache.prevKey[ type ] = prevKey;
+				animationCache.nextKey[ type ] = nextKey;
 
-			animationCache.prevKey[ type ] = prevKey;
-			animationCache.nextKey[ type ] = nextKey;
+			}
 
 		}
 
-	}
+	},
 
-};
+	resetBlendWeights: function () {
+
+		for ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) {
 
-THREE.Animation.prototype.resetBlendWeights = function () {
+			var object = this.hierarchy[ h ];
+			var animationCache = object.animationCache;
 
-	for ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) {
+			if ( animationCache !== undefined ) {
 
-		var object = this.hierarchy[ h ];
+				var blending = animationCache.blending;
 
-		if ( object.animationCache !== undefined ) {
+				blending.positionWeight = 0.0;
+				blending.quaternionWeight = 0.0;
+				blending.scaleWeight = 0.0;
 
-			object.animationCache.blending.positionWeight = 0.0;
-			object.animationCache.blending.quaternionWeight = 0.0;
-			object.animationCache.blending.scaleWeight = 0.0;
+			}
 
 		}
 
-	}
+	},
 
-};
+	update: ( function() {
 
-THREE.Animation.prototype.update = (function() {
+		var points = [];
+		var target = new THREE.Vector3();
+		var newVector = new THREE.Vector3();
+		var newQuat = new THREE.Quaternion();
 
-	var points = [];
-	var target = new THREE.Vector3();
-	var newVector = new THREE.Vector3();
-	var newQuat = new THREE.Quaternion();
+		// Catmull-Rom spline
 
-	// Catmull-Rom spline
+		var interpolateCatmullRom = function ( points, scale ) {
 
-	var interpolateCatmullRom = function ( points, scale ) {
+			var c = [], v3 = [],
+			point, intPoint, weight, w2, w3,
+			pa, pb, pc, pd;
 
-		var c = [], v3 = [],
-		point, intPoint, weight, w2, w3,
-		pa, pb, pc, pd;
+			point = ( points.length - 1 ) * scale;
+			intPoint = Math.floor( point );
+			weight = point - intPoint;
 
-		point = ( points.length - 1 ) * scale;
-		intPoint = Math.floor( point );
-		weight = point - intPoint;
+			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;
 
-		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;
+			pa = points[ c[ 0 ] ];
+			pb = points[ c[ 1 ] ];
+			pc = points[ c[ 2 ] ];
+			pd = points[ c[ 3 ] ];
 
-		pa = points[ c[ 0 ] ];
-		pb = points[ c[ 1 ] ];
-		pc = points[ c[ 2 ] ];
-		pd = points[ c[ 3 ] ];
+			w2 = weight * weight;
+			w3 = weight * w2;
 
-		w2 = weight * weight;
-		w3 = weight * w2;
+			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 );
 
-		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 );
+			return v3;
 
-		return v3;
+		};
 
-	};
+		var interpolate = function ( p0, p1, p2, p3, t, t2, t3 ) {
 
-	var interpolate = function ( p0, p1, p2, p3, t, t2, t3 ) {
+			var v0 = ( p2 - p0 ) * 0.5,
+				v1 = ( p3 - p1 ) * 0.5;
 
-		var v0 = ( p2 - p0 ) * 0.5,
-			v1 = ( p3 - p1 ) * 0.5;
+			return ( 2 * ( p1 - p2 ) + v0 + v1 ) * t3 + ( - 3 * ( p1 - p2 ) - 2 * v0 - v1 ) * t2 + v0 * t + p1;
 
-		return ( 2 * ( p1 - p2 ) + v0 + v1 ) * t3 + ( - 3 * ( p1 - p2 ) - 2 * v0 - v1 ) * t2 + v0 * t + p1;
+		};
 
-	};
+		return function ( delta ) {
 
-	return function ( delta ) {
+			if ( this.isPlaying === false ) return;
 
-		if ( this.isPlaying === false ) return;
+			this.currentTime += delta * this.timeScale;
 
-		this.currentTime += delta * this.timeScale;
+			if ( this.weight === 0 )
+				return;
 
-		if ( this.weight === 0 )
-			return;
+			//
 
-		//
+			var duration = this.data.length;
 
-		var duration = this.data.length;
+			if ( this.currentTime > duration || this.currentTime < 0 ) {
 
-		if ( this.currentTime > duration || this.currentTime < 0 ) {
+				if ( this.loop ) {
 
-			if ( this.loop ) {
+					this.currentTime %= duration;
 
-				this.currentTime %= duration;
+					if ( this.currentTime < 0 )
+						this.currentTime += duration;
 
-				if ( this.currentTime < 0 )
-					this.currentTime += duration;
+					this.reset();
 
-				this.reset();
+				} else {
 
-			} else {
+					this.stop();
 
-				this.stop();
+				}
 
 			}
 
-		}
+			for ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) {
 
-		for ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) {
+				var object = this.hierarchy[ h ];
+				var animationCache = object.animationCache.animations[this.data.name];
+				var blending = object.animationCache.blending;
 
-			var object = this.hierarchy[ h ];
-			var animationCache = object.animationCache.animations[this.data.name];
-			var blending = object.animationCache.blending;
+				// loop through pos/rot/scl
 
-			// loop through pos/rot/scl
+				for ( var t = 0; t < 3; t ++ ) {
 
-			for ( var t = 0; t < 3; t ++ ) {
+					// get keys
 
-				// get keys
+					var type    = this.keyTypes[ t ];
+					var prevKey = animationCache.prevKey[ type ];
+					var nextKey = animationCache.nextKey[ type ];
 
-				var type    = this.keyTypes[ t ];
-				var prevKey = animationCache.prevKey[ type ];
-				var nextKey = animationCache.nextKey[ type ];
+					if ( ( this.timeScale > 0 && nextKey.time <= this.currentTime ) ||
+						( this.timeScale < 0 && prevKey.time >= this.currentTime ) ) {
 
-				if ( ( this.timeScale > 0 && nextKey.time <= this.currentTime ) ||
-					( this.timeScale < 0 && prevKey.time >= this.currentTime ) ) {
+						prevKey = this.data.hierarchy[ h ].keys[ 0 ];
+						nextKey = this.getNextKeyWith( type, h, 1 );
 
-					prevKey = this.data.hierarchy[ h ].keys[ 0 ];
-					nextKey = this.getNextKeyWith( type, h, 1 );
+						while ( nextKey.time < this.currentTime && nextKey.index > prevKey.index ) {
 
-					while ( nextKey.time < this.currentTime && nextKey.index > prevKey.index ) {
+							prevKey = nextKey;
+							nextKey = this.getNextKeyWith( type, h, nextKey.index + 1 );
 
-						prevKey = nextKey;
-						nextKey = this.getNextKeyWith( type, h, nextKey.index + 1 );
+						}
+
+						animationCache.prevKey[ type ] = prevKey;
+						animationCache.nextKey[ type ] = nextKey;
 
 					}
 
-					animationCache.prevKey[ type ] = prevKey;
-					animationCache.nextKey[ type ] = nextKey;
+					var scale = ( this.currentTime - prevKey.time ) / ( nextKey.time - prevKey.time );
 
-				}
+					var prevXYZ = prevKey[ type ];
+					var nextXYZ = nextKey[ type ];
 
-				var scale = ( this.currentTime - prevKey.time ) / ( nextKey.time - prevKey.time );
+					if ( scale < 0 ) scale = 0;
+					if ( scale > 1 ) scale = 1;
 
-				var prevXYZ = prevKey[ type ];
-				var nextXYZ = nextKey[ type ];
+					// interpolate
 
-				if ( scale < 0 ) scale = 0;
-				if ( scale > 1 ) scale = 1;
+					if ( type === "pos" ) {
 
-				// interpolate
+						if ( this.interpolationType === THREE.AnimationHandler.LINEAR ) {
 
-				if ( type === "pos" ) {
+							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;
 
-					if ( this.interpolationType === THREE.AnimationHandler.LINEAR ) {
+							// blend
+							var proportionalWeight = this.weight / ( this.weight + blending.positionWeight );
+							object.position.lerp( newVector, proportionalWeight );
+							blending.positionWeight += this.weight;
 
-						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;
+						} else if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM ||
+									this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) {
 
-						// blend
-						var proportionalWeight = this.weight / ( this.weight + blending.positionWeight );
-						object.position.lerp( newVector, proportionalWeight );
-						blending.positionWeight += this.weight;
+							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" ];
 
-					} else if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM ||
-								this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) {
+							scale = scale * 0.33 + 0.33;
 
-						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 currentPoint = interpolateCatmullRom( points, scale );
+							var proportionalWeight = this.weight / ( this.weight + blending.positionWeight );
+							blending.positionWeight += this.weight;
 
-						scale = scale * 0.33 + 0.33;
+							// blend
 
-						var currentPoint = interpolateCatmullRom( points, scale );
-						var proportionalWeight = this.weight / ( this.weight + blending.positionWeight );
-						blending.positionWeight += this.weight;
+							var vector = object.position;
 
-						// blend
+							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;
 
-						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;
+							if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) {
 
-						if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) {
+								var forwardPoint = interpolateCatmullRom( points, scale * 1.01 );
 
-							var forwardPoint = interpolateCatmullRom( points, scale * 1.01 );
+								target.set( forwardPoint[ 0 ], forwardPoint[ 1 ], forwardPoint[ 2 ] );
+								target.sub( vector );
+								target.y = 0;
+								target.normalize();
 
-							target.set( forwardPoint[ 0 ], forwardPoint[ 1 ], forwardPoint[ 2 ] );
-							target.sub( vector );
-							target.y = 0;
-							target.normalize();
+								var angle = Math.atan2( target.x, target.z );
+								object.rotation.set( 0, angle, 0 );
 
-							var angle = Math.atan2( target.x, target.z );
-							object.rotation.set( 0, angle, 0 );
+							}
 
 						}
 
-					}
+					} else if ( type === "rot" ) {
 
-				} else if ( type === "rot" ) {
+						THREE.Quaternion.slerp( prevXYZ, nextXYZ, newQuat, scale );
 
-					THREE.Quaternion.slerp( prevXYZ, nextXYZ, newQuat, scale );
+						// Avoid paying the cost of an additional slerp if we don't have to
+						if ( blending.quaternionWeight === 0 ) {
 
-					// Avoid paying the cost of an additional slerp if we don't have to
-					if ( blending.quaternionWeight === 0 ) {
+							object.quaternion.copy(newQuat);
+							blending.quaternionWeight = this.weight;
 
-						object.quaternion.copy(newQuat);
-						blending.quaternionWeight = this.weight;
+						} else {
 
-					} else {
+							var proportionalWeight = this.weight / ( this.weight + blending.quaternionWeight );
+							THREE.Quaternion.slerp( object.quaternion, newQuat, object.quaternion, proportionalWeight );
+							blending.quaternionWeight += this.weight;
 
-						var proportionalWeight = this.weight / ( this.weight + blending.quaternionWeight );
-						THREE.Quaternion.slerp( object.quaternion, newQuat, object.quaternion, proportionalWeight );
-						blending.quaternionWeight += this.weight;
+						}
 
-					}
+					} else if ( type === "scl" ) {
 
-				} else if ( type === "scl" ) {
+						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;
 
-					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;
+						var proportionalWeight = this.weight / ( this.weight + blending.scaleWeight );
+						object.scale.lerp( newVector, proportionalWeight );
+						blending.scaleWeight += this.weight;
 
-					var proportionalWeight = this.weight / ( this.weight + blending.scaleWeight );
-					object.scale.lerp( newVector, proportionalWeight );
-					blending.scaleWeight += this.weight;
+					}
 
 				}
 
 			}
 
-		}
-
-		return true;
-
-	};
+			return true;
 
-})();
+		};
 
+	} )(),
 
+	getNextKeyWith: function ( type, h, key ) {
 
+		var keys = this.data.hierarchy[ h ].keys;
 
+		if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM ||
+			 this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) {
 
-// Get next key with
+			key = key < keys.length - 1 ? key : keys.length - 1;
 
-THREE.Animation.prototype.getNextKeyWith = function ( type, h, key ) {
+		} else {
 
-	var keys = this.data.hierarchy[ h ].keys;
+			key = key % keys.length;
 
-	if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM ||
-		 this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) {
-
-		key = key < keys.length - 1 ? key : keys.length - 1;
-
-	} else {
+		}
 
-		key = key % keys.length;
+		for ( ; key < keys.length; key ++ ) {
 
-	}
+			if ( keys[ key ][ type ] !== undefined ) {
 
-	for ( ; key < keys.length; key ++ ) {
+				return keys[ key ];
 
-		if ( keys[ key ][ type ] !== undefined ) {
-
-			return keys[ key ];
+			}
 
 		}
 
-	}
-
-	return this.data.hierarchy[ h ].keys[ 0 ];
+		return this.data.hierarchy[ h ].keys[ 0 ];
 
-};
+	},
 
-// Get previous key with
+	getPrevKeyWith: function ( type, h, key ) {
 
-THREE.Animation.prototype.getPrevKeyWith = function ( type, h, key ) {
+		var keys = this.data.hierarchy[ h ].keys;
 
-	var keys = this.data.hierarchy[ h ].keys;
+		if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM ||
+			this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) {
 
-	if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM ||
-		this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) {
+			key = key > 0 ? key : 0;
 
-		key = key > 0 ? key : 0;
+		} else {
 
-	} else {
+			key = key >= 0 ? key : key + keys.length;
 
-		key = key >= 0 ? key : key + keys.length;
+		}
 
-	}
 
+		for ( ; key >= 0; key -- ) {
 
-	for ( ; key >= 0; key -- ) {
+			if ( keys[ key ][ type ] !== undefined ) {
 
-		if ( keys[ key ][ type ] !== undefined ) {
+				return keys[ key ];
 
-			return keys[ key ];
+			}
 
 		}
 
-	}
+		return this.data.hierarchy[ h ].keys[ keys.length - 1 ];
 
-	return this.data.hierarchy[ h ].keys[ keys.length - 1 ];
+	}
 
 };

+ 98 - 101
src/extras/animation/KeyFrameAnimation.js

@@ -50,195 +50,192 @@ THREE.KeyFrameAnimation = function ( data ) {
 
 };
 
+THREE.KeyFrameAnimation.prototype = {
 
-THREE.KeyFrameAnimation.prototype.play = function ( startTime ) {
+	constructor: THREE.KeyFrameAnimation,
 
-	this.currentTime = startTime !== undefined ? startTime : 0;
+	play: function ( startTime ) {
 
-	if ( this.isPlaying === false ) {
+		this.currentTime = startTime !== undefined ? startTime : 0;
 
-		this.isPlaying = true;
+		if ( this.isPlaying === false ) {
 
-		// reset key cache
+			this.isPlaying = true;
 
-		var h, hl = this.hierarchy.length,
-			object,
-			node;
+			// reset key cache
 
-		for ( h = 0; h < hl; h ++ ) {
+			var h, hl = this.hierarchy.length,
+				object,
+				node;
 
-			object = this.hierarchy[ h ];
-			node = this.data.hierarchy[ h ];
+			for ( h = 0; h < hl; h ++ ) {
 
-			if ( node.animationCache === undefined ) {
+				object = this.hierarchy[ h ];
+				node = this.data.hierarchy[ h ];
 
-				node.animationCache = {};
-				node.animationCache.prevKey = null;
-				node.animationCache.nextKey = null;
-				node.animationCache.originalMatrix = object.matrix;
+				if ( node.animationCache === undefined ) {
 
-			}
+					node.animationCache = {};
+					node.animationCache.prevKey = null;
+					node.animationCache.nextKey = null;
+					node.animationCache.originalMatrix = object.matrix;
+
+				}
+
+				var keys = this.data.hierarchy[h].keys;
 
-			var keys = this.data.hierarchy[h].keys;
+				if (keys.length) {
 
-			if (keys.length) {
+					node.animationCache.prevKey = keys[ 0 ];
+					node.animationCache.nextKey = keys[ 1 ];
 
-				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 );
 
-				this.startTime = Math.min( keys[0].time, this.startTime );
-				this.endTime = Math.max( keys[keys.length - 1].time, this.endTime );
+				}
 
 			}
 
+			this.update( 0 );
+
 		}
 
-		this.update( 0 );
+		this.isPaused = false;
 
-	}
+		THREE.AnimationHandler.play( this );
 
-	this.isPaused = false;
+	},
 
-	THREE.AnimationHandler.play( this );
+	stop: function () {
 
-};
+		this.isPlaying = false;
+		this.isPaused  = false;
 
+		THREE.AnimationHandler.stop( this );
 
-THREE.KeyFrameAnimation.prototype.stop = function() {
+		// reset JIT matrix and remove cache
 
-	this.isPlaying = false;
-	this.isPaused  = false;
-
-	THREE.AnimationHandler.stop( this );
+		for ( var h = 0; h < this.data.hierarchy.length; h ++ ) {
 
-	// reset JIT matrix and remove cache
+			var obj = this.hierarchy[ h ];
+			var node = this.data.hierarchy[ h ];
 
-	for ( var h = 0; h < this.data.hierarchy.length; h ++ ) {
-		
-		var obj = this.hierarchy[ h ];
-		var node = this.data.hierarchy[ h ];
+			if ( node.animationCache !== undefined ) {
 
-		if ( node.animationCache !== undefined ) {
+				var original = node.animationCache.originalMatrix;
 
-			var original = node.animationCache.originalMatrix;
+				original.copy( obj.matrix );
+				obj.matrix = original;
 
-			original.copy( obj.matrix );
-			obj.matrix = original;
+				delete node.animationCache;
 
-			delete node.animationCache;
+			}
 
 		}
 
-	}
-
-};
+	},
 
+	update: function ( delta ) {
 
-// Update
+		if ( this.isPlaying === false ) return;
 
-THREE.KeyFrameAnimation.prototype.update = function ( delta ) {
+		this.currentTime += delta * this.timeScale;
 
-	if ( this.isPlaying === false ) return;
+		//
 
-	this.currentTime += delta * this.timeScale;
+		var duration = this.data.length;
 
-	//
+		if ( this.loop === true && this.currentTime > duration ) {
 
-	var duration = this.data.length;
+			this.currentTime %= duration;
 
-	if ( this.loop === true && this.currentTime > duration ) {
+		}
 
-		this.currentTime %= duration;
+		this.currentTime = Math.min( this.currentTime, duration );
 
-	}
+		for ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) {
 
-	this.currentTime = Math.min( this.currentTime, duration );
+			var object = this.hierarchy[ h ];
+			var node = this.data.hierarchy[ h ];
 
-	for ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) {
+			var keys = node.keys,
+				animationCache = node.animationCache;
 
-		var object = this.hierarchy[ h ];
-		var node = this.data.hierarchy[ h ];
 
-		var keys = node.keys,
-			animationCache = node.animationCache;
+			if ( keys.length ) {
 
+				var prevKey = animationCache.prevKey;
+				var nextKey = animationCache.nextKey;
 
-		if ( keys.length ) {
+				if ( nextKey.time <= this.currentTime ) {
 
-			var prevKey = animationCache.prevKey;
-			var nextKey = animationCache.nextKey;
+					while ( nextKey.time < this.currentTime && nextKey.index > prevKey.index ) {
 
-			if ( nextKey.time <= this.currentTime ) {
+						prevKey = nextKey;
+						nextKey = keys[ prevKey.index + 1 ];
 
-				while ( nextKey.time < this.currentTime && nextKey.index > prevKey.index ) {
+					}
 
-					prevKey = nextKey;
-					nextKey = keys[ prevKey.index + 1 ];
+					animationCache.prevKey = prevKey;
+					animationCache.nextKey = nextKey;
 
 				}
 
-				animationCache.prevKey = prevKey;
-				animationCache.nextKey = nextKey;
+				if ( nextKey.time >= this.currentTime ) {
 
-			}
+					prevKey.interpolate( nextKey, this.currentTime );
 
-			if ( nextKey.time >= this.currentTime ) {
+				} else {
 
-				prevKey.interpolate( nextKey, this.currentTime );
+					prevKey.interpolate( nextKey, nextKey.time );
 
-			} else {
+				}
 
-				prevKey.interpolate( nextKey, nextKey.time );
+				this.data.hierarchy[ h ].node.updateMatrix();
+				object.matrixWorldNeedsUpdate = true;
 
 			}
 
-			this.data.hierarchy[ h ].node.updateMatrix();
-			object.matrixWorldNeedsUpdate = true;
-
 		}
 
-	}
-
-};
+	},
 
-// Get next key with
+	getNextKeyWith: function ( sid, h, key ) {
 
-THREE.KeyFrameAnimation.prototype.getNextKeyWith = function( sid, h, key ) {
+		var keys = this.data.hierarchy[ h ].keys;
+		key = key % keys.length;
 
-	var keys = this.data.hierarchy[ h ].keys;
-	key = key % keys.length;
+		for ( ; key < keys.length; key ++ ) {
 
-	for ( ; key < keys.length; key ++ ) {
+			if ( keys[ key ].hasTarget( sid ) ) {
 
-		if ( keys[ key ].hasTarget( sid ) ) {
+				return keys[ key ];
 
-			return keys[ key ];
+			}
 
 		}
 
-	}
-
-	return keys[ 0 ];
+		return keys[ 0 ];
 
-};
+	},
 
-// Get previous key with
+	getPrevKeyWith: function ( sid, h, key ) {
 
-THREE.KeyFrameAnimation.prototype.getPrevKeyWith = function( sid, h, key ) {
+		var keys = this.data.hierarchy[ h ].keys;
+		key = key >= 0 ? key : key + keys.length;
 
-	var keys = this.data.hierarchy[ h ].keys;
-	key = key >= 0 ? key : key + keys.length;
+		for ( ; key >= 0; key -- ) {
 
-	for ( ; key >= 0; key -- ) {
+			if ( keys[ key ].hasTarget( sid ) ) {
 
-		if ( keys[ key ].hasTarget( sid ) ) {
+				return keys[ key ];
 
-			return keys[ key ];
+			}
 
 		}
 
-	}
+		return keys[ keys.length - 1 ];
 
-	return keys[ keys.length - 1 ];
+	}
 
 };

+ 7 - 5
src/extras/animation/MorphAnimation.js

@@ -50,19 +50,21 @@ THREE.MorphAnimation.prototype = {
 		var interpolation = this.duration / this.frames;
 		var frame = Math.floor( this.currentTime / interpolation );
 
+		var influences = this.mesh.morphTargetInfluences;
+
 		if ( frame != this.currentFrame ) {
 
-			this.mesh.morphTargetInfluences[ this.lastFrame ] = 0;
-			this.mesh.morphTargetInfluences[ this.currentFrame ] = 1;
-			this.mesh.morphTargetInfluences[ frame ] = 0;
+			influences[ this.lastFrame ] = 0;
+			influences[ this.currentFrame ] = 1;
+			influences[ frame ] = 0;
 
 			this.lastFrame = this.currentFrame;
 			this.currentFrame = frame;
 
 		}
 
-		this.mesh.morphTargetInfluences[ frame ] = ( this.currentTime % interpolation ) / interpolation;
-		this.mesh.morphTargetInfluences[ this.lastFrame ] = 1 - this.mesh.morphTargetInfluences[ frame ];
+		influences[ frame ] = ( this.currentTime % interpolation ) / interpolation;
+		influences[ this.lastFrame ] = 1 - influences[ frame ];
 
 	}
 

+ 57 - 2
src/extras/audio/Audio.js

@@ -10,6 +10,7 @@ THREE.Audio = function ( listener ) {
 
 	this.context = listener.context;
 	this.source = this.context.createBufferSource();
+	this.source.onended = this.onEnded.bind(this);
 
 	this.gain = this.context.createGain();
 	this.gain.connect( this.context.destination );
@@ -17,6 +18,11 @@ THREE.Audio = function ( listener ) {
 	this.panner = this.context.createPanner();
 	this.panner.connect( this.gain );
 
+	this.autoplay = false;
+
+	this.startTime = 0;
+	this.isPlaying = false;
+
 };
 
 THREE.Audio.prototype = Object.create( THREE.Object3D.prototype );
@@ -34,8 +40,8 @@ THREE.Audio.prototype.load = function ( file ) {
 		scope.context.decodeAudioData( this.response, function ( buffer ) {
 
 			scope.source.buffer = buffer;
-			scope.source.connect( scope.panner );
-			scope.source.start( 0 );
+
+			if( scope.autoplay ) scope.play();
 
 		} );
 
@@ -46,6 +52,49 @@ THREE.Audio.prototype.load = function ( file ) {
 
 };
 
+THREE.Audio.prototype.play = function () {
+
+	if ( this.isPlaying === true ) {
+
+		THREE.warn( 'THREE.Audio: Audio is already playing.' );
+		return;
+
+	}
+
+	var source = this.context.createBufferSource();
+
+	source.buffer = this.source.buffer;
+	source.loop = this.source.loop;
+	source.onended = this.source.onended;
+	source.connect( this.panner );
+	source.start( 0, this.startTime );
+
+	this.isPlaying = true;
+
+	this.source = source;
+
+};
+
+THREE.Audio.prototype.pause = function () {
+
+	this.source.stop();
+	this.startTime = this.context.currentTime;
+
+};
+
+THREE.Audio.prototype.stop = function () {
+
+	this.source.stop();
+	this.startTime = 0;
+
+};
+
+THREE.Audio.prototype.onEnded = function() {
+
+	this.isPlaying = false;
+
+};
+
 THREE.Audio.prototype.setLoop = function ( value ) {
 
 	this.source.loop = value;
@@ -64,6 +113,12 @@ THREE.Audio.prototype.setRolloffFactor = function ( value ) {
 
 };
 
+THREE.Audio.prototype.setVolume = function ( value ) {
+
+	this.gain.gain.value = value;
+
+};
+
 THREE.Audio.prototype.updateMatrixWorld = ( function () {
 
 	var position = new THREE.Vector3();

+ 0 - 7
src/extras/audio/AudioListener.js

@@ -22,9 +22,6 @@ THREE.AudioListener.prototype.updateMatrixWorld = ( function () {
 	var scale = new THREE.Vector3();
 
 	var orientation = new THREE.Vector3();
-	var velocity = new THREE.Vector3();
-
-	var positionPrev = new THREE.Vector3();
 
 	return function ( force ) {
 
@@ -36,13 +33,9 @@ THREE.AudioListener.prototype.updateMatrixWorld = ( function () {
 		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, up.x, up.y, up.z );
-		listener.setVelocity( velocity.x, velocity.y, velocity.z );
-
-		positionPrev.copy( position );
 
 	};
 

+ 0 - 1
src/extras/core/Path.js

@@ -633,7 +633,6 @@ THREE.Path.prototype.toShapes = function( isCCW, noHoles ) {
 			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];

+ 1 - 9
src/extras/geometries/ExtrudeGeometry.js

@@ -123,7 +123,6 @@ THREE.ExtrudeGeometry.prototype.addShape = function ( shape, options ) {
 
 	var ahole, h, hl; // looping of holes
 	var scope = this;
-	var bevelPoints = [];
 
 	var shapesOffset = this.vertices.length;
 
@@ -182,14 +181,11 @@ THREE.ExtrudeGeometry.prototype.addShape = function ( shape, options ) {
 
 	var b, bs, t, z,
 		vert, vlen = vertices.length,
-		face, flen = faces.length,
-		cont, clen = contour.length;
+		face, flen = faces.length;
 
 
 	// Find directions for point movement
 
-	var RAD_TO_DEGREES = 180 / Math.PI;
-
 
 	function getBevelVec( inPt, inPrev, inNext ) {
 
@@ -292,10 +288,6 @@ THREE.ExtrudeGeometry.prototype.addShape = function ( shape, options ) {
 		//  (j)---(i)---(k)
 		// console.log('i,j,k', i, j , k)
 
-		var pt_i = contour[ i ];
-		var pt_j = contour[ j ];
-		var pt_k = contour[ k ];
-
 		contourMovements[ i ] = getBevelVec( contour[ i ], contour[ j ], contour[ k ] );
 
 	}

+ 0 - 1
src/extras/geometries/ParametricGeometry.js

@@ -26,7 +26,6 @@ THREE.ParametricGeometry = function ( func, slices, stacks ) {
 	var i, j, p;
 	var u, v;
 
-	var stackCount = stacks + 1;
 	var sliceCount = slices + 1;
 
 	for ( i = 0; i <= stacks; i ++ ) {

+ 1 - 2
src/extras/geometries/PolyhedronGeometry.js

@@ -28,7 +28,7 @@ THREE.PolyhedronGeometry = function ( vertices, indices, radius, detail ) {
 
 	}
 
-	var midpoints = [], p = this.vertices;
+	var p = this.vertices;
 
 	var faces = [];
 
@@ -136,7 +136,6 @@ THREE.PolyhedronGeometry = function ( vertices, indices, radius, detail ) {
 	function subdivide( face, detail ) {
 
 		var cols = Math.pow(2, detail);
-		var cells = Math.pow(4, detail);
 		var a = prepare( that.vertices[ face.a ] );
 		var b = prepare( that.vertices[ face.b ] );
 		var c = prepare( that.vertices[ face.c ] );

+ 1 - 2
src/extras/geometries/ShapeGeometry.js

@@ -59,7 +59,7 @@ THREE.ShapeGeometry.prototype.addShape = function ( shape, options ) {
 
 	//
 
-	var i, l, hole, s;
+	var i, l, hole;
 
 	var shapesOffset = this.vertices.length;
 	var shapePoints = shape.extractPoints( curveSegments );
@@ -108,7 +108,6 @@ THREE.ShapeGeometry.prototype.addShape = function ( shape, options ) {
 
 	var vert, vlen = vertices.length;
 	var face, flen = faces.length;
-	var cont, clen = contour.length;
 
 	for ( i = 0; i < vlen; i ++ ) {
 

+ 2 - 6
src/extras/geometries/TubeGeometry.js

@@ -42,8 +42,6 @@ THREE.TubeGeometry = function ( path, segments, radius, radialSegments, closed,
 
 		numpoints = segments + 1,
 
-		x, y, z,
-		tx, ty, tz,
 		u, v, r,
 
 		cx, cy,
@@ -154,9 +152,7 @@ THREE.TubeGeometry.SinusoidalTaper = function ( u ) {
 // For computing of Frenet frames, exposing the tangents, normals and binormals the spline
 THREE.TubeGeometry.FrenetFrames = function ( path, segments, closed ) {
 
-	var	tangent = new THREE.Vector3(),
-		normal = new THREE.Vector3(),
-		binormal = new THREE.Vector3(),
+	var	normal = new THREE.Vector3(),
 
 		tangents = [],
 		normals = [],
@@ -171,7 +167,7 @@ THREE.TubeGeometry.FrenetFrames = function ( path, segments, closed ) {
 		smallest,
 
 		tx, ty, tz,
-		i, u, v;
+		i, u;
 
 
 	// expose internals

+ 11 - 2
src/extras/helpers/EdgesHelper.js

@@ -1,10 +1,19 @@
 /**
  * @author WestLangley / http://github.com/WestLangley
+ * @param object THREE.Mesh whose geometry will be used
+ * @param hex line color
+ * @param thresholdAngle the minimim angle (in degrees),
+ * between the face normals of adjacent faces,
+ * that is required to render an edge. A value of 10 means
+ * an edge is only rendered if the angle is at least 10 degrees.
  */
 
-THREE.EdgesHelper = function ( object, hex ) {
+THREE.EdgesHelper = function ( object, hex, thresholdAngle ) {
 
 	var color = ( hex !== undefined ) ? hex : 0xffffff;
+	thresholdAngle = ( thresholdAngle !== undefined ) ? thresholdAngle : 1;
+
+	var thresholdDot = Math.cos( THREE.Math.degToRad( thresholdAngle ) );
 
 	var edge = [ 0, 0 ], hash = {};
 	var sortFunction = function ( a, b ) { return a - b };
@@ -67,7 +76,7 @@ THREE.EdgesHelper = function ( object, hex ) {
 
 		var h = hash[ key ];
 
-		if ( h.face2 === undefined || faces[ h.face1 ].normal.dot( faces[ h.face2 ].normal ) < 0.9999 ) { // hardwired const OK
+		if ( h.face2 === undefined || faces[ h.face1 ].normal.dot( faces[ h.face2 ].normal ) <= thresholdDot ) {
 
 			var vertex = vertices[ h.vert1 ];
 			coords[ index ++ ] = vertex.x;

+ 0 - 2
src/extras/helpers/VertexNormalsHelper.js

@@ -15,8 +15,6 @@ THREE.VertexNormalsHelper = function ( object, size, hex, linewidth ) {
 
 	var geometry = new THREE.Geometry();
 
-	var vertices = object.geometry.vertices;
-
 	var faces = object.geometry.faces;
 
 	for ( var i = 0, l = faces.length; i < l; i ++ ) {

+ 0 - 2
src/extras/helpers/VertexTangentsHelper.js

@@ -15,8 +15,6 @@ THREE.VertexTangentsHelper = function ( object, size, hex, linewidth ) {
 
 	var geometry = new THREE.Geometry();
 
-	var vertices = object.geometry.vertices;
-
 	var faces = object.geometry.faces;
 
 	for ( var i = 0, l = faces.length; i < l; i ++ ) {

+ 0 - 1
src/extras/objects/MorphBlendMesh.js

@@ -76,7 +76,6 @@ THREE.MorphBlendMesh.prototype.autoCreateAnimations = function ( fps ) {
 		if ( chunks && chunks.length > 1 ) {
 
 			var name = chunks[ 1 ];
-			var num = chunks[ 2 ];
 
 			if ( ! frameRanges[ name ] ) frameRanges[ name ] = { start: Infinity, end: - Infinity };
 

+ 3 - 3
src/loaders/BufferGeometryLoader.js

@@ -36,7 +36,7 @@ THREE.BufferGeometryLoader.prototype = {
 
 		var geometry = new THREE.BufferGeometry();
 
-		var attributes = json.attributes;
+		var attributes = json.data.attributes;
 
 		for ( var key in attributes ) {
 
@@ -47,7 +47,7 @@ THREE.BufferGeometryLoader.prototype = {
 
 		}
 
-		var offsets = json.offsets;
+		var offsets = json.data.offsets;
 
 		if ( offsets !== undefined ) {
 
@@ -55,7 +55,7 @@ THREE.BufferGeometryLoader.prototype = {
 
 		}
 
-		var boundingSphere = json.boundingSphere;
+		var boundingSphere = json.data.boundingSphere;
 
 		if ( boundingSphere !== undefined ) {
 

+ 16 - 14
src/loaders/JSONLoader.js

@@ -16,8 +16,6 @@ THREE.JSONLoader.prototype.constructor = THREE.JSONLoader;
 
 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 );
@@ -42,18 +40,23 @@ THREE.JSONLoader.prototype.loadAjaxJSON = function ( context, url, callback, tex
 				if ( xhr.responseText ) {
 
 					var json = JSON.parse( xhr.responseText );
+					var metadata = json.metadata;
 
-					if ( json.metadata !== undefined && json.metadata.version >= 4 ) {
+					if ( metadata !== undefined ) {
 
-						console.error( 'THREE.JSONLoader: "' + url + '" should be loaded with THREE.ObjectLoader instead.' );
-						return;
+						if ( metadata.type === 'object' ) {
 
-					}
+							THREE.error( 'THREE.JSONLoader: ' + url + ' should be loaded with THREE.ObjectLoader instead.' );
+							return;
+
+						}
+
+						if ( metadata.type === 'scene' ) {
 
-					if ( json.metadata !== undefined && json.metadata.type === 'scene' ) {
+							THREE.error( 'THREE.JSONLoader: ' + url + ' seems to be a Scene. Use THREE.SceneLoader instead.' );
+							return;
 
-						THREE.error( 'THREE.JSONLoader: "' + url + '" seems to be a Scene. Use THREE.SceneLoader instead.' );
-						return;
+						}
 
 					}
 
@@ -62,7 +65,7 @@ THREE.JSONLoader.prototype.loadAjaxJSON = function ( context, url, callback, tex
 
 				} else {
 
-					THREE.error( 'THREE.JSONLoader: "' + url + '" seems to be unreachable or the file is empty.' );
+					THREE.error( 'THREE.JSONLoader: ' + url + ' seems to be unreachable or the file is empty.' );
 
 				}
 
@@ -74,7 +77,7 @@ THREE.JSONLoader.prototype.loadAjaxJSON = function ( context, url, callback, tex
 
 			} else {
 
-				THREE.error( 'THREE.JSONLoader: Couldn\'t load "' + url + '" (' + xhr.status + ')' );
+				THREE.error( 'THREE.JSONLoader: Couldn\'t load ' + url + ' (' + xhr.status + ')' );
 
 			}
 
@@ -112,8 +115,7 @@ THREE.JSONLoader.prototype.loadAjaxJSON = function ( context, url, callback, tex
 
 THREE.JSONLoader.prototype.parse = function ( json, texturePath ) {
 
-	var scope = this,
-	geometry = new THREE.Geometry(),
+	var geometry = new THREE.Geometry(),
 	scale = ( json.scale !== undefined ) ? 1.0 / json.scale : 1.0;
 
 	parseModel( scale );
@@ -145,7 +147,7 @@ THREE.JSONLoader.prototype.parse = function ( json, texturePath ) {
 		hasFaceNormal, hasFaceVertexNormal,
 		hasFaceColor, hasFaceVertexColor,
 
-		vertex, face, faceA, faceB, color, hex, normal,
+		vertex, face, faceA, faceB, hex, normal,
 
 		uvLayer, uv, u, v,
 

+ 3 - 2
src/loaders/ObjectLoader.js

@@ -85,8 +85,9 @@ THREE.ObjectLoader.prototype = {
 				switch ( data.type ) {
 
 					case 'PlaneGeometry':
+					case 'PlaneBufferGeometry':
 
-						geometry = new THREE.PlaneGeometry(
+						geometry = new THREE[ data.type ](
 							data.width,
 							data.height,
 							data.widthSegments,
@@ -182,7 +183,7 @@ THREE.ObjectLoader.prototype = {
 
 					case 'BufferGeometry':
 
-						geometry = bufferGeometryLoader.parse( data.data );
+						geometry = bufferGeometryLoader.parse( data );
 
 						break;
 

+ 1 - 1
src/math/Matrix3.js

@@ -91,7 +91,7 @@ THREE.Matrix3.prototype = {
 			if ( offset === undefined ) offset = 0;
 			if ( length === undefined ) length = array.length;
 
-			for ( var i = 0, j = offset, il; i < length; i += 3, j += 3 ) {
+			for ( var i = 0, j = offset; i < length; i += 3, j += 3 ) {
 
 				v1.x = array[ j ];
 				v1.y = array[ j + 1 ];

+ 1 - 1
src/math/Matrix4.js

@@ -470,7 +470,7 @@ THREE.Matrix4.prototype = {
 			if ( offset === undefined ) offset = 0;
 			if ( length === undefined ) length = array.length;
 
-			for ( var i = 0, j = offset, il; i < length; i += 3, j += 3 ) {
+			for ( var i = 0, j = offset; i < length; i += 3, j += 3 ) {
 
 				v1.x = array[ j ];
 				v1.y = array[ j + 1 ];

+ 1 - 1
src/math/Spline.js

@@ -125,7 +125,7 @@ THREE.Spline = function ( points ) {
 
 		var i, j,
 			index, indexCurrent, indexNext,
-			linearDistance, realDistance,
+			realDistance,
 			sampling, position,
 			newpoints = [],
 			tmpVec = new THREE.Vector3(),

+ 15 - 6
src/math/Vector2.js

@@ -90,19 +90,19 @@ THREE.Vector2.prototype = {
 
 	},
 
-	addVectors: function ( a, b ) {
+	addScalar: function ( s ) {
 
-		this.x = a.x + b.x;
-		this.y = a.y + b.y;
+		this.x += s;
+		this.y += s;
 
 		return this;
 
 	},
 
-	addScalar: function ( s ) {
+	addVectors: function ( a, b ) {
 
-		this.x += s;
-		this.y += s;
+		this.x = a.x + b.x;
+		this.y = a.y + b.y;
 
 		return this;
 
@@ -124,6 +124,15 @@ THREE.Vector2.prototype = {
 
 	},
 
+	subScalar: function ( s ) {
+
+		this.x -= s;
+		this.y -= s;
+
+		return this;
+
+	},
+
 	subVectors: function ( a, b ) {
 
 		this.x = a.x - b.x;

+ 10 - 0
src/math/Vector3.js

@@ -142,6 +142,16 @@ THREE.Vector3.prototype = {
 		return this;
 
 	},
+	
+	subScalar: function ( s ) {
+
+		this.x -= s;
+		this.y -= s;
+		this.z -= s;
+
+		return this;
+
+	},
 
 	subVectors: function ( a, b ) {
 

+ 11 - 0
src/math/Vector4.js

@@ -159,6 +159,17 @@ THREE.Vector4.prototype = {
 
 	},
 
+	subScalar: function ( s ) {
+
+		this.x -= s;
+		this.y -= s;
+		this.z -= s;
+		this.w -= s;
+
+		return this;
+
+	},
+
 	subVectors: function ( a, b ) {
 
 		this.x = a.x - b.x;

+ 1 - 1
src/objects/Mesh.js

@@ -220,7 +220,7 @@ THREE.Mesh.prototype.raycast = ( function () {
 			var isFaceMaterial = this.material instanceof THREE.MeshFaceMaterial;
 			var objectMaterials = isFaceMaterial === true ? this.material.materials : null;
 
-			var a, b, c, d;
+			var a, b, c;
 			var precision = raycaster.precision;
 
 			var vertices = geometry.vertices;

+ 0 - 1
src/objects/MorphAnimMesh.js

@@ -70,7 +70,6 @@ THREE.MorphAnimMesh.prototype.parseAnimations = function () {
 		if ( parts && parts.length > 1 ) {
 
 			var label = parts[ 1 ];
-			var num = parts[ 2 ];
 
 			if ( ! animations[ label ] ) animations[ label ] = { start: Infinity, end: - Infinity };
 

+ 29 - 45
src/renderers/WebGLRenderer.js

@@ -132,7 +132,6 @@ THREE.WebGLRenderer = function ( parameters ) {
 	 // camera matrices cache
 
 	_projScreenMatrix = new THREE.Matrix4(),
-	_projScreenMatrixPS = new THREE.Matrix4(),
 
 	_vector3 = new THREE.Vector3(),
 
@@ -300,11 +299,9 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 	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 () {
 
@@ -1020,8 +1017,6 @@ THREE.WebGLRenderer = function ( parameters ) {
 		geometry.__vertexArray = new Float32Array( nvertices * 3 );
 		geometry.__colorArray = new Float32Array( nvertices * 3 );
 
-		geometry.__sortArray = [];
-
 		geometry.__webglParticleCount = nvertices;
 
 		initCustomAttributes( object );
@@ -1191,7 +1186,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 	function setParticleBuffers ( geometry, hint, object ) {
 
-		var v, c, vertex, offset, index, color,
+		var v, c, vertex, offset, color,
 
 		vertices = geometry.vertices,
 		vl = vertices.length,
@@ -1202,15 +1197,12 @@ THREE.WebGLRenderer = function ( parameters ) {
 		vertexArray = geometry.__vertexArray,
 		colorArray = geometry.__colorArray,
 
-		sortArray = geometry.__sortArray,
-
 		dirtyVertices = geometry.verticesNeedUpdate,
-		dirtyElements = geometry.elementsNeedUpdate,
 		dirtyColors = geometry.colorsNeedUpdate,
 
 		customAttributes = geometry.__webglCustomAttributesList,
 		i, il,
-		a, ca, cal, value,
+		ca, cal, value,
 		customAttribute;
 
 		if ( dirtyVertices ) {
@@ -1369,7 +1361,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 		customAttributes = geometry.__webglCustomAttributesList,
 
 		i, il,
-		a, ca, cal, value,
+		ca, cal, value,
 		customAttribute;
 
 		if ( dirtyVertices ) {
@@ -1529,20 +1521,17 @@ THREE.WebGLRenderer = function ( parameters ) {
 		var needsFaceNormals = materialNeedsFaceNormals( material );
 
 		var f, fl, fi, face,
-		vertexNormals, faceNormal, normal,
+		vertexNormals, faceNormal,
 		vertexColors, faceColor,
 		vertexTangents,
-		uv, uv2, v1, v2, v3, v4, t1, t2, t3, t4, n1, n2, n3, n4,
+		uv, uv2, v1, v2, v3, t1, t2, t3, n1, n2, n3,
 		c1, c2, c3,
-		sw1, sw2, sw3, sw4,
-		si1, si2, si3, si4,
-		sa1, sa2, sa3, sa4,
-		sb1, sb2, sb3, sb4,
-		m, ml, i, il,
+		sw1, sw2, sw3,
+		si1, si2, si3,
+		i, il,
 		vn, uvi, uv2i,
 		vk, vkl, vka,
 		nka, chf, faceVertexNormals,
-		a,
 
 		vertexIndex = 0,
 
@@ -1557,7 +1546,6 @@ THREE.WebGLRenderer = function ( parameters ) {
 		offset_skin = 0,
 		offset_morphTarget = 0,
 		offset_custom = 0,
-		offset_customSrc = 0,
 
 		value,
 
@@ -1597,8 +1585,6 @@ THREE.WebGLRenderer = function ( parameters ) {
 		obj_uvs  = geometry.faceVertexUvs[ 0 ],
 		obj_uvs2 = geometry.faceVertexUvs[ 1 ],
 
-		obj_colors = geometry.colors,
-
 		obj_skinIndices = geometry.skinIndices,
 		obj_skinWeights = geometry.skinWeights,
 
@@ -2021,7 +2007,6 @@ THREE.WebGLRenderer = function ( parameters ) {
 				if ( ! customAttribute.__original.needsUpdate ) continue;
 
 				offset_custom = 0;
-				offset_customSrc = 0;
 
 				if ( customAttribute.size === 1 ) {
 
@@ -2590,7 +2575,7 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 				_this.info.render.calls ++;
 				_this.info.render.vertices += position.array.length / position.itemSize;
-				_this.info.render.faces += position.array.length / ( 3 * position.itemsize );
+				_this.info.render.faces += position.array.length / ( 3 * position.itemSize );
 
 			}
 
@@ -4767,29 +4752,29 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 	// If uniforms are marked as clean, they don't need to be loaded to the GPU.
 
-	function markUniformsLightsNeedsUpdate ( uniforms, boolean ) {
+	function markUniformsLightsNeedsUpdate ( uniforms, value ) {
 
-		uniforms.ambientLightColor.needsUpdate = boolean;
+		uniforms.ambientLightColor.needsUpdate = value;
 
-		uniforms.directionalLightColor.needsUpdate = boolean;
-		uniforms.directionalLightDirection.needsUpdate = boolean;
+		uniforms.directionalLightColor.needsUpdate = value;
+		uniforms.directionalLightDirection.needsUpdate = value;
 
-		uniforms.pointLightColor.needsUpdate = boolean;
-		uniforms.pointLightPosition.needsUpdate = boolean;
-		uniforms.pointLightDistance.needsUpdate = boolean;
-		uniforms.pointLightDecay.needsUpdate = boolean;
+		uniforms.pointLightColor.needsUpdate = value;
+		uniforms.pointLightPosition.needsUpdate = value;
+		uniforms.pointLightDistance.needsUpdate = value;
+		uniforms.pointLightDecay.needsUpdate = value;
 
-		uniforms.spotLightColor.needsUpdate = boolean;
-		uniforms.spotLightPosition.needsUpdate = boolean;
-		uniforms.spotLightDistance.needsUpdate = boolean;
-		uniforms.spotLightDirection.needsUpdate = boolean;
-		uniforms.spotLightAngleCos.needsUpdate = boolean;
-		uniforms.spotLightExponent.needsUpdate = boolean;
-		uniforms.spotLightDecay.needsUpdate = boolean;
+		uniforms.spotLightColor.needsUpdate = value;
+		uniforms.spotLightPosition.needsUpdate = value;
+		uniforms.spotLightDistance.needsUpdate = value;
+		uniforms.spotLightDirection.needsUpdate = value;
+		uniforms.spotLightAngleCos.needsUpdate = value;
+		uniforms.spotLightExponent.needsUpdate = value;
+		uniforms.spotLightDecay.needsUpdate = value;
 
-		uniforms.hemisphereLightSkyColor.needsUpdate = boolean;
-		uniforms.hemisphereLightGroundColor.needsUpdate = boolean;
-		uniforms.hemisphereLightDirection.needsUpdate = boolean;
+		uniforms.hemisphereLightSkyColor.needsUpdate = value;
+		uniforms.hemisphereLightGroundColor.needsUpdate = value;
+		uniforms.hemisphereLightDirection.needsUpdate = value;
 
 	}
 
@@ -5208,11 +5193,10 @@ THREE.WebGLRenderer = function ( parameters ) {
 
 	function setupLights ( lights ) {
 
-		var l, ll, light, n,
+		var l, ll, light,
 		r = 0, g = 0, b = 0,
 		color, skyColor, groundColor,
-		intensity,  intensitySq,
-		position,
+		intensity,
 		distance,
 
 		zlights = _lights,

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

@@ -1,5 +1,5 @@
 #ifdef USE_ALPHAMAP
 
-	gl_FragColor.a *= texture2D( alphaMap, vUv ).g;
+	diffuseColor.a *= texture2D( alphaMap, vUv ).g;
 
 #endif

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

@@ -1,5 +1,5 @@
 #ifdef ALPHATEST
 
-	if ( gl_FragColor.a < ALPHATEST ) discard;
+	if ( diffuseColor.a < ALPHATEST ) discard;
 
 #endif

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

@@ -1,5 +1,5 @@
 #ifdef USE_COLOR
 
-	gl_FragColor = gl_FragColor * vec4( vColor, 1.0 );
+	diffuseColor.rgb *= vColor;
 
 #endif

+ 4 - 4
src/renderers/shaders/ShaderChunk/envmap_fragment.glsl

@@ -37,7 +37,7 @@
 		sampleUV.y = saturate( flipNormal * reflectVec.y * 0.5 + 0.5 );
 		sampleUV.x = atan( flipNormal * reflectVec.z, flipNormal * reflectVec.x ) * RECIPROCAL_PI2 + 0.5;
 		vec4 envColor = texture2D( envMap, sampleUV );
-		
+
 	#elif defined( ENVMAP_TYPE_SPHERE )
 		vec3 reflectView = flipNormal * normalize((viewMatrix * vec4( reflectVec, 0.0 )).xyz + vec3(0.0,0.0,1.0));
 		vec4 envColor = texture2D( envMap, reflectView.xy * 0.5 + 0.5 );
@@ -47,15 +47,15 @@
 
 	#ifdef ENVMAP_BLENDING_MULTIPLY
 
-		gl_FragColor.xyz = mix( gl_FragColor.xyz, gl_FragColor.xyz * envColor.xyz, specularStrength * reflectivity );
+		outgoingLight = mix( outgoingLight, outgoingLight * envColor.xyz, specularStrength * reflectivity );
 
 	#elif defined( ENVMAP_BLENDING_MIX )
 
-		gl_FragColor.xyz = mix( gl_FragColor.xyz, envColor.xyz, specularStrength * reflectivity );
+		outgoingLight = mix( outgoingLight, envColor.xyz, specularStrength * reflectivity );
 
 	#elif defined( ENVMAP_BLENDING_ADD )
 
-		gl_FragColor.xyz += envColor.xyz * specularStrength * reflectivity;
+		outgoingLight += envColor.xyz * specularStrength * reflectivity;
 
 	#endif
 

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

@@ -21,6 +21,6 @@
 
 	#endif
 	
-	gl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );
+	outgoingLight = mix( outgoingLight, fogColor, fogFactor );
 
 #endif

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

@@ -1,5 +1,5 @@
 #ifdef USE_LIGHTMAP
 
-	gl_FragColor = gl_FragColor * texture2D( lightMap, vUv2 );
+	outgoingLight *= diffuseColor.xyz * texture2D( lightMap, vUv2 ).xyz;
 
 #endif

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

@@ -1,6 +1,3 @@
-uniform vec3 diffuse;
-uniform vec3 emissive;
-
 uniform vec3 ambientLightColor;
 
 #if MAX_DIR_LIGHTS > 0

+ 2 - 2
src/renderers/shaders/ShaderChunk/lights_lambert_vertex.glsl

@@ -187,10 +187,10 @@ for( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {
 
 #endif
 
-vLightFront = vLightFront * diffuse + diffuse * ambientLightColor + emissive;
+vLightFront += ambientLightColor;
 
 #ifdef DOUBLE_SIDED
 
-	vLightBack = vLightBack * diffuse + diffuse * ambientLightColor + emissive;
+	vLightBack += ambientLightColor;
 
 #endif

+ 17 - 57
src/renderers/shaders/ShaderChunk/lights_phong_fragment.glsl

@@ -28,10 +28,10 @@ vec3 viewPosition = normalize( vViewPosition );
 
 #endif
 
-#if MAX_POINT_LIGHTS > 0
+vec3 totalDiffuseLight = vec3( 0.0 );
+vec3 totalSpecularLight = vec3( 0.0 );
 
-	vec3 pointDiffuse = vec3( 0.0 );
-	vec3 pointSpecular = vec3( 0.0 );
+#if MAX_POINT_LIGHTS > 0
 
 	for ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {
 
@@ -42,7 +42,7 @@ vec3 viewPosition = normalize( vViewPosition );
 
 		lVector = normalize( lVector );
 
-				// diffuse
+		// diffuse
 
 		float dotProduct = dot( normal, lVector );
 
@@ -59,7 +59,7 @@ vec3 viewPosition = normalize( vViewPosition );
 
 		#endif
 
-		pointDiffuse += diffuse * pointLightColor[ i ] * pointDiffuseWeight * attenuation;
+		totalDiffuseLight += pointLightColor[ i ] * pointDiffuseWeight * attenuation;
 
 				// specular
 
@@ -70,7 +70,7 @@ vec3 viewPosition = normalize( vViewPosition );
 		float specularNormalization = ( shininess + 2.0 ) / 8.0;
 
 		vec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, pointHalfVector ), 0.0 ), 5.0 );
-		pointSpecular += schlick * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * attenuation * specularNormalization;
+		totalSpecularLight += schlick * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * attenuation * specularNormalization;
 
 	}
 
@@ -78,9 +78,6 @@ vec3 viewPosition = normalize( vViewPosition );
 
 #if MAX_SPOT_LIGHTS > 0
 
-	vec3 spotDiffuse = vec3( 0.0 );
-	vec3 spotSpecular = vec3( 0.0 );
-
 	for ( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {
 
 		vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );
@@ -96,7 +93,7 @@ vec3 viewPosition = normalize( vViewPosition );
 
 			spotEffect = max( pow( max( spotEffect, 0.0 ), spotLightExponent[ i ] ), 0.0 );
 
-					// diffuse
+			// diffuse
 
 			float dotProduct = dot( normal, lVector );
 
@@ -113,9 +110,9 @@ vec3 viewPosition = normalize( vViewPosition );
 
 			#endif
 
-			spotDiffuse += diffuse * spotLightColor[ i ] * spotDiffuseWeight * attenuation * spotEffect;
+			totalDiffuseLight += spotLightColor[ i ] * spotDiffuseWeight * attenuation * spotEffect;
 
-					// specular
+			// specular
 
 			vec3 spotHalfVector = normalize( lVector + viewPosition );
 			float spotDotNormalHalf = max( dot( normal, spotHalfVector ), 0.0 );
@@ -124,7 +121,7 @@ vec3 viewPosition = normalize( vViewPosition );
 			float specularNormalization = ( shininess + 2.0 ) / 8.0;
 
 			vec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, spotHalfVector ), 0.0 ), 5.0 );
-			spotSpecular += schlick * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * attenuation * specularNormalization * spotEffect;
+			totalSpecularLight += schlick * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * attenuation * specularNormalization * spotEffect;
 
 		}
 
@@ -134,14 +131,11 @@ vec3 viewPosition = normalize( vViewPosition );
 
 #if MAX_DIR_LIGHTS > 0
 
-	vec3 dirDiffuse = vec3( 0.0 );
-	vec3 dirSpecular = vec3( 0.0 );
-
 	for( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {
 
 		vec3 dirVector = transformDirection( directionalLightDirection[ i ], viewMatrix );
 
-				// diffuse
+		// diffuse
 
 		float dotProduct = dot( normal, dirVector );
 
@@ -158,7 +152,7 @@ vec3 viewPosition = normalize( vViewPosition );
 
 		#endif
 
-		dirDiffuse += diffuse * directionalLightColor[ i ] * dirDiffuseWeight;
+		totalDiffuseLight += directionalLightColor[ i ] * dirDiffuseWeight;
 
 		// specular
 
@@ -190,7 +184,7 @@ vec3 viewPosition = normalize( vViewPosition );
 		// 		dirSpecular += specular * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization * fresnel;
 
 		vec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( dirVector, dirHalfVector ), 0.0 ), 5.0 );
-		dirSpecular += schlick * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization;
+		totalSpecularLight += schlick * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization;
 
 
 	}
@@ -199,9 +193,6 @@ vec3 viewPosition = normalize( vViewPosition );
 
 #if MAX_HEMI_LIGHTS > 0
 
-	vec3 hemiDiffuse = vec3( 0.0 );
-	vec3 hemiSpecular = vec3( 0.0 );
-
 	for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {
 
 		vec3 lVector = transformDirection( hemisphereLightDirection[ i ], viewMatrix );
@@ -213,7 +204,7 @@ vec3 viewPosition = normalize( vViewPosition );
 
 		vec3 hemiColor = mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );
 
-		hemiDiffuse += diffuse * hemiColor;
+		totalDiffuseLight += hemiColor;
 
 		// specular (sky light)
 
@@ -235,49 +226,18 @@ vec3 viewPosition = normalize( vViewPosition );
 
 		vec3 schlickSky = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, hemiHalfVectorSky ), 0.0 ), 5.0 );
 		vec3 schlickGround = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVectorGround, hemiHalfVectorGround ), 0.0 ), 5.0 );
-		hemiSpecular += hemiColor * specularNormalization * ( schlickSky * hemiSpecularWeightSky * max( dotProduct, 0.0 ) + schlickGround * hemiSpecularWeightGround * max( dotProductGround, 0.0 ) );
+		totalSpecularLight += hemiColor * specularNormalization * ( schlickSky * hemiSpecularWeightSky * max( dotProduct, 0.0 ) + schlickGround * hemiSpecularWeightGround * max( dotProductGround, 0.0 ) );
 
 	}
 
 #endif
 
-vec3 totalDiffuse = vec3( 0.0 );
-vec3 totalSpecular = vec3( 0.0 );
-
-#if MAX_DIR_LIGHTS > 0
-
-	totalDiffuse += dirDiffuse;
-	totalSpecular += dirSpecular;
-
-#endif
-
-#if MAX_HEMI_LIGHTS > 0
-
-	totalDiffuse += hemiDiffuse;
-	totalSpecular += hemiSpecular;
-
-#endif
-
-#if MAX_POINT_LIGHTS > 0
-
-	totalDiffuse += pointDiffuse;
-	totalSpecular += pointSpecular;
-
-#endif
-
-#if MAX_SPOT_LIGHTS > 0
-
-	totalDiffuse += spotDiffuse;
-	totalSpecular += spotSpecular;
-
-#endif
-
 #ifdef METAL
 
-	gl_FragColor.xyz = gl_FragColor.xyz * ( emissive + totalDiffuse + ambientLightColor * diffuse + totalSpecular );
+	outgoingLight += diffuseColor.rgb * ( totalDiffuseLight + ambientLightColor ) * specular + totalSpecularLight + emissive;
 
 #else
 
-	gl_FragColor.xyz = gl_FragColor.xyz * ( emissive + totalDiffuse + ambientLightColor * diffuse ) + totalSpecular;
+	outgoingLight += diffuseColor.rgb * ( totalDiffuseLight + ambientLightColor ) + totalSpecularLight + emissive;
 
 #endif

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

@@ -1,2 +1,2 @@
 
-	gl_FragColor.xyz = linearToOutput( gl_FragColor.xyz );
+	outgoingLight = linearToOutput( outgoingLight );

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

@@ -4,6 +4,6 @@
 
 	texelColor.xyz = inputToLinear( texelColor.xyz );
 
-	gl_FragColor = gl_FragColor * texelColor;
+	diffuseColor *= texelColor;
 
 #endif

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

@@ -1,5 +1,5 @@
 #ifdef USE_MAP
 
-	gl_FragColor = gl_FragColor * texture2D( map, vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y ) * offsetRepeat.zw + offsetRepeat.xy );
+	diffuseColor *= texture2D( map, vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y ) * offsetRepeat.zw + offsetRepeat.xy );
 
 #endif

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

@@ -197,11 +197,11 @@
 
 			#ifdef SHADOWMAP_CASCADE
 
-				if ( inFrustum && inFrustumCount == 1 ) gl_FragColor.xyz *= frustumColors[ i ];
+				if ( inFrustum && inFrustumCount == 1 ) outgoingLight *= frustumColors[ i ];
 
 			#else
 
-				if ( inFrustum ) gl_FragColor.xyz *= frustumColors[ i ];
+				if ( inFrustum ) outgoingLight *= frustumColors[ i ];
 
 			#endif
 
@@ -212,6 +212,6 @@
 	// NOTE: I am unsure if this is correct in linear space.  -bhouston, Dec 29, 2014
 	shadowColor = inputToLinear( shadowColor );
 
-	gl_FragColor.xyz = gl_FragColor.xyz * shadowColor;
+	outgoingLight = outgoingLight * shadowColor;
 
 #endif

+ 43 - 18
src/renderers/shaders/ShaderLib.js

@@ -77,22 +77,28 @@ THREE.ShaderLib = {
 
 			"void main() {",
 
-			"	gl_FragColor = vec4( diffuse, opacity );",
+			"	vec3 outgoingLight = vec3( 0.0 );",	// outgoing light does not have an alpha, the surface does
+			"	vec4 diffuseColor = vec4( diffuse, opacity );",
 
 				THREE.ShaderChunk[ "logdepthbuf_fragment" ],
 				THREE.ShaderChunk[ "map_fragment" ],
+				THREE.ShaderChunk[ "color_fragment" ],
 				THREE.ShaderChunk[ "alphamap_fragment" ],
 				THREE.ShaderChunk[ "alphatest_fragment" ],
 				THREE.ShaderChunk[ "specularmap_fragment" ],
-				THREE.ShaderChunk[ "lightmap_fragment" ],
-				THREE.ShaderChunk[ "color_fragment" ],
+
+			"	outgoingLight = diffuseColor.rgb;", // simple shader
+
+				THREE.ShaderChunk[ "lightmap_fragment" ],		// TODO: Light map on an otherwise unlit surface doesn't make sense.
 				THREE.ShaderChunk[ "envmap_fragment" ],
-				THREE.ShaderChunk[ "shadowmap_fragment" ],
+				THREE.ShaderChunk[ "shadowmap_fragment" ],		// TODO: Shadows on an otherwise unlit surface doesn't make sense.
 
 				THREE.ShaderChunk[ "linear_to_gamma_fragment" ],
 
 				THREE.ShaderChunk[ "fog_fragment" ],
 
+			"	gl_FragColor = vec4( outgoingLight, diffuseColor.a );",	// TODO, this should be pre-multiplied to allow for bright highlights on very transparent objects
+
 			"}"
 
 		].join("\n")
@@ -165,6 +171,8 @@ THREE.ShaderLib = {
 
 		fragmentShader: [
 
+			"uniform vec3 diffuse;",
+			"uniform vec3 emissive;",
 			"uniform float opacity;",
 
 			"varying vec3 vLightFront;",
@@ -188,10 +196,12 @@ THREE.ShaderLib = {
 
 			"void main() {",
 
-			"	gl_FragColor = vec4( vec3( 1.0 ), opacity );",
+			"	vec3 outgoingLight = vec3( 0.0 );",	// outgoing light does not have an alpha, the surface does
+			"	vec4 diffuseColor = vec4( diffuse, opacity );",
 
 				THREE.ShaderChunk[ "logdepthbuf_fragment" ],
 				THREE.ShaderChunk[ "map_fragment" ],
+				THREE.ShaderChunk[ "color_fragment" ],
 				THREE.ShaderChunk[ "alphamap_fragment" ],
 				THREE.ShaderChunk[ "alphatest_fragment" ],
 				THREE.ShaderChunk[ "specularmap_fragment" ],
@@ -202,18 +212,17 @@ THREE.ShaderLib = {
 					//"gl_FragColor.xyz *= isFront * vLightFront + ( 1.0 - isFront ) * vLightBack;",
 
 			"		if ( gl_FrontFacing )",
-			"			gl_FragColor.xyz *= vLightFront;",
+			"			outgoingLight += diffuseColor.rgb * vLightFront + emissive;",
 			"		else",
-			"			gl_FragColor.xyz *= vLightBack;",
+			"			outgoingLight += diffuseColor.rgb * vLightBack + emissive;",
 
 			"	#else",
 
-			"		gl_FragColor.xyz *= vLightFront;",
+			"		outgoingLight += diffuseColor.rgb * vLightFront + emissive;",
 
 			"	#endif",
 
 				THREE.ShaderChunk[ "lightmap_fragment" ],
-				THREE.ShaderChunk[ "color_fragment" ],
 				THREE.ShaderChunk[ "envmap_fragment" ],
 				THREE.ShaderChunk[ "shadowmap_fragment" ],
 
@@ -221,6 +230,8 @@ THREE.ShaderLib = {
 
 				THREE.ShaderChunk[ "fog_fragment" ],
 
+			"	gl_FragColor = vec4( outgoingLight, diffuseColor.a );",	// TODO, this should be pre-multiplied to allow for bright highlights on very transparent objects
+
 			"}"
 
 		].join("\n")
@@ -281,7 +292,7 @@ THREE.ShaderLib = {
 				THREE.ShaderChunk[ "skinnormal_vertex" ],
 				THREE.ShaderChunk[ "defaultnormal_vertex" ],
 
-			"#ifndef FLAT_SHADED",
+			"#ifndef FLAT_SHADED", // Normal computed with derivatives when FLAT_SHADED
 
 			"	vNormal = normalize( transformedNormal );",
 
@@ -308,11 +319,10 @@ THREE.ShaderLib = {
 			"#define PHONG",
 
 			"uniform vec3 diffuse;",
-			"uniform float opacity;",
-
 			"uniform vec3 emissive;",
 			"uniform vec3 specular;",
 			"uniform float shininess;",
+			"uniform float opacity;",
 
 			THREE.ShaderChunk[ "common" ],
 			THREE.ShaderChunk[ "color_pars_fragment" ],
@@ -330,10 +340,12 @@ THREE.ShaderLib = {
 
 			"void main() {",
 
-			"	gl_FragColor = vec4( vec3( 1.0 ), opacity );",
+			"	vec3 outgoingLight = vec3( 0.0 );",	// outgoing light does not have an alpha, the surface does
+			"	vec4 diffuseColor = vec4( diffuse, opacity );",
 
 				THREE.ShaderChunk[ "logdepthbuf_fragment" ],
 				THREE.ShaderChunk[ "map_fragment" ],
+				THREE.ShaderChunk[ "color_fragment" ],
 				THREE.ShaderChunk[ "alphamap_fragment" ],
 				THREE.ShaderChunk[ "alphatest_fragment" ],
 				THREE.ShaderChunk[ "specularmap_fragment" ],
@@ -341,7 +353,6 @@ THREE.ShaderLib = {
 				THREE.ShaderChunk[ "lights_phong_fragment" ],
 
 				THREE.ShaderChunk[ "lightmap_fragment" ],
-				THREE.ShaderChunk[ "color_fragment" ],
 				THREE.ShaderChunk[ "envmap_fragment" ],
 				THREE.ShaderChunk[ "shadowmap_fragment" ],
 
@@ -349,6 +360,8 @@ THREE.ShaderLib = {
 
 				THREE.ShaderChunk[ "fog_fragment" ],
 
+			"	gl_FragColor = vec4( outgoingLight, diffuseColor.a );",	// TODO, this should be pre-multiplied to allow for bright highlights on very transparent objects
+
 			"}"
 
 		].join("\n")
@@ -410,15 +423,21 @@ THREE.ShaderLib = {
 
 			"void main() {",
 
-			"	gl_FragColor = vec4( psColor, opacity );",
+			"	vec3 outgoingLight = vec3( 0.0 );",	// outgoing light does not have an alpha, the surface does
+			"	vec4 diffuseColor = vec4( psColor, opacity );",
 
 				THREE.ShaderChunk[ "logdepthbuf_fragment" ],
 				THREE.ShaderChunk[ "map_particle_fragment" ],
-				THREE.ShaderChunk[ "alphatest_fragment" ],
 				THREE.ShaderChunk[ "color_fragment" ],
+				THREE.ShaderChunk[ "alphatest_fragment" ],
+
+			"	outgoingLight = diffuseColor.rgb;", // simple shader
+
 				THREE.ShaderChunk[ "shadowmap_fragment" ],
 				THREE.ShaderChunk[ "fog_fragment" ],
 
+			"	gl_FragColor = vec4( outgoingLight, diffuseColor.a );",	// TODO, this should be pre-multiplied to allow for bright highlights on very transparent objects
+
 			"}"
 
 		].join("\n")
@@ -489,12 +508,18 @@ THREE.ShaderLib = {
 
 			"	}",
 
-			"	gl_FragColor = vec4( diffuse, opacity );",
+			"	vec3 outgoingLight = vec3( 0.0 );",	// outgoing light does not have an alpha, the surface does
+			"	vec4 diffuseColor = vec4( diffuse, opacity );",
 
 				THREE.ShaderChunk[ "logdepthbuf_fragment" ],
 				THREE.ShaderChunk[ "color_fragment" ],
+
+			"	outgoingLight = diffuseColor.rgb;", // simple shader
+
 				THREE.ShaderChunk[ "fog_fragment" ],
 
+			"	gl_FragColor = vec4( outgoingLight, diffuseColor.a );",	// TODO, this should be pre-multiplied to allow for bright highlights on very transparent objects
+
 			"}"
 
 		].join("\n")
@@ -551,7 +576,7 @@ THREE.ShaderLib = {
 			"	#endif",
 
 			"	float color = 1.0 - smoothstep( mNear, mFar, depth );",
-			"	gl_FragColor = vec4( vec3( color ), opacity );",
+			"	gl_FragColor = vec4( vec3( color ), opacity );",   // TODO, this should be pre-multiplied to allow for bright highlights on very transparent objects
 
 			"}"
 

+ 1 - 1
src/renderers/webgl/plugins/ShadowMapPlugin.js

@@ -63,7 +63,7 @@ THREE.ShadowMapPlugin = function ( _renderer, _lights, _webglObjects, _webglObje
 		var i, il, j, jl, n,
 
 		shadowMap, shadowMatrix, shadowCamera,
-		program, buffer, material,
+		buffer, material,
 		webglObject, object, light,
 
 		lights = [],

+ 1 - 0
src/textures/Texture.js

@@ -11,6 +11,7 @@ THREE.Texture = function ( image, mapping, wrapS, wrapT, magFilter, minFilter, f
 	this.uuid = THREE.Math.generateUUID();
 
 	this.name = '';
+	this.sourceFile = '';
 
 	this.image = image !== undefined ? image : THREE.Texture.DEFAULT_IMAGE;
 	this.mipmaps = [];

+ 64 - 18
utils/build/build.js

@@ -1,7 +1,7 @@
 var fs = require("fs");
 var path = require("path");
 var argparse =  require( "argparse" );
-var uglify = require("uglify-js2");
+var uglify = require("uglify-js");
 var spawn = require('child_process').spawn;
 
 function main() {
@@ -14,7 +14,7 @@ function main() {
 	parser.addArgument( ['--amd'], { action: 'storeTrue', defaultValue: false } );
 	parser.addArgument( ['--minify'], { action: 'storeTrue', defaultValue: false } );
 	parser.addArgument( ['--output'], { defaultValue: '../../build/three.js' } );
-	parser.addArgument( ['--sourcemaps'], { action: 'storeTrue', defaultValue: false } );
+	parser.addArgument( ['--sourcemaps'], { action: 'storeTrue', defaultValue: true } );
 
 	
 	var args = parser.parseArgs();
@@ -28,13 +28,13 @@ function main() {
 	if ( args.sourcemaps ){
 
 		sourcemap = output + '.map';
-		sourcemapping = '\n//@ sourceMappingURL=' + sourcemap;
+		sourcemapping = '\n//# sourceMappingURL=three.min.js.map';
 
 	}
 
 	var buffer = [];
-	var sources = [];
-			
+	var sources = []; // used for source maps with minification
+
 	if ( args.amd ){
 		buffer.push('function ( root, factory ) {\n\n\tif ( typeof define === \'function\' && define.amd ) {\n\n\t\tdefine( [ \'exports\' ], factory );\n\n\t} else if ( typeof exports === \'object\' ) {\n\n\t\tfactory( exports );\n\n\t} else {\n\n\t\tfactory( root );\n\n\t}\n\n}( this, function ( exports ) {\n\n');
 	};
@@ -50,17 +50,20 @@ function main() {
 			
 			buffer.push('// File:' + files[ j ]);
 			buffer.push('\n\n');
+
+			contents = fs.readFileSync( file, 'utf8' );
+
 			if( file.indexOf( '.glsl') >= 0 ) {
-				buffer.push('THREE.ShaderChunk[\'' + path.basename(file, '.glsl') + '\'] = "');
-				buffer.push(fs.readFileSync( file, 'utf8' ));
-				buffer.push('";\n\n');
-			}
-			else {
-				sources.push( file );
-				buffer.push( fs.readFileSync( file, 'utf8' ) );
-				buffer.push('\n');
+
+				contents = 'THREE.ShaderChunk[ \'' +
+					path.basename( file, '.glsl' ) + '\' ] =' +
+					JSON.stringify( contents ) + ';\n';
+
 			}
 
+			sources.push( { file: file, contents: contents } );
+			buffer.push( contents );
+			buffer.push( '\n' );
 		}
 
 	}
@@ -73,17 +76,60 @@ function main() {
 	
 	if ( !args.minify ){
 
-		fs.writeFileSync( output,temp, 'utf8' );
+		fs.writeFileSync( output, temp, 'utf8' );
 
 	} else {
 
-		var result = uglify.minify( sources, { outSourceMap: sourcemap } );
-		
-		fs.writeFileSync( output, '// threejs.org/license\n' + result.code + sourcemapping, 'utf8' );
+		var LICENSE = "threejs.org/license";
+
+		// Parsing
+
+		var toplevel = null;
+
+		toplevel = uglify.parse( '// ' + LICENSE + '\n' );
+
+		sources.forEach( function( source ) {
+
+			toplevel = uglify.parse( source.contents, {
+				filename: source.file,
+				toplevel: toplevel
+			} );
+
+		} );
+
+		// Compression
+
+		toplevel.figure_out_scope();
+		var compressor = uglify.Compressor( {} );
+		var compressed_ast = toplevel.transform( compressor );
+
+		// Mangling
+
+		compressed_ast.figure_out_scope();
+		compressed_ast.compute_char_frequency();
+		compressed_ast.mangle_names();
+
+		// Output
+
+		var source_map_options = {
+			file: 'three.min.js',
+			root: 'src'
+		};
+
+		var source_map = uglify.SourceMap( source_map_options )
+		var stream = uglify.OutputStream( {
+			source_map: source_map,
+			comments: new RegExp( LICENSE )
+		} );
+
+		compressed_ast.print( stream );
+		var code = stream.toString();
+
+		fs.writeFileSync( output, code + sourcemapping, 'utf8' );
 
 		if ( args.sourcemaps ) {
 
-			fs.writeFileSync( sourcemap, result.map, 'utf8' );
+			fs.writeFileSync( sourcemap, source_map.toString(), 'utf8' );
 
 		}
 

+ 2 - 2
utils/build/package.json

@@ -9,8 +9,8 @@
     },
 
     "devDependencies": {
-    	"uglify-js2": "*",
-    	"argparse" : "*"
+        "uglify-js": "^2.4.17",
+        "argparse" : "*"
     },
     
     "repository" : {

+ 87 - 79
utils/exporters/blender/addons/io_three/__init__.py

@@ -36,13 +36,10 @@ logging.basicConfig(
     format='%(levelname)s:THREE:%(message)s',
     level=logging.DEBUG)
 
-SETTINGS_FILE_EXPORT = 'three_settings_export.js'
-
-
 bl_info = {
     'name': "Three.js Format",
-    'author': "repsac, mrdoob, yomotsu, mpk, jpweeks",
-    'version': (1, 3, 1),
+    'author': "repsac, mrdoob, yomotsu, mpk, jpweeks, rkusa",
+    'version': (1, 4, 0),
     'blender': (2, 7, 3),
     'location': "File > Export",
     'description': "Export Three.js formatted JSON files.",
@@ -53,6 +50,7 @@ bl_info = {
     'category': 'Import-Export'
 }
 
+
 def _geometry_types():
     """The valid geometry types that are supported by Three.js
 
@@ -257,88 +255,28 @@ class ThreeObject(bpy.types.Panel):
         row = layout.row()
         row.prop(obj, 'THREE_export', text='Export')
 
-def get_settings_fullpath():
-    """
-
-    :returns: Full path to the settings file (temp directory)
-
-    """
-    return os.path.join(bpy.app.tempdir, SETTINGS_FILE_EXPORT)
-
-
-def save_settings_export(properties):
-    """Save the current export settings to disk.
-
-    :param properties:
-    :returns: settings
-    :rtype: dict
-
-    """
-    settings = {
-        constants.VERTICES: properties.option_vertices,
-        constants.FACES: properties.option_faces,
-        constants.NORMALS: properties.option_normals,
-        constants.SKINNING: properties.option_skinning,
-        constants.BONES: properties.option_bones,
-        constants.GEOMETRY_TYPE: properties.option_geometry_type,
-
-        constants.MATERIALS: properties.option_materials,
-        constants.UVS: properties.option_uv_coords,
-        constants.FACE_MATERIALS: properties.option_face_materials,
-        constants.MAPS: properties.option_maps,
-        constants.COLORS: properties.option_colors,
-        constants.MIX_COLORS: properties.option_mix_colors,
-
-        constants.SCALE: properties.option_scale,
-        constants.ENABLE_PRECISION: properties.option_round_off,
-        constants.PRECISION: properties.option_round_value,
-        constants.LOGGING: properties.option_logging,
-        constants.COMPRESSION: properties.option_compression,
-        constants.INDENT: properties.option_indent,
-        constants.COPY_TEXTURES: properties.option_copy_textures,
-        constants.TEXTURE_FOLDER: properties.option_texture_folder,
+class ThreeExportSettings(bpy.types.Operator):
+    """Save the current export settings (gets saved in .blend)"""
+    bl_label = "Save Settings"
+    bl_idname = "scene.three_export_settings_set"
 
-        constants.SCENE: properties.option_export_scene,
-        #constants.EMBED_GEOMETRY: properties.option_embed_geometry,
-        constants.EMBED_ANIMATION: properties.option_embed_animation,
-        constants.LIGHTS: properties.option_lights,
-        constants.CAMERAS: properties.option_cameras,
-        constants.HIERARCHY: properties.option_hierarchy,
-
-        constants.MORPH_TARGETS: properties.option_animation_morph,
-        constants.ANIMATION: properties.option_animation_skeletal,
-        constants.FRAME_STEP: properties.option_frame_step,
-        constants.FRAME_INDEX_AS_TIME: properties.option_frame_index_as_time,
-        constants.INFLUENCES_PER_VERTEX: properties.option_influences
-    }
+    def execute(self, context):
+        cycles = context.scene.cycles
+        cycles.use_samples_final = True
 
-    fname = get_settings_fullpath()
-    logging.debug("Saving settings to %s", fname)
-    with open(fname, 'w') as stream:
-        json.dump(settings, stream)
+        context.scene[constants.EXPORT_SETTINGS_KEY] = set_settings(context.active_operator.properties)
 
-    return settings
+        self.report({"INFO"}, "Three Export Settings Saved")
 
+        return {"FINISHED"}
 
-def restore_settings_export(properties):
-    """Restore the settings (if settings file is found on disk)
-    If not found thend default to paramgers defined in
-    constants.EXPORT_OPTIONS
+def restore_export_settings(properties, settings):
+    """Restore the settings
 
     :param properties:
 
     """
 
-    settings = {}
-
-    fname = get_settings_fullpath()
-    if os.path.exists(fname) and os.access(fname, os.R_OK):
-        logging.debug("Settings cache found %s", fname)
-        with open(fname, 'r') as fs:
-            settings = json.load(fs)
-    else:
-        logging.debug("No settings file found, using defaults.")
-
     ## Geometry {
     properties.option_vertices = settings.get(
         constants.VERTICES,
@@ -472,6 +410,55 @@ def restore_settings_export(properties):
         constants.EXPORT_OPTIONS[constants.FRAME_INDEX_AS_TIME])
     ## }
 
+def set_settings(properties):
+    """Set the export settings to the correct keys.
+
+    :param properties:
+    :returns: settings
+    :rtype: dict
+
+    """
+    settings = {
+        constants.VERTICES: properties.option_vertices,
+        constants.FACES: properties.option_faces,
+        constants.NORMALS: properties.option_normals,
+        constants.SKINNING: properties.option_skinning,
+        constants.BONES: properties.option_bones,
+        constants.GEOMETRY_TYPE: properties.option_geometry_type,
+
+        constants.MATERIALS: properties.option_materials,
+        constants.UVS: properties.option_uv_coords,
+        constants.FACE_MATERIALS: properties.option_face_materials,
+        constants.MAPS: properties.option_maps,
+        constants.COLORS: properties.option_colors,
+        constants.MIX_COLORS: properties.option_mix_colors,
+
+        constants.SCALE: properties.option_scale,
+        constants.ENABLE_PRECISION: properties.option_round_off,
+        constants.PRECISION: properties.option_round_value,
+        constants.LOGGING: properties.option_logging,
+        constants.COMPRESSION: properties.option_compression,
+        constants.INDENT: properties.option_indent,
+        constants.COPY_TEXTURES: properties.option_copy_textures,
+        constants.TEXTURE_FOLDER: properties.option_texture_folder,
+
+        constants.SCENE: properties.option_export_scene,
+        #constants.EMBED_GEOMETRY: properties.option_embed_geometry,
+        constants.EMBED_ANIMATION: properties.option_embed_animation,
+        constants.LIGHTS: properties.option_lights,
+        constants.CAMERAS: properties.option_cameras,
+        constants.HIERARCHY: properties.option_hierarchy,
+
+        constants.MORPH_TARGETS: properties.option_animation_morph,
+        constants.ANIMATION: properties.option_animation_skeletal,
+        constants.FRAME_STEP: properties.option_frame_step,
+        constants.FRAME_INDEX_AS_TIME: properties.option_frame_index_as_time,
+        constants.INFLUENCES_PER_VERTEX: properties.option_influences
+    }
+
+    return settings
+
+
 def compression_types():
     """Supported compression formats
 
@@ -489,6 +476,7 @@ def compression_types():
 
     return types
 
+
 def animation_options():
     """The supported skeletal animation types
 
@@ -508,6 +496,7 @@ class ExportThree(bpy.types.Operator, ExportHelper):
 
     bl_idname = 'export.three'
     bl_label = 'Export THREE'
+    bl_options = {'PRESET'}
 
     filename_ext = constants.EXTENSION
 
@@ -692,7 +681,17 @@ class ExportThree(bpy.types.Operator, ExportHelper):
         default=2)
 
     def invoke(self, context, event):
-        restore_settings_export(self.properties)
+        settings = context.scene.get(constants.EXPORT_SETTINGS_KEY)
+        if settings:
+            try:
+                restore_export_settings(self.properties, settings)
+            except AttributeError as e:
+                logging.error("Loading export settings failed:")
+                logging.exception(e)
+                logging.debug("Removed corrupted settings")
+
+                del context.scene[constants.EXPORT_SETTINGS_KEY]
+
         return ExportHelper.invoke(self, context, event)
 
     @classmethod
@@ -713,7 +712,7 @@ class ExportThree(bpy.types.Operator, ExportHelper):
         if not self.properties.filepath:
             raise Exception("filename not set")
 
-        settings = save_settings_export(self.properties)
+        settings = set_settings(self.properties)
         settings['addon_version'] = bl_info['version']
 
         filepath = self.filepath
@@ -865,6 +864,15 @@ class ExportThree(bpy.types.Operator, ExportHelper):
         row.prop(self.properties, 'option_indent')
         ## }
 
+        ## Operators {
+        has_settings = context.scene.get(constants.EXPORT_SETTINGS_KEY, False)
+        row = layout.row()
+        row.operator(
+            ThreeExportSettings.bl_idname,
+            ThreeExportSettings.bl_label,
+            icon="%s" % "PINNED" if has_settings else "UNPINNED")
+        ## }
+
 
 
 def menu_func_export(self, context):

+ 1 - 0
utils/exporters/blender/addons/io_three/constants.py

@@ -329,3 +329,4 @@ DBG_COLORS = (0xeeeeee, 0xee0000, 0x00ee00, 0x0000ee,
 
 DOUBLE_SIDED = 'doubleSided'
 
+EXPORT_SETTINGS_KEY = 'threeExportSettings'

+ 4 - 12
utils/exporters/blender/addons/io_three/exporter/_json.py

@@ -5,18 +5,10 @@ ROUND = constants.DEFAULT_PRECISION
 
 ## THREE override function
 def _json_floatstr(o):
-    s = str(o)
-
-    if ROUND is None:
-        return s
-
-    if '.' in s and len(s[s.index('.'):]) > ROUND - 1:
-        s = '%.{0}f'.format(ROUND) % o
-        while '.' in s and s[-1] == '0':
-            s = s[:-1] # this actually removes the last '0' from the string
-        if s[-1] == '.': # added this test to avoid leaving '0.' instead of '0.0',
-            s += '0'    # which would throw an error while loading the file
-    return s
+    if ROUND is not None:
+        o = round(o, ROUND)
+        
+    return '%g' % o
 
 
 def _make_iterencode(markers, _default, _encoder, _indent, _floatstr,

+ 27 - 55
utils/exporters/blender/addons/io_three/exporter/api/animation.py

@@ -1,7 +1,11 @@
+"""
+Module for handling the parsing of skeletal animation data.
+"""
+
 import math
 import mathutils
 from bpy import data, context
-from .. import constants, logger, utilities
+from .. import constants, logger
 
 
 def pose_animation(armature, options):
@@ -42,22 +46,19 @@ def _parse_action(func, armature, options):
     """
     animations = []
     logger.info("Parsing %d actions", len(data.actions))
-    round_off, round_val = utilities.rounding(options)
     for action in data.actions:
         logger.info("Parsing action %s", action.name)
-        animation = func(action, armature, options, round_off, round_val)
+        animation = func(action, armature, options)
         animations.append(animation)
     return animations
 
 
-def _parse_rest_action(action, armature, options, round_off, round_val):
+def _parse_rest_action(action, armature, options):
     """
 
     :param action:
     :param armature:
     :param options:
-    :param round_off:
-    :param round_val:
 
     """
     end_frame = action.frame_range[1]
@@ -91,19 +92,13 @@ def _parse_rest_action(action, armature, options, round_off, round_val):
                                      action, rotation_matrix)
             rot = _normalize_quaternion(rot)
 
-            if round_off:
-                pos_x, pos_y, pos_z = utilities.round_off(
-                    [pos.x, pos.z, -pos.y], round_val)
-                rot_x, rot_y, rot_z, rot_w = utilities.round_off(
-                    [rot.x, rot.z, -rot.y, rot.w], round_val)
-            else:
-                pos_x, pos_y, pos_z = pos.x, pos.z, -pos.y
-                rot_x, rot_y, rot_z, rot_w = rot.x, rot.z, -rot.y, rot.w
+            pos_x, pos_y, pos_z = pos.x, pos.z, -pos.y
+            rot_x, rot_y, rot_z, rot_w = rot.x, rot.z, -rot.y, rot.w
 
             if frame == start_frame:
 
                 time = (frame * frame_step - start_frame) / fps
-                #@TODO: missing scale values
+                # @TODO: missing scale values
                 keyframe = {
                     constants.TIME: time,
                     constants.POS: [pos_x, pos_y, pos_z],
@@ -129,22 +124,22 @@ def _parse_rest_action(action, armature, options, round_off, round_val):
             # MIDDLE-FRAME: needs only one of the attributes,
             # can be an empty frame (optional frame)
 
-            elif pchange == True or rchange == True:
+            elif pchange is True or rchange is True:
 
                 time = (frame * frame_step - start_frame) / fps
 
-                if pchange == True and rchange == True:
+                if pchange is True and rchange is True:
                     keyframe = {
                         constants.TIME: time,
                         constants.POS: [pos_x, pos_y, pos_z],
                         constants.ROT: [rot_x, rot_y, rot_z, rot_w]
                     }
-                elif pchange == True:
+                elif pchange is True:
                     keyframe = {
                         constants.TIME: time,
                         constants.POS: [pos_x, pos_y, pos_z]
                     }
-                elif rchange == True:
+                elif rchange is True:
                     keyframe = {
                         constants.TIME: time,
                         constants.ROT: [rot_x, rot_y, rot_z, rot_w]
@@ -160,7 +155,7 @@ def _parse_rest_action(action, armature, options, round_off, round_val):
 
     animation = {
         constants.HIERARCHY: hierarchy,
-        constants.LENGTH:frame_length / fps,
+        constants.LENGTH: frame_length / fps,
         constants.FPS: fps,
         constants.NAME: action.name
     }
@@ -168,20 +163,18 @@ def _parse_rest_action(action, armature, options, round_off, round_val):
     return animation
 
 
-def _parse_pose_action(action, armature, options, round_off, round_val):
+def _parse_pose_action(action, armature, options):
     """
 
     :param action:
     :param armature:
     :param options:
-    :param round_off:
-    :param round_val:
 
     """
-    #@TODO: this seems to fail in batch mode meaning the
-    #       user has to have th GUI open. need to improve
-    #       this logic to allow batch processing, if Blender
-    #       chooses to behave....
+    # @TODO: this seems to fail in batch mode meaning the
+    #        user has to have th GUI open. need to improve
+    #        this logic to allow batch processing, if Blender
+    #        chooses to behave....
     current_context = context.area.type
     context.area.type = 'DOPESHEET_EDITOR'
     context.space_data.mode = 'ACTION'
@@ -285,27 +278,9 @@ def _parse_pose_action(action, armature, options, round_off, round_val):
             schange = True or has_keyframe_at(
                 channels_scale[bone_index], frame)
 
-            if round_off:
-                pos = (
-                    utilities.round_off(pos.x, round_val),
-                    utilities.round_off(pos.z, round_val),
-                    -utilities.round_off(pos.y, round_val)
-                )
-                rot = (
-                    utilities.round_off(rot.x, round_val),
-                    utilities.round_off(rot.z, round_val),
-                    -utilities.round_off(rot.y, round_val),
-                    utilities.round_off(rot.w, round_val)
-                )
-                scl = (
-                    utilities.round_off(scl.x, round_val),
-                    utilities.round_off(scl.z, round_val),
-                    utilities.round_off(scl.y, round_val)
-                )
-            else:
-                pos = (pos.x, pos.z, -pos.y)
-                rot = (rot.x, rot.z, -rot.y, rot.w)
-                scl = (scl.x, scl.z, scl.y)
+            pos = (pos.x, pos.z, -pos.y)
+            rot = (rot.x, rot.z, -rot.y, rot.w)
+            scl = (scl.x, scl.z, scl.y)
 
             keyframe = {constants.TIME: time}
             if frame == start_frame or frame == end_frame:
@@ -349,7 +324,7 @@ def _parse_pose_action(action, armature, options, round_off, round_val):
 
     animation = {
         constants.HIERARCHY: hierarchy,
-        constants.LENGTH:frame_length,
+        constants.LENGTH: frame_length,
         constants.FPS: fps,
         constants.NAME: action.name
     }
@@ -373,7 +348,7 @@ def _find_channels(action, bone, channel_type):
         for index, group in enumerate(action.groups):
             if group.name == bone.name:
                 group_index = index
-                #@TODO: break?
+                # @TODO: break?
 
         if group_index > -1:
             for channel in action.groups[group_index].channels:
@@ -426,8 +401,7 @@ def _position(bone, frame, action, armature_matrix):
 
         for channel in action.fcurves:
             data_path = channel.data_path
-            if bone_label in data_path and \
-            "location" in data_path:
+            if bone_label in data_path and "location" in data_path:
                 has_changed = _handle_position_channel(
                     channel, frame, position)
                 change = change or has_changed
@@ -497,8 +471,7 @@ def _rotation(bone, frame, action, armature_matrix):
 
         for channel in action.fcurves:
             data_path = channel.data_path
-            if bone_label in data_path and \
-            "quaternion" in data_path:
+            if bone_label in data_path and "quaternion" in data_path:
                 has_changed = _handle_rotation_channel(
                     channel, frame, rotation)
                 change = change or has_changed
@@ -602,4 +575,3 @@ def _normalize_quaternion(quat):
         enum.z = quat.z * length
         enum.w = quat.w * length
     return enum
-

+ 7 - 3
utils/exporters/blender/addons/io_three/exporter/api/material.py

@@ -179,7 +179,7 @@ def light_map(material):
 
     """
     logger.debug("material.light_map(%s)", material)
-    for texture in _valid_textures(material):
+    for texture in _valid_textures(material, strict_use=False):
         if texture.use_map_color_diffuse and \
         texture.blend_type == MULTIPLY:
             return texture.texture
@@ -370,7 +370,7 @@ def wireframe(material):
     return material.type == WIRE
 
 
-def _valid_textures(material):
+def _valid_textures(material, strict_use=True):
     """
 
     :param material:
@@ -380,7 +380,11 @@ def _valid_textures(material):
     for texture in material.texture_slots:
         if not texture:
             continue
-        if texture.texture.type != IMAGE or not texture.use:
+        if strict_use:
+            in_use = texture.use
+        else:
+            in_use = True
+        if texture.texture.type != IMAGE or not in_use:
             continue
         logger.debug("Valid texture found %s", texture)
         yield texture

+ 58 - 123
utils/exporters/blender/addons/io_three/exporter/api/mesh.py

@@ -1,3 +1,9 @@
+"""
+Blender API for querying mesh data. Animation data is also
+handled here since Three.js associates the animation (skeletal,
+morph targets) with the geometry nodes.
+"""
+
 import operator
 from bpy import data, types, context
 from . import material, texture, animation
@@ -37,6 +43,7 @@ def skeletal_animation(mesh, options):
 
     :param mesh:
     :param options:
+    :rtype: []
 
     """
     logger.debug("mesh.animation(%s, %s)", mesh, options)
@@ -47,16 +54,16 @@ def skeletal_animation(mesh, options):
         return []
 
     anim_type = options.get(constants.ANIMATION)
-    #pose_position = armature.data.pose_position
+#    pose_position = armature.data.pose_position
     dispatch = {
         constants.POSE: animation.pose_animation,
         constants.REST: animation.rest_animation
     }
 
     func = dispatch[anim_type]
-    #armature.data.pose_position = anim_type.upper()
+#    armature.data.pose_position = anim_type.upper()
     animations = func(armature, options)
-    #armature.data.pose_position = pose_position
+#    armature.data.pose_position = pose_position
 
     return animations
 
@@ -67,6 +74,7 @@ def bones(mesh, options):
 
     :param mesh:
     :param options:
+    :rtype: [], {}
 
     """
     logger.debug("mesh.bones(%s)", mesh)
@@ -75,15 +83,14 @@ def bones(mesh, options):
     if not armature:
         return [], {}
 
-    round_off, round_val = utilities.rounding(options)
     anim_type = options.get(constants.ANIMATION)
-    #pose_position = armature.data.pose_position
+#    pose_position = armature.data.pose_position
 
     if anim_type == constants.OFF:
-        logger.info("Animation type not set, defaulting "\
-            "to using REST position for the armature.")
+        logger.info("Animation type not set, defaulting "
+                    "to using REST position for the armature.")
         func = _rest_bones
-        #armature.data.pose_position = "REST"
+#        armature.data.pose_position = "REST"
     else:
         dispatch = {
             constants.REST: _rest_bones,
@@ -91,24 +98,23 @@ def bones(mesh, options):
         }
         logger.info("Using %s for the armature", anim_type)
         func = dispatch[anim_type]
-        #armature.data.pose_position = anim_type.upper()
+#        armature.data.pose_position = anim_type.upper()
 
-    bones_, bone_map = func(armature, round_off, round_val)
-    #armature.data.pose_position = pose_position
+    bones_, bone_map = func(armature)
+#    armature.data.pose_position = pose_position
 
     return (bones_, bone_map)
 
 
 @_mesh
-def buffer_normal(mesh, options):
+def buffer_normal(mesh):
     """
 
     :param mesh:
-    :param options:
+    :rtype: []
 
     """
     normals_ = []
-    round_off, round_val = utilities.rounding(options)
 
     for face in mesh.tessfaces:
         vert_count = len(face.vertices)
@@ -119,24 +125,20 @@ def buffer_normal(mesh, options):
         for vertex_index in face.vertices:
             normal = mesh.vertices[vertex_index].normal
             vector = (normal.x, normal.y, normal.z)
-            if round_off:
-                vector = utilities.round_off(vector, round_val)
-
             normals_.extend(vector)
 
     return normals_
 
 
 @_mesh
-def buffer_position(mesh, options):
+def buffer_position(mesh):
     """
 
     :param mesh:
-    :param options:
+    :rtype: []
 
     """
     position = []
-    round_off, round_val = utilities.rounding(options)
 
     for face in mesh.tessfaces:
         vert_count = len(face.vertices)
@@ -147,35 +149,29 @@ def buffer_position(mesh, options):
         for vertex_index in face.vertices:
             vertex = mesh.vertices[vertex_index]
             vector = (vertex.co.x, vertex.co.y, vertex.co.z)
-            if round_off:
-                vector = utilities.round_off(vector, round_val)
-
             position.extend(vector)
 
     return position
 
 
 @_mesh
-def buffer_uv(mesh, options):
+def buffer_uv(mesh):
     """
 
     :param mesh:
-    :param options:
+    :rtype: []
 
     """
+    uvs_ = []
     if len(mesh.uv_layers) is 0:
-        return
+        return uvs_
     elif len(mesh.uv_layers) > 1:
         # if memory serves me correctly buffer geometry
         # only uses one UV layer
         logger.warning("%s has more than 1 UV layer", mesh.name)
 
-    round_off, round_val = utilities.rounding(options)
-    uvs_ = []
     for uv_data in mesh.uv_layers[0].data:
         uv_tuple = (uv_data.uv[0], uv_data.uv[1])
-        if round_off:
-            uv_tuple = utilities.round_off(uv_tuple, round_val)
         uvs_.extend(uv_tuple)
 
     return uvs_
@@ -195,10 +191,6 @@ def faces(mesh, options):
     logger.info("Has UVs = %s", vertex_uv)
     logger.info("Has vertex colours = %s", has_colors)
 
-    round_off, round_val = utilities.rounding(options)
-    if round_off:
-        logger.debug("Rounding off of vectors set to %s", round_off)
-
     opt_colours = options[constants.COLORS] and has_colors
     opt_uvs = options[constants.UVS] and vertex_uv
     opt_materials = options.get(constants.FACE_MATERIALS)
@@ -208,8 +200,8 @@ def faces(mesh, options):
     logger.debug("Materials enabled = %s", opt_materials)
     logger.debug("Normals enabled = %s", opt_normals)
 
-    uv_layers = _uvs(mesh, options) if opt_uvs else None
-    vertex_normals = _normals(mesh, options) if opt_normals else None
+    uv_layers = _uvs(mesh) if opt_uvs else None
+    vertex_normals = _normals(mesh) if opt_normals else None
     vertex_colours = vertex_colors(mesh) if opt_colours else None
 
     faces_data = []
@@ -252,17 +244,14 @@ def faces(mesh, options):
         if mask[constants.MATERIALS]:
             face_data.append(face.material_index)
 
-        #@TODO: this needs the same optimization as what
-        #       was done for colours and normals
+        # @TODO: this needs the same optimization as what
+        #        was done for colours and normals
         if uv_layers:
             for index, uv_layer in enumerate(uv_layers):
                 layer = mesh.tessface_uv_textures[index]
 
                 for uv_data in layer.data[face.index].uv:
                     uv_tuple = (uv_data[0], uv_data[1])
-                    if round_off:
-                        uv_tuple = utilities.round_off(
-                            uv_tuple, round_val)
                     face_data.append(uv_layer.index(uv_tuple))
                     mask[constants.UVS] = True
 
@@ -270,8 +259,6 @@ def faces(mesh, options):
             for vertex in face.vertices:
                 normal = mesh.vertices[vertex].normal
                 normal = (normal.x, normal.y, normal.z)
-                if round_off:
-                    normal = utilities.round_off(normal, round_val)
                 face_data.append(normal_indices[str(normal)])
                 mask[constants.NORMALS] = True
 
@@ -310,7 +297,6 @@ def morph_targets(mesh, options):
                          frame_step)
 
     morphs = []
-    round_off, round_val = utilities.rounding(options)
 
     for frame in scene_frames:
         logger.info("Processing data at frame %d", frame)
@@ -319,15 +305,7 @@ def morph_targets(mesh, options):
         vertices_ = object_.extract_mesh(obj, options).vertices[:]
 
         for vertex in vertices_:
-            if round_off:
-                vectors = [
-                    utilities.round_off(vertex.co.x, round_val),
-                    utilities.round_off(vertex.co.y, round_val),
-                    utilities.round_off(vertex.co.z, round_val)
-                ]
-            else:
-                vectors = [vertex.co.x, vertex.co.y, vertex.co.z]
-            morphs[-1].extend(vectors)
+            morphs[-1].extend([vertex.co.x, vertex.co.y, vertex.co.z])
 
     context.scene.frame_set(original_frame, 0.0)
     morphs_detected = False
@@ -449,17 +427,17 @@ def materials(mesh, options):
 
 
 @_mesh
-def normals(mesh, options):
+def normals(mesh):
     """
 
     :param mesh:
-    :param options:
+    :rtype: []
 
     """
-    logger.debug("mesh.normals(%s, %s)", mesh, options)
+    logger.debug("mesh.normals(%s)", mesh)
     normal_vectors = []
 
-    for vector in _normals(mesh, options):
+    for vector in _normals(mesh):
         normal_vectors.extend(vector)
 
     return normal_vectors
@@ -544,16 +522,16 @@ def texture_registration(mesh):
 
 
 @_mesh
-def uvs(mesh, options):
+def uvs(mesh):
     """
 
     :param mesh:
-    :param options:
+    :rtype: []
 
     """
-    logger.debug("mesh.uvs(%s, %s)", mesh, options)
+    logger.debug("mesh.uvs(%s)", mesh)
     uvs_ = []
-    for layer in _uvs(mesh, options):
+    for layer in _uvs(mesh):
         uvs_.append([])
         logger.info("Parsing UV layer %d", len(uvs_))
         for pair in layer:
@@ -594,24 +572,18 @@ def vertex_colors(mesh):
 
 
 @_mesh
-def vertices(mesh, options):
+def vertices(mesh):
     """
 
     :param mesh:
-    :param options:
+    :rtype: []
 
     """
-    logger.debug("mesh.vertices(%s, %s)", mesh, options)
+    logger.debug("mesh.vertices(%s)", mesh)
     vertices_ = []
 
-    round_off, round_val = utilities.rounding(options)
-
     for vertex in mesh.vertices:
-        vector = (vertex.co.x, vertex.co.y, vertex.co.z)
-        if round_off:
-            vector = utilities.round_off(vector, round_val)
-
-        vertices_.extend(vector)
+        vertices_.extend((vertex.co.x, vertex.co.y, vertex.co.z))
 
     return vertices_
 
@@ -740,15 +712,14 @@ def _diffuse_map(mat):
     return diffuse
 
 
-def _normals(mesh, options):
+def _normals(mesh):
     """
 
     :param mesh:
-    :param options:
+    :rtype: []
 
     """
     vectors = []
-    round_off, round_val = utilities.rounding(options)
 
     vectors_ = {}
     for face in mesh.tessfaces:
@@ -756,8 +727,6 @@ def _normals(mesh, options):
         for vertex_index in face.vertices:
             normal = mesh.vertices[vertex_index].normal
             vector = (normal.x, normal.y, normal.z)
-            if round_off:
-                vector = utilities.round_off(vector, round_val)
 
             str_vec = str(vector)
             try:
@@ -769,23 +738,19 @@ def _normals(mesh, options):
     return vectors
 
 
-def _uvs(mesh, options):
+def _uvs(mesh):
     """
 
     :param mesh:
-    :param options:
 
     """
     uv_layers = []
-    round_off, round_val = utilities.rounding(options)
 
     for layer in mesh.uv_layers:
         uv_layers.append([])
 
         for uv_data in layer.data:
             uv_tuple = (uv_data.uv[0], uv_data.uv[1])
-            if round_off:
-                uv_tuple = utilities.round_off(uv_tuple, round_val)
 
             if uv_tuple not in uv_layers[-1]:
                 uv_layers[-1].append(uv_tuple)
@@ -853,12 +818,11 @@ def _skinning_data(mesh, bone_map, influences, array_index):
     return manifest
 
 
-def _pose_bones(armature, round_off, round_val):
+def _pose_bones(armature):
     """
 
     :param armature:
-    :param round_off:
-    :param round_val:
+    :rtype: [], {}
 
     """
     bones_ = []
@@ -889,44 +853,22 @@ def _pose_bones(armature, round_off, round_val):
         bone_map[bone_count] = bone_count
 
         pos, rot, scl = bone_matrix.decompose()
-        if round_off:
-            pos = (
-                utilities.round_off(pos.x, round_val),
-                utilities.round_off(pos.z, round_val),
-                -utilities.round_off(pos.y, round_val)
-            )
-            rot = (
-                utilities.round_off(rot.x, round_val),
-                utilities.round_off(rot.z, round_val),
-                -utilities.round_off(rot.y, round_val),
-                utilities.round_off(rot.w, round_val)
-            )
-            scl = (
-                utilities.round_off(scl.x, round_val),
-                utilities.round_off(scl.z, round_val),
-                utilities.round_off(scl.y, round_val)
-            )
-        else:
-            pos = (pos.x, pos.z, -pos.y)
-            rot = (rot.x, rot.z, -rot.y, rot.w)
-            scl = (scl.x, scl.z, scl.y)
         bones_.append({
             constants.PARENT: bone_index,
             constants.NAME: armature_bone.name,
-            constants.POS: pos,
-            constants.ROTQ: rot,
-            constants.SCL: scl
+            constants.POS: (pos.x, pos.z, -pos.y),
+            constants.ROTQ: (rot.x, rot.z, -rot.y, rot.w),
+            constants.SCL: (scl.x, scl.z, scl.y)
         })
 
     return bones_, bone_map
 
 
-def _rest_bones(armature, round_off, round_val):
+def _rest_bones(armature):
     """
 
     :param armature:
-    :param round_off:
-    :param round_val:
+    :rtype: [], {}
 
     """
     bones_ = []
@@ -955,21 +897,16 @@ def _rest_bones(armature, round_off, round_val):
                 index += 1
 
         bone_world_pos = armature.matrix_world * bone_pos
-        if round_off:
-            x_axis = utilities.round_off(bone_world_pos.x, round_val)
-            y_axis = utilities.round_off(bone_world_pos.z, round_val)
-            z_axis = -utilities.round_off(bone_world_pos.y, round_val)
-        else:
-            x_axis = bone_world_pos.x
-            y_axis = bone_world_pos.z
-            z_axis = -bone_world_pos.y
+        x_axis = bone_world_pos.x
+        y_axis = bone_world_pos.z
+        z_axis = -bone_world_pos.y
 
         logger.debug("Adding bone %s at: %s, %s",
                      bone.name, bone_index, bone_index_rel)
         bone_map[bone_count] = bone_index_rel
         bone_index_rel += 1
-        #@TODO: the rotq probably should not have these
-        #       hard coded values
+        # @TODO: the rotq probably should not have these
+        #        hard coded values
         bones_.append({
             constants.PARENT: bone_index,
             constants.NAME: bone.name,
@@ -980,5 +917,3 @@ def _rest_bones(armature, round_off, round_val):
         bone_count += 1
 
     return (bones_, bone_map)
-
-

+ 9 - 11
utils/exporters/blender/addons/io_three/exporter/geometry.py

@@ -1,3 +1,7 @@
+"""
+Module for creating Three.js geometry JSON nodes.
+"""
+
 import os
 from .. import constants, logger
 from . import base_classes, io, api
@@ -42,11 +46,8 @@ class Geometry(base_classes.BaseNode):
 
         key = ''
         for key in (constants.MORPH_TARGETS, constants.ANIMATION):
-            try:
-                self[key]
+            if key in self.keys():
                 break
-            except KeyError:
-                pass
         else:
             logger.info("%s has no animation data", self.node)
             return
@@ -367,7 +368,7 @@ class Geometry(base_classes.BaseNode):
             if not option:
                 continue
 
-            array = func(self.node, self.options) or []
+            array = func(self.node) or []
             if not array:
                 logger.warning("No array could be made for %s", key)
                 continue
@@ -382,13 +383,11 @@ class Geometry(base_classes.BaseNode):
         """Parse the geometry to Three.Geometry specs"""
         if self.options.get(constants.VERTICES):
             logger.info("Parsing %s", constants.VERTICES)
-            self[constants.VERTICES] = api.mesh.vertices(
-                self.node, self.options) or []
+            self[constants.VERTICES] = api.mesh.vertices(self.node) or []
 
         if self.options.get(constants.NORMALS):
             logger.info("Parsing %s", constants.NORMALS)
-            self[constants.NORMALS] = api.mesh.normals(
-                self.node, self.options) or []
+            self[constants.NORMALS] = api.mesh.normals(self.node) or []
 
         if self.options.get(constants.COLORS):
             logger.info("Parsing %s", constants.COLORS)
@@ -402,8 +401,7 @@ class Geometry(base_classes.BaseNode):
 
         if self.options.get(constants.UVS):
             logger.info("Parsing %s", constants.UVS)
-            self[constants.UVS] = api.mesh.uvs(
-                self.node, self.options) or []
+            self[constants.UVS] = api.mesh.uvs(self.node) or []
 
         if self.options.get(constants.FACES):
             logger.info("Parsing %s", constants.FACES)

+ 0 - 43
utils/exporters/blender/addons/io_three/exporter/utilities.py

@@ -68,46 +68,3 @@ def rgb2int(rgb):
 
     colour = (int(rgb[0]*255) << 16) + (int(rgb[1]*255) << 8) + int(rgb[2]*255)
     return colour
-
-
-def round_off(value, ndigits=ROUND):
-    """Round off values to specified limit
-
-    :param value: value(s) to round off
-    :param ndigits: limit (Default value = ROUND)
-    :type value: float|list|tuple
-    :return: the same data type that was passed
-    :rtype: float|list|tuple
-
-    """
-    is_tuple = isinstance(value, tuple)
-    is_list = isinstance(value, list)
-
-    value = list(value) if is_tuple else value
-    value = [value] if not is_list and not is_tuple else value
-
-    value = [round(val, ndigits) for val in value]
-
-    if is_tuple:
-        value = tuple(value)
-    elif not is_list:
-        value = value[0]
-
-    return value
-
-
-def rounding(options):
-    """By evaluation the options determine if precision was
-    enabled and what the value is
-
-    :type options: dict
-    :rtype: bool, int
-
-    """
-    round_off_ = options.get(constants.ENABLE_PRECISION)
-    if round_off_:
-        round_val = options[constants.PRECISION]
-    else:
-        round_val = None
-
-    return (round_off_, round_val)

+ 2 - 0
utils/exporters/blender/tests/scripts/exporter.py

@@ -27,6 +27,8 @@ def parse_args():
 
 def main():
     args = parse_args()
+    args[constants.ENABLE_PRECISION] = True
+    args[constants.INDENT] = True
     if args[constants.SCENE]:
         io_three.exporter.export_scene(args['filepath'], args)
     else:

部分文件因为文件数量过多而无法显示