Browse Source

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

Dusan Bosnjak 8 years ago
parent
commit
57bfcdb44c
100 changed files with 3799 additions and 2180 deletions
  1. 497 176
      build/three.js
  2. 306 340
      build/three.min.js
  3. 497 176
      build/three.module.js
  4. 149 97
      docs/api/animation/AnimationMixer.html
  5. 7 0
      docs/api/extras/core/Font.html
  6. 26 4
      docs/api/geometries/TextGeometry.html
  7. 1 0
      docs/api/loaders/FontLoader.html
  8. 7 0
      docs/api/materials/ShaderMaterial.html
  9. 6 6
      docs/api/math/Line3.html
  10. 4 4
      docs/api/math/Math.html
  11. 6 6
      docs/api/math/Quaternion.html
  12. 20 21
      docs/api/math/Vector2.html
  13. 5 5
      docs/api/math/Vector3.html
  14. 18 19
      docs/api/math/Vector4.html
  15. 10 10
      docs/examples/loaders/GLTFLoader.html
  16. 12 6
      docs/manual/introduction/Creating-text.html
  17. 2 2
      docs/scenes/js/geometry.js
  18. 18 0
      editor/js/Sidebar.Animation.js
  19. 23 0
      editor/js/Sidebar.Material.js
  20. 1 1
      examples/canvas_geometry_panorama.html
  21. 1 1
      examples/canvas_geometry_panorama_fisheye.html
  22. 3 3
      examples/canvas_geometry_text.html
  23. 1 1
      examples/canvas_materials.html
  24. 6 2
      examples/js/BlendCharacter.js
  25. 2 2
      examples/js/Car.js
  26. 84 162
      examples/js/Mirror.js
  27. 1 1
      examples/js/UCSCharacter.js
  28. 8 0
      examples/js/controls/OrbitControls.js
  29. 55 98
      examples/js/effects/OutlineEffect.js
  30. 269 199
      examples/js/geometries/DecalGeometry.js
  31. 4 9
      examples/js/lights/RectAreaLightUniformsLib.js
  32. 4 3
      examples/js/loaders/AssimpLoader.js
  33. 12 1
      examples/js/loaders/ColladaLoader.js
  34. 2 1
      examples/js/loaders/ColladaLoader2.js
  35. 14 0
      examples/js/loaders/FBXLoader.js
  36. 5 0
      examples/js/loaders/FBXLoader2.js
  37. 33 29
      examples/js/loaders/GLTF2Loader.js
  38. 20 18
      examples/js/loaders/GLTFLoader.js
  39. 5 4
      examples/js/loaders/MMDLoader.js
  40. 12 8
      examples/js/loaders/STLLoader.js
  41. 4 1
      examples/js/loaders/sea3d/SEA3DLoader.js
  42. 1 1
      examples/js/nodes/inputs/MirrorNode.js
  43. 83 81
      examples/js/renderers/CanvasRenderer.js
  44. 173 92
      examples/js/renderers/Projector.js
  45. 121 134
      examples/js/renderers/WebGLDeferredRenderer.js
  46. 2 2
      examples/js/vr/WebVR.js
  47. BIN
      examples/models/gltf/RiggedSimple/glTF/RiggedSimple.bin
  48. 588 0
      examples/models/gltf/RiggedSimple/glTF/RiggedSimple.gltf
  49. 24 0
      examples/models/gltf/RiggedSimple/glTF/RiggedSimple0FS.glsl
  50. 19 0
      examples/models/gltf/RiggedSimple/glTF/RiggedSimple0VS.glsl
  51. 12 0
      examples/models/json/suzanne.json
  52. 3 2
      examples/webgl_animation_skinning_morph.html
  53. 32 79
      examples/webgl_decals.html
  54. 4 4
      examples/webgl_effects_parallaxbarrier.html
  55. 0 2
      examples/webgl_effects_peppersghost.html
  56. 2 2
      examples/webgl_geometry_colors_blender.html
  57. 1 1
      examples/webgl_geometry_extrude_shapes.html
  58. 64 54
      examples/webgl_geometry_shapes.html
  59. 47 34
      examples/webgl_geometry_spline_editor.html
  60. 5 5
      examples/webgl_geometry_text.html
  61. 5 5
      examples/webgl_geometry_text_earcut.html
  62. 5 5
      examples/webgl_geometry_text_pnltri.html
  63. 166 0
      examples/webgl_geometry_text_shapes.html
  64. 0 17
      examples/webgl_loader_ctm_materials.html
  65. 10 3
      examples/webgl_loader_gltf.html
  66. 1 3
      examples/webgl_loader_json_blender.html
  67. 1 1
      examples/webgl_loader_json_objconverter.html
  68. 2 2
      examples/webgl_loader_mmd.html
  69. 1 1
      examples/webgl_materials.html
  70. 4 4
      examples/webgl_materials_cars.html
  71. 1 1
      examples/webgl_materials_lightmap.html
  72. 18 35
      examples/webgl_mirror.html
  73. 1 8
      examples/webgl_mirror_nodes.html
  74. 1 1
      examples/webgl_nearestneighbour.html
  75. 6 6
      examples/webgl_objects_update.html
  76. 1 1
      examples/webgl_panorama_cube.html
  77. 2 2
      examples/webgl_performance.html
  78. 2 2
      examples/webgl_performance_static.html
  79. 4 3
      examples/webgl_simple_gi.html
  80. 7 1
      examples/webgl_skinning_simple.html
  81. 1 0
      examples/webgldeferred_animation.html
  82. 38 10
      examples/webvr_shadow.html
  83. 1 1
      package.json
  84. 3 3
      rollup.config.js
  85. 7 14
      src/Three.Legacy.js
  86. 11 7
      src/animation/AnimationUtils.js
  87. 2 2
      src/animation/KeyframeTrackConstructor.js
  88. 66 30
      src/animation/PropertyBinding.js
  89. 0 16
      src/cameras/Camera.js
  90. 6 8
      src/core/BufferGeometry.js
  91. 2 2
      src/core/Face3.js
  92. 12 8
      src/core/InstancedBufferAttribute.js
  93. 29 27
      src/core/InstancedBufferGeometry.js
  94. 10 8
      src/core/InstancedInterleavedBuffer.js
  95. 2 2
      src/core/InterleavedBufferAttribute.js
  96. 5 5
      src/core/Layers.js
  97. 11 3
      src/core/Object3D.js
  98. 2 2
      src/core/Raycaster.js
  99. 12 4
      src/lights/RectAreaLight.js
  100. 0 18
      src/lights/RectAreaLightShadow.js

File diff suppressed because it is too large
+ 497 - 176
build/three.js


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


File diff suppressed because it is too large
+ 497 - 176
build/three.module.js


+ 149 - 97
docs/api/animation/AnimationMixer.html

@@ -1,102 +1,154 @@
 <!DOCTYPE html>
 <html lang="en">
-  <head>
-    <meta charset="utf-8" />
-    <base href="../../" />
-    <script src="list.js"></script>
-    <script src="page.js"></script>
-    <link type="text/css" rel="stylesheet" href="page.css" />
-  </head>
-  <body>
-    <h1>[name]</h1>
+	<head>
+		<meta charset="utf-8" />
+		<base href="../../" />
+		<script src="list.js"></script>
+		<script src="page.js"></script>
+		<link type="text/css" rel="stylesheet" href="page.css" />
+	</head>
+	<body>
+		<h1>[name]</h1>
+
+		<div class="desc">
+		The AnimationMixer is a player for animations on a particular object in the scene.
+		</div>
+
+		<p>
+		Each available animation sequence is stored as an [page:AnimationClip AnimationClip], and
+		playback of that clip is controlled with an [page:AnimationClip AnimationAction]. When multiple
+		objects in the scene are animated independently, one AnimationMixer may be used for each object.
+		</p>
+
+		<h2>Example</h2>
+
+		<p>
+		When loading a 3D model that includes animation, many loaders also return a list of
+		[page:AnimationClip AnimationClip] instances. Each clip represents a specific animation
+		sequence, and may be played or paused individually.
+		</p>
+
+		<code>
+		var mesh;
+
+		// Create an AnimationMixer, and get the list of AnimationClip instances
+		var mixer = new THREE.AnimationMixer( mesh );
+		var clips = mesh.animations;
+
+		// Update the mixer on each frame
+		function update () {
+			mixer.update( deltaSeconds );
+		}
+
+		// Play a specific animation
+		var clip = THREE.AnimationClip.findByName( clips, 'dance' );
+		var action = mixer.clipAction(clip);
+		action.play();
+
+		// Play all animations
+		clips.forEach( function (clip) {
+			mixer.clipAction(clip).play();
+		} );
+		</code>
+
+		<p>
+		Note that not all model formats include animation (OBJ notably does not), and that only some
+		THREE.js loaders support [page:AnimationClip AnimationClip] sequences. Several that <i>do</i>
+		support this animation type:
+		</p>
+
+		<ul>
+			<li>[page:ObjectLoader THREE.ObjectLoader]</li>
+			<li>THREE.BVHLoader</li>
+			<li>THREE.FBXLoader</li>
+			<li>THREE.FBXLoader2</li>
+			<li>[page:GLTFLoader THREE.GLTFLoader]</li>
+			<li>THREE.MMDLoader</li>
+			<li>THREE.SEA3DLoader</li>
+		</ul>
+
+		<h2>Constructor</h2>
+
+
+		<h3>[name]( [page:Object3D root] )</h3>
+
+
+		<h2>Properties</h2>
+
+
+		<h3>[property:Number time]</h3>
+
+		<h3>[property:Number timeScale]</h3>
+
+
+		<h2>Methods</h2>
+
+
+		<h3>[method:AnimationAction clipAction]([page:AnimationClip clip], [page:Object3D optionalRoot])</h3>
+		<div>
+		clip -- AnimationClip <br />
+		optionalRoot -- Object3D
+		</div>
+		<div>
+		Return an action for a clip, optionally using a custom root target object.
+		</div>
+
+		<h3>[method:AnimationAction existingAction]([page:AnimationClip clip], [page:Object3D optionalRoot])</h3>
+		<div>
+		clip -- AnimationClip <br />
+		optionalRoot -- Object3D
+		</div>
+		<div>
+		Return an existing action.
+		</div>
+
+		<h3>[method:AnimationMixer stopAllAction]()</h3>
+		<div>
+		Deactivates all scheduled actions.
+		</div>
+
+		<h3>[method:AnimationMixer update]([page:Number deltaTimeMS]) </h3>
+		<div>
+		deltaTimeMS -- Time elapsed since last update in milliseconds.
+		</div>
+		<div>
+		Updates the animation with deltaTimeMS.
+		</div>
+
+		<h3>[method:Object3D getRoot]()</h3>
+		<div>
+		Return this mixer's root target object.
+		</div>
+
+		<h3>[method:null uncacheClip]([page:AnimationClip clip])</h3>
+		<div>
+		clip -- AnimationClip
+		</div>
+		<div>
+		Free all resources for a clip.
+		</div>
+
+		<h3>[method:null uncacheRoot]([page:Object3D root]) </h3>
+		<div>
+		root -- Object3D
+		</div>
+		<div>
+		Free all resources for a root target object.
+		</div>
+
+		<h3>[method:null uncacheAction]([page:AnimationClip clip], [page:Object3D optionalRoot])</h3>
+		<div>
+		clip -- AnimationClip <br />
+		optionalRoot -- Object3D
+		</div>
+		<div>
+		Free all resources for an action.
+		</div>
+
+
+		<h2>Source</h2>
 
-    <div class="desc">
-    The AnimationMixer is a player for AnimationClip objects.
-    </div>
 
-
-    <h2>Constructor</h2>
-
-
-    <h3>[name]( [page:Object3D root] )</h3>
-
-
-    <h2>Properties</h2>
-
-
-    <h3>[property:Number time]</h3>
-
-    <h3>[property:Number timeScale]</h3>
-
-
-    <h2>Methods</h2>
-
-
-    <h3>[method:AnimationAction clipAction]([page:AnimationClip clip], [page:Object3D optionalRoot])</h3>
-    <div>
-    clip -- AnimationClip <br />
-    optionalRoot -- Object3D
-    </div>
-    <div>
-    Return an action for a clip, optionally using a custom root target object.
-    </div>
-
-    <h3>[method:AnimationAction existingAction]([page:AnimationClip clip], [page:Object3D optionalRoot])</h3>
-    <div>
-    clip -- AnimationClip <br />
-    optionalRoot -- Object3D
-    </div>
-    <div>
-    Return an existing action.
-    </div>
-
-    <h3>[method:AnimationMixer stopAllAction]()</h3>
-    <div>
-    Deactivates all scheduled actions.
-    </div>
-
-    <h3>[method:AnimationMixer update]([page:Number deltaTimeMS]) </h3>
-    <div>
-    deltaTimeMS -- Time elapsed since last update in milliseconds.
-    </div>
-    <div>
-    Updates the animation with deltaTimeMS.
-    </div>
-
-    <h3>[method:Object3D getRoot]()</h3>
-    <div>
-    Return this mixer's root target object.
-    </div>
-
-    <h3>[method:null uncacheClip]([page:AnimationClip clip])</h3>
-    <div>
-    clip -- AnimationClip
-    </div>
-    <div>
-    Free all resources for a clip.
-    </div>
-
-    <h3>[method:null uncacheRoot]([page:Object3D root]) </h3>
-    <div>
-    root -- Object3D
-    </div>
-    <div>
-    Free all resources for a root target object.
-    </div>
-
-    <h3>[method:null uncacheAction]([page:AnimationClip clip], [page:Object3D optionalRoot])</h3>
-    <div>
-    clip -- AnimationClip <br />
-    optionalRoot -- Object3D
-    </div>
-    <div>
-    Free all resources for an action.
-    </div>
-
-
-    <h2>Source</h2>
-
-
-    [link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
-  </body>
+		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
+	</body>
 </html>

+ 7 - 0
docs/api/extras/core/Font.html

@@ -16,6 +16,13 @@
 		This is used internally by the [page:FontLoader].
 		</div>
 
+		<h2>Examples</h2>
+
+		<div>
+		[example:webgl_geometry_text_shapes geometry / text / shapes ]<br/>
+		[example:webgl_shaders_vector vector / text ]<br/>
+		</div>
+
 		<h2>Constructor</h2>
 
 		<h3>[name]( data )</h3>

+ 26 - 4
docs/api/geometries/TextGeometry.html

@@ -12,7 +12,11 @@
 
 		<h1>[name]</h1>
 
-		<div class="desc">This object creates a 3D object of text as a single object.</div>
+		<div class="desc">
+			A class for generating text as a single geometry. It is constructed by providing a string of text, and a hash of 
+			parameters consisting of a loaded [page:Font] and settings for the geometry's parent [page:ExtrudeGeometry].
+			See the [page:Font], [page:FontLoader] and [page:Creating_Text] pages for additional details.
+		</div>
 
 		<iframe id="scene" src="scenes/geometry-browser.html#TextGeometry"></iframe>
 
@@ -32,13 +36,31 @@
 
 		</script>
 
-		<h2>Example</h2>
+		<h2>Examples</h2>
 
 		<div>
 		[example:webgl_geometry_text geometry / text ]<br/>
 		[example:webgl_geometry_text2 geometry / text2 ]
 		</div>
 
+		<code>
+		var loader = new THREE.FontLoader();
+		
+		loader.load( 'fonts/helvetiker_regular.typeface.json', function ( font ) {
+
+			var geometry = new THREE.TextGeometry( 'Hello three.js!', {
+				font: font,
+				size: 80,
+				height: 5,
+				curveSegments: 12,
+				bevelEnabled: true,
+				bevelThickness: 10,
+				bevelSize: 8,
+				bevelSegments: 5
+			} );
+		} );			
+		</code>
+
 		<h2>Constructor</h2>
 
 		<h3>[name]([page:String text], [page:Object parameters])</h3>
@@ -46,8 +68,8 @@
 		text — The text that needs to be shown. <br />
 		parameters — Object that can contains the following parameters.
 		<ul>
-			<li>font — THREE.Font.</li>
-			<li>size — Float. Size of the text.</li>
+			<li>font — an instance of THREE.Font.</li>
+			<li>size — Float. Size of the text. Default is 100.</li>
 			<li>height — Float. Thickness to extrude text.  Default is 50.</li>
 			<li>curveSegments — Integer. Number of points on the curves. Default is 12.</li>
 			<li>bevelEnabled — Boolean. Turn on bevel. Default is False.</li>

+ 1 - 0
docs/api/loaders/FontLoader.html

@@ -21,6 +21,7 @@
 		<h2>Examples</h2>
 
 		<div>
+		[example:webgl_geometry_text_shapes geometry / text / shapes ]<br/>
 		[example:webgl_geometry_text geometry / text ]<br />
 		[example:webgl_geometry_text_earcut geometry / text / earcut]<br />
 		[example:webgl_geometry_text_pnltri geometry / text / pnltri]<br />

+ 7 - 0
docs/api/materials/ShaderMaterial.html

@@ -234,6 +234,13 @@
 			</code>
 			</p>
 
+			<p>
+			You're recommended to update custom [page:Uniform] values depending on [page:Object3D object] and [page:Camera camera]
+			in [page:Object3D.onBeforeRender] because [page:Material] can be shared among [page:Mesh meshes], [page:Matrix4 matrixWorld]
+			of [page:Scene] and [page:Camera] are updated in [page:WebGLRenderer.render], and some effects(ex:VREffect) render a [page:Scene scene]
+			with private their own [page:Camera cameras].
+			</p>
+
 		</div>
 
 		<h2>Constructor</h2>

+ 6 - 6
docs/api/math/Line3.html

@@ -40,7 +40,7 @@
 		<h2>Methods</h2>
 
 		<h3>[method:Line3 applyMatrix4]( [page:Matrix4 matrix] )</h3>
-		<div>Apply a matrix transform to the line segment.</div>
+		<div>Applies a matrix transform to the line segment.</div>
 
 		<h3>[method:Vector3 at]( [page:Float t], [page:Vector3 optionalTarget] )</h3>
 		<div>
@@ -48,12 +48,12 @@
 		[page:Vector3 optionalTarget] - (optional) if specified, the result will be copied into this [page:Vector3],
 		otherwise a new [page:Vector3] will be created.<br /><br />
 
-		Return a vector at a certain position along the line. When [page:Float t] = 0, it returns the start vector,
+		Returns a vector at a certain position along the line. When [page:Float t] = 0, it returns the start vector,
 		and when [page:Float t] = 1 it returns the end vector.<br />
 		</div>
 
 		<h3>[method:Line3 clone]()</h3>
-		<div>Return a new [page:Line3] with the same [page:.start start] and [page:.end end] vectors as this one.</div>
+		<div>Returns a new [page:Line3] with the same [page:.start start] and [page:.end end] vectors as this one.</div>
 
 		<h3>[method:Vector3 closestPointToPoint]( [page:Vector3 point], [page:Boolean clampToLine], [page:Vector3 optionalTarget] )</h3>
 		<div>
@@ -72,7 +72,7 @@
 		[page:Boolean clampToLine] - Whether to clamp the result to the range [0, 1].<br /><br />
 
 		Returns a point parameter based on the closest point as projected on the line segement.
-		If clamp to line is true, then the returned value will be between 0 and 1.
+		If [page:Boolean clampToLine] is true, then the returned value will be between 0 and 1.
 		</div>
 
 		<h3>[method:Line3 copy]( [page:Line3 line] )</h3>
@@ -109,13 +109,13 @@
 			[page:Vector3 optionalTarget] - (optional) if specified, the result will be copied into this [page:Vector3],
 			otherwise a new [page:Vector3] will be created.<br /><br />
 
-		Return the center of the line segment.
+		Returns the center of the line segment.
 		</div>
 
 		<h3>[method:Line3 set]( [page:Vector3 start], [page:Vector3 end] )</h3>
 		<div>
 		[page:Vector3 start] - set the [page:.start start point] of the line.<br />
-		end - [page:Vector3] - set the [page:.end end point] of the line.<br /><br />
+		[page:Vector3 end] - set the [page:.end end point] of the line.<br /><br />
 
 		Sets the start and end values by copying the provided vectors.
 		</div>

+ 4 - 4
docs/api/math/Math.html

@@ -30,7 +30,7 @@
 		<div>
 		[page:Integer n], [page:Integer m] - Integers<br /><br />
 
-		Compute the Euclidean modulo of m % [page:Integer n], that is:
+		Computes the Euclidean modulo of [page:Integer m] % [page:Integer n], that is:
 		<code>( ( n % m ) + m ) % m</code>
 		</div>
 
@@ -71,10 +71,10 @@
 		</div>
 
 		<h3>[method:Integer nearestPowerOfTwo]( [page:Number n] )</h3>
-		<div>	Return the nearest power of 2 to a given number [page:Number n].</div>
+		<div>	Returns the nearest power of 2 to a given number [page:Number n].</div>
 
 		<h3>[method:Integer nextPowerOfTwo]( [page:Number n] )</h3>
-		<div>Return the nearest power of 2 that is bigger than [page:Number n].</div>
+		<div>Returns the nearest power of 2 that is bigger than [page:Number n].</div>
 
 		<h3>[method:Float radToDeg]( [page:Float radians] )</h3>
 		<div>Converts radians to degrees.</div>
@@ -83,7 +83,7 @@
 		<div>Random float in the interval [page:Float low] to [page:Float high].</div>
 
 		<h3>[method:Float randFloatSpread]( [page:Float range] )</h3>
-		<div>Random float in the intercal *- [page:Float range] / 2* to *[page:Float range] / 2*.</div>
+		<div>Random float in the interval *- [page:Float range] / 2* to *[page:Float range] / 2*.</div>
 
 		<h3>[method:Integer randInt]( [page:Integer low], [page:Integer high] )</h3>
 		<div>Random integer in the interval [page:Float low] to [page:Float high].</div>

+ 6 - 6
docs/api/math/Quaternion.html

@@ -89,7 +89,7 @@
 
 		<h3>[method:Float dot]( [page:Quaternion v] )</h3>
 		<div>
-			Calculate the [link:https://en.wikipedia.org/wiki/Dot_product dot product] of
+			Calculates the [link:https://en.wikipedia.org/wiki/Dot_product dot product] of
 			quaternions [page:Quaternion v] and this one.
 		</div>
 
@@ -137,11 +137,11 @@
 		</div>
 
 		<h3>[method:Quaternion onChange]( [page:Function onChangeCallback] )</h3>
-		<div>Set the [page:.onChangeCallback onChangeCallback]() method.</div>
+		<div>Sets the [page:.onChangeCallback onChangeCallback]() method.</div>
 
 		<h3>[method:Quaternion onChangeCallback]( )</h3>
 		<div>
-			This function is called whenever and of the following occur:
+			This function is called whenever any of the following occurs:
 			<ul>
 				<li>
 					The [page:.x x], [page:.y y], [page:.z z] or
@@ -188,7 +188,7 @@
 		<div>
 		Sets this quaternion from rotation specified by [page:Vector3 axis] and [page:Float angle].<br />
 		Adapted from the method [link:http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm here].<br />
-		*Axis* is asumed to be normalized, *angle* is in radians.
+		*Axis* is assumed to be normalized, *angle* is in radians.
 		</div>
 
 		<h3>[method:Quaternion setFromEuler]( [page:Euler euler] )</h3>
@@ -210,8 +210,8 @@
 
 		<h3>[method:Array toArray]( [page:Array array], [page:Integer offset] )</h3>
 		<div>
-		[page:Array array] - An optional array to store the quaternion. If not specified a new array will be created.<br/>
-		[page:Integer offset] - optional) if specified, the result will be copied
+		[page:Array array] - An optional array to store the quaternion. If not specified, a new array will be created.<br/>
+		[page:Integer offset] - (optional) if specified, the result will be copied
 		into this [page:Array].<br /><br />
 
 		Returns the numerical elements of this quaternion in an array of format [x, y, z, w].

+ 20 - 21
docs/api/math/Vector2.html

@@ -54,7 +54,7 @@
 		[page:Float x] - the x value of the vector. Default is *0*.<br />
 		[page:Float y] -  the y value of the vector. Default is *0*.<br /><br />
 
-		Created a new [name].
+		Creates a new [name].
 		</div>
 
 
@@ -64,7 +64,7 @@
 		<div>
 			Used to check whether this or derived classes are Vector2s. Default is *true*.<br /><br />
 
-			You should not change this, as it used internally for optimisation.
+			You should not change this, as it is used internally for optimisation.
 		</div>
 
 		<h3>[property:Float height]</h3>
@@ -84,7 +84,7 @@
 		<div>Adds [page:Vector2 v] to this vector.</div>
 
 		<h3>[method:Vector2 addScalar]( [page:Float s] )</h3>
-		<div>Add the scalar value s to this vector's [page:.x x] and [page:.y y] values.</div>
+		<div>Adds the scalar value [page:Float s] to this vector's [page:.x x] and [page:.y y] values.</div>
 
 		<h3>[method:Vector2 addScaledVector]( [page:Vector2 v], [page:Float s] )</h3>
 		<div>Adds the multiple of [page:Vector2 v] and [page:Float s] to this vector.</div>
@@ -131,13 +131,13 @@
 
 		<h3>[method:Vector2 clone]()</h3>
 		<div>
-		Returns a new vector2 with the same [page:.x x] and [page:.y y] values as this one.
+		Returns a new Vector2 with the same [page:.x x] and [page:.y y] values as this one.
 		</div>
 
 		<h3>[method:Vector2 copy]( [page:Vector2 v] )</h3>
 		<div>
-			Copies the values of the passed vector2's [page:.x x] and [page:.y y]
-			properties to this vector2.
+			Copies the values of the passed Vector2's [page:.x x] and [page:.y y]
+			properties to this Vector2.
 		</div>
 
 		<h3>[method:Float distanceTo]( [page:Vector2 v] )</h3>
@@ -166,7 +166,7 @@
 
 		<h3>[method:Float dot]( [page:Vector2 v] )</h3>
 		<div>
-		Calculate the [link:https://en.wikipedia.org/wiki/Dot_product dot product] of this
+		Calculates the [link:https://en.wikipedia.org/wiki/Dot_product dot product] of this
 	  vector and [page:Vector2 v].
 		</div>
 
@@ -179,9 +179,9 @@
 		<h3>[method:Vector2 fromArray]( [page:Array array], [page:Integer offset] )</h3>
 		<div>
 		[page:Array array] - the source array.<br />
-		[page:Integer offset] - ( optional) offset into the array. Default is 0.<br /><br />
+		[page:Integer offset] - (optional) offset into the array. Default is 0.<br /><br />
 
-		Sets this vector's [page:.x x] value to be array[0] and [page:.y y] value to be array[1].
+		Sets this vector's [page:.x x] value to be array[ offset ] and [page:.y y] value to be array[ offset + 1 ].
 		</div>
 
 		<h3>[method:Vector2 fromBufferAttribute]( [page:BufferAttribute attribute], [page:Integer index] )</h3>
@@ -221,7 +221,7 @@
 		[page:Vector2 v] - [page:Vector2] to interpolate towards.<br />
 		alpha - interpolation factor in the closed interval [0, 1].<br /><br />
 
-		Linearly interpolate between this vector and [page:Vector2 v], where alpha is the
+		Linearly interpolates between this vector and [page:Vector2 v], where alpha is the
 		distance along the line - alpha = 0 will be this vector, and alpha = 1 will be [page:Vector2 v].
 		</div>
 
@@ -241,19 +241,19 @@
 
 		<h3>[method:Vector2 normalize]()</h3>
 		<div>
-		Convert this vector to a [link:https://en.wikipedia.org/wiki/Unit_vector unit vector] - that is, sets it equal to the vector with the same direction
+		Converts this vector to a [link:https://en.wikipedia.org/wiki/Unit_vector unit vector] - that is, sets it equal to the vector with the same direction
 		as this one, but [page:.length length] 1.
 		</div>
 
 		<h3>[method:Vector2 max]( [page:Vector2 v] )</h3>
 		<div>
-		If this vector's x or y value is less than [page:Vector2 v's] x or y value, replace
+		If this vector's x or y value is less than [page:Vector2 v]'s x or y value, replace
 		that value with the corresponding max value.
 		</div>
 
 		<h3>[method:Vector2 min]( [page:Vector2 v] )</h3>
 		<div>
-		If this vector's x or y value is greater than [page:Vector2 v's] x or y value, replace
+		If this vector's x or y value is greater than [page:Vector2 v]'s x or y value, replace
 		that value with the corresponding min value.
 		</div>
 
@@ -269,7 +269,7 @@
 			[page:Vector2 center] - the point around which to rotate.<br />
 			[page:float angle] - the angle to rotate, in radians.<br /><br />
 
-			Rotate the vector arounf [page:Vector2 center] by [page:float angle] radians.
+			Rotates the vector around [page:Vector2 center] by [page:float angle] radians.
 		</div>
 
 		<h3>[method:Vector2 round]()</h3>
@@ -294,34 +294,33 @@
 
 		<h3>[method:Vector2 setLength]( [page:Float l] )</h3>
 		<div>
-		Set this vector to the vector with the same direction as this one, but [page:.length length]
+		Sets this vector to the vector with the same direction as this one, but [page:.length length]
 		[page:Float l].
 		</div>
 
 		<h3>[method:Vector2 setScalar]( [page:Float scalar] )</h3>
 		<div>
-		Set the [page:.x x] and [page:.y y] values of this vector both equal to [page:Float scalar].
+		Sets the [page:.x x] and [page:.y y] values of this vector both equal to [page:Float scalar].
 		</div>
 
 		<h3>[method:Vector2 setX]( [page:Float x] )</h3>
-		<div>Replace this vector's [page:.x x] value with [page:Float x].</div>
+		<div>Replaces this vector's [page:.x x] value with [page:Float x].</div>
 
 		<h3>[method:Vector2 setY]( [page:Float y] )</h3>
-		<div>Replace this vector's [page:.y y] value with [page:Float y].</div>
+		<div>Replaces this vector's [page:.y y] value with [page:Float y].</div>
 
 		<h3>[method:Vector2 sub]( [page:Vector2 v] )</h3>
 		<div>Subtracts [page:Vector2 v] from this vector.</div>
 
 		<h3>[method:Vector2 subScalar]( [page:Float s] )</h3>
-		<div>Subtracts [page:Float s]  from this vector's [page:.x x] and [page:.y y] compnents.</div>
+		<div>Subtracts [page:Float s]  from this vector's [page:.x x] and [page:.y y] components.</div>
 
 		<h3>[method:Vector2 subVectors]( [page:Vector2 a], [page:Vector2 b] )</h3>
 		<div>Sets this vector to [page:Vector2 a] - [page:Vector2 b].</div>
 
 		<h3>[method:Array toArray]( [page:Array array], [page:Integer offset] )</h3>
 		<div>
-		[page:Array array] - (optional) array to store the vector to. If this is not provided
-		a new array will be created.<br />
+		[page:Array array] - (optional) array to store the vector to. If this is not provided, a new array will be created.<br />
 		[page:Integer offset] - (optional) optional offset into the array.<br /><br />
 
 		Returns an array [x, y], or copies x and y into the provided [page:Array array].

+ 5 - 5
docs/api/math/Vector3.html

@@ -65,7 +65,7 @@ var d = a.distanceTo( b );
 		<div>
 			Used to check whether this or derived classes are Vector3s. Default is *true*.<br /><br />
 
-			You should not change this, as it used internally for optimisation.
+			You should not change this, as it is used internally for optimisation.
 		</div>
 
 		<h3>[property:Float x]</h3>
@@ -81,7 +81,7 @@ var d = a.distanceTo( b );
 		<div>Adds [page:Vector3 v] to this vector.</div>
 
 		<h3>[method:Vector3 addScalar]( [page:Float s] )</h3>
-		<div>Add the scalar value s to this vector's [page:.x x], [page:.y y] and [page:.z z] values.</div>
+		<div>Adds the scalar value s to this vector's [page:.x x], [page:.y y] and [page:.z z] values.</div>
 
 		<h3>[method:Vector3 addScaledVector]( [page:Vector3 v], [page:Float s] )</h3>
 		<div>Adds the multiple of [page:Vector3 v] and [page:Float s] to this vector.</div>
@@ -104,7 +104,7 @@ var d = a.distanceTo( b );
 		</div>
 
 		<h3>[method:Vector3 applyMatrix3]( [page:Matrix3 m] )</h3>
-		<div>Multiply this vector by [page:Matrix3 m]</div>
+		<div>Multiplies this vector by [page:Matrix3 m]</div>
 
 		<h3>[method:Vector3 applyMatrix4]( [page:Matrix4 m] )</h3>
 		<div>
@@ -284,13 +284,13 @@ var d = a.distanceTo( b );
 
 		<h3>[method:Vector3 max]( [page:Vector3 v] )</h3>
 		<div>
-		If this vector's x, y or z value is less than [page:Vector3 v's] x, y or z value, replace
+		If this vector's x, y or z value is less than [page:Vector3 v]'s x, y or z value, replace
 		that value with the corresponding max value.
 		</div>
 
 		<h3>[method:Vector3 min]( [page:Vector3 v] )</h3>
 		<div>
-		If this vector's x, y or z value is greater than [page:Vector3 v's] x, y or z value, replace
+		If this vector's x, y or z value is greater than [page:Vector3 v]'s x, y or z value, replace
 		that value with the corresponding min value.
 		</div>
 

+ 18 - 19
docs/api/math/Vector4.html

@@ -22,7 +22,7 @@
 			<li>
 				A direction and length in 4D space. In three.js the length will always be the
 				[link:https://en.wikipedia.org/wiki/Euclidean_distance Euclidean distance]
-				(straight-line distance) from (0, 0, 0, 0, 0) to (x, y, z, w) and the direction is also
+				(straight-line distance) from (0, 0, 0, 0) to (x, y, z, w) and the direction is also
 				measured from (0, 0, 0, 0) towards (x, y, z, w).
 			</li>
 			<li>
@@ -42,7 +42,7 @@ var a = new THREE.Vector4( 0, 1, 0, 0 );
 //no arguments; will be initialised to (0, 0, 0, 1)
 var b = new THREE.Vector4( );
 
-var d = a.distanceTo( b );
+var d = a.dot( b );
 		</code>
 
 
@@ -65,7 +65,7 @@ var d = a.distanceTo( b );
 		<div>
 			Used to check whether this or derived classes are Vector4s. Default is *true*.<br /><br />
 
-			You should not change this, as it used internally for optimisation.
+			You should not change this, as it is used internally for optimisation.
 		</div>
 
 		<h3>[property:Float x]</h3>
@@ -83,7 +83,7 @@ var d = a.distanceTo( b );
 		<div>Adds [page:Vector4 v] to this vector.</div>
 
 		<h3>[method:Vector4 addScalar]( [page:Float s] )</h3>
-		<div>Add the scalar value s to this vector's [page:.x x], [page:.y y], [page:.z z] and [page:.w w] values.</div>
+		<div>Adds the scalar value s to this vector's [page:.x x], [page:.y y], [page:.z z] and [page:.w w] values.</div>
 
 		<h3>[method:Vector4 addScaledVector]( [page:Vector4 v], [page:Float s] )</h3>
 		<div>Adds the multiple of [page:Vector4 v] and [page:Float s] to this vector.</div>
@@ -93,7 +93,7 @@ var d = a.distanceTo( b );
 
 		<h3>[method:Vector4 applyMatrix4]( [page:Matrix4 m] )</h3>
 		<div>
-		Multiply this vector by 4 x 4 [page:Matrix4 m].
+		Multiplies this vector by 4 x 4 [page:Matrix4 m].
 		</div>
 
 		<h3>[method:Vector4 ceil]()</h3>
@@ -138,7 +138,7 @@ var d = a.distanceTo( b );
 
 		<h3>[method:Float dot]( [page:Vector4 v] )</h3>
 		<div>
-		Calculate the [link:https://en.wikipedia.org/wiki/Dot_product dot product] of this
+		Calculates the [link:https://en.wikipedia.org/wiki/Dot_product dot product] of this
 		vector and [page:Vector4 v].
 		</div>
 
@@ -151,7 +151,7 @@ var d = a.distanceTo( b );
 		<h3>[method:Vector4 fromArray]( [page:Array array], [page:Integer offset] )</h3>
 		<div>
 		[page:Array array] - the source array.<br />
-		[page:Integer offset] - ( optional) offset into the array. Default is 0.<br /><br />
+		[page:Integer offset] - (optional) offset into the array. Default is 0.<br /><br />
 
 		Sets this vector's [page:.x x] value to be array[ offset + 0 ], [page:.y y] value to be array[ offset + 1 ]
 		[page:.z z] value to be array[ offset + 2 ] and [page:.w w ] value to be array[ offset + 3 ].
@@ -196,7 +196,7 @@ var d = a.distanceTo( b );
 		[page:Vector4 v] - [page:Vector4] to interpolate towards.<br />
 		alpha - interpolation factor in the closed interval [0, 1].<br /><br />
 
-		Linearly interpolate between this vector and [page:Vector4 v], where alpha is the
+		Linearly interpolates between this vector and [page:Vector4 v], where alpha is the
 		distance along the line - alpha = 0 will be this vector, and alpha = 1 will be [page:Vector4 v].
 		</div>
 
@@ -216,7 +216,7 @@ var d = a.distanceTo( b );
 
 		<h3>[method:Vector4 normalize]()</h3>
 		<div>
-		Convert this vector to a [link:https://en.wikipedia.org/wiki/Unit_vector unit vector] - that is, sets it equal to the vector with the same direction
+		Converts this vector to a [link:https://en.wikipedia.org/wiki/Unit_vector unit vector] - that is, sets it equal to the vector with the same direction
 		as this one, but [page:.length length] 1.
 		</div>
 
@@ -250,7 +250,7 @@ var d = a.distanceTo( b );
 		<div>
 			[page:Quaterion q] - a normalized [page:Quaterion]<br /><br />
 
-			Set the [page:.x x], [page:.y y] and [page:.z z] components of this vector to the
+			Sets the [page:.x x], [page:.y y] and [page:.z z] components of this vector to the
 			quaternion's axis and [page:.w w] to the angle.
 		</div>
 
@@ -258,7 +258,7 @@ var d = a.distanceTo( b );
 		<div>
 			 [page:Matrix4 m] - a [page:Matrix4] of which the upper left 3x3 matrix is a pure rotation matrix.<br /><br />
 
-			Set the [page:.x x], [page:.y y] and [page:.z z] to the axis of rotation and [page:.w w] to the angle.
+			Sets the [page:.x x], [page:.y y] and [page:.z z] to the axis of rotation and [page:.w w] to the angle.
 		</div>
 
 		<h3>[method:null setComponent]( [page:Integer index], [page:Float value] )</h3>
@@ -275,26 +275,26 @@ var d = a.distanceTo( b );
 
 		<h3>[method:Vector4 setLength]( [page:Float l] )</h3>
 		<div>
-		Set this vector to the vector with the same direction as this one, but [page:.length length]
+		Sets this vector to the vector with the same direction as this one, but [page:.length length]
 		[page:Float l].
 		</div>
 
 		<h3>[method:Vector4 setScalar]( [page:Float scalar] )</h3>
 		<div>
-		Set the [page:.x x], [page:.y y], [page:.z z] and [page:.w w] values of this vector both equal to [page:Float scalar].
+		Sets the [page:.x x], [page:.y y], [page:.z z] and [page:.w w] values of this vector both equal to [page:Float scalar].
 		</div>
 
 		<h3>[method:Vector4 setX]( [page:Float x] )</h3>
-		<div>Replace this vector's [page:.x x] value with [page:Float x].</div>
+		<div>Replaces this vector's [page:.x x] value with [page:Float x].</div>
 
 		<h3>[method:Vector4 setY]( [page:Float y] )</h3>
-		<div>Replace this vector's [page:.y y] value with [page:Float y].</div>
+		<div>Replaces this vector's [page:.y y] value with [page:Float y].</div>
 
 		<h3>[method:Vector4 setZ]( [page:Float z] )</h3>
-		<div>Replace this vector's [page:.z z] value with [page:Float z].</div>
+		<div>Replaces this vector's [page:.z z] value with [page:Float z].</div>
 
 		<h3>[method:Vector4 setW]( [page:Float w] )</h3>
-		<div>Replace this vector's [page:.w w] value with [page:Float w].</div>
+		<div>Replaces this vector's [page:.w w] value with [page:Float w].</div>
 
 		<h3>[method:Vector4 sub]( [page:Vector4 v] )</h3>
 		<div>Subtracts [page:Vector4 v] from this vector.</div>
@@ -307,8 +307,7 @@ var d = a.distanceTo( b );
 
 		<h3>[method:Array toArray]( [page:Array array], [page:Integer offset] )</h3>
 		<div>
-		[page:Array array] - (optional) array to store the vector to. If this is not provided
-		a new array will be created.<br />
+		[page:Array array] - (optional) array to store the vector to. If this is not provided, a new array will be created.<br />
 		[page:Integer offset] - (optional) optional offset into the array.<br /><br />
 
 		Returns an array [x, y, z, w], or copies x, y, z and w into the provided [page:Array array].

+ 10 - 10
docs/examples/loaders/GLTFLoader.html

@@ -26,18 +26,18 @@
 		<h2>Example</h2>
 
 		<code>
-		// instantiate a loader
+		// Instantiate a loader
 		var loader = new THREE.GLTFLoader();
 
-		// load a glTF resource
-		loader.load(
-			// resource URL
-			'models/gltf/duck/duck.json',
-			// Function when resource is loaded
-			function ( object ) {
-				scene.add( object.scene );
-			}
-		);
+		// Load a glTF resource
+		loader.load( 'models/gltf/duck/duck.gltf', function ( gltf ) {
+			scene.add( gltf.scene );
+
+			gltf.animations; // Array&lt;THREE.AnimationClip&gt;
+			gltf.scene;      // THREE.Scene
+			gltf.scenes;     // Array&lt;THREE.Scene&gt;
+			gltf.cameras;    // Array&lt;THREE.Camera&gt;
+		} );
 		</code>
 
 		[example:webgl_loader_gltf]

+ 12 - 6
docs/manual/introduction/Creating-text.html

@@ -61,13 +61,19 @@
 		<h2>4. Procedural Text Geometry</h2>
 		<div>
 			<p>
-				Use this method if you prefer to work purely in three.js or create procedural and dynamic 3d
-				text geometries. However, font data files in THREE.js JSON format need to be loaded
-				before this will work.
-				See the [page:TextGeometry] page for examples of JSON fonts.
+				If you prefer to work purely in THREE.js or to create procedural and dynamic 3D
+				text geometries, you can create a mesh whose geometry is an instance of THREE.TextGeometry:
+			</p>
+			<p>
+				<code>new THREE.TextGeometry( text, parameters );</code>
+			</p>
+			<p>
+				In order for this to work, however, your TextGeomety will need an instance of THREE.Font 
+				to be set on its "font" parameter.
+
+				See the [page:TextGeometry] page for more info on how this can be done, descriptions of each
+				accepted parameter, and a list of the JSON fonts that come with the THREE.js distribution itself.
 			</p>
-			<p>A Text Geometry can then be created with </p>
-			<code>new THREE.TextGeometry( text, parameters );</code>
 
 			<h3>Examples</h3>
 			[example:webgl_geometry_text WebGL / geometry / text]<br />

+ 2 - 2
docs/scenes/js/geometry.js

@@ -744,7 +744,7 @@ var guis = {
 
 		var folder = gui.addFolder( 'THREE.RingBufferGeometry' );
 
-		folder.add( data, 'innerRadius', 0, 30 ).onChange( generateGeometry );
+		folder.add( data, 'innerRadius', 1, 30 ).onChange( generateGeometry );
 		folder.add( data, 'outerRadius', 1, 30 ).onChange( generateGeometry );
 		folder.add( data, 'thetaSegments', 1, 30 ).step( 1 ).onChange( generateGeometry );
 		folder.add( data, 'phiSegments', 1, 30 ).step( 1 ).onChange( generateGeometry );
@@ -778,7 +778,7 @@ var guis = {
 
 		var folder = gui.addFolder( 'THREE.RingGeometry' );
 
-		folder.add( data, 'innerRadius', 0, 30 ).onChange( generateGeometry );
+		folder.add( data, 'innerRadius', 1, 30 ).onChange( generateGeometry );
 		folder.add( data, 'outerRadius', 1, 30 ).onChange( generateGeometry );
 		folder.add( data, 'thetaSegments', 1, 30 ).step( 1 ).onChange( generateGeometry );
 		folder.add( data, 'phiSegments', 1, 30 ).step( 1 ).onChange( generateGeometry );

+ 18 - 0
editor/js/Sidebar.Animation.js

@@ -27,6 +27,24 @@ Sidebar.Animation = function ( editor ) {
 
 		object.traverse( function ( child ) {
 
+			if ( child instanceof THREE.SkinnedMesh ) {
+
+				var material = child.material;
+
+				if ( material instanceof THREE.MultiMaterial ) {
+
+					for ( var i = 0; i < material.materials.length; i ++ ) {
+
+						material.materials[ i ].skinning = true;
+
+					}
+
+				} else {
+
+					child.material.skinning = true;
+
+				}
+
 				animations[ child.id ] = new THREE.Animation( child, child.geometry.animation );
 
 			} else if ( child instanceof THREE.MorphAnimMesh ) {

+ 23 - 0
editor/js/Sidebar.Material.js

@@ -229,6 +229,16 @@ Sidebar.Material = function ( editor ) {
 
 	container.add( materialVertexColorsRow );
 
+	// skinning
+
+	var materialSkinningRow = new UI.Row();
+	var materialSkinning = new UI.Checkbox( false ).onChange( update );
+
+	materialSkinningRow.add( new UI.Text( 'Skinning' ).setWidth( '90px' ) );
+	materialSkinningRow.add( materialSkinning );
+
+	container.add( materialSkinningRow );
+
 	// map
 
 	var materialMapRow = new UI.Row();
@@ -571,6 +581,12 @@ Sidebar.Material = function ( editor ) {
 
 			}
 
+			if ( material.skinning !== undefined && material.skinning !== materialSkinning.getValue() ) {
+
+				editor.execute( new SetMaterialValueCommand( currentObject, 'skinning', materialSkinning.getValue() ) );
+
+			}
+
 			if ( material.map !== undefined ) {
 
 				var mapEnabled = materialMapEnabled.getValue() === true;
@@ -938,6 +954,7 @@ Sidebar.Material = function ( editor ) {
 			'clearCoatRoughness': materialClearCoatRoughnessRow,
 			'vertexShader': materialProgramRow,
 			'vertexColors': materialVertexColorsRow,
+			'skinning': materialSkinningRow,
 			'map': materialMapRow,
 			'alphaMap': materialAlphaMapRow,
 			'bumpMap': materialBumpMapRow,
@@ -1044,6 +1061,12 @@ Sidebar.Material = function ( editor ) {
 
 		}
 
+		if ( material.skinning !== undefined ) {
+
+			materialSkinning.setValue( material.skinning );
+
+		}
+
 		if ( material.map !== undefined ) {
 
 			materialMapEnabled.setValue( material.map !== null );

+ 1 - 1
examples/canvas_geometry_panorama.html

@@ -81,7 +81,7 @@
 
 				];
 
-				mesh = new THREE.Mesh( new THREE.BoxGeometry( 300, 300, 300, 7, 7, 7 ), new THREE.MultiMaterial( materials ) );
+				mesh = new THREE.Mesh( new THREE.BoxGeometry( 300, 300, 300, 7, 7, 7 ), materials );
 				mesh.scale.x = - 1;
 				scene.add( mesh );
 

+ 1 - 1
examples/canvas_geometry_panorama_fisheye.html

@@ -81,7 +81,7 @@
 
 				];
 
-				mesh = new THREE.Mesh( new THREE.BoxGeometry( 300, 300, 300, 7, 7, 7 ), new THREE.MultiMaterial( materials ) );
+				mesh = new THREE.Mesh( new THREE.BoxGeometry( 300, 300, 300, 7, 7, 7 ), materials );
 				mesh.scale.x = - 1;
 				scene.add( mesh );
 

+ 3 - 3
examples/canvas_geometry_text.html

@@ -92,12 +92,12 @@
 
 				var centerOffset = -0.5 * ( geometry.boundingBox.max.x - geometry.boundingBox.min.x );
 
-				var material = new THREE.MultiMaterial( [
+				var materials = [
 					new THREE.MeshBasicMaterial( { color: Math.random() * 0xffffff, overdraw: 0.5 } ),
 					new THREE.MeshBasicMaterial( { color: 0x000000, overdraw: 0.5 } )
-				] );
+				];
 
-				var mesh = new THREE.Mesh( geometry, material );
+				var mesh = new THREE.Mesh( geometry, materials );
 
 				mesh.position.x = centerOffset;
 				mesh.position.y = 100;

+ 1 - 1
examples/canvas_materials.html

@@ -93,7 +93,7 @@
 
 				}
 
-				materials.push( new THREE.MultiMaterial( materials ) );
+				materials.push( materials );
 
 				objects = [];
 

+ 6 - 2
examples/js/BlendCharacter.js

@@ -36,6 +36,8 @@ THREE.BlendCharacter = function () {
 
 			}
 
+			scope.material.skinning = true;
+
 			scope.mixer = new THREE.AnimationMixer( scope );
 
 			// Create the animations
@@ -57,9 +59,10 @@ THREE.BlendCharacter = function () {
 		var scope = this;
 
 		var loader = new THREE.JSONLoader();
-		loader.load( url, function ( geometry, materials ) {
+		loader.load( url, function( geometry, materials ) {
 
 			var originalMaterial = materials[ 0 ];
+			originalMaterial.skinning = true;
 
 			THREE.SkinnedMesh.call( scope, geometry, originalMaterial );
 
@@ -79,7 +82,7 @@ THREE.BlendCharacter = function () {
 		} );
 
 	};
-
+	
 	this.update = function( dt ) {
 
 		this.mixer.update( dt );
@@ -176,3 +179,4 @@ THREE.BlendCharacter.prototype.getForward = function() {
 	}
 
 };
+

+ 2 - 2
examples/js/Car.js

@@ -299,8 +299,8 @@ THREE.Car = function () {
 			var s = scope.modelScale,
 				delta = new THREE.Vector3();
 
-			var bodyFaceMaterial = new THREE.MultiMaterial( scope.bodyMaterials );
-			var wheelFaceMaterial = new THREE.MultiMaterial( scope.wheelMaterials );
+			var bodyFaceMaterial = scope.bodyMaterials;
+			var wheelFaceMaterial = scope.wheelMaterials;
 
 			// body
 

+ 84 - 162
examples/js/Mirror.js

@@ -2,52 +2,50 @@
  * @author Slayvin / http://slayvin.net
  */
 
-THREE.Mirror = function ( renderer, camera, options ) {
+THREE.Mirror = function ( width, height, options ) {
 
-	THREE.Object3D.call( this );
+	THREE.Mesh.call( this, new THREE.PlaneBufferGeometry( width, height ) );
 
-	this.name = 'mirror_' + this.id;
+	var scope = this;
 
-	options = options || {};
-
-	this.matrixNeedsUpdate = true;
+	scope.name = 'mirror_' + scope.id;
+	scope.matrixNeedsUpdate = true;
 
-	var width = options.textureWidth !== undefined ? options.textureWidth : 512;
-	var height = options.textureHeight !== undefined ? options.textureHeight : 512;
+	options = options || {};
 
-	this.clipBias = options.clipBias !== undefined ? options.clipBias : 0.0;
+	var textureWidth = options.textureWidth !== undefined ? options.textureWidth : 512;
+	var textureHeight = options.textureHeight !== undefined ? options.textureHeight : 512;
 
+	var clipBias = options.clipBias !== undefined ? options.clipBias : 0.0;
 	var mirrorColor = options.color !== undefined ? new THREE.Color( options.color ) : new THREE.Color( 0x7F7F7F );
 
-	this.renderer = renderer;
-	this.mirrorPlane = new THREE.Plane();
-	this.normal = new THREE.Vector3( 0, 0, 1 );
-	this.mirrorWorldPosition = new THREE.Vector3();
-	this.cameraWorldPosition = new THREE.Vector3();
-	this.rotationMatrix = new THREE.Matrix4();
-	this.lookAtPosition = new THREE.Vector3( 0, 0, - 1 );
-	this.clipPlane = new THREE.Vector4();
+	var mirrorPlane = new THREE.Plane();
+	var normal = new THREE.Vector3();
+	var mirrorWorldPosition = new THREE.Vector3();
+	var cameraWorldPosition = new THREE.Vector3();
+	var rotationMatrix = new THREE.Matrix4();
+	var lookAtPosition = new THREE.Vector3( 0, 0, - 1 );
+	var clipPlane = new THREE.Vector4();
 
-	if ( camera instanceof THREE.PerspectiveCamera ) {
+	var textureMatrix = new THREE.Matrix4();
 
-		this.camera = camera;
+	var mirrorCamera = new THREE.PerspectiveCamera();
+	mirrorCamera.matrixAutoUpdate = true;
 
-	} else {
-
-		this.camera = new THREE.PerspectiveCamera();
-		console.log( this.name + ': camera is not a Perspective Camera!' );
-
-	}
+	var parameters = {
+		minFilter: THREE.LinearFilter,
+		magFilter: THREE.LinearFilter,
+		format: THREE.RGBFormat,
+		stencilBuffer: false
+	};
 
-	this.textureMatrix = new THREE.Matrix4();
+	var renderTarget = new THREE.WebGLRenderTarget( textureWidth, textureHeight, parameters );
 
-	this.mirrorCamera = this.camera.clone();
-	this.mirrorCamera.matrixAutoUpdate = true;
+	if ( ! THREE.Math.isPowerOfTwo( textureWidth ) || ! THREE.Math.isPowerOfTwo( textureHeight ) ) {
 
-	var parameters = { minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter, format: THREE.RGBFormat, stencilBuffer: false };
+		renderTarget.texture.generateMipmaps = false;
 
-	this.renderTarget = new THREE.WebGLRenderTarget( width, height, parameters );
-	this.renderTarget2 = new THREE.WebGLRenderTarget( width, height, parameters );
+	}
 
 	var mirrorShader = {
 
@@ -92,7 +90,7 @@ THREE.Mirror = function ( renderer, camera, options ) {
 
 	var mirrorUniforms = THREE.UniformsUtils.clone( mirrorShader.uniforms );
 
-	this.material = new THREE.ShaderMaterial( {
+	var material = new THREE.ShaderMaterial( {
 
 		fragmentShader: mirrorShader.fragmentShader,
 		vertexShader: mirrorShader.vertexShader,
@@ -100,181 +98,105 @@ THREE.Mirror = function ( renderer, camera, options ) {
 
 	} );
 
-	this.material.uniforms.mirrorSampler.value = this.renderTarget.texture;
-	this.material.uniforms.mirrorColor.value = mirrorColor;
-	this.material.uniforms.textureMatrix.value = this.textureMatrix;
-
-	if ( ! THREE.Math.isPowerOfTwo( width ) || ! THREE.Math.isPowerOfTwo( height ) ) {
-
-		this.renderTarget.texture.generateMipmaps = false;
-		this.renderTarget2.texture.generateMipmaps = false;
-
-	}
-
-	this.updateTextureMatrix();
-	this.render();
-
-};
-
-THREE.Mirror.prototype = Object.create( THREE.Object3D.prototype );
-
-Object.assign( THREE.Mirror.prototype, {
-
-	constructor: THREE.Mirror,
-
-	renderWithMirror: function ( otherMirror ) {
-
-		// update the mirror matrix to mirror the current view
-		this.updateTextureMatrix();
-		this.matrixNeedsUpdate = false;
-
-		// set the camera of the other mirror so the mirrored view is the reference view
-		var tempCamera = otherMirror.camera;
-		otherMirror.camera = this.mirrorCamera;
-
-		// render the other mirror in temp texture
-		otherMirror.renderTemp();
-		otherMirror.material.uniforms.mirrorSampler.value = otherMirror.renderTarget2.texture;
+	material.uniforms.mirrorSampler.value = renderTarget.texture;
+	material.uniforms.mirrorColor.value = mirrorColor;
+	material.uniforms.textureMatrix.value = textureMatrix;
 
-		// render the current mirror
-		this.render();
-		this.matrixNeedsUpdate = true;
+	scope.material = material;
 
-		// restore material and camera of other mirror
-		otherMirror.material.uniforms.mirrorSampler.value = otherMirror.renderTarget.texture;
-		otherMirror.camera = tempCamera;
+	function updateTextureMatrix( camera ) {
 
-		// restore texture matrix of other mirror
-		otherMirror.updateTextureMatrix();
+		camera.updateMatrixWorld();
 
-	},
+		mirrorCamera.copy( camera );
+		mirrorCamera.updateProjectionMatrix();
 
-	updateTextureMatrix: function () {
+		scope.updateMatrixWorld();
 
-		this.updateMatrixWorld();
-		this.camera.updateMatrixWorld();
+		mirrorWorldPosition.setFromMatrixPosition( scope.matrixWorld );
+		cameraWorldPosition.setFromMatrixPosition( camera.matrixWorld );
 
-		this.mirrorWorldPosition.setFromMatrixPosition( this.matrixWorld );
-		this.cameraWorldPosition.setFromMatrixPosition( this.camera.matrixWorld );
+		rotationMatrix.extractRotation( scope.matrixWorld );
 
-		this.rotationMatrix.extractRotation( this.matrixWorld );
+		normal.set( 0, 0, 1 );
+		normal.applyMatrix4( rotationMatrix );
 
-		this.normal.set( 0, 0, 1 );
-		this.normal.applyMatrix4( this.rotationMatrix );
+		var view = mirrorWorldPosition.clone().sub( cameraWorldPosition );
+		view.reflect( normal ).negate();
+		view.add( mirrorWorldPosition );
 
-		var view = this.mirrorWorldPosition.clone().sub( this.cameraWorldPosition );
-		view.reflect( this.normal ).negate();
-		view.add( this.mirrorWorldPosition );
+		rotationMatrix.extractRotation( camera.matrixWorld );
 
-		this.rotationMatrix.extractRotation( this.camera.matrixWorld );
+		lookAtPosition.set( 0, 0, - 1 );
+		lookAtPosition.applyMatrix4( rotationMatrix );
+		lookAtPosition.add( cameraWorldPosition );
 
-		this.lookAtPosition.set( 0, 0, - 1 );
-		this.lookAtPosition.applyMatrix4( this.rotationMatrix );
-		this.lookAtPosition.add( this.cameraWorldPosition );
+		var target = mirrorWorldPosition.clone().sub( lookAtPosition );
+		target.reflect( normal ).negate();
+		target.add( mirrorWorldPosition );
 
-		var target = this.mirrorWorldPosition.clone().sub( this.lookAtPosition );
-		target.reflect( this.normal ).negate();
-		target.add( this.mirrorWorldPosition );
+		mirrorCamera.position.copy( view );
+		mirrorCamera.up.set( 0, - 1, 0 );
+		mirrorCamera.up.applyMatrix4( rotationMatrix );
+		mirrorCamera.up.reflect( normal ).negate();
+		mirrorCamera.lookAt( target );
 
-		this.up.set( 0, - 1, 0 );
-		this.up.applyMatrix4( this.rotationMatrix );
-		this.up.reflect( this.normal ).negate();
-
-		this.mirrorCamera.position.copy( view );
-		this.mirrorCamera.up = this.up;
-		this.mirrorCamera.lookAt( target );
-
-		this.mirrorCamera.updateProjectionMatrix();
-		this.mirrorCamera.updateMatrixWorld();
-		this.mirrorCamera.matrixWorldInverse.getInverse( this.mirrorCamera.matrixWorld );
+		mirrorCamera.updateProjectionMatrix();
+		mirrorCamera.updateMatrixWorld();
+		mirrorCamera.matrixWorldInverse.getInverse( mirrorCamera.matrixWorld );
 
 		// Update the texture matrix
-		this.textureMatrix.set(
+		textureMatrix.set(
 			0.5, 0.0, 0.0, 0.5,
 			0.0, 0.5, 0.0, 0.5,
 			0.0, 0.0, 0.5, 0.5,
 			0.0, 0.0, 0.0, 1.0
 		);
-		this.textureMatrix.multiply( this.mirrorCamera.projectionMatrix );
-		this.textureMatrix.multiply( this.mirrorCamera.matrixWorldInverse );
+		textureMatrix.multiply( mirrorCamera.projectionMatrix );
+		textureMatrix.multiply( mirrorCamera.matrixWorldInverse );
 
 		// Now update projection matrix with new clip plane, implementing code from: http://www.terathon.com/code/oblique.html
 		// Paper explaining this technique: http://www.terathon.com/lengyel/Lengyel-Oblique.pdf
-		this.mirrorPlane.setFromNormalAndCoplanarPoint( this.normal, this.mirrorWorldPosition );
-		this.mirrorPlane.applyMatrix4( this.mirrorCamera.matrixWorldInverse );
+		mirrorPlane.setFromNormalAndCoplanarPoint( normal, mirrorWorldPosition );
+		mirrorPlane.applyMatrix4( mirrorCamera.matrixWorldInverse );
 
-		this.clipPlane.set( this.mirrorPlane.normal.x, this.mirrorPlane.normal.y, this.mirrorPlane.normal.z, this.mirrorPlane.constant );
+		clipPlane.set( mirrorPlane.normal.x, mirrorPlane.normal.y, mirrorPlane.normal.z, mirrorPlane.constant );
 
 		var q = new THREE.Vector4();
-		var projectionMatrix = this.mirrorCamera.projectionMatrix;
+		var projectionMatrix = mirrorCamera.projectionMatrix;
 
-		q.x = ( Math.sign( this.clipPlane.x ) + projectionMatrix.elements[ 8 ] ) / projectionMatrix.elements[ 0 ];
-		q.y = ( Math.sign( this.clipPlane.y ) + projectionMatrix.elements[ 9 ] ) / projectionMatrix.elements[ 5 ];
+		q.x = ( Math.sign( clipPlane.x ) + projectionMatrix.elements[ 8 ] ) / projectionMatrix.elements[ 0 ];
+		q.y = ( Math.sign( clipPlane.y ) + projectionMatrix.elements[ 9 ] ) / projectionMatrix.elements[ 5 ];
 		q.z = - 1.0;
 		q.w = ( 1.0 + projectionMatrix.elements[ 10 ] ) / projectionMatrix.elements[ 14 ];
 
 		// Calculate the scaled plane vector
 		var c = new THREE.Vector4();
-		c = this.clipPlane.multiplyScalar( 2.0 / this.clipPlane.dot( q ) );
+		c = clipPlane.multiplyScalar( 2.0 / clipPlane.dot( q ) );
 
 		// Replacing the third row of the projection matrix
 		projectionMatrix.elements[ 2 ] = c.x;
 		projectionMatrix.elements[ 6 ] = c.y;
-		projectionMatrix.elements[ 10 ] = c.z + 1.0 - this.clipBias;
+		projectionMatrix.elements[ 10 ] = c.z + 1.0 - clipBias;
 		projectionMatrix.elements[ 14 ] = c.w;
 
-	},
-
-	render: function () {
-
-		if ( this.matrixNeedsUpdate ) this.updateTextureMatrix();
-
-		this.matrixNeedsUpdate = true;
-
-		// Render the mirrored view of the current scene into the target texture
-		var scene = this;
-
-		while ( scene.parent !== null ) {
-
-			scene = scene.parent;
-
-		}
-
-		if ( scene !== undefined && scene instanceof THREE.Scene ) {
-
-			// We can't render ourself to ourself
-			var visible = this.material.visible;
-			this.material.visible = false;
-
-			this.renderer.render( scene, this.mirrorCamera, this.renderTarget, true );
-
-			this.material.visible = visible;
-
-		}
-
-	},
-
-	renderTemp: function () {
-
-		if ( this.matrixNeedsUpdate ) this.updateTextureMatrix();
-
-		this.matrixNeedsUpdate = true;
+	}
 
-		// Render the mirrored view of the current scene into the target texture
-		var scene = this;
+	scope.onBeforeRender = function ( renderer, scene, camera ) {
 
-		while ( scene.parent !== null ) {
+		updateTextureMatrix( camera );
 
-			scene = scene.parent;
+		scope.visible = false;
 
-		}
+		var currentRenderTarget = renderer.getRenderTarget();
 
-		if ( scene !== undefined && scene instanceof THREE.Scene ) {
+		renderer.render( scene, mirrorCamera, renderTarget, true );
+		renderer.setRenderTarget( currentRenderTarget );
 
-			this.renderer.render( scene, this.mirrorCamera, this.renderTarget2, true );
+		scope.visible = true;
 
-		}
+	};
 
-	}
+};
 
-} );
+THREE.Mirror.prototype = Object.create( THREE.Mesh.prototype );

+ 1 - 1
examples/js/UCSCharacter.js

@@ -44,7 +44,7 @@ THREE.UCSCharacter = function() {
 			geometry.computeBoundingBox();
 			geometry.computeVertexNormals();
 
-			mesh = new THREE.SkinnedMesh( geometry, new THREE.MultiMaterial() );
+			mesh = new THREE.SkinnedMesh( geometry, [] );
 			mesh.name = config.character;
 			scope.root.add( mesh );
 

+ 8 - 0
examples/js/controls/OrbitControls.js

@@ -96,6 +96,14 @@ THREE.OrbitControls = function ( object, domElement ) {
 
 	};
 
+	this.saveState = function () {
+
+		scope.target0.copy( scope.target );
+		scope.position0.copy( scope.object.position );
+		scope.zoom0 = scope.object.zoom;
+
+	};
+
 	this.reset = function () {
 
 		scope.target.copy( scope.target0 );

+ 55 - 98
examples/js/effects/OutlineEffect.js

@@ -13,11 +13,11 @@
  *
  * // How to set outline parameters for each material
  * material.outlineParameters = {
- * 	thickNess: 0.01,                     // this paremeter won't work for MultiMaterial
- * 	color: new THREE.Color( 0x888888 ),  // this paremeter won't work for MultiMaterial
- * 	alpha: 0.8,                          // this paremeter won't work for MultiMaterial
+ * 	thickNess: 0.01,
+ * 	color: new THREE.Color( 0x888888 ),
+ * 	alpha: 0.8,
  * 	visible: true,
- * 	keepAlive: true  // this paremeter won't work for Material in materials of MultiMaterial
+ * 	keepAlive: true
  * };
  *
  * TODO
@@ -35,8 +35,8 @@ THREE.OutlineEffect = function ( renderer, parameters ) {
 	var defaultAlpha = parameters.defaultAlpha !== undefined ? parameters.defaultAlpha : 1.0;
 	var defaultKeepAlive = parameters.defaultKeepAlive !== undefined ? parameters.defaultKeepAlive : false;
 
-	// object.material.uuid -> outlineMaterial
-	// (no mapping from children of MultiMaterial)
+	// object.material.uuid -> outlineMaterial or
+	// object.material[ n ].uuid -> outlineMaterial
 	// save at the outline material creation and release
 	// if it's unused removeThresholdCount frames
 	// unless keepAlive is true.
@@ -44,8 +44,8 @@ THREE.OutlineEffect = function ( renderer, parameters ) {
 
 	var removeThresholdCount = 60;
 
-	// outlineMaterial.uuid (or object.uuid for invisibleMaterial) -> originalMaterial
-	// including children of MultiMaterial.
+	// outlineMaterial.uuid -> object.material or
+	// outlineMaterial.uuid -> object.material[ n ]
 	// save before render and release after render.
 	var originalMaterials = {};
 
@@ -55,8 +55,6 @@ THREE.OutlineEffect = function ( renderer, parameters ) {
 
 	//this.cache = cache;  // for debug
 
-	var invisibleMaterial = new THREE.ShaderMaterial( { visible: false } );
-
 	// copied from WebGLPrograms and removed some materials
 	var shaderIDs = {
 		MeshBasicMaterial: 'basic',
@@ -139,6 +137,12 @@ THREE.OutlineEffect = function ( renderer, parameters ) {
 
 	].join( "\n" );
 
+	function createInvisibleMaterial() {
+
+		return new THREE.ShaderMaterial( { name: 'invisible', visible: false } );
+
+	}
+
 	function createMaterial( originalMaterial ) {
 
 		var shaderID = shaderIDs[ originalMaterial.type ];
@@ -162,7 +166,7 @@ THREE.OutlineEffect = function ( renderer, parameters ) {
 				console.warn( 'THREE.OutlineEffect requires both vec3 position and normal attributes in vertex shader, ' +
 				              'does not draw outline for ' + originalMaterial.name + '(uuid:' + originalMaterial.uuid + ') material.' );
 
-				return invisibleMaterial;
+				return createInvisibleMaterial();
 
 			}
 
@@ -173,7 +177,7 @@ THREE.OutlineEffect = function ( renderer, parameters ) {
 
 		} else {
 
-			return invisibleMaterial;
+			return createInvisibleMaterial();
 
 		}
 
@@ -195,85 +199,74 @@ THREE.OutlineEffect = function ( renderer, parameters ) {
 		if ( ! /vec3\s+transformed\s*=/.test( originalVertexShader ) &&
 		     ! /#include\s+<begin_vertex>/.test( originalVertexShader ) ) defines.DECLARE_TRANSFORMED = true;
 
-		var material = new THREE.ShaderMaterial( {
+		return new THREE.ShaderMaterial( {
 			defines: defines,
 			uniforms: uniforms,
 			vertexShader: vertexShader,
 			fragmentShader: fragmentShader,
 			side: THREE.BackSide,
 			//wireframe: true,
+			skinning: false,
 			morphTargets: false,
 			morphNormals: false,
 			fog: false
 		} );
 
-		return material;
-
-	}
-
-	function createMultiMaterial( originalMaterial ) {
-
-		var materials = [];
-
-		for ( var i = 0, il = originalMaterial.materials.length; i < il; i ++ ) {
-
-			materials.push( createMaterial( originalMaterial.materials[ i ] ) );
-
-		}
-
-		return new THREE.MultiMaterial( materials );
-
 	}
 
-	function setOutlineMaterial( object ) {
-
-		if ( object.material === undefined ) return;
+	function getOutlineMaterialFromCache( originalMaterial ) {
 
-		var data = cache[ object.material.uuid ];
+		var data = cache[ originalMaterial.uuid ];
 
 		if ( data === undefined ) {
 
 			data = {
-				material: object.material.isMultiMaterial === true ? createMultiMaterial( object.material ) : createMaterial( object.material ),
+				material: createMaterial( originalMaterial ),
 				used: true,
 				keepAlive: defaultKeepAlive,
 				count: 0
 			};
 
-			cache[ object.material.uuid ] = data;
+			cache[ originalMaterial.uuid ] = data;
 
 		}
 
-		var outlineMaterial = data.material;
 		data.used = true;
 
-		var uuid = outlineMaterial !== invisibleMaterial ? outlineMaterial.uuid : object.uuid;
-		originalMaterials[ uuid ] = object.material;
+		return data.material;
 
-		if ( object.material.isMultiMaterial === true ) {
+	}
 
-			for ( var i = 0, il = object.material.materials.length; i < il; i ++ ) {
+	function getOutlineMaterial( originalMaterial ) {
 
-				// originalMaterial of leaf material of MultiMaterial is used only for
-				// updating outlineMaterial. so need not to save for invisibleMaterial.
-				if ( outlineMaterial.materials[ i ] !== invisibleMaterial ) {
+		var outlineMaterial = getOutlineMaterialFromCache( originalMaterial );
 
-					originalMaterials[ outlineMaterial.materials[ i ].uuid ] = object.material.materials[ i ];
+		originalMaterials[ outlineMaterial.uuid ] = originalMaterial;
 
-				}
+		updateOutlineMaterial( outlineMaterial, originalMaterial );
 
-			}
+		return outlineMaterial;
+
+	}
+
+	function setOutlineMaterial( object ) {
+
+		if ( object.material === undefined ) return;
 
-			updateOutlineMultiMaterial( outlineMaterial, object.material );
+		if ( Array.isArray( object.material ) ) {
+
+			for ( var i = 0, il = object.material.length; i < il; i ++ ) {
+
+				object.material[ i ] = getOutlineMaterial( object.material[ i ] );
+
+			}
 
 		} else {
 
-			updateOutlineMaterial( outlineMaterial, object.material );
+			object.material = getOutlineMaterial( object.material );
 
 		}
 
-		object.material = outlineMaterial;
-
 		originalOnBeforeRenders[ object.uuid ] = object.onBeforeRender;
 		object.onBeforeRender = onBeforeRender;
 
@@ -283,31 +276,29 @@ THREE.OutlineEffect = function ( renderer, parameters ) {
 
 		if ( object.material === undefined ) return;
 
-		var originalMaterial = originalMaterials[ object.material.uuid ];
+		if ( Array.isArray( object.material ) ) {
+
+			for ( var i = 0, il = object.material.length; i < il; i ++ ) {
 
-		if ( originalMaterial === undefined ) {
+				object.material[ i ] = originalMaterials[ object.material[ i ].uuid ];
+
+			}
 
-			originalMaterial = originalMaterials[ object.uuid ];
+		} else {
 
-			if ( originalMaterial === undefined ) return;
+			object.material = originalMaterials[ object.material.uuid ];
 
 		}
 
-		object.material = originalMaterial;
 		object.onBeforeRender = originalOnBeforeRenders[ object.uuid ];
 
 	}
 
 	function onBeforeRender( renderer, scene, camera, geometry, material, group ) {
 
-		// check some things before updating just in case
-
-		if ( material === invisibleMaterial ) return;
-
-		if ( material.isMultiMaterial === true ) return;
-
 		var originalMaterial = originalMaterials[ material.uuid ];
 
+		// just in case
 		if ( originalMaterial === undefined ) return;
 
 		updateUniforms( material, originalMaterial );
@@ -332,10 +323,11 @@ THREE.OutlineEffect = function ( renderer, parameters ) {
 
 	function updateOutlineMaterial( material, originalMaterial ) {
 
-		if ( material === invisibleMaterial ) return;
+		if ( material.name === 'invisible' ) return;
 
 		var outlineParameters = originalMaterial.outlineParameters;
 
+		material.skinning = originalMaterial.skinning;
 		material.morphTargets = originalMaterial.morphTargets;
 		material.morphNormals = originalMaterial.morphNormals;
 		material.fog = originalMaterial.fog;
@@ -354,8 +346,7 @@ THREE.OutlineEffect = function ( renderer, parameters ) {
 
 			material.transparent = ( outlineParameters.alpha !== undefined && outlineParameters.alpha < 1.0 ) ? true : originalMaterial.transparent;
 
-			// cache[ originalMaterial.uuid ] is undefined if originalMaterial is in materials of MultiMaterial
-			if ( outlineParameters.keepAlive !== undefined && cache[ originalMaterial.uuid ] !== undefined ) cache[ originalMaterial.uuid ].keepAlive = outlineParameters.keepAlive;
+			if ( outlineParameters.keepAlive !== undefined ) cache[ originalMaterial.uuid ].keepAlive = outlineParameters.keepAlive;
 
 		} else {
 
@@ -368,40 +359,6 @@ THREE.OutlineEffect = function ( renderer, parameters ) {
 
 	}
 
-	function updateOutlineMultiMaterial( material, originalMaterial ) {
-
-		if ( material === invisibleMaterial ) return;
-
-		var outlineParameters = originalMaterial.outlineParameters;
-
-		if ( outlineParameters !== undefined ) {
-
-			if ( originalMaterial.visible === false ) {
-
-				material.visible = false;
-
-			} else {
-
-				material.visible = ( outlineParameters.visible !== undefined ) ? outlineParameters.visible : true;
-
-			}
-
-			if ( outlineParameters.keepAlive !== undefined ) cache[ originalMaterial.uuid ].keepAlive = outlineParameters.keepAlive;
-
-		} else {
-
-			material.visible = originalMaterial.visible;
-
-		}
-
-		for ( var i = 0, il = material.materials.length; i < il; i ++ ) {
-
-			updateOutlineMaterial( material.materials[ i ], originalMaterial.materials[ i ] );
-
-		}
-
-	}
-
 	function cleanupCache() {
 
 		var keys;

+ 269 - 199
examples/js/geometries/DecalGeometry.js

@@ -1,289 +1,359 @@
-THREE.DecalVertex = function( v, n ) {
+/**
+ * @author Mugen87 / https://github.com/Mugen87
+ * @author spite / https://github.com/spite
+ *
+ * You can use this geometry to create a decal mesh, that serves different kinds of purposes.
+ * e.g. adding unique details to models, performing dynamic visual environmental changes or covering seams.
+ *
+ * Constructor parameter:
+ *
+ * mesh — Any mesh object
+ * position — Position of the decal projector
+ * orientation — Orientation of the decal projector
+ * size — Size of the decal projector
+ *
+ * reference: http://blog.wolfire.com/2009/06/how-to-project-decals/
+ *
+ */
 
-	this.vertex = v;
-	this.normal = n;
+( function() {
 
-};
+  function DecalGeometry( mesh, position, orientation, size ) {
 
-THREE.DecalVertex.prototype.clone = function() {
+  	THREE.BufferGeometry.call( this );
 
-	return new THREE.DecalVertex( this.vertex.clone(), this.normal.clone() );
+  	this.type = 'DecalGeometry';
 
-};
+  	// buffers
 
-THREE.DecalGeometry = function( mesh, position, rotation, dimensions, check ) {
+  	var vertices = [];
+  	var normals = [];
+  	var uvs = [];
 
-	THREE.Geometry.call( this );
+  	// helpers
 
-	if ( check === undefined ) check = null;
-	check = check || new THREE.Vector3( 1, 1, 1 );
+  	var plane = new THREE.Vector3();
 
-	this.uvs = [];
+  	// this matrix represents the transformation of the decal projector
 
-	this.cube = new THREE.Mesh( new THREE.BoxGeometry( dimensions.x, dimensions.y, dimensions.z ), new THREE.MeshBasicMaterial() );
-	this.cube.rotation.set( rotation.x, rotation.y, rotation.z );
-	this.cube.position.copy( position );
-	this.cube.scale.set( 1, 1, 1 );
-	this.cube.updateMatrix();
+  	var projectorMatrix = new THREE.Matrix4();
+  	projectorMatrix.makeRotationFromEuler( orientation );
+  	projectorMatrix.setPosition( position );
 
-	this.iCubeMatrix = ( new THREE.Matrix4() ).getInverse( this.cube.matrix );
+  	var projectorMatrixInverse = new THREE.Matrix4().getInverse( projectorMatrix );
 
-	this.faceIndices = [ 'a', 'b', 'c', 'd' ];
+  	// generate buffers
 
-	this.clipFace = function( inVertices, plane ) {
+  	generate();
 
-		var size = .5 * Math.abs( ( dimensions.clone() ).dot( plane ) );
+  	// build geometry
 
-		function clip( v0, v1, p ) {
+  	this.addAttribute( 'position', new THREE.Float32BufferAttribute( vertices, 3 ) );
+  	this.addAttribute( 'normal', new THREE.Float32BufferAttribute( normals, 3 ) );
+  	this.addAttribute( 'uv', new THREE.Float32BufferAttribute( uvs, 2 ) );
 
-			var d0 = v0.vertex.dot( p ) - size,
-				d1 = v1.vertex.dot( p ) - size;
+  	function generate() {
 
-			var s = d0 / ( d0 - d1 );
-			var v = new THREE.DecalVertex(
-				new THREE.Vector3(
-					v0.vertex.x + s * ( v1.vertex.x - v0.vertex.x ),
-					v0.vertex.y + s * ( v1.vertex.y - v0.vertex.y ),
-					v0.vertex.z + s * ( v1.vertex.z - v0.vertex.z )
-				),
-				new THREE.Vector3(
-					v0.normal.x + s * ( v1.normal.x - v0.normal.x ),
-					v0.normal.y + s * ( v1.normal.y - v0.normal.y ),
-					v0.normal.z + s * ( v1.normal.z - v0.normal.z )
-				)
-			);
+  		var i, j;
+  		var geometry = new THREE.BufferGeometry();
+  		var decalVertices = [];
 
-			// need to clip more values (texture coordinates)? do it this way:
-			//intersectpoint.value = a.value + s*(b.value-a.value);
+  		var vertex = new THREE.Vector3();
+  		var normal = new THREE.Vector3();
 
-			return v;
+  		// handle different geometry types
 
-		}
+  		if ( mesh.geometry.isGeometry ) {
 
-		if ( inVertices.length === 0 ) return [];
-		var outVertices = [];
+  			geometry.fromGeometry( mesh.geometry );
 
-		for ( var j = 0; j < inVertices.length; j += 3 ) {
+  		} else {
 
-			var v1Out, v2Out, v3Out, total = 0;
+  			geometry.copy( mesh.geometry );
 
-			var d1 = inVertices[ j + 0 ].vertex.dot( plane ) - size,
-				d2 = inVertices[ j + 1 ].vertex.dot( plane ) - size,
-				d3 = inVertices[ j + 2 ].vertex.dot( plane ) - size;
+  		}
 
-			v1Out = d1 > 0;
-			v2Out = d2 > 0;
-			v3Out = d3 > 0;
+  		var positionAttribute = geometry.attributes.position;
+  		var normalAttribute = geometry.attributes.normal;
 
-			total = ( v1Out ? 1 : 0 ) + ( v2Out ? 1 : 0 ) + ( v3Out ? 1 : 0 );
+  		// first, create an array of 'DecalVertex' objects
+  		// three consecutive 'DecalVertex' objects represent a single face
+  		//
+  		// this data structure will be later used to perform the clipping
 
-			switch ( total ) {
-				case 0: {
+  		if ( geometry.index !== null ) {
 
-					outVertices.push( inVertices[ j ] );
-					outVertices.push( inVertices[ j + 1 ] );
-					outVertices.push( inVertices[ j + 2 ] );
-					break;
+  			// indexed BufferGeometry
 
-				}
-				case 1: {
+  			var index = geometry.index;
 
-					var nV1, nV2, nV3, nV4;
-					if ( v1Out ) {
+  			for ( i = 0; i < index.count; i ++ ) {
 
-						nV1 = inVertices[ j + 1 ];
-						nV2 = inVertices[ j + 2 ];
-						nV3 = clip( inVertices[ j ], nV1, plane );
-						nV4 = clip( inVertices[ j ], nV2, plane );
+  				vertex.fromBufferAttribute( positionAttribute, index.getX( i ) );
+  				normal.fromBufferAttribute( normalAttribute, index.getX( i ) );
 
-					}
-					if ( v2Out ) {
+  				pushDecalVertex( decalVertices, vertex, normal );
 
-						nV1 = inVertices[ j ];
-						nV2 = inVertices[ j + 2 ];
-						nV3 = clip( inVertices[ j + 1 ], nV1, plane );
-						nV4 = clip( inVertices[ j + 1 ], nV2, plane );
+  			}
 
-						outVertices.push( nV3 );
-						outVertices.push( nV2.clone() );
-						outVertices.push( nV1.clone() );
+  		} else {
 
-						outVertices.push( nV2.clone() );
-						outVertices.push( nV3.clone() );
-						outVertices.push( nV4 );
-						break;
+  			// non-indexed BufferGeometry
 
-					}
-					if ( v3Out ) {
+  			for ( i = 0; i < positionAttribute.count; i ++ ) {
 
-						nV1 = inVertices[ j ];
-						nV2 = inVertices[ j + 1 ];
-						nV3 = clip( inVertices[ j + 2 ], nV1, plane );
-						nV4 = clip( inVertices[ j + 2 ], nV2, plane );
+  				vertex.fromBufferAttribute( positionAttribute, i );
+  				normal.fromBufferAttribute( normalAttribute, i );
 
-					}
+  				pushDecalVertex( decalVertices, vertex, normal );
 
-					outVertices.push( nV1.clone() );
-					outVertices.push( nV2.clone() );
-					outVertices.push( nV3 );
+  			}
 
-					outVertices.push( nV4 );
-					outVertices.push( nV3.clone() );
-					outVertices.push( nV2.clone() );
+  		}
 
-					break;
+  		// second, clip the geometry so that it doesn't extend out from the projector
 
-				}
-				case 2: {
+  		decalVertices = clipGeometry( decalVertices, plane.set(   1,   0,   0 ) );
+  		decalVertices = clipGeometry( decalVertices, plane.set( - 1,   0,   0 ) );
+  		decalVertices = clipGeometry( decalVertices, plane.set(   0,   1,   0 ) );
+  		decalVertices = clipGeometry( decalVertices, plane.set(   0, - 1,   0 ) );
+  		decalVertices = clipGeometry( decalVertices, plane.set(   0,   0,   1 ) );
+  		decalVertices = clipGeometry( decalVertices, plane.set(   0,   0, - 1 ) );
 
-					var nV1, nV2, nV3;
-					if ( ! v1Out ) {
+  		// third, generate final vertices, normals and uvs
 
-						nV1 = inVertices[ j ].clone();
-						nV2 = clip( nV1, inVertices[ j + 1 ], plane );
-						nV3 = clip( nV1, inVertices[ j + 2 ], plane );
-						outVertices.push( nV1 );
-						outVertices.push( nV2 );
-						outVertices.push( nV3 );
+  		for ( i = 0; i < decalVertices.length; i ++ ) {
 
-					}
-					if ( ! v2Out ) {
+  			var decalVertex = decalVertices[ i ];
 
-						nV1 = inVertices[ j + 1 ].clone();
-						nV2 = clip( nV1, inVertices[ j + 2 ], plane );
-						nV3 = clip( nV1, inVertices[ j ], plane );
-						outVertices.push( nV1 );
-						outVertices.push( nV2 );
-						outVertices.push( nV3 );
+  			// create texture coordinates (we are still in projector space)
 
-					}
-					if ( ! v3Out ) {
+  			uvs.push(
+  				0.5 + ( decalVertex.position.x / size.x ),
+  				0.5 + ( decalVertex.position.y / size.y )
+  			);
 
-						nV1 = inVertices[ j + 2 ].clone();
-						nV2 = clip( nV1, inVertices[ j ], plane );
-						nV3 = clip( nV1, inVertices[ j + 1 ], plane );
-						outVertices.push( nV1 );
-						outVertices.push( nV2 );
-						outVertices.push( nV3 );
+  			// transform the vertex back to world space
 
-					}
+  			decalVertex.position.applyMatrix4( projectorMatrix );
 
-					break;
+  			// now create vertex and normal buffer data
 
-				}
-				case 3: {
+  			vertices.push( decalVertex.position.x, decalVertex.position.y, decalVertex.position.z );
+  			normals.push( decalVertex.normal.x, decalVertex.normal.y, decalVertex.normal.z );
 
-					break;
+  		}
 
-				}
-			}
+  	}
 
-		}
+  	function pushDecalVertex( decalVertices, vertex, normal ) {
 
-		return outVertices;
+  		// transform the vertex to world space, then to projector space
 
-	};
+  		vertex.applyMatrix4( mesh.matrix );
+  		vertex.applyMatrix4( projectorMatrixInverse );
 
-	this.pushVertex = function( vertices, id, n ) {
+  		decalVertices.push( new DecalVertex( vertex.clone(), normal.clone() ) );
 
-		var v = mesh.geometry.vertices[ id ].clone();
-		v.applyMatrix4( mesh.matrix );
-		v.applyMatrix4( this.iCubeMatrix );
-		vertices.push( new THREE.DecalVertex( v, n.clone() ) );
+  	}
 
-	};
+  	function clipGeometry( inVertices, plane ) {
 
-	this.computeDecal = function() {
+  		var outVertices = [];
 
-		var finalVertices = [];
+  		var s = 0.5 * Math.abs( size.dot( plane ) );
 
-		for ( var i = 0; i < mesh.geometry.faces.length; i ++ ) {
+  		// a single iteration clips one face,
+  		// which consists of three consecutive 'DecalVertex' objects
 
-			var f = mesh.geometry.faces[ i ];
-			var vertices = [];
+  		for ( var i = 0; i < inVertices.length; i += 3 ) {
 
-			this.pushVertex( vertices, f[ this.faceIndices[ 0 ] ], f.vertexNormals[ 0 ] );
-			this.pushVertex( vertices, f[ this.faceIndices[ 1 ] ], f.vertexNormals[ 1 ] );
-			this.pushVertex( vertices, f[ this.faceIndices[ 2 ] ], f.vertexNormals[ 2 ] );
+  			var v1Out, v2Out, v3Out, total = 0;
+  			var nV1, nV2, nV3, nV4;
 
-			if ( check.x ) {
+  			var d1 = inVertices[ i + 0 ].position.dot( plane ) - s;
+  			var d2 = inVertices[ i + 1 ].position.dot( plane ) - s;
+  			var d3 = inVertices[ i + 2 ].position.dot( plane ) - s;
 
-				vertices = this.clipFace( vertices, new THREE.Vector3( 1, 0, 0 ) );
-				vertices = this.clipFace( vertices, new THREE.Vector3( - 1, 0, 0 ) );
+  			v1Out = d1 > 0;
+  			v2Out = d2 > 0;
+  			v3Out = d3 > 0;
 
-			}
-			if ( check.y ) {
+  			// calculate, how many vertices of the face lie outside of the clipping plane
 
-				vertices = this.clipFace( vertices, new THREE.Vector3( 0, 1, 0 ) );
-				vertices = this.clipFace( vertices, new THREE.Vector3( 0, - 1, 0 ) );
+  			total = ( v1Out ? 1 : 0 ) + ( v2Out ? 1 : 0 ) + ( v3Out ? 1 : 0 );
 
-			}
-			if ( check.z ) {
+  			switch ( total ) {
 
-				vertices = this.clipFace( vertices, new THREE.Vector3( 0, 0, 1 ) );
-				vertices = this.clipFace( vertices, new THREE.Vector3( 0, 0, - 1 ) );
+  				case 0: {
 
-			}
+  					// the entire face lies inside of the plane, no clipping needed
 
-			for ( var j = 0; j < vertices.length; j ++ ) {
+  					outVertices.push( inVertices[ i ] );
+  					outVertices.push( inVertices[ i + 1 ] );
+  					outVertices.push( inVertices[ i + 2 ] );
+  					break;
 
-				var v = vertices[ j ];
+  				}
 
-				this.uvs.push( new THREE.Vector2(
-					.5 + ( v.vertex.x / dimensions.x ),
-					.5 + ( v.vertex.y / dimensions.y )
-				) );
+  				case 1: {
 
-				vertices[ j ].vertex.applyMatrix4( this.cube.matrix );
+  					// one vertex lies outside of the plane, perform clipping
 
-			}
+  					if ( v1Out ) {
 
-			if ( vertices.length === 0 ) continue;
+  						nV1 = inVertices[ i + 1 ];
+  						nV2 = inVertices[ i + 2 ];
+  						nV3 = clip( inVertices[ i ], nV1, plane, s );
+  						nV4 = clip( inVertices[ i ], nV2, plane, s );
 
-			finalVertices = finalVertices.concat( vertices );
+  					}
 
-		}
+  					if ( v2Out ) {
 
-		for ( var k = 0; k < finalVertices.length; k += 3 ) {
+  						nV1 = inVertices[ i ];
+  						nV2 = inVertices[ i + 2 ];
+  						nV3 = clip( inVertices[ i + 1 ], nV1, plane, s );
+  						nV4 = clip( inVertices[ i + 1 ], nV2, plane, s );
 
-			this.vertices.push(
-				finalVertices[ k ].vertex,
-				finalVertices[ k + 1 ].vertex,
-				finalVertices[ k + 2 ].vertex
-			);
+  						outVertices.push( nV3 );
+  						outVertices.push( nV2.clone() );
+  						outVertices.push( nV1.clone() );
 
-			var f = new THREE.Face3(
-				k,
-				k + 1,
-				k + 2
-			);
-			f.vertexNormals.push( finalVertices[ k + 0 ].normal );
-			f.vertexNormals.push( finalVertices[ k + 1 ].normal );
-			f.vertexNormals.push( finalVertices[ k + 2 ].normal );
+  						outVertices.push( nV2.clone() );
+  						outVertices.push( nV3.clone() );
+  						outVertices.push( nV4 );
+  						break;
 
-			this.faces.push( f );
+  					}
 
-			this.faceVertexUvs[ 0 ].push( [
-				this.uvs[ k ],
-				this.uvs[ k + 1 ],
-				this.uvs[ k + 2 ]
-			] );
+  					if ( v3Out ) {
 
-		}
+  						nV1 = inVertices[ i ];
+  						nV2 = inVertices[ i + 1 ];
+  						nV3 = clip( inVertices[ i + 2 ], nV1, plane, s );
+  						nV4 = clip( inVertices[ i + 2 ], nV2, plane, s );
 
-		this.verticesNeedUpdate = true;
-		this.elementsNeedUpdate = true;
-		this.morphTargetsNeedUpdate = true;
-		this.uvsNeedUpdate = true;
-		this.normalsNeedUpdate = true;
-		this.colorsNeedUpdate = true;
-		this.computeFaceNormals();
+  					}
 
-	};
+  					outVertices.push( nV1.clone() );
+  					outVertices.push( nV2.clone() );
+  					outVertices.push( nV3 );
 
-	this.computeDecal();
+  					outVertices.push( nV4 );
+  					outVertices.push( nV3.clone() );
+  					outVertices.push( nV2.clone() );
 
-};
+  					break;
 
-THREE.DecalGeometry.prototype = Object.create( THREE.Geometry.prototype );
-THREE.DecalGeometry.prototype.constructor = THREE.DecalGeometry;
+  				}
+
+  				case 2: {
+
+  					// two vertices lies outside of the plane, perform clipping
+
+  					if ( ! v1Out ) {
+
+  						nV1 = inVertices[ i ].clone();
+  						nV2 = clip( nV1, inVertices[ i + 1 ], plane, s );
+  						nV3 = clip( nV1, inVertices[ i + 2 ], plane, s );
+  						outVertices.push( nV1 );
+  						outVertices.push( nV2 );
+  						outVertices.push( nV3 );
+
+  					}
+
+  					if ( ! v2Out ) {
+
+  						nV1 = inVertices[ i + 1 ].clone();
+  						nV2 = clip( nV1, inVertices[ i + 2 ], plane, s );
+  						nV3 = clip( nV1, inVertices[ i ], plane, s );
+  						outVertices.push( nV1 );
+  						outVertices.push( nV2 );
+  						outVertices.push( nV3 );
+
+  					}
+
+  					if ( ! v3Out ) {
+
+  						nV1 = inVertices[ i + 2 ].clone();
+  						nV2 = clip( nV1, inVertices[ i ], plane, s );
+  						nV3 = clip( nV1, inVertices[ i + 1 ], plane, s );
+  						outVertices.push( nV1 );
+  						outVertices.push( nV2 );
+  						outVertices.push( nV3 );
+
+  					}
+
+  					break;
+
+  				}
+
+  				case 3: {
+
+  					// the entire face lies outside of the plane, so let's discard the corresponding vertices
+
+  					break;
+
+  				}
+
+  			}
+
+  		}
+
+  		return outVertices;
+
+  	}
+
+  	function clip( v0, v1, p, s ) {
+
+  		var d0 = v0.position.dot( p ) - s;
+  		var d1 = v1.position.dot( p ) - s;
+
+  		var s0 = d0 / ( d0 - d1 );
+
+  		var v = new DecalVertex(
+  			new THREE.Vector3(
+  				v0.position.x + s0 * ( v1.position.x - v0.position.x ),
+  				v0.position.y + s0 * ( v1.position.y - v0.position.y ),
+  				v0.position.z + s0 * ( v1.position.z - v0.position.z )
+  			),
+  			new THREE.Vector3(
+  				v0.normal.x + s0 * ( v1.normal.x - v0.normal.x ),
+  				v0.normal.y + s0 * ( v1.normal.y - v0.normal.y ),
+  				v0.normal.z + s0 * ( v1.normal.z - v0.normal.z )
+  			)
+  		);
+
+  		// need to clip more values (texture coordinates)? do it this way:
+  		// intersectpoint.value = a.value + s * ( b.value - a.value );
+
+  		return v;
+
+  	}
+
+  }
+
+  DecalGeometry.prototype = Object.create( THREE.BufferGeometry.prototype );
+  DecalGeometry.prototype.constructor = DecalGeometry;
+
+  // helper
+
+  function DecalVertex( position, normal ) {
+
+  	this.position = position;
+  	this.normal = normal;
+
+  }
+
+  DecalVertex.prototype.clone = function() {
+
+  	return new DecalVertex( this.position.clone(), this.normal.clone() );
+
+  };
+
+  // export
+
+  THREE.DecalGeometry = DecalGeometry;
+
+} ) ();

+ 4 - 9
examples/js/lights/RectAreaLightUniformsLib.js

@@ -27,8 +27,6 @@
 
 	//
 
-	var UniformsLib = THREE.UniformsLib;
-	var ShaderLib = THREE.ShaderLib;
 
 	var LTC_MAT_TEXTURE = new THREE.DataTexture(
 			new Float32Array( LTC_MAT ),
@@ -47,15 +45,12 @@
 	LTC_MAT_TEXTURE.needsUpdate = true;
 	LTC_MAG_TEXTURE.needsUpdate = true;
 
-	THREE.UniformsLib.LTC_MAT_TEXTURE = LTC_MAT_TEXTURE;
-	THREE.UniformsLib.LTC_MAG_TEXTURE = LTC_MAG_TEXTURE;
-
 	// Add ltc tables to materials
 
-	var ltc_brdf = { ltcMat: { value: null }, ltcMag: { value: null } };
+	var ltc_brdf = { ltcMat: { value: LTC_MAT_TEXTURE }, ltcMag: { value: LTC_MAT_TEXTURE } };
 
-	Object.assign( ShaderLib.phong.uniforms, ltc_brdf );
-	Object.assign( ShaderLib.standard.uniforms, ltc_brdf );
-	Object.assign( ShaderLib.physical.uniforms, ltc_brdf );
+	Object.assign( THREE.ShaderLib.phong.uniforms, ltc_brdf );
+	Object.assign( THREE.ShaderLib.standard.uniforms, ltc_brdf );
+	Object.assign( THREE.ShaderLib.physical.uniforms, ltc_brdf );
 
 } )()

+ 4 - 3
examples/js/loaders/AssimpLoader.js

@@ -635,6 +635,7 @@
 			var skeleton = new THREE.Skeleton( allBones, offsetMatrix );
 
 			this.threeNode.bind( skeleton, new THREE.Matrix4() );
+			this.threeNode.material.skinning = true;
 
 		};
 
@@ -1849,7 +1850,7 @@
 
 					}
 
-
+					
 
 				}
 
@@ -1872,7 +1873,7 @@
 				} else {
 
 					throw ( new Error( "Sorry, can't currently triangulate polys. Use the triangulate preprocessor in Assimp." ))
-
+					
 				}
 
 
@@ -2349,4 +2350,4 @@
 
 	THREE.AssimpLoader = AssimpLoader;
 
-} )();
+} )();

+ 12 - 1
examples/js/loaders/ColladaLoader.js

@@ -1197,7 +1197,18 @@ THREE.ColladaLoader = function () {
 
 					applySkin( geom, skinController );
 
-					material.morphTargets = geom.morphTargets.length > 0;
+					if ( geom.morphTargets.length > 0 ) {
+
+						material.morphTargets = true;
+						material.skinning = false;
+
+					} else {
+
+						material.morphTargets = false;
+						material.skinning = true;
+
+					}
+
 
 					mesh = new THREE.SkinnedMesh( geom, material, false );
 

+ 2 - 1
examples/js/loaders/ColladaLoader2.js

@@ -1439,7 +1439,8 @@ THREE.ColladaLoader.prototype = {
 			}
 
 			object.name = data.name;
-			matrix.decompose( object.position, object.quaternion, object.scale );
+			object.matrix.copy( matrix );
+			object.matrix.decompose( object.position, object.quaternion, object.scale );
 
 			return object;
 

+ 14 - 0
examples/js/loaders/FBXLoader.js

@@ -464,6 +464,20 @@
 
 			if ( geometry.bones !== undefined && geometry.skinWeights !== undefined && geometry.skinWeights.length > 0 ) {
 
+				if ( material instanceof THREE.MultiMaterial ) {
+
+					for ( var i = 0; i < material.materials.length; ++ i ) {
+
+						material.materials[ i ].skinning = true;
+
+					}
+
+				} else {
+
+					material.skinning = true;
+
+				}
+
 				mesh = new THREE.SkinnedMesh( geometry, material );
 
 			} else {

+ 5 - 0
examples/js/loaders/FBXLoader2.js

@@ -1224,6 +1224,11 @@
 								}
 								if ( geometry.FBX_Deformer ) {
 
+									for ( var materialsIndex = 0, materialsLength = materials.length; materialsIndex < materialsLength; ++ materialsIndex ) {
+
+										materials[ materialsIndex ].skinning = true;
+
+									}
 									model = new THREE.SkinnedMesh( geometry, material );
 
 								} else {

+ 33 - 29
examples/js/loaders/GLTF2Loader.js

@@ -136,15 +136,6 @@ THREE.GLTF2Loader = ( function () {
 
 			update: function ( scene, camera ) {
 
-				// update scene graph
-
-				scene.updateMatrixWorld();
-
-				// update camera matrices and frustum
-
-				camera.updateMatrixWorld();
-				camera.matrixWorldInverse.getInverse( camera.matrixWorld );
-
 				for ( var name in objects ) {
 
 					var object = objects[ name ];
@@ -163,10 +154,6 @@ THREE.GLTF2Loader = ( function () {
 
 	}
 
-	/* GLTFSHADERS */
-
-	GLTF2Loader.Shaders = new GLTFRegistry();
-
 	/* GLTFSHADER */
 
 	function GLTFShader( targetNode, allNodes ) {
@@ -568,9 +555,9 @@ THREE.GLTF2Loader = ( function () {
 
 						value.then( function( key, value ) {
 
-							results[ idx ] = value;
+							results[ key ] = value;
 
-						}.bind( this, key ));
+						}.bind( this, idx ));
 
 					} else {
 
@@ -632,8 +619,8 @@ THREE.GLTF2Loader = ( function () {
 		if ( typeof url !== 'string' || url === '' )
 			return '';
 
-		// Absolute URL
-		if ( /^https?:\/\//i.test( url ) ) {
+		// Absolute URL http://,https://,//
+		if ( /^(https?:)?\/\//i.test( url ) ) {
 
 			return url;
 
@@ -1063,7 +1050,7 @@ THREE.GLTF2Loader = ( function () {
 
 			return _each( json.textures, function ( texture ) {
 
-				if ( texture.source ) {
+				if ( texture.source !== undefined ) {
 
 					return new Promise( function ( resolve ) {
 
@@ -1103,7 +1090,7 @@ THREE.GLTF2Loader = ( function () {
 
 							_texture.type = texture.type !== undefined ? WEBGL_TEXTURE_DATATYPES[ texture.type ] : THREE.UnsignedByteType;
 
-							if ( texture.sampler ) {
+							if ( texture.sampler !== undefined ) {
 
 								var sampler = json.samplers[ texture.sampler ];
 
@@ -1573,7 +1560,7 @@ THREE.GLTF2Loader = ( function () {
 
 			return _each( json.meshes, function ( mesh ) {
 
-				var group = new THREE.Object3D();
+				var group = new THREE.Group();
 				if ( mesh.name !== undefined ) group.name = mesh.name;
 
 				if ( mesh.extras ) group.userData = mesh.extras;
@@ -1594,7 +1581,7 @@ THREE.GLTF2Loader = ( function () {
 
 							var attributeEntry = attributes[ attributeId ];
 
-							if ( ! attributeEntry ) return;
+							if ( attributeEntry === undefined ) return;
 
 							var bufferAttribute = dependencies.accessors[ attributeEntry ];
 
@@ -1632,7 +1619,7 @@ THREE.GLTF2Loader = ( function () {
 
 						}
 
-						if ( primitive.indices ) {
+						if ( primitive.indices !== undefined ) {
 
 							geometry.setIndex( dependencies.accessors[ primitive.indices ] );
 
@@ -1682,7 +1669,7 @@ THREE.GLTF2Loader = ( function () {
 
 						var meshNode;
 
-						if ( primitive.indices ) {
+						if ( primitive.indices !== undefined ) {
 
 							geometry.setIndex( dependencies.accessors[ primitive.indices ] );
 
@@ -1923,11 +1910,25 @@ THREE.GLTF2Loader = ( function () {
 
 					var node = json.nodes[ nodeId ];
 
-					if ( node.meshes !== undefined ) {
+					var meshes;
+
+					if ( node.mesh !== undefined) {
+
+						meshes = [ node.mesh ];
+
+					} else if ( node.meshes !== undefined ) {
+
+						console.warn( 'GLTF2Loader: Legacy glTF file detected. Nodes may have no more than 1 mesh.' );
+
+						meshes = node.meshes;
+
+					}
+
+					if ( meshes !== undefined ) {
 
-						for ( var meshId in node.meshes ) {
+						for ( var meshId in meshes ) {
 
-							var mesh = node.meshes[ meshId ];
+							var mesh = meshes[ meshId ];
 							var group = dependencies.meshes[ mesh ];
 
 							if ( group === undefined ) {
@@ -1985,7 +1986,7 @@ THREE.GLTF2Loader = ( function () {
 
 								var skinEntry;
 
-								if ( node.skin ) {
+								if ( node.skin !== undefined ) {
 
 									skinEntry = dependencies.skins[ node.skin ];
 
@@ -2012,6 +2013,7 @@ THREE.GLTF2Loader = ( function () {
 
 									var geometry = originalGeometry;
 									var material = originalMaterial;
+									material.skinning = true;
 
 									child = new THREE.SkinnedMesh( geometry, material, false );
 									child.castShadow = true;
@@ -2163,8 +2165,10 @@ THREE.GLTF2Loader = ( function () {
 					// Register raw material meshes with GLTF2Loader.Shaders
 					if ( child.material && child.material.isRawShaderMaterial ) {
 
-						var xshader = new GLTFShader( child, dependencies.nodes );
-						GLTF2Loader.Shaders.add( child.uuid, xshader );
+						child.gltfShader = new GLTFShader( child, dependencies.nodes );
+						child.onBeforeRender = function(renderer, scene, camera){
+							this.gltfShader.update(scene, camera);
+						};
 
 					}
 

+ 20 - 18
examples/js/loaders/GLTFLoader.js

@@ -135,15 +135,6 @@ THREE.GLTFLoader = ( function () {
 
 			update: function ( scene, camera ) {
 
-				// update scene graph
-
-				scene.updateMatrixWorld();
-
-				// update camera matrices and frustum
-
-				camera.updateMatrixWorld();
-				camera.matrixWorldInverse.getInverse( camera.matrixWorld );
-
 				for ( var name in objects ) {
 
 					var object = objects[ name ];
@@ -164,7 +155,15 @@ THREE.GLTFLoader = ( function () {
 
 	/* GLTFSHADERS */
 
-	GLTFLoader.Shaders = new GLTFRegistry();
+	GLTFLoader.Shaders = {
+
+		update: function () {
+
+			console.warn( 'THREE.GLTFLoader.Shaders has been deprecated, and now updates automatically.' );
+
+		}
+
+	};
 
 	/* GLTFSHADER */
 
@@ -580,9 +579,9 @@ THREE.GLTFLoader = ( function () {
 
 						value.then( function( key, value ) {
 
-							results[ idx ] = value;
+							results[ key ] = value;
 
-						}.bind( this, key ));
+						}.bind( this, idx ));
 
 					} else {
 
@@ -644,8 +643,8 @@ THREE.GLTFLoader = ( function () {
 		if ( typeof url !== 'string' || url === '' )
 			return '';
 
-		// Absolute URL
-		if ( /^https?:\/\//i.test( url ) ) {
+		// Absolute URL http://,https://,//
+		if ( /^(https?:)?\/\//i.test( url ) ) {
 
 			return url;
 
@@ -1109,7 +1108,7 @@ THREE.GLTFLoader = ( function () {
 							if ( texture.internalFormat !== undefined && _texture.format !== WEBGL_TEXTURE_FORMATS[ texture.internalFormat ] ) {
 
 								console.warn( 'THREE.GLTFLoader: Three.js doesn\'t support texture internalFormat which is different from texture format. ' +
-								              'internalFormat will be forced to be the same value as format.' );
+															'internalFormat will be forced to be the same value as format.' );
 
 							}
 
@@ -1585,7 +1584,7 @@ THREE.GLTFLoader = ( function () {
 
 			return _each( json.meshes, function ( mesh ) {
 
-				var group = new THREE.Object3D();
+				var group = new THREE.Group();
 				if ( mesh.name !== undefined ) group.name = mesh.name;
 
 				if ( mesh.extras ) group.userData = mesh.extras;
@@ -2024,6 +2023,7 @@ THREE.GLTFLoader = ( function () {
 
 									var geometry = originalGeometry;
 									var material = originalMaterial;
+									material.skinning = true;
 
 									child = new THREE.SkinnedMesh( geometry, material, false );
 									child.castShadow = true;
@@ -2175,8 +2175,10 @@ THREE.GLTFLoader = ( function () {
 					// Register raw material meshes with GLTFLoader.Shaders
 					if ( child.material && child.material.isRawShaderMaterial ) {
 
-						var xshader = new GLTFShader( child, dependencies.nodes );
-						GLTFLoader.Shaders.add( child.uuid, xshader );
+						child.gltfShader = new GLTFShader( child, dependencies.nodes );
+						child.onBeforeRender = function(renderer, scene, camera){
+							this.gltfShader.update(scene, camera);
+						};
 
 					}
 

+ 5 - 4
examples/js/loaders/MMDLoader.js

@@ -495,7 +495,7 @@ THREE.MMDLoader.prototype.createMesh = function ( model, texturePath, onProgress
 
 	var scope = this;
 	var geometry = new THREE.BufferGeometry();
-	var material = new THREE.MultiMaterial();
+	var materials = [];
 	var helper = new THREE.MMDLoader.DataCreationHelper();
 
 	var buffer = {};
@@ -1118,6 +1118,7 @@ THREE.MMDLoader.prototype.createMesh = function ( model, texturePath, onProgress
 
 			if ( p.name !== undefined ) m.name = p.name;
 
+			m.skinning = geometry.bones.length > 0 ? true : false;
 			m.morphTargets = geometry.morphTargets.length > 0 ? true : false;
 			m.lights = true;
 			m.side = ( model.metadata.format === 'pmx' && ( p2.flag & 0x1 ) === 1 ) ? THREE.DoubleSide : p.side;
@@ -1329,7 +1330,7 @@ THREE.MMDLoader.prototype.createMesh = function ( model, texturePath, onProgress
 
 			}
 
-			material.materials.push( m );
+			materials.push( m );
 
 		}
 
@@ -1353,7 +1354,7 @@ THREE.MMDLoader.prototype.createMesh = function ( model, texturePath, onProgress
 
 					}
 
-					var m = material.materials[ e.index ];
+					var m = materials[ e.index ];
 
 					if ( m.opacity !== e.diffuse[ 3 ] ) {
 
@@ -1498,7 +1499,7 @@ THREE.MMDLoader.prototype.createMesh = function ( model, texturePath, onProgress
 	initPhysics();
 	initGeometry();
 
-	var mesh = new THREE.SkinnedMesh( geometry, material );
+	var mesh = new THREE.SkinnedMesh( geometry, materials );
 
 	// console.log( mesh ); // for console debug
 

+ 12 - 8
examples/js/loaders/STLLoader.js

@@ -70,19 +70,23 @@ THREE.STLLoader.prototype = {
 
 			}
 
-			// some binary files will have different size from expected,
-			// checking characters higher than ASCII to confirm is binary
-			var fileLength = reader.byteLength;
-			for ( var index = 0; index < fileLength; index ++ ) {
+			// An ASCII STL data must begin with 'solid ' as the first six bytes.
+			// However, ASCII STLs lacking the SPACE after the 'd' are known to be
+			// plentiful.  So, check the first 5 bytes for 'solid'.
 
-				if ( reader.getUint8( index, false ) > 127 ) {
+			// US-ASCII ordinal values for 's', 'o', 'l', 'i', 'd'
+			var solid = [ 115, 111, 108, 105, 100 ];
 
-					return true;
+			for ( var i = 0; i < 5; i ++ ) {
 
-				}
+				// If solid[ i ] does not match the i-th byte, then it is not an
+				// ASCII STL; hence, it is binary and return true.
 
-			}
+				if ( solid[ i ] != reader.getUint8( i, false ) ) return true;
+
+ 			}
 
+			// First 5 bytes read "solid"; declare it to be an ASCII STL
 			return false;
 
 		};

+ 4 - 1
examples/js/loaders/sea3d/SEA3DLoader.js

@@ -1993,18 +1993,21 @@ THREE.SEA3D.prototype.readMesh = function ( sea ) {
 
 				mats[ i ] = sea.material[ i ].tag;
 
+				mats[ i ].skinning = skeleton != undefined;
 				mats[ i ].morphTargets = uMorph;
 				mats[ i ].morphNormals = uMorphNormal;
 				mats[ i ].vertexColors = sea.geometry.color ? THREE.VertexColors : THREE.NoColors;
 
 			}
 
-			mat = new THREE.MultiMaterial( mats );
+//			mat = new THREE.MultiMaterial( mats );
+			mat = mats;
 
 		} else {
 
 			mat = sea.material[ 0 ].tag;
 
+			mat.skinning = skeleton != undefined;
 			mat.morphTargets = uMorph;
 			mat.morphNormals = uMorphNormal;
 			mat.vertexColors = sea.geometry.color ? THREE.VertexColors : THREE.NoColors;

+ 1 - 1
examples/js/nodes/inputs/MirrorNode.js

@@ -11,7 +11,7 @@ THREE.MirrorNode = function( renderer, camera, options ) {
 	this.coord = new THREE.OperatorNode( this.textureMatrix, this.worldPosition, THREE.OperatorNode.MUL );
 	this.coordResult = new THREE.OperatorNode( null, this.coord, THREE.OperatorNode.ADD );
 
-	this.texture = new THREE.TextureNode( this.mirror.renderTarget.texture, this.coord, null, true );
+	this.texture = new THREE.TextureNode( this.mirror.material.uniforms.mirrorSampler.value, this.coord, null, true );
 
 };
 

+ 83 - 81
examples/js/renderers/CanvasRenderer.js

@@ -9,7 +9,7 @@ THREE.SpriteCanvasMaterial = function ( parameters ) {
 	this.type = 'SpriteCanvasMaterial';
 
 	this.color = new THREE.Color( 0xffffff );
-	this.program = function ( context, color ) {};
+	this.program = function () {};
 
 	this.setValues( parameters );
 
@@ -17,6 +17,7 @@ THREE.SpriteCanvasMaterial = function ( parameters ) {
 
 THREE.SpriteCanvasMaterial.prototype = Object.create( THREE.Material.prototype );
 THREE.SpriteCanvasMaterial.prototype.constructor = THREE.SpriteCanvasMaterial;
+THREE.SpriteCanvasMaterial.prototype.isSpriteCanvasMaterial = true;
 
 THREE.SpriteCanvasMaterial.prototype.clone = function () {
 
@@ -39,78 +40,69 @@ THREE.CanvasRenderer = function ( parameters ) {
 	parameters = parameters || {};
 
 	var _this = this,
-	_renderData, _elements, _lights,
-	_projector = new THREE.Projector(),
+		_renderData, _elements, _lights,
+		_projector = new THREE.Projector(),
 
-	_canvas = parameters.canvas !== undefined
-			 ? parameters.canvas
-			 : document.createElement( 'canvas' ),
+		_canvas = parameters.canvas !== undefined
+				 ? parameters.canvas
+				 : document.createElement( 'canvas' ),
 
-	_canvasWidth = _canvas.width,
-	_canvasHeight = _canvas.height,
-	_canvasWidthHalf = Math.floor( _canvasWidth / 2 ),
-	_canvasHeightHalf = Math.floor( _canvasHeight / 2 ),
+		_canvasWidth = _canvas.width,
+		_canvasHeight = _canvas.height,
+		_canvasWidthHalf = Math.floor( _canvasWidth / 2 ),
+		_canvasHeightHalf = Math.floor( _canvasHeight / 2 ),
 
-	_viewportX = 0,
-	_viewportY = 0,
-	_viewportWidth = _canvasWidth,
-	_viewportHeight = _canvasHeight,
+		_viewportX = 0,
+		_viewportY = 0,
+		_viewportWidth = _canvasWidth,
+		_viewportHeight = _canvasHeight,
 
-	_pixelRatio = 1,
+		_pixelRatio = 1,
 
-	_context = _canvas.getContext( '2d', {
-		alpha: parameters.alpha === true
-	} ),
+		_context = _canvas.getContext( '2d', {
+			alpha: parameters.alpha === true
+		} ),
 
-	_clearColor = new THREE.Color( 0x000000 ),
-	_clearAlpha = parameters.alpha === true ? 0 : 1,
+		_clearColor = new THREE.Color( 0x000000 ),
+		_clearAlpha = parameters.alpha === true ? 0 : 1,
 
-	_contextGlobalAlpha = 1,
-	_contextGlobalCompositeOperation = 0,
-	_contextStrokeStyle = null,
-	_contextFillStyle = null,
-	_contextLineWidth = null,
-	_contextLineCap = null,
-	_contextLineJoin = null,
-	_contextLineDash = [],
+		_contextGlobalAlpha = 1,
+		_contextGlobalCompositeOperation = 0,
+		_contextStrokeStyle = null,
+		_contextFillStyle = null,
+		_contextLineWidth = null,
+		_contextLineCap = null,
+		_contextLineJoin = null,
+		_contextLineDash = [],
 
-	_camera,
+		_v1, _v2, _v3,
 
-	_v1, _v2, _v3, _v4,
-	_v5 = new THREE.RenderableVertex(),
-	_v6 = new THREE.RenderableVertex(),
+		_v1x, _v1y, _v2x, _v2y, _v3x, _v3y,
 
-	_v1x, _v1y, _v2x, _v2y, _v3x, _v3y,
-	_v4x, _v4y, _v5x, _v5y, _v6x, _v6y,
+		_color = new THREE.Color(),
 
-	_color = new THREE.Color(),
-	_color1 = new THREE.Color(),
-	_color2 = new THREE.Color(),
-	_color3 = new THREE.Color(),
-	_color4 = new THREE.Color(),
+		_diffuseColor = new THREE.Color(),
+		_emissiveColor = new THREE.Color(),
 
-	_diffuseColor = new THREE.Color(),
-	_emissiveColor = new THREE.Color(),
+		_lightColor = new THREE.Color(),
 
-	_lightColor = new THREE.Color(),
+		_patterns = {},
 
-	_patterns = {},
+		_uvs,
+		_uv1x, _uv1y, _uv2x, _uv2y, _uv3x, _uv3y,
 
-	_image, _uvs,
-	_uv1x, _uv1y, _uv2x, _uv2y, _uv3x, _uv3y,
+		_clipBox = new THREE.Box2(),
+		_clearBox = new THREE.Box2(),
+		_elemBox = new THREE.Box2(),
 
-	_clipBox = new THREE.Box2(),
-	_clearBox = new THREE.Box2(),
-	_elemBox = new THREE.Box2(),
+		_ambientLight = new THREE.Color(),
+		_directionalLights = new THREE.Color(),
+		_pointLights = new THREE.Color(),
 
-	_ambientLight = new THREE.Color(),
-	_directionalLights = new THREE.Color(),
-	_pointLights = new THREE.Color(),
-
-	_vector3 = new THREE.Vector3(), // Needed for PointLight
-	_centroid = new THREE.Vector3(),
-	_normal = new THREE.Vector3(),
-	_normalViewMatrix = new THREE.Matrix3();
+		_vector3 = new THREE.Vector3(), // Needed for PointLight
+		_centroid = new THREE.Vector3(),
+		_normal = new THREE.Vector3(),
+		_normalViewMatrix = new THREE.Matrix3();
 
 	/* TODO
 	_canvas.mozImageSmoothingEnabled = false;
@@ -266,10 +258,10 @@ THREE.CanvasRenderer = function ( parameters ) {
 			_clearBox.intersect( _clipBox );
 			_clearBox.expandByScalar( 2 );
 
-			_clearBox.min.x = _clearBox.min.x + _canvasWidthHalf;
-			_clearBox.min.y =  - _clearBox.min.y + _canvasHeightHalf;		// higher y value !
-			_clearBox.max.x = _clearBox.max.x + _canvasWidthHalf;
-			_clearBox.max.y =  - _clearBox.max.y + _canvasHeightHalf;		// lower y value !
+			_clearBox.min.x =   _clearBox.min.x + _canvasWidthHalf;
+			_clearBox.min.y = - _clearBox.min.y + _canvasHeightHalf;		// higher y value !
+			_clearBox.max.x =   _clearBox.max.x + _canvasWidthHalf;
+			_clearBox.max.y = - _clearBox.max.y + _canvasHeightHalf;		// lower y value !
 
 			if ( _clearAlpha < 1 ) {
 
@@ -312,7 +304,7 @@ THREE.CanvasRenderer = function ( parameters ) {
 
 	this.render = function ( scene, camera ) {
 
-		if ( camera instanceof THREE.Camera === false ) {
+		if ( camera.isCamera === undefined ) {
 
 			console.error( 'THREE.CanvasRenderer.render: camera is not an instance of THREE.Camera.' );
 			return;
@@ -341,7 +333,6 @@ THREE.CanvasRenderer = function ( parameters ) {
 		_renderData = _projector.projectScene( scene, camera, this.sortObjects, this.sortElements );
 		_elements = _renderData.elements;
 		_lights = _renderData.lights;
-		_camera = camera;
 
 		_normalViewMatrix.getNormalMatrix( camera.matrixWorldInverse );
 
@@ -454,17 +445,17 @@ THREE.CanvasRenderer = function ( parameters ) {
 			var light = _lights[ l ];
 			var lightColor = light.color;
 
-			if ( light instanceof THREE.AmbientLight ) {
+			if ( light.isAmbientLight ) {
 
 				_ambientLight.add( lightColor );
 
-			} else if ( light instanceof THREE.DirectionalLight ) {
+			} else if ( light.isDirectionalLight ) {
 
 				// for sprites
 
 				_directionalLights.add( lightColor );
 
-			} else if ( light instanceof THREE.PointLight ) {
+			} else if ( light.isPointLight ) {
 
 				// for sprites
 
@@ -484,7 +475,7 @@ THREE.CanvasRenderer = function ( parameters ) {
 
 			_lightColor.copy( light.color );
 
-			if ( light instanceof THREE.DirectionalLight ) {
+			if ( light.isDirectionalLight ) {
 
 				var lightPosition = _vector3.setFromMatrixPosition( light.matrixWorld ).normalize();
 
@@ -496,7 +487,7 @@ THREE.CanvasRenderer = function ( parameters ) {
 
 				color.add( _lightColor.multiplyScalar( amount ) );
 
-			} else if ( light instanceof THREE.PointLight ) {
+			} else if ( light.isPointLight ) {
 
 				var lightPosition = _vector3.setFromMatrixPosition( light.matrixWorld );
 
@@ -530,7 +521,7 @@ THREE.CanvasRenderer = function ( parameters ) {
 		_elemBox.min.set( v1.x - dist, v1.y - dist );
 		_elemBox.max.set( v1.x + dist, v1.y + dist );
 
-		if ( material instanceof THREE.SpriteMaterial ) {
+		if ( material.isSpriteMaterial ) {
 
 			var texture = material.map;
 
@@ -586,7 +577,7 @@ THREE.CanvasRenderer = function ( parameters ) {
 
 			}
 
-		} else if ( material instanceof THREE.SpriteCanvasMaterial ) {
+		} else if ( material.isSpriteCanvasMaterial ) {
 
 			setStrokeStyle( material.color.getStyle() );
 			setFillStyle( material.color.getStyle() );
@@ -600,6 +591,17 @@ THREE.CanvasRenderer = function ( parameters ) {
 
 			_context.restore();
 
+		} else if ( material.isPointsMaterial ) {
+
+			setFillStyle( material.color.getStyle() );
+
+			_context.save();
+			_context.translate( v1.x, v1.y );
+			if ( material.rotation !== 0 ) _context.rotate( material.rotation );
+			_context.scale( scaleX * material.size, - scaleY * material.size );
+			_context.fillRect( - 0.5, - 0.5, 1, 1 );
+			_context.restore();
+
 		}
 
 		/* DEBUG
@@ -623,7 +625,7 @@ THREE.CanvasRenderer = function ( parameters ) {
 		_context.moveTo( v1.positionScreen.x, v1.positionScreen.y );
 		_context.lineTo( v2.positionScreen.x, v2.positionScreen.y );
 
-		if ( material instanceof THREE.LineBasicMaterial ) {
+		if ( material.isLineBasicMaterial ) {
 
 			setLineWidth( material.linewidth );
 			setLineCap( material.linecap );
@@ -670,7 +672,7 @@ THREE.CanvasRenderer = function ( parameters ) {
 			_context.stroke();
 			_elemBox.expandByScalar( material.linewidth * 2 );
 
-		} else if ( material instanceof THREE.LineDashedMaterial ) {
+		} else if ( material.isLineDashedMaterial ) {
 
 			setLineWidth( material.linewidth );
 			setLineCap( material.linecap );
@@ -702,7 +704,7 @@ THREE.CanvasRenderer = function ( parameters ) {
 
 		drawTriangle( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y );
 
-		if ( ( material instanceof THREE.MeshLambertMaterial || material instanceof THREE.MeshPhongMaterial ) && material.map === null ) {
+		if ( ( material.isMeshLambertMaterial || material.isMeshPhongMaterial || material.isMeshStandardMaterial ) && material.map === null ) {
 
 			_diffuseColor.copy( material.color );
 			_emissiveColor.copy( material.emissive );
@@ -725,9 +727,7 @@ THREE.CanvasRenderer = function ( parameters ) {
 				 ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin )
 				 : fillPath( _color );
 
-		} else if ( material instanceof THREE.MeshBasicMaterial ||
-				    material instanceof THREE.MeshLambertMaterial ||
-				    material instanceof THREE.MeshPhongMaterial ) {
+		} else if ( material.isMeshBasicMaterial || material.isMeshLambertMaterial || material.isMeshPhongMaterial || material.isMeshStandardMaterial ) {
 
 			if ( material.map !== null ) {
 
@@ -776,7 +776,7 @@ THREE.CanvasRenderer = function ( parameters ) {
 
 			}
 
-		} else if ( material instanceof THREE.MeshNormalMaterial ) {
+		} else if ( material.isMeshNormalMaterial ) {
 
 			_normal.copy( element.normalModel ).applyMatrix3( _normalViewMatrix );
 
@@ -944,10 +944,10 @@ THREE.CanvasRenderer = function ( parameters ) {
 		// http://extremelysatisfactorytotalitarianism.com/blog/?p=2120
 
 		var a, b, c, d, e, f, det, idet,
-		offsetX = texture.offset.x / texture.repeat.x,
-		offsetY = texture.offset.y / texture.repeat.y,
-		width = texture.image.width * texture.repeat.x,
-		height = texture.image.height * texture.repeat.y;
+			offsetX = texture.offset.x / texture.repeat.x,
+			offsetY = texture.offset.y / texture.repeat.y,
+			width = texture.image.width * texture.repeat.x,
+			height = texture.image.height * texture.repeat.y;
 
 		u0 = ( u0 + offsetX ) * width;
 		v0 = ( v0 + offsetY ) * height;
@@ -985,6 +985,7 @@ THREE.CanvasRenderer = function ( parameters ) {
 
 	}
 
+	/*
 	function clipImage( x0, y0, x1, y1, x2, y2, u0, v0, u1, v1, u2, v2, image ) {
 
 		// http://extremelysatisfactorytotalitarianism.com/blog/?p=2120
@@ -1022,13 +1023,14 @@ THREE.CanvasRenderer = function ( parameters ) {
 		_context.restore();
 
 	}
+	*/
 
 	// Hide anti-alias gaps
 
 	function expand( v1, v2, pixels ) {
 
 		var x = v2.x - v1.x, y = v2.y - v1.y,
-		det = x * x + y * y, idet;
+			det = x * x + y * y, idet;
 
 		if ( det === 0 ) return;
 

+ 173 - 92
examples/js/renderers/Projector.js

@@ -99,33 +99,32 @@ THREE.RenderableSprite = function () {
 THREE.Projector = function () {
 
 	var _object, _objectCount, _objectPool = [], _objectPoolLength = 0,
-	_vertex, _vertexCount, _vertexPool = [], _vertexPoolLength = 0,
-	_face, _faceCount, _facePool = [], _facePoolLength = 0,
-	_line, _lineCount, _linePool = [], _linePoolLength = 0,
-	_sprite, _spriteCount, _spritePool = [], _spritePoolLength = 0,
+		_vertex, _vertexCount, _vertexPool = [], _vertexPoolLength = 0,
+		_face, _faceCount, _facePool = [], _facePoolLength = 0,
+		_line, _lineCount, _linePool = [], _linePoolLength = 0,
+		_sprite, _spriteCount, _spritePool = [], _spritePoolLength = 0,
 
-	_renderData = { objects: [], lights: [], elements: [] },
+		_renderData = { objects: [], lights: [], elements: [] },
 
-	_vector3 = new THREE.Vector3(),
-	_vector4 = new THREE.Vector4(),
+		_vector3 = new THREE.Vector3(),
+		_vector4 = new THREE.Vector4(),
 
-	_clipBox = new THREE.Box3( new THREE.Vector3( - 1, - 1, - 1 ), new THREE.Vector3( 1, 1, 1 ) ),
-	_boundingBox = new THREE.Box3(),
-	_points3 = new Array( 3 ),
-	_points4 = new Array( 4 ),
+		_clipBox = new THREE.Box3( new THREE.Vector3( - 1, - 1, - 1 ), new THREE.Vector3( 1, 1, 1 ) ),
+		_boundingBox = new THREE.Box3(),
+		_points3 = new Array( 3 ),
 
-	_viewMatrix = new THREE.Matrix4(),
-	_viewProjectionMatrix = new THREE.Matrix4(),
+		_viewMatrix = new THREE.Matrix4(),
+		_viewProjectionMatrix = new THREE.Matrix4(),
 
-	_modelMatrix,
-	_modelViewProjectionMatrix = new THREE.Matrix4(),
+		_modelMatrix,
+		_modelViewProjectionMatrix = new THREE.Matrix4(),
 
-	_normalMatrix = new THREE.Matrix3(),
+		_normalMatrix = new THREE.Matrix3(),
 
-	_frustum = new THREE.Frustum(),
+		_frustum = new THREE.Frustum(),
 
-	_clippedVertex1PositionScreen = new THREE.Vector4(),
-	_clippedVertex2PositionScreen = new THREE.Vector4();
+		_clippedVertex1PositionScreen = new THREE.Vector4(),
+		_clippedVertex2PositionScreen = new THREE.Vector4();
 
 	//
 
@@ -143,7 +142,7 @@ THREE.Projector = function () {
 
 	};
 
-	this.pickingRay = function ( vector, camera ) {
+	this.pickingRay = function () {
 
 		console.error( 'THREE.Projector: .pickingRay() is now raycaster.setFromCamera().' );
 
@@ -154,6 +153,7 @@ THREE.Projector = function () {
 	var RenderList = function () {
 
 		var normals = [];
+		var colors = [];
 		var uvs = [];
 
 		var object = null;
@@ -169,6 +169,7 @@ THREE.Projector = function () {
 			normalMatrix.getNormalMatrix( object.matrixWorld );
 
 			normals.length = 0;
+			colors.length = 0;
 			uvs.length = 0;
 
 		}
@@ -209,6 +210,12 @@ THREE.Projector = function () {
 
 		}
 
+		function pushColor( r, g, b ) {
+
+			colors.push( r, g, b );
+
+		}
+
 		function pushUv( x, y ) {
 
 			uvs.push( x, y );
@@ -241,17 +248,36 @@ THREE.Projector = function () {
 			var v1 = _vertexPool[ a ];
 			var v2 = _vertexPool[ b ];
 
-			_line = getNextLineInPool();
+			// Clip
+
+			v1.positionScreen.copy( v1.position ).applyMatrix4( _modelViewProjectionMatrix );
+			v2.positionScreen.copy( v2.position ).applyMatrix4( _modelViewProjectionMatrix );
+
+			if ( clipLine( v1.positionScreen, v2.positionScreen ) === true ) {
 
-			_line.id = object.id;
-			_line.v1.copy( v1 );
-			_line.v2.copy( v2 );
-			_line.z = ( v1.positionScreen.z + v2.positionScreen.z ) / 2;
-			_line.renderOrder = object.renderOrder;
+				// Perform the perspective divide
+				v1.positionScreen.multiplyScalar( 1 / v1.positionScreen.w );
+				v2.positionScreen.multiplyScalar( 1 / v2.positionScreen.w );
 
-			_line.material = object.material;
+				_line = getNextLineInPool();
+				_line.id = object.id;
+				_line.v1.copy( v1 );
+				_line.v2.copy( v2 );
+				_line.z = Math.max( v1.positionScreen.z, v2.positionScreen.z );
+				_line.renderOrder = object.renderOrder;
 
-			_renderData.elements.push( _line );
+				_line.material = object.material;
+
+				if ( object.material.vertexColors === THREE.VertexColors ) {
+
+					_line.vertexColors[ 0 ].fromArray( colors, a * 3 );
+					_line.vertexColors[ 1 ].fromArray( colors, b * 3 );
+
+				}
+
+				_renderData.elements.push( _line );
+
+			}
 
 		}
 
@@ -307,76 +333,89 @@ THREE.Projector = function () {
 			checkBackfaceCulling: checkBackfaceCulling,
 			pushVertex: pushVertex,
 			pushNormal: pushNormal,
+			pushColor: pushColor,
 			pushUv: pushUv,
 			pushLine: pushLine,
 			pushTriangle: pushTriangle
-		}
+		};
 
 	};
 
 	var renderList = new RenderList();
 
-	this.projectScene = function ( scene, camera, sortObjects, sortElements ) {
+	function projectObject( object ) {
 
-		_faceCount = 0;
-		_lineCount = 0;
-		_spriteCount = 0;
+		if ( object.visible === false ) return;
 
-		_renderData.elements.length = 0;
+		if ( object instanceof THREE.Light ) {
 
-		if ( scene.autoUpdate === true ) scene.updateMatrixWorld();
-		if ( camera.parent === null ) camera.updateMatrixWorld();
+			_renderData.lights.push( object );
 
-		_viewMatrix.copy( camera.matrixWorldInverse.getInverse( camera.matrixWorld ) );
-		_viewProjectionMatrix.multiplyMatrices( camera.projectionMatrix, _viewMatrix );
+		} else if ( object instanceof THREE.Mesh || object instanceof THREE.Line || object instanceof THREE.Points ) {
 
-		_frustum.setFromMatrix( _viewProjectionMatrix );
+			if ( object.material.visible === false ) return;
+			if ( object.frustumCulled === true && _frustum.intersectsObject( object ) === false ) return;
 
-		//
+			addObject( object );
 
-		_objectCount = 0;
+		} else if ( object instanceof THREE.Sprite ) {
 
-		_renderData.objects.length = 0;
-		_renderData.lights.length = 0;
+			if ( object.material.visible === false ) return;
+			if ( object.frustumCulled === true && _frustum.intersectsSprite( object ) === false ) return;
+
+			addObject( object );
 
-		function addObject( object ) {
+		}
 
-			_object = getNextObjectInPool();
-			_object.id = object.id;
-			_object.object = object;
+		var children = object.children;
 
-			_vector3.setFromMatrixPosition( object.matrixWorld );
-			_vector3.applyMatrix4( _viewProjectionMatrix );
-			_object.z = _vector3.z;
-			_object.renderOrder = object.renderOrder;
+		for ( var i = 0, l = children.length; i < l; i ++ ) {
 
-			_renderData.objects.push( _object );
+			projectObject( children[ i ] );
 
 		}
 
-		scene.traverseVisible( function ( object ) {
+	}
 
-			if ( object instanceof THREE.Light ) {
+	function addObject( object ) {
 
-				_renderData.lights.push( object );
+		_object = getNextObjectInPool();
+		_object.id = object.id;
+		_object.object = object;
 
-			} else if ( object instanceof THREE.Mesh || object instanceof THREE.Line ) {
+		_vector3.setFromMatrixPosition( object.matrixWorld );
+		_vector3.applyMatrix4( _viewProjectionMatrix );
+		_object.z = _vector3.z;
+		_object.renderOrder = object.renderOrder;
 
-				if ( object.material.visible === false ) return;
-				if ( object.frustumCulled === true && _frustum.intersectsObject( object ) === false ) return;
+		_renderData.objects.push( _object );
 
-				addObject( object );
+	}
 
-			} else if ( object instanceof THREE.Sprite ) {
+	this.projectScene = function ( scene, camera, sortObjects, sortElements ) {
 
-				if ( object.material.visible === false ) return;
-				if ( object.frustumCulled === true && _frustum.intersectsSprite( object ) === false ) return;
+		_faceCount = 0;
+		_lineCount = 0;
+		_spriteCount = 0;
 
-				addObject( object );
+		_renderData.elements.length = 0;
 
-			}
+		if ( scene.autoUpdate === true ) scene.updateMatrixWorld();
+		if ( camera.parent === null ) camera.updateMatrixWorld();
+
+		_viewMatrix.copy( camera.matrixWorldInverse.getInverse( camera.matrixWorld ) );
+		_viewProjectionMatrix.multiplyMatrices( camera.projectionMatrix, _viewMatrix );
+
+		_frustum.setFromMatrix( _viewProjectionMatrix );
 
-		} );
+		//
+
+		_objectCount = 0;
+
+		_renderData.objects.length = 0;
+		_renderData.lights.length = 0;
+
+		projectObject( scene );
 
 		if ( sortObjects === true ) {
 
@@ -386,9 +425,11 @@ THREE.Projector = function () {
 
 		//
 
-		for ( var o = 0, ol = _renderData.objects.length; o < ol; o ++ ) {
+		var objects = _renderData.objects;
+
+		for ( var o = 0, ol = objects.length; o < ol; o ++ ) {
 
-			var object = _renderData.objects[ o ].object;
+			var object = objects[ o ].object;
 			var geometry = object.geometry;
 
 			renderList.setObject( object );
@@ -609,6 +650,8 @@ THREE.Projector = function () {
 
 			} else if ( object instanceof THREE.Line ) {
 
+				_modelViewProjectionMatrix.multiplyMatrices( _viewProjectionMatrix, _modelMatrix );
+
 				if ( geometry instanceof THREE.BufferGeometry ) {
 
 					var attributes = geometry.attributes;
@@ -623,6 +666,18 @@ THREE.Projector = function () {
 
 						}
 
+						if ( attributes.color !== undefined ) {
+
+							var colors = attributes.color.array;
+
+							for ( var i = 0, l = colors.length; i < l; i += 3 ) {
+
+								renderList.pushColor( colors[ i ], colors[ i + 1 ], colors[ i + 2 ] );
+
+							}
+
+						}
+
 						if ( geometry.index !== null ) {
 
 							var indices = geometry.index.array;
@@ -649,8 +704,6 @@ THREE.Projector = function () {
 
 				} else if ( geometry instanceof THREE.Geometry ) {
 
-					_modelViewProjectionMatrix.multiplyMatrices( _viewProjectionMatrix, _modelMatrix );
-
 					var vertices = object.geometry.vertices;
 
 					if ( vertices.length === 0 ) continue;
@@ -704,36 +757,34 @@ THREE.Projector = function () {
 
 				}
 
-			} else if ( object instanceof THREE.Sprite ) {
+			} else if ( object instanceof THREE.Points ) {
 
-				_vector4.set( _modelMatrix.elements[ 12 ], _modelMatrix.elements[ 13 ], _modelMatrix.elements[ 14 ], 1 );
-				_vector4.applyMatrix4( _viewProjectionMatrix );
+				_modelViewProjectionMatrix.multiplyMatrices( _viewProjectionMatrix, _modelMatrix );
 
-				var invW = 1 / _vector4.w;
+				if ( geometry instanceof THREE.Geometry ) {
 
-				_vector4.z *= invW;
-
-				if ( _vector4.z >= - 1 && _vector4.z <= 1 ) {
+					var vertices = object.geometry.vertices;
 
-					_sprite = getNextSpriteInPool();
-					_sprite.id = object.id;
-					_sprite.x = _vector4.x * invW;
-					_sprite.y = _vector4.y * invW;
-					_sprite.z = _vector4.z;
-					_sprite.renderOrder = object.renderOrder;
-					_sprite.object = object;
+					for ( var v = 0, vl = vertices.length; v < vl; v ++ ) {
 
-					_sprite.rotation = object.rotation;
+						var vertex = vertices[ v ];
 
-					_sprite.scale.x = object.scale.x * Math.abs( _sprite.x - ( _vector4.x + camera.projectionMatrix.elements[ 0 ] ) / ( _vector4.w + camera.projectionMatrix.elements[ 12 ] ) );
-					_sprite.scale.y = object.scale.y * Math.abs( _sprite.y - ( _vector4.y + camera.projectionMatrix.elements[ 5 ] ) / ( _vector4.w + camera.projectionMatrix.elements[ 13 ] ) );
+						_vector4.set( vertex.x, vertex.y, vertex.z, 1 );
+						_vector4.applyMatrix4( _modelViewProjectionMatrix );
 
-					_sprite.material = object.material;
+						pushPoint( _vector4, object, camera );
 
-					_renderData.elements.push( _sprite );
+					}
 
 				}
 
+			} else if ( object instanceof THREE.Sprite ) {
+
+				_vector4.set( _modelMatrix.elements[ 12 ], _modelMatrix.elements[ 13 ], _modelMatrix.elements[ 14 ], 1 );
+				_vector4.applyMatrix4( _viewProjectionMatrix );
+
+				pushPoint( _vector4, object, camera );
+
 			}
 
 		}
@@ -748,6 +799,35 @@ THREE.Projector = function () {
 
 	};
 
+	function pushPoint( _vector4, object, camera ) {
+
+		var invW = 1 / _vector4.w;
+
+		_vector4.z *= invW;
+
+		if ( _vector4.z >= - 1 && _vector4.z <= 1 ) {
+
+			_sprite = getNextSpriteInPool();
+			_sprite.id = object.id;
+			_sprite.x = _vector4.x * invW;
+			_sprite.y = _vector4.y * invW;
+			_sprite.z = _vector4.z;
+			_sprite.renderOrder = object.renderOrder;
+			_sprite.object = object;
+
+			_sprite.rotation = object.rotation;
+
+			_sprite.scale.x = object.scale.x * Math.abs( _sprite.x - ( _vector4.x + camera.projectionMatrix.elements[ 0 ] ) / ( _vector4.w + camera.projectionMatrix.elements[ 12 ] ) );
+			_sprite.scale.y = object.scale.y * Math.abs( _sprite.y - ( _vector4.y + camera.projectionMatrix.elements[ 5 ] ) / ( _vector4.w + camera.projectionMatrix.elements[ 13 ] ) );
+
+			_sprite.material = object.material;
+
+			_renderData.elements.push( _sprite );
+
+		}
+
+	}
+
 	// Pools
 
 	function getNextObjectInPool() {
@@ -861,10 +941,11 @@ THREE.Projector = function () {
 
 		// Calculate the boundary coordinate of each vertex for the near and far clip planes,
 		// Z = -1 and Z = +1, respectively.
-		bc1near =  s1.z + s1.w,
-		bc2near =  s2.z + s2.w,
-		bc1far =  - s1.z + s1.w,
-		bc2far =  - s2.z + s2.w;
+
+			bc1near = s1.z + s1.w,
+			bc2near = s2.z + s2.w,
+			bc1far = - s1.z + s1.w,
+			bc2far = - s2.z + s2.w;
 
 		if ( bc1near >= 0 && bc2near >= 0 && bc1far >= 0 && bc2far >= 0 ) {
 

+ 121 - 134
examples/js/renderers/WebGLDeferredRenderer.js

@@ -67,8 +67,7 @@ THREE.WebGLDeferredRenderer = function ( parameters ) {
 	var _lightPrePass = false;
 	var _cacheKeepAlive = false;
 
-	var _invisibleMaterial = new THREE.ShaderMaterial( { visible: false } );
-
+	var _tmpMaterial = new THREE.ShaderMaterial( { visible: false } );
 	var _tmpVector3 = new THREE.Vector3();
 
 	// scene/material/light cache for deferred rendering.
@@ -80,13 +79,12 @@ THREE.WebGLDeferredRenderer = function ( parameters ) {
 	var _lightScenesCache = {};
 	var _lightFullscreenScenesCache = {};
 
-	// originalMaterial.uuid -> deferredMaterial
-	// (no mapping from children of MultiMaterial)
+	// object.material.uuid -> deferredMaterial or
+	// object.material[ n ].uuid -> deferredMaterial
 	var _normalDepthMaterialsCache = {};
 	var _normalDepthShininessMaterialsCache = {};
 	var _colorMaterialsCache = {};
 	var _reconstructionMaterialsCache = {};
-	var _invisibleMultiMaterialsCache = {};
 
 	// originalLight.uuid -> deferredLight
 	var _deferredLightsCache = {};
@@ -97,8 +95,8 @@ THREE.WebGLDeferredRenderer = function ( parameters ) {
 
 	var _removeThresholdCount = 60;
 
-	// object.uuid -> originalMaterial
-	// deferred materials.uuid -> originalMaterial
+	// deferredMaterials.uuid -> object.material or
+	// deferredMaterials.uuid -> object.material[ n ]
 	// save before render and release after render.
 	var _originalMaterialsTable = {};
 
@@ -106,6 +104,11 @@ THREE.WebGLDeferredRenderer = function ( parameters ) {
 	// save before render and release after render.
 	var _originalOnBeforeRendersTable = {};
 
+	// object.material.uuid -> object.material.visible or
+	// object.material[ i ].uuid -> object.material[ i ].visible or
+	// save before render and release after render.
+	var _originalVisibleTable = {};
+
 	// external properties
 
 	this.renderer = undefined;
@@ -328,70 +331,73 @@ THREE.WebGLDeferredRenderer = function ( parameters ) {
 
 	}
 
-	function getMaterialFromCacheOrCreate( originalMaterial, cache, func ) {
+	function getMaterialFromCacheOrCreate( originalMaterial, cache, createFunc, updateFunc ) {
 
 		var data = cache[ originalMaterial.uuid ];
 
 		if ( data === undefined ) {
 
 			data = createCacheData();
+			data.material = createFunc( originalMaterial );
+			cache[ originalMaterial.uuid ] = data;
 
-			var material;
+		}
 
-			if ( originalMaterial.isMultiMaterial === true ) {
+		data.used = true;
 
-				var materials = [];
+		updateFunc( data.material, originalMaterial );
 
-				for ( var i = 0, il = originalMaterial.materials.length; i < il; i ++ ) {
+		_originalMaterialsTable[ data.material.uuid ] = originalMaterial;
 
-					materials.push( func( originalMaterial.materials[ i ] ) );
+		return data.material;
 
-				}
+	}
 
-				material = new THREE.MultiMaterial( materials );
+	function overrideMaterialAndOnBeforeRender( object, getMaterialFunc, onBeforeRender ) {
 
-			} else {
+		if ( object.material === undefined ) return;
+
+		if ( Array.isArray( object.material ) ) {
 
-				material = func( originalMaterial );
+			for ( var i = 0, il = object.material.length; i < il; i ++ ) {
+
+				object.material[ i ] = getMaterialFunc( object.material[ i ] );
 
 			}
 
-			data.material = material;
+		} else {
 
-			cache[ originalMaterial.uuid ] = data;
+			object.material = getMaterialFunc( object.material );
 
 		}
 
-		return data.material;
+		object.onBeforeRender = onBeforeRender;
 
 	}
 
-	function setMaterialNormalDepth( object ) {
+	function restoreOriginalMaterial( object ) {
 
 		if ( object.material === undefined ) return;
 
-		var originalMaterial = _originalMaterialsTable[ object.uuid ];
-		var material = getNormalDepthMaterial( originalMaterial );
-
-		_originalMaterialsTable[ material.uuid ] = originalMaterial;
+		if ( Array.isArray( object.material ) ) {
 
-		if ( material.isMultiMaterial === true ) {
+			for ( var i = 0, il = object.material.length; i < il; i ++ ) {
 
-			for ( var i = 0, il = material.materials.length; i < il; i ++ ) {
-
-				_originalMaterialsTable[ material.materials[ i ].uuid ] = originalMaterial.materials[ i ];
-				updateDeferredNormalDepthMaterial( material.materials[ i ], originalMaterial.materials[ i ] );
+				object.material[ i ] = _originalMaterialsTable[ object.material[ i ].uuid ];
 
 			}
 
 		} else {
 
-			updateDeferredNormalDepthMaterial( material, originalMaterial );
+			object.material = _originalMaterialsTable[ object.material.uuid ];
 
 		}
 
-		object.material = material;
-		object.onBeforeRender = updateDeferredNormalDepthUniforms;
+	}
+
+	function setMaterialNormalDepth( object ) {
+
+		overrideMaterialAndOnBeforeRender( object, getNormalDepthMaterial, updateDeferredNormalDepthUniforms );
 
 	}
 
@@ -400,7 +406,8 @@ THREE.WebGLDeferredRenderer = function ( parameters ) {
 		return getMaterialFromCacheOrCreate(
 			originalMaterial,
 			( _lightPrePass ) ? _normalDepthShininessMaterialsCache : _normalDepthMaterialsCache,
-			createDeferredNormalDepthMaterial
+			createDeferredNormalDepthMaterial,
+			updateDeferredNormalDepthMaterial
 		);
 
 	}
@@ -420,6 +427,7 @@ THREE.WebGLDeferredRenderer = function ( parameters ) {
 
 	function updateDeferredNormalDepthMaterial( material, originalMaterial ) {
 
+		if ( originalMaterial.skinning !== undefined ) material.skinning = originalMaterial.skinning;
 		if ( originalMaterial.morphTargets !== undefined ) material.morphTargets = originalMaterial.morphTargets;
 
 		if ( originalMaterial.visible === true ) {
@@ -448,30 +456,7 @@ THREE.WebGLDeferredRenderer = function ( parameters ) {
 
 	function setMaterialColor( object ) {
 
-		if ( object.material === undefined ) return;
-
-		var originalMaterial = _originalMaterialsTable[ object.uuid ];
-		var material = getColorMaterial( originalMaterial );
-
-		_originalMaterialsTable[ material.uuid ] = originalMaterial;
-
-		if ( originalMaterial.isMultiMaterial === true ) {
-
-			for ( var i = 0, il = originalMaterial.materials.length; i < il; i ++ ) {
-
-				_originalMaterialsTable[ material.materials[ i ].uuid ] = originalMaterial.materials[ i ];
-				updateDeferredColorMaterial( material.materials[ i ], originalMaterial.materials[ i ] );
-
-			}
-
-		} else {
-
-			updateDeferredColorMaterial( material, originalMaterial );
-
-		}
-
-		object.material = material;
-		object.onBeforeRender = updateDeferredColorUniforms;
+		overrideMaterialAndOnBeforeRender( object, getColorMaterial, updateDeferredColorUniforms );
 
 	}
 
@@ -480,7 +465,8 @@ THREE.WebGLDeferredRenderer = function ( parameters ) {
 		return getMaterialFromCacheOrCreate(
 			originalMaterial,
 			_colorMaterialsCache,
-			createDeferredColorMaterial
+			createDeferredColorMaterial,
+			updateDeferredColorMaterial
 		);
 
 	}
@@ -505,6 +491,7 @@ THREE.WebGLDeferredRenderer = function ( parameters ) {
 	function updateDeferredColorMaterial( material, originalMaterial ) {
 
 		if ( originalMaterial.map !== undefined ) material.map = originalMaterial.map;
+		if ( originalMaterial.skinning !== undefined ) material.skinning = originalMaterial.skinning;
 		if ( originalMaterial.morphTargets !== undefined ) material.morphTargets = originalMaterial.morphTargets;
 
 		if ( originalMaterial.visible === true ) {
@@ -551,48 +538,24 @@ THREE.WebGLDeferredRenderer = function ( parameters ) {
 
 	function setMaterialReconstruction( object ) {
 
-		if ( object.material === undefined ) return;
-
-		var originalMaterial = _originalMaterialsTable[ object.uuid ];
-
-		if ( originalMaterial.transparent === true ) {
-
-			object.material = originalMaterial;
-			object.onBeforeRender = _originalOnBeforeRendersTable[ object.uuid ];
-
-			return;
-
-		}
-
-		var material = getReconstructionMaterial( originalMaterial );
-		_originalMaterialsTable[ material.uuid ] = originalMaterial;
+		overrideMaterialAndOnBeforeRender( object, getReconstructionMaterial, updateDeferredReconstructionUniforms );
 
-		if ( originalMaterial.isMultiMaterial === true ) {
-
-			for ( var i = 0, il = originalMaterial.materials.length; i < il; i ++ ) {
-
-				_originalMaterialsTable[ material.materials[ i ].uuid ] = originalMaterial.materials[ i ];
-				updateDeferredReconstructionMaterial( material.materials[ i ], originalMaterial.materials[ i ] );
+	}
 
-			}
+	function getReconstructionMaterial( originalMaterial ) {
 
-		} else {
+		if ( originalMaterial.transparent === true ) {
 
-			updateDeferredReconstructionMaterial( material, originalMaterial );
+			_originalMaterialsTable[ originalMaterial.uuid ] = originalMaterial;
+			return originalMaterial;
 
 		}
 
-		object.material = material;
-		object.onBeforeRender = updateDeferredReconstructionUniforms;
-
-	}
-
-	function getReconstructionMaterial( originalMaterial ) {
-
 		return getMaterialFromCacheOrCreate(
 			originalMaterial,
 			_reconstructionMaterialsCache,
-			createDeferredReconstructionMaterial
+			createDeferredReconstructionMaterial,
+			updateDeferredReconstructionMaterial
 		);
 
 	}
@@ -622,65 +585,72 @@ THREE.WebGLDeferredRenderer = function ( parameters ) {
 
 	function updateDeferredReconstructionUniforms( renderer, scene, camera, geometry, material, group ) {
 
+		if ( material.transparent === true ) {
+
+			// 'this' is object here because this method is set as object.onBefore()
+			var onBeforeRender = _originalOnBeforeRendersTable[ this.uuid ];
+
+			if ( onBeforeRender ) {
+
+				onBeforeRender.call( this, renderer, scene, camera, geometry, material, group );
+
+			}
+
+			return;
+
+		}
+
 		updateDeferredColorUniforms( renderer, scene, camera, geometry, material, group );
 
 		material.uniforms.samplerLight.value = _compLight.renderTarget2.texture;
 
 	}
 
-	function setMaterialForwardRendering( object ) {
+	function setVisibleForForwardRendering( object ) {
 
 		if ( object.material === undefined ) return;
 
-		var originalMaterial = _originalMaterialsTable[ object.uuid ];
+		if ( Array.isArray( object.material ) ) {
 
-		if ( originalMaterial.isMultiMaterial === true ) {
+			for ( var i = 0, il = object.material.length; i < il; i ++ ) {
 
-			var material = getInvisibleMultiMaterial( originalMaterial );
+				if ( _originalVisibleTable[ object.material[ i ].uuid ] === undefined ) {
 
-			for ( var i = 0, il = originalMaterial.materials.length; i < il; i ++ ) {
+					_originalVisibleTable[ object.material[ i ].uuid ] = object.material[ i ].visible;
+					object.material[ i ].visible = object.material[ i ].transparent && object.material[ i ].visible;
 
-				material.materials[ i ] = getForwardRenderingMaterial( originalMaterial.materials[ i ] );
+				}
 
 			}
 
-			object.material = material;
-
 		} else {
 
-			object.material = getForwardRenderingMaterial( originalMaterial );
+			if ( _originalVisibleTable[ object.material.uuid ] === undefined ) {
 
-		}
+				_originalVisibleTable[ object.material.uuid ] = object.material.visible;
+				object.material.visible = object.material.transparent && object.material.visible;
 
-		object.onBeforeRender = _originalOnBeforeRendersTable[ object.uuid ];
-
-	}
-
-	function getInvisibleMultiMaterial( originalMaterial ) {
+			}
 
-		return getMaterialFromCacheOrCreate(
-			originalMaterial,
-			_invisibleMultiMaterialsCache,
-			createInvisibleMaterial
-		);
+		}
 
 	}
 
-	function createInvisibleMaterial( originalMaterial ) {
+	function restoreVisible( object ) {
 
-		return _invisibleMaterial;
+		if ( object.material === undefined ) return;
 
-	}
+		if ( Array.isArray( object.material ) ) {
 
-	function getForwardRenderingMaterial( originalMaterial ) {
+			for ( var i = 0, il = object.material.length; i < il; i ++ ) {
 
-		if ( originalMaterial.transparent === true && originalMaterial.visible === true ) {
+				object.material[ i ].visible = _originalVisibleTable[ object.material[ i ].uuid ];
 
-			return originalMaterial;
+			}
 
 		} else {
 
-			return _invisibleMaterial;
+			object.material.visible = _originalVisibleTable[ object.material.uuid ];
 
 		}
 
@@ -761,11 +731,12 @@ THREE.WebGLDeferredRenderer = function ( parameters ) {
 
 			data = createCacheData();
 			data.material = createDeferredLightMaterial( light.userData.originalLight );
-
 			cache[ light.uuid ] = data;
 
 		}
 
+		data.used = true;
+
 		return data.material;
 
 	}
@@ -784,7 +755,7 @@ THREE.WebGLDeferredRenderer = function ( parameters ) {
 
 	function createDeferredLightMesh( light, geometry ) {
 
-		var mesh = new THREE.Mesh( geometry, _invisibleMaterial );
+		var mesh = new THREE.Mesh( geometry, _tmpMaterial );
 
 		mesh.userData.originalLight = light;
 
@@ -973,21 +944,22 @@ THREE.WebGLDeferredRenderer = function ( parameters ) {
 
 	}
 
-	function saveOriginalMaterialAndCheckTransparency( object ) {
+	function saveOriginalOnBeforeRenderAndCheckTransparency( object ) {
 
 		if ( object.material === undefined ) return;
 
-		_originalMaterialsTable[ object.uuid ] = object.material;
 		_originalOnBeforeRendersTable[ object.uuid ] = object.onBeforeRender;
 
 		// _hasTransparentObject is used only for Classic Deferred Rendering
 		if ( _hasTransparentObject || _lightPrePass ) return;
 
-		if ( object.material.isMultiMaterial === true ) {
+		if ( ! object.visible ) return;
+
+		if ( Array.isArray( object.material ) ) {
 
-			for ( var i = 0, il = object.material.materials.length; i < il; i ++ ) {
+			for ( var i = 0, il = object.material.length; i < il; i ++ ) {
 
-				if ( object.material.materials[ i ].transparent === true ) {
+				if ( object.material[ i ].visible === true && object.material[ i ].transparent === true ) {
 
 					_hasTransparentObject = true;
 					break;
@@ -998,17 +970,16 @@ THREE.WebGLDeferredRenderer = function ( parameters ) {
 
 		} else {
 
-			if ( object.material.transparent === true ) _hasTransparentObject = true;
+			if ( object.material.visible === true && object.material.transparent === true ) _hasTransparentObject = true;
 
 		}
 
 	}
 
-	function restoreOriginalMaterial( object ) {
+	function restoreOriginalOnBeforeRender( object ) {
 
 		if ( object.material === undefined ) return;
 
-		object.material = _originalMaterialsTable[ object.uuid ];
 		object.onBeforeRender = _originalOnBeforeRendersTable[ object.uuid ];
 
 	}
@@ -1023,11 +994,12 @@ THREE.WebGLDeferredRenderer = function ( parameters ) {
 
 			data = createCacheData();
 			data.light = createDeferredLight( object );
-
 			_deferredLightsCache[ object.uuid ] = data;
 
 		}
 
+		data.used = true;
+
 		var light = data.light;
 
 		if ( light === null ) return;
@@ -1225,7 +1197,7 @@ THREE.WebGLDeferredRenderer = function ( parameters ) {
 
 	function cleanupTable( table ) {
 
-		var keys = Object.keys( cache );
+		var keys = Object.keys( table );
 
 		for ( var i = 0, il = keys.length; i < il; i ++ ) {
 
@@ -1245,13 +1217,13 @@ THREE.WebGLDeferredRenderer = function ( parameters ) {
 		cleanupCache( _normalDepthShininessMaterialsCache );
 		cleanupCache( _colorMaterialsCache );
 		cleanupCache( _reconstructionMaterialsCache );
-		cleanupCache( _invisibleMultiMaterialsCache );
 		cleanupCache( _classicDeferredLightMaterialsCache );
 		cleanupCache( _lightPrePassMaterialsCache );
 		cleanupCache( _deferredLightsCache );
 
 		cleanupTable( _originalMaterialsTable );
 		cleanupTable( _originalOnBeforeRendersTable );
+		cleanupTable( _originalVisibleTable );
 
 	}
 
@@ -1289,6 +1261,8 @@ THREE.WebGLDeferredRenderer = function ( parameters ) {
 
 		_compNormalDepth.render();
 
+		scene.traverse( restoreOriginalMaterial );
+
 	}
 
 	/*
@@ -1317,6 +1291,8 @@ THREE.WebGLDeferredRenderer = function ( parameters ) {
 
 		_compColor.render();
 
+		scene.traverse( restoreOriginalMaterial );
+
 	}
 
 	/*
@@ -1397,6 +1373,8 @@ THREE.WebGLDeferredRenderer = function ( parameters ) {
 
 		_gl.disable( _gl.STENCIL_TEST );
 
+		scene.traverse( restoreOriginalMaterial );
+
 	}
 
 	/*
@@ -1426,7 +1404,8 @@ THREE.WebGLDeferredRenderer = function ( parameters ) {
 
 		if ( ! _lightPrePass && _hasTransparentObject ) {
 
-			scene.traverse( setMaterialForwardRendering );
+			scene.traverse( setVisibleForForwardRendering );
+			scene.traverse( restoreOriginalOnBeforeRender );
 
 			_passForward.scene = scene;
 			_passForward.camera = camera;
@@ -1440,6 +1419,12 @@ THREE.WebGLDeferredRenderer = function ( parameters ) {
 
 		_compFinal.render();
 
+		if ( ! _lightPrePass && _hasTransparentObject ) {
+
+			scene.traverse( restoreVisible );
+
+		}
+
 	}
 
 	// external APIs
@@ -1504,7 +1489,7 @@ THREE.WebGLDeferredRenderer = function ( parameters ) {
 
 		_hasTransparentObject = false;
 
-		scene.traverse( saveOriginalMaterialAndCheckTransparency );
+		scene.traverse( saveOriginalOnBeforeRenderAndCheckTransparency );
 
 		updateDeferredCommonUniforms( camera );
 
@@ -1524,7 +1509,9 @@ THREE.WebGLDeferredRenderer = function ( parameters ) {
 
 		renderFinal( scene, camera );
 
-		scene.traverse( restoreOriginalMaterial );
+		scene.traverse( restoreOriginalOnBeforeRender );
+
+		cleanupCaches();
 
 		scene.autoUpdate = currentSceneAutoUpdate;
 		this.renderer.autoClearColor = currentAutoClearColor;

+ 2 - 2
examples/js/vr/WebVR.js

@@ -83,13 +83,13 @@ var WEBVR = {
 		button.style.textAlign = 'center';
 		button.style.zIndex = '999';
 		button.textContent = 'ENTER VR';
-		button.onclick = function() {
+		button.onclick = function () {
 
 			effect.isPresenting ? effect.exitPresent() : effect.requestPresent();
 
 		};
 
-		window.addEventListener( 'vrdisplaypresentchange', function ( event ) {
+		window.addEventListener( 'vrdisplaypresentchange', function () {
 
 			button.textContent = effect.isPresenting ? 'EXIT VR' : 'ENTER VR';
 

BIN
examples/models/gltf/RiggedSimple/glTF/RiggedSimple.bin


+ 588 - 0
examples/models/gltf/RiggedSimple/glTF/RiggedSimple.gltf

@@ -0,0 +1,588 @@
+{
+    "accessors": {
+        "IBM_Armature_Cylinder-skin": {
+            "bufferView": "bufferView_43",
+            "byteOffset": 0,
+            "componentType": 5126,
+            "count": 2,
+            "type": "MAT4"
+        },
+        "accessor_16": {
+            "bufferView": "bufferView_44",
+            "byteOffset": 0,
+            "byteStride": 0,
+            "componentType": 5123,
+            "count": 564,
+            "type": "SCALAR"
+        },
+        "accessor_18": {
+            "bufferView": "bufferView_45",
+            "byteOffset": 0,
+            "byteStride": 12,
+            "componentType": 5126,
+            "count": 96,
+            "max": [
+                1,
+                1,
+                4.57508
+            ],
+            "min": [
+                -1,
+                -1,
+                -4.57508
+            ],
+            "type": "VEC3"
+        },
+        "accessor_20": {
+            "bufferView": "bufferView_45",
+            "byteOffset": 1152,
+            "byteStride": 12,
+            "componentType": 5126,
+            "count": 96,
+            "max": [
+                0.998198,
+                0.998198,
+                0.688838
+            ],
+            "min": [
+                -0.998198,
+                -0.998198,
+                -0.644473
+            ],
+            "type": "VEC3"
+        },
+        "accessor_37": {
+            "bufferView": "bufferView_45",
+            "byteOffset": 3840,
+            "byteStride": 16,
+            "componentType": 5126,
+            "count": 96,
+            "max": [
+                1,
+                0.261398,
+                0,
+                0
+            ],
+            "min": [
+                0.738602,
+                0,
+                0,
+                0
+            ],
+            "type": "VEC4"
+        },
+        "accessor_40": {
+            "bufferView": "bufferView_45",
+            "byteOffset": 2304,
+            "byteStride": 16,
+            "componentType": 5126,
+            "count": 96,
+            "max": [
+                1,
+                1,
+                0,
+                0
+            ],
+            "min": [
+                0,
+                0,
+                0,
+                0
+            ],
+            "type": "VEC4"
+        },
+        "animAccessor_0": {
+            "bufferView": "bufferView_43",
+            "byteOffset": 128,
+            "componentType": 5126,
+            "count": 3,
+            "type": "SCALAR"
+        },
+        "animAccessor_1": {
+            "bufferView": "bufferView_43",
+            "byteOffset": 140,
+            "componentType": 5126,
+            "count": 3,
+            "type": "VEC3"
+        },
+        "animAccessor_2": {
+            "bufferView": "bufferView_43",
+            "byteOffset": 176,
+            "componentType": 5126,
+            "count": 3,
+            "type": "VEC3"
+        },
+        "animAccessor_3": {
+            "bufferView": "bufferView_43",
+            "byteOffset": 212,
+            "componentType": 5126,
+            "count": 3,
+            "type": "VEC4"
+        },
+        "animAccessor_4": {
+            "bufferView": "bufferView_43",
+            "byteOffset": 260,
+            "componentType": 5126,
+            "count": 3,
+            "type": "VEC3"
+        },
+        "animAccessor_5": {
+            "bufferView": "bufferView_43",
+            "byteOffset": 296,
+            "componentType": 5126,
+            "count": 3,
+            "type": "VEC3"
+        },
+        "animAccessor_6": {
+            "bufferView": "bufferView_43",
+            "byteOffset": 332,
+            "componentType": 5126,
+            "count": 3,
+            "type": "VEC4"
+        }
+    },
+    "animations": {
+        "animation_0": {
+            "channels": [
+                {
+                    "sampler": "animation_0_scale_sampler",
+                    "target": {
+                        "id": "Bone",
+                        "path": "scale"
+                    }
+                },
+                {
+                    "sampler": "animation_0_translation_sampler",
+                    "target": {
+                        "id": "Bone",
+                        "path": "translation"
+                    }
+                },
+                {
+                    "sampler": "animation_0_rotation_sampler",
+                    "target": {
+                        "id": "Bone",
+                        "path": "rotation"
+                    }
+                }
+            ],
+            "parameters": {
+                "TIME": "animAccessor_0",
+                "rotation": "animAccessor_3",
+                "scale": "animAccessor_1",
+                "translation": "animAccessor_2"
+            },
+            "samplers": {
+                "animation_0_rotation_sampler": {
+                    "input": "TIME",
+                    "interpolation": "LINEAR",
+                    "output": "rotation"
+                },
+                "animation_0_scale_sampler": {
+                    "input": "TIME",
+                    "interpolation": "LINEAR",
+                    "output": "scale"
+                },
+                "animation_0_translation_sampler": {
+                    "input": "TIME",
+                    "interpolation": "LINEAR",
+                    "output": "translation"
+                }
+            }
+        },
+        "animation_1": {
+            "channels": [
+                {
+                    "sampler": "animation_1_scale_sampler",
+                    "target": {
+                        "id": "Bone_001",
+                        "path": "scale"
+                    }
+                },
+                {
+                    "sampler": "animation_1_translation_sampler",
+                    "target": {
+                        "id": "Bone_001",
+                        "path": "translation"
+                    }
+                },
+                {
+                    "sampler": "animation_1_rotation_sampler",
+                    "target": {
+                        "id": "Bone_001",
+                        "path": "rotation"
+                    }
+                }
+            ],
+            "parameters": {
+                "TIME": "animAccessor_0",
+                "rotation": "animAccessor_6",
+                "scale": "animAccessor_4",
+                "translation": "animAccessor_5"
+            },
+            "samplers": {
+                "animation_1_rotation_sampler": {
+                    "input": "TIME",
+                    "interpolation": "LINEAR",
+                    "output": "rotation"
+                },
+                "animation_1_scale_sampler": {
+                    "input": "TIME",
+                    "interpolation": "LINEAR",
+                    "output": "scale"
+                },
+                "animation_1_translation_sampler": {
+                    "input": "TIME",
+                    "interpolation": "LINEAR",
+                    "output": "translation"
+                }
+            }
+        }
+    },
+    "asset": {
+        "generator": "collada2gltf@027f74366341d569dea42e9a68b7104cc3892054",
+        "premultipliedAlpha": true,
+        "profile": {
+            "api": "WebGL",
+            "version": "1.0.2"
+        },
+        "version": "1.0"
+    },
+    "bufferViews": {
+        "bufferView_43": {
+            "buffer": "RiggedSimple",
+            "byteLength": 380,
+            "byteOffset": 0
+        },
+        "bufferView_44": {
+            "buffer": "RiggedSimple",
+            "byteLength": 1128,
+            "byteOffset": 380,
+            "target": 34963
+        },
+        "bufferView_45": {
+            "buffer": "RiggedSimple",
+            "byteLength": 5376,
+            "byteOffset": 1508,
+            "target": 34962
+        }
+    },
+    "buffers": {
+        "RiggedSimple": {
+            "byteLength": 6884,
+            "type": "arraybuffer",
+            "uri": "RiggedSimple.bin"
+        }
+    },
+    "materials": {
+        "Material_001-effect": {
+            "name": "Material_001",
+            "technique": "technique0",
+            "values": {
+                "ambient": [
+                    0,
+                    0,
+                    0,
+                    1
+                ],
+                "diffuse": [
+                    0.279635,
+                    0.64,
+                    0.210944,
+                    1
+                ],
+                "emission": [
+                    0,
+                    0,
+                    0,
+                    1
+                ],
+                "shininess": 50,
+                "specular": [
+                    0.5,
+                    0.5,
+                    0.5,
+                    1
+                ]
+            }
+        }
+    },
+    "meshes": {
+        "Cylinder-mesh": {
+            "name": "Cylinder",
+            "primitives": [
+                {
+                    "attributes": {
+                        "JOINT": "accessor_40",
+                        "NORMAL": "accessor_20",
+                        "POSITION": "accessor_18",
+                        "WEIGHT": "accessor_37"
+                    },
+                    "indices": "accessor_16",
+                    "material": "Material_001-effect",
+                    "mode": 4
+                }
+            ]
+        }
+    },
+    "nodes": {
+        "Armature": {
+            "children": [
+                "Bone"
+            ],
+            "matrix": [
+                1,
+                0,
+                0,
+                0,
+                0,
+                1,
+                0,
+                0,
+                0,
+                0,
+                1,
+                0,
+                0,
+                0,
+                0,
+                1
+            ],
+            "name": "Armature"
+        },
+        "Bone": {
+            "children": [
+                "Bone_001"
+            ],
+            "jointName": "Bone",
+            "name": "Bone",
+            "rotation": [
+                0.70474,
+                0,
+                0,
+                0.709465
+            ],
+            "scale": [
+                1,
+                1,
+                1
+            ],
+            "translation": [
+                0,
+                -3.15606e-007,
+                -4.18033
+            ]
+        },
+        "Bone_001": {
+            "children": [],
+            "jointName": "Bone_001",
+            "name": "Bone.001",
+            "rotation": [
+                0.00205211,
+                9.94789e-008,
+                0.000291371,
+                0.999998
+            ],
+            "scale": [
+                1,
+                1,
+                1
+            ],
+            "translation": [
+                0,
+                4.18717,
+                0
+            ]
+        },
+        "Cylinder": {
+            "children": [],
+            "matrix": [
+                1,
+                0,
+                0,
+                0,
+                0,
+                1,
+                0,
+                0,
+                0,
+                0,
+                1,
+                0,
+                0,
+                0,
+                0,
+                1
+            ],
+            "meshes": [
+                "Cylinder-mesh"
+            ],
+            "name": "Cylinder",
+            "skeletons": [
+                "Bone"
+            ],
+            "skin": "Armature_Cylinder-skin"
+        },
+        "node_4": {
+            "children": [
+                "Armature",
+                "Cylinder"
+            ],
+            "matrix": [
+                1,
+                0,
+                0,
+                0,
+                0,
+                0,
+                -1,
+                0,
+                0,
+                1,
+                0,
+                0,
+                0,
+                0,
+                0,
+                1
+            ],
+            "name": "Y_UP_Transform"
+        }
+    },
+    "programs": {
+        "program_0": {
+            "attributes": [
+                "a_joint",
+                "a_normal",
+                "a_position",
+                "a_weight"
+            ],
+            "fragmentShader": "RiggedSimple0FS",
+            "vertexShader": "RiggedSimple0VS"
+        }
+    },
+    "scene": "defaultScene",
+    "scenes": {
+        "defaultScene": {
+            "nodes": [
+                "node_4"
+            ]
+        }
+    },
+    "shaders": {
+        "RiggedSimple0FS": {
+            "type": 35632,
+            "uri": "RiggedSimple0FS.glsl"
+        },
+        "RiggedSimple0VS": {
+            "type": 35633,
+            "uri": "RiggedSimple0VS.glsl"
+        }
+    },
+    "skins": {
+        "Armature_Cylinder-skin": {
+            "bindShapeMatrix": [
+                1,
+                0,
+                0,
+                0,
+                0,
+                1,
+                0,
+                0,
+                0,
+                0,
+                1,
+                0,
+                0,
+                0,
+                0,
+                1
+            ],
+            "inverseBindMatrices": "IBM_Armature_Cylinder-skin",
+            "jointNames": [
+                "Bone",
+                "Bone_001"
+            ],
+            "name": "Armature"
+        }
+    },
+    "techniques": {
+        "technique0": {
+            "attributes": {
+                "a_joint": "joint",
+                "a_normal": "normal",
+                "a_position": "position",
+                "a_weight": "weight"
+            },
+            "parameters": {
+                "ambient": {
+                    "type": 35666
+                },
+                "diffuse": {
+                    "type": 35666
+                },
+                "emission": {
+                    "type": 35666
+                },
+                "joint": {
+                    "semantic": "JOINT",
+                    "type": 35666
+                },
+                "jointMat": {
+                    "count": 2,
+                    "semantic": "JOINTMATRIX",
+                    "type": 35676
+                },
+                "modelViewMatrix": {
+                    "semantic": "MODELVIEW",
+                    "type": 35676
+                },
+                "normal": {
+                    "semantic": "NORMAL",
+                    "type": 35665
+                },
+                "normalMatrix": {
+                    "semantic": "MODELVIEWINVERSETRANSPOSE",
+                    "type": 35675
+                },
+                "position": {
+                    "semantic": "POSITION",
+                    "type": 35665
+                },
+                "projectionMatrix": {
+                    "semantic": "PROJECTION",
+                    "type": 35676
+                },
+                "shininess": {
+                    "type": 5126
+                },
+                "specular": {
+                    "type": 35666
+                },
+                "weight": {
+                    "semantic": "WEIGHT",
+                    "type": 35666
+                }
+            },
+            "program": "program_0",
+            "states": {
+                "enable": [
+                    2929,
+                    2884
+                ]
+            },
+            "uniforms": {
+                "u_ambient": "ambient",
+                "u_diffuse": "diffuse",
+                "u_emission": "emission",
+                "u_jointMat": "jointMat",
+                "u_modelViewMatrix": "modelViewMatrix",
+                "u_normalMatrix": "normalMatrix",
+                "u_projectionMatrix": "projectionMatrix",
+                "u_shininess": "shininess",
+                "u_specular": "specular"
+            }
+        }
+    }
+}

+ 24 - 0
examples/models/gltf/RiggedSimple/glTF/RiggedSimple0FS.glsl

@@ -0,0 +1,24 @@
+precision highp float;
+varying vec3 v_normal;
+uniform vec4 u_ambient;
+uniform vec4 u_diffuse;
+uniform vec4 u_emission;
+uniform vec4 u_specular;
+uniform float u_shininess;
+void main(void) {
+vec3 normal = normalize(v_normal);
+vec4 color = vec4(0., 0., 0., 0.);
+vec4 diffuse = vec4(0., 0., 0., 1.);
+vec4 emission;
+vec4 ambient;
+vec4 specular;
+ambient = u_ambient;
+diffuse = u_diffuse;
+emission = u_emission;
+specular = u_specular;
+diffuse.xyz *= max(dot(normal,vec3(0.,0.,1.)), 0.);
+color.xyz += diffuse.xyz;
+color.xyz += emission.xyz;
+color = vec4(color.rgb * diffuse.a, diffuse.a);
+gl_FragColor = color;
+}

+ 19 - 0
examples/models/gltf/RiggedSimple/glTF/RiggedSimple0VS.glsl

@@ -0,0 +1,19 @@
+precision highp float;
+attribute vec3 a_position;
+attribute vec3 a_normal;
+varying vec3 v_normal;
+attribute vec4 a_joint;
+attribute vec4 a_weight;
+uniform mat4 u_jointMat[2];
+uniform mat3 u_normalMatrix;
+uniform mat4 u_modelViewMatrix;
+uniform mat4 u_projectionMatrix;
+void main(void) {
+mat4 skinMat = a_weight.x * u_jointMat[int(a_joint.x)];
+skinMat += a_weight.y * u_jointMat[int(a_joint.y)];
+skinMat += a_weight.z * u_jointMat[int(a_joint.z)];
+skinMat += a_weight.w * u_jointMat[int(a_joint.w)];
+vec4 pos = u_modelViewMatrix * skinMat * vec4(a_position,1.0);
+v_normal = u_normalMatrix * mat3(skinMat)* a_normal;
+gl_Position = u_projectionMatrix * pos;
+}

File diff suppressed because it is too large
+ 12 - 0
examples/models/json/suzanne.json


+ 3 - 2
examples/webgl_animation_skinning_morph.html

@@ -198,6 +198,7 @@
 				for ( var i = 0; i < materials.length; i ++ ) {
 
 					var m = materials[ i ];
+					m.skinning = true;
 					m.morphTargets = true;
 
 					m.specular.setHSL( 0, 0, 0.1 );
@@ -214,7 +215,7 @@
 
 				}
 
-				mesh = new THREE.SkinnedMesh( geometry, new THREE.MultiMaterial( materials ) );
+				mesh = new THREE.SkinnedMesh( geometry, materials );
 				mesh.name = "Knight Mesh";
 				mesh.position.set( x, y - bb.min.y * s, z );
 				mesh.scale.set( s, s, s );
@@ -224,7 +225,7 @@
 				mesh.receiveShadow = true;
 
 
-				mesh2 = new THREE.SkinnedMesh( geometry, new THREE.MultiMaterial( materials ) );
+				mesh2 = new THREE.SkinnedMesh( geometry, materials );
 				mesh2.name = "Lil' Bro Mesh";
 				mesh2.position.set( x - 240, y - bb.min.y * s, z + 500 );
 				mesh2.scale.set( s / 2, s / 2, s / 2 );

+ 32 - 79
examples/webgl_decals.html

@@ -1,30 +1,38 @@
 <!DOCTYPE html>
 <html lang="en">
 	<head>
-		<title>WebGL decals</title>
+		<title>three.js webgl - decals - Decal Splatter</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 {
-				color: #fff;
+				background:#777;
+				padding:0;
+				margin:0;
+				font-weight: bold;
+				overflow:hidden;
+			}
+
+			#info {
+				position: absolute;
+				top: 0px;
+				width: 100%;
+				color: #ffffff;
+				padding: 5px;
 				font-family:Monospace;
 				font-size:13px;
-				margin: 0px;
 				text-align:center;
-				overflow: hidden;
 			}
-			#info{ position: absolute; width: 100%; padding: 5px; }
+
+			a {
+				color: #ffffff;
+			}
 		</style>
 	</head>
 	<body>
 
 		<div id="container"></div>
-		<div id="info">
-			<p>
-				<strong>Decal Splatter</strong><br />
-				Click or tap to shoot.
-			</p>
-		</div>
+		<div id="info"><a href="https://threejs.org" target="_blank">three.js</a> - decals - Decal Splatter (click or tap to shoot)</div>
 
 		<script src="../build/three.js"></script>
 		<script src="js/geometries/DecalGeometry.js"></script>
@@ -67,15 +75,13 @@
 		} );
 
 		var decals = [];
-		var decalHelper, mouseHelper;
-		var p = new THREE.Vector3( 0, 0, 0 );
-		var r = new THREE.Vector3( 0, 0, 0 );
-		var s = new THREE.Vector3( 10, 10, 10 );
+		var mouseHelper;
+		var position = new THREE.Vector3();
+		var orientation = new THREE.Euler();
+		var size = new THREE.Vector3( 10, 10, 10 );
 		var up = new THREE.Vector3( 0, 1, 0 );
-		var check = new THREE.Vector3( 1, 1, 1 );
 
 		var params = {
-			projection: 'normal',
 			minScale: 10,
 			maxScale: 20,
 			rotate: true,
@@ -98,7 +104,7 @@
 			scene = new THREE.Scene();
 
 			camera = new THREE.PerspectiveCamera( fov, window.innerWidth / window.innerHeight, 1, 1000 );
-			camera.position.z = 100;
+			camera.position.z = 120;
 			camera.target = new THREE.Vector3();
 
 			controls = new THREE.OrbitControls( camera, renderer.domElement );
@@ -148,7 +154,7 @@
 			window.addEventListener( 'mouseup', function() {
 
 				checkIntersection();
-				if ( ! moved ) shoot();
+				if ( ! moved && intersection.intersects ) shoot();
 
 			} );
 
@@ -213,7 +219,6 @@
 
 			var gui = new dat.GUI();
 
-			gui.add( params, 'projection', { 'From cam to mesh': 'camera', 'Normal to mesh': 'normal' } );
 			gui.add( params, 'minScale', 1, 30 );
 			gui.add( params, 'maxScale', 1, 30 );
 			gui.add( params, 'rotate' );
@@ -236,7 +241,6 @@
 					map: textureLoader.load( 'obj/leeperrysmith/Map-COL.jpg' ),
 					specularMap: textureLoader.load( 'obj/leeperrysmith/Map-SPEC.jpg' ),
 					normalMap: textureLoader.load( 'obj/leeperrysmith/Infinite-Level_02_Tangent_SmoothUV.jpg' ),
-					normalScale: new THREE.Vector2( 0.75, 0.75 ),
 					shininess: 25
 				} );
 
@@ -244,50 +248,25 @@
 				scene.add( mesh );
 				mesh.scale.set( 10, 10, 10 );
 
-				//scene.add( new THREE.FaceNormalsHelper( mesh, 1 ) );
-				//scene.add( new THREE.VertexNormalsHelper( mesh, 1 ) );
-
 			} );
 
 		}
 
 		function shoot() {
 
-			if ( params.projection == 'camera' ) {
-
-				var dir = camera.target.clone();
-				dir.sub( camera.position );
-
-				p = intersection.point;
+			position.copy( intersection.point );
+			orientation.copy( mouseHelper.rotation );
 
-				var m = new THREE.Matrix4();
-				var c = dir.clone();
-				c.negate();
-				c.multiplyScalar( 10 );
-				c.add( p );
-				m.lookAt( p, c, up );
-				m = m.extractRotation( m );
-
-				dummy = new THREE.Object3D();
-				dummy.rotation.setFromRotationMatrix( m );
-				r.set( dummy.rotation.x, dummy.rotation.y, dummy.rotation.z );
-
-			} else {
-
-				p = intersection.point;
-				r.copy( mouseHelper.rotation );
-
-			}
+			if ( params.rotate ) orientation.z = Math.random() * 2 * Math.PI;
 
 			var scale = params.minScale + Math.random() * ( params.maxScale - params.minScale );
-			s.set( scale, scale, scale );
-
-			if ( params.rotate ) r.z = Math.random() * 2 * Math.PI;
+			size.set( scale, scale, scale );
 
 			var material = decalMaterial.clone();
 			material.color.setHex( Math.random() * 0xffffff );
 
-			var m = new THREE.Mesh( new THREE.DecalGeometry( mesh, p, r, s, check ), material );
+			var m = new THREE.Mesh( new THREE.DecalGeometry( mesh, position, orientation, size ), material );
+
 			decals.push( m );
 			scene.add( m );
 
@@ -298,36 +277,10 @@
 			decals.forEach( function( d ) {
 
 				scene.remove( d );
-				d = null;
 
 			} );
-			decals = [];
-
-		}
-
-		function mergeDecals() {
-
-			var merge = {};
-			decals.forEach( function ( decal ) {
-
-				var uuid = decal.material.uuid;
-				var d = merge[ uuid ] = merge[ uuid ] || {};
-				d.material = d.material || decal.material;
-				d.geometry = d.geometry || new THREE.Geometry();
-				d.geometry.merge( decal.geometry, decal.matrix );
-
-			} );
-
-			removeDecals();
 
-			for ( var key in merge ) {
-
-				var d = merge[ key ];
-				var mesh = new THREE.Mesh( d.geometry, d.material );
-				scene.add( mesh );
-				decals.push( mesh );
-
-			}
+			decals = [];
 
 		}
 

+ 4 - 4
examples/webgl_effects_parallaxbarrier.html

@@ -517,7 +517,7 @@
 
 			}
 
-			function attachButtonMaterials( materials, faceMaterial, material_indices, car ) {
+			function attachButtonMaterials( materials, faceMaterials, material_indices, car ) {
 
 				for( var i = 0; i < materials.length; i++ ) {
 
@@ -526,7 +526,7 @@
 
 						for ( var j = 0; j < material_indices.length; j ++ ) {
 
-							faceMaterial.materials[ material_indices [ j ] ] = materials[ this.counter ][ 1 ];
+							faceMaterials[ material_indices [ j ] ] = materials[ this.counter ][ 1 ];
 
 						}
 
@@ -540,7 +540,7 @@
 
 				geometry.sortFacesByMaterialIndex();
 
-				var m = new THREE.MultiMaterial(),
+				var m = [],
 					s = CARS[ car ].scale * 1,
 					r = CARS[ car ].init_rotation,
 					materials = CARS[ car ].materials,
@@ -549,7 +549,7 @@
 
 				for( var i in CARS[ car ].mmap ) {
 
-					m.materials[ i ] = CARS[ car ].mmap[ i ];
+					m[ i ] = CARS[ car ].mmap[ i ];
 
 				}
 

+ 0 - 2
examples/webgl_effects_peppersghost.html

@@ -125,8 +125,6 @@
 
 		function render() {
 
-				camera.lookAt( scene.position );
-
 				group.rotation.y += 0.01;
 
 				effect.render( scene, camera );

+ 2 - 2
examples/webgl_geometry_colors_blender.html

@@ -107,7 +107,7 @@
 
 				materials[ 0 ].shading = THREE.FlatShading;
 
-				mesh = new THREE.Mesh( geometry, new THREE.MultiMaterial( materials ) );
+				mesh = new THREE.Mesh( geometry, materials );
 				mesh.position.x = 400;
 				mesh.scale.x = mesh.scale.y = mesh.scale.z = 250;
 				scene.add( mesh );
@@ -118,7 +118,7 @@
 
 				materials[ 0 ].shading = THREE.FlatShading;
 
-				mesh2 = new THREE.Mesh( geometry, new THREE.MultiMaterial( materials ) );
+				mesh2 = new THREE.Mesh( geometry, materials );
 				mesh2.position.x = - 400;
 				mesh2.scale.x = mesh2.scale.y = mesh2.scale.z = 250;
 				scene.add( mesh2 );

+ 1 - 1
examples/webgl_geometry_extrude_shapes.html

@@ -170,7 +170,7 @@
 
 				var geometry = new THREE.ExtrudeGeometry( shape, extrudeSettings );
 
-				var mesh = new THREE.Mesh( geometry, new THREE.MultiMaterial( materials ) );
+				var mesh = new THREE.Mesh( geometry, materials );
 
 				mesh.position.set( 50, 100, 50 );
 

+ 64 - 54
examples/webgl_geometry_shapes.html

@@ -33,7 +33,6 @@
 			var mouseXOnMouseDown = 0;
 
 			var windowHalfX = window.innerWidth / 2;
-			var windowHalfY = window.innerHeight / 2;
 
 			init();
 			animate();
@@ -105,6 +104,12 @@
 					mesh.scale.set( s, s, s );
 					group.add( mesh );
 
+					addLineShape( shape, color, x, y, z, rx, ry, rz, s );
+
+				}
+
+				function addLineShape( shape, color, x, y, z, rx, ry, rz, s ) {
+
 					// lines
 
 					shape.autoClose = true;
@@ -150,28 +155,28 @@
 
 				var californiaPts = [];
 
-				californiaPts.push( new THREE.Vector2 ( 610, 320 ) );
-				californiaPts.push( new THREE.Vector2 ( 450, 300 ) );
-				californiaPts.push( new THREE.Vector2 ( 392, 392 ) );
-				californiaPts.push( new THREE.Vector2 ( 266, 438 ) );
-				californiaPts.push( new THREE.Vector2 ( 190, 570 ) );
-				californiaPts.push( new THREE.Vector2 ( 190, 600 ) );
-				californiaPts.push( new THREE.Vector2 ( 160, 620 ) );
-				californiaPts.push( new THREE.Vector2 ( 160, 650 ) );
-				californiaPts.push( new THREE.Vector2 ( 180, 640 ) );
-				californiaPts.push( new THREE.Vector2 ( 165, 680 ) );
-				californiaPts.push( new THREE.Vector2 ( 150, 670 ) );
-				californiaPts.push( new THREE.Vector2 (  90, 737 ) );
-				californiaPts.push( new THREE.Vector2 (  80, 795 ) );
-				californiaPts.push( new THREE.Vector2 (  50, 835 ) );
-				californiaPts.push( new THREE.Vector2 (  64, 870 ) );
-				californiaPts.push( new THREE.Vector2 (  60, 945 ) );
-				californiaPts.push( new THREE.Vector2 ( 300, 945 ) );
-				californiaPts.push( new THREE.Vector2 ( 300, 743 ) );
-				californiaPts.push( new THREE.Vector2 ( 600, 473 ) );
-				californiaPts.push( new THREE.Vector2 ( 626, 425 ) );
-				californiaPts.push( new THREE.Vector2 ( 600, 370 ) );
-				californiaPts.push( new THREE.Vector2 ( 610, 320 ) );
+				californiaPts.push( new THREE.Vector2( 610, 320 ) );
+				californiaPts.push( new THREE.Vector2( 450, 300 ) );
+				californiaPts.push( new THREE.Vector2( 392, 392 ) );
+				californiaPts.push( new THREE.Vector2( 266, 438 ) );
+				californiaPts.push( new THREE.Vector2( 190, 570 ) );
+				californiaPts.push( new THREE.Vector2( 190, 600 ) );
+				californiaPts.push( new THREE.Vector2( 160, 620 ) );
+				californiaPts.push( new THREE.Vector2( 160, 650 ) );
+				californiaPts.push( new THREE.Vector2( 180, 640 ) );
+				californiaPts.push( new THREE.Vector2( 165, 680 ) );
+				californiaPts.push( new THREE.Vector2( 150, 670 ) );
+				californiaPts.push( new THREE.Vector2(  90, 737 ) );
+				californiaPts.push( new THREE.Vector2(  80, 795 ) );
+				californiaPts.push( new THREE.Vector2(  50, 835 ) );
+				californiaPts.push( new THREE.Vector2(  64, 870 ) );
+				californiaPts.push( new THREE.Vector2(  60, 945 ) );
+				californiaPts.push( new THREE.Vector2( 300, 945 ) );
+				californiaPts.push( new THREE.Vector2( 300, 743 ) );
+				californiaPts.push( new THREE.Vector2( 600, 473 ) );
+				californiaPts.push( new THREE.Vector2( 626, 425 ) );
+				californiaPts.push( new THREE.Vector2( 600, 370 ) );
+				californiaPts.push( new THREE.Vector2( 610, 320 ) );
 
 				for( var i = 0; i < californiaPts.length; i ++ ) californiaPts[ i ].multiplyScalar( 0.25 );
 
@@ -181,10 +186,10 @@
 				// Triangle
 
 				var triangleShape = new THREE.Shape();
-				triangleShape.moveTo(  80, 20 );
-				triangleShape.lineTo(  40, 80 );
+				triangleShape.moveTo( 80, 20 );
+				triangleShape.lineTo( 40, 80 );
 				triangleShape.lineTo( 120, 80 );
-				triangleShape.lineTo(  80, 20 ); // close path
+				triangleShape.lineTo( 80, 20 ); // close path
 
 
 				// Heart
@@ -195,7 +200,7 @@
 
 				heartShape.moveTo( x + 25, y + 25 );
 				heartShape.bezierCurveTo( x + 25, y + 25, x + 20, y, x, y );
-				heartShape.bezierCurveTo( x - 30, y, x - 30, y + 35,x - 30,y + 35 );
+				heartShape.bezierCurveTo( x - 30, y, x - 30, y + 35, x - 30, y + 35 );
 				heartShape.bezierCurveTo( x - 30, y + 55, x - 10, y + 77, x + 25, y + 95 );
 				heartShape.bezierCurveTo( x + 60, y + 77, x + 80, y + 55, x + 80, y + 35 );
 				heartShape.bezierCurveTo( x + 80, y + 35, x + 80, y, x + 50, y );
@@ -207,7 +212,7 @@
 				var sqLength = 80;
 
 				var squareShape = new THREE.Shape();
-				squareShape.moveTo( 0,0 );
+				squareShape.moveTo( 0, 0 );
 				squareShape.lineTo( 0, sqLength );
 				squareShape.lineTo( sqLength, sqLength );
 				squareShape.lineTo( sqLength, 0 );
@@ -219,7 +224,7 @@
 				var rectLength = 120, rectWidth = 40;
 
 				var rectShape = new THREE.Shape();
-				rectShape.moveTo( 0,0 );
+				rectShape.moveTo( 0, 0 );
 				rectShape.lineTo( 0, rectWidth );
 				rectShape.lineTo( rectLength, rectWidth );
 				rectShape.lineTo( rectLength, 0 );
@@ -230,12 +235,12 @@
 
 				var roundedRectShape = new THREE.Shape();
 
-				( function roundedRect( ctx, x, y, width, height, radius ){
+				( function roundedRect( ctx, x, y, width, height, radius ) {
 
 					ctx.moveTo( x, y + radius );
 					ctx.lineTo( x, y + height - radius );
 					ctx.quadraticCurveTo( x, y + height, x + radius, y + height );
-					ctx.lineTo( x + width - radius, y + height) ;
+					ctx.lineTo( x + width - radius, y + height );
 					ctx.quadraticCurveTo( x + width, y + height, x + width, y + height - radius );
 					ctx.lineTo( x + width, y + radius );
 					ctx.quadraticCurveTo( x + width, y, x + width - radius, y );
@@ -262,9 +267,9 @@
 				var circleShape = new THREE.Shape();
 				circleShape.moveTo( 0, circleRadius );
 				circleShape.quadraticCurveTo( circleRadius, circleRadius, circleRadius, 0 );
-				circleShape.quadraticCurveTo( circleRadius, -circleRadius, 0, -circleRadius );
-				circleShape.quadraticCurveTo( -circleRadius, -circleRadius, -circleRadius, 0 );
-				circleShape.quadraticCurveTo( -circleRadius, circleRadius, 0, circleRadius );
+				circleShape.quadraticCurveTo( circleRadius, - circleRadius, 0, - circleRadius );
+				circleShape.quadraticCurveTo( - circleRadius, - circleRadius, - circleRadius, 0 );
+				circleShape.quadraticCurveTo( - circleRadius, circleRadius, 0, circleRadius );
 
 
 				// Fish
@@ -273,23 +278,23 @@
 
 				var fishShape = new THREE.Shape();
 
-				fishShape.moveTo(x,y);
-				fishShape.quadraticCurveTo(x + 50, y - 80, x + 90, y - 10);
-				fishShape.quadraticCurveTo(x + 100, y - 10, x + 115, y - 40);
-				fishShape.quadraticCurveTo(x + 115, y, x + 115, y + 40);
-				fishShape.quadraticCurveTo(x + 100, y + 10, x + 90, y + 10);
-				fishShape.quadraticCurveTo(x + 50, y + 80, x, y);
+				fishShape.moveTo( x, y );
+				fishShape.quadraticCurveTo( x + 50, y - 80, x + 90, y - 10 );
+				fishShape.quadraticCurveTo( x + 100, y - 10, x + 115, y - 40 );
+				fishShape.quadraticCurveTo( x + 115, y, x + 115, y + 40 );
+				fishShape.quadraticCurveTo( x + 100, y + 10, x + 90, y + 10 );
+				fishShape.quadraticCurveTo( x + 50, y + 80, x, y );
 
 
 				// Arc circle
 
 				var arcShape = new THREE.Shape();
 				arcShape.moveTo( 50, 10 );
-				arcShape.absarc( 10, 10, 40, 0, Math.PI*2, false );
+				arcShape.absarc( 10, 10, 40, 0, Math.PI * 2, false );
 
 				var holePath = new THREE.Path();
 				holePath.moveTo( 20, 10 );
-				holePath.absarc( 10, 10, 10, 0, Math.PI*2, true );
+				holePath.absarc( 10, 10, 10, 0, Math.PI * 2, true );
 				arcShape.holes.push( holePath );
 
 
@@ -297,17 +302,17 @@
 
 				var smileyShape = new THREE.Shape();
 				smileyShape.moveTo( 80, 40 );
-				smileyShape.absarc( 40, 40, 40, 0, Math.PI*2, false );
+				smileyShape.absarc( 40, 40, 40, 0, Math.PI * 2, false );
 
 				var smileyEye1Path = new THREE.Path();
 				smileyEye1Path.moveTo( 35, 20 );
-				smileyEye1Path.absellipse( 25, 20, 10, 10, 0, Math.PI*2, true );
+				smileyEye1Path.absellipse( 25, 20, 10, 10, 0, Math.PI * 2, true );
 
 				smileyShape.holes.push( smileyEye1Path );
 
 				var smileyEye2Path = new THREE.Path();
 				smileyEye2Path.moveTo( 65, 20 );
-				smileyEye2Path.absarc( 55, 20, 10, 0, Math.PI*2, true );
+				smileyEye2Path.absarc( 55, 20, 10, 0, Math.PI * 2, true );
 				smileyShape.holes.push( smileyEye2Path );
 
 				var smileyMouthPath = new THREE.Path();
@@ -323,10 +328,10 @@
 				// Spline shape
 
 				var splinepts = [];
-				splinepts.push( new THREE.Vector2 ( 70, 20 ) );
-				splinepts.push( new THREE.Vector2 ( 80, 90 ) );
-				splinepts.push( new THREE.Vector2 ( -30, 70 ) );
-				splinepts.push( new THREE.Vector2 ( 0, 0 ) );
+				splinepts.push( new THREE.Vector2( 70, 20 ) );
+				splinepts.push( new THREE.Vector2( 80, 90 ) );
+				splinepts.push( new THREE.Vector2( - 30, 70 ) );
+				splinepts.push( new THREE.Vector2( 0, 0 ) );
 
 				var splineShape = new THREE.Shape();
 				splineShape.moveTo( 0, 0 );
@@ -343,10 +348,18 @@
 				addShape( squareShape,      extrudeSettings, 0x0040f0,  150,  100, 0, 0, 0, 0, 1 );
 				addShape( heartShape,       extrudeSettings, 0xf00000,   60,  100, 0, 0, 0, Math.PI, 1 );
 				addShape( circleShape,      extrudeSettings, 0x00f000,  120,  250, 0, 0, 0, 0, 1 );
-				addShape( fishShape,        extrudeSettings, 0x404040,  -60,  200, 0, 0, 0, 0, 1 );
+				addShape( fishShape,        extrudeSettings, 0x404040, - 60,  200, 0, 0, 0, 0, 1 );
 				addShape( smileyShape,      extrudeSettings, 0xf000f0, -200,  250, 0, 0, 0, Math.PI, 1 );
 				addShape( arcShape,         extrudeSettings, 0x804000,  150,    0, 0, 0, 0, 0, 1 );
-				addShape( splineShape,      extrudeSettings, 0x808080,  -50, -100, 0, 0, 0, 0, 1 );
+				addShape( splineShape,      extrudeSettings, 0x808080, - 50, -100, 0, 0, 0, 0, 1 );
+
+				addLineShape( arcShape.holes[ 0 ], 0x804000, 150, 0, 0, 0, 0, 0, 1 );
+
+				for ( var i = 0; i < smileyShape.holes.length; i += 1 ) {
+
+					addLineShape( smileyShape.holes[ i ], 0xf000f0, - 200, 250, 0, 0, 0, Math.PI, 1 );
+
+				}
 
 				//
 
@@ -371,9 +384,6 @@
 
 			function onWindowResize() {
 
-				windowHalfX = window.innerWidth / 2;
-				windowHalfY = window.innerHeight / 2;
-
 				camera.aspect = window.innerWidth / window.innerHeight;
 				camera.updateProjectionMatrix();
 

+ 47 - 34
examples/webgl_geometry_spline_editor.html

@@ -11,10 +11,23 @@
 				margin: 0px;
 				overflow: hidden;
 			}
+
+			#info {
+				position: absolute;
+				top: 0px;
+				width: 100%;
+				padding: 5px;
+				font-family:Monospace;
+				font-size:13px;
+				text-align:center;
+			}
 		</style>
 	</head>
 	<body>
 
+		<div id="container"></div>
+		<div id="info"><a href="https://threejs.org" target="_blank">three.js</a> - geometry - catmull spline editor</div>
+
 		<script src="../build/three.js"></script>
 
 		<script src="js/controls/DragControls.js"></script>
@@ -22,6 +35,7 @@
 		<script src="js/controls/TransformControls.js"></script>
 
 		<script src="js/libs/stats.min.js"></script>
+		<script src="js/libs/dat.gui.min.js"></script>
 
 		<script>
 
@@ -39,8 +53,7 @@
 
 			var container, stats;
 			var camera, scene, renderer;
-			var splineHelperObjects = [],
-				splineOutline;
+			var splineHelperObjects = [], splineOutline;
 			var splinePointsLength = 4;
 			var positions = [];
 			var options;
@@ -50,8 +63,16 @@
 			var ARC_SEGMENTS = 200;
 			var splineMesh;
 
-			var splines = {
+			var splines = {};
 
+			var params = {
+				uniform: true,
+				tension: 0.5,
+				centripetal: true,
+				chordal: true,
+				addPoint: addPoint,
+				removePoint: removePoint,
+				exportSpline: exportSpline
 			};
 
 			init();
@@ -59,11 +80,11 @@
 
 			function init() {
 
-				container = document.createElement( 'div' );
-				document.body.appendChild( container );
+				container = document.getElementById( 'container' );
+
 				scene = new THREE.Scene();
 				camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 10000 );
-				camera.position.z = 1000;
+				camera.position.set( 0, 250, 1000 );
 				scene.add( camera );
 
 				scene.add( new THREE.AmbientLight( 0xf0f0f0 ) );
@@ -106,31 +127,23 @@
 				renderer.shadowMap.enabled = true;
 				container.appendChild( renderer.domElement );
 
-				var info = document.createElement( 'div' );
-				info.style.position = 'absolute';
-				info.style.top = '10px';
-				info.style.width = '100%';
-				info.style.textAlign = 'center';
-				info.innerHTML = 'catmull-rom rom spline comparisions';
-				options = document.createElement( 'div' );
-				options.style.position = 'absolute';
-				options.style.top = '30px';
-				options.style.width = '100%';
-				options.style.textAlign = 'center';
-
-				options.innerHTML = 'Points: <input type="button" onclick="addPoint();" value="+" />\
-					<input type="button" onclick="removePoint();" value="-" />\
-					<input type="button" onclick="exportSpline();" value="Export" /><br />\
-					<input type="checkbox" id="uniform" checked /> <label for="uniform">Uniform Catmull-rom</label>  <input type="range" id="tension" onchange="splines.uniform.tension = tension.value;updateSplineOutline();" min=0 max=1 step=0.01 value=0.5 /> <span id="tension_value" /></span> <br />\
-					<input type="checkbox" id="centripetal" checked /> Centripetal Catmull-rom<br />\
-					<input type="checkbox" id="chordal" checked /> Chordal Catmull-rom<br />';
-
-				container.appendChild( info );
-				container.appendChild( options );
-
 				stats = new Stats();
 				container.appendChild( stats.dom );
 
+				var gui = new dat.GUI();
+
+				gui.add( params, 'uniform' );
+				gui.add( params, 'tension', 0, 1 ).step( 0.01 ).onChange( function( value ) {
+					splines.uniform.tension = value;
+					updateSplineOutline();
+				});
+				gui.add( params, 'centripetal' );
+				gui.add( params, 'chordal' );
+				gui.add( params, 'addPoint' );
+				gui.add( params, 'removePoint' );
+				gui.add( params, 'exportSpline' );
+				gui.open();
+
 				// Controls
 				controls = new THREE.OrbitControls( camera, renderer.domElement );
 				controls.damping = 0.2;
@@ -377,13 +390,14 @@
 					strplace.push( 'new THREE.Vector3({0}, {1}, {2})'.format( p.x, p.y, p.z ) )
 
 				}
+
 				console.log( strplace.join( ',\n' ) );
 				var code = '[' + ( strplace.join( ',\n\t' ) ) + ']';
 				prompt( 'copy and paste code', code );
 
-				}
+			}
 
-				function load( new_positions ) {
+			function load( new_positions ) {
 
 				while ( new_positions.length > positions.length ) {
 
@@ -412,16 +426,15 @@
 				requestAnimationFrame( animate );
 				render();
 				stats.update();
-				controls.update();
 				transformControl.update();
 
 			}
 
 			function render() {
 
-				splines.uniform.mesh.visible = uniform.checked;
-				splines.centripetal.mesh.visible = centripetal.checked;
-				splines.chordal.mesh.visible = chordal.checked;
+				splines.uniform.mesh.visible = params.uniform;
+				splines.centripetal.mesh.visible = params.centripetal;
+				splines.chordal.mesh.visible = params.chordal;
 				renderer.render( scene, camera );
 
 			}

+ 5 - 5
examples/webgl_geometry_text.html

@@ -52,7 +52,7 @@
 
 			var camera, cameraTarget, scene, renderer;
 
-			var group, textMesh1, textMesh2, textGeo, material;
+			var group, textMesh1, textMesh2, textGeo, materials;
 
 			var firstLetter = true;
 
@@ -181,10 +181,10 @@
 
 				}
 
-				material = new THREE.MultiMaterial( [
+				materials = [
 					new THREE.MeshPhongMaterial( { color: 0xffffff, shading: THREE.FlatShading } ), // front
 					new THREE.MeshPhongMaterial( { color: 0xffffff, shading: THREE.SmoothShading } ) // side
-				] );
+				];
 
 				group = new THREE.Group();
 				group.position.y = 100;
@@ -427,7 +427,7 @@
 
 				var centerOffset = -0.5 * ( textGeo.boundingBox.max.x - textGeo.boundingBox.min.x );
 
-				textMesh1 = new THREE.Mesh( textGeo, material );
+				textMesh1 = new THREE.Mesh( textGeo, materials );
 
 				textMesh1.position.x = centerOffset;
 				textMesh1.position.y = hover;
@@ -440,7 +440,7 @@
 
 				if ( mirror ) {
 
-					textMesh2 = new THREE.Mesh( textGeo, material );
+					textMesh2 = new THREE.Mesh( textGeo, materials );
 
 					textMesh2.position.x = centerOffset;
 					textMesh2.position.y = -hover;

+ 5 - 5
examples/webgl_geometry_text_earcut.html

@@ -110,7 +110,7 @@
 
 			var camera, cameraTarget, scene, renderer;
 
-			var group, textMesh1, textMesh2, textGeo, material;
+			var group, textMesh1, textMesh2, textGeo, materials;
 
 			var firstLetter = true;
 
@@ -239,10 +239,10 @@
 
 				}
 
-				material = new THREE.MultiMaterial( [
+				materials = [
 					new THREE.MeshPhongMaterial( { color: 0xffffff, shading: THREE.FlatShading } ), // front
 					new THREE.MeshPhongMaterial( { color: 0xffffff, shading: THREE.SmoothShading } ) // side
-				] );
+				];
 
 				group = new THREE.Group();
 				group.position.y = 100;
@@ -485,7 +485,7 @@
 
 				var centerOffset = -0.5 * ( textGeo.boundingBox.max.x - textGeo.boundingBox.min.x );
 
-				textMesh1 = new THREE.Mesh( textGeo, material );
+				textMesh1 = new THREE.Mesh( textGeo, materials );
 
 				textMesh1.position.x = centerOffset;
 				textMesh1.position.y = hover;
@@ -498,7 +498,7 @@
 
 				if ( mirror ) {
 
-					textMesh2 = new THREE.Mesh( textGeo, material );
+					textMesh2 = new THREE.Mesh( textGeo, materials );
 
 					textMesh2.position.x = centerOffset;
 					textMesh2.position.y = -hover;

+ 5 - 5
examples/webgl_geometry_text_pnltri.html

@@ -82,7 +82,7 @@
 
 			var camera, cameraTarget, scene, renderer;
 
-			var group, textMesh1, textMesh2, textGeo, material;
+			var group, textMesh1, textMesh2, textGeo, materials;
 
 			var firstLetter = true;
 
@@ -211,10 +211,10 @@
 
 				}
 
-				material = new THREE.MultiMaterial( [
+				materials = [
 					new THREE.MeshPhongMaterial( { color: 0xffffff, shading: THREE.FlatShading } ), // front
 					new THREE.MeshPhongMaterial( { color: 0xffffff, shading: THREE.SmoothShading } ) // side
-				] );
+				];
 
 				group = new THREE.Group();
 				group.position.y = 100;
@@ -457,7 +457,7 @@
 
 				var centerOffset = -0.5 * ( textGeo.boundingBox.max.x - textGeo.boundingBox.min.x );
 
-				textMesh1 = new THREE.Mesh( textGeo, material );
+				textMesh1 = new THREE.Mesh( textGeo, materials );
 
 				textMesh1.position.x = centerOffset;
 				textMesh1.position.y = hover;
@@ -470,7 +470,7 @@
 
 				if ( mirror ) {
 
-					textMesh2 = new THREE.Mesh( textGeo, material );
+					textMesh2 = new THREE.Mesh( textGeo, materials );
 
 					textMesh2.position.x = centerOffset;
 					textMesh2.position.y = -hover;

+ 166 - 0
examples/webgl_geometry_text_shapes.html

@@ -0,0 +1,166 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<title>three.js webgl - Simple text from json</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%;
+				text-align: center;
+			}
+		</style>
+	</head>
+	<body>
+		<div id="info">
+			<a href="http://threejs.org" target="_blank">three.js</a> webgl - Simple text from json fonts.
+		</div>
+
+		<script src="../build/three.js"></script>
+		<script src="js/controls/OrbitControls.js"></script>
+
+		<script>
+
+			var camera, scene, renderer, controls;
+
+			init();
+			animate();
+
+			function init( ) {
+
+				camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 10000 );
+				camera.position.set( 0, - 400, 600 );
+
+				controls = new THREE.OrbitControls( camera );
+				controls.target.set( 0, 0, 0 );
+
+				scene = new THREE.Scene();
+
+				var loader = new THREE.FontLoader();
+				loader.load( 'fonts/helvetiker_regular.typeface.json', function ( font ) {
+
+					var xMid, text;
+
+					var textShape = new THREE.BufferGeometry();
+
+					var color = 0x006699;
+
+					var matDark = new THREE.LineBasicMaterial( {
+						color: color,
+						side: THREE.DoubleSide
+					} );
+
+					var matLite = new THREE.MeshBasicMaterial( {
+						color: color,
+						transparent: true,
+						opacity: 0.4,
+						side: THREE.DoubleSide
+					} );
+
+					var message = "   Three.js\nSimple text.";
+
+					var shapes = font.generateShapes( message, 100, 2 );
+
+					var geometry = new THREE.ShapeGeometry( shapes );
+
+					geometry.computeBoundingBox();
+
+					xMid = - 0.5 * ( geometry.boundingBox.max.x - geometry.boundingBox.min.x );
+
+					geometry.translate( xMid, 0, 0 );
+
+					// make shape ( N.B. edge view not visible )
+
+					textShape.fromGeometry( geometry );
+
+					text = new THREE.Mesh( textShape, matLite );
+					text.position.z = - 150;
+					scene.add( text );
+
+			        // make line shape ( N.B. edge view remains visible )
+
+			      		var holeShapes = [];
+
+					for ( var i = 0; i < shapes.length; i ++ ) {
+
+						var shape = shapes[ i ];
+
+						if ( shape.holes && shape.holes.length > 0 ) {
+
+							for ( var j = 0; j < shape.holes.length; j ++ ) {
+
+								var hole = shape.holes[ j ];
+								holeShapes.push( hole );
+
+							}
+
+						}
+
+					}
+
+					shapes.push.apply( shapes, holeShapes );
+
+					var lineText = new THREE.Object3D();
+
+					for ( var i = 0; i < shapes.length; i ++ ) {
+
+						var shape = shapes[ i ];
+
+						var lineGeometry = shape.createPointsGeometry();
+
+						lineGeometry.translate( xMid, 0, 0 );
+
+						var lineMesh = new THREE.Line( lineGeometry, matDark );
+						lineText.add( lineMesh );
+
+					}
+
+					scene.add( lineText );
+
+				} ); //end load function
+
+				renderer = new THREE.WebGLRenderer( { antialias: true } );
+				renderer.setClearColor( 0xf0f0f0 );
+				renderer.setSize( window.innerWidth, window.innerHeight );
+				document.body.appendChild( renderer.domElement );
+
+				window.addEventListener( 'resize', onWindowResize, false );
+
+			} // end init
+
+			function onWindowResize() {
+
+				camera.aspect = window.innerWidth / window.innerHeight;
+				camera.updateProjectionMatrix();
+
+				renderer.setSize( window.innerWidth, window.innerHeight );
+
+			}
+
+			function animate() {
+
+				requestAnimationFrame( animate );
+
+				render();
+
+			}
+
+			function render() {
+
+				controls.update();
+				renderer.render( scene, camera );
+
+			}
+
+		</script>
+
+	</body>
+</html>

+ 0 - 17
examples/webgl_loader_ctm_materials.html

@@ -254,23 +254,6 @@
 
 			//
 
-			function createScene( geometry, materials, x, y, z, s ) {
-
-				geometry.center();
-
-				hackMaterials( materials );
-
-				var material = new THREE.MultiMaterial( materials );
-
-				mesh = new THREE.Mesh( geometry, material );
-				mesh.position.set( x, y, z );
-				mesh.scale.set( s, s, s );
-				scene.add( mesh );
-
-			}
-
-			//
-
 			function onWindowResize( event ) {
 
 				SCREEN_WIDTH = window.innerWidth;

+ 10 - 3
examples/webgl_loader_gltf.html

@@ -202,8 +202,7 @@
 					scene.add(ground);
 				}
 
-				THREE.GLTF2Loader.Shaders.removeAll(); // remove all previous shaders
-				loader = new THREE.GLTF2Loader;
+				loader = new THREE.GLTF2Loader();
 
 				for (var i = 0; i < extensionSelect.children.length; i++) {
 					var child = extensionSelect.children[i];
@@ -338,7 +337,6 @@
 			function animate() {
 				requestAnimationFrame( animate );
 				if (mixer) mixer.update(clock.getDelta());
-				THREE.GLTF2Loader.Shaders.update(scene, camera);
 				if (cameraIndex == 0)
 					orbitControls.update();
 				render();
@@ -409,6 +407,15 @@
 					shadows:true,
 					extensions: ["glTF", "glTF-MaterialsCommon", "glTF-Binary"]
 				},
+				{
+					name : "Rigged Simple",
+					url : "./models/gltf/RiggedSimple/%s/RiggedSimple.gltf",
+					cameraPos: new THREE.Vector3(0, 5, 15),
+					objectRotation: new THREE.Euler(0, 90, 0),
+					addLights:true,
+					shadows:true,
+					extensions: ["glTF"]
+				},
 				{
 					name : "Snowflake",
 					url : "./models/gltf/snowflake/snowFlake.gltf",

+ 1 - 3
examples/webgl_loader_json_blender.html

@@ -108,8 +108,6 @@
 					material.morphTargets = true;
 					material.color.setHex( 0xffaaaa );
 
-					var faceMaterial = new THREE.MultiMaterial( materials );
-
 					for ( var i = 0; i < 729; i ++ ) {
 
 						// random placement in a grid
@@ -121,7 +119,7 @@
 
 						if ( Math.abs( x ) < 2 && Math.abs( z ) < 2 ) continue;
 
-						mesh = new THREE.Mesh( geometry, faceMaterial );
+						mesh = new THREE.Mesh( geometry, materials );
 
 						var s = THREE.Math.randFloat( 0.00075, 0.001 );
 						mesh.scale.set( s, s, s );

+ 1 - 1
examples/webgl_loader_json_objconverter.html

@@ -217,7 +217,7 @@
 
 			function createScene( geometry, materials, x, y, z, b ) {
 
-				zmesh = new THREE.Mesh( geometry, new THREE.MultiMaterial( materials ) );
+				zmesh = new THREE.Mesh( geometry, materials );
 				zmesh.position.set( x, y, z );
 				zmesh.scale.set( 3, 3, 3 );
 				scene.add( zmesh );

+ 2 - 2
examples/webgl_loader_mmd.html

@@ -177,7 +177,7 @@
 
 					}
 
-					phongMaterials = new THREE.MultiMaterial( array );
+					phongMaterials = array;
 
 				}
 
@@ -202,7 +202,7 @@
 					gui.add( api, 'gradient mapping' ).onChange( function () {
 
 						if ( originalMaterials === undefined ) originalMaterials = mesh.material;
-						if ( phongMaterials === undefined ) makePhongMaterials( mesh.material.materials );
+						if ( phongMaterials === undefined ) makePhongMaterials( mesh.material );
 
 						if ( api[ 'gradient mapping' ] ) {
 

+ 1 - 1
examples/webgl_materials.html

@@ -108,7 +108,7 @@
 
 				}
 
-				addMesh( geometry, new THREE.MultiMaterial( materials ) );
+				addMesh( geometry, materials );
 
 				particleLight = new THREE.Mesh( new THREE.SphereGeometry( 4, 8, 8 ), new THREE.MeshBasicMaterial( { color: 0xffffff } ) );
 				scene.add( particleLight );

+ 4 - 4
examples/webgl_materials_cars.html

@@ -516,7 +516,7 @@
 
 			}
 
-			function attachButtonMaterials( materials, faceMaterial, material_indices, car ) {
+			function attachButtonMaterials( materials, faceMaterials, material_indices, car ) {
 
 				for( var i = 0; i < materials.length; i ++ ) {
 
@@ -525,7 +525,7 @@
 
 						for ( var j = 0; j < material_indices.length; j ++ ) {
 
-							faceMaterial.materials[ material_indices [ j ] ] = materials[ this.counter ][ 1 ];
+							faceMaterials[ material_indices [ j ] ] = materials[ this.counter ][ 1 ];
 
 						}
 
@@ -539,7 +539,7 @@
 
 				geometry.sortFacesByMaterialIndex();
 
-				var m = new THREE.MultiMaterial(),
+				var m = [],
 					s = CARS[ car ].scale * 1,
 					r = CARS[ car ].init_rotation,
 					materials = CARS[ car ].materials,
@@ -548,7 +548,7 @@
 
 				for ( var i in CARS[ car ].mmap ) {
 
-					m.materials[ i ] = CARS[ car ].mmap[ i ];
+					m[ i ] = CARS[ car ].mmap[ i ];
 
 				}
 

+ 1 - 1
examples/webgl_materials_lightmap.html

@@ -149,7 +149,7 @@
 
 					}
 
-					var mesh = new THREE.Mesh( geometry, new THREE.MultiMaterial( materials ) );
+					var mesh = new THREE.Mesh( geometry, materials );
 
 					mesh.scale.multiplyScalar( 100 );
 					scene.add( mesh );

+ 18 - 35
examples/webgl_mirror.html

@@ -54,15 +54,20 @@
 
 			var cameraControls;
 
-			var verticalMirror, groundMirror;
 			var sphereGroup, smallSphere;
 
+			init();
+			animate();
+
 			function init() {
 
+				var container = document.getElementById( 'container' );
+
 				// renderer
 				renderer = new THREE.WebGLRenderer();
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( WIDTH, HEIGHT );
+				container.appendChild( renderer.domElement );
 
 				// scene
 				scene = new THREE.Scene();
@@ -77,30 +82,21 @@
 				cameraControls.minDistance = 10;
 				cameraControls.update();
 
-				var container = document.getElementById( 'container' );
-				container.appendChild( renderer.domElement );
-
-			}
-
-			function fillScene() {
+				//
 
 				var planeGeo = new THREE.PlaneBufferGeometry( 100.1, 100.1 );
 
 				// 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 );
-				mirrorMesh.add( groundMirror );
-				mirrorMesh.rotateX( - Math.PI / 2 );
-				scene.add( mirrorMesh );
+				var groundMirror = new THREE.Mirror( 100, 100, { clipBias: 0.003, textureWidth: WIDTH, textureHeight: HEIGHT, color: 0x777777 } );
+				groundMirror.rotateX( - Math.PI / 2 );
+				scene.add( groundMirror );
 
-				verticalMirror = new THREE.Mirror( renderer, camera, { clipBias: 0.003, textureWidth: WIDTH, textureHeight: HEIGHT, color:0x889999 } );
+				var verticalMirror = new THREE.Mirror( 60, 60, { clipBias: 0.003, textureWidth: WIDTH, textureHeight: HEIGHT, color:0x889999 } );
+				verticalMirror.position.y = 35;
+				verticalMirror.position.z = -45;
+				scene.add( verticalMirror );
 
-				var verticalMirrorMesh = new THREE.Mesh( new THREE.PlaneBufferGeometry( 60, 60 ), verticalMirror.material );
-				verticalMirrorMesh.add( verticalMirror );
-				verticalMirrorMesh.position.y = 35;
-				verticalMirrorMesh.position.z = -45;
-				scene.add( verticalMirrorMesh );
 
 				sphereGroup = new THREE.Object3D();
 				scene.add( sphereGroup );
@@ -173,19 +169,9 @@
 
 			}
 
-			function render() {
+			function animate() {
 
-				// render (update) the mirrors
-				groundMirror.renderWithMirror( verticalMirror );
-				verticalMirror.renderWithMirror( groundMirror );
-
-				renderer.render(scene, camera);
-
-			}
-
-			function update() {
-
-				requestAnimationFrame( update );
+				requestAnimationFrame( animate );
 
 				var timer = Date.now() * 0.01;
 
@@ -201,12 +187,9 @@
 
 				cameraControls.update();
 
-				render();
-			}
+				renderer.render(scene, camera);
 
-			init();
-			fillScene();
-			update();
+			}
 
 		</script>
 	</body>

+ 1 - 8
examples/webgl_mirror_nodes.html

@@ -116,7 +116,7 @@
 			var clock = new THREE.Clock();
 
 			var cameraControls;
-			
+
 			var gui = new dat.GUI();
 
 			var groundMirror;
@@ -283,13 +283,6 @@
 
 			function render() {
 
-				// render (update) the mirrors
-				groundMirrorMaterial.visible = false;
-
-				groundMirror.render();
-
-				groundMirrorMaterial.visible = true;
-
 				renderer.render(scene, camera);
 
 			}

+ 1 - 1
examples/webgl_nearestneighbour.html

@@ -109,7 +109,7 @@
 
 				];
 
-				mesh = new THREE.Mesh( new THREE.BoxGeometry( 10000, 10000, 10000, 7, 7, 7 ), new THREE.MultiMaterial( materials ) );
+				mesh = new THREE.Mesh( new THREE.BoxGeometry( 10000, 10000, 10000, 7, 7, 7 ), materials );
 				mesh.scale.x = - 1;
 				scene.add(mesh);
 

+ 6 - 6
examples/webgl_objects_update.html

@@ -47,22 +47,22 @@
 
 				//
 
-				var object = createObject( createMultiMaterial(), 1 );
+				var object = createObject( createMaterials(), 1 );
 				object.position.set( -100, 100, 0 );
 				scene.add( object );
 				objectNewGeometry = object;
 
-				object = createObject( createMultiMaterial(), 1 );
+				object = createObject( createMaterials(), 1 );
 				object.position.set( 100, 100, 0 );
 				scene.add( object );
 				objectToggleAddRemove = object;
 
-				object = createObject( createMultiMaterial(), 4 );
+				object = createObject( createMaterials(), 4 );
 				object.position.set( -100, -100, 0 );
 				scene.add( object );
 				objectRandomizeFaces = object;
 
-				object = createObject( createMultiMaterial(), 4 );
+				object = createObject( createMaterials(), 4 );
 				object.position.set( 100, -100, 0 );
 				scene.add( object );
 				objectRandomizeMaterialIndices = object;
@@ -99,7 +99,7 @@
 
 			}
 
-			function createMultiMaterial(){
+			function createMaterials(){
 				var materials = [
 					new THREE.MeshBasicMaterial( { color: 0xff0000 } ),
 					new THREE.MeshBasicMaterial( { color: 0xffff00 } ),
@@ -109,7 +109,7 @@
 					new THREE.MeshBasicMaterial( { color: 0xff00ff } )
 				];
 
-				return new THREE.MultiMaterial( materials );
+				return materials;
 			}
 
 			function onWindowResize() {

+ 1 - 1
examples/webgl_panorama_cube.html

@@ -74,7 +74,7 @@
 
 			}
 
-			var skyBox = new THREE.Mesh( new THREE.CubeGeometry( 1, 1, 1 ), new THREE.MultiMaterial( materials ) );
+			var skyBox = new THREE.Mesh( new THREE.CubeGeometry( 1, 1, 1 ), materials );
 			skyBox.applyMatrix( new THREE.Matrix4().makeScale( 1, 1, - 1 ) );
 			scene.add( skyBox );
 

+ 2 - 2
examples/webgl_performance.html

@@ -52,8 +52,8 @@
 
 				var material = new THREE.MeshNormalMaterial();
 
-				var loader = new THREE.JSONLoader();
-				loader.load( 'obj/Suzanne.js', function ( geometry ) {
+				var loader = new THREE.BufferGeometryLoader();
+				loader.load( 'models/json/suzanne.json', function ( geometry ) {
 
 					geometry.computeVertexNormals();
 

+ 2 - 2
examples/webgl_performance_static.html

@@ -50,8 +50,8 @@
 
 				var material = new THREE.MeshNormalMaterial();
 
-				var loader = new THREE.JSONLoader();
-				loader.load( 'obj/Suzanne.js', function ( geometry ) {
+				var loader = new THREE.BufferGeometryLoader();
+				loader.load( 'models/json/suzanne.json', function ( geometry ) {
 
 					geometry.computeVertexNormals();
 

+ 4 - 3
examples/webgl_simple_gi.html

@@ -42,7 +42,9 @@
 
 			THREE.Mesh.prototype.clone = function () {
 
-				return new this.constructor( this.geometry.clone(), this.material.clone() ).copy( this );
+				var newMaterial = ( this.material.isMaterial ) ? this.material.clone() : this.material.slice();
+
+				return new this.constructor( this.geometry.clone(), newMaterial ).copy( this );
 
 			};
 
@@ -211,9 +213,8 @@
 				}
 
 				var geometry = new THREE.BoxBufferGeometry( 3, 3, 3 );
-				var material = new THREE.MultiMaterial( materials );
 
-				var mesh = new THREE.Mesh( geometry, material );
+				var mesh = new THREE.Mesh( geometry, materials );
 				scene.add( mesh );
 
 				//

+ 7 - 1
examples/webgl_skinning_simple.html

@@ -63,7 +63,13 @@
 
 				loader.load( './models/skinned/simple/simple.js', function ( geometry, materials ) {
 
-					skinnedMesh = new THREE.SkinnedMesh(geometry, new THREE.MultiMaterial(materials));
+					for ( var k in materials ) {
+
+						materials[k].skinning = true;
+
+					}
+
+					skinnedMesh = new THREE.SkinnedMesh(geometry, materials );
 					skinnedMesh.scale.set( 1, 1, 1 );
 
 					// Note: We test the corresponding code path with this example -

+ 1 - 0
examples/webgldeferred_animation.html

@@ -112,6 +112,7 @@
 
 					var material = materials[ 0 ];
 					material.emissive.set( 0x101010 );
+					material.skinning = true;
 					material.morphTargets = true;
 
 					var mesh = new THREE.SkinnedMesh( geometry, material );

+ 38 - 10
examples/webvr_shadow.html

@@ -19,6 +19,8 @@
 		<script src="js/effects/VREffect.js"></script>
 		<script src="js/vr/WebVR.js"></script>
 
+		<script src="js/Mirror.js"></script>
+
 		<script>
 
 			if ( WEBVR.isAvailable() === false ) {
@@ -32,6 +34,8 @@
 			var camera, scene, renderer;
 			var effect, controls;
 
+			var mirror;
+
 			init();
 			animate();
 
@@ -39,41 +43,65 @@
 
 				scene = new THREE.Scene();
 
-				var dummy = new THREE.Camera();
-				dummy.position.set( 2, 1, 2 );
-				dummy.lookAt( scene.position );
-				scene.add( dummy );
-
 				camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 0.1, 10 );
-				dummy.add( camera );
+				scene.add( camera );
 
 				var geometry = new THREE.TorusKnotGeometry( 0.4, 0.15, 150, 20 );
 				var material = new THREE.MeshStandardMaterial( { roughness: 0.01, metalness: 0.2 } );
 				var mesh = new THREE.Mesh( geometry, material );
 				mesh.position.y = 0.75;
+				mesh.position.z = - 2;
 				mesh.castShadow = true;
 				mesh.receiveShadow = true;
 				scene.add( mesh );
 
-				var geometry = new THREE.BoxGeometry( 3, 0.1, 3 );
+				var geometry = new THREE.BoxGeometry( 1.5, 0.1, 1.5 );
 				var material = new THREE.MeshStandardMaterial( { roughness: 1.0, metalness: 0.0 } );
 				var mesh = new THREE.Mesh( geometry, material );
-				mesh.position.y = - 0.1;
+				mesh.position.y = - 0.2;
+				mesh.position.z = - 2;
 				mesh.castShadow = true;
 				mesh.receiveShadow = true;
 				scene.add( mesh );
 
 				var light = new THREE.DirectionalLight( 0x8800ff );
-				light.position.set( - 1, 1.5, 0.5 );
+				light.position.set( - 1, 1.5, - 1.5 );
 				light.castShadow = true;
 				light.shadow.camera.zoom = 4;
 				scene.add( light );
+				light.target.position.set( 0, 0, - 2 );
+				scene.add( light.target );
+
+				var helper = new THREE.CameraHelper( light.shadow.camera );
+				// scene.add( helper );
 
 				var light = new THREE.DirectionalLight( 0xff0000 );
-				light.position.set( 1, 1.5, - 0.5 );
+				light.position.set( 1, 1.5, - 2.5 );
 				light.castShadow = true;
 				light.shadow.camera.zoom = 4;
 				scene.add( light );
+				light.target.position.set( 0, 0, - 2 );
+				scene.add( light.target );
+
+				var helper = new THREE.CameraHelper( light.shadow.camera );
+				// scene.add( helper );
+
+				//
+
+				mirror = new THREE.Mirror( 1.4, 1.4, { textureWidth: window.innerWidth, textureHeight: window.innerHeight } );
+				mirror.position.x = 1;
+				mirror.position.y = 0.5;
+				mirror.position.z = -3;
+				mirror.rotation.y = - Math.PI / 4;
+				scene.add( mirror );
+
+				var geometry = new THREE.BoxGeometry( 1.5, 1.5, 0.1 );
+				var material = new THREE.MeshStandardMaterial( { roughness: 1.0, metalness: 0.0 } );
+				var mesh = new THREE.Mesh( geometry, material );
+				mesh.position.z = - 0.07;
+				mesh.castShadow = true;
+				mesh.receiveShadow = true;
+				mirror.add( mesh );
 
 				//
 

+ 1 - 1
package.json

@@ -33,7 +33,7 @@
     "build-closure": "rollup -c && java -jar utils/build/compiler/closure-compiler-v20160713.jar --warning_level=VERBOSE --jscomp_off=globalThis --jscomp_off=checkTypes --externs utils/build/externs.js --language_in=ECMASCRIPT5_STRICT --js build/three.js --js_output_file build/three.min.js",
     "dev": "rollup -c -w",
     "lint": "eslint src",
-    "test": "echo \"Error: no test specified\" && exit 1"
+    "test": "rollup -c test/rollup.unit.config.js -w"
   },
   "keywords": [
     "three",

+ 3 - 3
rollup.config.js

@@ -8,9 +8,9 @@ function glsl() {
 
 			var transformedCode = 'export default ' + JSON.stringify(
 				code
-					.replace( /[ \t]*\/\/.*\n/g, '' )
-					.replace( /[ \t]*\/\*[\s\S]*?\*\//g, '' )
-					.replace( /\n{2,}/g, '\n' )
+					.replace( /[ \t]*\/\/.*\n/g, '' ) // remove //
+					.replace( /[ \t]*\/\*[\s\S]*?\*\//g, '' ) // remove /* */
+					.replace( /\n{2,}/g, '\n' ) // # \n+ to \n
 			) + ';';
 			return {
 				code: transformedCode,

+ 7 - 14
src/Three.Legacy.js

@@ -994,20 +994,6 @@ Object.defineProperties( Uniform.prototype, {
 
 Object.defineProperties( Material.prototype, {
 
-	skinning: {
-		get: function () {
-
-			console.warn( 'THREE.Material: .skinning has been removed.' );
-
-		},
-		set: function () {
-
-			console.warn( 'THREE.Material: .skinning has been removed.' );
-
-		}
-
-	},
-
 	wrapAround: {
 		get: function () {
 
@@ -1072,6 +1058,13 @@ Object.defineProperties( ShaderMaterial.prototype, {
 
 Object.assign( WebGLRenderer.prototype, {
 
+	getCurrentRenderTarget: function () {
+
+		console.warn( 'THREE.WebGLRenderer: .getCurrentRenderTarget() is now .getRenderTarget().' );
+		return this.getRenderTarget();
+
+	},
+
 	supportsFloatTextures: function () {
 
 		console.warn( 'THREE.WebGLRenderer: .supportsFloatTextures() is now .extensions.get( \'OES_texture_float\' ).' );

+ 11 - 7
src/animation/AnimationUtils.js

@@ -7,11 +7,13 @@
 var AnimationUtils = {
 
 	// same as Array.prototype.slice, but also works on typed arrays
-	arraySlice: function( array, from, to ) {
+	arraySlice: function ( array, from, to ) {
 
 		if ( AnimationUtils.isTypedArray( array ) ) {
 
-			return new array.constructor( array.subarray( from, to ) );
+			// in ios9 array.subarray(from, undefined) will return empty array
+			// but array.subarray(from) or array.subarray(from, len) is correct
+			return new array.constructor( array.subarray( from, to !== undefined ? to : array.length ) );
 
 		}
 
@@ -20,7 +22,7 @@ var AnimationUtils = {
 	},
 
 	// converts an array to a specific type
-	convertArray: function( array, type, forceClone ) {
+	convertArray: function ( array, type, forceClone ) {
 
 		if ( ! array || // let 'undefined' and 'null' pass
 				! forceClone && array.constructor === type ) return array;
@@ -35,7 +37,7 @@ var AnimationUtils = {
 
 	},
 
-	isTypedArray: function( object ) {
+	isTypedArray: function ( object ) {
 
 		return ArrayBuffer.isView( object ) &&
 				! ( object instanceof DataView );
@@ -43,7 +45,7 @@ var AnimationUtils = {
 	},
 
 	// returns an array by which times and values can be sorted
-	getKeyframeOrder: function( times ) {
+	getKeyframeOrder: function ( times ) {
 
 		function compareTime( i, j ) {
 
@@ -62,7 +64,7 @@ var AnimationUtils = {
 	},
 
 	// uses the array previously returned by 'getKeyframeOrder' to sort data
-	sortedArray: function( values, stride, order ) {
+	sortedArray: function ( values, stride, order ) {
 
 		var nValues = values.length;
 		var result = new values.constructor( nValues );
@@ -84,7 +86,7 @@ var AnimationUtils = {
 	},
 
 	// function for parsing AOS keyframe formats
-	flattenJSON: function( jsonKeys, times, values, valuePropertyName ) {
+	flattenJSON: function ( jsonKeys, times, values, valuePropertyName ) {
 
 		var i = 1, key = jsonKeys[ 0 ];
 
@@ -117,6 +119,7 @@ var AnimationUtils = {
 			} while ( key !== undefined );
 
 		} else if ( value.toArray !== undefined ) {
+
 			// ...assume THREE.Math-ish
 
 			do {
@@ -135,6 +138,7 @@ var AnimationUtils = {
 			} while ( key !== undefined );
 
 		} else {
+
 			// otherwise push as-is
 
 			do {

+ 2 - 2
src/animation/KeyframeTrackConstructor.js

@@ -2,9 +2,9 @@ import { AnimationUtils } from './AnimationUtils';
 
 function KeyframeTrackConstructor( name, times, values, interpolation ) {
 
-	if( name === undefined ) throw new Error( "track name is undefined" );
+	if ( name === undefined ) throw new Error( "track name is undefined" );
 
-	if( times === undefined || times.length === 0 ) {
+	if ( times === undefined || times.length === 0 ) {
 
 		throw new Error( "no keyframes in track named " + name );
 

+ 66 - 30
src/animation/PropertyBinding.js

@@ -102,47 +102,83 @@ Object.assign( PropertyBinding, {
 
 	},
 
-	parseTrackName: function ( trackName ) {
+	parseTrackName: function () {
 
-		// matches strings in the form of:
-		//    nodeName.property
-		//    nodeName.property[accessor]
-		//    nodeName.material.property[accessor]
-		//    uuid.property[accessor]
-		//    uuid.objectName[objectIndex].propertyName[propertyIndex]
-		//    parentName/nodeName.property
-		//    parentName/parentName/nodeName.property[index]
-		//    .bone[Armature.DEF_cog].position
-		//    scene:helium_balloon_model:helium_balloon_model.position
-		// created and tested via https://regex101.com/#javascript
+		// Parent directories, delimited by '/' or ':'. Currently unused, but must
+		// be matched to parse the rest of the track name.
+		var directoryRe = /((?:[\w-]+[\/:])*)/;
 
-		var re = /^((?:[\w-]+[\/:])*)([\w-]+)?(?:\.([\w-]+)(?:\[(.+)\])?)?\.([\w-]+)(?:\[(.+)\])?$/;
-		var matches = re.exec( trackName );
+		// Target node. May contain word characters (a-zA-Z0-9_) and '.' or '-'.
+		var nodeRe = /([\w-\.]+)?/;
 
-		if ( ! matches ) {
+		// Object on target node, and accessor. Name may contain only word
+		// characters. Accessor may contain any character except closing bracket.
+		var objectRe = /(?:\.([\w-]+)(?:\[(.+)\])?)?/;
 
-			throw new Error( "cannot parse trackName at all: " + trackName );
+		// Property and accessor. May contain only word characters. Accessor may
+		// contain any non-bracket characters.
+		var propertyRe = /\.([\w-]+)(?:\[(.+)\])?/;
 
-		}
+		var trackRe = new RegExp(''
+			+ '^'
+			+ directoryRe.source
+			+ nodeRe.source
+			+ objectRe.source
+			+ propertyRe.source
+			+ '$'
+		);
 
-		var results = {
-			// directoryName: matches[ 1 ], // (tschw) currently unused
-			nodeName: matches[ 2 ], 	// allowed to be null, specified root node.
-			objectName: matches[ 3 ],
-			objectIndex: matches[ 4 ],
-			propertyName: matches[ 5 ],
-			propertyIndex: matches[ 6 ]	// allowed to be null, specifies that the whole property is set.
-		};
+		var supportedObjectNames = [ 'material', 'materials', 'bones' ];
 
-		if ( results.propertyName === null || results.propertyName.length === 0 ) {
+		return function ( trackName ) {
 
-			throw new Error( "can not parse propertyName from trackName: " + trackName );
+				var matches = trackRe.exec( trackName );
 
-		}
+				if ( ! matches ) {
 
-		return results;
+					throw new Error( 'PropertyBinding: Cannot parse trackName: ' + trackName );
 
-	},
+				}
+
+				var results = {
+					// directoryName: matches[ 1 ], // (tschw) currently unused
+					nodeName: matches[ 2 ],
+					objectName: matches[ 3 ],
+					objectIndex: matches[ 4 ],
+					propertyName: matches[ 5 ],     // required
+					propertyIndex: matches[ 6 ]
+				};
+
+				var lastDot = results.nodeName && results.nodeName.lastIndexOf( '.' );
+
+				if ( lastDot !== undefined && lastDot !== -1 ) {
+
+					var objectName = results.nodeName.substring( lastDot + 1 );
+
+					// Object names must be checked against a whitelist. Otherwise, there
+					// is no way to parse 'foo.bar.baz': 'baz' must be a property, but
+					// 'bar' could be the objectName, or part of a nodeName (which can
+					// include '.' characters).
+					if ( supportedObjectNames.indexOf( objectName ) !== -1 ) {
+
+						results.nodeName = results.nodeName.substring( 0, lastDot );
+						results.objectName = objectName;
+
+					}
+
+				}
+
+				if ( results.propertyName === null || results.propertyName.length === 0 ) {
+
+					throw new Error( 'PropertyBinding: can not parse propertyName from trackName: ' + trackName );
+
+				}
+
+				return results;
+
+			};
+
+	}(),
 
 	findNode: function ( root, nodeName ) {
 

+ 0 - 16
src/cameras/Camera.js

@@ -41,22 +41,6 @@ Camera.prototype.getWorldDirection = function () {
 
 }();
 
-Camera.prototype.lookAt = function () {
-
-	// This routine does not support cameras with rotated and/or translated parent(s)
-
-	var m1 = new Matrix4();
-
-	return function lookAt( vector ) {
-
-		m1.lookAt( this.position, vector, this.up );
-
-		this.quaternion.setFromRotationMatrix( m1 );
-
-	};
-
-}();
-
 Camera.prototype.clone = function () {
 
 	return new this.constructor().copy( this );

+ 6 - 8
src/core/BufferGeometry.js

@@ -814,21 +814,19 @@ Object.assign( BufferGeometry.prototype, EventDispatcher.prototype, {
 
 	normalizeNormals: function () {
 
-		var normals = this.attributes.normal.array;
+		var normals = this.attributes.normal;
 
 		var x, y, z, n;
 
-		for ( var i = 0, il = normals.length; i < il; i += 3 ) {
+		for ( var i = 0, il = normals.count; i < il; i ++ ) {
 
-			x = normals[ i ];
-			y = normals[ i + 1 ];
-			z = normals[ i + 2 ];
+			x = normals.getX( i );
+			y = normals.getY( i );
+			z = normals.getZ( i );
 
 			n = 1.0 / Math.sqrt( x * x + y * y + z * z );
 
-			normals[ i ] *= n;
-			normals[ i + 1 ] *= n;
-			normals[ i + 2 ] *= n;
+			normals.setXYZ(i, x * n, y * n, z * n)
 
 		}
 

+ 2 - 2
src/core/Face3.js

@@ -12,10 +12,10 @@ function Face3( a, b, c, normal, color, materialIndex ) {
 	this.b = b;
 	this.c = c;
 
-	this.normal = (normal && normal.isVector3) ? normal : new Vector3();
+	this.normal = ( normal && normal.isVector3 ) ? normal : new Vector3();
 	this.vertexNormals = Array.isArray( normal ) ? normal : [];
 
-	this.color = (color && color.isColor) ? color : new Color();
+	this.color = ( color && color.isColor ) ? color : new Color();
 	this.vertexColors = Array.isArray( color ) ? color : [];
 
 	this.materialIndex = materialIndex !== undefined ? materialIndex : 0;

+ 12 - 8
src/core/InstancedBufferAttribute.js

@@ -12,20 +12,24 @@ function InstancedBufferAttribute( array, itemSize, meshPerAttribute ) {
 
 }
 
-InstancedBufferAttribute.prototype = Object.create( BufferAttribute.prototype );
-InstancedBufferAttribute.prototype.constructor = InstancedBufferAttribute;
+InstancedBufferAttribute.prototype = Object.assign( Object.create( BufferAttribute.prototype ), {
 
-InstancedBufferAttribute.prototype.isInstancedBufferAttribute = true;
+	constructor: InstancedBufferAttribute,
 
-InstancedBufferAttribute.prototype.copy = function ( source ) {
+	isInstancedBufferAttribute: true,
 
-	BufferAttribute.prototype.copy.call( this, source );
+	copy: function ( source ) {
 
-	this.meshPerAttribute = source.meshPerAttribute;
+		BufferAttribute.prototype.copy.call( this, source );
 
-	return this;
+		this.meshPerAttribute = source.meshPerAttribute;
+
+		return this;
+
+	}
+
+} );
 
-};
 
 
 export { InstancedBufferAttribute };

+ 29 - 27
src/core/InstancedBufferGeometry.js

@@ -13,54 +13,56 @@ function InstancedBufferGeometry() {
 
 }
 
-InstancedBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
-InstancedBufferGeometry.prototype.constructor = InstancedBufferGeometry;
+InstancedBufferGeometry.prototype = Object.assign( Object.create( BufferGeometry.prototype ), {
 
-InstancedBufferGeometry.prototype.isInstancedBufferGeometry = true;
+	constructor: InstancedBufferGeometry,
 
-InstancedBufferGeometry.prototype.addGroup = function ( start, count, materialIndex ) {
+	isInstancedBufferGeometry: true,
 
-	this.groups.push( {
+	addGroup: function ( start, count, materialIndex ) {
 
-		start: start,
-		count: count,
-		materialIndex: materialIndex
+		this.groups.push( {
 
-	} );
+			start: start,
+			count: count,
+			materialIndex: materialIndex
 
-};
+		} );
 
-InstancedBufferGeometry.prototype.copy = function ( source ) {
+	},
 
-	var index = source.index;
+	copy: function ( source ) {
 
-	if ( index !== null ) {
+		var index = source.index;
 
-		this.setIndex( index.clone() );
+		if ( index !== null ) {
 
-	}
+			this.setIndex( index.clone() );
 
-	var attributes = source.attributes;
+		}
 
-	for ( var name in attributes ) {
+		var attributes = source.attributes;
 
-		var attribute = attributes[ name ];
-		this.addAttribute( name, attribute.clone() );
+		for ( var name in attributes ) {
 
-	}
+			var attribute = attributes[ name ];
+			this.addAttribute( name, attribute.clone() );
 
-	var groups = source.groups;
+		}
 
-	for ( var i = 0, l = groups.length; i < l; i ++ ) {
+		var groups = source.groups;
 
-		var group = groups[ i ];
-		this.addGroup( group.start, group.count, group.materialIndex );
+		for ( var i = 0, l = groups.length; i < l; i ++ ) {
 
-	}
+			var group = groups[ i ];
+			this.addGroup( group.start, group.count, group.materialIndex );
 
-	return this;
+		}
 
-};
+		return this;
+
+	}
 
+} );
 
 export { InstancedBufferGeometry };

+ 10 - 8
src/core/InstancedInterleavedBuffer.js

@@ -12,20 +12,22 @@ function InstancedInterleavedBuffer( array, stride, meshPerAttribute ) {
 
 }
 
-InstancedInterleavedBuffer.prototype = Object.create( InterleavedBuffer.prototype );
-InstancedInterleavedBuffer.prototype.constructor = InstancedInterleavedBuffer;
+InstancedInterleavedBuffer.prototype = Object.assign( Object.create( InterleavedBuffer.prototype ), {
 
-InstancedInterleavedBuffer.prototype.isInstancedInterleavedBuffer = true;
+	constructor: InstancedInterleavedBuffer,
 
-InstancedInterleavedBuffer.prototype.copy = function ( source ) {
+	isInstancedInterleavedBuffer: true,
 
-	InterleavedBuffer.prototype.copy.call( this, source );
+	copy: function ( source ) {
 
-	this.meshPerAttribute = source.meshPerAttribute;
+		InterleavedBuffer.prototype.copy.call( this, source );
 
-	return this;
+		this.meshPerAttribute = source.meshPerAttribute;
 
-};
+		return this;
 
+	}
+
+} );
 
 export { InstancedInterleavedBuffer };

+ 2 - 2
src/core/InterleavedBufferAttribute.js

@@ -18,7 +18,7 @@ function InterleavedBufferAttribute( interleavedBuffer, itemSize, offset, normal
 
 Object.defineProperties( InterleavedBufferAttribute.prototype, {
 
-	"count" : {
+	count: {
 
 		get: function () {
 
@@ -28,7 +28,7 @@ Object.defineProperties( InterleavedBufferAttribute.prototype, {
 
 	},
 
-	"array" : {
+	array: {
 
 		get: function () {
 

+ 5 - 5
src/core/Layers.js

@@ -4,7 +4,7 @@
 
 function Layers() {
 
-	this.mask = 1;
+	this.mask = 1 | 0;
 
 }
 
@@ -12,25 +12,25 @@ Object.assign( Layers.prototype, {
 
 	set: function ( channel ) {
 
-		this.mask = 1 << channel;
+		this.mask = 1 << channel | 0;
 
 	},
 
 	enable: function ( channel ) {
 
-		this.mask |= 1 << channel;
+		this.mask |= 1 << channel | 0;
 
 	},
 
 	toggle: function ( channel ) {
 
-		this.mask ^= 1 << channel;
+		this.mask ^= 1 << channel | 0;
 
 	},
 
 	disable: function ( channel ) {
 
-		this.mask &= ~ ( 1 << channel );
+		this.mask &= ~ ( 1 << channel | 0 );
 
 	},
 

+ 11 - 3
src/core/Object3D.js

@@ -279,7 +279,15 @@ Object.assign( Object3D.prototype, EventDispatcher.prototype, {
 
 		return function lookAt( vector ) {
 
-			m1.lookAt( vector, this.position, this.up );
+			if ( this.isCamera ) {
+
+				m1.lookAt( this.position, vector, this.up );
+
+			} else {
+
+				m1.lookAt( vector, this.position, this.up );
+
+			}
 
 			this.quaternion.setFromRotationMatrix( m1 );
 
@@ -526,9 +534,9 @@ Object.assign( Object3D.prototype, EventDispatcher.prototype, {
 
 	updateMatrixWorld: function ( force ) {
 
-		if ( this.matrixAutoUpdate === true ) this.updateMatrix();
+		if ( this.matrixAutoUpdate ) this.updateMatrix();
 
-		if ( this.matrixWorldNeedsUpdate === true || force === true ) {
+		if ( this.matrixWorldNeedsUpdate || force ) {
 
 			if ( this.parent === null ) {
 

+ 2 - 2
src/core/Raycaster.js

@@ -73,12 +73,12 @@ Object.assign( Raycaster.prototype, {
 
 	setFromCamera: function ( coords, camera ) {
 
-		if ( (camera && camera.isPerspectiveCamera) ) {
+		if ( ( camera && camera.isPerspectiveCamera ) ) {
 
 			this.ray.origin.setFromMatrixPosition( camera.matrixWorld );
 			this.ray.direction.set( coords.x, coords.y, 0.5 ).unproject( camera ).sub( this.ray.origin ).normalize();
 
-		} else if ( (camera && camera.isOrthographicCamera) ) {
+		} else if ( ( camera && camera.isOrthographicCamera ) ) {
 
 			this.ray.origin.set( coords.x, coords.y, ( camera.near + camera.far ) / ( camera.near - camera.far ) ).unproject( camera ); // set origin in plane of camera
 			this.ray.direction.set( 0, 0, - 1 ).transformDirection( camera.matrixWorld );

+ 12 - 4
src/lights/RectAreaLight.js

@@ -4,7 +4,7 @@ import { Light } from './Light';
  * @author abelnation / http://github.com/abelnation
  */
 
-function RectAreaLight ( color, intensity, width, height ) {
+function RectAreaLight( color, intensity, width, height ) {
 
 	Light.call( this, color, intensity );
 
@@ -21,7 +21,6 @@ function RectAreaLight ( color, intensity, width, height ) {
 	// TODO (abelnation): update method for RectAreaLight to update transform to lookat target
 
 	// TODO (abelnation): shadows
-	// this.shadow = new THREE.RectAreaLightShadow( new THREE.PerspectiveCamera( 90, 1, 0.5, 500 ) );
 
 }
 
@@ -39,10 +38,19 @@ RectAreaLight.prototype = Object.assign( Object.create( Light.prototype ), {
 		this.width = source.width;
 		this.height = source.height;
 
-		// this.shadow = source.shadow.clone();
-
 		return this;
 
+	},
+
+	toJSON: function ( meta ) {
+
+		var data = Light.prototype.toJSON.call( this, meta );
+
+		data.object.width = this.width;
+		data.object.height = this.height;
+
+		return data;
+
 	}
 
 } );

+ 0 - 18
src/lights/RectAreaLightShadow.js

@@ -1,18 +0,0 @@
-/**
- * @author aallison / http://github.com/abelnation
- */
-
-THREE.RectAreaLightShadow = function () {
-
-	THREE.LightShadow.call( this, new THREE.PerspectiveCamera( 50, 1, 0.5, 500 ) );
-
-};
-
-THREE.RectAreaLightShadow.prototype = Object.create( THREE.LightShadow.prototype );
-THREE.RectAreaLightShadow.prototype.constructor = THREE.RectAreaLightShadow;
-
-THREE.RectAreaLightShadow.prototype.update = function ( light ) {
-
-	// TODO (abelnation): implement
-
-};

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