Mr.doob 8 years ago
parent
commit
bf9f3eab54
100 changed files with 15574 additions and 5666 deletions
  1. 3055 3013
      build/three.js
  2. 116 331
      build/three.min.js
  3. 5000 0
      build/three.modules.js
  4. 4 0
      docs/api/cameras/Camera.html
  5. 2 2
      docs/api/constants/CustomBlendingEquations.html
  6. 24 0
      docs/api/constants/DrawModes.html
  7. 2 2
      docs/api/constants/GLState.html
  8. 1 1
      docs/api/constants/Materials.html
  9. 2 2
      docs/api/constants/ShadowingTypes.html
  10. 2 2
      docs/api/constants/Textures.html
  11. 5 1
      docs/api/core/Geometry.html
  12. 81 0
      docs/api/core/Layers.html
  13. 19 0
      docs/api/core/Object3D.html
  14. 1 1
      docs/api/core/Raycaster.html
  15. 0 17
      docs/api/core/Uniform.html
  16. 4 0
      docs/api/extras/core/Curve.html
  17. 1 1
      docs/api/geometries/ConeBufferGeometry.html
  18. 1 1
      docs/api/geometries/ConeGeometry.html
  19. 54 0
      docs/api/geometries/DodecahedronBufferGeometry.html
  20. 1 1
      docs/api/geometries/DodecahedronGeometry.html
  21. 91 45
      docs/api/geometries/ExtrudeGeometry.html
  22. 53 0
      docs/api/geometries/IcosahedronBufferGeometry.html
  23. 2 1
      docs/api/geometries/IcosahedronGeometry.html
  24. 53 0
      docs/api/geometries/OctahedronBufferGeometry.html
  25. 2 1
      docs/api/geometries/OctahedronGeometry.html
  26. 60 0
      docs/api/geometries/ParametricBufferGeometry.html
  27. 27 0
      docs/api/geometries/ParametricGeometry.html
  28. 64 0
      docs/api/geometries/PolyhedronBufferGeometry.html
  29. 1 3
      docs/api/geometries/PolyhedronGeometry.html
  30. 32 13
      docs/api/geometries/ShapeGeometry.html
  31. 54 0
      docs/api/geometries/TetrahedronBufferGeometry.html
  32. 1 1
      docs/api/geometries/TetrahedronGeometry.html
  33. 104 0
      docs/api/geometries/TubeBufferGeometry.html
  34. 44 39
      docs/api/geometries/TubeGeometry.html
  35. 38 7
      docs/api/loaders/glTFLoader.html
  36. 6 2
      docs/api/materials/Material.html
  37. 1 1
      docs/api/materials/MeshStandardMaterial.html
  38. 2 2
      docs/api/math/Box2.html
  39. 18 2
      docs/api/math/Box3.html
  40. 8 0
      docs/api/math/Color.html
  41. 1 1
      docs/api/math/Line3.html
  42. 12 0
      docs/api/math/Math.html
  43. 3 2
      docs/api/math/Matrix3.html
  44. 3 2
      docs/api/math/Matrix4.html
  45. 16 0
      docs/api/math/Plane.html
  46. 16 0
      docs/api/math/Sphere.html
  47. 8 0
      docs/api/math/Vector2.html
  48. 11 3
      docs/api/math/Vector3.html
  49. 8 0
      docs/api/math/Vector4.html
  50. 5 0
      docs/api/objects/Mesh.html
  51. 13 8
      docs/api/scenes/Scene.html
  52. 11 2
      docs/list.js
  53. 1 1
      docs/manual/introduction/Creating-a-scene.html
  54. 1 4
      docs/scenes/bones-browser.html
  55. 1 3
      docs/scenes/geometry-browser.html
  56. 293 0
      docs/scenes/js/geometry.js
  57. 5 0
      editor/examples/arkanoid.app.json
  58. 8 0
      editor/examples/camera.app.json
  59. 1 1
      editor/index.html
  60. 4 3
      editor/js/Loader.js
  61. 2 2
      editor/js/libs/tern-threejs/threejs.js
  62. 1 1
      examples/css3d_youtube.html
  63. 5 1
      examples/files.js
  64. BIN
      examples/fonts/ttf/kenpixel.ttf
  65. 1 1
      examples/js/ParametricGeometries.js
  66. 98 133
      examples/js/SkyShader.js
  67. 7 4
      examples/js/controls/EditorControls.js
  68. 6 6
      examples/js/controls/TrackballControls.js
  69. 15 1
      examples/js/controls/VRControls.js
  70. 294 0
      examples/js/effects/OutlineEffect.js
  71. 1 1
      examples/js/effects/StereoEffect.js
  72. 46 19
      examples/js/effects/VREffect.js
  73. 19 0
      examples/js/libs/opentype.min.js
  74. 1556 190
      examples/js/loaders/GLTFLoader.js
  75. 263 435
      examples/js/loaders/MMDLoader.js
  76. 74 75
      examples/js/loaders/PLYLoader.js
  77. 193 0
      examples/js/loaders/TTFLoader.js
  78. 0 0
      examples/js/loaders/deprecated/gltf/glTF-parser.js
  79. 0 0
      examples/js/loaders/deprecated/gltf/glTFAnimation.js
  80. 53 23
      examples/js/loaders/deprecated/gltf/glTFLoader.js
  81. 39 23
      examples/js/loaders/deprecated/gltf/glTFLoaderUtils.js
  82. 0 0
      examples/js/loaders/deprecated/gltf/glTFShaders.js
  83. 0 0
      examples/js/loaders/deprecated/gltf/gltfUtilities.js
  84. 671 656
      examples/js/modifiers/BufferSubdivisionModifier.js
  85. 2377 0
      examples/js/renderers/WebGLDeferredRenderer.js
  86. 107 0
      examples/js/vr/PaintViveController.js
  87. 0 0
      examples/js/vr/ViveController.js
  88. 3 6
      examples/js/vr/WebVR.js
  89. BIN
      examples/models/ply/binary/Lucy100k.ply
  90. BIN
      examples/obj/lucy/Lucy100k_bin.bin
  91. 0 23
      examples/obj/lucy/Lucy100k_bin.js
  92. 0 23
      examples/obj/lucy/Lucy100k_slim.js
  93. 161 0
      examples/webgl_clipping_intersection.html
  94. 5 48
      examples/webgl_geometries2.html
  95. 62 121
      examples/webgl_geometry_extrude_splines.html
  96. 0 276
      examples/webgl_geometry_large_mesh.html
  97. 1 1
      examples/webgl_geometry_nurbs.html
  98. 40 35
      examples/webgl_interactive_instances_gpu.html
  99. 9 28
      examples/webgl_lights_hemisphere.html
  100. 8 12
      examples/webgl_loader_gltf.html

File diff suppressed because it is too large
+ 3055 - 3013
build/three.js


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


File diff suppressed because it is too large
+ 5000 - 0
build/three.modules.js


+ 4 - 0
docs/api/cameras/Camera.html

@@ -33,6 +33,10 @@
 		<h3>[property:Matrix4 projectionMatrix]</h3>
 		<div>This is the matrix which contains the projection.</div>
 
+		<h3>[property:Layers layers]</h3>
+		<div>
+		The layer membership of the camera. Only objects that have at least one layer in common with the camera will be visible. 
+		</div>
 
 		<h2>Methods</h2>
 

+ 2 - 2
docs/api/constants/CustomBlendingEquations.html

@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html lang="en">
 	<head>
-		<meta charset="utf-8" />
+		<meta charset="utf-8" />
 		<base href="../../" />
 		<script src="list.js"></script>
 		<script src="page.js"></script>
@@ -40,6 +40,6 @@
 
 		<h2>Source</h2>
 
-		[link:https://github.com/mrdoob/three.js/blob/master/src/Three.js src/Three.js]
+		[link:https://github.com/mrdoob/three.js/blob/master/src/constants.js src/constants.js]
 	</body>
 </html>

+ 24 - 0
docs/api/constants/DrawModes.html

@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<meta charset="utf-8" />
+		<base href="../../" />
+		<script src="list.js"></script>
+		<script src="page.js"></script>
+		<link type="text/css" rel="stylesheet" href="page.css" />
+	</head>
+	<body>
+		<h1>Draw Mode Constants</h1>
+
+		<h2>Draw Mode</h2>
+		<div>
+		THREE.TrianglesDrawMode<br />
+		THREE.TriangleStripDrawMode<br />
+		THREE.TriangleFanDrawMode
+		</div>
+
+		<h2>Source</h2>
+
+		[link:https://github.com/mrdoob/three.js/blob/master/src/constants.js src/constants.js]
+	</body>
+</html>

+ 2 - 2
docs/api/constants/GLState.html

@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html lang="en">
 	<head>
-		<meta charset="utf-8" />
+		<meta charset="utf-8" />
 		<base href="../../" />
 		<script src="list.js"></script>
 		<script src="page.js"></script>
@@ -26,6 +26,6 @@
 	
 		<h2>Source</h2>
 
-		[link:https://github.com/mrdoob/three.js/blob/master/src/Three.js src/Three.js]
+		[link:https://github.com/mrdoob/three.js/blob/master/src/constants.js src/constants.js]
 	</body>
 </html>

+ 1 - 1
docs/api/constants/Materials.html

@@ -53,6 +53,6 @@
 
 		<h2>Source</h2>
 
-		[link:https://github.com/mrdoob/three.js/blob/master/src/Three.js src/Three.js]
+		[link:https://github.com/mrdoob/three.js/blob/master/src/constants.js src/constants.js]
 	</body>
 </html>

+ 2 - 2
docs/api/constants/ShadowingTypes.html

@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html lang="en">
 	<head>
-		<meta charset="utf-8" />
+		<meta charset="utf-8" />
 		<base href="../../" />
 		<script src="list.js"></script>
 		<script src="page.js"></script>
@@ -19,6 +19,6 @@
 	
 		<h2>Source</h2>
 
-		[link:https://github.com/mrdoob/three.js/blob/master/src/Three.js src/Three.js]
+		[link:https://github.com/mrdoob/three.js/blob/master/src/constants.js src/constants.js]
 	</body>
 </html>

+ 2 - 2
docs/api/constants/Textures.html

@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html lang="en">
 	<head>
-		<meta charset="utf-8" />
+		<meta charset="utf-8" />
 		<base href="../../" />
 		<script src="list.js"></script>
 		<script src="page.js"></script>
@@ -91,6 +91,6 @@
 
 		<h2>Source</h2>
 
-		[link:https://github.com/mrdoob/three.js/blob/master/src/Three.js src/Three.js]
+		[link:https://github.com/mrdoob/three.js/blob/master/src/constants.js src/constants.js]
 	</body>
 </html>

+ 5 - 1
docs/api/core/Geometry.html

@@ -256,7 +256,11 @@
 		</div>
 		<div>
 		Computes vertex normals by averaging face normals.<br />
-		Face normals must be existing / computed beforehand.
+		</div>
+
+		<h3>[method:null computeFlatVertexNormals]()</h3>
+		<div>
+		Computes flat vertex normals. Sets the vertex normal of each vertex of each face to be the same as the face's normal.<br />
 		</div>
 
 		<h3>[method:null computeMorphNormals]()</h3>

+ 81 - 0
docs/api/core/Layers.html

@@ -0,0 +1,81 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<meta charset="utf-8" />
+		<base href="../../" />
+		<script src="list.js"></script>
+		<script src="page.js"></script>
+		<link type="text/css" rel="stylesheet" href="page.css" />
+	</head>
+	<body>
+		<h1>[name]</h1>
+
+		<div class="desc">
+		An object providing a bit mask and accessor method used to control an [page:Object3D]'s visibility.
+		A [page:Layers] object assigns an [page:Object3D] to 0 or more of 32 layers numbered 0 to 31.
+		</div>
+
+
+		<h2>Constructor</h2>
+
+
+		<h3>[name]()</h3>
+		<div>
+		Create a new Layers object, with an initial mask set to layer 1.
+		</div>
+
+		<h2>Properties</h2>
+
+		<h3>[property:Integer mask]</h3>
+		<div>
+		Internal layer mask.
+		</div>
+
+
+		<h2>Methods</h2>
+
+		<h3>[method:null set]( [page:Integer layer] )</h3>
+		<div>
+		layer - an integer from 0 to 31.
+		</div>
+		<div>
+		Set the layer mask to the value *layer*.
+		</div>
+
+		<h3>[method:null enable]( [page:Integer layer] )</h3>
+		<div>
+		layer - an integer from 0 to 31.
+		</div>
+		<div>
+		Add *layer* to the mask.
+		</div>
+
+		<h3>[method:null disable]( [page:Integer layer] )</h3>
+		<div>
+		layer - an integer from 0 to 31.
+		</div>
+		<div>
+		Remove *layer* from the mask.
+		</div>
+
+		<h3>[method:null toggle]( [page:Integer layer] )</h3>
+		<div>
+		layer - an integer from 0 to 31.
+		</div>
+		<div>
+		Toggle the *layer* value in the mask.
+		</div>
+
+		<h3>[method:Boolean test]( [page:Integer layers] )</h3>
+		<div>
+		layers - a 32bit bit mask of layer numbers.
+		</div>
+		<div>
+		Returns true if *layers* and .mask have any bits set in common.
+		</div>
+
+		<h2>Source</h2>
+
+		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
+	</body>
+</html>

+ 19 - 0
docs/api/core/Object3D.html

@@ -138,6 +138,25 @@
 		The global transform of the object. If the Object3d has no parent, then it's identical to the local transform.
 		</div>
 
+		<h3>[property:function onBeforeRender]</h3>
+		<div>
+		An optional callback that is executed immediately before the Object3D is rendered.  This function is called with the following parameters: renderer, scene, camera, geometry, material, group.
+		</div>
+
+		<h3>[property:function onAfterRender]</h3>
+		<div>
+		An optional callback that is executed immediately after the Object3D is rendered.  This function is called with the following parameters: renderer, scene, camera, geometry, material, group.
+		</div>
+
+		<h3>[property:Number renderOrder]</h3>
+		<div>
+		This value allows the default rendering order of scene graph objects to be overridden although opaque and transparent objects remain sorted independently. Sorting is from lowest to highest renderOrder. Default value is 0.
+		</div>
+
+		<h3>[property:Layers layers]</h3>
+		<div>
+		The layer membership of the object. The object is only visible if it has at least one layer in common with the [page:Camera] in use. 
+		</div>
 
 		<h2>Methods</h2>
 

+ 1 - 1
docs/api/core/Raycaster.html

@@ -100,7 +100,7 @@
 		This value shouldn't be negative and should be larger than the near property. 
 		</div>
 
-		<h3>.[page:float linePrecision]</h3>
+		<h3>[property:float linePrecision]</h3>
 		<div>
 		The precision factor of the raycaster when intersecting [page:Line] objects. 
 		</div>

+ 0 - 17
docs/api/core/Uniform.html

@@ -189,23 +189,6 @@
 		Current value of the uniform.
 		</div>
 
-		<h3>[property:Boolean dynamic]</h3>
-		<div>
-		Sets wether this uniform is updated at each render call when used by a renderer.
-		You must set this attribute by calling [page:.onUpdate].
-		</div>
-
-		<h2>Methods</h2>
-
-		<h3>[method:Uniform onUpdate]( [page:Function callback] ) [page:Uniform this]</h3>
-		<div>
-		Set the callback function to update this uniform at each render call. The callback has two optional parameters :
-		<ul>
-			<li>[page:Object object] : The current object associated to the [page:Material] using this [page:Uniform]</li>
-			<li>[page:Camera camera] : The current camera used by the current [page:WebGLRenderer]</li>
-		</ul>
-		</div>
-
 		<h2>Source</h2>
 
 		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]

+ 4 - 0
docs/api/extras/core/Curve.html

@@ -60,6 +60,10 @@
 		<h3>[method:Vector getTangentAt]( u )</h3>
 		<div>Returns tangent at equidistant point u on the curve</div>
 
+		<h3>[method:Object computeFrenetFrames]( segments, closed )</h3>
+		<div>
+		Generates the Frenet Frames. Used in geometries like [page:TubeGeometry] or [page:ExtrudeGeometry].
+		</div>
 
 		<h2>Source</h2>
 

+ 1 - 1
docs/api/geometries/ConeBufferGeometry.html

@@ -8,7 +8,7 @@
 		<link type="text/css" rel="stylesheet" href="page.css" />
 	</head>
 	<body>
-		[page:BufferGeometry] &rarr;
+		[page:CylinderBufferGeometry] &rarr;
 
 		<h1>[name]</h1>
 

+ 1 - 1
docs/api/geometries/ConeGeometry.html

@@ -8,7 +8,7 @@
 		<link type="text/css" rel="stylesheet" href="page.css" />
 	</head>
 	<body>
-		[page:Geometry] &rarr;
+		[page:CylinderGeometry] &rarr;
 
 		<h1>[name]</h1>
 

+ 54 - 0
docs/api/geometries/DodecahedronBufferGeometry.html

@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<meta charset="utf-8" />
+		<base href="../../" />
+		<script src="list.js"></script>
+		<script src="page.js"></script>
+		<link type="text/css" rel="stylesheet" href="page.css" />
+	</head>
+	<body>
+		[page:PolyhedronBufferGeometry] &rarr;
+
+		<h1>[name]</h1>
+
+		<div class="desc">A class for generating a dodecahedron geometries.</div>
+
+		<iframe id="scene" src="scenes/geometry-browser.html#DodecahedronBufferGeometry"></iframe>
+
+		<script>
+
+		// iOS iframe auto-resize workaround
+
+		if ( /(iPad|iPhone|iPod)/g.test( navigator.userAgent ) ) {
+
+			var scene = document.getElementById( 'scene' );
+
+			scene.style.width = getComputedStyle( scene ).width;
+			scene.style.height = getComputedStyle( scene ).height;
+			scene.setAttribute( 'scrolling', 'no' );
+
+		}
+
+		</script>
+
+		<h2>Constructor</h2>
+
+		<h3>[name]([page:Float radius], [page:Integer detail])</h3>
+		<div>
+		radius — Radius of the dodecahedron. Default is 1.<br />
+		detail — Default is 0. Setting this to a value greater than 0 adds vertices making it no longer a dodecahedron.
+		</div>
+
+		<h2>Properties</h2>
+
+		<h3>[property:Object parameters]</h3>
+		<div>
+		An object with all of the parameters that were used to generate the geometry.
+		</div>
+
+		<h2>Source</h2>
+
+		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
+	</body>
+</html>

+ 1 - 1
docs/api/geometries/DodecahedronGeometry.html

@@ -8,7 +8,7 @@
 		<link type="text/css" rel="stylesheet" href="page.css" />
 	</head>
 	<body>
-		[page:PolyhedronGeometry] &rarr;
+		[page:Geometry] &rarr;
 
 		<h1>[name]</h1>
 

+ 91 - 45
docs/api/geometries/ExtrudeGeometry.html

@@ -12,7 +12,53 @@
 
 		<h1>[name]</h1>
 
-		<div class="desc">Creates extruded geometry from a path shape</div>
+		<div class="desc">Creates extruded geometry from a path shape.</div>
+
+		<iframe id="scene" src="scenes/geometry-browser.html#ExtrudeGeometry"></iframe>
+
+		<script>
+
+		// iOS iframe auto-resize workaround
+
+		if ( /(iPad|iPhone|iPod)/g.test( navigator.userAgent ) ) {
+
+			var scene = document.getElementById( 'scene' );
+
+			scene.style.width = getComputedStyle( scene ).width;
+			scene.style.height = getComputedStyle( scene ).height;
+			scene.setAttribute( 'scrolling', 'no' );
+
+		}
+
+		</script>
+
+		<h2>Example</h2>
+
+
+		<code>
+		var length = 12, width = 8;
+
+		var shape = new THREE.Shape();
+		shape.moveTo( 0,0 );
+		shape.lineTo( 0, width );
+		shape.lineTo( length, width );
+		shape.lineTo( length, 0 );
+		shape.lineTo( 0, 0 );
+
+		var extrudeSettings = {
+			steps: 2,
+			amount: 16,
+			bevelEnabled: true,
+			bevelThickness: 1,
+			bevelSize: 1,
+			bevelSegments: 1
+		};
+
+		var geometry = new THREE.ExtrudeGeometry( shape, data );
+		var material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
+		var mesh = new THREE.Mesh( geometry, material ) ;
+		scene.add( mesh );
+		</code>
 
 
 		<h2>Constructor</h2>
@@ -23,20 +69,20 @@
 		shapes — Shape or an array of shapes. <br />
 		options — Object that can contain the following parameters.
 
-	<ul>
-<li>curveSegments —  int. number of points on the curves</li>
-<li>steps —  int. number of points used for subdividing segements of extrude spline</li>
-<li>amount —  int. Depth to extrude the shape</li>
-<li>bevelEnabled —  bool. turn on bevel</li>
-<li>bevelThickness —  float. how deep into the original shape bevel goes</li>
-<li>bevelSize —  float. how far from shape outline is bevel</li>
-<li>bevelSegments —  int. number of bevel layers</li>
-<li>extrudePath —  THREE.CurvePath. 3d spline path to extrude shape along. (creates Frames if (frames aren't defined)</li>
-<li>frames —  THREE.TubeGeometry.FrenetFrames.  containing arrays of tangents, normals, binormals</li>
-<li>material —  int. material index for front and back faces</li>
-<li>extrudeMaterial —  int. material index for extrusion and beveled faces</li>
-<li>UVGenerator —  Object. object that provides UV generator functions</li>
-	</ul>
+			<ul>
+				<li>curveSegments —  int. number of points on the curves</li>
+				<li>steps —  int. number of points used for subdividing segements of extrude spline</li>
+				<li>amount —  int. Depth to extrude the shape</li>
+				<li>bevelEnabled —  bool. turn on bevel</li>
+				<li>bevelThickness —  float. how deep into the original shape bevel goes</li>
+				<li>bevelSize —  float. how far from shape outline is bevel</li>
+				<li>bevelSegments —  int. number of bevel layers</li>
+				<li>extrudePath —  THREE.CurvePath. 3d spline path to extrude shape along. (creates Frames if frames aren't defined)</li>
+				<li>frames —  THREE.TubeGeometry.FrenetFrames.  containing arrays of tangents, normals, binormals</li>
+				<li>material —  int. material index for front and back faces</li>
+				<li>extrudeMaterial —  int. material index for extrusion and beveled faces</li>
+				<li>UVGenerator —  Object. object that provides UV generator functions</li>
+			</ul>
 
 		</div>
 		<div>
@@ -53,42 +99,42 @@
 		<div>
 			shapes — An Array of shapes to add. <br />
 			options — Object that can contain the following parameters.
-	<ul>
-<li>curveSegments —  int. number of points on the curves</li>
-<li>steps —  int. number of points used for subdividing segements of extrude spline</li>
-<li>amount —  int. Depth to extrude the shape</li>
-<li>bevelEnabled —  bool. turn on bevel</li>
-<li>bevelThickness —  float. how deep into the original shape bevel goes</li>
-<li>bevelSize —  float. how far from shape outline is bevel</li>
-<li>bevelSegments —  int. number of bevel layers</li>
-<li>extrudePath —  THREE.CurvePath. 3d spline path to extrude shape along. (creates Frames if (frames aren't defined)</li>
-<li>frames —  THREE.TubeGeometry.FrenetFrames.  containing arrays of tangents, normals, binormals</li>
-<li>material —  int. material index for front and back faces</li>
-<li>extrudeMaterial —  int. material index for extrusion and beveled faces</li>
-<li>UVGenerator —  Object. object that provides UV generator functions</li>
-	</ul>
-	</div>
+			<ul>
+				<li>curveSegments —  int. number of points on the curves</li>
+				<li>steps —  int. number of points used for subdividing segements of extrude spline</li>
+				<li>amount —  int. Depth to extrude the shape</li>
+				<li>bevelEnabled —  bool. turn on bevel</li>
+				<li>bevelThickness —  float. how deep into the original shape bevel goes</li>
+				<li>bevelSize —  float. how far from shape outline is bevel</li>
+				<li>bevelSegments —  int. number of bevel layers</li>
+				<li>extrudePath —  THREE.CurvePath. 3d spline path to extrude shape along. (creates Frames if (frames aren't defined)</li>
+				<li>frames —  THREE.TubeGeometry.FrenetFrames.  containing arrays of tangents, normals, binormals</li>
+				<li>material —  int. material index for front and back faces</li>
+				<li>extrudeMaterial —  int. material index for extrusion and beveled faces</li>
+				<li>UVGenerator —  Object. object that provides UV generator functions</li>
+			</ul>
+		</div>
 		<div>Adds the shapes to the list to extrude.</div>
 
 		<h3>[method:null addShape]([page:Shape shape], [page:Object options])</h3>
 		<div>
 			shape — A shape to add. <br />
 			options — Object that can contain the following parameters.
-	<ul>
-<li>curveSegments —  int. number of points on the curves</li>
-<li>steps —  int. number of points used for subdividing segements of extrude spline</li>
-<li>amount —  int. Depth to extrude the shape</li>
-<li>bevelEnabled —  bool. turn on bevel</li>
-<li>bevelThickness —  float. how deep into the original shape bevel goes</li>
-<li>bevelSize —  float. how far from shape outline is bevel</li>
-<li>bevelSegments —  int. number of bevel layers</li>
-<li>extrudePath —  THREE.CurvePath. 3d spline path to extrude shape along. (creates Frames if (frames aren't defined)</li>
-<li>frames —  THREE.TubeGeometry.FrenetFrames.  containing arrays of tangents, normals, binormals</li>
-<li>material —  int. material index for front and back faces</li>
-<li>extrudeMaterial —  int. material index for extrusion and beveled faces</li>
-<li>UVGenerator —  Object. object that provides UV generator functions</li>
-	</ul>
-	</div>
+			<ul>
+				<li>curveSegments —  int. number of points on the curves</li>
+				<li>steps —  int. number of points used for subdividing segements of extrude spline</li>
+				<li>amount —  int. Depth to extrude the shape</li>
+				<li>bevelEnabled —  bool. turn on bevel</li>
+				<li>bevelThickness —  float. how deep into the original shape bevel goes</li>
+				<li>bevelSize —  float. how far from shape outline is bevel</li>
+				<li>bevelSegments —  int. number of bevel layers</li>
+				<li>extrudePath —  THREE.CurvePath. 3d spline path to extrude shape along. (creates Frames if (frames aren't defined)</li>
+				<li>frames —  THREE.TubeGeometry.FrenetFrames.  containing arrays of tangents, normals, binormals</li>
+				<li>material —  int. material index for front and back faces</li>
+				<li>extrudeMaterial —  int. material index for extrusion and beveled faces</li>
+				<li>UVGenerator —  Object. object that provides UV generator functions</li>
+			</ul>
+		</div>
 		<div>Add the shape to the list to extrude.</div>
 
 

+ 53 - 0
docs/api/geometries/IcosahedronBufferGeometry.html

@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<meta charset="utf-8" />
+		<base href="../../" />
+		<script src="list.js"></script>
+		<script src="page.js"></script>
+		<link type="text/css" rel="stylesheet" href="page.css" />
+	</head>
+	<body>
+		[page:PolyhedronBufferGeometry] &rarr;
+		<h1>[name]</h1>
+
+		<div class="desc">A class for generating an icosahedron geometry.</div>
+
+		<iframe id="scene" src="scenes/geometry-browser.html#IcosahedronBufferGeometry"></iframe>
+
+		<script>
+
+		// iOS iframe auto-resize workaround
+
+		if ( /(iPad|iPhone|iPod)/g.test( navigator.userAgent ) ) {
+
+			var scene = document.getElementById( 'scene' );
+
+			scene.style.width = getComputedStyle( scene ).width;
+			scene.style.height = getComputedStyle( scene ).height;
+			scene.setAttribute( 'scrolling', 'no' );
+
+		}
+
+		</script>
+
+		<h2>Constructor</h2>
+
+		<h3>[name]([page:Float radius], [page:Integer detail])</h3>
+		<div>
+		radius — Default is 1. <br />
+		detail — Default is 0.  Setting this to a value greater than 0 adds more vertices making it no longer an icosahedron.  When detail is greater than 1, it's effectively a sphere.
+		</div>
+
+		<h2>Properties</h2>
+
+		<h3>[property:Object parameters]</h3>
+		<div>
+		An object with all of the parameters that were used to generate the geometry.
+		</div>
+
+		<h2>Source</h2>
+
+		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
+	</body>
+</html>

+ 2 - 1
docs/api/geometries/IcosahedronGeometry.html

@@ -8,7 +8,8 @@
 		<link type="text/css" rel="stylesheet" href="page.css" />
 	</head>
 	<body>
-		[page:PolyhedronGeometry] &rarr;
+		[page:Geometry] &rarr;
+		
 		<h1>[name]</h1>
 
 		<div class="desc">A class for generating an icosahedron geometry.</div>

+ 53 - 0
docs/api/geometries/OctahedronBufferGeometry.html

@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<meta charset="utf-8" />
+		<base href="../../" />
+		<script src="list.js"></script>
+		<script src="page.js"></script>
+		<link type="text/css" rel="stylesheet" href="page.css" />
+	</head>
+	<body>
+		[page:PolyhedronBufferGeometry] &rarr;
+		<h1>[name]</h1>
+
+		<div class="desc">A class for generating an octahedron geometry.</div>
+
+		<iframe id="scene" src="scenes/geometry-browser.html#OctahedronBufferGeometry"></iframe>
+
+		<script>
+
+		// iOS iframe auto-resize workaround
+
+		if ( /(iPad|iPhone|iPod)/g.test( navigator.userAgent ) ) {
+
+			var scene = document.getElementById( 'scene' );
+
+			scene.style.width = getComputedStyle( scene ).width;
+			scene.style.height = getComputedStyle( scene ).height;
+			scene.setAttribute( 'scrolling', 'no' );
+
+		}
+
+		</script>
+
+		<h2>Constructor</h2>
+
+		<h3>[name]([page:Float radius], [page:Integer detail])</h3>
+		<div>
+		radius — Radius of the octahedron. Default is 1.<br />
+		detail — Default is 0.  Setting this to a value greater than zero add vertices making it no longer an octahedron.
+		</div>
+
+		<h2>Properties</h2>
+
+		<h3>[property:Object parameters]</h3>
+		<div>
+		An object with all of the parameters that were used to generate the geometry.
+		</div>
+
+		<h2>Source</h2>
+
+		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
+	</body>
+</html>

+ 2 - 1
docs/api/geometries/OctahedronGeometry.html

@@ -8,7 +8,8 @@
 		<link type="text/css" rel="stylesheet" href="page.css" />
 	</head>
 	<body>
-		[page:PolyhedronGeometry] &rarr;
+		[page:Geometry] &rarr;
+		
 		<h1>[name]</h1>
 
 		<div class="desc">A class for generating an octahedron geometry.</div>

+ 60 - 0
docs/api/geometries/ParametricBufferGeometry.html

@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<meta charset="utf-8" />
+		<base href="../../" />
+		<script src="list.js"></script>
+		<script src="page.js"></script>
+		<link type="text/css" rel="stylesheet" href="page.css" />
+	</head>
+	<body>
+		[page:BufferGeometry] &rarr;
+
+		<h1>[name]</h1>
+
+		<div class="desc">Generate geometry representing a parametric surface.</div>
+
+		<iframe id="scene" src="scenes/geometry-browser.html#ParametricBufferGeometry"></iframe>
+
+		<script>
+
+		// iOS iframe auto-resize workaround
+
+		if ( /(iPad|iPhone|iPod)/g.test( navigator.userAgent ) ) {
+
+			var scene = document.getElementById( 'scene' );
+
+			scene.style.width = getComputedStyle( scene ).width;
+			scene.style.height = getComputedStyle( scene ).height;
+			scene.setAttribute( 'scrolling', 'no' );
+
+		}
+
+		</script>
+
+		<h2>Example</h2>
+
+		<code>
+		var geometry = new THREE.ParametricBufferGeometry( THREE.ParametricGeometries.klein, 25, 25 );
+		var material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
+		var cube = new THREE.Mesh( geometry, material );
+		scene.add( cube );
+		</code>
+
+
+		<h2>Constructor</h2>
+
+
+		<h3>[name]([page:Function func], [page:Integer slices], [page:Integer stacks])</h3>
+		<div>
+		func — A function that takes in a [page:Float u] and [page:Float v] value each between 0 and 1 and returns a [page:Vector3]<br />
+		slices — The count of slices to use for the parametric function <br />
+		stacks — The count of stacks to use for the parametric function
+		</div>
+
+
+		<h2>Source</h2>
+
+		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
+	</body>
+</html>

+ 27 - 0
docs/api/geometries/ParametricGeometry.html

@@ -14,6 +14,33 @@
 
 		<div class="desc">Generate geometry representing a parametric surface.</div>
 
+		<iframe id="scene" src="scenes/geometry-browser.html#ParametricGeometry"></iframe>
+
+		<script>
+
+		// iOS iframe auto-resize workaround
+
+		if ( /(iPad|iPhone|iPod)/g.test( navigator.userAgent ) ) {
+
+			var scene = document.getElementById( 'scene' );
+
+			scene.style.width = getComputedStyle( scene ).width;
+			scene.style.height = getComputedStyle( scene ).height;
+			scene.setAttribute( 'scrolling', 'no' );
+
+		}
+
+		</script>
+
+		<h2>Example</h2>
+
+		<code>
+		var geometry = new THREE.ParametricGeometry( THREE.ParametricGeometries.klein, 25, 25 );
+		var material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
+		var cube = new THREE.Mesh( geometry, material );
+		scene.add( cube );
+		</code>
+
 
 		<h2>Constructor</h2>
 

+ 64 - 0
docs/api/geometries/PolyhedronBufferGeometry.html

@@ -0,0 +1,64 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<meta charset="utf-8" />
+		<base href="../../" />
+		<script src="list.js"></script>
+		<script src="page.js"></script>
+		<link type="text/css" rel="stylesheet" href="page.css" />
+	</head>
+	<body>
+		[page:BufferGeometry] &rarr;
+
+		<h1>[name]</h1>
+
+		<div class="desc">
+			A polyhedron is a solid in three dimensions with flat faces. This class will take an array of vertices,
+			project them onto a sphere, and then divide them up to the desired level of detail. This class is used
+			by [page:DodecahedronBufferGeometry], [page:IcosahedronBufferGeometry], [page:OctahedronBufferGeometry],
+			and [page:TetrahedronBufferGeometry] to generate their respective geometries.
+		</div>
+
+		<h2>Example</h2>
+<code>
+var verticesOfCube = [
+    -1,-1,-1,    1,-1,-1,    1, 1,-1,    -1, 1,-1,
+    -1,-1, 1,    1,-1, 1,    1, 1, 1,    -1, 1, 1,
+];
+
+var indicesOfFaces = [
+    2,1,0,    0,3,2,
+    0,4,7,    7,3,0,
+    0,1,5,    5,4,0,
+    1,2,6,    6,5,1,
+    2,3,7,    7,6,2,
+    4,5,6,    6,7,4
+];
+
+var geometry = new THREE.PolyhedronBufferGeometry( verticesOfCube, indicesOfFaces, 6, 2 );
+</code>
+
+		<h2>Constructor</h2>
+
+
+		<h3>[name]([page:Array vertices], [page:Array faces], [page:Float radius], [page:Integer detail])</h3>
+		<div>
+		vertices — [page:Array] of points of the form [1,1,1, -1,-1,-1, ... ] <br />
+		faces — [page:Array] of indices that make up the faces of the form [0,1,2, 2,3,0, ... ] <br />
+		radius — [page:Float] - The radius of the final shape <br />
+		detail — [page:Integer] - How many levels to subdivide the geometry. The more detail, the smoother the shape.
+		</div>
+
+		<h2>Properties</h2>
+
+		<h3>[property:Object parameters]</h3>
+		<div>
+		An object with all of the parameters that were used to generate the geometry.
+		</div>
+
+
+		<h2>Source</h2>
+
+		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
+	</body>
+</html>

+ 1 - 3
docs/api/geometries/PolyhedronGeometry.html

@@ -14,9 +14,7 @@
 
 		<div class="desc">
 			A polyhedron is a solid in three dimensions with flat faces. This class will take an array of vertices,
-			project them onto a sphere, and then divide them up to the desired level of detail. This class is used
-			by [page:DodecahedronGeometry], [page:IcosahedronGeometry], [page:OctahedronGeometry],
-			and [page:TetrahedronGeometry] to generate their respective geometries.
+			project them onto a sphere, and then divide them up to the desired level of detail.
 		</div>
 
 		<h2>Example</h2>

+ 32 - 13
docs/api/geometries/ShapeGeometry.html

@@ -12,25 +12,44 @@
 
 		<h1>[name]</h1>
 
-		<div class="desc">Creates a one-sided polygonal geometry from one or more path shapes. Similar to [page:ExtrudeGeometry]</div>
+		<div class="desc">Creates a one-sided polygonal geometry from one or more path shapes. Similar to [page:ExtrudeGeometry].</div>
 
-		<h2>Example</h2>
+		<iframe id="scene" src="scenes/geometry-browser.html#ShapeGeometry"></iframe>
 
+		<script>
 
-		<code>
-var rectLength = 120, rectWidth = 40;
+		// iOS iframe auto-resize workaround
+
+		if ( /(iPad|iPhone|iPod)/g.test( navigator.userAgent ) ) {
+
+			var scene = document.getElementById( 'scene' );
+
+			scene.style.width = getComputedStyle( scene ).width;
+			scene.style.height = getComputedStyle( scene ).height;
+			scene.setAttribute( 'scrolling', 'no' );
 
-var rectShape = new THREE.Shape();
-rectShape.moveTo( 0,0 );
-rectShape.lineTo( 0, rectWidth );
-rectShape.lineTo( rectLength, rectWidth );
-rectShape.lineTo( rectLength, 0 );
-rectShape.lineTo( 0, 0 );
+		}
 
-var rectGeom = new THREE.ShapeGeometry( rectShape );
-var rectMesh = new THREE.Mesh( rectGeom, new THREE.MeshBasicMaterial( { color: 0xff0000 } ) ) ;
+		</script>
 
-scene.add( rectMesh );
+
+		<h2>Example</h2>
+
+
+		<code>
+		var length = 16, width = 12;
+
+		var shape = new THREE.Shape();
+		shape.moveTo( 0,0 );
+		shape.lineTo( 0, width );
+		shape.lineTo( length, width );
+		shape.lineTo( length, 0 );
+		shape.lineTo( 0, 0 );
+
+		var geometry = new THREE.ShapeGeometry( shape );
+		var material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
+		var mesh = new THREE.Mesh( geometry, material ) ;
+		scene.add( mesh );
 		</code>
 
 		<h2>Constructor</h2>

+ 54 - 0
docs/api/geometries/TetrahedronBufferGeometry.html

@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<meta charset="utf-8" />
+		<base href="../../" />
+		<script src="list.js"></script>
+		<script src="page.js"></script>
+		<link type="text/css" rel="stylesheet" href="page.css" />
+	</head>
+	<body>
+		[page:PolyhedronBufferGeometry] &rarr;
+
+		<h1>[name]</h1>
+
+		<div class="desc">A class for generating a tetrahedron geometries.</div>
+
+		<iframe id="scene" src="scenes/geometry-browser.html#TetrahedronBufferGeometry"></iframe>
+
+		<script>
+
+		// iOS iframe auto-resize workaround
+
+		if ( /(iPad|iPhone|iPod)/g.test( navigator.userAgent ) ) {
+
+			var scene = document.getElementById( 'scene' );
+
+			scene.style.width = getComputedStyle( scene ).width;
+			scene.style.height = getComputedStyle( scene ).height;
+			scene.setAttribute( 'scrolling', 'no' );
+
+		}
+
+		</script>
+
+		<h2>Constructor</h2>
+
+		<h3>[name]([page:Float radius], [page:Integer detail])</h3>
+		<div>
+		radius — Radius of the tetrahedron. Default is 1.<br />
+		detail — Default is 0. Setting this to a value greater than 0 adds vertices making it no longer a tetrahedron.
+		</div>
+
+		<h2>Properties</h2>
+
+		<h3>[property:Object parameters]</h3>
+		<div>
+		An object with all of the parameters that were used to generate the geometry.
+		</div>
+
+		<h2>Source</h2>
+
+		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
+	</body>
+</html>

+ 1 - 1
docs/api/geometries/TetrahedronGeometry.html

@@ -8,7 +8,7 @@
 		<link type="text/css" rel="stylesheet" href="page.css" />
 	</head>
 	<body>
-		[page:PolyhedronGeometry] &rarr;
+		[page:Geometry] &rarr;
 
 		<h1>[name]</h1>
 

+ 104 - 0
docs/api/geometries/TubeBufferGeometry.html

@@ -0,0 +1,104 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<meta charset="utf-8" />
+		<base href="../../" />
+		<script src="list.js"></script>
+		<script src="page.js"></script>
+		<link type="text/css" rel="stylesheet" href="page.css" />
+	</head>
+	<body>
+		[page:BufferGeometry] &rarr;
+
+		<h1>[name]</h1>
+
+		<div class="desc">Creates a tube that extrudes along a 3d curve.</div>
+
+		<iframe id="scene" src="scenes/geometry-browser.html#TubeBufferGeometry"></iframe>
+
+		<script>
+
+		// iOS iframe auto-resize workaround
+
+		if ( /(iPad|iPhone|iPod)/g.test( navigator.userAgent ) ) {
+
+			var scene = document.getElementById( 'scene' );
+
+			scene.style.width = getComputedStyle( scene ).width;
+			scene.style.height = getComputedStyle( scene ).height;
+			scene.setAttribute( 'scrolling', 'no' );
+
+		}
+
+		</script>
+
+		<h2>Example</h2>
+
+		<code>
+		var CustomSinCurve = THREE.Curve.create(
+
+			function ( scale ) { //custom curve constructor
+
+				this.scale = ( scale === undefined ) ? 1 : scale;
+
+			},
+
+			function ( t ) { //getPoint: t is between 0-1
+
+				var tx = t * 3 - 1.5;
+				var ty = Math.sin( 2 * Math.PI * t );
+				var tz = 0;
+
+				return new THREE.Vector3( tx, ty, tz ).multiplyScalar( this.scale );
+
+			}
+
+		);
+
+		var path = new CustomSinCurve( 10 );
+		var geometry = new THREE.TubeBufferGeometry( path, 20, 2, 8, false );
+		var material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
+		var mesh = new THREE.Mesh( geometry, material );
+		scene.add( mesh );
+		</code>
+
+		<h2>Constructor</h2>
+
+
+		<h3>[name]([page:Curve path], [page:Integer tubularSegments], [page:Float radius], [page:Integer radiusSegments], [page:Boolean closed])</h3>
+		<div>
+		path — [page:Curve] - A path that inherits from the [page:Curve] base class<br />
+		tubularSegments — [page:Integer] - The number of segments that make up the tube, default is 64<br />
+		radius — [page:Float] - The radius of the tube, default is 1<br />
+		radiusSegments — [page:Integer] - The number of segments that make up the cross-section, default is 8 <br />
+		closed — [page:Boolean] Is the tube open or closed, default is false <br />
+		</div>
+
+
+		<h2>Properties</h2>
+
+		<h3>[property:Object parameters]</h3>
+		<div>
+		An object with all of the parameters that were used to generate the geometry.
+		</div>
+
+		<h3>[property:Array tangents]</h3>
+		<div>
+		An array of [page:Vector3] tangents
+		</div>
+
+		<h3>[property:Array normals]</h3>
+		<div>
+		An array of [page:Vector3] normals
+		</div>
+
+		<h3>[property:Array binormals]</h3>
+		<div>
+		An array of [page:Vector3] binormals
+		</div>
+
+		<h2>Source</h2>
+
+		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
+	</body>
+</html>

+ 44 - 39
docs/api/geometries/TubeGeometry.html

@@ -12,43 +12,63 @@
 
 		<h1>[name]</h1>
 
-		<div class="desc">Creates a tube that extrudes along a 3d curve</div>
+		<div class="desc">Creates a tube that extrudes along a 3d curve.</div>
+
+		<iframe id="scene" src="scenes/geometry-browser.html#TubeGeometry"></iframe>
+
+		<script>
+
+		// iOS iframe auto-resize workaround
+
+		if ( /(iPad|iPhone|iPod)/g.test( navigator.userAgent ) ) {
+
+			var scene = document.getElementById( 'scene' );
+
+			scene.style.width = getComputedStyle( scene ).width;
+			scene.style.height = getComputedStyle( scene ).height;
+			scene.setAttribute( 'scrolling', 'no' );
+
+		}
+
+		</script>
 
 		<h2>Example</h2>
 
-<code>
-var CustomSinCurve = THREE.Curve.create(
-    function ( scale ) { //custom curve constructor
-        this.scale = (scale === undefined) ? 1 : scale;
-    },
+		<code>
+		var CustomSinCurve = THREE.Curve.create(
+
+			function ( scale ) { //custom curve constructor
+
+				this.scale = ( scale === undefined ) ? 1 : scale;
+
+			},
 
-    function ( t ) { //getPoint: t is between 0-1
-        var tx = t * 3 - 1.5,
-            ty = Math.sin( 2 * Math.PI * t ),
-            tz = 0;
+			function ( t ) { //getPoint: t is between 0-1
 
-        return new THREE.Vector3(tx, ty, tz).multiplyScalar(this.scale);
-    }
-);
+				var tx = t * 3 - 1.5;
+				var ty = Math.sin( 2 * Math.PI * t );
+				var tz = 0;
 
-var path = new CustomSinCurve( 10 );
+				return new THREE.Vector3( tx, ty, tz ).multiplyScalar( this.scale );
 
-var geometry = new THREE.TubeGeometry(
-    path,  //path
-    20,    //segments
-    2,     //radius
-    8,     //radiusSegments
-    false  //closed
-);
-</code>
+			}
+
+		);
+
+		var path = new CustomSinCurve( 10 );
+		var geometry = new THREE.TubeGeometry( path, 20, 2, 8, false );
+		var material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
+		var mesh = new THREE.Mesh( geometry, material );
+		scene.add( mesh );
+		</code>
 
 		<h2>Constructor</h2>
 
 
-		<h3>[name]([page:Curve path], [page:Integer segments], [page:Float radius], [page:Integer radiusSegments], [page:Boolean closed])</h3>
+		<h3>[name]([page:Curve path], [page:Integer tubularSegments], [page:Float radius], [page:Integer radiusSegments], [page:Boolean closed])</h3>
 		<div>
 		path — [page:Curve] - A path that inherits from the [page:Curve] base class<br />
-		segments — [page:Integer] - The number of segments that make up the tube, default is 64<br />
+		tubularSegments — [page:Integer] - The number of segments that make up the tube, default is 64<br />
 		radius — [page:Float] - The radius of the tube, default is 1<br />
 		radiusSegments — [page:Integer] - The number of segments that make up the cross-section, default is 8 <br />
 		closed — [page:Boolean] Is the tube open or closed, default is false <br />
@@ -77,21 +97,6 @@ var geometry = new THREE.TubeGeometry(
 		An array of [page:Vector3] binormals
 		</div>
 
-
-		<h2>Methods</h2>
-
-
-		<h3>THREE.TubeGeometry.FrenetFrames([page:Curve path], [page:Integer segments], [page:Boolean closed])</h3>
-		<div>
-		path — A path that inherits from the [page:Curve] base class <br />
-		segments — The number of segments that make up the tube <br />
-		closed — Is the tube open or closed
-		</div>
-		<div>
-		A static method that generates the Frenet Frames. This is internally run on any new TubeGeometry and then the
-		generated tangents, normals, and binormals are exposed as properties on the TubeGeometry object.
-		</div>
-
 		<h2>Source</h2>
 
 		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]

+ 38 - 7
docs/api/loaders/glTFLoader.html

@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html lang="en">
 	<head>
-		<meta charset="utf-8" />
+		<meta charset="utf-8" />
 		<base href="../../" />
 		<script src="list.js"></script>
 		<script src="page.js"></script>
@@ -20,7 +20,10 @@
 
 		<h2>Constructor</h2>
 
-		<h3>[name]( )</h3>
+		<h3>[name]( [page:LoadingManager manager] )</h3>
+		<div>
+		[page:LoadingManager manager] — The [page:LoadingManager loadingManager] for the loader to use. Default is [page:LoadingManager THREE.DefaultLoadingManager].
+		</div>
 		<div>
 		Creates a new [name].
 		</div>
@@ -30,28 +33,56 @@
 
 		<h2>Methods</h2>
 
-		<h3>[method:Object3D load]( [page:String url], [page:Function callback] )</h3>
+		<h3>[method:null load]( [page:String url], [page:Function onLoad], [page:Function onProgress], [page:Function onError] )</h3>
 		<div>
 		[page:String url] — required<br />
-		[page:Function callback] — Will be called when load completes. The argument will be an [page:Object] containing the loaded .[page:Object3D scene],  .[page:Array cameras] and .[page:Array animations].<br />
+		[page:Function onLoad] — Will be called when load completes. The argument will be the loaded JSON response returned from [page:Function parse].<br />
+		[page:Function onProgress] — Will be called while load progresses. The argument will be the XMLHttpRequest instance, that contains .[page:Integer total] and .[page:Integer loaded] bytes.<br />
+		[page:Function onError] — Will be called when load errors.<br />
 		</div>
 		<div>
 		Begin loading from url and call the callback function with the parsed response content.
 		</div>
 
+		<h3>[method:null setPath]( [page:String path] )</h3>
+		<div>
+		[page:String path] — Base path for loading additional resources e.g. textures, GLSL shaders, .bin data.
+		</div>
+		<div>
+		Set the base path for additional resources.
+		</div>
+
+		<h3>[method:null setCrossOrigin]( [page:String value] )</h3>
+		<div>
+		[page:String value] — The crossOrigin string to implement CORS for loading the url from a different domain that allows CORS.
+		</div>
+
+		<h3>[method:null parse]( [page:Object json], [page:Function callBack], [page:String path] )</h3>
+		<div>
+		[page:Object json] — <em>JSON</em> object to parse.<br />
+		[page:Function callBack] — Will be called when parse completes.<br />
+		[page:String path] — The base path from which to find subsequent glTF resources such as textures, GLSL shaders and .bin data files.<br />
+		</div>
+		<div>
+		Parse a glTF-based <em>JSON</em> structure and fire [page:Function callback] when complete. The argument to [page:Function callback] will be an [page:object] that contains loaded parts: .[page:Scene scene], .[page:Array cameras], .[page:Array animations] and .[page:Array shaders]
+		</div>
+
 
 		<h2>Notes</h2>
 
 		<div>
-		This class is often used with [page:glTFAnimator THREE.glTFAnimator] to animate parsed animations.
+		When using custom shaders provided within a glTF file [page:THREE.GLTFLoader.Shaders] should be updated on each render loop. See [example:webgl_loader_gltf] demo source code for example usage.
 		</div>
 
+		<div>
+		This class is often used with [page:THREE.GLTFLoader.Animations THREE.GLTFLoader.Animations] to animate parsed animations. See [example:webgl_loader_gltf] demo source code for example usage.
+		</div>
 
 		<h2>Example</h2>
 
 		<code>
 		// instantiate a loader
-		var loader = new THREE.glTFLoader();
+		var loader = new THREE.GLTFLoader();
 
 		// load a glTF resource
 		loader.load(
@@ -69,6 +100,6 @@
 
 		<h2>Source</h2>
 
-		[link:https://github.com/mrdoob/three.js/blob/master/examples/js/loaders/gltf/glTFLoader.js examples/js/loaders/gltf/glTFLoader.js]
+		[link:https://github.com/mrdoob/three.js/blob/master/examples/js/loaders/GLTFLoader.js examples/js/loaders/GLTFLoader.js]
 	</body>
 </html>

+ 6 - 2
docs/api/materials/Material.html

@@ -54,13 +54,13 @@
 		</div>
 		<div>Default is *false*.</div>
 
-		<h3>.[page:Blending blending]</h3>
+		<h3>[property:Blending blending]</h3>
 		<div>
 		Which blending to use when displaying objects with this material. Default is [page:Materials NormalBlending]. See the blending mode [page:Materials constants] for all possible values.
 
 		</div>
 
-		<h3>.[page:Integer blendSrc]</h3>
+		<h3>[property:Integer blendSrc]</h3>
 		<div>
 		Blending source. It's one of the blending mode constants defined in Three.js. Default is [page:CustomBlendingEquation SrcAlphaFactor]. See the destination factors [page:CustomBlendingEquation constants] for all possible values.
 		</div>
@@ -119,6 +119,10 @@
 		User-defined clipping planes specified as THREE.Plane objects in world space. These planes apply to the objects this material is attached to. Points in space whose dot product with the plane is negative are cut away. Default is null.
 		</div>
 
+		<h3>[property:Boolean clipIntersection]</h3>
+
+		<div>Changes the behavior of clipping planes so that only their intersection is clipped, rather than their union. Default is false. See <a href="http://threejs.org/examples/#webgl_clipping_intersection">example</a> </div>
+
 		<h3>[property:Boolean clipShadows]</h3>
 		<div>
 		Defines whether to clip shadows according to the clipping planes specified on this material. Default is false.

+ 1 - 1
docs/api/materials/MeshStandardMaterial.html

@@ -53,7 +53,7 @@
 		bumpMap — Set bump map. Default is null.<br />
 		bumpMapScale — Set bump map scale. Default is 1.<br />
 		normalMap — Set normal map. Default is null.<br />
-		normalMapScale — Set normal map scale. Default is (1, 1).<br />
+		normalScale — Set normal XY scale. Default is (1, 1).<br />
 		displacementMap — Set displacement map. Default is null.<br />
 		displacementScale — Set displacement scale. Default is 1.<br />
 		displacementBias — Set displacement offset. Default is 0.<br />

+ 2 - 2
docs/api/math/Box2.html

@@ -86,7 +86,7 @@
 		Sets the upper and lower bounds of this box to include all of the points in *points*.
 		</div>
 
-		<h3>[method:Vector2 size]( [page:Vector2 optionalTarget] ) [page:Box2 this]</h3>
+		<h3>[method:Vector2 getSize]( [page:Vector2 optionalTarget] ) [page:Box2 this]</h3>
 		<div>
 		optionalTarget -- If specified, the result will be copied here.
 		</div>
@@ -194,7 +194,7 @@
 		Makes this box empty.
 		</div>
 
-		<h3>[method:Vector2 center]( [page:Vector2 optionalTarget] ) [page:Box2 this]</h3>
+		<h3>[method:Vector2 getCenter]( [page:Vector2 optionalTarget] ) [page:Box2 this]</h3>
 		<div>
 		optionalTarget -- If specified, the result will be copied here.
 		</div>

+ 18 - 2
docs/api/math/Box3.html

@@ -77,6 +77,22 @@
 		Determines whether or not this box intersects *box*.
 		</div>
 
+		<h3>[method:Boolean intersectsSphere]( [page:Sphere sphere] ) [page:Box3 this]</h3>
+		<div>
+		sphere -- Sphere to check for intersection against.
+		</div>
+		<div>
+		Determines whether or not this box intersects *sphere*.
+		</div>
+
+		<h3>[method:Boolean intersectsPlane]( [page:Plane plane] ) [page:Box3 this]</h3>
+		<div>
+		plane -- Plane to check for intersection against.
+		</div>
+		<div>
+		Determines whether or not this box intersects *plane*.
+		</div>
+
 		<h3>[method:Box3 setFromPoints]( [page:Array points] ) [page:Box3 this]</h3>
 		<div>
 		points -- Set of points that the resulting box will envelop.
@@ -96,7 +112,7 @@
 
 
 
-		<h3>[method:Vector3 size]( [page:Vector3 optionalTarget] ) [page:Box3 this]</h3>
+		<h3>[method:Vector3 getSize]( [page:Vector3 optionalTarget] ) [page:Box3 this]</h3>
 		<div>
 		optionalTarget -- If specified, the result will be copied here.
 		</div>
@@ -221,7 +237,7 @@
 		Makes this box empty.
 		</div>
 
-		<h3>[method:Vector3 center]( [page:Vector3 optionalTarget] ) [page:Box3 this]</h3>
+		<h3>[method:Vector3 getCenter]( [page:Vector3 optionalTarget] ) [page:Box3 this]</h3>
 		<div>
 		optionalTarget -- If specified, the result will be copied here.
 		</div>

+ 8 - 0
docs/api/math/Color.html

@@ -165,6 +165,14 @@
 		Returns the value of this color as a CSS-style string. Example: rgb(255,0,0)
 		</div>
 
+		<h3>[method:Color setScalar]( [page:Float scalar] ) [page:Color this]</h3>
+		<div>
+		scalar — a value between 0.0 and 1.0.
+		</div>
+		<div>
+		Sets all three color components to the value *scalar*.
+		</div>
+
 		<h3>[method:Color setHSL]( [page:Float h], [page:Float s], [page:Float l] ) [page:Color this]</h3>
 		<div>
 		h — hue value between 0.0 and 1.0 <br />

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

@@ -95,7 +95,7 @@
 		Return a vector at a certain position along the line. When t = 0, it returns the start vector, and when t=1 it returns the end vector.
 		</div>
 
-		<h3>[method:Vector3 center]( [page:Vector3 optionalTarget] )</h3>
+		<h3>[method:Vector3 getCenter]( [page:Vector3 optionalTarget] )</h3>
 		<div>
 		optionalTarget -- [page:Vector3] Optional target to set the result.
 		</div>

+ 12 - 0
docs/api/math/Math.html

@@ -75,6 +75,18 @@
 		Converts radians to degrees
 		</div>
 
+		<h3>[method:Float lerp]( [page:Float x], [page:Float y], [page:Float t] )</h3>
+		<div>
+		x -- Start point. <br />
+		y -- End point. <br />
+		t -- Closed unit interval from [0,1].
+		</div>
+		<div>
+		Returns a value interpolated from two known points based on the interval.<br/><br/>
+
+		[link:https://en.wikipedia.org/wiki/Linear_interpolation Wikipedia]
+		</div>
+
 		<h3>[method:Float smoothstep]( [page:Float x], [page:Float min], [page:Float max] )</h3>
 		<div>
 		x -- The value to evaluate based on its position between min and max. <br />

+ 3 - 2
docs/api/math/Matrix3.html

@@ -57,9 +57,10 @@
 		Copies the values of matrix *m* into this matrix.
 		</div>
 
-		<h3>[method:Matrix3 fromArray]( [page:Array array] ) [page:Matrix3 this]</h3>
+		<h3>[method:Matrix3 fromArray]( [page:Array array], [page:Integer offset] ) [page:Matrix3 this]</h3>
 		<div>
-		array -- [page:Array] The array to read the elements from.
+		array -- [page:Array] The array to read the elements from.<br />
+		offset -- [page:Integer] optional offset into the array. Default is 0.
 		</div>
 		<div>
 		Sets the elements of this matrix based on an array in column-major format.

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

@@ -67,9 +67,10 @@
 		Copies the values of matrix *m* into this matrix.
 		</div>
 
-		<h3>[method:Matrix4 fromArray]( [page:Array array] ) [page:Matrix4 this]</h3>
+		<h3>[method:Matrix4 fromArray]( [page:Array array], [page:Integer offset] ) [page:Matrix4 this]</h3>
 		<div>
-		array -- [page:Array] The array to read the elements from.
+		array -- [page:Array] The array to read the elements from.<br />
+		offset -- [page:Integer] optional offset into the array. Default is 0.
 		</div>
 		<div>
 		Sets the elements of this matrix based on an array in column-major format.

+ 16 - 0
docs/api/math/Plane.html

@@ -86,6 +86,22 @@
 		Tests whether a line segment intersects with the plane. (Do not mistake this for a collinear check.)
 		</div>
 
+		<h3>[method:Boolean intersectsBox]( [page:Box3 box] ) [page:Plane this]</h3>
+		<div>
+		box -- Box to check for intersection against.
+		</div>
+		<div>
+		Determines whether or not this plane intersects *box*.
+		</div>
+
+		<h3>[method:Boolean intersectsSphere]( [page:Sphere sphere] ) [page:Plane this]</h3>
+		<div>
+		sphere -- Sphere to check for intersection against.
+		</div>
+		<div>
+		Determines whether or not this plane intersects *sphere*.
+		</div>
+
 		<h3>[method:Vector3 intersectLine]( [page:Line3 line], [page:Vector3 optionalTarget] ) or [page:undefined]</h3>
 		<div>
 		line -- [page:Line3] <br />

+ 16 - 0
docs/api/math/Sphere.html

@@ -131,6 +131,22 @@
 		Checks to see if two spheres intersect.
 		</div>
 
+		<h3>[method:Boolean intersectsBox]( [page:Box3 box] ) [page:Sphere this]</h3>
+		<div>
+		box -- Box to check for intersection against.
+		</div>
+		<div>
+		Determines whether or not this sphere intersects *box*.
+		</div>
+
+		<h3>[method:Boolean intersectsPlane]( [page:Plane plane] ) [page:Sphere this]</h3>
+		<div>
+		plane -- Plane to check for intersection against.
+		</div>
+		<div>
+		Determines whether or not this sphere intersects *plane*.
+		</div>
+
 		<h3>[method:Boolean empty]()</h3>
 		<div>
 		Checks to see if the sphere is empty (the radius set to 0).

+ 8 - 0
docs/api/math/Vector2.html

@@ -64,6 +64,14 @@
 		replace this vector's y value with y.
 		</div>
 
+		<h3>[method:Vector2 setScalar]( [page:Float scalar] ) [page:Vector2 this]</h3>
+		<div>
+		scalar -- [page:Float]
+		</div>
+		<div>
+		set all component values of this vector to *scalar*.
+		</div>
+
 		<h3>[method:Vector2 copy]( [page:Vector2 v] ) [page:Vector2 this]</h3>
 		<div>
 		Copies value of *v* to this vector.

+ 11 - 3
docs/api/math/Vector3.html

@@ -68,6 +68,14 @@
 		Sets z value of this vector.
 		</div>
 
+		<h3>[method:Vector3 setScalar]( [page:Float scalar] ) [page:Vector3 this]</h3>
+		<div>
+		scalar -- [page:Float]
+		</div>
+		<div>
+		set all component values of this vector to *scalar*.
+		</div>
+
 		<h3>[method:Vector3 copy]( [page:Vector3 v] ) [page:Vector3 this]</h3>
 		<div>
 		Copies value of *v* to this vector.
@@ -380,10 +388,10 @@
 		Returns the angle between this vector and vector v in radians.
 		</div>
 
-		<h3>[method:Vector3 setFromMatrixColumn]( [page:Integer index], [page:Matrix4 matrix] ) [page:Vector3 this]</h3>
+		<h3>[method:Vector3 setFromMatrixColumn]( [page:Matrix4 matrix], [page:Integer index] ) [page:Vector3 this]</h3>
 		<div>
-		index -- 0, 1, 2, or 3 <br />
-		matrix -- [page:Matrix4]
+		matrix -- [page:Matrix4]<br />
+		index -- 0, 1, 2, or 3
 		</div>
 		<div>
 		Sets this vector's x, y, and z equal to the column of the matrix specified by the index.

+ 8 - 0
docs/api/math/Vector4.html

@@ -75,6 +75,14 @@
 		Sets the w component of the vector.
 		</div>
 
+		<h3>[method:Vector4 setScalar]( [page:Float scalar] ) [page:Vector4 this]</h3>
+		<div>
+		scalar -- [page:Float]
+		</div>
+		<div>
+		set all component values of this vector to *scalar*.
+		</div>
+
 		<h3>[method:Vector4 copy]( [page:Vector4 v] ) [page:Vector4 this]</h3>
 		<div>
 		Copies value of *v* to this vector.

+ 5 - 0
docs/api/objects/Mesh.html

@@ -58,6 +58,11 @@
 		Undefined by default, but rebuilt [page:Mesh.updateMorphTargets updateMorphTargets].
 		</div>
 
+		<h3>[property:Integer drawMode]</h3>
+
+		<div>
+		Determines how the mesh triangles are constructed from the vertices. See the draw mode [page:DrawModes constants] for all possible values. Default is [page:DrawModes TrianglesDrawMode].
+		</div>
 
 		<h2>Methods</h2>
 

+ 13 - 8
docs/api/scenes/Scene.html

@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html lang="en">
 	<head>
-		<meta charset="utf-8" />
+		<meta charset="utf-8" />
 		<base href="../../" />
 		<script src="list.js"></script>
 		<script src="page.js"></script>
@@ -26,18 +26,23 @@
 		<h2>Properties</h2>
 
 		<h3>[property:Fog fog]</h3>
-		
+
 		<div>A [page:Fog fog] instance defining the type of fog that affects everything rendered in the scene. Default is null.</div>
-		
+
 		<h3>[property:Material overrideMaterial]</h3>
-		
+
 		<div>If not null, it will force everything in the scene to be rendered with that material. Default is null.</div>
-		
+
 		<h3>[property:boolean autoUpdate]</h3>
 		<div>
-		Default is true. If set, then the renderer checks every frame if the scene and its objects needs matrix updates. 
-		When it isn't, then you have to maintain all matrices in the scene yourself.  
-		</div> 
+		Default is true. If set, then the renderer checks every frame if the scene and its objects needs matrix updates.
+		When it isn't, then you have to maintain all matrices in the scene yourself.
+		</div>
+
+		<h3>[property:Object background]</h3>
+		<div>
+		If not null, sets the background used when rendering the scene, and is always rendered first. Can be set to a [page:Color] which sets the clear color, a [page:Texture] covering the canvas, or a [page:CubeTexture]. Default is null.
+		</div>
 
 		<h2>Methods</h2>
 

+ 11 - 2
docs/list.js

@@ -10,6 +10,7 @@ var list = {
 	"Reference": {
 		"Constants": [
 			[ "CustomBlendingEquation", "api/constants/CustomBlendingEquations" ],
+			[ "DrawModes", "api/constants/DrawModes" ],
 			[ "GLState", "api/constants/GLState" ],
 			[ "Materials", "api/constants/Materials" ],
 			[ "ShadowingTypes", "api/constants/ShadowingTypes" ],
@@ -30,6 +31,7 @@ var list = {
 			[ "EventDispatcher", "api/core/EventDispatcher" ],
 			[ "Face3", "api/core/Face3" ],
 			[ "Geometry", "api/core/Geometry" ],
+			[ "Layers", "api/core/Layers" ],
 			[ "Object3D", "api/core/Object3D" ],
 			[ "Raycaster", "api/core/Raycaster" ],
 			[ "Uniform", "api/core/Uniform"]
@@ -44,28 +46,35 @@ var list = {
 			[ "ConeGeometry", "api/geometries/ConeGeometry" ],
 			[ "CylinderBufferGeometry", "api/geometries/CylinderBufferGeometry" ],
 			[ "CylinderGeometry", "api/geometries/CylinderGeometry" ],
+			[ "DodecahedronBufferGeometry", "api/geometries/DodecahedronBufferGeometry" ],
 			[ "DodecahedronGeometry", "api/geometries/DodecahedronGeometry" ],
 			[ "ExtrudeGeometry", "api/geometries/ExtrudeGeometry" ],
+			[ "IcosahedronBufferGeometry", "api/geometries/IcosahedronBufferGeometry" ],
 			[ "IcosahedronGeometry", "api/geometries/IcosahedronGeometry" ],
 			[ "LatheBufferGeometry", "api/geometries/LatheBufferGeometry" ],
 			[ "LatheGeometry", "api/geometries/LatheGeometry" ],
+			[ "OctahedronBufferGeometry", "api/geometries/OctahedronBufferGeometry" ],
 			[ "OctahedronGeometry", "api/geometries/OctahedronGeometry" ],
+			[ "ParametricBufferGeometry", "api/geometries/ParametricBufferGeometry" ],
 			[ "ParametricGeometry", "api/geometries/ParametricGeometry" ],
 			[ "PlaneBufferGeometry", "api/geometries/PlaneBufferGeometry" ],
 			[ "PlaneGeometry", "api/geometries/PlaneGeometry" ],
+			[ "PolyhedronBufferGeometry", "api/geometries/PolyhedronBufferGeometry" ],
 			[ "PolyhedronGeometry", "api/geometries/PolyhedronGeometry" ],
 			[ "RingBufferGeometry", "api/geometries/RingBufferGeometry" ],
 			[ "RingGeometry", "api/geometries/RingGeometry" ],
 			[ "ShapeGeometry", "api/geometries/ShapeGeometry" ],
 			[ "SphereBufferGeometry", "api/geometries/SphereBufferGeometry" ],
 			[ "SphereGeometry", "api/geometries/SphereGeometry" ],
+			[ "TetrahedronBufferGeometry", "api/geometries/TetrahedronBufferGeometry" ],
 			[ "TetrahedronGeometry", "api/geometries/TetrahedronGeometry" ],
 			[ "TextGeometry", "api/geometries/TextGeometry" ],
 			[ "TorusBufferGeometry", "api/geometries/TorusBufferGeometry" ],
 			[ "TorusGeometry", "api/geometries/TorusGeometry" ],
 			[ "TorusKnotBufferGeometry", "api/geometries/TorusKnotBufferGeometry" ],
 			[ "TorusKnotGeometry", "api/geometries/TorusKnotGeometry" ],
-			[ "TubeGeometry", "api/geometries/TubeGeometry" ]
+			[ "TubeGeometry", "api/geometries/TubeGeometry" ],
+			[ "TubeBufferGeometry", "api/geometries/TubeBufferGeometry" ]
 		],
 
 		"Lights": [
@@ -87,7 +96,7 @@ var list = {
 			[ "BufferGeometryLoader", "api/loaders/BufferGeometryLoader" ],
 			[ "Cache", "api/loaders/Cache" ],
 			[ "ColladaLoader", "api/loaders/ColladaLoader" ],
-			[ "glTFLoader", "api/loaders/glTFLoader" ],
+			[ "GLTFLoader", "api/loaders/GLTFLoader" ],
 			[ "ImageLoader", "api/loaders/ImageLoader" ],
 			[ "JSONLoader", "api/loaders/JSONLoader" ],
 			[ "Loader", "api/loaders/Loader" ],

+ 1 - 1
docs/manual/introduction/Creating-a-scene.html

@@ -61,7 +61,7 @@
 
 		<div>In addition to creating the renderer instance, we also need to set the size at which we want it to render our app. It's a good idea to use the width and height of the area we want to fill with our app - in this case, the width and height of the browser window. For performance intensive apps, you can also give <strong>setSize</strong> smaller values, like <strong>window.innerWidth/2</strong> and <strong>window.innerHeight/2</strong>, which will make the app render at half size.</div>
 
-		<div>If you wish to keep the size of your app but render it at a lower resolution, you can do so by calling <strong>setSize</strong> with false as <strong>updateStyle</strong> (the third arugment). For example, <strong>setSize(window.innerWidth/2, window.innerHeight/2, false)</strong> will render your app at half resolution, given that your &lt;canvas&gt; has 100% width and height.</div>
+		<div>If you wish to keep the size of your app but render it at a lower resolution, you can do so by calling <strong>setSize</strong> with false as <strong>updateStyle</strong> (the third argument). For example, <strong>setSize(window.innerWidth/2, window.innerHeight/2, false)</strong> will render your app at half resolution, given that your &lt;canvas&gt; has 100% width and height.</div>
 
 		<div>Last but not least, we add the <strong>renderer</strong> element to our HTML document. This is a &lt;canvas&gt; element the renderer uses to display the scene to us.</div>
 

+ 1 - 4
docs/scenes/bones-browser.html

@@ -40,7 +40,7 @@
 
 		<script>
 
-			var gui, scene, camera, renderer, orbit, ambientLight, lights, mesh, bones, skeletonHelper;
+			var gui, scene, camera, renderer, orbit, lights, mesh, bones, skeletonHelper;
 
 			var state = {
 
@@ -65,9 +65,6 @@
 				orbit = new THREE.OrbitControls( camera, renderer.domElement );
 				orbit.enableZoom = false;
 
-				ambientLight = new THREE.AmbientLight( 0x000000 );
-				scene.add( ambientLight );
-
 				lights = [];
 				lights[ 0 ] = new THREE.PointLight( 0xffffff, 1, 0 );
 				lights[ 1 ] = new THREE.PointLight( 0xffffff, 1, 0 );

+ 1 - 3
docs/scenes/geometry-browser.html

@@ -37,6 +37,7 @@
 		<script src="../../build/three.min.js"></script>
 		<script src='../../examples/js/libs/dat.gui.min.js'></script>
 		<script src="../../examples/js/controls/OrbitControls.js"></script>
+		<script src="../../examples/js/ParametricGeometries.js"></script>
 
 		<script src='js/geometry.js'></script>
 
@@ -58,9 +59,6 @@
 			var orbit = new THREE.OrbitControls( camera, renderer.domElement );
 			orbit.enableZoom = false;
 
-			var ambientLight = new THREE.AmbientLight( 0x000000 );
-			scene.add( ambientLight );
-
 			var lights = [];
 			lights[ 0 ] = new THREE.PointLight( 0xffffff, 1, 0 );
 			lights[ 1 ] = new THREE.PointLight( 0xffffff, 1, 0 );

+ 293 - 0
docs/scenes/js/geometry.js

@@ -91,6 +91,26 @@ function updateGroupGeometry( mesh, geometry ) {
 
 }
 
+var CustomSinCurve = THREE.Curve.create(
+
+	function ( scale ) {
+
+		this.scale = ( scale === undefined ) ? 1 : scale;
+
+	},
+
+	function ( t ) {
+
+		var tx = t * 3 - 1.5;
+		var ty = Math.sin( 2 * Math.PI * t );
+		var tz = 0;
+
+		return new THREE.Vector3( tx, ty, tz ).multiplyScalar( this.scale );
+
+	}
+
+);
+
 var guis = {
 
 	BoxBufferGeometry : function( mesh ) {
@@ -426,6 +446,32 @@ var guis = {
 
 	},
 
+	DodecahedronBufferGeometry : function() {
+
+		var data = {
+			radius : 10,
+			detail : 0,
+		};
+
+		function generateGeometry() {
+
+			updateGroupGeometry( mesh,
+				new THREE.DodecahedronBufferGeometry(
+					data.radius, data.detail
+				)
+			);
+
+		}
+
+		var folder = gui.addFolder( 'THREE.DodecahedronBufferGeometry' );
+
+		folder.add( data, 'radius', 1, 20 ).onChange( generateGeometry );
+		folder.add( data, 'detail', 0, 5 ).step( 1 ).onChange( generateGeometry );
+
+		generateGeometry();
+
+	},
+
 	IcosahedronGeometry : function() {
 
 		var data = {
@@ -452,6 +498,32 @@ var guis = {
 
 	},
 
+	IcosahedronBufferGeometry : function() {
+
+		var data = {
+			radius : 10,
+			detail : 0,
+		};
+
+		function generateGeometry() {
+
+			updateGroupGeometry( mesh,
+				new THREE.IcosahedronBufferGeometry(
+					data.radius, data.detail
+				)
+			);
+
+		}
+
+		var folder = gui.addFolder( 'THREE.IcosahedronBufferGeometry' );
+
+		folder.add( data, 'radius', 1, 20 ).onChange( generateGeometry );
+		folder.add( data, 'detail', 0, 5 ).step( 1 ).onChange( generateGeometry );
+
+		generateGeometry();
+
+	},
+
 	LatheBufferGeometry : function() {
 
 		var points = [];
@@ -550,6 +622,32 @@ var guis = {
 
 	},
 
+	OctahedronBufferGeometry : function() {
+
+		var data = {
+			radius : 10,
+			detail : 0,
+		};
+
+		function generateGeometry() {
+
+			updateGroupGeometry( mesh,
+				new THREE.OctahedronBufferGeometry(
+					data.radius, data.detail
+				)
+			);
+
+		}
+
+		var folder = gui.addFolder( 'THREE.OctahedronBufferGeometry' );
+
+		folder.add( data, 'radius', 1, 20 ).onChange( generateGeometry );
+		folder.add( data, 'detail', 0, 5 ).step( 1 ).onChange( generateGeometry );
+
+		generateGeometry();
+
+	},
+
 	PlaneBufferGeometry : function( mesh ) {
 
 		var data = {
@@ -776,6 +874,32 @@ var guis = {
 
 	},
 
+	TetrahedronBufferGeometry : function() {
+
+		var data = {
+			radius : 10,
+			detail : 0,
+		};
+
+		function generateGeometry() {
+
+			updateGroupGeometry( mesh,
+				new THREE.TetrahedronBufferGeometry(
+					data.radius, data.detail
+				)
+			);
+
+		}
+
+		var folder = gui.addFolder( 'THREE.TetrahedronBufferGeometry' );
+
+		folder.add( data, 'radius', 1, 20 ).onChange( generateGeometry );
+		folder.add( data, 'detail', 0, 5 ).step( 1 ).onChange( generateGeometry );
+
+		generateGeometry();
+
+	},
+
 	TextGeometry : function( mesh ) {
 
 		var data = {
@@ -974,6 +1098,175 @@ var guis = {
 
 		generateGeometry();
 
+	},
+
+	ParametricBufferGeometry : function( mesh ) {
+
+		var data = {
+			slices : 25,
+			stacks : 25
+		};
+
+		function generateGeometry() {
+
+			updateGroupGeometry( mesh,
+				new THREE.ParametricBufferGeometry( THREE.ParametricGeometries.klein, data.slices, data.stacks )
+			);
+
+		}
+
+		var folder = gui.addFolder( 'THREE.ParametricBufferGeometry' );
+
+		folder.add( data, 'slices', 1, 100 ).step( 1 ).onChange( generateGeometry );
+		folder.add( data, 'stacks', 1, 100 ).step( 1 ).onChange( generateGeometry );
+
+		generateGeometry();
+
+	},
+
+	ParametricGeometry : function( mesh ) {
+
+		var data = {
+			slices : 25,
+			stacks : 25
+		};
+
+		function generateGeometry() {
+
+			updateGroupGeometry( mesh,
+				new THREE.ParametricGeometry( THREE.ParametricGeometries.klein, data.slices, data.stacks )
+			);
+
+		}
+
+		var folder = gui.addFolder( 'THREE.ParametricGeometry' );
+
+		folder.add( data, 'slices', 1, 100 ).step( 1 ).onChange( generateGeometry );
+		folder.add( data, 'stacks', 1, 100 ).step( 1 ).onChange( generateGeometry );
+
+		generateGeometry();
+
+	},
+
+	TubeGeometry : function( mesh ) {
+
+		var data = {
+			segments : 20,
+			radius : 2,
+			radiusSegments: 8
+		};
+
+		var path = new CustomSinCurve( 10 );
+
+		function generateGeometry() {
+
+			updateGroupGeometry( mesh,
+				new THREE.TubeGeometry( path, data.segments, data.radius, data.radiusSegments, false )
+			);
+
+		}
+
+		var folder = gui.addFolder( 'THREE.TubeGeometry' );
+
+		folder.add( data, 'segments', 1, 100 ).step( 1 ).onChange( generateGeometry );
+		folder.add( data, 'radius', 1, 10 ).onChange( generateGeometry );
+		folder.add( data, 'radiusSegments', 1, 20 ).step( 1 ).onChange( generateGeometry );
+
+		generateGeometry();
+
+	},
+
+	TubeBufferGeometry : function( mesh ) {
+
+		var data = {
+			segments : 20,
+			radius : 2,
+			radiusSegments: 8
+		};
+
+		var path = new CustomSinCurve( 10 );
+
+		function generateGeometry() {
+
+			updateGroupGeometry( mesh,
+				new THREE.TubeBufferGeometry( path, data.segments, data.radius, data.radiusSegments, false )
+			);
+
+		}
+
+		var folder = gui.addFolder( 'THREE.TubeBufferGeometry' );
+
+		folder.add( data, 'segments', 1, 100 ).step( 1 ).onChange( generateGeometry );
+		folder.add( data, 'radius', 1, 10 ).onChange( generateGeometry );
+		folder.add( data, 'radiusSegments', 1, 20 ).step( 1 ).onChange( generateGeometry );
+
+		generateGeometry();
+
+	},
+
+	ShapeGeometry: function( mesh ) {
+
+		var length = 16, width = 12;
+
+		var shape = new THREE.Shape();
+		shape.moveTo( 0,0 );
+		shape.lineTo( 0, width );
+		shape.lineTo( length, width );
+		shape.lineTo( length, 0 );
+		shape.lineTo( 0, 0 );
+
+		function generateGeometry() {
+
+			updateGroupGeometry( mesh,
+				new THREE.ShapeGeometry( shape )
+			);
+
+		}
+
+		var folder = gui.addFolder( 'THREE.ShapeGeometry' );
+
+		generateGeometry();
+
+	},
+
+	ExtrudeGeometry: function( mesh ) {
+
+		var data = {
+			steps: 2,
+			amount: 16,
+			bevelEnabled: true,
+			bevelThickness: 1,
+			bevelSize: 1,
+			bevelSegments: 1
+		};
+
+		var length = 12, width = 8;
+
+		var shape = new THREE.Shape();
+		shape.moveTo( 0,0 );
+		shape.lineTo( 0, width );
+		shape.lineTo( length, width );
+		shape.lineTo( length, 0 );
+		shape.lineTo( 0, 0 );
+
+		function generateGeometry() {
+
+			updateGroupGeometry( mesh,
+				new THREE.ExtrudeGeometry( shape, data )
+			);
+
+		}
+
+		var folder = gui.addFolder( 'THREE.ExtrudeGeometry' );
+
+		folder.add( data, 'steps', 1, 10 ).step( 1 ).onChange( generateGeometry );
+		folder.add( data, 'amount', 1, 20 ).step( 1 ).onChange( generateGeometry );
+		folder.add( data, 'bevelThickness', 1, 5 ).step( 1 ).onChange( generateGeometry );
+		folder.add( data, 'bevelSize', 1, 5 ).step( 1 ).onChange( generateGeometry );
+		folder.add( data, 'bevelSegments', 1, 5 ).step( 1 ).onChange( generateGeometry );
+
+		generateGeometry();
+
 	}
 
 };

+ 5 - 0
editor/examples/arkanoid.app.json

@@ -1,5 +1,10 @@
 {
+	"metadata": {
+		"type": "App"
+	},
 	"project": {
+		"shadows": true,
+		"editable": true,
 		"vr": false
 	},
 	"camera": {

+ 8 - 0
editor/examples/camera.app.json

@@ -1,4 +1,12 @@
 {
+	"metadata": {
+		"type": "App"
+	},
+	"project": {
+		"shadows": true,
+		"editable": true,
+		"vr": false
+	},
 	"camera": {
 		"metadata": {
 			"version": 4.3,

+ 1 - 1
editor/index.html

@@ -98,7 +98,7 @@
 
 		<script src="../examples/js/effects/VREffect.js"></script>
 		<script src="../examples/js/controls/VRControls.js"></script>
-		<script src="../examples/js/WebVR.js"></script>
+		<script src="../examples/js/vr/WebVR.js"></script>
 
 		<script src="js/Storage.js"></script>
 

+ 4 - 3
editor/js/Loader.js

@@ -163,11 +163,12 @@ var Loader = function ( editor ) {
 						var json = JSON.parse( contents );
 
 						var loader = new THREE.GLTFLoader();
-						var collada = loader.parse( json );
+						loader.parse( json, function ( result ) {
 
-						collada.scene.name = filename;
+							result.scene.name = filename;
+							editor.execute( new AddObjectCommand( result.scene ) );
 
-						editor.execute( new AddObjectCommand( collada.scene ) );
+						} );
 
 					}, false );
 					reader.readAsText( file );

+ 2 - 2
editor/js/libs/tern-threejs/threejs.js

@@ -2544,8 +2544,8 @@
       "!doc": "A low level class for loading resources with XmlHttpRequest, used internaly by most loaders.",
       "!type": "fn(manager: +THREE.LoadingManager)"
     },
-    "glTFLoader": {
-      "!url": "http://threejs.org/docs/#Reference/loaders/glTFLoader",
+    "GLTFLoader": {
+      "!url": "http://threejs.org/docs/#Reference/loaders/GLTFLoader",
       "prototype": {
         "!proto": "THREE.Loader.prototype",
         "load": {

+ 1 - 1
examples/css3d_youtube.html

@@ -42,7 +42,7 @@
 				iframe.style.width = '480px';
 				iframe.style.height = '360px';
 				iframe.style.border = '0px';
-				iframe.src = [ 'http://www.youtube.com/embed/', id, '?rel=0' ].join( '' );
+				iframe.src = [ 'https://www.youtube.com/embed/', id, '?rel=0' ].join( '' );
 				div.appendChild( iframe );
 
 				var object = new THREE.CSS3DObject( div );

+ 5 - 1
examples/files.js

@@ -9,6 +9,7 @@ var files = {
 		"webgl_camera_logarithmicdepthbuffer",
 		"webgl_clipping",
 		"webgl_clipping_advanced",
+		"webgl_clipping_intersection",
 		"webgl_decals",
 		"webgl_depth_texture",
 		"webgl_effects_anaglyph",
@@ -29,7 +30,6 @@ var files = {
 		"webgl_geometry_extrude_splines",
 		"webgl_geometry_hierarchy",
 		"webgl_geometry_hierarchy2",
-		"webgl_geometry_large_mesh",
 		"webgl_geometry_minecraft",
 		"webgl_geometry_minecraft_ao",
 		"webgl_geometry_normals",
@@ -101,6 +101,7 @@ var files = {
 		"webgl_loader_pcd",
 		"webgl_loader_pdb",
 		"webgl_loader_ply",
+		"webgl_loader_ttf",
 		"webgl_loader_sea3d",
 		"webgl_loader_sea3d_hierarchy",
 		"webgl_loader_sea3d_keyframe",
@@ -258,6 +259,9 @@ var files = {
 		"webgl_custom_attributes_points3",
 		"webgl_raymarching_reflect"
 	],
+	"webgl deferred": [
+		"webgldeferred_animation"
+	],
 	"webvr": [
 		"webvr_cubes",
 		"webvr_panorama",

BIN
examples/fonts/ttf/kenpixel.ttf


+ 1 - 1
examples/js/ParametricGeometries.js

@@ -112,7 +112,7 @@ THREE.ParametricGeometries.TubeGeometry = function( path, segments, radius, segm
 		cx, cy, pos, pos2 = new THREE.Vector3(),
 		i, j, ip, jp, a, b, c, d, uva, uvb, uvc, uvd;
 
-	var frames = new THREE.TubeGeometry.FrenetFrames( path, segments, closed ),
+	var frames = path.computeFrenetFrames( segments, closed ),
 		tangents = frames.tangents,
 		normals = frames.normals,
 		binormals = frames.binormals;

+ 98 - 133
examples/js/SkyShader.js

@@ -20,7 +20,7 @@ THREE.ShaderLib[ 'sky' ] = {
 
 		luminance: { value: 1 },
 		turbidity: { value: 2 },
-		reileigh: { value: 1 },
+		rayleigh: { value: 1 },
 		mieCoefficient: { value: 0.005 },
 		mieDirectionalG: { value: 0.8 },
 		sunPosition: { value: new THREE.Vector3() }
@@ -29,7 +29,52 @@ THREE.ShaderLib[ 'sky' ] = {
 
 	vertexShader: [
 
+		"uniform vec3 sunPosition;",
+		"uniform float rayleigh;",
+		"uniform float turbidity;",
+		"uniform float mieCoefficient;",
+
 		"varying vec3 vWorldPosition;",
+		"varying vec3 vSunDirection;",
+		"varying float vSunfade;",
+		"varying vec3 vBetaR;",
+		"varying vec3 vBetaM;",
+		"varying float vSunE;",
+
+		"const vec3 up = vec3(0.0, 1.0, 0.0);",
+
+		// constants for atmospheric scattering
+		"const float e = 2.71828182845904523536028747135266249775724709369995957;",
+		"const float pi = 3.141592653589793238462643383279502884197169;",
+
+		// mie stuff
+		// K coefficient for the primaries
+		"const float v = 4.0;",
+		"const vec3 K = vec3(0.686, 0.678, 0.666);",
+
+		// see http://blenderartists.org/forum/showthread.php?321110-Shaders-and-Skybox-madness
+		// A simplied version of the total Reayleigh scattering to works on browsers that use ANGLE
+		"const vec3 simplifiedRayleigh = 0.0005 / vec3(94, 40, 18);",
+
+		// wavelength of used primaries, according to preetham
+		"const vec3 lambda = vec3(680E-9, 550E-9, 450E-9);",
+
+		// earth shadow hack
+		"const float cutoffAngle = pi/1.95;",
+		"const float steepness = 1.5;",
+		"const float EE = 1000.0;",
+
+		"float sunIntensity(float zenithAngleCos)",
+		"{",
+			"zenithAngleCos = clamp(zenithAngleCos, -1.0, 1.0);",
+			"return EE * max(0.0, 1.0 - pow(e, -((cutoffAngle - acos(zenithAngleCos))/steepness)));",
+		"}",
+
+		"vec3 totalMie(vec3 lambda, float T)",
+		"{",
+			"float c = (0.2 * T ) * 10E-18;",
+			"return 0.434 * c * pi * pow((2.0 * pi) / lambda, vec3(v - 2.0)) * K;",
+		"}",
 
 		"void main() {",
 
@@ -38,85 +83,57 @@ THREE.ShaderLib[ 'sky' ] = {
 
 			"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
 
+			"vSunDirection = normalize(sunPosition);",
+
+			"vSunE = sunIntensity(dot(vSunDirection, up));",
+
+			"vSunfade = 1.0-clamp(1.0-exp((sunPosition.y/450000.0)),0.0,1.0);",
+
+			"float rayleighCoefficient = rayleigh - (1.0 * (1.0-vSunfade));",
+
+			// extinction (absorbtion + out scattering)
+			// rayleigh coefficients
+			"vBetaR = simplifiedRayleigh * rayleighCoefficient;",
+
+			// mie coefficients
+			"vBetaM = totalMie(lambda, turbidity) * mieCoefficient;",
+
 		"}",
 
 	].join( "\n" ),
 
 	fragmentShader: [
 
-		"uniform sampler2D skySampler;",
-		"uniform vec3 sunPosition;",
 		"varying vec3 vWorldPosition;",
-
-		"vec3 cameraPos = vec3(0., 0., 0.);",
-		"// uniform sampler2D sDiffuse;",
-		"// const float turbidity = 10.0; //",
-		"// const float reileigh = 2.; //",
-		"// const float luminance = 1.0; //",
-		"// const float mieCoefficient = 0.005;",
-		"// const float mieDirectionalG = 0.8;",
+		"varying vec3 vSunDirection;",
+		"varying float vSunfade;",
+		"varying vec3 vBetaR;",
+		"varying vec3 vBetaM;",
+		"varying float vSunE;",
 
 		"uniform float luminance;",
-		"uniform float turbidity;",
-		"uniform float reileigh;",
-		"uniform float mieCoefficient;",
 		"uniform float mieDirectionalG;",
 
-		"// constants for atmospheric scattering",
-		"const float e = 2.71828182845904523536028747135266249775724709369995957;",
-		"const float pi = 3.141592653589793238462643383279502884197169;",
+		"const vec3 cameraPos = vec3(0., 0., 0.);",
 
-		"const float n = 1.0003; // refractive index of air",
-		"const float N = 2.545E25; // number of molecules per unit volume for air at",
-								"// 288.15K and 1013mb (sea level -45 celsius)",
-		"const float pn = 0.035;	// depolatization factor for standard air",
-
-		"// wavelength of used primaries, according to preetham",
-		"const vec3 lambda = vec3(680E-9, 550E-9, 450E-9);",
+		// constants for atmospheric scattering
+		"const float pi = 3.141592653589793238462643383279502884197169;",
 
-		"// mie stuff",
-		"// K coefficient for the primaries",
-		"const vec3 K = vec3(0.686, 0.678, 0.666);",
-		"const float v = 4.0;",
+		"const float n = 1.0003;", // refractive index of air
+		"const float N = 2.545E25;", // number of molecules per unit volume for air at
+									// 288.15K and 1013mb (sea level -45 celsius)
 
-		"// optical length at zenith for molecules",
+		// optical length at zenith for molecules
 		"const float rayleighZenithLength = 8.4E3;",
 		"const float mieZenithLength = 1.25E3;",
 		"const vec3 up = vec3(0.0, 1.0, 0.0);",
 
-		"const float EE = 1000.0;",
 		"const float sunAngularDiameterCos = 0.999956676946448443553574619906976478926848692873900859324;",
-		"// 66 arc seconds -> degrees, and the cosine of that",
-
-		"// earth shadow hack",
-		"const float cutoffAngle = pi/1.95;",
-		"const float steepness = 1.5;",
-
-
-		"vec3 totalRayleigh(vec3 lambda)",
-		"{",
-			"return (8.0 * pow(pi, 3.0) * pow(pow(n, 2.0) - 1.0, 2.0) * (6.0 + 3.0 * pn)) / (3.0 * N * pow(lambda, vec3(4.0)) * (6.0 - 7.0 * pn));",
-		"}",
-
-		// see http://blenderartists.org/forum/showthread.php?321110-Shaders-and-Skybox-madness
-		"// A simplied version of the total Reayleigh scattering to works on browsers that use ANGLE",
-		"vec3 simplifiedRayleigh()",
-		"{",
-			"return 0.0005 / vec3(94, 40, 18);",
-			// return 0.00054532832366 / (3.0 * 2.545E25 * pow(vec3(680E-9, 550E-9, 450E-9), vec3(4.0)) * 6.245);
-		"}",
+		// 66 arc seconds -> degrees, and the cosine of that
 
 		"float rayleighPhase(float cosTheta)",
-		"{	 ",
-			"return (3.0 / (16.0*pi)) * (1.0 + pow(cosTheta, 2.0));",
-		"//	return (1.0 / (3.0*pi)) * (1.0 + pow(cosTheta, 2.0));",
-		"//	return (3.0 / 4.0) * (1.0 + pow(cosTheta, 2.0));",
-		"}",
-
-		"vec3 totalMie(vec3 lambda, vec3 K, float T)",
 		"{",
-			"float c = (0.2 * T ) * 10E-18;",
-			"return 0.434 * c * pi * pow((2.0 * pi) / lambda, vec3(v - 2.0)) * K;",
+			"return (3.0 / (16.0*pi)) * (1.0 + pow(cosTheta, 2.0));",
 		"}",
 
 		"float hgPhase(float cosTheta, float g)",
@@ -124,27 +141,15 @@ THREE.ShaderLib[ 'sky' ] = {
 			"return (1.0 / (4.0*pi)) * ((1.0 - pow(g, 2.0)) / pow(1.0 - 2.0*g*cosTheta + pow(g, 2.0), 1.5));",
 		"}",
 
-		"float sunIntensity(float zenithAngleCos)",
-		"{",
-		// This function originally used `exp(n)`, but it returns an incorrect value
-		// on Samsung S6 phones. So it has been replaced with the equivalent `pow(e, n)`.
-		// See https://github.com/mrdoob/three.js/issues/8382
-			"return EE * max(0.0, 1.0 - pow(e, -((cutoffAngle - acos(zenithAngleCos))/steepness)));",
-		"}",
-
-		"// float logLuminance(vec3 c)",
-		"// {",
-		"// 	return log(c.r * 0.2126 + c.g * 0.7152 + c.b * 0.0722);",
-		"// }",
+		// Filmic ToneMapping http://filmicgames.com/archives/75
+		"const float A = 0.15;",
+		"const float B = 0.50;",
+		"const float C = 0.10;",
+		"const float D = 0.20;",
+		"const float E = 0.02;",
+		"const float F = 0.30;",
 
-		"// Filmic ToneMapping http://filmicgames.com/archives/75",
-		"float A = 0.15;",
-		"float B = 0.50;",
-		"float C = 0.10;",
-		"float D = 0.20;",
-		"float E = 0.02;",
-		"float F = 0.30;",
-		"float W = 1000.0;",
+		"const float whiteScale = 1.0748724675633854;", // 1.0 / Uncharted2Tonemap(1000.0)
 
 		"vec3 Uncharted2Tonemap(vec3 x)",
 		"{",
@@ -154,83 +159,44 @@ THREE.ShaderLib[ 'sky' ] = {
 
 		"void main() ",
 		"{",
-			"float sunfade = 1.0-clamp(1.0-exp((sunPosition.y/450000.0)),0.0,1.0);",
-
-			"// luminance =  1.0 ;// vWorldPosition.y / 450000. + 0.5; //sunPosition.y / 450000. * 1. + 0.5;",
-
-			 "// gl_FragColor = vec4(sunfade, sunfade, sunfade, 1.0);",
-
-			"float reileighCoefficient = reileigh - (1.0* (1.0-sunfade));",
-
-			"vec3 sunDirection = normalize(sunPosition);",
-
-			"float sunE = sunIntensity(dot(sunDirection, up));",
-
-			"// extinction (absorbtion + out scattering) ",
-			"// rayleigh coefficients",
-
-			// "vec3 betaR = totalRayleigh(lambda) * reileighCoefficient;",
-			"vec3 betaR = simplifiedRayleigh() * reileighCoefficient;",
-
-			"// mie coefficients",
-			"vec3 betaM = totalMie(lambda, K, turbidity) * mieCoefficient;",
-
-			"// optical length",
-			"// cutoff angle at 90 to avoid singularity in next formula.",
+			// optical length
+			// cutoff angle at 90 to avoid singularity in next formula.
 			"float zenithAngle = acos(max(0.0, dot(up, normalize(vWorldPosition - cameraPos))));",
 			"float sR = rayleighZenithLength / (cos(zenithAngle) + 0.15 * pow(93.885 - ((zenithAngle * 180.0) / pi), -1.253));",
 			"float sM = mieZenithLength / (cos(zenithAngle) + 0.15 * pow(93.885 - ((zenithAngle * 180.0) / pi), -1.253));",
 
+			// combined extinction factor
+			"vec3 Fex = exp(-(vBetaR * sR + vBetaM * sM));",
 
-
-			"// combined extinction factor	",
-			"vec3 Fex = exp(-(betaR * sR + betaM * sM));",
-
-			"// in scattering",
-			"float cosTheta = dot(normalize(vWorldPosition - cameraPos), sunDirection);",
+			// in scattering
+			"float cosTheta = dot(normalize(vWorldPosition - cameraPos), vSunDirection);",
 
 			"float rPhase = rayleighPhase(cosTheta*0.5+0.5);",
-			"vec3 betaRTheta = betaR * rPhase;",
+			"vec3 betaRTheta = vBetaR * rPhase;",
 
 			"float mPhase = hgPhase(cosTheta, mieDirectionalG);",
-			"vec3 betaMTheta = betaM * mPhase;",
-
+			"vec3 betaMTheta = vBetaM * mPhase;",
 
-			"vec3 Lin = pow(sunE * ((betaRTheta + betaMTheta) / (betaR + betaM)) * (1.0 - Fex),vec3(1.5));",
-			"Lin *= mix(vec3(1.0),pow(sunE * ((betaRTheta + betaMTheta) / (betaR + betaM)) * Fex,vec3(1.0/2.0)),clamp(pow(1.0-dot(up, sunDirection),5.0),0.0,1.0));",
+			"vec3 Lin = pow(vSunE * ((betaRTheta + betaMTheta) / (vBetaR + vBetaM)) * (1.0 - Fex),vec3(1.5));",
+			"Lin *= mix(vec3(1.0),pow(vSunE * ((betaRTheta + betaMTheta) / (vBetaR + vBetaM)) * Fex,vec3(1.0/2.0)),clamp(pow(1.0-dot(up, vSunDirection),5.0),0.0,1.0));",
 
-			"//nightsky",
+			//nightsky
 			"vec3 direction = normalize(vWorldPosition - cameraPos);",
 			"float theta = acos(direction.y); // elevation --> y-axis, [-pi/2, pi/2]",
 			"float phi = atan(direction.z, direction.x); // azimuth --> x-axis [-pi/2, pi/2]",
 			"vec2 uv = vec2(phi, theta) / vec2(2.0*pi, pi) + vec2(0.5, 0.0);",
-			"// vec3 L0 = texture2D(skySampler, uv).rgb+0.1 * Fex;",
 			"vec3 L0 = vec3(0.1) * Fex;",
 
-			"// composition + solar disc",
-			"//if (cosTheta > sunAngularDiameterCos)",
+			// composition + solar disc
 			"float sundisk = smoothstep(sunAngularDiameterCos,sunAngularDiameterCos+0.00002,cosTheta);",
-			"// if (normalize(vWorldPosition - cameraPos).y>0.0)",
-			"L0 += (sunE * 19000.0 * Fex)*sundisk;",
-
+			"L0 += (vSunE * 19000.0 * Fex)*sundisk;",
 
-			"vec3 whiteScale = 1.0/Uncharted2Tonemap(vec3(W));",
-
-			"vec3 texColor = (Lin+L0);   ",
-			"texColor *= 0.04 ;",
-			"texColor += vec3(0.0,0.001,0.0025)*0.3;",
-
-			"float g_fMaxLuminance = 1.0;",
-			"float fLumScaled = 0.1 / luminance;     ",
-			"float fLumCompressed = (fLumScaled * (1.0 + (fLumScaled / (g_fMaxLuminance * g_fMaxLuminance)))) / (1.0 + fLumScaled); ",
-
-			"float ExposureBias = fLumCompressed;",
+			"vec3 texColor = (Lin+L0) * 0.04 + vec3(0.0, 0.0003, 0.00075);",
 
 			"vec3 curr = Uncharted2Tonemap((log2(2.0/pow(luminance,4.0)))*texColor);",
 			"vec3 color = curr*whiteScale;",
 
-			"vec3 retColor = pow(color,vec3(1.0/(1.2+(1.2*sunfade))));",
-
+			"vec3 retColor = pow(color,vec3(1.0/(1.2+(1.2*vSunfade))));",
 
 			"gl_FragColor.rgb = retColor;",
 
@@ -256,7 +222,6 @@ THREE.Sky = function () {
 	var skyGeo = new THREE.SphereBufferGeometry( 450000, 32, 15 );
 	var skyMesh = new THREE.Mesh( skyGeo, skyMat );
 
-
 	// Expose variables
 	this.mesh = skyMesh;
 	this.uniforms = skyUniforms;

+ 7 - 4
examples/js/controls/EditorControls.js

@@ -13,6 +13,9 @@ THREE.EditorControls = function ( object, domElement ) {
 
 	this.enabled = true;
 	this.center = new THREE.Vector3();
+	this.panSpeed = 0.001
+	this.zoomSpeed = 0.001
+	this.rotationSpeed = 0.005
 
 	// internals
 
@@ -57,7 +60,7 @@ THREE.EditorControls = function ( object, domElement ) {
 
 		var distance = object.position.distanceTo( center );
 
-		delta.multiplyScalar( distance * 0.001 );
+		delta.multiplyScalar( distance * scope.panSpeed );
 		delta.applyMatrix3( normalMatrix.getNormalMatrix( object.matrix ) );
 
 		object.position.add( delta );
@@ -71,7 +74,7 @@ THREE.EditorControls = function ( object, domElement ) {
 
 		var distance = object.position.distanceTo( center );
 
-		delta.multiplyScalar( distance * 0.001 );
+		delta.multiplyScalar( distance * scope.zoomSpeed );
 
 		if ( delta.length() > distance ) return;
 
@@ -144,7 +147,7 @@ THREE.EditorControls = function ( object, domElement ) {
 
 		if ( state === STATE.ROTATE ) {
 
-			scope.rotate( new THREE.Vector3( - movementX * 0.005, - movementY * 0.005, 0 ) );
+			scope.rotate( new THREE.Vector3( - movementX * scope.rotationSpeed, - movementY * scope.rotationSpeed, 0 ) );
 
 		} else if ( state === STATE.ZOOM ) {
 
@@ -267,7 +270,7 @@ THREE.EditorControls = function ( object, domElement ) {
 			case 1:
 				touches[ 0 ].set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY, 0 );
 				touches[ 1 ].set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY, 0 );
-				scope.rotate( touches[ 0 ].sub( getClosest( touches[ 0 ], prevTouches ) ).multiplyScalar( - 0.005 ) );
+				scope.rotate( touches[ 0 ].sub( getClosest( touches[ 0 ], prevTouches ) ).multiplyScalar( - scope.rotationSpeed ) );
 				break;
 
 			case 2:

+ 6 - 6
examples/js/controls/TrackballControls.js

@@ -218,16 +218,16 @@ THREE.TrackballControls = function ( object, domElement ) {
 			if ( factor !== 1.0 && factor > 0.0 ) {
 
 				_eye.multiplyScalar( factor );
+				
+			}
 
-				if ( _this.staticMoving ) {
-
-					_zoomStart.copy( _zoomEnd );
+			if ( _this.staticMoving ) {
 
-				} else {
+				_zoomStart.copy( _zoomEnd );
 
-					_zoomStart.y += ( _zoomEnd.y - _zoomStart.y ) * this.dynamicDampingFactor;
+			} else {
 
-				}
+				_zoomStart.y += ( _zoomEnd.y - _zoomStart.y ) * this.dynamicDampingFactor;
 
 			}
 

+ 15 - 1
examples/js/controls/VRControls.js

@@ -12,8 +12,11 @@ THREE.VRControls = function ( object, onError ) {
 	var standingMatrix = new THREE.Matrix4();
 
 	var frameData = null;
+
 	if ( 'VRFrameData' in window ) {
+
 		frameData = new VRFrameData();
+
 	}
 
 	function gotVRDisplays( displays ) {
@@ -34,7 +37,11 @@ THREE.VRControls = function ( object, onError ) {
 
 	if ( navigator.getVRDisplays ) {
 
-		navigator.getVRDisplays().then( gotVRDisplays );
+		navigator.getVRDisplays().then( gotVRDisplays ).catch ( function () {
+
+			console.warn( 'THREE.VRControls: Unable to get VR Displays' );
+
+		} );
 
 	}
 
@@ -58,8 +65,15 @@ THREE.VRControls = function ( object, onError ) {
 
 	};
 
+	this.setVRDisplay = function ( value ) {
+
+		vrDisplay = value;
+
+	};
+
 	this.getVRDisplays = function () {
 
+		console.warn( 'THREE.VRControls: getVRDisplays() is being deprecated.' );
 		return vrDisplays;
 
 	};

+ 294 - 0
examples/js/effects/OutlineEffect.js

@@ -0,0 +1,294 @@
+/**
+ * @author takahirox / http://github.com/takahirox/
+ *
+ * Reference: https://en.wikipedia.org/wiki/Cel_shading
+ *
+ * // How to set default outline parameters
+ * new THREE.OutlineEffect( renderer, {
+ * 	defaultThickNess: 0.01,
+ * 	defaultColor: new THREE.Color( 0x888888 ),
+ * 	defaultAlpha: 0.8
+ * } );
+ *
+ * // How to set outline parameters for each material
+ * material.outlineParameters = {
+ * 	thickNess: 0.01,
+ * 	color: new THREE.Color( 0x888888 ),
+ * 	alpha: 0.8,
+ * 	visible: true
+ * };
+ *
+ * TODO
+ *  - shared material
+ *  - support shader material without objectNormal in its vertexShader
+ */
+
+THREE.OutlineEffect = function ( renderer, parameters ) {
+
+	var _this = this;
+
+	parameters = parameters || {};
+
+	this.autoClear = parameters.autoClear !== undefined ? parameters.autoClear : true;
+
+	var defaultThickness = parameters.defaultThickness !== undefined ? parameters.defaultThickness : 0.003;
+	var defaultColor = parameters.defaultColor !== undefined ? parameters.defaultColor : new THREE.Color( 0x000000 );
+	var defaultAlpha = parameters.defaultAlpha !== undefined ? parameters.defaultAlpha : 1.0;
+
+	var invisibleMaterial = new THREE.ShaderMaterial( { visible: false } );
+
+	// copied from WebGLPrograms and removed some materials
+	var shaderIDs = {
+		MeshBasicMaterial: 'basic',
+		MeshLambertMaterial: 'lambert',
+		MeshPhongMaterial: 'phong',
+		MeshStandardMaterial: 'physical',
+		MeshPhysicalMaterial: 'physical'
+	};
+
+	var uniformsChunk = {
+		outlineThickness: { type: "f", value: defaultThickness },
+		outlineColor: { type: "c", value: defaultColor },
+		outlineAlpha: { type: "f", value: defaultAlpha }
+	};
+
+	var vertexShaderChunk = [
+
+		"uniform float outlineThickness;",
+
+		"vec4 calculateOutline( vec4 pos, vec3 objectNormal, vec4 skinned ) {",
+
+		"	float thickness = outlineThickness;",
+		"	float ratio = 1.0;", // TODO: support outline thickness ratio for each vertex
+		"	vec4 pos2 = projectionMatrix * modelViewMatrix * vec4( skinned.xyz + objectNormal, 1.0 );",
+		// NOTE: subtract pos2 from pos because BackSide objectNormal is negative
+		"	vec4 norm = normalize( pos - pos2 );",
+		"	return pos + norm * thickness * pos.w * ratio;",
+
+		"}",
+
+	].join( "\n" );
+
+	var vertexShaderChunk2 = [
+
+		"#if ! defined( LAMBERT ) && ! defined( PHONG ) && ! defined( PHYSICAL )",
+
+		"	#ifndef USE_ENVMAP",
+		"		vec3 objectNormal = normalize( normal );",
+
+		"		#ifdef FLIP_SIDED",
+		"			objectNormal = -objectNormal;",
+		"		#endif",
+
+		"	#endif",
+
+		"#endif",
+
+		"#ifdef USE_SKINNING",
+		"	gl_Position = calculateOutline( gl_Position, objectNormal, skinned );",
+		"#else",
+		"	gl_Position = calculateOutline( gl_Position, objectNormal, vec4( transformed, 1.0 ) );",
+		"#endif",
+
+	].join( "\n" );
+
+	var fragmentShader = [
+
+		"#include <common>",
+		"#include <fog_pars_fragment>",
+
+		"uniform vec3 outlineColor;",
+		"uniform float outlineAlpha;",
+
+		"void main() {",
+
+		"	gl_FragColor = vec4( outlineColor, outlineAlpha );",
+
+		"	#include <fog_fragment>",
+
+		"}",
+
+	].join( "\n" );
+
+	function createMaterial ( originalMaterial ) {
+
+		var shaderID = shaderIDs[ originalMaterial.type ];
+		var originalUniforms, originalVertexShader;
+		var outlineParameters = originalMaterial.outlineParameters;
+
+		if ( shaderID !== undefined ) {
+
+			var shader = THREE.ShaderLib[ shaderID ];
+			originalUniforms = shader.uniforms;
+			originalVertexShader = shader.vertexShader;
+
+		} else if ( originalMaterial.isShaderMaterial === true ) {
+
+			originalUniforms = originalMaterial.uniforms;
+			originalVertexShader = originalMaterial.vertexShader;
+
+		} else {
+
+			return invisibleMaterial;
+
+		}
+
+		var uniforms = THREE.UniformsUtils.merge( [
+			originalUniforms,
+			uniformsChunk
+		] );
+
+		var vertexShader = originalVertexShader
+					// put vertexShaderChunk right before "void main() {...}"
+					.replace( /void\s+main\s*\(\s*\)/, vertexShaderChunk + '\nvoid main()' )
+					// put vertexShaderChunk2 the end of "void main() {...}"
+					// Note: here assums originalVertexShader ends with "}" of "void main() {...}"
+					.replace( /\}\s*$/, vertexShaderChunk2 + '\n}' )
+					// remove any light related lines
+					// Note: here is very sensitive to originalVertexShader
+					// TODO: consider safer way
+					.replace( /#include\s+<[\w_]*light[\w_]*>/g, '' );
+
+		var material = new THREE.ShaderMaterial( {
+			uniforms: THREE.UniformsUtils.clone( uniforms ),
+			vertexShader: vertexShader,
+			fragmentShader: fragmentShader,
+			side: THREE.BackSide,
+			//wireframe: true,
+			skinning: false,
+			morphTargets: false,
+			morphNormals: false,
+			fog: false
+		} );
+
+		return material;
+
+	}
+
+	function createMultiMaterial ( originalMaterial ) {
+
+		var materials = [];
+
+		for ( var i = 0, il = originalMaterial.materials.length; i < il; i ++ ) {
+
+			materials.push( createMaterial( originalMaterial.materials[ i ] ) );
+
+		}
+
+		return new THREE.MultiMaterial( materials );
+
+	}
+
+	function setOutlineMaterial ( object ) {
+
+		if ( object.material === undefined ) return;
+
+		object.userData.originalMaterial = object.material;
+
+		if ( object.userData.outlineMaterial === undefined ) {
+
+			object.userData.outlineMaterial = object.material.type === 'MultiMaterial' ? createMultiMaterial( object.material ) : createMaterial( object.material );
+
+		}
+
+		if ( object.userData.outlineMaterial.type === 'MultiMaterial' ) {
+
+			updateOutlineMultiMaterial( object.userData.outlineMaterial, object.userData.originalMaterial );
+
+		} else {
+
+			updateOutlineMaterial( object.userData.outlineMaterial, object.userData.originalMaterial );
+
+		}
+
+		object.material = object.userData.outlineMaterial;
+
+	}
+
+	function updateOutlineMaterial ( material, originalMaterial ) {
+
+		if ( material === invisibleMaterial ) return;
+
+		var outlineParameters = originalMaterial.outlineParameters;
+
+		material.skinning = originalMaterial.skinning;
+		material.morphTargets = originalMaterial.morphTargets;
+		material.morphNormals = originalMaterial.morphNormals;
+		material.fog = originalMaterial.fog;
+		material.visible = originalMaterial.visible;
+		material.uniforms.outlineAlpha.value = originalMaterial.opacity;
+
+		if ( outlineParameters !== undefined ) {
+
+			if ( outlineParameters.thickness !== undefined ) material.uniforms.outlineThickness.value = outlineParameters.thickness;
+			if ( outlineParameters.color !== undefined ) material.uniforms.outlineColor.value.copy( outlineParameters.color );
+			if ( outlineParameters.alpha !== undefined ) material.uniforms.outlineAlpha.value = outlineParameters.alpha;
+			if ( outlineParameters.visible !== undefined ) material.visible = outlineParameters.visible;
+
+		}
+
+		if ( material.uniforms.outlineAlpha.value < 1.0 ) material.transparent = true;
+
+	}
+
+	function updateOutlineMultiMaterial ( material, originalMaterial ) {
+
+		var outlineParameters = originalMaterial.outlineParameters;
+
+		material.visible = originalMaterial.visible;
+
+		if ( outlineParameters !== undefined ) {
+
+			if ( outlineParameters.visible !== undefined ) material.visible = outlineParameters.visible;
+
+		}
+
+		for ( var i = 0, il = material.materials.length; i < il; i ++ ) {
+
+			updateOutlineMaterial( material.materials[ i ], originalMaterial.materials[ i ] );
+
+		}
+
+	}
+
+	function restoreOriginalMaterial ( object ) {
+
+		if ( object.userData.originalMaterial !== undefined ) object.material = object.userData.originalMaterial;
+
+	}
+
+	this.setSize = function ( width, height ) {
+
+		renderer.setSize( width, height );
+
+	};
+
+	this.render = function ( scene, camera, renderTarget, forceClear ) {
+
+		var currentAutoClear = renderer.autoClear;
+		renderer.autoClear = this.autoClear;
+
+		// 1. render normally
+		renderer.render( scene, camera, renderTarget, forceClear );
+
+		// 2. render outline
+		var currentSceneAutoUpdate = scene.autoUpdate;
+		var currentShadowMapEnabled = renderer.shadowMap.enabled;
+
+		scene.autoUpdate = false;
+		renderer.autoClear = false;
+		renderer.shadowMap.enabled = false;
+
+		scene.traverse( setOutlineMaterial );
+
+		renderer.render( scene, camera, renderTarget );
+
+		scene.traverse( restoreOriginalMaterial );
+
+		scene.autoUpdate = currentSceneAutoUpdate;
+		renderer.autoClear = currentAutoClear;
+		renderer.shadowMap.enabled = currentShadowMapEnabled;
+
+	};
+
+};

+ 1 - 1
examples/js/effects/StereoEffect.js

@@ -32,7 +32,7 @@ THREE.StereoEffect = function ( renderer ) {
 
 		var size = renderer.getSize();
 
-		renderer.clear();
+		if ( renderer.autoClear ) renderer.clear();
 		renderer.setScissorTest( true );
 
 		renderer.setScissor( 0, 0, size.width / 2, size.height );

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

@@ -17,6 +17,7 @@ THREE.VREffect = function ( renderer, onError ) {
 	var renderRectL, renderRectR;
 
 	var frameData = null;
+
 	if ( 'VRFrameData' in window ) {
 
 		frameData = new VRFrameData();
@@ -41,7 +42,11 @@ THREE.VREffect = function ( renderer, onError ) {
 
 	if ( navigator.getVRDisplays ) {
 
-		navigator.getVRDisplays().then( gotVRDisplays );
+		navigator.getVRDisplays().then( gotVRDisplays ).catch ( function () {
+
+			console.warn( 'THREE.VREffect: Unable to get VR Displays' );
+
+		} );
 
 	}
 
@@ -62,8 +67,15 @@ THREE.VREffect = function ( renderer, onError ) {
 
 	};
 
+	this.setVRDisplay = function ( value ) {
+
+		vrDisplay = value;
+
+	};
+
 	this.getVRDisplays = function () {
 
+		console.warn( 'THREE.VREffect: getVRDisplays() is being deprecated.' );
 		return vrDisplays;
 
 	};
@@ -94,10 +106,10 @@ THREE.VREffect = function ( renderer, onError ) {
 	var requestFullscreen;
 	var exitFullscreen;
 	var fullscreenElement;
-	var leftBounds = [ 0.0, 0.0, 0.5, 1.0 ];
-	var rightBounds = [ 0.5, 0.0, 0.5, 1.0 ];
+	var defaultLeftBounds = [ 0.0, 0.0, 0.5, 1.0 ];
+	var defaultRightBounds = [ 0.5, 0.0, 0.5, 1.0 ];
 
-	function onFullscreenChange() {
+	function onVRDisplayPresentChange() {
 
 		var wasPresenting = scope.isPresenting;
 		scope.isPresenting = vrDisplay !== undefined && vrDisplay.isPresenting;
@@ -108,16 +120,6 @@ THREE.VREffect = function ( renderer, onError ) {
 			var eyeWidth = eyeParamsL.renderWidth;
 			var eyeHeight = eyeParamsL.renderHeight;
 
-			var layers = vrDisplay.getLayers();
-			if ( layers.length ) {
-
-				var layer = layers[0];
-
-				leftBounds = layer.leftBounds !== null && layer.leftBounds.length === 4 ? layer.leftBounds : [ 0.0, 0.0, 0.5, 1.0 ];
-				rightBounds = layer.rightBounds !== null && layer.rightBounds.length === 4 ? layer.rightBounds : [ 0.5, 0.0, 0.5, 1.0 ];
-
-			}
-
 			if ( !wasPresenting ) {
 
 				rendererPixelRatio = renderer.getPixelRatio();
@@ -137,7 +139,7 @@ THREE.VREffect = function ( renderer, onError ) {
 
 	}
 
-	window.addEventListener( 'vrdisplaypresentchange', onFullscreenChange, false );
+	window.addEventListener( 'vrdisplaypresentchange', onVRDisplayPresentChange, false );
 
 	this.setFullScreen = function ( boolean ) {
 
@@ -260,17 +262,35 @@ THREE.VREffect = function ( renderer, onError ) {
 			// When rendering we don't care what the recommended size is, only what the actual size
 			// of the backbuffer is.
 			var size = renderer.getSize();
+			var layers = vrDisplay.getLayers();
+			var leftBounds;
+			var rightBounds;
+
+			if ( layers.length ) {
+
+				var layer = layers[ 0 ];
+
+				leftBounds = layer.leftBounds !== null && layer.leftBounds.length === 4 ? layer.leftBounds : defaultLeftBounds;
+				rightBounds = layer.rightBounds !== null && layer.rightBounds.length === 4 ? layer.rightBounds : defaultRightBounds;
+
+			} else {
+
+				leftBounds = defaultLeftBounds;
+				rightBounds = defaultRightBounds;
+
+			}
+
 			renderRectL = {
 				x: Math.round( size.width * leftBounds[ 0 ] ),
 				y: Math.round( size.height * leftBounds[ 1 ] ),
 				width: Math.round( size.width * leftBounds[ 2 ] ),
-				height:  Math.round(size.height * leftBounds[ 3 ] )
+				height: Math.round(size.height * leftBounds[ 3 ] )
 			};
 			renderRectR = {
 				x: Math.round( size.width * rightBounds[ 0 ] ),
 				y: Math.round( size.height * rightBounds[ 1 ] ),
 				width: Math.round( size.width * rightBounds[ 2 ] ),
-				height:  Math.round(size.height * rightBounds[ 3 ] )
+				height: Math.round(size.height * rightBounds[ 3 ] )
 			};
 
 			if ( renderTarget ) {
@@ -278,8 +298,9 @@ THREE.VREffect = function ( renderer, onError ) {
 				renderer.setRenderTarget( renderTarget );
 				renderTarget.scissorTest = true;
 
-			} else  {
+			} else {
 
+				renderer.setRenderTarget( null );
 				renderer.setScissorTest( true );
 
 			}
@@ -310,7 +331,6 @@ THREE.VREffect = function ( renderer, onError ) {
 				cameraL.projectionMatrix = fovToProjection( eyeParamsL.fieldOfView, true, camera.near, camera.far );
 				cameraR.projectionMatrix = fovToProjection( eyeParamsR.fieldOfView, true, camera.near, camera.far );
 
-				
 			}
 
 			// render left eye
@@ -350,6 +370,7 @@ THREE.VREffect = function ( renderer, onError ) {
 
 			} else {
 
+				renderer.setViewport( 0, 0, size.width, size.height );
 				renderer.setScissorTest( false );
 
 			}
@@ -376,6 +397,12 @@ THREE.VREffect = function ( renderer, onError ) {
 
 	};
 
+	this.dispose = function () {
+
+		window.removeEventListener( 'vrdisplaypresentchange', onVRDisplayPresentChange, false );
+
+	};
+
 	//
 
 	function fovToNDCScaleOffset( fov ) {

File diff suppressed because it is too large
+ 19 - 0
examples/js/libs/opentype.min.js


+ 1556 - 190
examples/js/loaders/GLTFLoader.js

@@ -1,373 +1,1739 @@
 /**
+ * @author Rich Tibbett / https://github.com/richtr
  * @author mrdoob / http://mrdoob.com/
+ * @author Tony Parisi / http://www.tonyparisi.com/
  */
 
-THREE.GLTFLoader = function ( manager ) {
+(function() {
+
+THREE.GLTFLoader = function( manager ) {
 
 	this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
 
+	this.parser = GLTFParser;
+
 };
 
 THREE.GLTFLoader.prototype = {
 
 	constructor: THREE.GLTFLoader,
 
-	load: function ( url, onLoad, onProgress, onError ) {
+	load: function( url, onLoad, onProgress, onError ) {
 
 		var scope = this;
 
+		var path = this.path && ( typeof this.path === "string" ) ? this.path : THREE.Loader.prototype.extractUrlBase( url );
+
 		var loader = new THREE.XHRLoader( scope.manager );
-		loader.load( url, function ( text ) {
+		loader.load( url, function( text ) {
 
-			onLoad( scope.parse( JSON.parse( text ) ) );
+			scope.parse( JSON.parse( text ), onLoad, path );
 
 		}, onProgress, onError );
 
 	},
 
-	setCrossOrigin: function ( value ) {
+	setCrossOrigin: function( value ) {
 
 		this.crossOrigin = value;
 
 	},
 
-	parse: function ( json ) {
+	setPath: function( value ) {
 
-		function stringToArrayBuffer( string ) {
+		this.path = value;
 
-			var bytes = atob( string );
-			var buffer = new ArrayBuffer( bytes.length );
-			var bufferView = new Uint8Array( buffer );
+	},
 
-			for ( var i = 0; i < bytes.length; i ++ ) {
+	parse: function( json, callback, path ) {
 
-				bufferView[ i ] = bytes.charCodeAt( i );
+		console.time( 'GLTFLoader' );
 
-			}
+		var glTFParser = new this.parser( json, {
+			path: path || this.path,
+			crossOrigin: !!this.crossOrigin
+		});
 
-			return buffer;
+		glTFParser.parse( function( scene, cameras, animations ) {
 
-		}
+			console.timeEnd( 'GLTFLoader' );
 
-		console.time( 'GLTFLoader' );
+			var glTF = {
+				"scene": scene,
+				"cameras": cameras,
+				"animations": animations
+			};
+
+			callback( glTF );
+
+		});
+
+		// Developers should use `callback` argument for async notification on
+		// completion to prevent side effects.
+		// Function return is kept only for backward-compatability purposes.
+		return {
+			get scene() {
+
+				console.warn( "Synchronous glTF object access is deprecated." +
+					" Use the asynchronous 'callback' argument instead." );
+				return scene;
+
+			},
+			set scene( value ) {
+
+				console.warn( "Synchronous glTF object access is deprecated." +
+					" Use the asynchronous 'callback' argument instead." );
+				scene = value;
+
+			}
 
-		var library = {
-			buffers: {},
-			bufferViews: {},
-			accessors: {},
-			textures: {},
-			materials: {},
-			meshes: {},
-			nodes: {},
-			scenes: {}
 		};
 
-		// buffers
+	}
+
+};
+
+/* GLTFREGISTRY */
+
+var GLTFRegistry = function() {
+
+	var objects = {};
+
+	return	{
+		get : function( key ) {
+
+			return objects[ key ];
+
+		},
+
+		add : function( key, object ) {
+
+			objects[ key ] = object;
+
+		},
+
+		remove: function( key ) {
+
+			delete objects[ key ];
+
+		},
 
-		var buffers = json.buffers;
+		removeAll: function() {
 
-		for ( var bufferId in buffers ) {
+			objects = {};
 
-			var buffer = buffers[ bufferId ];
+		},
 
-			if ( buffer.type === 'arraybuffer' ) {
+		update : function( scene, camera ) {
 
-				var header = 'data:application/octet-stream;base64,';
+			_each( objects, function( object ) {
 
-				if ( buffer.uri.indexOf( header ) === 0 ) {
+				if ( object.update ) {
 
-					library.buffers[ bufferId ] = stringToArrayBuffer( buffer.uri.substr( header.length ) );
+					object.update( scene, camera );
 
 				}
 
-			}
+			});
 
 		}
+	};
+};
+
+/* GLTFSHADERS */
+
+THREE.GLTFLoader.Shaders = new GLTFRegistry();
 
-		// buffer views
+/* GLTFSHADER */
 
-		var bufferViews = json.bufferViews;
+var GLTFShader = function( targetNode, allNodes ) {
 
-		for ( var bufferViewId in bufferViews ) {
+	this.boundUniforms = {};
 
-			var bufferView = bufferViews[ bufferViewId ];
-			var arraybuffer = library.buffers[ bufferView.buffer ];
+	// bind each uniform to its source node
+	_each(targetNode.material.uniforms, function(uniform, uniformId) {
+
+		if (uniform.semantic) {
+
+			var sourceNodeRef = uniform.node;
+
+			var sourceNode = targetNode;
+			if ( sourceNodeRef ) {
+				sourceNode = allNodes[ sourceNodeRef ];
+			}
 
-			library.bufferViews[ bufferViewId ] = arraybuffer.slice( bufferView.byteOffset, bufferView.byteOffset + bufferView.byteLength );
+			this.boundUniforms[ uniformId ] = {
+				semantic: uniform.semantic,
+				sourceNode: sourceNode,
+				targetNode: targetNode,
+				uniform: uniform
+			};
 
 		}
 
-		// accessors
+	}.bind( this ));
 
-		var COMPONENT_TYPES = {
-			5120: Int8Array,
-			5121: Uint8Array,
-			5122: Int16Array,
-			5123: Uint16Array,
-			5125: Uint32Array,
-			5126: Float32Array,
-		};
+	this._m4 = new THREE.Matrix4();
 
-		var TYPE_SIZES = {
-			'SCALAR': 1, 'VEC2': 2, 'VEC3': 3, 'VEC4': 4,
-			'MAT2': 4, 'MAT3': 9, 'MAT4': 16
-		};
+}
 
-		var accessors = json.accessors;
+// Update - update all the uniform values
+GLTFShader.prototype.update = function( scene, camera ) {
 
-		for ( var accessorId in accessors ) {
+	// update scene graph
 
-			var accessor = accessors[ accessorId ];
+	scene.updateMatrixWorld();
 
-			var arraybuffer = library.bufferViews[ accessor.bufferView ];
-			var itemSize = TYPE_SIZES[ accessor.type ];
-			var TypedArray = COMPONENT_TYPES[ accessor.componentType ];
+	// update camera matrices and frustum
 
-			var array = new TypedArray( arraybuffer, accessor.byteOffset, accessor.count * itemSize );
+	camera.updateMatrixWorld();
+	camera.matrixWorldInverse.getInverse( camera.matrixWorld );
+
+	_each( this.boundUniforms, function( boundUniform ) {
+
+		switch (boundUniform.semantic) {
+
+			case "MODELVIEW":
+
+				var m4 = boundUniform.uniform.value;
+				m4.multiplyMatrices(camera.matrixWorldInverse,
+				boundUniform.sourceNode.matrixWorld);
+				break;
+
+			case "MODELVIEWINVERSETRANSPOSE":
 
-			library.accessors[ accessorId ] = new THREE.BufferAttribute( array, itemSize );
+				var m3 = boundUniform.uniform.value;
+				this._m4.multiplyMatrices(camera.matrixWorldInverse,
+				boundUniform.sourceNode.matrixWorld);
+				m3.getNormalMatrix(this._m4);
+				break;
+
+			case "PROJECTION":
+
+				var m4 = boundUniform.uniform.value;
+				m4.copy(camera.projectionMatrix);
+				break;
+
+			case "JOINTMATRIX":
+
+				var m4v = boundUniform.uniform.value;
+				for (var mi = 0; mi < m4v.length; mi++) {
+					// So it goes like this:
+					// SkinnedMesh world matrix is already baked into MODELVIEW;
+					// ransform joints to local space,
+					// then transform using joint's inverse
+					m4v[mi]
+						.getInverse(boundUniform.sourceNode.matrixWorld)
+						.multiply(boundUniform.targetNode.skeleton.bones[ mi ].matrixWorld)
+						.multiply(boundUniform.targetNode.skeleton.boneInverses[mi]);
+				}
+				break;
+
+			default :
+
+				console.warn("Unhandled shader semantic: " + boundUniform.semantic);
+				break;
 
 		}
 
-		// textures
+	}.bind( this ));
 
-		var FILTERS = {
-			9728: THREE.NearestFilter,
-			9729: THREE.LinearFilter,
-			9984: THREE.NearestMipMapNearestFilter,
-			9985: THREE.LinearMipMapNearestFilter,
-			9986: THREE.NearestMipMapLinearFilter,
-			9987: THREE.LinearMipMapLinearFilter
-		};
+};
 
-		var WRAPPINGS = {
-			33071: THREE.ClampToEdgeWrapping,
-			33648: THREE.MirroredRepeatWrapping,
-			10497: THREE.RepeatWrapping
-		};
 
-		var textures = json.textures;
+/* GLTFANIMATION */
 
-		for ( var textureId in textures ) {
+THREE.GLTFLoader.Animations = new GLTFRegistry();
 
-			var texture = textures[ textureId ];
+// Construction/initialization
+var GLTFAnimation = function( interps ) {
 
-			var _texture = new THREE.Texture();
-			_texture.flipY = false;
+	this.running = false;
+	this.loop = false;
+	this.duration = 0;
+	this.startTime = 0;
+	this.interps = [];
 
-			if ( texture.source ) {
+	this.uuid = THREE.Math.generateUUID();
 
-				var source = json.images[ texture.source ];
+	if ( interps ) {
 
-				_texture.image = new Image();
-				_texture.image.src = source.uri;
-				_texture.needsUpdate = true;
+		this.createInterpolators( interps );
 
-			}
+	}
 
-			if ( texture.sampler ) {
+};
 
-				var sampler = json.samplers[ texture.sampler ];
+GLTFAnimation.prototype.createInterpolators = function( interps ) {
 
-				_texture.magFilter = FILTERS[ sampler.magFilter ];
-				_texture.minFilter = FILTERS[ sampler.minFilter ];
-				_texture.wrapS = WRAPPINGS[ sampler.wrapS ];
-				_texture.wrapT = WRAPPINGS[ sampler.wrapT ];
+	for ( var i = 0, len = interps.length; i < len; i ++ ) {
 
-			}
+		var interp = new GLTFInterpolator( interps[ i ] );
+		this.interps.push( interp );
+		this.duration = Math.max( this.duration, interp.duration );
 
-			library.textures[ textureId ] = _texture;
+	}
 
-		}
+}
 
-		// materials
+// Start/stop
+GLTFAnimation.prototype.play = function() {
 
-		var materials = json.materials;
+	if ( this.running )
+		return;
 
-		for ( var materialId in materials ) {
+	this.startTime = Date.now();
+	this.running = true;
+	THREE.GLTFLoader.Animations.add( this.uuid, this );
 
-			var material = materials[ materialId ];
+};
 
-			var _material = new THREE.MeshPhongMaterial();
-			_material.name = material.name;
+GLTFAnimation.prototype.stop = function() {
 
-			var values = material.values;
+	this.running = false;
+	THREE.GLTFLoader.Animations.remove( this.uuid );
 
-			if ( Array.isArray( values.diffuse ) ) {
+};
 
-					_material.color.fromArray( values.diffuse );
+// Update - drive key frame evaluation
+GLTFAnimation.prototype.update = function() {
 
-			} else if ( typeof( values.diffuse ) === 'string' ) {
+	if ( !this.running )
+		return;
 
-					_material.map = library.textures[ values.diffuse ];
+	var now = Date.now();
+	var deltat = ( now - this.startTime ) / 1000;
+	var t = deltat % this.duration;
+	var nCycles = Math.floor( deltat / this.duration );
 
-			}
+	if ( nCycles >= 1 && ! this.loop ) {
 
-			if ( Array.isArray( values.emission ) ) _material.emissive.fromArray( values.emission );
-			if ( Array.isArray( values.specular ) ) _material.specular.fromArray( values.specular );
+		this.running = false;
+		_each( this.interps, function( _, i ) {
 
-			if ( values.shininess !== undefined ) _material.shininess = values.shininess;
+			this.interps[ i ].interp( this.duration );
 
+		}.bind( this ));
+		this.stop();
+		return;
 
-			library.materials[ materialId ] = _material;
+	} else {
 
-		}
+		_each( this.interps, function( _, i ) {
 
-		// meshes
+			this.interps[ i ].interp( t );
 
-		var meshes = json.meshes;
+		}.bind( this ));
 
-		for ( var meshId in meshes ) {
+	}
 
-			var mesh = meshes[ meshId ];
+};
 
-			var group = new THREE.Group();
-			group.name = mesh.name;
+/* GLTFINTERPOLATOR */
 
-			var primitives = mesh.primitives;
+var GLTFInterpolator = function( param ) {
 
-			for ( var i = 0; i < primitives.length; i ++ ) {
+	this.keys = param.keys;
+	this.values = param.values;
+	this.count = param.count;
+	this.type = param.type;
+	this.path = param.path;
+	this.isRot = false;
 
-				var primitive = primitives[ i ];
-				var attributes = primitive.attributes;
+	var node = param.target;
+	node.updateMatrix();
+	node.matrixAutoUpdate = true;
+	this.targetNode = node;
 
-				var geometry = new THREE.BufferGeometry();
+	switch ( param.path ) {
 
-				if ( primitive.indices ) {
+		case "translation" :
 
-					geometry.setIndex( library.accessors[ primitive.indices ] );
+			this.target = node.position;
+			this.originalValue = node.position.clone();
+			break;
 
-				}
+		case "rotation" :
 
-				for ( var attributeId in attributes ) {
+			this.target = node.quaternion;
+			this.originalValue = node.quaternion.clone();
+			this.isRot = true;
+			break;
 
-					var attribute = attributes[ attributeId ];
-					var bufferAttribute = library.accessors[ attribute ];
+		case "scale" :
 
-					switch ( attributeId ) {
+			this.target = node.scale;
+			this.originalValue = node.scale.clone();
+			break;
 
-						case 'POSITION':
-							geometry.addAttribute( 'position', bufferAttribute );
-							break;
+	}
 
-						case 'NORMAL':
-							geometry.addAttribute( 'normal', bufferAttribute );
-							break;
+	this.duration = this.keys[ this.count - 1 ];
 
-						case 'TEXCOORD_0':
-							geometry.addAttribute( 'uv', bufferAttribute );
-							break;
+	this.vec1 = new THREE.Vector3();
+	this.vec2 = new THREE.Vector3();
+	this.vec3 = new THREE.Vector3();
+	this.quat1 = new THREE.Quaternion();
+	this.quat2 = new THREE.Quaternion();
+	this.quat3 = new THREE.Quaternion();
 
-					}
+};
 
-				}
+//Interpolation and tweening methods
+GLTFInterpolator.prototype.interp = function( t ) {
 
-				var material = library.materials[ primitive.material ];
+	if ( t == this.keys[ 0 ] ) {
 
-				group.add( new THREE.Mesh( geometry, material ) );
+		if ( this.isRot ) {
 
-			}
+			this.quat3.fromArray( this.values );
+
+		} else {
 
-			library.meshes[ meshId ] = group;
+			this.vec3.fromArray( this.values );
 
 		}
 
-		// nodes
+	} else if ( t < this.keys[ 0 ] ) {
 
-		var nodes = json.nodes;
-		var matrix = new THREE.Matrix4();
+		if ( this.isRot ) {
 
-		for ( var nodeId in nodes ) {
+			this.quat1.copy( this.originalValue );
+			this.quat2.fromArray( this.values );
+			THREE.Quaternion.slerp( this.quat1, this.quat2, this.quat3, t / this.keys[ 0 ] );
 
-			var node = nodes[ nodeId ];
+		} else {
 
-			var object = new THREE.Group();
-			object.name = node.name;
+			this.vec3.copy( this.originalValue );
+			this.vec2.fromArray( this.values );
+			this.vec3.lerp( this.vec2, t / this.keys[ 0 ] );
 
-			if ( node.translation !== undefined ) {
+		}
 
-				object.position.fromArray( node.translation );
+	} else if ( t >= this.keys[ this.count - 1 ] ) {
 
-			}
+		if ( this.isRot ) {
 
-			if ( node.rotation !== undefined ) {
+			this.quat3.fromArray( this.values, ( this.count - 1 ) * 4 );
 
-				object.quaternion.fromArray( node.rotation );
+		} else {
 
-			}
+			this.vec3.fromArray( this.values, ( this.count - 1 ) * 3 );
 
-			if ( node.scale !== undefined ) {
+		}
 
-				object.scale.fromArray( node.scale );
+	} else {
 
-			}
+		for ( var i = 0; i < this.count - 1; i ++ ) {
+
+			var key1 = this.keys[ i ];
+			var key2 = this.keys[ i + 1 ];
+
+			if ( t >= key1 && t <= key2 ) {
+
+				if ( this.isRot ) {
 
-			if ( node.matrix !== undefined ) {
+					this.quat1.fromArray( this.values, i * 4 );
+					this.quat2.fromArray( this.values, ( i + 1 ) * 4 );
+					THREE.Quaternion.slerp( this.quat1, this.quat2, this.quat3, ( t - key1 ) / ( key2 - key1 ) );
 
-				matrix.fromArray( node.matrix );
-				matrix.decompose( object.position, object.quaternion, object.scale );
+				} else {
+
+					this.vec3.fromArray( this.values, i * 3 );
+					this.vec2.fromArray( this.values, ( i + 1 ) * 3 );
+					this.vec3.lerp( this.vec2, ( t - key1 ) / ( key2 - key1 ) );
+
+				}
 
 			}
 
-			if ( node.meshes !== undefined ) {
+		}
+
+	}
+
+	if ( this.target ) {
+
+		if ( this.isRot ) {
+
+			this.target.copy( this.quat3 );
+
+		} else {
+
+			this.target.copy( this.vec3 );
+
+		}
+
+	}
+
+};
+
+
+/*********************************/
+/********** INTERNALS ************/
+/*********************************/
+
+/* CONSTANTS */
+
+var WEBGL_CONSTANTS = {
+	FLOAT: 5126,
+	//FLOAT_MAT2: 35674,
+	FLOAT_MAT3: 35675,
+	FLOAT_MAT4: 35676,
+	FLOAT_VEC2: 35664,
+	FLOAT_VEC3: 35665,
+	FLOAT_VEC4: 35666,
+	LINEAR: 9729,
+	REPEAT: 10497,
+	SAMPLER_2D: 35678,
+	TRIANGLES: 4,
+	UNSIGNED_BYTE: 5121,
+	UNSIGNED_SHORT: 5123,
+
+	VERTEX_SHADER: 35633,
+	FRAGMENT_SHADER: 35632
+};
+
+var WEBGL_TYPE = {
+	5126: Number,
+	//35674: THREE.Matrix2,
+	35675: THREE.Matrix3,
+	35676: THREE.Matrix4,
+	35664: THREE.Vector2,
+	35665: THREE.Vector3,
+	35666: THREE.Vector4,
+	35678: THREE.Texture
+};
+
+var WEBGL_COMPONENT_TYPES = {
+	5120: Int8Array,
+	5121: Uint8Array,
+	5122: Int16Array,
+	5123: Uint16Array,
+	5125: Uint32Array,
+	5126: Float32Array
+};
+
+var WEBGL_FILTERS = {
+	9728: THREE.NearestFilter,
+	9729: THREE.LinearFilter,
+	9984: THREE.NearestMipMapNearestFilter,
+	9985: THREE.LinearMipMapNearestFilter,
+	9986: THREE.NearestMipMapLinearFilter,
+	9987: THREE.LinearMipMapLinearFilter
+};
+
+var WEBGL_WRAPPINGS = {
+	33071: THREE.ClampToEdgeWrapping,
+	33648: THREE.MirroredRepeatWrapping,
+	10497: THREE.RepeatWrapping
+};
+
+var WEBGL_TYPE_SIZES = {
+	'SCALAR': 1,
+	'VEC2': 2,
+	'VEC3': 3,
+	'VEC4': 4,
+	'MAT2': 4,
+	'MAT3': 9,
+	'MAT4': 16
+};
+
+/* UTILITY FUNCTIONS */
+
+var _each = function( object, callback, thisObj ) {
 
-				for ( var i = 0; i < node.meshes.length; i ++ ) {
+	if ( !object ) {
+		return Promise.resolve();
+	}
+
+	var results;
+	var fns = [];
 
-					var meshId = node.meshes[ i ];
-					var group = library.meshes[ meshId ];
+	if ( Object.prototype.toString.call( object ) === '[object Array]' ) {
 
-					object.add( group.clone() );
+		results = [];
 
+		var length = object.length;
+		for ( var idx = 0; idx < length; idx ++ ) {
+			var value = callback.call( thisObj || this, object[ idx ], idx );
+			if ( value ) {
+				fns.push( value );
+				if ( value instanceof Promise ) {
+					value.then( function( key, value ) {
+						results[ idx ] = value;
+					}.bind( this, key ));
+				} else {
+					results[ idx ] = value;
 				}
+			}
+		}
 
+	} else {
+
+		results = {};
+
+		for ( var key in object ) {
+			if ( object.hasOwnProperty( key ) ) {
+				var value = callback.call( thisObj || this, object[ key ], key );
+				if ( value ) {
+					fns.push( value );
+					if ( value instanceof Promise ) {
+						value.then( function( key, value ) {
+							results[ key ] = value;
+						}.bind( this, key ));
+					} else {
+						results[ key ] = value;
+					}
+				}
 			}
+		}
+
+	}
+
+	return Promise.all( fns ).then( function() {
+		return results;
+	});
+
+};
+
+var resolveURL = function( url, path ) {
+
+	// Invalid URL
+	if ( typeof url !== 'string' || url === '' )
+		return '';
+
+	// Absolute URL
+	if ( /^https?:\/\//i.test( url ) ) {
+
+		return url;
+
+	}
+
+	// Data URI
+	if ( /^data:.*,.*$/i.test( url ) ) {
+
+		return url;
+
+	}
+
+	// Relative URL
+	return (path || '') + url;
+
+};
+
+// Three.js seems too dependent on attribute names so globally
+// replace those in the shader code
+var replaceTHREEShaderAttributes = function( shaderText, technique ) {
+
+	// Expected technique attributes
+	var attributes = {};
+
+	_each( technique.attributes, function( pname, attributeId ) {
+
+		var param = technique.parameters[ pname ];
+		var atype = param.type;
+		var semantic = param.semantic;
+
+		attributes[ attributeId ] = {
+			type : atype,
+			semantic : semantic
+		};
+
+	});
+
+	// Figure out which attributes to change in technique
+
+	var shaderParams = technique.parameters;
+	var shaderAttributes = technique.attributes;
+	var params = {};
+
+	_each( attributes, function( _, attributeId ) {
+
+		var pname = shaderAttributes[ attributeId ];
+		var shaderParam = shaderParams[ pname ];
+		var semantic = shaderParam.semantic;
+		if ( semantic ) {
 
-			library.nodes[ nodeId ] = object;
+			params[ attributeId ] = shaderParam;
 
 		}
 
-		for ( var nodeId in nodes ) {
+	});
 
-			var node = nodes[ nodeId ];
+	_each( params, function( param, pname ) {
 
-			for ( var i = 0; i < node.children.length; i ++ ) {
+		var semantic = param.semantic;
 
-				var child = node.children[ i ];
+		var regEx = new RegExp( "\\b" + pname + "\\b", "g" );
 
-				library.nodes[ nodeId ].add( library.nodes[ child ] );
+		switch ( semantic ) {
 
-			}
+			case "POSITION":
+
+				shaderText = shaderText.replace( regEx, 'position' );
+				break;
+
+			case "NORMAL":
+
+				shaderText = shaderText.replace( regEx, 'normal' );
+				break;
+
+			case 'TEXCOORD_0':
+			case 'TEXCOORD0':
+			case 'TEXCOORD':
+
+				shaderText = shaderText.replace( regEx, 'uv' );
+				break;
+
+			case "WEIGHT":
+
+				shaderText = shaderText.replace(regEx, 'skinWeight');
+				break;
+
+			case "JOINT":
+
+				shaderText = shaderText.replace(regEx, 'skinIndex');
+				break;
 
 		}
 
-		// scenes
+	});
 
-		var scenes = json.scenes;
+	return shaderText;
 
-		for ( var sceneId in scenes ) {
+};
 
-			var scene = scenes[ sceneId ];
-			var container = new THREE.Scene();
+// Deferred constructor for RawShaderMaterial types
+var DeferredShaderMaterial = function( params ) {
 
-			for ( var i = 0; i < scene.nodes.length; i ++ ) {
+	this.isDeferredShaderMaterial = true;
 
-				var node = scene.nodes[ i ];
-				container.add( library.nodes[ node ] );
+	this.params = params;
 
-			}
+};
+
+DeferredShaderMaterial.prototype.create = function() {
+
+	var uniforms = THREE.UniformsUtils.clone( this.params.uniforms );
+
+	_each( this.params.uniforms, function( originalUniform, uniformId ) {
 
-			library.scenes[ sceneId ] = container;
+		if ( originalUniform.value instanceof THREE.Texture ) {
+
+			uniforms[ uniformId ].value = originalUniform.value;
+			uniforms[ uniformId ].value.needsUpdate = true;
 
 		}
 
-		console.timeEnd( 'GLTFLoader' );
+		uniforms[ uniformId ].semantic = originalUniform.semantic;
+		uniforms[ uniformId ].node = originalUniform.node;
 
-		return {
+	});
 
-			scene: library.scenes[ json.scene ]
+	this.params.uniforms = uniforms;
 
-		};
+	return new THREE.RawShaderMaterial( this.params );
+
+};
+
+/* GLTF PARSER */
+
+var GLTFParser = function(json, options) {
+
+	this.json = json || {};
+	this.options = options || {};
+
+	// loader object cache
+	this.cache = new GLTFRegistry();
+
+};
+
+GLTFParser.prototype._withDependencies = function( dependencies ) {
+
+	var _dependencies = {};
+
+	for ( var i = 0; i < dependencies.length; i ++ ) {
+
+		var dependency = dependencies[ i ];
+		var fnName = "load" + dependency.charAt(0).toUpperCase() + dependency.slice(1);
+
+		var cached = this.cache.get( dependency );
+
+		if ( cached !== undefined ) {
+
+			_dependencies[ dependency ] = cached;
+
+		} else if ( this[ fnName ] ) {
+
+			var fn = this[ fnName ]();
+			this.cache.add( dependency, fn );
+
+			_dependencies[ dependency ] = fn;
+
+		}
 
 	}
 
+	return _each( _dependencies, function( dependency, dependencyId ) {
+
+		return dependency;
+
+	});
+
+};
+
+GLTFParser.prototype.parse = function( callback ) {
+
+	// Clear the loader cache
+	this.cache.removeAll();
+
+	// Fire the callback on complete
+	this._withDependencies([
+		"scenes",
+		"cameras",
+		"animations"
+	]).then(function( dependencies ) {
+
+		var scene = dependencies.scenes[ this.json.scene ];
+
+		var cameras = [];
+		_each( dependencies.cameras, function( camera ) {
+
+			cameras.push( camera );
+
+		});
+
+		var animations = [];
+		_each( dependencies.animations, function( animation ) {
+
+			animations.push( animation );
+
+		});
+
+		callback( scene, cameras, animations );
+
+	}.bind( this ));
+
+};
+
+GLTFParser.prototype.loadShaders = function() {
+
+	return _each( this.json.shaders, function( shader, shaderId ) {
+
+		return new Promise( function( resolve ) {
+
+			var loader = new THREE.XHRLoader();
+			loader.responseType = 'text';
+			loader.load( resolveURL( shader.uri, this.options.path ), function( shaderText ) {
+
+				resolve( shaderText );
+
+			});
+
+		}.bind( this ));
+
+	}.bind( this ));
+
+};
+
+GLTFParser.prototype.loadBuffers = function() {
+
+	return _each( this.json.buffers, function( buffer, bufferId ) {
+
+		if ( buffer.type === 'arraybuffer' ) {
+
+			return new Promise( function( resolve ) {
+
+				var loader = new THREE.XHRLoader();
+				loader.responseType = 'arraybuffer';
+				loader.load( resolveURL( buffer.uri, this.options.path ), function( buffer ) {
+
+					resolve( buffer );
+
+				} );
+
+			}.bind( this ));
+
+		}
+
+	}.bind( this ));
+
+};
+
+GLTFParser.prototype.loadBufferViews = function() {
+
+	return this._withDependencies([
+		"buffers"
+	]).then( function( dependencies ) {
+
+		return _each( this.json.bufferViews, function( bufferView, bufferViewId ) {
+
+			var arraybuffer = dependencies.buffers[ bufferView.buffer ];
+
+			return arraybuffer.slice( bufferView.byteOffset, bufferView.byteOffset + bufferView.byteLength );
+
+		});
+
+	}.bind( this ));
+
 };
+
+GLTFParser.prototype.loadAccessors = function() {
+
+	return this._withDependencies([
+		"bufferViews"
+	]).then( function( dependencies ) {
+
+		return _each( this.json.accessors, function( accessor, accessorId ) {
+
+			var arraybuffer = dependencies.bufferViews[ accessor.bufferView ];
+			var itemSize = WEBGL_TYPE_SIZES[ accessor.type ];
+			var TypedArray = WEBGL_COMPONENT_TYPES[ accessor.componentType ];
+
+			var array = new TypedArray( arraybuffer, accessor.byteOffset, accessor.count * itemSize );
+
+			return new THREE.BufferAttribute( array, itemSize );
+
+		});
+
+	}.bind( this ));
+
+};
+
+GLTFParser.prototype.loadTextures = function() {
+
+	return _each( this.json.textures, function( texture, textureId ) {
+
+		if ( texture.source ) {
+
+			return new Promise( function( resolve ) {
+
+				var source = this.json.images[ texture.source ];
+
+				var textureLoader = THREE.Loader.Handlers.get( source.uri );
+				if ( textureLoader === null ) {
+
+					textureLoader = new THREE.TextureLoader();
+
+				}
+				textureLoader.crossOrigin = this.options.crossOrigin || false;
+
+				textureLoader.load( resolveURL( source.uri, this.options.path ), function( _texture ) {
+
+					_texture.flipY = false;
+
+					if ( texture.sampler ) {
+
+						var sampler = this.json.samplers[ texture.sampler ];
+
+						_texture.magFilter = WEBGL_FILTERS[ sampler.magFilter ];
+						_texture.minFilter = WEBGL_FILTERS[ sampler.minFilter ];
+						_texture.wrapS = WEBGL_WRAPPINGS[ sampler.wrapS ];
+						_texture.wrapT = WEBGL_WRAPPINGS[ sampler.wrapT ];
+
+					}
+
+					resolve( _texture );
+
+				}.bind( this ));
+
+			}.bind( this ));
+
+		}
+
+	}.bind( this ));
+
+};
+
+GLTFParser.prototype.loadMaterials = function() {
+
+	return this._withDependencies([
+		"shaders",
+		"textures"
+	]).then( function( dependencies ) {
+
+		return _each( this.json.materials, function( material, materialId ) {
+
+			var materialType;
+			var materialValues = {};
+			var materialParams = {};
+
+			var khr_material;
+
+			if ( material.extensions && material.extensions.KHR_materials_common ) {
+
+				khr_material = material.extensions.KHR_materials_common;
+
+			} else if ( this.json.extensions && this.json.extensions.KHR_materials_common ) {
+
+				khr_material = this.json.extensions.KHR_materials_common;
+
+			}
+
+			if ( khr_material ) {
+
+				switch ( khr_material.technique )
+				{
+					case 'BLINN' :
+					case 'PHONG' :
+						materialType = THREE.MeshPhongMaterial;
+						break;
+
+					case 'LAMBERT' :
+						materialType = THREE.MeshLambertMaterial;
+						break;
+
+					case 'CONSTANT' :
+					default :
+						materialType = THREE.MeshBasicMaterial;
+						break;
+				}
+
+				_each( khr_material.values, function( value, prop ) {
+
+					materialValues[ prop ] = value;
+
+				});
+
+				if ( khr_material.doubleSided || materialValues.doubleSided ) {
+
+					materialParams.side = THREE.DoubleSide;
+
+				}
+
+				if ( khr_material.transparent || materialValues.transparent ) {
+
+					materialParams.transparent = true;
+					materialParams.opacity = ( materialValues.transparency !== undefined ) ? materialValues.transparency : 1;
+
+				}
+
+			} else if ( material.technique === undefined ) {
+
+				materialType = THREE.MeshPhongMaterial;
+
+				_each( material.values, function( value, prop ) {
+
+					materialValues[ prop ] = value;
+
+				});
+
+			} else {
+
+				materialType = DeferredShaderMaterial;
+
+				var technique = this.json.techniques[ material.technique ];
+
+				materialParams.uniforms = {};
+
+				var program = this.json.programs[ technique.program ];
+
+				if ( program ) {
+
+					materialParams.fragmentShader = dependencies.shaders[ program.fragmentShader ];
+
+					if ( ! materialParams.fragmentShader ) {
+
+						console.warn( "ERROR: Missing fragment shader definition:", program.fragmentShader );
+						materialType = THREE.MeshPhongMaterial;
+
+					}
+
+					var vertexShader = dependencies.shaders[ program.vertexShader ];
+
+					if ( ! vertexShader ) {
+
+						console.warn( "ERROR: Missing vertex shader definition:", program.vertexShader );
+						materialType = THREE.MeshPhongMaterial;
+
+					}
+
+					// IMPORTANT: FIX VERTEX SHADER ATTRIBUTE DEFINITIONS
+					materialParams.vertexShader = replaceTHREEShaderAttributes( vertexShader, technique );
+
+					var uniforms = technique.uniforms;
+
+					_each( uniforms, function( pname, uniformId ) {
+
+						var shaderParam = technique.parameters[ pname ];
+
+						var ptype = shaderParam.type;
+
+						if ( WEBGL_TYPE[ ptype ] ) {
+
+							var pcount = shaderParam.count;
+							var value = material.values[ pname ];
+
+							var uvalue = new WEBGL_TYPE[ ptype ]();
+							var usemantic = shaderParam.semantic;
+							var unode = shaderParam.node;
+
+							switch ( ptype ) {
+
+								case WEBGL_CONSTANTS.FLOAT:
+
+									uvalue = shaderParam.value;
+
+									if ( pname == "transparency" ) {
+
+										materialParams.transparent = true;
+
+									}
+
+									if ( value ) {
+
+										uvalue = value;
+
+									}
+
+									break;
+
+								case WEBGL_CONSTANTS.FLOAT_VEC2:
+								case WEBGL_CONSTANTS.FLOAT_VEC3:
+								case WEBGL_CONSTANTS.FLOAT_VEC4:
+								case WEBGL_CONSTANTS.FLOAT_MAT3:
+
+									if ( shaderParam && shaderParam.value ) {
+
+										uvalue.fromArray( shaderParam.value );
+
+									}
+
+									if ( value ) {
+
+										uvalue.fromArray( value );
+
+									}
+
+									break;
+
+								case WEBGL_CONSTANTS.FLOAT_MAT2:
+
+									// what to do?
+									console.warn("FLOAT_MAT2 is not a supported uniform type");
+									break;
+
+								case WEBGL_CONSTANTS.FLOAT_MAT4:
+
+									if ( pcount ) {
+
+										uvalue = new Array( pcount );
+
+										for ( var mi = 0; mi < pcount; mi ++ ) {
+
+											uvalue[ mi ] = new WEBGL_TYPE[ ptype ]();
+
+										}
+
+										if ( shaderParam && shaderParam.value ) {
+
+											var m4v = shaderParam.value;
+											uvalue.fromArray( m4v );
+
+										}
+
+										if ( value ) {
+
+											uvalue.fromArray( value );
+
+										}
+
+									}	else {
+
+										if ( shaderParam && shaderParam.value ) {
+
+											var m4 = shaderParam.value;
+											uvalue.fromArray( m4 );
+
+										}
+
+										if ( value ) {
+
+											uvalue.fromArray( value );
+
+										}
+
+									}
+
+									break;
+
+								case WEBGL_CONSTANTS.SAMPLER_2D:
+
+									uvalue = value ? dependencies.textures[ value ] : null;
+
+									break;
+
+							}
+
+							materialParams.uniforms[ uniformId ] = {
+								value: uvalue,
+								semantic: usemantic,
+								node: unode
+							};
+
+						} else {
+
+							throw new Error( "Unknown shader uniform param type: " + ptype );
+
+						}
+
+					});
+
+				}
+
+			}
+
+			if ( Array.isArray( materialValues.diffuse ) ) {
+
+				materialParams.color = new THREE.Color().fromArray( materialValues.diffuse );
+
+			} else if ( typeof( materialValues.diffuse ) === 'string' ) {
+
+				materialParams.map = dependencies.textures[ materialValues.diffuse ];
+
+			}
+
+			delete materialParams.diffuse;
+
+			if ( typeof( materialValues.reflective ) === 'string' ) {
+
+				materialParams.envMap = dependencies.textures[ materialValues.reflective ];
+
+			}
+
+			if ( typeof( materialValues.bump ) === 'string' ) {
+
+				materialParams.bumpMap = dependencies.textures[ materialValues.bump ];
+
+			}
+
+			if ( Array.isArray( materialValues.emission ) ) {
+
+				materialParams.emissive = new THREE.Color().fromArray( materialValues.emission );
+
+			}
+
+			if ( Array.isArray( materialValues.specular ) ) {
+
+				materialParams.specular = new THREE.Color().fromArray( materialValues.specular );
+
+			}
+
+			if ( materialValues.shininess !== undefined ) {
+
+				materialParams.shininess = materialValues.shininess;
+
+			}
+
+			var _material = new materialType( materialParams );
+			_material.name = material.name;
+
+			return _material;
+
+		}.bind( this ));
+
+	}.bind( this ));
+
+};
+
+GLTFParser.prototype.loadMeshes = function() {
+
+	return this._withDependencies([
+		"accessors",
+		"materials"
+	]).then( function( dependencies ) {
+
+		return _each( this.json.meshes, function( mesh, meshId ) {
+
+			var group = new THREE.Object3D();
+			group.name = mesh.name;
+
+			var primitives = mesh.primitives;
+
+			_each( primitives, function( primitive ) {
+
+				if ( primitive.mode === WEBGL_CONSTANTS.TRIANGLES || primitive.mode === undefined ) {
+
+					var geometry = new THREE.BufferGeometry();
+
+					var attributes = primitive.attributes;
+
+					_each( attributes, function( attributeEntry, attributeId ) {
+
+						if ( !attributeEntry ) {
+
+							return;
+
+						}
+
+						var bufferAttribute = dependencies.accessors[ attributeEntry ];
+
+						switch ( attributeId ) {
+
+							case 'POSITION':
+								geometry.addAttribute( 'position', bufferAttribute );
+								break;
+
+							case 'NORMAL':
+								geometry.addAttribute( 'normal', bufferAttribute );
+								break;
+
+							case 'TEXCOORD_0':
+							case 'TEXCOORD0':
+							case 'TEXCOORD':
+								geometry.addAttribute( 'uv', bufferAttribute );
+								break;
+
+							case 'WEIGHT':
+								geometry.addAttribute( 'skinWeight', bufferAttribute );
+								break;
+
+							case 'JOINT':
+								geometry.addAttribute( 'skinIndex', bufferAttribute );
+								break;
+
+						}
+
+					});
+
+					if ( primitive.indices ) {
+
+						var indexArray = dependencies.accessors[ primitive.indices ];
+
+						geometry.setIndex( indexArray );
+
+						var offset = {
+								start: 0,
+								index: 0,
+								count: indexArray.count
+							};
+
+						geometry.groups.push( offset );
+
+						geometry.computeBoundingSphere();
+
+					}
+
+
+					var material = dependencies.materials[ primitive.material ];
+
+					var meshNode = new THREE.Mesh( geometry, material );
+					meshNode.castShadow = true;
+
+					group.add( meshNode );
+
+				} else {
+
+					console.warn("Non-triangular primitives are not supported");
+
+				}
+
+			});
+
+			return group;
+
+		});
+
+	}.bind( this ));
+
+};
+
+GLTFParser.prototype.loadCameras = function() {
+
+	return _each( this.json.cameras, function( camera, cameraId ) {
+
+		if ( camera.type == "perspective" && camera.perspective ) {
+
+			var yfov = camera.perspective.yfov;
+			var xfov = camera.perspective.xfov;
+			var aspect_ratio = camera.perspective.aspect_ratio || 1;
+
+			// According to COLLADA spec...
+			// aspect_ratio = xfov / yfov
+			xfov = ( xfov === undefined && yfov ) ? yfov * aspect_ratio : xfov;
+
+			// According to COLLADA spec...
+			// aspect_ratio = xfov / yfov
+			// yfov = ( yfov === undefined && xfov ) ? xfov / aspect_ratio : yfov;
+
+			var _camera = new THREE.PerspectiveCamera( THREE.Math.radToDeg( xfov ), aspect_ratio, camera.perspective.znear || 1, camera.perspective.zfar || 2e6 );
+			_camera.name = camera.name;
+
+			return _camera;
+
+		} else if ( camera.type == "orthographic" && camera.orthographic ) {
+
+			var _camera = new THREE.OrthographicCamera( window.innerWidth / - 2, window.innerWidth / 2, window.innerHeight / 2, window.innerHeight / - 2, camera.orthographic.znear, camera.orthographic.zfar );
+			_camera.name = camera.name;
+
+			return _camera;
+
+		}
+
+	}.bind( this ));
+
+};
+
+GLTFParser.prototype.loadSkins = function() {
+
+	return this._withDependencies([
+		"accessors"
+	]).then( function( dependencies ) {
+
+		return _each( this.json.skins, function( skin, skinId ) {
+
+			var _skin = {
+				bindShapeMatrix: new THREE.Matrix4().fromArray( skin.bindShapeMatrix ),
+				jointNames: skin.jointNames,
+				inverseBindMatrices: dependencies.accessors[ skin.inverseBindMatrices ]
+			};
+
+			return _skin;
+
+		});
+
+	}.bind( this ));
+
+};
+
+GLTFParser.prototype.loadAnimations = function() {
+
+	return this._withDependencies([
+		"accessors",
+		"nodes"
+	]).then( function( dependencies ) {
+
+		return _each( this.json.animations, function( animation, animationId ) {
+
+			var interps = [];
+
+			_each( animation.channels, function( channel ) {
+
+				var sampler = animation.samplers[ channel.sampler ];
+
+				if (sampler && animation.parameters) {
+
+						var target = channel.target;
+						var name = target.id;
+						var input = animation.parameters[sampler.input];
+						var output = animation.parameters[sampler.output];
+
+						var inputAccessor = dependencies.accessors[ input ];
+						var outputAccessor = dependencies.accessors[ output ];
+
+						var node = dependencies.nodes[ name ];
+
+						if ( node ) {
+
+							var interp = {
+								keys : inputAccessor.array,
+								values : outputAccessor.array,
+								count : inputAccessor.count,
+								target : node,
+								path : target.path,
+								type : sampler.interpolation
+							};
+
+							interps.push( interp );
+
+						}
+
+				}
+
+			});
+
+			var _animation = new GLTFAnimation(interps);
+			_animation.name = "animation_" + animationId;
+
+			return _animation;
+
+		});
+
+	}.bind( this ));
+
+};
+
+GLTFParser.prototype.loadNodes = function() {
+
+	return _each( this.json.nodes, function( node, nodeId ) {
+
+		var matrix = new THREE.Matrix4();
+
+		var _node;
+
+		if ( node.jointName ) {
+
+			_node = new THREE.Bone();
+			_node.jointName = node.jointName;
+
+		} else {
+
+			_node = new THREE.Object3D()
+
+		}
+
+		_node.name = node.name;
+
+		_node.matrixAutoUpdate = false;
+
+		if ( node.matrix !== undefined ) {
+
+			matrix.fromArray( node.matrix );
+			_node.applyMatrix( matrix );
+
+		} else {
+
+			if ( node.translation !== undefined ) {
+
+				_node.position.fromArray( node.translation );
+
+			}
+
+			if ( node.rotation !== undefined ) {
+
+				_node.quaternion.fromArray( node.rotation );
+
+			}
+
+			if ( node.scale !== undefined ) {
+
+				_node.scale.fromArray( node.scale );
+
+			}
+
+		}
+
+		return _node;
+
+	}.bind( this )).then( function( __nodes ) {
+
+		return this._withDependencies([
+			"meshes",
+			"skins",
+			"cameras",
+			"extensions"
+		]).then( function( dependencies ) {
+
+			return _each( __nodes, function( _node, nodeId ) {
+
+				var node = this.json.nodes[ nodeId ];
+
+				if ( node.meshes !== undefined ) {
+
+					_each( node.meshes, function( meshId ) {
+
+						var group = dependencies.meshes[ meshId ];
+
+						_each( group.children, function( mesh ) {
+
+							// clone Mesh to add to _node
+
+							var originalMaterial = mesh.material;
+							var originalGeometry = mesh.geometry;
+
+							var material;
+							if(originalMaterial.isDeferredShaderMaterial) {
+								originalMaterial = material = originalMaterial.create();
+							} else {
+								material = originalMaterial;
+							}
+
+							mesh = new THREE.Mesh( originalGeometry, material );
+							mesh.castShadow = true;
+
+							var skinEntry;
+							if ( node.skin ) {
+
+								skinEntry = dependencies.skins[ node.skin ];
+
+							}
+
+							// Replace Mesh with SkinnedMesh in library
+							if (skinEntry) {
+
+								var geometry = originalGeometry;
+								var material = originalMaterial;
+								material.skinning = true;
+
+								mesh = new THREE.SkinnedMesh( geometry, material, false );
+								mesh.castShadow = true;
+
+								var bones = [];
+								var boneInverses = [];
+
+								_each( skinEntry.jointNames, function( jointId, i ) {
+
+									var jointNode = __nodes[ jointId ];
+
+									if ( jointNode ) {
+
+										jointNode.skin = mesh;
+										bones.push(jointNode);
+
+										var m = skinEntry.inverseBindMatrices.array;
+										var mat = new THREE.Matrix4().fromArray( m, i * 16 );
+										boneInverses.push(mat);
+
+									} else {
+										console.warn( "WARNING: joint: ''" + jointId + "' could not be found" );
+									}
+
+								});
+
+								mesh.bind( new THREE.Skeleton( bones, boneInverses, false ), skinEntry.bindShapeMatrix );
+
+							}
+
+							_node.add( mesh );
+
+						});
+
+					});
+
+				}
+
+				if ( node.camera !== undefined ) {
+
+					var camera = dependencies.cameras[ node.camera ];
+
+					_node.add( camera );
+
+				}
+
+				if (node.extensions && node.extensions.KHR_materials_common
+						&& node.extensions.KHR_materials_common.light) {
+
+					var light = dependencies.extensions.KHR_materials_common.lights[ node.extensions.KHR_materials_common.light ];
+
+					_node.add(light);
+
+				}
+
+				return _node;
+
+			}.bind( this ));
+
+		}.bind( this ));
+
+	}.bind( this ));
+
+};
+
+GLTFParser.prototype.loadExtensions = function() {
+
+	return _each( this.json.extensions, function( extension, extensionId ) {
+
+		switch ( extensionId ) {
+
+			case "KHR_materials_common":
+
+				var extensionNode = {
+					lights: {}
+				};
+
+				var lights = extension.lights;
+
+				_each( lights, function( light, lightID ) {
+
+					var lightNode;
+
+					var lightParams = light[light.type];
+					var color = new THREE.Color().fromArray( lightParams.color );
+
+					switch ( light.type ) {
+
+						case "directional":
+							lightNode = new THREE.DirectionalLight( color );
+							lightNode.position.set( 0, 0, 1 );
+						break;
+
+						case "point":
+							lightNode = new THREE.PointLight( color );
+						break;
+
+						case "spot ":
+							lightNode = new THREE.SpotLight( color );
+							lightNode.position.set( 0, 0, 1 );
+						break;
+
+						case "ambient":
+							lightNode = new THREE.AmbientLight( color );
+						break;
+
+					}
+
+					if ( lightNode ) {
+
+						extensionNode.lights[ lightID ] = lightNode;
+
+					}
+
+				});
+
+				return extensionNode;
+
+				break;
+
+		}
+
+	}.bind( this ));
+
+};
+
+GLTFParser.prototype.loadScenes = function() {
+
+	// scene node hierachy builder
+
+	var buildNodeHierachy = function( nodeId, parentObject, allNodes ) {
+
+		var _node = allNodes[ nodeId ];
+		parentObject.add( _node );
+
+		var node = this.json.nodes[ nodeId ];
+
+		if ( node.children ) {
+
+			_each( node.children, function( child ) {
+
+				buildNodeHierachy( child, _node, allNodes );
+
+			});
+
+		}
+
+	}.bind( this );
+
+	return this._withDependencies([
+		"nodes"
+	]).then( function( dependencies ) {
+
+		return _each( this.json.scenes, function( scene, sceneId ) {
+
+			var _scene = new THREE.Scene();
+			_scene.name = scene.name;
+
+			_each( scene.nodes, function( nodeId ) {
+
+				buildNodeHierachy( nodeId, _scene, dependencies.nodes );
+
+			});
+
+			_scene.traverse( function( child ) {
+
+				// Register raw material meshes with GLTFLoader.Shaders
+				if (child.material && child.material.isRawShaderMaterial) {
+					var xshader = new GLTFShader( child, dependencies.nodes );
+					THREE.GLTFLoader.Shaders.add( child.uuid, xshader );
+				}
+
+			});
+
+			return _scene;
+
+		});
+
+	}.bind( this ));
+
+};
+
+})();

+ 263 - 435
examples/js/loaders/MMDLoader.js

@@ -3,7 +3,11 @@
  *
  * Dependencies
  *  - charset-encoder-js https://github.com/takahirox/charset-encoder-js
+ *  - ammo.js https://github.com/kripken/ammo.js
  *  - THREE.TGALoader
+ *  - THREE.MMDPhysics
+ *  - THREE.CCDIKSolver
+ *  - THREE.OutlineEffect
  *
  *
  * This loader loads and parses PMD/PMX and VMD binary files
@@ -1227,6 +1231,22 @@ THREE.MMDLoader.prototype.parsePmx = function ( buffer ) {
 					m.uv = dv.getFloat32Array( 4 );
 					p.elements.push( m );
 
+				} else if ( p.type === 4 ) {  // additional uv1
+
+					// TODO: implement
+
+				} else if ( p.type === 5 ) {  // additional uv2
+
+					// TODO: implement
+
+				} else if ( p.type === 6 ) {  // additional uv3
+
+					// TODO: implement
+
+				} else if ( p.type === 7 ) {  // additional uv4
+
+					// TODO: implement
+
 				} else if ( p.type === 8 ) {  // material morph
 
 					var m = {};
@@ -1677,41 +1697,54 @@ THREE.MMDLoader.prototype.parseVpd = function ( text ) {
 THREE.MMDLoader.prototype.createMesh = function ( model, texturePath, onProgress, onError ) {
 
 	var scope = this;
-	var geometry = new THREE.Geometry();
-        var material = new THREE.MultiMaterial();
+	var geometry = new THREE.BufferGeometry();
+	var material = new THREE.MultiMaterial();
 	var helper = new THREE.MMDLoader.DataCreationHelper();
 
+	var buffer = {};
+
+	buffer.vertices = [];
+	buffer.uvs = [];
+	buffer.normals = [];
+	buffer.skinIndices = [];
+	buffer.skinWeights = [];
+	buffer.indices = [];
+
 	var initVartices = function () {
 
 		for ( var i = 0; i < model.metadata.vertexCount; i++ ) {
 
 			var v = model.vertices[ i ];
 
-			geometry.vertices.push(
-				new THREE.Vector3(
-					v.position[ 0 ],
-					v.position[ 1 ],
-					v.position[ 2 ]
-				)
-			);
+			for ( var j = 0, jl = v.position.length; j < jl; j ++ ) {
 
-			geometry.skinIndices.push(
-				new THREE.Vector4(
-					v.skinIndices.length >= 1 ? v.skinIndices[ 0 ] : 0.0,
-					v.skinIndices.length >= 2 ? v.skinIndices[ 1 ] : 0.0,
-					v.skinIndices.length >= 3 ? v.skinIndices[ 2 ] : 0.0,
-					v.skinIndices.length >= 4 ? v.skinIndices[ 3 ] : 0.0
-				)
-			);
+				buffer.vertices.push( v.position[ j ] );
 
-			geometry.skinWeights.push(
-				new THREE.Vector4(
-					v.skinWeights.length >= 1 ? v.skinWeights[ 0 ] : 0.0,
-					v.skinWeights.length >= 2 ? v.skinWeights[ 1 ] : 0.0,
-					v.skinWeights.length >= 3 ? v.skinWeights[ 2 ] : 0.0,
-					v.skinWeights.length >= 4 ? v.skinWeights[ 3 ] : 0.0
-				)
-			);
+			}
+
+			for ( var j = 0, jl = v.normal.length; j < jl; j ++ ) {
+
+				buffer.normals.push( v.normal[ j ] );
+
+			}
+
+			for ( var j = 0, jl = v.uv.length; j < jl; j ++ ) {
+
+				buffer.uvs.push( v.uv[ j ] );
+
+			}
+
+			for ( var j = 0; j < 4; j ++ ) {
+
+				buffer.skinIndices.push( v.skinIndices.length - 1 >= j ? v.skinIndices[ j ] : 0.0 );
+
+			}
+
+			for ( var j = 0; j < 4; j ++ ) {
+
+				buffer.skinWeights.push( v.skinWeights.length - 1 >= j ? v.skinWeights[ j ] : 0.0 );
+
+			}
 
 		}
 
@@ -1721,22 +1754,11 @@ THREE.MMDLoader.prototype.createMesh = function ( model, texturePath, onProgress
 
 		for ( var i = 0; i < model.metadata.faceCount; i++ ) {
 
-			geometry.faces.push(
-				new THREE.Face3(
-					model.faces[ i ].indices[ 0 ],
-					model.faces[ i ].indices[ 1 ],
-					model.faces[ i ].indices[ 2 ]
-				)
-			);
+			var f = model.faces[ i ];
 
-			for ( var j = 0; j < 3; j++ ) {
+			for ( var j = 0, jl = f.indices.length; j < jl; j ++ ) {
 
-				geometry.faces[ i ].vertexNormals[ j ] =
-					new THREE.Vector3(
-						model.vertices[ model.faces[ i ].indices[ j ] ].normal[ 0 ],
-						model.vertices[ model.faces[ i ].indices[ j ] ].normal[ 1 ],
-						model.vertices[ model.faces[ i ].indices[ j ] ].normal[ 2 ]
-					);
+				buffer.indices.push( f.indices[ j ] );
 
 			}
 
@@ -1901,15 +1923,15 @@ THREE.MMDLoader.prototype.createMesh = function ( model, texturePath, onProgress
 
 	var initMorphs = function () {
 
-		function updateVertex ( params, index, v, ratio ) {
+		function updateVertex( attribute, index, v, ratio ) {
 
-			params.vertices[ index ].x += v.position[ 0 ] * ratio;
-			params.vertices[ index ].y += v.position[ 1 ] * ratio;
-			params.vertices[ index ].z += v.position[ 2 ] * ratio;
+			attribute.array[ index * 3 + 0 ] += v.position[ 0 ] * ratio;
+			attribute.array[ index * 3 + 1 ] += v.position[ 1 ] * ratio;
+			attribute.array[ index * 3 + 2 ] += v.position[ 2 ] * ratio;
 
 		};
 
-		function updateVertices ( params, m, ratio ) {
+		function updateVertices( attribute, m, ratio ) {
 
 			for ( var i = 0; i < m.elementCount; i++ ) {
 
@@ -1927,26 +1949,25 @@ THREE.MMDLoader.prototype.createMesh = function ( model, texturePath, onProgress
 
 				}
 
-				updateVertex( params, index, v, ratio );
+				updateVertex( attribute, index, v, ratio );
 
 			}
 
 		};
 
+		var morphTargets = [];
+		var attributes = [];
+
 		for ( var i = 0; i < model.metadata.morphCount; i++ ) {
 
 			var m = model.morphs[ i ];
-			var params = {};
+			var params = { name: m.name };
 
-			params.name = m.name;
-			params.vertices = [];
+			var attribute = new THREE.Float32Attribute( model.metadata.vertexCount * 3, 3 );
 
-			for ( var j = 0; j < model.metadata.vertexCount; j++ ) {
+			for ( var j = 0; j < model.metadata.vertexCount * 3; j++ ) {
 
-				params.vertices[ j ] = new THREE.Vector3( 0, 0, 0 );
-				params.vertices[ j ].x = geometry.vertices[ j ].x;
-				params.vertices[ j ].y = geometry.vertices[ j ].y;
-				params.vertices[ j ].z = geometry.vertices[ j ].z;
+				attribute.array[ j ] = buffer.vertices[ j ];
 
 			}
 
@@ -1954,13 +1975,13 @@ THREE.MMDLoader.prototype.createMesh = function ( model, texturePath, onProgress
 
 				if ( i !== 0 ) {
 
-					updateVertices( params, m, 1.0 );
+					updateVertices( attribute, m, 1.0 );
 
 				}
 
 			} else {
 
-				if ( m.type === 0 ) {
+				if ( m.type === 0 ) {    // group
 
 					for ( var j = 0; j < m.elementCount; j++ ) {
 
@@ -1969,25 +1990,60 @@ THREE.MMDLoader.prototype.createMesh = function ( model, texturePath, onProgress
 
 						if ( m2.type === 1 ) {
 
-							updateVertices( params, m2, ratio );
+							updateVertices( attribute, m2, ratio );
+
+						} else {
+
+							// TODO: implement
 
 						}
 
 					}
 
-				} else if ( m.type === 1 ) {
+				} else if ( m.type === 1 ) {    // vertex
+
+					updateVertices( attribute, m, 1.0 );
 
-					updateVertices( params, m, 1.0 );
+				} else if ( m.type === 2 ) {    // bone
+
+					// TODO: implement
+
+				} else if ( m.type === 3 ) {    // uv
+
+					// TODO: implement
+
+				} else if ( m.type === 4 ) {    // additional uv1
+
+					// TODO: implement
+
+				} else if ( m.type === 5 ) {    // additional uv2
+
+					// TODO: implement
+
+				} else if ( m.type === 6 ) {    // additional uv3
+
+					// TODO: implement
+
+				} else if ( m.type === 7 ) {    // additional uv4
+
+					// TODO: implement
+
+				} else if ( m.type === 8 ) {    // material
+
+					// TODO: implement
 
 				}
 
 			}
 
-			// TODO: skip if this's non-vertex morphing of PMX to reduce CPU/Memory use
-			geometry.morphTargets.push( params );
+			morphTargets.push( params );
+			attributes.push( attribute );
 
 		}
 
+		geometry.morphTargets = morphTargets;
+		geometry.morphAttributes.position = attributes;
+
 	};
 
 	var initMaterials = function () {
@@ -2062,12 +2118,6 @@ THREE.MMDLoader.prototype.createMesh = function ( model, texturePath, onProgress
 
 		};
 
-		for ( var i = 0; i < model.metadata.materialCount; i++ ) {
-
-			geometry.faceVertexUvs.push( [] );
-
-		}
-
 		for ( var i = 0; i < model.metadata.materialCount; i++ ) {
 
 			var m = model.materials[ i ];
@@ -2076,24 +2126,7 @@ THREE.MMDLoader.prototype.createMesh = function ( model, texturePath, onProgress
 			params.faceOffset = offset;
 			params.faceNum = m.faceCount;
 
-			for ( var j = 0; j < m.faceCount; j++ ) {
-
-				geometry.faces[ offset ].materialIndex = i;
-
-				var uvs = [];
-
-				for ( var k = 0; k < 3; k++ ) {
-
-					var v = model.vertices[ model.faces[ offset ].indices[ k ] ];
-					uvs.push( new THREE.Vector2( v.uv[ 0 ], v.uv[ 1 ] ) );
-
-				}
-
-				geometry.faceVertexUvs[ 0 ].push( uvs );
-
-				offset++;
-
-			}
+			offset += m.faceCount;
 
 			params.name = m.name;
 			params.color = color.fromArray( [ m.diffuse[ 0 ], m.diffuse[ 1 ], m.diffuse[ 2 ] ] ).clone();
@@ -2213,15 +2246,14 @@ THREE.MMDLoader.prototype.createMesh = function ( model, texturePath, onProgress
 				fragmentShader: shader.fragmentShader
 			} );
 
-			m.faceOffset = p.faceOffset;
-			m.faceNum = p.faceNum;
+			geometry.addGroup( p.faceOffset * 3, p.faceNum * 3, i );
 
 			if ( p.name !== undefined ) m.name = p.name;
 
 			m.skinning = geometry.bones.length > 0 ? true : false;
 			m.morphTargets = geometry.morphTargets.length > 0 ? true : false;
 			m.lights = true;
-			m.side = p.side;
+			m.side = ( model.metadata.format === 'pmx' && ( p2.flag & 0x1 ) === 1 ) ? THREE.DoubleSide : p.side;
 			m.transparent = p.transparent;
 			m.fog = true;
 
@@ -2233,6 +2265,9 @@ THREE.MMDLoader.prototype.createMesh = function ( model, texturePath, onProgress
 
 			if ( p.map !== undefined ) {
 
+				m.faceOffset = p.faceOffset;
+				m.faceNum = p.faceNum;
+
 				// Check if this part of the texture image the material uses requires transparency
 				function checkTextureTransparency ( m ) {
 
@@ -2252,7 +2287,7 @@ THREE.MMDLoader.prototype.createMesh = function ( model, texturePath, onProgress
 
 						};
 
-						function detectTextureTransparency ( image, uvs ) {
+						function detectTextureTransparency( image, uvs, indices ) {
 
 							var width = image.width;
 							var height = image.height;
@@ -2265,13 +2300,14 @@ THREE.MMDLoader.prototype.createMesh = function ( model, texturePath, onProgress
 
 							}
 
-							for ( var i = 0; i < uvs.length; i++ ) {
+							for ( var i = 0; i < indices.length; i += 3 ) {
 
 								var centerUV = { x: 0.0, y: 0.0 };
 
 								for ( var j = 0; j < 3; j++ ) {
 
-									var uv = uvs[ i ][ j ];
+									var index = indices[ i * 3 + j ];
+									var uv = { x: uvs[ index * 2 + 0 ], y: uvs[ index * 2 + 1 ] };
 
 									if ( getAlphaByUv( image, uv ) < threshold ) {
 
@@ -2287,7 +2323,6 @@ THREE.MMDLoader.prototype.createMesh = function ( model, texturePath, onProgress
 								centerUV.x /= 3;
 								centerUV.y /= 3;
 
-
 								if ( getAlphaByUv( image, centerUV ) < threshold ) {
 
 									return true;
@@ -2334,9 +2369,9 @@ THREE.MMDLoader.prototype.createMesh = function ( model, texturePath, onProgress
 						};
 
 						var imageData = t.image.data !== undefined ? t.image : createImageData( t.image );
-						var uvs = geometry.faceVertexUvs[ 0 ].slice( m.faceOffset, m.faceOffset + m.faceNum );
+						var indices = geometry.index.array.slice( m.faceOffset * 3, m.faceOffset * 3 + m.faceNum * 3 );
 
-						m.textureTransparency = detectTextureTransparency( imageData, uvs );
+						if ( detectTextureTransparency( imageData, geometry.attributes.uv.array, indices ) ) m.transparent = true;
 
 						delete m.faceOffset;
 						delete m.faceNum;
@@ -2392,9 +2427,14 @@ THREE.MMDLoader.prototype.createMesh = function ( model, texturePath, onProgress
 
 				};
 
-				m.uniforms.outlineThickness.value = p2.edgeFlag === 1 ? 0.003 : 0.0;
-				m.uniforms.outlineColor.value = new THREE.Color( 0.0, 0.0, 0.0 );
-				m.uniforms.outlineAlpha.value = 1.0;
+				m.outlineParameters = {
+					thickness: p2.edgeFlag === 1 ? 0.003 : 0.0,
+					color: new THREE.Color( 0.0, 0.0, 0.0 ),
+					alpha: 1.0
+				};
+
+				if ( m.outlineParameters.thickness === 0.0 ) m.outlineParameters.visible = false;
+
 				m.uniforms.toonMap.value = textures[ p2.toonIndex ];
 				m.uniforms.celShading.value = 1;
 
@@ -2408,13 +2448,19 @@ THREE.MMDLoader.prototype.createMesh = function ( model, texturePath, onProgress
 					var uuid = loadTexture( n, { defaultTexturePath: isDefaultToonTexture( n ) } );
 					m.uniforms.toonMap.value = textures[ uuid ];
 					m.uniforms.hasToonTexture.value = 1;
+
 				}
 
 			} else {
 
-				m.uniforms.outlineThickness.value = p2.edgeSize / 300;
-				m.uniforms.outlineColor.value = new THREE.Color( p2.edgeColor[ 0 ], p2.edgeColor[ 1 ], p2.edgeColor[ 2 ] );
-				m.uniforms.outlineAlpha.value = p2.edgeColor[ 3 ];
+				m.outlineParameters = {
+					thickness: p2.edgeSize / 300,
+					color: new THREE.Color( p2.edgeColor[ 0 ], p2.edgeColor[ 1 ], p2.edgeColor[ 2 ] ),
+					alpha: p2.edgeColor[ 3 ]
+				};
+
+				if ( ( p2.flag & 0x10 ) === 0 || m.outlineParameters.thickness === 0.0 ) m.outlineParameters.visible = false;
+
 				m.uniforms.celShading.value = 1;
 
 				if ( p2.toonIndex === -1 ) {
@@ -2472,7 +2518,7 @@ THREE.MMDLoader.prototype.createMesh = function ( model, texturePath, onProgress
 
 					if ( m.uniforms.opacity.value !== e.diffuse[ 3 ] ) {
 
-						m.morphTransparency = true;
+						m.transparent = true;
 
 					}
 
@@ -2567,8 +2613,7 @@ THREE.MMDLoader.prototype.createMesh = function ( model, texturePath, onProgress
 			var bodyB = rigidBodies[ p.rigidBodyIndex2 ];
 
 			/*
-			 * Refer http://www20.atpages.jp/katwat/wp/?p=4135
-			 * for what this is for
+			 * Refer to http://www20.atpages.jp/katwat/wp/?p=4135
 			 */
 			if ( bodyA.type !== 0 && bodyB.type === 2 ) {
 
@@ -2590,6 +2635,20 @@ THREE.MMDLoader.prototype.createMesh = function ( model, texturePath, onProgress
 
 	};
 
+	var initGeometry = function () {
+
+		geometry.setIndex( ( buffer.indices.length > 65535 ? THREE.Uint32Attribute : THREE.Uint16Attribute )( buffer.indices, 1 ) );
+		geometry.addAttribute( 'position', THREE.Float32Attribute( buffer.vertices, 3 ) );
+		geometry.addAttribute( 'normal', THREE.Float32Attribute( buffer.normals, 3 ) );
+		geometry.addAttribute( 'uv', THREE.Float32Attribute( buffer.uvs, 2 ) );
+		geometry.addAttribute( 'skinIndex', THREE.Float32Attribute( buffer.skinIndices, 4 ) );
+		geometry.addAttribute( 'skinWeight', THREE.Float32Attribute( buffer.skinWeights, 4 ) );
+
+		geometry.computeBoundingSphere();
+		geometry.mmdFormat = model.metadata.format;
+
+	};
+
 	this.leftToRightModel( model );
 
 	initVartices();
@@ -2600,12 +2659,7 @@ THREE.MMDLoader.prototype.createMesh = function ( model, texturePath, onProgress
 	initMorphs();
 	initMaterials();
 	initPhysics();
-
-	geometry.computeFaceNormals();
-	geometry.verticesNeedUpdate = true;
-	geometry.normalsNeedUpdate = true;
-	geometry.uvsNeedUpdate = true;
-	geometry.mmdFormat = model.metadata.format;
+	initGeometry();
 
 	var mesh = new THREE.SkinnedMesh( geometry, material );
 
@@ -2792,21 +2846,14 @@ THREE.MMDLoader.prototype.leftToRightModel = function ( model ) {
 
 		var m = model.morphs[ i ];
 
-		if ( model.metadata.format === 'pmx' ) {
-
-			if ( m.type === 1 ) {
-
-				m = m.elements;
+		if ( model.metadata.format === 'pmx' && m.type !== 1 ) {
 
-			} else {
-
-				continue;
-
-			}
+			// TODO: implement
+			continue;
 
 		}
 
-		for ( var j = 0; j < m.elementCount; j++ ) {
+		for ( var j = 0; j < m.elements.length; j++ ) {
 
 			helper.leftToRightVector3( m.elements[ j ].position );
 
@@ -3558,148 +3605,22 @@ THREE.ShaderLib[ 'mmd' ] = {
 
 	uniforms: THREE.UniformsUtils.merge( [
 
-		THREE.UniformsLib[ "common" ],
-		THREE.UniformsLib[ "aomap" ],
-		THREE.UniformsLib[ "lightmap" ],
-		THREE.UniformsLib[ "emissivemap" ],
-		THREE.UniformsLib[ "bumpmap" ],
-		THREE.UniformsLib[ "normalmap" ],
-		THREE.UniformsLib[ "displacementmap" ],
-		THREE.UniformsLib[ "fog" ],
-		THREE.UniformsLib[ "lights" ],
-
-		{
-			"emissive" : { value: new THREE.Color( 0x000000 ) },
-			"specular" : { value: new THREE.Color( 0x111111 ) },
-			"shininess": { value: 30 }
-		},
+		THREE.ShaderLib[ 'phong' ].uniforms,
 
-		// ---- MMD specific for cel shading(outline drawing and toon mapping)
+		// MMD specific for toon mapping
 		{
-			"outlineDrawing"  : { value: 0 },
-			"outlineThickness": { value: 0.0 },
-			"outlineColor"    : { value: new THREE.Color( 0x000000 ) },
-			"outlineAlpha"    : { value: 1.0 },
-			"celShading"      : { value: 0 },
-			"toonMap"         : { value: null },
-			"hasToonTexture"  : { value: 0 }
+			"celShading"      : { type: "i", value: 0 },
+			"toonMap"         : { type: "t", value: null },
+			"hasToonTexture"  : { type: "i", value: 0 }
 		}
-		// ---- MMD specific for cel shading(outline drawing and toon mapping)
 
 	] ),
 
-	vertexShader: [
-
-		"#define PHONG",
-
-		"varying vec3 vViewPosition;",
+	vertexShader: THREE.ShaderLib[ 'phong' ].vertexShader,
 
-		"#ifndef FLAT_SHADED",
+	// put toon mapping logic right before "void main() {...}"
+	fragmentShader: THREE.ShaderLib[ 'phong' ].fragmentShader.replace( /void\s+main\s*\(\s*\)/, [
 
-		"	varying vec3 vNormal;",
-
-		"#endif",
-
-		THREE.ShaderChunk[ "common" ],
-		THREE.ShaderChunk[ "uv_pars_vertex" ],
-		THREE.ShaderChunk[ "uv2_pars_vertex" ],
-		THREE.ShaderChunk[ "displacementmap_pars_vertex" ],
-		THREE.ShaderChunk[ "envmap_pars_vertex" ],
-		THREE.ShaderChunk[ "color_pars_vertex" ],
-		THREE.ShaderChunk[ "morphtarget_pars_vertex" ],
-		THREE.ShaderChunk[ "skinning_pars_vertex" ],
-		THREE.ShaderChunk[ "shadowmap_pars_vertex" ],
-		THREE.ShaderChunk[ "logdepthbuf_pars_vertex" ],
-		THREE.ShaderChunk[ "clipping_planes_pars_vertex" ],
-
-		// ---- MMD specific for outline drawing
-		"	uniform bool outlineDrawing;",
-		"	uniform float outlineThickness;",
-		// ---- MMD specific for outline drawing
-
-		"void main() {",
-
-			THREE.ShaderChunk[ "uv_vertex" ],
-			THREE.ShaderChunk[ "uv2_vertex" ],
-			THREE.ShaderChunk[ "color_vertex" ],
-
-			THREE.ShaderChunk[ "beginnormal_vertex" ],
-			THREE.ShaderChunk[ "morphnormal_vertex" ],
-			THREE.ShaderChunk[ "skinbase_vertex" ],
-			THREE.ShaderChunk[ "skinnormal_vertex" ],
-			THREE.ShaderChunk[ "defaultnormal_vertex" ],
-
-		"#ifndef FLAT_SHADED", // Normal computed with derivatives when FLAT_SHADED
-
-		"	vNormal = normalize( transformedNormal );",
-
-		"#endif",
-
-			THREE.ShaderChunk[ "begin_vertex" ],
-			THREE.ShaderChunk[ "displacementmap_vertex" ],
-			THREE.ShaderChunk[ "morphtarget_vertex" ],
-			THREE.ShaderChunk[ "skinning_vertex" ],
-			THREE.ShaderChunk[ "project_vertex" ],
-			THREE.ShaderChunk[ "logdepthbuf_vertex" ],
-			THREE.ShaderChunk[ "clipping_planes_vertex" ],
-
-		"	vViewPosition = - mvPosition.xyz;",
-
-			THREE.ShaderChunk[ "worldpos_vertex" ],
-			THREE.ShaderChunk[ "envmap_vertex" ],
-			THREE.ShaderChunk[ "shadowmap_vertex" ],
-
-		// ---- MMD specific for outline drawing
-		"	if ( outlineDrawing ) {",
-		"		float thickness = outlineThickness;",
-		"		float ratio = 1.0;", // TODO: support outline size ratio for each vertex
-		"		vec4 epos = projectionMatrix * modelViewMatrix * skinned;",
-		"		vec4 epos2 = projectionMatrix * modelViewMatrix * vec4( skinned.xyz + objectNormal, 1.0 );",
-		"		vec4 enorm = normalize( epos2 - epos );",
-		"		gl_Position = epos + enorm * thickness * epos.w * ratio;",
-		"	}",
-		// ---- MMD specific for outline drawing
-
-		"}"
-
-	].join( "\n" ),
-
-	fragmentShader: [
-
-		"#define PHONG",
-
-		"uniform vec3 diffuse;",
-		"uniform vec3 emissive;",
-		"uniform vec3 specular;",
-		"uniform float shininess;",
-		"uniform float opacity;",
-
-		THREE.ShaderChunk[ "common" ],
-		THREE.ShaderChunk[ "packing" ],
-		THREE.ShaderChunk[ "color_pars_fragment" ],
-		THREE.ShaderChunk[ "uv_pars_fragment" ],
-		THREE.ShaderChunk[ "uv2_pars_fragment" ],
-		THREE.ShaderChunk[ "map_pars_fragment" ],
-		THREE.ShaderChunk[ "alphamap_pars_fragment" ],
-		THREE.ShaderChunk[ "aomap_pars_fragment" ],
-		THREE.ShaderChunk[ "lightmap_pars_fragment" ],
-		THREE.ShaderChunk[ "emissivemap_pars_fragment" ],
-		THREE.ShaderChunk[ "envmap_pars_fragment" ],
-		THREE.ShaderChunk[ "fog_pars_fragment" ],
-		THREE.ShaderChunk[ "bsdfs" ],
-		THREE.ShaderChunk[ "lights_pars" ],
-		THREE.ShaderChunk[ "lights_phong_pars_fragment" ],
-		THREE.ShaderChunk[ "shadowmap_pars_fragment" ],
-		THREE.ShaderChunk[ "bumpmap_pars_fragment" ],
-		THREE.ShaderChunk[ "normalmap_pars_fragment" ],
-		THREE.ShaderChunk[ "specularmap_pars_fragment" ],
-		THREE.ShaderChunk[ "logdepthbuf_pars_fragment" ],
-		THREE.ShaderChunk[ "clipping_planes_pars_fragment" ],
-
-		// ---- MMD specific for cel shading
-		"	uniform bool outlineDrawing;",
-		"	uniform vec3 outlineColor;",
-		"	uniform float outlineAlpha;",
 		"	uniform bool celShading;",
 		"	uniform sampler2D toonMap;",
 		"	uniform bool hasToonTexture;",
@@ -3738,52 +3659,9 @@ THREE.ShaderLib[ 'mmd' ] = {
 		"#define RE_Direct	RE_Direct_BlinnMMD",
 		// ---- MMD specific for toon mapping
 
-		"void main() {",
+		"void main()",
 
-		// ---- MMD specific for outline drawing
-		"	if ( outlineDrawing ) {",
-		"		gl_FragColor = vec4( outlineColor, outlineAlpha );",
-		"		return;",
-		"	}",
-		// ---- MMD specific for outline drawing
-
-			THREE.ShaderChunk[ "clipping_planes_fragment" ],
-
-		"	vec4 diffuseColor = vec4( diffuse, opacity );",
-		"	ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );",
-		"	vec3 totalEmissiveRadiance = emissive;",
-
-			THREE.ShaderChunk[ "logdepthbuf_fragment" ],
-			THREE.ShaderChunk[ "map_fragment" ],
-			THREE.ShaderChunk[ "color_fragment" ],
-			THREE.ShaderChunk[ "alphamap_fragment" ],
-			THREE.ShaderChunk[ "alphatest_fragment" ],
-			THREE.ShaderChunk[ "specularmap_fragment" ],
-			THREE.ShaderChunk[ "normal_flip" ],
-			THREE.ShaderChunk[ "normal_fragment" ],
-			THREE.ShaderChunk[ "emissivemap_fragment" ],
-
-			// accumulation
-			THREE.ShaderChunk[ "lights_phong_fragment" ],
-			THREE.ShaderChunk[ "lights_template" ],
-
-			// modulation
-			THREE.ShaderChunk[ "aomap_fragment" ],
-
-			"vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;",
-
-			THREE.ShaderChunk[ "envmap_fragment" ],
-
-		"	gl_FragColor = vec4( outgoingLight, diffuseColor.a );",
-
-			THREE.ShaderChunk[ "premultiplied_alpha_fragment" ],
-			THREE.ShaderChunk[ "tonemapping_fragment" ],
-			THREE.ShaderChunk[ "encodings_fragment" ],
-			THREE.ShaderChunk[ "fog_fragment" ],
-
-		"}"
-
-	].join( "\n" )
+	].join( "\n" ) )
 
 };
 
@@ -3935,8 +3813,13 @@ THREE.MMDGrantSolver.prototype = {
 THREE.MMDHelper = function ( renderer ) {
 
 	this.renderer = renderer;
+
+	this.outlineEffect = null;
+
 	this.effect = null;
 
+	this.autoClear = true;
+
 	this.meshes = [];
 
 	this.doAnimation = true;
@@ -3959,15 +3842,10 @@ THREE.MMDHelper.prototype = {
 
 	init: function () {
 
-		this.initRender();
-
-	},
+		this.outlineEffect = new THREE.OutlineEffect( this.renderer );
 
-	initRender: function () {
-
-		this.renderer.autoClear = false;
-		this.renderer.autoClearColor = false;
-		this.renderer.autoClearDepth = false;
+		var size = this.renderer.getSize();
+		this.setSize( size.width, size.height );
 
 	},
 
@@ -3990,6 +3868,12 @@ THREE.MMDHelper.prototype = {
 
 	},
 
+	setSize: function ( width, height ) {
+
+		this.outlineEffect.setSize( width, height );
+
+	},
+
 	/*
 	 * Note: There may be a possibility that Outline wouldn't work well with Effect.
 	 *       In such a case, try to set doOutlineDrawing = false or
@@ -4106,7 +3990,7 @@ THREE.MMDHelper.prototype = {
 	},
 
 	/*
-	 * detect the longest duration among model, camera, and audio animation and then
+	 * detect the longest duration among model, camera, and audio animations and then
 	 * set it to them to sync.
 	 * TODO: touching private properties ( ._actions and ._clip ) so consider better way
 	 *       to access them for safe and modularity.
@@ -4243,9 +4127,12 @@ THREE.MMDHelper.prototype = {
 
 		if ( mixer !== null && this.doAnimation === true ) {
 
+			// restore/backupBones are workaround
+			// until I make IK, Grant, and Physics Animation plugin
+			this.restoreBones( mesh );
+
 			mixer.update( delta );
 
-			// workaround until I make IK, Grant, and Physics Animation plugin
 			this.backupBones( mesh );
 
 		}
@@ -4295,194 +4182,135 @@ THREE.MMDHelper.prototype = {
 
 	render: function ( scene, camera ) {
 
-		this.renderer.clearColor();
-		this.renderer.clearDepth();
-		this.renderer.clear( true, true );
-
-		this.renderMain( scene, camera );
-
-		if ( this.doOutlineDrawing ) {
-
-			this.renderOutline( scene, camera );
-
-		}
-
-		// workaround until I make IK and Physics Animation plugin
-		for ( var i = 0; i < this.meshes.length; i++ ) {
-
-			this.restoreBones( this.meshes[ i ] );
-
-		}
-
-	},
-
-	renderMain: function ( scene, camera ) {
-
-		this.setupMainRendering();
-		this.callRender( scene, camera );
-
-	},
-
-	renderOutline: function () {
-
-		var invisibledObjects = [];
-		var setInvisible;
-		var restoreVisible;
-
-		return function renderOutline( scene, camera ) {
-
-			var self = this;
+		if ( this.effect === null ) {
 
-			if ( setInvisible === undefined ) {
+			if ( this.doOutlineDrawing ) {
 
-				setInvisible = function ( object ) {
+				this.outlineEffect.autoClear = this.autoClear;
+				this.outlineEffect.render( scene, camera );
 
-					if ( ! object.visible || ! object.layers.test( camera.layers ) ) return;
+			} else {
 
-					// any types else to skip?
-					if ( object instanceof THREE.Scene ||
-					     object instanceof THREE.Bone ||
-					     object instanceof THREE.Light ||
-					     object instanceof THREE.Camera ||
-					     object instanceof THREE.Audio ||
-					     object instanceof THREE.AudioListener ) return;
+				var currentAutoClear = this.renderer.autoClear;
+				this.renderer.autoClear = this.autoClear;
+				this.renderer.render( scene, camera );
+				this.renderer.autoClear = currentAutoClear;
 
-					if ( object instanceof THREE.SkinnedMesh ) {
+			}
 
-						for ( var i = 0, il = self.meshes.length; i < il; i ++ ) {
+		} else {
 
-							if ( self.meshes[ i ] === object ) return;
+			var currentAutoClear = this.renderer.autoClear;
+			this.renderer.autoClear = this.autoClear;
 
-						}
+			if ( this.doOutlineDrawing ) {
 
-					}
+				this.renderWithEffectAndOutline( scene, camera );
 
-					object.layers.mask &= ~ camera.layers.mask;
-					invisibledObjects.push( object );
+			} else {
 
-				};
+				this.effect.render( scene, camera );
 
 			}
 
-			if ( restoreVisible === undefined ) {
+			this.renderer.autoClear = currentAutoClear;
 
-				restoreVisible = function () {
-
-					for ( var i = 0, il = invisibledObjects.length; i < il; i ++ ) {
-
-						invisibledObjects[ i ].layers.mask |= camera.layers.mask;
-
-					}
-
-					invisibledObjects.length = 0;
-
-				};
-
-			}
+		}
 
-			scene.traverse( setInvisible );
+	},
 
-			var tmpEnabled = this.renderer.shadowMap.enabled;
-			this.renderer.shadowMap.enabled = false;
+	/*
+	 * Currently(r82 dev) there's no way to render with two Effects
+	 * then attempt to get them to coordinately run by myself.
+	 *
+	 * What this method does
+	 * 1. let OutlineEffect make outline materials (only once)
+	 * 2. render normally with effect
+	 * 3. set outline materials
+	 * 4. render outline with effect
+	 * 5. restore original materials
+	 */
+	renderWithEffectAndOutline: function ( scene, camera ) {
 
-			this.setupOutlineRendering();
-			this.callRender( scene, camera );
+		var hasOutlineMaterial = false;
 
-			this.renderer.shadowMap.enabled = tmpEnabled;
+		function checkIfObjectHasOutlineMaterial ( object ) {
 
-			restoreVisible();
+			if ( object.material === undefined ) return;
 
-		};
+			if ( object.userData.outlineMaterial !== undefined ) hasOutlineMaterial = true;
 
-	}(),
+		}
 
-	callRender: function ( scene, camera ) {
+		function setOutlineMaterial ( object ) {
 
-		if ( this.effect === null ) {
+			if ( object.material === undefined ) return;
 
-			this.renderer.render( scene, camera );
+			if ( object.userData.outlineMaterial === undefined ) return;
 
-		} else {
+			object.userData.originalMaterial = object.material;
 
-			this.effect.render( scene, camera );
+			object.material = object.userData.outlineMaterial;
 
 		}
 
-	},
+		function restoreOriginalMaterial ( object ) {
 
-	setupMainRendering: function () {
+			if ( object.material === undefined ) return;
 
-		for ( var i = 0; i < this.meshes.length; i++ ) {
+			if ( object.userData.originalMaterial === undefined ) return;
 
-			this.setupMainRenderingOneMesh( this.meshes[ i ] );
+			object.material = object.userData.originalMaterial;
 
 		}
 
-	},
-
-	setupMainRenderingOneMesh: function ( mesh ) {
-
-		for ( var i = 0; i < mesh.material.materials.length; i++ ) {
+		return function renderWithEffectAndOutline( scene, camera ) {
 
-			var m = mesh.material.materials[ i ];
-			m.uniforms.outlineDrawing.value = 0;
-			m.visible = true;
+			hasOutlineMaterial = false;
 
-			if ( m.uniforms.opacity.value === 1.0 ) {
+			var forceClear = false;
 
-				m.side = THREE.FrontSide;
-				m.transparent = false;
+			scene.traverse( checkIfObjectHasOutlineMaterial );
 
-			} else {
-
-				m.side = THREE.DoubleSide;
-				m.transparent = true;
+			if ( ! hasOutlineMaterial ) {
 
-			}
+				this.outlineEffect.render( scene, camera );
 
-			if ( m.textureTransparency === true || m.morphTransparency === true ) {
+				forceClear = true;
 
-				m.transparent = true;
+				scene.traverse( checkIfObjectHasOutlineMaterial );
 
 			}
 
-		}
-
-	},
+			if ( hasOutlineMaterial ) {
 
-	setupOutlineRendering: function () {
+				this.renderer.autoClear = this.autoClear || forceClear;
 
-		for ( var i = 0; i < this.meshes.length; i++ ) {
+				this.effect.render( scene, camera );
 
-			this.setupOutlineRenderingOneMesh( this.meshes[ i ] );
+				scene.traverse( setOutlineMaterial );
 
-		}
-
-	},
+				var currentShadowMapEnabled = this.renderer.shadowMap.enabled;
 
-	setupOutlineRenderingOneMesh: function ( mesh ) {
+				this.renderer.autoClear = false;
+				this.renderer.shadowMap.enabled = false;
 
-		for ( var i = 0; i < mesh.material.materials.length; i++ ) {
+				this.effect.render( scene, camera );
 
-			var m = mesh.material.materials[ i ];
-			m.uniforms.outlineDrawing.value = 1;
-			m.side = THREE.BackSide;
+				this.renderer.shadowMap.enabled = currentShadowMapEnabled;
 
-			if ( m.uniforms.outlineAlpha.value < 1.0 ) {
+				scene.traverse( restoreOriginalMaterial );
 
-				m.transparent = true;
-
-			}
-
-			if ( m.uniforms.outlineThickness.value === 0.0 ) {
+			} else {
 
-				m.visible = false;
+				this.outlineEffect.autoClear = this.autoClear || forceClear;
+				this.outlineEffect.render( scene, camera );
 
 			}
 
 		}
 
-	},
+	}(),
 
 	poseAsVpd: function ( mesh, vpd, params ) {
 

+ 74 - 75
examples/js/loaders/PLYLoader.js

@@ -64,7 +64,7 @@ THREE.PLYLoader.prototype = {
 		function isASCII( data ) {
 
 			var header = parseHeader( bin2str( data ) );
-			return header.format === "ascii";
+			return header.format === 'ascii';
 
 		}
 
@@ -86,7 +86,7 @@ THREE.PLYLoader.prototype = {
 		function parseHeader( data ) {
 
 			var patternHeader = /ply([\s\S]*)end_header\s/;
-			var headerText = "";
+			var headerText = '';
 			var headerLength = 0;
 			var result = patternHeader.exec( data );
 
@@ -138,28 +138,28 @@ THREE.PLYLoader.prototype = {
 				var line = lines[ i ];
 				line = line.trim();
 
-				if ( line === "" ) continue;
+				if ( line === '' ) continue;
 
 				lineValues = line.split( /\s+/ );
 				lineType = lineValues.shift();
-				line = lineValues.join( " " );
+				line = lineValues.join( ' ' );
 
 				switch ( lineType ) {
 
-					case "format":
+					case 'format':
 
 						header.format = lineValues[ 0 ];
 						header.version = lineValues[ 1 ];
 
 						break;
 
-					case "comment":
+					case 'comment':
 
 						header.comments.push( line );
 
 						break;
 
-					case "element":
+					case 'element':
 
 						if ( currentElement !== undefined ) {
 
@@ -174,7 +174,7 @@ THREE.PLYLoader.prototype = {
 
 						break;
 
-					case "property":
+					case 'property':
 
 						currentElement.properties.push( make_ply_element_property( lineValues, scope.propertyNameMapping ) );
 
@@ -183,7 +183,7 @@ THREE.PLYLoader.prototype = {
 
 					default:
 
-						console.log( "unhandled", lineType, lineValues );
+						console.log( 'unhandled', lineType, lineValues );
 
 				}
 
@@ -224,7 +224,7 @@ THREE.PLYLoader.prototype = {
 
 			for ( var i = 0; i < properties.length; i ++ ) {
 
-				if ( properties[ i ].type === "list" ) {
+				if ( properties[ i ].type === 'list' ) {
 
 					var list = [];
 					var n = parseASCIINumber( values.shift(), properties[ i ].countType );
@@ -253,14 +253,20 @@ THREE.PLYLoader.prototype = {
 
 			// PLY ascii format specification, as per http://en.wikipedia.org/wiki/PLY_(file_format)
 
-			var geometry = new THREE.Geometry();
+			var buffer = {
+				indices : [],
+				vertices : [],
+				normals : [],
+				uvs : [],
+				colors : []
+			};
 
 			var result;
 
 			var header = parseHeader( data );
 
 			var patternBody = /end_header\s([\s\S]*)$/;
-			var body = "";
+			var body = '';
 			if ( ( result = patternBody.exec( data ) ) !== null ) {
 
 				body = result [ 1 ];
@@ -270,13 +276,12 @@ THREE.PLYLoader.prototype = {
 			var lines = body.split( '\n' );
 			var currentElement = 0;
 			var currentElementCount = 0;
-			geometry.useColor = false;
 
 			for ( var i = 0; i < lines.length; i ++ ) {
 
 				var line = lines[ i ];
 				line = line.trim();
-				if ( line === "" ) {
+				if ( line === '' ) {
 
 					continue;
 
@@ -291,31 +296,42 @@ THREE.PLYLoader.prototype = {
 
 				var element = parseASCIIElement( header.elements[ currentElement ].properties, line );
 
-				handleElement( geometry, header.elements[ currentElement ].name, element );
+				handleElement( buffer, header.elements[ currentElement ].name, element );
 
 				currentElementCount ++;
 
 			}
 
-			return postProcess( geometry );
+			return postProcess( buffer );
 
 		}
 
-		function postProcess( geometry ) {
+		function postProcess( buffer ) {
 
-			if ( geometry.useColor ) {
+			var geometry = new THREE.BufferGeometry();
 
-				for ( var i = 0; i < geometry.faces.length; i ++ ) {
+			// mandatory buffer data
 
-					geometry.faces[ i ].vertexColors = [
-						geometry.colors[ geometry.faces[ i ].a ],
-						geometry.colors[ geometry.faces[ i ].b ],
-						geometry.colors[ geometry.faces[ i ].c ]
-					];
+			geometry.setIndex( ( buffer.indices.length > 65535 ? THREE.Uint32Attribute : THREE.Uint16Attribute )( buffer.indices, 1 ) );
+			geometry.addAttribute( 'position', THREE.Float32Attribute( buffer.vertices, 3 ) );
 
-				}
+			// optional buffer data
+
+			if ( buffer.normals.length > 0 ) {
+
+				geometry.addAttribute( 'normal', THREE.Float32Attribute( buffer.normals, 3 ) );
+
+			}
+
+			if ( buffer.uvs.length > 0 ) {
 
-				geometry.elementsNeedUpdate = true;
+				geometry.addAttribute( 'uv', THREE.Float32Attribute( buffer.uvs, 2 ) );
+
+			}
+
+			if ( buffer.colors.length > 0 ) {
+
+				geometry.addAttribute( 'color', THREE.Float32Attribute( buffer.colors, 3 ) );
 
 			}
 
@@ -325,61 +341,42 @@ THREE.PLYLoader.prototype = {
 
 		}
 
-		function handleElement( geometry, elementName, element ) {
+		function handleElement( buffer, elementName, element ) {
 
-			if ( elementName === "vertex" ) {
+			if ( elementName === 'vertex' ) {
 
-				geometry.vertices.push(
-					new THREE.Vector3( element.x, element.y, element.z )
-				);
+				buffer.vertices.push( element.x, element.y, element.z );
 
-				if ( 'red' in element && 'green' in element && 'blue' in element ) {
+				if ( 'nx' in element && 'ny' in element && 'nz' in element ) {
+
+					buffer.normals.push( element.nx, element.ny, element.nz );
 
-					geometry.useColor = true;
+				}
+
+				if ( 's' in element && 't' in element ) {
 
-					var color = new THREE.Color();
-					color.setRGB( element.red / 255.0, element.green / 255.0, element.blue / 255.0 );
-					geometry.colors.push( color );
+					buffer.uvs.push( element.s, element.t );
 
 				}
 
-			} else if ( elementName === "face" ) {
+				if ( 'red' in element && 'green' in element && 'blue' in element ) {
 
-				var vertex_indices = element.vertex_indices;
-				var texcoord = element.texcoord;
+					buffer.colors.push( element.red / 255.0, element.green / 255.0, element.blue / 255.0 );
 
-				if ( vertex_indices.length === 3 ) {
+				}
 
-					geometry.faces.push(
-						new THREE.Face3( vertex_indices[ 0 ], vertex_indices[ 1 ], vertex_indices[ 2 ] )
-					);
+			} else if ( elementName === 'face' ) {
 
-					if ( texcoord ) {
-						geometry.faceVertexUvs[ 0 ].push( [
-							new THREE.Vector2( texcoord[ 0 ], texcoord[ 1 ]),
-							new THREE.Vector2( texcoord[ 2 ], texcoord[ 3 ]),
-							new THREE.Vector2( texcoord[ 4 ], texcoord[ 5 ])
-						] );
-					}
+				var vertex_indices = element.vertex_indices || element.vertex_index; // issue #9338
+
+				if ( vertex_indices.length === 3 ) {
+
+					buffer.indices.push( vertex_indices[ 0 ], vertex_indices[ 1 ], vertex_indices[ 2 ] );
 
 				} else if ( vertex_indices.length === 4 ) {
 
-					geometry.faces.push(
-						new THREE.Face3( vertex_indices[ 0 ], vertex_indices[ 1 ], vertex_indices[ 3 ] ),
-						new THREE.Face3( vertex_indices[ 1 ], vertex_indices[ 2 ], vertex_indices[ 3 ] )
-					);
-
-					if ( texcoord ) {
-						geometry.faceVertexUvs[ 0 ].push( [
-							new THREE.Vector2( texcoord[ 0 ], texcoord[ 1 ]),
-							new THREE.Vector2( texcoord[ 2 ], texcoord[ 3 ]),
-							new THREE.Vector2( texcoord[ 6 ], texcoord[ 7 ])
-						], [
-							new THREE.Vector2( texcoord[ 2 ], texcoord[ 3 ]),
-							new THREE.Vector2( texcoord[ 4 ], texcoord[ 5 ]),
-							new THREE.Vector2( texcoord[ 6 ], texcoord[ 7 ])
-						] );
-					}
+					buffer.indices.push( vertex_indices[ 0 ], vertex_indices[ 1 ], vertex_indices[ 3 ] );
+					buffer.indices.push( vertex_indices[ 1 ], vertex_indices[ 2 ], vertex_indices[ 3 ] );
 
 				}
 
@@ -412,7 +409,7 @@ THREE.PLYLoader.prototype = {
 
 			for ( var i = 0; i < properties.length; i ++ ) {
 
-				if ( properties[ i ].type === "list" ) {
+				if ( properties[ i ].type === 'list' ) {
 
 					var list = [];
 
@@ -446,10 +443,16 @@ THREE.PLYLoader.prototype = {
 
 		function parseBinary( data ) {
 
-			var geometry = new THREE.Geometry();
+			var buffer = {
+				indices : [],
+				vertices : [],
+				normals : [],
+				uvs : [],
+				colors : []
+			};
 
 			var header = parseHeader( bin2str( data ) );
-			var little_endian = ( header.format === "binary_little_endian" );
+			var little_endian = ( header.format === 'binary_little_endian' );
 			var body = new DataView( data, header.headerLength );
 			var result, loc = 0;
 
@@ -461,20 +464,18 @@ THREE.PLYLoader.prototype = {
 					loc += result[ 1 ];
 					var element = result[ 0 ];
 
-					handleElement( geometry, header.elements[ currentElement ].name, element );
+					handleElement( buffer, header.elements[ currentElement ].name, element );
 
 				}
 
 			}
 
-			return postProcess( geometry );
+			return postProcess( buffer );
 
 		}
 
 		//
 
-		console.time( 'PLYLoader' );
-
 		var geometry;
 		var scope = this;
 
@@ -488,8 +489,6 @@ THREE.PLYLoader.prototype = {
 
 		}
 
-		console.timeEnd( 'PLYLoader' );
-
 		return geometry;
 
 	}

+ 193 - 0
examples/js/loaders/TTFLoader.js

@@ -0,0 +1,193 @@
+/**
+ * @author gero3 / https://github.com/gero3
+ * @author tentone / https://github.com/tentone
+ * Requires opentype.js to be included in the project
+ * Loads TTF files and converts them into typeface JSON that can be used directly
+ * to create THREE.Font objects
+ */
+
+'use strict';
+
+THREE.TTFLoader = function ( manager ) {
+
+	this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
+	this.reversed = false;
+
+};
+
+THREE.TTFLoader.prototype.load = function ( url, onLoad, onProgress, onError ) {
+
+	var scope = this;
+
+	var loader = new THREE.XHRLoader( this.manager );
+	loader.setResponseType( 'arraybuffer' );
+	loader.load( url, function ( buffer ) {
+
+		if ( onLoad !== undefined ) {
+
+			onLoad( scope.parse( buffer ) );
+
+		}
+
+	}, onProgress, onError );
+
+};
+
+THREE.TTFLoader.prototype.parse = function ( arraybuffer ) {
+
+	if ( typeof opentype === 'undefined' ) {
+
+		console.warn( 'TTFLoader requires opentype.js Make sure it\'s included before using the loader' );
+		return null;
+
+	}
+
+	function convert( font, reversed ) {
+
+		var round = Math.round;
+
+		var glyphs = {};
+		var scale = ( 100000 ) / ( ( font.unitsPerEm || 2048 ) * 72 );
+
+		for ( var i = 0; i < font.glyphs.length; i ++ ) {
+
+			var glyph = font.glyphs.glyphs[ i ];
+
+			if ( glyph.unicode !== undefined ) {
+
+				var token = {
+					ha: round( glyph.advanceWidth * scale ),
+					x_min: round( glyph.xMin * scale ),
+					x_max: round( glyph.xMax * scale ),
+					o: ''
+				};
+
+				if ( reversed ) {
+
+					glyph.path.commands = reverseCommands( glyph.path.commands );
+
+				}
+
+				glyph.path.commands.forEach( function ( command, i ) {
+
+					if ( command.type.toLowerCase() === 'c' ) {
+
+						command.type = 'b';
+
+					}
+
+					token.o += command.type.toLowerCase() + ' ';
+
+					if ( command.x !== undefined && command.y !== undefined ) {
+
+						token.o += round( command.x * scale ) + ' ' + round( command.y * scale ) + ' ';
+
+					}
+
+					if ( command.x1 !== undefined && command.y1 !== undefined ) {
+
+						token.o += round( command.x1 * scale ) + ' ' + round( command.y1 * scale ) + ' ';
+
+					}
+
+					if ( command.x2 !== undefined && command.y2 !== undefined ) {
+
+						token.o += round( command.x2 * scale ) + ' ' + round( command.y2 * scale ) + ' ';
+
+					}
+
+				} );
+
+				glyphs[ String.fromCharCode( glyph.unicode ) ] = token;
+
+			}
+
+		}
+
+		return {
+			glyphs: glyphs,
+
+			familyName: font.familyName,
+			ascender: round( font.ascender * scale ),
+			descender: round( font.descender * scale ),
+			underlinePosition: font.tables.post.underlinePosition,
+			underlineThickness: font.tables.post.underlineThickness,
+			boundingBox: {
+				xMin: font.tables.head.xMin,
+				xMax: font.tables.head.xMax,
+				yMin: font.tables.head.yMin,
+				yMax: font.tables.head.yMax
+			},
+
+			resolution: 1000,
+			original_font_information: font.tables.name
+		};
+
+	}
+
+	function reverseCommands( commands ) {
+
+		var paths = [];
+		var path;
+
+		commands.forEach( function ( c ) {
+
+			if ( c.type.toLowerCase() === 'm' ) {
+
+				path = [ c ];
+				paths.push( path );
+
+			} else if ( c.type.toLowerCase() !== 'z' ) {
+
+				path.push( c );
+
+			}
+
+		} );
+
+		var reversed = [];
+
+		paths.forEach( function ( p ) {
+
+			var result = {
+				type: 'm',
+				x: p[ p.length - 1 ].x,
+				y: p[ p.length - 1 ].y
+			};
+
+			reversed.push( result );
+
+			for ( var i = p.length - 1; i > 0; i -- ) {
+
+				var command = p[ i ];
+				var result = { type: command.type };
+
+				if ( command.x2 !== undefined && command.y2 !== undefined ) {
+
+					result.x1 = command.x2;
+					result.y1 = command.y2;
+					result.x2 = command.x1;
+					result.y2 = command.y1;
+
+				} else if ( command.x1 !== undefined && command.y1 !== undefined ) {
+
+					result.x1 = command.x1;
+					result.y1 = command.y1;
+
+				}
+
+				result.x = p[ i - 1 ].x;
+				result.y = p[ i - 1 ].y;
+				reversed.push( result );
+
+			}
+
+		} );
+
+		return reversed;
+
+	}
+
+	return convert( opentype.parse( arraybuffer ), this.reversed );
+
+};

+ 0 - 0
examples/js/loaders/gltf/glTF-parser.js → examples/js/loaders/deprecated/gltf/glTF-parser.js


+ 0 - 0
examples/js/loaders/gltf/glTFAnimation.js → examples/js/loaders/deprecated/gltf/glTFAnimation.js


+ 53 - 23
examples/js/loaders/gltf/glTFLoader.js → examples/js/loaders/deprecated/gltf/glTFLoader.js

@@ -268,7 +268,13 @@ THREE.glTFLoader.prototype.load = function( url, callback ) {
 			return texture;
 		}
 
-		return new THREE.TextureLoader().load(src);
+		var textureLoader = THREE.Loader.Handlers.get(src);
+		if ( textureLoader === null ) {
+			textureLoader = new THREE.TextureLoader();
+		}
+		textureLoader.crossOrigin = true;
+
+		return textureLoader.load(src);
 	}
 
 	function CreateTexture(resources, resource) {
@@ -299,13 +305,13 @@ THREE.glTFLoader.prototype.load = function( url, callback ) {
 		var texture = LoadTexture(texturePath);
 		if (texture && textureParams) {
 
-			if (textureParams.wrapS == WebGLRenderingContext.REPEAT)
+			if (textureParams.wrapS == THREE.GLTFLoaderUtils.WEBGL_CONSTANTS.REPEAT)
 				texture.wrapS = THREE.RepeatWrapping;
 
-			if (textureParams.wrapT == WebGLRenderingContext.REPEAT)
+			if (textureParams.wrapT == THREE.GLTFLoaderUtils.WEBGL_CONSTANTS.REPEAT)
 				texture.wrapT = THREE.RepeatWrapping;
 
-			if (textureParams.magFilter == WebGLRenderingContext.LINEAR)
+			if (textureParams.magFilter == THREE.GLTFLoaderUtils.WEBGL_CONSTANTS.LINEAR)
 				texture.magFilter = THREE.LinearFilter;
 
 //                  if (textureParams.minFilter == "LINEAR")
@@ -818,7 +824,7 @@ THREE.glTFLoader.prototype.load = function( url, callback ) {
 
 
 						switch (ptype) {
-							case WebGLRenderingContext.FLOAT :
+							case THREE.GLTFLoaderUtils.WEBGL_CONSTANTS.FLOAT :
 								utype = "f";
 								uvalue = shaderParam.value;
 								if (pname == "transparency") {
@@ -828,7 +834,7 @@ THREE.glTFLoader.prototype.load = function( url, callback ) {
 									params.transparent = true;
 								}
 								break;
-							case WebGLRenderingContext.FLOAT_VEC2 :
+							case THREE.GLTFLoaderUtils.WEBGL_CONSTANTS.FLOAT_VEC2 :
 								utype = "v2";
 								uvalue = new THREE.Vector2;
 								if (shaderParam && shaderParam.value) {
@@ -839,7 +845,7 @@ THREE.glTFLoader.prototype.load = function( url, callback ) {
 									uvalue.fromArray(value);
 								}
 								break;
-							case WebGLRenderingContext.FLOAT_VEC3 :
+							case THREE.GLTFLoaderUtils.WEBGL_CONSTANTS.FLOAT_VEC3 :
 								utype = "v3";
 								uvalue = new THREE.Vector3;
 								if (shaderParam && shaderParam.value) {
@@ -850,7 +856,7 @@ THREE.glTFLoader.prototype.load = function( url, callback ) {
 									uvalue.fromArray(value);
 								}
 								break;
-							case WebGLRenderingContext.FLOAT_VEC4 :
+							case THREE.GLTFLoaderUtils.WEBGL_CONSTANTS.FLOAT_VEC4 :
 								utype = "v4";
 								uvalue = new THREE.Vector4;
 								if (shaderParam && shaderParam.value) {
@@ -861,11 +867,11 @@ THREE.glTFLoader.prototype.load = function( url, callback ) {
 									uvalue.fromArray(value);
 								}
 								break;
-							case WebGLRenderingContext.FLOAT_MAT2 :
+							case THREE.GLTFLoaderUtils.WEBGL_CONSTANTS.FLOAT_MAT2 :
 								// what to do?
 								console.log("Warning: FLOAT_MAT2");
 								break;
-							case WebGLRenderingContext.FLOAT_MAT3 :
+							case THREE.GLTFLoaderUtils.WEBGL_CONSTANTS.FLOAT_MAT3 :
 								utype = "m3";
 								uvalue = new THREE.Matrix3;
 								if (shaderParam && shaderParam.value) {
@@ -876,7 +882,7 @@ THREE.glTFLoader.prototype.load = function( url, callback ) {
 									uvalue.fromArray(value);
 								}
 								break;
-							case WebGLRenderingContext.FLOAT_MAT4 :
+							case THREE.GLTFLoaderUtils.WEBGL_CONSTANTS.FLOAT_MAT4 :
 								if (pcount !== undefined) {
 									utype = "m4v";
 									uvalue = new Array(pcount);
@@ -908,7 +914,7 @@ THREE.glTFLoader.prototype.load = function( url, callback ) {
 									}
 								}
 								break;
-							case WebGLRenderingContext.SAMPLER_2D :
+							case THREE.GLTFLoaderUtils.WEBGL_CONSTANTS.SAMPLER_2D :
 								utype = "t";
 								uvalue = value ? CreateTexture(this.resources, value) : null;
 								break;
@@ -981,13 +987,36 @@ THREE.glTFLoader.prototype.load = function( url, callback ) {
 						values[prop] = khr_material.values[prop];
 					}
 
+				}
+				else if (material.technique === undefined) {
+
+					materialType = THREE.MeshPhongMaterial;
+
+					if (material.doubleSided)
+					{
+						params.side = THREE.DoubleSide;
+					}
+
+					if (material.transparent)
+					{
+						params.transparent = true;
+					}
+
+					values = {};
+					for (var prop in material.values) {
+						values[prop] = material.values[prop];
+					}
+
 				}
 				else {
-					var technique = material.technique ?
-						this.resources.getEntry(material.technique) :
-						null;
 
-					values = material.values;
+					var technique = this.resources.getEntry(material.technique);
+
+					values = {};
+					for (var prop in material.values) {
+						values[prop] = material.values[prop];
+					}
+
 					var description = technique.description;
 
 					if (++description.refCount > 1) {
@@ -1002,6 +1031,7 @@ THREE.glTFLoader.prototype.load = function( url, callback ) {
 					if (loadshaders) {
 						materialType = Material;
 					}
+
 				}
 
 				if (values.diffuse && typeof(values.diffuse) == 'string') {
@@ -1091,7 +1121,7 @@ THREE.glTFLoader.prototype.load = function( url, callback ) {
 				for (var i = 0 ; i < primitivesDescription.length ; i++) {
 					var primitiveDescription = primitivesDescription[i];
 
-					if (primitiveDescription.mode === WebGLRenderingContext.TRIANGLES) {
+					if (primitiveDescription.mode === THREE.GLTFLoaderUtils.WEBGL_CONSTANTS.TRIANGLES) {
 
 						var geometry = new ClassicGeometry();
 						var materialEntry = this.resources.getEntry(primitiveDescription.material);
@@ -1870,16 +1900,16 @@ THREE.glTFLoader.prototype.load = function( url, callback ) {
 
 	var self = this;
 
-	var loader = Object.create(ThreeGLTFLoader);
-	loader.initWithPath(url);
-	loader.load(new Context(rootObj,
+	this.callback = callback;
+	this.rootObj = rootObj;
+
+	this.loader = Object.create(ThreeGLTFLoader);
+	this.loader.initWithPath(url);
+	this.loader.load(new Context(rootObj,
 						function(obj) {
 						}),
 				null);
 
-	this.loader = loader;
-	this.callback = callback;
-	this.rootObj = rootObj;
 	return rootObj;
 }
 

+ 39 - 23
examples/js/loaders/gltf/glTFLoaderUtils.js → examples/js/loaders/deprecated/gltf/glTFLoaderUtils.js

@@ -5,18 +5,34 @@
 THREE.GLTFLoaderUtils = Object.create(Object, {
 
     // errors
-    MISSING_DESCRIPTION: { value: "MISSING_DESCRIPTION" },
-    INVALID_PATH: { value: "INVALID_PATH" },
-    INVALID_TYPE: { value: "INVALID_TYPE" },
+    INVALID_PATH_ERROR: { value: "INVALID_PATH" },
+    INVALID_TYPE_ERROR: { value: "INVALID_TYPE" },
     XMLHTTPREQUEST_STATUS_ERROR: { value: "XMLHTTPREQUEST_STATUS_ERROR" },
-    NOT_FOUND: { value: "NOT_FOUND" },
     // misc constants
     ARRAY_BUFFER: { value: "ArrayBuffer" },
+    // webgl constants (from https://www.opengl.org/registry/api/GL/glcorearb.h)
+    WEBGL_CONSTANTS: {
+        value: {
+            FLOAT: 5126,
+            FLOAT_MAT2: 35674,
+            FLOAT_MAT3: 35675,
+            FLOAT_MAT4: 35676,
+            FLOAT_VEC2: 35664,
+            FLOAT_VEC3: 35665,
+            FLOAT_VEC4: 35666,
+            LINEAR: 9729,
+            REPEAT: 10497,
+            SAMPLER_2D: 35678,
+            TRIANGLES: 4,
+            UNSIGNED_BYTE: 5121,
+            UNSIGNED_SHORT: 5123
+        }
+    },
 
     _streams : { value:{}, writable: true },
 
     _streamsStatus: { value: {}, writable: true },
-    
+
     _resources: { value: {}, writable: true },
 
     _resourcesStatus: { value: {}, writable: true },
@@ -123,18 +139,18 @@ THREE.GLTFLoaderUtils = Object.create(Object, {
             var self = this;
 
             if (!type) {
-                delegate.handleError(THREE.GLTFLoaderUtils.INVALID_TYPE, null);
+                delegate.handleError(THREE.GLTFLoaderUtils.INVALID_TYPE_ERROR, null);
                 return;
             }
 
             if (!path) {
-                delegate.handleError(THREE.GLTFLoaderUtils.INVALID_PATH);
+                delegate.handleError(THREE.GLTFLoaderUtils.INVALID_PATH_ERROR);
                 return;
             }
 
             var xhr = new XMLHttpRequest();
             xhr.open('GET', path, true);
-            xhr.responseType = (type === this.ARRAY_BUFFER) ? "arraybuffer" : "text";
+            xhr.responseType = (type === THREE.GLTFLoaderUtils.ARRAY_BUFFER) ? "arraybuffer" : "text";
 
             //if this is not specified, 1 "big blob" scenes fails to load.
             xhr.setRequestHeader("If-Modified-Since", "Sat, 01 Jan 1970 00:00:00 GMT");
@@ -165,16 +181,16 @@ THREE.GLTFLoaderUtils = Object.create(Object, {
             {
             	this._resourcesStatus[request.id] = 1;
             }
-            
+
             var streamStatus = this._streamsStatus[request.uri];
             if (streamStatus && streamStatus.status === "loading" )
             {
             	streamStatus.requests.push(request);
                 return;
             }
-            
+
             this._streamsStatus[request.uri] = { status : "loading", requests : [request] };
-    		
+
             var self = this;
             var processResourceDelegate = {};
 
@@ -189,7 +205,7 @@ THREE.GLTFLoaderUtils = Object.create(Object, {
                     --self._resourcesStatus[req_.id];
 
                 }, this);
-            	
+
                 delete self._streamsStatus[path];
 
             };
@@ -205,9 +221,9 @@ THREE.GLTFLoaderUtils = Object.create(Object, {
 
     _elementSizeForGLType: {
         value: function(componentType, type) {
-    	
+
     		var nElements = 0;
-    		switch(type) {    		
+    		switch(type) {
 	            case "SCALAR" :
 	                nElements = 1;
 	                break;
@@ -233,13 +249,13 @@ THREE.GLTFLoaderUtils = Object.create(Object, {
 	            	debugger;
 	            	break;
     		}
-    		
+
             switch (componentType) {
-                case WebGLRenderingContext.FLOAT :
+                case THREE.GLTFLoaderUtils.WEBGL_CONSTANTS.FLOAT :
                     return Float32Array.BYTES_PER_ELEMENT * nElements;
-                case WebGLRenderingContext.UNSIGNED_BYTE :
+                case THREE.GLTFLoaderUtils.WEBGL_CONSTANTS.UNSIGNED_BYTE :
                     return Uint8Array.BYTES_PER_ELEMENT * nElements;
-                case WebGLRenderingContext.UNSIGNED_SHORT :
+                case THREE.GLTFLoaderUtils.WEBGL_CONSTANTS.UNSIGNED_SHORT :
                     return Uint16Array.BYTES_PER_ELEMENT * nElements;
                 default :
                 	debugger;
@@ -263,9 +279,9 @@ THREE.GLTFLoaderUtils = Object.create(Object, {
                                     "ctx" : ctx }, null);
         }
     },
-    
+
     getBuffer: {
-    	
+
             value: function(wrappedBufferView, delegate, ctx) {
 
             var savedBuffer = this._getResource(wrappedBufferView.id);
@@ -280,7 +296,7 @@ THREE.GLTFLoaderUtils = Object.create(Object, {
     },
 
     getFile: {
-    	
+
         value: function(request, delegate, ctx) {
 
     		request.delegate = delegate;
@@ -292,8 +308,8 @@ THREE.GLTFLoaderUtils = Object.create(Object, {
                 "type" : "text",
                 "delegate" : delegate,
                 "ctx" : ctx }, null);
-    	
+
             return null;
 	    }
-	},    
+	},
 });

+ 0 - 0
examples/js/loaders/gltf/glTFShaders.js → examples/js/loaders/deprecated/gltf/glTFShaders.js


+ 0 - 0
examples/js/loaders/gltf/gltfUtilities.js → examples/js/loaders/deprecated/gltf/gltfUtilities.js


+ 671 - 656
examples/js/modifiers/BufferSubdivisionModifier.js

@@ -1,778 +1,793 @@
 /*
- *	@author zz85 / http://twitter.com/blurspline / http://www.lab4games.net/zz85/blog 
- *	@author Matthew Adams / http://www.centerionware.com - added UV support and rewrote to use buffergeometry.
+ * @author zz85 / http://twitter.com/blurspline / http://www.lab4games.net/zz85/blog
+ * @author Matthew Adams / http://www.centerionware.com - added UV support and rewrote to use buffergeometry.
  *
- *	Subdivision Geometry Modifier 
- *		using Loop Subdivision Scheme for Geometry / BufferGeometry
+ * Subdivision Geometry Modifier using Loop Subdivision Scheme for Geometry / BufferGeometry
  *
- *	References:
- *		http://graphics.stanford.edu/~mdfisher/subdivision.html
- *		http://www.holmes3d.net/graphics/subdivision/
- *		http://www.cs.rutgers.edu/~decarlo/readings/subdiv-sg00c.pdf
+ * References:
+ *	http://graphics.stanford.edu/~mdfisher/subdivision.html
+ *	http://www.holmes3d.net/graphics/subdivision/
+ *	http://www.cs.rutgers.edu/~decarlo/readings/subdiv-sg00c.pdf
  *
- *	Known Issues:
- *		- currently doesn't handle "Sharp Edges"
- *      - no checks to prevent breaking when uv's don't exist.
- *      - vertex colors are unsupported.
- *     **DDS Images when using corrected uv's passed to subdivision modifier will have their uv's flipy'd within the correct uv set
- *     **Either flipy the DDS image, or use shaders. Don't try correcting the uv's before passing into subdiv (eg: v=1-v).
+ * Known Issues:
+ *	- currently doesn't handle "Sharp Edges"
+ *	- no checks to prevent breaking when uv's don't exist.
+ *	- vertex colors are unsupported.
+ *	**DDS Images when using corrected uv's passed to subdivision modifier will have their uv's flipy'd within the correct uv set
+ *	**Either flipy the DDS image, or use shaders. Don't try correcting the uv's before passing into subdiv (eg: v=1-v).
  *
  * @input THREE.Geometry, or index'd THREE.BufferGeometry with faceUV's (Not vertex uv's)
  * @output non-indexed vertex points, uv's, normals.
- *     
- */
-
-/*
  *
  * The TypedArrayHelper class is designed to assist managing typed arrays, and to allow the removal of all 'new Vector3, new Face3, new Vector2'.
- * 
+ *
  * It will automatically resize them if trying to push a new element to an array that isn't long enough
  * It provides 'registers' that the units can be mapped to. This allows a small set of objects
  * (ex: vector3's, face3's, vector2's) to be allocated then used, to eliminate any need to rewrite all
  * the features those classes offer while not requiring some_huge_number to be allocated.
  * It should be moved into it's own file honestly, then included before the BufferSubdivisionModifier - maybe in three's core?
  *
- *
- * EX: new TypedArrayHelper(initial_size_in_elements, 3, THREE.Vector3, Float32Array, 3, ['x', 'y', 'z']); (the x,y,z comes from THREE.Vector3. It would be abc if it were a face3. etc etc)
- *
  */
-THREE.Face3.prototype.set = function (a, b, c) {
-    this.a = a;
-    this.b = b;
-    this.c = c;
-}
-var TypedArrayHelper = function (size, registers, register_type, array_type, unit_size, accessors) {
-    this.array_type = array_type;
-    this.register_type = register_type;
-    this.unit_size = unit_size;
-    this.accessors = accessors;
-    this.buffer = new array_type(size * unit_size);
-    this.register = [];
-    this.length = 0;
-    this.real_length = size;
-    this.available_registers = registers;
-    for (var i = 0; i < registers; i++) { this.register.push(new register_type()); }
-}
+
+THREE.Face3.prototype.set = function( a, b, c ) {
+
+	this.a = a;
+	this.b = b;
+	this.c = c;
+
+};
+
+var TypedArrayHelper = function( size, registers, register_type, array_type, unit_size, accessors ) {
+
+	this.array_type = array_type;
+	this.register_type = register_type;
+	this.unit_size = unit_size;
+	this.accessors = accessors;
+	this.buffer = new array_type( size * unit_size );
+	this.register = [];
+	this.length = 0;
+	this.real_length = size;
+	this.available_registers = registers;
+
+	for ( var i = 0; i < registers; i++ ) {
+
+		this.register.push( new register_type() );
+
+	}
+
+};
+
 TypedArrayHelper.prototype = {
-    constructor: TypedArrayHelper,
-    index_to_register: function (index, register, isLoop) {
-        var base = index * this.unit_size;
-        if (register >= this.available_registers) {
-            throw ("Nope nope nope, not enough registers!");
-        }
-        if (index > this.length) {
-            throw ("Nope nope nope, index is out of range");
-        }
-        for (var i = 0; i < this.unit_size; i++)
-            (this.register[register])[this.accessors[i]] = this.buffer[base + i];
-
-    },
-    resize: function (new_size) {
-        if (new_size == 0) new_size = 8;
-        if (new_size < this.length) {
-            this.buffer = this.buffer.subarray(0, this.length * this.unit_size);
-        } else {
-            if (this.buffer.length < new_size * this.unit_size) {
-                var nBuffer = new this.array_type(new_size * this.unit_size);
-                nBuffer.set(this.buffer);
-                this.buffer = nBuffer;
-                this.real_length = new_size;
-            } else {
-                var nBuffer = new this.array_type(new_size * this.unit_size);
-                nBuffer.set(this.buffer.subarray(0, this.length * this.unit_size));
-                this.buffer = nBuffer;
-                this.real_length = new_size;
-            }
-        }
-    },
-    from_existing: function (oldArray) {
-        var new_size = oldArray.length;
-        this.buffer = new this.array_type(new_size);//this.resize(oldArray.length);
-        this.buffer.set(oldArray);//.slice(0, oldArray.length));
-        this.length = oldArray.length / this.unit_size;
-        this.real_length = this.length;
-    },
-    push_element: function (vector) {
-        if (this.length + 1 > this.real_length) { this.resize(this.real_length * 2); }
-        var bpos = this.length * this.unit_size;
-        for (var i = 0; i < this.unit_size; i++) {
-            this.buffer[bpos + i] = vector[this.accessors[i]];
-        }
-        this.length++;
-    },
-    trim_size: function () {
-        if (this.length < this.real_length) this.resize(this.length);
-    },
-    each: function (function_pointer, xtra) {
-        if (typeof this.loop_register == 'undefined') this.loop_register = new this.register_type();
-        for (var i = 0; i < this.length; i++) {
-            for (var j = 0; j < this.unit_size; j++)
-                this.loop_register[this.accessors[j]] = this.buffer[i * this.unit_size + j];
-            function_pointer(this.loop_register, i, xtra);
-        }
-    },
-    push_array: function (vector) {
-        if (this.length + 1 > this.real_length) { this.resize(this.real_length * 2); }
-        var bpos = this.length * this.unit_size;
-        for (var i = 0; i < this.unit_size; i++) {
-            this.buffer[bpos + i] = vector[i];
-        }
-        this.length++;
-    }
-}
 
+	constructor: TypedArrayHelper,
+
+	index_to_register: function( index, register, isLoop ) {
+
+		var base = index * this.unit_size;
+
+		if ( register >= this.available_registers ) {
+
+			throw new Error( 'THREE.BufferSubdivisionModifier: Not enough registers in TypedArrayHelper.' );
+
+		}
+
+		if ( index > this.length ) {
+
+			throw new Error( 'THREE.BufferSubdivisionModifier: Index is out of range in TypedArrayHelper.' );
+
+		}
+
+		for ( var i = 0; i < this.unit_size; i++ ) {
+
+			( this.register[ register ] )[ this.accessors[ i ] ] = this.buffer[ base + i ];
+
+		}
+
+	},
+
+	resize: function( new_size ) {
+
+		if ( new_size === 0 ) {
+
+			new_size = 8;
+
+		}
+
+		if ( new_size < this.length ) {
+
+			this.buffer = this.buffer.subarray( 0, this.length * this.unit_size );
+
+		} else {
+
+			var nBuffer;
+
+			if ( this.buffer.length < new_size * this.unit_size ) {
+
+				nBuffer = new this.array_type( new_size * this.unit_size );
+				nBuffer.set( this.buffer );
+				this.buffer = nBuffer;
+				this.real_length = new_size;
+
+			} else {
+
+				nBuffer = new this.array_type( new_size * this.unit_size );
+				nBuffer.set( this.buffer.subarray( 0, this.length * this.unit_size ) );
+				this.buffer = nBuffer;
+				this.real_length = new_size;
+
+			}
+
+		}
+
+	},
+
+	from_existing: function( oldArray ) {
+
+		var new_size = oldArray.length;
+		this.buffer = new this.array_type( new_size );
+		this.buffer.set( oldArray );
+		this.length = oldArray.length / this.unit_size;
+		this.real_length = this.length;
+
+	},
+
+	push_element: function( vector ) {
+
+		if ( this.length + 1 > this.real_length ) {
+
+			this.resize( this.real_length * 2 );
+
+		}
+
+		var bpos = this.length * this.unit_size;
+
+		for ( var i = 0; i < this.unit_size; i++ ) {
+
+			this.buffer[ bpos + i ] = vector[ this.accessors[ i ] ];
+
+		}
+
+		this.length++;
+
+	},
+
+	trim_size: function() {
+
+		if ( this.length < this.real_length ) {
+
+			this.resize( this.length );
+
+		}
+
+	}
+
+};
+
+
+function convertGeometryToIndexedBuffer( geometry ) {
+
+	var BGeom = new THREE.BufferGeometry();
+
+	// create a new typed array
+	var vertArray = new TypedArrayHelper( geometry.vertices.length, 0, THREE.Vector3, Float32Array, 3, [ 'x', 'y', 'z' ] );
+	var indexArray = new TypedArrayHelper( geometry.faces.length, 0, THREE.Face3, Uint32Array, 3, [ 'a', 'b', 'c' ] );
+	var uvArray = new TypedArrayHelper( geometry.faceVertexUvs[0].length * 3 * 3, 0, THREE.Vector2, Float32Array, 2, [ 'x', 'y' ] );
+
+	var i, il;
+
+	for ( i = 0, il = geometry.vertices.length; i < il; i++ ) {
+
+		vertArray.push_element( geometry.vertices[ i ] );
+
+	}
+
+	for ( i = 0, il = geometry.faces.length; i < il; i++ ) {
+
+		indexArray.push_element( geometry.faces[ i ] );
+
+	}
+
+	for ( i = 0, il = geometry.faceVertexUvs[ 0 ].length; i < il; i++ ) {
+
+		uvArray.push_element( geometry.faceVertexUvs[ 0 ][ i ][ 0 ] );
+		uvArray.push_element( geometry.faceVertexUvs[ 0 ][ i ][ 1 ] );
+		uvArray.push_element( geometry.faceVertexUvs[ 0 ][ i ][ 2 ] );
+
+	}
+
+	indexArray.trim_size();
+	vertArray.trim_size();
+	uvArray.trim_size();
+
+	BGeom.setIndex( new THREE.BufferAttribute( indexArray.buffer, 3 ) );
+	BGeom.addAttribute( 'position', new THREE.BufferAttribute( vertArray.buffer, 3 ) );
+	BGeom.addAttribute( 'uv', new THREE.BufferAttribute( uvArray.buffer, 2 ) );
+
+	return BGeom;
 
-function convertGeometryToIndexedBuffer(geometry) {
-    var BGeom = new THREE.BufferGeometry();
-    // create a new typed array
-    var vertArray = new TypedArrayHelper(geometry.vertices.length, 0, THREE.Vector3, Float32Array, 3, ['x', 'y', 'z']);
-    var indexArray = new TypedArrayHelper(geometry.faces.length, 0, THREE.Face3, Uint32Array, 3, ['a', 'b', 'c']);
-    var uvArray = new TypedArrayHelper(geometry.faceVertexUvs[0].length * 3 * 3, 0, THREE.Vector2, Float32Array, 2, ['x', 'y']);
-
-    var i, il;
-    for (i = 0, il = geometry.vertices.length; i < il; i++) vertArray.push_element(geometry.vertices[i]);
-    for (i = 0, il = geometry.faces.length; i < il; i++) indexArray.push_element(geometry.faces[i]);
-    for (i = 0, il = geometry.faceVertexUvs[0].length; i < il; i++) {
-        uvArray.push_element(geometry.faceVertexUvs[0][i][0]);
-        uvArray.push_element(geometry.faceVertexUvs[0][i][1]);
-        uvArray.push_element(geometry.faceVertexUvs[0][i][2]);
-    }
-    indexArray.trim_size();
-    vertArray.trim_size();
-    uvArray.trim_size();
-    BGeom.setIndex(new THREE.BufferAttribute(indexArray.buffer,3));
-    BGeom.addAttribute('position', new THREE.BufferAttribute(vertArray.buffer, 3));
-    BGeom.addAttribute('uv', new THREE.BufferAttribute(uvArray.buffer, 2));
-    return BGeom;
-}
-function addNormal(old, newn) {
-   // old.x += newn.x;
-   // old.y += newn.y;
-   // old.z += newn.z;
-    ///*
-    if (old.x == 0) old.x = newn.x;
-    else old.x = (old.x + newn.x) / 2;
-    if (old.y == 0) old.y = newn.y;
-    else old.y = (old.y + newn.y) / 2;
-    if (old.z == 0) old.z = newn.z;
-    else old.z = (old.z + newn.z) / 2;
-   // */
-}
-function findArea(a, b, c) {
-    return Math.abs(((a.x * (b.y - c.y)) + (b.x * (c.y - a.y)) + (c.x * (a.y - b.y))) / 2.0);
-}
-function find_angle3d(A, B, C) {
-    var AB = Math.sqrt(Math.pow(B.x - A.x, 2) + Math.pow(B.y - A.y, 2));
-    var BC = Math.sqrt(Math.pow(B.x - C.x, 2) + Math.pow(B.y - C.y, 2));
-    var AC = Math.sqrt(Math.pow(C.x - A.x, 2) + Math.pow(C.y - A.y, 2));
-    return Math.acos((BC * BC + AB * AB - AC * AC) / (2 * BC * AB));
-}
-function find_angle2d(p1,p2) {
-    return Math.atan2(p2.y - p1.y, p2.x - p1.x);
 }
-function compute_vertex_normals(geometry) {
-    var ABC = ['a', 'b', 'c'];
-    var XYZ = ['x', 'y', 'z'];
-    var XY = ['x', 'y'];
-    var oldVertices = new TypedArrayHelper(0, 5, THREE.Vector3, Float32Array, 3, XYZ);
-    var oldFaces = new TypedArrayHelper(0, 3, THREE.Face3, Uint32Array, 3, ABC);
-    oldVertices.from_existing(geometry.getAttribute('position').array);
-    var newNormals = new TypedArrayHelper(oldVertices.length * 3, 4, THREE.Vector3, Float32Array, 3, XYZ);
-    
-    var newNormalFaces = new TypedArrayHelper(oldVertices.length, 1, function () { this.x = 0; }, Float32Array, 1, ['x']);
-    
-    newNormals.length = oldVertices.length;
-    var a, b, c;
-    oldFaces.from_existing(geometry.index.array);
-    var j, jl;
-    var k,l;
-    var my_weight;
-    var full_weights = [0.0,0.0,0.0];
-
-    for (var i = 0, il = oldFaces.length; i < il; i++) {
-        oldFaces.index_to_register(i, 0);
-        oldVertices.index_to_register(oldFaces.register[0].a, 0);
-        oldVertices.index_to_register(oldFaces.register[0].b, 1);
-        oldVertices.index_to_register(oldFaces.register[0].c, 2);
-        newNormals.register[0].subVectors(oldVertices.register[1], oldVertices.register[0]);
-        newNormals.register[1].subVectors(oldVertices.register[2], oldVertices.register[1]);
-        newNormals.register[0].cross(newNormals.register[1]);
-        my_weight = Math.abs(newNormals.register[0].length());
-        //my_weight = findArea(oldVertices.register[0], oldVertices.register[1], oldVertices.register[2]);
-        newNormalFaces.buffer[oldFaces.register[0].a] += my_weight;
-        newNormalFaces.buffer[oldFaces.register[0].b] += my_weight;
-        newNormalFaces.buffer[oldFaces.register[0].c] += my_weight;
-    }
-    var tmpx;
-    var tmpy;
-    var tmpz;
-    var t_len;
-    for (var i = 0, il = oldFaces.length; i < il; i++) {
-        oldFaces.index_to_register(i, 0);
-        oldVertices.index_to_register(oldFaces.register[0].a, 0);
-        oldVertices.index_to_register(oldFaces.register[0].b, 1);
-        oldVertices.index_to_register(oldFaces.register[0].c, 2);
-
-        newNormals.register[0].subVectors(oldVertices.register[1], oldVertices.register[0]);
-        newNormals.register[1].subVectors(oldVertices.register[2], oldVertices.register[0]);
-/*
-      //  newNormals.register[0].cross(newNormals.register[1]);
-
-        newNormals.register[3].copy(newNormals.register[0]);//(a, b, c);
-
-        t_len = (newNormals.register[3].x + newNormals.register[3].y + newNormals.register[3].z);
-        newNormals.register[3].x = newNormals.register[3].x / t_len;
-        newNormals.register[3].y = newNormals.register[3].y / t_len;
-        newNormals.register[3].z = newNormals.register[3].z / t_len;
-*/
-        newNormals.register[3].set(0,0,0);
-        newNormals.register[3].x = (newNormals.register[0].y*newNormals.register[1].z )-(newNormals.register[0].z*newNormals.register[1].y);
-        newNormals.register[3].y = (newNormals.register[0].z*newNormals.register[1].x )-(newNormals.register[0].x*newNormals.register[1].z);
-        newNormals.register[3].z = (newNormals.register[0].x*newNormals.register[1].y )-(newNormals.register[0].y*newNormals.register[1].x);
-         
-	newNormals.register[0].cross(newNormals.register[1]);
-
-
-
-        my_weight = Math.abs(newNormals.register[0].length() );
-       // oldVertices.register[3].subVectors(oldVertices.register[2],oldVertices.register[0]);
-       // oldVertices.register[4].subVectors(oldVertices.register[2],oldVertices.register[1]);
-       // var angle = find_angle2d(oldVertices.register[3],oldVertices.register[4]);
-        full_weights[0] = (my_weight / newNormalFaces.buffer[oldFaces.register[0].a]) ;
-        full_weights[1] = (my_weight / newNormalFaces.buffer[oldFaces.register[0].b]) ;
-        full_weights[2] = (my_weight / newNormalFaces.buffer[oldFaces.register[0].c]) ;
-        tmpx = newNormals.register[3].x * full_weights[0];
-        tmpy = newNormals.register[3].y * full_weights[0];
-        tmpz = newNormals.register[3].z * full_weights[0];
-        
-        newNormals.buffer[ oldFaces.register[0].a * 3     ] += newNormals.register[3].x * full_weights[0];
-        newNormals.buffer[(oldFaces.register[0].a * 3) + 1] += newNormals.register[3].y * full_weights[0];
-        newNormals.buffer[(oldFaces.register[0].a * 3) + 2] += newNormals.register[3].z * full_weights[0];
-
-        newNormals.buffer[ oldFaces.register[0].b * 3     ] += newNormals.register[3].x * full_weights[1];
-        newNormals.buffer[(oldFaces.register[0].b * 3) + 1] += newNormals.register[3].y * full_weights[1];
-        newNormals.buffer[(oldFaces.register[0].b * 3) + 2] += newNormals.register[3].z * full_weights[1];
-
-        newNormals.buffer[ oldFaces.register[0].c * 3     ] += newNormals.register[3].x * full_weights[2];
-        newNormals.buffer[(oldFaces.register[0].c * 3) + 1] += newNormals.register[3].y * full_weights[2];
-        newNormals.buffer[(oldFaces.register[0].c * 3) + 2] += newNormals.register[3].z * full_weights[2];
-/*
 
-        newNormals.index_to_register(oldFaces.register[0].a, 0);
-        newNormals.index_to_register(oldFaces.register[0].b, 1);
-        newNormals.index_to_register(oldFaces.register[0].c, 2);
-
-        addNormal(newNormals.register[3], newNormals.register[0]);
-        addNormal(newNormals.register[3], newNormals.register[1]);
-        addNormal(newNormals.register[3], newNormals.register[2]);
-
-        newNormals.buffer[oldFaces.register[0].a * 3] = newNormals.register[3].x;
-        newNormals.buffer[(oldFaces.register[0].a * 3)+1] = newNormals.register[3].y;
-        newNormals.buffer[(oldFaces.register[0].a * 3) + 2] = newNormals.register[3].z;
-
-        newNormals.buffer[oldFaces.register[0].b * 3] = newNormals.register[3].x;
-        newNormals.buffer[(oldFaces.register[0].b * 3) + 1] = newNormals.register[3].y;
-        newNormals.buffer[(oldFaces.register[0].b * 3) + 2] = newNormals.register[3].z;
-
-        newNormals.buffer[oldFaces.register[0].c * 3] = newNormals.register[3].x;
-        newNormals.buffer[(oldFaces.register[0].c * 3) + 1] = newNormals.register[3].y;
-        newNormals.buffer[(oldFaces.register[0].c * 3) + 2] = newNormals.register[3].z;
-        */
-      //  newNormalFaces[oldFaces.register[0].a] += 1;
-    //    newNormalFaces[oldFaces.register[0].b] += 1;
-     //   newNormalFaces[oldFaces.register[0].c] += 1;
-
-    }
-   // for (var i = 0, il = newNormalFaces.length; i < i; i++) {
-   //     newNormals.buffer[(i * 3)] = newNormals.buffer[(i * 3)] / newNormalFaces.buffer[i];
-  //      newNormals.buffer[(i * 3)+1] = newNormals.buffer[(i * 3)+1] / newNormalFaces.buffer[i];
-   //     newNormals.buffer[(i * 3)+2] = newNormals.buffer[(i * 3)+2] / newNormalFaces.buffer[i];
-
-    // }
-    newNormals.trim_size();
-    geometry.addAttribute('normal', new THREE.BufferAttribute(newNormals.buffer, 3));
+function compute_vertex_normals( geometry ) {
+
+	var ABC = [ 'a', 'b', 'c' ];
+	var XYZ = [ 'x', 'y', 'z' ];
+	var XY = [ 'x', 'y' ];
+
+	var oldVertices = new TypedArrayHelper( 0, 5, THREE.Vector3, Float32Array, 3, XYZ );
+	var oldFaces = new TypedArrayHelper( 0, 3, THREE.Face3, Uint32Array, 3, ABC );
+	oldVertices.from_existing( geometry.getAttribute( 'position' ).array );
+	var newNormals = new TypedArrayHelper( oldVertices.length * 3, 4, THREE.Vector3, Float32Array, 3, XYZ );
+	var newNormalFaces = new TypedArrayHelper( oldVertices.length, 1, function () { this.x = 0; }, Float32Array, 1, [ 'x' ] );
+
+	newNormals.length = oldVertices.length;
+	oldFaces.from_existing( geometry.index.array );
+	var a, b, c;
+	var i, j, jl;
+	var my_weight;
+	var full_weights = [ 0.0, 0.0, 0.0 ];
+
+	for ( i = 0, il = oldFaces.length; i < il; i++ ) {
+
+		oldFaces.index_to_register( i, 0 );
+
+		oldVertices.index_to_register( oldFaces.register[ 0 ].a, 0 );
+		oldVertices.index_to_register( oldFaces.register[ 0 ].b, 1 );
+		oldVertices.index_to_register( oldFaces.register[ 0 ].c, 2 );
+
+		newNormals.register[ 0 ].subVectors( oldVertices.register[ 1 ], oldVertices.register[ 0 ] );
+		newNormals.register[ 1 ].subVectors( oldVertices.register[ 2 ], oldVertices.register[ 1 ] );
+		newNormals.register[ 0 ].cross( newNormals.register[ 1 ] );
+		my_weight = Math.abs( newNormals.register[ 0 ].length() );
+
+		newNormalFaces.buffer[ oldFaces.register[ 0 ].a ] += my_weight;
+		newNormalFaces.buffer[ oldFaces.register[ 0 ].b ] += my_weight;
+		newNormalFaces.buffer[ oldFaces.register[ 0 ].c ] += my_weight;
+
+	}
+
+	var tmpx, tmpy, tmpz;
+	var t_len;
+
+	for ( i = 0, il = oldFaces.length; i < il; i++ ) {
+
+		oldFaces.index_to_register( i, 0 );
+		oldVertices.index_to_register( oldFaces.register[ 0 ].a, 0 );
+		oldVertices.index_to_register( oldFaces.register[ 0 ].b, 1 );
+		oldVertices.index_to_register( oldFaces.register[ 0 ].c, 2 );
+
+		newNormals.register[ 0 ].subVectors( oldVertices.register[ 1 ], oldVertices.register[ 0 ] );
+		newNormals.register[ 1 ].subVectors( oldVertices.register[ 2 ], oldVertices.register[ 0 ] );
+
+		newNormals.register[ 3 ].set( 0, 0, 0 );
+		newNormals.register[ 3 ].x = ( newNormals.register[ 0 ].y * newNormals.register[ 1 ].z ) - ( newNormals.register[ 0 ].z * newNormals.register[ 1 ].y );
+		newNormals.register[ 3 ].y = ( newNormals.register[ 0 ].z * newNormals.register[ 1 ].x ) - ( newNormals.register[ 0 ].x * newNormals.register[ 1 ].z );
+		newNormals.register[ 3 ].z = ( newNormals.register[ 0 ].x * newNormals.register[ 1 ].y ) - ( newNormals.register[ 0 ].y * newNormals.register[ 1 ].x );
+
+		newNormals.register[ 0 ].cross( newNormals.register[ 1 ] );
+
+		my_weight = Math.abs( newNormals.register[ 0 ].length() );
+
+		full_weights[ 0 ] = ( my_weight / newNormalFaces.buffer[ oldFaces.register[ 0 ].a ] );
+		full_weights[ 1 ] = ( my_weight / newNormalFaces.buffer[ oldFaces.register[ 0 ].b ] );
+		full_weights[ 2 ] = ( my_weight / newNormalFaces.buffer[ oldFaces.register[ 0 ].c ] );
+
+		tmpx = newNormals.register[ 3 ].x * full_weights[ 0 ];
+		tmpy = newNormals.register[ 3 ].y * full_weights[ 0 ];
+		tmpz = newNormals.register[ 3 ].z * full_weights[ 0 ];
+
+		newNormals.buffer[ ( oldFaces.register[ 0 ].a * 3 ) + 0 ] += newNormals.register[ 3 ].x * full_weights[ 0 ];
+		newNormals.buffer[ ( oldFaces.register[ 0 ].a * 3 ) + 1 ] += newNormals.register[ 3 ].y * full_weights[ 0 ];
+		newNormals.buffer[ ( oldFaces.register[ 0 ].a * 3 ) + 2 ] += newNormals.register[ 3 ].z * full_weights[ 0 ];
+
+		newNormals.buffer[ ( oldFaces.register[ 0 ].b * 3 ) + 0 ] += newNormals.register[ 3 ].x * full_weights[ 1 ];
+		newNormals.buffer[ ( oldFaces.register[ 0 ].b * 3 ) + 1 ] += newNormals.register[ 3 ].y * full_weights[ 1 ];
+		newNormals.buffer[ ( oldFaces.register[ 0 ].b * 3 ) + 2 ] += newNormals.register[ 3 ].z * full_weights[ 1 ];
+
+		newNormals.buffer[ ( oldFaces.register[ 0 ].c * 3 ) + 0 ] += newNormals.register[ 3 ].x * full_weights[ 2 ];
+		newNormals.buffer[ ( oldFaces.register[ 0 ].c * 3 ) + 1 ] += newNormals.register[ 3 ].y * full_weights[ 2 ];
+		newNormals.buffer[ ( oldFaces.register[ 0 ].c * 3 ) + 2 ] += newNormals.register[ 3 ].z * full_weights[ 2 ];
+
+	}
+
+	newNormals.trim_size();
+	geometry.addAttribute( 'normal', new THREE.BufferAttribute( newNormals.buffer, 3 ) );
+
 }
-function unIndexIndexedGeometry(geometry) {
-    
-    var ABC = ['a', 'b', 'c'];
-    var XYZ = ['x', 'y', 'z'];
-    var XY = ['x', 'y'];
-
-
-    var oldVertices = new TypedArrayHelper(0, 3, THREE.Vector3, Float32Array, 3, XYZ);
-    var oldFaces = new TypedArrayHelper(0, 3, THREE.Face3, Uint32Array, 3, ABC);
-    var oldUvs = new TypedArrayHelper(0, 3, THREE.Vector2, Float32Array, 2, XY);
-    var oldNormals = new TypedArrayHelper(0, 3, THREE.Vector3, Float32Array, 3, XYZ);
-    oldVertices.from_existing(geometry.getAttribute('position').array);
-    oldFaces.from_existing(geometry.index.array);
-    oldUvs.from_existing(geometry.getAttribute('uv').array);
-   // geometry.computeFaceNormals();
-    // geometry.computeVertexNormals();
-    compute_vertex_normals(geometry);
-    oldNormals.from_existing(geometry.getAttribute('normal').array);
-
-    var newVertices = new TypedArrayHelper(oldFaces.length * 3, 3, THREE.Vector3, Float32Array, 3, XYZ);
-    var newNormals = new TypedArrayHelper(oldFaces.length * 3, 3, THREE.Vector3, Float32Array, 3, XYZ);
-    var newUvs = new TypedArrayHelper(oldFaces.length * 3, 3, THREE.Vector2, Float32Array, 2, XY);
-    var v, w;
-    for (var i = 0, il = oldFaces.length; i < il; i++) {
-        oldFaces.index_to_register(i, 0);
-        oldVertices.index_to_register(oldFaces.register[0].a, 0);
-        oldVertices.index_to_register(oldFaces.register[0].b, 1);
-        oldVertices.index_to_register(oldFaces.register[0].c, 2);
-
-        newVertices.push_element(oldVertices.register[0]);
-        newVertices.push_element(oldVertices.register[1]);
-        newVertices.push_element(oldVertices.register[2]);
-        if (oldUvs.length != 0) {
-            oldUvs.index_to_register((i * 3) + 0, 0);
-            oldUvs.index_to_register((i * 3) + 1, 1);
-            oldUvs.index_to_register((i * 3) + 2, 2);
-
-            newUvs.push_element(oldUvs.register[0]);
-            newUvs.push_element(oldUvs.register[1]);
-            newUvs.push_element(oldUvs.register[2]);
-        }
-        oldNormals.index_to_register(oldFaces.register[0].a, 0);
-        oldNormals.index_to_register(oldFaces.register[0].b, 1);
-        oldNormals.index_to_register(oldFaces.register[0].c, 2);
-
-        newNormals.push_element(oldNormals.register[0]);
-        newNormals.push_element(oldNormals.register[1]);
-        newNormals.push_element(oldNormals.register[2]);
-        
-     /*   oldVertices.index_to_register(oldFaces.register[0].a, 0);
-        oldVertices.index_to_register(oldFaces.register[0].b, 1);
-        oldVertices.index_to_register(oldFaces.register[0].c, 2);
-        newNormals.register[0].subVectors(oldVertices.register[1], oldVertices.register[0]);
-        newNormals.register[1].subVectors(oldVertices.register[2], oldVertices.register[0]);
-        v = newNormals.register[0];
-        w = newNormals.register[1];
-        newNormals.register[2].x = (v.y * w.z) - (v.z * w.y);
-        newNormals.register[2].y = (v.z * w.x) - (v.x * w.z)
-        newNormals.register[2].z = (v.x * w.y) - (v.y * w.x)
-        newNormals.push_element(newNormals.register[2]);
-        newNormals.push_element(newNormals.register[2]);
-        newNormals.push_element(newNormals.register[2]);?*/
-
-    }
-    newVertices.trim_size();
-    newUvs.trim_size();
-    newNormals.trim_size();
-    geometry.index = null;
-    geometry.addAttribute('position', new THREE.BufferAttribute(newVertices.buffer, 3));
-    geometry.addAttribute('normal', new THREE.BufferAttribute(newNormals.buffer, 3));
-    if(newUvs.length != 0)
-        geometry.addAttribute('uv', new THREE.BufferAttribute(newUvs.buffer, 2));
-  //  geometry.computeVertexNormals();
-    return geometry;
+
+function unIndexIndexedGeometry( geometry ) {
+
+	var ABC = [ 'a', 'b', 'c' ];
+	var XYZ = [ 'x', 'y', 'z' ];
+	var XY = [ 'x', 'y' ];
+
+	var oldVertices = new TypedArrayHelper( 0, 3, THREE.Vector3, Float32Array, 3, XYZ );
+	var oldFaces = new TypedArrayHelper( 0, 3, THREE.Face3, Uint32Array, 3, ABC );
+	var oldUvs = new TypedArrayHelper( 0, 3, THREE.Vector2, Float32Array, 2, XY );
+	var oldNormals = new TypedArrayHelper( 0, 3, THREE.Vector3, Float32Array, 3, XYZ );
+
+	oldVertices.from_existing( geometry.getAttribute( 'position' ).array );
+	oldFaces.from_existing( geometry.index.array );
+	oldUvs.from_existing( geometry.getAttribute( 'uv' ).array );
+
+	compute_vertex_normals( geometry );
+	oldNormals.from_existing( geometry.getAttribute( 'normal' ).array );
+
+	var newVertices = new TypedArrayHelper( oldFaces.length * 3, 3, THREE.Vector3, Float32Array, 3, XYZ );
+	var newNormals = new TypedArrayHelper( oldFaces.length * 3, 3, THREE.Vector3, Float32Array, 3, XYZ );
+	var newUvs = new TypedArrayHelper( oldFaces.length * 3, 3, THREE.Vector2, Float32Array, 2, XY );
+	var v, w;
+
+	for ( var i = 0, il = oldFaces.length; i < il; i++ ) {
+
+		oldFaces.index_to_register( i, 0 );
+
+		oldVertices.index_to_register( oldFaces.register[ 0 ].a, 0 );
+		oldVertices.index_to_register( oldFaces.register[ 0 ].b, 1 );
+		oldVertices.index_to_register( oldFaces.register[ 0 ].c, 2 );
+
+		newVertices.push_element( oldVertices.register[ 0 ] );
+		newVertices.push_element( oldVertices.register[ 1 ] );
+		newVertices.push_element( oldVertices.register[ 2 ] );
+
+			if ( oldUvs.length !== 0 ) {
+
+				oldUvs.index_to_register( ( i * 3 ) + 0, 0 );
+				oldUvs.index_to_register( ( i * 3 ) + 1, 1 );
+				oldUvs.index_to_register( ( i * 3 ) + 2, 2 );
+
+				newUvs.push_element( oldUvs.register[ 0 ] );
+				newUvs.push_element( oldUvs.register[ 1 ] );
+				newUvs.push_element( oldUvs.register[ 2 ] );
+
+			}
+
+		oldNormals.index_to_register( oldFaces.register[ 0 ].a, 0 );
+		oldNormals.index_to_register( oldFaces.register[ 0 ].b, 1 );
+		oldNormals.index_to_register( oldFaces.register[ 0 ].c, 2 );
+
+		newNormals.push_element( oldNormals.register[ 0 ] );
+		newNormals.push_element( oldNormals.register[ 1 ] );
+		newNormals.push_element( oldNormals.register[ 2 ] );
+
+	}
+
+	newVertices.trim_size();
+	newUvs.trim_size();
+	newNormals.trim_size();
+
+	geometry.index = null;
+
+	geometry.addAttribute( 'position', new THREE.BufferAttribute( newVertices.buffer, 3 ) );
+	geometry.addAttribute( 'normal', new THREE.BufferAttribute( newNormals.buffer, 3 ) );
+
+	if ( newUvs.length !== 0 ) {
+
+		geometry.addAttribute( 'uv', new THREE.BufferAttribute( newUvs.buffer, 2 ) );
+
+	}
+
+	return geometry;
+
 }
-THREE.BufferSubdivisionModifier = function (subdivisions) {
 
-    this.subdivisions = (subdivisions === undefined) ? 1 : subdivisions;
-    //this.subdivisions = 3;
+THREE.BufferSubdivisionModifier = function( subdivisions ) {
+
+	this.subdivisions = ( subdivisions === undefined ) ? 1 : subdivisions;
 
 };
 
-// Applies the "modify" pattern
-THREE.BufferSubdivisionModifier.prototype.modify = function (geometry) {
-    
-    if (geometry instanceof THREE.Geometry) {
-        geometry.mergeVertices();
-        if (typeof (geometry.normals) == 'undefined') geometry.normals = [];
-            var BGEom = convertGeometryToIndexedBuffer(geometry);
-            geometry = BGEom;
-        } else if( !(geometry instanceof THREE.BufferGeometry) ) console.log("Geometry is not an instance of THREE.BufferGeometry or THREE.Geometry");
-    
-    var repeats = this.subdivisions;
+THREE.BufferSubdivisionModifier.prototype.modify = function( geometry ) {
+
+	if ( geometry instanceof THREE.Geometry ) {
+
+		geometry.mergeVertices();
+
+		if ( typeof geometry.normals === 'undefined' ) {
+
+			geometry.normals = [];
 
-    while (repeats-- > 0) {
+		}
 
-        this.smooth(geometry);
+		geometry = convertGeometryToIndexedBuffer( geometry );
 
-    }
+	} else if ( !( geometry instanceof THREE.BufferGeometry ) ) {
 
-    return unIndexIndexedGeometry(geometry); // it doesn't change what geometry points to in the function that calls this.. >_<. how annoying.
+		console.error( 'THREE.BufferSubdivisionModifier: Geometry is not an instance of THREE.BufferGeometry or THREE.Geometry' );
+
+	}
+
+	var repeats = this.subdivisions;
+
+	while ( repeats -- > 0 ) {
+
+		this.smooth( geometry );
+
+	}
+
+	return unIndexIndexedGeometry( geometry );
 
 };
-var edge_type = function (a, b) {
-    this.a = a;
-    this.b = b;
-    this.faces = [];
-    this.newEdge = null;
+
+var edge_type = function ( a, b ) {
+
+	this.a = a;
+	this.b = b;
+	this.faces = [];
+	this.newEdge = null;
+
 };
 
-(function () {
+( function () {
+
+	// Some constants
+	var ABC = [ 'a', 'b', 'c' ];
+	var XYZ = [ 'x', 'y', 'z' ];
+	var XY = [ 'x', 'y' ];
+
+	function getEdge( a, b, map ) {
+
+		var key = Math.min( a, b ) + '_' + Math.max( a, b );
+		return map[ key ];
+
+	}
+
+
+	function processEdge( a, b, vertices, map, face, metaVertices ) {
+
+		var vertexIndexA = Math.min( a, b );
+		var vertexIndexB = Math.max( a, b );
+
+		var key = vertexIndexA + '_' + vertexIndexB;
+
+		var edge;
+
+		if ( key in map ) {
+
+			edge = map[ key ];
+
+		} else {
+
+			edge = new edge_type( vertexIndexA,vertexIndexB );
+			map[key] = edge;
+
+		}
+
+		edge.faces.push( face );
+
+		metaVertices[ a ].edges.push( edge );
+		metaVertices[ b ].edges.push( edge );
+
+	}
+
+	function generateLookups( vertices, faces, metaVertices, edges ) {
+
+		var i, il, face, edge;
+
+		for ( i = 0, il = vertices.length; i < il; i++ ) {
+
+			metaVertices[ i ] = { edges: [] };
+
+		}
+
+		for ( i = 0, il = faces.length; i < il; i++ ) {
+
+			faces.index_to_register( i, 0 );
+			face = faces.register[ 0 ]; // Faces is now a TypedArrayHelper class, not a face3.
+
+			processEdge( face.a, face.b, vertices, edges, i, metaVertices );
+			processEdge( face.b, face.c, vertices, edges, i, metaVertices );
+			processEdge( face.c, face.a, vertices, edges, i, metaVertices );
+
+		}
+
+	}
+
+	function newFace( newFaces, face ) {
+
+		newFaces.push_element( face );
+
+	}
+
+	function midpoint( a, b ) {
+
+		return ( Math.abs( b - a ) / 2 ) + Math.min( a, b );
+
+	}
+
+	function newUv( newUvs, a, b, c ) {
+
+		newUvs.push_element( a );
+		newUvs.push_element( b );
+		newUvs.push_element( c );
+
+	}
+
+	/////////////////////////////
+
+	// Performs one iteration of Subdivision
+
+	THREE.BufferSubdivisionModifier.prototype.smooth = function ( geometry ) {
 
-    // Some constants
-    var WARNINGS = ! true; // Set to true for development
-    var ABC = ['a', 'b', 'c'];
-    var XYZ = ['x', 'y', 'z'];
-    var XY = ['x', 'y'];
+		var oldVertices, oldFaces, oldUvs;
+		var newVertices, newFaces, newUVs;
 
-    function getEdge(a, b, map) {
-        var key = Math.min(a, b) + "_" + Math.max(a, b);
-        return map[key];
+		var n, l, i, il, j, k;
+		var metaVertices, sourceEdges;
 
-    }
+		oldVertices = new TypedArrayHelper( 0, 3, THREE.Vector3, Float32Array, 3, XYZ );
+		oldFaces = new TypedArrayHelper( 0, 3, THREE.Face3, Uint32Array, 3, ABC );
+		oldUvs = new TypedArrayHelper( 0, 3, THREE.Vector2, Float32Array, 2, XY );
+		oldVertices.from_existing( geometry.getAttribute( 'position' ).array );
+		oldFaces.from_existing( geometry.index.array );
+		oldUvs.from_existing( geometry.getAttribute( 'uv' ).array );
 
+		var doUvs = false;
 
-    function processEdge(a, b, vertices, map, face, metaVertices) {
+		if ( typeof oldUvs !== 'undefined' && oldUvs.length !== 0 ) {
 
-        var vertexIndexA = Math.min(a, b);
-        var vertexIndexB = Math.max(a, b);
+			doUvs = true;
 
-        var key = vertexIndexA + "_" + vertexIndexB;
+		}
+		/******************************************************
+		*
+		* Step 0: Preprocess Geometry to Generate edges Lookup
+		*
+		*******************************************************/
 
-        var edge;
+		metaVertices = new Array( oldVertices.length );
+		sourceEdges = {}; // Edge => { oldVertex1, oldVertex2, faces[]  }
 
-        if (key in map) {
+		generateLookups( oldVertices, oldFaces, metaVertices, sourceEdges );
 
-            edge = map[key];
 
-        } else {
+		/******************************************************
+		*
+		*	Step 1.
+		*	For each edge, create a new Edge Vertex,
+		*	then position it.
+		*
+		*******************************************************/
 
-          //  var vertexA = vertices[vertexIndexA];
-          //  var vertexB = vertices[vertexIndexB];
+		newVertices = new TypedArrayHelper( ( geometry.getAttribute( 'position' ).array.length * 2 ) / 3, 2, THREE.Vector3, Float32Array, 3, XYZ );
+		var other, currentEdge, newEdge, face;
+		var edgeVertexWeight, adjacentVertexWeight, connectedFaces;
 
-            edge = new edge_type(vertexIndexA,vertexIndexB);
+		var tmp = newVertices.register[ 1 ];
+		for ( i in sourceEdges ) {
 
-            map[key] = edge;
+		currentEdge = sourceEdges[ i ];
+		newEdge = newVertices.register[ 0 ];
 
-        }
+		edgeVertexWeight = 3 / 8;
+		adjacentVertexWeight = 1 / 8;
 
-        edge.faces.push(face);
+		connectedFaces = currentEdge.faces.length;
 
-        metaVertices[a].edges.push(edge);
-        metaVertices[b].edges.push(edge);
+		// check how many linked faces. 2 should be correct.
+		if ( connectedFaces !== 2 ) {
 
+			// if length is not 2, handle condition
+			edgeVertexWeight = 0.5;
+			adjacentVertexWeight = 0;
 
-    }
+		}
 
-    function generateLookups(vertices, faces, metaVertices, edges) {
-        var i, il, face, edge;
+		oldVertices.index_to_register( currentEdge.a, 0 );
+		oldVertices.index_to_register( currentEdge.b, 1 );
+		newEdge.addVectors( oldVertices.register[ 0 ], oldVertices.register[ 1 ] ).multiplyScalar( edgeVertexWeight );
 
-        for (i = 0, il = vertices.length; i < il; i++) {
-            metaVertices[i] = { edges: [] };
-        }
+		tmp.set( 0, 0, 0 );
 
-        for (i = 0, il = faces.length; i < il; i++) {
-            faces.index_to_register(i, 0);
-            face = faces.register[0]; // Faces is now a TypedArrayHelper class, not a face3.
+		for ( j = 0; j < connectedFaces; j++ ) {
 
-            processEdge(face.a, face.b, vertices, edges, i, metaVertices);
-            processEdge(face.b, face.c, vertices, edges, i, metaVertices);
-            processEdge(face.c, face.a, vertices, edges, i, metaVertices);
+			oldFaces.index_to_register( currentEdge.faces[ j ], 0 );
+			face = oldFaces.register[ 0 ];
 
-        }
+			for ( k = 0; k < 3; k++ ) {
 
-    }
+				oldVertices.index_to_register( face[ ABC[ k ] ], 2 );
+				other = oldVertices.register[ 2 ];
 
-    function newFace(newFaces, face) {
-        newFaces.push_element(face);
-    }
-    function midpoint(a, b) {
-        return (Math.abs(b - a) / 2) + Math.min(a, b);
-    }
-    function newUv(newUvs, a, b, c) {
-        newUvs.push_element(a);
-        newUvs.push_element(b);
-        newUvs.push_element(c);
-    }
+				if ( face[ ABC[ k ] ] !== currentEdge.a && face[ ABC[ k ] ] !== currentEdge.b) {
 
-    /////////////////////////////
+					break;
 
-    // Performs one iteration of Subdivision
-    THREE.BufferSubdivisionModifier.prototype.smooth = function (geometry) {
-        var oldVertices, oldFaces, oldUvs;
-        var newVertices, newFaces, newUVs;
+				}
 
-        var n, l, i, il, j, k;
-        var metaVertices, sourceEdges;
+		}
 
-        // new stuff.
-        var sourceEdges;
+		tmp.add( other );
 
+		}
 
-        oldVertices = new TypedArrayHelper(0, 3, THREE.Vector3, Float32Array, 3, XYZ);
-        oldFaces = new TypedArrayHelper(0, 3, THREE.Face3, Uint32Array, 3, ABC);
-        oldUvs = new TypedArrayHelper(0, 3, THREE.Vector2, Float32Array, 2, XY);
-        oldVertices.from_existing(geometry.getAttribute('position').array);
-        oldFaces.from_existing(geometry.index.array);
-        oldUvs.from_existing(geometry.getAttribute('uv').array);
+		tmp.multiplyScalar( adjacentVertexWeight );
+		newEdge.add( tmp );
 
-        var doUvs = false;
-        if (typeof (oldUvs) != 'undefined' && oldUvs.length != 0) doUvs = true;
-        /******************************************************
-		 *
-		 * Step 0: Preprocess Geometry to Generate edges Lookup
-		 *
-		 *******************************************************/
+		currentEdge.newEdge = newVertices.length;
+		newVertices.push_element( newEdge );
 
-        metaVertices = new Array(oldVertices.length);
-        sourceEdges = {}; // Edge => { oldVertex1, oldVertex2, faces[]  }
+		}
 
-        generateLookups(oldVertices, oldFaces, metaVertices, sourceEdges);
+		var edgeLength = newVertices.length;
+		/******************************************************
+		*
+		*	Step 2.
+		*	Reposition each source vertices.
+		*
+		*******************************************************/
 
+		var beta, sourceVertexWeight, connectingVertexWeight;
+		var connectingEdge, connectingEdges, oldVertex, newSourceVertex;
 
-        /******************************************************
-		 *
-		 *	Step 1. 
-		 *	For each edge, create a new Edge Vertex,
-		 *	then position it.
-		 *
-		 *******************************************************/
+		for ( i = 0, il = oldVertices.length; i < il; i++ ) {
 
-        newVertices = new TypedArrayHelper((geometry.getAttribute('position').array.length*2)/3, 2, THREE.Vector3, Float32Array, 3, XYZ);
-        var other, currentEdge, newEdge, face;
-        var edgeVertexWeight, adjacentVertexWeight, connectedFaces;
+			oldVertices.index_to_register( i, 0, XYZ );
+			oldVertex = oldVertices.register[ 0 ];
 
-        var tmp = newVertices.register[1];
-        for (i in sourceEdges) {
+			// find all connecting edges (using lookupTable)
+			connectingEdges = metaVertices[ i ].edges;
+			n = connectingEdges.length;
 
-            currentEdge = sourceEdges[i];
-            newEdge = newVertices.register[0];
+			if ( n === 3 ) {
 
-            edgeVertexWeight = 3 / 8;
-            adjacentVertexWeight = 1 / 8;
+				beta = 3 / 16;
 
-            connectedFaces = currentEdge.faces.length;
+			} else if (n > 3) {
 
-            // check how many linked faces. 2 should be correct.
-            if (connectedFaces != 2) {
+				beta = 3 / (8 * n); // Warren's modified formula
 
-                // if length is not 2, handle condition
-                edgeVertexWeight = 0.5;
-                adjacentVertexWeight = 0;
+			}
 
-                if (connectedFaces != 1) {
+			// Loop's original beta formula
+			// beta = 1 / n * ( 5/8 - Math.pow( 3/8 + 1/4 * Math.cos( 2 * Math. PI / n ), 2) );
 
-                    if (WARNINGS) console.warn('Subdivision Modifier: Number of connected faces != 2, is: ', connectedFaces, currentEdge);
+			sourceVertexWeight = 1 - n * beta;
+			connectingVertexWeight = beta;
 
-                }
+			if ( n <= 2 ) {
 
-            }
-            oldVertices.index_to_register(currentEdge.a, 0);
-            oldVertices.index_to_register(currentEdge.b, 1);
-            newEdge.addVectors(oldVertices.register[0], oldVertices.register[1]).multiplyScalar(edgeVertexWeight);
+				// crease and boundary rules
 
-            tmp.set(0, 0, 0);
+				if ( n === 2 ) {
 
-            for (j = 0; j < connectedFaces; j++) {
-                oldFaces.index_to_register(currentEdge.faces[j], 0);
-                face = oldFaces.register[0];
+					sourceVertexWeight = 3 / 4;
+					connectingVertexWeight = 1 / 8;
 
-                for (k = 0; k < 3; k++) {
-                    oldVertices.index_to_register(face[ABC[k]], 2);
-                    other = oldVertices.register[2];
-                    if (face[ABC[k]] !== currentEdge.a && face[ABC[k]] !== currentEdge.b) break;
-                }
+				}
 
-                tmp.add(other);
+			}
 
-            }
+			newSourceVertex = oldVertex.multiplyScalar( sourceVertexWeight );
 
-            tmp.multiplyScalar(adjacentVertexWeight);
-            newEdge.add(tmp);
+			tmp.set( 0, 0, 0 );
 
-            currentEdge.newEdge = newVertices.length;
-            newVertices.push_element(newEdge);
+			for ( j = 0; j < n; j++ ) {
 
-            // console.log(currentEdge, newEdge);
+				connectingEdge = connectingEdges[ j ];
+				other = connectingEdge.a !== i ? connectingEdge.a : connectingEdge.b;
+				oldVertices.index_to_register( other, 1, XYZ );
+				tmp.add( oldVertices.register[ 1 ] );
 
-        }
-        var edgeLength = newVertices.length;
-        /******************************************************
-		 *
-		 *	Step 2. 
-		 *	Reposition each source vertices.
-		 *
-		 *******************************************************/
+			}
 
-        var beta, sourceVertexWeight, connectingVertexWeight;
-        var connectingEdge, connectingEdges, oldVertex, newSourceVertex;
-        for (i = 0, il = oldVertices.length; i < il; i++) {
-            oldVertices.index_to_register(i, 0, XYZ);
-            oldVertex = oldVertices.register[0];
+			tmp.multiplyScalar( connectingVertexWeight );
+			newSourceVertex.add( tmp );
 
-            // find all connecting edges (using lookupTable)
-            connectingEdges = metaVertices[i].edges;
-            n = connectingEdges.length;
-            
+			newVertices.push_element( newSourceVertex,XYZ );
 
-            if (n == 3) {
+		}
 
-                beta = 3 / 16;
 
-            } else if (n > 3) {
+		/******************************************************
+		*
+		*	Step 3.
+		*	Generate faces between source vertices and edge vertices.
+		*
+		*******************************************************/
 
-                beta = 3 / (8 * n); // Warren's modified formula
 
-            }
+		var edge1, edge2, edge3;
+		newFaces = new TypedArrayHelper( ( geometry.index.array.length * 4 ) / 3, 1, THREE.Face3, Float32Array, 3, ABC );
+		newUVs = new TypedArrayHelper( ( geometry.getAttribute( 'uv' ).array.length * 4 ) / 2, 3, THREE.Vector2, Float32Array, 2, XY );
+		var x3 = newUVs.register[ 0 ];
+		var x4 = newUVs.register[ 1 ];
+		var x5 = newUVs.register[ 2 ];
+		var tFace = newFaces.register[ 0 ];
 
-            // Loop's original beta formula
-            // beta = 1 / n * ( 5/8 - Math.pow( 3/8 + 1/4 * Math.cos( 2 * Math. PI / n ), 2) );
+		for ( i = 0, il = oldFaces.length; i < il; i++ ) {
 
-            sourceVertexWeight = 1 - n * beta;
-            connectingVertexWeight = beta;
+			oldFaces.index_to_register( i, 0 );
+			face = oldFaces.register[ 0 ];
 
-            if (n <= 2) {
+			// find the 3 new edges vertex of each old face
+			// The new source verts are added after the new edge verts now..
 
-                // crease and boundary rules
-                // console.warn('crease and boundary rules');
+			edge1 = getEdge( face.a, face.b, sourceEdges ).newEdge;
+			edge2 = getEdge( face.b, face.c, sourceEdges ).newEdge;
+			edge3 = getEdge( face.c, face.a, sourceEdges ).newEdge;
 
-                if (n == 2) {
+			// create 4 faces.
+			tFace.set( edge1, edge2, edge3 );
+			newFace( newFaces, tFace );
+			tFace.set( face.a + edgeLength, edge1, edge3 );
+			newFace( newFaces, tFace );
+			tFace.set( face.b + edgeLength, edge2, edge1 );
+			newFace( newFaces, tFace );
+			tFace.set( face.c + edgeLength, edge3, edge2 );
+			newFace( newFaces, tFace );
 
-                    if (WARNINGS) console.warn('2 connecting edges', connectingEdges);
-                    sourceVertexWeight = 3 / 4;
-                    connectingVertexWeight = 1 / 8;
 
-                    // sourceVertexWeight = 1;
-                    // connectingVertexWeight = 0;
+			/*
 
-                } else if (n == 1) {
 
-                    if (WARNINGS) console.warn('only 1 connecting edge');
+				0___________________C___________________2
+				 \                 /\                  /
+				  \              /   \      F4        /
+				   \     F2    /       \             /
+				    \        /            \         /
+				     \     /                \      /
+				      \  /         F1         \   /
+				       \/_______________________\/
+				      A \                       / B
+				         \       F3            /
+				          \                   /
+				           \                 /
+				            \               /
+				             \             /
+				              \           /
+				               \         /
+				                   \/
+				                    1
 
-                } else if (n == 0) {
 
-                    if (WARNINGS) console.warn('0 connecting edges');
+			Draw orders:
+			F1: ABC x3,x4,x5
+			F2: 0AC x0,x3,x5
+			F3: 1BA x1,x4,x3
+			F4: 2CB x2,x5,x4
 
-                }
+			0: x0
+			1: x1
+			2: x2
+			A: x3
+			B: x4
+			C: x5
+			*/
 
-            }
+			if ( doUvs === true ) {
 
-            newSourceVertex = oldVertex.multiplyScalar(sourceVertexWeight);
+				oldUvs.index_to_register( ( i * 3 ) + 0, 0 );
+				oldUvs.index_to_register( ( i * 3 ) + 1, 1 );
+				oldUvs.index_to_register( ( i * 3 ) + 2, 2 );
 
-            tmp.set(0, 0, 0);
+				x0 = oldUvs.register[ 0 ]; //uv[0];
+				x1 = oldUvs.register[ 1 ]; //uv[1];
+				x2 = oldUvs.register[ 2 ]; //uv[2];
 
-            for (j = 0; j < n; j++) {
+				x3.set( midpoint( x0.x, x1.x ), midpoint( x0.y, x1.y ) );
+				x4.set( midpoint( x1.x, x2.x ), midpoint( x1.y, x2.y ) );
+				x5.set( midpoint( x0.x, x2.x ), midpoint( x0.y, x2.y ) );
 
-                connectingEdge = connectingEdges[j];
-                other = connectingEdge.a !== i ? connectingEdge.a : connectingEdge.b;
-                oldVertices.index_to_register(other, 1, XYZ);
-                tmp.add(oldVertices.register[1]);
+				newUv( newUVs, x3, x4, x5 );
+				newUv( newUVs, x0, x3, x5 );
 
-            }
+				newUv( newUVs, x1, x4, x3 );
+				newUv( newUVs, x2, x5, x4 );
 
-            tmp.multiplyScalar(connectingVertexWeight);
-            newSourceVertex.add(tmp);
+			}
 
-            newVertices.push_element(newSourceVertex,XYZ);
+		}
 
-        }
+		// Overwrite old arrays
+
+		newFaces.trim_size();
+		newVertices.trim_size();
+		newUVs.trim_size();
 
+		geometry.setIndex( new THREE.BufferAttribute( newFaces.buffer ,3 ) );
+		geometry.addAttribute( 'position', new THREE.BufferAttribute( newVertices.buffer, 3 ) );
+		geometry.addAttribute( 'uv', new THREE.BufferAttribute( newUVs.buffer, 2 ) );
+
+	};
 
-        /******************************************************
-		 *
-		 *	Step 3. 
-		 *	Generate Faces between source vertecies
-		 *	and edge vertices.
-		 *
-		 *******************************************************/
-
-      
-        var edge1, edge2, edge3;
-        newFaces = new TypedArrayHelper((geometry.index.array.length*4) / 3, 1, THREE.Face3, Float32Array, 3, ABC);
-        newUVs = new TypedArrayHelper((geometry.getAttribute('uv').array.length * 4) / 2, 3, THREE.Vector2, Float32Array, 2, XY);
-        var x3 = newUVs.register[0];
-        var x4 = newUVs.register[1];
-        var x5 = newUVs.register[2];
-        var tFace = newFaces.register[0];
-        for (i = 0, il = oldFaces.length; i < il; i++) {
-            oldFaces.index_to_register(i, 0);
-            face = oldFaces.register[0];//oldFaces[i];
-
-            // find the 3 new edges vertex of each old face
-            // The new source verts are added after the new edge verts now.. 
-            edge1 = getEdge(face.a, face.b, sourceEdges).newEdge;
-            edge2 = getEdge(face.b, face.c, sourceEdges).newEdge;
-            edge3 = getEdge(face.c, face.a, sourceEdges).newEdge;
-
-            // create 4 faces.
-            tFace.set(edge1, edge2, edge3);
-            newFace(newFaces, tFace);
-            tFace.set(face.a + edgeLength, edge1, edge3);
-            newFace(newFaces, tFace);
-            tFace.set(face.b + edgeLength,edge2,edge1);
-            newFace(newFaces, tFace);
-            tFace.set(face.c + edgeLength,edge3,edge2);
-            newFace(newFaces, tFace);
-            // create 4 new uv's
-
-            /*
-        
-
-0___________________C___________________2
- \                 /\                  /
-  \              /   \      F4        /
-   \     F2    /       \             /
-    \        /            \         /
-     \     /                \      /
-      \  /         F1         \   /
-       \/_______________________\/
-      A \                       / B
-         \       F3            /
-          \                   /
-           \                 /
-            \               /
-             \             /
-              \           /
-               \         /
-                   \/
-                    1
-
-
-Draw orders: 
-F1: ABC x3,x4,x5
-F2: 0AC x0,x3,x5
-F3: 1BA x1,x4,x3
-F4: 2CB x2,x5,x4
-
-0: x0
-1: x1
-2: x2
-A: x3
-B: x4 
-C: x5
-*/
-            if (doUvs) {
-
-                oldUvs.index_to_register(i * 3, 0);
-                oldUvs.index_to_register((i * 3)+1, 1);
-                oldUvs.index_to_register((i * 3)+2, 2);
-
-              //  uv = oldUvs[i];
-                x0 = oldUvs.register[0];//uv[0];
-                x1 = oldUvs.register[1];//uv[1];
-                x2 = oldUvs.register[2];//uv[2];
-
-                x3.set(midpoint(x0.x, x1.x), midpoint(x0.y, x1.y));
-                x4.set(midpoint(x1.x, x2.x), midpoint(x1.y, x2.y));
-                x5.set(midpoint(x0.x, x2.x), midpoint(x0.y, x2.y));
-                newUv(newUVs, x3, x4, x5);
-                newUv(newUVs, x0, x3, x5);
-
-                newUv(newUVs, x1, x4, x3);
-                newUv(newUVs, x2, x5, x4);
-            }
-        }
-
-        // Overwrite old arrays
-        //geometry.addAttribute('position', THREE.BufferAttribute(newVertices, 3).copy)
-        newVertices.trim_size();
-        newFaces.trim_size();
-        newUVs.trim_size();
-        geometry.addAttribute('position', new THREE.BufferAttribute(newVertices.buffer,3));
-        geometry.setIndex(new THREE.BufferAttribute(newFaces.buffer,3));
-        geometry.addAttribute('uv', new THREE.BufferAttribute(newUVs.buffer,2));
-        /*
-        geometry.vertices = newVertices;
-        geometry.faces = newFaces;
-        geometry.faceVertexUvs[0] = newUVs; */
-        // console.log('done');
-
-    };
-
-
-})();
+} ) ();

+ 2377 - 0
examples/js/renderers/WebGLDeferredRenderer.js

@@ -0,0 +1,2377 @@
+/**
+ * @author alteredq / http://alteredqualia.com/
+ * @author MPanknin / http://www.redplant.de/
+ * @author takahiro / https://github.com/takahirox
+ *
+ * WebGLDeferredRenderer supports two types of Deferred Renderings.
+ * One is Classic Deferred Rendering and the other one is
+ * Light Pre-Pass (Deferred Lighting).
+ * Classic Deferred Rendering is default. You can use Light Pre-Pass
+ * by calling .enableLightPrePass( true ) method.
+ *
+ * Dependencies
+ *  - THREE.CopyShader
+ *  - THREE.RenderPass
+ *  - THREE.ShaderPass
+ *  - THREE.EffectComposer
+ *  - THREE.FXAAShader
+ *
+ * TODO
+ *  - reuse existing glsl
+ *  - shared material
+ *  - shadow
+ *  - optimization
+ *  - MRT (when it's available on Three.js)
+ *  - AmbientLight
+ *  - HemisphereLight
+ *  - PointLight (distance < 0)
+ *  - morphNormals
+ *  - BumpMap
+ *  - ToneMap
+ *  - envMap
+ *  - wrapAround
+ *  - addEffect
+ */
+
+THREE.WebGLDeferredRenderer = function ( parameters ) {
+
+	parameters = parameters || {};
+
+	// private properties
+
+	var _this = this;
+
+	var _gl;
+
+	var _width, _height;
+
+	// for Classic Deferred Rendering
+	var _compColor;
+	var _passColor, _passForward, _passCopy;
+
+	// for Light Pre-Pass
+	var _compReconstruction;
+	var _passReconstruction;
+
+	// for Common
+	var _compNormalDepth, _compLight, _compFinal;
+	var _passNormalDepth, _passLight, _passLightFullscreen, _passFinal, _passFXAA;
+
+	var _depthTexture;
+
+	var _lightScene, _lightFullscreenScene;
+
+	var _antialias = false, _hasTransparentObject = false, _lightPrePass = false;
+
+	var _invisibleMaterial = new THREE.ShaderMaterial( { visible: false } );
+
+	var _tmpVector3 = new THREE.Vector3();
+
+	// external properties
+
+	this.renderer;
+	this.domElement;
+
+	this.forwardRendering = false;  // for debug
+
+	// private methods
+
+	var init = function ( parameters ) {
+
+		_this.renderer = parameters.renderer !== undefined ? parameters.renderer : new THREE.WebGLRenderer( { antialias: false } );
+		_this.domElement = _this.renderer.domElement;
+
+		_gl = _this.renderer.context;
+
+		_width = parameters.width !== undefined ? parameters.width : _this.renderer.getSize().width;
+		_height = parameters.height !== undefined ? parameters.height : _this.renderer.getSize().height;
+
+		var antialias = parameters.antialias !== undefined ? parameters.antialias : false;
+
+		initDepthTexture();
+
+		initPassNormalDepth();
+		initPassColor();
+		initPassLight();
+		initPassReconstruction();
+		initPassFinal();
+
+		_this.setSize( _width, _height );
+		_this.setAntialias( antialias );
+		_this.enableLightPrePass( false );
+
+	};
+
+	var initDepthTexture = function () {
+
+		_depthTexture = new THREE.DepthTexture(
+			_width,
+			_height,
+			THREE.UnsignedInt248Type,
+			undefined,
+			undefined,
+			undefined,
+			undefined,
+			undefined,
+			undefined,
+			THREE.DepthStencilFormat
+		)
+
+	};
+
+	var initPassNormalDepth = function () {
+
+		_passNormalDepth = new THREE.RenderPass();
+		_passNormalDepth.clear = true;
+
+		var rt = new THREE.WebGLRenderTarget( _width, _height, {
+			minFilter: THREE.NearestFilter,
+			magFilter: THREE.NearestFilter,
+			format: THREE.RGBAFormat,
+			type: THREE.FloatType,
+			stencilBuffer: true,
+			depthTexture: _depthTexture
+		} );
+
+		rt.texture.generateMipamps = false;
+
+		_compNormalDepth = new THREE.EffectComposer( _this.renderer, rt );
+		_compNormalDepth.addPass( _passNormalDepth );
+
+	};
+
+	var initPassColor = function () {
+
+		_passColor = new THREE.RenderPass();
+		_passColor.clear = true;
+
+		var rt = new THREE.WebGLRenderTarget( _width, _height, {
+			minFilter: THREE.NearestFilter,
+			magFilter: THREE.NearestFilter,
+			format: THREE.RGBAFormat,
+			type: THREE.FloatType,
+			depthTexture: _depthTexture
+		} );
+
+		rt.texture.generateMipamps = false;
+
+		_compColor = new THREE.EffectComposer( _this.renderer, rt );
+		_compColor.addPass( _passColor );
+
+	};
+
+	var initPassLight = function () {
+
+		_passLightFullscreen = new THREE.RenderPass();
+		_passLightFullscreen.clear = true;
+		_passLightFullscreen.camera = new THREE.OrthographicCamera( -1, 1, 1, -1, 0, 1 );
+
+		_passLight = new THREE.RenderPass();
+		_passLight.clear = false;
+
+		var rt = new THREE.WebGLRenderTarget( _width, _height, {
+			minFilter: THREE.NearestFilter,
+			magFilter: THREE.NearestFilter,
+			format: THREE.RGBAFormat,
+			type: THREE.FloatType,
+			depthTexture: _depthTexture
+		} );
+
+		rt.texture.generateMipamps = false;
+
+		_compLight = new THREE.EffectComposer( _this.renderer, rt );
+		_compLight.addPass( _passLightFullscreen );
+		_compLight.addPass( _passLight );
+
+	};
+
+	var initPassReconstruction = function () {
+
+		_passReconstruction = new THREE.RenderPass();
+		_passReconstruction.clear = true;
+
+		var rt = new THREE.WebGLRenderTarget( _width, _height, {
+			minFilter: THREE.NearestFilter,
+			magFilter: THREE.NearestFilter,
+			format: THREE.RGBAFormat,
+			type: THREE.FloatType,
+			depthTexture: _depthTexture
+		} );
+
+		rt.texture.generateMipamps = false;
+
+		_compReconstruction = new THREE.EffectComposer( _this.renderer, rt );
+		_compReconstruction.addPass( _passReconstruction );
+
+	};
+
+	var initPassFinal = function () {
+
+		_passFinal = new THREE.ShaderPass( THREE.ShaderDeferred[ 'final' ] );
+		_passFinal.clear = true;
+		_passFinal.uniforms.samplerResult.value = _compLight.renderTarget2.texture;
+		_passFinal.material.blending = THREE.NoBlending;
+		_passFinal.material.depthWrite = false;
+		_passFinal.material.depthTest = false;
+
+		_passForward = new THREE.RenderPass();
+		_passForward.clear = false;
+
+		_passCopy = new THREE.ShaderPass( THREE.CopyShader );
+
+		_passFXAA = new THREE.ShaderPass( THREE.FXAAShader );
+
+		var rt = new THREE.WebGLRenderTarget( _width, _height, {
+			minFilter: THREE.NearestFilter,
+			magFilter: THREE.LinearFilter,
+			format: THREE.RGBFormat,
+			type: THREE.UnsignedByteType,
+			depthTexture: _depthTexture
+		} );
+
+		rt.texture.generateMipamps = false;
+
+		_compFinal = new THREE.EffectComposer( _this.renderer, rt );
+		_compFinal.addPass( _passFinal );
+		_compFinal.addPass( _passForward );
+		_compFinal.addPass( _passCopy );
+		_compFinal.addPass( _passFXAA );
+
+	};
+
+	var initLightScene = function ( scene ) {
+
+		if ( scene.userData.lightScene === undefined ) {
+
+			var lightScene = new THREE.Scene();
+			lightScene.userData.lights = {};
+
+			scene.userData.lightScene = lightScene;
+
+		}
+
+		if ( scene.userData.lightFullscreenScene === undefined ) {
+
+			var lightScene = new THREE.Scene();
+			lightScene.userData.lights = {};
+
+			lightScene.userData.emissiveLight = createDeferredEmissiveLight();
+			lightScene.add( lightScene.userData.emissiveLight );
+
+			scene.userData.lightFullscreenScene = lightScene;
+
+		}
+
+		_lightScene = scene.userData.lightScene;
+		_lightFullscreenScene = scene.userData.lightFullscreenScene;
+
+		// emissiveLight is only for Classic Deferred Rendering
+		_lightFullscreenScene.userData.emissiveLight.visible = ! _lightPrePass;
+
+	};
+
+	var setMaterialNormalDepth = function ( object ) {
+
+		if ( object.material === undefined ) return;
+
+		object.material = getNormalDepthMaterial( object );
+
+		if ( object.userData.originalMaterial.isMultiMaterial === true ) {
+
+			for ( var i = 0, il = object.userData.originalMaterial.materials.length; i < il; i ++ ) {
+
+				updateDeferredNormalDepthMaterial( object.material.materials[ i ], object.userData.originalMaterial.materials[ i ], _lightPrePass );
+
+			}
+
+		} else {
+
+			updateDeferredNormalDepthMaterial( object.material, object.userData.originalMaterial, _lightPrePass );
+
+		}
+
+	};
+
+	var getNormalDepthMaterial = function ( object ) {
+
+		if ( ( _lightPrePass && object.userData.normalDepthShininessMaterial === undefined ) ||
+		     ( ! _lightPrePass && object.userData.normalDepthMaterial === undefined ) ) {
+
+			initDeferredNormalDepthMaterial( object, _lightPrePass );
+
+		}
+
+		return ( _lightPrePass ) ? object.userData.normalDepthShininessMaterial : object.userData.normalDepthMaterial;
+
+	};
+
+	var initDeferredNormalDepthMaterial = function ( object, isLightPrePass ) {
+
+		var originalMaterial = object.userData.originalMaterial;
+		var material;
+
+		if ( originalMaterial.isMultiMaterial === true ) {
+
+			var materials = [];
+
+			for ( var i = 0, il = originalMaterial.materials.length; i < il; i ++ ) {
+
+				materials.push( createDeferredNormalDepthMaterial( originalMaterial.materials[ i ], isLightPrePass ) );
+
+			}
+
+			material = new THREE.MultiMaterial( materials );
+
+		} else {
+
+			material = createDeferredNormalDepthMaterial( originalMaterial, isLightPrePass );
+
+		}
+
+		if ( isLightPrePass ) {
+
+			object.userData.normalDepthShininessMaterial = material;
+
+		} else {
+
+			object.userData.normalDepthMaterial = material;
+
+		}
+
+	};
+
+	var createDeferredNormalDepthMaterial = function ( originalMaterial, isLightPrePass ) {
+
+		var shader = ( isLightPrePass ) ? THREE.ShaderDeferred[ 'normalDepthShininess' ] : THREE.ShaderDeferred[ 'normalDepth' ];
+
+		var material = new THREE.ShaderMaterial( {
+			uniforms: THREE.UniformsUtils.clone( shader.uniforms ),
+			fragmentShader: shader.fragmentShader,
+			vertexShader: shader.vertexShader,
+			blending: THREE.NoBlending
+		} );
+
+		return material;
+
+	};
+
+	var updateDeferredNormalDepthMaterial = function ( material, originalMaterial, isLightPrePass ) {
+
+		if ( originalMaterial.skinning !== undefined ) material.skinning = originalMaterial.skinning;
+		if ( originalMaterial.morphTargets !== undefined ) material.morphTargets = originalMaterial.morphTargets;
+
+		if ( isLightPrePass ) {
+
+			var shininess = originalMaterial.shininess;
+
+			if ( ( originalMaterial.isShaderMaterial === true ) && originalMaterial.uniforms !== undefined ) {
+
+				if ( shininess === undefined && originalMaterial.uniforms.shininess !== undefined ) shininess = originalMaterial.uniforms.shininess.value;
+
+			}
+
+			if ( shininess !== undefined ) material.uniforms.shininess.value = shininess;
+
+		}
+
+		if ( originalMaterial.visible === true ) {
+
+			material.visible = ! originalMaterial.transparent;
+
+		} else {
+
+			material.visible = false;
+
+		}
+
+	};
+
+	var setMaterialColor = function ( object ) {
+
+		if ( object.material === undefined ) return;
+
+		object.material = getColorMaterial( object );
+
+		if ( object.userData.originalMaterial.isMultiMaterial === true ) {
+
+			for ( var i = 0, il = object.userData.originalMaterial.materials.length; i < il; i ++ ) {
+
+				updateDeferredColorMaterial( object.material.materials[ i ], object.userData.originalMaterial.materials[ i ] );
+
+			}
+
+		} else {
+
+			updateDeferredColorMaterial( object.material, object.userData.originalMaterial );
+
+		}
+
+	};
+
+	var getColorMaterial = function ( object ) {
+
+		if ( object.userData.colorMaterial === undefined ) {
+
+			initDeferredColorMaterial( object );
+
+		}
+
+		return object.userData.colorMaterial;
+
+	};
+
+	var initDeferredColorMaterial = function ( object ) {
+
+		var originalMaterial = object.userData.originalMaterial;
+
+		if ( originalMaterial.isMultiMaterial === true ) {
+
+			var materials = [];
+
+			for ( var i = 0, il = originalMaterial.materials.length; i < il; i ++ ) {
+
+				materials.push( createDeferredColorMaterial( originalMaterial.materials[ i ] ) );
+
+			}
+
+			object.userData.colorMaterial = new THREE.MultiMaterial( materials );
+
+		} else {
+
+			object.userData.colorMaterial = createDeferredColorMaterial( originalMaterial );
+
+		}
+
+	};
+
+	var createDeferredColorMaterial = function ( originalMaterial ) {
+
+		var shader = THREE.ShaderDeferred[ 'color' ];
+
+		var material = new THREE.ShaderMaterial( {
+			uniforms: THREE.UniformsUtils.clone( shader.uniforms ),
+			fragmentShader: shader.fragmentShader,
+			vertexShader: shader.vertexShader,
+			blending: THREE.NoBlending
+		} );
+
+		if ( originalMaterial.map !== undefined ) material.map = originalMaterial.map;
+
+		return material;
+
+	};
+
+	var updateDeferredColorMaterial = function ( material, originalMaterial ) {
+
+		var diffuse, emissive;
+
+		if ( originalMaterial.isMeshBasicMaterial === true ) {
+
+			emissive = originalMaterial.color;
+
+		} else {
+
+			diffuse = originalMaterial.color;
+			emissive = originalMaterial.emissive;
+
+		}
+
+		var specular = originalMaterial.specular;
+		var shininess = originalMaterial.shininess;
+		var map = originalMaterial.map;
+
+		if ( originalMaterial.isShaderMaterial === true && originalMaterial.uniforms !== undefined ) {
+
+			if ( diffuse === undefined && originalMaterial.uniforms.diffuse !== undefined ) diffuse = originalMaterial.uniforms.diffuse.value;
+			if ( emissive === undefined && originalMaterial.uniforms.emissive !== undefined ) emissive = originalMaterial.uniforms.emissive.value;
+			if ( specular === undefined && originalMaterial.uniforms.specular !== undefined ) specular = originalMaterial.uniforms.specular.value;
+			if ( shininess === undefined && originalMaterial.uniforms.shininess !== undefined ) shininess = originalMaterial.uniforms.shininess.value;
+
+		}
+
+		if ( diffuse !== undefined ) material.uniforms.diffuse.value.copy( diffuse );
+		if ( emissive !== undefined ) material.uniforms.emissive.value.copy( emissive );
+		if ( specular !== undefined ) material.uniforms.specular.value.copy( specular );
+		if ( shininess !== undefined && material.uniforms.shininess !== undefined ) material.uniforms.shininess.value = shininess;
+
+		if ( map !== undefined ) {
+
+			material.map = map;
+			material.uniforms.map.value = map;
+
+		}
+
+		if ( originalMaterial.skinning !== undefined ) material.skinning = originalMaterial.skinning;
+		if ( originalMaterial.morphTargets !== undefined ) material.morphTargets = originalMaterial.morphTargets;
+
+		if ( originalMaterial.visible === true ) {
+
+			material.visible = ! originalMaterial.transparent;
+
+		} else {
+
+			material.visible = false;
+
+		}
+
+	};
+
+	var setMaterialReconstruction = function ( object ) {
+
+		if ( object.material === undefined ) return;
+
+		if ( object.userData.originalMaterial.transparent === true ) {
+
+			object.material = object.userData.originalMaterial;
+
+			return;
+
+		}
+
+		object.material = getReconstructionMaterial( object );
+
+		if ( object.userData.originalMaterial.isMultiMaterial === true ) {
+
+			for ( var i = 0, il = object.userData.originalMaterial.materials.length; i < il; i ++ ) {
+
+				updateDeferredReconstructionMaterial( object.material.materials[ i ], object.userData.originalMaterial.materials[ i ] );
+
+			}
+
+		} else {
+
+			updateDeferredReconstructionMaterial( object.material, object.userData.originalMaterial );
+
+		}
+
+	};
+
+	var getReconstructionMaterial = function ( object ) {
+
+		if ( object.userData.reconstructionMaterial === undefined ) {
+
+			initDeferredReconstructionMaterial( object );
+
+		}
+
+		return object.userData.reconstructionMaterial;
+
+	};
+
+	var initDeferredReconstructionMaterial = function ( object ) {
+
+		var originalMaterial = object.userData.originalMaterial;
+
+		if ( originalMaterial.isMultiMaterial === true ) {
+
+			var materials = [];
+
+			for ( var i = 0, il = originalMaterial.materials.length; i < il; i ++ ) {
+
+				materials.push( createDeferredReconstructionMaterial( originalMaterial.materials[ i ] ) );
+
+			}
+
+			object.userData.reconstructionMaterial = new THREE.MultiMaterial( materials );
+
+		} else {
+
+			object.userData.reconstructionMaterial = createDeferredReconstructionMaterial( originalMaterial );
+
+		}
+
+	};
+
+	var createDeferredReconstructionMaterial = function ( originalMaterial ) {
+
+		var shader = THREE.ShaderDeferred[ 'reconstruction' ];
+
+		var material = new THREE.ShaderMaterial( {
+			uniforms: THREE.UniformsUtils.clone( shader.uniforms ),
+			fragmentShader: shader.fragmentShader,
+			vertexShader: shader.vertexShader,
+			blending: THREE.NoBlending
+		} );
+
+		if ( originalMaterial.map !== undefined ) material.map = originalMaterial.map;
+
+		material.uniforms.samplerLight.value = _compLight.renderTarget2.texture;
+
+		return material;
+
+	};
+
+	var updateDeferredReconstructionMaterial = function ( material, originalMaterial ) {
+
+		updateDeferredColorMaterial( material, originalMaterial );
+
+		material.uniforms.viewWidth.value = _width;
+		material.uniforms.viewHeight.value = _height;
+
+	};
+
+	var setMaterialForwardRendering = function ( object ) {
+
+		if ( object.material === undefined ) return;
+
+		if ( object.userData.originalMaterial.isMultiMaterial === true ) {
+
+			if ( object.userData.forwardMaterial === undefined ) {
+
+				initInvisibleMaterial( object );
+
+			}
+
+			object.material = object.userData.forwardMaterial;
+
+			for ( var i = 0, il = object.userData.originalMaterial.materials.length; i < il; i ++ ) {
+
+				object.material.materials[ i ] = getForwardRenderingMaterial( object.userData.originalMaterial.materials[ i ] );
+
+			}
+
+		} else {
+
+			object.material = getForwardRenderingMaterial( object.userData.originalMaterial );
+
+		}
+
+	};
+
+	var initInvisibleMaterial = function ( object ) {
+
+		if ( object.userData.originalMaterial.isMultiMaterial === true ) {
+
+			var materials = [];
+
+			for ( var i = 0, il = object.userData.originalMaterial.materials.length; i < il; i ++ ) {
+
+				materials.push( _invisibleMaterial );
+
+			}
+
+			object.userData.forwardMaterial = new THREE.MultiMaterial( materials );
+
+		}
+
+	};
+
+	var getForwardRenderingMaterial = function ( originalMaterial ) {
+
+		if ( originalMaterial.transparent === true && originalMaterial.visible === true ) {
+
+			return originalMaterial
+
+		} else {
+
+			return _invisibleMaterial;
+
+		}
+
+	};
+
+	var createDeferredEmissiveLight = function () {
+
+		var shader = THREE.ShaderDeferred[ 'emissiveLight' ];
+
+		var material = new THREE.ShaderMaterial( {
+			uniforms: THREE.UniformsUtils.clone( shader.uniforms ),
+			vertexShader: shader.vertexShader,
+			fragmentShader: shader.fragmentShader,
+			blending: THREE.NoBlending,
+			depthWrite: false
+		} );
+
+		material.uniforms.samplerColor.value = _compColor.renderTarget2.texture;
+
+		var geometry = new THREE.PlaneBufferGeometry( 2, 2 );
+		var mesh = new THREE.Mesh( geometry, material );
+
+		return mesh;
+
+	};
+
+	var updateDeferredEmissiveLight = function ( light, camera ) {
+
+		var uniforms = light.material.uniforms;
+
+		uniforms.viewWidth.value = _width;
+		uniforms.viewHeight.value = _height;
+
+	};
+
+	var initDeferredLight = function ( light ) {
+
+		var deferredLight;
+
+		if ( light.isPointLight ) {
+
+			deferredLight = createDeferredPointLight( light );
+
+		} else if ( light.isSpotLight ) {
+
+			deferredLight = createDeferredSpotLight( light );
+
+		} else if ( light.isDirectionalLight ) {
+
+			deferredLight = createDeferredDirectionalLight( light );
+
+		} else {
+
+			deferredLight = null;
+
+		}
+
+		light.userData.deferredLight = deferredLight;
+
+	};
+
+	var initDeferredLightMaterial = function ( light, isLightPrePass ) {
+
+		var originalLight = light.userData.originalLight;
+		var material;
+
+		if ( originalLight.isPointLight ) {
+
+			material = createDeferredPointLightMaterial( isLightPrePass );
+
+		} else if ( originalLight.isSpotLight ) {
+
+			material = createDeferredSpotLightMaterial( isLightPrePass );
+
+		} else if ( originalLight.isDirectionalLight ) {
+
+			material = createDeferredDirectionalLightMaterial( isLightPrePass );
+
+		} else {
+
+			material = null;
+
+		}
+
+		if ( isLightPrePass ) {
+
+			light.userData.materialLightPrePass = material;
+
+		} else {
+
+			light.userData.materialClassic = material;
+
+		}
+
+	};
+
+	var getDeferredLightMaterial = function ( light ) {
+
+		if ( ( _lightPrePass && light.userData.materialLightPrePass === undefined ) ||
+		     ( ! _lightPrePass && light.userData.materialClassic === undefined ) ) {
+
+			initDeferredLightMaterial( light, _lightPrePass );
+
+		}
+
+		return ( _lightPrePass ) ? light.userData.materialLightPrePass : light.userData.materialClassic;
+
+	};
+
+	var updateDeferredLight = function ( light, camera ) {
+
+		var originalLight = light.userData.originalLight;
+
+		if ( originalLight.isPointLight ) {
+
+			updateDeferredPointLight( light, camera );
+
+		} else if ( originalLight.isSpotLight ) {
+
+			updateDeferredSpotLight( light, camera );
+
+		} else if ( originalLight.isDirectionalLight ) {
+
+			updateDeferredDirectionalLight( light, camera );
+
+		}
+
+	};
+
+	var createDeferredLightMesh = function ( light, geometry ) {
+
+		var mesh = new THREE.Mesh( geometry, _invisibleMaterial );
+
+		mesh.userData.originalLight = light;
+
+		return mesh;
+
+	};
+
+	var createDeferredLightMaterial = function ( shader, isLightPrePass ) {
+
+		var material = new THREE.ShaderMaterial( {
+			uniforms: THREE.UniformsUtils.clone( shader.uniforms ),
+			vertexShader: shader.vertexShader,
+			fragmentShader: shader.fragmentShader,
+			transparent: true,
+			blending: THREE.AdditiveBlending,
+			depthWrite: false
+		} );
+
+		if ( isLightPrePass ) {
+
+			material.premultipliedAlpha = true;
+			material.uniforms.samplerNormalDepthShininess.value = _compNormalDepth.renderTarget2.texture;
+
+		} else {
+
+			material.uniforms.samplerNormalDepth.value = _compNormalDepth.renderTarget2.texture;
+			material.uniforms.samplerColor.value = _compColor.renderTarget2.texture;
+
+		}
+
+		return material;
+
+	};
+
+	var createDeferredPointLight = function ( light ) {
+
+		return createDeferredLightMesh( light, new THREE.SphereGeometry( 1, 16, 8 ) );
+
+	};
+
+	/*
+	 * optimization:
+	 * Renders PointLight only back face with stencil test.
+	 */
+	var createDeferredPointLightMaterial = function ( isLightPrePass ) {
+
+		var shader = ( isLightPrePass ) ? THREE.ShaderDeferred[ 'pointLightPre' ] : THREE.ShaderDeferred[ 'pointLight' ];
+
+		var material = createDeferredLightMaterial( shader, isLightPrePass );
+
+		material.side = THREE.BackSide;
+		material.depthFunc = THREE.GreaterEqualDepth;
+
+		return material;
+
+	};
+
+	var updateDeferredPointLight = function ( light, camera ) {
+
+		var originalLight = light.userData.originalLight;
+		var distance = originalLight.distance;
+		var uniforms = light.material.uniforms;
+
+		uniforms.matProjInverse.value.getInverse( camera.projectionMatrix );
+		uniforms.viewWidth.value = _width;
+		uniforms.viewHeight.value = _height;
+		uniforms.lightColor.value.copy( originalLight.color );
+
+		if ( distance > 0 ) {
+
+			light.scale.set( 1, 1, 1 ).multiplyScalar( distance );
+			uniforms.lightRadius.value = distance;
+			uniforms.lightIntensity.value = originalLight.intensity;
+			uniforms.lightPositionVS.value.setFromMatrixPosition( originalLight.matrixWorld ).applyMatrix4( camera.matrixWorldInverse );
+			light.position.setFromMatrixPosition( originalLight.matrixWorld );
+
+		} else {
+
+			uniforms.lightRadius.value = Infinity;
+
+		}
+
+	};
+
+	var createDeferredSpotLight = function ( light ) {
+
+		return createDeferredLightMesh(	light, new THREE.PlaneBufferGeometry( 2, 2 ) );
+
+	};
+
+	var createDeferredSpotLightMaterial = function ( isLightPrePass ) {
+
+		var shader = ( isLightPrePass ) ? THREE.ShaderDeferred[ 'spotLightPre' ] : THREE.ShaderDeferred[ 'spotLight' ];
+
+		var material = createDeferredLightMaterial( shader, isLightPrePass );
+
+		material.depthTest = false;
+
+		return material;
+
+	};
+
+	var updateDeferredSpotLight = function ( light, camera ) {
+
+		var originalLight = light.userData.originalLight;
+		var uniforms = light.material.uniforms;
+
+		uniforms.matProjInverse.value.getInverse( camera.projectionMatrix );
+		uniforms.viewWidth.value = _width;
+		uniforms.viewHeight.value = _height;
+		uniforms.lightAngle.value = originalLight.angle;
+		uniforms.lightColor.value.copy( originalLight.color );
+		uniforms.lightIntensity.value = originalLight.intensity;
+		uniforms.lightPositionVS.value.setFromMatrixPosition( originalLight.matrixWorld ).applyMatrix4( camera.matrixWorldInverse );
+
+		var vec = uniforms.lightDirectionVS.value;
+		var vec2 = _tmpVector3;
+
+		vec.setFromMatrixPosition( originalLight.matrixWorld );
+		vec2.setFromMatrixPosition( originalLight.target.matrixWorld );
+		vec.sub( vec2 ).normalize().transformDirection( camera.matrixWorldInverse );
+
+	};
+
+	var createDeferredDirectionalLight = function ( light ) {
+
+		return createDeferredLightMesh(	light, new THREE.PlaneBufferGeometry( 2, 2 ) );
+
+	};
+
+	var createDeferredDirectionalLightMaterial = function ( isLightPrePass ) {
+
+		var shader = ( isLightPrePass ) ? THREE.ShaderDeferred[ 'directionalLightPre' ] : THREE.ShaderDeferred[ 'directionalLight' ];
+
+		var material = createDeferredLightMaterial( shader, isLightPrePass );
+
+		material.depthTest = false;
+
+		return material;
+
+	};
+
+	var updateDeferredDirectionalLight = function ( light, camera ) {
+
+		var originalLight = light.userData.originalLight;
+		var uniforms = light.material.uniforms;
+
+		uniforms.matProjInverse.value.getInverse( camera.projectionMatrix );
+		uniforms.viewWidth.value = _width;
+		uniforms.viewHeight.value = _height;
+		uniforms.lightColor.value.copy( originalLight.color );
+		uniforms.lightIntensity.value = originalLight.intensity;
+
+		var vec = uniforms.lightDirectionVS.value;
+		var vec2 = _tmpVector3;
+
+		vec.setFromMatrixPosition( originalLight.matrixWorld );
+		vec2.setFromMatrixPosition( originalLight.target.matrixWorld );
+		vec.sub( vec2 ).normalize().transformDirection( camera.matrixWorldInverse );
+
+	};
+
+	var saveOriginalMaterialAndCheckTransparency = function ( object ) {
+
+		if ( object.material !== undefined ) {
+
+			object.userData.originalMaterial = object.material;
+
+			if ( _hasTransparentObject ) return;
+
+			if ( object.material.isMultiMaterial === true ) {
+
+				for ( var i = 0, il = object.material.materials.length; i < il; i ++ ) {
+
+					if ( object.material.materials[ i ].transparent === true ) {
+
+						_hasTransparentObject = true;
+						break;
+
+					}
+
+				}
+
+			} else {
+
+				if ( object.material.transparent === true ) _hasTransparentObject = true;
+
+			}
+
+		}
+
+	};
+
+	var restoreOriginalMaterial = function ( object ) {
+
+		if ( object.userData.originalMaterial !== undefined ) object.material = object.userData.originalMaterial;
+
+	};
+
+	var addDeferredLightsToLightScene = function ( object ) {
+
+		if ( object.isLight !== true ) return;
+
+		if ( object.userData.deferredLight === undefined ) {
+
+			initDeferredLight( object );
+
+		}
+
+		var light = object.userData.deferredLight;
+
+		if ( light === null ) return;
+
+		var scene = ( object.isPointLight === true ) ? _lightScene : _lightFullscreenScene;
+
+		var lights = scene.userData.lights;
+
+		if ( lights[ light.uuid ] === undefined ) {
+
+			scene.add( light );
+
+			lights[ light.uuid ] = {
+				light: light,
+				found: true
+			};
+
+		}
+
+		lights[ light.uuid ].found = true;
+
+	};
+
+	var updateDeferredLightsInLightScene = function ( scene, camera ) {
+
+		var lights = scene.userData.lights;
+		var keys = Object.keys( lights );
+
+		for ( var i = 0, il = keys.length; i < il; i ++ ) {
+
+			var key = keys[ i ];
+
+			if ( lights[ key ].found === false ) {
+
+				scene.remove( lights[ key ].light );
+				delete lights[ key ];
+
+			} else {
+
+				var light = lights[ key ].light;
+				var material = getDeferredLightMaterial( light );
+				light.material = material;
+
+				updateDeferredLight( light, camera );
+				lights[ key ].found = false;
+
+			}
+
+		}
+
+	};
+
+	var enableFinalPasses = function () {
+
+		if ( _lightPrePass ) {
+
+			_passForward.renderToScreen = false;
+			_passForward.enabled = false;
+
+			_passCopy.renderToScreen = false;
+			_passCopy.enabled = false;
+
+			if ( _antialias ) {
+
+				_passFinal.renderToScreen = false;
+
+				_passFXAA.renderToScreen = true;
+				_passFXAA.enabled = true;
+
+			} else {
+
+				_passFinal.renderToScreen = true;
+
+				_passFXAA.renderToScreen = false;
+				_passFXAA.enabled = false;
+
+			}
+
+		} else {
+
+			if ( _hasTransparentObject ) {
+
+				if ( _antialias ) {
+
+					_passFinal.renderToScreen = false;
+
+					_passForward.renderToScreen = false;
+					_passForward.enabled = true;
+
+					_passCopy.renderToScreen = false;
+					_passCopy.enabled = false;
+
+					_passFXAA.renderToScreen = true;
+					_passFXAA.enabled = true;
+
+				} else {
+
+					_passFinal.renderToScreen = false;
+
+					_passForward.renderToScreen = false;
+					_passForward.enabled = true;
+
+					_passCopy.renderToScreen = true;
+					_passCopy.enabled = true;
+
+					_passFXAA.renderToScreen = false;
+					_passFXAA.enabled = false;
+
+				}
+
+			} else {
+
+				if ( _antialias ) {
+
+					_passFinal.renderToScreen = false;
+
+					_passForward.renderToScreen = false;
+					_passForward.enabled = false;
+
+					_passCopy.renderToScreen = false;
+					_passCopy.enabled = false;
+
+					_passFXAA.renderToScreen = true;
+					_passFXAA.enabled = true;
+
+				} else {
+
+					_passFinal.renderToScreen = true;
+
+					_passForward.renderToScreen = false;
+					_passForward.enabled = false;
+
+					_passCopy.renderToScreen = false;
+					_passCopy.enabled = false;
+
+					_passFXAA.renderToScreen = false;
+					_passFXAA.enabled = false;
+
+				}
+
+			}
+
+		}
+
+	};
+
+	/*
+	 * Classic Deferred Rendering
+	 *
+	 * 1) g-buffer normal + depth pass
+	 *
+	 * RGB: normal
+	 *   A: depth
+	 *
+	 *
+	 * Light Pre-Pass Rendering
+	 *
+	 * 1') g-buffer normal + depth pass + shininess
+	 *
+	 *   R: normal
+	 *   B: shininess
+	 *   A: depth
+	 */
+
+	var renderNormalDepth = function ( scene, camera ) {
+
+		scene.traverse( setMaterialNormalDepth );
+
+		_passNormalDepth.scene = scene;
+		_passNormalDepth.camera = camera;
+
+		_this.renderer.autoClearDepth = true;
+		_this.renderer.autoClearStencil = true;
+
+		_gl.enable( _gl.STENCIL_TEST );
+		_gl.stencilFunc( _gl.ALWAYS, 1, 0xffffffff );
+		_gl.stencilOp( _gl.REPLACE, _gl.REPLACE, _gl.REPLACE );
+
+		_compNormalDepth.render();
+
+	};
+
+	/*
+	 * Classic Deferred Rendering
+	 *
+	 * 2) g-buffer color pass
+	 *
+	 * R: diffuse
+	 * G: emissive
+	 * B: specular
+	 * A: shininess
+	 */
+
+	var renderColor = function ( scene, camera ) {
+
+		scene.traverse( setMaterialColor );
+
+		_passColor.scene = scene;
+		_passColor.camera = camera;
+
+		_this.renderer.autoClearDepth = false;
+		_this.renderer.autoClearStencil = false;
+
+		_gl.stencilFunc( _gl.EQUAL, 1, 0xffffffff );
+		_gl.stencilOp( _gl.KEEP, _gl.KEEP, _gl.KEEP );
+
+		_compColor.render();
+
+	};
+
+	/*
+	 * Classic Deferred Rendering
+	 *
+	 * 3) light pass
+	 */
+
+	var renderLight = function ( scene, camera ) {
+
+		updateDeferredEmissiveLight( _lightFullscreenScene.userData.emissiveLight, camera );
+
+		scene.traverse( addDeferredLightsToLightScene );
+
+		updateDeferredLightsInLightScene( _lightScene, camera );
+		updateDeferredLightsInLightScene( _lightFullscreenScene, camera );
+
+		_passLight.scene = _lightScene;
+		_passLight.camera = camera;
+
+		_passLightFullscreen.scene = _lightFullscreenScene;
+
+		_this.renderer.autoClearDepth = false;
+		_this.renderer.autoClearStencil = false;
+
+		_compLight.render();
+
+		_gl.disable( _gl.STENCIL_TEST );
+
+	};
+
+	/*
+	 * Light Pre-Pass Rendering
+	 *
+	 * 2') Light pre pass
+	 */
+
+	var renderLightPre = function ( scene, camera ) {
+
+		scene.traverse( addDeferredLightsToLightScene );
+
+		updateDeferredLightsInLightScene( _lightScene, camera );
+		updateDeferredLightsInLightScene( _lightFullscreenScene, camera );
+
+		_passLight.scene = _lightScene;
+		_passLight.camera = camera;
+
+		_passLightFullscreen.scene = _lightFullscreenScene;
+
+		_this.renderer.autoClearDepth = false;
+		_this.renderer.autoClearStencil = false;
+
+		_gl.stencilFunc( _gl.EQUAL, 1, 0xffffffff );
+		_gl.stencilOp( _gl.KEEP, _gl.KEEP, _gl.KEEP );
+
+		_compLight.render();
+
+	};
+
+	/*
+	 * Light Pre-Pass Rendering
+	 *
+	 * 3') Reconstruction pass
+	 *
+	 * Transprency handling:
+	 * Here renders transparent objects with normal forward rendering.
+	 */
+
+	var renderReconstruction = function ( scene, camera ) {
+
+		scene.traverse( setMaterialReconstruction );
+
+		_passReconstruction.scene = scene;
+		_passReconstruction.camera = camera;
+
+		_this.renderer.autoClearDepth = false;
+		_this.renderer.autoClearStencil = false;
+
+		_compReconstruction.render();
+
+		_gl.disable( _gl.STENCIL_TEST );
+
+	};
+
+	/*
+	 * Classic Deferred Rendering
+	 *
+	 * 4) Final pass
+	 *
+	 * transparency handling:
+	 * If there's any transparent objects, here renders them on the deferred rendering result
+	 * with normal forward rendering. This may be the easist way but heavy.
+	 * We should consider any better ways someday.
+	 *
+	 *
+	 * Light Pre-Pass Rendering
+	 *
+	 * 4') Final pass
+	 *
+	 *
+	 * Common
+	 *
+	 * antialias handling:
+	 * Here uses postprocessing FXAA for antialias.
+	 *
+	 */
+
+	var renderFinal = function ( scene, camera ) {
+
+		if ( ! _lightPrePass && _hasTransparentObject ) {
+
+			scene.traverse( setMaterialForwardRendering );
+
+			_passForward.scene = scene;
+			_passForward.camera = camera;
+
+		}
+
+		enableFinalPasses();
+
+		_this.renderer.autoClearDepth = false;
+		_this.renderer.autoClearStencil = false;
+
+		_compFinal.render();
+
+	};
+
+	// external APIs
+
+	this.setSize = function ( width, height ) {
+
+		_width = width;
+		_height = height;
+
+		this.renderer.setSize( _width, _height );
+
+		_compNormalDepth.setSize( _width, _height );
+		_compColor.setSize( _width, _height );
+		_compLight.setSize( _width, _height );
+		_compReconstruction.setSize( _width, _height );
+		_compFinal.setSize( _width, _height );
+
+		_depthTexture.image.width = _width;
+		_depthTexture.image.height = _height;
+		_depthTexture.needsUpdate = true;
+
+		_passFXAA.uniforms.resolution.value.set( 1 / _width, 1 / _height );
+
+	};
+
+	this.setAntialias = function ( enabled ) {
+
+		_antialias = enabled;
+
+	};
+
+	this.enableLightPrePass = function ( enabled ) {
+
+		_lightPrePass = enabled;
+
+		_passFinal.uniforms.samplerResult.value = ( _lightPrePass ) ? _compReconstruction.renderTarget2.texture : _compLight.renderTarget2.texture;
+
+	};
+
+	this.render = function ( scene, camera ) {
+
+		// for debug to compare with normal forward rendering
+
+		if ( this.forwardRendering ) {
+
+			this.renderer.render( scene, camera );
+			return;
+
+		}
+
+		var tmpSceneAutoUpdate = scene.autoUpdate;
+		var tmpAutoClearColor = this.renderer.autoClearColor;
+		var tmpAutoClearDepth = this.renderer.autoClearDepth;
+		var tmpAutoClearStencil = this.renderer.autoClearStencil;
+
+		initLightScene( scene );
+
+		scene.autoUpdate = false;
+		scene.updateMatrixWorld();
+
+		_hasTransparentObject = false;
+
+		scene.traverse( saveOriginalMaterialAndCheckTransparency );
+
+		renderNormalDepth( scene, camera );
+
+		if ( _lightPrePass ) {
+
+			renderLightPre( scene, camera );
+			renderReconstruction( scene, camera );
+
+		} else {
+
+			renderColor( scene, camera );
+			renderLight( scene, camera );
+
+		}
+
+		renderFinal( scene, camera );
+
+		scene.traverse( restoreOriginalMaterial );
+
+		scene.autoUpdate = tmpSceneAutoUpdate;
+		this.renderer.autoClearColor = tmpAutoClearColor;
+		this.renderer.autoClearDepth = tmpAutoClearDepth;
+		this.renderer.autoClearStencil = tmpAutoClearStencil;
+
+	};
+
+	// initialize
+
+	init( parameters );
+
+};
+
+THREE.DeferredShaderChunk = {
+
+	packVector3: [
+
+		"float vec3_to_float( vec3 data ) {",
+
+			"const float unit = 255.0/256.0;",
+			"highp float compressed = fract( data.x * unit ) + floor( data.y * unit * 255.0 ) + floor( data.z * unit * 255.0 ) * 255.0;",
+			"return compressed;",
+
+		"}"
+
+	].join( "\n" ),
+
+	unpackFloat: [
+
+		"vec3 float_to_vec3( float data ) {",
+
+			"const float unit = 255.0;",
+			"vec3 uncompressed;",
+			"uncompressed.x = fract( data );",
+			"float zInt = floor( data / unit );",
+			"uncompressed.z = fract( zInt / unit );",
+			"uncompressed.y = fract( floor( data - ( zInt * unit ) ) / unit );",
+			"return uncompressed;",
+
+		"}"
+
+	].join( "\n" ),
+
+	computeTextureCoord: [
+
+		"vec2 texCoord = gl_FragCoord.xy / vec2( viewWidth, viewHeight );"
+
+	].join( "\n" ),
+
+	packNormalDepth: [
+
+		"vec4 packedNormalDepth;",
+		"packedNormalDepth.xyz = normal * 0.5 + 0.5;",
+		"packedNormalDepth.w = position.z / position.w;",
+
+	].join( "\n" ),
+
+	unpackNormalDepth: [
+
+		"vec4 normalDepthMap = texture2D( samplerNormalDepth, texCoord );",
+		"float depth = normalDepthMap.w;",
+
+		"if ( depth == 0.0 ) discard;",
+
+		"vec3 normal = normalDepthMap.xyz * 2.0 - 1.0;"
+
+	].join( "\n" ),
+
+	// TODO: optimize normal packing. reference http://aras-p.info/texts/CompactNormalStorage.html
+	packNormalDepthShininess: [
+
+		"vec4 packedNormalDepthShininess;",
+		"packedNormalDepthShininess.x = vec3_to_float( normal * 0.5 + 0.5 );",
+		"packedNormalDepthShininess.z = shininess;",
+		"packedNormalDepthShininess.w = position.z / position.w;"
+
+	].join( "\n" ),
+
+	unpackNormalDepthShininess: [
+
+		"vec4 normalDepthMap = texture2D( samplerNormalDepthShininess, texCoord );",
+		"float depth = normalDepthMap.w;",
+
+		"if ( depth == 0.0 ) discard;",
+
+		"vec3 normal = float_to_vec3( normalDepthMap.x ) * 2.0 - 1.0;",
+		"float shininess = normalDepthMap.z;"
+
+
+	].join( "\n" ),
+
+	packColor: [
+
+		"vec4 packedColor;",
+		"packedColor.x = vec3_to_float( diffuseColor.rgb );",
+		"packedColor.y = vec3_to_float( emissiveColor );",
+		"packedColor.z = vec3_to_float( specularColor );",
+		"packedColor.w = shininess;"
+
+	].join( "\n" ),
+
+	unpackColor: [
+
+		"vec4 colorMap = texture2D( samplerColor, texCoord );",
+		"vec3 diffuseColor = float_to_vec3( colorMap.x );",
+		"vec3 emissiveColor = float_to_vec3( colorMap.y );",
+		"vec3 specularColor = float_to_vec3( colorMap.z );",
+		"float shininess = colorMap.w;",
+
+	].join( "\n" ),
+
+	packLight: [
+
+		"vec4 packedLight;",
+		"packedLight.xyz = lightIntensity * lightColor * max( dot( lightVector, normal ), 0.0 ) * attenuation;",
+		"packedLight.w = lightIntensity * specular * max( dot( lightVector, normal ), 0.0 ) * attenuation;",
+
+	].join( "\n" ),
+
+	computeVertexPositionVS: [
+
+		"vec2 xy = texCoord * 2.0 - 1.0;",
+		"vec4 vertexPositionProjected = vec4( xy, depth, 1.0 );",
+		"vec4 vertexPositionVS = matProjInverse * vertexPositionProjected;",
+		"vertexPositionVS.xyz /= vertexPositionVS.w;",
+		"vertexPositionVS.w = 1.0;"
+
+	].join( "\n" ),
+
+	// TODO: calculate schlick
+	computeSpecular: [
+
+		"vec3 halfVector = normalize( lightVector - normalize( vertexPositionVS.xyz ) );",
+		"float dotNormalHalf = max( dot( normal, halfVector ), 0.0 );",
+		"float specular = 0.31830988618 * ( shininess * 0.5 + 1.0 ) * pow( dotNormalHalf, shininess );",
+
+	].join( "\n" ),
+
+	combine: [
+
+		"gl_FragColor = vec4( lightIntensity * lightColor * max( dot( lightVector, normal ), 0.0 ) * ( diffuseColor + specular * specularColor ) * attenuation, 1.0 );"
+
+	].join( "\n" )
+
+};
+
+THREE.ShaderDeferred = {
+
+	normalDepth: {
+
+		uniforms: {},
+
+		vertexShader: [
+
+			"varying vec3 vNormal;",
+			"varying vec4 vPosition;",
+
+			THREE.ShaderChunk[ "morphtarget_pars_vertex" ],
+			THREE.ShaderChunk[ "skinning_pars_vertex" ],
+
+			"void main() {",
+
+				THREE.ShaderChunk[ "begin_vertex" ],
+				THREE.ShaderChunk[ "beginnormal_vertex" ],
+				THREE.ShaderChunk[ "skinbase_vertex" ],
+				THREE.ShaderChunk[ "skinnormal_vertex" ],
+				THREE.ShaderChunk[ "defaultnormal_vertex" ],
+				THREE.ShaderChunk[ "morphtarget_vertex" ],
+				THREE.ShaderChunk[ "skinning_vertex" ],
+				THREE.ShaderChunk[ "project_vertex" ],
+
+				"vNormal = normalize( normalMatrix * objectNormal );",
+				"vPosition = gl_Position;",
+
+			"}"
+
+		].join( "\n" ),
+
+		fragmentShader: [
+
+			"varying vec3 vNormal;",
+			"varying vec4 vPosition;",
+
+			"void main() {",
+
+				"vec3 normal = vNormal;",
+				"vec4 position = vPosition;",
+
+				THREE.DeferredShaderChunk[ "packNormalDepth" ],
+
+				"gl_FragColor = packedNormalDepth;",
+
+			"}"
+
+		].join( "\n" )
+
+	},
+
+	color: {
+
+		uniforms: {
+
+			map: { type: "t", value: null },
+			offsetRepeat: { type: "v4", value: new THREE.Vector4( 0, 0, 1, 1 ) },
+
+			diffuse: { type: "c", value: new THREE.Color( 0x000000 ) },
+			emissive: { type: "c", value: new THREE.Color( 0x000000 ) },
+			specular: { type: "c", value: new THREE.Color( 0x000000 ) },
+			shininess: { type: "f", value: 30.0 }
+
+		},
+
+		vertexShader: [
+
+			THREE.ShaderChunk[ "uv_pars_vertex" ],
+			THREE.ShaderChunk[ "morphtarget_pars_vertex" ],
+			THREE.ShaderChunk[ "skinning_pars_vertex" ],
+
+			"void main() {",
+
+				THREE.ShaderChunk[ "uv_vertex" ],
+				THREE.ShaderChunk[ "begin_vertex" ],
+				THREE.ShaderChunk[ "beginnormal_vertex" ],
+				THREE.ShaderChunk[ "skinbase_vertex" ],
+				THREE.ShaderChunk[ "skinnormal_vertex" ],
+				THREE.ShaderChunk[ "defaultnormal_vertex" ],
+				THREE.ShaderChunk[ "morphtarget_vertex" ],
+				THREE.ShaderChunk[ "skinning_vertex" ],
+				THREE.ShaderChunk[ "project_vertex" ],
+
+			"}"
+
+		].join( "\n" ),
+
+		fragmentShader: [
+
+			"uniform vec3 diffuse;",
+			"uniform vec3 emissive;",
+			"uniform vec3 specular;",
+			"uniform float shininess;",
+
+			THREE.ShaderChunk[ "uv_pars_fragment" ],
+			THREE.ShaderChunk[ "map_pars_fragment" ],
+			THREE.DeferredShaderChunk[ "packVector3" ],
+
+			"void main() {",
+
+				"vec4 diffuseColor = vec4( diffuse, 1.0 );",
+				"vec3 emissiveColor = emissive;",
+				"vec3 specularColor = specular;",
+
+				THREE.ShaderChunk[ "map_fragment" ],
+				THREE.DeferredShaderChunk[ "packColor" ],
+
+				"gl_FragColor = packedColor;",
+
+			"}"
+
+		].join( "\n" )
+
+	},
+
+	emissiveLight: {
+
+		uniforms: {
+
+			samplerColor: { type: "t", value: null },
+			viewWidth: { type: "f", value: 800 },
+			viewHeight: { type: "f", value: 600 }
+
+		},
+
+		vertexShader: [
+
+			"void main() { ",
+
+				"gl_Position = vec4( sign( position.xy ), 0.0, 1.0 );",
+
+			"}"
+
+		].join( '\n' ),
+
+		fragmentShader: [
+
+			"uniform sampler2D samplerColor;",
+
+			"uniform float viewHeight;",
+			"uniform float viewWidth;",
+
+			THREE.DeferredShaderChunk[ "unpackFloat" ],
+
+			"void main() {",
+
+				THREE.DeferredShaderChunk[ "computeTextureCoord" ],
+				THREE.DeferredShaderChunk[ "unpackColor" ],
+
+				"gl_FragColor = vec4( emissiveColor, 1.0 );",
+
+			"}"
+
+		].join( '\n' )
+
+	},
+
+	pointLight: {
+
+		uniforms: {
+
+			samplerNormalDepth: { type: "t", value: null },
+			samplerColor: { type: "t", value: null },
+
+			matProjInverse: { type: "m4", value: new THREE.Matrix4() },
+
+			viewWidth: { type: "f", value: 800 },
+			viewHeight: { type: "f", value: 600 },
+
+			lightColor: { type: "c", value: new THREE.Color( 0x000000 ) },
+			lightPositionVS: { type: "v3", value: new THREE.Vector3( 0, 1, 0 ) },
+			lightIntensity: { type: "f", value: 1.0 },
+			lightRadius: { type: "f", value: 1.0 }
+
+		},
+
+		vertexShader: [
+
+			"void main() {",
+
+				"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
+
+			"}"
+
+		].join( "\n" ),
+
+		fragmentShader: [
+
+			"uniform sampler2D samplerNormalDepth;",
+			"uniform sampler2D samplerColor;",
+
+			"uniform float viewHeight;",
+			"uniform float viewWidth;",
+
+			"uniform vec3 lightColor;",
+			"uniform vec3 lightPositionVS;",
+			"uniform float lightIntensity;",
+			"uniform float lightRadius;",
+
+			"uniform mat4 matProjInverse;",
+
+			THREE.DeferredShaderChunk[ "unpackFloat" ],
+
+			"void main() {",
+
+				THREE.DeferredShaderChunk[ "computeTextureCoord" ],
+				THREE.DeferredShaderChunk[ "unpackNormalDepth" ],
+				THREE.DeferredShaderChunk[ "computeVertexPositionVS" ],
+
+				"vec3 lightVector = lightPositionVS - vertexPositionVS.xyz;",
+				"float distance = length( lightVector );",
+
+				"if ( distance > lightRadius ) discard;",
+
+				"lightVector = normalize( lightVector );",
+
+				THREE.DeferredShaderChunk[ "unpackColor" ],
+				THREE.DeferredShaderChunk[ "computeSpecular" ],
+
+				"//float cutoff = 0.3;",
+				"//float denom = distance / lightRadius + 1.0;",
+				"//float attenuation = 1.0 / ( denom * denom );",
+				"//attenuation = ( attenuation - cutoff ) / ( 1.0 - cutoff );",
+				"//attenuation = max( attenuation, 0.0 );",
+				"//attenuation *= attenuation;",
+
+				"//diffuseColor *= saturate( -distance / lightRadius + 1.0 );",
+				"//float attenuation = 1.0;",
+
+				"float attenuation = saturate( -distance / lightRadius + 1.0 );",
+
+				THREE.DeferredShaderChunk[ "combine" ],
+
+			"}"
+
+		].join( "\n" )
+
+	},
+
+	spotLight: {
+
+		uniforms: {
+
+			samplerNormalDepth: { type: "t", value: null },
+			samplerColor: { type: "t", value: null },
+
+			matProjInverse: { type: "m4", value: new THREE.Matrix4() },
+
+			viewWidth: { type: "f", value: 800 },
+			viewHeight: { type: "f", value: 600 },
+
+			lightColor: { type: "c", value: new THREE.Color( 0x000000 ) },
+			lightDirectionVS: { type: "v3", value: new THREE.Vector3( 0, 1, 0 ) },
+			lightPositionVS: { type: "v3", value: new THREE.Vector3( 0, 1, 0 ) },
+			lightAngle: { type: "f", value: 1.0 },
+			lightIntensity: { type: "f", value: 1.0 }
+
+		},
+
+		vertexShader: [
+
+			"void main() { ",
+
+				"gl_Position = vec4( sign( position.xy ), 0.0, 1.0 );",
+
+			"}"
+
+		].join( "\n" ),
+
+		fragmentShader: [
+
+			"uniform sampler2D samplerNormalDepth;",
+			"uniform sampler2D samplerColor;",
+
+			"uniform float viewHeight;",
+			"uniform float viewWidth;",
+
+			"uniform vec3 lightColor;",
+			"uniform vec3 lightPositionVS;",
+			"uniform vec3 lightDirectionVS;",
+			"uniform float lightAngle;",
+			"uniform float lightIntensity;",
+
+			"uniform mat4 matProjInverse;",
+
+			THREE.DeferredShaderChunk[ "unpackFloat" ],
+
+			"void main() {",
+
+				THREE.DeferredShaderChunk[ "computeTextureCoord" ],
+				THREE.DeferredShaderChunk[ "unpackNormalDepth" ],
+				THREE.DeferredShaderChunk[ "computeVertexPositionVS" ],
+				THREE.DeferredShaderChunk[ "unpackColor" ],
+
+				"vec3 lightVector = normalize( lightPositionVS.xyz - vertexPositionVS.xyz );",
+
+				"float rho = dot( lightDirectionVS, lightVector );",
+				"float rhoMax = cos( lightAngle * 0.5 );",
+
+				"if ( rho <= rhoMax ) discard;",
+
+				"float theta = rhoMax + 0.0001;",
+				"float phi = rhoMax + 0.05;",
+				"float falloff = 4.0;",
+
+				"float spot = 0.0;",
+
+				"if ( rho >= phi ) {",
+
+					"spot = 1.0;",
+
+				"} else if ( rho <= theta ) {",
+
+					"spot = 0.0;",
+
+				"} else { ",
+
+					"spot = pow( ( rho - theta ) / ( phi - theta ), falloff );",
+
+				"}",
+
+				"diffuseColor *= spot;",
+
+				THREE.DeferredShaderChunk[ "computeSpecular" ],
+
+				"const float attenuation = 1.0;",
+
+				THREE.DeferredShaderChunk[ "combine" ],
+
+			"}"
+
+		].join( "\n" )
+
+	},
+
+	directionalLight: {
+
+		uniforms: {
+
+			samplerNormalDepth: { type: "t", value: null },
+			samplerColor: { type: "t", value: null },
+
+			matProjInverse: { type: "m4", value: new THREE.Matrix4() },
+
+			viewWidth: { type: "f", value: 800 },
+			viewHeight: { type: "f", value: 600 },
+
+			lightColor: { type: "c", value: new THREE.Color( 0x000000 ) },
+			lightDirectionVS : { type: "v3", value: new THREE.Vector3( 0, 1, 0 ) },
+			lightIntensity: { type: "f", value: 1.0 }
+
+		},
+
+		vertexShader: [
+
+			"void main() { ",
+
+				"gl_Position = vec4( sign( position.xy ), 0.0, 1.0 );",
+
+			"}"
+
+		].join( '\n' ),
+
+		fragmentShader: [
+
+			"uniform sampler2D samplerNormalDepth;",
+			"uniform sampler2D samplerColor;",
+
+			"uniform float viewHeight;",
+			"uniform float viewWidth;",
+
+			"uniform vec3 lightColor;",
+			"uniform vec3 lightDirectionVS;",
+			"uniform float lightIntensity;",
+
+			"uniform mat4 matProjInverse;",
+
+			THREE.DeferredShaderChunk[ "unpackFloat" ],
+
+			"void main() {",
+
+				THREE.DeferredShaderChunk[ "computeTextureCoord" ],
+				THREE.DeferredShaderChunk[ "unpackNormalDepth" ],
+				THREE.DeferredShaderChunk[ "computeVertexPositionVS" ],
+				THREE.DeferredShaderChunk[ "unpackColor" ],
+
+				"vec3 lightVector = normalize( lightDirectionVS );",
+
+				THREE.DeferredShaderChunk[ "computeSpecular" ],
+
+				"const float attenuation = 1.0;",
+
+				THREE.DeferredShaderChunk[ "combine" ],
+
+			"}"
+
+		].join( '\n' ),
+
+	},
+
+	normalDepthShininess: {
+
+		uniforms: {
+
+			shininess: { type: "f", value: 30.0 }
+
+		},
+
+		vertexShader: [
+
+			"varying vec3 vNormal;",
+			"varying vec4 vPosition;",
+
+			THREE.ShaderChunk[ "morphtarget_pars_vertex" ],
+			THREE.ShaderChunk[ "skinning_pars_vertex" ],
+
+			"void main() {",
+
+				THREE.ShaderChunk[ "begin_vertex" ],
+				THREE.ShaderChunk[ "beginnormal_vertex" ],
+				THREE.ShaderChunk[ "skinbase_vertex" ],
+				THREE.ShaderChunk[ "skinnormal_vertex" ],
+				THREE.ShaderChunk[ "defaultnormal_vertex" ],
+				THREE.ShaderChunk[ "morphtarget_vertex" ],
+				THREE.ShaderChunk[ "skinning_vertex" ],
+				THREE.ShaderChunk[ "project_vertex" ],
+
+				"vNormal = normalize( normalMatrix * objectNormal );",
+				"vPosition = gl_Position;",
+
+			"}"
+
+		].join( "\n" ),
+
+		fragmentShader: [
+
+			"varying vec3 vNormal;",
+			"varying vec4 vPosition;",
+
+			"uniform float shininess;",
+
+			THREE.DeferredShaderChunk[ "packVector3" ],
+
+			"void main() {",
+
+				"vec3 normal = vNormal;",
+				"vec4 position = vPosition;",
+
+				THREE.DeferredShaderChunk[ "packNormalDepthShininess" ],
+
+				"gl_FragColor = packedNormalDepthShininess;",
+
+			"}"
+
+		].join( "\n" )
+
+	},
+
+	pointLightPre: {
+
+		uniforms: {
+
+			samplerNormalDepthShininess: { type: "t", value: null },
+
+			matProjInverse: { type: "m4", value: new THREE.Matrix4() },
+
+			viewWidth: { type: "f", value: 800 },
+			viewHeight: { type: "f", value: 600 },
+
+			lightColor: { type: "c", value: new THREE.Color( 0x000000 ) },
+			lightPositionVS: { type: "v3", value: new THREE.Vector3( 0, 1, 0 ) },
+			lightIntensity: { type: "f", value: 1.0 },
+			lightRadius: { type: "f", value: 1.0 }
+
+		},
+
+		vertexShader: [
+
+			"void main() {",
+
+				"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
+
+			"}"
+
+		].join( "\n" ),
+
+		fragmentShader: [
+
+			"uniform sampler2D samplerNormalDepthShininess;",
+
+			"uniform float viewHeight;",
+			"uniform float viewWidth;",
+
+			"uniform vec3 lightColor;",
+			"uniform vec3 lightPositionVS;",
+			"uniform float lightIntensity;",
+			"uniform float lightRadius;",
+
+			"uniform mat4 matProjInverse;",
+
+			THREE.DeferredShaderChunk[ "unpackFloat" ],
+
+			"void main() {",
+
+				THREE.DeferredShaderChunk[ "computeTextureCoord" ],
+				THREE.DeferredShaderChunk[ "unpackNormalDepthShininess" ],
+				THREE.DeferredShaderChunk[ "computeVertexPositionVS" ],
+
+				"vec3 lightVector = lightPositionVS - vertexPositionVS.xyz;",
+				"float distance = length( lightVector );",
+
+				"if ( distance > lightRadius ) discard;",
+
+				"lightVector = normalize( lightVector );",
+
+				THREE.DeferredShaderChunk[ "computeSpecular" ],
+
+				"float attenuation = saturate( -distance / lightRadius + 1.0 );",
+
+				THREE.DeferredShaderChunk[ "packLight" ],
+
+				"gl_FragColor = packedLight;",
+
+			"}"
+
+		].join( "\n" )
+
+	},
+
+	spotLightPre: {
+
+		uniforms: {
+
+			samplerNormalDepthShininess: { type: "t", value: null },
+
+			matProjInverse: { type: "m4", value: new THREE.Matrix4() },
+
+			viewWidth: { type: "f", value: 800 },
+			viewHeight: { type: "f", value: 600 },
+
+			lightColor: { type: "c", value: new THREE.Color( 0x000000 ) },
+			lightDirectionVS: { type: "v3", value: new THREE.Vector3( 0, 1, 0 ) },
+			lightPositionVS: { type: "v3", value: new THREE.Vector3( 0, 1, 0 ) },
+			lightAngle: { type: "f", value: 1.0 },
+			lightIntensity: { type: "f", value: 1.0 }
+
+		},
+
+		vertexShader: [
+
+			"void main() { ",
+
+				"gl_Position = vec4( sign( position.xy ), 0.0, 1.0 );",
+
+			"}"
+
+		].join( "\n" ),
+
+		fragmentShader: [
+
+			"uniform sampler2D samplerNormalDepthShininess;",
+
+			"uniform float viewHeight;",
+			"uniform float viewWidth;",
+
+			"uniform vec3 lightColor;",
+			"uniform vec3 lightPositionVS;",
+			"uniform vec3 lightDirectionVS;",
+			"uniform float lightAngle;",
+			"uniform float lightIntensity;",
+
+			"uniform mat4 matProjInverse;",
+
+			THREE.DeferredShaderChunk[ "unpackFloat" ],
+
+			"void main() {",
+
+				THREE.DeferredShaderChunk[ "computeTextureCoord" ],
+				THREE.DeferredShaderChunk[ "unpackNormalDepthShininess" ],
+				THREE.DeferredShaderChunk[ "computeVertexPositionVS" ],
+
+				"vec3 lightVector = normalize( lightPositionVS.xyz - vertexPositionVS.xyz );",
+
+				"float rho = dot( lightDirectionVS, lightVector );",
+				"float rhoMax = cos( lightAngle * 0.5 );",
+
+				"if ( rho <= rhoMax ) discard;",
+
+				"float theta = rhoMax + 0.0001;",
+				"float phi = rhoMax + 0.05;",
+				"float falloff = 4.0;",
+
+				"float spot = 0.0;",
+
+				"if ( rho >= phi ) {",
+
+					"spot = 1.0;",
+
+				"} else if ( rho <= theta ) {",
+
+					"spot = 0.0;",
+
+				"} else { ",
+
+					"spot = pow( ( rho - theta ) / ( phi - theta ), falloff );",
+
+				"}",
+
+				THREE.DeferredShaderChunk[ "computeSpecular" ],
+
+				"const float attenuation = 1.0;",
+
+				THREE.DeferredShaderChunk[ "packLight" ],
+
+				"gl_FragColor = spot * packedLight;",
+
+			"}"
+
+		].join( "\n" )
+
+	},
+
+	directionalLightPre: {
+
+		uniforms: {
+
+			samplerNormalDepthShininess: { type: "t", value: null },
+
+			matProjInverse: { type: "m4", value: new THREE.Matrix4() },
+
+			viewWidth: { type: "f", value: 800 },
+			viewHeight: { type: "f", value: 600 },
+
+			lightColor: { type: "c", value: new THREE.Color( 0x000000 ) },
+			lightDirectionVS : { type: "v3", value: new THREE.Vector3( 0, 1, 0 ) },
+			lightIntensity: { type: "f", value: 1.0 }
+
+		},
+
+		vertexShader: [
+
+			"void main() { ",
+
+				"gl_Position = vec4( sign( position.xy ), 0.0, 1.0 );",
+
+			"}"
+
+		].join( '\n' ),
+
+		fragmentShader: [
+
+			"uniform sampler2D samplerNormalDepthShininess;",
+
+			"uniform float viewHeight;",
+			"uniform float viewWidth;",
+
+			"uniform vec3 lightColor;",
+			"uniform vec3 lightDirectionVS;",
+			"uniform float lightIntensity;",
+
+			"uniform mat4 matProjInverse;",
+
+			THREE.DeferredShaderChunk[ "unpackFloat" ],
+
+			"void main() {",
+
+				THREE.DeferredShaderChunk[ "computeTextureCoord" ],
+				THREE.DeferredShaderChunk[ "unpackNormalDepthShininess" ],
+				THREE.DeferredShaderChunk[ "computeVertexPositionVS" ],
+
+				"vec3 lightVector = normalize( lightDirectionVS );",
+
+				THREE.DeferredShaderChunk[ "computeSpecular" ],
+
+				"const float attenuation = 1.0;",
+
+				THREE.DeferredShaderChunk[ "packLight" ],
+
+				"gl_FragColor = packedLight;",
+
+			"}"
+
+		].join( '\n' ),
+
+	},
+
+	reconstruction: {
+
+		uniforms: {
+
+			samplerLight: { type: "t", value: null },
+
+			map: { type: "t", value: null },
+			offsetRepeat: { type: "v4", value: new THREE.Vector4( 0, 0, 1, 1 ) },
+
+			viewWidth: { type: "f", value: 800 },
+			viewHeight: { type: "f", value: 600 },
+
+			diffuse: { type: "c", value: new THREE.Color( 0x000000 ) },
+			emissive: { type: "c", value: new THREE.Color( 0x000000 ) },
+			specular: { type: "c", value: new THREE.Color( 0x000000 ) },
+			shininess: { type: "f", value: 30.0 }
+
+		},
+
+		vertexShader: [
+
+			THREE.ShaderChunk[ "uv_pars_vertex" ],
+			THREE.ShaderChunk[ "morphtarget_pars_vertex" ],
+			THREE.ShaderChunk[ "skinning_pars_vertex" ],
+
+			"void main() {",
+
+				THREE.ShaderChunk[ "uv_vertex" ],
+				THREE.ShaderChunk[ "begin_vertex" ],
+				THREE.ShaderChunk[ "beginnormal_vertex" ],
+				THREE.ShaderChunk[ "skinbase_vertex" ],
+				THREE.ShaderChunk[ "skinnormal_vertex" ],
+				THREE.ShaderChunk[ "defaultnormal_vertex" ],
+				THREE.ShaderChunk[ "morphtarget_vertex" ],
+				THREE.ShaderChunk[ "skinning_vertex" ],
+				THREE.ShaderChunk[ "project_vertex" ],
+
+			"}"
+
+		].join( "\n" ),
+
+		fragmentShader: [
+
+			"uniform sampler2D samplerLight;",
+
+			"uniform vec3 diffuse;",
+			"uniform vec3 emissive;",
+			"uniform vec3 specular;",
+			"uniform float shininess;",
+
+			"uniform float viewHeight;",
+			"uniform float viewWidth;",
+
+			THREE.ShaderChunk[ "uv_pars_fragment" ],
+			THREE.ShaderChunk[ "map_pars_fragment" ],
+
+			THREE.DeferredShaderChunk[ "unpackFloat" ],
+
+			"void main() {",
+
+				"vec4 diffuseColor = vec4( diffuse, 1.0 );",
+				"vec3 emissiveColor = emissive;",
+				"vec3 specularColor = specular;",
+
+				THREE.DeferredShaderChunk[ "computeTextureCoord" ],
+
+				"vec4 light = texture2D( samplerLight, texCoord );",
+
+				THREE.ShaderChunk[ "map_fragment" ],
+
+				"vec3 diffuseFinal = diffuseColor.rgb * light.rgb;",
+				"vec3 emissiveFinal = emissiveColor;",
+				"vec3 specularFinal = specularColor * light.rgb * ( light.a / ( 0.2126 * light.r + 0.7152 * light.g + 0.0722 * light.b + 0.00001 ) );",
+
+				"gl_FragColor = vec4( diffuseFinal + emissiveFinal + specularFinal, 1.0 );",
+
+			"}"
+
+		].join( "\n" )
+
+	},
+
+	// TODO: implement tone mapping
+	final: {
+
+		uniforms: {
+
+			samplerResult: { type: "t", value: null }
+
+		},
+
+		vertexShader: [
+
+			"varying vec2 texCoord;",
+
+			"void main() {",
+
+				"vec4 pos = vec4( sign( position.xy ), 0.0, 1.0 );",
+				"texCoord = pos.xy * vec2( 0.5 ) + 0.5;",
+				"gl_Position = pos;",
+
+			"}"
+
+		].join( "\n" ),
+
+		fragmentShader: [
+
+			"varying vec2 texCoord;",
+			"uniform sampler2D samplerResult;",
+
+			"void main() {",
+
+				"gl_FragColor = texture2D( samplerResult, texCoord );",
+
+			"}"
+
+		].join( "\n" )
+
+	}
+
+};

+ 107 - 0
examples/js/vr/PaintViveController.js

@@ -0,0 +1,107 @@
+/**
+ * @author mrdoob / http://mrdoob.com
+ */
+
+THREE.PaintViveController = function ( id ) {
+
+	THREE.ViveController.call( this, id );
+
+	var PI2 = Math.PI * 2;
+
+	var MODES = { COLOR: 0, SIZE: 1 };
+	var mode = MODES.COLOR;
+
+	var color = new THREE.Color( 1, 1, 1 );
+	var size = 1.0;
+
+	//
+
+	function generateHueTexture() {
+
+		var canvas = document.createElement( 'canvas' );
+		canvas.width = 256;
+		canvas.height = 256;
+
+		var context = canvas.getContext( '2d' );
+		var imageData = context.getImageData( 0, 0, 256, 256 );
+		var data = imageData.data;
+
+		for ( var i = 0, j = 0; i < data.length; i += 4, j ++ ) {
+
+			var x = ( ( j % 256 ) / 256 ) - 0.5;
+			var y = ( Math.floor( j / 256 ) / 256 ) - 0.5;
+
+			color.setHSL( Math.atan2( y, x ) / PI2, 1,( 0.5 - Math.sqrt( x * x + y * y ) ) * 2.0 );
+
+			data[ i + 0 ] = color.r * 256;
+			data[ i + 1 ] = color.g * 256;
+			data[ i + 2 ] = color.b * 256;
+			data[ i + 3 ] = 256;
+
+		}
+
+		context.putImageData( imageData, 0, 0 );
+
+		return new THREE.CanvasTexture( canvas );
+
+	}
+
+	var geometry = new THREE.CircleGeometry( 1, 32 );
+	var material = new THREE.MeshBasicMaterial( { map: generateHueTexture() } );
+	var mesh = new THREE.Mesh( geometry, material );
+	mesh.position.set( 0, 0.005, 0.0495 );
+	mesh.rotation.x = - 1.45;
+	mesh.scale.setScalar( 0.02 );
+	this.add( mesh )
+
+	var geometry = new THREE.IcosahedronGeometry( 0.1, 2 );
+	var material = new THREE.MeshBasicMaterial();
+	material.color = color;
+	var ball = new THREE.Mesh( geometry, material );
+	mesh.add( ball );
+
+	function onAxisChanged( event ) {
+
+		if ( this.getButtonState( 'thumbpad' ) === false ) return;
+
+		var x = event.axes[ 0 ] / 2.0;
+		var y = - event.axes[ 1 ] / 2.0;
+
+		if ( mode === MODES.COLOR ) {
+			color.setHSL( Math.atan2( y, x ) / PI2, 1, ( 0.5 - Math.sqrt( x * x + y * y ) ) * 2.0 );
+			ball.position.x = event.axes[ 0 ];
+			ball.position.y = event.axes[ 1 ];
+		}
+
+		if ( mode === MODES.SIZE ) {
+			size = y + 1;
+		}
+
+	}
+
+	function onGripsDown( event ) {
+
+		if ( mode === MODES.COLOR ) {
+			mode = MODES.SIZE;
+			mesh.visible = false;
+			return;
+		}
+
+		if ( mode === MODES.SIZE ) {
+			mode = MODES.COLOR;
+			mesh.visible = true;
+			return;
+		}
+
+	}
+
+	this.getColor = function () { return color; };
+	this.getSize = function () { return size; };
+
+	this.addEventListener( 'axischanged', onAxisChanged );
+	this.addEventListener( 'gripsdown', onGripsDown );
+
+};
+
+THREE.PaintViveController.prototype = Object.create( THREE.ViveController.prototype );
+THREE.PaintViveController.prototype.constructor = THREE.PaintViveController;

+ 0 - 0
examples/js/ViveController.js → examples/js/vr/ViveController.js


+ 3 - 6
examples/js/WebVR.js → examples/js/vr/WebVR.js

@@ -7,13 +7,14 @@ var WEBVR = {
 
 	isLatestAvailable: function () {
 
-		return navigator.getVRDisplays !== undefined;
+		console.warn( 'WEBVR: isLatestAvailable() is being deprecated. Use .isAvailable() instead.' );
+		return this.isAvailable();
 
 	},
 
 	isAvailable: function () {
 
-		return navigator.getVRDisplays !== undefined || navigator.getVRDevices !== undefined;
+		return navigator.getVRDisplays !== undefined;
 
 	},
 
@@ -29,10 +30,6 @@ var WEBVR = {
 
 			} );
 
-		} else if ( navigator.getVRDevices ) {
-
-			message = 'Your browser supports WebVR but not the latest version. See <a href="http://webvr.info">webvr.info</a> for more info.';
-
 		} else {
 
 			message = 'Your browser does not support WebVR. See <a href="http://webvr.info">webvr.info</a> for assistance.';

BIN
examples/models/ply/binary/Lucy100k.ply


BIN
examples/obj/lucy/Lucy100k_bin.bin


+ 0 - 23
examples/obj/lucy/Lucy100k_bin.js

@@ -1,23 +0,0 @@
-{
-
-    "metadata" :
-    {
-        "formatVersion" : 3.1,
-        "sourceFile"    : "lucy100k.obj",
-        "generatedBy"   : "OBJConverter",
-        "vertices"      : 50002,
-        "faces"         : 100000,
-        "normals"       : 0,
-        "uvs"           : 0,
-        "materials"     : 0
-    },
-
-    "materials": [	{
-	"DbgColor" : 15658734,
-	"DbgIndex" : 0,
-	"DbgName" : "default"
-	}],
-
-    "buffers": "Lucy100k_bin.bin"
-
-}

File diff suppressed because it is too large
+ 0 - 23
examples/obj/lucy/Lucy100k_slim.js


+ 161 - 0
examples/webgl_clipping_intersection.html

@@ -0,0 +1,161 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<title>three.js webgl - clipIntersection</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 {
+				margin: 0px;
+				background-color: #000000;
+				overflow: hidden;
+			}
+		</style>
+	</head>
+	<body>
+
+		<script src="../build/three.js"></script>
+		<script src="js/controls/OrbitControls.js"></script>
+		<script src="js/libs/stats.min.js"></script>
+		<script src="js/libs/dat.gui.min.js"></script>
+
+		<script>
+
+			var camera, scene, renderer;
+			var group;
+
+			init();
+			animate();
+
+			function init() {
+
+				camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 1, 800 );
+
+				camera.position.set( -20, 10, 50 );
+				camera.lookAt( new THREE.Vector3( 0, 0, 0) );
+
+				scene = new THREE.Scene();
+
+				// Lights
+
+				var light = new THREE.HemisphereLight( 0xffffbb, 0x080820, 1 );
+				scene.add( light );
+
+				var clipPlanes = [
+					new THREE.Plane( new THREE.Vector3( 1,  0,  0 ), 0 ),
+					new THREE.Plane( new THREE.Vector3( 0, -1,  0 ), 0 ),
+					new THREE.Plane( new THREE.Vector3( 0,  0, -1 ), 0 )
+				];
+
+				scene.add( new THREE.AmbientLight( 0x505050 ) );
+
+				group = new THREE.Object3D();
+
+				for ( var i = 1; i < 25; i ++ ) {
+
+					var geometry = new THREE.SphereBufferGeometry( i / 2, 48, 48 );
+					var material = new THREE.MeshStandardMaterial( {
+						color: new THREE.Color( Math.sin( i * 0.5 ) * 0.5 + 0.5, Math.cos( i * 1.5 ) * 0.5 + 0.5, Math.sin( i * 4.5 + 0 ) * 0.5 + 0.5 ),
+						roughness: 0.95,
+						metalness: 0.0,
+						side: THREE.DoubleSide,
+						clippingPlanes: clipPlanes,
+						clipIntersection: true
+					} );
+					group.add( new THREE.Mesh( geometry, material ) );
+
+				}
+
+				scene.add( group );
+
+				// Renderer
+
+				var container = document.body;
+
+				renderer = new THREE.WebGLRenderer();
+				renderer.antialias = true;
+				renderer.setPixelRatio( window.devicePixelRatio );
+				renderer.setSize( window.innerWidth, window.innerHeight );
+				renderer.setClearColor( 0x222222 );
+				renderer.localClippingEnabled = true;
+
+				window.addEventListener( 'resize', onWindowResize, false );
+				container.appendChild( renderer.domElement );
+
+				// Stats
+
+				stats = new Stats();
+				container.appendChild( stats.dom );
+
+				// GUI
+
+				mode = {};
+				mode.clipIntersection = true;
+				mode.clipPosition = 0;
+
+				var gui = new dat.GUI();
+				gui.add( mode, 'clipIntersection' ).onChange( function () {
+
+					var children = group.children;
+
+					for ( var i = 0; i < children.length; i ++ ) {
+
+						var child = children[ i ];
+						child.material.clipIntersection = ! child.material.clipIntersection;
+
+					}
+
+				} );
+				gui.add( mode, 'clipPosition', -16, 16 );
+
+				// Controls
+
+				var controls = new THREE.OrbitControls( camera, renderer.domElement );
+				controls.target.set( 0, 1, 0 );
+				controls.update();
+
+				// Start
+
+				startTime = Date.now();
+				time = 0;
+
+			}
+
+			function onWindowResize() {
+
+				camera.aspect = window.innerWidth / window.innerHeight;
+				camera.updateProjectionMatrix();
+
+				renderer.setSize( window.innerWidth, window.innerHeight );
+
+			}
+
+			function animate() {
+
+				requestAnimationFrame( animate );
+
+				var children = group.children;
+
+				for ( var i = 0; i < children.length; i ++ ) {
+
+					var current = children[ i ].material;
+
+					for ( var j = 0; j < current.clippingPlanes.length; j ++ ) {
+
+						var plane = current.clippingPlanes[ j ];
+						plane.constant = ( 49 * plane.constant + mode.clipPosition ) / 50;
+
+					}
+
+				}
+
+				stats.begin();
+				renderer.render( scene, camera );
+				stats.end();
+
+			}
+
+		</script>
+
+	</body>
+</html>

+ 5 - 48
examples/webgl_geometries2.html

@@ -25,8 +25,6 @@
 
 		<script>
 
-			/* Testing the new Parametric Surfaces Geometries*/
-
 			if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
 
 			var container, stats;
@@ -73,26 +71,11 @@
 				var sphere2 = new THREE.ParametricGeometries.SphereGeometry( 75, 20, 10 );
 				var tube2 = new THREE.ParametricGeometries.TubeGeometry( GrannyKnot, 150, 2, 8, true, false );
 
-				// var torus = new THREE.TorusKnotGeometry( radius, tube, segmentsR, segmentsT, p , q );
-				// var sphere = new THREE.SphereGeometry( 75, 20, 10 );
-				// var tube = new THREE.TubeGeometry( GrannyKnot, 150, 2, 8, true, false );
-
-
-				// var benchmarkCopies = 1000;
-				// var benchmarkObject = tube;
-				// var rand = function() { return (Math.random() - 0.5 ) * 600; };
-				// for (var b=0;b<benchmarkCopies;b++) {
-				//    object = THREE.SceneUtils.createMultiMaterialObject( benchmarkObject, materials );
-				//   object.position.set( rand(), rand(), rand() );
-				//   scene.add( object );
-				// }
-
-				console.log(THREE.ParametricGeometries);
 				var geo;
 
 				// Klein Bottle
 
-				geo = new THREE.ParametricGeometry( THREE.ParametricGeometries.klein, 20, 20 );
+				geo = new THREE.ParametricBufferGeometry( THREE.ParametricGeometries.klein, 20, 20 );
 				object = THREE.SceneUtils.createMultiMaterialObject( geo, materials );
 				object.position.set( 0, 0, 0 );
 				object.scale.multiplyScalar( 10 );
@@ -100,57 +83,35 @@
 
 				// Mobius Strip
 
-				geo = new THREE.ParametricGeometry( THREE.ParametricGeometries.mobius, 20, 20 );
+				geo = new THREE.ParametricBufferGeometry( THREE.ParametricGeometries.mobius, 20, 20 );
 				object = THREE.SceneUtils.createMultiMaterialObject( geo, materials );
 				object.position.set( 10, 0, 0 );
 				object.scale.multiplyScalar( 100 );
 				scene.add( object );
 
-				var geo = new THREE.ParametricGeometry( THREE.ParametricGeometries.plane( 200, 200 ), 10, 20 );
+				// Plane
+
+				geo = new THREE.ParametricBufferGeometry( THREE.ParametricGeometries.plane( 200, 200 ), 10, 20 );
 				object = THREE.SceneUtils.createMultiMaterialObject( geo, materials );
 				object.position.set( 0, 0, 0 );
 				scene.add( object );
 
-				// object = THREE.SceneUtils.createMultiMaterialObject( torus, materials );
-				// object.position.set( 0, 0, 0 );
-				// scene.add( object );
-
 				object = THREE.SceneUtils.createMultiMaterialObject( torus2, materials );
 				object.position.set( 0, 100, 0 );
 				scene.add( object );
 
-
-
-
-				//  object = THREE.SceneUtils.createMultiMaterialObject( sphere, materials );
-				//  object.position.set( 500, 0, 0 );
-				//  scene.add( object );
-
 				object = THREE.SceneUtils.createMultiMaterialObject( sphere2, materials );
 				object.position.set( 200, 0, 0 );
 				scene.add( object );
 
-				// object = THREE.SceneUtils.createMultiMaterialObject( tube, materials );
-				// object.position.set( 0, 0, 0 );
-				// scene.add( object );
-
 				object = THREE.SceneUtils.createMultiMaterialObject( tube2, materials );
 				object.position.set( 100, 0, 0 );
 				scene.add( object );
 
-
-				// object = THREE.SceneUtils.createMultiMaterialObject( new THREE.PlaneGeometry( 400, 400, 4, 4 ), materials );
-				// object.position.set( -200, 100, 0 );
-				// scene.add( object );
-
 				object = new THREE.AxisHelper( 50 );
 				object.position.set( 200, 0, -200 );
 				scene.add( object );
 
-				object = new THREE.ArrowHelper( new THREE.Vector3( 0, 1, 0 ), new THREE.Vector3( 0, 0, 0 ), 50 );
-				object.position.set( 200, 0, 400 );
-				scene.add( object );
-
 				renderer = new THREE.WebGLRenderer( { antialias: true } );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth, window.innerHeight );
@@ -159,8 +120,6 @@
 				stats = new Stats();
 				container.appendChild( stats.dom );
 
-				//
-
 				window.addEventListener( 'resize', onWindowResize, false );
 
 			}
@@ -174,8 +133,6 @@
 
 			}
 
-			//
-
 			function animate() {
 
 				requestAnimationFrame( animate );

+ 62 - 121
examples/webgl_geometry_extrude_splines.html

@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html lang="en">
 	<head>
-		<title>three.js webgl - geometry - shapes</title>
+		<title>three.js webgl - geometry - spline extrusion</title>
 		<meta charset="utf-8">
 		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
 		<style>
@@ -16,6 +16,7 @@
 	<body>
 
 		<script src="../build/three.js"></script>
+		<script src="js/controls/OrbitControls.js"></script>
 
 		<!-- where curves formulas are defined -->
 		<script src="js/CurveExtras.js"></script>
@@ -43,16 +44,30 @@
 		var normal = new THREE.Vector3();
 
 
-		var pipeSpline = new THREE.CatmullRomCurve3([
-				new THREE.Vector3(0, 10, -10), new THREE.Vector3(10, 0, -10), new THREE.Vector3(20, 0, 0), new THREE.Vector3(30, 0, 10), new THREE.Vector3(30, 0, 20), new THREE.Vector3(20, 0, 30), new THREE.Vector3(10, 0, 30), new THREE.Vector3(0, 0, 30), new THREE.Vector3(-10, 10, 30), new THREE.Vector3(-10, 20, 30), new THREE.Vector3(0, 30, 30), new THREE.Vector3(10, 30, 30), new THREE.Vector3(20, 30, 15), new THREE.Vector3(10, 30, 10), new THREE.Vector3(0, 30, 10), new THREE.Vector3(-10, 20, 10), new THREE.Vector3(-10, 10, 10), new THREE.Vector3(0, 0, 10), new THREE.Vector3(10, -10, 10), new THREE.Vector3(20, -15, 10), new THREE.Vector3(30, -15, 10), new THREE.Vector3(40, -15, 10), new THREE.Vector3(50, -15, 10), new THREE.Vector3(60, 0, 10), new THREE.Vector3(70, 0, 0), new THREE.Vector3(80, 0, 0), new THREE.Vector3(90, 0, 0), new THREE.Vector3(100, 0, 0)]);
-
-		var sampleClosedSpline = new THREE.CatmullRomCurve3([
-			new THREE.Vector3(0, -40, -40),
-			new THREE.Vector3(0, 40, -40),
-			new THREE.Vector3(0, 140, -40),
-			new THREE.Vector3(0, 40, 40),
-			new THREE.Vector3(0, -40, 40),
-		]);
+		var pipeSpline = new THREE.CatmullRomCurve3( [
+				new THREE.Vector3( 0, 10, -10 ), new THREE.Vector3( 10, 0, -10 ),
+				new THREE.Vector3( 20, 0, 0 ), new THREE.Vector3( 30, 0, 10 ),
+				new THREE.Vector3( 30, 0, 20 ), new THREE.Vector3( 20, 0, 30 ),
+				new THREE.Vector3( 10, 0, 30 ), new THREE.Vector3( 0, 0, 30 ),
+				new THREE.Vector3( -10, 10, 30 ), new THREE.Vector3( -10, 20, 30 ),
+				new THREE.Vector3( 0, 30, 30 ), new THREE.Vector3( 10, 30, 30 ),
+				new THREE.Vector3( 20, 30, 15 ), new THREE.Vector3( 10, 30, 10 ),
+				new THREE.Vector3( 0, 30, 10 ), new THREE.Vector3( -10, 20, 10 ),
+				new THREE.Vector3( -10, 10, 10 ), new THREE.Vector3( 0, 0, 10 ),
+				new THREE.Vector3( 10, -10, 10 ), new THREE.Vector3( 20, -15, 10 ),
+				new THREE.Vector3( 30, -15, 10 ), new THREE.Vector3( 40, -15, 10 ),
+				new THREE.Vector3( 50, -15, 10 ), new THREE.Vector3( 60, 0, 10 ),
+				new THREE.Vector3( 70, 0, 0 ), new THREE.Vector3( 80, 0, 0 ),
+				new THREE.Vector3( 90, 0, 0 ), new THREE.Vector3( 100, 0, 0 )
+		] );
+
+		var sampleClosedSpline = new THREE.CatmullRomCurve3( [
+			new THREE.Vector3( 0, -40, -40 ),
+			new THREE.Vector3( 0, 40, -40 ),
+			new THREE.Vector3( 0, 140, -40 ),
+			new THREE.Vector3( 0, 40, 40 ),
+			new THREE.Vector3( 0, -40, 40 ),
+		] );
 
 		sampleClosedSpline.type = 'catmullrom';
 		sampleClosedSpline.closed = true;
@@ -60,14 +75,14 @@
 		// Keep a dictionary of Curve instances
 		var splines = {
 			GrannyKnot: new THREE.Curves.GrannyKnot(),
-			HeartCurve: new THREE.Curves.HeartCurve(3.5),
-			VivianiCurve: new THREE.Curves.VivianiCurve(70),
+			HeartCurve: new THREE.Curves.HeartCurve( 3.5 ),
+			VivianiCurve: new THREE.Curves.VivianiCurve( 70 ),
 			KnotCurve: new THREE.Curves.KnotCurve(),
 			HelixCurve: new THREE.Curves.HelixCurve(),
 			TrefoilKnot: new THREE.Curves.TrefoilKnot(),
-			TorusKnot: new THREE.Curves.TorusKnot(20),
-			CinquefoilKnot: new THREE.Curves.CinquefoilKnot(20),
-			TrefoilPolynomialKnot: new THREE.Curves.TrefoilPolynomialKnot(14),
+			TorusKnot: new THREE.Curves.TorusKnot( 20 ),
+			CinquefoilKnot: new THREE.Curves.CinquefoilKnot( 20 ),
+			TrefoilPolynomialKnot: new THREE.Curves.TrefoilPolynomialKnot( 14 ),
 			FigureEightPolynomialKnot: new THREE.Curves.FigureEightPolynomialKnot(),
 			DecoratedTorusKnot4a: new THREE.Curves.DecoratedTorusKnot4a(),
 			DecoratedTorusKnot4b: new THREE.Curves.DecoratedTorusKnot4b(),
@@ -77,17 +92,16 @@
 			SampleClosedSpline: sampleClosedSpline
 		};
 
-
-
-
 		extrudePath = new THREE.Curves.TrefoilKnot();
 
 		var dropdown = '<select id="dropdown" onchange="addTube(this.value)">';
 
 		var s;
 		for ( s in splines ) {
+
 			dropdown += '<option value="' + s + '"';
 			dropdown += '>' + s + '</option>';
+
 		}
 
 		dropdown += '</select>';
@@ -101,27 +115,27 @@
 
 		function addTube() {
 
-			var value = document.getElementById('dropdown').value;
+			var value = document.getElementById( 'dropdown' ).value;
 
-			var segments = parseInt(document.getElementById('segments').value);
-			closed2 = document.getElementById('closed').checked;
+			var segments = parseInt( document.getElementById( 'segments' ).value );
+			closed2 = document.getElementById( 'closed' ).checked;
 
-			var radiusSegments = parseInt(document.getElementById('radiusSegments').value);
+			var radiusSegments = parseInt( document.getElementById( 'radiusSegments' ).value );
 
-			if (tubeMesh) parent.remove(tubeMesh);
+			if ( tubeMesh !== undefined ) parent.remove( tubeMesh );
 
-			extrudePath = splines[value];
+			extrudePath = splines[ value ];
 
-			tube = new THREE.TubeGeometry(extrudePath, segments, 2, radiusSegments, closed2);
+			tube = new THREE.TubeBufferGeometry( extrudePath, segments, 2, radiusSegments, closed2 );
 
-			addGeometry(tube, 0xff00ff);
+			addGeometry( tube, 0xff00ff );
 			setScale();
 
 		}
 
 		function setScale() {
 
-			scale = parseInt( document.getElementById('scale').value );
+			scale = parseInt( document.getElementById( 'scale' ).value );
 			tubeMesh.scale.set( scale, scale, scale );
 
 		}
@@ -132,15 +146,15 @@
 			// 3d shape
 
 			tubeMesh = THREE.SceneUtils.createMultiMaterialObject( geometry, [
-				new THREE.MeshLambertMaterial({
+				new THREE.MeshLambertMaterial( {
 					color: color
-				}),
-				new THREE.MeshBasicMaterial({
+				} ),
+				new THREE.MeshBasicMaterial( {
 					color: 0x000000,
 					opacity: 0.3,
 					wireframe: true,
 					transparent: true
-			})]);
+			} ) ] );
 
 			parent.add( tubeMesh );
 
@@ -148,31 +162,31 @@
 
 		function animateCamera( toggle ) {
 
-			if ( toggle ) {
+			if ( toggle === true ) {
 
 				animation = animation === false;
-				document.getElementById('animation').value = 'Camera Spline Animation View: ' + (animation? 'ON': 'OFF');
+				document.getElementById( 'animation' ).value = 'Camera Spline Animation View: ' + ( animation ? 'ON' : 'OFF' );
 
 			}
 
-			lookAhead = document.getElementById('lookAhead').checked;
+			lookAhead = document.getElementById( 'lookAhead' ).checked;
 
-			showCameraHelper = document.getElementById('cameraHelper').checked;
+			showCameraHelper = document.getElementById( 'cameraHelper' ).checked;
 
 			cameraHelper.visible = showCameraHelper;
 			cameraEye.visible = showCameraHelper;
-		}
 
+		}
 
 		init();
 		animate();
 
 		function init() {
 
-			container = document.createElement('div');
-			document.body.appendChild(container);
+			container = document.createElement( 'div' );
+			document.body.appendChild( container );
 
-			var info = document.createElement('div');
+			var info = document.createElement( 'div' );
 			info.style.position = 'absolute';
 			info.style.top = '10px';
 			info.style.width = '100%';
@@ -188,12 +202,12 @@
 
 			info.innerHTML += '<br/><br/><input id="animation" type="button" onclick="animateCamera(true)" value="Camera Spline Animation View: OFF"/><br/> Look Ahead <input id="lookAhead" type="checkbox" onchange="animateCamera()" /> Camera Helper <input id="cameraHelper" type="checkbox" onchange="animateCamera()" />';
 
-			container.appendChild(info);
+			container.appendChild( info );
 
 			//
 
-			camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.01, 1000);
-			camera.position.set(0, 50, 500);
+			camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 0.01, 10000 );
+			camera.position.set( 0, 50, 500 );
 
 			scene = new THREE.Scene();
 
@@ -202,7 +216,6 @@
 			scene.add( light );
 
 			parent = new THREE.Object3D();
-			parent.position.y = 100;
 			scene.add( parent );
 
 			splineCamera = new THREE.PerspectiveCamera( 84, window.innerWidth / window.innerHeight, 0.01, 1000 );
@@ -213,7 +226,7 @@
 
 			addTube();
 
-			// Debug point
+			// debug camera
 
 			cameraEye = new THREE.Mesh( new THREE.SphereGeometry( 5 ), new THREE.MeshBasicMaterial( { color: 0xdddddd } ) );
 			parent.add( cameraEye );
@@ -232,9 +245,9 @@
 			stats = new Stats();
 			container.appendChild( stats.dom );
 
-			renderer.domElement.addEventListener( 'mousedown', onDocumentMouseDown, false );
-			renderer.domElement.addEventListener( 'touchstart', onDocumentTouchStart, false );
-			renderer.domElement.addEventListener( 'touchmove', onDocumentTouchMove, false );
+			//
+
+			controls = new THREE.OrbitControls( camera, renderer.domElement );
 
 			//
 
@@ -256,71 +269,6 @@
 
 		//
 
-		function onDocumentMouseDown(event) {
-
-			event.preventDefault();
-
-			renderer.domElement.addEventListener( 'mousemove', onDocumentMouseMove, false );
-			renderer.domElement.addEventListener( 'mouseup', onDocumentMouseUp, false );
-			renderer.domElement.addEventListener( 'mouseout', onDocumentMouseOut, false );
-
-			mouseXOnMouseDown = event.clientX - windowHalfX;
-			targetRotationOnMouseDown = targetRotation;
-
-		}
-
-		function onDocumentMouseMove(event) {
-
-			mouseX = event.clientX - windowHalfX;
-
-			targetRotation = targetRotationOnMouseDown + (mouseX - mouseXOnMouseDown) * 0.02;
-
-		}
-
-		function onDocumentMouseUp(event) {
-
-			renderer.domElement.removeEventListener( 'mousemove', onDocumentMouseMove, false );
-			renderer.domElement.removeEventListener( 'mouseup', onDocumentMouseUp, false );
-			renderer.domElement.removeEventListener( 'mouseout', onDocumentMouseOut, false );
-
-		}
-
-		function onDocumentMouseOut(event) {
-
-			renderer.domElement.removeEventListener( 'mousemove', onDocumentMouseMove, false );
-			renderer.domElement.removeEventListener( 'mouseup', onDocumentMouseUp, false );
-			renderer.domElement.removeEventListener( 'mouseout', onDocumentMouseOut, false );
-
-		}
-
-		function onDocumentTouchStart(event) {
-
-			if (event.touches.length == 1) {
-
-				event.preventDefault();
-
-				mouseXOnMouseDown = event.touches[ 0 ].pageX - windowHalfX;
-				targetRotationOnMouseDown = targetRotation;
-
-			}
-
-		}
-
-		function onDocumentTouchMove(event) {
-
-			if (event.touches.length == 1) {
-
-				event.preventDefault();
-
-				mouseX = event.touches[ 0 ].pageX - windowHalfX;
-				targetRotation = targetRotationOnMouseDown + ( mouseX - mouseXOnMouseDown ) * 0.05;
-
-			}
-
-		}
-
-		//
-
 		function animate() {
 
 			requestAnimationFrame( animate );
@@ -362,23 +310,16 @@
 			splineCamera.position.copy( pos );
 			cameraEye.position.copy( pos );
 
-
-			// Camera Orientation 1 - default look at
-			// splineCamera.lookAt( lookAt );
-
 			// Using arclength for stablization in look ahead.
 			var lookAt = tube.parameters.path.getPointAt( ( t + 30 / tube.parameters.path.getLength() ) % 1 ).multiplyScalar( scale );
 
 			// Camera Orientation 2 - up orientation via normal
-			if (!lookAhead)
-			lookAt.copy( pos ).add( dir );
+			if ( !lookAhead ) lookAt.copy( pos ).add( dir );
 			splineCamera.matrix.lookAt(splineCamera.position, lookAt, normal);
 			splineCamera.rotation.setFromRotationMatrix( splineCamera.matrix, splineCamera.rotation.order );
 
 			cameraHelper.update();
 
-			parent.rotation.y += ( targetRotation - parent.rotation.y ) * 0.05;
-
 			renderer.render( scene, animation === true ? splineCamera : camera );
 
 		}

+ 0 - 276
examples/webgl_geometry_large_mesh.html

@@ -1,276 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-	<head>
-		<title>three.js webgl - geometry - large mesh</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 {
-				background:#000;
-				color:#fff;
-				padding:0;
-				margin:0;
-				overflow:hidden;
-				font-family:georgia;
-				text-align:center;
-			}
-			h1 { }
-			a { color:skyblue }
-			canvas { pointer-events:none; z-index:10; }
-			#log { position:absolute; top:50px; text-align:left; display:block; z-index:100 }
-			#d { text-align:center; margin:1em 0 -18em 0; z-index:0; position:relative; display:block }
-			.button { background:orange; color:#fff; padding:0.2em 0.5em; cursor:pointer }
-			.inactive { background:#999; color:#eee }
-		</style>
-	</head>
-
-	<body>
-		<div id="d">
-			<h1>Large mesh test</h1>
-
-			<span id="rcanvas" class="button inactive">2d canvas renderer</span>
-			<span id="rwebgl" class="button">WebGL renderer</span>
-			<br/>
-
-			<p>Lucy model from <a href="http://graphics.stanford.edu/data/3Dscanrep/">Stanford 3d scanning repository</a>
-			(decimated with <a href="http://meshlab.sourceforge.net/">Meshlab</a>).
-
-			<p>Please be patient while the mesh is loading. It may take a while, it's 2 MB file.
-
-			<br/>
-			<p>Best viewed in Chrome or Firefox using WebGL renderer.
-			<p>Canvas renderer is very slow for this demo and only diffuse material works there.
-			<p>Use the flag --allow-file-access-from-files if working localy in Chrome.
-		</div>
-
-		<pre id="log"></pre>
-
-		<script src="../build/three.js"></script>
-
-		<script src="js/loaders/BinaryLoader.js"></script>
-
-		<script src="js/renderers/Projector.js"></script>
-		<script src="js/renderers/CanvasRenderer.js"></script>
-
-		<script src="js/libs/stats.min.js"></script>
-
-		<script>
-
-			var SCREEN_WIDTH = window.innerWidth;
-			var SCREEN_HEIGHT = window.innerHeight;
-
-			var container, stats;
-
-			var camera, scene, canvasRenderer, webglRenderer;
-
-			var loader;
-
-			var mesh, zmesh, lightMesh;
-
-			var directionalLight, pointLight;
-
-			var mouseX = 0, mouseY = 0;
-
-			var windowHalfX = window.innerWidth / 2;
-			var windowHalfY = window.innerHeight / 2;
-
-			var render_canvas = 1, render_gl = 1;
-			var has_gl = 0;
-
-			var bcanvas = document.getElementById( "rcanvas" );
-			var bwebgl = document.getElementById( "rwebgl" );
-
-			document.addEventListener( 'mousemove', onDocumentMouseMove, false );
-
-			init();
-			animate();
-
-			render_canvas = !has_gl;
-			bwebgl.style.display = has_gl ? "inline" : "none";
-			bcanvas.className = render_canvas ? "button" : "button inactive";
-
-			function addMesh( geometry, scale, x, y, z, rx, ry, rz, material ) {
-
-				mesh = new THREE.Mesh( geometry, material );
-
-				mesh.scale.set( scale, scale, scale );
-				mesh.position.set( x, y, z );
-				mesh.rotation.set( rx, ry, rz );
-
-				scene.add( mesh );
-
-			}
-
-			function init() {
-
-				container = document.createElement( 'div' );
-				document.body.appendChild( container );
-
-				camera = new THREE.PerspectiveCamera( 50, SCREEN_WIDTH / SCREEN_HEIGHT, 1, 100000 );
-				camera.position.z = 1500;
-
-				scene = new THREE.Scene();
-
-				// LIGHTS
-
-				directionalLight = new THREE.DirectionalLight( 0xffffff, 0.5 );
-				directionalLight.position.set( 1, 1, 2 ).normalize();
-				scene.add( directionalLight );
-
-				pointLight = new THREE.PointLight( 0xffffff, 3, 1000 );
-				scene.add( pointLight );
-
-				// light representation
-
-				sphere = new THREE.SphereGeometry( 10, 16, 8, 1 );
-
-				lightMesh = new THREE.Mesh( sphere, new THREE.MeshBasicMaterial( { color: 0xffffff } ) );
-				scene.add( lightMesh );
-
-				if ( render_gl ) {
-					try {
-
-						webglRenderer = new THREE.WebGLRenderer( { antialias: true, alpha: true } );
-						webglRenderer.setPixelRatio( window.devicePixelRatio );
-						webglRenderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT );
-						webglRenderer.domElement.style.position = "relative";
-						container.appendChild( webglRenderer.domElement );
-						has_gl = 1;
-
-					} catch (e) {
-
-					}
-				}
-
-				if( render_canvas ) {
-
-					canvasRenderer = new THREE.CanvasRenderer();
-					canvasRenderer.setPixelRatio( window.devicePixelRatio );
-					canvasRenderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT );
-					container.appendChild( canvasRenderer.domElement );
-
-				}
-
-
-				stats = new Stats();
-				container.appendChild( stats.dom );
-
-				bcanvas.addEventListener( "click", toggleCanvas, false );
-				bwebgl.addEventListener( "click", toggleWebGL, false );
-
-				loader = new THREE.BinaryLoader();
-
-				var start = Date.now();
-
-				loader.load( 'obj/lucy/Lucy100k_bin.js', function ( geometry, materials ) {
-
-					addMesh( geometry, 0.75, 900, 0, 0,  0,0,0, new THREE.MeshPhongMaterial( { color: 0x030303, specular: 0x990000, shininess: 30 } ) );
-					addMesh( geometry, 0.75, 300, 0, 0,  0,0,0, new THREE.MultiMaterial( materials ) );
-					addMesh( geometry, 0.75, -300, 0, 0, 0,0,0, new THREE.MeshPhongMaterial( { color: 0x111111, specular: 0xffaa00, shininess: 10 } ) );
-					addMesh( geometry, 0.75, -900, 0, 0, 0,0,0, new THREE.MeshPhongMaterial( { color: 0x555555, specular: 0x666666, shininess: 10 } ) );
-
-					log( "geometry.vertices: " + geometry.vertices.length );
-					log( "geometry.faces: " + geometry.faces.length );
-
-					log( "model loaded and created in " + ( Date.now() - start ) + " ms" );
-
-				} );
-
-				//
-
-				window.addEventListener( 'resize', onWindowResize, false );
-
-			}
-
-			function onWindowResize() {
-
-				windowHalfX = window.innerWidth / 2;
-				windowHalfY = window.innerHeight / 2;
-
-				camera.aspect = window.innerWidth / window.innerHeight;
-				camera.updateProjectionMatrix();
-
-				if ( render_canvas ) canvasRenderer.setSize( window.innerWidth, window.innerHeight );
-				if ( render_gl && has_gl ) webglRenderer.setSize( window.innerWidth, window.innerHeight );
-
-			}
-
-			function onDocumentMouseMove( event ) {
-
-				mouseX = ( event.clientX - windowHalfX );
-				mouseY = ( event.clientY - windowHalfY );
-
-			}
-
-			//
-
-			function animate() {
-
-				requestAnimationFrame( animate );
-
-				render();
-				stats.update();
-
-			}
-
-			function render() {
-
-				var time = Date.now() * 0.001;
-
-				camera.position.x += ( mouseX - camera.position.x ) * 0.05;
-				camera.position.y += ( - mouseY - camera.position.y ) * 0.05;
-
-				camera.lookAt( scene.position );
-
-				pointLight.position.x = 600 * Math.cos( time );
-				pointLight.position.y = 400 * Math.cos( time * 1.25 );
-				pointLight.position.z = 300 * Math.sin( time );
-
-				lightMesh.position.copy( pointLight.position );
-
-				if ( render_canvas ) canvasRenderer.render( scene, camera );
-				if ( render_gl && has_gl ) webglRenderer.render( scene, camera );
-
-			}
-
-			function log( text ) {
-
-				var e = document.getElementById( "log" );
-				e.innerHTML = text + "<br/>" + e.innerHTML;
-
-			}
-
-			function toggleCanvas() {
-
-				render_canvas = !render_canvas;
-				bcanvas.className = render_canvas ? "button" : "button inactive";
-
-				render_gl = !render_canvas;
-				bwebgl.className = render_gl ? "button" : "button inactive";
-
-				if( has_gl )
-					webglRenderer.domElement.style.display = render_gl ? "block" : "none";
-
-				canvasRenderer.domElement.style.display = render_canvas ? "block" : "none";
-
-			}
-
-			function toggleWebGL() {
-
-				render_gl = !render_gl;
-				bwebgl.className = render_gl ? "button" : "button inactive";
-
-				render_canvas = !render_gl;
-				bcanvas.className = render_canvas ? "button" : "button inactive";
-
-				if( has_gl )
-					webglRenderer.domElement.style.display = render_gl ? "block" : "none";
-
-				canvasRenderer.domElement.style.display = render_canvas ? "block" : "none";
-
-			}
-
-		</script>
-
-	</body>
-</html>

+ 1 - 1
examples/webgl_geometry_nurbs.html

@@ -159,7 +159,7 @@
 					return nurbsSurface.getPoint(u, v);
 				};
 
-				var geometry = new THREE.ParametricGeometry( getSurfacePoint, 20, 20 );
+				var geometry = new THREE.ParametricBufferGeometry( getSurfacePoint, 20, 20 );
 				var material = new THREE.MeshLambertMaterial( { map: map, side: THREE.DoubleSide } );
 				var object = new THREE.Mesh( geometry, material );
 				object.position.set( - 200, 100, 0 );

+ 40 - 35
examples/webgl_interactive_instances_gpu.html

@@ -151,21 +151,23 @@
 			attribute vec3 pickingColor;
 		#else
 			attribute vec3 color;
+			varying vec3 vPosition;
 		#endif
 
 		varying vec3 vColor;
-		varying vec3 vPosition;
 
 		void main()	{
 
+			vec3 positionEye = ( modelViewMatrix * vec4( position, 1.0 ) ).xyz;
+
 			#ifdef PICKING
 				vColor = pickingColor;
 			#else
 				vColor = color;
+				vPosition = positionEye;
 			#endif
-			vPosition = ( modelViewMatrix * vec4( position, 1.0 ) ).xyz;
 
-			gl_Position = projectionMatrix * vec4( vPosition, 1.0 );
+			gl_Position = projectionMatrix * vec4( positionEye, 1.0 );
 
 		}
 
@@ -179,7 +181,10 @@
 		precision highp float;
 
 		varying vec3 vColor;
-		varying vec3 vPosition;
+
+		#ifndef PICKING
+			varying vec3 vPosition;
+		#endif
 
 		void main()	{
 
@@ -187,9 +192,9 @@
 				gl_FragColor = vec4( vColor, 1.0 );
 			#else
 				vec3 fdx = dFdx( vPosition );
-	            vec3 fdy = dFdy( vPosition );
-	            vec3 normal = normalize( cross( fdx, fdy ) );
-	            float diffuse = dot( normal, vec3( 0.0, 0.0, 1.0 ) );
+				vec3 fdy = dFdy( vPosition );
+				vec3 normal = normalize( cross( fdx, fdy ) );
+				float diffuse = dot( normal, vec3( 0.0, 0.0, 1.0 ) );
 
 				gl_FragColor = vec4( diffuse * vColor, 1.0 );
 			#endif
@@ -207,19 +212,19 @@
 		uniform mat4 projectionMatrix;
 
 		attribute vec3 position;
-		// attribute mat4 matrix;
 		attribute vec3 mcol0;
 		attribute vec3 mcol1;
 		attribute vec3 mcol2;
 		attribute vec3 mcol3;
+
 		#ifdef PICKING
 			attribute vec3 pickingColor;
 		#else
 			attribute vec3 color;
+			varying vec3 vPosition;
 		#endif
 
 		varying vec3 vColor;
-		varying vec3 vPosition;
 
 		void main()	{
 
@@ -230,14 +235,16 @@
 				vec4( mcol3, 1 )
 			);
 
+			vec3 positionEye = ( modelViewMatrix * matrix * vec4( position, 1.0 ) ).xyz;
+
 			#ifdef PICKING
 				vColor = pickingColor;
 			#else
 				vColor = color;
+				vPosition = positionEye;
 			#endif
-			vPosition = ( modelViewMatrix * matrix * vec4( position, 1.0 ) ).xyz;
 
-			gl_Position = projectionMatrix * vec4( vPosition, 1.0 );
+			gl_Position = projectionMatrix * vec4( positionEye, 1.0 );
 
 		}
 
@@ -251,7 +258,10 @@
 		precision highp float;
 
 		varying vec3 vColor;
-		varying vec3 vPosition;
+
+		#ifndef PICKING
+			varying vec3 vPosition;
+		#endif
 
 		void main()	{
 
@@ -259,9 +269,9 @@
 				gl_FragColor = vec4( vColor, 1.0 );
 			#else
 				vec3 fdx = dFdx( vPosition );
-	            vec3 fdy = dFdy( vPosition );
-	            vec3 normal = normalize( cross( fdx, fdy ) );
-	            float diffuse = dot( normal, vec3( 0.0, 0.0, 1.0 ) );
+				vec3 fdy = dFdy( vPosition );
+				vec3 normal = normalize( cross( fdx, fdy ) );
+				float diffuse = dot( normal, vec3( 0.0, 0.0, 1.0 ) );
 
 				gl_FragColor = vec4( diffuse * vColor, 1.0 );
 			#endif
@@ -280,13 +290,19 @@
 
 		attribute vec3 position;
 
-		varying vec3 vPosition;
+		#ifndef PICKING
+			varying vec3 vPosition;
+		#endif
 
 		void main()	{
 
-			vPosition = ( modelViewMatrix * vec4( position, 1.0 ) ).xyz;
+			vec3 positionEye = ( modelViewMatrix * vec4( position, 1.0 ) ).xyz;
+
+			#ifndef PICKING
+				vPosition = positionEye;
+			#endif
 
-			gl_Position = projectionMatrix * vec4( vPosition, 1.0 );
+			gl_Position = projectionMatrix * vec4( positionEye, 1.0 );
 
 		}
 
@@ -303,19 +319,18 @@
 			uniform vec3 pickingColor;
 		#else
 			uniform vec3 color;
+			varying vec3 vPosition;
 		#endif
 
-		varying vec3 vPosition;
-
 		void main()	{
 
 			#ifdef PICKING
 				gl_FragColor = vec4( pickingColor, 1.0 );
 			#else
 				vec3 fdx = dFdx( vPosition );
-	            vec3 fdy = dFdy( vPosition );
-	            vec3 normal = normalize( cross( fdx, fdy ) );
-	            float diffuse = dot( normal, vec3( 0.0, 0.0, 1.0 ) );
+				vec3 fdy = dFdy( vPosition );
+				vec3 normal = normalize( cross( fdx, fdy ) );
+				float diffuse = dot( normal, vec3( 0.0, 0.0, 1.0 ) );
 
 				gl_FragColor = vec4( diffuse * color, 1.0 );
 			#endif
@@ -486,13 +501,9 @@
 			loader.load( 'obj/Suzanne.js', function ( geo ) {
 
 				geo.computeBoundingBox();
-				geometrySize = geo.boundingBox.size();
+				geometrySize = geo.boundingBox.getSize();
 				geometryList.push( geo );
 
-				console.log( "method:", method );
-				console.log( "instanceCount:", instanceCount );
-
-				console.time( "init mesh" );
 				var start = window.performance.now();
 
 				switch ( method ){
@@ -517,15 +528,8 @@
 
 				render();
 
-				console.timeEnd( "init mesh", method );
 				var end = window.performance.now();
 
-				console.log( "material count:", materialList.length );
-				console.log( "geometry count:", geometryList.length );
-				console.log( "object count:", objectCount );
-				console.log( renderer.info.memory )
-				console.log( renderer.info.render )
-
 				document.getElementById( 'materialCount' ).innerText = materialList.length;
 				document.getElementById( 'objectCount' ).innerText = objectCount;
 				document.getElementById( 'drawcalls' ).innerText = renderer.info.render.calls;
@@ -971,6 +975,7 @@
 			camera.updateProjectionMatrix();
 
 			renderer.setSize( window.innerWidth, window.innerHeight );
+			pickingRenderTarget.setSize( window.innerWidth, window.innerHeight );
 
 		}
 

+ 9 - 28
examples/webgl_lights_hemisphere.html

@@ -47,8 +47,6 @@
 
 		<script src="../build/three.js"></script>
 
-		<script src="js/controls/TrackballControls.js"></script>
-
 		<script src="js/Detector.js"></script>
 		<script src="js/libs/stats.min.js"></script>
 
@@ -110,20 +108,6 @@
 				scene.fog = new THREE.Fog( 0xffffff, 1, 5000 );
 				scene.fog.color.setHSL( 0.6, 0, 1 );
 
-				/*
-				controls = new THREE.TrackballControls( camera );
-
-				controls.rotateSpeed = 1.0;
-				controls.zoomSpeed = 1.2;
-				controls.panSpeed = 0.8;
-
-				controls.noZoom = false;
-				controls.noPan = false;
-
-				controls.staticMoving = true;
-				controls.dynamicDampingFactor = 0.15;
-				*/
-
 				// LIGHTS
 
 				hemiLight = new THREE.HemisphereLight( 0xffffff, 0xffffff, 0.6 );
@@ -142,19 +126,18 @@
 
 				dirLight.castShadow = true;
 
-				dirLight.shadowMapWidth = 2048;
-				dirLight.shadowMapHeight = 2048;
+				dirLight.shadow.mapSize.width = 2048;
+				dirLight.shadow.mapSize.height = 2048;
 
 				var d = 50;
 
-				dirLight.shadowCameraLeft = -d;
-				dirLight.shadowCameraRight = d;
-				dirLight.shadowCameraTop = d;
-				dirLight.shadowCameraBottom = -d;
+				dirLight.shadow.camera.left = -d;
+				dirLight.shadow.camera.right = d;
+				dirLight.shadow.camera.top = d;
+				dirLight.shadow.camera.bottom = -d;
 
-				dirLight.shadowCameraFar = 3500;
-				dirLight.shadowBias = -0.0001;
-				//dirLight.shadowCameraVisible = true;
+				dirLight.shadow.camera.far = 3500;
+				dirLight.shadow.bias = -0.0001;
 
 				// GROUND
 
@@ -193,7 +176,7 @@
 
 				var loader = new THREE.JSONLoader();
 
-				loader.load( "models/animated/flamingo.js", function( geometry ) {
+				loader.load( 'models/animated/flamingo.js', function( geometry ) {
 
 					var material = new THREE.MeshPhongMaterial( { color: 0xffffff, specular: 0xffffff, shininess: 20, morphTargets: true, vertexColors: THREE.FaceColors, shading: THREE.FlatShading } );
 					var mesh = new THREE.Mesh( geometry, material );
@@ -282,8 +265,6 @@
 
 				var delta = clock.getDelta();
 
-				//controls.update();
-
 				for ( var i = 0; i < mixers.length; i ++ ) {
 
 					mixers[ i ].update( delta );

+ 8 - 12
examples/webgl_loader_gltf.html

@@ -126,11 +126,7 @@
 	</div>
 		<script src="../build/three.js"></script>
 		<script src="js/controls/OrbitControls.js"></script>
-		<script src="js/loaders/gltf/glTF-parser.js"></script>
-		<script src="js/loaders/gltf/glTFLoader.js"></script>
-		<script src="js/loaders/gltf/glTFLoaderUtils.js"></script>
-		<script src="js/loaders/gltf/glTFAnimation.js"></script>
-		<script src="js/loaders/gltf/glTFShaders.js"></script>
+		<script src="js/loaders/GLTFLoader.js"></script>
 
 		<script>
 			var orbitControls = null;
@@ -235,7 +231,8 @@
 					scene.add(ground);
 				}
 
-				loader = new THREE.glTFLoader;
+				THREE.GLTFLoader.Shaders.removeAll(); // remove all previous shaders
+				loader = new THREE.GLTFLoader;
 				var loadStartTime = Date.now();
 				var status = document.getElementById("status");
 				status.innerHTML = "Loading...";
@@ -356,8 +353,8 @@
 
 			function animate() {
 				requestAnimationFrame( animate );
-				THREE.glTFAnimator.update();
-				THREE.glTFShaders.update(scene, camera);
+				THREE.GLTFLoader.Animations.update();
+				THREE.GLTFLoader.Shaders.update(scene, camera);
 				if (cameraIndex == 0)
 					orbitControls.update();
 				render();
@@ -393,8 +390,8 @@
 				{
 					name : "Monster", url : "./models/gltf/monster/%s/monster.gltf",
 					cameraPos: new THREE.Vector3(30, 10, 70),
-					objectScale: new THREE.Vector3(0.01, 0.01, 0.01),
-					objectPosition: new THREE.Vector3(2, 6, 0),
+					objectScale: new THREE.Vector3(0.4, 0.4, 0.4),
+					objectPosition: new THREE.Vector3(2, 1, 0),
 					objectRotation: new THREE.Euler(0, - 3 * Math.PI / 4, 0),
 					animationTime: 3,
 					addLights:true,
@@ -423,8 +420,7 @@
 					addLights:true,
 					addGround:true,
 					shadows:true
-				},
-
+				}
 			];
 
 			function buildSceneList() {

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