浏览代码

Merge branch 'dev' into 91dev-shadercompile

sunag 7 年之前
父节点
当前提交
4f67097030
共有 100 个文件被更改,包括 6126 次插入2677 次删除
  1. 647 886
      build/three.js
  2. 307 330
      build/three.min.js
  3. 647 886
      build/three.module.js
  4. 1 4
      docs/api/animation/AnimationAction.html
  5. 4 7
      docs/api/cameras/Camera.html
  6. 0 3
      docs/api/core/BufferAttribute.html
  7. 3 2
      docs/api/core/BufferGeometry.html
  8. 0 21
      docs/api/core/DirectGeometry.html
  9. 10 14
      docs/api/core/Object3D.html
  10. 1 0
      docs/api/deprecated/DeprecatedList.html
  11. 9 9
      docs/api/math/Vector3.html
  12. 6 2
      docs/api/renderers/WebGLRenderer.html
  13. 1 1
      docs/api/renderers/shaders/ShaderChunk.html
  14. 51 0
      docs/examples/BufferGeometryUtils.html
  15. 4 2
      docs/examples/exporters/GLTFExporter.html
  16. 29 29
      docs/examples/loaders/GLTFLoader.html
  17. 1 0
      docs/list.js
  18. 3 0
      docs/manual/introduction/Useful-links.html
  19. 26 0
      editor/js/Menubar.File.js
  20. 34 0
      editor/js/Sidebar.Object.js
  21. 1 0
      editor/js/libs/ui.three.js
  22. 10 9
      examples/canvas_geometry_nurbs.html
  23. 2 2
      examples/canvas_geometry_shapes.html
  24. 4 2
      examples/canvas_lines.html
  25. 1 0
      examples/files.js
  26. 188 0
      examples/js/BufferGeometryUtils.js
  27. 23 1
      examples/js/controls/EditorControls.js
  28. 23 2
      examples/js/controls/OrbitControls.js
  29. 366 145
      examples/js/exporters/GLTFExporter.js
  30. 2 2
      examples/js/exporters/OBJExporter.js
  31. 7 12
      examples/js/loaders/ColladaLoader.js
  32. 730 72
      examples/js/loaders/EXRLoader.js
  33. 85 24
      examples/js/loaders/GLTFLoader.js
  34. 1 1
      examples/js/loaders/MMDLoader.js
  35. 2 4
      examples/js/loaders/OBJLoader.js
  36. 7 5
      examples/js/math/Lut.js
  37. 0 2
      examples/js/objects/Lensflare.js
  38. 2 1
      examples/js/objects/Sky.js
  39. 1 1
      examples/js/postprocessing/AdaptiveToneMappingPass.js
  40. 1 1
      examples/js/postprocessing/BokehPass.js
  41. 8 4
      examples/js/postprocessing/SAOPass.js
  42. 2 2
      examples/js/postprocessing/SMAAPass.js
  43. 1 1
      examples/js/postprocessing/ShaderPass.js
  44. 1 1
      examples/js/renderers/WebGLDeferredRenderer.js
  45. 10 1
      examples/js/vr/DaydreamController.js
  46. 10 1
      examples/js/vr/GearVRController.js
  47. 17 10
      examples/misc_controls_orbit.html
  48. 1 1
      examples/misc_controls_trackball.html
  49. 29 3
      examples/misc_exporter_gltf.html
  50. 二进制
      examples/models/gltf/BotSkinned/glTF-MaterialsUnlit/AvatarBotA_Head_Tex_Combined.png
  51. 二进制
      examples/models/gltf/BotSkinned/glTF-MaterialsUnlit/AvatarBotA_Tex_Combined.png
  52. 2265 0
      examples/models/gltf/BotSkinned/glTF-MaterialsUnlit/Bot_Skinned.gltf
  53. 二进制
      examples/models/gltf/BotSkinned/glTF-MaterialsUnlit/buffer.bin
  54. 二进制
      examples/textures/piz_compressed.exr
  55. 1 1
      examples/webgl_buffergeometry.html
  56. 1 1
      examples/webgl_buffergeometry_lines.html
  57. 1 1
      examples/webgl_buffergeometry_lines_indexed.html
  58. 1 1
      examples/webgl_buffergeometry_points.html
  59. 1 1
      examples/webgl_buffergeometry_points_interleaved.html
  60. 1 1
      examples/webgl_buffergeometry_uint.html
  61. 6 5
      examples/webgl_decals.html
  62. 1 1
      examples/webgl_effects_anaglyph.html
  63. 1 1
      examples/webgl_effects_parallaxbarrier.html
  64. 12 9
      examples/webgl_geometry_nurbs.html
  65. 1 1
      examples/webgl_interactive_buffergeometry.html
  66. 1 1
      examples/webgl_lights_pointlights2.html
  67. 1 1
      examples/webgl_lines_colors.html
  68. 14 1
      examples/webgl_loader_gltf_extensions.html
  69. 1 1
      examples/webgl_loader_nrrd.html
  70. 1 1
      examples/webgl_loader_texture_exr.html
  71. 1 1
      examples/webgl_loader_vrml.html
  72. 1 1
      examples/webgl_loader_vtk.html
  73. 1 1
      examples/webgl_materials_bumpmap.html
  74. 1 1
      examples/webgl_materials_cubemap_dynamic.html
  75. 378 0
      examples/webgl_materials_curvature.html
  76. 1 1
      examples/webgl_materials_envmaps_hdr.html
  77. 9 21
      examples/webgl_materials_modified.html
  78. 1 1
      examples/webgl_materials_normalmap.html
  79. 1 1
      examples/webgl_materials_shaders_fresnel.html
  80. 1 1
      examples/webgl_materials_skin.html
  81. 1 1
      examples/webgl_materials_video.html
  82. 1 1
      examples/webgl_multiple_renderers.html
  83. 1 1
      examples/webgl_performance_static.html
  84. 1 1
      examples/webgl_points_dynamic.html
  85. 1 1
      examples/webgl_postprocessing_advanced.html
  86. 1 1
      examples/webgl_postprocessing_backgrounds.html
  87. 1 1
      examples/webgl_postprocessing_dof.html
  88. 1 1
      examples/webgl_postprocessing_dof2.html
  89. 1 1
      examples/webgl_postprocessing_godrays.html
  90. 1 1
      examples/webgl_postprocessing_masking.html
  91. 1 1
      examples/webgl_postprocessing_outline.html
  92. 1 1
      examples/webgl_postprocessing_procedural.html
  93. 1 1
      examples/webgl_postprocessing_smaa.html
  94. 1 1
      examples/webgl_postprocessing_ssaa.html
  95. 1 1
      examples/webgl_postprocessing_ssaa_unbiased.html
  96. 1 1
      examples/webgl_postprocessing_ssao.html
  97. 1 1
      examples/webgl_postprocessing_taa.html
  98. 1 1
      examples/webgl_postprocessing_unreal_bloom.html
  99. 83 95
      examples/webgl_shaders_ocean.html
  100. 1 1
      examples/webgl_shadowmap_performance.html

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


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


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


+ 1 - 4
docs/api/animation/AnimationAction.html

@@ -91,10 +91,7 @@
 			The number of repetitions of the performed [page:AnimationClip] over the course of this action.
 			The number of repetitions of the performed [page:AnimationClip] over the course of this action.
 			Can be set via [page:.setLoop setLoop]. Default is *Infinity*.<br /><br />
 			Can be set via [page:.setLoop setLoop]. Default is *Infinity*.<br /><br />
 			Setting this number has no effect, if the [page:.loop loop mode] is set to
 			Setting this number has no effect, if the [page:.loop loop mode] is set to
-			[page:Animation THREE.LoopOnce].<br /><br />
-
-			Note: The first run is not taken into account. For example: if *repetition* is set to 2, the
-			total number of executed rounds will be 3.
+			[page:Animation THREE.LoopOnce].
 		</div>
 		</div>
 
 
 		<h3>[property:Number time]</h3>
 		<h3>[property:Number time]</h3>

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

@@ -69,16 +69,13 @@
 		Copy the properties from the source camera into this one.
 		Copy the properties from the source camera into this one.
 		</div>
 		</div>
 
 
-		<h3>[method:Vector3 getWorldDirection]( [param:Vector3 optionalTarget] )</h3>
+		<h3>[method:Vector3 getWorldDirection]( [param:Vector3 target] )</h3>
 		<div>
 		<div>
-		Returns a [page:Vector3] representing the world space direction in which the camera is looking.<br /><br />
 
 
-		Note: This is not the camera’s positive, but its negative z-axis, in contrast to
-		[page:Object3D.getWorldDirection getWorldDirection] of the base class (Object3D).<br /><br />
+		[page:Vector3 target] — the result will be copied into this Vector3. <br /><br />
 
 
-		If an [page:Vector3 optionalTarget] vector is specified, the result will be copied into this vector
-		(which can be reused in this way), otherwise a new vector will be created.
-		</div>
+		Returns a [page:Vector3] representing the world space direction in which the camera is looking.
+		(Note: A camera looks down its local, negative z-axis).<br /><br />
 
 
 		<h2>Source</h2>
 		<h2>Source</h2>
 
 

+ 0 - 3
docs/api/core/BufferAttribute.html

@@ -140,9 +140,6 @@
 		<h3>[method:BufferAttribute copyColorsArray]( colors ) </h3>
 		<h3>[method:BufferAttribute copyColorsArray]( colors ) </h3>
 		<div>Copy an array representing RGB color values into [page:BufferAttribute.array array].</div>
 		<div>Copy an array representing RGB color values into [page:BufferAttribute.array array].</div>
 
 
-		<h3>[method:BufferAttribute copyIndicesArray]( indices ) </h3>
-		<div>Copy an array representing [page:Face3] indices into [page:BufferAttribute.array array].</div>
-
 		<h3>[method:BufferAttribute copyVector2sArray]( vectors ) </h3>
 		<h3>[method:BufferAttribute copyVector2sArray]( vectors ) </h3>
 		<div>Copy an array representing [page:Vector2]s into [page:BufferAttribute.array array].</div>
 		<div>Copy an array representing [page:Vector2]s into [page:BufferAttribute.array array].</div>
 
 

+ 3 - 2
docs/api/core/BufferGeometry.html

@@ -134,8 +134,9 @@
 
 
 			Each group is an object of the form:
 			Each group is an object of the form:
 			<code>{ start: Integer, count: Integer, materialIndex: Integer }</code>
 			<code>{ start: Integer, count: Integer, materialIndex: Integer }</code>
-			where start specifies the index of the first vertex in this draw call, count specifies
-			how many vertices are included, and materialIndex specifies the material array index to use.<br /><br />
+			where start specifies the first element in this draw call – the first vertex for non-indexed geometry,
+			otherwise the first triangle index. Count specifies how many vertices (or indices) are included, and
+			materialIndex specifies the material array index to use.<br /><br />
 
 
 			Use [page:.addGroup] to add groups, rather than modifying this array directly.
 			Use [page:.addGroup] to add groups, rather than modifying this array directly.
 		</div>
 		</div>

+ 0 - 21
docs/api/core/DirectGeometry.html

@@ -34,9 +34,6 @@
 		<h3>[property:Array type]</h3>
 		<h3>[property:Array type]</h3>
 		<div>String 'DirectGeometry'.</div>
 		<div>String 'DirectGeometry'.</div>
 
 
-		<h3>[property:Array indices]</h3>
-		<div>Initialiased as an empty array, this is populated by [page:.fromGeometry]().</div>
-
 		<h3>[property:Array vertices]</h3>
 		<h3>[property:Array vertices]</h3>
 		<div>Initialiased as an empty array, this is populated by [page:.fromGeometry]().</div>
 		<div>Initialiased as an empty array, this is populated by [page:.fromGeometry]().</div>
 
 
@@ -94,30 +91,12 @@
 
 
 		<h2>Methods</h2>
 		<h2>Methods</h2>
 
 
-		<h3>[page:EventDispatcher EventDispatcher] methods are available on this class.</h3>
-
-		<h3>[property:null computeBoundingBox](  )</h3>
-		<div>
-		 See [page:Geometry.computeBoundingBox].
-		</div>
-
-		<h3>[property:null computeBoundingSphere](  )</h3>
-		<div>
-		 See [page:Geometry.computeBoundingSphere].
-		</div>
-
 		<h3>[property:null computeGroups]( [page:Geometry geometry] )</h3>
 		<h3>[property:null computeGroups]( [page:Geometry geometry] )</h3>
 		<div>
 		<div>
 			Compute the parts of the geometry that have different materialIndex.
 			Compute the parts of the geometry that have different materialIndex.
 			See [page:BufferGeometry.groups].
 			See [page:BufferGeometry.groups].
 		</div>
 		</div>
 
 
-		<h3>[method:null dispose]()</h3>
-		<div>
-		Disposes the object from memory. <br />
-		You need to call this when you want the directGeometry removed while the application is running.
-		</div>
-
 		<h3>[property:null fromGeometry]( [page:Geometry geometry] )</h3>
 		<h3>[property:null fromGeometry]( [page:Geometry geometry] )</h3>
 		<div>Pass in a [page:Geometry] instance for conversion.</div>
 		<div>Pass in a [page:Geometry] instance for conversion.</div>
 
 

+ 10 - 14
docs/api/core/Object3D.html

@@ -240,41 +240,37 @@
 		Searches through the object's children and returns the first with a property that matches the value given.
 		Searches through the object's children and returns the first with a property that matches the value given.
 		</div>
 		</div>
 
 
-		<h3>[method:Vector3 getWorldPosition]( [param:Vector3 optionalTarget] )</h3>
+		<h3>[method:Vector3 getWorldPosition]( [param:Vector3 target] )</h3>
 		<div>
 		<div>
-		optionalTarget — (optional) target to set the result. Otherwise, a new [page:Vector3] is instantiated. <br /><br />
+		[page:Vector3 target] — the result will be copied into this Vector3. <br /><br />
 
 
 		Returns a vector representing the position of the object in world space.
 		Returns a vector representing the position of the object in world space.
 		</div>
 		</div>
 
 
-		<h3>[method:Quaternion getWorldQuaternion]( [param:Quaternion optionalTarget] )</h3>
+		<h3>[method:Quaternion getWorldQuaternion]( [param:Quaternion target] )</h3>
 		<div>
 		<div>
-		optionalTarget — (optional) if specified, the result will be copied into this Quaternion,
-		otherwise a new Quaternion will be created. <br /><br />
+		[page:Quaternion target] — the result will be copied into this Quaternion. <br /><br />
 
 
 		Returns a quaternion representing the rotation of the object in world space.
 		Returns a quaternion representing the rotation of the object in world space.
 		</div>
 		</div>
 
 
-		<h3>[method:Euler getWorldRotation]( [param:Euler optionalTarget] )</h3>
+		<h3>[method:Euler getWorldRotation]( [param:Euler target] )</h3>
 		<div>
 		<div>
-		optionalTarget — (optional) if specified, the result will be copied into this Euler,
-		otherwise a new Euler will be created. <br /><br />
+		[page:Euler target] — the result will be copied into this Euler. <br /><br />
 
 
 		Returns the euler angles representing the rotation of the object in world space.
 		Returns the euler angles representing the rotation of the object in world space.
 		</div>
 		</div>
 
 
-		<h3>[method:Vector3 getWorldScale]( [param:Vector3 optionalTarget] )</h3>
+		<h3>[method:Vector3 getWorldScale]( [param:Vector3 target] )</h3>
 		<div>
 		<div>
-		[page:Vector3 optionalTarget] — (optional) if specified, the result will be copied into this Vector3,
-		otherwise a new Vector3 will be created. <br /><br />
+		[page:Vector3 target] — the result will be copied into this Vector3. <br /><br />
 
 
 		Returns a vector of the scaling factors applied to the object for each axis in world space.
 		Returns a vector of the scaling factors applied to the object for each axis in world space.
 		</div>
 		</div>
 
 
-		<h3>[method:Vector3 getWorldDirection]( [param:Vector3 optionalTarget] )</h3>
+		<h3>[method:Vector3 getWorldDirection]( [param:Vector3 target] )</h3>
 		<div>
 		<div>
-		[page:Vector3 optionalTarget] — (optional) if specified, the result will be copied into this Vector3,
-		otherwise a new Vector3 will be created. <br /><br />
+		[page:Vector3 target] — the result will be copied into this Vector3. <br /><br />
 
 
 		Returns a vector representing the direction of object's positive z-axis in world space.
 		Returns a vector representing the direction of object's positive z-axis in world space.
 		</div>
 		</div>

+ 1 - 0
docs/api/deprecated/DeprecatedList.html

@@ -51,6 +51,7 @@
 
 
 		<h3>[page:BufferAttribute]</h3>
 		<h3>[page:BufferAttribute]</h3>
 		<div>BufferAttribute.length has been renamed to [page:BufferAttribute.count].</div>
 		<div>BufferAttribute.length has been renamed to [page:BufferAttribute.count].</div>
+		<div>BufferAttribute.copyIndicesArray() has been removed.</div>
 
 
 
 
 		<h3>[page:DynamicBufferAttribute]</h3>
 		<h3>[page:DynamicBufferAttribute]</h3>

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

@@ -273,15 +273,6 @@ var d = a.distanceTo( b );
 		- alpha = 0 will be [page:Vector3 v1], and alpha = 1 will be [page:Vector3 v2].
 		- alpha = 0 will be [page:Vector3 v1], and alpha = 1 will be [page:Vector3 v2].
 		</div>
 		</div>
 
 
-		<h3>[method:Vector3 negate]()</h3>
-		<div>Inverts this vector - i.e. sets x = -x, y = -y and z = -z.</div>
-
-		<h3>[method:Vector3 normalize]()</h3>
-		<div>
-		Convert this vector to a [link:https://en.wikipedia.org/wiki/Unit_vector unit vector] - that is, sets it equal to the vector with the same direction
-		as this one, but [page:.length length] 1.
-		</div>
-
 		<h3>[method:Vector3 max]( [param:Vector3 v] )</h3>
 		<h3>[method:Vector3 max]( [param:Vector3 v] )</h3>
 		<div>
 		<div>
 		If this vector's x, y or z value is less than [page:Vector3 v]'s x, y or z value, replace
 		If this vector's x, y or z value is less than [page:Vector3 v]'s x, y or z value, replace
@@ -303,6 +294,15 @@ var d = a.distanceTo( b );
 		<h3>[method:Vector3 multiplyVectors]( [param:Vector3 a], [param:Vector3 b] )</h3>
 		<h3>[method:Vector3 multiplyVectors]( [param:Vector3 a], [param:Vector3 b] )</h3>
 		<div>Sets this vector equal to [page:Vector3 a] * [page:Vector3 b], component-wise.</div>
 		<div>Sets this vector equal to [page:Vector3 a] * [page:Vector3 b], component-wise.</div>
 
 
+		<h3>[method:Vector3 negate]()</h3>
+		<div>Inverts this vector - i.e. sets x = -x, y = -y and z = -z.</div>
+
+		<h3>[method:Vector3 normalize]()</h3>
+		<div>
+		Convert this vector to a [link:https://en.wikipedia.org/wiki/Unit_vector unit vector] - that is, sets it equal to the vector with the same direction
+		as this one, but [page:.length length] 1.
+		</div>
+
 		<h3>[method:Vector3 project]( [param:Camera camera] )</h3>
 		<h3>[method:Vector3 project]( [param:Camera camera] )</h3>
 		<div>
 		<div>
 		[page:Camera camera] — camera to use in the projection.<br /><br />
 		[page:Camera camera] — camera to use in the projection.<br /><br />

+ 6 - 2
docs/api/renderers/WebGLRenderer.html

@@ -180,9 +180,9 @@
 			<li>render:
 			<li>render:
 				<ul>
 				<ul>
 					<li>calls</li>
 					<li>calls</li>
-					<li>vertices</li>
-					<li>faces</li>
+					<li>triangles</li>
 					<li>points</li>
 					<li>points</li>
+					<li>lines</li>
 				</ul>
 				</ul>
 			</li>
 			</li>
 			<li>programs
 			<li>programs
@@ -286,6 +286,10 @@
 		See [page:WebGLRenderer.capabilities capabilities.maxTextures].
 		See [page:WebGLRenderer.capabilities capabilities.maxTextures].
 		</div>
 		</div>
 
 
+		<h3>[method:null animate]( [param:Function callback] )</h3>
+		<div>[page:Function callback] — The function will be called every available frame. If `null` is passed it will stop any already ongoing animation.</div>
+		<div>A build in function that can be used instead of [link:https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame requestAnimationFrame]. For WebVR projects this function must be used.</div>
+
 		<h3>[method:null clear]( [param:Boolean color], [param:Boolean depth], [param:Boolean stencil] )</h3>
 		<h3>[method:null clear]( [param:Boolean color], [param:Boolean depth], [param:Boolean stencil] )</h3>
 		<div>
 		<div>
 		Tells the renderer to clear its color, depth or stencil drawing buffer(s).
 		Tells the renderer to clear its color, depth or stencil drawing buffer(s).

+ 1 - 1
docs/api/renderers/shaders/ShaderChunk.html

@@ -10,7 +10,7 @@
 	<body>
 	<body>
 		<h1>[name]</h1>
 		<h1>[name]</h1>
 
 
-		<div class="desc">Shader chunks for WebLG Shader library</div>
+		<div class="desc">Shader chunks for WebGL Shader library</div>
 
 
 
 
 
 

+ 51 - 0
docs/examples/BufferGeometryUtils.html

@@ -0,0 +1,51 @@
+<!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">
+    A class containing utility functions for [page:BufferGeometry BufferGeometry] instances.<br /><br />
+    </div>
+
+
+    <h2>Methods</h2>
+
+    <h3>[method:null computeTangents]( [param:BufferGeometry geometry] )</h3>
+    <div>
+    geometry -- A [page:BufferGeometry BufferGeometry] instance, which must have index, position, normal, and uv attributes.<br /><br />
+
+    Calculates and adds tangent attribute to a geometry.<br /><br />
+
+    </div>
+
+    <h3>[method:BufferGeometry mergeBufferGeometries]( [param:Array geometries] )</h3>
+    <div>
+    geometries -- Array of [page:BufferGeometry BufferGeometry] instances.<br /><br />
+
+    Merges a set of geometries into a single instance. All geometries must have compatible attributes.
+    If merge does not succeed, the method returns null.<br /><br />
+
+    </div>
+
+    <h3>[method:BufferAttribute mergeBufferAttributes]( [param:Array attributes] )</h3>
+    <div>
+    attributes -- Array of [page:BufferAttribute BufferAttribute] instances.<br /><br />
+
+    Merges a set of attributes into a single instance. All attributes must have compatible properties
+    and types, and [page:InterleavedBufferAttribute InterleavedBufferAttributes] are not supported. If merge does not succeed, the method
+    returns null.
+
+    </div>
+
+    <h2>Source</h2>
+
+    [link:https://github.com/mrdoob/three.js/blob/master/examples/js/BufferGeometryUtils.js examples/js/BufferGeometryUtils.js]
+  </body>
+</html>

+ 4 - 2
docs/examples/exporters/GLTFExporter.html

@@ -16,7 +16,7 @@
 		<a href="https://www.khronos.org/gltf">glTF</a> (GL Transmission Format) is an
 		<a href="https://www.khronos.org/gltf">glTF</a> (GL Transmission Format) is an
 		<a href="https://github.com/KhronosGroup/glTF/tree/master/specification/2.0">open format specification</a>
 		<a href="https://github.com/KhronosGroup/glTF/tree/master/specification/2.0">open format specification</a>
 		for efficient delivery and loading of 3D content. Assets may be provided either in JSON (.gltf)
 		for efficient delivery and loading of 3D content. Assets may be provided either in JSON (.gltf)
-		or binary (.glb) format. External files store textures (.jpg, .png, ...) and additional binary
+		or binary (.glb) format. External files store textures (.jpg, .png) and additional binary
 		data (.bin). A glTF asset may deliver one or more scenes, including meshes, materials,
 		data (.bin). A glTF asset may deliver one or more scenes, including meshes, materials,
 		textures, skins, skeletons, morph targets, animations, lights, and/or cameras.
 		textures, skins, skeletons, morph targets, animations, lights, and/or cameras.
 		</div>
 		</div>
@@ -80,7 +80,9 @@ exporter.parse( [ scene1, object1, object2, scene2 ], ...)
 			<li>truncateDrawRange - bool. Export just the attributes within the drawRange, if defined, instead of exporting the whole array. Default is true.</li>
 			<li>truncateDrawRange - bool. Export just the attributes within the drawRange, if defined, instead of exporting the whole array. Default is true.</li>
 			<li>binary - bool. Export in binary (.glb) format, returning an ArrayBuffer. Default is false.</li>
 			<li>binary - bool. Export in binary (.glb) format, returning an ArrayBuffer. Default is false.</li>
 			<li>embedImages - bool. Export with images embedded into the glTF asset. Default is true.</li>
 			<li>embedImages - bool. Export with images embedded into the glTF asset. Default is true.</li>
-			<li>animations - Array<[page:AnimationClip AnimationClip]>. List of animations to be included in the export.
+			<li>animations - Array<[page:AnimationClip AnimationClip]>. List of animations to be included in the export.</li>
+			<li>forceIndices - bool. Generate indices for non-index geometry and export with them. Default is false.</li>
+			<li>forcePowerOfTwoTextures - bool. Export with images resized to POT size. This option works only if embedImages is true. Default is false.</li>
 		</ul>
 		</ul>
 		</div>
 		</div>
 		<div>
 		<div>

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

@@ -15,7 +15,7 @@
 		<a href="https://www.khronos.org/gltf">glTF</a> (GL Transmission Format) is an
 		<a href="https://www.khronos.org/gltf">glTF</a> (GL Transmission Format) is an
 		<a href="https://github.com/KhronosGroup/glTF/tree/master/specification/2.0">open format specification</a>
 		<a href="https://github.com/KhronosGroup/glTF/tree/master/specification/2.0">open format specification</a>
 		for efficient delivery and loading of 3D content. Assets may be provided either in JSON (.gltf)
 		for efficient delivery and loading of 3D content. Assets may be provided either in JSON (.gltf)
-		or binary (.glb) format. External files store textures (.jpg, .png, ...) and additional binary
+		or binary (.glb) format. External files store textures (.jpg, .png) and additional binary
 		data (.bin). A glTF asset may deliver one or more scenes, including meshes, materials,
 		data (.bin). A glTF asset may deliver one or more scenes, including meshes, materials,
 		textures, skins, skeletons, morph targets, animations, lights, and/or cameras.
 		textures, skins, skeletons, morph targets, animations, lights, and/or cameras.
 		</div>
 		</div>
@@ -45,43 +45,43 @@
 		<h2>Example</h2>
 		<h2>Example</h2>
 
 
 		<code>
 		<code>
-			// Instantiate a loader
-			var loader = new THREE.GLTFLoader();
+		// Instantiate a loader
+		var loader = new THREE.GLTFLoader();
 
 
-			// Optional: Provide a DRACOLoader instance to decode compressed mesh data
-			THREE.DRACOLoader.setDecoderPath( '/examples/js/libs/draco' );
-			loader.setDRACOLoader( new THREE.DRACOLoader() );
+		// Optional: Provide a DRACOLoader instance to decode compressed mesh data
+		THREE.DRACOLoader.setDecoderPath( '/examples/js/libs/draco' );
+		loader.setDRACOLoader( new THREE.DRACOLoader() );
 
 
-			// Load a glTF resource
-			loader.load(
-				// resource URL
-				'models/gltf/duck/duck.gltf',
-				// called when the resource is loaded
-				function ( gltf ) {
+		// Load a glTF resource
+		loader.load(
+			// resource URL
+			'models/gltf/duck/duck.gltf',
+			// called when the resource is loaded
+			function ( gltf ) {
 
 
-					scene.add( gltf.scene );
+				scene.add( gltf.scene );
 
 
-					gltf.animations; // Array&lt;THREE.AnimationClip&gt;
-					gltf.scene; // THREE.Scene
-					gltf.scenes; // Array&lt;THREE.Scene&gt;
-					gltf.cameras; // Array&lt;THREE.Camera&gt;
-					gltf.asset; // Object
+				gltf.animations; // Array&lt;THREE.AnimationClip&gt;
+				gltf.scene; // THREE.Scene
+				gltf.scenes; // Array&lt;THREE.Scene&gt;
+				gltf.cameras; // Array&lt;THREE.Camera&gt;
+				gltf.asset; // Object
 
 
-				},
-				// called when loading is in progresses
-				function ( xhr ) {
+			},
+			// called when loading is in progresses
+			function ( xhr ) {
 
 
-					console.log( ( xhr.loaded / xhr.total * 100 ) + '% loaded' );
+				console.log( ( xhr.loaded / xhr.total * 100 ) + '% loaded' );
 
 
-				},
-				// called when loading has errors
-				function ( error ) {
+			},
+			// called when loading has errors
+			function ( error ) {
 
 
-					console.log( 'An error happened' );
+				console.log( 'An error happened' );
 
 
-				}
-			);
-			</code>
+			}
+		);
+		</code>
 
 
 		[example:webgl_loader_gltf]
 		[example:webgl_loader_gltf]
 
 

+ 1 - 0
docs/list.js

@@ -386,6 +386,7 @@ var list = {
 		},
 		},
 
 
 		"Utils": {
 		"Utils": {
+			"BufferGeometryUtils": "examples/BufferGeometryUtils",
 			"SceneUtils": "examples/utils/SceneUtils"
 			"SceneUtils": "examples/utils/SceneUtils"
 		}
 		}
 
 

+ 3 - 0
docs/manual/introduction/Useful-links.html

@@ -91,6 +91,9 @@
 
 
 		<h2>Examples</h2>
 		<h2>Examples</h2>
 		<ul>
 		<ul>
+			<li>
+				[link:https://github.com/edwinwebb/three-seed/ three-seed] - three.js starter project with ES6 and Webpack
+			</li>
 			<li>
 			<li>
 				[link:http://stemkoski.github.io/Three.js/index.html Professor Stemkoskis Examples] - a collection of beginner friendly
 				[link:http://stemkoski.github.io/Three.js/index.html Professor Stemkoskis Examples] - a collection of beginner friendly
 				examples built using three.js r60.
 				examples built using three.js r60.

+ 26 - 0
editor/js/Menubar.File.js

@@ -184,6 +184,26 @@ Menubar.File = function ( editor ) {
 
 
 	options.add( new UI.HorizontalRule() );
 	options.add( new UI.HorizontalRule() );
 
 
+	// Export GLB
+
+	var option = new UI.Row();
+	option.setClass( 'option' );
+	option.setTextContent( 'Export GLB' );
+	option.onClick( function () {
+
+		var exporter = new THREE.GLTFExporter();
+
+		exporter.parse( editor.scene, function ( result ) {
+
+			saveArrayBuffer( result, 'scene.glb' );
+
+			// forceIndices: true, forcePowerOfTwoTextures: true
+			// to allow compatibility with facebook
+		}, { binary: true, forceIndices: true, forcePowerOfTwoTextures: true } );
+		
+	} );
+	options.add( option );
+
 	// Export GLTF
 	// Export GLTF
 
 
 	var option = new UI.Row();
 	var option = new UI.Row();
@@ -352,6 +372,12 @@ Menubar.File = function ( editor ) {
 
 
 	}
 	}
 
 
+	function saveArrayBuffer( buffer, filename ) {
+
+		save( new Blob( [ buffer ], { type: 'application/octet-stream' } ), filename );
+
+	}
+
 	function saveString( text, filename ) {
 	function saveString( text, filename ) {
 
 
 		save( new Blob( [ text ], { type: 'text/plain' } ), filename );
 		save( new Blob( [ text ], { type: 'text/plain' } ), filename );

+ 34 - 0
editor/js/Sidebar.Object.js

@@ -259,6 +259,26 @@ Sidebar.Object = function ( editor ) {
 
 
 	container.add( objectVisibleRow );
 	container.add( objectVisibleRow );
 
 
+	// frustumCulled
+
+	var objectFrustumCulledRow = new UI.Row();
+	var objectFrustumCulled = new UI.Checkbox().onChange( update );
+
+	objectFrustumCulledRow.add( new UI.Text( 'Frustum Culled' ).setWidth( '90px' ) );
+	objectFrustumCulledRow.add( objectFrustumCulled );
+
+	container.add( objectFrustumCulledRow );
+
+	// renderOrder
+
+	var objectRenderOrderRow = new UI.Row();
+	var objectRenderOrder = new UI.Integer().setWidth( '50px' ).onChange( update );
+
+	objectRenderOrderRow.add( new UI.Text( 'Render Order' ).setWidth( '90px' ) );
+	objectRenderOrderRow.add( objectRenderOrder );
+
+	container.add( objectRenderOrderRow );
+
 	// user data
 	// user data
 
 
 	var timeout;
 	var timeout;
@@ -436,6 +456,18 @@ Sidebar.Object = function ( editor ) {
 
 
 			}
 			}
 
 
+			if ( object.frustumCulled !== objectFrustumCulled.getValue() ) {
+
+				editor.execute( new SetValueCommand( object, 'frustumCulled', objectFrustumCulled.getValue() ) );
+
+			}
+
+			if ( object.renderOrder !== objectRenderOrder.getValue() ) {
+
+				editor.execute( new SetValueCommand( object, 'renderOrder', objectRenderOrder.getValue() ) );
+
+			}
+
 			if ( object.castShadow !== undefined && object.castShadow !== objectCastShadow.getValue() ) {
 			if ( object.castShadow !== undefined && object.castShadow !== objectCastShadow.getValue() ) {
 
 
 				editor.execute( new SetValueCommand( object, 'castShadow', objectCastShadow.getValue() ) );
 				editor.execute( new SetValueCommand( object, 'castShadow', objectCastShadow.getValue() ) );
@@ -654,6 +686,8 @@ Sidebar.Object = function ( editor ) {
 		}
 		}
 
 
 		objectVisible.setValue( object.visible );
 		objectVisible.setValue( object.visible );
+		objectFrustumCulled.setValue( object.frustumCulled );
+		objectRenderOrder.setValue( object.renderOrder );
 
 
 		try {
 		try {
 
 

+ 1 - 0
editor/js/libs/ui.three.js

@@ -79,6 +79,7 @@ UI.Texture = function ( mapping ) {
 
 
 						var texture = new THREE.Texture( this, mapping );
 						var texture = new THREE.Texture( this, mapping );
 						texture.sourceFile = file.name;
 						texture.sourceFile = file.name;
+						texture.format = file.type === 'image/jpeg' ? THREE.RGBFormat : THREE.RGBAFormat;
 						texture.needsUpdate = true;
 						texture.needsUpdate = true;
 
 
 						scope.setValue( texture );
 						scope.setValue( texture );

+ 10 - 9
examples/canvas_geometry_nurbs.html

@@ -105,25 +105,26 @@
 
 
 				}
 				}
 
 
-				var nurbsCurve = new THREE.NURBSCurve(nurbsDegree, nurbsKnots, nurbsControlPoints);
+				var nurbsCurve = new THREE.NURBSCurve( nurbsDegree, nurbsKnots, nurbsControlPoints );
+
+				var nurbsGeometry = new THREE.BufferGeometry();
+				nurbsGeometry.setFromPoints( nurbsCurve.getPoints( 200 ) );
 
 
-				var nurbsGeometry = new THREE.Geometry();
-				nurbsGeometry.vertices = nurbsCurve.getPoints( 200 );
 				var nurbsMaterial = new THREE.LineBasicMaterial( { linewidth: 10, color: 0x333333 } );
 				var nurbsMaterial = new THREE.LineBasicMaterial( { linewidth: 10, color: 0x333333 } );
 
 
 				var nurbsLine = new THREE.Line( nurbsGeometry, nurbsMaterial );
 				var nurbsLine = new THREE.Line( nurbsGeometry, nurbsMaterial );
-				nurbsLine.position.set( 0, -100, 0 );
+				nurbsLine.position.set( 0, - 100, 0 );
+				group.add( nurbsLine );
+
+				var nurbsControlPointsGeometry = new THREE.BufferGeometry();
+				nurbsControlPointsGeometry.setFromPoints( nurbsCurve.controlPoints );
 
 
-				var nurbsControlPointsGeometry = new THREE.Geometry();
-				nurbsControlPointsGeometry.vertices = nurbsCurve.controlPoints;
 				var nurbsControlPointsMaterial = new THREE.LineBasicMaterial( { linewidth: 2, color: 0x333333, opacity: 0.25 } );
 				var nurbsControlPointsMaterial = new THREE.LineBasicMaterial( { linewidth: 2, color: 0x333333, opacity: 0.25 } );
 
 
 				var nurbsControlPointsLine = new THREE.Line( nurbsControlPointsGeometry, nurbsControlPointsMaterial );
 				var nurbsControlPointsLine = new THREE.Line( nurbsControlPointsGeometry, nurbsControlPointsMaterial );
 				nurbsControlPointsLine.position.copy( nurbsLine.position );
 				nurbsControlPointsLine.position.copy( nurbsLine.position );
 
 
-				group.add( nurbsLine, nurbsControlPointsLine );
-				// this also works:
-				// group.add( nurbsLine ).add( nurbsControlPointsLine );
+				group.add( nurbsControlPointsLine );
 
 
 				//
 				//
 
 

+ 2 - 2
examples/canvas_geometry_shapes.html

@@ -83,9 +83,9 @@
 					// line
 					// line
 
 
 					var points = shape.getPoints();
 					var points = shape.getPoints();
-					var geometry = new THREE.Geometry().setFromPoints( points );
+					var geometry = new THREE.BufferGeometry().setFromPoints( points );
 
 
-					var material = new THREE.LineBasicMaterial( { linewidth: 10, color: 0x333333, transparent: true } );
+					var material = new THREE.LineBasicMaterial( { linewidth: 10, color: 0x333333 } );
 
 
 					var line = new THREE.Line( geometry, material );
 					var line = new THREE.Line( geometry, material );
 					line.position.set( x, y, z );
 					line.position.set( x, y, z );

+ 4 - 2
examples/canvas_lines.html

@@ -73,7 +73,7 @@
 
 
 				} );
 				} );
 
 
-				var geometry = new THREE.Geometry();
+				var points = [];
 
 
 				for ( var i = 0; i < 100; i ++ ) {
 				for ( var i = 0; i < 100; i ++ ) {
 
 
@@ -86,12 +86,14 @@
 					particle.scale.x = particle.scale.y = 10;
 					particle.scale.x = particle.scale.y = 10;
 					scene.add( particle );
 					scene.add( particle );
 
 
-					geometry.vertices.push( particle.position );
+					points.push( particle.position );
 
 
 				}
 				}
 
 
 				// lines
 				// lines
 
 
+				var geometry = new THREE.BufferGeometry().setFromPoints( points );
+
 				var line = new THREE.Line( geometry, new THREE.LineBasicMaterial( { color: 0xffffff, opacity: 0.5 } ) );
 				var line = new THREE.Line( geometry, new THREE.LineBasicMaterial( { color: 0xffffff, opacity: 0.5 } ) );
 				scene.add( line );
 				scene.add( line );
 
 

+ 1 - 0
examples/files.js

@@ -152,6 +152,7 @@ var files = {
 		"webgl_materials_cubemap_dynamic",
 		"webgl_materials_cubemap_dynamic",
 		"webgl_materials_cubemap_dynamic2",
 		"webgl_materials_cubemap_dynamic2",
 		"webgl_materials_cubemap_refraction",
 		"webgl_materials_cubemap_refraction",
+		"webgl_materials_curvature",
 		"webgl_materials_displacementmap",
 		"webgl_materials_displacementmap",
 		"webgl_materials_envmaps",
 		"webgl_materials_envmaps",
 		"webgl_materials_envmaps_hdr",
 		"webgl_materials_envmaps_hdr",

+ 188 - 0
examples/js/BufferGeometryUtils.js

@@ -182,6 +182,194 @@ THREE.BufferGeometryUtils = {
 
 
 		}
 		}
 
 
+	},
+
+	/**
+	 * @param  {Array<THREE.BufferGeometry>} geometries
+	 * @return {THREE.BufferGeometry}
+	 */
+	mergeBufferGeometries: function ( geometries ) {
+
+		var isIndexed = geometries[ 0 ].index !== null;
+
+		var attributesUsed = new Set( Object.keys( geometries[ 0 ].attributes ) );
+		var morphAttributesUsed = new Set( Object.keys( geometries[ 0 ].morphAttributes ) );
+
+		var attributes = {};
+		var morphAttributes = {};
+
+		var mergedGeometry = new THREE.BufferGeometry();
+
+		for ( var i = 0; i < geometries.length; ++ i ) {
+
+			var geometry = geometries[ i ];
+
+			// ensure that all geometries are indexed, or none
+
+			if ( isIndexed !== ( geometry.index !== null ) ) return null;
+
+			// gather attributes, exit early if they're different
+
+			for ( var name in geometry.attributes ) {
+
+				if ( !attributesUsed.has( name ) ) return null;
+
+				if ( attributes[ name ] === undefined ) attributes[ name ] = [];
+
+				attributes[ name ].push( geometry.attributes[ name ] );
+
+			}
+
+			// gather morph attributes, exit early if they're different
+
+			for ( var name in geometry.morphAttributes ) {
+
+				if ( !morphAttributesUsed.has( name ) ) return null;
+
+				if ( morphAttributes[ name ] === undefined ) morphAttributes[ name ] = [];
+
+				morphAttributes[ name ].push( geometry.morphAttributes[ name ] );
+
+			}
+
+			// gather .userData
+
+			if ( geometry.userData !== undefined ) {
+
+				mergedGeometry.userData = mergedGeometry.userData || {};
+				mergedGeometry.userData.mergedUserData = mergedGeometry.userData.mergedUserData || [];
+				mergedGeometry.userData.mergedUserData.push( geometry.userData );
+
+			}
+
+		}
+
+		// merge indices
+
+		if ( isIndexed ) {
+
+			var indexOffset = 0;
+			var indexList = [];
+
+			for ( var i = 0; i < geometries.length; ++ i ) {
+
+				var index = geometries[ i ].index;
+
+				if ( indexOffset > 0 ) {
+
+					index = index.clone();
+
+					for ( var j = 0; j < index.count; ++ j ) {
+
+						index.setX( j, index.getX( j ) + indexOffset );
+
+					}
+
+				}
+
+				indexList.push( index );
+				indexOffset += geometries[ i ].attributes.position.count;
+
+			}
+
+			var mergedIndex = this.mergeBufferAttributes( indexList );
+
+			if ( !mergedIndex ) return null;
+
+			mergedGeometry.index = mergedIndex;
+
+		}
+
+		// merge attributes
+
+		for ( var name in attributes ) {
+
+			var mergedAttribute = this.mergeBufferAttributes( attributes[ name ] );
+
+			if ( ! mergedAttribute ) return null;
+
+			mergedGeometry.addAttribute( name, mergedAttribute );
+
+		}
+
+		// merge morph attributes
+
+		for ( var name in morphAttributes ) {
+
+			var numMorphTargets = morphAttributes[ name ][ 0 ].length;
+
+			if ( numMorphTargets === 0 ) break;
+
+			mergedGeometry.morphAttributes = mergedGeometry.morphAttributes || {};
+			mergedGeometry.morphAttributes[ name ] = [];
+
+			for ( var i = 0; i < numMorphTargets; ++ i ) {
+
+				var morphAttributesToMerge = [];
+
+				for ( var j = 0; j < morphAttributes[ name ].length; ++ j ) {
+
+					morphAttributesToMerge.push( morphAttributes[ name ][ j ][ i ] );
+
+				}
+
+				var mergedMorphAttribute = this.mergeBufferAttributes( morphAttributesToMerge );
+
+				if ( !mergedMorphAttribute ) return null;
+
+				mergedGeometry.morphAttributes[ name ].push( mergedMorphAttribute );
+
+			}
+
+		}
+
+		return mergedGeometry;
+
+	},
+
+	/**
+	 * @param {Array<THREE.BufferAttribute>} attributes
+	 * @return {THREE.BufferAttribute}
+	 */
+	mergeBufferAttributes: function ( attributes ) {
+
+		var TypedArray;
+		var itemSize;
+		var normalized;
+		var arrayLength = 0;
+
+		for ( var i = 0; i < attributes.length; ++ i ) {
+
+			var attribute = attributes[ i ];
+
+			if ( attribute.isInterleavedBufferAttribute ) return null;
+
+			if ( TypedArray === undefined ) TypedArray = attribute.array.constructor;
+			if ( TypedArray !== attribute.array.constructor ) return null;
+
+			if ( itemSize === undefined ) itemSize = attribute.itemSize;
+			if ( itemSize !== attribute.itemSize ) return null;
+
+			if ( normalized === undefined ) normalized = attribute.normalized;
+			if ( normalized !== attribute.normalized ) return null;
+
+			arrayLength += attribute.array.length;
+
+		}
+
+		var array = new TypedArray( arrayLength );
+		var offset = 0;
+
+		for ( var j = 0; j < attributes.length; ++ j ) {
+
+			array.set( attributes[ j ].array, offset );
+
+			offset += attributes[ j ].array.length;
+
+		}
+
+		return new THREE.BufferAttribute( array, itemSize, normalized );
+
 	}
 	}
 
 
 };
 };

+ 23 - 1
examples/js/controls/EditorControls.js

@@ -38,7 +38,29 @@ THREE.EditorControls = function ( object, domElement ) {
 	this.focus = function ( target ) {
 	this.focus = function ( target ) {
 
 
 		var box = new THREE.Box3().setFromObject( target );
 		var box = new THREE.Box3().setFromObject( target );
-		object.lookAt( center.copy( box.getCenter() ) );
+
+		var distance;
+
+		if ( box.isEmpty() === false ) {
+
+			center.copy( box.getCenter() );
+			distance = box.getBoundingSphere().radius;
+
+		} else {
+
+			// Focusing on an Group, AmbientLight, etc
+
+			center.setFromMatrixPosition( target.matrixWorld );
+			distance = 0.1;
+
+		}
+
+		var delta = new THREE.Vector3( 0, 0, 1 );
+		delta.applyQuaternion( object.quaternion );
+		delta.multiplyScalar( distance * 4 );
+
+		object.position.copy( center ).add( delta );
+
 		scope.dispatchEvent( changeEvent );
 		scope.dispatchEvent( changeEvent );
 
 
 	};
 	};

+ 23 - 2
examples/js/controls/OrbitControls.js

@@ -59,6 +59,7 @@ THREE.OrbitControls = function ( object, domElement ) {
 
 
 	// Set to false to disable panning
 	// Set to false to disable panning
 	this.enablePan = true;
 	this.enablePan = true;
+	this.panningMode = THREE.ScreenSpacePanning; // alternate THREE.HorizontalPanning
 	this.keyPanSpeed = 7.0;	// pixels moved per arrow key push
 	this.keyPanSpeed = 7.0;	// pixels moved per arrow key push
 
 
 	// Set to true to automatically rotate around the target
 	// Set to true to automatically rotate around the target
@@ -183,14 +184,17 @@ THREE.OrbitControls = function ( object, domElement ) {
 				sphericalDelta.theta *= ( 1 - scope.dampingFactor );
 				sphericalDelta.theta *= ( 1 - scope.dampingFactor );
 				sphericalDelta.phi *= ( 1 - scope.dampingFactor );
 				sphericalDelta.phi *= ( 1 - scope.dampingFactor );
 
 
+				panOffset.multiplyScalar( 1 - scope.dampingFactor );
+
 			} else {
 			} else {
 
 
 				sphericalDelta.set( 0, 0, 0 );
 				sphericalDelta.set( 0, 0, 0 );
 
 
+				panOffset.set( 0, 0, 0 );
+
 			}
 			}
 
 
 			scale = 1;
 			scale = 1;
-			panOffset.set( 0, 0, 0 );
 
 
 			// update condition is:
 			// update condition is:
 			// min(camera displacement, camera rotation in radians)^2 > EPS
 			// min(camera displacement, camera rotation in radians)^2 > EPS
@@ -316,7 +320,21 @@ THREE.OrbitControls = function ( object, domElement ) {
 
 
 		return function panUp( distance, objectMatrix ) {
 		return function panUp( distance, objectMatrix ) {
 
 
-			v.setFromMatrixColumn( objectMatrix, 1 ); // get Y column of objectMatrix
+			switch ( scope.panningMode ) {
+
+				case THREE.ScreenSpacePanning:
+
+					v.setFromMatrixColumn( objectMatrix, 1 );
+					break;
+
+				case THREE.HorizontalPanning:
+
+					v.setFromMatrixColumn( objectMatrix, 0 );
+					v.crossVectors( scope.object.up, v );
+					break;
+
+			}
+
 			v.multiplyScalar( distance );
 			v.multiplyScalar( distance );
 
 
 			panOffset.add( v );
 			panOffset.add( v );
@@ -1041,3 +1059,6 @@ Object.defineProperties( THREE.OrbitControls.prototype, {
 	}
 	}
 
 
 } );
 } );
+
+THREE.ScreenSpacePanning = 0;
+THREE.HorizontalPanning = 1;

+ 366 - 145
examples/js/exporters/GLTFExporter.js

@@ -1,5 +1,7 @@
 /**
 /**
  * @author fernandojsg / http://fernandojsg.com
  * @author fernandojsg / http://fernandojsg.com
+ * @author Don McCurdy / https://www.donmccurdy.com
+ * @author Takahiro / https://github.com/takahirox
  */
  */
 
 
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
@@ -68,7 +70,9 @@ THREE.GLTFExporter.prototype = {
 			onlyVisible: true,
 			onlyVisible: true,
 			truncateDrawRange: true,
 			truncateDrawRange: true,
 			embedImages: true,
 			embedImages: true,
-			animations: []
+			animations: [],
+			forceIndices: false,
+			forcePowerOfTwoTextures: false
 		};
 		};
 
 
 		options = Object.assign( {}, DEFAULT_OPTIONS, options );
 		options = Object.assign( {}, DEFAULT_OPTIONS, options );
@@ -92,13 +96,14 @@ THREE.GLTFExporter.prototype = {
 		};
 		};
 
 
 		var byteOffset = 0;
 		var byteOffset = 0;
-		var dataViews = [];
+		var buffers = [];
+		var pending = [];
 		var nodeMap = {};
 		var nodeMap = {};
 		var skins = [];
 		var skins = [];
 		var cachedData = {
 		var cachedData = {
 
 
-			images: {},
-			materials: {}
+			materials: {},
+			textures: {}
 
 
 		};
 		};
 
 
@@ -128,7 +133,18 @@ THREE.GLTFExporter.prototype = {
 		 * @param  {string} text
 		 * @param  {string} text
 		 * @return {ArrayBuffer}
 		 * @return {ArrayBuffer}
 		 */
 		 */
-		function stringToArrayBuffer( text ) {
+		function stringToArrayBuffer( text, padded ) {
+			if ( padded ) {
+
+				var pad = getPaddedBufferSize( text.length ) - text.length;
+
+				for ( var i = 0; i < pad; i++ ) {
+
+					text += ' ';
+
+				}
+
+			}
 
 
 			if ( window.TextEncoder !== undefined ) {
 			if ( window.TextEncoder !== undefined ) {
 
 
@@ -180,6 +196,19 @@ THREE.GLTFExporter.prototype = {
 
 
 		}
 		}
 
 
+		/**
+		 * Checks if image size is POT.
+		 *
+		 * @param {Image} image The image to be checked.
+		 * @returns {Boolean} Returns true if image size is POT.
+		 *
+		 */
+		function isPowerOfTwo( image ) {
+
+			return THREE.Math.isPowerOfTwo( image.width ) && THREE.Math.isPowerOfTwo( image.height );
+
+		}
+
 		/**
 		/**
 		 * Get the required size + padding for a buffer, rounded to the next 4-byte boundary.
 		 * Get the required size + padding for a buffer, rounded to the next 4-byte boundary.
 		 * https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#data-alignment
 		 * https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#data-alignment
@@ -194,45 +223,77 @@ THREE.GLTFExporter.prototype = {
 
 
 		}
 		}
 
 
+		/**
+		 * Returns a buffer aligned to 4-byte boundary.
+		 *
+		 * @param {ArrayBuffer} arrayBuffer Buffer to pad
+		 * @returns {ArrayBuffer} The same buffer if it's already aligned to 4-byte boundary or a new buffer
+		 */
+		function getPaddedArrayBuffer( arrayBuffer ) {
+
+			var paddedLength = getPaddedBufferSize( arrayBuffer.byteLength );
+
+			if (paddedLength !== arrayBuffer.byteLength ) {
+
+				var paddedBuffer = new ArrayBuffer( paddedLength );
+				new Uint8Array( paddedBuffer ).set(new Uint8Array(arrayBuffer));
+				return paddedBuffer;
+
+			}
+
+			return arrayBuffer;
+
+		}
+
 		/**
 		/**
 		 * Process a buffer to append to the default one.
 		 * Process a buffer to append to the default one.
-		 * @param  {THREE.BufferAttribute} attribute     Attribute to store
-		 * @param  {Integer} componentType Component type (Unsigned short, unsigned int or float)
-		 * @return {Integer}               Index of the buffer created (Currently always 0)
+		 * @param  {ArrayBuffer} buffer
+		 * @return {Integer}
 		 */
 		 */
-		function processBuffer( attribute, componentType, start, count ) {
+		function processBuffer( buffer ) {
 
 
 			if ( ! outputJSON.buffers ) {
 			if ( ! outputJSON.buffers ) {
 
 
-				outputJSON.buffers = [
+				outputJSON.buffers = [ { byteLength: 0 } ];
 
 
-					{
+			}
 
 
-						byteLength: 0,
-						uri: ''
+			// All buffers are merged before export.
+			buffers.push( buffer );
 
 
-					}
+			return 0;
 
 
-				];
+		}
 
 
-			}
+		/**
+		 * Process and generate a BufferView
+		 * @param  {THREE.BufferAttribute} attribute
+		 * @param  {number} componentType
+		 * @param  {number} start
+		 * @param  {number} count
+		 * @param  {number} target (Optional) Target usage of the BufferView
+		 * @return {Object}
+		 */
+		function processBufferView( attribute, componentType, start, count, target ) {
 
 
-			var offset = 0;
-			var componentSize = componentType === WEBGL_CONSTANTS.UNSIGNED_SHORT ? 2 : 4;
+			if ( ! outputJSON.bufferViews ) {
 
 
-			// Create a new dataview and dump the attribute's array into it
-			var byteLength = count * attribute.itemSize * componentSize;
+				outputJSON.bufferViews = [];
 
 
-			// adjust required size of array buffer with padding
-			// to satisfy gltf requirement that the length is divisible by 4
-			byteLength = getPaddedBufferSize( byteLength );
+			}
 
 
+			// Create a new dataview and dump the attribute's array into it
+			var componentSize = componentType === WEBGL_CONSTANTS.UNSIGNED_SHORT ? 2 : 4;
+			var byteLength = getPaddedBufferSize( count * attribute.itemSize * componentSize );
 			var dataView = new DataView( new ArrayBuffer( byteLength ) );
 			var dataView = new DataView( new ArrayBuffer( byteLength ) );
+			var offset = 0;
 
 
 			for ( var i = start; i < start + count; i ++ ) {
 			for ( var i = start; i < start + count; i ++ ) {
 
 
 				for ( var a = 0; a < attribute.itemSize; a ++ ) {
 				for ( var a = 0; a < attribute.itemSize; a ++ ) {
 
 
+					// @TODO Fails on InterleavedBufferAttribute, and could probably be
+					// optimized for normal BufferAttribute.
 					var value = attribute.array[ i * attribute.itemSize + a ];
 					var value = attribute.array[ i * attribute.itemSize + a ];
 
 
 					if ( componentType === WEBGL_CONSTANTS.FLOAT ) {
 					if ( componentType === WEBGL_CONSTANTS.FLOAT ) {
@@ -255,39 +316,9 @@ THREE.GLTFExporter.prototype = {
 
 
 			}
 			}
 
 
-			// We just use one buffer
-			dataViews.push( dataView );
-
-			// Always using just one buffer
-			return 0;
-
-		}
-
-		/**
-		 * Process and generate a BufferView
-		 * @param  {THREE.BufferAttribute} data
-		 * @param  {number} componentType
-		 * @param  {number} start
-		 * @param  {number} count
-		 * @param  {number} target (Optional) Target usage of the BufferView
-		 * @return {Object}
-		 */
-		function processBufferView( data, componentType, start, count, target ) {
-
-			if ( ! outputJSON.bufferViews ) {
-
-				outputJSON.bufferViews = [];
-
-			}
-
-			var componentSize = componentType === WEBGL_CONSTANTS.UNSIGNED_SHORT ? 2 : 4;
-
-			// Create a new dataview and dump the attribute's array into it
-			var byteLength = count * data.itemSize * componentSize;
-
 			var gltfBufferView = {
 			var gltfBufferView = {
 
 
-				buffer: processBuffer( data, componentType, start, count ),
+				buffer: processBuffer( dataView.buffer ),
 				byteOffset: byteOffset,
 				byteOffset: byteOffset,
 				byteLength: byteLength
 				byteLength: byteLength
 
 
@@ -298,7 +329,7 @@ THREE.GLTFExporter.prototype = {
 			if ( target === WEBGL_CONSTANTS.ARRAY_BUFFER ) {
 			if ( target === WEBGL_CONSTANTS.ARRAY_BUFFER ) {
 
 
 				// Only define byteStride for vertex attributes.
 				// Only define byteStride for vertex attributes.
-				gltfBufferView.byteStride = data.itemSize * componentSize;
+				gltfBufferView.byteStride = attribute.itemSize * componentSize;
 
 
 			}
 			}
 
 
@@ -306,7 +337,7 @@ THREE.GLTFExporter.prototype = {
 
 
 			outputJSON.bufferViews.push( gltfBufferView );
 			outputJSON.bufferViews.push( gltfBufferView );
 
 
-			// @TODO Ideally we'll have just two bufferviews: 0 is for vertex attributes, 1 for indices
+			// @TODO Merge bufferViews where possible.
 			var output = {
 			var output = {
 
 
 				id: outputJSON.bufferViews.length - 1,
 				id: outputJSON.bufferViews.length - 1,
@@ -318,6 +349,45 @@ THREE.GLTFExporter.prototype = {
 
 
 		}
 		}
 
 
+		/**
+		 * Process and generate a BufferView from an image Blob.
+		 * @param {Blob} blob
+		 * @return {Promise<Integer>}
+		 */
+		function processBufferViewImage( blob ) {
+
+			if ( ! outputJSON.bufferViews ) {
+
+				outputJSON.bufferViews = [];
+
+			}
+
+			return new Promise( function ( resolve ) {
+
+				var reader = new window.FileReader();
+				reader.readAsArrayBuffer( blob );
+				reader.onloadend = function () {
+
+					var buffer = getPaddedArrayBuffer( reader.result );
+
+					var bufferView = {
+						buffer: processBuffer( buffer ),
+						byteOffset: byteOffset,
+						byteLength: buffer.byteLength
+					};
+
+					byteOffset += buffer.byteLength;
+
+					outputJSON.bufferViews.push( bufferView );
+
+					resolve( outputJSON.bufferViews.length - 1 );
+
+				};
+
+			} );
+
+		}
+
 		/**
 		/**
 		 * Process attribute to generate an accessor
 		 * Process attribute to generate an accessor
 		 * @param  {THREE.BufferAttribute} attribute Attribute to process
 		 * @param  {THREE.BufferAttribute} attribute Attribute to process
@@ -414,11 +484,7 @@ THREE.GLTFExporter.prototype = {
 		 */
 		 */
 		function processImage( map ) {
 		function processImage( map ) {
 
 
-			if ( cachedData.images[ map.uuid ] !== undefined ) {
-
-				return cachedData.images[ map.uuid ];
-
-			}
+			// @TODO Cache
 
 
 			if ( ! outputJSON.images ) {
 			if ( ! outputJSON.images ) {
 
 
@@ -432,22 +498,53 @@ THREE.GLTFExporter.prototype = {
 			if ( options.embedImages ) {
 			if ( options.embedImages ) {
 
 
 				var canvas = cachedCanvas = cachedCanvas || document.createElement( 'canvas' );
 				var canvas = cachedCanvas = cachedCanvas || document.createElement( 'canvas' );
+
 				canvas.width = map.image.width;
 				canvas.width = map.image.width;
 				canvas.height = map.image.height;
 				canvas.height = map.image.height;
+
+				if ( options.forcePowerOfTwoTextures && ! isPowerOfTwo( map.image ) ) {
+
+					console.warn( 'GLTFExporter: Resized non-power-of-two image.', map.image );
+
+					canvas.width = THREE.Math.floorPowerOfTwo( canvas.width );
+					canvas.height = THREE.Math.floorPowerOfTwo( canvas.height );
+
+				}
+
 				var ctx = canvas.getContext( '2d' );
 				var ctx = canvas.getContext( '2d' );
 
 
 				if ( map.flipY === true ) {
 				if ( map.flipY === true ) {
 
 
-					ctx.translate( 0, map.image.height );
+					ctx.translate( 0, canvas.height );
 					ctx.scale( 1, - 1 );
 					ctx.scale( 1, - 1 );
 
 
 				}
 				}
 
 
-				ctx.drawImage( map.image, 0, 0 );
+				ctx.drawImage( map.image, 0, 0, canvas.width, canvas.height );
+
+				if ( options.binary === true ) {
+
+					pending.push( new Promise( function ( resolve ) {
+
+						canvas.toBlob( function ( blob ) {
+
+							processBufferViewImage( blob ).then( function ( bufferViewIndex ) {
+
+								gltfImage.bufferView = bufferViewIndex;
+
+								resolve();
+
+							} );
+
+						}, mimeType );
 
 
-				// @TODO Embed in { bufferView } if options.binary set.
+					} ) );
 
 
-				gltfImage.uri = canvas.toDataURL( mimeType );
+				} else {
+
+					gltfImage.uri = canvas.toDataURL( mimeType );
+
+				}
 
 
 			} else {
 			} else {
 
 
@@ -457,10 +554,7 @@ THREE.GLTFExporter.prototype = {
 
 
 			outputJSON.images.push( gltfImage );
 			outputJSON.images.push( gltfImage );
 
 
-			var index = outputJSON.images.length - 1;
-			cachedData.images[ map.uuid ] = index;
-
-			return index;
+			return outputJSON.images.length - 1;
 
 
 		}
 		}
 
 
@@ -499,6 +593,12 @@ THREE.GLTFExporter.prototype = {
 		 */
 		 */
 		function processTexture( map ) {
 		function processTexture( map ) {
 
 
+			if ( cachedData.textures[ map.uuid ] !== undefined ) {
+
+				return cachedData.textures[ map.uuid ];
+
+			}
+
 			if ( ! outputJSON.textures ) {
 			if ( ! outputJSON.textures ) {
 
 
 				outputJSON.textures = [];
 				outputJSON.textures = [];
@@ -514,7 +614,10 @@ THREE.GLTFExporter.prototype = {
 
 
 			outputJSON.textures.push( gltfTexture );
 			outputJSON.textures.push( gltfTexture );
 
 
-			return outputJSON.textures.length - 1;
+			var index = outputJSON.textures.length - 1;
+			cachedData.textures[ map.uuid ] = index;
+
+			return index;
 
 
 		}
 		}
 
 
@@ -547,7 +650,7 @@ THREE.GLTFExporter.prototype = {
 
 
 			if ( ! ( material instanceof THREE.MeshStandardMaterial ) ) {
 			if ( ! ( material instanceof THREE.MeshStandardMaterial ) ) {
 
 
-				console.warn( 'GLTFExporter: Currently just THREE.StandardMaterial is supported. Material conversion may lose information.' );
+				console.warn( 'GLTFExporter: Currently just THREE.MeshStandardMaterial is supported. Material conversion may lose information.' );
 
 
 			}
 			}
 
 
@@ -579,6 +682,25 @@ THREE.GLTFExporter.prototype = {
 
 
 			}
 			}
 
 
+			// pbrMetallicRoughness.metallicRoughnessTexture
+			if ( material.metalnessMap || material.roughnessMap ) {
+
+				if ( material.metalnessMap === material.roughnessMap ) {
+
+					gltfMaterial.pbrMetallicRoughness.metallicRoughnessTexture = {
+
+						index: processTexture( material.metalnessMap )
+
+					};
+
+				} else {
+
+					console.warn( 'THREE.GLTFExporter: Ignoring metalnessMap and roughnessMap because they are not the same Texture.' );
+
+				}
+
+			}
+
 			// pbrMetallicRoughness.baseColorTexture
 			// pbrMetallicRoughness.baseColorTexture
 			if ( material.map ) {
 			if ( material.map ) {
 
 
@@ -776,6 +898,18 @@ THREE.GLTFExporter.prototype = {
 
 
 				gltfMesh.primitives[ 0 ].indices = processAccessor( geometry.index, geometry );
 				gltfMesh.primitives[ 0 ].indices = processAccessor( geometry.index, geometry );
 
 
+			} else if ( options.forceIndices ) {
+
+				var numFaces = geometry.attributes.position.count;
+				var indices = new Uint32Array( numFaces );
+				for ( var i = 0; i < numFaces; i ++ ) {
+
+					indices[ i ] = i;
+
+				}
+
+				gltfMesh.primitives[ 0 ].indices = processAccessor( new THREE.Uint32BufferAttribute( indices, 1 ), geometry );
+
 			}
 			}
 
 
 			// We've just one primitive per mesh
 			// We've just one primitive per mesh
@@ -811,28 +945,87 @@ THREE.GLTFExporter.prototype = {
 			if ( mesh.morphTargetInfluences !== undefined && mesh.morphTargetInfluences.length > 0 ) {
 			if ( mesh.morphTargetInfluences !== undefined && mesh.morphTargetInfluences.length > 0 ) {
 
 
 				var weights = [];
 				var weights = [];
+				var targetNames = [];
+				var reverseDictionary = {};
+
+				if ( mesh.morphTargetDictionary !== undefined ) {
+
+					for ( var key in mesh.morphTargetDictionary ) {
+
+						reverseDictionary[ mesh.morphTargetDictionary[ key ] ] = key;
+
+					}
+
+				}
+
 				gltfMesh.primitives[ 0 ].targets = [];
 				gltfMesh.primitives[ 0 ].targets = [];
 
 
 				for ( var i = 0; i < mesh.morphTargetInfluences.length; ++ i ) {
 				for ( var i = 0; i < mesh.morphTargetInfluences.length; ++ i ) {
 
 
 					var target = {};
 					var target = {};
 
 
+					var warned = false;
+
 					for ( var attributeName in geometry.morphAttributes ) {
 					for ( var attributeName in geometry.morphAttributes ) {
 
 
+						// glTF 2.0 morph supports only POSITION/NORMAL/TANGENT.
+						// Three.js doesn't support TANGENT yet.
+
+						if ( attributeName !== 'position' && attributeName !== 'normal' ) {
+
+							if ( ! warned ) {
+
+								console.warn( 'GLTFExporter: Only POSITION and NORMAL morph are supported.' );
+								warned = true;
+
+							}
+
+							continue;
+
+						}
+
 						var attribute = geometry.morphAttributes[ attributeName ][ i ];
 						var attribute = geometry.morphAttributes[ attributeName ][ i ];
-						attributeName = nameConversion[ attributeName ] || attributeName.toUpperCase();
-						target[ attributeName ] = processAccessor( attribute, geometry );
+
+						// Three.js morph attribute has absolute values while the one of glTF has relative values.
+						//
+						// glTF 2.0 Specification:
+						// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#morph-targets
+
+						var baseAttribute = geometry.attributes[ attributeName ];
+						// Clones attribute not to override
+						var relativeAttribute = attribute.clone();
+
+						for ( var j = 0, jl = attribute.count; j < jl; j ++ ) {
+
+							relativeAttribute.setXYZ(
+								j,
+								attribute.getX( j ) - baseAttribute.getX( j ),
+								attribute.getY( j ) - baseAttribute.getY( j ),
+								attribute.getZ( j ) - baseAttribute.getZ( j )
+							);
+
+						}
+
+						target[ attributeName.toUpperCase() ] = processAccessor( relativeAttribute, geometry );
 
 
 					}
 					}
 
 
 					gltfMesh.primitives[ 0 ].targets.push( target );
 					gltfMesh.primitives[ 0 ].targets.push( target );
 
 
 					weights.push( mesh.morphTargetInfluences[ i ] );
 					weights.push( mesh.morphTargetInfluences[ i ] );
+					if ( mesh.morphTargetDictionary !== undefined ) targetNames.push( reverseDictionary[ i ] );
 
 
 				}
 				}
 
 
 				gltfMesh.weights = weights;
 				gltfMesh.weights = weights;
 
 
+				if ( targetNames.length > 0 ) {
+
+					gltfMesh.extras = {};
+					gltfMesh.extras.targetNames = targetNames;
+
+				}
+
 			}
 			}
 
 
 			outputJSON.meshes.push( gltfMesh );
 			outputJSON.meshes.push( gltfMesh );
@@ -868,8 +1061,8 @@ THREE.GLTFExporter.prototype = {
 
 
 					xmag: camera.right * 2,
 					xmag: camera.right * 2,
 					ymag: camera.top * 2,
 					ymag: camera.top * 2,
-					zfar: camera.far,
-					znear: camera.near
+					zfar: camera.far <= 0 ? 0.001 : camera.far,
+					znear: camera.near < 0 ? 0 : camera.near
 
 
 				};
 				};
 
 
@@ -879,8 +1072,8 @@ THREE.GLTFExporter.prototype = {
 
 
 					aspectRatio: camera.aspect,
 					aspectRatio: camera.aspect,
 					yfov: THREE.Math.degToRad( camera.fov ) / camera.aspect,
 					yfov: THREE.Math.degToRad( camera.fov ) / camera.aspect,
-					zfar: camera.far,
-					znear: camera.near
+					zfar: camera.far <= 0 ? 0.001 : camera.far,
+					znear: camera.near < 0 ? 0 : camera.near
 
 
 				};
 				};
 
 
@@ -903,7 +1096,6 @@ THREE.GLTFExporter.prototype = {
 		 *
 		 *
 		 * Status:
 		 * Status:
 		 * - Only properties listed in PATH_PROPERTIES may be animated.
 		 * - Only properties listed in PATH_PROPERTIES may be animated.
-		 * - Only LINEAR and STEP interpolation currently supported.
 		 *
 		 *
 		 * @param {THREE.AnimationClip} clip
 		 * @param {THREE.AnimationClip} clip
 		 * @param {THREE.Object3D} root
 		 * @param {THREE.Object3D} root
@@ -957,11 +1149,37 @@ THREE.GLTFExporter.prototype = {
 
 
 				}
 				}
 
 
+				var interpolation;
+
+				// @TODO export CubicInterpolant(InterpolateSmooth) as CUBICSPLINE
+
+				// Detecting glTF cubic spline interpolant by checking factory method's special property
+				// GLTFCubicSplineInterpolant is a custom interpolant and track doesn't return
+				// valid value from .getInterpolation().
+				if ( track.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline === true ) {
+
+					interpolation = 'CUBICSPLINE';
+
+					// itemSize of CUBICSPLINE keyframe is 9
+					// (VEC3 * 3: inTangent, splineVertex, and outTangent)
+					// but needs to be stored as VEC3 so dividing by 3 here.
+					outputItemSize /= 3;
+
+				} else if ( track.getInterpolation() === THREE.InterpolateDiscrete ) {
+
+					interpolation = 'STEP';
+
+				} else {
+
+					interpolation = 'LINEAR';
+
+				}
+
 				samplers.push( {
 				samplers.push( {
 
 
 					input: processAccessor( new THREE.BufferAttribute( track.times, inputItemSize ) ),
 					input: processAccessor( new THREE.BufferAttribute( track.times, inputItemSize ) ),
 					output: processAccessor( new THREE.BufferAttribute( track.values, outputItemSize ) ),
 					output: processAccessor( new THREE.BufferAttribute( track.values, outputItemSize ) ),
-					interpolation: track.getInterpolation() === THREE.InterpolateDiscrete ? 'STEP' : 'LINEAR'
+					interpolation: interpolation
 
 
 				} );
 				} );
 
 
@@ -1086,7 +1304,8 @@ THREE.GLTFExporter.prototype = {
 
 
 			}
 			}
 
 
-			if ( object.name ) {
+			// We don't export empty strings name because it represents no-name in Three.js.
+			if ( object.name !== '' ) {
 
 
 				gltfNode.name = String( object.name );
 				gltfNode.name = String( object.name );
 
 
@@ -1281,91 +1500,93 @@ THREE.GLTFExporter.prototype = {
 
 
 		processInput( input );
 		processInput( input );
 
 
-		// Generate buffer
-		// Create a new blob with all the dataviews from the buffers
-		var blob = new Blob( dataViews, { type: 'application/octet-stream' } );
+		Promise.all( pending ).then( function () {
 
 
-		// Update the bytlength of the only main buffer and update the uri with the base64 representation of it
-		if ( outputJSON.buffers && outputJSON.buffers.length > 0 ) {
+			// Merge buffers.
+			var blob = new Blob( buffers, { type: 'application/octet-stream' } );
 
 
-			outputJSON.buffers[ 0 ].byteLength = blob.size;
+			if ( outputJSON.buffers && outputJSON.buffers.length > 0 ) {
 
 
-			var reader = new window.FileReader();
+				// Update bytelength of the single buffer.
+				outputJSON.buffers[ 0 ].byteLength = blob.size;
 
 
-			if ( options.binary === true ) {
+				var reader = new window.FileReader();
 
 
-				// https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#glb-file-format-specification
+				if ( options.binary === true ) {
 
 
-				var GLB_HEADER_BYTES = 12;
-				var GLB_HEADER_MAGIC = 0x46546C67;
-				var GLB_VERSION = 2;
+					// https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#glb-file-format-specification
 
 
-				var GLB_CHUNK_PREFIX_BYTES = 8;
-				var GLB_CHUNK_TYPE_JSON = 0x4E4F534A;
-				var GLB_CHUNK_TYPE_BIN = 0x004E4942;
+					var GLB_HEADER_BYTES = 12;
+					var GLB_HEADER_MAGIC = 0x46546C67;
+					var GLB_VERSION = 2;
 
 
-				reader.readAsArrayBuffer( blob );
-				reader.onloadend = function () {
+					var GLB_CHUNK_PREFIX_BYTES = 8;
+					var GLB_CHUNK_TYPE_JSON = 0x4E4F534A;
+					var GLB_CHUNK_TYPE_BIN = 0x004E4942;
+
+					reader.readAsArrayBuffer( blob );
+					reader.onloadend = function () {
+
+						// Binary chunk.
+						var binaryChunk = getPaddedArrayBuffer( reader.result );
+						var binaryChunkPrefix = new DataView( new ArrayBuffer( GLB_CHUNK_PREFIX_BYTES ) );
+						binaryChunkPrefix.setUint32( 0, binaryChunk.byteLength, true );
+						binaryChunkPrefix.setUint32( 4, GLB_CHUNK_TYPE_BIN, true );
+
+						// JSON chunk.
+						var jsonChunk = stringToArrayBuffer( JSON.stringify( outputJSON ), true );
+						var jsonChunkPrefix = new DataView( new ArrayBuffer( GLB_CHUNK_PREFIX_BYTES ) );
+						jsonChunkPrefix.setUint32( 0, jsonChunk.byteLength, true );
+						jsonChunkPrefix.setUint32( 4, GLB_CHUNK_TYPE_JSON, true );
+
+						// GLB header.
+						var header = new ArrayBuffer( GLB_HEADER_BYTES );
+						var headerView = new DataView( header );
+						headerView.setUint32( 0, GLB_HEADER_MAGIC, true );
+						headerView.setUint32( 4, GLB_VERSION, true );
+						var totalByteLength = GLB_HEADER_BYTES
+							+ jsonChunkPrefix.byteLength + jsonChunk.byteLength
+							+ binaryChunkPrefix.byteLength + binaryChunk.byteLength;
+						headerView.setUint32( 8, totalByteLength, true );
+
+						var glbBlob = new Blob( [
+							header,
+							jsonChunkPrefix,
+							jsonChunk,
+							binaryChunkPrefix,
+							binaryChunk
+						], { type: 'application/octet-stream' } );
 
 
-					// Binary chunk.
-					var binaryChunk = reader.result;
-					var binaryChunkPrefix = new DataView( new ArrayBuffer( GLB_CHUNK_PREFIX_BYTES ) );
-					binaryChunkPrefix.setUint32( 0, binaryChunk.byteLength, true );
-					binaryChunkPrefix.setUint32( 4, GLB_CHUNK_TYPE_BIN, true );
-
-					// JSON chunk.
-					delete outputJSON.buffers[ 0 ].uri; // Omitted URI indicates use of binary chunk.
-					var jsonChunk = stringToArrayBuffer( JSON.stringify( outputJSON ) );
-					var jsonChunkPrefix = new DataView( new ArrayBuffer( GLB_CHUNK_PREFIX_BYTES ) );
-					jsonChunkPrefix.setUint32( 0, jsonChunk.byteLength, true );
-					jsonChunkPrefix.setUint32( 4, GLB_CHUNK_TYPE_JSON, true );
-
-					// GLB header.
-					var header = new ArrayBuffer( GLB_HEADER_BYTES );
-					var headerView = new DataView( header );
-					headerView.setUint32( 0, GLB_HEADER_MAGIC, true );
-					headerView.setUint32( 4, GLB_VERSION, true );
-					var totalByteLength = GLB_HEADER_BYTES
-						+ jsonChunkPrefix.byteLength + jsonChunk.byteLength
-						+ binaryChunkPrefix.byteLength + binaryChunk.byteLength;
-					headerView.setUint32( 8, totalByteLength, true );
-
-					var glbBlob = new Blob( [
-						header,
-						jsonChunkPrefix,
-						jsonChunk,
-						binaryChunkPrefix,
-						binaryChunk
-					], { type: 'application/octet-stream' } );
-
-					var glbReader = new window.FileReader();
-					glbReader.readAsArrayBuffer( glbBlob );
-					glbReader.onloadend = function () {
-
-						onDone( glbReader.result );
+						var glbReader = new window.FileReader();
+						glbReader.readAsArrayBuffer( glbBlob );
+						glbReader.onloadend = function () {
+
+							onDone( glbReader.result );
+
+						};
 
 
 					};
 					};
 
 
-				};
+				} else {
 
 
-			} else {
+					reader.readAsDataURL( blob );
+					reader.onloadend = function () {
 
 
-				reader.readAsDataURL( blob );
-				reader.onloadend = function () {
+						var base64data = reader.result;
+						outputJSON.buffers[ 0 ].uri = base64data;
+						onDone( outputJSON );
 
 
-					var base64data = reader.result;
-					outputJSON.buffers[ 0 ].uri = base64data;
-					onDone( outputJSON );
+					};
 
 
-				};
+				}
 
 
-			}
+			} else {
 
 
-		} else {
+				onDone( outputJSON );
 
 
-			onDone( outputJSON );
+			}
 
 
-		}
+		} );
 
 
 	}
 	}
 
 

+ 2 - 2
examples/js/exporters/OBJExporter.js

@@ -124,7 +124,7 @@ THREE.OBJExporter.prototype = {
 
 
 							j = indices.getX( i + m ) + 1;
 							j = indices.getX( i + m ) + 1;
 
 
-							face[ m ] = ( indexVertex + j ) + '/' + ( uvs ? ( indexVertexUvs + j ) : '' ) + '/' + ( indexNormals + j );
+							face[ m ] = ( indexVertex + j ) + ( normals || uvs ? '/' + ( uvs ? ( indexVertexUvs + j ) : '' ) + ( normals ? '/' + ( indexNormals + j ) : '' ) : '' );
 
 
 						}
 						}
 
 
@@ -141,7 +141,7 @@ THREE.OBJExporter.prototype = {
 
 
 							j = i + m + 1;
 							j = i + m + 1;
 
 
-							face[ m ] = ( indexVertex + j ) + '/' + ( uvs ? ( indexVertexUvs + j ) : '' ) + '/' + ( indexNormals + j );
+							face[ m ] = ( indexVertex + j ) + ( normals || uvs ? '/' + ( uvs ? ( indexVertexUvs + j ) : '' ) + ( normals ? '/' + ( indexNormals + j ) : '' ) : '' );
 
 
 						}
 						}
 
 

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

@@ -3306,7 +3306,12 @@ THREE.ColladaLoader.prototype = {
 
 
 			}
 			}
 
 
-			object.name = ( type === 'JOINT' ) ? data.sid : data.name;
+			if ( object.name === '' ) {
+
+				object.name = ( type === 'JOINT' ) ? data.sid : data.name;
+				
+			}
+
 			object.matrix.copy( matrix );
 			object.matrix.copy( matrix );
 			object.matrix.decompose( object.position, object.quaternion, object.scale );
 			object.matrix.decompose( object.position, object.quaternion, object.scale );
 
 
@@ -3450,17 +3455,7 @@ THREE.ColladaLoader.prototype = {
 
 
 				var child = children[ i ];
 				var child = children[ i ];
 
 
-				if ( child.id === null ) {
-
-					group.add( buildNode( child ) );
-
-				} else {
-
-					// if there is an ID, let's try to get the finished build (e.g. joints are already build)
-
-					group.add( getNode( child.id ) );
-
-				}
+				group.add( getNode( child.id ) );
 
 
 			}
 			}
 
 

+ 730 - 72
examples/js/loaders/EXRLoader.js

@@ -1,9 +1,77 @@
 /**
 /**
  * @author Richard M. / https://github.com/richardmonette
  * @author Richard M. / https://github.com/richardmonette
+ *
+ * OpenEXR loader which, currently, supports reading 16 bit half data, in either
+ * uncompressed or PIZ wavelet compressed form.
+ *
+ * Referred to the original Industrial Light & Magic OpenEXR implementation and the TinyEXR / Syoyo Fujita
+ * implementation, so I have preserved their copyright notices.
  */
  */
 
 
-// https://github.com/mrdoob/three.js/issues/10652
-// https://en.wikipedia.org/wiki/OpenEXR
+// /*
+// Copyright (c) 2014 - 2017, Syoyo Fujita
+// All rights reserved.
+
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above copyright
+//       notice, this list of conditions and the following disclaimer in the
+//       documentation and/or other materials provided with the distribution.
+//     * Neither the name of the Syoyo Fujita nor the
+//       names of its contributors may be used to endorse or promote products
+//       derived from this software without specific prior written permission.
+
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+// */
+
+// // TinyEXR contains some OpenEXR code, which is licensed under ------------
+
+// ///////////////////////////////////////////////////////////////////////////
+// //
+// // Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
+// // Digital Ltd. LLC
+// //
+// // All rights reserved.
+// //
+// // Redistribution and use in source and binary forms, with or without
+// // modification, are permitted provided that the following conditions are
+// // met:
+// // *       Redistributions of source code must retain the above copyright
+// // notice, this list of conditions and the following disclaimer.
+// // *       Redistributions in binary form must reproduce the above
+// // copyright notice, this list of conditions and the following disclaimer
+// // in the documentation and/or other materials provided with the
+// // distribution.
+// // *       Neither the name of Industrial Light & Magic nor the names of
+// // its contributors may be used to endorse or promote products derived
+// // from this software without specific prior written permission.
+// //
+// // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+// //
+// ///////////////////////////////////////////////////////////////////////////
+
+// // End of OpenEXR license -------------------------------------------------
 
 
 THREE.EXRLoader = function ( manager ) {
 THREE.EXRLoader = function ( manager ) {
 
 
@@ -15,6 +83,518 @@ THREE.EXRLoader.prototype = Object.create( THREE.DataTextureLoader.prototype );
 
 
 THREE.EXRLoader.prototype._parser = function ( buffer ) {
 THREE.EXRLoader.prototype._parser = function ( buffer ) {
 
 
+	const USHORT_RANGE = (1 << 16);
+	const BITMAP_SIZE = (USHORT_RANGE >> 3);
+
+	const HUF_ENCBITS = 16;  // literal (value) bit length
+	const HUF_DECBITS = 14;  // decoding bit size (>= 8)
+
+	const HUF_ENCSIZE = (1 << HUF_ENCBITS) + 1;  // encoding table size
+	const HUF_DECSIZE = 1 << HUF_DECBITS;        // decoding table size
+	const HUF_DECMASK = HUF_DECSIZE - 1;
+
+	const SHORT_ZEROCODE_RUN = 59;
+	const LONG_ZEROCODE_RUN = 63;
+	const SHORTEST_LONG_RUN = 2 + LONG_ZEROCODE_RUN - SHORT_ZEROCODE_RUN;
+	const LONGEST_LONG_RUN = 255 + SHORTEST_LONG_RUN;
+
+	const BYTES_PER_HALF = 2;
+
+	const ULONG_SIZE = 8;
+	const FLOAT32_SIZE = 4;
+	const INT32_SIZE = 4;
+	const INT16_SIZE = 2;
+	const INT8_SIZE = 1;
+
+	function reverseLutFromBitmap(bitmap, lut) {
+		var k = 0;
+
+		for (var i = 0; i < USHORT_RANGE; ++i) {
+			if ((i == 0) || (bitmap[i >> 3] & (1 << (i & 7)))) {
+				lut[k++] = i;
+			}
+		}
+
+		var n = k - 1;
+
+		while (k < USHORT_RANGE) lut[k++] = 0;
+
+		return n;
+	}
+
+	function hufClearDecTable(hdec) {
+		for (var i = 0; i < HUF_DECSIZE; i++) {
+			hdec[i] = {}
+			hdec[i].len = 0;
+			hdec[i].lit = 0;
+			hdec[i].p = null;
+		}
+	}
+
+	const getBitsReturn = { l: 0, c: 0, lc: 0 };
+	function getBits(nBits, c, lc, uInt8Array, inOffset) {
+		while (lc < nBits) {
+			c = (c << 8) | parseUint8Array(uInt8Array, inOffset);
+			lc += 8;
+		}
+
+		lc -= nBits;
+
+		getBitsReturn.l = (c >> lc) & ((1 << nBits) - 1);
+		getBitsReturn.c = c;
+		getBitsReturn.lc = lc;
+	}
+
+	const hufTableBuffer = new Array(59);
+	function hufCanonicalCodeTable(hcode) {
+		for (var i = 0; i <= 58; ++i) hufTableBuffer[i] = 0;
+
+		for (var i = 0; i < HUF_ENCSIZE; ++i) hufTableBuffer[hcode[i]] += 1;
+
+		var c = 0;
+
+		for (var i = 58; i > 0; --i) {
+			var nc = ((c + hufTableBuffer[i]) >> 1);
+			hufTableBuffer[i] = c;
+			c = nc;
+		}
+
+		for (var i = 0; i < HUF_ENCSIZE; ++i) {
+			var l = hcode[i];
+
+			if (l > 0) hcode[i] = l | (hufTableBuffer[l]++ << 6);
+		}
+	}
+
+	function hufUnpackEncTable(uInt8Array, inDataView, inOffset, ni, im, iM, hcode) {
+		var p = inOffset;
+		var c = 0;
+		var lc = 0;
+
+		for (; im <= iM; im++) {
+			if (p.value - inOffset.value > ni) {
+				return false;
+			}
+
+			getBits(6, c, lc, uInt8Array, p);
+			var l = getBitsReturn.l;
+			c = getBitsReturn.c;
+			lc = getBitsReturn.lc;
+			hcode[im] = l;
+
+			if (l == LONG_ZEROCODE_RUN) {
+				if (p.value - inOffset.value > ni) {
+					throw 'Something wrong with hufUnpackEncTable';
+				}
+
+				getBits(8, c, lc, uInt8Array, p);
+				var zerun = getBitsReturn.l + SHORTEST_LONG_RUN;
+				c = getBitsReturn.c;
+				lc = getBitsReturn.lc;
+
+				if (im + zerun > iM + 1) {
+					throw 'Something wrong with hufUnpackEncTable';
+				}
+
+				while (zerun--) hcode[im++] = 0;
+
+				im--;
+			} else if (l >= SHORT_ZEROCODE_RUN) {
+				var zerun = l - SHORT_ZEROCODE_RUN + 2;
+
+				if (im + zerun > iM + 1) {
+					throw 'Something wrong with hufUnpackEncTable';
+				}
+
+				while (zerun--) hcode[im++] = 0;
+
+				im--;
+			}
+		}
+
+		hufCanonicalCodeTable(hcode);
+	}
+
+	function hufLength(code) { return code & 63; }
+
+	function hufCode(code) { return code >> 6; }
+
+	function hufBuildDecTable(hcode, im, iM, hdecod) {
+		for (; im <= iM; im++) {
+			var c = hufCode(hcode[im]);
+			var l = hufLength(hcode[im]);
+
+			if (c >> l) {
+				throw 'Invalid table entry';
+			}
+
+			if (l > HUF_DECBITS) {
+				var pl = hdecod[(c >> (l - HUF_DECBITS))];
+
+				if (pl.len) {
+					throw 'Invalid table entry';
+				}
+
+				pl.lit++;
+
+				if (pl.p) {
+					var p = pl.p;
+					pl.p = new Array(pl.lit);
+
+					for (var i = 0; i < pl.lit - 1; ++i) {
+						pl.p[i] = p[i];
+					}
+				} else {
+					pl.p = new Array(1);
+				}
+
+				pl.p[pl.lit - 1] = im;
+			} else if (l) {
+				var plOffset = 0;
+
+				for (var i = 1 << (HUF_DECBITS - l); i > 0; i--) {
+					var pl = hdecod[(c << (HUF_DECBITS - l)) + plOffset];
+
+					if (pl.len || pl.p) {
+						throw 'Invalid table entry';
+					}
+
+					pl.len = l;
+					pl.lit = im;
+
+					plOffset++;
+				}
+			}
+		}
+
+		return true;
+	}
+
+	const getCharReturn = { c: 0, lc: 0 };
+	function getChar(c, lc, uInt8Array, inOffset) {
+		c = (c << 8) | parseUint8Array(uInt8Array, inOffset);
+		lc += 8;
+
+		getCharReturn.c = c;
+		getCharReturn.lc = lc;
+	}
+
+	const getCodeReturn = { c: 0, lc: 0 };
+	function getCode(po, rlc, c, lc, uInt8Array, inDataView, inOffset, outBuffer, outBufferOffset, outBufferEndOffset) {
+		if (po == rlc) {
+			if (lc < 8) {
+				getChar(c, lc, uInt8Array, inOffset);
+				c = getCharReturn.c;
+				lc = getCharReturn.lc;
+			}
+
+			lc -= 8;
+
+			var cs = (c >> lc);
+
+			if (out + cs > oe) {
+				throw 'Issue with getCode';
+			}
+
+			var s = out[-1];
+
+			while (cs-- > 0) {
+				outBuffer[outBufferOffset.value++] = s;
+			}
+		} else if (outBufferOffset.value < outBufferEndOffset) {
+			outBuffer[outBufferOffset.value++] = po;
+		} else {
+			throw 'Issue with getCode';
+		}
+
+		getCodeReturn.c = c;
+		getCodeReturn.lc = lc;
+	}
+
+	var NBITS = 16;
+	var A_OFFSET = 1 << (NBITS - 1);
+	var M_OFFSET = 1 << (NBITS - 1);
+	var MOD_MASK = (1 << NBITS) - 1;
+
+	function UInt16(value) {
+		return (value & 0xFFFF);
+	};
+
+	function Int16(value) {
+		var ref = UInt16(value);
+		return (ref > 0x7FFF) ? ref - 0x10000 : ref;
+	};
+
+	const wdec14Return = { a: 0, b: 0 };
+	function wdec14(l, h) {
+		var ls = Int16(l);
+		var hs = Int16(h);
+
+		var hi = hs;
+		var ai = ls + (hi & 1) + (hi >> 1);
+
+		var as = ai;
+		var bs = ai - hi;
+
+		wdec14Return.a = as;
+		wdec14Return.b = bs;
+	}
+
+	function wav2Decode(j, buffer, nx, ox, ny, oy, mx) {
+		var n = (nx > ny) ? ny : nx;
+		var p = 1;
+		var p2;
+
+		while (p <= n) p <<= 1;
+
+		p >>= 1;
+		p2 = p;
+		p >>= 1;
+
+		while (p >= 1) {
+			var py = 0;
+			var ey = py + oy * (ny - p2);
+			var oy1 = oy * p;
+			var oy2 = oy * p2;
+			var ox1 = ox * p;
+			var ox2 = ox * p2;
+			var i00, i01, i10, i11;
+
+			for (; py <= ey; py += oy2) {
+				var px = py;
+				var ex = py + ox * (nx - p2);
+
+				for (; px <= ex; px += ox2) {
+					var p01 = px + ox1;
+					var p10 = px + oy1;
+					var p11 = p10 + ox1;
+
+					wdec14(buffer[px + j], buffer[p10 + j]);
+					i00 = wdec14Return.a;
+					i10 = wdec14Return.b;
+
+					wdec14(buffer[p01 + j], buffer[p11 + j]);
+					i01 = wdec14Return.a;
+					i11 = wdec14Return.b;
+
+					wdec14(i00, i01);
+					buffer[px + j] = wdec14Return.a;
+					buffer[p01 + j] = wdec14Return.b;
+
+					wdec14(i10, i11);
+					buffer[p10 + j] = wdec14Return.a;
+					buffer[p11 + j] = wdec14Return.b;
+				}
+
+				if (nx & p) {
+					var p10 = px + oy1;
+
+					wdec14(buffer[px + j], buffer[p10 + j]);
+					i00 = wdec14Return.a;
+					buffer[p10 + j] = wdec14Return.b;
+
+					buffer[px + j] = i00;
+				}
+			}
+
+			if (ny & p) {
+				var px = py;
+				var ex = py + ox * (nx - p2);
+
+				for (; px <= ex; px += ox2) {
+					var p01 = px + ox1;
+
+					wdec14(buffer[px + j], buffer[p01 + j]);
+					i00 = wdec14Return.a;
+					buffer[p01 + j] = wdec14Return.b;
+
+					buffer[px + j] = i00;
+				}
+			}
+
+			p2 = p;
+			p >>= 1;
+		}
+
+		return py;
+	}
+
+	function hufDecode(encodingTable, decodingTable, uInt8Array, inDataView, inOffset, ni, rlc, no, outBuffer, outOffset) {
+		var c = 0;
+		var lc = 0;
+		var outBufferEndOffset = no;
+		var inOffsetEnd = Math.trunc(inOffset.value + (ni + 7) / 8);
+
+		while (inOffset.value < inOffsetEnd) {
+			getChar(c, lc, uInt8Array, inOffset);
+			c = getCharReturn.c;
+			lc = getCharReturn.lc;
+
+			while (lc >= HUF_DECBITS) {
+				var index = (c >> (lc - HUF_DECBITS)) & HUF_DECMASK;
+				var pl = decodingTable[index];
+
+				if (pl.len) {
+					lc -= pl.len;
+					getCode(pl.lit, rlc, c, lc, uInt8Array, inDataView, inOffset, outBuffer, outOffset, outBufferEndOffset);
+					c = getCodeReturn.c;
+					lc = getCodeReturn.lc;
+				} else {
+					if (!pl.p) {
+						throw 'hufDecode issues';
+					}
+
+					var j;
+
+					for (j = 0; j < pl.lit; j++) {
+						var l = hufLength(encodingTable[pl.p[j]]);
+
+						while (lc < l && inOffset.value < inOffsetEnd) {
+							getChar(c, lc, uInt8Array, inOffset);
+							c = getCharReturn.c;
+							lc = getCharReturn.lc;
+						}
+
+						if (lc >= l) {
+							if (hufCode(encodingTable[pl.p[j]]) ==
+								((c >> (lc - l)) & ((1 << l) - 1))) {
+
+								lc -= l;
+								getCode(pl.p[j], rlc, c, lc, uInt8Array, inDataView, inOffset, outBuffer, outOffset, outBufferEndOffset);
+								c = getCodeReturn.c;
+								lc = getCodeReturn.lc;
+								break;
+							}
+						}
+					}
+
+					if (j == pl.lit) {
+						throw 'hufDecode issues';
+					}
+				}
+			}
+		}
+
+		var i = (8 - ni) & 7;
+		c >>= i;
+		lc -= i;
+
+		while (lc > 0) {
+			var pl = decodingTable[(c << (HUF_DECBITS - lc)) & HUF_DECMASK];
+
+			if (pl.len) {
+				lc -= pl.len;
+				getCode(pl.lit, rlc, c, lc, uInt8Array, inDataView, inOffset, outBuffer, outOffset, outBufferEndOffset);
+				c = getCodeReturn.c;
+				lc = getCodeReturn.lc;
+			} else {
+				throw 'hufDecode issues';
+			}
+		}
+
+		return true;
+	}
+
+	function hufUncompress(uInt8Array, inDataView, inOffset, nCompressed, outBuffer, outOffset, nRaw) {
+		var initialInOffset = inOffset.value;
+
+		var im = parseUint32(inDataView, inOffset);
+		var iM = parseUint32(inDataView, inOffset);
+		inOffset.value += 4;
+		var nBits = parseUint32(inDataView, inOffset);
+		inOffset.value += 4;
+
+		if (im < 0 || im >= HUF_ENCSIZE || iM < 0 || iM >= HUF_ENCSIZE) {
+			throw 'Something wrong with HUF_ENCSIZE';
+		}
+
+		var freq = new Array(HUF_ENCSIZE);
+		var hdec = new Array(HUF_DECSIZE);
+
+		hufClearDecTable(hdec);
+
+		var ni = nCompressed - (inOffset.value - initialInOffset);
+
+		hufUnpackEncTable(uInt8Array, inDataView, inOffset, ni, im, iM, freq);
+
+		if (nBits > 8 * (nCompressed - (inOffset.value - initialInOffset))) {
+			throw 'Something wrong with hufUncompress';
+		}
+
+		hufBuildDecTable(freq, im, iM, hdec);
+
+		hufDecode(freq, hdec, uInt8Array, inDataView, inOffset, nBits, iM, nRaw, outBuffer, outOffset);
+	}
+
+	function applyLut(lut, data, nData) {
+		for (var i = 0; i < nData; ++i) {
+			data[i] = lut[data[i]];
+		}
+	}
+
+	function decompressPIZ(outBuffer, outOffset, uInt8Array, inDataView, inOffset, tmpBufSize, num_channels, exrChannelInfos, dataWidth, num_lines) {
+		var bitmap = new Uint8Array(BITMAP_SIZE);
+
+		var minNonZero = parseUint16(inDataView, inOffset);
+		var maxNonZero = parseUint16(inDataView, inOffset);
+
+		if (maxNonZero >= BITMAP_SIZE) {
+			throw 'Something is wrong with PIZ_COMPRESSION BITMAP_SIZE'
+		}
+
+		if (minNonZero <= maxNonZero) {
+			for (var i = 0; i < maxNonZero - minNonZero + 1; i++) {
+				bitmap[i + minNonZero] = parseUint8(inDataView, inOffset);
+			}
+		}
+
+		var lut = new Uint16Array(USHORT_RANGE);
+		var maxValue = reverseLutFromBitmap(bitmap, lut);
+
+		var length = parseUint32(inDataView, inOffset);
+
+		hufUncompress(uInt8Array, inDataView, inOffset, length, outBuffer, outOffset, tmpBufSize);
+
+		var pizChannelData = new Array(num_channels);
+
+		var outBufferEnd = 0
+
+		for (var i = 0; i < num_channels; i++) {
+			var exrChannelInfo = exrChannelInfos[i];
+
+			var pixelSize = 2; // assumes HALF_FLOAT
+
+			pizChannelData[i] = {};
+			pizChannelData[i]['start'] = outBufferEnd;
+			pizChannelData[i]['end'] = pizChannelData[i]['start'];
+			pizChannelData[i]['nx'] = dataWidth;
+			pizChannelData[i]['ny'] = num_lines;
+			pizChannelData[i]['size'] = 1;
+
+			outBufferEnd += pizChannelData[i].nx * pizChannelData[i].ny * pizChannelData[i].size;
+		}
+
+		var fooOffset = 0;
+
+		for (var i = 0; i < num_channels; i++) {
+			for (var j = 0; j < pizChannelData[i].size; ++j) {
+				fooOffset += wav2Decode(
+				j + fooOffset,
+				outBuffer,
+				pizChannelData[i].nx,
+				pizChannelData[i].size,
+				pizChannelData[i].ny,
+				pizChannelData[i].nx * pizChannelData[i].size,
+				maxValue
+				);
+			}
+		}
+
+		applyLut(lut, outBuffer, outBufferEnd);
+
+		return true;
+	}
+
 	function parseNullTerminatedString( buffer, offset ) {
 	function parseNullTerminatedString( buffer, offset ) {
 
 
 		var uintBuffer = new Uint8Array( buffer );
 		var uintBuffer = new Uint8Array( buffer );
@@ -27,7 +607,7 @@ THREE.EXRLoader.prototype._parser = function ( buffer ) {
 		}
 		}
 
 
 		var stringValue = new TextDecoder().decode(
 		var stringValue = new TextDecoder().decode(
-			new Uint8Array( buffer ).slice( offset.value, offset.value + endOffset )
+			uintBuffer.slice( offset.value, offset.value + endOffset )
 		);
 		);
 
 
 		offset.value = offset.value + endOffset + 1;
 		offset.value = offset.value + endOffset + 1;
@@ -48,41 +628,51 @@ THREE.EXRLoader.prototype._parser = function ( buffer ) {
 
 
 	}
 	}
 
 
-	function parseUlong( buffer, offset ) {
+	function parseUlong( dataView, offset ) {
 
 
-		var uLong = new DataView( buffer.slice( offset.value, offset.value + 4 ) ).getUint32( 0, true );
+		var uLong = dataView.getUint32( 0, true );
 
 
-		offset.value = offset.value + 8;
+		offset.value = offset.value + ULONG_SIZE;
 
 
 		return uLong;
 		return uLong;
 
 
 	}
 	}
 
 
-	function parseUint32( buffer, offset ) {
+	function parseUint32( dataView, offset ) {
 
 
-		var Uint32 = new DataView( buffer.slice( offset.value, offset.value + 4 ) ).getUint32( 0, true );
+		var Uint32 = dataView.getUint32(offset.value, true);
 
 
-		offset.value = offset.value + 4;
+		offset.value = offset.value + INT32_SIZE;
 
 
 		return Uint32;
 		return Uint32;
 
 
 	}
 	}
 
 
-	function parseUint8( buffer, offset ) {
+	function parseUint8Array( uInt8Array, offset ) {
+
+		var Uint8 = uInt8Array[offset.value];
+
+		offset.value = offset.value + INT8_SIZE;
+
+		return Uint8;
+
+	}
+
+	function parseUint8( dataView, offset ) {
 
 
-		var Uint8 = new DataView( buffer.slice( offset.value, offset.value + 1 ) ).getUint8( 0, true );
+		var Uint8 = dataView.getUint8(offset.value);
 
 
-		offset.value = offset.value + 1;
+		offset.value = offset.value + INT8_SIZE;
 
 
 		return Uint8;
 		return Uint8;
 
 
 	}
 	}
 
 
-	function parseFloat32( buffer, offset ) {
+	function parseFloat32( dataView, offset ) {
 
 
-		var float = new DataView( buffer.slice( offset.value, offset.value + 4 ) ).getFloat32( 0, true );
+		var float = dataView.getFloat32(offset.value, true);
 
 
-		offset.value += 4;
+		offset.value += FLOAT32_SIZE;
 
 
 		return float;
 		return float;
 
 
@@ -106,17 +696,23 @@ THREE.EXRLoader.prototype._parser = function ( buffer ) {
 
 
 	}
 	}
 
 
-	function parseFloat16( buffer, offset ) {
+	function parseUint16( dataView, offset ) {
 
 
-		var float = new DataView( buffer.slice( offset.value, offset.value + 2 ) ).getUint16( 0, true );
+		var Uint16 = dataView.getUint16( offset.value, true );
 
 
-		offset.value += 2;
+		offset.value += INT16_SIZE;
 
 
-		return decodeFloat16( float );
+		return Uint16;
 
 
 	}
 	}
 
 
-	function parseChlist( buffer, offset, size ) {
+	function parseFloat16( buffer, offset ) {
+
+		return decodeFloat16( parseUint16( buffer, offset) );
+
+	}
+
+	function parseChlist( dataView, buffer, offset, size ) {
 
 
 		var startOffset = offset.value;
 		var startOffset = offset.value;
 		var channels = [];
 		var channels = [];
@@ -124,11 +720,11 @@ THREE.EXRLoader.prototype._parser = function ( buffer ) {
 		while ( offset.value < ( startOffset + size - 1 ) ) {
 		while ( offset.value < ( startOffset + size - 1 ) ) {
 
 
 			var name = parseNullTerminatedString( buffer, offset );
 			var name = parseNullTerminatedString( buffer, offset );
-			var pixelType = parseUint32( buffer, offset ); // TODO: Cast this to UINT, HALF or FLOAT
-			var pLinear = parseUint8( buffer, offset );
+			var pixelType = parseUint32( dataView, offset ); // TODO: Cast this to UINT, HALF or FLOAT
+			var pLinear = parseUint8( dataView, offset );
 			offset.value += 3; // reserved, three chars
 			offset.value += 3; // reserved, three chars
-			var xSampling = parseUint32( buffer, offset );
-			var ySampling = parseUint32( buffer, offset );
+			var xSampling = parseUint32( dataView, offset );
+			var ySampling = parseUint32( dataView, offset );
 
 
 			channels.push( {
 			channels.push( {
 				name: name,
 				name: name,
@@ -146,67 +742,70 @@ THREE.EXRLoader.prototype._parser = function ( buffer ) {
 
 
 	}
 	}
 
 
-	function parseChromaticities( buffer, offset ) {
+	function parseChromaticities( dataView, offset ) {
 
 
-		var redX = parseFloat32( buffer, offset );
-		var redY = parseFloat32( buffer, offset );
-		var greenX = parseFloat32( buffer, offset );
-		var greenY = parseFloat32( buffer, offset );
-		var blueX = parseFloat32( buffer, offset );
-		var blueY = parseFloat32( buffer, offset );
-		var whiteX = parseFloat32( buffer, offset );
-		var whiteY = parseFloat32( buffer, offset );
+		var redX = parseFloat32( dataView, offset );
+		var redY = parseFloat32( dataView, offset );
+		var greenX = parseFloat32( dataView, offset );
+		var greenY = parseFloat32( dataView, offset );
+		var blueX = parseFloat32( dataView, offset );
+		var blueY = parseFloat32( dataView, offset );
+		var whiteX = parseFloat32( dataView, offset );
+		var whiteY = parseFloat32( dataView, offset );
 
 
 		return { redX: redX, redY: redY, greenX, greenY, blueX, blueY, whiteX, whiteY };
 		return { redX: redX, redY: redY, greenX, greenY, blueX, blueY, whiteX, whiteY };
 
 
 	}
 	}
 
 
-	function parseCompression( buffer, offset ) {
+	function parseCompression( dataView, offset ) {
 
 
 		var compressionCodes = [
 		var compressionCodes = [
 			'NO_COMPRESSION',
 			'NO_COMPRESSION',
+			'RLE_COMPRESSION',
+			'ZIPS_COMPRESSION',
+			'ZIP_COMPRESSION',
 			'PIZ_COMPRESSION'
 			'PIZ_COMPRESSION'
 		];
 		];
 
 
-		var compression = parseUint8( buffer, offset );
+		var compression = parseUint8( dataView, offset );
 
 
 		return compressionCodes[ compression ];
 		return compressionCodes[ compression ];
 
 
 	}
 	}
 
 
-	function parseBox2i( buffer, offset ) {
+	function parseBox2i( dataView, offset ) {
 
 
-		var xMin = parseUint32( buffer, offset );
-		var yMin = parseUint32( buffer, offset );
-		var xMax = parseUint32( buffer, offset );
-		var yMax = parseUint32( buffer, offset );
+		var xMin = parseUint32( dataView, offset );
+		var yMin = parseUint32( dataView, offset );
+		var xMax = parseUint32( dataView, offset );
+		var yMax = parseUint32( dataView, offset );
 
 
 		return { xMin: xMin, yMin: yMin, xMax: xMax, yMax: yMax };
 		return { xMin: xMin, yMin: yMin, xMax: xMax, yMax: yMax };
 
 
 	}
 	}
 
 
-	function parseLineOrder( buffer, offset ) {
+	function parseLineOrder( dataView, offset ) {
 
 
 		var lineOrders = [
 		var lineOrders = [
 			'INCREASING_Y'
 			'INCREASING_Y'
 		];
 		];
 
 
-		var lineOrder = parseUint8( buffer, offset );
+		var lineOrder = parseUint8( dataView, offset );
 
 
 		return lineOrders[ lineOrder ];
 		return lineOrders[ lineOrder ];
 
 
 	}
 	}
 
 
-	function parseV2f( buffer, offset ) {
+	function parseV2f( dataView, offset ) {
 
 
-		var x = parseFloat32( buffer, offset );
-		var y = parseFloat32( buffer, offset );
+		var x = parseFloat32( dataView, offset );
+		var y = parseFloat32( dataView, offset );
 
 
 		return [ x, y ];
 		return [ x, y ];
 
 
 	}
 	}
 
 
-	function parseValue( buffer, offset, type, size ) {
+	function parseValue( dataView, buffer, offset, type, size ) {
 
 
 		if ( type == 'string' || type == 'iccProfile' ) {
 		if ( type == 'string' || type == 'iccProfile' ) {
 
 
@@ -214,7 +813,7 @@ THREE.EXRLoader.prototype._parser = function ( buffer ) {
 
 
 		} else if ( type == 'chlist' ) {
 		} else if ( type == 'chlist' ) {
 
 
-			return parseChlist( buffer, offset, size );
+			return parseChlist( dataView, buffer, offset, size );
 
 
 		} else if ( type == 'chromaticities' ) {
 		} else if ( type == 'chromaticities' ) {
 
 
@@ -222,23 +821,23 @@ THREE.EXRLoader.prototype._parser = function ( buffer ) {
 
 
 		} else if ( type == 'compression' ) {
 		} else if ( type == 'compression' ) {
 
 
-			return parseCompression( buffer, offset );
+			return parseCompression( dataView, offset );
 
 
 		} else if ( type == 'box2i' ) {
 		} else if ( type == 'box2i' ) {
 
 
-			return parseBox2i( buffer, offset );
+			return parseBox2i( dataView, offset );
 
 
 		} else if ( type == 'lineOrder' ) {
 		} else if ( type == 'lineOrder' ) {
 
 
-			return parseLineOrder( buffer, offset );
+			return parseLineOrder( dataView, offset );
 
 
 		} else if ( type == 'float' ) {
 		} else if ( type == 'float' ) {
 
 
-			return parseFloat32( buffer, offset );
+			return parseFloat32( dataView, offset );
 
 
 		} else if ( type == 'v2f' ) {
 		} else if ( type == 'v2f' ) {
 
 
-			return parseV2f( buffer, offset );
+			return parseV2f( dataView, offset );
 
 
 		} else {
 		} else {
 
 
@@ -248,11 +847,14 @@ THREE.EXRLoader.prototype._parser = function ( buffer ) {
 
 
 	}
 	}
 
 
+	var bufferDataView = new DataView(buffer);
+	var uInt8Array = new Uint8Array(buffer);
+
 	var EXRHeader = {};
 	var EXRHeader = {};
 
 
-	var magic = new DataView( buffer ).getUint32( 0, true );
-	var versionByteZero = new DataView( buffer ).getUint8( 4, true );
-	var fullMask = new DataView( buffer ).getUint8( 5, true );
+	var magic = bufferDataView.getUint32( 0, true );
+	var versionByteZero = bufferDataView.getUint8( 4, true );
+	var fullMask = bufferDataView.getUint8( 5, true );
 
 
 	// start of header
 	// start of header
 
 
@@ -271,8 +873,8 @@ THREE.EXRLoader.prototype._parser = function ( buffer ) {
 		} else {
 		} else {
 
 
 			var attributeType = parseNullTerminatedString( buffer, offset );
 			var attributeType = parseNullTerminatedString( buffer, offset );
-			var attributeSize = parseUint32( buffer, offset );
-			var attributeValue = parseValue( buffer, offset, attributeType, attributeSize );
+			var attributeSize = parseUint32( bufferDataView, offset );
+			var attributeValue = parseValue( bufferDataView, buffer, offset, attributeType, attributeSize );
 
 
 			EXRHeader[ attributeName ] = attributeValue;
 			EXRHeader[ attributeName ] = attributeValue;
 
 
@@ -283,12 +885,15 @@ THREE.EXRLoader.prototype._parser = function ( buffer ) {
 	// offsets
 	// offsets
 
 
 	var dataWindowHeight = EXRHeader.dataWindow.yMax + 1;
 	var dataWindowHeight = EXRHeader.dataWindow.yMax + 1;
-	var scanlineBlockSize = 1; // 1 for no compression, 32 for PIZ
+	var scanlineBlockSize = 1; // 1 for NO_COMPRESSION
+	if (EXRHeader.compression == 'PIZ_COMPRESSION') {
+		scanlineBlockSize = 32;
+	}
 	var numBlocks = dataWindowHeight / scanlineBlockSize;
 	var numBlocks = dataWindowHeight / scanlineBlockSize;
 
 
 	for ( var i = 0; i < numBlocks; i ++ ) {
 	for ( var i = 0; i < numBlocks; i ++ ) {
 
 
-		var scanlineOffset = parseUlong( buffer, offset );
+		var scanlineOffset = parseUlong( bufferDataView, offset );
 
 
 	}
 	}
 
 
@@ -307,33 +912,86 @@ THREE.EXRLoader.prototype._parser = function ( buffer ) {
 		A: 3
 		A: 3
 	};
 	};
 
 
-	for ( var y = 0; y < height; y ++ ) {
+	if (EXRHeader.compression == 'NO_COMPRESSION') {
 
 
-		var y_scanline = parseUint32( buffer, offset );
-		var dataSize = parseUint32( buffer, offset );
+		for ( var y = 0; y < height; y ++ ) {
 
 
-		for ( var channelID = 0; channelID < EXRHeader.channels.length; channelID ++ ) {
+			var y_scanline = parseUint32( buffer, offset );
+			var dataSize = parseUint32( buffer, offset );
 
 
-			if ( EXRHeader.channels[ channelID ].pixelType == 1 ) {
+			for ( var channelID = 0; channelID < EXRHeader.channels.length; channelID ++ ) {
 
 
-				// HALF
-				for ( var x = 0; x < width; x ++ ) {
+				var cOff = channelOffsets[ EXRHeader.channels[ channelID ].name ];
 
 
-					var val = parseFloat16( buffer, offset );
-					var cOff = channelOffsets[ EXRHeader.channels[ channelID ].name ];
+				if ( EXRHeader.channels[ channelID ].pixelType == 1 ) {
+
+					// HALF
+					for ( var x = 0; x < width; x ++ ) {
+
+						var val = parseFloat16( buffer, offset );
+
+						byteArray[ ( ( ( width - y_scanline ) * ( height * numChannels ) ) + ( x * numChannels ) ) + cOff ] = val;
+
+					}
 
 
-					byteArray[ ( ( ( width - y_scanline ) * ( height * numChannels ) ) + ( x * numChannels ) ) + cOff ] = val;
+				} else {
+
+					throw 'Only supported pixel format is HALF';
 
 
 				}
 				}
 
 
-			} else {
+			}
+
+		}
+
+	} else if (EXRHeader.compression == 'PIZ_COMPRESSION') {
+
+		for ( var scanlineBlockIdx = 0; scanlineBlockIdx < height / scanlineBlockSize; scanlineBlockIdx++ ) {
+
+			var line_no = parseUint32( bufferDataView, offset );
+			var data_len = parseUint32( bufferDataView, offset );
+
+			var tmpBufferSize = width * scanlineBlockSize * (EXRHeader.channels.length * BYTES_PER_HALF);
+			var tmpBuffer = new Uint16Array(tmpBufferSize);
+			var tmpOffset = { value: 0 };
+
+			decompressPIZ(tmpBuffer, tmpOffset, uInt8Array, bufferDataView, offset, tmpBufferSize, numChannels, EXRHeader.channels, width, scanlineBlockSize);
+
+			for ( var line_y = 0; line_y < scanlineBlockSize; line_y ++ ) {
+
+				for ( var channelID = 0; channelID < EXRHeader.channels.length; channelID ++ ) {
+
+					var cOff = channelOffsets[ EXRHeader.channels[ channelID ].name ];
+
+					if ( EXRHeader.channels[ channelID ].pixelType == 1 ) {
+
+						// HALF
+						for ( var x = 0; x < width; x ++ ) {
+
+							var val = decodeFloat16(tmpBuffer[ (channelID * (scanlineBlockSize * width)) + (line_y * width) + x ]);
+
+							var true_y = line_y + (scanlineBlockIdx * scanlineBlockSize);
+
+							byteArray[ ( ( (height - true_y) * ( width * numChannels ) ) + ( x * numChannels ) ) + cOff ] = val;
+
+						}
 
 
-				throw 'Only supported pixel format is HALF';
+					} else {
+
+						throw 'Only supported pixel format is HALF';
+
+					}
+
+				}
 
 
 			}
 			}
 
 
 		}
 		}
 
 
+	} else {
+
+		throw 'Cannot decompress unsupported compression';
+
 	}
 	}
 
 
 	return {
 	return {
@@ -341,7 +999,7 @@ THREE.EXRLoader.prototype._parser = function ( buffer ) {
 		width: width,
 		width: width,
 		height: height,
 		height: height,
 		data: byteArray,
 		data: byteArray,
-		format: THREE.RGBAFormat,
+		format: THREE.RGBFormat,
 		type: THREE.FloatType
 		type: THREE.FloatType
 	};
 	};
 
 

+ 85 - 24
examples/js/loaders/GLTFLoader.js

@@ -128,6 +128,12 @@ THREE.GLTFLoader = ( function () {
 
 
 				}
 				}
 
 
+				if ( json.extensionsUsed.indexOf( EXTENSIONS.KHR_MATERIALS_UNLIT ) >= 0 ) {
+
+					extensions[ EXTENSIONS.KHR_MATERIALS_UNLIT ] = new GLTFMaterialsUnlitExtension( json );
+
+				}
+
 				if ( json.extensionsUsed.indexOf( EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS ) >= 0 ) {
 				if ( json.extensionsUsed.indexOf( EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS ) >= 0 ) {
 
 
 					extensions[ EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS ] = new GLTFMaterialsPbrSpecularGlossinessExtension();
 					extensions[ EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS ] = new GLTFMaterialsPbrSpecularGlossinessExtension();
@@ -216,7 +222,8 @@ THREE.GLTFLoader = ( function () {
 		KHR_BINARY_GLTF: 'KHR_binary_glTF',
 		KHR_BINARY_GLTF: 'KHR_binary_glTF',
 		KHR_DRACO_MESH_COMPRESSION: 'KHR_draco_mesh_compression',
 		KHR_DRACO_MESH_COMPRESSION: 'KHR_draco_mesh_compression',
 		KHR_LIGHTS: 'KHR_lights',
 		KHR_LIGHTS: 'KHR_lights',
-		KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS: 'KHR_materials_pbrSpecularGlossiness'
+		KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS: 'KHR_materials_pbrSpecularGlossiness',
+		KHR_MATERIALS_UNLIT: 'KHR_materials_unlit'
 	};
 	};
 
 
 	/**
 	/**
@@ -303,6 +310,55 @@ THREE.GLTFLoader = ( function () {
 
 
 	}
 	}
 
 
+	/**
+	 * Unlit Materials Extension (pending)
+	 *
+	 * PR: https://github.com/KhronosGroup/glTF/pull/1163
+	 */
+	function GLTFMaterialsUnlitExtension( json ) {
+
+		this.name = EXTENSIONS.KHR_MATERIALS_UNLIT;
+
+	}
+
+	GLTFMaterialsUnlitExtension.prototype.getMaterialType = function ( material ) {
+
+		return THREE.MeshBasicMaterial;
+
+	};
+
+	GLTFMaterialsUnlitExtension.prototype.extendParams = function ( materialParams, material, parser ) {
+
+		var pending = [];
+
+		materialParams.color = new THREE.Color( 1.0, 1.0, 1.0 );
+		materialParams.opacity = 1.0;
+
+		var metallicRoughness = material.pbrMetallicRoughness;
+
+		if ( metallicRoughness ) {
+
+			if ( Array.isArray( metallicRoughness.baseColorFactor ) ) {
+
+				var array = metallicRoughness.baseColorFactor;
+
+				materialParams.color.fromArray( array );
+				materialParams.opacity = array[ 3 ];
+
+			}
+
+			if ( metallicRoughness.baseColorTexture !== undefined ) {
+
+				pending.push( parser.assignTexture( materialParams, 'map', metallicRoughness.baseColorTexture.index ) );
+
+			}
+
+		}
+
+		return Promise.all( pending );
+
+	};
+
 	/* BINARY EXTENSION */
 	/* BINARY EXTENSION */
 
 
 	var BINARY_EXTENSION_BUFFER_NAME = 'binary_glTF';
 	var BINARY_EXTENSION_BUFFER_NAME = 'binary_glTF';
@@ -1205,6 +1261,17 @@ THREE.GLTFLoader = ( function () {
 
 
 		}
 		}
 
 
+		// .extras has user-defined data, so check that .extras.targetNames is an array.
+		if ( meshDef.extras && Array.isArray( meshDef.extras.targetNames ) ) {
+
+			for ( var i = 0, il = meshDef.extras.targetNames.length; i < il; i ++ ) {
+
+				mesh.morphTargetDictionary[ meshDef.extras.targetNames[ i ] ] = i;
+
+			}
+
+		}
+
 	}
 	}
 
 
 	function isPrimitiveEqual( a, b ) {
 	function isPrimitiveEqual( a, b ) {
@@ -1797,6 +1864,12 @@ THREE.GLTFLoader = ( function () {
 			materialType = sgExtension.getMaterialType( materialDef );
 			materialType = sgExtension.getMaterialType( materialDef );
 			pending.push( sgExtension.extendParams( materialParams, materialDef, parser ) );
 			pending.push( sgExtension.extendParams( materialParams, materialDef, parser ) );
 
 
+		} else if ( materialExtensions[ EXTENSIONS.KHR_MATERIALS_UNLIT ] ) {
+
+			var kmuExtension = extensions[ EXTENSIONS.KHR_MATERIALS_UNLIT ];
+			materialType = kmuExtension.getMaterialType( materialDef );
+			pending.push( kmuExtension.extendParams( materialParams, materialDef, parser ) );
+
 		} else if ( materialDef.pbrMetallicRoughness !== undefined ) {
 		} else if ( materialDef.pbrMetallicRoughness !== undefined ) {
 
 
 			// Specification:
 			// Specification:
@@ -1865,7 +1938,7 @@ THREE.GLTFLoader = ( function () {
 
 
 		}
 		}
 
 
-		if ( materialDef.normalTexture !== undefined ) {
+		if ( materialDef.normalTexture !== undefined && materialType !== THREE.MeshBasicMaterial) {
 
 
 			pending.push( parser.assignTexture( materialParams, 'normalMap', materialDef.normalTexture.index ) );
 			pending.push( parser.assignTexture( materialParams, 'normalMap', materialDef.normalTexture.index ) );
 
 
@@ -1879,7 +1952,7 @@ THREE.GLTFLoader = ( function () {
 
 
 		}
 		}
 
 
-		if ( materialDef.occlusionTexture !== undefined ) {
+		if ( materialDef.occlusionTexture !== undefined && materialType !== THREE.MeshBasicMaterial) {
 
 
 			pending.push( parser.assignTexture( materialParams, 'aoMap', materialDef.occlusionTexture.index ) );
 			pending.push( parser.assignTexture( materialParams, 'aoMap', materialDef.occlusionTexture.index ) );
 
 
@@ -1891,31 +1964,15 @@ THREE.GLTFLoader = ( function () {
 
 
 		}
 		}
 
 
-		if ( materialDef.emissiveFactor !== undefined ) {
-
-			if ( materialType === THREE.MeshBasicMaterial ) {
-
-				materialParams.color = new THREE.Color().fromArray( materialDef.emissiveFactor );
+		if ( materialDef.emissiveFactor !== undefined && materialType !== THREE.MeshBasicMaterial) {
 
 
-			} else {
-
-				materialParams.emissive = new THREE.Color().fromArray( materialDef.emissiveFactor );
-
-			}
+			materialParams.emissive = new THREE.Color().fromArray( materialDef.emissiveFactor );
 
 
 		}
 		}
 
 
-		if ( materialDef.emissiveTexture !== undefined ) {
+		if ( materialDef.emissiveTexture !== undefined && materialType !== THREE.MeshBasicMaterial) {
 
 
-			if ( materialType === THREE.MeshBasicMaterial ) {
-
-				pending.push( parser.assignTexture( materialParams, 'map', materialDef.emissiveTexture.index ) );
-
-			} else {
-
-				pending.push( parser.assignTexture( materialParams, 'emissiveMap', materialDef.emissiveTexture.index ) );
-
-			}
+			pending.push( parser.assignTexture( materialParams, 'emissiveMap', materialDef.emissiveTexture.index ) );
 
 
 		}
 		}
 
 
@@ -2453,7 +2510,7 @@ THREE.GLTFLoader = ( function () {
 							// Overrides .createInterpolant in a factory method which creates custom interpolation.
 							// Overrides .createInterpolant in a factory method which creates custom interpolation.
 							if ( sampler.interpolation === 'CUBICSPLINE' ) {
 							if ( sampler.interpolation === 'CUBICSPLINE' ) {
 
 
-								track.createInterpolant = function ( result ) {
+								track.createInterpolant = function InterpolantFactoryMethodGLTFCubicSpline( result ) {
 
 
 									// A CUBICSPLINE keyframe in glTF has three output values for each input value,
 									// A CUBICSPLINE keyframe in glTF has three output values for each input value,
 									// representing inTangent, splineVertex, and outTangent. As a result, track.getValueSize()
 									// representing inTangent, splineVertex, and outTangent. As a result, track.getValueSize()
@@ -2463,6 +2520,10 @@ THREE.GLTFLoader = ( function () {
 
 
 								};
 								};
 
 
+								// Workaround, provide an alternate way to know if the interpolant type is cubis spline to track.
+								// track.getInterpolation() doesn't return valid value for custom interpolant.
+								track.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline = true;
+
 							}
 							}
 
 
 							tracks.push( track );
 							tracks.push( track );

+ 1 - 1
examples/js/loaders/MMDLoader.js

@@ -1476,7 +1476,7 @@ THREE.MMDLoader.prototype.createMesh = function ( model, texturePath, onProgress
 		geometry.addAttribute( 'position', new THREE.Float32BufferAttribute( buffer.vertices, 3 ) );
 		geometry.addAttribute( 'position', new THREE.Float32BufferAttribute( buffer.vertices, 3 ) );
 		geometry.addAttribute( 'normal', new THREE.Float32BufferAttribute( buffer.normals, 3 ) );
 		geometry.addAttribute( 'normal', new THREE.Float32BufferAttribute( buffer.normals, 3 ) );
 		geometry.addAttribute( 'uv', new THREE.Float32BufferAttribute( buffer.uvs, 2 ) );
 		geometry.addAttribute( 'uv', new THREE.Float32BufferAttribute( buffer.uvs, 2 ) );
-		geometry.addAttribute( 'skinIndex', new THREE.Float32BufferAttribute( buffer.skinIndices, 4 ) );
+		geometry.addAttribute( 'skinIndex', new THREE.Uint16BufferAttribute( buffer.skinIndices, 4 ) );
 		geometry.addAttribute( 'skinWeight', new THREE.Float32BufferAttribute( buffer.skinWeights, 4 ) );
 		geometry.addAttribute( 'skinWeight', new THREE.Float32BufferAttribute( buffer.skinWeights, 4 ) );
 
 
 		geometry.computeBoundingSphere();
 		geometry.computeBoundingSphere();

+ 2 - 4
examples/js/loaders/OBJLoader.js

@@ -286,19 +286,17 @@ THREE.OBJLoader = ( function () {
 
 
 				this.addVertex( ia, ib, ic );
 				this.addVertex( ia, ib, ic );
 
 
-				if ( ua !== undefined ) {
+				if ( ua !== undefined && ua !== '' ) {
 
 
 					var uvLen = this.uvs.length;
 					var uvLen = this.uvs.length;
-
 					ia = this.parseUVIndex( ua, uvLen );
 					ia = this.parseUVIndex( ua, uvLen );
 					ib = this.parseUVIndex( ub, uvLen );
 					ib = this.parseUVIndex( ub, uvLen );
 					ic = this.parseUVIndex( uc, uvLen );
 					ic = this.parseUVIndex( uc, uvLen );
-
 					this.addUV( ia, ib, ic );
 					this.addUV( ia, ib, ic );
 
 
 				}
 				}
 
 
-				if ( na !== undefined ) {
+				if ( na !== undefined && na !== '' ) {
 
 
 					// Normals are many times the same. If so, skip function call and parseInt.
 					// Normals are many times the same. If so, skip function call and parseInt.
 					var nLen = this.normals.length;
 					var nLen = this.normals.length;

+ 7 - 5
examples/js/math/Lut.js

@@ -451,16 +451,16 @@ THREE.Lut.prototype = {
 
 
 				var material = new THREE.LineBasicMaterial( { color: 0x000000, linewidth: 2 } );
 				var material = new THREE.LineBasicMaterial( { color: 0x000000, linewidth: 2 } );
 
 
-				var geometry = new THREE.Geometry();
+				var points = [];
 
 
 
 
 				if ( this.legend.layout == 'vertical' ) {
 				if ( this.legend.layout == 'vertical' ) {
 
 
 					var linePosition = ( this.legend.position.y - ( this.legend.dimensions.height * 0.5 ) + 0.01 ) + ( this.legend.dimensions.height ) * ( ( value - this.minV ) / ( this.maxV - this.minV ) * 0.99 );
 					var linePosition = ( this.legend.position.y - ( this.legend.dimensions.height * 0.5 ) + 0.01 ) + ( this.legend.dimensions.height ) * ( ( value - this.minV ) / ( this.maxV - this.minV ) * 0.99 );
 
 
-					geometry.vertices.push( new THREE.Vector3( this.legend.position.x + this.legend.dimensions.width * 0.55, linePosition, this.legend.position.z  ) );
+					points.push( new THREE.Vector3( this.legend.position.x + this.legend.dimensions.width * 0.55, linePosition, this.legend.position.z  ) );
 
 
-					geometry.vertices.push( new THREE.Vector3( this.legend.position.x + this.legend.dimensions.width * 0.7, linePosition, this.legend.position.z  ) );
+					points.push( new THREE.Vector3( this.legend.position.x + this.legend.dimensions.width * 0.7, linePosition, this.legend.position.z  ) );
 
 
 				}
 				}
 
 
@@ -468,12 +468,14 @@ THREE.Lut.prototype = {
 
 
 					var linePosition = ( this.legend.position.x - ( this.legend.dimensions.height * 0.5 ) + 0.01 ) + ( this.legend.dimensions.height ) * ( ( value - this.minV ) / ( this.maxV - this.minV ) * 0.99 );
 					var linePosition = ( this.legend.position.x - ( this.legend.dimensions.height * 0.5 ) + 0.01 ) + ( this.legend.dimensions.height ) * ( ( value - this.minV ) / ( this.maxV - this.minV ) * 0.99 );
 
 
-					geometry.vertices.push( new THREE.Vector3( linePosition, this.legend.position.y - this.legend.dimensions.width * 0.55, this.legend.position.z  ) );
+					points.push( new THREE.Vector3( linePosition, this.legend.position.y - this.legend.dimensions.width * 0.55, this.legend.position.z  ) );
 
 
-					geometry.vertices.push( new THREE.Vector3( linePosition, this.legend.position.y - this.legend.dimensions.width * 0.7, this.legend.position.z  ) );
+					points.push( new THREE.Vector3( linePosition, this.legend.position.y - this.legend.dimensions.width * 0.7, this.legend.position.z  ) );
 
 
 				}
 				}
 
 
+				var geometry = new THREE.BufferGeometry().setFromPoints( points );
+
 				var line = new THREE.Line( geometry, material );
 				var line = new THREE.Line( geometry, material );
 
 
 				lines[ i ] = line;
 				lines[ i ] = line;

+ 0 - 2
examples/js/objects/Lensflare.js

@@ -35,8 +35,6 @@ THREE.Lensflare = function () {
 
 
 	var geometry = THREE.Lensflare.Geometry;
 	var geometry = THREE.Lensflare.Geometry;
 
 
-	var shader = THREE.Lensflare.Shader;
-
 	var material1a = new THREE.RawShaderMaterial( {
 	var material1a = new THREE.RawShaderMaterial( {
 		uniforms: {
 		uniforms: {
 			'scale': { value: null },
 			'scale': { value: null },

+ 2 - 1
examples/js/objects/Sky.js

@@ -25,7 +25,7 @@ THREE.Sky = function () {
 		side: THREE.BackSide
 		side: THREE.BackSide
 	} );
 	} );
 
 
-	THREE.Mesh.call( this, new THREE.SphereBufferGeometry( 1, 32, 15 ), material );
+	THREE.Mesh.call( this, new THREE.BoxBufferGeometry( 1, 1, 1 ), material );
 
 
 };
 };
 
 
@@ -96,6 +96,7 @@ THREE.Sky.SkyShader = {
 		'	vWorldPosition = worldPosition.xyz;',
 		'	vWorldPosition = worldPosition.xyz;',
 
 
 		'	gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );',
 		'	gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );',
+		'	gl_Position.z = gl_Position.w;', // set z to camera.far
 
 
 		'	vSunDirection = normalize( sunPosition );',
 		'	vSunDirection = normalize( sunPosition );',
 
 

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

@@ -102,7 +102,7 @@ THREE.AdaptiveToneMappingPass = function ( adaptive, resolution ) {
 		uniforms: THREE.UniformsUtils.clone( this.adaptLuminanceShader.uniforms ),
 		uniforms: THREE.UniformsUtils.clone( this.adaptLuminanceShader.uniforms ),
 		vertexShader: this.adaptLuminanceShader.vertexShader,
 		vertexShader: this.adaptLuminanceShader.vertexShader,
 		fragmentShader: this.adaptLuminanceShader.fragmentShader,
 		fragmentShader: this.adaptLuminanceShader.fragmentShader,
-		defines: this.adaptLuminanceShader.defines,
+		defines: Object.assign( {}, this.adaptLuminanceShader.defines ),
 		blending: THREE.NoBlending
 		blending: THREE.NoBlending
 	} );
 	} );
 
 

+ 1 - 1
examples/js/postprocessing/BokehPass.js

@@ -57,7 +57,7 @@ THREE.BokehPass = function ( scene, camera, params ) {
 	bokehUniforms[ "farClip" ].value = camera.far;
 	bokehUniforms[ "farClip" ].value = camera.far;
 
 
 	this.materialBokeh = new THREE.ShaderMaterial( {
 	this.materialBokeh = new THREE.ShaderMaterial( {
-		defines: bokehShader.defines,
+		defines: Object.assign( {}, bokehShader.defines ),
 		uniforms: bokehUniforms,
 		uniforms: bokehUniforms,
 		vertexShader: bokehShader.vertexShader,
 		vertexShader: bokehShader.vertexShader,
 		fragmentShader: bokehShader.fragmentShader
 		fragmentShader: bokehShader.fragmentShader

+ 8 - 4
examples/js/postprocessing/SAOPass.js

@@ -74,9 +74,13 @@ THREE.SAOPass = function ( scene, camera, depthTexture, useNormals, resolution )
 
 
 	}
 	}
 
 
-	this.saoMaterial = new THREE.ShaderMaterial( THREE.SAOShader );
+	this.saoMaterial = new THREE.ShaderMaterial( {
+		defines: Object.assign( {}, THREE.SAOShader.defines ),
+		fragmentShader: THREE.SAOShader.fragmentShader,
+		vertexShader: THREE.SAOShader.vertexShader,
+		uniforms: THREE.UniformsUtils.clone( THREE.SAOShader.uniforms )
+	} );
 	this.saoMaterial.extensions.derivatives = true;
 	this.saoMaterial.extensions.derivatives = true;
-	this.saoMaterial.extensions.drawBuffers = true;
 	this.saoMaterial.defines[ 'DEPTH_PACKING' ] = this.supportsDepthTextureExtension ? 0 : 1;
 	this.saoMaterial.defines[ 'DEPTH_PACKING' ] = this.supportsDepthTextureExtension ? 0 : 1;
 	this.saoMaterial.defines[ 'NORMAL_TEXTURE' ] = this.supportsNormalTexture ? 1 : 0;
 	this.saoMaterial.defines[ 'NORMAL_TEXTURE' ] = this.supportsNormalTexture ? 1 : 0;
 	this.saoMaterial.defines[ 'PERSPECTIVE_CAMERA' ] = this.camera.isPerspectiveCamera ? 1 : 0;
 	this.saoMaterial.defines[ 'PERSPECTIVE_CAMERA' ] = this.camera.isPerspectiveCamera ? 1 : 0;
@@ -95,7 +99,7 @@ THREE.SAOPass = function ( scene, camera, depthTexture, useNormals, resolution )
 
 
 	this.vBlurMaterial = new THREE.ShaderMaterial( {
 	this.vBlurMaterial = new THREE.ShaderMaterial( {
 		uniforms: THREE.UniformsUtils.clone( THREE.DepthLimitedBlurShader.uniforms ),
 		uniforms: THREE.UniformsUtils.clone( THREE.DepthLimitedBlurShader.uniforms ),
-		defines: THREE.DepthLimitedBlurShader.defines,
+		defines: Object.assign( {}, THREE.DepthLimitedBlurShader.defines ),
 		vertexShader: THREE.DepthLimitedBlurShader.vertexShader,
 		vertexShader: THREE.DepthLimitedBlurShader.vertexShader,
 		fragmentShader: THREE.DepthLimitedBlurShader.fragmentShader
 		fragmentShader: THREE.DepthLimitedBlurShader.fragmentShader
 	} );
 	} );
@@ -108,7 +112,7 @@ THREE.SAOPass = function ( scene, camera, depthTexture, useNormals, resolution )
 
 
 	this.hBlurMaterial = new THREE.ShaderMaterial( {
 	this.hBlurMaterial = new THREE.ShaderMaterial( {
 		uniforms: THREE.UniformsUtils.clone( THREE.DepthLimitedBlurShader.uniforms ),
 		uniforms: THREE.UniformsUtils.clone( THREE.DepthLimitedBlurShader.uniforms ),
-		defines: THREE.DepthLimitedBlurShader.defines,
+		defines: Object.assign( {}, THREE.DepthLimitedBlurShader.defines ),
 		vertexShader: THREE.DepthLimitedBlurShader.vertexShader,
 		vertexShader: THREE.DepthLimitedBlurShader.vertexShader,
 		fragmentShader: THREE.DepthLimitedBlurShader.fragmentShader
 		fragmentShader: THREE.DepthLimitedBlurShader.fragmentShader
 	} );
 	} );

+ 2 - 2
examples/js/postprocessing/SMAAPass.js

@@ -63,7 +63,7 @@ THREE.SMAAPass = function ( width, height ) {
 	this.uniformsEdges[ "resolution" ].value.set( 1 / width, 1 / height );
 	this.uniformsEdges[ "resolution" ].value.set( 1 / width, 1 / height );
 
 
 	this.materialEdges = new THREE.ShaderMaterial( {
 	this.materialEdges = new THREE.ShaderMaterial( {
-		defines: THREE.SMAAShader[0].defines,
+		defines: Object.assign( {}, THREE.SMAAShader[ 0 ].defines ),
 		uniforms: this.uniformsEdges,
 		uniforms: this.uniformsEdges,
 		vertexShader: THREE.SMAAShader[0].vertexShader,
 		vertexShader: THREE.SMAAShader[0].vertexShader,
 		fragmentShader: THREE.SMAAShader[0].fragmentShader
 		fragmentShader: THREE.SMAAShader[0].fragmentShader
@@ -79,7 +79,7 @@ THREE.SMAAPass = function ( width, height ) {
 	this.uniformsWeights[ "tSearch" ].value = this.searchTexture;
 	this.uniformsWeights[ "tSearch" ].value = this.searchTexture;
 
 
 	this.materialWeights = new THREE.ShaderMaterial( {
 	this.materialWeights = new THREE.ShaderMaterial( {
-		defines: THREE.SMAAShader[1].defines,
+		defines: Object.assign( {}, THREE.SMAAShader[ 1 ].defines ),
 		uniforms: this.uniformsWeights,
 		uniforms: this.uniformsWeights,
 		vertexShader: THREE.SMAAShader[1].vertexShader,
 		vertexShader: THREE.SMAAShader[1].vertexShader,
 		fragmentShader: THREE.SMAAShader[1].fragmentShader
 		fragmentShader: THREE.SMAAShader[1].fragmentShader

+ 1 - 1
examples/js/postprocessing/ShaderPass.js

@@ -20,7 +20,7 @@ THREE.ShaderPass = function ( shader, textureID ) {
 
 
 		this.material = new THREE.ShaderMaterial( {
 		this.material = new THREE.ShaderMaterial( {
 
 
-			defines: shader.defines || {},
+			defines: Object.assign( {}, shader.defines ),
 			uniforms: this.uniforms,
 			uniforms: this.uniforms,
 			vertexShader: shader.vertexShader,
 			vertexShader: shader.vertexShader,
 			fragmentShader: shader.fragmentShader
 			fragmentShader: shader.fragmentShader

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

@@ -120,7 +120,7 @@ THREE.WebGLDeferredRenderer = function ( parameters ) {
 
 
 	function init( parameters ) {
 	function init( parameters ) {
 
 
-		_this.renderer = parameters.renderer !== undefined ? parameters.renderer : new THREE.WebGLRenderer( { antialias: false } );
+		_this.renderer = parameters.renderer !== undefined ? parameters.renderer : new THREE.WebGLRenderer();
 		_this.domElement = _this.renderer.domElement;
 		_this.domElement = _this.renderer.domElement;
 
 
 		_gl = _this.renderer.context;
 		_gl = _this.renderer.context;

+ 10 - 1
examples/js/vr/DaydreamController.js

@@ -42,7 +42,7 @@ THREE.DaydreamController = function () {
 
 
 	};
 	};
 
 
-	this.getTouchPadState = function () {
+	this.getTouchpadState = function () {
 
 
 		return touchpadIsPressed;
 		return touchpadIsPressed;
 
 
@@ -103,6 +103,15 @@ THREE.DaydreamController = function () {
 
 
 	};
 	};
 
 
+	// DEPRECATED
+
+	this.getTouchPadState = function () {
+
+		console.warn( 'THREE.DaydreamController: getTouchPadState() is now getTouchpadState()' );
+		return touchpadIsPressed;
+
+	};
+
 };
 };
 
 
 THREE.DaydreamController.prototype = Object.create( THREE.Object3D.prototype );
 THREE.DaydreamController.prototype = Object.create( THREE.Object3D.prototype );

+ 10 - 1
examples/js/vr/GearVRController.js

@@ -60,7 +60,7 @@ THREE.GearVRController = function () {
 
 
 	};
 	};
 
 
-	this.getTouchPadState = function () {
+	this.getTouchpadState = function () {
 
 
 		return touchpadIsPressed;
 		return touchpadIsPressed;
 
 
@@ -131,6 +131,15 @@ THREE.GearVRController = function () {
 
 
 	};
 	};
 
 
+	// DEPRECATED
+
+	this.getTouchPadState = function () {
+
+		console.warn( 'THREE.GearVRController: getTouchPadState() is now getTouchpadState()' );
+		return touchpadIsPressed;
+
+	};
+
 };
 };
 
 
 THREE.GearVRController.prototype = Object.create( THREE.Object3D.prototype );
 THREE.GearVRController.prototype = Object.create( THREE.Object3D.prototype );

+ 17 - 10
examples/misc_controls_orbit.html

@@ -48,8 +48,8 @@
 			var camera, controls, scene, renderer;
 			var camera, controls, scene, renderer;
 
 
 			init();
 			init();
-			render(); // remove when using next line for animation loop (requestAnimationFrame)
-			//animate();
+			//render(); // remove when using next line for animation loop (requestAnimationFrame)
+			animate();
 
 
 			function init() {
 			function init() {
 
 
@@ -67,13 +67,20 @@
 				camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 1000 );
 				camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 1000 );
 				camera.position.set( 400, 200, 0 );
 				camera.position.set( 400, 200, 0 );
 
 
+				// controls
+
 				controls = new THREE.OrbitControls( camera, renderer.domElement );
 				controls = new THREE.OrbitControls( camera, renderer.domElement );
-				controls.addEventListener( 'change', render ); // remove when using animation loop
-				// enable animation loop when using damping or autorotation
-				//controls.enableDamping = true;
-				//controls.dampingFactor = 0.25;
+
+				//controls.addEventListener( 'change', render ); // call this only in static scenes (i.e., if there is no animation loop)
+
+				controls.enableDamping = true; // an animation loop is required when either damping or auto-rotation are enabled
+				controls.dampingFactor = 0.25;
+
+				controls.panningMode = THREE.HorizontalPanning; // default is THREE.ScreenSpacePanning
+
 				controls.minDistance = 100;
 				controls.minDistance = 100;
 				controls.maxDistance = 500
 				controls.maxDistance = 500
+
 				controls.maxPolarAngle = Math.PI / 2;
 				controls.maxPolarAngle = Math.PI / 2;
 
 
 				// world
 				// world
@@ -84,9 +91,9 @@
 				for ( var i = 0; i < 500; i ++ ) {
 				for ( var i = 0; i < 500; i ++ ) {
 
 
 					var mesh = new THREE.Mesh( geometry, material );
 					var mesh = new THREE.Mesh( geometry, material );
-					mesh.position.x = ( Math.random() - 0.5 ) * 1000;
+					mesh.position.x = Math.random() * 1600 - 800;
 					mesh.position.y = 0;
 					mesh.position.y = 0;
-					mesh.position.z = ( Math.random() - 0.5 ) * 1000;
+					mesh.position.z = Math.random() * 1600 - 800;
 					mesh.updateMatrix();
 					mesh.updateMatrix();
 					mesh.matrixAutoUpdate = false;
 					mesh.matrixAutoUpdate = false;
 					scene.add( mesh );
 					scene.add( mesh );
@@ -100,7 +107,7 @@
 				scene.add( light );
 				scene.add( light );
 
 
 				var light = new THREE.DirectionalLight( 0x002288 );
 				var light = new THREE.DirectionalLight( 0x002288 );
-				light.position.set( -1, -1, -1 );
+				light.position.set( - 1, - 1, - 1 );
 				scene.add( light );
 				scene.add( light );
 
 
 				var light = new THREE.AmbientLight( 0x222222 );
 				var light = new THREE.AmbientLight( 0x222222 );
@@ -125,7 +132,7 @@
 
 
 				requestAnimationFrame( animate );
 				requestAnimationFrame( animate );
 
 
-				//controls.update(); // only required if controls.enableDamping = true, or if controls.autoRotate = true
+				controls.update(); // only required if controls.enableDamping = true, or if controls.autoRotate = true
 
 
 				render();
 				render();
 
 

+ 1 - 1
examples/misc_controls_trackball.html

@@ -117,7 +117,7 @@
 
 
 				// renderer
 				// renderer
 
 
-				renderer = new THREE.WebGLRenderer( { antialias: false } );
+				renderer = new THREE.WebGLRenderer();
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 
 

+ 29 - 3
examples/misc_exporter_gltf.html

@@ -26,6 +26,7 @@
 			<button id="export_scene">Export Scene1</button>
 			<button id="export_scene">Export Scene1</button>
 			<button id="export_scenes">Export Scene1 and Scene 2</button>
 			<button id="export_scenes">Export Scene1 and Scene 2</button>
 			<button id="export_object">Export Sphere</button>
 			<button id="export_object">Export Sphere</button>
+			<button id="export_obj">Export WaltHead</button>
 			<button id="export_objects">Export Sphere and Grid</button>
 			<button id="export_objects">Export Sphere and Grid</button>
 			<button id="export_scene_object">Export Scene1 and Sphere</button>
 			<button id="export_scene_object">Export Scene1 and Sphere</button>
 			<br/>
 			<br/>
@@ -33,11 +34,14 @@
 			<label><input id="option_visible" name="visible" type="checkbox" checked="checked"/>Only Visible</label>
 			<label><input id="option_visible" name="visible" type="checkbox" checked="checked"/>Only Visible</label>
 			<label><input id="option_drawrange" name="visible" type="checkbox" checked="checked"/>Truncate drawRange</label>
 			<label><input id="option_drawrange" name="visible" type="checkbox" checked="checked"/>Truncate drawRange</label>
 			<label><input id="option_binary" name="visible" type="checkbox">Binary (<code>.glb</code>)</label>
 			<label><input id="option_binary" name="visible" type="checkbox">Binary (<code>.glb</code>)</label>
+			<label><input id="option_forceindices" name="visible" type="checkbox">Force indices</label>
+			<label><input id="option_forcepot" name="visible" type="checkbox">Force POT textures</label>
 		</div>
 		</div>
 
 
 		<script src="../build/three.js"></script>
 		<script src="../build/three.js"></script>
 
 
 		<script src="js/Detector.js"></script>
 		<script src="js/Detector.js"></script>
+		<script src="js/loaders/OBJLoader.js"></script>
 		<script src="js/exporters/GLTFExporter.js"></script>
 		<script src="js/exporters/GLTFExporter.js"></script>
 
 
 		<script>
 		<script>
@@ -50,7 +54,9 @@
 					trs: document.getElementById('option_trs').checked,
 					trs: document.getElementById('option_trs').checked,
 					onlyVisible: document.getElementById('option_visible').checked,
 					onlyVisible: document.getElementById('option_visible').checked,
 					truncateDrawRange: document.getElementById('option_drawrange').checked,
 					truncateDrawRange: document.getElementById('option_drawrange').checked,
-					binary: document.getElementById('option_binary').checked
+					binary: document.getElementById('option_binary').checked,
+					forceIndices: document.getElementById('option_forceindices').checked,
+					forcePowerOfTwoTextures: document.getElementById('option_forcepot').checked
 				};
 				};
 				gltfExporter.parse( input, function( result ) {
 				gltfExporter.parse( input, function( result ) {
 
 
@@ -88,6 +94,12 @@
 
 
 			} );
 			} );
 
 
+			document.getElementById( 'export_obj' ).addEventListener( 'click', function () {
+
+				exportGLTF( waltHead );
+
+			} );
+
 			document.getElementById( 'export_objects' ).addEventListener( 'click', function () {
 			document.getElementById( 'export_objects' ).addEventListener( 'click', function () {
 
 
 				exportGLTF( [ sphere, gridHelper ] );
 				exportGLTF( [ sphere, gridHelper ] );
@@ -133,7 +145,7 @@
 			var container;
 			var container;
 
 
 			var camera, object, scene1, scene2, renderer;
 			var camera, object, scene1, scene2, renderer;
-			var gridHelper, sphere;
+			var gridHelper, sphere, waltHead;
 
 
 			init();
 			init();
 			animate();
 			animate();
@@ -428,7 +440,7 @@
 				// ---------------------------------------------------------------------
 				// ---------------------------------------------------------------------
 				// Ortho camera
 				// Ortho camera
 				// ---------------------------------------------------------------------
 				// ---------------------------------------------------------------------
-				var cameraOrtho = new THREE.OrthographicCamera( window.innerWidth / - 2, window.innerWidth / 2, window.innerHeight / 2, window.innerHeight / - 2, - 10, 10 );
+				var cameraOrtho = new THREE.OrthographicCamera( window.innerWidth / - 2, window.innerWidth / 2, window.innerHeight / 2, window.innerHeight / - 2, 0.1, 10 );
 				scene1.add( cameraOrtho );
 				scene1.add( cameraOrtho );
 				cameraOrtho.name = 'OrthographicCamera';
 				cameraOrtho.name = 'OrthographicCamera';
 
 
@@ -474,6 +486,20 @@
 				object.visible = false;
 				object.visible = false;
 				scene1.add( object );
 				scene1.add( object );
 
 
+				// ---------------------------------------------------------------------
+				//
+				//
+				var loader = new THREE.OBJLoader();
+				loader.load( 'models/obj/walt/WaltHead.obj', function ( obj ) {
+
+					waltHead = obj;
+					waltHead.scale.multiplyScalar( 1.5 );
+					waltHead.position.set(400, 0, 0);
+					scene1.add( waltHead );
+
+				} );
+				
+				
 				// ---------------------------------------------------------------------
 				// ---------------------------------------------------------------------
 				// 2nd Scene
 				// 2nd Scene
 				// ---------------------------------------------------------------------
 				// ---------------------------------------------------------------------

二进制
examples/models/gltf/BotSkinned/glTF-MaterialsUnlit/AvatarBotA_Head_Tex_Combined.png


二进制
examples/models/gltf/BotSkinned/glTF-MaterialsUnlit/AvatarBotA_Tex_Combined.png


+ 2265 - 0
examples/models/gltf/BotSkinned/glTF-MaterialsUnlit/Bot_Skinned.gltf

@@ -0,0 +1,2265 @@
+{
+    "asset": {
+        "generator": "FBX2glTF",
+        "version": "2.0"
+    },
+    "scene": 0,
+    "extensionsUsed": [
+        "KHR_materials_unlit"
+    ],
+    "buffers": [
+        {
+            "byteLength": 272844,
+            "uri": "buffer.bin"
+        }
+    ],
+    "bufferViews": [
+        {
+            "buffer": 0,
+            "byteLength": 644,
+            "byteOffset": 0
+        },
+        {
+            "buffer": 0,
+            "byteLength": 2576,
+            "byteOffset": 644
+        },
+        {
+            "buffer": 0,
+            "byteLength": 2576,
+            "byteOffset": 3220
+        },
+        {
+            "buffer": 0,
+            "byteLength": 2576,
+            "byteOffset": 5796
+        },
+        {
+            "buffer": 0,
+            "byteLength": 2576,
+            "byteOffset": 8372
+        },
+        {
+            "buffer": 0,
+            "byteLength": 2576,
+            "byteOffset": 10948
+        },
+        {
+            "buffer": 0,
+            "byteLength": 2576,
+            "byteOffset": 13524
+        },
+        {
+            "buffer": 0,
+            "byteLength": 2576,
+            "byteOffset": 16100
+        },
+        {
+            "buffer": 0,
+            "byteLength": 2576,
+            "byteOffset": 18676
+        },
+        {
+            "buffer": 0,
+            "byteLength": 2576,
+            "byteOffset": 21252
+        },
+        {
+            "buffer": 0,
+            "byteLength": 2576,
+            "byteOffset": 23828
+        },
+        {
+            "buffer": 0,
+            "byteLength": 2576,
+            "byteOffset": 26404
+        },
+        {
+            "buffer": 0,
+            "byteLength": 2576,
+            "byteOffset": 28980
+        },
+        {
+            "buffer": 0,
+            "byteLength": 2576,
+            "byteOffset": 31556
+        },
+        {
+            "buffer": 0,
+            "byteLength": 2576,
+            "byteOffset": 34132
+        },
+        {
+            "buffer": 0,
+            "byteLength": 2576,
+            "byteOffset": 36708
+        },
+        {
+            "buffer": 0,
+            "byteLength": 2576,
+            "byteOffset": 39284
+        },
+        {
+            "buffer": 0,
+            "byteLength": 2576,
+            "byteOffset": 41860
+        },
+        {
+            "buffer": 0,
+            "byteLength": 2576,
+            "byteOffset": 44436
+        },
+        {
+            "buffer": 0,
+            "byteLength": 2576,
+            "byteOffset": 47012
+        },
+        {
+            "buffer": 0,
+            "byteLength": 2576,
+            "byteOffset": 49588
+        },
+        {
+            "buffer": 0,
+            "byteLength": 2576,
+            "byteOffset": 52164
+        },
+        {
+            "buffer": 0,
+            "byteLength": 2576,
+            "byteOffset": 54740
+        },
+        {
+            "buffer": 0,
+            "byteLength": 2576,
+            "byteOffset": 57316
+        },
+        {
+            "buffer": 0,
+            "byteLength": 2576,
+            "byteOffset": 59892
+        },
+        {
+            "buffer": 0,
+            "byteLength": 2576,
+            "byteOffset": 62468
+        },
+        {
+            "buffer": 0,
+            "byteLength": 2576,
+            "byteOffset": 65044
+        },
+        {
+            "buffer": 0,
+            "byteLength": 2576,
+            "byteOffset": 67620
+        },
+        {
+            "buffer": 0,
+            "byteLength": 2576,
+            "byteOffset": 70196
+        },
+        {
+            "buffer": 0,
+            "byteLength": 1932,
+            "byteOffset": 72772
+        },
+        {
+            "buffer": 0,
+            "byteLength": 2576,
+            "byteOffset": 74704
+        },
+        {
+            "buffer": 0,
+            "byteLength": 1932,
+            "byteOffset": 77280
+        },
+        {
+            "buffer": 0,
+            "byteLength": 2576,
+            "byteOffset": 79212
+        },
+        {
+            "buffer": 0,
+            "byteLength": 12330,
+            "byteOffset": 81788,
+            "target": 34963
+        },
+        {
+            "buffer": 0,
+            "byteLength": 33108,
+            "byteOffset": 94120,
+            "target": 34962
+        },
+        {
+            "buffer": 0,
+            "byteLength": 33108,
+            "byteOffset": 127228,
+            "target": 34962
+        },
+        {
+            "buffer": 0,
+            "byteLength": 22072,
+            "byteOffset": 160336,
+            "target": 34962
+        },
+        {
+            "buffer": 0,
+            "byteLength": 22072,
+            "byteOffset": 182408,
+            "target": 34962
+        },
+        {
+            "buffer": 0,
+            "byteLength": 44144,
+            "byteOffset": 204480,
+            "target": 34962
+        },
+        {
+            "buffer": 0,
+            "byteLength": 2268,
+            "byteOffset": 248624,
+            "target": 34963
+        },
+        {
+            "buffer": 0,
+            "byteLength": 4032,
+            "byteOffset": 250892,
+            "target": 34962
+        },
+        {
+            "buffer": 0,
+            "byteLength": 4032,
+            "byteOffset": 254924,
+            "target": 34962
+        },
+        {
+            "buffer": 0,
+            "byteLength": 2688,
+            "byteOffset": 258956,
+            "target": 34962
+        },
+        {
+            "buffer": 0,
+            "byteLength": 2688,
+            "byteOffset": 261644,
+            "target": 34962
+        },
+        {
+            "buffer": 0,
+            "byteLength": 5376,
+            "byteOffset": 264332,
+            "target": 34962
+        },
+        {
+            "buffer": 0,
+            "byteLength": 3136,
+            "byteOffset": 269708
+        }
+    ],
+    "scenes": [
+        {
+            "name": "Root Scene",
+            "nodes": [
+                0
+            ]
+        }
+    ],
+    "accessors": [
+        {
+            "componentType": 5126,
+            "type": "SCALAR",
+            "count": 161,
+            "bufferView": 0,
+            "byteOffset": 0,
+            "min": [
+                0.0
+            ],
+            "max": [
+                6.66666650772095
+            ]
+        },
+        {
+            "componentType": 5126,
+            "type": "VEC4",
+            "count": 161,
+            "bufferView": 1,
+            "byteOffset": 0
+        },
+        {
+            "componentType": 5126,
+            "type": "VEC4",
+            "count": 161,
+            "bufferView": 2,
+            "byteOffset": 0
+        },
+        {
+            "componentType": 5126,
+            "type": "VEC4",
+            "count": 161,
+            "bufferView": 3,
+            "byteOffset": 0
+        },
+        {
+            "componentType": 5126,
+            "type": "VEC4",
+            "count": 161,
+            "bufferView": 4,
+            "byteOffset": 0
+        },
+        {
+            "componentType": 5126,
+            "type": "VEC4",
+            "count": 161,
+            "bufferView": 5,
+            "byteOffset": 0
+        },
+        {
+            "componentType": 5126,
+            "type": "VEC4",
+            "count": 161,
+            "bufferView": 6,
+            "byteOffset": 0
+        },
+        {
+            "componentType": 5126,
+            "type": "VEC4",
+            "count": 161,
+            "bufferView": 7,
+            "byteOffset": 0
+        },
+        {
+            "componentType": 5126,
+            "type": "VEC4",
+            "count": 161,
+            "bufferView": 8,
+            "byteOffset": 0
+        },
+        {
+            "componentType": 5126,
+            "type": "VEC4",
+            "count": 161,
+            "bufferView": 9,
+            "byteOffset": 0
+        },
+        {
+            "componentType": 5126,
+            "type": "VEC4",
+            "count": 161,
+            "bufferView": 10,
+            "byteOffset": 0
+        },
+        {
+            "componentType": 5126,
+            "type": "VEC4",
+            "count": 161,
+            "bufferView": 11,
+            "byteOffset": 0
+        },
+        {
+            "componentType": 5126,
+            "type": "VEC4",
+            "count": 161,
+            "bufferView": 12,
+            "byteOffset": 0
+        },
+        {
+            "componentType": 5126,
+            "type": "VEC4",
+            "count": 161,
+            "bufferView": 13,
+            "byteOffset": 0
+        },
+        {
+            "componentType": 5126,
+            "type": "VEC4",
+            "count": 161,
+            "bufferView": 14,
+            "byteOffset": 0
+        },
+        {
+            "componentType": 5126,
+            "type": "VEC4",
+            "count": 161,
+            "bufferView": 15,
+            "byteOffset": 0
+        },
+        {
+            "componentType": 5126,
+            "type": "VEC4",
+            "count": 161,
+            "bufferView": 16,
+            "byteOffset": 0
+        },
+        {
+            "componentType": 5126,
+            "type": "VEC4",
+            "count": 161,
+            "bufferView": 17,
+            "byteOffset": 0
+        },
+        {
+            "componentType": 5126,
+            "type": "VEC4",
+            "count": 161,
+            "bufferView": 18,
+            "byteOffset": 0
+        },
+        {
+            "componentType": 5126,
+            "type": "VEC4",
+            "count": 161,
+            "bufferView": 19,
+            "byteOffset": 0
+        },
+        {
+            "componentType": 5126,
+            "type": "VEC4",
+            "count": 161,
+            "bufferView": 20,
+            "byteOffset": 0
+        },
+        {
+            "componentType": 5126,
+            "type": "VEC4",
+            "count": 161,
+            "bufferView": 21,
+            "byteOffset": 0
+        },
+        {
+            "componentType": 5126,
+            "type": "VEC4",
+            "count": 161,
+            "bufferView": 22,
+            "byteOffset": 0
+        },
+        {
+            "componentType": 5126,
+            "type": "VEC4",
+            "count": 161,
+            "bufferView": 23,
+            "byteOffset": 0
+        },
+        {
+            "componentType": 5126,
+            "type": "VEC4",
+            "count": 161,
+            "bufferView": 24,
+            "byteOffset": 0
+        },
+        {
+            "componentType": 5126,
+            "type": "VEC4",
+            "count": 161,
+            "bufferView": 25,
+            "byteOffset": 0
+        },
+        {
+            "componentType": 5126,
+            "type": "VEC4",
+            "count": 161,
+            "bufferView": 26,
+            "byteOffset": 0
+        },
+        {
+            "componentType": 5126,
+            "type": "VEC4",
+            "count": 161,
+            "bufferView": 27,
+            "byteOffset": 0
+        },
+        {
+            "componentType": 5126,
+            "type": "VEC4",
+            "count": 161,
+            "bufferView": 28,
+            "byteOffset": 0
+        },
+        {
+            "componentType": 5126,
+            "type": "VEC3",
+            "count": 161,
+            "bufferView": 29,
+            "byteOffset": 0
+        },
+        {
+            "componentType": 5126,
+            "type": "VEC4",
+            "count": 161,
+            "bufferView": 30,
+            "byteOffset": 0
+        },
+        {
+            "componentType": 5126,
+            "type": "VEC3",
+            "count": 161,
+            "bufferView": 31,
+            "byteOffset": 0
+        },
+        {
+            "componentType": 5126,
+            "type": "VEC4",
+            "count": 161,
+            "bufferView": 32,
+            "byteOffset": 0
+        },
+        {
+            "componentType": 5123,
+            "type": "SCALAR",
+            "count": 6165,
+            "bufferView": 33,
+            "byteOffset": 0
+        },
+        {
+            "componentType": 5126,
+            "type": "VEC3",
+            "count": 2759,
+            "bufferView": 34,
+            "byteOffset": 0,
+            "min": [
+                -81.9805221557617,
+                86.7850799560547,
+                -18.6015281677246
+            ],
+            "max": [
+                81.9540557861328,
+                143.793167114258,
+                17.2828502655029
+            ]
+        },
+        {
+            "componentType": 5126,
+            "type": "VEC3",
+            "count": 2759,
+            "bufferView": 35,
+            "byteOffset": 0
+        },
+        {
+            "componentType": 5126,
+            "type": "VEC2",
+            "count": 2759,
+            "bufferView": 36,
+            "byteOffset": 0
+        },
+        {
+            "componentType": 5123,
+            "type": "VEC4",
+            "count": 2759,
+            "bufferView": 37,
+            "byteOffset": 0
+        },
+        {
+            "componentType": 5126,
+            "type": "VEC4",
+            "count": 2759,
+            "bufferView": 38,
+            "byteOffset": 0
+        },
+        {
+            "componentType": 5123,
+            "type": "SCALAR",
+            "count": 1134,
+            "bufferView": 39,
+            "byteOffset": 0
+        },
+        {
+            "componentType": 5126,
+            "type": "VEC3",
+            "count": 336,
+            "bufferView": 40,
+            "byteOffset": 0,
+            "min": [
+                -12.0123357772827,
+                151.862823486328,
+                -8.23231601715088
+            ],
+            "max": [
+                12.0123262405396,
+                174.369445800781,
+                16.5866527557373
+            ]
+        },
+        {
+            "componentType": 5126,
+            "type": "VEC3",
+            "count": 336,
+            "bufferView": 41,
+            "byteOffset": 0
+        },
+        {
+            "componentType": 5126,
+            "type": "VEC2",
+            "count": 336,
+            "bufferView": 42,
+            "byteOffset": 0
+        },
+        {
+            "componentType": 5123,
+            "type": "VEC4",
+            "count": 336,
+            "bufferView": 43,
+            "byteOffset": 0
+        },
+        {
+            "componentType": 5126,
+            "type": "VEC4",
+            "count": 336,
+            "bufferView": 44,
+            "byteOffset": 0
+        },
+        {
+            "componentType": 5126,
+            "type": "MAT4",
+            "count": 49,
+            "bufferView": 45,
+            "byteOffset": 0
+        }
+    ],
+    "images": [
+        {
+            "name": "AvatarBotA_Tex_Combined.png",
+            "uri": "AvatarBotA_Tex_Combined.png"
+        },
+        {
+            "name": "AvatarBotA_Head_Tex_Combined.png",
+            "uri": "AvatarBotA_Head_Tex_Combined.png"
+        }
+    ],
+    "samplers": [
+        {}
+    ],
+    "textures": [
+        {
+            "name": "file5",
+            "sampler": 0,
+            "source": 0
+        },
+        {
+            "name": "file6",
+            "sampler": 0,
+            "source": 1
+        }
+    ],
+    "materials": [
+        {
+            "name": "Bot_BodyHands_mat",
+            "alphaMode": "OPAQUE",
+            "pbrMetallicRoughness": {
+                "baseColorTexture": {
+                    "index": 0,
+                    "texCoord": 0
+                },
+                "baseColorFactor": [
+                    0.800000011920929,
+                    0.800000011920929,
+                    0.800000011920929,
+                    1.0
+                ],
+                "metallicFactor": 0.0,
+                "roughnessFactor": 1.0
+            },
+            "extensions": {
+                "KHR_materials_unlit": {}
+            }
+        },
+        {
+            "name": "Bot_Head_mat",
+            "alphaMode": "OPAQUE",
+            "pbrMetallicRoughness": {
+                "baseColorTexture": {
+                    "index": 1,
+                    "texCoord": 0
+                },
+                "baseColorFactor": [
+                    1.0,
+                    1.0,
+                    1.0,
+                    1.0
+                ],
+                "metallicFactor": 0.0,
+                "roughnessFactor": 1.0
+            },
+            "extensions": {
+                "KHR_materials_unlit": {}
+            }
+        }
+    ],
+    "meshes": [
+        {
+            "name": "Bot_Skinned",
+            "primitives": [
+                {
+                    "material": 0,
+                    "mode": 4,
+                    "attributes": {
+                        "JOINTS_0": 37,
+                        "NORMAL": 35,
+                        "POSITION": 34,
+                        "TEXCOORD_0": 36,
+                        "WEIGHTS_0": 38
+                    },
+                    "indices": 33
+                },
+                {
+                    "material": 1,
+                    "mode": 4,
+                    "attributes": {
+                        "JOINTS_0": 43,
+                        "NORMAL": 41,
+                        "POSITION": 40,
+                        "TEXCOORD_0": 42,
+                        "WEIGHTS_0": 44
+                    },
+                    "indices": 39
+                }
+            ]
+        }
+    ],
+    "skins": [
+        {
+            "joints": [
+                1,
+                2,
+                3,
+                4,
+                5,
+                6,
+                7,
+                8,
+                9,
+                10,
+                11,
+                12,
+                13,
+                14,
+                15,
+                16,
+                17,
+                18,
+                19,
+                20,
+                21,
+                22,
+                23,
+                24,
+                25,
+                26,
+                27,
+                28,
+                29,
+                30,
+                31,
+                32,
+                33,
+                34,
+                35,
+                36,
+                37,
+                38,
+                39,
+                40,
+                41,
+                42,
+                43,
+                44,
+                45,
+                46,
+                47,
+                48,
+                49
+            ],
+            "inverseBindMatrices": 45,
+            "skeleton": 1
+        }
+    ],
+    "animations": [
+        {
+            "name": "Take 001",
+            "channels": [
+                {
+                    "sampler": 0,
+                    "target": {
+                        "node": 5,
+                        "path": "rotation"
+                    }
+                },
+                {
+                    "sampler": 1,
+                    "target": {
+                        "node": 6,
+                        "path": "rotation"
+                    }
+                },
+                {
+                    "sampler": 2,
+                    "target": {
+                        "node": 8,
+                        "path": "rotation"
+                    }
+                },
+                {
+                    "sampler": 3,
+                    "target": {
+                        "node": 9,
+                        "path": "rotation"
+                    }
+                },
+                {
+                    "sampler": 4,
+                    "target": {
+                        "node": 10,
+                        "path": "rotation"
+                    }
+                },
+                {
+                    "sampler": 5,
+                    "target": {
+                        "node": 12,
+                        "path": "rotation"
+                    }
+                },
+                {
+                    "sampler": 6,
+                    "target": {
+                        "node": 13,
+                        "path": "rotation"
+                    }
+                },
+                {
+                    "sampler": 7,
+                    "target": {
+                        "node": 14,
+                        "path": "rotation"
+                    }
+                },
+                {
+                    "sampler": 8,
+                    "target": {
+                        "node": 16,
+                        "path": "rotation"
+                    }
+                },
+                {
+                    "sampler": 9,
+                    "target": {
+                        "node": 17,
+                        "path": "rotation"
+                    }
+                },
+                {
+                    "sampler": 10,
+                    "target": {
+                        "node": 18,
+                        "path": "rotation"
+                    }
+                },
+                {
+                    "sampler": 11,
+                    "target": {
+                        "node": 20,
+                        "path": "rotation"
+                    }
+                },
+                {
+                    "sampler": 12,
+                    "target": {
+                        "node": 21,
+                        "path": "rotation"
+                    }
+                },
+                {
+                    "sampler": 13,
+                    "target": {
+                        "node": 22,
+                        "path": "rotation"
+                    }
+                },
+                {
+                    "sampler": 14,
+                    "target": {
+                        "node": 26,
+                        "path": "rotation"
+                    }
+                },
+                {
+                    "sampler": 15,
+                    "target": {
+                        "node": 27,
+                        "path": "rotation"
+                    }
+                },
+                {
+                    "sampler": 16,
+                    "target": {
+                        "node": 29,
+                        "path": "rotation"
+                    }
+                },
+                {
+                    "sampler": 17,
+                    "target": {
+                        "node": 30,
+                        "path": "rotation"
+                    }
+                },
+                {
+                    "sampler": 18,
+                    "target": {
+                        "node": 31,
+                        "path": "rotation"
+                    }
+                },
+                {
+                    "sampler": 19,
+                    "target": {
+                        "node": 33,
+                        "path": "rotation"
+                    }
+                },
+                {
+                    "sampler": 20,
+                    "target": {
+                        "node": 34,
+                        "path": "rotation"
+                    }
+                },
+                {
+                    "sampler": 21,
+                    "target": {
+                        "node": 35,
+                        "path": "rotation"
+                    }
+                },
+                {
+                    "sampler": 22,
+                    "target": {
+                        "node": 37,
+                        "path": "rotation"
+                    }
+                },
+                {
+                    "sampler": 23,
+                    "target": {
+                        "node": 38,
+                        "path": "rotation"
+                    }
+                },
+                {
+                    "sampler": 24,
+                    "target": {
+                        "node": 39,
+                        "path": "rotation"
+                    }
+                },
+                {
+                    "sampler": 25,
+                    "target": {
+                        "node": 41,
+                        "path": "rotation"
+                    }
+                },
+                {
+                    "sampler": 26,
+                    "target": {
+                        "node": 42,
+                        "path": "rotation"
+                    }
+                },
+                {
+                    "sampler": 27,
+                    "target": {
+                        "node": 43,
+                        "path": "rotation"
+                    }
+                },
+                {
+                    "sampler": 28,
+                    "target": {
+                        "node": 48,
+                        "path": "translation"
+                    }
+                },
+                {
+                    "sampler": 29,
+                    "target": {
+                        "node": 48,
+                        "path": "rotation"
+                    }
+                },
+                {
+                    "sampler": 30,
+                    "target": {
+                        "node": 49,
+                        "path": "translation"
+                    }
+                },
+                {
+                    "sampler": 31,
+                    "target": {
+                        "node": 49,
+                        "path": "rotation"
+                    }
+                }
+            ],
+            "samplers": [
+                {
+                    "input": 0,
+                    "interpolation": "LINEAR",
+                    "output": 1
+                },
+                {
+                    "input": 0,
+                    "interpolation": "LINEAR",
+                    "output": 2
+                },
+                {
+                    "input": 0,
+                    "interpolation": "LINEAR",
+                    "output": 3
+                },
+                {
+                    "input": 0,
+                    "interpolation": "LINEAR",
+                    "output": 4
+                },
+                {
+                    "input": 0,
+                    "interpolation": "LINEAR",
+                    "output": 5
+                },
+                {
+                    "input": 0,
+                    "interpolation": "LINEAR",
+                    "output": 6
+                },
+                {
+                    "input": 0,
+                    "interpolation": "LINEAR",
+                    "output": 7
+                },
+                {
+                    "input": 0,
+                    "interpolation": "LINEAR",
+                    "output": 8
+                },
+                {
+                    "input": 0,
+                    "interpolation": "LINEAR",
+                    "output": 9
+                },
+                {
+                    "input": 0,
+                    "interpolation": "LINEAR",
+                    "output": 10
+                },
+                {
+                    "input": 0,
+                    "interpolation": "LINEAR",
+                    "output": 11
+                },
+                {
+                    "input": 0,
+                    "interpolation": "LINEAR",
+                    "output": 12
+                },
+                {
+                    "input": 0,
+                    "interpolation": "LINEAR",
+                    "output": 13
+                },
+                {
+                    "input": 0,
+                    "interpolation": "LINEAR",
+                    "output": 14
+                },
+                {
+                    "input": 0,
+                    "interpolation": "LINEAR",
+                    "output": 15
+                },
+                {
+                    "input": 0,
+                    "interpolation": "LINEAR",
+                    "output": 16
+                },
+                {
+                    "input": 0,
+                    "interpolation": "LINEAR",
+                    "output": 17
+                },
+                {
+                    "input": 0,
+                    "interpolation": "LINEAR",
+                    "output": 18
+                },
+                {
+                    "input": 0,
+                    "interpolation": "LINEAR",
+                    "output": 19
+                },
+                {
+                    "input": 0,
+                    "interpolation": "LINEAR",
+                    "output": 20
+                },
+                {
+                    "input": 0,
+                    "interpolation": "LINEAR",
+                    "output": 21
+                },
+                {
+                    "input": 0,
+                    "interpolation": "LINEAR",
+                    "output": 22
+                },
+                {
+                    "input": 0,
+                    "interpolation": "LINEAR",
+                    "output": 23
+                },
+                {
+                    "input": 0,
+                    "interpolation": "LINEAR",
+                    "output": 24
+                },
+                {
+                    "input": 0,
+                    "interpolation": "LINEAR",
+                    "output": 25
+                },
+                {
+                    "input": 0,
+                    "interpolation": "LINEAR",
+                    "output": 26
+                },
+                {
+                    "input": 0,
+                    "interpolation": "LINEAR",
+                    "output": 27
+                },
+                {
+                    "input": 0,
+                    "interpolation": "LINEAR",
+                    "output": 28
+                },
+                {
+                    "input": 0,
+                    "interpolation": "LINEAR",
+                    "output": 29
+                },
+                {
+                    "input": 0,
+                    "interpolation": "LINEAR",
+                    "output": 30
+                },
+                {
+                    "input": 0,
+                    "interpolation": "LINEAR",
+                    "output": 31
+                },
+                {
+                    "input": 0,
+                    "interpolation": "LINEAR",
+                    "output": 32
+                }
+            ]
+        }
+    ],
+    "nodes": [
+        {
+            "name": "RootNode",
+            "translation": [
+                0.0,
+                0.0,
+                0.0
+            ],
+            "rotation": [
+                0.0,
+                0.0,
+                0.0,
+                1.0
+            ],
+            "scale": [
+                1.0,
+                1.0,
+                1.0
+            ],
+            "children": [
+                1,
+                50
+            ]
+        },
+        {
+            "name": "Hips",
+            "translation": [
+                0.0,
+                1.0,
+                0.0
+            ],
+            "rotation": [
+                0.0,
+                0.0,
+                0.0,
+                1.0
+            ],
+            "scale": [
+                0.00999999977648258,
+                0.00999999977648258,
+                0.00999999977648258
+            ],
+            "children": [
+                2
+            ]
+        },
+        {
+            "name": "Chest",
+            "translation": [
+                0.0,
+                33.0,
+                0.0
+            ],
+            "rotation": [
+                0.0,
+                0.0,
+                0.0,
+                1.0
+            ],
+            "scale": [
+                1.0,
+                1.0,
+                1.0
+            ],
+            "children": [
+                3,
+                24,
+                45
+            ]
+        },
+        {
+            "name": "RightHand",
+            "translation": [
+                -65.8264923095703,
+                0.0,
+                2.53653403836651e-10
+            ],
+            "rotation": [
+                -0.52379697561264,
+                -0.475012362003326,
+                -0.475012362003326,
+                0.52379697561264
+            ],
+            "scale": [
+                1.0,
+                1.0,
+                1.0
+            ],
+            "children": [
+                4,
+                8,
+                12,
+                16,
+                20
+            ]
+        },
+        {
+            "name": "RightHandThumb1",
+            "translation": [
+                2.75763964653015,
+                -2.15007448196411,
+                0.0
+            ],
+            "rotation": [
+                -0.0845961794257164,
+                0.24460332095623,
+                0.315717250108719,
+                0.912872016429901
+            ],
+            "scale": [
+                1.0,
+                1.0,
+                1.0
+            ],
+            "children": [
+                5
+            ]
+        },
+        {
+            "name": "RightHandThumb2",
+            "translation": [
+                -0.193791568279266,
+                -3.45449066162109,
+                -0.111885614693165
+            ],
+            "rotation": [
+                0.259822696447372,
+                0.0406266376376152,
+                -0.0417451933026314,
+                0.963897824287415
+            ],
+            "scale": [
+                1.0,
+                1.0,
+                1.0
+            ],
+            "children": [
+                6
+            ]
+        },
+        {
+            "name": "RightHandThumb3",
+            "translation": [
+                0.0183828547596931,
+                -2.60901737213135,
+                0.604700565338135
+            ],
+            "rotation": [
+                0.130526185035706,
+                -3.11409512388451e-17,
+                -2.38952924416889e-17,
+                0.991444885730743
+            ],
+            "scale": [
+                1.0,
+                1.0,
+                1.0
+            ],
+            "children": [
+                7
+            ]
+        },
+        {
+            "name": "RightHandThumb4",
+            "translation": [
+                -0.00614145956933498,
+                -1.84276032447815,
+                0.275437027215958
+            ],
+            "rotation": [
+                -0.0143108321353793,
+                -0.00529135810211301,
+                -0.346111297607422,
+                0.938069403171539
+            ],
+            "scale": [
+                1.0,
+                1.0,
+                1.0
+            ]
+        },
+        {
+            "name": "RightHandIndex1",
+            "translation": [
+                2.1877007484436,
+                -8.50447845458984,
+                -0.00400000018998981
+            ],
+            "rotation": [
+                0.129879087209702,
+                0.00267119123600423,
+                0.0197229869663715,
+                0.991330087184906
+            ],
+            "scale": [
+                1.0,
+                1.0,
+                1.0
+            ],
+            "children": [
+                9
+            ]
+        },
+        {
+            "name": "RightHandIndex2",
+            "translation": [
+                1.10285200207727e-05,
+                -3.35957384109497,
+                -0.000199394213268533
+            ],
+            "rotation": [
+                0.131140783429146,
+                0.000969027169048786,
+                0.00806150026619434,
+                0.991330504417419
+            ],
+            "scale": [
+                1.0,
+                1.0,
+                1.0
+            ],
+            "children": [
+                10
+            ]
+        },
+        {
+            "name": "RightHandIndex3",
+            "translation": [
+                -2.62199250755657e-07,
+                -2.57685971260071,
+                1.63709046319127e-11
+            ],
+            "rotation": [
+                0.130491554737091,
+                -0.00300704198889434,
+                -0.02284075319767,
+                0.99118173122406
+            ],
+            "scale": [
+                1.0,
+                1.0,
+                1.0
+            ],
+            "children": [
+                11
+            ]
+        },
+        {
+            "name": "RightHandIndex4",
+            "translation": [
+                -6.4880941863521e-07,
+                -2.16984295845032,
+                1.45519152283669e-11
+            ],
+            "rotation": [
+                7.44831396559675e-09,
+                -1.83785861529451e-10,
+                -0.0246648676693439,
+                0.999695777893066
+            ],
+            "scale": [
+                1.0,
+                1.0,
+                1.0
+            ]
+        },
+        {
+            "name": "RightHandMiddle1",
+            "translation": [
+                -1.02776675703353e-06,
+                -8.89051723480225,
+                0.0
+            ],
+            "rotation": [
+                0.13047268986702,
+                -0.00373660982586443,
+                -0.0283823702484369,
+                0.991038501262665
+            ],
+            "scale": [
+                1.0,
+                1.0,
+                1.0
+            ],
+            "children": [
+                13
+            ]
+        },
+        {
+            "name": "RightHandMiddle2",
+            "translation": [
+                1.85175611022714e-06,
+                -3.40467071533203,
+                0.0
+            ],
+            "rotation": [
+                0.130523636937141,
+                -0.000818223459646106,
+                -0.00621502334252,
+                0.991425395011902
+            ],
+            "scale": [
+                1.0,
+                1.0,
+                1.0
+            ],
+            "children": [
+                14
+            ]
+        },
+        {
+            "name": "RightHandMiddle3",
+            "translation": [
+                1.05654953586054e-06,
+                -2.67793536186218,
+                -1.81898940354586e-12
+            ],
+            "rotation": [
+                0.130522698163986,
+                0.000956544012296945,
+                0.00726567255333066,
+                0.991418242454529
+            ],
+            "scale": [
+                1.0,
+                1.0,
+                1.0
+            ],
+            "children": [
+                15
+            ]
+        },
+        {
+            "name": "RightHandMiddle4",
+            "translation": [
+                -3.79802463612577e-06,
+                -2.63057136535645,
+                6.78955984767526e-08
+            ],
+            "rotation": [
+                1.82495529799098e-08,
+                3.47519013566e-10,
+                0.0078874584287405,
+                0.999968886375427
+            ],
+            "scale": [
+                1.0,
+                1.0,
+                1.0
+            ]
+        },
+        {
+            "name": "RightHandRing1",
+            "translation": [
+                -1.72323477268219,
+                -8.434814453125,
+                0.0
+            ],
+            "rotation": [
+                0.130034267902374,
+                -0.0113214813172817,
+                -0.085995189845562,
+                0.987708330154419
+            ],
+            "scale": [
+                1.0,
+                1.0,
+                1.0
+            ],
+            "children": [
+                17
+            ]
+        },
+        {
+            "name": "RightHandRing2",
+            "translation": [
+                4.97117707709549e-06,
+                -2.92135119438171,
+                0.0
+            ],
+            "rotation": [
+                0.130523890256882,
+                0.000776301021687686,
+                0.00589659111574292,
+                0.991427302360535
+            ],
+            "scale": [
+                1.0,
+                1.0,
+                1.0
+            ],
+            "children": [
+                18
+            ]
+        },
+        {
+            "name": "RightHandRing3",
+            "translation": [
+                -4.25719008489978e-06,
+                -2.7104823589325,
+                -1.81898940354586e-12
+            ],
+            "rotation": [
+                0.130523800849915,
+                -0.000789301353506744,
+                -0.0059953392483294,
+                0.991426706314087
+            ],
+            "scale": [
+                1.0,
+                1.0,
+                1.0
+            ],
+            "children": [
+                19
+            ]
+        },
+        {
+            "name": "RightHandRing4",
+            "translation": [
+                -1.67088660418813e-06,
+                -2.41632723808289,
+                0.0
+            ],
+            "rotation": [
+                -2.85607333715533e-17,
+                4.32810741164245e-17,
+                0.067211352288723,
+                0.997738778591156
+            ],
+            "scale": [
+                1.0,
+                1.0,
+                1.0
+            ]
+        },
+        {
+            "name": "RightHandPinky1",
+            "translation": [
+                -3.45131826400757,
+                -7.36873292922974,
+                0.0
+            ],
+            "rotation": [
+                0.128799960017204,
+                -0.0211579278111458,
+                -0.160710424184799,
+                0.978332817554474
+            ],
+            "scale": [
+                1.0,
+                1.0,
+                1.0
+            ],
+            "children": [
+                21
+            ]
+        },
+        {
+            "name": "RightHandPinky2",
+            "translation": [
+                7.14437692295178e-06,
+                -3.33492231369019,
+                -1.81898940354586e-12
+            ],
+            "rotation": [
+                0.130520552396774,
+                0.00121425895486027,
+                0.00922321155667305,
+                0.991401970386505
+            ],
+            "scale": [
+                1.0,
+                1.0,
+                1.0
+            ],
+            "children": [
+                22
+            ]
+        },
+        {
+            "name": "RightHandPinky3",
+            "translation": [
+                -6.04431488682167e-06,
+                -1.95470726490021,
+                5.04514900967479e-08
+            ],
+            "rotation": [
+                0.13052274286747,
+                -0.0009512152755633,
+                -0.00722519494593143,
+                0.991418540477753
+            ],
+            "scale": [
+                1.0,
+                1.0,
+                1.0
+            ],
+            "children": [
+                23
+            ]
+        },
+        {
+            "name": "RightHandPinky4",
+            "translation": [
+                7.62369018048048e-06,
+                -1.84980952739716,
+                1.02871126728132e-07
+            ],
+            "rotation": [
+                2.44651445768795e-08,
+                1.11148032999608e-08,
+                0.140648439526558,
+                0.990059614181519
+            ],
+            "scale": [
+                1.0,
+                1.0,
+                1.0
+            ]
+        },
+        {
+            "name": "LeftHand",
+            "translation": [
+                65.8000030517578,
+                0.0,
+                0.0
+            ],
+            "rotation": [
+                0.52379697561264,
+                0.475012362003326,
+                -0.475012362003326,
+                0.52379697561264
+            ],
+            "scale": [
+                1.0,
+                1.0,
+                1.0
+            ],
+            "children": [
+                25,
+                29,
+                33,
+                37,
+                41
+            ]
+        },
+        {
+            "name": "LeftHandThumb1",
+            "translation": [
+                -2.7576425075531,
+                2.15009140968323,
+                -1.09139364212751e-11
+            ],
+            "rotation": [
+                -0.0845961794257164,
+                0.24460332095623,
+                0.315717250108719,
+                0.912872016429901
+            ],
+            "scale": [
+                1.0,
+                1.0,
+                1.0
+            ],
+            "children": [
+                26
+            ]
+        },
+        {
+            "name": "LeftHandThumb2",
+            "translation": [
+                0.193819507956505,
+                3.45451331138611,
+                0.111901737749577
+            ],
+            "rotation": [
+                0.258741647005081,
+                0.0406734235584736,
+                -0.0416996106505394,
+                0.964188575744629
+            ],
+            "scale": [
+                1.0,
+                1.0,
+                1.0
+            ],
+            "children": [
+                27
+            ]
+        },
+        {
+            "name": "LeftHandThumb3",
+            "translation": [
+                -0.018382428213954,
+                2.60901665687561,
+                -0.604700148105621
+            ],
+            "rotation": [
+                0.130526185035706,
+                8.98000309354021e-17,
+                4.41677554847997e-17,
+                0.991444885730743
+            ],
+            "scale": [
+                1.0,
+                1.0,
+                1.0
+            ],
+            "children": [
+                28
+            ]
+        },
+        {
+            "name": "LeftHandThumb4",
+            "translation": [
+                0.00620248122140765,
+                1.84271383285522,
+                -0.275547921657562
+            ],
+            "rotation": [
+                -0.0143108321353793,
+                -0.00529135810211301,
+                -0.346111297607422,
+                0.938069403171539
+            ],
+            "scale": [
+                1.0,
+                1.0,
+                1.0
+            ]
+        },
+        {
+            "name": "LeftHandIndex1",
+            "translation": [
+                -2.18770694732666,
+                8.50446128845215,
+                0.00419948389753699
+            ],
+            "rotation": [
+                0.129879087209702,
+                0.00267119123600423,
+                0.0197229869663715,
+                0.991330087184906
+            ],
+            "scale": [
+                1.0,
+                1.0,
+                1.0
+            ],
+            "children": [
+                30
+            ]
+        },
+        {
+            "name": "LeftHandIndex2",
+            "translation": [
+                -1.13686837721616e-13,
+                3.35964441299438,
+                1.81898940354586e-12
+            ],
+            "rotation": [
+                0.131140783429146,
+                0.000969027169048786,
+                0.00806150026619434,
+                0.991330504417419
+            ],
+            "scale": [
+                1.0,
+                1.0,
+                1.0
+            ],
+            "children": [
+                31
+            ]
+        },
+        {
+            "name": "LeftHandIndex3",
+            "translation": [
+                0.0,
+                2.57680535316467,
+                0.0
+            ],
+            "rotation": [
+                0.130491554737091,
+                -0.00300704198889434,
+                -0.02284075319767,
+                0.99118173122406
+            ],
+            "scale": [
+                1.0,
+                1.0,
+                1.0
+            ],
+            "children": [
+                32
+            ]
+        },
+        {
+            "name": "LeftHandIndex4",
+            "translation": [
+                -1.13686837721616e-13,
+                2.16987800598145,
+                0.0
+            ],
+            "rotation": [
+                4.28986164068626e-18,
+                6.83516462791247e-18,
+                -0.0246648676693439,
+                0.999695777893066
+            ],
+            "scale": [
+                1.0,
+                1.0,
+                1.0
+            ]
+        },
+        {
+            "name": "LeftHandMiddle1",
+            "translation": [
+                0.0,
+                8.89050388336182,
+                4.54747350886464e-11
+            ],
+            "rotation": [
+                0.13047268986702,
+                -0.00373660982586443,
+                -0.0283823702484369,
+                0.991038501262665
+            ],
+            "scale": [
+                1.0,
+                1.0,
+                1.0
+            ],
+            "children": [
+                34
+            ]
+        },
+        {
+            "name": "LeftHandMiddle2",
+            "translation": [
+                -5.6843418860808e-14,
+                3.40468168258667,
+                2.36468622460961e-11
+            ],
+            "rotation": [
+                0.13052362203598,
+                -0.000818223343230784,
+                -0.00621502334252,
+                0.991425395011902
+            ],
+            "scale": [
+                1.0,
+                1.0,
+                1.0
+            ],
+            "children": [
+                35
+            ]
+        },
+        {
+            "name": "LeftHandMiddle3",
+            "translation": [
+                -2.8421709430404e-14,
+                2.67797994613647,
+                3.63797880709171e-12
+            ],
+            "rotation": [
+                0.130522683262825,
+                0.000956543954089284,
+                0.00726567255333066,
+                0.991418242454529
+            ],
+            "scale": [
+                1.0,
+                1.0,
+                1.0
+            ],
+            "children": [
+                36
+            ]
+        },
+        {
+            "name": "LeftHandMiddle4",
+            "translation": [
+                0.0,
+                2.63050961494446,
+                -1.81898940354586e-12
+            ],
+            "rotation": [
+                -6.30038723337714e-17,
+                1.23782160635548e-18,
+                0.0078874584287405,
+                0.999968886375427
+            ],
+            "scale": [
+                1.0,
+                1.0,
+                1.0
+            ]
+        },
+        {
+            "name": "LeftHandRing1",
+            "translation": [
+                1.72323560714722,
+                8.4348258972168,
+                6.00266503170133e-11
+            ],
+            "rotation": [
+                0.130034267902374,
+                -0.0113214813172817,
+                -0.085995189845562,
+                0.987708330154419
+            ],
+            "scale": [
+                1.0,
+                1.0,
+                1.0
+            ],
+            "children": [
+                38
+            ]
+        },
+        {
+            "name": "LeftHandRing2",
+            "translation": [
+                0.0,
+                2.92133402824402,
+                2.36468622460961e-11
+            ],
+            "rotation": [
+                0.130523890256882,
+                0.000776300963480026,
+                0.00589659111574292,
+                0.991427302360535
+            ],
+            "scale": [
+                1.0,
+                1.0,
+                1.0
+            ],
+            "children": [
+                39
+            ]
+        },
+        {
+            "name": "LeftHandRing3",
+            "translation": [
+                0.0,
+                2.71053099632263,
+                0.0
+            ],
+            "rotation": [
+                0.130523800849915,
+                -0.000789301353506744,
+                -0.0059953392483294,
+                0.991426706314087
+            ],
+            "scale": [
+                1.0,
+                1.0,
+                1.0
+            ],
+            "children": [
+                40
+            ]
+        },
+        {
+            "name": "LeftHandRing4",
+            "translation": [
+                0.0,
+                2.4163134098053,
+                1.81898940354586e-12
+            ],
+            "rotation": [
+                5.34889858011413e-17,
+                -6.82871510067639e-18,
+                0.067211352288723,
+                0.997738778591156
+            ],
+            "scale": [
+                1.0,
+                1.0,
+                1.0
+            ]
+        },
+        {
+            "name": "LeftHandPinky1",
+            "translation": [
+                3.45132112503052,
+                7.36876058578491,
+                6.54836185276508e-11
+            ],
+            "rotation": [
+                0.128799960017204,
+                -0.0211579278111458,
+                -0.160710424184799,
+                0.978332817554474
+            ],
+            "scale": [
+                1.0,
+                1.0,
+                1.0
+            ],
+            "children": [
+                42
+            ]
+        },
+        {
+            "name": "LeftHandPinky2",
+            "translation": [
+                0.0,
+                3.33487010002136,
+                3.09228198602796e-11
+            ],
+            "rotation": [
+                0.130520537495613,
+                0.00121425883844495,
+                0.00922321155667305,
+                0.991401970386505
+            ],
+            "scale": [
+                1.0,
+                1.0,
+                1.0
+            ],
+            "children": [
+                43
+            ]
+        },
+        {
+            "name": "LeftHandPinky3",
+            "translation": [
+                2.27373675443232e-13,
+                1.95477187633514,
+                1.81898940354586e-12
+            ],
+            "rotation": [
+                0.130522727966309,
+                -0.000951214926317334,
+                -0.00722519494593143,
+                0.991418540477753
+            ],
+            "scale": [
+                1.0,
+                1.0,
+                1.0
+            ],
+            "children": [
+                44
+            ]
+        },
+        {
+            "name": "LeftHandPinky4",
+            "translation": [
+                0.0,
+                1.84976482391357,
+                1.81898940354586e-12
+            ],
+            "rotation": [
+                8.82180761380352e-18,
+                -1.27638923328801e-17,
+                0.140648439526558,
+                0.990059614181519
+            ],
+            "scale": [
+                1.0,
+                1.0,
+                1.0
+            ]
+        },
+        {
+            "name": "Neck",
+            "translation": [
+                -2.09076530502568e-16,
+                14.3466949462891,
+                -3.28626015289046e-14
+            ],
+            "rotation": [
+                0.0,
+                0.0,
+                0.0,
+                1.0
+            ],
+            "scale": [
+                1.0,
+                1.0,
+                1.0
+            ],
+            "children": [
+                46
+            ]
+        },
+        {
+            "name": "Head",
+            "translation": [
+                -1.72115390890012e-17,
+                9.05494976043701,
+                2.07404236001782e-16
+            ],
+            "rotation": [
+                -6.93889390390723e-18,
+                1.27054942088145e-20,
+                1.0842021724855e-19,
+                1.0
+            ],
+            "scale": [
+                1.0,
+                1.0,
+                1.0
+            ],
+            "children": [
+                47,
+                48,
+                49
+            ]
+        },
+        {
+            "name": "HeadTop_End",
+            "translation": [
+                -2.66453525910038e-15,
+                17.8367767333984,
+                -4.03896783473158e-28
+            ],
+            "rotation": [
+                0.0,
+                0.0,
+                1.76324152623343e-37,
+                1.0
+            ],
+            "scale": [
+                1.0,
+                1.0,
+                1.0
+            ]
+        },
+        {
+            "name": "RightEye",
+            "translation": [
+                -6.14273977279663,
+                6.2331337928772,
+                13.0336484909058
+            ],
+            "rotation": [
+                -6.938892249546e-18,
+                -1.36491360355013e-20,
+                0.00379808945581317,
+                0.999992787837982
+            ],
+            "scale": [
+                1.0,
+                1.0,
+                1.0
+            ]
+        },
+        {
+            "name": "LeftEye",
+            "translation": [
+                6.14274263381958,
+                6.2331337928772,
+                13.0336484909058
+            ],
+            "rotation": [
+                -6.938892249546e-18,
+                -1.36491360355013e-20,
+                0.00379808945581317,
+                0.999992787837982
+            ],
+            "scale": [
+                1.0,
+                1.0,
+                1.0
+            ]
+        },
+        {
+            "name": "Bot_Skinned",
+            "translation": [
+                0.0,
+                0.0,
+                0.0
+            ],
+            "rotation": [
+                0.0,
+                0.0,
+                0.0,
+                1.0
+            ],
+            "scale": [
+                0.00999999977648258,
+                0.00999999977648258,
+                0.00999999977648258
+            ],
+            "mesh": 0,
+            "skin": 0
+        }
+    ]
+}

二进制
examples/models/gltf/BotSkinned/glTF-MaterialsUnlit/buffer.bin


二进制
examples/textures/piz_compressed.exr


+ 1 - 1
examples/webgl_buffergeometry.html

@@ -174,7 +174,7 @@
 
 
 				//
 				//
 
 
-				renderer = new THREE.WebGLRenderer( { antialias: false } );
+				renderer = new THREE.WebGLRenderer();
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 
 

+ 1 - 1
examples/webgl_buffergeometry_lines.html

@@ -100,7 +100,7 @@
 
 
 				//
 				//
 
 
-				renderer = new THREE.WebGLRenderer( { antialias: false } );
+				renderer = new THREE.WebGLRenderer();
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 
 

+ 1 - 1
examples/webgl_buffergeometry_lines_indexed.html

@@ -210,7 +210,7 @@
 
 
 				scene.add( parent_node );
 				scene.add( parent_node );
 
 
-				renderer = new THREE.WebGLRenderer( { antialias: false } );
+				renderer = new THREE.WebGLRenderer();
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 
 

+ 1 - 1
examples/webgl_buffergeometry_points.html

@@ -112,7 +112,7 @@
 
 
 				//
 				//
 
 
-				renderer = new THREE.WebGLRenderer( { antialias: false } );
+				renderer = new THREE.WebGLRenderer();
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 
 

+ 1 - 1
examples/webgl_buffergeometry_points_interleaved.html

@@ -126,7 +126,7 @@
 
 
 				//
 				//
 
 
-				renderer = new THREE.WebGLRenderer( { antialias: false } );
+				renderer = new THREE.WebGLRenderer();
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 
 

+ 1 - 1
examples/webgl_buffergeometry_uint.html

@@ -179,7 +179,7 @@
 
 
 				//
 				//
 
 
-				renderer = new THREE.WebGLRenderer( { antialias: false } );
+				renderer = new THREE.WebGLRenderer();
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 
 

+ 6 - 5
examples/webgl_decals.html

@@ -124,8 +124,8 @@
 			light.position.set( -1, 0.75, -0.5 );
 			light.position.set( -1, 0.75, -0.5 );
 			scene.add( light );
 			scene.add( light );
 
 
-			var geometry = new THREE.Geometry();
-			geometry.vertices.push( new THREE.Vector3(), new THREE.Vector3() );
+			var geometry = new THREE.BufferGeometry();
+			geometry.setFromPoints( [ new THREE.Vector3(), new THREE.Vector3() ] );
 
 
 			line = new THREE.Line( geometry, new THREE.LineBasicMaterial( { linewidth: 4 } ) );
 			line = new THREE.Line( geometry, new THREE.LineBasicMaterial( { linewidth: 4 } ) );
 			scene.add( line );
 			scene.add( line );
@@ -209,9 +209,10 @@
 					intersection.normal.copy( intersects[ 0 ].face.normal );
 					intersection.normal.copy( intersects[ 0 ].face.normal );
 					mouseHelper.lookAt( n );
 					mouseHelper.lookAt( n );
 
 
-					line.geometry.vertices[ 0 ].copy( intersection.point );
-					line.geometry.vertices[ 1 ].copy( n );
-					line.geometry.verticesNeedUpdate = true;
+					var positions = line.geometry.attributes.position;
+					positions.setXYZ( 0, p.x, p.y, p.z );
+					positions.setXYZ( 1, n.x, n.y, n.z );
+					positions.needsUpdate = true;
 
 
 					intersection.intersects = true;
 					intersection.intersects = true;
 
 

+ 1 - 1
examples/webgl_effects_anaglyph.html

@@ -108,7 +108,7 @@
 
 
 				//
 				//
 
 
-				renderer = new THREE.WebGLRenderer( { antialias: false } );
+				renderer = new THREE.WebGLRenderer();
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				container.appendChild( renderer.domElement );
 				container.appendChild( renderer.domElement );
 
 

+ 1 - 1
examples/webgl_effects_parallaxbarrier.html

@@ -189,7 +189,7 @@
 
 
 				//
 				//
 
 
-				renderer = new THREE.WebGLRenderer( { antialias: false } );
+				renderer = new THREE.WebGLRenderer();
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				container.appendChild( renderer.domElement );
 				container.appendChild( renderer.domElement );
 
 

+ 12 - 9
examples/webgl_geometry_nurbs.html

@@ -107,19 +107,22 @@
 
 
 				}
 				}
 
 
-				var nurbsCurve = new THREE.NURBSCurve(nurbsDegree, nurbsKnots, nurbsControlPoints);
+				var nurbsCurve = new THREE.NURBSCurve( nurbsDegree, nurbsKnots, nurbsControlPoints );
 
 
-				var nurbsGeometry = new THREE.Geometry();
-				nurbsGeometry.vertices = nurbsCurve.getPoints(200);
-				var nurbsMaterial = new THREE.LineBasicMaterial( { linewidth: 10, color: 0x333333, transparent: true } );
+				var nurbsGeometry = new THREE.BufferGeometry();
+				nurbsGeometry.setFromPoints( nurbsCurve.getPoints( 200 ) );
+
+				var nurbsMaterial = new THREE.LineBasicMaterial( { linewidth: 10, color: 0x333333 } );
 
 
 				var nurbsLine = new THREE.Line( nurbsGeometry, nurbsMaterial );
 				var nurbsLine = new THREE.Line( nurbsGeometry, nurbsMaterial );
-				nurbsLine.position.set( 200, -100, 0 );
+				nurbsLine.position.set( 200, - 100, 0 );
 				group.add( nurbsLine );
 				group.add( nurbsLine );
 
 
-				var nurbsControlPointsGeometry = new THREE.Geometry();
-				nurbsControlPointsGeometry.vertices = nurbsCurve.controlPoints;
+				var nurbsControlPointsGeometry = new THREE.BufferGeometry();
+				nurbsControlPointsGeometry.setFromPoints( nurbsCurve.controlPoints );
+
 				var nurbsControlPointsMaterial = new THREE.LineBasicMaterial( { linewidth: 2, color: 0x333333, opacity: 0.25, transparent: true } );
 				var nurbsControlPointsMaterial = new THREE.LineBasicMaterial( { linewidth: 2, color: 0x333333, opacity: 0.25, transparent: true } );
+
 				var nurbsControlPointsLine = new THREE.Line( nurbsControlPointsGeometry, nurbsControlPointsMaterial );
 				var nurbsControlPointsLine = new THREE.Line( nurbsControlPointsGeometry, nurbsControlPointsMaterial );
 				nurbsControlPointsLine.position.copy( nurbsLine.position );
 				nurbsControlPointsLine.position.copy( nurbsLine.position );
 				group.add( nurbsControlPointsLine );
 				group.add( nurbsControlPointsLine );
@@ -156,9 +159,9 @@
 				map.wrapS = map.wrapT = THREE.RepeatWrapping;
 				map.wrapS = map.wrapT = THREE.RepeatWrapping;
 				map.anisotropy = 16;
 				map.anisotropy = 16;
 
 
-				function getSurfacePoint(u, v) {
+				function getSurfacePoint( u, v ) {
 
 
-					return nurbsSurface.getPoint(u, v);
+					return nurbsSurface.getPoint( u, v );
 
 
 				}
 				}
 
 

+ 1 - 1
examples/webgl_interactive_buffergeometry.html

@@ -213,7 +213,7 @@
 
 
 				//
 				//
 
 
-				renderer = new THREE.WebGLRenderer( { antialias: false } );
+				renderer = new THREE.WebGLRenderer();
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				container.appendChild( renderer.domElement );
 				container.appendChild( renderer.domElement );

+ 1 - 1
examples/webgl_lights_pointlights2.html

@@ -175,7 +175,7 @@
 
 
 				// RENDERER
 				// RENDERER
 
 
-				renderer = new THREE.WebGLRenderer( { antialias: false } );
+				renderer = new THREE.WebGLRenderer();
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				container.appendChild( renderer.domElement );
 				container.appendChild( renderer.domElement );

+ 1 - 1
examples/webgl_lines_colors.html

@@ -89,7 +89,7 @@
 
 
 				scene = new THREE.Scene();
 				scene = new THREE.Scene();
 
 
-				renderer = new THREE.WebGLRenderer( { antialias: false } );
+				renderer = new THREE.WebGLRenderer();
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				renderer.autoClear = false;
 				renderer.autoClear = false;

+ 14 - 1
examples/webgl_loader_gltf_extensions.html

@@ -89,6 +89,7 @@
 				<option value="glTF">None (Default)</option>
 				<option value="glTF">None (Default)</option>
 				<option value="glTF-Embedded">None (Embedded)</option>
 				<option value="glTF-Embedded">None (Embedded)</option>
 				<option value="glTF-Binary">None (Binary)</option>
 				<option value="glTF-Binary">None (Binary)</option>
+				<option value="glTF-MaterialsUnlit">Materials Unlit</option>
 				<option value="glTF-pbrSpecularGlossiness">Specular-Glossiness (PBR)</option>
 				<option value="glTF-pbrSpecularGlossiness">Specular-Glossiness (PBR)</option>
 				<option value="glTF-Draco">Draco (Compressed)</option>
 				<option value="glTF-Draco">Draco (Compressed)</option>
 			</select>
 			</select>
@@ -213,7 +214,11 @@
 					var child = extensionSelect.children[i];
 					var child = extensionSelect.children[i];
 					child.disabled = sceneInfo.extensions.indexOf(child.value) === -1;
 					child.disabled = sceneInfo.extensions.indexOf(child.value) === -1;
 					if (child.disabled && child.selected) {
 					if (child.disabled && child.selected) {
-						extensionSelect.value = extension = 'glTF';
+						if (sceneInfo.extensions.length === 0) {
+							extensionSelect.value = extension = 'glTF';
+						} else {
+							extensionSelect.value = extension = sceneInfo.extensions[0];
+						}
 					}
 					}
 				}
 				}
 
 
@@ -436,6 +441,14 @@
 					extensions: ['glTF', 'glTF-pbrSpecularGlossiness', 'glTF-Binary'],
 					extensions: ['glTF', 'glTF-pbrSpecularGlossiness', 'glTF-Binary'],
 					addEnvMap: true
 					addEnvMap: true
 				},
 				},
+				{
+					name : 'Bot Skinned', url : './models/gltf/BotSkinned/%s/Bot_Skinned.gltf',
+					cameraPos: new THREE.Vector3(0, 4, 6),
+					objectRotation: new THREE.Euler(0, 0, 0),
+					addLights:true,
+					extensions: ['glTF-MaterialsUnlit'],
+					addEnvMap: true
+				},
 				{
 				{
 					name : 'MetalRoughSpheres (PBR)', url : './models/gltf/MetalRoughSpheres/%s/MetalRoughSpheres.gltf',
 					name : 'MetalRoughSpheres (PBR)', url : './models/gltf/MetalRoughSpheres/%s/MetalRoughSpheres.gltf',
 					cameraPos: new THREE.Vector3(2, 1, 15),
 					cameraPos: new THREE.Vector3(2, 1, 15),

+ 1 - 1
examples/webgl_loader_nrrd.html

@@ -176,7 +176,7 @@
 				} );
 				} );
 				// renderer
 				// renderer
 
 
-				renderer = new THREE.WebGLRenderer( { antialias: false, alpha: true } );
+				renderer = new THREE.WebGLRenderer( { alpha: true } );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 
 

+ 1 - 1
examples/webgl_loader_texture_exr.html

@@ -111,7 +111,7 @@
 
 
 				var loader = new THREE.EXRLoader();
 				var loader = new THREE.EXRLoader();
 
 
-				var texture = loader.load( "textures/uncompressed.exr", function( texture, textureData ){
+				var texture = loader.load( "textures/piz_compressed.exr", function( texture, textureData ){
 					console.log( textureData.header ); // exr header
 					console.log( textureData.header ); // exr header
 
 
 					texture.minFilter = THREE.NearestFilter;
 					texture.minFilter = THREE.NearestFilter;

+ 1 - 1
examples/webgl_loader_vrml.html

@@ -84,7 +84,7 @@
 
 
 				// renderer
 				// renderer
 
 
-				renderer = new THREE.WebGLRenderer( { antialias: false } );
+				renderer = new THREE.WebGLRenderer();
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 
 

+ 1 - 1
examples/webgl_loader_vtk.html

@@ -152,7 +152,7 @@
 
 
 				// renderer
 				// renderer
 
 
-				renderer = new THREE.WebGLRenderer( { antialias: false } );
+				renderer = new THREE.WebGLRenderer();
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 
 

+ 1 - 1
examples/webgl_materials_bumpmap.html

@@ -123,7 +123,7 @@
 				loader = new THREE.JSONLoader();
 				loader = new THREE.JSONLoader();
 				loader.load( "models/json/leeperrysmith/LeePerrySmith.json", function( geometry ) { createScene( geometry, 100, material ) } );
 				loader.load( "models/json/leeperrysmith/LeePerrySmith.json", function( geometry ) { createScene( geometry, 100, material ) } );
 
 
-				renderer = new THREE.WebGLRenderer( { antialias: false } );
+				renderer = new THREE.WebGLRenderer();
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				container.appendChild( renderer.domElement );
 				container.appendChild( renderer.domElement );

+ 1 - 1
examples/webgl_materials_cubemap_dynamic.html

@@ -177,7 +177,7 @@
 
 
 				// RENDERER
 				// RENDERER
 
 
-				renderer = new THREE.WebGLRenderer( { antialias: false } );
+				renderer = new THREE.WebGLRenderer();
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT );
 				renderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT );
 				container.appendChild( renderer.domElement );
 				container.appendChild( renderer.domElement );

+ 378 - 0
examples/webgl_materials_curvature.html

@@ -0,0 +1,378 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<title>three.js webgl - shader - curvature [ninja]</title>
+		<meta charset="utf-8">
+		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
+		<style>
+			body {
+				color: #ffffff;
+				font-family:Monospace;
+				font-size:13px;
+				text-align:center;
+				font-weight: bold;
+
+				background-color: #000000;
+				margin: 0px;
+				overflow: hidden;
+			}
+
+			#info {
+				position: absolute;
+				top: 0px; width: 100%;
+				padding: 5px;
+			}
+
+			a {
+
+				color: #ffffff;
+			}
+
+			#oldie a { color:#da0 }
+		</style>
+	</head>
+	<body>
+
+		<div id="container"></div>
+		<div id="info"><a href="http://threejs.org" target="_blank" rel="noopener">three.js</a> - curvature estimation of a geometry by <a href="http://codercat.club" target="_blank" rel="noopener">CoderCat</a></div>
+
+		<script src="../build/three.js"></script>
+		<script src="js/Detector.js"></script>
+
+		<script src="js/controls/OrbitControls.js"></script>
+		<script src="js/loaders/OBJLoader.js"></script>
+		<script src="js/libs/dat.gui.min.js"></script>
+
+		<script id="vertexShaderRaw" type="x-shader/x-vertex">
+
+		attribute float curvature;
+
+		varying float vCurvature;
+
+		void main() {
+
+			vec3 p = position;
+			vec4 modelViewPosition = modelViewMatrix * vec4( p , 1.0 );
+			gl_Position = projectionMatrix * modelViewPosition;
+			vCurvature = curvature;
+
+		}
+
+		</script>
+
+		<script id="fragmentShaderRaw" type="x-shader/x-fragment">
+
+		varying vec3 vViewPosition;
+		varying float vCurvature;
+
+		void main() {
+				gl_FragColor = vec4( vCurvature * 2.0, 0.0, 0.0, 0.0 );
+		}
+
+		</script>
+
+		<script>
+
+			if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
+
+			var container;
+
+			var camera, scene, renderer;
+
+			var ninjaMeshRaw, curvatureAttribute;
+
+			init();
+			animate();
+
+			//returns average of elements in a dictionary
+			function average( dict ) {
+
+				var sum = 0;
+				var length = 0;
+
+				Object.keys( dict ).forEach( function( key ) {
+
+					sum += dict[ key ];
+					length ++;
+
+				});
+
+				return sum / length;
+
+			}
+
+			//clamp a number between min and max
+			function clamp( number, min, max ) {
+
+			  return Math.max( min, Math.min( number, max ) );
+
+			}
+
+			//filter the curvature array to only show concave values
+			function filterConcave( curvature ) {
+
+				for ( var i = 0; i < curvature.length; i++ ) {
+
+					curvature[ i ] = Math.abs( clamp( curvature[ i ], -1, 0 ) );
+
+				}
+
+			}
+
+			//filter the curvature array to only show convex values
+			function filterConvex( curvature ) {
+
+				for ( var i = 0; i < curvature.length; i++ ) {
+
+					curvature[ i ] = clamp( curvature[ i ], 0, 1 );
+
+				}
+
+			}
+
+			//filter the curvature array to show both the concave and convex values
+			function filterBoth( curvature ) {
+
+				for ( var i = 0; i < curvature.length; i++ ) {
+
+					curvature[ i ] = Math.abs( curvature[ i ] );
+
+				}
+
+			}
+
+			//initialize the scene
+			function init() {
+
+				scene = new THREE.Scene();
+
+				camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
+
+				camera.position.x = -23;
+				camera.position.y = 2;
+				camera.position.z = 24;
+
+				controls = new THREE.OrbitControls( camera );
+
+				renderer = new THREE.WebGLRenderer();
+				renderer.setSize( window.innerWidth, window.innerHeight );
+				renderer.autoClear = false;
+
+				document.body.appendChild( renderer.domElement );
+
+				var loader = new THREE.OBJLoader();
+				//load the obj
+				loader.load( 'models/obj/ninja/ninjaHead_Low.obj', function ( object ) {
+					object.traverse( function ( child ) {
+						if ( child instanceof THREE.Mesh ) {
+
+							bufferGeo = child.geometry;
+							bufferGeo.center();
+							var dict= {};
+
+							for ( var i = 0; i < bufferGeo.attributes.position.count; i+=3 ) {
+								//create a dictionary of every position, and its neighboring positions
+								var array = bufferGeo.attributes.position.array;
+								var normArray = bufferGeo.attributes.normal.array;
+
+								var posA = new THREE.Vector3(array[ 3 * i ], array[ 3 * i + 1 ], array[ 3 * i + 2 ]);
+								var posB = new THREE.Vector3(array[ 3 * ( i + 1 ) ], array[ 3 * ( i + 1 ) + 1 ], array[ 3 * ( i + 1 ) + 2 ]);
+								var posC = new THREE.Vector3(array[ 3 * ( i + 2 ) ], array[ 3 * ( i + 2 ) + 1 ], array[ 3 * ( i + 2 ) + 2 ]);
+
+								var normA = new THREE.Vector3(normArray[ 3 * i ], normArray[ 3 * i + 1 ], normArray[ 3 * i + 2 ]).normalize();
+								var normB = new THREE.Vector3(normArray[ 3 * ( i + 1 ) ], normArray[ 3 * ( i + 1 ) + 1 ], normArray[ 3 * ( i + 1 ) + 2 ]).normalize();
+								var normC = new THREE.Vector3(normArray[ 3 * ( i + 2 ) ], normArray[ 3 * ( i + 2 ) + 1 ], normArray[ 3 * ( i + 2 ) + 2 ]).normalize();
+
+								var strA = posA.toArray().toString();
+								var strB = posB.toArray().toString();
+								var strC = posC.toArray().toString();
+
+								var posB_A = new THREE.Vector3().subVectors( posB, posA );
+								var posB_C = new THREE.Vector3().subVectors( posB, posC );
+								var posC_A = new THREE.Vector3().subVectors( posC, posA );
+
+								var normB_A = new THREE.Vector3().subVectors( normB, normA );
+								var normB_C = new THREE.Vector3().subVectors( normB, normC );
+								var normC_A = new THREE.Vector3().subVectors( normC, normA );
+
+								var b2a = normB.dot( posB_A.normalize() );
+								var b2c = normB.dot( posB_C.normalize() );
+								var c2a = normC.dot( posC_A.normalize() );
+
+								var a2b = -normA.dot( posB_A.normalize() );
+								var c2b = -normC.dot( posB_C.normalize() );
+								var a2c = -normA.dot( posC_A.normalize() );
+
+								if (dict[ strA ] === undefined ) {
+									dict[ strA ] = {};
+								}
+								if (dict[ strB ] === undefined ) {
+									dict[ strB ] = {};
+								}
+								if (dict[ strC ] === undefined ) {
+									dict[ strC ] = {};
+								}
+
+								dict[ strA ][ strB ] = a2b;
+								dict[ strA ][ strC ] = a2c;
+								dict[ strB ][ strA ] = b2a;
+								dict[ strB ][ strC ] = b2c;
+								dict[ strC ][ strA ] = c2a;
+								dict[ strC ][ strB ] = c2b;
+
+							}
+
+							curvatureDict = {};
+							var min = 10, max = 0;
+
+							Object.keys( dict ).forEach( function( key ) {
+
+								curvatureDict[ key ] = average( dict[ key ] );
+
+							});
+
+							//smoothing
+							var smoothCurvatureDict  = Object.create(curvatureDict);
+
+							Object.keys( dict ).forEach( function( key ) {
+
+								var count = 0;
+								var sum = 0;
+								Object.keys( dict[ key ] ).forEach( function( key2 ) {
+
+									sum += smoothCurvatureDict[ key2 ];
+									count ++;
+
+								});
+								smoothCurvatureDict[key] = sum / count;
+
+							});
+
+							curvatureDict = smoothCurvatureDict;
+
+							// fit values to 0 and 1
+							Object.keys( curvatureDict ).forEach( function( key ) {
+
+								val = Math.abs( curvatureDict[ key ] );
+								if ( val < min ) min = val;
+								if ( val > max ) max = val;
+
+							});
+
+							var range = ( max - min );
+
+							Object.keys( curvatureDict ).forEach( function( key ) {
+
+								val = Math.abs( curvatureDict[ key ] );
+								if ( curvatureDict[ key ] < 0 ) {
+									curvatureDict[ key ] = (min - val) / range
+								} else {
+									curvatureDict[ key ] = (val - min) / range;
+								}
+
+							});
+
+							curvatureAttribute = new Float32Array( bufferGeo.attributes.position.count );
+
+							for ( var i = 0; i < bufferGeo.attributes.position.count; i++ ) {
+
+								array = bufferGeo.attributes.position.array;
+								var pos = new THREE.Vector3( array[ 3 * i ], array[ 3 * i + 1 ], array[ 3 * i + 2 ] );
+								var str = pos.toArray().toString();
+								curvatureAttribute[i] = curvatureDict[ str ];
+							}
+
+							bufferGeo.addAttribute( 'curvature', new THREE.BufferAttribute( curvatureAttribute, 1 ) );
+
+							//starting filter is to show both concave and convex
+							var curvatureFiltered = new Float32Array( curvatureAttribute );
+							filterBoth(curvatureFiltered);
+
+							var materialRaw = new THREE.ShaderMaterial ({
+
+								vertexShader: document.getElementById( 'vertexShaderRaw' ).textContent,
+								fragmentShader: document.getElementById( 'fragmentShaderRaw' ).textContent
+
+							} );
+
+							ninjaMeshRaw = new THREE.Mesh( bufferGeo, materialRaw );
+
+						}
+					} );
+
+					scene.add( ninjaMeshRaw );
+
+				} );
+
+
+				//init GUI
+				var params = {
+
+					filterConvex: function () {
+
+						var curvatureFiltered = new Float32Array( curvatureAttribute );
+						filterConvex(curvatureFiltered);
+						bufferGeo.attributes.curvature.array = curvatureFiltered;
+						bufferGeo.attributes.curvature.needsUpdate = true;
+
+
+					},
+					filterConcave: function () {
+
+						var curvatureFiltered = new Float32Array( curvatureAttribute );
+						filterConcave(curvatureFiltered);
+						bufferGeo.attributes.curvature.array = curvatureFiltered;
+						bufferGeo.attributes.curvature.needsUpdate = true;
+
+
+					},
+					filterBoth: function () {
+
+						var curvatureFiltered = new Float32Array( curvatureAttribute );
+						filterBoth(curvatureFiltered);
+						bufferGeo.attributes.curvature.array = curvatureFiltered;
+						bufferGeo.attributes.curvature.needsUpdate = true;
+
+					}
+				};
+
+				var gui = new dat.GUI();
+
+				topologyFolder = gui.addFolder( 'Topology' );
+				topologyFolder.add( params, 'filterConvex' );
+				topologyFolder.add( params, 'filterConcave' );
+				topologyFolder.add( params, 'filterBoth' );
+				topologyFolder.open()
+
+				onWindowResize();
+
+				window.addEventListener( 'resize', onWindowResize, false );
+
+			}
+
+			function onWindowResize( event ) {
+
+				renderer.setSize( window.innerWidth, window.innerHeight );
+				camera.aspect = window.innerWidth / window.innerHeight;
+				camera.updateProjectionMatrix();
+
+			}
+
+			function animate() {
+
+				requestAnimationFrame( animate );
+
+				render();
+
+			}
+
+			function render() {
+
+				renderer.render(scene, camera);
+
+			}
+
+		</script>
+
+	</body>
+</html>

+ 1 - 1
examples/webgl_materials_envmaps_hdr.html

@@ -86,7 +86,7 @@
 				scene = new THREE.Scene();
 				scene = new THREE.Scene();
 				scene.background = new THREE.Color( 0xffffff );
 				scene.background = new THREE.Color( 0xffffff );
 
 
-				renderer = new THREE.WebGLRenderer( { antialias: false } );
+				renderer = new THREE.WebGLRenderer();
 				renderer.toneMapping = THREE.LinearToneMapping;
 				renderer.toneMapping = THREE.LinearToneMapping;
 
 
 				standardMaterial = new THREE.MeshStandardMaterial( {
 				standardMaterial = new THREE.MeshStandardMaterial( {

+ 9 - 21
examples/webgl_materials_modified.html

@@ -48,23 +48,11 @@
 		<script src="js/Detector.js"></script>
 		<script src="js/Detector.js"></script>
 		<script src="js/libs/stats.min.js"></script>
 		<script src="js/libs/stats.min.js"></script>
 
 
-		<script src="js/shaders/BleachBypassShader.js"></script>
-		<script src="js/shaders/ColorCorrectionShader.js"></script>
-		<script src="js/shaders/CopyShader.js"></script>
-		<script src="js/shaders/FXAAShader.js"></script>
-
-		<script src="js/postprocessing/EffectComposer.js"></script>
-		<script src="js/postprocessing/RenderPass.js"></script>
-		<script src="js/postprocessing/ShaderPass.js"></script>
-		<script src="js/postprocessing/MaskPass.js"></script>
-
 		<script>
 		<script>
 
 
 			if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
 			if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
 
 
-			var container, stats, loader;
-
-			var camera, scene, renderer;
+			var camera, scene, renderer, stats;
 
 
 			var mesh, materialShader;
 			var mesh, materialShader;
 
 
@@ -82,9 +70,6 @@
 
 
 			function init() {
 			function init() {
 
 
-				container = document.createElement( 'div' );
-				document.body.appendChild( container );
-
 				camera = new THREE.PerspectiveCamera( 27, window.innerWidth / window.innerHeight, 1, 10000 );
 				camera = new THREE.PerspectiveCamera( 27, window.innerWidth / window.innerHeight, 1, 10000 );
 				camera.position.z = 1200;
 				camera.position.z = 1200;
 
 
@@ -114,8 +99,8 @@
 
 
 				};
 				};
 
 
-				loader = new THREE.JSONLoader();
-				loader.load( "models/json/leeperrysmith/LeePerrySmith.json", function( geometry ) {
+				var loader = new THREE.JSONLoader();
+				loader.load( 'models/json/leeperrysmith/LeePerrySmith.json', function( geometry ) {
 
 
 					mesh = new THREE.Mesh( geometry, material );
 					mesh = new THREE.Mesh( geometry, material );
 					mesh.position.y = - 50;
 					mesh.position.y = - 50;
@@ -124,15 +109,15 @@
 
 
 				} );
 				} );
 
 
-				renderer = new THREE.WebGLRenderer( { antialias: false } );
+				renderer = new THREE.WebGLRenderer( { antialias: true } );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				renderer.setSize( window.innerWidth, window.innerHeight );
-				container.appendChild( renderer.domElement );
+				document.body.appendChild( renderer.domElement );
 
 
 				//
 				//
 
 
 				stats = new Stats();
 				stats = new Stats();
-				container.appendChild( stats.dom );
+				document.body.appendChild( stats.dom );
 
 
 				// EVENTS
 				// EVENTS
 
 
@@ -148,6 +133,9 @@
 				var width = window.innerWidth;
 				var width = window.innerWidth;
 				var height = window.innerHeight;
 				var height = window.innerHeight;
 
 
+				windowHalfX = width / 2;
+				windowHalfY = height / 2;
+
 				camera.aspect = width / height;
 				camera.aspect = width / height;
 				camera.updateProjectionMatrix();
 				camera.updateProjectionMatrix();
 
 

+ 1 - 1
examples/webgl_materials_normalmap.html

@@ -133,7 +133,7 @@
 				loader = new THREE.JSONLoader();
 				loader = new THREE.JSONLoader();
 				loader.load( "models/json/leeperrysmith/LeePerrySmith.json", function( geometry ) { createScene( geometry, 100, material ) } );
 				loader.load( "models/json/leeperrysmith/LeePerrySmith.json", function( geometry ) { createScene( geometry, 100, material ) } );
 
 
-				renderer = new THREE.WebGLRenderer( { antialias: false } );
+				renderer = new THREE.WebGLRenderer();
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				container.appendChild( renderer.domElement );
 				container.appendChild( renderer.domElement );
 
 

+ 1 - 1
examples/webgl_materials_shaders_fresnel.html

@@ -122,7 +122,7 @@
 
 
 				//
 				//
 
 
-				renderer = new THREE.WebGLRenderer( { antialias: false } );
+				renderer = new THREE.WebGLRenderer();
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				container.appendChild( renderer.domElement );
 				container.appendChild( renderer.domElement );

+ 1 - 1
examples/webgl_materials_skin.html

@@ -158,7 +158,7 @@
 
 
 				// RENDERER
 				// RENDERER
 
 
-				renderer = new THREE.WebGLRenderer( { antialias: false } );
+				renderer = new THREE.WebGLRenderer();
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				renderer.autoClear = false;
 				renderer.autoClear = false;

+ 1 - 1
examples/webgl_materials_video.html

@@ -97,7 +97,7 @@
 				light.position.set( 0.5, 1, 1 ).normalize();
 				light.position.set( 0.5, 1, 1 ).normalize();
 				scene.add( light );
 				scene.add( light );
 
 
-				renderer = new THREE.WebGLRenderer( { antialias: false } );
+				renderer = new THREE.WebGLRenderer();
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				container.appendChild( renderer.domElement );
 				container.appendChild( renderer.domElement );

+ 1 - 1
examples/webgl_multiple_renderers.html

@@ -172,7 +172,7 @@
 				renderer1.setSize( window.innerWidth, window.innerHeight / 2 );
 				renderer1.setSize( window.innerWidth, window.innerHeight / 2 );
 				document.body.appendChild( renderer1.domElement );
 				document.body.appendChild( renderer1.domElement );
 
 
-				renderer2 = new THREE.WebGLRenderer( { antialias: false } );
+				renderer2 = new THREE.WebGLRenderer();
 				renderer2.setPixelRatio( window.devicePixelRatio );
 				renderer2.setPixelRatio( window.devicePixelRatio );
 				renderer2.setSize( window.innerWidth, window.innerHeight / 2 );
 				renderer2.setSize( window.innerWidth, window.innerHeight / 2 );
 				document.body.appendChild( renderer2.domElement );
 				document.body.appendChild( renderer2.domElement );

+ 1 - 1
examples/webgl_performance_static.html

@@ -75,7 +75,7 @@
 
 
 				} );
 				} );
 
 
-				renderer = new THREE.WebGLRenderer( { antialias: false } );
+				renderer = new THREE.WebGLRenderer();
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				//renderer.sortObjects = false;
 				//renderer.sortObjects = false;

+ 1 - 1
examples/webgl_points_dynamic.html

@@ -107,7 +107,7 @@
 				} );
 				} );
 
 
 
 
-				renderer = new THREE.WebGLRenderer( { antialias: false } );
+				renderer = new THREE.WebGLRenderer();
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth,window.innerHeight );
 				renderer.setSize( window.innerWidth,window.innerHeight );
 				renderer.autoClear = false;
 				renderer.autoClear = false;

+ 1 - 1
examples/webgl_postprocessing_advanced.html

@@ -141,7 +141,7 @@
 
 
 				//
 				//
 
 
-				renderer = new THREE.WebGLRenderer( { antialias: false } );
+				renderer = new THREE.WebGLRenderer();
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( width, height );
 				renderer.setSize( width, height );
 				renderer.autoClear = false;
 				renderer.autoClear = false;

+ 1 - 1
examples/webgl_postprocessing_backgrounds.html

@@ -118,7 +118,7 @@
 				var aspect = width / height;
 				var aspect = width / height;
 				var devicePixelRatio = window.devicePixelRatio || 1;
 				var devicePixelRatio = window.devicePixelRatio || 1;
 
 
-				renderer = new THREE.WebGLRenderer( { antialias: false } );
+				renderer = new THREE.WebGLRenderer();
 				renderer.setPixelRatio( devicePixelRatio );
 				renderer.setPixelRatio( devicePixelRatio );
 				renderer.setSize( width, height );
 				renderer.setSize( width, height );
 				document.body.appendChild( renderer.domElement );
 				document.body.appendChild( renderer.domElement );

+ 1 - 1
examples/webgl_postprocessing_dof.html

@@ -88,7 +88,7 @@
 
 
 				scene = new THREE.Scene();
 				scene = new THREE.Scene();
 
 
-				renderer = new THREE.WebGLRenderer( { antialias: false } );
+				renderer = new THREE.WebGLRenderer();
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( width, height );
 				renderer.setSize( width, height );
 				container.appendChild( renderer.domElement );
 				container.appendChild( renderer.domElement );

+ 1 - 1
examples/webgl_postprocessing_dof2.html

@@ -93,7 +93,7 @@ Use WEBGL Depth buffer support?
 				scene = new THREE.Scene();
 				scene = new THREE.Scene();
 				scene.add( camera );
 				scene.add( camera );
 
 
-				renderer = new THREE.WebGLRenderer( { antialias: false } );
+				renderer = new THREE.WebGLRenderer();
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth, height );
 				renderer.setSize( window.innerWidth, height );
 				//renderer.sortObjects = false;
 				//renderer.sortObjects = false;

+ 1 - 1
examples/webgl_postprocessing_godrays.html

@@ -110,7 +110,7 @@
 
 
 				//
 				//
 
 
-				renderer = new THREE.WebGLRenderer( { antialias: false } );
+				renderer = new THREE.WebGLRenderer();
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				container.appendChild( renderer.domElement );
 				container.appendChild( renderer.domElement );

+ 1 - 1
examples/webgl_postprocessing_masking.html

@@ -53,7 +53,7 @@
 				torus = new THREE.Mesh( new THREE.TorusGeometry( 3, 1, 16, 32 ) );
 				torus = new THREE.Mesh( new THREE.TorusGeometry( 3, 1, 16, 32 ) );
 				scene2.add( torus );
 				scene2.add( torus );
 
 
-				renderer = new THREE.WebGLRenderer( { antialias: false } );
+				renderer = new THREE.WebGLRenderer();
 				renderer.setClearColor( 0xe0e0e0 );
 				renderer.setClearColor( 0xe0e0e0 );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				renderer.setSize( window.innerWidth, window.innerHeight );

+ 1 - 1
examples/webgl_postprocessing_outline.html

@@ -145,7 +145,7 @@
 				var width = window.innerWidth;
 				var width = window.innerWidth;
 				var height = window.innerHeight;
 				var height = window.innerHeight;
 
 
-				renderer = new THREE.WebGLRenderer( { antialias: false } );
+				renderer = new THREE.WebGLRenderer();
 				renderer.shadowMap.enabled = true;
 				renderer.shadowMap.enabled = true;
 				// todo - support pixelRatio in this demo
 				// todo - support pixelRatio in this demo
 				renderer.setSize( width, height );
 				renderer.setSize( width, height );

+ 1 - 1
examples/webgl_postprocessing_procedural.html

@@ -105,7 +105,7 @@
 
 
 				var container = document.getElementById( "container" );
 				var container = document.getElementById( "container" );
 
 
-				renderer = new THREE.WebGLRenderer( { antialias: false } );
+				renderer = new THREE.WebGLRenderer();
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				document.body.appendChild( renderer.domElement );
 				document.body.appendChild( renderer.domElement );

+ 1 - 1
examples/webgl_postprocessing_smaa.html

@@ -40,7 +40,7 @@
 
 
 				var container = document.getElementById( "container" );
 				var container = document.getElementById( "container" );
 
 
-				renderer = new THREE.WebGLRenderer( { antialias: false } );
+				renderer = new THREE.WebGLRenderer();
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				document.body.appendChild( renderer.domElement );
 				document.body.appendChild( renderer.domElement );

+ 1 - 1
examples/webgl_postprocessing_ssaa.html

@@ -87,7 +87,7 @@
 
 
 				var container = document.getElementById( "container" );
 				var container = document.getElementById( "container" );
 
 
-				renderer = new THREE.WebGLRenderer( { antialias: false } );
+				renderer = new THREE.WebGLRenderer();
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				document.body.appendChild( renderer.domElement );
 				document.body.appendChild( renderer.domElement );

+ 1 - 1
examples/webgl_postprocessing_ssaa_unbiased.html

@@ -107,7 +107,7 @@
 				var aspect = width / height;
 				var aspect = width / height;
 				var devicePixelRatio = window.devicePixelRatio || 1;
 				var devicePixelRatio = window.devicePixelRatio || 1;
 
 
-				renderer = new THREE.WebGLRenderer( { antialias: false } );
+				renderer = new THREE.WebGLRenderer();
 				renderer.setPixelRatio( devicePixelRatio );
 				renderer.setPixelRatio( devicePixelRatio );
 				renderer.setSize( width, height );
 				renderer.setSize( width, height );
 				document.body.appendChild( renderer.domElement );
 				document.body.appendChild( renderer.domElement );

+ 1 - 1
examples/webgl_postprocessing_ssao.html

@@ -79,7 +79,7 @@ Spiral sampling http://web.archive.org/web/20120421191837/http://www.cgafaq.info
 				container = document.createElement( 'div' );
 				container = document.createElement( 'div' );
 				document.body.appendChild( container );
 				document.body.appendChild( container );
 
 
-				renderer = new THREE.WebGLRenderer( { antialias: false } );
+				renderer = new THREE.WebGLRenderer();
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				document.body.appendChild( renderer.domElement );
 				document.body.appendChild( renderer.domElement );
 
 

+ 1 - 1
examples/webgl_postprocessing_taa.html

@@ -107,7 +107,7 @@
 
 
 				var container = document.getElementById( "container" );
 				var container = document.getElementById( "container" );
 
 
-				renderer = new THREE.WebGLRenderer( { antialias: false } );
+				renderer = new THREE.WebGLRenderer();
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				document.body.appendChild( renderer.domElement );
 				document.body.appendChild( renderer.domElement );

+ 1 - 1
examples/webgl_postprocessing_unreal_bloom.html

@@ -96,7 +96,7 @@
 				scene = new THREE.Scene();
 				scene = new THREE.Scene();
 				scene.background = new THREE.Color( 0x111111 );
 				scene.background = new THREE.Color( 0x111111 );
 
 
-				renderer = new THREE.WebGLRenderer( { antialias: false } );
+				renderer = new THREE.WebGLRenderer();
 				renderer.toneMapping = THREE.LinearToneMapping;
 				renderer.toneMapping = THREE.LinearToneMapping;
 
 
 				standardMaterial = new THREE.MeshStandardMaterial( {
 				standardMaterial = new THREE.MeshStandardMaterial( {

+ 83 - 95
examples/webgl_shaders_ocean.html

@@ -34,6 +34,7 @@
 
 
 		<script src="js/controls/OrbitControls.js"></script>
 		<script src="js/controls/OrbitControls.js"></script>
 		<script src="js/objects/Water.js"></script>
 		<script src="js/objects/Water.js"></script>
+		<script src="js/objects/Sky.js"></script>
 
 
 		<script src="js/Detector.js"></script>
 		<script src="js/Detector.js"></script>
 		<script src="js/libs/stats.min.js"></script>
 		<script src="js/libs/stats.min.js"></script>
@@ -45,14 +46,7 @@
 
 
 			var container, stats;
 			var container, stats;
 			var camera, scene, renderer, light;
 			var camera, scene, renderer, light;
-			var controls, water, sphere, cubeMap;
-
-			var parameters = {
-				oceanSide: 2000,
-				size: 1.0,
-				distortionScale: 3.7,
-				alpha: 1.0
-			};
+			var controls, water, sphere;
 
 
 			init();
 			init();
 			animate();
 			animate();
@@ -66,13 +60,11 @@
 				renderer = new THREE.WebGLRenderer();
 				renderer = new THREE.WebGLRenderer();
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				renderer.setSize( window.innerWidth, window.innerHeight );
-				renderer.shadowMap.enabled = true;
 				container.appendChild( renderer.domElement );
 				container.appendChild( renderer.domElement );
 
 
 				//
 				//
 
 
 				scene = new THREE.Scene();
 				scene = new THREE.Scene();
-				scene.fog = new THREE.FogExp2( 0xaabbbb, 0.001 );
 
 
 				//
 				//
 
 
@@ -82,29 +74,77 @@
 				//
 				//
 
 
 				light = new THREE.DirectionalLight( 0xffffff, 0.8 );
 				light = new THREE.DirectionalLight( 0xffffff, 0.8 );
-				light.position.set( - 30, 30, 30 );
-				light.castShadow = true;
-				light.shadow.camera.top = 45;
-				light.shadow.camera.right = 40;
-				light.shadow.camera.left = light.shadow.camera.bottom = -40;
-				light.shadow.camera.near = 1;
-				light.shadow.camera.far = 200;
 				scene.add( light );
 				scene.add( light );
 
 
-				var ambientLight = new THREE.AmbientLight( 0xcccccc, 0.4 );
-				scene.add( ambientLight );
+				// Water
 
 
-				//
+				var waterGeometry = new THREE.PlaneBufferGeometry( 10000, 10000 );
 
 
-				setWater();
+				water = new THREE.Water(
+					waterGeometry,
+					{
+						textureWidth: 512,
+						textureHeight: 512,
+						waterNormals: new THREE.TextureLoader().load( 'textures/waternormals.jpg', function ( texture ) {
+							texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
+						}),
+						alpha: 1.0,
+						sunDirection: light.position.clone().normalize(),
+						sunColor: 0xffffff,
+						waterColor: 0x001e0f,
+						distortionScale:  3.7,
+						fog: scene.fog !== undefined
+					}
+				);
 
 
-				//
+				water.rotation.x = - Math.PI / 2;
 
 
-				setSkybox();
+				scene.add( water );
+
+				// Skybox
+
+				var sky = new THREE.Sky();
+				sky.scale.setScalar( 10000 );
+				scene.add( sky );
+
+				var uniforms = sky.material.uniforms;
+
+				uniforms.turbidity.value = 10;
+				uniforms.rayleigh.value = 2;
+				uniforms.luminance.value = 1;
+				uniforms.mieCoefficient.value = 0.005;
+				uniforms.mieDirectionalG.value = 0.8;
+
+				var parameters = {
+					distance: 400,
+					inclination: 0.49,
+					azimuth: 0.205
+				};
+
+				var cubeCamera = new THREE.CubeCamera( 1, 20000, 256 );
+				cubeCamera.renderTarget.texture.minFilter = THREE.LinearMipMapLinearFilter;
+
+				function updateSun() {
+
+					var theta = Math.PI * ( parameters.inclination - 0.5 );
+					var phi = 2 * Math.PI * ( parameters.azimuth - 0.5 );
+
+					light.position.x = parameters.distance * Math.cos( phi );
+					light.position.y = parameters.distance * Math.sin( phi ) * Math.sin( theta );
+					light.position.z = parameters.distance * Math.sin( phi ) * Math.cos( theta );
+
+					sky.material.uniforms.sunPosition.value = light.position.copy( light.position );
+					water.material.uniforms.sunDirection.value.copy( light.position ).normalize();
+
+					cubeCamera.update( renderer, scene );
+
+				}
+
+				updateSun();
 
 
 				//
 				//
 
 
-				var geometry = new THREE.IcosahedronGeometry( 20, 2 );
+				var geometry = new THREE.IcosahedronGeometry( 20, 1 );
 
 
 				for ( var i = 0, j = geometry.faces.length; i < j; i ++ ) {
 				for ( var i = 0, j = geometry.faces.length; i < j; i ++ ) {
 
 
@@ -112,15 +152,15 @@
 
 
 				}
 				}
 
 
-				var material = new THREE.MeshPhongMaterial( {
+				var material = new THREE.MeshStandardMaterial( {
 					vertexColors: THREE.FaceColors,
 					vertexColors: THREE.FaceColors,
-					shininess: 10,
-					envMap: cubeMap,
+					roughness: 0.0,
+					flatShading: true,
+					envMap: cubeCamera.renderTarget.texture,
 					side: THREE.DoubleSide
 					side: THREE.DoubleSide
 				} );
 				} );
 
 
 				sphere = new THREE.Mesh( geometry, material );
 				sphere = new THREE.Mesh( geometry, material );
-				sphere.castShadow = true;
 				scene.add( sphere );
 				scene.add( sphere );
 
 
 				//
 				//
@@ -128,7 +168,7 @@
 				controls = new THREE.OrbitControls( camera, renderer.domElement );
 				controls = new THREE.OrbitControls( camera, renderer.domElement );
 				controls.maxPolarAngle = Math.PI * 0.495;
 				controls.maxPolarAngle = Math.PI * 0.495;
 				controls.target.set( 0, 10, 0 );
 				controls.target.set( 0, 10, 0 );
-				controls.enablePan = false;
+				controls.panningMode = THREE.HorizontalPanning;
 				controls.minDistance = 40.0;
 				controls.minDistance = 40.0;
 				controls.maxDistance = 200.0;
 				controls.maxDistance = 200.0;
 				camera.lookAt( controls.target );
 				camera.lookAt( controls.target );
@@ -138,77 +178,28 @@
 				stats = new Stats();
 				stats = new Stats();
 				container.appendChild( stats.dom );
 				container.appendChild( stats.dom );
 
 
-				//
+				// GUI
 
 
 				var gui = new dat.GUI();
 				var gui = new dat.GUI();
 
 
-				gui.add( parameters, 'distortionScale', 0, 8, 0.1 );
-				gui.add( parameters, 'size', 0.1, 10, 0.1 );
-				gui.add( parameters, 'alpha', 0.9, 1, .001 );
+				var uniforms = sky.material.uniforms;
 
 
-				//
+				var folder = gui.addFolder( 'Sky' );
+				folder.add( parameters, 'inclination', 0, 0.5, 0.0001 ).onChange( updateSun );
+				folder.add( parameters, 'azimuth', 0, 1, 0.0001 ).onChange( updateSun );
+				folder.open();
 
 
-				window.addEventListener( 'resize', onWindowResize, false );
-
-			}
-
-			function setWater() {
-
-				var waterGeometry = new THREE.PlaneBufferGeometry( parameters.oceanSide * 5, parameters.oceanSide * 5 );
-
-				water = new THREE.Water(
-					waterGeometry,
-					{
-						textureWidth: 512,
-						textureHeight: 512,
-						waterNormals: new THREE.TextureLoader().load( 'textures/waternormals.jpg', function ( texture ) {
-							texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
-						}),
-						alpha: parameters.alpha,
-						sunDirection: light.position.clone().normalize(),
-						sunColor: 0xffffff,
-						waterColor: 0x001e0f,
-						distortionScale: parameters.distortionScale,
-						fog: scene.fog !== undefined
-					}
-				);
-
-				water.rotation.x = - Math.PI / 2;
-				water.receiveShadow = true;
-
-				scene.add( water );
-
-			}
+				var uniforms = water.material.uniforms;
 
 
-			function setSkybox() {
+				var folder = gui.addFolder( 'Water' );
+				folder.add( uniforms.distortionScale, 'value', 0, 8, 0.1 ).name( 'distortionScale' );
+				folder.add( uniforms.size, 'value', 0.1, 10, 0.1 ).name( 'size' );
+				folder.add( uniforms.alpha, 'value', 0.9, 1, .001 ).name( 'alpha' );
+				folder.open();
 
 
-				var cubeTextureLoader = new THREE.CubeTextureLoader();
-				cubeTextureLoader.setPath( 'textures/cube/skyboxsun25deg/' );
-
-				cubeMap = cubeTextureLoader.load( [
-					'px.jpg', 'nx.jpg',
-					'py.jpg', 'ny.jpg',
-					'pz.jpg', 'nz.jpg',
-				] );
-
-				var cubeShader = THREE.ShaderLib[ 'cube' ];
-				cubeShader.uniforms[ 'tCube' ].value = cubeMap;
-
-				var skyBoxMaterial = new THREE.ShaderMaterial( {
-					fragmentShader: cubeShader.fragmentShader,
-					vertexShader: cubeShader.vertexShader,
-					uniforms: cubeShader.uniforms,
-					side: THREE.BackSide
-				} );
-
-				var skyBoxGeometry = new THREE.BoxBufferGeometry(
-					parameters.oceanSide * 5 + 100,
-					parameters.oceanSide * 5 + 100,
-					parameters.oceanSide * 5 + 100 );
-
-				var skyBox = new THREE.Mesh( skyBoxGeometry, skyBoxMaterial );
+				//
 
 
-				scene.add( skyBox );
+				window.addEventListener( 'resize', onWindowResize, false );
 
 
 			}
 			}
 
 
@@ -238,9 +229,6 @@
 				sphere.rotation.z = time * 0.51;
 				sphere.rotation.z = time * 0.51;
 
 
 				water.material.uniforms.time.value += 1.0 / 60.0;
 				water.material.uniforms.time.value += 1.0 / 60.0;
-				water.material.uniforms.size.value = parameters.size;
-				water.material.uniforms.distortionScale.value = parameters.distortionScale;
-				water.material.uniforms.alpha.value = parameters.alpha;
 
 
 				renderer.render( scene, camera );
 				renderer.render( scene, camera );
 
 

+ 1 - 1
examples/webgl_shadowmap_performance.html

@@ -120,7 +120,7 @@
 
 
 				// RENDERER
 				// RENDERER
 
 
-				renderer = new THREE.WebGLRenderer( { antialias: false } );
+				renderer = new THREE.WebGLRenderer();
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT );
 				renderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT );
 				container.appendChild( renderer.domElement );
 				container.appendChild( renderer.domElement );

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