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>
 <!DOCTYPE html>
 <html lang="en">
 <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>
 </html>

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

@@ -16,6 +16,13 @@
 		This is used internally by the [page:FontLoader].
 		This is used internally by the [page:FontLoader].
 		</div>
 		</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>
 		<h2>Constructor</h2>
 
 
 		<h3>[name]( data )</h3>
 		<h3>[name]( data )</h3>

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

@@ -12,7 +12,11 @@
 
 
 		<h1>[name]</h1>
 		<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>
 		<iframe id="scene" src="scenes/geometry-browser.html#TextGeometry"></iframe>
 
 
@@ -32,13 +36,31 @@
 
 
 		</script>
 		</script>
 
 
-		<h2>Example</h2>
+		<h2>Examples</h2>
 
 
 		<div>
 		<div>
 		[example:webgl_geometry_text geometry / text ]<br/>
 		[example:webgl_geometry_text geometry / text ]<br/>
 		[example:webgl_geometry_text2 geometry / text2 ]
 		[example:webgl_geometry_text2 geometry / text2 ]
 		</div>
 		</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>
 		<h2>Constructor</h2>
 
 
 		<h3>[name]([page:String text], [page:Object parameters])</h3>
 		<h3>[name]([page:String text], [page:Object parameters])</h3>
@@ -46,8 +68,8 @@
 		text — The text that needs to be shown. <br />
 		text — The text that needs to be shown. <br />
 		parameters — Object that can contains the following parameters.
 		parameters — Object that can contains the following parameters.
 		<ul>
 		<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>height — Float. Thickness to extrude text.  Default is 50.</li>
 			<li>curveSegments — Integer. Number of points on the curves. Default is 12.</li>
 			<li>curveSegments — Integer. Number of points on the curves. Default is 12.</li>
 			<li>bevelEnabled — Boolean. Turn on bevel. Default is False.</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>
 		<h2>Examples</h2>
 
 
 		<div>
 		<div>
+		[example:webgl_geometry_text_shapes geometry / text / shapes ]<br/>
 		[example:webgl_geometry_text geometry / text ]<br />
 		[example:webgl_geometry_text geometry / text ]<br />
 		[example:webgl_geometry_text_earcut geometry / text / earcut]<br />
 		[example:webgl_geometry_text_earcut geometry / text / earcut]<br />
 		[example:webgl_geometry_text_pnltri geometry / text / pnltri]<br />
 		[example:webgl_geometry_text_pnltri geometry / text / pnltri]<br />

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

@@ -234,6 +234,13 @@
 			</code>
 			</code>
 			</p>
 			</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>
 		</div>
 
 
 		<h2>Constructor</h2>
 		<h2>Constructor</h2>

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

@@ -40,7 +40,7 @@
 		<h2>Methods</h2>
 		<h2>Methods</h2>
 
 
 		<h3>[method:Line3 applyMatrix4]( [page:Matrix4 matrix] )</h3>
 		<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>
 		<h3>[method:Vector3 at]( [page:Float t], [page:Vector3 optionalTarget] )</h3>
 		<div>
 		<div>
@@ -48,12 +48,12 @@
 		[page:Vector3 optionalTarget] - (optional) if specified, the result will be copied into this [page:Vector3],
 		[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 />
 		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 />
 		and when [page:Float t] = 1 it returns the end vector.<br />
 		</div>
 		</div>
 
 
 		<h3>[method:Line3 clone]()</h3>
 		<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>
 		<h3>[method:Vector3 closestPointToPoint]( [page:Vector3 point], [page:Boolean clampToLine], [page:Vector3 optionalTarget] )</h3>
 		<div>
 		<div>
@@ -72,7 +72,7 @@
 		[page:Boolean clampToLine] - Whether to clamp the result to the range [0, 1].<br /><br />
 		[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.
 		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>
 		</div>
 
 
 		<h3>[method:Line3 copy]( [page:Line3 line] )</h3>
 		<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],
 			[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 />
 			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>
 		</div>
 
 
 		<h3>[method:Line3 set]( [page:Vector3 start], [page:Vector3 end] )</h3>
 		<h3>[method:Line3 set]( [page:Vector3 start], [page:Vector3 end] )</h3>
 		<div>
 		<div>
 		[page:Vector3 start] - set the [page:.start start point] of the line.<br />
 		[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.
 		Sets the start and end values by copying the provided vectors.
 		</div>
 		</div>

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

@@ -30,7 +30,7 @@
 		<div>
 		<div>
 		[page:Integer n], [page:Integer m] - Integers<br /><br />
 		[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>
 		<code>( ( n % m ) + m ) % m</code>
 		</div>
 		</div>
 
 
@@ -71,10 +71,10 @@
 		</div>
 		</div>
 
 
 		<h3>[method:Integer nearestPowerOfTwo]( [page:Number n] )</h3>
 		<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>
 		<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>
 		<h3>[method:Float radToDeg]( [page:Float radians] )</h3>
 		<div>Converts radians to degrees.</div>
 		<div>Converts radians to degrees.</div>
@@ -83,7 +83,7 @@
 		<div>Random float in the interval [page:Float low] to [page:Float high].</div>
 		<div>Random float in the interval [page:Float low] to [page:Float high].</div>
 
 
 		<h3>[method:Float randFloatSpread]( [page:Float range] )</h3>
 		<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>
 		<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>
 		<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>
 		<h3>[method:Float dot]( [page:Quaternion v] )</h3>
 		<div>
 		<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.
 			quaternions [page:Quaternion v] and this one.
 		</div>
 		</div>
 
 
@@ -137,11 +137,11 @@
 		</div>
 		</div>
 
 
 		<h3>[method:Quaternion onChange]( [page:Function onChangeCallback] )</h3>
 		<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>
 		<h3>[method:Quaternion onChangeCallback]( )</h3>
 		<div>
 		<div>
-			This function is called whenever and of the following occur:
+			This function is called whenever any of the following occurs:
 			<ul>
 			<ul>
 				<li>
 				<li>
 					The [page:.x x], [page:.y y], [page:.z z] or
 					The [page:.x x], [page:.y y], [page:.z z] or
@@ -188,7 +188,7 @@
 		<div>
 		<div>
 		Sets this quaternion from rotation specified by [page:Vector3 axis] and [page:Float angle].<br />
 		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 />
 		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>
 		</div>
 
 
 		<h3>[method:Quaternion setFromEuler]( [page:Euler euler] )</h3>
 		<h3>[method:Quaternion setFromEuler]( [page:Euler euler] )</h3>
@@ -210,8 +210,8 @@
 
 
 		<h3>[method:Array toArray]( [page:Array array], [page:Integer offset] )</h3>
 		<h3>[method:Array toArray]( [page:Array array], [page:Integer offset] )</h3>
 		<div>
 		<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 />
 		into this [page:Array].<br /><br />
 
 
 		Returns the numerical elements of this quaternion in an array of format [x, y, z, w].
 		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 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 />
 		[page:Float y] -  the y value of the vector. Default is *0*.<br /><br />
 
 
-		Created a new [name].
+		Creates a new [name].
 		</div>
 		</div>
 
 
 
 
@@ -64,7 +64,7 @@
 		<div>
 		<div>
 			Used to check whether this or derived classes are Vector2s. Default is *true*.<br /><br />
 			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>
 		</div>
 
 
 		<h3>[property:Float height]</h3>
 		<h3>[property:Float height]</h3>
@@ -84,7 +84,7 @@
 		<div>Adds [page:Vector2 v] to this vector.</div>
 		<div>Adds [page:Vector2 v] to this vector.</div>
 
 
 		<h3>[method:Vector2 addScalar]( [page:Float s] )</h3>
 		<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>
 		<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>
 		<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>
 		<h3>[method:Vector2 clone]()</h3>
 		<div>
 		<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>
 		</div>
 
 
 		<h3>[method:Vector2 copy]( [page:Vector2 v] )</h3>
 		<h3>[method:Vector2 copy]( [page:Vector2 v] )</h3>
 		<div>
 		<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>
 		</div>
 
 
 		<h3>[method:Float distanceTo]( [page:Vector2 v] )</h3>
 		<h3>[method:Float distanceTo]( [page:Vector2 v] )</h3>
@@ -166,7 +166,7 @@
 
 
 		<h3>[method:Float dot]( [page:Vector2 v] )</h3>
 		<h3>[method:Float dot]( [page:Vector2 v] )</h3>
 		<div>
 		<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].
 	  vector and [page:Vector2 v].
 		</div>
 		</div>
 
 
@@ -179,9 +179,9 @@
 		<h3>[method:Vector2 fromArray]( [page:Array array], [page:Integer offset] )</h3>
 		<h3>[method:Vector2 fromArray]( [page:Array array], [page:Integer offset] )</h3>
 		<div>
 		<div>
 		[page:Array array] - the source array.<br />
 		[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>
 		</div>
 
 
 		<h3>[method:Vector2 fromBufferAttribute]( [page:BufferAttribute attribute], [page:Integer index] )</h3>
 		<h3>[method:Vector2 fromBufferAttribute]( [page:BufferAttribute attribute], [page:Integer index] )</h3>
@@ -221,7 +221,7 @@
 		[page:Vector2 v] - [page:Vector2] to interpolate towards.<br />
 		[page:Vector2 v] - [page:Vector2] to interpolate towards.<br />
 		alpha - interpolation factor in the closed interval [0, 1].<br /><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].
 		distance along the line - alpha = 0 will be this vector, and alpha = 1 will be [page:Vector2 v].
 		</div>
 		</div>
 
 
@@ -241,19 +241,19 @@
 
 
 		<h3>[method:Vector2 normalize]()</h3>
 		<h3>[method:Vector2 normalize]()</h3>
 		<div>
 		<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.
 		as this one, but [page:.length length] 1.
 		</div>
 		</div>
 
 
 		<h3>[method:Vector2 max]( [page:Vector2 v] )</h3>
 		<h3>[method:Vector2 max]( [page:Vector2 v] )</h3>
 		<div>
 		<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.
 		that value with the corresponding max value.
 		</div>
 		</div>
 
 
 		<h3>[method:Vector2 min]( [page:Vector2 v] )</h3>
 		<h3>[method:Vector2 min]( [page:Vector2 v] )</h3>
 		<div>
 		<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.
 		that value with the corresponding min value.
 		</div>
 		</div>
 
 
@@ -269,7 +269,7 @@
 			[page:Vector2 center] - the point around which to rotate.<br />
 			[page:Vector2 center] - the point around which to rotate.<br />
 			[page:float angle] - the angle to rotate, in radians.<br /><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>
 		</div>
 
 
 		<h3>[method:Vector2 round]()</h3>
 		<h3>[method:Vector2 round]()</h3>
@@ -294,34 +294,33 @@
 
 
 		<h3>[method:Vector2 setLength]( [page:Float l] )</h3>
 		<h3>[method:Vector2 setLength]( [page:Float l] )</h3>
 		<div>
 		<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].
 		[page:Float l].
 		</div>
 		</div>
 
 
 		<h3>[method:Vector2 setScalar]( [page:Float scalar] )</h3>
 		<h3>[method:Vector2 setScalar]( [page:Float scalar] )</h3>
 		<div>
 		<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>
 		</div>
 
 
 		<h3>[method:Vector2 setX]( [page:Float x] )</h3>
 		<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>
 		<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>
 		<h3>[method:Vector2 sub]( [page:Vector2 v] )</h3>
 		<div>Subtracts [page:Vector2 v] from this vector.</div>
 		<div>Subtracts [page:Vector2 v] from this vector.</div>
 
 
 		<h3>[method:Vector2 subScalar]( [page:Float s] )</h3>
 		<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>
 		<h3>[method:Vector2 subVectors]( [page:Vector2 a], [page:Vector2 b] )</h3>
 		<div>Sets this vector to [page:Vector2 a] - [page:Vector2 b].</div>
 		<div>Sets this vector to [page:Vector2 a] - [page:Vector2 b].</div>
 
 
 		<h3>[method:Array toArray]( [page:Array array], [page:Integer offset] )</h3>
 		<h3>[method:Array toArray]( [page:Array array], [page:Integer offset] )</h3>
 		<div>
 		<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 />
 		[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].
 		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>
 		<div>
 			Used to check whether this or derived classes are Vector3s. Default is *true*.<br /><br />
 			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>
 		</div>
 
 
 		<h3>[property:Float x]</h3>
 		<h3>[property:Float x]</h3>
@@ -81,7 +81,7 @@ var d = a.distanceTo( b );
 		<div>Adds [page:Vector3 v] to this vector.</div>
 		<div>Adds [page:Vector3 v] to this vector.</div>
 
 
 		<h3>[method:Vector3 addScalar]( [page:Float s] )</h3>
 		<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>
 		<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>
 		<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>
 		</div>
 
 
 		<h3>[method:Vector3 applyMatrix3]( [page:Matrix3 m] )</h3>
 		<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>
 		<h3>[method:Vector3 applyMatrix4]( [page:Matrix4 m] )</h3>
 		<div>
 		<div>
@@ -284,13 +284,13 @@ var d = a.distanceTo( b );
 
 
 		<h3>[method:Vector3 max]( [page:Vector3 v] )</h3>
 		<h3>[method:Vector3 max]( [page:Vector3 v] )</h3>
 		<div>
 		<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.
 		that value with the corresponding max value.
 		</div>
 		</div>
 
 
 		<h3>[method:Vector3 min]( [page:Vector3 v] )</h3>
 		<h3>[method:Vector3 min]( [page:Vector3 v] )</h3>
 		<div>
 		<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.
 		that value with the corresponding min value.
 		</div>
 		</div>
 
 

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

@@ -22,7 +22,7 @@
 			<li>
 			<li>
 				A direction and length in 4D space. In three.js the length will always be the
 				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]
 				[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).
 				measured from (0, 0, 0, 0) towards (x, y, z, w).
 			</li>
 			</li>
 			<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)
 //no arguments; will be initialised to (0, 0, 0, 1)
 var b = new THREE.Vector4( );
 var b = new THREE.Vector4( );
 
 
-var d = a.distanceTo( b );
+var d = a.dot( b );
 		</code>
 		</code>
 
 
 
 
@@ -65,7 +65,7 @@ var d = a.distanceTo( b );
 		<div>
 		<div>
 			Used to check whether this or derived classes are Vector4s. Default is *true*.<br /><br />
 			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>
 		</div>
 
 
 		<h3>[property:Float x]</h3>
 		<h3>[property:Float x]</h3>
@@ -83,7 +83,7 @@ var d = a.distanceTo( b );
 		<div>Adds [page:Vector4 v] to this vector.</div>
 		<div>Adds [page:Vector4 v] to this vector.</div>
 
 
 		<h3>[method:Vector4 addScalar]( [page:Float s] )</h3>
 		<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>
 		<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>
 		<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>
 		<h3>[method:Vector4 applyMatrix4]( [page:Matrix4 m] )</h3>
 		<div>
 		<div>
-		Multiply this vector by 4 x 4 [page:Matrix4 m].
+		Multiplies this vector by 4 x 4 [page:Matrix4 m].
 		</div>
 		</div>
 
 
 		<h3>[method:Vector4 ceil]()</h3>
 		<h3>[method:Vector4 ceil]()</h3>
@@ -138,7 +138,7 @@ var d = a.distanceTo( b );
 
 
 		<h3>[method:Float dot]( [page:Vector4 v] )</h3>
 		<h3>[method:Float dot]( [page:Vector4 v] )</h3>
 		<div>
 		<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].
 		vector and [page:Vector4 v].
 		</div>
 		</div>
 
 
@@ -151,7 +151,7 @@ var d = a.distanceTo( b );
 		<h3>[method:Vector4 fromArray]( [page:Array array], [page:Integer offset] )</h3>
 		<h3>[method:Vector4 fromArray]( [page:Array array], [page:Integer offset] )</h3>
 		<div>
 		<div>
 		[page:Array array] - the source array.<br />
 		[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 ]
 		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 ].
 		[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 />
 		[page:Vector4 v] - [page:Vector4] to interpolate towards.<br />
 		alpha - interpolation factor in the closed interval [0, 1].<br /><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].
 		distance along the line - alpha = 0 will be this vector, and alpha = 1 will be [page:Vector4 v].
 		</div>
 		</div>
 
 
@@ -216,7 +216,7 @@ var d = a.distanceTo( b );
 
 
 		<h3>[method:Vector4 normalize]()</h3>
 		<h3>[method:Vector4 normalize]()</h3>
 		<div>
 		<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.
 		as this one, but [page:.length length] 1.
 		</div>
 		</div>
 
 
@@ -250,7 +250,7 @@ var d = a.distanceTo( b );
 		<div>
 		<div>
 			[page:Quaterion q] - a normalized [page:Quaterion]<br /><br />
 			[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.
 			quaternion's axis and [page:.w w] to the angle.
 		</div>
 		</div>
 
 
@@ -258,7 +258,7 @@ var d = a.distanceTo( b );
 		<div>
 		<div>
 			 [page:Matrix4 m] - a [page:Matrix4] of which the upper left 3x3 matrix is a pure rotation matrix.<br /><br />
 			 [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>
 		</div>
 
 
 		<h3>[method:null setComponent]( [page:Integer index], [page:Float value] )</h3>
 		<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>
 		<h3>[method:Vector4 setLength]( [page:Float l] )</h3>
 		<div>
 		<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].
 		[page:Float l].
 		</div>
 		</div>
 
 
 		<h3>[method:Vector4 setScalar]( [page:Float scalar] )</h3>
 		<h3>[method:Vector4 setScalar]( [page:Float scalar] )</h3>
 		<div>
 		<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>
 		</div>
 
 
 		<h3>[method:Vector4 setX]( [page:Float x] )</h3>
 		<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>
 		<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>
 		<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>
 		<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>
 		<h3>[method:Vector4 sub]( [page:Vector4 v] )</h3>
 		<div>Subtracts [page:Vector4 v] from this vector.</div>
 		<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>
 		<h3>[method:Array toArray]( [page:Array array], [page:Integer offset] )</h3>
 		<div>
 		<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 />
 		[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].
 		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>
 		<h2>Example</h2>
 
 
 		<code>
 		<code>
-		// instantiate a loader
+		// Instantiate a loader
 		var loader = new THREE.GLTFLoader();
 		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>
 		</code>
 
 
 		[example:webgl_loader_gltf]
 		[example:webgl_loader_gltf]

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

@@ -61,13 +61,19 @@
 		<h2>4. Procedural Text Geometry</h2>
 		<h2>4. Procedural Text Geometry</h2>
 		<div>
 		<div>
 			<p>
 			<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>
-			<p>A Text Geometry can then be created with </p>
-			<code>new THREE.TextGeometry( text, parameters );</code>
 
 
 			<h3>Examples</h3>
 			<h3>Examples</h3>
 			[example:webgl_geometry_text WebGL / geometry / text]<br />
 			[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' );
 		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, 'outerRadius', 1, 30 ).onChange( generateGeometry );
 		folder.add( data, 'thetaSegments', 1, 30 ).step( 1 ).onChange( generateGeometry );
 		folder.add( data, 'thetaSegments', 1, 30 ).step( 1 ).onChange( generateGeometry );
 		folder.add( data, 'phiSegments', 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' );
 		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, 'outerRadius', 1, 30 ).onChange( generateGeometry );
 		folder.add( data, 'thetaSegments', 1, 30 ).step( 1 ).onChange( generateGeometry );
 		folder.add( data, 'thetaSegments', 1, 30 ).step( 1 ).onChange( generateGeometry );
 		folder.add( data, 'phiSegments', 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 ) {
 		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 );
 				animations[ child.id ] = new THREE.Animation( child, child.geometry.animation );
 
 
 			} else if ( child instanceof THREE.MorphAnimMesh ) {
 			} else if ( child instanceof THREE.MorphAnimMesh ) {

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

@@ -229,6 +229,16 @@ Sidebar.Material = function ( editor ) {
 
 
 	container.add( materialVertexColorsRow );
 	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
 	// map
 
 
 	var materialMapRow = new UI.Row();
 	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 ) {
 			if ( material.map !== undefined ) {
 
 
 				var mapEnabled = materialMapEnabled.getValue() === true;
 				var mapEnabled = materialMapEnabled.getValue() === true;
@@ -938,6 +954,7 @@ Sidebar.Material = function ( editor ) {
 			'clearCoatRoughness': materialClearCoatRoughnessRow,
 			'clearCoatRoughness': materialClearCoatRoughnessRow,
 			'vertexShader': materialProgramRow,
 			'vertexShader': materialProgramRow,
 			'vertexColors': materialVertexColorsRow,
 			'vertexColors': materialVertexColorsRow,
+			'skinning': materialSkinningRow,
 			'map': materialMapRow,
 			'map': materialMapRow,
 			'alphaMap': materialAlphaMapRow,
 			'alphaMap': materialAlphaMapRow,
 			'bumpMap': materialBumpMapRow,
 			'bumpMap': materialBumpMapRow,
@@ -1044,6 +1061,12 @@ Sidebar.Material = function ( editor ) {
 
 
 		}
 		}
 
 
+		if ( material.skinning !== undefined ) {
+
+			materialSkinning.setValue( material.skinning );
+
+		}
+
 		if ( material.map !== undefined ) {
 		if ( material.map !== undefined ) {
 
 
 			materialMapEnabled.setValue( material.map !== null );
 			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;
 				mesh.scale.x = - 1;
 				scene.add( mesh );
 				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;
 				mesh.scale.x = - 1;
 				scene.add( mesh );
 				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 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: Math.random() * 0xffffff, overdraw: 0.5 } ),
 					new THREE.MeshBasicMaterial( { color: 0x000000, 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.x = centerOffset;
 				mesh.position.y = 100;
 				mesh.position.y = 100;

+ 1 - 1
examples/canvas_materials.html

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

+ 6 - 2
examples/js/BlendCharacter.js

@@ -36,6 +36,8 @@ THREE.BlendCharacter = function () {
 
 
 			}
 			}
 
 
+			scope.material.skinning = true;
+
 			scope.mixer = new THREE.AnimationMixer( scope );
 			scope.mixer = new THREE.AnimationMixer( scope );
 
 
 			// Create the animations
 			// Create the animations
@@ -57,9 +59,10 @@ THREE.BlendCharacter = function () {
 		var scope = this;
 		var scope = this;
 
 
 		var loader = new THREE.JSONLoader();
 		var loader = new THREE.JSONLoader();
-		loader.load( url, function ( geometry, materials ) {
+		loader.load( url, function( geometry, materials ) {
 
 
 			var originalMaterial = materials[ 0 ];
 			var originalMaterial = materials[ 0 ];
+			originalMaterial.skinning = true;
 
 
 			THREE.SkinnedMesh.call( scope, geometry, originalMaterial );
 			THREE.SkinnedMesh.call( scope, geometry, originalMaterial );
 
 
@@ -79,7 +82,7 @@ THREE.BlendCharacter = function () {
 		} );
 		} );
 
 
 	};
 	};
-
+	
 	this.update = function( dt ) {
 	this.update = function( dt ) {
 
 
 		this.mixer.update( 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,
 			var s = scope.modelScale,
 				delta = new THREE.Vector3();
 				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
 			// body
 
 

+ 84 - 162
examples/js/Mirror.js

@@ -2,52 +2,50 @@
  * @author Slayvin / http://slayvin.net
  * @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 );
 	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 = {
 	var mirrorShader = {
 
 
@@ -92,7 +90,7 @@ THREE.Mirror = function ( renderer, camera, options ) {
 
 
 	var mirrorUniforms = THREE.UniformsUtils.clone( mirrorShader.uniforms );
 	var mirrorUniforms = THREE.UniformsUtils.clone( mirrorShader.uniforms );
 
 
-	this.material = new THREE.ShaderMaterial( {
+	var material = new THREE.ShaderMaterial( {
 
 
 		fragmentShader: mirrorShader.fragmentShader,
 		fragmentShader: mirrorShader.fragmentShader,
 		vertexShader: mirrorShader.vertexShader,
 		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
 		// Update the texture matrix
-		this.textureMatrix.set(
+		textureMatrix.set(
 			0.5, 0.0, 0.0, 0.5,
 			0.5, 0.0, 0.0, 0.5,
 			0.0, 0.5, 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.5, 0.5,
 			0.0, 0.0, 0.0, 1.0
 			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
 		// 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
 		// 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 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.z = - 1.0;
 		q.w = ( 1.0 + projectionMatrix.elements[ 10 ] ) / projectionMatrix.elements[ 14 ];
 		q.w = ( 1.0 + projectionMatrix.elements[ 10 ] ) / projectionMatrix.elements[ 14 ];
 
 
 		// Calculate the scaled plane vector
 		// Calculate the scaled plane vector
 		var c = new THREE.Vector4();
 		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
 		// Replacing the third row of the projection matrix
 		projectionMatrix.elements[ 2 ] = c.x;
 		projectionMatrix.elements[ 2 ] = c.x;
 		projectionMatrix.elements[ 6 ] = c.y;
 		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;
 		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.computeBoundingBox();
 			geometry.computeVertexNormals();
 			geometry.computeVertexNormals();
 
 
-			mesh = new THREE.SkinnedMesh( geometry, new THREE.MultiMaterial() );
+			mesh = new THREE.SkinnedMesh( geometry, [] );
 			mesh.name = config.character;
 			mesh.name = config.character;
 			scope.root.add( mesh );
 			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 () {
 	this.reset = function () {
 
 
 		scope.target.copy( scope.target0 );
 		scope.target.copy( scope.target0 );

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

@@ -13,11 +13,11 @@
  *
  *
  * // How to set outline parameters for each material
  * // How to set outline parameters for each material
  * material.outlineParameters = {
  * 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,
  * 	visible: true,
- * 	keepAlive: true  // this paremeter won't work for Material in materials of MultiMaterial
+ * 	keepAlive: true
  * };
  * };
  *
  *
  * TODO
  * TODO
@@ -35,8 +35,8 @@ THREE.OutlineEffect = function ( renderer, parameters ) {
 	var defaultAlpha = parameters.defaultAlpha !== undefined ? parameters.defaultAlpha : 1.0;
 	var defaultAlpha = parameters.defaultAlpha !== undefined ? parameters.defaultAlpha : 1.0;
 	var defaultKeepAlive = parameters.defaultKeepAlive !== undefined ? parameters.defaultKeepAlive : false;
 	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
 	// save at the outline material creation and release
 	// if it's unused removeThresholdCount frames
 	// if it's unused removeThresholdCount frames
 	// unless keepAlive is true.
 	// unless keepAlive is true.
@@ -44,8 +44,8 @@ THREE.OutlineEffect = function ( renderer, parameters ) {
 
 
 	var removeThresholdCount = 60;
 	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.
 	// save before render and release after render.
 	var originalMaterials = {};
 	var originalMaterials = {};
 
 
@@ -55,8 +55,6 @@ THREE.OutlineEffect = function ( renderer, parameters ) {
 
 
 	//this.cache = cache;  // for debug
 	//this.cache = cache;  // for debug
 
 
-	var invisibleMaterial = new THREE.ShaderMaterial( { visible: false } );
-
 	// copied from WebGLPrograms and removed some materials
 	// copied from WebGLPrograms and removed some materials
 	var shaderIDs = {
 	var shaderIDs = {
 		MeshBasicMaterial: 'basic',
 		MeshBasicMaterial: 'basic',
@@ -139,6 +137,12 @@ THREE.OutlineEffect = function ( renderer, parameters ) {
 
 
 	].join( "\n" );
 	].join( "\n" );
 
 
+	function createInvisibleMaterial() {
+
+		return new THREE.ShaderMaterial( { name: 'invisible', visible: false } );
+
+	}
+
 	function createMaterial( originalMaterial ) {
 	function createMaterial( originalMaterial ) {
 
 
 		var shaderID = shaderIDs[ originalMaterial.type ];
 		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, ' +
 				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.' );
 				              '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 {
 		} else {
 
 
-			return invisibleMaterial;
+			return createInvisibleMaterial();
 
 
 		}
 		}
 
 
@@ -195,85 +199,74 @@ THREE.OutlineEffect = function ( renderer, parameters ) {
 		if ( ! /vec3\s+transformed\s*=/.test( originalVertexShader ) &&
 		if ( ! /vec3\s+transformed\s*=/.test( originalVertexShader ) &&
 		     ! /#include\s+<begin_vertex>/.test( originalVertexShader ) ) defines.DECLARE_TRANSFORMED = true;
 		     ! /#include\s+<begin_vertex>/.test( originalVertexShader ) ) defines.DECLARE_TRANSFORMED = true;
 
 
-		var material = new THREE.ShaderMaterial( {
+		return new THREE.ShaderMaterial( {
 			defines: defines,
 			defines: defines,
 			uniforms: uniforms,
 			uniforms: uniforms,
 			vertexShader: vertexShader,
 			vertexShader: vertexShader,
 			fragmentShader: fragmentShader,
 			fragmentShader: fragmentShader,
 			side: THREE.BackSide,
 			side: THREE.BackSide,
 			//wireframe: true,
 			//wireframe: true,
+			skinning: false,
 			morphTargets: false,
 			morphTargets: false,
 			morphNormals: false,
 			morphNormals: false,
 			fog: 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 ) {
 		if ( data === undefined ) {
 
 
 			data = {
 			data = {
-				material: object.material.isMultiMaterial === true ? createMultiMaterial( object.material ) : createMaterial( object.material ),
+				material: createMaterial( originalMaterial ),
 				used: true,
 				used: true,
 				keepAlive: defaultKeepAlive,
 				keepAlive: defaultKeepAlive,
 				count: 0
 				count: 0
 			};
 			};
 
 
-			cache[ object.material.uuid ] = data;
+			cache[ originalMaterial.uuid ] = data;
 
 
 		}
 		}
 
 
-		var outlineMaterial = data.material;
 		data.used = true;
 		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 {
 		} else {
 
 
-			updateOutlineMaterial( outlineMaterial, object.material );
+			object.material = getOutlineMaterial( object.material );
 
 
 		}
 		}
 
 
-		object.material = outlineMaterial;
-
 		originalOnBeforeRenders[ object.uuid ] = object.onBeforeRender;
 		originalOnBeforeRenders[ object.uuid ] = object.onBeforeRender;
 		object.onBeforeRender = onBeforeRender;
 		object.onBeforeRender = onBeforeRender;
 
 
@@ -283,31 +276,29 @@ THREE.OutlineEffect = function ( renderer, parameters ) {
 
 
 		if ( object.material === undefined ) return;
 		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 ];
 		object.onBeforeRender = originalOnBeforeRenders[ object.uuid ];
 
 
 	}
 	}
 
 
 	function onBeforeRender( renderer, scene, camera, geometry, material, group ) {
 	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 ];
 		var originalMaterial = originalMaterials[ material.uuid ];
 
 
+		// just in case
 		if ( originalMaterial === undefined ) return;
 		if ( originalMaterial === undefined ) return;
 
 
 		updateUniforms( material, originalMaterial );
 		updateUniforms( material, originalMaterial );
@@ -332,10 +323,11 @@ THREE.OutlineEffect = function ( renderer, parameters ) {
 
 
 	function updateOutlineMaterial( material, originalMaterial ) {
 	function updateOutlineMaterial( material, originalMaterial ) {
 
 
-		if ( material === invisibleMaterial ) return;
+		if ( material.name === 'invisible' ) return;
 
 
 		var outlineParameters = originalMaterial.outlineParameters;
 		var outlineParameters = originalMaterial.outlineParameters;
 
 
+		material.skinning = originalMaterial.skinning;
 		material.morphTargets = originalMaterial.morphTargets;
 		material.morphTargets = originalMaterial.morphTargets;
 		material.morphNormals = originalMaterial.morphNormals;
 		material.morphNormals = originalMaterial.morphNormals;
 		material.fog = originalMaterial.fog;
 		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;
 			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 {
 		} 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() {
 	function cleanupCache() {
 
 
 		var keys;
 		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(
 	var LTC_MAT_TEXTURE = new THREE.DataTexture(
 			new Float32Array( LTC_MAT ),
 			new Float32Array( LTC_MAT ),
@@ -47,15 +45,12 @@
 	LTC_MAT_TEXTURE.needsUpdate = true;
 	LTC_MAT_TEXTURE.needsUpdate = true;
 	LTC_MAG_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
 	// 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 );
 			var skeleton = new THREE.Skeleton( allBones, offsetMatrix );
 
 
 			this.threeNode.bind( skeleton, new THREE.Matrix4() );
 			this.threeNode.bind( skeleton, new THREE.Matrix4() );
+			this.threeNode.material.skinning = true;
 
 
 		};
 		};
 
 
@@ -1849,7 +1850,7 @@
 
 
 					}
 					}
 
 
-
+					
 
 
 				}
 				}
 
 
@@ -1872,7 +1873,7 @@
 				} else {
 				} else {
 
 
 					throw ( new Error( "Sorry, can't currently triangulate polys. Use the triangulate preprocessor in Assimp." ))
 					throw ( new Error( "Sorry, can't currently triangulate polys. Use the triangulate preprocessor in Assimp." ))
-
+					
 				}
 				}
 
 
 
 
@@ -2349,4 +2350,4 @@
 
 
 	THREE.AssimpLoader = AssimpLoader;
 	THREE.AssimpLoader = AssimpLoader;
 
 
-} )();
+} )();

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

@@ -1197,7 +1197,18 @@ THREE.ColladaLoader = function () {
 
 
 					applySkin( geom, skinController );
 					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 );
 					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;
 			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;
 			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 ( 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 );
 				mesh = new THREE.SkinnedMesh( geometry, material );
 
 
 			} else {
 			} else {

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

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

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

@@ -136,15 +136,6 @@ THREE.GLTF2Loader = ( function () {
 
 
 			update: function ( scene, camera ) {
 			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 ) {
 				for ( var name in objects ) {
 
 
 					var object = objects[ name ];
 					var object = objects[ name ];
@@ -163,10 +154,6 @@ THREE.GLTF2Loader = ( function () {
 
 
 	}
 	}
 
 
-	/* GLTFSHADERS */
-
-	GLTF2Loader.Shaders = new GLTFRegistry();
-
 	/* GLTFSHADER */
 	/* GLTFSHADER */
 
 
 	function GLTFShader( targetNode, allNodes ) {
 	function GLTFShader( targetNode, allNodes ) {
@@ -568,9 +555,9 @@ THREE.GLTF2Loader = ( function () {
 
 
 						value.then( function( key, value ) {
 						value.then( function( key, value ) {
 
 
-							results[ idx ] = value;
+							results[ key ] = value;
 
 
-						}.bind( this, key ));
+						}.bind( this, idx ));
 
 
 					} else {
 					} else {
 
 
@@ -632,8 +619,8 @@ THREE.GLTF2Loader = ( function () {
 		if ( typeof url !== 'string' || url === '' )
 		if ( typeof url !== 'string' || url === '' )
 			return '';
 			return '';
 
 
-		// Absolute URL
-		if ( /^https?:\/\//i.test( url ) ) {
+		// Absolute URL http://,https://,//
+		if ( /^(https?:)?\/\//i.test( url ) ) {
 
 
 			return url;
 			return url;
 
 
@@ -1063,7 +1050,7 @@ THREE.GLTF2Loader = ( function () {
 
 
 			return _each( json.textures, function ( texture ) {
 			return _each( json.textures, function ( texture ) {
 
 
-				if ( texture.source ) {
+				if ( texture.source !== undefined ) {
 
 
 					return new Promise( function ( resolve ) {
 					return new Promise( function ( resolve ) {
 
 
@@ -1103,7 +1090,7 @@ THREE.GLTF2Loader = ( function () {
 
 
 							_texture.type = texture.type !== undefined ? WEBGL_TEXTURE_DATATYPES[ texture.type ] : THREE.UnsignedByteType;
 							_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 ];
 								var sampler = json.samplers[ texture.sampler ];
 
 
@@ -1573,7 +1560,7 @@ THREE.GLTF2Loader = ( function () {
 
 
 			return _each( json.meshes, function ( mesh ) {
 			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.name !== undefined ) group.name = mesh.name;
 
 
 				if ( mesh.extras ) group.userData = mesh.extras;
 				if ( mesh.extras ) group.userData = mesh.extras;
@@ -1594,7 +1581,7 @@ THREE.GLTF2Loader = ( function () {
 
 
 							var attributeEntry = attributes[ attributeId ];
 							var attributeEntry = attributes[ attributeId ];
 
 
-							if ( ! attributeEntry ) return;
+							if ( attributeEntry === undefined ) return;
 
 
 							var bufferAttribute = dependencies.accessors[ attributeEntry ];
 							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 ] );
 							geometry.setIndex( dependencies.accessors[ primitive.indices ] );
 
 
@@ -1682,7 +1669,7 @@ THREE.GLTF2Loader = ( function () {
 
 
 						var meshNode;
 						var meshNode;
 
 
-						if ( primitive.indices ) {
+						if ( primitive.indices !== undefined ) {
 
 
 							geometry.setIndex( dependencies.accessors[ primitive.indices ] );
 							geometry.setIndex( dependencies.accessors[ primitive.indices ] );
 
 
@@ -1923,11 +1910,25 @@ THREE.GLTF2Loader = ( function () {
 
 
 					var node = json.nodes[ nodeId ];
 					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 ];
 							var group = dependencies.meshes[ mesh ];
 
 
 							if ( group === undefined ) {
 							if ( group === undefined ) {
@@ -1985,7 +1986,7 @@ THREE.GLTF2Loader = ( function () {
 
 
 								var skinEntry;
 								var skinEntry;
 
 
-								if ( node.skin ) {
+								if ( node.skin !== undefined ) {
 
 
 									skinEntry = dependencies.skins[ node.skin ];
 									skinEntry = dependencies.skins[ node.skin ];
 
 
@@ -2012,6 +2013,7 @@ THREE.GLTF2Loader = ( function () {
 
 
 									var geometry = originalGeometry;
 									var geometry = originalGeometry;
 									var material = originalMaterial;
 									var material = originalMaterial;
+									material.skinning = true;
 
 
 									child = new THREE.SkinnedMesh( geometry, material, false );
 									child = new THREE.SkinnedMesh( geometry, material, false );
 									child.castShadow = true;
 									child.castShadow = true;
@@ -2163,8 +2165,10 @@ THREE.GLTF2Loader = ( function () {
 					// Register raw material meshes with GLTF2Loader.Shaders
 					// Register raw material meshes with GLTF2Loader.Shaders
 					if ( child.material && child.material.isRawShaderMaterial ) {
 					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: 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 ) {
 				for ( var name in objects ) {
 
 
 					var object = objects[ name ];
 					var object = objects[ name ];
@@ -164,7 +155,15 @@ THREE.GLTFLoader = ( function () {
 
 
 	/* GLTFSHADERS */
 	/* GLTFSHADERS */
 
 
-	GLTFLoader.Shaders = new GLTFRegistry();
+	GLTFLoader.Shaders = {
+
+		update: function () {
+
+			console.warn( 'THREE.GLTFLoader.Shaders has been deprecated, and now updates automatically.' );
+
+		}
+
+	};
 
 
 	/* GLTFSHADER */
 	/* GLTFSHADER */
 
 
@@ -580,9 +579,9 @@ THREE.GLTFLoader = ( function () {
 
 
 						value.then( function( key, value ) {
 						value.then( function( key, value ) {
 
 
-							results[ idx ] = value;
+							results[ key ] = value;
 
 
-						}.bind( this, key ));
+						}.bind( this, idx ));
 
 
 					} else {
 					} else {
 
 
@@ -644,8 +643,8 @@ THREE.GLTFLoader = ( function () {
 		if ( typeof url !== 'string' || url === '' )
 		if ( typeof url !== 'string' || url === '' )
 			return '';
 			return '';
 
 
-		// Absolute URL
-		if ( /^https?:\/\//i.test( url ) ) {
+		// Absolute URL http://,https://,//
+		if ( /^(https?:)?\/\//i.test( url ) ) {
 
 
 			return url;
 			return url;
 
 
@@ -1109,7 +1108,7 @@ THREE.GLTFLoader = ( function () {
 							if ( texture.internalFormat !== undefined && _texture.format !== WEBGL_TEXTURE_FORMATS[ texture.internalFormat ] ) {
 							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. ' +
 								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 ) {
 			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.name !== undefined ) group.name = mesh.name;
 
 
 				if ( mesh.extras ) group.userData = mesh.extras;
 				if ( mesh.extras ) group.userData = mesh.extras;
@@ -2024,6 +2023,7 @@ THREE.GLTFLoader = ( function () {
 
 
 									var geometry = originalGeometry;
 									var geometry = originalGeometry;
 									var material = originalMaterial;
 									var material = originalMaterial;
+									material.skinning = true;
 
 
 									child = new THREE.SkinnedMesh( geometry, material, false );
 									child = new THREE.SkinnedMesh( geometry, material, false );
 									child.castShadow = true;
 									child.castShadow = true;
@@ -2175,8 +2175,10 @@ THREE.GLTFLoader = ( function () {
 					// Register raw material meshes with GLTFLoader.Shaders
 					// Register raw material meshes with GLTFLoader.Shaders
 					if ( child.material && child.material.isRawShaderMaterial ) {
 					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 scope = this;
 	var geometry = new THREE.BufferGeometry();
 	var geometry = new THREE.BufferGeometry();
-	var material = new THREE.MultiMaterial();
+	var materials = [];
 	var helper = new THREE.MMDLoader.DataCreationHelper();
 	var helper = new THREE.MMDLoader.DataCreationHelper();
 
 
 	var buffer = {};
 	var buffer = {};
@@ -1118,6 +1118,7 @@ THREE.MMDLoader.prototype.createMesh = function ( model, texturePath, onProgress
 
 
 			if ( p.name !== undefined ) m.name = p.name;
 			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.morphTargets = geometry.morphTargets.length > 0 ? true : false;
 			m.lights = true;
 			m.lights = true;
 			m.side = ( model.metadata.format === 'pmx' && ( p2.flag & 0x1 ) === 1 ) ? THREE.DoubleSide : p.side;
 			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 ] ) {
 					if ( m.opacity !== e.diffuse[ 3 ] ) {
 
 
@@ -1498,7 +1499,7 @@ THREE.MMDLoader.prototype.createMesh = function ( model, texturePath, onProgress
 	initPhysics();
 	initPhysics();
 	initGeometry();
 	initGeometry();
 
 
-	var mesh = new THREE.SkinnedMesh( geometry, material );
+	var mesh = new THREE.SkinnedMesh( geometry, materials );
 
 
 	// console.log( mesh ); // for console debug
 	// 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;
 			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 ] = sea.material[ i ].tag;
 
 
+				mats[ i ].skinning = skeleton != undefined;
 				mats[ i ].morphTargets = uMorph;
 				mats[ i ].morphTargets = uMorph;
 				mats[ i ].morphNormals = uMorphNormal;
 				mats[ i ].morphNormals = uMorphNormal;
 				mats[ i ].vertexColors = sea.geometry.color ? THREE.VertexColors : THREE.NoColors;
 				mats[ i ].vertexColors = sea.geometry.color ? THREE.VertexColors : THREE.NoColors;
 
 
 			}
 			}
 
 
-			mat = new THREE.MultiMaterial( mats );
+//			mat = new THREE.MultiMaterial( mats );
+			mat = mats;
 
 
 		} else {
 		} else {
 
 
 			mat = sea.material[ 0 ].tag;
 			mat = sea.material[ 0 ].tag;
 
 
+			mat.skinning = skeleton != undefined;
 			mat.morphTargets = uMorph;
 			mat.morphTargets = uMorph;
 			mat.morphNormals = uMorphNormal;
 			mat.morphNormals = uMorphNormal;
 			mat.vertexColors = sea.geometry.color ? THREE.VertexColors : THREE.NoColors;
 			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.coord = new THREE.OperatorNode( this.textureMatrix, this.worldPosition, THREE.OperatorNode.MUL );
 	this.coordResult = new THREE.OperatorNode( null, this.coord, THREE.OperatorNode.ADD );
 	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.type = 'SpriteCanvasMaterial';
 
 
 	this.color = new THREE.Color( 0xffffff );
 	this.color = new THREE.Color( 0xffffff );
-	this.program = function ( context, color ) {};
+	this.program = function () {};
 
 
 	this.setValues( parameters );
 	this.setValues( parameters );
 
 
@@ -17,6 +17,7 @@ THREE.SpriteCanvasMaterial = function ( parameters ) {
 
 
 THREE.SpriteCanvasMaterial.prototype = Object.create( THREE.Material.prototype );
 THREE.SpriteCanvasMaterial.prototype = Object.create( THREE.Material.prototype );
 THREE.SpriteCanvasMaterial.prototype.constructor = THREE.SpriteCanvasMaterial;
 THREE.SpriteCanvasMaterial.prototype.constructor = THREE.SpriteCanvasMaterial;
+THREE.SpriteCanvasMaterial.prototype.isSpriteCanvasMaterial = true;
 
 
 THREE.SpriteCanvasMaterial.prototype.clone = function () {
 THREE.SpriteCanvasMaterial.prototype.clone = function () {
 
 
@@ -39,78 +40,69 @@ THREE.CanvasRenderer = function ( parameters ) {
 	parameters = parameters || {};
 	parameters = parameters || {};
 
 
 	var _this = this,
 	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
 	/* TODO
 	_canvas.mozImageSmoothingEnabled = false;
 	_canvas.mozImageSmoothingEnabled = false;
@@ -266,10 +258,10 @@ THREE.CanvasRenderer = function ( parameters ) {
 			_clearBox.intersect( _clipBox );
 			_clearBox.intersect( _clipBox );
 			_clearBox.expandByScalar( 2 );
 			_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 ) {
 			if ( _clearAlpha < 1 ) {
 
 
@@ -312,7 +304,7 @@ THREE.CanvasRenderer = function ( parameters ) {
 
 
 	this.render = function ( scene, camera ) {
 	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.' );
 			console.error( 'THREE.CanvasRenderer.render: camera is not an instance of THREE.Camera.' );
 			return;
 			return;
@@ -341,7 +333,6 @@ THREE.CanvasRenderer = function ( parameters ) {
 		_renderData = _projector.projectScene( scene, camera, this.sortObjects, this.sortElements );
 		_renderData = _projector.projectScene( scene, camera, this.sortObjects, this.sortElements );
 		_elements = _renderData.elements;
 		_elements = _renderData.elements;
 		_lights = _renderData.lights;
 		_lights = _renderData.lights;
-		_camera = camera;
 
 
 		_normalViewMatrix.getNormalMatrix( camera.matrixWorldInverse );
 		_normalViewMatrix.getNormalMatrix( camera.matrixWorldInverse );
 
 
@@ -454,17 +445,17 @@ THREE.CanvasRenderer = function ( parameters ) {
 			var light = _lights[ l ];
 			var light = _lights[ l ];
 			var lightColor = light.color;
 			var lightColor = light.color;
 
 
-			if ( light instanceof THREE.AmbientLight ) {
+			if ( light.isAmbientLight ) {
 
 
 				_ambientLight.add( lightColor );
 				_ambientLight.add( lightColor );
 
 
-			} else if ( light instanceof THREE.DirectionalLight ) {
+			} else if ( light.isDirectionalLight ) {
 
 
 				// for sprites
 				// for sprites
 
 
 				_directionalLights.add( lightColor );
 				_directionalLights.add( lightColor );
 
 
-			} else if ( light instanceof THREE.PointLight ) {
+			} else if ( light.isPointLight ) {
 
 
 				// for sprites
 				// for sprites
 
 
@@ -484,7 +475,7 @@ THREE.CanvasRenderer = function ( parameters ) {
 
 
 			_lightColor.copy( light.color );
 			_lightColor.copy( light.color );
 
 
-			if ( light instanceof THREE.DirectionalLight ) {
+			if ( light.isDirectionalLight ) {
 
 
 				var lightPosition = _vector3.setFromMatrixPosition( light.matrixWorld ).normalize();
 				var lightPosition = _vector3.setFromMatrixPosition( light.matrixWorld ).normalize();
 
 
@@ -496,7 +487,7 @@ THREE.CanvasRenderer = function ( parameters ) {
 
 
 				color.add( _lightColor.multiplyScalar( amount ) );
 				color.add( _lightColor.multiplyScalar( amount ) );
 
 
-			} else if ( light instanceof THREE.PointLight ) {
+			} else if ( light.isPointLight ) {
 
 
 				var lightPosition = _vector3.setFromMatrixPosition( light.matrixWorld );
 				var lightPosition = _vector3.setFromMatrixPosition( light.matrixWorld );
 
 
@@ -530,7 +521,7 @@ THREE.CanvasRenderer = function ( parameters ) {
 		_elemBox.min.set( v1.x - dist, v1.y - dist );
 		_elemBox.min.set( v1.x - dist, v1.y - dist );
 		_elemBox.max.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;
 			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() );
 			setStrokeStyle( material.color.getStyle() );
 			setFillStyle( material.color.getStyle() );
 			setFillStyle( material.color.getStyle() );
@@ -600,6 +591,17 @@ THREE.CanvasRenderer = function ( parameters ) {
 
 
 			_context.restore();
 			_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
 		/* DEBUG
@@ -623,7 +625,7 @@ THREE.CanvasRenderer = function ( parameters ) {
 		_context.moveTo( v1.positionScreen.x, v1.positionScreen.y );
 		_context.moveTo( v1.positionScreen.x, v1.positionScreen.y );
 		_context.lineTo( v2.positionScreen.x, v2.positionScreen.y );
 		_context.lineTo( v2.positionScreen.x, v2.positionScreen.y );
 
 
-		if ( material instanceof THREE.LineBasicMaterial ) {
+		if ( material.isLineBasicMaterial ) {
 
 
 			setLineWidth( material.linewidth );
 			setLineWidth( material.linewidth );
 			setLineCap( material.linecap );
 			setLineCap( material.linecap );
@@ -670,7 +672,7 @@ THREE.CanvasRenderer = function ( parameters ) {
 			_context.stroke();
 			_context.stroke();
 			_elemBox.expandByScalar( material.linewidth * 2 );
 			_elemBox.expandByScalar( material.linewidth * 2 );
 
 
-		} else if ( material instanceof THREE.LineDashedMaterial ) {
+		} else if ( material.isLineDashedMaterial ) {
 
 
 			setLineWidth( material.linewidth );
 			setLineWidth( material.linewidth );
 			setLineCap( material.linecap );
 			setLineCap( material.linecap );
@@ -702,7 +704,7 @@ THREE.CanvasRenderer = function ( parameters ) {
 
 
 		drawTriangle( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y );
 		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 );
 			_diffuseColor.copy( material.color );
 			_emissiveColor.copy( material.emissive );
 			_emissiveColor.copy( material.emissive );
@@ -725,9 +727,7 @@ THREE.CanvasRenderer = function ( parameters ) {
 				 ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin )
 				 ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin )
 				 : fillPath( _color );
 				 : 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 ) {
 			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 );
 			_normal.copy( element.normalModel ).applyMatrix3( _normalViewMatrix );
 
 
@@ -944,10 +944,10 @@ THREE.CanvasRenderer = function ( parameters ) {
 		// http://extremelysatisfactorytotalitarianism.com/blog/?p=2120
 		// http://extremelysatisfactorytotalitarianism.com/blog/?p=2120
 
 
 		var a, b, c, d, e, f, det, idet,
 		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;
 		u0 = ( u0 + offsetX ) * width;
 		v0 = ( v0 + offsetY ) * height;
 		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 ) {
 	function clipImage( x0, y0, x1, y1, x2, y2, u0, v0, u1, v1, u2, v2, image ) {
 
 
 		// http://extremelysatisfactorytotalitarianism.com/blog/?p=2120
 		// http://extremelysatisfactorytotalitarianism.com/blog/?p=2120
@@ -1022,13 +1023,14 @@ THREE.CanvasRenderer = function ( parameters ) {
 		_context.restore();
 		_context.restore();
 
 
 	}
 	}
+	*/
 
 
 	// Hide anti-alias gaps
 	// Hide anti-alias gaps
 
 
 	function expand( v1, v2, pixels ) {
 	function expand( v1, v2, pixels ) {
 
 
 		var x = v2.x - v1.x, y = v2.y - v1.y,
 		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;
 		if ( det === 0 ) return;
 
 

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

@@ -99,33 +99,32 @@ THREE.RenderableSprite = function () {
 THREE.Projector = function () {
 THREE.Projector = function () {
 
 
 	var _object, _objectCount, _objectPool = [], _objectPoolLength = 0,
 	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().' );
 		console.error( 'THREE.Projector: .pickingRay() is now raycaster.setFromCamera().' );
 
 
@@ -154,6 +153,7 @@ THREE.Projector = function () {
 	var RenderList = function () {
 	var RenderList = function () {
 
 
 		var normals = [];
 		var normals = [];
+		var colors = [];
 		var uvs = [];
 		var uvs = [];
 
 
 		var object = null;
 		var object = null;
@@ -169,6 +169,7 @@ THREE.Projector = function () {
 			normalMatrix.getNormalMatrix( object.matrixWorld );
 			normalMatrix.getNormalMatrix( object.matrixWorld );
 
 
 			normals.length = 0;
 			normals.length = 0;
+			colors.length = 0;
 			uvs.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 ) {
 		function pushUv( x, y ) {
 
 
 			uvs.push( x, y );
 			uvs.push( x, y );
@@ -241,17 +248,36 @@ THREE.Projector = function () {
 			var v1 = _vertexPool[ a ];
 			var v1 = _vertexPool[ a ];
 			var v2 = _vertexPool[ b ];
 			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,
 			checkBackfaceCulling: checkBackfaceCulling,
 			pushVertex: pushVertex,
 			pushVertex: pushVertex,
 			pushNormal: pushNormal,
 			pushNormal: pushNormal,
+			pushColor: pushColor,
 			pushUv: pushUv,
 			pushUv: pushUv,
 			pushLine: pushLine,
 			pushLine: pushLine,
 			pushTriangle: pushTriangle
 			pushTriangle: pushTriangle
-		}
+		};
 
 
 	};
 	};
 
 
 	var renderList = new RenderList();
 	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 ) {
 		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;
 			var geometry = object.geometry;
 
 
 			renderList.setObject( object );
 			renderList.setObject( object );
@@ -609,6 +650,8 @@ THREE.Projector = function () {
 
 
 			} else if ( object instanceof THREE.Line ) {
 			} else if ( object instanceof THREE.Line ) {
 
 
+				_modelViewProjectionMatrix.multiplyMatrices( _viewProjectionMatrix, _modelMatrix );
+
 				if ( geometry instanceof THREE.BufferGeometry ) {
 				if ( geometry instanceof THREE.BufferGeometry ) {
 
 
 					var attributes = geometry.attributes;
 					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 ) {
 						if ( geometry.index !== null ) {
 
 
 							var indices = geometry.index.array;
 							var indices = geometry.index.array;
@@ -649,8 +704,6 @@ THREE.Projector = function () {
 
 
 				} else if ( geometry instanceof THREE.Geometry ) {
 				} else if ( geometry instanceof THREE.Geometry ) {
 
 
-					_modelViewProjectionMatrix.multiplyMatrices( _viewProjectionMatrix, _modelMatrix );
-
 					var vertices = object.geometry.vertices;
 					var vertices = object.geometry.vertices;
 
 
 					if ( vertices.length === 0 ) continue;
 					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
 	// Pools
 
 
 	function getNextObjectInPool() {
 	function getNextObjectInPool() {
@@ -861,10 +941,11 @@ THREE.Projector = function () {
 
 
 		// Calculate the boundary coordinate of each vertex for the near and far clip planes,
 		// Calculate the boundary coordinate of each vertex for the near and far clip planes,
 		// Z = -1 and Z = +1, respectively.
 		// 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 ) {
 		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 _lightPrePass = false;
 	var _cacheKeepAlive = false;
 	var _cacheKeepAlive = false;
 
 
-	var _invisibleMaterial = new THREE.ShaderMaterial( { visible: false } );
-
+	var _tmpMaterial = new THREE.ShaderMaterial( { visible: false } );
 	var _tmpVector3 = new THREE.Vector3();
 	var _tmpVector3 = new THREE.Vector3();
 
 
 	// scene/material/light cache for deferred rendering.
 	// scene/material/light cache for deferred rendering.
@@ -80,13 +79,12 @@ THREE.WebGLDeferredRenderer = function ( parameters ) {
 	var _lightScenesCache = {};
 	var _lightScenesCache = {};
 	var _lightFullscreenScenesCache = {};
 	var _lightFullscreenScenesCache = {};
 
 
-	// originalMaterial.uuid -> deferredMaterial
-	// (no mapping from children of MultiMaterial)
+	// object.material.uuid -> deferredMaterial or
+	// object.material[ n ].uuid -> deferredMaterial
 	var _normalDepthMaterialsCache = {};
 	var _normalDepthMaterialsCache = {};
 	var _normalDepthShininessMaterialsCache = {};
 	var _normalDepthShininessMaterialsCache = {};
 	var _colorMaterialsCache = {};
 	var _colorMaterialsCache = {};
 	var _reconstructionMaterialsCache = {};
 	var _reconstructionMaterialsCache = {};
-	var _invisibleMultiMaterialsCache = {};
 
 
 	// originalLight.uuid -> deferredLight
 	// originalLight.uuid -> deferredLight
 	var _deferredLightsCache = {};
 	var _deferredLightsCache = {};
@@ -97,8 +95,8 @@ THREE.WebGLDeferredRenderer = function ( parameters ) {
 
 
 	var _removeThresholdCount = 60;
 	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.
 	// save before render and release after render.
 	var _originalMaterialsTable = {};
 	var _originalMaterialsTable = {};
 
 
@@ -106,6 +104,11 @@ THREE.WebGLDeferredRenderer = function ( parameters ) {
 	// save before render and release after render.
 	// save before render and release after render.
 	var _originalOnBeforeRendersTable = {};
 	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
 	// external properties
 
 
 	this.renderer = undefined;
 	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 ];
 		var data = cache[ originalMaterial.uuid ];
 
 
 		if ( data === undefined ) {
 		if ( data === undefined ) {
 
 
 			data = createCacheData();
 			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;
 		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 {
 		} 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(
 		return getMaterialFromCacheOrCreate(
 			originalMaterial,
 			originalMaterial,
 			( _lightPrePass ) ? _normalDepthShininessMaterialsCache : _normalDepthMaterialsCache,
 			( _lightPrePass ) ? _normalDepthShininessMaterialsCache : _normalDepthMaterialsCache,
-			createDeferredNormalDepthMaterial
+			createDeferredNormalDepthMaterial,
+			updateDeferredNormalDepthMaterial
 		);
 		);
 
 
 	}
 	}
@@ -420,6 +427,7 @@ THREE.WebGLDeferredRenderer = function ( parameters ) {
 
 
 	function updateDeferredNormalDepthMaterial( material, originalMaterial ) {
 	function updateDeferredNormalDepthMaterial( material, originalMaterial ) {
 
 
+		if ( originalMaterial.skinning !== undefined ) material.skinning = originalMaterial.skinning;
 		if ( originalMaterial.morphTargets !== undefined ) material.morphTargets = originalMaterial.morphTargets;
 		if ( originalMaterial.morphTargets !== undefined ) material.morphTargets = originalMaterial.morphTargets;
 
 
 		if ( originalMaterial.visible === true ) {
 		if ( originalMaterial.visible === true ) {
@@ -448,30 +456,7 @@ THREE.WebGLDeferredRenderer = function ( parameters ) {
 
 
 	function setMaterialColor( object ) {
 	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(
 		return getMaterialFromCacheOrCreate(
 			originalMaterial,
 			originalMaterial,
 			_colorMaterialsCache,
 			_colorMaterialsCache,
-			createDeferredColorMaterial
+			createDeferredColorMaterial,
+			updateDeferredColorMaterial
 		);
 		);
 
 
 	}
 	}
@@ -505,6 +491,7 @@ THREE.WebGLDeferredRenderer = function ( parameters ) {
 	function updateDeferredColorMaterial( material, originalMaterial ) {
 	function updateDeferredColorMaterial( material, originalMaterial ) {
 
 
 		if ( originalMaterial.map !== undefined ) material.map = originalMaterial.map;
 		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.morphTargets !== undefined ) material.morphTargets = originalMaterial.morphTargets;
 
 
 		if ( originalMaterial.visible === true ) {
 		if ( originalMaterial.visible === true ) {
@@ -551,48 +538,24 @@ THREE.WebGLDeferredRenderer = function ( parameters ) {
 
 
 	function setMaterialReconstruction( object ) {
 	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(
 		return getMaterialFromCacheOrCreate(
 			originalMaterial,
 			originalMaterial,
 			_reconstructionMaterialsCache,
 			_reconstructionMaterialsCache,
-			createDeferredReconstructionMaterial
+			createDeferredReconstructionMaterial,
+			updateDeferredReconstructionMaterial
 		);
 		);
 
 
 	}
 	}
@@ -622,65 +585,72 @@ THREE.WebGLDeferredRenderer = function ( parameters ) {
 
 
 	function updateDeferredReconstructionUniforms( renderer, scene, camera, geometry, material, group ) {
 	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 );
 		updateDeferredColorUniforms( renderer, scene, camera, geometry, material, group );
 
 
 		material.uniforms.samplerLight.value = _compLight.renderTarget2.texture;
 		material.uniforms.samplerLight.value = _compLight.renderTarget2.texture;
 
 
 	}
 	}
 
 
-	function setMaterialForwardRendering( object ) {
+	function setVisibleForForwardRendering( object ) {
 
 
 		if ( object.material === undefined ) return;
 		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 {
 		} 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 {
 		} else {
 
 
-			return _invisibleMaterial;
+			object.material.visible = _originalVisibleTable[ object.material.uuid ];
 
 
 		}
 		}
 
 
@@ -761,11 +731,12 @@ THREE.WebGLDeferredRenderer = function ( parameters ) {
 
 
 			data = createCacheData();
 			data = createCacheData();
 			data.material = createDeferredLightMaterial( light.userData.originalLight );
 			data.material = createDeferredLightMaterial( light.userData.originalLight );
-
 			cache[ light.uuid ] = data;
 			cache[ light.uuid ] = data;
 
 
 		}
 		}
 
 
+		data.used = true;
+
 		return data.material;
 		return data.material;
 
 
 	}
 	}
@@ -784,7 +755,7 @@ THREE.WebGLDeferredRenderer = function ( parameters ) {
 
 
 	function createDeferredLightMesh( light, geometry ) {
 	function createDeferredLightMesh( light, geometry ) {
 
 
-		var mesh = new THREE.Mesh( geometry, _invisibleMaterial );
+		var mesh = new THREE.Mesh( geometry, _tmpMaterial );
 
 
 		mesh.userData.originalLight = light;
 		mesh.userData.originalLight = light;
 
 
@@ -973,21 +944,22 @@ THREE.WebGLDeferredRenderer = function ( parameters ) {
 
 
 	}
 	}
 
 
-	function saveOriginalMaterialAndCheckTransparency( object ) {
+	function saveOriginalOnBeforeRenderAndCheckTransparency( object ) {
 
 
 		if ( object.material === undefined ) return;
 		if ( object.material === undefined ) return;
 
 
-		_originalMaterialsTable[ object.uuid ] = object.material;
 		_originalOnBeforeRendersTable[ object.uuid ] = object.onBeforeRender;
 		_originalOnBeforeRendersTable[ object.uuid ] = object.onBeforeRender;
 
 
 		// _hasTransparentObject is used only for Classic Deferred Rendering
 		// _hasTransparentObject is used only for Classic Deferred Rendering
 		if ( _hasTransparentObject || _lightPrePass ) return;
 		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;
 					_hasTransparentObject = true;
 					break;
 					break;
@@ -998,17 +970,16 @@ THREE.WebGLDeferredRenderer = function ( parameters ) {
 
 
 		} else {
 		} 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;
 		if ( object.material === undefined ) return;
 
 
-		object.material = _originalMaterialsTable[ object.uuid ];
 		object.onBeforeRender = _originalOnBeforeRendersTable[ object.uuid ];
 		object.onBeforeRender = _originalOnBeforeRendersTable[ object.uuid ];
 
 
 	}
 	}
@@ -1023,11 +994,12 @@ THREE.WebGLDeferredRenderer = function ( parameters ) {
 
 
 			data = createCacheData();
 			data = createCacheData();
 			data.light = createDeferredLight( object );
 			data.light = createDeferredLight( object );
-
 			_deferredLightsCache[ object.uuid ] = data;
 			_deferredLightsCache[ object.uuid ] = data;
 
 
 		}
 		}
 
 
+		data.used = true;
+
 		var light = data.light;
 		var light = data.light;
 
 
 		if ( light === null ) return;
 		if ( light === null ) return;
@@ -1225,7 +1197,7 @@ THREE.WebGLDeferredRenderer = function ( parameters ) {
 
 
 	function cleanupTable( table ) {
 	function cleanupTable( table ) {
 
 
-		var keys = Object.keys( cache );
+		var keys = Object.keys( table );
 
 
 		for ( var i = 0, il = keys.length; i < il; i ++ ) {
 		for ( var i = 0, il = keys.length; i < il; i ++ ) {
 
 
@@ -1245,13 +1217,13 @@ THREE.WebGLDeferredRenderer = function ( parameters ) {
 		cleanupCache( _normalDepthShininessMaterialsCache );
 		cleanupCache( _normalDepthShininessMaterialsCache );
 		cleanupCache( _colorMaterialsCache );
 		cleanupCache( _colorMaterialsCache );
 		cleanupCache( _reconstructionMaterialsCache );
 		cleanupCache( _reconstructionMaterialsCache );
-		cleanupCache( _invisibleMultiMaterialsCache );
 		cleanupCache( _classicDeferredLightMaterialsCache );
 		cleanupCache( _classicDeferredLightMaterialsCache );
 		cleanupCache( _lightPrePassMaterialsCache );
 		cleanupCache( _lightPrePassMaterialsCache );
 		cleanupCache( _deferredLightsCache );
 		cleanupCache( _deferredLightsCache );
 
 
 		cleanupTable( _originalMaterialsTable );
 		cleanupTable( _originalMaterialsTable );
 		cleanupTable( _originalOnBeforeRendersTable );
 		cleanupTable( _originalOnBeforeRendersTable );
+		cleanupTable( _originalVisibleTable );
 
 
 	}
 	}
 
 
@@ -1289,6 +1261,8 @@ THREE.WebGLDeferredRenderer = function ( parameters ) {
 
 
 		_compNormalDepth.render();
 		_compNormalDepth.render();
 
 
+		scene.traverse( restoreOriginalMaterial );
+
 	}
 	}
 
 
 	/*
 	/*
@@ -1317,6 +1291,8 @@ THREE.WebGLDeferredRenderer = function ( parameters ) {
 
 
 		_compColor.render();
 		_compColor.render();
 
 
+		scene.traverse( restoreOriginalMaterial );
+
 	}
 	}
 
 
 	/*
 	/*
@@ -1397,6 +1373,8 @@ THREE.WebGLDeferredRenderer = function ( parameters ) {
 
 
 		_gl.disable( _gl.STENCIL_TEST );
 		_gl.disable( _gl.STENCIL_TEST );
 
 
+		scene.traverse( restoreOriginalMaterial );
+
 	}
 	}
 
 
 	/*
 	/*
@@ -1426,7 +1404,8 @@ THREE.WebGLDeferredRenderer = function ( parameters ) {
 
 
 		if ( ! _lightPrePass && _hasTransparentObject ) {
 		if ( ! _lightPrePass && _hasTransparentObject ) {
 
 
-			scene.traverse( setMaterialForwardRendering );
+			scene.traverse( setVisibleForForwardRendering );
+			scene.traverse( restoreOriginalOnBeforeRender );
 
 
 			_passForward.scene = scene;
 			_passForward.scene = scene;
 			_passForward.camera = camera;
 			_passForward.camera = camera;
@@ -1440,6 +1419,12 @@ THREE.WebGLDeferredRenderer = function ( parameters ) {
 
 
 		_compFinal.render();
 		_compFinal.render();
 
 
+		if ( ! _lightPrePass && _hasTransparentObject ) {
+
+			scene.traverse( restoreVisible );
+
+		}
+
 	}
 	}
 
 
 	// external APIs
 	// external APIs
@@ -1504,7 +1489,7 @@ THREE.WebGLDeferredRenderer = function ( parameters ) {
 
 
 		_hasTransparentObject = false;
 		_hasTransparentObject = false;
 
 
-		scene.traverse( saveOriginalMaterialAndCheckTransparency );
+		scene.traverse( saveOriginalOnBeforeRenderAndCheckTransparency );
 
 
 		updateDeferredCommonUniforms( camera );
 		updateDeferredCommonUniforms( camera );
 
 
@@ -1524,7 +1509,9 @@ THREE.WebGLDeferredRenderer = function ( parameters ) {
 
 
 		renderFinal( scene, camera );
 		renderFinal( scene, camera );
 
 
-		scene.traverse( restoreOriginalMaterial );
+		scene.traverse( restoreOriginalOnBeforeRender );
+
+		cleanupCaches();
 
 
 		scene.autoUpdate = currentSceneAutoUpdate;
 		scene.autoUpdate = currentSceneAutoUpdate;
 		this.renderer.autoClearColor = currentAutoClearColor;
 		this.renderer.autoClearColor = currentAutoClearColor;

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

@@ -83,13 +83,13 @@ var WEBVR = {
 		button.style.textAlign = 'center';
 		button.style.textAlign = 'center';
 		button.style.zIndex = '999';
 		button.style.zIndex = '999';
 		button.textContent = 'ENTER VR';
 		button.textContent = 'ENTER VR';
-		button.onclick = function() {
+		button.onclick = function () {
 
 
 			effect.isPresenting ? effect.exitPresent() : effect.requestPresent();
 			effect.isPresenting ? effect.exitPresent() : effect.requestPresent();
 
 
 		};
 		};
 
 
-		window.addEventListener( 'vrdisplaypresentchange', function ( event ) {
+		window.addEventListener( 'vrdisplaypresentchange', function () {
 
 
 			button.textContent = effect.isPresenting ? 'EXIT VR' : 'ENTER VR';
 			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 ++ ) {
 				for ( var i = 0; i < materials.length; i ++ ) {
 
 
 					var m = materials[ i ];
 					var m = materials[ i ];
+					m.skinning = true;
 					m.morphTargets = true;
 					m.morphTargets = true;
 
 
 					m.specular.setHSL( 0, 0, 0.1 );
 					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.name = "Knight Mesh";
 				mesh.position.set( x, y - bb.min.y * s, z );
 				mesh.position.set( x, y - bb.min.y * s, z );
 				mesh.scale.set( s, s, s );
 				mesh.scale.set( s, s, s );
@@ -224,7 +225,7 @@
 				mesh.receiveShadow = true;
 				mesh.receiveShadow = true;
 
 
 
 
-				mesh2 = new THREE.SkinnedMesh( geometry, new THREE.MultiMaterial( materials ) );
+				mesh2 = new THREE.SkinnedMesh( geometry, materials );
 				mesh2.name = "Lil' Bro Mesh";
 				mesh2.name = "Lil' Bro Mesh";
 				mesh2.position.set( x - 240, y - bb.min.y * s, z + 500 );
 				mesh2.position.set( x - 240, y - bb.min.y * s, z + 500 );
 				mesh2.scale.set( s / 2, s / 2, s / 2 );
 				mesh2.scale.set( s / 2, s / 2, s / 2 );

+ 32 - 79
examples/webgl_decals.html

@@ -1,30 +1,38 @@
 <!DOCTYPE html>
 <!DOCTYPE html>
 <html lang="en">
 <html lang="en">
 	<head>
 	<head>
-		<title>WebGL decals</title>
+		<title>three.js webgl - decals - Decal Splatter</title>
 		<meta charset="utf-8">
 		<meta charset="utf-8">
 		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
 		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
 		<style>
 		<style>
 			body {
 			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-family:Monospace;
 				font-size:13px;
 				font-size:13px;
-				margin: 0px;
 				text-align:center;
 				text-align:center;
-				overflow: hidden;
 			}
 			}
-			#info{ position: absolute; width: 100%; padding: 5px; }
+
+			a {
+				color: #ffffff;
+			}
 		</style>
 		</style>
 	</head>
 	</head>
 	<body>
 	<body>
 
 
 		<div id="container"></div>
 		<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="../build/three.js"></script>
 		<script src="js/geometries/DecalGeometry.js"></script>
 		<script src="js/geometries/DecalGeometry.js"></script>
@@ -67,15 +75,13 @@
 		} );
 		} );
 
 
 		var decals = [];
 		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 up = new THREE.Vector3( 0, 1, 0 );
-		var check = new THREE.Vector3( 1, 1, 1 );
 
 
 		var params = {
 		var params = {
-			projection: 'normal',
 			minScale: 10,
 			minScale: 10,
 			maxScale: 20,
 			maxScale: 20,
 			rotate: true,
 			rotate: true,
@@ -98,7 +104,7 @@
 			scene = new THREE.Scene();
 			scene = new THREE.Scene();
 
 
 			camera = new THREE.PerspectiveCamera( fov, window.innerWidth / window.innerHeight, 1, 1000 );
 			camera = new THREE.PerspectiveCamera( fov, window.innerWidth / window.innerHeight, 1, 1000 );
-			camera.position.z = 100;
+			camera.position.z = 120;
 			camera.target = new THREE.Vector3();
 			camera.target = new THREE.Vector3();
 
 
 			controls = new THREE.OrbitControls( camera, renderer.domElement );
 			controls = new THREE.OrbitControls( camera, renderer.domElement );
@@ -148,7 +154,7 @@
 			window.addEventListener( 'mouseup', function() {
 			window.addEventListener( 'mouseup', function() {
 
 
 				checkIntersection();
 				checkIntersection();
-				if ( ! moved ) shoot();
+				if ( ! moved && intersection.intersects ) shoot();
 
 
 			} );
 			} );
 
 
@@ -213,7 +219,6 @@
 
 
 			var gui = new dat.GUI();
 			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, 'minScale', 1, 30 );
 			gui.add( params, 'maxScale', 1, 30 );
 			gui.add( params, 'maxScale', 1, 30 );
 			gui.add( params, 'rotate' );
 			gui.add( params, 'rotate' );
@@ -236,7 +241,6 @@
 					map: textureLoader.load( 'obj/leeperrysmith/Map-COL.jpg' ),
 					map: textureLoader.load( 'obj/leeperrysmith/Map-COL.jpg' ),
 					specularMap: textureLoader.load( 'obj/leeperrysmith/Map-SPEC.jpg' ),
 					specularMap: textureLoader.load( 'obj/leeperrysmith/Map-SPEC.jpg' ),
 					normalMap: textureLoader.load( 'obj/leeperrysmith/Infinite-Level_02_Tangent_SmoothUV.jpg' ),
 					normalMap: textureLoader.load( 'obj/leeperrysmith/Infinite-Level_02_Tangent_SmoothUV.jpg' ),
-					normalScale: new THREE.Vector2( 0.75, 0.75 ),
 					shininess: 25
 					shininess: 25
 				} );
 				} );
 
 
@@ -244,50 +248,25 @@
 				scene.add( mesh );
 				scene.add( mesh );
 				mesh.scale.set( 10, 10, 10 );
 				mesh.scale.set( 10, 10, 10 );
 
 
-				//scene.add( new THREE.FaceNormalsHelper( mesh, 1 ) );
-				//scene.add( new THREE.VertexNormalsHelper( mesh, 1 ) );
-
 			} );
 			} );
 
 
 		}
 		}
 
 
 		function shoot() {
 		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 );
 			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();
 			var material = decalMaterial.clone();
 			material.color.setHex( Math.random() * 0xffffff );
 			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 );
 			decals.push( m );
 			scene.add( m );
 			scene.add( m );
 
 
@@ -298,36 +277,10 @@
 			decals.forEach( function( d ) {
 			decals.forEach( function( d ) {
 
 
 				scene.remove( 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++ ) {
 				for( var i = 0; i < materials.length; i++ ) {
 
 
@@ -526,7 +526,7 @@
 
 
 						for ( var j = 0; j < material_indices.length; j ++ ) {
 						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();
 				geometry.sortFacesByMaterialIndex();
 
 
-				var m = new THREE.MultiMaterial(),
+				var m = [],
 					s = CARS[ car ].scale * 1,
 					s = CARS[ car ].scale * 1,
 					r = CARS[ car ].init_rotation,
 					r = CARS[ car ].init_rotation,
 					materials = CARS[ car ].materials,
 					materials = CARS[ car ].materials,
@@ -549,7 +549,7 @@
 
 
 				for( var i in CARS[ car ].mmap ) {
 				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() {
 		function render() {
 
 
-				camera.lookAt( scene.position );
-
 				group.rotation.y += 0.01;
 				group.rotation.y += 0.01;
 
 
 				effect.render( scene, camera );
 				effect.render( scene, camera );

+ 2 - 2
examples/webgl_geometry_colors_blender.html

@@ -107,7 +107,7 @@
 
 
 				materials[ 0 ].shading = THREE.FlatShading;
 				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.position.x = 400;
 				mesh.scale.x = mesh.scale.y = mesh.scale.z = 250;
 				mesh.scale.x = mesh.scale.y = mesh.scale.z = 250;
 				scene.add( mesh );
 				scene.add( mesh );
@@ -118,7 +118,7 @@
 
 
 				materials[ 0 ].shading = THREE.FlatShading;
 				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.position.x = - 400;
 				mesh2.scale.x = mesh2.scale.y = mesh2.scale.z = 250;
 				mesh2.scale.x = mesh2.scale.y = mesh2.scale.z = 250;
 				scene.add( mesh2 );
 				scene.add( mesh2 );

+ 1 - 1
examples/webgl_geometry_extrude_shapes.html

@@ -170,7 +170,7 @@
 
 
 				var geometry = new THREE.ExtrudeGeometry( shape, extrudeSettings );
 				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 );
 				mesh.position.set( 50, 100, 50 );
 
 

+ 64 - 54
examples/webgl_geometry_shapes.html

@@ -33,7 +33,6 @@
 			var mouseXOnMouseDown = 0;
 			var mouseXOnMouseDown = 0;
 
 
 			var windowHalfX = window.innerWidth / 2;
 			var windowHalfX = window.innerWidth / 2;
-			var windowHalfY = window.innerHeight / 2;
 
 
 			init();
 			init();
 			animate();
 			animate();
@@ -105,6 +104,12 @@
 					mesh.scale.set( s, s, s );
 					mesh.scale.set( s, s, s );
 					group.add( mesh );
 					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
 					// lines
 
 
 					shape.autoClose = true;
 					shape.autoClose = true;
@@ -150,28 +155,28 @@
 
 
 				var californiaPts = [];
 				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 );
 				for( var i = 0; i < californiaPts.length; i ++ ) californiaPts[ i ].multiplyScalar( 0.25 );
 
 
@@ -181,10 +186,10 @@
 				// Triangle
 				// Triangle
 
 
 				var triangleShape = new THREE.Shape();
 				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( 120, 80 );
-				triangleShape.lineTo(  80, 20 ); // close path
+				triangleShape.lineTo( 80, 20 ); // close path
 
 
 
 
 				// Heart
 				// Heart
@@ -195,7 +200,7 @@
 
 
 				heartShape.moveTo( x + 25, y + 25 );
 				heartShape.moveTo( x + 25, y + 25 );
 				heartShape.bezierCurveTo( x + 25, y + 25, x + 20, y, x, y );
 				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 - 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 + 60, y + 77, x + 80, y + 55, x + 80, y + 35 );
 				heartShape.bezierCurveTo( x + 80, y + 35, x + 80, y, x + 50, y );
 				heartShape.bezierCurveTo( x + 80, y + 35, x + 80, y, x + 50, y );
@@ -207,7 +212,7 @@
 				var sqLength = 80;
 				var sqLength = 80;
 
 
 				var squareShape = new THREE.Shape();
 				var squareShape = new THREE.Shape();
-				squareShape.moveTo( 0,0 );
+				squareShape.moveTo( 0, 0 );
 				squareShape.lineTo( 0, sqLength );
 				squareShape.lineTo( 0, sqLength );
 				squareShape.lineTo( sqLength, sqLength );
 				squareShape.lineTo( sqLength, sqLength );
 				squareShape.lineTo( sqLength, 0 );
 				squareShape.lineTo( sqLength, 0 );
@@ -219,7 +224,7 @@
 				var rectLength = 120, rectWidth = 40;
 				var rectLength = 120, rectWidth = 40;
 
 
 				var rectShape = new THREE.Shape();
 				var rectShape = new THREE.Shape();
-				rectShape.moveTo( 0,0 );
+				rectShape.moveTo( 0, 0 );
 				rectShape.lineTo( 0, rectWidth );
 				rectShape.lineTo( 0, rectWidth );
 				rectShape.lineTo( rectLength, rectWidth );
 				rectShape.lineTo( rectLength, rectWidth );
 				rectShape.lineTo( rectLength, 0 );
 				rectShape.lineTo( rectLength, 0 );
@@ -230,12 +235,12 @@
 
 
 				var roundedRectShape = new THREE.Shape();
 				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.moveTo( x, y + radius );
 					ctx.lineTo( x, y + height - radius );
 					ctx.lineTo( x, y + height - radius );
 					ctx.quadraticCurveTo( x, y + height, x + radius, y + height );
 					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.quadraticCurveTo( x + width, y + height, x + width, y + height - radius );
 					ctx.lineTo( x + width, y + radius );
 					ctx.lineTo( x + width, y + radius );
 					ctx.quadraticCurveTo( x + width, y, x + width - radius, y );
 					ctx.quadraticCurveTo( x + width, y, x + width - radius, y );
@@ -262,9 +267,9 @@
 				var circleShape = new THREE.Shape();
 				var circleShape = new THREE.Shape();
 				circleShape.moveTo( 0, circleRadius );
 				circleShape.moveTo( 0, circleRadius );
 				circleShape.quadraticCurveTo( circleRadius, circleRadius, circleRadius, 0 );
 				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
 				// Fish
@@ -273,23 +278,23 @@
 
 
 				var fishShape = new THREE.Shape();
 				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
 				// Arc circle
 
 
 				var arcShape = new THREE.Shape();
 				var arcShape = new THREE.Shape();
 				arcShape.moveTo( 50, 10 );
 				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();
 				var holePath = new THREE.Path();
 				holePath.moveTo( 20, 10 );
 				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 );
 				arcShape.holes.push( holePath );
 
 
 
 
@@ -297,17 +302,17 @@
 
 
 				var smileyShape = new THREE.Shape();
 				var smileyShape = new THREE.Shape();
 				smileyShape.moveTo( 80, 40 );
 				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();
 				var smileyEye1Path = new THREE.Path();
 				smileyEye1Path.moveTo( 35, 20 );
 				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 );
 				smileyShape.holes.push( smileyEye1Path );
 
 
 				var smileyEye2Path = new THREE.Path();
 				var smileyEye2Path = new THREE.Path();
 				smileyEye2Path.moveTo( 65, 20 );
 				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 );
 				smileyShape.holes.push( smileyEye2Path );
 
 
 				var smileyMouthPath = new THREE.Path();
 				var smileyMouthPath = new THREE.Path();
@@ -323,10 +328,10 @@
 				// Spline shape
 				// Spline shape
 
 
 				var splinepts = [];
 				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();
 				var splineShape = new THREE.Shape();
 				splineShape.moveTo( 0, 0 );
 				splineShape.moveTo( 0, 0 );
@@ -343,10 +348,18 @@
 				addShape( squareShape,      extrudeSettings, 0x0040f0,  150,  100, 0, 0, 0, 0, 1 );
 				addShape( squareShape,      extrudeSettings, 0x0040f0,  150,  100, 0, 0, 0, 0, 1 );
 				addShape( heartShape,       extrudeSettings, 0xf00000,   60,  100, 0, 0, 0, Math.PI, 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( 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( smileyShape,      extrudeSettings, 0xf000f0, -200,  250, 0, 0, 0, Math.PI, 1 );
 				addShape( arcShape,         extrudeSettings, 0x804000,  150,    0, 0, 0, 0, 0, 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() {
 			function onWindowResize() {
 
 
-				windowHalfX = window.innerWidth / 2;
-				windowHalfY = window.innerHeight / 2;
-
 				camera.aspect = window.innerWidth / window.innerHeight;
 				camera.aspect = window.innerWidth / window.innerHeight;
 				camera.updateProjectionMatrix();
 				camera.updateProjectionMatrix();
 
 

+ 47 - 34
examples/webgl_geometry_spline_editor.html

@@ -11,10 +11,23 @@
 				margin: 0px;
 				margin: 0px;
 				overflow: hidden;
 				overflow: hidden;
 			}
 			}
+
+			#info {
+				position: absolute;
+				top: 0px;
+				width: 100%;
+				padding: 5px;
+				font-family:Monospace;
+				font-size:13px;
+				text-align:center;
+			}
 		</style>
 		</style>
 	</head>
 	</head>
 	<body>
 	<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="../build/three.js"></script>
 
 
 		<script src="js/controls/DragControls.js"></script>
 		<script src="js/controls/DragControls.js"></script>
@@ -22,6 +35,7 @@
 		<script src="js/controls/TransformControls.js"></script>
 		<script src="js/controls/TransformControls.js"></script>
 
 
 		<script src="js/libs/stats.min.js"></script>
 		<script src="js/libs/stats.min.js"></script>
+		<script src="js/libs/dat.gui.min.js"></script>
 
 
 		<script>
 		<script>
 
 
@@ -39,8 +53,7 @@
 
 
 			var container, stats;
 			var container, stats;
 			var camera, scene, renderer;
 			var camera, scene, renderer;
-			var splineHelperObjects = [],
-				splineOutline;
+			var splineHelperObjects = [], splineOutline;
 			var splinePointsLength = 4;
 			var splinePointsLength = 4;
 			var positions = [];
 			var positions = [];
 			var options;
 			var options;
@@ -50,8 +63,16 @@
 			var ARC_SEGMENTS = 200;
 			var ARC_SEGMENTS = 200;
 			var splineMesh;
 			var splineMesh;
 
 
-			var splines = {
+			var splines = {};
 
 
+			var params = {
+				uniform: true,
+				tension: 0.5,
+				centripetal: true,
+				chordal: true,
+				addPoint: addPoint,
+				removePoint: removePoint,
+				exportSpline: exportSpline
 			};
 			};
 
 
 			init();
 			init();
@@ -59,11 +80,11 @@
 
 
 			function init() {
 			function init() {
 
 
-				container = document.createElement( 'div' );
-				document.body.appendChild( container );
+				container = document.getElementById( 'container' );
+
 				scene = new THREE.Scene();
 				scene = new THREE.Scene();
 				camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 10000 );
 				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( camera );
 
 
 				scene.add( new THREE.AmbientLight( 0xf0f0f0 ) );
 				scene.add( new THREE.AmbientLight( 0xf0f0f0 ) );
@@ -106,31 +127,23 @@
 				renderer.shadowMap.enabled = true;
 				renderer.shadowMap.enabled = true;
 				container.appendChild( renderer.domElement );
 				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();
 				stats = new Stats();
 				container.appendChild( stats.dom );
 				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
 				controls = new THREE.OrbitControls( camera, renderer.domElement );
 				controls = new THREE.OrbitControls( camera, renderer.domElement );
 				controls.damping = 0.2;
 				controls.damping = 0.2;
@@ -377,13 +390,14 @@
 					strplace.push( 'new THREE.Vector3({0}, {1}, {2})'.format( p.x, p.y, p.z ) )
 					strplace.push( 'new THREE.Vector3({0}, {1}, {2})'.format( p.x, p.y, p.z ) )
 
 
 				}
 				}
+
 				console.log( strplace.join( ',\n' ) );
 				console.log( strplace.join( ',\n' ) );
 				var code = '[' + ( strplace.join( ',\n\t' ) ) + ']';
 				var code = '[' + ( strplace.join( ',\n\t' ) ) + ']';
 				prompt( 'copy and paste code', code );
 				prompt( 'copy and paste code', code );
 
 
-				}
+			}
 
 
-				function load( new_positions ) {
+			function load( new_positions ) {
 
 
 				while ( new_positions.length > positions.length ) {
 				while ( new_positions.length > positions.length ) {
 
 
@@ -412,16 +426,15 @@
 				requestAnimationFrame( animate );
 				requestAnimationFrame( animate );
 				render();
 				render();
 				stats.update();
 				stats.update();
-				controls.update();
 				transformControl.update();
 				transformControl.update();
 
 
 			}
 			}
 
 
 			function render() {
 			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 );
 				renderer.render( scene, camera );
 
 
 			}
 			}

+ 5 - 5
examples/webgl_geometry_text.html

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

+ 5 - 5
examples/webgl_geometry_text_earcut.html

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

+ 5 - 5
examples/webgl_geometry_text_pnltri.html

@@ -82,7 +82,7 @@
 
 
 			var camera, cameraTarget, scene, renderer;
 			var camera, cameraTarget, scene, renderer;
 
 
-			var group, textMesh1, textMesh2, textGeo, material;
+			var group, textMesh1, textMesh2, textGeo, materials;
 
 
 			var firstLetter = true;
 			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.FlatShading } ), // front
 					new THREE.MeshPhongMaterial( { color: 0xffffff, shading: THREE.SmoothShading } ) // side
 					new THREE.MeshPhongMaterial( { color: 0xffffff, shading: THREE.SmoothShading } ) // side
-				] );
+				];
 
 
 				group = new THREE.Group();
 				group = new THREE.Group();
 				group.position.y = 100;
 				group.position.y = 100;
@@ -457,7 +457,7 @@
 
 
 				var centerOffset = -0.5 * ( textGeo.boundingBox.max.x - textGeo.boundingBox.min.x );
 				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.x = centerOffset;
 				textMesh1.position.y = hover;
 				textMesh1.position.y = hover;
@@ -470,7 +470,7 @@
 
 
 				if ( mirror ) {
 				if ( mirror ) {
 
 
-					textMesh2 = new THREE.Mesh( textGeo, material );
+					textMesh2 = new THREE.Mesh( textGeo, materials );
 
 
 					textMesh2.position.x = centerOffset;
 					textMesh2.position.x = centerOffset;
 					textMesh2.position.y = -hover;
 					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 ) {
 			function onWindowResize( event ) {
 
 
 				SCREEN_WIDTH = window.innerWidth;
 				SCREEN_WIDTH = window.innerWidth;

+ 10 - 3
examples/webgl_loader_gltf.html

@@ -202,8 +202,7 @@
 					scene.add(ground);
 					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++) {
 				for (var i = 0; i < extensionSelect.children.length; i++) {
 					var child = extensionSelect.children[i];
 					var child = extensionSelect.children[i];
@@ -338,7 +337,6 @@
 			function animate() {
 			function animate() {
 				requestAnimationFrame( animate );
 				requestAnimationFrame( animate );
 				if (mixer) mixer.update(clock.getDelta());
 				if (mixer) mixer.update(clock.getDelta());
-				THREE.GLTF2Loader.Shaders.update(scene, camera);
 				if (cameraIndex == 0)
 				if (cameraIndex == 0)
 					orbitControls.update();
 					orbitControls.update();
 				render();
 				render();
@@ -409,6 +407,15 @@
 					shadows:true,
 					shadows:true,
 					extensions: ["glTF", "glTF-MaterialsCommon", "glTF-Binary"]
 					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",
 					name : "Snowflake",
 					url : "./models/gltf/snowflake/snowFlake.gltf",
 					url : "./models/gltf/snowflake/snowFlake.gltf",

+ 1 - 3
examples/webgl_loader_json_blender.html

@@ -108,8 +108,6 @@
 					material.morphTargets = true;
 					material.morphTargets = true;
 					material.color.setHex( 0xffaaaa );
 					material.color.setHex( 0xffaaaa );
 
 
-					var faceMaterial = new THREE.MultiMaterial( materials );
-
 					for ( var i = 0; i < 729; i ++ ) {
 					for ( var i = 0; i < 729; i ++ ) {
 
 
 						// random placement in a grid
 						// random placement in a grid
@@ -121,7 +119,7 @@
 
 
 						if ( Math.abs( x ) < 2 && Math.abs( z ) < 2 ) continue;
 						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 );
 						var s = THREE.Math.randFloat( 0.00075, 0.001 );
 						mesh.scale.set( s, s, s );
 						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 ) {
 			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.position.set( x, y, z );
 				zmesh.scale.set( 3, 3, 3 );
 				zmesh.scale.set( 3, 3, 3 );
 				scene.add( zmesh );
 				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 () {
 					gui.add( api, 'gradient mapping' ).onChange( function () {
 
 
 						if ( originalMaterials === undefined ) originalMaterials = mesh.material;
 						if ( originalMaterials === undefined ) originalMaterials = mesh.material;
-						if ( phongMaterials === undefined ) makePhongMaterials( mesh.material.materials );
+						if ( phongMaterials === undefined ) makePhongMaterials( mesh.material );
 
 
 						if ( api[ 'gradient mapping' ] ) {
 						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 } ) );
 				particleLight = new THREE.Mesh( new THREE.SphereGeometry( 4, 8, 8 ), new THREE.MeshBasicMaterial( { color: 0xffffff } ) );
 				scene.add( particleLight );
 				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 ++ ) {
 				for( var i = 0; i < materials.length; i ++ ) {
 
 
@@ -525,7 +525,7 @@
 
 
 						for ( var j = 0; j < material_indices.length; j ++ ) {
 						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();
 				geometry.sortFacesByMaterialIndex();
 
 
-				var m = new THREE.MultiMaterial(),
+				var m = [],
 					s = CARS[ car ].scale * 1,
 					s = CARS[ car ].scale * 1,
 					r = CARS[ car ].init_rotation,
 					r = CARS[ car ].init_rotation,
 					materials = CARS[ car ].materials,
 					materials = CARS[ car ].materials,
@@ -548,7 +548,7 @@
 
 
 				for ( var i in CARS[ car ].mmap ) {
 				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 );
 					mesh.scale.multiplyScalar( 100 );
 					scene.add( mesh );
 					scene.add( mesh );

+ 18 - 35
examples/webgl_mirror.html

@@ -54,15 +54,20 @@
 
 
 			var cameraControls;
 			var cameraControls;
 
 
-			var verticalMirror, groundMirror;
 			var sphereGroup, smallSphere;
 			var sphereGroup, smallSphere;
 
 
+			init();
+			animate();
+
 			function init() {
 			function init() {
 
 
+				var container = document.getElementById( 'container' );
+
 				// renderer
 				// renderer
 				renderer = new THREE.WebGLRenderer();
 				renderer = new THREE.WebGLRenderer();
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( WIDTH, HEIGHT );
 				renderer.setSize( WIDTH, HEIGHT );
+				container.appendChild( renderer.domElement );
 
 
 				// scene
 				// scene
 				scene = new THREE.Scene();
 				scene = new THREE.Scene();
@@ -77,30 +82,21 @@
 				cameraControls.minDistance = 10;
 				cameraControls.minDistance = 10;
 				cameraControls.update();
 				cameraControls.update();
 
 
-				var container = document.getElementById( 'container' );
-				container.appendChild( renderer.domElement );
-
-			}
-
-			function fillScene() {
+				//
 
 
 				var planeGeo = new THREE.PlaneBufferGeometry( 100.1, 100.1 );
 				var planeGeo = new THREE.PlaneBufferGeometry( 100.1, 100.1 );
 
 
 				// MIRROR planes
 				// MIRROR planes
-				groundMirror = new THREE.Mirror( renderer, camera, { clipBias: 0.003, textureWidth: WIDTH, textureHeight: HEIGHT, color: 0x777777 } );
 
 
-				var mirrorMesh = new THREE.Mesh( planeGeo, groundMirror.material );
-				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();
 				sphereGroup = new THREE.Object3D();
 				scene.add( sphereGroup );
 				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;
 				var timer = Date.now() * 0.01;
 
 
@@ -201,12 +187,9 @@
 
 
 				cameraControls.update();
 				cameraControls.update();
 
 
-				render();
-			}
+				renderer.render(scene, camera);
 
 
-			init();
-			fillScene();
-			update();
+			}
 
 
 		</script>
 		</script>
 	</body>
 	</body>

+ 1 - 8
examples/webgl_mirror_nodes.html

@@ -116,7 +116,7 @@
 			var clock = new THREE.Clock();
 			var clock = new THREE.Clock();
 
 
 			var cameraControls;
 			var cameraControls;
-			
+
 			var gui = new dat.GUI();
 			var gui = new dat.GUI();
 
 
 			var groundMirror;
 			var groundMirror;
@@ -283,13 +283,6 @@
 
 
 			function render() {
 			function render() {
 
 
-				// render (update) the mirrors
-				groundMirrorMaterial.visible = false;
-
-				groundMirror.render();
-
-				groundMirrorMaterial.visible = true;
-
 				renderer.render(scene, camera);
 				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;
 				mesh.scale.x = - 1;
 				scene.add(mesh);
 				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 );
 				object.position.set( -100, 100, 0 );
 				scene.add( object );
 				scene.add( object );
 				objectNewGeometry = object;
 				objectNewGeometry = object;
 
 
-				object = createObject( createMultiMaterial(), 1 );
+				object = createObject( createMaterials(), 1 );
 				object.position.set( 100, 100, 0 );
 				object.position.set( 100, 100, 0 );
 				scene.add( object );
 				scene.add( object );
 				objectToggleAddRemove = object;
 				objectToggleAddRemove = object;
 
 
-				object = createObject( createMultiMaterial(), 4 );
+				object = createObject( createMaterials(), 4 );
 				object.position.set( -100, -100, 0 );
 				object.position.set( -100, -100, 0 );
 				scene.add( object );
 				scene.add( object );
 				objectRandomizeFaces = object;
 				objectRandomizeFaces = object;
 
 
-				object = createObject( createMultiMaterial(), 4 );
+				object = createObject( createMaterials(), 4 );
 				object.position.set( 100, -100, 0 );
 				object.position.set( 100, -100, 0 );
 				scene.add( object );
 				scene.add( object );
 				objectRandomizeMaterialIndices = object;
 				objectRandomizeMaterialIndices = object;
@@ -99,7 +99,7 @@
 
 
 			}
 			}
 
 
-			function createMultiMaterial(){
+			function createMaterials(){
 				var materials = [
 				var materials = [
 					new THREE.MeshBasicMaterial( { color: 0xff0000 } ),
 					new THREE.MeshBasicMaterial( { color: 0xff0000 } ),
 					new THREE.MeshBasicMaterial( { color: 0xffff00 } ),
 					new THREE.MeshBasicMaterial( { color: 0xffff00 } ),
@@ -109,7 +109,7 @@
 					new THREE.MeshBasicMaterial( { color: 0xff00ff } )
 					new THREE.MeshBasicMaterial( { color: 0xff00ff } )
 				];
 				];
 
 
-				return new THREE.MultiMaterial( materials );
+				return materials;
 			}
 			}
 
 
 			function onWindowResize() {
 			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 ) );
 			skyBox.applyMatrix( new THREE.Matrix4().makeScale( 1, 1, - 1 ) );
 			scene.add( skyBox );
 			scene.add( skyBox );
 
 

+ 2 - 2
examples/webgl_performance.html

@@ -52,8 +52,8 @@
 
 
 				var material = new THREE.MeshNormalMaterial();
 				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();
 					geometry.computeVertexNormals();
 
 

+ 2 - 2
examples/webgl_performance_static.html

@@ -50,8 +50,8 @@
 
 
 				var material = new THREE.MeshNormalMaterial();
 				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();
 					geometry.computeVertexNormals();
 
 

+ 4 - 3
examples/webgl_simple_gi.html

@@ -42,7 +42,9 @@
 
 
 			THREE.Mesh.prototype.clone = function () {
 			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 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 );
 				scene.add( mesh );
 
 
 				//
 				//

+ 7 - 1
examples/webgl_skinning_simple.html

@@ -63,7 +63,13 @@
 
 
 				loader.load( './models/skinned/simple/simple.js', function ( geometry, materials ) {
 				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 );
 					skinnedMesh.scale.set( 1, 1, 1 );
 
 
 					// Note: We test the corresponding code path with this example -
 					// Note: We test the corresponding code path with this example -

+ 1 - 0
examples/webgldeferred_animation.html

@@ -112,6 +112,7 @@
 
 
 					var material = materials[ 0 ];
 					var material = materials[ 0 ];
 					material.emissive.set( 0x101010 );
 					material.emissive.set( 0x101010 );
+					material.skinning = true;
 					material.morphTargets = true;
 					material.morphTargets = true;
 
 
 					var mesh = new THREE.SkinnedMesh( geometry, material );
 					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/effects/VREffect.js"></script>
 		<script src="js/vr/WebVR.js"></script>
 		<script src="js/vr/WebVR.js"></script>
 
 
+		<script src="js/Mirror.js"></script>
+
 		<script>
 		<script>
 
 
 			if ( WEBVR.isAvailable() === false ) {
 			if ( WEBVR.isAvailable() === false ) {
@@ -32,6 +34,8 @@
 			var camera, scene, renderer;
 			var camera, scene, renderer;
 			var effect, controls;
 			var effect, controls;
 
 
+			var mirror;
+
 			init();
 			init();
 			animate();
 			animate();
 
 
@@ -39,41 +43,65 @@
 
 
 				scene = new THREE.Scene();
 				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 );
 				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 geometry = new THREE.TorusKnotGeometry( 0.4, 0.15, 150, 20 );
 				var material = new THREE.MeshStandardMaterial( { roughness: 0.01, metalness: 0.2 } );
 				var material = new THREE.MeshStandardMaterial( { roughness: 0.01, metalness: 0.2 } );
 				var mesh = new THREE.Mesh( geometry, material );
 				var mesh = new THREE.Mesh( geometry, material );
 				mesh.position.y = 0.75;
 				mesh.position.y = 0.75;
+				mesh.position.z = - 2;
 				mesh.castShadow = true;
 				mesh.castShadow = true;
 				mesh.receiveShadow = true;
 				mesh.receiveShadow = true;
 				scene.add( mesh );
 				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 material = new THREE.MeshStandardMaterial( { roughness: 1.0, metalness: 0.0 } );
 				var mesh = new THREE.Mesh( geometry, material );
 				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.castShadow = true;
 				mesh.receiveShadow = true;
 				mesh.receiveShadow = true;
 				scene.add( mesh );
 				scene.add( mesh );
 
 
 				var light = new THREE.DirectionalLight( 0x8800ff );
 				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.castShadow = true;
 				light.shadow.camera.zoom = 4;
 				light.shadow.camera.zoom = 4;
 				scene.add( light );
 				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 );
 				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.castShadow = true;
 				light.shadow.camera.zoom = 4;
 				light.shadow.camera.zoom = 4;
 				scene.add( light );
 				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",
     "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",
     "dev": "rollup -c -w",
     "lint": "eslint src",
     "lint": "eslint src",
-    "test": "echo \"Error: no test specified\" && exit 1"
+    "test": "rollup -c test/rollup.unit.config.js -w"
   },
   },
   "keywords": [
   "keywords": [
     "three",
     "three",

+ 3 - 3
rollup.config.js

@@ -8,9 +8,9 @@ function glsl() {
 
 
 			var transformedCode = 'export default ' + JSON.stringify(
 			var transformedCode = 'export default ' + JSON.stringify(
 				code
 				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 {
 			return {
 				code: transformedCode,
 				code: transformedCode,

+ 7 - 14
src/Three.Legacy.js

@@ -994,20 +994,6 @@ Object.defineProperties( Uniform.prototype, {
 
 
 Object.defineProperties( Material.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: {
 	wrapAround: {
 		get: function () {
 		get: function () {
 
 
@@ -1072,6 +1058,13 @@ Object.defineProperties( ShaderMaterial.prototype, {
 
 
 Object.assign( WebGLRenderer.prototype, {
 Object.assign( WebGLRenderer.prototype, {
 
 
+	getCurrentRenderTarget: function () {
+
+		console.warn( 'THREE.WebGLRenderer: .getCurrentRenderTarget() is now .getRenderTarget().' );
+		return this.getRenderTarget();
+
+	},
+
 	supportsFloatTextures: function () {
 	supportsFloatTextures: function () {
 
 
 		console.warn( 'THREE.WebGLRenderer: .supportsFloatTextures() is now .extensions.get( \'OES_texture_float\' ).' );
 		console.warn( 'THREE.WebGLRenderer: .supportsFloatTextures() is now .extensions.get( \'OES_texture_float\' ).' );

+ 11 - 7
src/animation/AnimationUtils.js

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

+ 2 - 2
src/animation/KeyframeTrackConstructor.js

@@ -2,9 +2,9 @@ import { AnimationUtils } from './AnimationUtils';
 
 
 function KeyframeTrackConstructor( name, times, values, interpolation ) {
 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 );
 		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 ) {
 	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 () {
 Camera.prototype.clone = function () {
 
 
 	return new this.constructor().copy( this );
 	return new this.constructor().copy( this );

+ 6 - 8
src/core/BufferGeometry.js

@@ -814,21 +814,19 @@ Object.assign( BufferGeometry.prototype, EventDispatcher.prototype, {
 
 
 	normalizeNormals: function () {
 	normalizeNormals: function () {
 
 
-		var normals = this.attributes.normal.array;
+		var normals = this.attributes.normal;
 
 
 		var x, y, z, n;
 		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 );
 			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.b = b;
 	this.c = c;
 	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.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.vertexColors = Array.isArray( color ) ? color : [];
 
 
 	this.materialIndex = materialIndex !== undefined ? materialIndex : 0;
 	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 };
 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 };
 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 };
 export { InstancedInterleavedBuffer };

+ 2 - 2
src/core/InterleavedBufferAttribute.js

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

+ 5 - 5
src/core/Layers.js

@@ -4,7 +4,7 @@
 
 
 function Layers() {
 function Layers() {
 
 
-	this.mask = 1;
+	this.mask = 1 | 0;
 
 
 }
 }
 
 
@@ -12,25 +12,25 @@ Object.assign( Layers.prototype, {
 
 
 	set: function ( channel ) {
 	set: function ( channel ) {
 
 
-		this.mask = 1 << channel;
+		this.mask = 1 << channel | 0;
 
 
 	},
 	},
 
 
 	enable: function ( channel ) {
 	enable: function ( channel ) {
 
 
-		this.mask |= 1 << channel;
+		this.mask |= 1 << channel | 0;
 
 
 	},
 	},
 
 
 	toggle: function ( channel ) {
 	toggle: function ( channel ) {
 
 
-		this.mask ^= 1 << channel;
+		this.mask ^= 1 << channel | 0;
 
 
 	},
 	},
 
 
 	disable: function ( channel ) {
 	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 ) {
 		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 );
 			this.quaternion.setFromRotationMatrix( m1 );
 
 
@@ -526,9 +534,9 @@ Object.assign( Object3D.prototype, EventDispatcher.prototype, {
 
 
 	updateMatrixWorld: function ( force ) {
 	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 ) {
 			if ( this.parent === null ) {
 
 

+ 2 - 2
src/core/Raycaster.js

@@ -73,12 +73,12 @@ Object.assign( Raycaster.prototype, {
 
 
 	setFromCamera: function ( coords, camera ) {
 	setFromCamera: function ( coords, camera ) {
 
 
-		if ( (camera && camera.isPerspectiveCamera) ) {
+		if ( ( camera && camera.isPerspectiveCamera ) ) {
 
 
 			this.ray.origin.setFromMatrixPosition( camera.matrixWorld );
 			this.ray.origin.setFromMatrixPosition( camera.matrixWorld );
 			this.ray.direction.set( coords.x, coords.y, 0.5 ).unproject( camera ).sub( this.ray.origin ).normalize();
 			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.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 );
 			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
  * @author abelnation / http://github.com/abelnation
  */
  */
 
 
-function RectAreaLight ( color, intensity, width, height ) {
+function RectAreaLight( color, intensity, width, height ) {
 
 
 	Light.call( this, color, intensity );
 	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): update method for RectAreaLight to update transform to lookat target
 
 
 	// TODO (abelnation): shadows
 	// 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.width = source.width;
 		this.height = source.height;
 		this.height = source.height;
 
 
-		// this.shadow = source.shadow.clone();
-
 		return this;
 		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