Mr.doob 5 years ago
parent
commit
4fb9818fd4
100 changed files with 2855 additions and 8339 deletions
  1. 112 62
      build/three.js
  2. 150 321
      build/three.min.js
  3. 111 61
      build/three.module.js
  4. 7 0
      docs/api/en/core/BufferGeometry.html
  5. 3 3
      docs/api/en/core/Object3D.html
  6. 3 1
      docs/api/en/core/Raycaster.html
  7. 6 2
      docs/api/en/materials/Material.html
  8. 2 1
      docs/api/en/math/Box2.html
  9. 4 1
      docs/api/en/math/Box3.html
  10. 2 1
      docs/api/en/math/Frustum.html
  11. 1 1
      docs/api/en/math/Plane.html
  12. 3 4
      docs/api/en/math/Ray.html
  13. 2 1
      docs/api/en/math/Sphere.html
  14. 2 2
      docs/api/en/math/Spherical.html
  15. 2 1
      docs/api/en/math/Triangle.html
  16. 3 0
      docs/api/en/math/Vector3.html
  17. 11 0
      docs/api/en/objects/InstancedMesh.html
  18. 1 1
      docs/api/zh/core/Geometry.html
  19. 3 1
      docs/api/zh/core/Raycaster.html
  20. 6 2
      docs/api/zh/materials/Material.html
  21. 3 3
      docs/api/zh/math/Ray.html
  22. 11 0
      docs/api/zh/objects/InstancedMesh.html
  23. 9 1
      docs/examples/en/loaders/DRACOLoader.html
  24. 2 1
      docs/examples/en/loaders/GLTFLoader.html
  25. 1 1
      docs/examples/en/loaders/MTLLoader.html
  26. 9 1
      docs/examples/zh/loaders/DRACOLoader.html
  27. 3 2
      docs/examples/zh/loaders/GLTFLoader.html
  28. 16 15
      docs/manual/en/introduction/How-to-create-VR-content.html
  29. 16 15
      docs/manual/zh/introduction/How-to-create-VR-content.html
  30. 13 0
      docs/prettify/threejs.css
  31. 0 1
      editor/index.html
  32. 1 1
      editor/js/Loader.js
  33. 6 6
      editor/js/Menubar.Examples.js
  34. 1 0
      editor/js/Sidebar.Material.js
  35. 10 0
      editor/js/Strings.js
  36. 1 2
      editor/sw.js
  37. 0 5
      examples/css3d_molecules.html
  38. 15 14
      examples/files.js
  39. 25 2
      examples/js/controls/DeviceOrientationControls.js
  40. 95 105
      examples/js/effects/OutlineEffect.js
  41. 12 8
      examples/js/exporters/GLTFExporter.js
  42. 1 1
      examples/js/exporters/OBJExporter.js
  43. 2 2
      examples/js/exporters/PLYExporter.js
  44. 3 1
      examples/js/lines/LineMaterial.js
  45. 192 8
      examples/js/loaders/3MFLoader.js
  46. 8 0
      examples/js/loaders/DRACOLoader.js
  47. 292 92
      examples/js/loaders/EXRLoader.js
  48. 12 14
      examples/js/loaders/FBXLoader.js
  49. 88 114
      examples/js/loaders/GLTFLoader.js
  50. 2 0
      examples/js/loaders/LWOLoader.js
  51. 1 0
      examples/js/loaders/MD2Loader.js
  52. 1 0
      examples/js/loaders/MMDLoader.js
  53. 9 0
      examples/js/loaders/OBJLoader.js
  54. 0 3
      examples/js/loaders/PCDLoader.js
  55. 279 59
      examples/js/loaders/VRMLLoader.js
  56. 0 2219
      examples/js/loaders/deprecated/LegacyGLTFLoader.js
  57. 0 821
      examples/js/loaders/deprecated/LegacyJSONLoader.js
  58. 2 0
      examples/js/pmrem/PMREMGenerator.js
  59. 7 3
      examples/js/renderers/CSS2DRenderer.js
  60. 1 1
      examples/js/renderers/CSS3DRenderer.js
  61. 14 3
      examples/js/renderers/Projector.js
  62. 1 1
      examples/js/renderers/SVGRenderer.js
  63. 4 0
      examples/js/utils/BufferGeometryUtils.js
  64. 13 155
      examples/js/vr/HelioWebXRPolyfill.js
  65. 0 184
      examples/js/vr/PaintViveController.js
  66. 0 128
      examples/js/vr/ViveController.js
  67. 3 1
      examples/js/vr/WebVR.js
  68. 0 118
      examples/js/vr/deprecated/DaydreamController.js
  69. 0 132
      examples/js/vr/deprecated/GearVRController.js
  70. 25 2
      examples/jsm/controls/DeviceOrientationControls.js
  71. 98 107
      examples/jsm/effects/OutlineEffect.js
  72. 12 8
      examples/jsm/exporters/GLTFExporter.js
  73. 1 1
      examples/jsm/exporters/OBJExporter.js
  74. 2 2
      examples/jsm/exporters/PLYExporter.js
  75. 3 1
      examples/jsm/lines/LineMaterial.js
  76. 195 8
      examples/jsm/loaders/3MFLoader.js
  77. 1 0
      examples/jsm/loaders/DRACOLoader.d.ts
  78. 8 0
      examples/jsm/loaders/DRACOLoader.js
  79. 293 92
      examples/jsm/loaders/EXRLoader.js
  80. 12 14
      examples/jsm/loaders/FBXLoader.js
  81. 91 114
      examples/jsm/loaders/GLTFLoader.js
  82. 2 0
      examples/jsm/loaders/LWOLoader.js
  83. 1 0
      examples/jsm/loaders/MD2Loader.js
  84. 1 0
      examples/jsm/loaders/MMDLoader.js
  85. 9 0
      examples/jsm/loaders/OBJLoader.js
  86. 0 3
      examples/jsm/loaders/PCDLoader.js
  87. 282 59
      examples/jsm/loaders/VRMLLoader.js
  88. 0 23
      examples/jsm/loaders/deprecated/LegacyGLTFLoader.d.ts
  89. 0 2311
      examples/jsm/loaders/deprecated/LegacyGLTFLoader.js
  90. 0 21
      examples/jsm/loaders/deprecated/LegacyJSONLoader.d.ts
  91. 0 851
      examples/jsm/loaders/deprecated/LegacyJSONLoader.js
  92. 1 1
      examples/jsm/misc/MorphAnimMesh.d.ts
  93. 170 0
      examples/jsm/misc/TubePainter.js
  94. 1 1
      examples/jsm/misc/Volume.d.ts
  95. 4 3
      examples/jsm/nodes/materials/NodeMaterial.js
  96. 1 1
      examples/jsm/nodes/materials/nodes/MeshStandardNode.d.ts
  97. 2 0
      examples/jsm/pmrem/PMREMGenerator.js
  98. 7 3
      examples/jsm/renderers/CSS2DRenderer.js
  99. 1 1
      examples/jsm/renderers/CSS3DRenderer.js
  100. 14 3
      examples/jsm/renderers/Projector.js

File diff suppressed because it is too large
+ 112 - 62
build/three.js


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


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


+ 7 - 0
docs/api/en/core/BufferGeometry.html

@@ -144,6 +144,13 @@
 			Hashmap of [page:BufferAttribute]s holding details of the geometry's [page:Geometry.morphTargets morphTargets].
 			Hashmap of [page:BufferAttribute]s holding details of the geometry's [page:Geometry.morphTargets morphTargets].
 		</p>
 		</p>
 
 
+		<h3>[property:Boolean morphTargetsRelative]</h3>
+		<p>
+			Used to control the morph target behavior; when set to true, the morph target data is treated as relative offsets, rather than as absolute positions/normals.
+
+			Default is *false*.
+		</p>
+
 		<h3>[property:String name]</h3>
 		<h3>[property:String name]</h3>
 		<p>
 		<p>
 		Optional name for this bufferGeometry instance. Default is an empty string.
 		Optional name for this bufferGeometry instance. Default is an empty string.

+ 3 - 3
docs/api/en/core/Object3D.html

@@ -240,7 +240,7 @@
 		<p>
 		<p>
 		id -- Unique number of the object instance<br /><br />
 		id -- Unique number of the object instance<br /><br />
 
 
-		Searches through the object's children and returns the first with a matching id.<br />
+		Searches through an object and its children, starting with the object itself, and returns the first with a matching id.<br />
 		Note that ids are assigned in chronological order: 1, 2, 3, ..., incrementing by one for each new object.
 		Note that ids are assigned in chronological order: 1, 2, 3, ..., incrementing by one for each new object.
 		</p>
 		</p>
 
 
@@ -248,7 +248,7 @@
 		<p>
 		<p>
 		name -- String to match to the children's Object3D.name property. <br /><br />
 		name -- String to match to the children's Object3D.name property. <br /><br />
 
 
-		Searches through the object's children and returns the first with a matching name.<br />
+		Searches through an object and its children, starting with the object itself, and returns the first with a matching name.<br />
 		Note that for most objects the name is an empty string by default. You will
 		Note that for most objects the name is an empty string by default. You will
 		have to set it manually to make use of this method.
 		have to set it manually to make use of this method.
 		</p>
 		</p>
@@ -258,7 +258,7 @@
 		name -- the property name to search for. <br />
 		name -- the property name to search for. <br />
 		value -- value of the given property. <br /><br />
 		value -- value of the given property. <br /><br />
 
 
-		Searches through the object's children and returns the first with a property that matches the value given.
+		Searches through an object and its children, starting with the object itself, and returns the first with a property that matches the value given.
 		</p>
 		</p>
 
 
 		<h3>[method:Vector3 getWorldPosition]( [param:Vector3 target] )</h3>
 		<h3>[method:Vector3 getWorldPosition]( [param:Vector3 target] )</h3>

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

@@ -58,6 +58,7 @@
 			Examples: [example:webgl_interactive_cubes Raycasting to a Mesh]<br />
 			Examples: [example:webgl_interactive_cubes Raycasting to a Mesh]<br />
 			[example:webgl_interactive_cubes_ortho Raycasting to a Mesh in using an OrthographicCamera]<br />
 			[example:webgl_interactive_cubes_ortho Raycasting to a Mesh in using an OrthographicCamera]<br />
 			[example:webgl_interactive_buffergeometry Raycasting to a Mesh with BufferGeometry]<br />
 			[example:webgl_interactive_buffergeometry Raycasting to a Mesh with BufferGeometry]<br />
+			[example:webgl_instancing_raycast Raycasting to a InstancedMesh]<br />
 			[example:webgl_interactive_lines Raycasting to a Line]<br />
 			[example:webgl_interactive_lines Raycasting to a Line]<br />
 			[example:webgl_interactive_raycasting_points Raycasting to Points]<br />
 			[example:webgl_interactive_raycasting_points Raycasting to Points]<br />
 			[example:webgl_geometry_terrain_raycast Terrain raycasting]<br />
 			[example:webgl_geometry_terrain_raycast Terrain raycasting]<br />
@@ -170,7 +171,8 @@
 			[page:Integer faceIndex] – index of the intersected face<br />
 			[page:Integer faceIndex] – index of the intersected face<br />
 			[page:Object3D object] – the intersected object<br />
 			[page:Object3D object] – the intersected object<br />
 			[page:Vector2 uv] - U,V coordinates at point of intersection<br />
 			[page:Vector2 uv] - U,V coordinates at point of intersection<br />
-			[page:Vector2 uv2] - Second set of U,V coordinates at point of intersection
+			[page:Vector2 uv2] - Second set of U,V coordinates at point of intersection<br />
+			[page:Integer instanceId] – The index number of the instance where the ray intersects the InstancedMesh
 		</p>
 		</p>
 		<p>
 		<p>
 		*Raycaster* delegates to the [page:Object3D.raycast raycast] method of the passed object, when evaluating whether the ray intersects the object or not. This allows [page:Mesh meshes] to respond differently to ray casting than [page:Line lines] and [page:Points pointclouds].
 		*Raycaster* delegates to the [page:Object3D.raycast raycast] method of the passed object, when evaluating whether the ray intersects the object or not. This allows [page:Mesh meshes] to respond differently to ray casting than [page:Line lines] and [page:Points pointclouds].

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

@@ -186,8 +186,7 @@
 
 
 		<h3>[property:Boolean needsUpdate]</h3>
 		<h3>[property:Boolean needsUpdate]</h3>
 		<p>
 		<p>
-		Specifies that the material needs to be recompiled.<br />
-		This property is automatically set to *true* when instancing a new material.
+		Specifies that the material needs to be recompiled.
 		</p>
 		</p>
 
 
 		<h3>[property:Float opacity]</h3>
 		<h3>[property:Float opacity]</h3>
@@ -296,6 +295,11 @@
 		This gets automatically assigned, so this shouldn't be edited.
 		This gets automatically assigned, so this shouldn't be edited.
 		</p>
 		</p>
 
 
+		<h3>[property:Integer version]</h3>
+		<p>
+		This starts at *0* and counts how many times [property:Boolean needsUpdate] is set to *true*.
+		</p>
+
 		<h3>[property:Integer vertexColors]</h3>
 		<h3>[property:Integer vertexColors]</h3>
 		<p>
 		<p>
 		Defines whether vertex coloring is used.
 		Defines whether vertex coloring is used.

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

@@ -174,7 +174,8 @@
 			[page:Vector2 min] - (required ) [page:Vector2] representing the lower (x, y) boundary of the box. <br>
 			[page:Vector2 min] - (required ) [page:Vector2] representing the lower (x, y) boundary of the box. <br>
 			[page:Vector2 max]  - (required) [page:Vector2] representing the upper (x, y) boundary of the box. <br /><br />
 			[page:Vector2 max]  - (required) [page:Vector2] representing the upper (x, y) boundary of the box. <br /><br />
 
 
-			Sets the lower and upper (x, y) boundaries of this box.
+			Sets the lower and upper (x, y) boundaries of this box.<br>
+			Please note that this method only copies the values from the given objects.
 		</p>
 		</p>
 
 
 		<h3>[method:Box2 setFromCenterAndSize]( [param:Vector2 center], [param:Vector2 size] )</h3>
 		<h3>[method:Box2 setFromCenterAndSize]( [param:Vector2 center], [param:Vector2 size] )</h3>

+ 4 - 1
docs/api/en/math/Box3.html

@@ -138,6 +138,7 @@
 
 
 		Expands the boundaries of this box to include [page:Object3D object] and its children,
 		Expands the boundaries of this box to include [page:Object3D object] and its children,
 		accounting for the object's, and children's, world transforms.
 		accounting for the object's, and children's, world transforms.
+		The function may result in a larger box than strictly necessary.
 
 
 		</p>
 		</p>
 
 
@@ -247,7 +248,8 @@
 		[page:Vector3 min] - [page:Vector3] representing the lower (x, y, z) boundary of the box.<br />
 		[page:Vector3 min] - [page:Vector3] representing the lower (x, y, z) boundary of the box.<br />
 		[page:Vector3 max] - [page:Vector3] representing the lower upper (x, y, z) boundary of the box.<br /><br />
 		[page:Vector3 max] - [page:Vector3] representing the lower upper (x, y, z) boundary of the box.<br /><br />
 
 
-		Sets the lower and upper (x, y, z) boundaries of this box.
+		Sets the lower and upper (x, y, z) boundaries of this box.<br>
+		Please note that this method only copies the values from the given objects.
 		</p>
 		</p>
 
 
 		<h3>[method:Box3 setFromArray]( [param:Array array] ) [param:Box3 this]</h3>
 		<h3>[method:Box3 setFromArray]( [param:Array array] ) [param:Box3 this]</h3>
@@ -279,6 +281,7 @@
 
 
 		Computes the world-axis-aligned bounding box of an [page:Object3D] (including its children),
 		Computes the world-axis-aligned bounding box of an [page:Object3D] (including its children),
 		accounting for the object's, and children's, world transforms.
 		accounting for the object's, and children's, world transforms.
+		The function may result in a larger box than strictly necessary.
 
 
 		</p>
 		</p>
 
 

+ 2 - 1
docs/api/en/math/Frustum.html

@@ -91,7 +91,8 @@
 
 
 		<h3>[method:Frustum set]( [param:Plane p0], [param:Plane p1], [param:Plane p2], [param:Plane p3], [param:Plane p4], [param:Plane p5] )</h3>
 		<h3>[method:Frustum set]( [param:Plane p0], [param:Plane p1], [param:Plane p2], [param:Plane p3], [param:Plane p4], [param:Plane p5] )</h3>
 		<p>
 		<p>
-		Sets the current frustum from the passed planes. No plane order is implicitely implied.
+		Sets the current frustum from the passed planes. No plane order is implicitely implied.<br>
+		Please note that this method only copies the values from the given objects.
 		</p>
 		</p>
 
 
 		<h3>[method:Frustum setFromMatrix]( [param:Matrix4 matrix] )</h3>
 		<h3>[method:Frustum setFromMatrix]( [param:Matrix4 matrix] )</h3>

+ 1 - 1
docs/api/en/math/Plane.html

@@ -130,7 +130,7 @@
 			[page:Vector3 normal] - a unit length [page:Vector3] defining the normal of the plane.<br />
 			[page:Vector3 normal] - a unit length [page:Vector3] defining the normal of the plane.<br />
 			[page:Float constant] - the signed distance from the origin to the plane. Default is *0*.<br /><br />
 			[page:Float constant] - the signed distance from the origin to the plane. Default is *0*.<br /><br />
 
 
-			 Sets the plane's [page:.normal normal] and [page:.constant constant] properties.
+			Sets this plane's [page:.normal normal] and [page:.constant constant] properties by copying the values from the given normal.
 		</p>
 		</p>
 
 
 		<h3>[method:Plane setComponents]( [param:Float x], [param:Float y], [param:Float z], [param:Float w] )</h3>
 		<h3>[method:Plane setComponents]( [param:Float x], [param:Float y], [param:Float z], [param:Float w] )</h3>

+ 3 - 4
docs/api/en/math/Ray.html

@@ -25,7 +25,7 @@
 		<p>
 		<p>
 		[page:Vector3 origin] - (optional) the origin of the [page:Ray]. Default is a [page:Vector3] at (0, 0, 0).<br />
 		[page:Vector3 origin] - (optional) the origin of the [page:Ray]. Default is a [page:Vector3] at (0, 0, 0).<br />
 		[page:Vector3 direction] - [page:Vector3] The direction of the [page:Ray]. This must be normalized
 		[page:Vector3 direction] - [page:Vector3] The direction of the [page:Ray]. This must be normalized
-		 (with [page:Vector3.normalize]) for the methods to operate properly.  Default is a [page:Vector3] at (0, 0, 0).<br /><br />
+		 (with [page:Vector3.normalize]) for the methods to operate properly.  Default is a [page:Vector3] at (0, 0, -1).<br /><br />
 
 
 		Creates a new [name].
 		Creates a new [name].
 		</p>
 		</p>
@@ -38,7 +38,7 @@
 		<h3>[property:Vector3 direction]</h3>
 		<h3>[property:Vector3 direction]</h3>
 		<p>
 		<p>
 		The direction of the [page:Ray]. This must be normalized (with [page:Vector3.normalize])
 		The direction of the [page:Ray]. This must be normalized (with [page:Vector3.normalize])
-		for the methods to operate properly. Default is a [page:Vector3] at (0, 0, 0).
+		for the methods to operate properly. Default is a [page:Vector3] at (0, 0, -1).
 		</p>
 		</p>
 
 
 
 
@@ -201,8 +201,7 @@
 		This must be normalized (with [page:Vector3.normalize]) for the methods to operate
 		This must be normalized (with [page:Vector3.normalize]) for the methods to operate
 		properly.<br /><br />
 		properly.<br /><br />
 
 
-		Copy the parameters to the [page:.origin origin] and [page:.direction direction] properties
-		of this ray.
+		Sets this ray's [page:.origin origin] and [page:.direction direction] properties by copying the values from the given objects.
 		</p>
 		</p>
 
 
 
 

+ 2 - 1
docs/api/en/math/Sphere.html

@@ -114,7 +114,8 @@
 			[page:Vector3 center] - center of the sphere.<br />
 			[page:Vector3 center] - center of the sphere.<br />
 			[page:Float radius] - radius of the sphere.<br /><br />
 			[page:Float radius] - radius of the sphere.<br /><br />
 
 
-		Sets the [page:.center center] and [page:.radius radius] properties of this sphere.
+		Sets the [page:.center center] and [page:.radius radius] properties of this sphere.<br>
+		Please note that this method only copies the values from the given center.
 		</p>
 		</p>
 
 
 		<h3>[method:Sphere setFromPoints]( [param:Array points], [param:Vector3 optionalCenter] )</h3>
 		<h3>[method:Sphere setFromPoints]( [param:Array points], [param:Vector3 optionalCenter] )</h3>

+ 2 - 2
docs/api/en/math/Spherical.html

@@ -20,8 +20,8 @@
 		<p>
 		<p>
 		[page:Float radius] - the radius, or the [link:https://en.wikipedia.org/wiki/Euclidean_distance Euclidean distance]
 		[page:Float radius] - the radius, or the [link:https://en.wikipedia.org/wiki/Euclidean_distance Euclidean distance]
 		(straight-line distance) from the point to the origin. Default is *1.0*.<br />
 		(straight-line distance) from the point to the origin. Default is *1.0*.<br />
-		[page:Float phi] - polar angle from the y (up) axis. Default is *0*.<br />
-		[page:Float theta] - equator angle around the y (up) axis. Default is *0*.<br /><br />
+		[page:Float phi] - polar angle in radians from the y (up) axis. Default is *0*.<br />
+		[page:Float theta] - equator angle in radians around the y (up) axis. Default is *0*.<br /><br />
 
 
 		The poles (phi) are at the positive and negative y axis. The equator (theta) starts at positive z.
 		The poles (phi) are at the positive and negative y axis. The equator (theta) starts at positive z.
 		</p>
 		</p>

+ 2 - 1
docs/api/en/math/Triangle.html

@@ -123,7 +123,8 @@
 
 
 		<h3>[method:Triangle set]( [param:Vector3 a], [param:Vector3 b], [param:Vector3 c] ) [param:Triangle this]</h3>
 		<h3>[method:Triangle set]( [param:Vector3 a], [param:Vector3 b], [param:Vector3 c] ) [param:Triangle this]</h3>
 		<p>
 		<p>
-		Sets the triangle's [page:.a a], [page:.b b] and [page:.c c] properties to the passed [page:vector3 vector3s].
+		Sets the triangle's [page:.a a], [page:.b b] and [page:.c c] properties to the passed [page:vector3 vector3s].<br>
+		Please note that this method only copies the values from the given objects.
 		</p>
 		</p>
 
 
 		<h3>[method:Triangle setFromPointsAndIndices]( [param:Array points], [param:Integer i0], [param:Integer i1], [param:Integer i2] ) [param:Triangle this]</h3>
 		<h3>[method:Triangle setFromPointsAndIndices]( [param:Array points], [param:Integer i0], [param:Integer i1], [param:Integer i2] ) [param:Triangle this]</h3>

+ 3 - 0
docs/api/en/math/Vector3.html

@@ -113,6 +113,9 @@ var d = a.distanceTo( b );
 		Multiplies this vector (with an implicit 1 in the 4th dimension) and m, and divides by perspective.
 		Multiplies this vector (with an implicit 1 in the 4th dimension) and m, and divides by perspective.
 		</p>
 		</p>
 
 
+		<h3>[method:this applyNormalMatrix]( [param:Matrix3 m] )</h3>
+		<p>Multiplies this vector by normal matrix [page:Matrix3 m] and normalizes the result.</p>
+
 		<h3>[method:this applyQuaternion]( [param:Quaternion quaternion] )</h3>
 		<h3>[method:this applyQuaternion]( [param:Quaternion quaternion] )</h3>
 		<p>
 		<p>
 		Applies a [page:Quaternion] transform to this vector.
 		Applies a [page:Quaternion] transform to this vector.

+ 11 - 0
docs/api/en/objects/InstancedMesh.html

@@ -53,6 +53,17 @@
 		<h2>Methods</h2>
 		<h2>Methods</h2>
 		<p>See the base [page:Mesh] class for common methods.</p>
 		<p>See the base [page:Mesh] class for common methods.</p>
 
 
+		<h3>[method:null getMatrixAt]( [param:Integer index], [param:Matrix4 matrix] )</h3>
+		<p>
+			[page:Integer index]: The index of an instance. Values have to be in the range [0, count].
+		</p>
+		<p>
+			[page:Matrix4 matrix]: This 4x4 matrix will be set to the local transformation matrix of the defined instance.
+		</p>
+		<p>
+			Get the local transformation matrix of the defined instance.
+		</p>
+
 		<h3>[method:null setMatrixAt]( [param:Integer index], [param:Matrix4 matrix] )</h3>
 		<h3>[method:null setMatrixAt]( [param:Integer index], [param:Matrix4 matrix] )</h3>
 		<p>
 		<p>
 			[page:Integer index]: The index of an instance. Values have to be in the range [0, count].
 			[page:Integer index]: The index of an instance. Values have to be in the range [0, count].

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

@@ -12,7 +12,7 @@
 
 
 		<div class="desc">
 		<div class="desc">
 		<p>
 		<p>
-			Geometry 是对 [page:BufferGeometry] 的用户有好替代。Geometry 利用 [page:Vector3]
+			Geometry 是一个便于用户使用的 [page:BufferGeometry] 的替代品。Geometry 利用 [page:Vector3]
 			或 [page:Color] 存储了几何体的相关 attributes(如顶点位置,面信息,颜色等)比起 BufferGeometry
 			或 [page:Color] 存储了几何体的相关 attributes(如顶点位置,面信息,颜色等)比起 BufferGeometry
 			更容易读写,但是运行效率不如有类型的队列。
 			更容易读写,但是运行效率不如有类型的队列。
 		</p>
 		</p>

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

@@ -56,6 +56,7 @@
 			其它示例:<br>[example:webgl_interactive_cubes Raycasting to a Mesh]<br />
 			其它示例:<br>[example:webgl_interactive_cubes Raycasting to a Mesh]<br />
 			[example:webgl_interactive_cubes_ortho Raycasting to a Mesh in using an OrthographicCamera]<br />
 			[example:webgl_interactive_cubes_ortho Raycasting to a Mesh in using an OrthographicCamera]<br />
 			[example:webgl_interactive_buffergeometry Raycasting to a Mesh with BufferGeometry]<br />
 			[example:webgl_interactive_buffergeometry Raycasting to a Mesh with BufferGeometry]<br />
+			[example:webgl_instancing_raycast Raycasting to a InstancedMesh]<br />
 			[example:webgl_interactive_lines Raycasting to a Line]<br />
 			[example:webgl_interactive_lines Raycasting to a Line]<br />
 			[example:webgl_interactive_raycasting_points Raycasting to Points]<br />
 			[example:webgl_interactive_raycasting_points Raycasting to Points]<br />
 			[example:webgl_geometry_terrain_raycast Terrain raycasting]<br />
 			[example:webgl_geometry_terrain_raycast Terrain raycasting]<br />
@@ -170,7 +171,8 @@
 			[page:Integer faceIndex] —— 相交的面的索引<br />
 			[page:Integer faceIndex] —— 相交的面的索引<br />
 			[page:Object3D object] —— 相交的物体<br />
 			[page:Object3D object] —— 相交的物体<br />
 			[page:Vector2 uv] —— 相交部分的点的UV坐标。<br />
 			[page:Vector2 uv] —— 相交部分的点的UV坐标。<br />
-			[page:Vector2 uv2] —— Second set of U,V coordinates at point of intersection
+			[page:Vector2 uv2] —— Second set of U,V coordinates at point of intersection<br />
+			[page:Integer instanceId] – The index number of the instance where the ray intersects the InstancedMesh
 		</p>
 		</p>
 		<p>
 		<p>
 			当计算这条射线是否和物体相交的时候,*Raycaster*将传入的对象委托给[page:Object3D.raycast raycast]方法。
 			当计算这条射线是否和物体相交的时候,*Raycaster*将传入的对象委托给[page:Object3D.raycast raycast]方法。

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

@@ -163,8 +163,7 @@ Which stencil operation to perform when the comparison function returns true and
 <p>对象的可选名称(不必是唯一的)。默认值为空字符串。</p>
 <p>对象的可选名称(不必是唯一的)。默认值为空字符串。</p>
 
 
 <h3>[property:Boolean needsUpdate]</h3>
 <h3>[property:Boolean needsUpdate]</h3>
-<p>指定需要重新编译材质。<br/>
-	实例化新材质时,此属性自动设置为true。
+<p>指定需要重新编译材质。
 </p>
 </p>
 
 
 <h3>[property:Float opacity]</h3>
 <h3>[property:Float opacity]</h3>
@@ -255,6 +254,11 @@ Defines whether this material is tone mapped according to the renderer's [page:W
 <p> 此材质实例的[link:http://en.wikipedia.org/wiki/Universally_unique_identifier UUID],会自动分配,不应该被更改。
 <p> 此材质实例的[link:http://en.wikipedia.org/wiki/Universally_unique_identifier UUID],会自动分配,不应该被更改。
 </p>
 </p>
 
 
+<h3>[property:Integer version]</h3>
+<p>
+This starts at *0* and counts how many times [property:Boolean needsUpdate] is set to *true*.
+</p>
+
 <h3>[property:Integer vertexColors]</h3>
 <h3>[property:Integer vertexColors]</h3>
 <p> 是否使用顶点着色。默认值为[page:Materials THREE.NoColors]。
 <p> 是否使用顶点着色。默认值为[page:Materials THREE.NoColors]。
 	其他选项有[page:Materials THREE.VertexColors] 和 [page:Materials THREE.FaceColors]。
 	其他选项有[page:Materials THREE.VertexColors] 和 [page:Materials THREE.FaceColors]。

+ 3 - 3
docs/api/zh/math/Ray.html

@@ -24,7 +24,7 @@
 		<p>
 		<p>
 		[page:Vector3 origin] - (可选)[page:Ray](射线)的原点,默认值是一个位于(0, 0, 0)的[page:Vector3]。<br />
 		[page:Vector3 origin] - (可选)[page:Ray](射线)的原点,默认值是一个位于(0, 0, 0)的[page:Vector3]。<br />
 		[page:Vector3 direction] - [page:Vector3] [page:Ray](射线)的方向。该向量必须经过标准化(使用[page:Vector3.normalize]),这样才能使方法正常运行。
 		[page:Vector3 direction] - [page:Vector3] [page:Ray](射线)的方向。该向量必须经过标准化(使用[page:Vector3.normalize]),这样才能使方法正常运行。
-		默认值是一个位于(0, 0, 0)的[page:Vector3]。<br /><br />
+		默认值是一个位于(0, 0, -1)的[page:Vector3]。<br /><br />
 
 
 		创建一个新的[name]。
 		创建一个新的[name]。
 		</p>
 		</p>
@@ -37,7 +37,7 @@
 		<h3>[property:Vector3 direction]</h3>
 		<h3>[property:Vector3 direction]</h3>
 		<p>
 		<p>
 		[page:Ray](射线)的方向。该向量必须经过标准化(使用[page:Vector3.normalize]),这样才能使方法正常运行。
 		[page:Ray](射线)的方向。该向量必须经过标准化(使用[page:Vector3.normalize]),这样才能使方法正常运行。
-		默认值是一个位于(0, 0, 0)的[page:Vector3]。
+		默认值是一个位于(0, 0, -1)的[page:Vector3]。
 		</p>
 		</p>
 
 
 
 
@@ -190,7 +190,7 @@
 		<p>
 		<p>
 		[page:Vector3 origin] - [page:Ray](射线)的[page:.origin origin](原点)。<br />
 		[page:Vector3 origin] - [page:Ray](射线)的[page:.origin origin](原点)。<br />
 		[page:Vector3 origin] - [page:Ray](射线)的[page:.direction direction](方向)。
 		[page:Vector3 origin] - [page:Ray](射线)的[page:.direction direction](方向)。
-		
+
 		该向量必须经过标准化(使用[page:Vector3.normalize]),这样才能使方法正常运行。
 		该向量必须经过标准化(使用[page:Vector3.normalize]),这样才能使方法正常运行。
 		<br /><br />
 		<br /><br />
 
 

+ 11 - 0
docs/api/zh/objects/InstancedMesh.html

@@ -53,6 +53,17 @@
 		<h2>Methods</h2>
 		<h2>Methods</h2>
 		<p>See the base [page:Mesh] class for common methods.</p>
 		<p>See the base [page:Mesh] class for common methods.</p>
 
 
+		<h3>[method:null getMatrixAt]( [param:Integer index], [param:Matrix4 matrix] )</h3>
+		<p>
+			[page:Integer index]: The index of an instance. Values have to be in the range [0, count].
+		</p>
+		<p>
+			[page:Matrix4 matrix]: This 4x4 matrix will be set to the local transformation matrix of the defined instance.
+		</p>
+		<p>
+			Get the local transformation matrix of the defined instance.
+		</p>
+
 		<h3>[method:null setMatrixAt]( [param:Integer index], [param:Matrix4 matrix] )</h3>
 		<h3>[method:null setMatrixAt]( [param:Integer index], [param:Matrix4 matrix] )</h3>
 		<p>
 		<p>
 			[page:Integer index]: The index of an instance. Values have to be in the range [0, count].
 			[page:Integer index]: The index of an instance. Values have to be in the range [0, count].

+ 9 - 1
docs/examples/en/loaders/DRACOLoader.html

@@ -34,7 +34,10 @@
 		var loader = new THREE.DRACOLoader();
 		var loader = new THREE.DRACOLoader();
 
 
 		// Specify path to a folder containing WASM/JS decoding libraries.
 		// Specify path to a folder containing WASM/JS decoding libraries.
-		loader.setDecoderPath( '/examples/js/libs/draco' );
+		loader.setDecoderPath( '/examples/js/libs/draco/' );
+
+		// Optional: Pre-fetch Draco WASM/JS module.
+		loader.preload();
 
 
 		// Load a Draco geometry
 		// Load a Draco geometry
 		loader.load(
 		loader.load(
@@ -128,6 +131,11 @@
 		in the application.
 		in the application.
 		</p>
 		</p>
 
 
+		<h3>[method:this preload]()</h3>
+		<p>
+		Requests the decoder libraries, if not already loaded.
+		</p>
+
 		<h3>[method:this dispose]()</h3>
 		<h3>[method:this dispose]()</h3>
 		<p>
 		<p>
 		Disposes of the decoder resources and deallocates memory. The decoder
 		Disposes of the decoder resources and deallocates memory. The decoder

+ 2 - 1
docs/examples/en/loaders/GLTFLoader.html

@@ -32,6 +32,7 @@
 			<li>KHR_draco_mesh_compression</li>
 			<li>KHR_draco_mesh_compression</li>
 			<li>KHR_materials_pbrSpecularGlossiness</li>
 			<li>KHR_materials_pbrSpecularGlossiness</li>
 			<li>KHR_materials_unlit</li>
 			<li>KHR_materials_unlit</li>
+			<li>KHR_mesh_quantization</li>
 			<li>KHR_lights_punctual<sup>1</sup></li>
 			<li>KHR_lights_punctual<sup>1</sup></li>
 			<li>KHR_texture_transform<sup>2</sup></li>
 			<li>KHR_texture_transform<sup>2</sup></li>
 			<li>MSFT_texture_dds</li>
 			<li>MSFT_texture_dds</li>
@@ -58,7 +59,7 @@
 
 
 		// Optional: Provide a DRACOLoader instance to decode compressed mesh data
 		// Optional: Provide a DRACOLoader instance to decode compressed mesh data
 		var dracoLoader = new THREE.DRACOLoader();
 		var dracoLoader = new THREE.DRACOLoader();
-		dracoLoader.setDecoderPath( '/examples/js/libs/draco' );
+		dracoLoader.setDecoderPath( '/examples/js/libs/draco/' );
 		loader.setDRACOLoader( dracoLoader );
 		loader.setDRACOLoader( dracoLoader );
 
 
 		// Load a glTF resource
 		// Load a glTF resource

+ 1 - 1
docs/examples/en/loaders/MTLLoader.html

@@ -12,7 +12,7 @@
 
 
 		<h1>[name]</h1>
 		<h1>[name]</h1>
 
 
-		<p class="desc">A loader for loading an <em>.mtl</em> resource, used internaly by [page:OBJLoader].<br />
+		<p class="desc">A loader for loading an <em>.mtl</em> resource, used internally by [page:OBJLoader].<br />
 		The Material Template Library format (MTL) or .MTL File Format is a companion file format to .OBJ that describes surface shading
 		The Material Template Library format (MTL) or .MTL File Format is a companion file format to .OBJ that describes surface shading
 		(material) properties of objects within one or more .OBJ files.
 		(material) properties of objects within one or more .OBJ files.
 		</p>
 		</p>

+ 9 - 1
docs/examples/zh/loaders/DRACOLoader.html

@@ -34,7 +34,10 @@
 		var loader = new THREE.DRACOLoader();
 		var loader = new THREE.DRACOLoader();
 
 
 		// Specify path to a folder containing WASM/JS decoding libraries.
 		// Specify path to a folder containing WASM/JS decoding libraries.
-		loader.setDecoderPath( '/examples/js/libs/draco' );
+		loader.setDecoderPath( '/examples/js/libs/draco/' );
+
+		// Optional: Pre-fetch Draco WASM/JS module.
+		loader.preload();
 
 
 		// Load a Draco geometry
 		// Load a Draco geometry
 		loader.load(
 		loader.load(
@@ -128,6 +131,11 @@
 		in the application.
 		in the application.
 		</p>
 		</p>
 
 
+		<h3>[method:this preload]()</h3>
+		<p>
+		Requests the decoder libraries, if not already loaded.
+		</p>
+
 		<h3>[method:this dispose]()</h3>
 		<h3>[method:this dispose]()</h3>
 		<p>
 		<p>
 		Disposes of the decoder resources and deallocates memory. The decoder
 		Disposes of the decoder resources and deallocates memory. The decoder

+ 3 - 2
docs/examples/zh/loaders/GLTFLoader.html

@@ -30,6 +30,7 @@
 			<li>KHR_draco_mesh_compression</li>
 			<li>KHR_draco_mesh_compression</li>
 			<li>KHR_materials_pbrSpecularGlossiness</li>
 			<li>KHR_materials_pbrSpecularGlossiness</li>
 			<li>KHR_materials_unlit</li>
 			<li>KHR_materials_unlit</li>
+			<li>KHR_mesh_quantization</li>
 			<li>KHR_lights_punctual<sup>1</sup></li>
 			<li>KHR_lights_punctual<sup>1</sup></li>
 			<li>KHR_texture_transform<sup>2</sup></li>
 			<li>KHR_texture_transform<sup>2</sup></li>
 			<li>MSFT_texture_dds</li>
 			<li>MSFT_texture_dds</li>
@@ -42,7 +43,7 @@
 			<sup>2</sup>支持UV变换,但存在一些重要的限制。
 			<sup>2</sup>支持UV变换,但存在一些重要的限制。
 			Transforms applied to
 			Transforms applied to
 			a texture using the first UV slot (all textures except aoMap and lightMap) must share the same
 			a texture using the first UV slot (all textures except aoMap and lightMap) must share the same
-			transform, or no transfor at all. 
+			transform, or no transfor at all.
 			aoMap 和 lightMap 纹理不能被变换。每个材质最多只能使用一次变换。
 			aoMap 和 lightMap 纹理不能被变换。每个材质最多只能使用一次变换。
 			每次对使用具有唯一变换的纹理都会导致一次额外的GPU纹理上传。
 			每次对使用具有唯一变换的纹理都会导致一次额外的GPU纹理上传。
 			请参阅#[link:https://github.com/mrdoob/three.js/pull/13831 13831] 和
 			请参阅#[link:https://github.com/mrdoob/three.js/pull/13831 13831] 和
@@ -57,7 +58,7 @@
 
 
 		// Optional: Provide a DRACOLoader instance to decode compressed mesh data
 		// Optional: Provide a DRACOLoader instance to decode compressed mesh data
 		var dracoLoader = new THREE.DRACOLoader();
 		var dracoLoader = new THREE.DRACOLoader();
-		dracoLoader.setDecoderPath( '/examples/js/libs/draco' );
+		dracoLoader.setDecoderPath( '/examples/js/libs/draco/' );
 		loader.setDRACOLoader( dracoLoader );
 		loader.setDRACOLoader( dracoLoader );
 
 
 		// Load a glTF resource
 		// Load a glTF resource

+ 16 - 15
docs/manual/en/introduction/How-to-create-VR-content.html

@@ -20,22 +20,22 @@
 	<h2>Workflow</h2>
 	<h2>Workflow</h2>
 
 
 	<p>
 	<p>
-		First, you have to include [link:https://github.com/mrdoob/three.js/blob/master/examples/js/vr/WebVR.js WebVR.js]
+		First, you have to include [link:https://github.com/mrdoob/three.js/blob/master/examples/jsm/webxr/VRButton.js VRButton.js]
 		into your project.
 		into your project.
 	</p>
 	</p>
 
 
 	<code>
 	<code>
-import { WEBVR } from 'three/examples/jsm/vr/WebVR.js';
+import { VRButton } from 'three/examples/jsm/webxr/VRButton.js';
 	</code>
 	</code>
 
 
 	<p>
 	<p>
-		*WEBVR.createButton()* does two important things: It creates a button which indicates
+		*VRButton.createButton()* does two important things: It creates a button which indicates
 		VR compatibility. Besides, it initiates a VR session if the user activates the button. The only thing you have
 		VR compatibility. Besides, it initiates a VR session if the user activates the button. The only thing you have
 		to do is to add the following line of code to your app.
 		to do is to add the following line of code to your app.
 	</p>
 	</p>
 
 
 	<code>
 	<code>
-document.body.appendChild( WEBVR.createButton( renderer ) );
+document.body.appendChild( VRButton.createButton( renderer ) );
 	</code>
 	</code>
 
 
 	<p>
 	<p>
@@ -65,17 +65,18 @@ renderer.setAnimationLoop( function () {
 	<p>
 	<p>
 		Have a look at one of the official WebVR examples to see this workflow in action.<br /><br />
 		Have a look at one of the official WebVR examples to see this workflow in action.<br /><br />
 
 
-		[example:webvr_ballshooter WebVR / ballshoter]<br />
-		[example:webvr_cubes WebVR / cubes]<br />
-		[example:webvr_dragging WebVR / dragging]<br />
-		[example:webvr_lorenzattractor WebVR / lorenzattractor]<br />
-		[example:webvr_panorama WebVR / panorama]<br />
-		[example:webvr_paint WebVR / paint]<br />
-		[example:webvr_rollercoaster WebVR / rollercoaster]<br />
-		[example:webvr_sandbox WebVR / sandbox]<br />
-		[example:webvr_sculpt WebVR / sculpt]<br />
-		[example:webvr_vive_paint WebVR / vive / paint]<br />
-		[example:webvr_vive_sculpt WebVR / vive / sculpt]<br />
+		[example:webxr_vr_ballshooter WebXR / VR / ballshoter]<br />
+		[example:webxr_vr_cubes WebXR / VR / cubes]<br />
+		[example:webxr_vr_dragging WebXR / VR / dragging]<br />
+		[example:webxr_vr_lorenzattractor WebXR / VR / lorenzattractor]<br />
+		[example:webxr_vr_multiview WebXR / VR / multiview]<br />
+		[example:webxr_vr_paint WebXR / VR / paint]<br />
+		[example:webxr_vr_panorama_depth WebXR / VR / panorama_depth]<br />
+		[example:webxr_vr_panorama WebXR / VR / panorama]<br />
+		[example:webxr_vr_rollercoaster WebXR / VR / rollercoaster]<br />
+		[example:webxr_vr_sandbox WebXR / VR / sandbox]<br />
+		[example:webxr_vr_sculpt WebXR / VR / sculpt]<br />
+		[example:webxr_vr_video WebXR / VR / video]
 	</p>
 	</p>
 
 
 </body>
 </body>

+ 16 - 15
docs/manual/zh/introduction/How-to-create-VR-content.html

@@ -19,21 +19,21 @@
 	<h2>工作流程</h2>
 	<h2>工作流程</h2>
 
 
 	<p>
 	<p>
-		首先,你需要将[link:https://github.com/mrdoob/three.js/blob/master/examples/js/vr/WebVR.js WebVR.js]
+		首先,你需要将[link:https://github.com/mrdoob/three.js/blob/master/examples/jsm/webxr/VRButton.js VRButton.js]
 		包含到你的项目中。
 		包含到你的项目中。
 	</p>
 	</p>
 
 
 	<code>
 	<code>
-import { WEBVR } from 'three/examples/jsm/vr/WebVR.js';
+import { VRButton } from 'three/examples/jsm/webxr/VRButton.js';
 	</code>
 	</code>
 
 
-	<p>*WEBVR.createButton()*做了两件重要的事情:首先,它创建了一个按钮,指示了VR的兼容性;
+	<p>*VRButton.createButton()*做了两件重要的事情:首先,它创建了一个按钮,指示了VR的兼容性;
 		此外,若用户激活了这个按钮,则它将开启一个VR会话。
 		此外,若用户激活了这个按钮,则它将开启一个VR会话。
 		你所要做的唯一一件事情,便是把下面的这一行代码加入到你的应用程序里。
 		你所要做的唯一一件事情,便是把下面的这一行代码加入到你的应用程序里。
 	</p>
 	</p>
 
 
 	<code>
 	<code>
-document.body.appendChild( WEBVR.createButton( renderer ) );
+document.body.appendChild( VRButton.createButton( renderer ) );
 	</code>
 	</code>
 
 
 	<p>
 	<p>
@@ -65,17 +65,18 @@ renderer.setAnimationLoop( function () {
 		请查看官方示例中与WebVR相关的示例,了解这一工作流程的实际使用、运行情况。
 		请查看官方示例中与WebVR相关的示例,了解这一工作流程的实际使用、运行情况。
 		<br /><br />
 		<br /><br />
 
 
-		[example:webvr_ballshooter WebVR / ballshoter]<br />
-		[example:webvr_cubes WebVR / cubes]<br />
-		[example:webvr_dragging WebVR / dragging]<br />
-		[example:webvr_lorenzattractor WebVR / lorenzattractor]<br />
-		[example:webvr_panorama WebVR / panorama]<br />
-		[example:webvr_paint WebVR / paint]<br />
-		[example:webvr_rollercoaster WebVR / rollercoaster]<br />
-		[example:webvr_sandbox WebVR / sandbox]<br />
-		[example:webvr_sculpt WebVR / sculpt]<br />
-		[example:webvr_vive_paint WebVR / vive / paint]<br />
-		[example:webvr_vive_sculpt WebVR / vive / sculpt]<br />
+		[example:webxr_vr_ballshooter WebXR / VR / ballshoter]<br />
+		[example:webxr_vr_cubes WebXR / VR / cubes]<br />
+		[example:webxr_vr_dragging WebXR / VR / dragging]<br />
+		[example:webxr_vr_lorenzattractor WebXR / VR / lorenzattractor]<br />
+		[example:webxr_vr_multiview WebXR / VR / multiview]<br />
+		[example:webxr_vr_paint WebXR / VR / paint]<br />
+		[example:webxr_vr_panorama_depth WebXR / VR / panorama_depth]<br />
+		[example:webxr_vr_panorama WebXR / VR / panorama]<br />
+		[example:webxr_vr_rollercoaster WebXR / VR / rollercoaster]<br />
+		[example:webxr_vr_sandbox WebXR / VR / sandbox]<br />
+		[example:webxr_vr_sculpt WebXR / VR / sculpt]<br />
+		[example:webxr_vr_video WebXR / VR / video]
 	</p>
 	</p>
 
 
 </body>
 </body>

+ 13 - 0
docs/prettify/threejs.css

@@ -13,3 +13,16 @@ pre.prettyprint, code.prettyprint {
 	background-color: #F5F5F5;
 	background-color: #F5F5F5;
 	font-family: 'Roboto Mono', monospace;
 	font-family: 'Roboto Mono', monospace;
 }
 }
+
+@media (prefers-color-scheme: dark) {
+
+	pre .str, code .str { color: #BB55FF; } /* string */
+	pre .com, code .com { color: #666666; } /* comment */
+	pre .lit, code .lit { color: #ff3399; } /* literal */
+	pre .pln, code .pln { color: #aaaaaa; } /* plaintext */
+
+	pre.prettyprint, code.prettyprint {
+		background-color: #333333;
+	}
+
+}

+ 0 - 1
editor/index.html

@@ -40,7 +40,6 @@
 		<script src="../examples/js/loaders/DRACOLoader.js"></script>
 		<script src="../examples/js/loaders/DRACOLoader.js"></script>
 		<script src="../examples/js/loaders/FBXLoader.js"></script>
 		<script src="../examples/js/loaders/FBXLoader.js"></script>
 		<script src="../examples/js/loaders/GLTFLoader.js"></script>
 		<script src="../examples/js/loaders/GLTFLoader.js"></script>
-		<script src="../examples/js/loaders/deprecated/LegacyGLTFLoader.js"></script>
 		<script src="../examples/js/loaders/KMZLoader.js"></script>
 		<script src="../examples/js/loaders/KMZLoader.js"></script>
 		<script src="../examples/js/loaders/MD2Loader.js"></script>
 		<script src="../examples/js/loaders/MD2Loader.js"></script>
 		<script src="../examples/js/loaders/OBJLoader.js"></script>
 		<script src="../examples/js/loaders/OBJLoader.js"></script>

+ 1 - 1
editor/js/Loader.js

@@ -158,7 +158,7 @@ var Loader = function ( editor ) {
 
 
 					if ( isGLTF1( contents ) ) {
 					if ( isGLTF1( contents ) ) {
 
 
-						loader = new THREE.LegacyGLTFLoader( manager );
+						alert( 'Import of glTF asset not possible. Only versions >= 2.0 are supported. Please try to upgrade the file to glTF 2.0 using glTF-Pipeline.' );
 
 
 					} else {
 					} else {
 
 

+ 6 - 6
editor/js/Menubar.Examples.js

@@ -21,11 +21,11 @@ Menubar.Examples = function ( editor ) {
 	// Examples
 	// Examples
 
 
 	var items = [
 	var items = [
-		{ title: 'Arkanoid', file: 'arkanoid.app.json' },
-		{ title: 'Camera', file: 'camera.app.json' },
-		{ title: 'Particles', file: 'particles.app.json' },
-		{ title: 'Pong', file: 'pong.app.json' },
-		{ title: 'Shaders', file: 'shaders.app.json' }
+		{ title: 'menubar/examples/Arkanoid', file: 'arkanoid.app.json' },
+		{ title: 'menubar/examples/Camera', file: 'camera.app.json' },
+		{ title: 'menubar/examples/Particles', file: 'particles.app.json' },
+		{ title: 'menubar/examples/Pong', file: 'pong.app.json' },
+		{ title: 'menubar/examples/Shaders', file: 'shaders.app.json' }
 	];
 	];
 
 
 	var loader = new THREE.FileLoader();
 	var loader = new THREE.FileLoader();
@@ -38,7 +38,7 @@ Menubar.Examples = function ( editor ) {
 
 
 			var option = new UI.Row();
 			var option = new UI.Row();
 			option.setClass( 'option' );
 			option.setClass( 'option' );
-			option.setTextContent( item.title );
+			option.setTextContent( strings.getKey( item.title ) );
 			option.onClick( function () {
 			option.onClick( function () {
 
 
 				if ( confirm( 'Any unsaved data will be lost. Are you sure?' ) ) {
 				if ( confirm( 'Any unsaved data will be lost. Are you sure?' ) ) {

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

@@ -1160,6 +1160,7 @@ Sidebar.Material = function ( editor ) {
 			'alphaMap': materialAlphaMapRow,
 			'alphaMap': materialAlphaMapRow,
 			'bumpMap': materialBumpMapRow,
 			'bumpMap': materialBumpMapRow,
 			'normalMap': materialNormalMapRow,
 			'normalMap': materialNormalMapRow,
+			'clearcoatNormalMap': materialClearcoatNormalMapRow,
 			'displacementMap': materialDisplacementMapRow,
 			'displacementMap': materialDisplacementMapRow,
 			'roughnessMap': materialRoughnessMapRow,
 			'roughnessMap': materialRoughnessMapRow,
 			'metalnessMap': materialMetalnessMapRow,
 			'metalnessMap': materialMetalnessMapRow,

+ 10 - 0
editor/js/Strings.js

@@ -65,6 +65,11 @@ var Strings = function ( config ) {
 			'menubar/play/play': 'Play',
 			'menubar/play/play': 'Play',
 
 
 			'menubar/examples': 'Examples',
 			'menubar/examples': 'Examples',
+			'menubar/examples/Arkanoid': 'Arkanoid',
+			'menubar/examples/Camera': 'Camera',
+			'menubar/examples/Particles': 'Particles',
+			'menubar/examples/Pong': 'Pong',
+			'menubar/examples/Shaders': 'Shaders',
 
 
 			'menubar/help': 'Help',
 			'menubar/help': 'Help',
 			'menubar/help/source_code': 'Source Code',
 			'menubar/help/source_code': 'Source Code',
@@ -364,6 +369,11 @@ var Strings = function ( config ) {
 			'menubar/play/play': '启动',
 			'menubar/play/play': '启动',
 
 
 			'menubar/examples': '示例',
 			'menubar/examples': '示例',
+			'menubar/examples/Arkanoid': '打砖块',
+			'menubar/examples/Camera': ' 摄像机',
+			'menubar/examples/Particles': '粒子',
+			'menubar/examples/Pong': '乒乓球',
+			'menubar/examples/Shaders': '着色器',
 
 
 			'menubar/help': '帮助',
 			'menubar/help': '帮助',
 			'menubar/help/source_code': '源码',
 			'menubar/help/source_code': '源码',

+ 1 - 2
editor/sw.js

@@ -1,4 +1,4 @@
-// r110
+// r111
 
 
 const assets = [
 const assets = [
 	'./',
 	'./',
@@ -18,7 +18,6 @@ const assets = [
 	'../examples/js/loaders/DRACOLoader.js',
 	'../examples/js/loaders/DRACOLoader.js',
 	'../examples/js/loaders/FBXLoader.js',
 	'../examples/js/loaders/FBXLoader.js',
 	'../examples/js/loaders/GLTFLoader.js',
 	'../examples/js/loaders/GLTFLoader.js',
-	'../examples/js/loaders/deprecated/LegacyGLTFLoader.js',
 	'../examples/js/loaders/KMZLoader.js',
 	'../examples/js/loaders/KMZLoader.js',
 	'../examples/js/loaders/MD2Loader.js',
 	'../examples/js/loaders/MD2Loader.js',
 	'../examples/js/loaders/OBJLoader.js',
 	'../examples/js/loaders/OBJLoader.js',

+ 0 - 5
examples/css3d_molecules.html

@@ -135,7 +135,6 @@
 
 
 				controls = new TrackballControls( camera, renderer.domElement );
 				controls = new TrackballControls( camera, renderer.domElement );
 				controls.rotateSpeed = 0.5;
 				controls.rotateSpeed = 0.5;
-				controls.addEventListener( 'change', render );
 
 
 				//
 				//
 
 
@@ -484,8 +483,6 @@
 
 
 					}
 					}
 
 
-					render();
-
 				} );
 				} );
 
 
 
 
@@ -500,8 +497,6 @@
 
 
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				renderer.setSize( window.innerWidth, window.innerHeight );
 
 
-				render();
-
 			}
 			}
 
 
 			function animate() {
 			function animate() {

+ 15 - 14
examples/files.js

@@ -47,6 +47,7 @@ var files = {
 		"webgl_geometry_text_shapes",
 		"webgl_geometry_text_shapes",
 		"webgl_geometry_text_stroke",
 		"webgl_geometry_text_stroke",
 		"webgl_helpers",
 		"webgl_helpers",
+		"webgl_instancing_raycast",
 		"webgl_instancing_suzanne",
 		"webgl_instancing_suzanne",
 		"webgl_interactive_buffergeometry",
 		"webgl_interactive_buffergeometry",
 		"webgl_interactive_cubes",
 		"webgl_interactive_cubes",
@@ -321,20 +322,20 @@ var files = {
 		"webaudio_timing",
 		"webaudio_timing",
 		"webaudio_visualizer"
 		"webaudio_visualizer"
 	],
 	],
-	"webvr": [
-		"webvr_ballshooter",
-		"webvr_cubes",
-		"webvr_dragging",
-		"webvr_lorenzattractor",
-		"webvr_multiview",
-		"webvr_panorama",
-		"webvr_paint",
-		"webvr_rollercoaster",
-		"webvr_sandbox",
-		"webvr_sculpt",
-		"webvr_video",
-		"webvr_vive_paint",
-		"webvr_vive_sculpt"
+	"webxr": [
+		"webxr_ar_paint",
+		"webxr_vr_ballshooter",
+		"webxr_vr_cubes",
+		"webxr_vr_dragging",
+		"webxr_vr_lorenzattractor",
+		"webxr_vr_multiview",
+		"webxr_vr_panorama",
+		"webxr_vr_panorama_depth",
+		"webxr_vr_paint",
+		"webxr_vr_rollercoaster",
+		"webxr_vr_sandbox",
+		"webxr_vr_sculpt",
+		"webxr_vr_video"
 	],
 	],
 	"physics": [
 	"physics": [
 		"webgl_physics_cloth",
 		"webgl_physics_cloth",

+ 25 - 2
examples/js/controls/DeviceOrientationControls.js

@@ -61,8 +61,31 @@ THREE.DeviceOrientationControls = function ( object ) {
 
 
 		onScreenOrientationChangeEvent(); // run once on load
 		onScreenOrientationChangeEvent(); // run once on load
 
 
-		window.addEventListener( 'orientationchange', onScreenOrientationChangeEvent, false );
-		window.addEventListener( 'deviceorientation', onDeviceOrientationChangeEvent, false );
+		// iOS 13+
+
+		if ( window.DeviceOrientationEvent !== undefined && typeof window.DeviceOrientationEvent.requestPermission === 'function' ) {
+
+			window.DeviceOrientationEvent.requestPermission().then( function ( response ) {
+
+				if ( response == 'granted' ) {
+
+					window.addEventListener( 'orientationchange', onScreenOrientationChangeEvent, false );
+					window.addEventListener( 'deviceorientation', onDeviceOrientationChangeEvent, false );
+
+				}
+
+			} ).catch( function ( error ) {
+
+				console.error( 'THREE.DeviceOrientationControls: Unable to use DeviceOrientation API:', error );
+
+			} );
+
+		} else {
+
+			window.addEventListener( 'orientationchange', onScreenOrientationChangeEvent, false );
+			window.addEventListener( 'deviceorientation', onDeviceOrientationChangeEvent, false );
+
+		}
 
 
 		scope.enabled = true;
 		scope.enabled = true;
 
 

+ 95 - 105
examples/js/effects/OutlineEffect.js

@@ -54,9 +54,6 @@
  * 	visible: true,
  * 	visible: true,
  * 	keepAlive: true
  * 	keepAlive: true
  * };
  * };
- *
- * TODO
- *  - support shader material without objectNormal in its vertexShader
  */
  */
 
 
 THREE.OutlineEffect = function ( renderer, parameters ) {
 THREE.OutlineEffect = function ( renderer, parameters ) {
@@ -90,58 +87,57 @@ THREE.OutlineEffect = function ( renderer, parameters ) {
 
 
 	//this.cache = cache;  // for debug
 	//this.cache = cache;  // for debug
 
 
-	// copied from WebGLPrograms and removed some materials
-	var shaderIDs = {
-		MeshBasicMaterial: 'basic',
-		MeshLambertMaterial: 'lambert',
-		MeshPhongMaterial: 'phong',
-		MeshToonMaterial: 'phong',
-		MeshStandardMaterial: 'physical',
-		MeshPhysicalMaterial: 'physical'
-	};
-
-	var uniformsChunk = {
+	var uniformsOutline = {
 		outlineThickness: { value: defaultThickness },
 		outlineThickness: { value: defaultThickness },
 		outlineColor: { value: defaultColor },
 		outlineColor: { value: defaultColor },
 		outlineAlpha: { value: defaultAlpha }
 		outlineAlpha: { value: defaultAlpha }
 	};
 	};
 
 
-	var vertexShaderChunk = [
+	var vertexShader = [
+		"#include <common>",
+		"#include <uv_pars_vertex>",
+		"#include <displacementmap_pars_vertex>",
+		"#include <fog_pars_vertex>",
+		"#include <morphtarget_pars_vertex>",
+		"#include <skinning_pars_vertex>",
+		"#include <logdepthbuf_pars_vertex>",
+		"#include <clipping_planes_pars_vertex>",
 
 
 		"uniform float outlineThickness;",
 		"uniform float outlineThickness;",
 
 
-		"vec4 calculateOutline( vec4 pos, vec3 objectNormal, vec4 skinned ) {",
-
+		"vec4 calculateOutline( vec4 pos, vec3 normal, vec4 skinned ) {",
 		"	float thickness = outlineThickness;",
 		"	float thickness = outlineThickness;",
 		"	const float ratio = 1.0;", // TODO: support outline thickness ratio for each vertex
 		"	const float ratio = 1.0;", // TODO: support outline thickness ratio for each vertex
-		"	vec4 pos2 = projectionMatrix * modelViewMatrix * vec4( skinned.xyz + objectNormal, 1.0 );",
+		"	vec4 pos2 = projectionMatrix * modelViewMatrix * vec4( skinned.xyz + normal, 1.0 );",
 		// NOTE: subtract pos2 from pos because BackSide objectNormal is negative
 		// NOTE: subtract pos2 from pos because BackSide objectNormal is negative
 		"	vec4 norm = normalize( pos - pos2 );",
 		"	vec4 norm = normalize( pos - pos2 );",
 		"	return pos + norm * thickness * pos.w * ratio;",
 		"	return pos + norm * thickness * pos.w * ratio;",
+		"}",
 
 
-		"}"
+		"void main() {",
 
 
-	].join( "\n" );
+		"	#include <uv_vertex>",
 
 
-	var vertexShaderChunk2 = [
+		"	#include <beginnormal_vertex>",
+		"	#include <morphnormal_vertex>",
+		"	#include <skinbase_vertex>",
+		"	#include <skinnormal_vertex>",
 
 
-		"#if ! defined( LAMBERT ) && ! defined( PHONG ) && ! defined( TOON ) && ! defined( STANDARD )",
-		"	#ifndef USE_ENVMAP",
-		"		vec3 objectNormal = normalize( normal );",
-		"	#endif",
-		"#endif",
+		"	#include <begin_vertex>",
+		"	#include <morphtarget_vertex>",
+		"	#include <skinning_vertex>",
+		"	#include <displacementmap_vertex>",
+		"	#include <project_vertex>",
 
 
-		"#ifdef FLIP_SIDED",
-		"	objectNormal = -objectNormal;",
-		"#endif",
+		"	vec3 outlineNormal = - objectNormal;", // the outline material is always rendered with THREE.BackSide
 
 
-		"#ifdef DECLARE_TRANSFORMED",
-		"	vec3 transformed = vec3( position );",
-		"#endif",
+		"	gl_Position = calculateOutline( gl_Position, outlineNormal, vec4( transformed, 1.0 ) );",
 
 
-		"gl_Position = calculateOutline( gl_Position, objectNormal, vec4( transformed, 1.0 ) );",
+		"	#include <logdepthbuf_vertex>",
+		"	#include <clipping_planes_vertex>",
+		"	#include <fog_vertex>",
 
 
-		"#include <fog_vertex>"
+		"}",
 
 
 	].join( "\n" );
 	].join( "\n" );
 
 
@@ -149,92 +145,40 @@ THREE.OutlineEffect = function ( renderer, parameters ) {
 
 
 		"#include <common>",
 		"#include <common>",
 		"#include <fog_pars_fragment>",
 		"#include <fog_pars_fragment>",
+		"#include <logdepthbuf_pars_fragment>",
+		"#include <clipping_planes_pars_fragment>",
 
 
 		"uniform vec3 outlineColor;",
 		"uniform vec3 outlineColor;",
 		"uniform float outlineAlpha;",
 		"uniform float outlineAlpha;",
 
 
 		"void main() {",
 		"void main() {",
 
 
+		"	#include <clipping_planes_fragment>",
+		"	#include <logdepthbuf_fragment>",
+
 		"	gl_FragColor = vec4( outlineColor, outlineAlpha );",
 		"	gl_FragColor = vec4( outlineColor, outlineAlpha );",
 
 
+		"	#include <premultiplied_alpha_fragment>",
+		"	#include <tonemapping_fragment>",
+		"	#include <encodings_fragment>",
 		"	#include <fog_fragment>",
 		"	#include <fog_fragment>",
 
 
 		"}"
 		"}"
 
 
 	].join( "\n" );
 	].join( "\n" );
 
 
-	function createInvisibleMaterial() {
-
-		return new THREE.ShaderMaterial( { name: 'invisible', visible: false } );
-
-	}
-
-	function createMaterial( originalMaterial ) {
-
-		var shaderID = shaderIDs[ originalMaterial.type ];
-		var originalUniforms, originalVertexShader;
-
-		if ( shaderID !== undefined ) {
-
-			var shader = THREE.ShaderLib[ shaderID ];
-			originalUniforms = shader.uniforms;
-			originalVertexShader = shader.vertexShader;
-
-		} else if ( originalMaterial.isRawShaderMaterial === true ) {
-
-			originalUniforms = originalMaterial.uniforms;
-			originalVertexShader = originalMaterial.vertexShader;
-
-			if ( ! /attribute\s+vec3\s+position\s*;/.test( originalVertexShader ) ||
-			     ! /attribute\s+vec3\s+normal\s*;/.test( originalVertexShader ) ) {
-
-				console.warn( 'THREE.OutlineEffect requires both vec3 position and normal attributes in vertex shader, ' +
-				              'does not draw outline for ' + originalMaterial.name + '(uuid:' + originalMaterial.uuid + ') material.' );
-
-				return createInvisibleMaterial();
-
-			}
-
-		} else if ( originalMaterial.isShaderMaterial === true ) {
-
-			originalUniforms = originalMaterial.uniforms;
-			originalVertexShader = originalMaterial.vertexShader;
-
-		} else {
-
-			return createInvisibleMaterial();
-
-		}
-
-		var uniforms = Object.assign( {}, originalUniforms, uniformsChunk );
-
-		var vertexShader = originalVertexShader
-			// put vertexShaderChunk right before "void main() {...}"
-			.replace( /void\s+main\s*\(\s*\)/, vertexShaderChunk + '\nvoid main()' )
-			// put vertexShaderChunk2 the end of "void main() {...}"
-			// Note: here assums originalVertexShader ends with "}" of "void main() {...}"
-			.replace( /\}\s*$/, vertexShaderChunk2 + '\n}' )
-			// remove any light related lines
-			// Note: here is very sensitive to originalVertexShader
-			// TODO: consider safer way
-			.replace( /#include\s+<[\w_]*light[\w_]*>/g, '' );
-
-		var defines = {};
-
-		if ( ! /vec3\s+transformed\s*=/.test( originalVertexShader ) &&
-		     ! /#include\s+<begin_vertex>/.test( originalVertexShader ) ) defines.DECLARE_TRANSFORMED = true;
+	function createMaterial() {
 
 
 		return new THREE.ShaderMaterial( {
 		return new THREE.ShaderMaterial( {
-			defines: defines,
-			uniforms: uniforms,
+			type: 'OutlineEffect',
+			uniforms: THREE.UniformsUtils.merge( [
+				THREE.UniformsLib[ 'fog' ],
+				THREE.UniformsLib[ 'displacementmap' ],
+				uniformsOutline
+			] ),
 			vertexShader: vertexShader,
 			vertexShader: vertexShader,
 			fragmentShader: fragmentShader,
 			fragmentShader: fragmentShader,
-			side: THREE.BackSide,
-			//wireframe: true,
-			skinning: false,
-			morphTargets: false,
-			morphNormals: false,
-			fog: false
+			side: THREE.BackSide
 		} );
 		} );
 
 
 	}
 	}
@@ -246,7 +190,7 @@ THREE.OutlineEffect = function ( renderer, parameters ) {
 		if ( data === undefined ) {
 		if ( data === undefined ) {
 
 
 			data = {
 			data = {
-				material: createMaterial( originalMaterial ),
+				material: createMaterial(),
 				used: true,
 				used: true,
 				keepAlive: defaultKeepAlive,
 				keepAlive: defaultKeepAlive,
 				count: 0
 				count: 0
@@ -274,9 +218,32 @@ THREE.OutlineEffect = function ( renderer, parameters ) {
 
 
 	}
 	}
 
 
+	function isCompatible( object ) {
+
+		var geometry = object.geometry;
+		var hasNormals = false;
+
+		if ( object.geometry !== undefined ) {
+
+			if ( geometry.isBufferGeometry ) {
+
+				hasNormals = geometry.attributes.normal !== undefined;
+
+			} else {
+
+				hasNormals = true; // the renderer always produces a normal attribute for Geometry
+
+			}
+
+		}
+
+		return ( object.isMesh === true && object.material !== undefined && hasNormals === true );
+
+	}
+
 	function setOutlineMaterial( object ) {
 	function setOutlineMaterial( object ) {
 
 
-		if ( object.material === undefined ) return;
+		if ( isCompatible( object ) === false ) return;
 
 
 		if ( Array.isArray( object.material ) ) {
 		if ( Array.isArray( object.material ) ) {
 
 
@@ -299,7 +266,7 @@ THREE.OutlineEffect = function ( renderer, parameters ) {
 
 
 	function restoreOriginalMaterial( object ) {
 	function restoreOriginalMaterial( object ) {
 
 
-		if ( object.material === undefined ) return;
+		if ( isCompatible( object ) === false ) return;
 
 
 		if ( Array.isArray( object.material ) ) {
 		if ( Array.isArray( object.material ) ) {
 
 
@@ -344,6 +311,14 @@ THREE.OutlineEffect = function ( renderer, parameters ) {
 
 
 		}
 		}
 
 
+		if ( originalMaterial.displacementMap ) {
+
+			material.uniforms.displacementMap.value = originalMaterial.displacementMap;
+			material.uniforms.displacementScale.value = originalMaterial.displacementScale;
+			material.uniforms.displacementBias.value = originalMaterial.displacementBias;
+
+		}
+
 	}
 	}
 
 
 	function updateOutlineMaterial( material, originalMaterial ) {
 	function updateOutlineMaterial( material, originalMaterial ) {
@@ -356,6 +331,9 @@ THREE.OutlineEffect = function ( renderer, parameters ) {
 		material.morphTargets = originalMaterial.morphTargets;
 		material.morphTargets = originalMaterial.morphTargets;
 		material.morphNormals = originalMaterial.morphNormals;
 		material.morphNormals = originalMaterial.morphNormals;
 		material.fog = originalMaterial.fog;
 		material.fog = originalMaterial.fog;
+		material.toneMapped = originalMaterial.toneMapped;
+		material.premultipliedAlpha = originalMaterial.premultipliedAlpha;
+		material.displacementMap = originalMaterial.displacementMap;
 
 
 		if ( outlineParameters !== undefined ) {
 		if ( outlineParameters !== undefined ) {
 
 
@@ -382,6 +360,18 @@ THREE.OutlineEffect = function ( renderer, parameters ) {
 
 
 		if ( originalMaterial.wireframe === true || originalMaterial.depthTest === false ) material.visible = false;
 		if ( originalMaterial.wireframe === true || originalMaterial.depthTest === false ) material.visible = false;
 
 
+		if ( originalMaterial.clippingPlanes ) {
+
+			material.clipping = true;
+
+			material.clippingPlanes = originalMaterial.clippingPlanes;
+			material.clipIntersection = originalMaterial.clipIntersection;
+			material.clipShadows = originalMaterial.clipShadows;
+
+		}
+
+		material.version = originalMaterial.version; // update outline material if necessary
+
 	}
 	}
 
 
 	function cleanupCache() {
 	function cleanupCache() {

+ 12 - 8
examples/js/exporters/GLTFExporter.js

@@ -1339,14 +1339,18 @@ THREE.GLTFExporter.prototype = {
 						// Clones attribute not to override
 						// Clones attribute not to override
 						var relativeAttribute = attribute.clone();
 						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 )
-							);
+						if ( ! geometry.morphTargetsRelative ) {
+
+							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 )
+									);
+
+							}
 
 
 						}
 						}
 
 

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

@@ -105,7 +105,7 @@ THREE.OBJExporter.prototype = {
 						normal.z = normals.getZ( i );
 						normal.z = normals.getZ( i );
 
 
 						// transfrom the normal to world space
 						// transfrom the normal to world space
-						normal.applyMatrix3( normalMatrixWorld );
+						normal.applyMatrix3( normalMatrixWorld ).normalize();
 
 
 						// transform the normal to export format
 						// transform the normal to export format
 						output += 'vn ' + normal.x + ' ' + normal.y + ' ' + normal.z + '\n';
 						output += 'vn ' + normal.x + ' ' + normal.y + ' ' + normal.z + '\n';

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

@@ -276,7 +276,7 @@ THREE.PLYExporter.prototype = {
 							vertex.y = normals.getY( i );
 							vertex.y = normals.getY( i );
 							vertex.z = normals.getZ( i );
 							vertex.z = normals.getZ( i );
 
 
-							vertex.applyMatrix3( normalMatrixWorld );
+							vertex.applyMatrix3( normalMatrixWorld ).normalize();
 
 
 							output.setFloat32( vOffset, vertex.x );
 							output.setFloat32( vOffset, vertex.x );
 							vOffset += 4;
 							vOffset += 4;
@@ -452,7 +452,7 @@ THREE.PLYExporter.prototype = {
 							vertex.y = normals.getY( i );
 							vertex.y = normals.getY( i );
 							vertex.z = normals.getZ( i );
 							vertex.z = normals.getZ( i );
 
 
-							vertex.applyMatrix3( normalMatrixWorld );
+							vertex.applyMatrix3( normalMatrixWorld ).normalize();
 
 
 							line += ' ' +
 							line += ' ' +
 								vertex.x + ' ' +
 								vertex.x + ' ' +

+ 3 - 1
examples/js/lines/LineMaterial.js

@@ -246,7 +246,9 @@ THREE.LineMaterial = function ( parameters ) {
 		uniforms: THREE.UniformsUtils.clone( THREE.ShaderLib[ 'line' ].uniforms ),
 		uniforms: THREE.UniformsUtils.clone( THREE.ShaderLib[ 'line' ].uniforms ),
 
 
 		vertexShader: THREE.ShaderLib[ 'line' ].vertexShader,
 		vertexShader: THREE.ShaderLib[ 'line' ].vertexShader,
-		fragmentShader: THREE.ShaderLib[ 'line' ].fragmentShader
+		fragmentShader: THREE.ShaderLib[ 'line' ].fragmentShader,
+
+		clipping: true // required for clipping support
 
 
 	} );
 	} );
 
 

+ 192 - 8
examples/js/loaders/3MFLoader.js

@@ -14,6 +14,8 @@
  *
  *
  * - Texture 2D
  * - Texture 2D
  * - Texture 2D Groups
  * - Texture 2D Groups
+ * - Color Groups (Vertex Colors)
+ * - Metallic Display Properties (PBR)
  */
  */
 
 
 THREE.ThreeMFLoader = function ( manager ) {
 THREE.ThreeMFLoader = function ( manager ) {
@@ -260,6 +262,7 @@ THREE.ThreeMFLoader.prototype = Object.assign( Object.create( THREE.Loader.proto
 
 
 				var basematerialNode = basematerialNodes[ i ];
 				var basematerialNode = basematerialNodes[ i ];
 				var basematerialData = parseBasematerialNode( basematerialNode );
 				var basematerialData = parseBasematerialNode( basematerialNode );
+				basematerialData.index = i; // the order and count of the material nodes form an implicit 0-based index
 				basematerialsData.basematerials.push( basematerialData );
 				basematerialsData.basematerials.push( basematerialData );
 
 
 			}
 			}
@@ -283,7 +286,7 @@ THREE.ThreeMFLoader.prototype = Object.assign( Object.create( THREE.Loader.proto
 
 
 		}
 		}
 
 
-		function parseTextures2DGroupNodes( texture2DGroupNode ) {
+		function parseTextures2DGroupNode( texture2DGroupNode ) {
 
 
 			var texture2DGroupData = {
 			var texture2DGroupData = {
 				id: texture2DGroupNode.getAttribute( 'id' ), // required
 				id: texture2DGroupNode.getAttribute( 'id' ), // required
@@ -311,12 +314,71 @@ THREE.ThreeMFLoader.prototype = Object.assign( Object.create( THREE.Loader.proto
 
 
 		}
 		}
 
 
+		function parseColorGroupNode( colorGroupNode ) {
+
+			var colorGroupData = {
+				id: colorGroupNode.getAttribute( 'id' ), // required
+				displaypropertiesid: colorGroupNode.getAttribute( 'displaypropertiesid' )
+			};
+
+			var colorNodes = colorGroupNode.querySelectorAll( 'color' );
+
+			var colors = [];
+			var colorObject = new THREE.Color();
+
+			for ( var i = 0; i < colorNodes.length; i ++ ) {
+
+				var colorNode = colorNodes[ i ];
+				var color = colorNode.getAttribute( 'color' );
+
+				colorObject.setStyle( color.substring( 0, 7 ) );
+				colorObject.convertSRGBToLinear(); // color is in sRGB
+
+				colors.push( colorObject.r, colorObject.g, colorObject.b );
+
+			}
+
+			colorGroupData[ 'colors' ] = new Float32Array( colors );
+
+			return colorGroupData;
+
+		}
+
+		function parseMetallicDisplaypropertiesNode( metallicDisplaypropetiesNode ) {
+
+			var metallicDisplaypropertiesData = {
+				id: metallicDisplaypropetiesNode.getAttribute( 'id' ) // required
+			};
+
+			var metallicNodes = metallicDisplaypropetiesNode.querySelectorAll( 'pbmetallic' );
+
+			var metallicData = [];
+
+			for ( var i = 0; i < metallicNodes.length; i ++ ) {
+
+				var metallicNode = metallicNodes[ i ];
+
+				metallicData.push( {
+					name: metallicNode.getAttribute( 'name' ), // required
+					metallicness: parseFloat( metallicNode.getAttribute( 'metallicness' ) ), // required
+					roughness: parseFloat( metallicNode.getAttribute( 'roughness' ) ) // required
+				} );
+
+			}
+
+			metallicDisplaypropertiesData.data = metallicData;
+
+			return metallicDisplaypropertiesData;
+
+		}
+
 		function parseBasematerialNode( basematerialNode ) {
 		function parseBasematerialNode( basematerialNode ) {
 
 
 			var basematerialData = {};
 			var basematerialData = {};
 
 
 			basematerialData[ 'name' ] = basematerialNode.getAttribute( 'name' ); // required
 			basematerialData[ 'name' ] = basematerialNode.getAttribute( 'name' ); // required
 			basematerialData[ 'displaycolor' ] = basematerialNode.getAttribute( 'displaycolor' ); // required
 			basematerialData[ 'displaycolor' ] = basematerialNode.getAttribute( 'displaycolor' ); // required
+			basematerialData[ 'displaypropertiesid' ] = basematerialNode.getAttribute( 'displaypropertiesid' );
 
 
 			return basematerialData;
 			return basematerialData;
 
 
@@ -567,13 +629,39 @@ THREE.ThreeMFLoader.prototype = Object.assign( Object.create( THREE.Loader.proto
 
 
 			//
 			//
 
 
+			resourcesData[ 'colorgroup' ] = {};
+			var colorGroupNodes = resourcesNode.querySelectorAll( 'colorgroup' );
+
+			for ( var i = 0; i < colorGroupNodes.length; i ++ ) {
+
+				var colorGroupNode = colorGroupNodes[ i ];
+				var colorGroupData = parseColorGroupNode( colorGroupNode );
+				resourcesData[ 'colorgroup' ][ colorGroupData[ 'id' ] ] = colorGroupData;
+
+			}
+
+			//
+
+			resourcesData[ 'pbmetallicdisplayproperties' ] = {};
+			var pbmetallicdisplaypropertiesNodes = resourcesNode.querySelectorAll( 'pbmetallicdisplayproperties' );
+
+			for ( var i = 0; i < pbmetallicdisplaypropertiesNodes.length; i ++ ) {
+
+				var pbmetallicdisplaypropertiesNode = pbmetallicdisplaypropertiesNodes[ i ];
+				var pbmetallicdisplaypropertiesData = parseMetallicDisplaypropertiesNode( pbmetallicdisplaypropertiesNode );
+				resourcesData[ 'pbmetallicdisplayproperties' ][ pbmetallicdisplaypropertiesData[ 'id' ] ] = pbmetallicdisplaypropertiesData;
+
+			}
+
+			//
+
 			resourcesData[ 'texture2dgroup' ] = {};
 			resourcesData[ 'texture2dgroup' ] = {};
 			var textures2DGroupNodes = resourcesNode.querySelectorAll( 'texture2dgroup' );
 			var textures2DGroupNodes = resourcesNode.querySelectorAll( 'texture2dgroup' );
 
 
 			for ( var i = 0; i < textures2DGroupNodes.length; i ++ ) {
 			for ( var i = 0; i < textures2DGroupNodes.length; i ++ ) {
 
 
 				var textures2DGroupNode = textures2DGroupNodes[ i ];
 				var textures2DGroupNode = textures2DGroupNodes[ i ];
-				var textures2DGroupData = parseTextures2DGroupNodes( textures2DGroupNode );
+				var textures2DGroupData = parseTextures2DGroupNode( textures2DGroupNode );
 				resourcesData[ 'texture2dgroup' ][ textures2DGroupData[ 'id' ] ] = textures2DGroupData;
 				resourcesData[ 'texture2dgroup' ][ textures2DGroupData[ 'id' ] ] = textures2DGroupData;
 
 
 			}
 			}
@@ -877,6 +965,73 @@ THREE.ThreeMFLoader.prototype = Object.assign( Object.create( THREE.Loader.proto
 
 
 		}
 		}
 
 
+		function buildVertexColorMesh( colorgroup, triangleProperties, modelData, meshData ) {
+
+			// geometry
+
+			var geometry = new THREE.BufferGeometry();
+
+			var positionData = [];
+			var colorData = [];
+
+			var vertices = meshData.vertices;
+			var colors = colorgroup.colors;
+
+			for ( var i = 0, l = triangleProperties.length; i < l; i ++ ) {
+
+				var triangleProperty = triangleProperties[ i ];
+
+				var v1 = triangleProperty.v1;
+				var v2 = triangleProperty.v2;
+				var v3 = triangleProperty.v3;
+
+				positionData.push( vertices[ ( v1 * 3 ) + 0 ] );
+				positionData.push( vertices[ ( v1 * 3 ) + 1 ] );
+				positionData.push( vertices[ ( v1 * 3 ) + 2 ] );
+
+				positionData.push( vertices[ ( v2 * 3 ) + 0 ] );
+				positionData.push( vertices[ ( v2 * 3 ) + 1 ] );
+				positionData.push( vertices[ ( v2 * 3 ) + 2 ] );
+
+				positionData.push( vertices[ ( v3 * 3 ) + 0 ] );
+				positionData.push( vertices[ ( v3 * 3 ) + 1 ] );
+				positionData.push( vertices[ ( v3 * 3 ) + 2 ] );
+
+				//
+
+				var p1 = triangleProperty.p1;
+				var p2 = triangleProperty.p2;
+				var p3 = triangleProperty.p3;
+
+				colorData.push( colors[ ( p1 * 3 ) + 0 ] );
+				colorData.push( colors[ ( p1 * 3 ) + 1 ] );
+				colorData.push( colors[ ( p1 * 3 ) + 2 ] );
+
+				colorData.push( colors[ ( ( p2 || p1 ) * 3 ) + 0 ] );
+				colorData.push( colors[ ( ( p2 || p1 ) * 3 ) + 1 ] );
+				colorData.push( colors[ ( ( p2 || p1 ) * 3 ) + 2 ] );
+
+				colorData.push( colors[ ( ( p3 || p1 ) * 3 ) + 0 ] );
+				colorData.push( colors[ ( ( p3 || p1 ) * 3 ) + 1 ] );
+				colorData.push( colors[ ( ( p3 || p1 ) * 3 ) + 2 ] );
+
+			}
+
+			geometry.setAttribute( 'position', new THREE.Float32BufferAttribute( positionData, 3 ) );
+			geometry.setAttribute( 'color', new THREE.Float32BufferAttribute( colorData, 3 ) );
+
+			// material
+
+			var material = new THREE.MeshPhongMaterial( { vertexColors: THREE.VertexColors, flatShading: true } );
+
+			// mesh
+
+			var mesh = new THREE.Mesh( geometry, material );
+
+			return mesh;
+
+		}
+
 		function buildDefaultMesh( meshData ) {
 		function buildDefaultMesh( meshData ) {
 
 
 			var geometry = new THREE.BufferGeometry();
 			var geometry = new THREE.BufferGeometry();
@@ -896,7 +1051,7 @@ THREE.ThreeMFLoader.prototype = Object.assign( Object.create( THREE.Loader.proto
 			var keys = Object.keys( resourceMap );
 			var keys = Object.keys( resourceMap );
 			var meshes = [];
 			var meshes = [];
 
 
-			for ( var i = 0; i < keys.length; i ++ ) {
+			for ( var i = 0, il = keys.length; i < il; i ++ ) {
 
 
 				var resourceId = keys[ i ];
 				var resourceId = keys[ i ];
 				var triangleProperties = resourceMap[ resourceId ];
 				var triangleProperties = resourceMap[ resourceId ];
@@ -908,16 +1063,21 @@ THREE.ThreeMFLoader.prototype = Object.assign( Object.create( THREE.Loader.proto
 						var basematerials = modelData.resources.basematerials[ resourceId ];
 						var basematerials = modelData.resources.basematerials[ resourceId ];
 						var newMeshes = buildBasematerialsMeshes( basematerials, triangleProperties, modelData, meshData, textureData, objectData );
 						var newMeshes = buildBasematerialsMeshes( basematerials, triangleProperties, modelData, meshData, textureData, objectData );
 
 
-						for ( var i = 0, l = newMeshes.length; i < l; i ++ ) {
+						for ( var j = 0, jl = newMeshes.length; j < jl; j ++ ) {
 
 
-							meshes.push( newMeshes[ i ] );
+							meshes.push( newMeshes[ j ] );
 
 
 						}
 						}
 						break;
 						break;
 
 
 					case 'texture':
 					case 'texture':
 						var texture2dgroup = modelData.resources.texture2dgroup[ resourceId ];
 						var texture2dgroup = modelData.resources.texture2dgroup[ resourceId ];
-						meshes.push( buildTexturedMesh( texture2dgroup, triangleProperties, modelData, meshData, textureData ) );
+						meshes.push( buildTexturedMesh( texture2dgroup, triangleProperties, modelData, meshData, textureData, objectData ) );
+						break;
+
+					case 'vertexColors':
+						var colorgroup = modelData.resources.colorgroup[ resourceId ];
+						meshes.push( buildVertexColorMesh( colorgroup, triangleProperties, modelData, meshData ) );
 						break;
 						break;
 
 
 					case 'default':
 					case 'default':
@@ -945,6 +1105,10 @@ THREE.ThreeMFLoader.prototype = Object.assign( Object.create( THREE.Loader.proto
 
 
 				return 'material';
 				return 'material';
 
 
+			} else if ( modelData.resources.colorgroup[ pid ] !== undefined ) {
+
+				return 'vertexColors';
+
 			} else if ( pid === 'default' ) {
 			} else if ( pid === 'default' ) {
 
 
 				return 'default';
 				return 'default';
@@ -1047,9 +1211,29 @@ THREE.ThreeMFLoader.prototype = Object.assign( Object.create( THREE.Loader.proto
 
 
 		}
 		}
 
 
-		function buildBasematerial( materialData ) {
+		function buildBasematerial( materialData, objects, modelData ) {
+
+			var material;
+
+			var displaypropertiesid = materialData.displaypropertiesid;
+			var pbmetallicdisplayproperties = modelData.resources.pbmetallicdisplayproperties;
+
+			if ( displaypropertiesid !== null && pbmetallicdisplayproperties[ displaypropertiesid ] !== undefined ) {
+
+				// metallic display property, use StandardMaterial
+
+				var pbmetallicdisplayproperty = pbmetallicdisplayproperties[ displaypropertiesid ];
+				var metallicData = pbmetallicdisplayproperty.data[ materialData.index ];
 
 
-			var material = new THREE.MeshPhongMaterial( { flatShading: true } );
+				material = new THREE.MeshStandardMaterial( { flatShading: true, roughness: metallicData.roughness, metalness: metallicData.metallicness } );
+
+			} else {
+
+				// otherwise use PhongMaterial
+
+				material = new THREE.MeshPhongMaterial( { flatShading: true } );
+
+			}
 
 
 			material.name = materialData.name;
 			material.name = materialData.name;
 
 

+ 8 - 0
examples/js/loaders/DRACOLoader.js

@@ -220,6 +220,14 @@ THREE.DRACOLoader.prototype = Object.assign( Object.create( THREE.Loader.prototy
 
 
 	},
 	},
 
 
+	preload: function () {
+
+		this._initDecoder();
+
+		return this;
+
+	},
+
 	_initDecoder: function () {
 	_initDecoder: function () {
 
 
 		if ( this.decoderPending ) return this.decoderPending;
 		if ( this.decoderPending ) return this.decoderPending;

+ 292 - 92
examples/js/loaders/EXRLoader.js

@@ -1,8 +1,9 @@
 /**
 /**
  * @author Richard M. / https://github.com/richardmonette
  * @author Richard M. / https://github.com/richardmonette
+ * @author ScieCode / http://github.com/sciecode
  *
  *
- * OpenEXR loader which, currently, supports reading 16 bit half data, in either
- * uncompressed or PIZ wavelet compressed form.
+ * OpenEXR loader which, currently, supports uncompressed, ZIP(S), RLE and PIZ wavelet compression.
+ * Supports reading 16 and 32 bit data format, except for PIZ compression which only reads 16-bit data.
  *
  *
  * Referred to the original Industrial Light & Magic OpenEXR implementation and the TinyEXR / Syoyo Fujita
  * Referred to the original Industrial Light & Magic OpenEXR implementation and the TinyEXR / Syoyo Fujita
  * implementation, so I have preserved their copyright notices.
  * implementation, so I have preserved their copyright notices.
@@ -690,7 +691,134 @@ THREE.EXRLoader.prototype = Object.assign( Object.create( THREE.DataTextureLoade
 
 
 		}
 		}
 
 
-		function decompressPIZ( outBuffer, outOffset, uInt8Array, inDataView, inOffset, tmpBufSize, num_channels, exrChannelInfos, dataWidth, num_lines ) {
+		function predictor( source ) {
+
+			for ( var t = 1; t < source.length; t ++ ) {
+
+				var d = source[ t - 1 ] + source[ t ] - 128;
+				source[ t ] = d;
+
+			}
+
+		}
+
+		function interleaveScalar( source, out ) {
+
+			var t1 = 0;
+			var t2 = Math.floor( ( source.length + 1 ) / 2 );
+			var s = 0;
+			var stop = source.length - 1;
+
+			while ( true ) {
+
+				if ( s > stop ) break;
+				out[ s ++ ] = source[ t1 ++ ];
+
+				if ( s > stop ) break;
+				out[ s ++ ] = source[ t2 ++ ];
+
+			}
+
+		}
+
+		function decodeRunLength( source ) {
+
+			var size = source.byteLength;
+			var out = new Array();
+			var p = 0;
+
+			var reader = new DataView( source );
+
+			while ( size > 0 ) {
+
+				var l = reader.getInt8( p ++ );
+
+				if ( l < 0 ) {
+
+					var count = - l;
+					size -= count + 1;
+
+					for ( var i = 0; i < count; i ++ ) {
+
+						out.push( reader.getUint8( p ++ ) );
+
+					}
+
+
+				} else {
+
+					var count = l;
+					size -= 2;
+
+					var value = reader.getUint8( p ++ );
+
+					for ( var i = 0; i < count + 1; i ++ ) {
+
+						out.push( value );
+
+					}
+
+
+				}
+
+			}
+
+			return out;
+
+		}
+
+		function uncompressRaw( info ) {
+
+			return new DataView( info.array.buffer, info.offset.value, info.size );
+
+		}
+
+		function uncompressRLE( info ) {
+
+			var compressed = info.viewer.buffer.slice( info.offset.value, info.offset.value + info.size );
+
+			var rawBuffer = new Uint8Array( decodeRunLength( compressed ) );
+			var tmpBuffer = new Uint8Array( rawBuffer.length );
+
+			predictor( rawBuffer ); // revert predictor
+
+			interleaveScalar( rawBuffer, tmpBuffer ); // interleave pixels
+
+			return new DataView( tmpBuffer.buffer );
+
+		}
+
+		function uncompressZIP( info ) {
+
+			var compressed = info.array.slice( info.offset.value, info.offset.value + info.size );
+
+			if ( typeof Zlib === 'undefined' ) {
+
+				console.error( 'THREE.EXRLoader: External library Inflate.min.js required, obtain or import from https://github.com/imaya/zlib.js' );
+
+			}
+
+			var inflate = new Zlib.Inflate( compressed, { resize: true, verify: true } ); // eslint-disable-line no-undef
+
+			var rawBuffer = new Uint8Array( inflate.decompress().buffer );
+			var tmpBuffer = new Uint8Array( rawBuffer.length );
+
+			predictor( rawBuffer ); // revert predictor
+
+			interleaveScalar( rawBuffer, tmpBuffer ); // interleave pixels
+
+			return new DataView( tmpBuffer.buffer );
+
+		}
+
+		function uncompressPIZ( info ) {
+
+			var inDataView = info.viewer;
+			var inOffset = { value: info.offset.value };
+
+			var tmpBufSize = info.width * scanlineBlockSize * ( EXRHeader.channels.length * BYTES_PER_HALF );
+			var outBuffer = new Uint16Array( tmpBufSize );
+			var outOffset = { value: 0 };
 
 
 			var bitmap = new Uint8Array( BITMAP_SIZE );
 			var bitmap = new Uint8Array( BITMAP_SIZE );
 
 
@@ -718,19 +846,19 @@ THREE.EXRLoader.prototype = Object.assign( Object.create( THREE.DataTextureLoade
 
 
 			var length = parseUint32( inDataView, inOffset );
 			var length = parseUint32( inDataView, inOffset );
 
 
-			hufUncompress( uInt8Array, inDataView, inOffset, length, outBuffer, outOffset, tmpBufSize );
+			hufUncompress( info.array, inDataView, inOffset, length, outBuffer, outOffset, tmpBufSize );
 
 
-			var pizChannelData = new Array( num_channels );
+			var pizChannelData = new Array( info.channels );
 
 
 			var outBufferEnd = 0;
 			var outBufferEnd = 0;
 
 
-			for ( var i = 0; i < num_channels; i ++ ) {
+			for ( var i = 0; i < info.channels; i ++ ) {
 
 
 				pizChannelData[ i ] = {};
 				pizChannelData[ i ] = {};
 				pizChannelData[ i ][ 'start' ] = outBufferEnd;
 				pizChannelData[ i ][ 'start' ] = outBufferEnd;
 				pizChannelData[ i ][ 'end' ] = pizChannelData[ i ][ 'start' ];
 				pizChannelData[ i ][ 'end' ] = pizChannelData[ i ][ 'start' ];
-				pizChannelData[ i ][ 'nx' ] = dataWidth;
-				pizChannelData[ i ][ 'ny' ] = num_lines;
+				pizChannelData[ i ][ 'nx' ] = info.width;
+				pizChannelData[ i ][ 'ny' ] = info.lines;
 				pizChannelData[ i ][ 'size' ] = 1;
 				pizChannelData[ i ][ 'size' ] = 1;
 
 
 				outBufferEnd += pizChannelData[ i ].nx * pizChannelData[ i ].ny * pizChannelData[ i ].size;
 				outBufferEnd += pizChannelData[ i ].nx * pizChannelData[ i ].ny * pizChannelData[ i ].size;
@@ -739,7 +867,7 @@ THREE.EXRLoader.prototype = Object.assign( Object.create( THREE.DataTextureLoade
 
 
 			var fooOffset = 0;
 			var fooOffset = 0;
 
 
-			for ( var i = 0; i < num_channels; i ++ ) {
+			for ( var i = 0; i < info.channels; i ++ ) {
 
 
 				for ( var j = 0; j < pizChannelData[ i ].size; ++ j ) {
 				for ( var j = 0; j < pizChannelData[ i ].size; ++ j ) {
 
 
@@ -758,7 +886,25 @@ THREE.EXRLoader.prototype = Object.assign( Object.create( THREE.DataTextureLoade
 
 
 			applyLut( lut, outBuffer, outBufferEnd );
 			applyLut( lut, outBuffer, outBufferEnd );
 
 
-			return true;
+			var tmpBuffer = new Uint8Array( outBuffer.buffer.byteLength );
+			var tmpOffset = 0;
+			var n = info.width * 2;
+
+			for ( var y = 0; y < info.lines; y ++ ) {
+
+				for ( var c = 0; c < info.channels; c ++ ) {
+
+					var cd = pizChannelData[ c ];
+					var cp = new Uint8Array( outBuffer.buffer, cd.end * 2 + y * n, n );
+
+					tmpBuffer.set( cp, tmpOffset );
+					tmpOffset += n;
+
+				}
+
+			}
+
+			return new DataView( tmpBuffer.buffer );
 
 
 		}
 		}
 
 
@@ -1059,147 +1205,205 @@ THREE.EXRLoader.prototype = Object.assign( Object.create( THREE.DataTextureLoade
 		}
 		}
 
 
 		// offsets
 		// offsets
-
 		var dataWindowHeight = EXRHeader.dataWindow.yMax + 1;
 		var dataWindowHeight = EXRHeader.dataWindow.yMax + 1;
-		var scanlineBlockSize = 1; // 1 for NO_COMPRESSION
-
-		if ( EXRHeader.compression === 'PIZ_COMPRESSION' ) {
-
-			scanlineBlockSize = 32;
 
 
-		}
+		var uncompress;
+		var scanlineBlockSize;
 
 
-		var numBlocks = dataWindowHeight / scanlineBlockSize;
+		switch ( EXRHeader.compression ) {
 
 
-		for ( var i = 0; i < numBlocks; i ++ ) {
+			case 'NO_COMPRESSION':
 
 
-			parseUlong( bufferDataView, offset ); // scanlineOffset
+				scanlineBlockSize = 1;
+				uncompress = uncompressRaw;
+				break;
 
 
-		}
+			case 'RLE_COMPRESSION':
 
 
-		// we should be passed the scanline offset table, start reading pixel data
+				scanlineBlockSize = 1;
+				uncompress = uncompressRLE;
+				break;
 
 
-		var width = EXRHeader.dataWindow.xMax - EXRHeader.dataWindow.xMin + 1;
-		var height = EXRHeader.dataWindow.yMax - EXRHeader.dataWindow.yMin + 1;
-		var numChannels = EXRHeader.channels.length;
+			case 'ZIPS_COMPRESSION':
 
 
-		switch ( this.type ) {
+				scanlineBlockSize = 1;
+				uncompress = uncompressZIP;
+				break;
 
 
-			case THREE.FloatType:
+			case 'ZIP_COMPRESSION':
 
 
-				var byteArray = new Float32Array( width * height * numChannels );
+				scanlineBlockSize = 16;
+				uncompress = uncompressZIP;
 				break;
 				break;
 
 
-			case THREE.HalfFloatType:
+			case 'PIZ_COMPRESSION':
 
 
-				var byteArray = new Uint16Array( width * height * numChannels );
+				scanlineBlockSize = 32;
+				uncompress = uncompressPIZ;
 				break;
 				break;
 
 
 			default:
 			default:
 
 
-				console.error( 'THREE.EXRLoader: unsupported type: ', this.type );
-				break;
+				throw 'EXRLoader.parse: ' + EXRHeader.compression + ' is unsupported';
 
 
 		}
 		}
 
 
-		var channelOffsets = {
-			R: 0,
-			G: 1,
-			B: 2,
-			A: 3
-		};
+		var size_t;
+		var getValue;
 
 
-		if ( EXRHeader.compression === 'NO_COMPRESSION' ) {
+		// mixed pixelType not supported
+		var pixelType = EXRHeader.channels[ 0 ].pixelType;
 
 
-			for ( var y = 0; y < height; y ++ ) {
+		if ( pixelType === 1 ) { // half
 
 
-				var y_scanline = parseUint32( bufferDataView, offset );
-				parseUint32( bufferDataView, offset ); // dataSize
+			switch ( this.type ) {
 
 
-				for ( var channelID = 0; channelID < EXRHeader.channels.length; channelID ++ ) {
+				case THREE.FloatType:
 
 
-					var cOff = channelOffsets[ EXRHeader.channels[ channelID ].name ];
+					getValue = parseFloat16;
+					size_t = INT16_SIZE;
+					break;
 
 
-					if ( EXRHeader.channels[ channelID ].pixelType === 1 ) { // half
+				case THREE.HalfFloatType:
 
 
-						for ( var x = 0; x < width; x ++ ) {
+					getValue = parseUint16;
+					size_t = INT16_SIZE;
+					break;
 
 
-							switch ( this.type ) {
+			}
 
 
-								case THREE.FloatType:
+		} else if ( pixelType === 2 ) { // float
 
 
-									var val = parseFloat16( bufferDataView, offset );
-									break;
+			switch ( this.type ) {
 
 
-								case THREE.HalfFloatType:
+				case THREE.FloatType:
 
 
-									var val = parseUint16( bufferDataView, offset );
-									break;
+					getValue = parseFloat32;
+					size_t = FLOAT32_SIZE;
+					break;
 
 
-							}
+				case THREE.HalfFloatType:
 
 
-							byteArray[ ( ( ( height - y_scanline ) * ( width * numChannels ) ) + ( x * numChannels ) ) + cOff ] = val;
+					throw 'EXRLoader.parse: unsupported HalfFloatType texture for FloatType image file.';
 
 
-						}
+			}
 
 
-					} else {
+		} else {
 
 
-						throw 'EXRLoader._parser: unsupported pixelType ' + EXRHeader.channels[ channelID ].pixelType + '. Only pixelType is 1 (HALF) is supported.';
+			throw 'EXRLoader.parse: unsupported pixelType ' + pixelType + ' for ' + EXRHeader.compression + '.';
 
 
-					}
+		}
+
+		var numBlocks = dataWindowHeight / scanlineBlockSize;
+
+		for ( var i = 0; i < numBlocks; i ++ ) {
+
+			parseUlong( bufferDataView, offset ); // scanlineOffset
+
+		}
+
+		// we should be passed the scanline offset table, start reading pixel data
+
+		var width = EXRHeader.dataWindow.xMax - EXRHeader.dataWindow.xMin + 1;
+		var height = EXRHeader.dataWindow.yMax - EXRHeader.dataWindow.yMin + 1;
+		// Firefox only supports RGBA (half) float textures
+		// var numChannels = EXRHeader.channels.length;
+		var numChannels = 4;
+		var size = width * height * numChannels;
+
+		// Fill initially with 1s for the alpha value if the texture is not RGBA, RGB values will be overwritten
+		switch ( this.type ) {
+
+			case THREE.FloatType:
+
+				var byteArray = new Float32Array( size );
+
+				if ( EXRHeader.channels.length < numChannels ) {
+
+					byteArray.fill( 1, 0, size );
 
 
 				}
 				}
 
 
-			}
+				break;
 
 
-		} else if ( EXRHeader.compression === 'PIZ_COMPRESSION' ) {
+			case THREE.HalfFloatType:
 
 
-			for ( var scanlineBlockIdx = 0; scanlineBlockIdx < height / scanlineBlockSize; scanlineBlockIdx ++ ) {
+				var byteArray = new Uint16Array( size );
 
 
-				parseUint32( bufferDataView, offset ); // line_no
-				parseUint32( bufferDataView, offset ); // data_len
+				if ( EXRHeader.channels.length < numChannels ) {
 
 
-				var tmpBufferSize = width * scanlineBlockSize * ( EXRHeader.channels.length * BYTES_PER_HALF );
-				var tmpBuffer = new Uint16Array( tmpBufferSize );
-				var tmpOffset = { value: 0 };
+					byteArray.fill( 0x3C00, 0, size ); // Uint16Array holds half float data, 0x3C00 is 1
 
 
-				decompressPIZ( tmpBuffer, tmpOffset, uInt8Array, bufferDataView, offset, tmpBufferSize, numChannels, EXRHeader.channels, width, scanlineBlockSize );
+				}
 
 
-				for ( var line_y = 0; line_y < scanlineBlockSize; line_y ++ ) {
+				break;
 
 
-					for ( var channelID = 0; channelID < EXRHeader.channels.length; channelID ++ ) {
+			default:
 
 
-						var cOff = channelOffsets[ EXRHeader.channels[ channelID ].name ];
+				console.error( 'THREE.EXRLoader: unsupported type: ', this.type );
+				break;
+
+		}
+
+		var channelOffsets = {
+			R: 0,
+			G: 1,
+			B: 2,
+			A: 3
+		};
 
 
-						if ( EXRHeader.channels[ channelID ].pixelType === 1 ) { // half
+		var compressionInfo = {
 
 
-							for ( var x = 0; x < width; x ++ ) {
+			array: uInt8Array,
+			viewer: bufferDataView,
+			offset: offset,
+			channels: EXRHeader.channels.length,
+			width: width,
+			lines: scanlineBlockSize,
+			size: 0
 
 
-								var idx = ( channelID * ( scanlineBlockSize * width ) ) + ( line_y * width ) + x;
+		};
 
 
-								switch ( this.type ) {
+		if ( EXRHeader.compression === 'NO_COMPRESSION' ||
+			EXRHeader.compression === 'ZIP_COMPRESSION' ||
+			EXRHeader.compression === 'ZIPS_COMPRESSION' ||
+			EXRHeader.compression === 'RLE_COMPRESSION' ||
+			EXRHeader.compression === 'PIZ_COMPRESSION' ) {
 
 
-									case THREE.FloatType:
+			var size;
+			var viewer;
+			var tmpOffset = { value: 0 };
 
 
-										var val = decodeFloat16( tmpBuffer[ idx ] );
-										break;
+			for ( var scanlineBlockIdx = 0; scanlineBlockIdx < height / scanlineBlockSize; scanlineBlockIdx ++ ) {
 
 
-									case THREE.HalfFloatType:
+				parseUint32( bufferDataView, offset ); // line_no
+				size = parseUint32( bufferDataView, offset ); // data_len
 
 
-										var val = tmpBuffer[ idx ];
-										break;
+				compressionInfo.offset = offset;
+				compressionInfo.size = size;
 
 
-								}
+				viewer = uncompress( compressionInfo );
 
 
-								var true_y = line_y + ( scanlineBlockIdx * scanlineBlockSize );
+				offset.value += size;
 
 
-								byteArray[ ( ( ( height - true_y ) * ( width * numChannels ) ) + ( x * numChannels ) ) + cOff ] = val;
+				for ( var line_y = 0; line_y < scanlineBlockSize; line_y ++ ) {
 
 
-							}
+					var true_y = line_y + ( scanlineBlockIdx * scanlineBlockSize );
 
 
-						} else {
+					if ( true_y >= height ) break;
 
 
-							throw 'EXRLoader._parser: unsupported pixelType ' + EXRHeader.channels[ channelID ].pixelType + '. Only pixelType is 1 (HALF) is supported.';
+					for ( var channelID = 0; channelID < EXRHeader.channels.length; channelID ++ ) {
+
+						var cOff = channelOffsets[ EXRHeader.channels[ channelID ].name ];
+
+						for ( var x = 0; x < width; x ++ ) {
+
+							var idx = ( line_y * ( EXRHeader.channels.length * width ) ) + ( channelID * width ) + x;
+							tmpOffset.value = idx * size_t;
+
+							var val = getValue( viewer, tmpOffset );
+
+							byteArray[ ( ( ( height - 1 - true_y ) * ( width * numChannels ) ) + ( x * numChannels ) ) + cOff ] = val;
 
 
 						}
 						}
 
 
@@ -1209,10 +1413,6 @@ THREE.EXRLoader.prototype = Object.assign( Object.create( THREE.DataTextureLoade
 
 
 			}
 			}
 
 
-		} else {
-
-			throw 'EXRLoader._parser: ' + EXRHeader.compression + ' is unsupported';
-
 		}
 		}
 
 
 		return {
 		return {
@@ -1220,7 +1420,7 @@ THREE.EXRLoader.prototype = Object.assign( Object.create( THREE.DataTextureLoade
 			width: width,
 			width: width,
 			height: height,
 			height: height,
 			data: byteArray,
 			data: byteArray,
-			format: EXRHeader.channels.length == 4 ? THREE.RGBAFormat : THREE.RGBFormat,
+			format: numChannels === 4 ? THREE.RGBAFormat : THREE.RGBFormat,
 			type: this.type
 			type: this.type
 		};
 		};
 
 

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

@@ -2058,10 +2058,12 @@ THREE.FBXLoader = ( function () {
 
 
 			if ( morphTargets.length === 0 ) return;
 			if ( morphTargets.length === 0 ) return;
 
 
+			parentGeo.morphTargetsRelative = true;
+
 			parentGeo.morphAttributes.position = [];
 			parentGeo.morphAttributes.position = [];
 			// parentGeo.morphAttributes.normal = []; // not implemented
 			// parentGeo.morphAttributes.normal = []; // not implemented
 
 
-			 var self = this;
+			var self = this;
 			morphTargets.forEach( function ( morphTarget ) {
 			morphTargets.forEach( function ( morphTarget ) {
 
 
 				morphTarget.rawTargets.forEach( function ( rawTarget ) {
 				morphTarget.rawTargets.forEach( function ( rawTarget ) {
@@ -2086,33 +2088,29 @@ THREE.FBXLoader = ( function () {
 		// Normal and position attributes only have data for the vertices that are affected by the morph
 		// Normal and position attributes only have data for the vertices that are affected by the morph
 		genMorphGeometry: function ( parentGeo, parentGeoNode, morphGeoNode, preTransform, name ) {
 		genMorphGeometry: function ( parentGeo, parentGeoNode, morphGeoNode, preTransform, name ) {
 
 
-			var morphGeo = new THREE.BufferGeometry();
-			if ( morphGeoNode.attrName ) morphGeo.name = morphGeoNode.attrName;
-
 			var vertexIndices = ( parentGeoNode.PolygonVertexIndex !== undefined ) ? parentGeoNode.PolygonVertexIndex.a : [];
 			var vertexIndices = ( parentGeoNode.PolygonVertexIndex !== undefined ) ? parentGeoNode.PolygonVertexIndex.a : [];
 
 
-			// make a copy of the parent's vertex positions
-			var vertexPositions = ( parentGeoNode.Vertices !== undefined ) ? parentGeoNode.Vertices.a.slice() : [];
-
-			var morphPositions = ( morphGeoNode.Vertices !== undefined ) ? morphGeoNode.Vertices.a : [];
+			var morphPositionsSparse = ( morphGeoNode.Vertices !== undefined ) ? morphGeoNode.Vertices.a : [];
 			var indices = ( morphGeoNode.Indexes !== undefined ) ? morphGeoNode.Indexes.a : [];
 			var indices = ( morphGeoNode.Indexes !== undefined ) ? morphGeoNode.Indexes.a : [];
 
 
+			var length = parentGeo.attributes.position.count * 3;
+			var morphPositions = new Float32Array( length );
+
 			for ( var i = 0; i < indices.length; i ++ ) {
 			for ( var i = 0; i < indices.length; i ++ ) {
 
 
 				var morphIndex = indices[ i ] * 3;
 				var morphIndex = indices[ i ] * 3;
 
 
-				// FBX format uses blend shapes rather than morph targets. This can be converted
-				// by additively combining the blend shape positions with the original geometry's positions
-				vertexPositions[ morphIndex ] += morphPositions[ i * 3 ];
-				vertexPositions[ morphIndex + 1 ] += morphPositions[ i * 3 + 1 ];
-				vertexPositions[ morphIndex + 2 ] += morphPositions[ i * 3 + 2 ];
+				morphPositions[ morphIndex ] = morphPositionsSparse[ i * 3 ];
+				morphPositions[ morphIndex + 1 ] = morphPositionsSparse[ i * 3 + 1 ];
+				morphPositions[ morphIndex + 2 ] = morphPositionsSparse[ i * 3 + 2 ];
 
 
 			}
 			}
 
 
 			// TODO: add morph normal support
 			// TODO: add morph normal support
 			var morphGeoInfo = {
 			var morphGeoInfo = {
 				vertexIndices: vertexIndices,
 				vertexIndices: vertexIndices,
-				vertexPositions: vertexPositions,
+				vertexPositions: morphPositions,
+
 			};
 			};
 
 
 			var morphBuffers = this.genBuffers( morphGeoInfo );
 			var morphBuffers = this.genBuffers( morphGeoInfo );

+ 88 - 114
examples/js/loaders/GLTFLoader.js

@@ -150,7 +150,7 @@ THREE.GLTFLoader = ( function () {
 
 
 			if ( json.asset === undefined || json.asset.version[ 0 ] < 2 ) {
 			if ( json.asset === undefined || json.asset.version[ 0 ] < 2 ) {
 
 
-				if ( onError ) onError( new Error( 'THREE.GLTFLoader: Unsupported asset. glTF versions >=2.0 are supported. Use LegacyGLTFLoader instead.' ) );
+				if ( onError ) onError( new Error( 'THREE.GLTFLoader: Unsupported asset. glTF versions >=2.0 are supported.' ) );
 				return;
 				return;
 
 
 			}
 			}
@@ -188,6 +188,10 @@ THREE.GLTFLoader = ( function () {
 							extensions[ extensionName ] = new GLTFTextureTransformExtension();
 							extensions[ extensionName ] = new GLTFTextureTransformExtension();
 							break;
 							break;
 
 
+						case EXTENSIONS.KHR_MESH_QUANTIZATION:
+							extensions[ extensionName ] = new GLTFMeshQuantizationExtension();
+							break;
+
 						default:
 						default:
 
 
 							if ( extensionsRequired.indexOf( extensionName ) >= 0 ) {
 							if ( extensionsRequired.indexOf( extensionName ) >= 0 ) {
@@ -263,6 +267,7 @@ THREE.GLTFLoader = ( function () {
 		KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS: 'KHR_materials_pbrSpecularGlossiness',
 		KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS: 'KHR_materials_pbrSpecularGlossiness',
 		KHR_MATERIALS_UNLIT: 'KHR_materials_unlit',
 		KHR_MATERIALS_UNLIT: 'KHR_materials_unlit',
 		KHR_TEXTURE_TRANSFORM: 'KHR_texture_transform',
 		KHR_TEXTURE_TRANSFORM: 'KHR_texture_transform',
+		KHR_MESH_QUANTIZATION: 'KHR_mesh_quantization',
 		MSFT_TEXTURE_DDS: 'MSFT_texture_dds'
 		MSFT_TEXTURE_DDS: 'MSFT_texture_dds'
 	};
 	};
 
 
@@ -428,7 +433,7 @@ THREE.GLTFLoader = ( function () {
 
 
 		} else if ( this.header.version < 2.0 ) {
 		} else if ( this.header.version < 2.0 ) {
 
 
-			throw new Error( 'THREE.GLTFLoader: Legacy binary file detected. Use LegacyGLTFLoader instead.' );
+			throw new Error( 'THREE.GLTFLoader: Legacy binary file detected.' );
 
 
 		}
 		}
 
 
@@ -981,6 +986,17 @@ THREE.GLTFLoader = ( function () {
 
 
 	}
 	}
 
 
+	/**
+	 * Mesh Quantization Extension
+	 *
+	 * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_mesh_quantization
+	 */
+	function GLTFMeshQuantizationExtension() {
+
+		this.name = EXTENSIONS.KHR_MESH_QUANTIZATION;
+
+	}
+
 	/*********************************/
 	/*********************************/
 	/********** INTERPOLATION ********/
 	/********** INTERPOLATION ********/
 	/*********************************/
 	/*********************************/
@@ -1309,95 +1325,9 @@ THREE.GLTFLoader = ( function () {
 			var morphPositions = accessors[ 0 ];
 			var morphPositions = accessors[ 0 ];
 			var morphNormals = accessors[ 1 ];
 			var morphNormals = accessors[ 1 ];
 
 
-			// Clone morph target accessors before modifying them.
-
-			for ( var i = 0, il = morphPositions.length; i < il; i ++ ) {
-
-				if ( geometry.attributes.position === morphPositions[ i ] ) continue;
-
-				morphPositions[ i ] = cloneBufferAttribute( morphPositions[ i ] );
-
-			}
-
-			for ( var i = 0, il = morphNormals.length; i < il; i ++ ) {
-
-				if ( geometry.attributes.normal === morphNormals[ i ] ) continue;
-
-				morphNormals[ i ] = cloneBufferAttribute( morphNormals[ i ] );
-
-			}
-
-			for ( var i = 0, il = targets.length; i < il; i ++ ) {
-
-				var target = targets[ i ];
-				var attributeName = 'morphTarget' + i;
-
-				if ( hasMorphPosition ) {
-
-					// Three.js morph position is absolute value. The formula is
-					//   basePosition
-					//     + weight0 * ( morphPosition0 - basePosition )
-					//     + weight1 * ( morphPosition1 - basePosition )
-					//     ...
-					// while the glTF one is relative
-					//   basePosition
-					//     + weight0 * glTFmorphPosition0
-					//     + weight1 * glTFmorphPosition1
-					//     ...
-					// then we need to convert from relative to absolute here.
-
-					if ( target.POSITION !== undefined ) {
-
-						var positionAttribute = morphPositions[ i ];
-						positionAttribute.name = attributeName;
-
-						var position = geometry.attributes.position;
-
-						for ( var j = 0, jl = positionAttribute.count; j < jl; j ++ ) {
-
-							positionAttribute.setXYZ(
-								j,
-								positionAttribute.getX( j ) + position.getX( j ),
-								positionAttribute.getY( j ) + position.getY( j ),
-								positionAttribute.getZ( j ) + position.getZ( j )
-							);
-
-						}
-
-					}
-
-				}
-
-				if ( hasMorphNormal ) {
-
-					// see target.POSITION's comment
-
-					if ( target.NORMAL !== undefined ) {
-
-						var normalAttribute = morphNormals[ i ];
-						normalAttribute.name = attributeName;
-
-						var normal = geometry.attributes.normal;
-
-						for ( var j = 0, jl = normalAttribute.count; j < jl; j ++ ) {
-
-							normalAttribute.setXYZ(
-								j,
-								normalAttribute.getX( j ) + normal.getX( j ),
-								normalAttribute.getY( j ) + normal.getY( j ),
-								normalAttribute.getZ( j ) + normal.getZ( j )
-							);
-
-						}
-
-					}
-
-				}
-
-			}
-
 			if ( hasMorphPosition ) geometry.morphAttributes.position = morphPositions;
 			if ( hasMorphPosition ) geometry.morphAttributes.position = morphPositions;
 			if ( hasMorphNormal ) geometry.morphAttributes.normal = morphNormals;
 			if ( hasMorphNormal ) geometry.morphAttributes.normal = morphNormals;
+			geometry.morphTargetsRelative = true;
 
 
 			return geometry;
 			return geometry;
 
 
@@ -1485,31 +1415,6 @@ THREE.GLTFLoader = ( function () {
 
 
 	}
 	}
 
 
-	function cloneBufferAttribute( attribute ) {
-
-		if ( attribute.isInterleavedBufferAttribute ) {
-
-			var count = attribute.count;
-			var itemSize = attribute.itemSize;
-			var array = attribute.array.slice( 0, count * itemSize );
-
-			for ( var i = 0, j = 0; i < count; ++ i ) {
-
-				array[ j ++ ] = attribute.getX( i );
-				if ( itemSize >= 2 ) array[ j ++ ] = attribute.getY( i );
-				if ( itemSize >= 3 ) array[ j ++ ] = attribute.getZ( i );
-				if ( itemSize >= 4 ) array[ j ++ ] = attribute.getW( i );
-
-			}
-
-			return new THREE.BufferAttribute( array, itemSize, attribute.normalized );
-
-		}
-
-		return attribute.clone();
-
-	}
-
 	/* GLTF PARSER */
 	/* GLTF PARSER */
 
 
 	function GLTFParser( json, extensions, options ) {
 	function GLTFParser( json, extensions, options ) {
@@ -2362,6 +2267,73 @@ THREE.GLTFLoader = ( function () {
 
 
 	};
 	};
 
 
+	/**
+	 * @param {THREE.BufferGeometry} geometry
+	 * @param {GLTF.Primitive} primitiveDef
+	 * @param {GLTFParser} parser
+	 */
+	function computeBounds( geometry, primitiveDef, parser ) {
+
+		var attributes = primitiveDef.attributes;
+
+		var box = new THREE.Box3();
+
+		if ( attributes.POSITION !== undefined ) {
+
+			var accessor = parser.json.accessors[ attributes.POSITION ];
+			var min = accessor.min;
+			var max = accessor.max;
+
+			box.set(
+				new THREE.Vector3( min[ 0 ], min[ 1 ], min[ 2 ] ),
+				new THREE.Vector3( max[ 0 ], max[ 1 ], max[ 2 ] ) );
+
+		} else {
+
+			return;
+
+		}
+
+		var targets = primitiveDef.targets;
+
+		if ( targets !== undefined ) {
+
+			var vector = new THREE.Vector3();
+
+			for ( var i = 0, il = targets.length; i < il; i ++ ) {
+
+				var target = targets[ i ];
+
+				if ( target.POSITION !== undefined ) {
+
+					var accessor = parser.json.accessors[ target.POSITION ];
+					var min = accessor.min;
+					var max = accessor.max;
+
+					// we need to get max of absolute components because target weight is [-1,1]
+					vector.setX( Math.max( Math.abs( min[ 0 ] ), Math.abs( max[ 0 ] ) ) );
+					vector.setY( Math.max( Math.abs( min[ 1 ] ), Math.abs( max[ 1 ] ) ) );
+					vector.setZ( Math.max( Math.abs( min[ 2 ] ), Math.abs( max[ 2 ] ) ) );
+
+					box.expandByVector( vector );
+
+				}
+
+			}
+
+		}
+
+		geometry.boundingBox = box;
+
+		var sphere = new THREE.Sphere();
+
+		box.getCenter( sphere.center );
+		sphere.radius = box.min.distanceTo( box.max ) / 2;
+
+		geometry.boundingSphere = sphere;
+
+	}
+
 	/**
 	/**
 	 * @param {THREE.BufferGeometry} geometry
 	 * @param {THREE.BufferGeometry} geometry
 	 * @param {GLTF.Primitive} primitiveDef
 	 * @param {GLTF.Primitive} primitiveDef
@@ -2410,6 +2382,8 @@ THREE.GLTFLoader = ( function () {
 
 
 		assignExtrasToUserData( geometry, primitiveDef );
 		assignExtrasToUserData( geometry, primitiveDef );
 
 
+		computeBounds( geometry, primitiveDef, parser );
+
 		return Promise.all( pending ).then( function () {
 		return Promise.all( pending ).then( function () {
 
 
 			return primitiveDef.targets !== undefined
 			return primitiveDef.targets !== undefined

+ 2 - 0
examples/js/loaders/LWOLoader.js

@@ -3013,6 +3013,8 @@ GeometryParser.prototype = {
 
 
 		}
 		}
 
 
+		geometry.morphTargetsRelative = false;
+
 	},
 	},
 
 
 };
 };

+ 1 - 0
examples/js/loaders/MD2Loader.js

@@ -366,6 +366,7 @@ THREE.MD2Loader.prototype = Object.assign( Object.create( THREE.Loader.prototype
 
 
 			geometry.morphAttributes.position = morphPositions;
 			geometry.morphAttributes.position = morphPositions;
 			geometry.morphAttributes.normal = morphNormals;
 			geometry.morphAttributes.normal = morphNormals;
+			geometry.morphTargetsRelative = false;
 
 
 			geometry.animations = THREE.AnimationClip.CreateClipsFromMorphTargetSequences( frames, 10 );
 			geometry.animations = THREE.AnimationClip.CreateClipsFromMorphTargetSequences( frames, 10 );
 
 

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

@@ -922,6 +922,7 @@ THREE.MMDLoader = ( function () {
 
 
 			geometry.morphTargets = morphTargets;
 			geometry.morphTargets = morphTargets;
 			geometry.morphAttributes.position = morphPositions;
 			geometry.morphAttributes.position = morphPositions;
+			geometry.morphTargetsRelative = false;
 
 
 			geometry.userData.MMD = {
 			geometry.userData.MMD = {
 				bones: bones,
 				bones: bones,

+ 9 - 0
examples/js/loaders/OBJLoader.js

@@ -10,6 +10,8 @@ THREE.OBJLoader = ( function () {
 	var material_library_pattern = /^mtllib /;
 	var material_library_pattern = /^mtllib /;
 	// usemtl material_name
 	// usemtl material_name
 	var material_use_pattern = /^usemtl /;
 	var material_use_pattern = /^usemtl /;
+	// usemap map_name
+	var map_use_pattern = /^usemap /;
 
 
 	function ParserState() {
 	function ParserState() {
 
 
@@ -570,6 +572,13 @@ THREE.OBJLoader = ( function () {
 
 
 					state.materialLibraries.push( line.substring( 7 ).trim() );
 					state.materialLibraries.push( line.substring( 7 ).trim() );
 
 
+				} else if ( map_use_pattern.test( line ) ) {
+
+					// the line is parsed but ignored since the loader assumes textures are defined MTL files
+					// (according to https://www.okino.com/conv/imp_wave.htm, 'usemap' is the old-style Wavefront texture reference method)
+
+					console.warn( 'THREE.OBJLoader: Rendering identifier "usemap" not supported. Textures must be defined in MTL files.' );
+
 				} else if ( lineFirstChar === 's' ) {
 				} else if ( lineFirstChar === 's' ) {
 
 
 					result = line.split( ' ' );
 					result = line.split( ' ' );

+ 0 - 3
examples/js/loaders/PCDLoader.js

@@ -3,9 +3,6 @@
  * @author Mugen87 / https://github.com/Mugen87
  * @author Mugen87 / https://github.com/Mugen87
  *
  *
  * Description: A THREE loader for PCD ascii and binary files.
  * Description: A THREE loader for PCD ascii and binary files.
- *
- * Limitations: Compressed binary files are not supported.
- *
  */
  */
 
 
 THREE.PCDLoader = function ( manager ) {
 THREE.PCDLoader = function ( manager ) {

+ 279 - 59
examples/js/loaders/VRMLLoader.js

@@ -146,6 +146,7 @@ THREE.VRMLLoader = ( function () {
 				//
 				//
 
 
 				var StringLiteral = createToken( { name: "StringLiteral", pattern: /"(:?[^\\"\n\r]+|\\(:?[bfnrtv"\\/]|u[0-9a-fA-F]{4}))*"/ } );
 				var StringLiteral = createToken( { name: "StringLiteral", pattern: /"(:?[^\\"\n\r]+|\\(:?[bfnrtv"\\/]|u[0-9a-fA-F]{4}))*"/ } );
+				var HexLiteral = createToken( { name: 'HexLiteral', pattern: /0[xX][0-9a-fA-F]+/ } );
 				var NumberLiteral = createToken( { name: 'NumberLiteral', pattern: /[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?/ } );
 				var NumberLiteral = createToken( { name: 'NumberLiteral', pattern: /[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?/ } );
 				var TrueLiteral = createToken( { name: 'TrueLiteral', pattern: /TRUE/ } );
 				var TrueLiteral = createToken( { name: 'TrueLiteral', pattern: /TRUE/ } );
 				var FalseLiteral = createToken( { name: 'FalseLiteral', pattern: /FALSE/ } );
 				var FalseLiteral = createToken( { name: 'FalseLiteral', pattern: /FALSE/ } );
@@ -184,6 +185,7 @@ THREE.VRMLLoader = ( function () {
 					Identifier,
 					Identifier,
 					RouteIdentifier,
 					RouteIdentifier,
 					StringLiteral,
 					StringLiteral,
+					HexLiteral,
 					NumberLiteral,
 					NumberLiteral,
 					LSquare,
 					LSquare,
 					RSquare,
 					RSquare,
@@ -425,6 +427,20 @@ THREE.VRMLLoader = ( function () {
 
 
 					}
 					}
 
 
+					if ( ctx.HexLiteral ) {
+
+						field.type = 'hex';
+
+						for ( var i = 0, l = ctx.HexLiteral.length; i < l; i ++ ) {
+
+							var hexLiteral = ctx.HexLiteral[ i ];
+
+							field.values.push( hexLiteral.image );
+
+						}
+
+					}
+
 					if ( ctx.TrueLiteral ) {
 					if ( ctx.TrueLiteral ) {
 
 
 						field.type = 'boolean';
 						field.type = 'boolean';
@@ -578,7 +594,7 @@ THREE.VRMLLoader = ( function () {
 						break;
 						break;
 
 
 					case 'Appearance':
 					case 'Appearance':
-						build = buildApperanceNode( node );
+						build = buildAppearanceNode( node );
 						break;
 						break;
 
 
 					case 'Material':
 					case 'Material':
@@ -589,6 +605,10 @@ THREE.VRMLLoader = ( function () {
 						build = buildImageTextureNode( node );
 						build = buildImageTextureNode( node );
 						break;
 						break;
 
 
+					case 'PixelTexture':
+						build = buildPixelTextureNode( node );
+						break;
+
 					case 'TextureTransform':
 					case 'TextureTransform':
 						build = buildTextureTransformNode( node );
 						build = buildTextureTransformNode( node );
 						break;
 						break;
@@ -658,7 +678,6 @@ THREE.VRMLLoader = ( function () {
 
 
 					case 'FontStyle':
 					case 'FontStyle':
 					case 'MovieTexture':
 					case 'MovieTexture':
-					case 'PixelTexture':
 
 
 					case 'ColorInterpolator':
 					case 'ColorInterpolator':
 					case 'CoordinateInterpolator':
 					case 'CoordinateInterpolator':
@@ -810,12 +829,12 @@ THREE.VRMLLoader = ( function () {
 
 
 				}
 				}
 
 
+				var radius = 10000;
+
 				// sky
 				// sky
 
 
 				if ( skyColor ) {
 				if ( skyColor ) {
 
 
-					var radius = 10000;
-
 					var skyGeometry = new THREE.SphereBufferGeometry( radius, 32, 16 );
 					var skyGeometry = new THREE.SphereBufferGeometry( radius, 32, 16 );
 					var skyMaterial = new THREE.MeshBasicMaterial( { fog: false, side: THREE.BackSide, depthWrite: false, depthTest: false } );
 					var skyMaterial = new THREE.MeshBasicMaterial( { fog: false, side: THREE.BackSide, depthWrite: false, depthTest: false } );
 
 
@@ -990,7 +1009,7 @@ THREE.VRMLLoader = ( function () {
 
 
 			}
 			}
 
 
-			function buildApperanceNode( node ) {
+			function buildAppearanceNode( node ) {
 
 
 				var material = new THREE.MeshPhongMaterial();
 				var material = new THREE.MeshPhongMaterial();
 				var transformData;
 				var transformData;
@@ -1030,13 +1049,13 @@ THREE.VRMLLoader = ( function () {
 							var textureNode = fieldValues[ 0 ];
 							var textureNode = fieldValues[ 0 ];
 							if ( textureNode !== null ) {
 							if ( textureNode !== null ) {
 
 
-								if ( textureNode.name === 'ImageTexture' ) {
+								if ( textureNode.name === 'ImageTexture' || textureNode.name === 'PixelTexture' ) {
 
 
 									material.map = getNode( textureNode );
 									material.map = getNode( textureNode );
 
 
 								} else {
 								} else {
 
 
-									// MovieTexture and PixelTexture not supported yet
+									// MovieTexture not supported yet
 
 
 								}
 								}
 
 
@@ -1061,12 +1080,45 @@ THREE.VRMLLoader = ( function () {
 
 
 				// only apply texture transform data if a texture was defined
 				// only apply texture transform data if a texture was defined
 
 
-				if ( material.map && transformData ) {
+				if ( material.map ) {
+
+					// respect VRML lighting model
+
+					if ( material.map.__type ) {
+
+						switch ( material.map.__type ) {
+
+							case TEXTURE_TYPE.INTENSITY_ALPHA:
+								material.opacity = 1; // ignore transparency
+								break;
+
+							case TEXTURE_TYPE.RGB:
+								material.color.set( 0xffffff ); // ignore material color
+								break;
 
 
-					material.map.center.copy( transformData.center );
-					material.map.rotation = transformData.rotation;
-					material.map.repeat.copy( transformData.scale );
-					material.map.offset.copy( transformData.translation );
+							case TEXTURE_TYPE.RGBA:
+								material.color.set( 0xffffff ); // ignore material color
+								material.opacity = 1; // ignore transparency
+								break;
+
+							default:
+
+						}
+
+						delete material.map.__type;
+
+					}
+
+					// apply texture transform
+
+					if ( transformData ) {
+
+						material.map.center.copy( transformData.center );
+						material.map.rotation = transformData.rotation;
+						material.map.repeat.copy( transformData.scale );
+						material.map.offset.copy( transformData.translation );
+
+					}
 
 
 				}
 				}
 
 
@@ -1124,6 +1176,163 @@ THREE.VRMLLoader = ( function () {
 
 
 			}
 			}
 
 
+			function parseHexColor( hex, textureType, color ) {
+
+				switch ( textureType ) {
+
+					case TEXTURE_TYPE.INTENSITY:
+						// Intensity texture: A one-component image specifies one-byte hexadecimal or integer values representing the intensity of the image
+						var value = parseInt( hex );
+						color.r = value;
+						color.g = value;
+						color.b = value;
+						break;
+
+					case TEXTURE_TYPE.INTENSITY_ALPHA:
+						// Intensity+Alpha texture: A two-component image specifies the intensity in the first (high) byte and the alpha opacity in the second (low) byte.
+						var value = parseInt( "0x" + hex.substring( 2, 4 ) );
+						color.r = value;
+						color.g = value;
+						color.b = value;
+						color.a = parseInt( "0x" + hex.substring( 4, 6 ) );
+						break;
+
+					case TEXTURE_TYPE.RGB:
+						// RGB texture: Pixels in a three-component image specify the red component in the first (high) byte, followed by the green and blue components
+						color.r = parseInt( "0x" + hex.substring( 2, 4 ) );
+						color.g = parseInt( "0x" + hex.substring( 4, 6 ) );
+						color.b = parseInt( "0x" + hex.substring( 6, 8 ) );
+						break;
+
+					case TEXTURE_TYPE.RGBA:
+						// RGBA texture: Four-component images specify the alpha opacity byte after red/green/blue
+						color.r = parseInt( "0x" + hex.substring( 2, 4 ) );
+						color.g = parseInt( "0x" + hex.substring( 4, 6 ) );
+						color.b = parseInt( "0x" + hex.substring( 6, 8 ) );
+						color.a = parseInt( "0x" + hex.substring( 8, 10 ) );
+						break;
+
+					default:
+
+				}
+
+			}
+
+			function getTextureType( num_components ) {
+
+				var type;
+
+				switch ( num_components ) {
+
+					case 1:
+						type = TEXTURE_TYPE.INTENSITY;
+						break;
+
+					case 2:
+						type = TEXTURE_TYPE.INTENSITY_ALPHA;
+						break;
+
+					case 3:
+						type = TEXTURE_TYPE.RGB;
+						break;
+
+					case 4:
+						type = TEXTURE_TYPE.RGBA;
+						break;
+
+					default:
+
+				}
+
+				return type;
+
+			}
+
+			function buildPixelTextureNode( node ) {
+
+				var texture;
+				var wrapS = THREE.RepeatWrapping;
+				var wrapT = THREE.RepeatWrapping;
+
+				var fields = node.fields;
+
+				for ( var i = 0, l = fields.length; i < l; i ++ ) {
+
+					var field = fields[ i ];
+					var fieldName = field.name;
+					var fieldValues = field.values;
+
+					switch ( fieldName ) {
+
+						case 'image':
+							var width = fieldValues[ 0 ];
+							var height = fieldValues[ 1 ];
+							var num_components = fieldValues[ 2 ];
+
+							var useAlpha = ( num_components === 2 || num_components === 4 );
+							var textureType = getTextureType( num_components );
+
+							var size = ( ( useAlpha === true ) ? 4 : 3 ) * ( width * height );
+							var data = new Uint8Array( size );
+
+							var color = { r: 0, g: 0, b: 0, a: 0 };
+
+							for ( var j = 3, k = 0, jl = fieldValues.length; j < jl; j ++, k ++ ) {
+
+								parseHexColor( fieldValues[ j ], textureType, color );
+
+								if ( useAlpha === true ) {
+
+									var stride = k * 4;
+
+									data[ stride + 0 ] = color.r;
+									data[ stride + 1 ] = color.g;
+									data[ stride + 2 ] = color.b;
+									data[ stride + 3 ] = color.a;
+
+								} else {
+
+									var stride = k * 3;
+
+									data[ stride + 0 ] = color.r;
+									data[ stride + 1 ] = color.g;
+									data[ stride + 2 ] = color.b;
+
+								}
+
+							}
+
+							texture = new THREE.DataTexture( data, width, height, ( useAlpha === true ) ? THREE.RGBAFormat : THREE.RGBFormat );
+							texture.__type = textureType; // needed for material modifications
+							break;
+
+						case 'repeatS':
+							if ( fieldValues[ 0 ] === false ) wrapS = THREE.ClampToEdgeWrapping;
+							break;
+
+						case 'repeatT':
+							if ( fieldValues[ 0 ] === false ) wrapT = THREE.ClampToEdgeWrapping;
+							break;
+
+						default:
+							console.warn( 'THREE.VRMLLoader: Unknown field:', fieldName );
+							break;
+
+					}
+
+				}
+
+				if ( texture ) {
+
+					texture.wrapS = wrapS;
+					texture.wrapT = wrapT;
+
+				}
+
+				return texture;
+
+			}
+
 			function buildImageTextureNode( node ) {
 			function buildImageTextureNode( node ) {
 
 
 				var texture;
 				var texture;
@@ -2223,83 +2432,69 @@ THREE.VRMLLoader = ( function () {
 			 */
 			 */
 			function paintFaces( geometry, radius, angles, colors, topDown ) {
 			function paintFaces( geometry, radius, angles, colors, topDown ) {
 
 
-				var direction = ( topDown === true ) ? 1 : - 1;
+				// compute threshold values
 
 
-				var coord = [], A = {}, B = {}, applyColor = false;
+				var thresholds = [];
+				var startAngle = ( topDown === true ) ? 0 : Math.PI;
 
 
-				for ( var k = 0; k < angles.length; k ++ ) {
+				for ( var i = 0, l = colors.length; i < l; i ++ ) {
 
 
-					// push the vector at which the color changes
+					var angle = ( i === 0 ) ? 0 : angles[ i - 1 ];
+					angle = ( topDown === true ) ? angle : ( startAngle - angle );
 
 
-					var vec = {
-						x: direction * ( Math.cos( angles[ k ] ) * radius ),
-						y: direction * ( Math.sin( angles[ k ] ) * radius )
-					};
+					var point = new THREE.Vector3();
+					point.setFromSphericalCoords( radius, angle, 0 );
 
 
-					coord.push( vec );
+					thresholds.push( point );
 
 
 				}
 				}
 
 
-				var index = geometry.index;
+				// generate vertex colors
+
+				var indices = geometry.index;
 				var positionAttribute = geometry.attributes.position;
 				var positionAttribute = geometry.attributes.position;
 				var colorAttribute = new THREE.BufferAttribute( new Float32Array( geometry.attributes.position.count * 3 ), 3 );
 				var colorAttribute = new THREE.BufferAttribute( new Float32Array( geometry.attributes.position.count * 3 ), 3 );
 
 
 				var position = new THREE.Vector3();
 				var position = new THREE.Vector3();
 				var color = new THREE.Color();
 				var color = new THREE.Color();
 
 
-				for ( var i = 0; i < index.count; i ++ ) {
-
-					var vertexIndex = index.getX( i );
-
-					position.fromBufferAttribute( positionAttribute, vertexIndex );
-
-					for ( var j = 0; j < colors.length; j ++ ) {
-
-						// linear interpolation between aColor and bColor, calculate proportion
-						// A is previous point (angle)
-
-						if ( j === 0 ) {
-
-							A.x = 0;
-							A.y = ( topDown === true ) ? radius : - 1 * radius;
+				for ( var i = 0; i < indices.count; i ++ ) {
 
 
-						} else {
-
-							A.x = coord[ j - 1 ].x;
-							A.y = coord[ j - 1 ].y;
+					var index = indices.getX( i );
+					position.fromBufferAttribute( positionAttribute, index );
 
 
-						}
+					var thresholdIndexA, thresholdIndexB;
+					var t = 1;
 
 
-						// B is current point (angle)
+					for ( var j = 1; j < thresholds.length; j ++ ) {
 
 
-						B = coord[ j ];
+						thresholdIndexA = j - 1;
+						thresholdIndexB = j;
 
 
-						if ( B !== undefined ) {
+						var thresholdA = thresholds[ thresholdIndexA ];
+						var thresholdB = thresholds[ thresholdIndexB ];
 
 
-							// p has to be between the points A and B which we interpolate
+						if ( topDown === true ) {
 
 
-							applyColor = ( topDown === true ) ? ( position.y <= A.y && position.y > B.y ) : ( position.y >= A.y && position.y < B.y );
+							// interpolation for sky color
 
 
-							if ( applyColor === true ) {
+							if ( position.y <= thresholdA.y && position.y > thresholdB.y ) {
 
 
-								var aColor = colors[ j ];
-								var bColor = colors[ j + 1 ];
+								t = Math.abs( thresholdA.y - position.y ) / Math.abs( thresholdA.y - thresholdB.y );
 
 
-								// below is simple linear interpolation
+								break;
 
 
-								var t = Math.abs( position.y - A.y ) / ( A.y - B.y );
+							}
 
 
-								// to make it faster, you can only calculate this if the y coord changes, the color is the same for points with the same y
+						} else {
 
 
-								color.copy( aColor ).lerp( bColor, t );
+							// interpolation for ground color
 
 
-								colorAttribute.setXYZ( vertexIndex, color.r, color.g, color.b );
+							if ( position.y >= thresholdA.y && position.y < thresholdB.y ) {
 
 
-							} else {
+								t = Math.abs( thresholdA.y - position.y ) / Math.abs( thresholdA.y - thresholdB.y );
 
 
-								var colorIndex = ( topDown === true ) ? colors.length - 1 : 0;
-								var c = colors[ colorIndex ];
-								colorAttribute.setXYZ( vertexIndex, c.r, c.g, c.b );
+								break;
 
 
 							}
 							}
 
 
@@ -2307,6 +2502,13 @@ THREE.VRMLLoader = ( function () {
 
 
 					}
 					}
 
 
+					var colorA = colors[ thresholdIndexA ];
+					var colorB = colors[ thresholdIndexB ];
+
+					color.copy( colorA ).lerp( colorB, t );
+
+					colorAttribute.setXYZ( index, color.r, color.g, color.b );
+
 				}
 				}
 
 
 				geometry.setAttribute( 'color', colorAttribute );
 				geometry.setAttribute( 'color', colorAttribute );
@@ -2382,6 +2584,7 @@ THREE.VRMLLoader = ( function () {
 		var Identifier = tokenVocabulary[ 'Identifier' ];
 		var Identifier = tokenVocabulary[ 'Identifier' ];
 		var RouteIdentifier = tokenVocabulary[ 'RouteIdentifier' ];
 		var RouteIdentifier = tokenVocabulary[ 'RouteIdentifier' ];
 		var StringLiteral = tokenVocabulary[ 'StringLiteral' ];
 		var StringLiteral = tokenVocabulary[ 'StringLiteral' ];
+		var HexLiteral = tokenVocabulary[ 'HexLiteral' ];
 		var NumberLiteral = tokenVocabulary[ 'NumberLiteral' ];
 		var NumberLiteral = tokenVocabulary[ 'NumberLiteral' ];
 		var TrueLiteral = tokenVocabulary[ 'TrueLiteral' ];
 		var TrueLiteral = tokenVocabulary[ 'TrueLiteral' ];
 		var FalseLiteral = tokenVocabulary[ 'FalseLiteral' ];
 		var FalseLiteral = tokenVocabulary[ 'FalseLiteral' ];
@@ -2485,6 +2688,11 @@ THREE.VRMLLoader = ( function () {
 
 
 						$.CONSUME( StringLiteral );
 						$.CONSUME( StringLiteral );
 
 
+					} },
+					{ ALT: function () {
+
+						$.CONSUME( HexLiteral );
+
 					} },
 					} },
 					{ ALT: function () {
 					{ ALT: function () {
 
 
@@ -2533,6 +2741,11 @@ THREE.VRMLLoader = ( function () {
 
 
 						$.CONSUME( StringLiteral );
 						$.CONSUME( StringLiteral );
 
 
+					} },
+					{ ALT: function () {
+
+						$.CONSUME( HexLiteral );
+
 					} },
 					} },
 					{ ALT: function () {
 					{ ALT: function () {
 
 
@@ -2576,6 +2789,13 @@ THREE.VRMLLoader = ( function () {
 
 
 	}
 	}
 
 
+	var TEXTURE_TYPE = {
+		INTENSITY: 1,
+		INTENSITY_ALPHA: 2,
+		RGB: 3,
+		RGBA: 4
+	};
+
 	return VRMLLoader;
 	return VRMLLoader;
 
 
 } )();
 } )();

+ 0 - 2219
examples/js/loaders/deprecated/LegacyGLTFLoader.js

@@ -1,2219 +0,0 @@
-/**
- * @author Rich Tibbett / https://github.com/richtr
- * @author mrdoob / http://mrdoob.com/
- * @author Tony Parisi / http://www.tonyparisi.com/
- * @author Takahiro / https://github.com/takahirox
- */
-
-THREE.LegacyGLTFLoader = ( function () {
-
-	function LegacyGLTFLoader( manager ) {
-
-		THREE.Loader.call( this, manager );
-
-	}
-
-	LegacyGLTFLoader.prototype = Object.assign( Object.create( THREE.Loader.prototype ), {
-
-		constructor: LegacyGLTFLoader,
-
-		load: function ( url, onLoad, onProgress, onError ) {
-
-			var scope = this;
-
-			var resourcePath;
-
-			if ( this.resourcePath !== '' ) {
-
-				resourcePath = this.resourcePath;
-
-			} else if ( this.path !== '' ) {
-
-				resourcePath = this.path;
-
-			} else {
-
-				resourcePath = THREE.LoaderUtils.extractUrlBase( url );
-
-			}
-
-			var loader = new THREE.FileLoader( scope.manager );
-
-			loader.setPath( this.path );
-			loader.setResponseType( 'arraybuffer' );
-
-			loader.load( url, function ( data ) {
-
-				scope.parse( data, resourcePath, onLoad );
-
-			}, onProgress, onError );
-
-		},
-
-		parse: function ( data, path, callback ) {
-
-			var content;
-			var extensions = {};
-
-			var magic = THREE.LoaderUtils.decodeText( new Uint8Array( data, 0, 4 ) );
-
-			if ( magic === BINARY_EXTENSION_HEADER_DEFAULTS.magic ) {
-
-				extensions[ EXTENSIONS.KHR_BINARY_GLTF ] = new GLTFBinaryExtension( data );
-				content = extensions[ EXTENSIONS.KHR_BINARY_GLTF ].content;
-
-			} else {
-
-				content = THREE.LoaderUtils.decodeText( new Uint8Array( data ) );
-
-			}
-
-			var json = JSON.parse( content );
-
-			if ( json.extensionsUsed && json.extensionsUsed.indexOf( EXTENSIONS.KHR_MATERIALS_COMMON ) >= 0 ) {
-
-				extensions[ EXTENSIONS.KHR_MATERIALS_COMMON ] = new GLTFMaterialsCommonExtension( json );
-
-			}
-
-			var parser = new GLTFParser( json, extensions, {
-
-				crossOrigin: this.crossOrigin,
-				manager: this.manager,
-				path: path || this.resourcePath || ''
-
-			} );
-
-			parser.parse( function ( scene, scenes, cameras, animations ) {
-
-				var glTF = {
-					"scene": scene,
-					"scenes": scenes,
-					"cameras": cameras,
-					"animations": animations
-				};
-
-				callback( glTF );
-
-			} );
-
-		}
-
-	} );
-
-	/* GLTFREGISTRY */
-
-	function GLTFRegistry() {
-
-		var objects = {};
-
-		return	{
-
-			get: function ( key ) {
-
-				return objects[ key ];
-
-			},
-
-			add: function ( key, object ) {
-
-				objects[ key ] = object;
-
-			},
-
-			remove: function ( key ) {
-
-				delete objects[ key ];
-
-			},
-
-			removeAll: function () {
-
-				objects = {};
-
-			},
-
-			update: function ( scene, camera ) {
-
-				for ( var name in objects ) {
-
-					var object = objects[ name ];
-
-					if ( object.update ) {
-
-						object.update( scene, camera );
-
-					}
-
-				}
-
-			}
-
-		};
-
-	}
-
-	/* GLTFSHADERS */
-
-	LegacyGLTFLoader.Shaders = {
-
-		update: function () {
-
-			console.warn( 'THREE.LegacyGLTFLoader.Shaders has been deprecated, and now updates automatically.' );
-
-		}
-
-	};
-
-	/* GLTFSHADER */
-
-	function GLTFShader( targetNode, allNodes ) {
-
-		var boundUniforms = {};
-
-		// bind each uniform to its source node
-
-		var uniforms = targetNode.material.uniforms;
-
-		for ( var uniformId in uniforms ) {
-
-			var uniform = uniforms[ uniformId ];
-
-			if ( uniform.semantic ) {
-
-				var sourceNodeRef = uniform.node;
-
-				var sourceNode = targetNode;
-
-				if ( sourceNodeRef ) {
-
-					sourceNode = allNodes[ sourceNodeRef ];
-
-				}
-
-				boundUniforms[ uniformId ] = {
-					semantic: uniform.semantic,
-					sourceNode: sourceNode,
-					targetNode: targetNode,
-					uniform: uniform
-				};
-
-			}
-
-		}
-
-		this.boundUniforms = boundUniforms;
-		this._m4 = new THREE.Matrix4();
-
-	}
-
-	// Update - update all the uniform values
-	GLTFShader.prototype.update = function ( scene, camera ) {
-
-		var boundUniforms = this.boundUniforms;
-
-		for ( var name in boundUniforms ) {
-
-			var boundUniform = boundUniforms[ name ];
-
-			switch ( boundUniform.semantic ) {
-
-				case "MODELVIEW":
-
-					var m4 = boundUniform.uniform.value;
-					m4.multiplyMatrices( camera.matrixWorldInverse, boundUniform.sourceNode.matrixWorld );
-					break;
-
-				case "MODELVIEWINVERSETRANSPOSE":
-
-					var m3 = boundUniform.uniform.value;
-					this._m4.multiplyMatrices( camera.matrixWorldInverse, boundUniform.sourceNode.matrixWorld );
-					m3.getNormalMatrix( this._m4 );
-					break;
-
-				case "PROJECTION":
-
-					var m4 = boundUniform.uniform.value;
-					m4.copy( camera.projectionMatrix );
-					break;
-
-				case "JOINTMATRIX":
-
-					var m4v = boundUniform.uniform.value;
-
-					for ( var mi = 0; mi < m4v.length; mi ++ ) {
-
-						// So it goes like this:
-						// SkinnedMesh world matrix is already baked into MODELVIEW;
-						// transform joints to local space,
-						// then transform using joint's inverse
-						m4v[ mi ]
-							.getInverse( boundUniform.sourceNode.matrixWorld )
-							.multiply( boundUniform.targetNode.skeleton.bones[ mi ].matrixWorld )
-							.multiply( boundUniform.targetNode.skeleton.boneInverses[ mi ] )
-							.multiply( boundUniform.targetNode.bindMatrix );
-
-					}
-
-					break;
-
-				default :
-
-					console.warn( "Unhandled shader semantic: " + boundUniform.semantic );
-					break;
-
-			}
-
-		}
-
-	};
-
-
-	/* ANIMATION */
-
-	LegacyGLTFLoader.Animations = {
-
-		update: function () {
-
-			console.warn( 'THREE.LegacyGLTFLoader.Animation has been deprecated. Use THREE.AnimationMixer instead.' );
-
-		}
-
-	};
-
-	/*********************************/
-	/********** EXTENSIONS ***********/
-	/*********************************/
-
-	var EXTENSIONS = {
-		KHR_BINARY_GLTF: 'KHR_binary_glTF',
-		KHR_MATERIALS_COMMON: 'KHR_materials_common'
-	};
-
-	/* MATERIALS COMMON EXTENSION */
-
-	function GLTFMaterialsCommonExtension( json ) {
-
-		this.name = EXTENSIONS.KHR_MATERIALS_COMMON;
-
-		this.lights = {};
-
-		var extension = ( json.extensions && json.extensions[ EXTENSIONS.KHR_MATERIALS_COMMON ] ) || {};
-		var lights = extension.lights || {};
-
-		for ( var lightId in lights ) {
-
-			var light = lights[ lightId ];
-			var lightNode;
-
-			var lightParams = light[ light.type ];
-			var color = new THREE.Color().fromArray( lightParams.color );
-
-			switch ( light.type ) {
-
-				case "directional":
-					lightNode = new THREE.DirectionalLight( color );
-					lightNode.position.set( 0, 0, 1 );
-					break;
-
-				case "point":
-					lightNode = new THREE.PointLight( color );
-					break;
-
-				case "spot":
-					lightNode = new THREE.SpotLight( color );
-					lightNode.position.set( 0, 0, 1 );
-					break;
-
-				case "ambient":
-					lightNode = new THREE.AmbientLight( color );
-					break;
-
-			}
-
-			if ( lightNode ) {
-
-				this.lights[ lightId ] = lightNode;
-
-			}
-
-		}
-
-	}
-
-	/* BINARY EXTENSION */
-
-	var BINARY_EXTENSION_BUFFER_NAME = 'binary_glTF';
-
-	var BINARY_EXTENSION_HEADER_DEFAULTS = { magic: 'glTF', version: 1, contentFormat: 0 };
-
-	var BINARY_EXTENSION_HEADER_LENGTH = 20;
-
-	function GLTFBinaryExtension( data ) {
-
-		this.name = EXTENSIONS.KHR_BINARY_GLTF;
-
-		var headerView = new DataView( data, 0, BINARY_EXTENSION_HEADER_LENGTH );
-
-		var header = {
-			magic: THREE.LoaderUtils.decodeText( new Uint8Array( data.slice( 0, 4 ) ) ),
-			version: headerView.getUint32( 4, true ),
-			length: headerView.getUint32( 8, true ),
-			contentLength: headerView.getUint32( 12, true ),
-			contentFormat: headerView.getUint32( 16, true )
-		};
-
-		for ( var key in BINARY_EXTENSION_HEADER_DEFAULTS ) {
-
-			var value = BINARY_EXTENSION_HEADER_DEFAULTS[ key ];
-
-			if ( header[ key ] !== value ) {
-
-				throw new Error( 'Unsupported glTF-Binary header: Expected "%s" to be "%s".', key, value );
-
-			}
-
-		}
-
-		var contentArray = new Uint8Array( data, BINARY_EXTENSION_HEADER_LENGTH, header.contentLength );
-
-		this.header = header;
-		this.content = THREE.LoaderUtils.decodeText( contentArray );
-		this.body = data.slice( BINARY_EXTENSION_HEADER_LENGTH + header.contentLength, header.length );
-
-	}
-
-	GLTFBinaryExtension.prototype.loadShader = function ( shader, bufferViews ) {
-
-		var bufferView = bufferViews[ shader.extensions[ EXTENSIONS.KHR_BINARY_GLTF ].bufferView ];
-		var array = new Uint8Array( bufferView );
-
-		return THREE.LoaderUtils.decodeText( array );
-
-	};
-
-	/*********************************/
-	/********** INTERNALS ************/
-	/*********************************/
-
-	/* CONSTANTS */
-
-	var WEBGL_CONSTANTS = {
-		FLOAT: 5126,
-		//FLOAT_MAT2: 35674,
-		FLOAT_MAT3: 35675,
-		FLOAT_MAT4: 35676,
-		FLOAT_VEC2: 35664,
-		FLOAT_VEC3: 35665,
-		FLOAT_VEC4: 35666,
-		LINEAR: 9729,
-		REPEAT: 10497,
-		SAMPLER_2D: 35678,
-		TRIANGLES: 4,
-		LINES: 1,
-		UNSIGNED_BYTE: 5121,
-		UNSIGNED_SHORT: 5123,
-
-		VERTEX_SHADER: 35633,
-		FRAGMENT_SHADER: 35632
-	};
-
-	var WEBGL_TYPE = {
-		5126: Number,
-		//35674: THREE.Matrix2,
-		35675: THREE.Matrix3,
-		35676: THREE.Matrix4,
-		35664: THREE.Vector2,
-		35665: THREE.Vector3,
-		35666: THREE.Vector4,
-		35678: THREE.Texture
-	};
-
-	var WEBGL_COMPONENT_TYPES = {
-		5120: Int8Array,
-		5121: Uint8Array,
-		5122: Int16Array,
-		5123: Uint16Array,
-		5125: Uint32Array,
-		5126: Float32Array
-	};
-
-	var WEBGL_FILTERS = {
-		9728: THREE.NearestFilter,
-		9729: THREE.LinearFilter,
-		9984: THREE.NearestMipmapNearestFilter,
-		9985: THREE.LinearMipmapNearestFilter,
-		9986: THREE.NearestMipmapLinearFilter,
-		9987: THREE.LinearMipmapLinearFilter
-	};
-
-	var WEBGL_WRAPPINGS = {
-		33071: THREE.ClampToEdgeWrapping,
-		33648: THREE.MirroredRepeatWrapping,
-		10497: THREE.RepeatWrapping
-	};
-
-	var WEBGL_TEXTURE_FORMATS = {
-		6406: THREE.AlphaFormat,
-		6407: THREE.RGBFormat,
-		6408: THREE.RGBAFormat,
-		6409: THREE.LuminanceFormat,
-		6410: THREE.LuminanceAlphaFormat
-	};
-
-	var WEBGL_TEXTURE_DATATYPES = {
-		5121: THREE.UnsignedByteType,
-		32819: THREE.UnsignedShort4444Type,
-		32820: THREE.UnsignedShort5551Type,
-		33635: THREE.UnsignedShort565Type
-	};
-
-	var WEBGL_SIDES = {
-		1028: THREE.BackSide, // Culling front
-		1029: THREE.FrontSide // Culling back
-		//1032: THREE.NoSide   // Culling front and back, what to do?
-	};
-
-	var WEBGL_DEPTH_FUNCS = {
-		512: THREE.NeverDepth,
-		513: THREE.LessDepth,
-		514: THREE.EqualDepth,
-		515: THREE.LessEqualDepth,
-		516: THREE.GreaterEqualDepth,
-		517: THREE.NotEqualDepth,
-		518: THREE.GreaterEqualDepth,
-		519: THREE.AlwaysDepth
-	};
-
-	var WEBGL_BLEND_EQUATIONS = {
-		32774: THREE.AddEquation,
-		32778: THREE.SubtractEquation,
-		32779: THREE.ReverseSubtractEquation
-	};
-
-	var WEBGL_BLEND_FUNCS = {
-		0: THREE.ZeroFactor,
-		1: THREE.OneFactor,
-		768: THREE.SrcColorFactor,
-		769: THREE.OneMinusSrcColorFactor,
-		770: THREE.SrcAlphaFactor,
-		771: THREE.OneMinusSrcAlphaFactor,
-		772: THREE.DstAlphaFactor,
-		773: THREE.OneMinusDstAlphaFactor,
-		774: THREE.DstColorFactor,
-		775: THREE.OneMinusDstColorFactor,
-		776: THREE.SrcAlphaSaturateFactor
-		// The followings are not supported by Three.js yet
-		//32769: CONSTANT_COLOR,
-		//32770: ONE_MINUS_CONSTANT_COLOR,
-		//32771: CONSTANT_ALPHA,
-		//32772: ONE_MINUS_CONSTANT_COLOR
-	};
-
-	var WEBGL_TYPE_SIZES = {
-		'SCALAR': 1,
-		'VEC2': 2,
-		'VEC3': 3,
-		'VEC4': 4,
-		'MAT2': 4,
-		'MAT3': 9,
-		'MAT4': 16
-	};
-
-	var PATH_PROPERTIES = {
-		scale: 'scale',
-		translation: 'position',
-		rotation: 'quaternion'
-	};
-
-	var INTERPOLATION = {
-		LINEAR: THREE.InterpolateLinear,
-		STEP: THREE.InterpolateDiscrete
-	};
-
-	var STATES_ENABLES = {
-		2884: 'CULL_FACE',
-		2929: 'DEPTH_TEST',
-		3042: 'BLEND',
-		3089: 'SCISSOR_TEST',
-		32823: 'POLYGON_OFFSET_FILL',
-		32926: 'SAMPLE_ALPHA_TO_COVERAGE'
-	};
-
-	/* UTILITY FUNCTIONS */
-
-	function _each( object, callback, thisObj ) {
-
-		if ( ! object ) {
-
-			return Promise.resolve();
-
-		}
-
-		var results;
-		var fns = [];
-
-		if ( Object.prototype.toString.call( object ) === '[object Array]' ) {
-
-			results = [];
-
-			var length = object.length;
-
-			for ( var idx = 0; idx < length; idx ++ ) {
-
-				var value = callback.call( thisObj || this, object[ idx ], idx );
-
-				if ( value ) {
-
-					fns.push( value );
-
-					if ( value instanceof Promise ) {
-
-						value.then( function ( key, value ) {
-
-							results[ key ] = value;
-
-						}.bind( this, idx ) );
-
-					} else {
-
-						results[ idx ] = value;
-
-					}
-
-				}
-
-			}
-
-		} else {
-
-			results = {};
-
-			for ( var key in object ) {
-
-				if ( object.hasOwnProperty( key ) ) {
-
-					var value = callback.call( thisObj || this, object[ key ], key );
-
-					if ( value ) {
-
-						fns.push( value );
-
-						if ( value instanceof Promise ) {
-
-							value.then( function ( key, value ) {
-
-								results[ key ] = value;
-
-							}.bind( this, key ) );
-
-						} else {
-
-							results[ key ] = value;
-
-						}
-
-					}
-
-				}
-
-			}
-
-		}
-
-		return Promise.all( fns ).then( function () {
-
-			return results;
-
-		} );
-
-	}
-
-	function resolveURL( url, path ) {
-
-		// Invalid URL
-		if ( typeof url !== 'string' || url === '' )
-			return '';
-
-		// Absolute URL http://,https://,//
-		if ( /^(https?:)?\/\//i.test( url ) ) {
-
-			return url;
-
-		}
-
-		// Data URI
-		if ( /^data:.*,.*$/i.test( url ) ) {
-
-			return url;
-
-		}
-
-		// Blob URL
-		if ( /^blob:.*$/i.test( url ) ) {
-
-			return url;
-
-		}
-
-		// Relative URL
-		return ( path || '' ) + url;
-
-	}
-
-	// Three.js seems too dependent on attribute names so globally
-	// replace those in the shader code
-	function replaceTHREEShaderAttributes( shaderText, technique ) {
-
-		// Expected technique attributes
-		var attributes = {};
-
-		for ( var attributeId in technique.attributes ) {
-
-			var pname = technique.attributes[ attributeId ];
-
-			var param = technique.parameters[ pname ];
-			var atype = param.type;
-			var semantic = param.semantic;
-
-			attributes[ attributeId ] = {
-				type: atype,
-				semantic: semantic
-			};
-
-		}
-
-		// Figure out which attributes to change in technique
-
-		var shaderParams = technique.parameters;
-		var shaderAttributes = technique.attributes;
-		var params = {};
-
-		for ( var attributeId in attributes ) {
-
-			var pname = shaderAttributes[ attributeId ];
-			var shaderParam = shaderParams[ pname ];
-			var semantic = shaderParam.semantic;
-			if ( semantic ) {
-
-				params[ attributeId ] = shaderParam;
-
-			}
-
-		}
-
-		for ( var pname in params ) {
-
-			var param = params[ pname ];
-			var semantic = param.semantic;
-
-			var regEx = new RegExp( "\\b" + pname + "\\b", "g" );
-
-			switch ( semantic ) {
-
-				case "POSITION":
-
-					shaderText = shaderText.replace( regEx, 'position' );
-					break;
-
-				case "NORMAL":
-
-					shaderText = shaderText.replace( regEx, 'normal' );
-					break;
-
-				case 'TEXCOORD_0':
-				case 'TEXCOORD0':
-				case 'TEXCOORD':
-
-					shaderText = shaderText.replace( regEx, 'uv' );
-					break;
-
-				case 'TEXCOORD_1':
-
-					shaderText = shaderText.replace( regEx, 'uv2' );
-					break;
-
-				case 'COLOR_0':
-				case 'COLOR0':
-				case 'COLOR':
-
-					shaderText = shaderText.replace( regEx, 'color' );
-					break;
-
-				case "WEIGHT":
-
-					shaderText = shaderText.replace( regEx, 'skinWeight' );
-					break;
-
-				case "JOINT":
-
-					shaderText = shaderText.replace( regEx, 'skinIndex' );
-					break;
-
-			}
-
-		}
-
-		return shaderText;
-
-	}
-
-	function createDefaultMaterial() {
-
-		return new THREE.MeshPhongMaterial( {
-			color: 0x00000,
-			emissive: 0x888888,
-			specular: 0x000000,
-			shininess: 0,
-			transparent: false,
-			depthTest: true,
-			side: THREE.FrontSide
-		} );
-
-	}
-
-	// Deferred constructor for RawShaderMaterial types
-	function DeferredShaderMaterial( params ) {
-
-		this.isDeferredShaderMaterial = true;
-
-		this.params = params;
-
-	}
-
-	DeferredShaderMaterial.prototype.create = function () {
-
-		var uniforms = THREE.UniformsUtils.clone( this.params.uniforms );
-
-		for ( var uniformId in this.params.uniforms ) {
-
-			var originalUniform = this.params.uniforms[ uniformId ];
-
-			if ( originalUniform.value instanceof THREE.Texture ) {
-
-				uniforms[ uniformId ].value = originalUniform.value;
-				uniforms[ uniformId ].value.needsUpdate = true;
-
-			}
-
-			uniforms[ uniformId ].semantic = originalUniform.semantic;
-			uniforms[ uniformId ].node = originalUniform.node;
-
-		}
-
-		this.params.uniforms = uniforms;
-
-		return new THREE.RawShaderMaterial( this.params );
-
-	};
-
-	/* GLTF PARSER */
-
-	function GLTFParser( json, extensions, options ) {
-
-		this.json = json || {};
-		this.extensions = extensions || {};
-		this.options = options || {};
-
-		// loader object cache
-		this.cache = new GLTFRegistry();
-
-	}
-
-	GLTFParser.prototype._withDependencies = function ( dependencies ) {
-
-		var _dependencies = {};
-
-		for ( var i = 0; i < dependencies.length; i ++ ) {
-
-			var dependency = dependencies[ i ];
-			var fnName = "load" + dependency.charAt( 0 ).toUpperCase() + dependency.slice( 1 );
-
-			var cached = this.cache.get( dependency );
-
-			if ( cached !== undefined ) {
-
-				_dependencies[ dependency ] = cached;
-
-			} else if ( this[ fnName ] ) {
-
-				var fn = this[ fnName ]();
-				this.cache.add( dependency, fn );
-
-				_dependencies[ dependency ] = fn;
-
-			}
-
-		}
-
-		return _each( _dependencies, function ( dependency ) {
-
-			return dependency;
-
-		} );
-
-	};
-
-	GLTFParser.prototype.parse = function ( callback ) {
-
-		var json = this.json;
-
-		// Clear the loader cache
-		this.cache.removeAll();
-
-		// Fire the callback on complete
-		this._withDependencies( [
-
-			"scenes",
-			"cameras",
-			"animations"
-
-		] ).then( function ( dependencies ) {
-
-			var scenes = [];
-
-			for ( var name in dependencies.scenes ) {
-
-				scenes.push( dependencies.scenes[ name ] );
-
-			}
-
-			var scene = json.scene !== undefined ? dependencies.scenes[ json.scene ] : scenes[ 0 ];
-
-			var cameras = [];
-
-			for ( var name in dependencies.cameras ) {
-
-				var camera = dependencies.cameras[ name ];
-				cameras.push( camera );
-
-			}
-
-			var animations = [];
-
-			for ( var name in dependencies.animations ) {
-
-				animations.push( dependencies.animations[ name ] );
-
-			}
-
-			callback( scene, scenes, cameras, animations );
-
-		} );
-
-	};
-
-	GLTFParser.prototype.loadShaders = function () {
-
-		var json = this.json;
-		var extensions = this.extensions;
-		var options = this.options;
-
-		return this._withDependencies( [
-
-			"bufferViews"
-
-		] ).then( function ( dependencies ) {
-
-			return _each( json.shaders, function ( shader ) {
-
-				if ( shader.extensions && shader.extensions[ EXTENSIONS.KHR_BINARY_GLTF ] ) {
-
-					return extensions[ EXTENSIONS.KHR_BINARY_GLTF ].loadShader( shader, dependencies.bufferViews );
-
-				}
-
-				return new Promise( function ( resolve ) {
-
-					var loader = new THREE.FileLoader( options.manager );
-					loader.setResponseType( 'text' );
-					loader.load( resolveURL( shader.uri, options.path ), function ( shaderText ) {
-
-						resolve( shaderText );
-
-					} );
-
-				} );
-
-			} );
-
-		} );
-
-	};
-
-	GLTFParser.prototype.loadBuffers = function () {
-
-		var json = this.json;
-		var extensions = this.extensions;
-		var options = this.options;
-
-		return _each( json.buffers, function ( buffer, name ) {
-
-			if ( name === BINARY_EXTENSION_BUFFER_NAME ) {
-
-				return extensions[ EXTENSIONS.KHR_BINARY_GLTF ].body;
-
-			}
-
-			if ( buffer.type === 'arraybuffer' || buffer.type === undefined ) {
-
-				return new Promise( function ( resolve ) {
-
-					var loader = new THREE.FileLoader( options.manager );
-					loader.setResponseType( 'arraybuffer' );
-					loader.load( resolveURL( buffer.uri, options.path ), function ( buffer ) {
-
-						resolve( buffer );
-
-					} );
-
-				} );
-
-			} else {
-
-				console.warn( 'THREE.LegacyGLTFLoader: ' + buffer.type + ' buffer type is not supported' );
-
-			}
-
-		} );
-
-	};
-
-	GLTFParser.prototype.loadBufferViews = function () {
-
-		var json = this.json;
-
-		return this._withDependencies( [
-
-			"buffers"
-
-		] ).then( function ( dependencies ) {
-
-			return _each( json.bufferViews, function ( bufferView ) {
-
-				var arraybuffer = dependencies.buffers[ bufferView.buffer ];
-
-				var byteLength = bufferView.byteLength !== undefined ? bufferView.byteLength : 0;
-
-				return arraybuffer.slice( bufferView.byteOffset, bufferView.byteOffset + byteLength );
-
-			} );
-
-		} );
-
-	};
-
-	GLTFParser.prototype.loadAccessors = function () {
-
-		var json = this.json;
-
-		return this._withDependencies( [
-
-			"bufferViews"
-
-		] ).then( function ( dependencies ) {
-
-			return _each( json.accessors, function ( accessor ) {
-
-				var arraybuffer = dependencies.bufferViews[ accessor.bufferView ];
-				var itemSize = WEBGL_TYPE_SIZES[ accessor.type ];
-				var TypedArray = WEBGL_COMPONENT_TYPES[ accessor.componentType ];
-
-				// For VEC3: itemSize is 3, elementBytes is 4, itemBytes is 12.
-				var elementBytes = TypedArray.BYTES_PER_ELEMENT;
-				var itemBytes = elementBytes * itemSize;
-
-				// The buffer is not interleaved if the stride is the item size in bytes.
-				if ( accessor.byteStride && accessor.byteStride !== itemBytes ) {
-
-					// Use the full buffer if it's interleaved.
-					var array = new TypedArray( arraybuffer );
-
-					// Integer parameters to IB/IBA are in array elements, not bytes.
-					var ib = new THREE.InterleavedBuffer( array, accessor.byteStride / elementBytes );
-
-					return new THREE.InterleavedBufferAttribute( ib, itemSize, accessor.byteOffset / elementBytes );
-
-				} else {
-
-					array = new TypedArray( arraybuffer, accessor.byteOffset, accessor.count * itemSize );
-
-					return new THREE.BufferAttribute( array, itemSize );
-
-				}
-
-			} );
-
-		} );
-
-	};
-
-	GLTFParser.prototype.loadTextures = function () {
-
-		var json = this.json;
-		var options = this.options;
-
-		return this._withDependencies( [
-
-			"bufferViews"
-
-		] ).then( function ( dependencies ) {
-
-			return _each( json.textures, function ( texture ) {
-
-				if ( texture.source ) {
-
-					return new Promise( function ( resolve ) {
-
-						var source = json.images[ texture.source ];
-						var sourceUri = source.uri;
-						var isObjectURL = false;
-
-						if ( source.extensions && source.extensions[ EXTENSIONS.KHR_BINARY_GLTF ] ) {
-
-							var metadata = source.extensions[ EXTENSIONS.KHR_BINARY_GLTF ];
-							var bufferView = dependencies.bufferViews[ metadata.bufferView ];
-							var blob = new Blob( [ bufferView ], { type: metadata.mimeType } );
-							sourceUri = URL.createObjectURL( blob );
-							isObjectURL = true;
-
-						}
-
-						var textureLoader = options.manager.getHandler( sourceUri );
-
-						if ( textureLoader === null ) {
-
-							textureLoader = new THREE.TextureLoader( options.manager );
-
-						}
-
-						textureLoader.setCrossOrigin( options.crossOrigin );
-
-						textureLoader.load( resolveURL( sourceUri, options.path ), function ( _texture ) {
-
-							if ( isObjectURL ) URL.revokeObjectURL( sourceUri );
-
-							_texture.flipY = false;
-
-							if ( texture.name !== undefined ) _texture.name = texture.name;
-
-							_texture.format = texture.format !== undefined ? WEBGL_TEXTURE_FORMATS[ texture.format ] : THREE.RGBAFormat;
-
-							if ( texture.internalFormat !== undefined && _texture.format !== WEBGL_TEXTURE_FORMATS[ texture.internalFormat ] ) {
-
-								console.warn( 'THREE.LegacyGLTFLoader: Three.js doesn\'t support texture internalFormat which is different from texture format. ' +
-															'internalFormat will be forced to be the same value as format.' );
-
-							}
-
-							_texture.type = texture.type !== undefined ? WEBGL_TEXTURE_DATATYPES[ texture.type ] : THREE.UnsignedByteType;
-
-							if ( texture.sampler ) {
-
-								var sampler = json.samplers[ texture.sampler ];
-
-								_texture.magFilter = WEBGL_FILTERS[ sampler.magFilter ] || THREE.LinearFilter;
-								_texture.minFilter = WEBGL_FILTERS[ sampler.minFilter ] || THREE.NearestMipmapLinearFilter;
-								_texture.wrapS = WEBGL_WRAPPINGS[ sampler.wrapS ] || THREE.RepeatWrapping;
-								_texture.wrapT = WEBGL_WRAPPINGS[ sampler.wrapT ] || THREE.RepeatWrapping;
-
-							}
-
-							resolve( _texture );
-
-						}, undefined, function () {
-
-							if ( isObjectURL ) URL.revokeObjectURL( sourceUri );
-
-							resolve();
-
-						} );
-
-					} );
-
-				}
-
-			} );
-
-		} );
-
-	};
-
-	GLTFParser.prototype.loadMaterials = function () {
-
-		var json = this.json;
-
-		return this._withDependencies( [
-
-			"shaders",
-			"textures"
-
-		] ).then( function ( dependencies ) {
-
-			return _each( json.materials, function ( material ) {
-
-				var materialType;
-				var materialValues = {};
-				var materialParams = {};
-
-				var khr_material;
-
-				if ( material.extensions && material.extensions[ EXTENSIONS.KHR_MATERIALS_COMMON ] ) {
-
-					khr_material = material.extensions[ EXTENSIONS.KHR_MATERIALS_COMMON ];
-
-				}
-
-				if ( khr_material ) {
-
-					// don't copy over unused values to avoid material warning spam
-					var keys = [ 'ambient', 'emission', 'transparent', 'transparency', 'doubleSided' ];
-
-					switch ( khr_material.technique ) {
-
-						case 'BLINN' :
-						case 'PHONG' :
-							materialType = THREE.MeshPhongMaterial;
-							keys.push( 'diffuse', 'specular', 'shininess' );
-							break;
-
-						case 'LAMBERT' :
-							materialType = THREE.MeshLambertMaterial;
-							keys.push( 'diffuse' );
-							break;
-
-						case 'CONSTANT' :
-						default :
-							materialType = THREE.MeshBasicMaterial;
-							break;
-
-					}
-
-					keys.forEach( function ( v ) {
-
-						if ( khr_material.values[ v ] !== undefined ) materialValues[ v ] = khr_material.values[ v ];
-
-					} );
-
-					if ( khr_material.doubleSided || materialValues.doubleSided ) {
-
-						materialParams.side = THREE.DoubleSide;
-
-					}
-
-					if ( khr_material.transparent || materialValues.transparent ) {
-
-						materialParams.transparent = true;
-						materialParams.opacity = ( materialValues.transparency !== undefined ) ? materialValues.transparency : 1;
-
-					}
-
-				} else if ( material.technique === undefined ) {
-
-					materialType = THREE.MeshPhongMaterial;
-
-					Object.assign( materialValues, material.values );
-
-				} else {
-
-					materialType = DeferredShaderMaterial;
-
-					var technique = json.techniques[ material.technique ];
-
-					materialParams.uniforms = {};
-
-					var program = json.programs[ technique.program ];
-
-					if ( program ) {
-
-						materialParams.fragmentShader = dependencies.shaders[ program.fragmentShader ];
-
-						if ( ! materialParams.fragmentShader ) {
-
-							console.warn( "ERROR: Missing fragment shader definition:", program.fragmentShader );
-							materialType = THREE.MeshPhongMaterial;
-
-						}
-
-						var vertexShader = dependencies.shaders[ program.vertexShader ];
-
-						if ( ! vertexShader ) {
-
-							console.warn( "ERROR: Missing vertex shader definition:", program.vertexShader );
-							materialType = THREE.MeshPhongMaterial;
-
-						}
-
-						// IMPORTANT: FIX VERTEX SHADER ATTRIBUTE DEFINITIONS
-						materialParams.vertexShader = replaceTHREEShaderAttributes( vertexShader, technique );
-
-						var uniforms = technique.uniforms;
-
-						for ( var uniformId in uniforms ) {
-
-							var pname = uniforms[ uniformId ];
-							var shaderParam = technique.parameters[ pname ];
-
-							var ptype = shaderParam.type;
-
-							if ( WEBGL_TYPE[ ptype ] ) {
-
-								var pcount = shaderParam.count;
-								var value;
-
-								if ( material.values !== undefined ) value = material.values[ pname ];
-
-								var uvalue = new WEBGL_TYPE[ ptype ]();
-								var usemantic = shaderParam.semantic;
-								var unode = shaderParam.node;
-
-								switch ( ptype ) {
-
-									case WEBGL_CONSTANTS.FLOAT:
-
-										uvalue = shaderParam.value;
-
-										if ( pname == "transparency" ) {
-
-											materialParams.transparent = true;
-
-										}
-
-										if ( value !== undefined ) {
-
-											uvalue = value;
-
-										}
-
-										break;
-
-									case WEBGL_CONSTANTS.FLOAT_VEC2:
-									case WEBGL_CONSTANTS.FLOAT_VEC3:
-									case WEBGL_CONSTANTS.FLOAT_VEC4:
-									case WEBGL_CONSTANTS.FLOAT_MAT3:
-
-										if ( shaderParam && shaderParam.value ) {
-
-											uvalue.fromArray( shaderParam.value );
-
-										}
-
-										if ( value ) {
-
-											uvalue.fromArray( value );
-
-										}
-
-										break;
-
-									case WEBGL_CONSTANTS.FLOAT_MAT2:
-
-										// what to do?
-										console.warn( "FLOAT_MAT2 is not a supported uniform type" );
-										break;
-
-									case WEBGL_CONSTANTS.FLOAT_MAT4:
-
-										if ( pcount ) {
-
-											uvalue = new Array( pcount );
-
-											for ( var mi = 0; mi < pcount; mi ++ ) {
-
-												uvalue[ mi ] = new WEBGL_TYPE[ ptype ]();
-
-											}
-
-											if ( shaderParam && shaderParam.value ) {
-
-												var m4v = shaderParam.value;
-												uvalue.fromArray( m4v );
-
-											}
-
-											if ( value ) {
-
-												uvalue.fromArray( value );
-
-											}
-
-										} else {
-
-											if ( shaderParam && shaderParam.value ) {
-
-												var m4 = shaderParam.value;
-												uvalue.fromArray( m4 );
-
-											}
-
-											if ( value ) {
-
-												uvalue.fromArray( value );
-
-											}
-
-										}
-
-										break;
-
-									case WEBGL_CONSTANTS.SAMPLER_2D:
-
-										if ( value !== undefined ) {
-
-											uvalue = dependencies.textures[ value ];
-
-										} else if ( shaderParam.value !== undefined ) {
-
-											uvalue = dependencies.textures[ shaderParam.value ];
-
-										} else {
-
-											uvalue = null;
-
-										}
-
-										break;
-
-								}
-
-								materialParams.uniforms[ uniformId ] = {
-									value: uvalue,
-									semantic: usemantic,
-									node: unode
-								};
-
-							} else {
-
-								throw new Error( "Unknown shader uniform param type: " + ptype );
-
-							}
-
-						}
-
-						var states = technique.states || {};
-						var enables = states.enable || [];
-						var functions = states.functions || {};
-
-						var enableCullFace = false;
-						var enableDepthTest = false;
-						var enableBlend = false;
-
-						for ( var i = 0, il = enables.length; i < il; i ++ ) {
-
-							var enable = enables[ i ];
-
-							switch ( STATES_ENABLES[ enable ] ) {
-
-								case 'CULL_FACE':
-
-									enableCullFace = true;
-
-									break;
-
-								case 'DEPTH_TEST':
-
-									enableDepthTest = true;
-
-									break;
-
-								case 'BLEND':
-
-									enableBlend = true;
-
-									break;
-
-								// TODO: implement
-								case 'SCISSOR_TEST':
-								case 'POLYGON_OFFSET_FILL':
-								case 'SAMPLE_ALPHA_TO_COVERAGE':
-
-									break;
-
-								default:
-
-									throw new Error( "Unknown technique.states.enable: " + enable );
-
-							}
-
-						}
-
-						if ( enableCullFace ) {
-
-							materialParams.side = functions.cullFace !== undefined ? WEBGL_SIDES[ functions.cullFace ] : THREE.FrontSide;
-
-						} else {
-
-							materialParams.side = THREE.DoubleSide;
-
-						}
-
-						materialParams.depthTest = enableDepthTest;
-						materialParams.depthFunc = functions.depthFunc !== undefined ? WEBGL_DEPTH_FUNCS[ functions.depthFunc ] : THREE.LessDepth;
-						materialParams.depthWrite = functions.depthMask !== undefined ? functions.depthMask[ 0 ] : true;
-
-						materialParams.blending = enableBlend ? THREE.CustomBlending : THREE.NoBlending;
-						materialParams.transparent = enableBlend;
-
-						var blendEquationSeparate = functions.blendEquationSeparate;
-
-						if ( blendEquationSeparate !== undefined ) {
-
-							materialParams.blendEquation = WEBGL_BLEND_EQUATIONS[ blendEquationSeparate[ 0 ] ];
-							materialParams.blendEquationAlpha = WEBGL_BLEND_EQUATIONS[ blendEquationSeparate[ 1 ] ];
-
-						} else {
-
-							materialParams.blendEquation = THREE.AddEquation;
-							materialParams.blendEquationAlpha = THREE.AddEquation;
-
-						}
-
-						var blendFuncSeparate = functions.blendFuncSeparate;
-
-						if ( blendFuncSeparate !== undefined ) {
-
-							materialParams.blendSrc = WEBGL_BLEND_FUNCS[ blendFuncSeparate[ 0 ] ];
-							materialParams.blendDst = WEBGL_BLEND_FUNCS[ blendFuncSeparate[ 1 ] ];
-							materialParams.blendSrcAlpha = WEBGL_BLEND_FUNCS[ blendFuncSeparate[ 2 ] ];
-							materialParams.blendDstAlpha = WEBGL_BLEND_FUNCS[ blendFuncSeparate[ 3 ] ];
-
-						} else {
-
-							materialParams.blendSrc = THREE.OneFactor;
-							materialParams.blendDst = THREE.ZeroFactor;
-							materialParams.blendSrcAlpha = THREE.OneFactor;
-							materialParams.blendDstAlpha = THREE.ZeroFactor;
-
-						}
-
-					}
-
-				}
-
-				if ( Array.isArray( materialValues.diffuse ) ) {
-
-					materialParams.color = new THREE.Color().fromArray( materialValues.diffuse );
-
-				} else if ( typeof ( materialValues.diffuse ) === 'string' ) {
-
-					materialParams.map = dependencies.textures[ materialValues.diffuse ];
-
-				}
-
-				delete materialParams.diffuse;
-
-				if ( typeof ( materialValues.reflective ) === 'string' ) {
-
-					materialParams.envMap = dependencies.textures[ materialValues.reflective ];
-
-				}
-
-				if ( typeof ( materialValues.bump ) === 'string' ) {
-
-					materialParams.bumpMap = dependencies.textures[ materialValues.bump ];
-
-				}
-
-				if ( Array.isArray( materialValues.emission ) ) {
-
-					if ( materialType === THREE.MeshBasicMaterial ) {
-
-						materialParams.color = new THREE.Color().fromArray( materialValues.emission );
-
-					} else {
-
-						materialParams.emissive = new THREE.Color().fromArray( materialValues.emission );
-
-					}
-
-				} else if ( typeof ( materialValues.emission ) === 'string' ) {
-
-					if ( materialType === THREE.MeshBasicMaterial ) {
-
-						materialParams.map = dependencies.textures[ materialValues.emission ];
-
-					} else {
-
-						materialParams.emissiveMap = dependencies.textures[ materialValues.emission ];
-
-					}
-
-				}
-
-				if ( Array.isArray( materialValues.specular ) ) {
-
-					materialParams.specular = new THREE.Color().fromArray( materialValues.specular );
-
-				} else if ( typeof ( materialValues.specular ) === 'string' ) {
-
-					materialParams.specularMap = dependencies.textures[ materialValues.specular ];
-
-				}
-
-				if ( materialValues.shininess !== undefined ) {
-
-					materialParams.shininess = materialValues.shininess;
-
-				}
-
-				var _material = new materialType( materialParams );
-				if ( material.name !== undefined ) _material.name = material.name;
-
-				return _material;
-
-			} );
-
-		} );
-
-	};
-
-	GLTFParser.prototype.loadMeshes = function () {
-
-		var json = this.json;
-
-		return this._withDependencies( [
-
-			"accessors",
-			"materials"
-
-		] ).then( function ( dependencies ) {
-
-			return _each( json.meshes, function ( mesh ) {
-
-				var group = new THREE.Group();
-				if ( mesh.name !== undefined ) group.name = mesh.name;
-
-				if ( mesh.extras ) group.userData = mesh.extras;
-
-				var primitives = mesh.primitives || [];
-
-				for ( var name in primitives ) {
-
-					var primitive = primitives[ name ];
-
-					if ( primitive.mode === WEBGL_CONSTANTS.TRIANGLES || primitive.mode === undefined ) {
-
-						var geometry = new THREE.BufferGeometry();
-
-						var attributes = primitive.attributes;
-
-						for ( var attributeId in attributes ) {
-
-							var attributeEntry = attributes[ attributeId ];
-
-							if ( ! attributeEntry ) return;
-
-							var bufferAttribute = dependencies.accessors[ attributeEntry ];
-
-							switch ( attributeId ) {
-
-								case 'POSITION':
-									geometry.setAttribute( 'position', bufferAttribute );
-									break;
-
-								case 'NORMAL':
-									geometry.setAttribute( 'normal', bufferAttribute );
-									break;
-
-								case 'TEXCOORD_0':
-								case 'TEXCOORD0':
-								case 'TEXCOORD':
-									geometry.setAttribute( 'uv', bufferAttribute );
-									break;
-
-								case 'TEXCOORD_1':
-									geometry.setAttribute( 'uv2', bufferAttribute );
-									break;
-
-								case 'COLOR_0':
-								case 'COLOR0':
-								case 'COLOR':
-									geometry.setAttribute( 'color', bufferAttribute );
-									break;
-
-								case 'WEIGHT':
-									geometry.setAttribute( 'skinWeight', bufferAttribute );
-									break;
-
-								case 'JOINT':
-									geometry.setAttribute( 'skinIndex', bufferAttribute );
-									break;
-
-								default:
-
-									if ( ! primitive.material ) break;
-
-									var material = json.materials[ primitive.material ];
-
-									if ( ! material.technique ) break;
-
-									var parameters = json.techniques[ material.technique ].parameters || {};
-
-									for ( var attributeName in parameters ) {
-
-										if ( parameters[ attributeName ][ 'semantic' ] === attributeId ) {
-
-											geometry.setAttribute( attributeName, bufferAttribute );
-
-										}
-
-									}
-
-							}
-
-						}
-
-						if ( primitive.indices ) {
-
-							geometry.setIndex( dependencies.accessors[ primitive.indices ] );
-
-						}
-
-						var material = dependencies.materials !== undefined ? dependencies.materials[ primitive.material ] : createDefaultMaterial();
-
-						var meshNode = new THREE.Mesh( geometry, material );
-						meshNode.castShadow = true;
-						meshNode.name = ( name === "0" ? group.name : group.name + name );
-
-						if ( primitive.extras ) meshNode.userData = primitive.extras;
-
-						group.add( meshNode );
-
-					} else if ( primitive.mode === WEBGL_CONSTANTS.LINES ) {
-
-						var geometry = new THREE.BufferGeometry();
-
-						var attributes = primitive.attributes;
-
-						for ( var attributeId in attributes ) {
-
-							var attributeEntry = attributes[ attributeId ];
-
-							if ( ! attributeEntry ) return;
-
-							var bufferAttribute = dependencies.accessors[ attributeEntry ];
-
-							switch ( attributeId ) {
-
-								case 'POSITION':
-									geometry.setAttribute( 'position', bufferAttribute );
-									break;
-
-								case 'COLOR_0':
-								case 'COLOR0':
-								case 'COLOR':
-									geometry.setAttribute( 'color', bufferAttribute );
-									break;
-
-							}
-
-						}
-
-						var material = dependencies.materials[ primitive.material ];
-
-						var meshNode;
-
-						if ( primitive.indices ) {
-
-							geometry.setIndex( dependencies.accessors[ primitive.indices ] );
-
-							meshNode = new THREE.LineSegments( geometry, material );
-
-						} else {
-
-							meshNode = new THREE.Line( geometry, material );
-
-						}
-
-						meshNode.name = ( name === "0" ? group.name : group.name + name );
-
-						if ( primitive.extras ) meshNode.userData = primitive.extras;
-
-						group.add( meshNode );
-
-					} else {
-
-						console.warn( "Only triangular and line primitives are supported" );
-
-					}
-
-				}
-
-				return group;
-
-			} );
-
-		} );
-
-	};
-
-	GLTFParser.prototype.loadCameras = function () {
-
-		var json = this.json;
-
-		return _each( json.cameras, function ( camera ) {
-
-			if ( camera.type == "perspective" && camera.perspective ) {
-
-				var yfov = camera.perspective.yfov;
-				var aspectRatio = camera.perspective.aspectRatio !== undefined ? camera.perspective.aspectRatio : 1;
-
-				// According to COLLADA spec...
-				// aspectRatio = xfov / yfov
-				var xfov = yfov * aspectRatio;
-
-				var _camera = new THREE.PerspectiveCamera( THREE.Math.radToDeg( xfov ), aspectRatio, camera.perspective.znear || 1, camera.perspective.zfar || 2e6 );
-				if ( camera.name !== undefined ) _camera.name = camera.name;
-
-				if ( camera.extras ) _camera.userData = camera.extras;
-
-				return _camera;
-
-			} else if ( camera.type == "orthographic" && camera.orthographic ) {
-
-				var _camera = new THREE.OrthographicCamera( window.innerWidth / - 2, window.innerWidth / 2, window.innerHeight / 2, window.innerHeight / - 2, camera.orthographic.znear, camera.orthographic.zfar );
-				if ( camera.name !== undefined ) _camera.name = camera.name;
-
-				if ( camera.extras ) _camera.userData = camera.extras;
-
-				return _camera;
-
-			}
-
-		} );
-
-	};
-
-	GLTFParser.prototype.loadSkins = function () {
-
-		var json = this.json;
-
-		return this._withDependencies( [
-
-			"accessors"
-
-		] ).then( function ( dependencies ) {
-
-			return _each( json.skins, function ( skin ) {
-
-				var bindShapeMatrix = new THREE.Matrix4();
-
-				if ( skin.bindShapeMatrix !== undefined ) bindShapeMatrix.fromArray( skin.bindShapeMatrix );
-
-				var _skin = {
-					bindShapeMatrix: bindShapeMatrix,
-					jointNames: skin.jointNames,
-					inverseBindMatrices: dependencies.accessors[ skin.inverseBindMatrices ]
-				};
-
-				return _skin;
-
-			} );
-
-		} );
-
-	};
-
-	GLTFParser.prototype.loadAnimations = function () {
-
-		var json = this.json;
-
-		return this._withDependencies( [
-
-			"accessors",
-			"nodes"
-
-		] ).then( function ( dependencies ) {
-
-			return _each( json.animations, function ( animation, animationId ) {
-
-				var tracks = [];
-
-				for ( var channelId in animation.channels ) {
-
-					var channel = animation.channels[ channelId ];
-					var sampler = animation.samplers[ channel.sampler ];
-
-					if ( sampler ) {
-
-						var target = channel.target;
-						var name = target.id;
-						var input = animation.parameters !== undefined ? animation.parameters[ sampler.input ] : sampler.input;
-						var output = animation.parameters !== undefined ? animation.parameters[ sampler.output ] : sampler.output;
-
-						var inputAccessor = dependencies.accessors[ input ];
-						var outputAccessor = dependencies.accessors[ output ];
-
-						var node = dependencies.nodes[ name ];
-
-						if ( node ) {
-
-							node.updateMatrix();
-							node.matrixAutoUpdate = true;
-
-							var TypedKeyframeTrack = PATH_PROPERTIES[ target.path ] === PATH_PROPERTIES.rotation
-								? THREE.QuaternionKeyframeTrack
-								: THREE.VectorKeyframeTrack;
-
-							var targetName = node.name ? node.name : node.uuid;
-							var interpolation = sampler.interpolation !== undefined ? INTERPOLATION[ sampler.interpolation ] : THREE.InterpolateLinear;
-
-							// KeyframeTrack.optimize() will modify given 'times' and 'values'
-							// buffers before creating a truncated copy to keep. Because buffers may
-							// be reused by other tracks, make copies here.
-							tracks.push( new TypedKeyframeTrack(
-								targetName + '.' + PATH_PROPERTIES[ target.path ],
-								THREE.AnimationUtils.arraySlice( inputAccessor.array, 0 ),
-								THREE.AnimationUtils.arraySlice( outputAccessor.array, 0 ),
-								interpolation
-							) );
-
-						}
-
-					}
-
-				}
-
-				var name = animation.name !== undefined ? animation.name : "animation_" + animationId;
-
-				return new THREE.AnimationClip( name, undefined, tracks );
-
-			} );
-
-		} );
-
-	};
-
-	GLTFParser.prototype.loadNodes = function () {
-
-		var json = this.json;
-		var extensions = this.extensions;
-		var scope = this;
-
-		return _each( json.nodes, function ( node ) {
-
-			var matrix = new THREE.Matrix4();
-
-			var _node;
-
-			if ( node.jointName ) {
-
-				_node = new THREE.Bone();
-				_node.name = node.name !== undefined ? node.name : node.jointName;
-				_node.jointName = node.jointName;
-
-			} else {
-
-				_node = new THREE.Object3D();
-				if ( node.name !== undefined ) _node.name = node.name;
-
-			}
-
-			if ( node.extras ) _node.userData = node.extras;
-
-			if ( node.matrix !== undefined ) {
-
-				matrix.fromArray( node.matrix );
-				_node.applyMatrix( matrix );
-
-			} else {
-
-				if ( node.translation !== undefined ) {
-
-					_node.position.fromArray( node.translation );
-
-				}
-
-				if ( node.rotation !== undefined ) {
-
-					_node.quaternion.fromArray( node.rotation );
-
-				}
-
-				if ( node.scale !== undefined ) {
-
-					_node.scale.fromArray( node.scale );
-
-				}
-
-			}
-
-			return _node;
-
-		} ).then( function ( __nodes ) {
-
-			return scope._withDependencies( [
-
-				"meshes",
-				"skins",
-				"cameras"
-
-			] ).then( function ( dependencies ) {
-
-				return _each( __nodes, function ( _node, nodeId ) {
-
-					var node = json.nodes[ nodeId ];
-
-					if ( node.meshes !== undefined ) {
-
-						for ( var meshId in node.meshes ) {
-
-							var mesh = node.meshes[ meshId ];
-							var group = dependencies.meshes[ mesh ];
-
-							if ( group === undefined ) {
-
-								console.warn( 'LegacyGLTFLoader: Couldn\'t find node "' + mesh + '".' );
-								continue;
-
-							}
-
-							for ( var childrenId in group.children ) {
-
-								var child = group.children[ childrenId ];
-
-								// clone Mesh to add to _node
-
-								var originalMaterial = child.material;
-								var originalGeometry = child.geometry;
-								var originalUserData = child.userData;
-								var originalName = child.name;
-
-								var material;
-
-								if ( originalMaterial.isDeferredShaderMaterial ) {
-
-									originalMaterial = material = originalMaterial.create();
-
-								} else {
-
-									material = originalMaterial;
-
-								}
-
-								switch ( child.type ) {
-
-									case 'LineSegments':
-										child = new THREE.LineSegments( originalGeometry, material );
-										break;
-
-									case 'LineLoop':
-										child = new THREE.LineLoop( originalGeometry, material );
-										break;
-
-									case 'Line':
-										child = new THREE.Line( originalGeometry, material );
-										break;
-
-									default:
-										child = new THREE.Mesh( originalGeometry, material );
-
-								}
-
-								child.castShadow = true;
-								child.userData = originalUserData;
-								child.name = originalName;
-
-								var skinEntry;
-
-								if ( node.skin ) {
-
-									skinEntry = dependencies.skins[ node.skin ];
-
-								}
-
-								// Replace Mesh with SkinnedMesh in library
-								if ( skinEntry ) {
-
-									var getJointNode = function ( jointId ) {
-
-										var keys = Object.keys( __nodes );
-
-										for ( var i = 0, il = keys.length; i < il; i ++ ) {
-
-											var n = __nodes[ keys[ i ] ];
-
-											if ( n.jointName === jointId ) return n;
-
-										}
-
-										return null;
-
-									};
-
-									var geometry = originalGeometry;
-									var material = originalMaterial;
-									material.skinning = true;
-
-									child = new THREE.SkinnedMesh( geometry, material );
-									child.castShadow = true;
-									child.userData = originalUserData;
-									child.name = originalName;
-
-									var bones = [];
-									var boneInverses = [];
-
-									for ( var i = 0, l = skinEntry.jointNames.length; i < l; i ++ ) {
-
-										var jointId = skinEntry.jointNames[ i ];
-										var jointNode = getJointNode( jointId );
-
-										if ( jointNode ) {
-
-											bones.push( jointNode );
-
-											var m = skinEntry.inverseBindMatrices.array;
-											var mat = new THREE.Matrix4().fromArray( m, i * 16 );
-											boneInverses.push( mat );
-
-										} else {
-
-											console.warn( "WARNING: joint: '" + jointId + "' could not be found" );
-
-										}
-
-									}
-
-									child.bind( new THREE.Skeleton( bones, boneInverses ), skinEntry.bindShapeMatrix );
-
-									var buildBoneGraph = function ( parentJson, parentObject, property ) {
-
-										var children = parentJson[ property ];
-
-										if ( children === undefined ) return;
-
-										for ( var i = 0, il = children.length; i < il; i ++ ) {
-
-											var nodeId = children[ i ];
-											var bone = __nodes[ nodeId ];
-											var boneJson = json.nodes[ nodeId ];
-
-											if ( bone !== undefined && bone.isBone === true && boneJson !== undefined ) {
-
-												parentObject.add( bone );
-												buildBoneGraph( boneJson, bone, 'children' );
-
-											}
-
-										}
-
-									};
-
-									buildBoneGraph( node, child, 'skeletons' );
-
-								}
-
-								_node.add( child );
-
-							}
-
-						}
-
-					}
-
-					if ( node.camera !== undefined ) {
-
-						var camera = dependencies.cameras[ node.camera ];
-
-						_node.add( camera );
-
-					}
-
-					if ( node.extensions
-							 && node.extensions[ EXTENSIONS.KHR_MATERIALS_COMMON ]
-							 && node.extensions[ EXTENSIONS.KHR_MATERIALS_COMMON ].light ) {
-
-						var extensionLights = extensions[ EXTENSIONS.KHR_MATERIALS_COMMON ].lights;
-						var light = extensionLights[ node.extensions[ EXTENSIONS.KHR_MATERIALS_COMMON ].light ];
-
-						_node.add( light );
-
-					}
-
-					return _node;
-
-				} );
-
-			} );
-
-		} );
-
-	};
-
-	GLTFParser.prototype.loadScenes = function () {
-
-		var json = this.json;
-
-		// scene node hierachy builder
-
-		function buildNodeHierachy( nodeId, parentObject, allNodes ) {
-
-			var _node = allNodes[ nodeId ];
-			parentObject.add( _node );
-
-			var node = json.nodes[ nodeId ];
-
-			if ( node.children ) {
-
-				var children = node.children;
-
-				for ( var i = 0, l = children.length; i < l; i ++ ) {
-
-					var child = children[ i ];
-					buildNodeHierachy( child, _node, allNodes );
-
-				}
-
-			}
-
-		}
-
-		return this._withDependencies( [
-
-			"nodes"
-
-		] ).then( function ( dependencies ) {
-
-			return _each( json.scenes, function ( scene ) {
-
-				var _scene = new THREE.Scene();
-				if ( scene.name !== undefined ) _scene.name = scene.name;
-
-				if ( scene.extras ) _scene.userData = scene.extras;
-
-				var nodes = scene.nodes || [];
-
-				for ( var i = 0, l = nodes.length; i < l; i ++ ) {
-
-					var nodeId = nodes[ i ];
-					buildNodeHierachy( nodeId, _scene, dependencies.nodes );
-
-				}
-
-				_scene.traverse( function ( child ) {
-
-					// Register raw material meshes with LegacyGLTFLoader.Shaders
-					if ( child.material && child.material.isRawShaderMaterial ) {
-
-						child.gltfShader = new GLTFShader( child, dependencies.nodes );
-						child.onBeforeRender = function ( renderer, scene, camera ) {
-
-							this.gltfShader.update( scene, camera );
-
-						};
-
-					}
-
-				} );
-
-				return _scene;
-
-			} );
-
-		} );
-
-	};
-
-	return LegacyGLTFLoader;
-
-} )();

+ 0 - 821
examples/js/loaders/deprecated/LegacyJSONLoader.js

@@ -1,821 +0,0 @@
-/**
- * @author mrdoob / http://mrdoob.com/
- * @author alteredq / http://alteredqualia.com/
- */
-
-THREE.LegacyJSONLoader = ( function () {
-
-	function LegacyJSONLoader( manager ) {
-
-		if ( typeof manager === 'boolean' ) {
-
-			console.warn( 'THREE.JSONLoader: showStatus parameter has been removed from constructor.' );
-			manager = undefined;
-
-		}
-
-		THREE.Loader.call( this, manager );
-
-		this.withCredentials = false;
-
-	}
-
-	LegacyJSONLoader.prototype = Object.assign( Object.create( THREE.Loader.prototype ), {
-
-		constructor: LegacyJSONLoader,
-
-		load: function ( url, onLoad, onProgress, onError ) {
-
-			var scope = this;
-
-			var path = ( this.path === '' ) ? THREE.LoaderUtils.extractUrlBase( url ) : this.path;
-
-			var loader = new THREE.FileLoader( this.manager );
-			loader.setPath( this.path );
-			loader.setWithCredentials( this.withCredentials );
-			loader.load( url, function ( text ) {
-
-				var json = JSON.parse( text );
-				var metadata = json.metadata;
-
-				if ( metadata !== undefined ) {
-
-					var type = metadata.type;
-
-					if ( type !== undefined ) {
-
-						if ( type.toLowerCase() === 'object' ) {
-
-							console.error( 'THREE.JSONLoader: ' + url + ' should be loaded with THREE.ObjectLoader instead.' );
-							return;
-
-						}
-
-					}
-
-				}
-
-				var object = scope.parse( json, path );
-				onLoad( object.geometry, object.materials );
-
-			}, onProgress, onError );
-
-		},
-
-		parse: ( function () {
-
-			var _BlendingMode = {
-				NoBlending: THREE.NoBlending,
-				NormalBlending: THREE.NormalBlending,
-				AdditiveBlending: THREE.AdditiveBlending,
-				SubtractiveBlending: THREE.SubtractiveBlending,
-				MultiplyBlending: THREE.MultiplyBlending,
-				CustomBlending: THREE.CustomBlending
-			};
-
-			var _color = new THREE.Color();
-			var _textureLoader = new THREE.TextureLoader();
-			var _materialLoader = new THREE.MaterialLoader();
-
-			function initMaterials( materials, texturePath, crossOrigin, manager ) {
-
-				var array = [];
-
-				for ( var i = 0; i < materials.length; ++ i ) {
-
-					array[ i ] = createMaterial( materials[ i ], texturePath, crossOrigin, manager );
-
-				}
-
-				return array;
-
-			}
-
-			function createMaterial( m, texturePath, crossOrigin, manager ) {
-
-				// convert from old material format
-
-				var textures = {};
-
-				//
-
-				var json = {
-					uuid: THREE.Math.generateUUID(),
-					type: 'MeshLambertMaterial'
-				};
-
-				for ( var name in m ) {
-
-					var value = m[ name ];
-
-					switch ( name ) {
-
-						case 'DbgColor':
-						case 'DbgIndex':
-						case 'opticalDensity':
-						case 'illumination':
-							break;
-						case 'DbgName':
-							json.name = value;
-							break;
-						case 'blending':
-							json.blending = _BlendingMode[ value ];
-							break;
-						case 'colorAmbient':
-						case 'mapAmbient':
-							console.warn( 'THREE.LegacyJSONLoader.createMaterial:', name, 'is no longer supported.' );
-							break;
-						case 'colorDiffuse':
-							json.color = _color.fromArray( value ).getHex();
-							break;
-						case 'colorSpecular':
-							json.specular = _color.fromArray( value ).getHex();
-							break;
-						case 'colorEmissive':
-							json.emissive = _color.fromArray( value ).getHex();
-							break;
-						case 'specularCoef':
-							json.shininess = value;
-							break;
-						case 'shading':
-							if ( value.toLowerCase() === 'basic' ) json.type = 'MeshBasicMaterial';
-							if ( value.toLowerCase() === 'phong' ) json.type = 'MeshPhongMaterial';
-							if ( value.toLowerCase() === 'standard' ) json.type = 'MeshStandardMaterial';
-							break;
-						case 'mapDiffuse':
-							json.map = loadTexture( value, m.mapDiffuseRepeat, m.mapDiffuseOffset, m.mapDiffuseWrap, m.mapDiffuseAnisotropy, textures, texturePath, crossOrigin, manager );
-							break;
-						case 'mapDiffuseRepeat':
-						case 'mapDiffuseOffset':
-						case 'mapDiffuseWrap':
-						case 'mapDiffuseAnisotropy':
-							break;
-						case 'mapEmissive':
-							json.emissiveMap = loadTexture( value, m.mapEmissiveRepeat, m.mapEmissiveOffset, m.mapEmissiveWrap, m.mapEmissiveAnisotropy, textures, texturePath, crossOrigin, manager );
-							break;
-						case 'mapEmissiveRepeat':
-						case 'mapEmissiveOffset':
-						case 'mapEmissiveWrap':
-						case 'mapEmissiveAnisotropy':
-							break;
-						case 'mapLight':
-							json.lightMap = loadTexture( value, m.mapLightRepeat, m.mapLightOffset, m.mapLightWrap, m.mapLightAnisotropy, textures, texturePath, crossOrigin, manager );
-							break;
-						case 'mapLightRepeat':
-						case 'mapLightOffset':
-						case 'mapLightWrap':
-						case 'mapLightAnisotropy':
-							break;
-						case 'mapAO':
-							json.aoMap = loadTexture( value, m.mapAORepeat, m.mapAOOffset, m.mapAOWrap, m.mapAOAnisotropy, textures, texturePath, crossOrigin, manager );
-							break;
-						case 'mapAORepeat':
-						case 'mapAOOffset':
-						case 'mapAOWrap':
-						case 'mapAOAnisotropy':
-							break;
-						case 'mapBump':
-							json.bumpMap = loadTexture( value, m.mapBumpRepeat, m.mapBumpOffset, m.mapBumpWrap, m.mapBumpAnisotropy, textures, texturePath, crossOrigin, manager );
-							break;
-						case 'mapBumpScale':
-							json.bumpScale = value;
-							break;
-						case 'mapBumpRepeat':
-						case 'mapBumpOffset':
-						case 'mapBumpWrap':
-						case 'mapBumpAnisotropy':
-							break;
-						case 'mapNormal':
-							json.normalMap = loadTexture( value, m.mapNormalRepeat, m.mapNormalOffset, m.mapNormalWrap, m.mapNormalAnisotropy, textures, texturePath, crossOrigin, manager );
-							break;
-						case 'mapNormalFactor':
-							json.normalScale = value;
-							break;
-						case 'mapNormalRepeat':
-						case 'mapNormalOffset':
-						case 'mapNormalWrap':
-						case 'mapNormalAnisotropy':
-							break;
-						case 'mapSpecular':
-							json.specularMap = loadTexture( value, m.mapSpecularRepeat, m.mapSpecularOffset, m.mapSpecularWrap, m.mapSpecularAnisotropy, textures, texturePath, crossOrigin, manager );
-							break;
-						case 'mapSpecularRepeat':
-						case 'mapSpecularOffset':
-						case 'mapSpecularWrap':
-						case 'mapSpecularAnisotropy':
-							break;
-						case 'mapMetalness':
-							json.metalnessMap = loadTexture( value, m.mapMetalnessRepeat, m.mapMetalnessOffset, m.mapMetalnessWrap, m.mapMetalnessAnisotropy, textures, texturePath, crossOrigin, manager );
-							break;
-						case 'mapMetalnessRepeat':
-						case 'mapMetalnessOffset':
-						case 'mapMetalnessWrap':
-						case 'mapMetalnessAnisotropy':
-							break;
-						case 'mapRoughness':
-							json.roughnessMap = loadTexture( value, m.mapRoughnessRepeat, m.mapRoughnessOffset, m.mapRoughnessWrap, m.mapRoughnessAnisotropy, textures, texturePath, crossOrigin, manager );
-							break;
-						case 'mapRoughnessRepeat':
-						case 'mapRoughnessOffset':
-						case 'mapRoughnessWrap':
-						case 'mapRoughnessAnisotropy':
-							break;
-						case 'mapAlpha':
-							json.alphaMap = loadTexture( value, m.mapAlphaRepeat, m.mapAlphaOffset, m.mapAlphaWrap, m.mapAlphaAnisotropy, textures, texturePath, crossOrigin, manager );
-							break;
-						case 'mapAlphaRepeat':
-						case 'mapAlphaOffset':
-						case 'mapAlphaWrap':
-						case 'mapAlphaAnisotropy':
-							break;
-						case 'flipSided':
-							json.side = THREE.BackSide;
-							break;
-						case 'doubleSided':
-							json.side = THREE.DoubleSide;
-							break;
-						case 'transparency':
-							console.warn( 'THREE.LegacyJSONLoader.createMaterial: transparency has been renamed to opacity' );
-							json.opacity = value;
-							break;
-						case 'depthTest':
-						case 'depthWrite':
-						case 'colorWrite':
-						case 'opacity':
-						case 'reflectivity':
-						case 'transparent':
-						case 'visible':
-						case 'wireframe':
-							json[ name ] = value;
-							break;
-						case 'vertexColors':
-							if ( value === true ) json.vertexColors = THREE.VertexColors;
-							if ( value === 'face' ) json.vertexColors = THREE.FaceColors;
-							break;
-						default:
-							console.error( 'THREE.LegacyJSONLoader.createMaterial: Unsupported', name, value );
-							break;
-
-					}
-
-				}
-
-				if ( json.type === 'MeshBasicMaterial' ) delete json.emissive;
-				if ( json.type !== 'MeshPhongMaterial' ) delete json.specular;
-
-				if ( json.opacity < 1 ) json.transparent = true;
-
-				_materialLoader.setTextures( textures );
-
-				return _materialLoader.parse( json );
-
-			}
-
-			function loadTexture( path, repeat, offset, wrap, anisotropy, textures, texturePath, crossOrigin, manager ) {
-
-				var fullPath = texturePath + path;
-				var loader = manager.getHandler( fullPath );
-
-				var texture;
-
-				if ( loader !== null ) {
-
-					texture = loader.load( fullPath );
-
-				} else {
-
-					_textureLoader.setCrossOrigin( crossOrigin );
-					texture = _textureLoader.load( fullPath );
-
-				}
-
-				if ( repeat !== undefined ) {
-
-					texture.repeat.fromArray( repeat );
-
-					if ( repeat[ 0 ] !== 1 ) texture.wrapS = THREE.RepeatWrapping;
-					if ( repeat[ 1 ] !== 1 ) texture.wrapT = THREE.RepeatWrapping;
-
-				}
-
-				if ( offset !== undefined ) {
-
-					texture.offset.fromArray( offset );
-
-				}
-
-				if ( wrap !== undefined ) {
-
-					if ( wrap[ 0 ] === 'repeat' ) texture.wrapS = THREE.RepeatWrapping;
-					if ( wrap[ 0 ] === 'mirror' ) texture.wrapS = THREE.MirroredRepeatWrapping;
-
-					if ( wrap[ 1 ] === 'repeat' ) texture.wrapT = THREE.RepeatWrapping;
-					if ( wrap[ 1 ] === 'mirror' ) texture.wrapT = THREE.MirroredRepeatWrapping;
-
-				}
-
-				if ( anisotropy !== undefined ) {
-
-					texture.anisotropy = anisotropy;
-
-				}
-
-				var uuid = THREE.Math.generateUUID();
-
-				textures[ uuid ] = texture;
-
-				return uuid;
-
-			}
-
-			function parseModel( json, geometry ) {
-
-				function isBitSet( value, position ) {
-
-					return value & ( 1 << position );
-
-				}
-
-				var i, j, fi,
-
-					offset, zLength,
-
-					colorIndex, normalIndex, uvIndex, materialIndex,
-
-					type,
-					isQuad,
-					hasMaterial,
-					hasFaceVertexUv,
-					hasFaceNormal, hasFaceVertexNormal,
-					hasFaceColor, hasFaceVertexColor,
-
-					vertex, face, faceA, faceB, hex, normal,
-
-					uvLayer, uv, u, v,
-
-					faces = json.faces,
-					vertices = json.vertices,
-					normals = json.normals,
-					colors = json.colors,
-
-					scale = json.scale,
-
-					nUvLayers = 0;
-
-
-				if ( json.uvs !== undefined ) {
-
-					// disregard empty arrays
-
-					for ( i = 0; i < json.uvs.length; i ++ ) {
-
-						if ( json.uvs[ i ].length ) nUvLayers ++;
-
-					}
-
-					for ( i = 0; i < nUvLayers; i ++ ) {
-
-						geometry.faceVertexUvs[ i ] = [];
-
-					}
-
-				}
-
-				offset = 0;
-				zLength = vertices.length;
-
-				while ( offset < zLength ) {
-
-					vertex = new THREE.Vector3();
-
-					vertex.x = vertices[ offset ++ ] * scale;
-					vertex.y = vertices[ offset ++ ] * scale;
-					vertex.z = vertices[ offset ++ ] * scale;
-
-					geometry.vertices.push( vertex );
-
-				}
-
-				offset = 0;
-				zLength = faces.length;
-
-				while ( offset < zLength ) {
-
-					type = faces[ offset ++ ];
-
-					isQuad = isBitSet( type, 0 );
-					hasMaterial = isBitSet( type, 1 );
-					hasFaceVertexUv = isBitSet( type, 3 );
-					hasFaceNormal = isBitSet( type, 4 );
-					hasFaceVertexNormal = isBitSet( type, 5 );
-					hasFaceColor = isBitSet( type, 6 );
-					hasFaceVertexColor = isBitSet( type, 7 );
-
-					// console.log("type", type, "bits", isQuad, hasMaterial, hasFaceVertexUv, hasFaceNormal, hasFaceVertexNormal, hasFaceColor, hasFaceVertexColor);
-
-					if ( isQuad ) {
-
-						faceA = new THREE.Face3();
-						faceA.a = faces[ offset ];
-						faceA.b = faces[ offset + 1 ];
-						faceA.c = faces[ offset + 3 ];
-
-						faceB = new THREE.Face3();
-						faceB.a = faces[ offset + 1 ];
-						faceB.b = faces[ offset + 2 ];
-						faceB.c = faces[ offset + 3 ];
-
-						offset += 4;
-
-						if ( hasMaterial ) {
-
-							materialIndex = faces[ offset ++ ];
-							faceA.materialIndex = materialIndex;
-							faceB.materialIndex = materialIndex;
-
-						}
-
-						// to get face <=> uv index correspondence
-
-						fi = geometry.faces.length;
-
-						if ( hasFaceVertexUv ) {
-
-							for ( i = 0; i < nUvLayers; i ++ ) {
-
-								uvLayer = json.uvs[ i ];
-
-								geometry.faceVertexUvs[ i ][ fi ] = [];
-								geometry.faceVertexUvs[ i ][ fi + 1 ] = [];
-
-								for ( j = 0; j < 4; j ++ ) {
-
-									uvIndex = faces[ offset ++ ];
-
-									u = uvLayer[ uvIndex * 2 ];
-									v = uvLayer[ uvIndex * 2 + 1 ];
-
-									uv = new THREE.Vector2( u, v );
-
-									if ( j !== 2 ) geometry.faceVertexUvs[ i ][ fi ].push( uv );
-									if ( j !== 0 ) geometry.faceVertexUvs[ i ][ fi + 1 ].push( uv );
-
-								}
-
-							}
-
-						}
-
-						if ( hasFaceNormal ) {
-
-							normalIndex = faces[ offset ++ ] * 3;
-
-							faceA.normal.set(
-								normals[ normalIndex ++ ],
-								normals[ normalIndex ++ ],
-								normals[ normalIndex ]
-							);
-
-							faceB.normal.copy( faceA.normal );
-
-						}
-
-						if ( hasFaceVertexNormal ) {
-
-							for ( i = 0; i < 4; i ++ ) {
-
-								normalIndex = faces[ offset ++ ] * 3;
-
-								normal = new THREE.Vector3(
-									normals[ normalIndex ++ ],
-									normals[ normalIndex ++ ],
-									normals[ normalIndex ]
-								);
-
-
-								if ( i !== 2 ) faceA.vertexNormals.push( normal );
-								if ( i !== 0 ) faceB.vertexNormals.push( normal );
-
-							}
-
-						}
-
-
-						if ( hasFaceColor ) {
-
-							colorIndex = faces[ offset ++ ];
-							hex = colors[ colorIndex ];
-
-							faceA.color.setHex( hex );
-							faceB.color.setHex( hex );
-
-						}
-
-
-						if ( hasFaceVertexColor ) {
-
-							for ( i = 0; i < 4; i ++ ) {
-
-								colorIndex = faces[ offset ++ ];
-								hex = colors[ colorIndex ];
-
-								if ( i !== 2 ) faceA.vertexColors.push( new THREE.Color( hex ) );
-								if ( i !== 0 ) faceB.vertexColors.push( new THREE.Color( hex ) );
-
-							}
-
-						}
-
-						geometry.faces.push( faceA );
-						geometry.faces.push( faceB );
-
-					} else {
-
-						face = new THREE.Face3();
-						face.a = faces[ offset ++ ];
-						face.b = faces[ offset ++ ];
-						face.c = faces[ offset ++ ];
-
-						if ( hasMaterial ) {
-
-							materialIndex = faces[ offset ++ ];
-							face.materialIndex = materialIndex;
-
-						}
-
-						// to get face <=> uv index correspondence
-
-						fi = geometry.faces.length;
-
-						if ( hasFaceVertexUv ) {
-
-							for ( i = 0; i < nUvLayers; i ++ ) {
-
-								uvLayer = json.uvs[ i ];
-
-								geometry.faceVertexUvs[ i ][ fi ] = [];
-
-								for ( j = 0; j < 3; j ++ ) {
-
-									uvIndex = faces[ offset ++ ];
-
-									u = uvLayer[ uvIndex * 2 ];
-									v = uvLayer[ uvIndex * 2 + 1 ];
-
-									uv = new THREE.Vector2( u, v );
-
-									geometry.faceVertexUvs[ i ][ fi ].push( uv );
-
-								}
-
-							}
-
-						}
-
-						if ( hasFaceNormal ) {
-
-							normalIndex = faces[ offset ++ ] * 3;
-
-							face.normal.set(
-								normals[ normalIndex ++ ],
-								normals[ normalIndex ++ ],
-								normals[ normalIndex ]
-							);
-
-						}
-
-						if ( hasFaceVertexNormal ) {
-
-							for ( i = 0; i < 3; i ++ ) {
-
-								normalIndex = faces[ offset ++ ] * 3;
-
-								normal = new THREE.Vector3(
-									normals[ normalIndex ++ ],
-									normals[ normalIndex ++ ],
-									normals[ normalIndex ]
-								);
-
-								face.vertexNormals.push( normal );
-
-							}
-
-						}
-
-
-						if ( hasFaceColor ) {
-
-							colorIndex = faces[ offset ++ ];
-							face.color.setHex( colors[ colorIndex ] );
-
-						}
-
-
-						if ( hasFaceVertexColor ) {
-
-							for ( i = 0; i < 3; i ++ ) {
-
-								colorIndex = faces[ offset ++ ];
-								face.vertexColors.push( new THREE.Color( colors[ colorIndex ] ) );
-
-							}
-
-						}
-
-						geometry.faces.push( face );
-
-					}
-
-				}
-
-			}
-
-			function parseSkin( json, geometry ) {
-
-				var influencesPerVertex = ( json.influencesPerVertex !== undefined ) ? json.influencesPerVertex : 2;
-
-				if ( json.skinWeights ) {
-
-					for ( var i = 0, l = json.skinWeights.length; i < l; i += influencesPerVertex ) {
-
-						var x = json.skinWeights[ i ];
-						var y = ( influencesPerVertex > 1 ) ? json.skinWeights[ i + 1 ] : 0;
-						var z = ( influencesPerVertex > 2 ) ? json.skinWeights[ i + 2 ] : 0;
-						var w = ( influencesPerVertex > 3 ) ? json.skinWeights[ i + 3 ] : 0;
-
-						geometry.skinWeights.push( new THREE.Vector4( x, y, z, w ) );
-
-					}
-
-				}
-
-				if ( json.skinIndices ) {
-
-					for ( var i = 0, l = json.skinIndices.length; i < l; i += influencesPerVertex ) {
-
-						var a = json.skinIndices[ i ];
-						var b = ( influencesPerVertex > 1 ) ? json.skinIndices[ i + 1 ] : 0;
-						var c = ( influencesPerVertex > 2 ) ? json.skinIndices[ i + 2 ] : 0;
-						var d = ( influencesPerVertex > 3 ) ? json.skinIndices[ i + 3 ] : 0;
-
-						geometry.skinIndices.push( new THREE.Vector4( a, b, c, d ) );
-
-					}
-
-				}
-
-				geometry.bones = json.bones;
-
-				if ( geometry.bones && geometry.bones.length > 0 && ( geometry.skinWeights.length !== geometry.skinIndices.length || geometry.skinIndices.length !== geometry.vertices.length ) ) {
-
-					console.warn( 'When skinning, number of vertices (' + geometry.vertices.length + '), skinIndices (' +
-						geometry.skinIndices.length + '), and skinWeights (' + geometry.skinWeights.length + ') should match.' );
-
-				}
-
-			}
-
-			function parseMorphing( json, geometry ) {
-
-				var scale = json.scale;
-
-				if ( json.morphTargets !== undefined ) {
-
-					for ( var i = 0, l = json.morphTargets.length; i < l; i ++ ) {
-
-						geometry.morphTargets[ i ] = {};
-						geometry.morphTargets[ i ].name = json.morphTargets[ i ].name;
-						geometry.morphTargets[ i ].vertices = [];
-
-						var dstVertices = geometry.morphTargets[ i ].vertices;
-						var srcVertices = json.morphTargets[ i ].vertices;
-
-						for ( var v = 0, vl = srcVertices.length; v < vl; v += 3 ) {
-
-							var vertex = new THREE.Vector3();
-							vertex.x = srcVertices[ v ] * scale;
-							vertex.y = srcVertices[ v + 1 ] * scale;
-							vertex.z = srcVertices[ v + 2 ] * scale;
-
-							dstVertices.push( vertex );
-
-						}
-
-					}
-
-				}
-
-				if ( json.morphColors !== undefined && json.morphColors.length > 0 ) {
-
-					console.warn( 'THREE.JSONLoader: "morphColors" no longer supported. Using them as face colors.' );
-
-					var faces = geometry.faces;
-					var morphColors = json.morphColors[ 0 ].colors;
-
-					for ( var i = 0, l = faces.length; i < l; i ++ ) {
-
-						faces[ i ].color.fromArray( morphColors, i * 3 );
-
-					}
-
-				}
-
-			}
-
-			function parseAnimations( json, geometry ) {
-
-				var outputAnimations = [];
-
-				// parse old style Bone/Hierarchy animations
-				var animations = [];
-
-				if ( json.animation !== undefined ) {
-
-					animations.push( json.animation );
-
-				}
-
-				if ( json.animations !== undefined ) {
-
-					if ( json.animations.length ) {
-
-						animations = animations.concat( json.animations );
-
-					} else {
-
-						animations.push( json.animations );
-
-					}
-
-				}
-
-				for ( var i = 0; i < animations.length; i ++ ) {
-
-					var clip = THREE.AnimationClip.parseAnimation( animations[ i ], geometry.bones );
-					if ( clip ) outputAnimations.push( clip );
-
-				}
-
-				// parse implicit morph animations
-				if ( geometry.morphTargets ) {
-
-					// TODO: Figure out what an appropraite FPS is for morph target animations -- defaulting to 10, but really it is completely arbitrary.
-					var morphAnimationClips = THREE.AnimationClip.CreateClipsFromMorphTargetSequences( geometry.morphTargets, 10 );
-					outputAnimations = outputAnimations.concat( morphAnimationClips );
-
-				}
-
-				if ( outputAnimations.length > 0 ) geometry.animations = outputAnimations;
-
-			}
-
-			return function parse( json, path ) {
-
-				if ( json.data !== undefined ) {
-
-					// Geometry 4.0 spec
-					json = json.data;
-
-				}
-
-				if ( json.scale !== undefined ) {
-
-					json.scale = 1.0 / json.scale;
-
-				} else {
-
-					json.scale = 1.0;
-
-				}
-
-				var geometry = new THREE.Geometry();
-
-				parseModel( json, geometry );
-				parseSkin( json, geometry );
-				parseMorphing( json, geometry );
-				parseAnimations( json, geometry );
-
-				geometry.computeFaceNormals();
-				geometry.computeBoundingSphere();
-
-				if ( json.materials === undefined || json.materials.length === 0 ) {
-
-					return { geometry: geometry };
-
-				} else {
-
-					var materials = initMaterials( json.materials, this.resourcePath || path, this.crossOrigin, this.manager );
-
-					return { geometry: geometry, materials: materials };
-
-				}
-
-			};
-
-		} )()
-
-	} );
-
-	return LegacyJSONLoader;
-
-} )();

+ 2 - 0
examples/js/pmrem/PMREMGenerator.js

@@ -150,6 +150,8 @@ THREE.PMREMGenerator = ( function () {
 
 
 			}
 			}
 
 
+			shader.dispose();
+
 		},
 		},
 
 
 	};
 	};

+ 7 - 3
examples/js/renderers/CSS2DRenderer.js

@@ -11,11 +11,15 @@ THREE.CSS2DObject = function ( element ) {
 
 
 	this.addEventListener( 'removed', function () {
 	this.addEventListener( 'removed', function () {
 
 
-		if ( this.element.parentNode !== null ) {
+		this.traverse( function ( object ) {
 
 
-			this.element.parentNode.removeChild( this.element );
+			if ( object.element instanceof Element && object.element.parentNode !== null ) {
 
 
-		}
+				object.element.parentNode.removeChild( object.element );
+
+			}
+
+		} );
 
 
 	} );
 	} );
 
 

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

@@ -13,7 +13,7 @@ THREE.CSS3DObject = function ( element ) {
 
 
 	this.addEventListener( 'removed', function () {
 	this.addEventListener( 'removed', function () {
 
 
-		this.traverse( function( object ) {
+		this.traverse( function ( object ) {
 
 
 			if ( object.element instanceof Element && object.element.parentNode !== null ) {
 			if ( object.element instanceof Element && object.element.parentNode !== null ) {
 
 

+ 14 - 3
examples/js/renderers/Projector.js

@@ -470,6 +470,7 @@ THREE.Projector = function () {
 						if ( material.morphTargets === true ) {
 						if ( material.morphTargets === true ) {
 
 
 							var morphTargets = geometry.morphAttributes.position;
 							var morphTargets = geometry.morphAttributes.position;
+							var morphTargetsRelative = geometry.morphTargetsRelative;
 							var morphInfluences = object.morphTargetInfluences;
 							var morphInfluences = object.morphTargetInfluences;
 
 
 							for ( var t = 0, tl = morphTargets.length; t < tl; t ++ ) {
 							for ( var t = 0, tl = morphTargets.length; t < tl; t ++ ) {
@@ -480,9 +481,19 @@ THREE.Projector = function () {
 
 
 								var target = morphTargets[ t ];
 								var target = morphTargets[ t ];
 
 
-								x += ( target.getX( i / 3 ) - positions[ i ] ) * influence;
-								y += ( target.getY( i / 3 ) - positions[ i + 1 ] ) * influence;
-								z += ( target.getZ( i / 3 ) - positions[ i + 2 ] ) * influence;
+								if ( morphTargetsRelative ) {
+
+									x += target.getX( i / 3 ) * influence;
+									y += target.getY( i / 3 ) * influence;
+									z += target.getZ( i / 3 ) * influence;
+
+								} else {
+
+									x += ( target.getX( i / 3 ) - positions[ i ] ) * influence;
+									y += ( target.getY( i / 3 ) - positions[ i + 1 ] ) * influence;
+									z += ( target.getZ( i / 3 ) - positions[ i + 2 ] ) * influence;
+
+								}
 
 
 							}
 							}
 
 

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

@@ -439,7 +439,7 @@ THREE.SVGRenderer = function () {
 
 
 		} else if ( material.isMeshNormalMaterial ) {
 		} else if ( material.isMeshNormalMaterial ) {
 
 
-			_normal.copy( element.normalModel ).applyMatrix3( _normalViewMatrix );
+			_normal.copy( element.normalModel ).applyMatrix3( _normalViewMatrix ).normalize();
 
 
 			_color.setRGB( _normal.x, _normal.y, _normal.z ).multiplyScalar( 0.5 ).addScalar( 0.5 );
 			_color.setRGB( _normal.x, _normal.y, _normal.z ).multiplyScalar( 0.5 ).addScalar( 0.5 );
 
 

+ 4 - 0
examples/js/utils/BufferGeometryUtils.js

@@ -199,6 +199,8 @@ THREE.BufferGeometryUtils = {
 		var attributes = {};
 		var attributes = {};
 		var morphAttributes = {};
 		var morphAttributes = {};
 
 
+		var morphTargetsRelative = geometries[ 0 ].morphTargetsRelative;
+
 		var mergedGeometry = new THREE.BufferGeometry();
 		var mergedGeometry = new THREE.BufferGeometry();
 
 
 		var offset = 0;
 		var offset = 0;
@@ -225,6 +227,8 @@ THREE.BufferGeometryUtils = {
 
 
 			// gather morph attributes, exit early if they're different
 			// gather morph attributes, exit early if they're different
 
 
+			if ( morphTargetsRelative !== geometry.morphTargetsRelative ) return null;
+
 			for ( var name in geometry.morphAttributes ) {
 			for ( var name in geometry.morphAttributes ) {
 
 
 				if ( ! morphAttributesUsed.has( name ) ) return null;
 				if ( ! morphAttributesUsed.has( name ) ) return null;

+ 13 - 155
examples/js/vr/HelioWebXRPolyfill.js

@@ -2,29 +2,24 @@
  * @author mvilledieu / http://github.com/mvilledieu
  * @author mvilledieu / http://github.com/mvilledieu
  */
  */
 
 
-if ( /(Helio)/g.test( navigator.userAgent ) && "xr" in navigator && 'isSessionSupported' in navigator.xr === false) {
+if ( /(Helio)/g.test( navigator.userAgent ) && 'xr' in navigator ) {
 
 
-	console.log( "Helio WebXR Polyfill (Lumin 0.97.0)" );
+	console.log( "Helio WebXR Polyfill (Lumin 0.98.0)" );
 
 
-	const isHelio96 = navigator.userAgent.includes( "Chrome/73" );
+	if ( 'isSessionSupported' in navigator.xr ) {
 
 
-	// WebXRManager - XR.supportSession() Polyfill - WebVR.js line 147
+		const tempIsSessionSupported = navigator.xr.isSessionSupported.bind( navigator.xr );
 
 
-	if (
-		"supportsSession" in navigator.xr === false &&
-	"supportsSessionMode" in navigator.xr
-	) {
-
-		navigator.xr.supportsSession = function ( /*sessionType*/ ) {
+		navigator.xr.isSessionSupported = function ( /*sessionType*/ ) {
 
 
 			// Force using immersive-ar
 			// Force using immersive-ar
-			return navigator.xr.supportsSessionMode( 'immersive-ar' );
+			return tempIsSessionSupported( 'immersive-ar' );
 
 
 		};
 		};
 
 
 	}
 	}
 
 
-	if ( "requestSession" in navigator.xr ) {
+	if ( 'isSessionSupported' in navigator.xr && 'requestSession' in navigator.xr ) {
 
 
 		const tempRequestSession = navigator.xr.requestSession.bind( navigator.xr );
 		const tempRequestSession = navigator.xr.requestSession.bind( navigator.xr );
 
 
@@ -32,154 +27,17 @@ if ( /(Helio)/g.test( navigator.userAgent ) && "xr" in navigator && 'isSessionSu
 
 
 			return new Promise( function ( resolve, reject ) {
 			return new Promise( function ( resolve, reject ) {
 
 
-				const sessionType = ( isHelio96 ? {
-					mode: 'immersive-ar' // Force using immersive-ar
-				} : 'immersive-ar' );
-
-				tempRequestSession( sessionType )
-					.then( function ( session ) {
-
-						// WebXRManager - xrFrame.getPose() Polyfill - line 279
-
-						const tempRequestAnimationFrame = session.requestAnimationFrame.bind(
-							session
-						);
-
-						session.requestAnimationFrame = function ( callback ) {
-
-							return tempRequestAnimationFrame( function ( time, frame ) {
-
-								// WebXRManager - xrFrame.getViewerPose() Polyfill - line 279
-								// Transforms view.viewMatrix to view.transform.inverse.matrix
-
-								const tempGetViewerPose = frame.getViewerPose.bind( frame );
-
-								frame.getViewerPose = function ( referenceSpace ) {
-
-									const pose = tempGetViewerPose( referenceSpace );
-
-									pose.views.forEach( function ( view ) {
-
-										view.transform = {
-											inverse: {
-												matrix: view.viewMatrix
-											}
-										};
-
-									} );
-
-									return pose;
-
-								};
-
-								// WebXRManager - xrFrame.getPose() Polyfill - line 259
-
-								const tempGetPose = ( isHelio96 ? null : frame.getPose.bind( frame ) );
-
-								frame.getPose = function ( targetRaySpace, referenceSpace ) {
-
-									if ( isHelio96 ) {
-
-										const inputPose = frame.getInputPose(
-											targetRaySpace,
-											referenceSpace
-										);
-
-										inputPose.transform = {
-											matrix: inputPose.targetRay.transformMatrix
-										};
-
-										return inputPose;
-
-									} else {
-
-										return tempGetPose( targetRaySpace.gripSpace, referenceSpace );
-
-									}
-
-								};
-
-								callback( time, frame );
-
-							} );
-
-						};
-
-						// WebXRManager - xrFrame.getPose( inputSource.targetRaySpace, referenceSpace) Polyfill - line 279
-
-						const tempGetInputSources = session.getInputSources.bind( session );
-
-						session.getInputSources = function () {
-
-							const res = tempGetInputSources();
-
-							res.forEach( function ( xrInputSource ) {
-
-								Object.defineProperty( xrInputSource, "targetRaySpace", {
-									get: function () {
-
-										return xrInputSource;
-
-									}
-								} );
-
-							} );
-
-							return res;
-
-						};
-
-						// WebXRManager - xrSession.getInputSources() Polyfill Line 132 - 136
-
-						session.inputSources = Object.defineProperty(
-							session,
-							"inputSources",
-							{
-								get: session.getInputSources
-							}
-						);
-
-						// WebXRManager - xrSession.updateRenderState() Polyfill Line 129
-
-						if ( isHelio96 ) {
-
-							session.updateRenderState = function ( { baseLayer } ) {
-
-								session.baseLayer = baseLayer;
-
-								// WebXRManager - xrSession.renderState.baseLayer Polyfill Line 219
-
-								session.renderState = {
-									baseLayer: baseLayer
-								};
-
-							};
-
-						}
-
-						// WebXRManager - xrSession.requestReferenceSpace() Polyfill Line 130
-
-						const tempRequestReferenceSpace = session.requestReferenceSpace.bind(
-							session
-						);
-
-						session.requestReferenceSpace = function () {
-
-							return tempRequestReferenceSpace( {
-								type: "stationary",
-								subtype: "floor-level"
-							} );
+				var sessionInit = { optionalFeatures: [ 'local-floor', 'bounded-floor' ] };
 
 
-						};
+				tempRequestSession( 'immersive-ar', sessionInit ).then( function ( session ) {
 
 
-						resolve( session );
+					resolve( session );
 
 
-					} )
-					.catch( function ( error ) {
+				} ).catch( function ( error ) {
 
 
-						return reject( error );
+					return reject( error );
 
 
-					} );
+				} );
 
 
 			} );
 			} );
 
 

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

@@ -1,184 +0,0 @@
-/**
- * @author mrdoob / http://mrdoob.com
- */
-
-THREE.PaintViveController = function ( id ) {
-
-	THREE.ViveController.call( this, id );
-
-	var PI2 = Math.PI * 2;
-
-	var MODES = { COLOR: 0, SIZE: 1 };
-	var mode = MODES.COLOR;
-
-	var color = new THREE.Color( 1, 1, 1 );
-	var size = 1.0;
-
-	//
-
-	function generateHueTexture() {
-
-		var canvas = document.createElement( 'canvas' );
-		canvas.width = 256;
-		canvas.height = 256;
-
-		var context = canvas.getContext( '2d' );
-		var imageData = context.getImageData( 0, 0, 256, 256 );
-		var data = imageData.data;
-		var swatchColor = new THREE.Color();
-
-		for ( var i = 0, j = 0; i < data.length; i += 4, j ++ ) {
-
-			var x = ( ( j % 256 ) / 256 ) - 0.5;
-			var y = ( Math.floor( j / 256 ) / 256 ) - 0.5;
-
-			swatchColor.setHSL( Math.atan2( y, x ) / PI2, 1, ( 0.5 - Math.sqrt( x * x + y * y ) ) * 2.0 );
-
-			data[ i + 0 ] = swatchColor.r * 256;
-			data[ i + 1 ] = swatchColor.g * 256;
-			data[ i + 2 ] = swatchColor.b * 256;
-			data[ i + 3 ] = 256;
-
-		}
-
-		context.putImageData( imageData, 0, 0 );
-
-		return new THREE.CanvasTexture( canvas );
-
-	}
-
-	// COLOR UI
-
-	var geometry = new THREE.CircleBufferGeometry( 1, 32 );
-	var material = new THREE.MeshBasicMaterial( { map: generateHueTexture() } );
-	var colorUI = new THREE.Mesh( geometry, material );
-	colorUI.position.set( 0, 0.005, 0.0495 );
-	colorUI.rotation.x = - 1.45;
-	colorUI.scale.setScalar( 0.02 );
-	this.add( colorUI );
-
-	var geometry = new THREE.IcosahedronBufferGeometry( 0.1, 2 );
-	var material = new THREE.MeshBasicMaterial();
-	material.color = color;
-	var ball = new THREE.Mesh( geometry, material );
-	colorUI.add( ball );
-
-
-	// SIZE UI
-	var sizeUI = new THREE.Group();
-	sizeUI.position.set( 0, 0.005, 0.0495 );
-	sizeUI.rotation.x = - 1.45;
-	sizeUI.scale.setScalar( 0.02 );
-	this.add( sizeUI );
-
-	var triangleShape = new THREE.Shape();
-	triangleShape.moveTo( 0, - 1 );
-	triangleShape.lineTo( 1, 1 );
-	triangleShape.lineTo( - 1, 1 );
-
-	var geometry = new THREE.ShapeBufferGeometry( triangleShape );
-	var material = new THREE.MeshBasicMaterial( { color: 0x222222, wireframe: true } );
-	var sizeUIOutline = new THREE.Mesh( geometry, material );
-	sizeUIOutline.position.z = 0.001;
-	resizeTriangleGeometry( sizeUIOutline.geometry, 1.0 );
-	sizeUI.add( sizeUIOutline );
-
-	var geometry = new THREE.ShapeBufferGeometry( triangleShape );
-	var material = new THREE.MeshBasicMaterial( { side: THREE.DoubleSide } );
-	material.color = color;
-	var sizeUIFill = new THREE.Mesh( geometry, material );
-	sizeUIFill.position.z = 0.0011;
-	resizeTriangleGeometry( sizeUIFill.geometry, 0.5 );
-	sizeUI.add( sizeUIFill );
-
-	sizeUI.visible = false;
-
-
-
-	function onAxisChanged( event ) {
-
-		if ( this.getButtonState( 'thumbpad' ) === false ) return;
-
-		var x = event.axes[ 0 ] / 2.0;
-		var y = - event.axes[ 1 ] / 2.0;
-
-		if ( mode === MODES.COLOR ) {
-
-			color.setHSL( Math.atan2( y, x ) / PI2, 1, ( 0.5 - Math.sqrt( x * x + y * y ) ) * 2.0 );
-
-			ball.position.set( event.axes[ 0 ], event.axes[ 1 ], 0 );
-
-		}
-
-		if ( mode === MODES.SIZE ) {
-
-			var ratio = 0.5 - y;
-			size = ratio * 2;
-
-			resizeTriangleGeometry( sizeUIFill.geometry, ratio );
-
-		}
-
-	}
-
-	function resizeTriangleGeometry( geometry, ratio ) {
-
-		var x = 0, y = 0;
-		var fullWidth = 0.75, fullHeight = 1.5;
-		var angle = Math.atan( ( fullWidth / 2 ) / fullHeight );
-
-		var bottomY = y - fullHeight / 2;
-		var height = fullHeight * ratio;
-		var width = ( Math.tan( angle ) * height ) * 2;
-
-		var position = geometry.attributes.position;
-
-		position.setXYZ( 0, x, bottomY, 0 );
-		position.setXYZ( 1, x + width / 2, bottomY + height, 0 );
-		position.setXYZ( 2, x - width / 2, bottomY + height, 0 );
-
-		position.needsUpdate = true;
-
-	}
-
-	function onGripsDown() {
-
-		if ( mode === MODES.COLOR ) {
-
-			mode = MODES.SIZE;
-			colorUI.visible = false;
-			sizeUI.visible = true;
-			return;
-
-		}
-
-		if ( mode === MODES.SIZE ) {
-
-			mode = MODES.COLOR;
-			colorUI.visible = true;
-			sizeUI.visible = false;
-			return;
-
-		}
-
-	}
-
-	this.getColor = function () {
-
-		return color;
-
-	};
-
-	this.getSize = function () {
-
-		return size;
-
-	 };
-
-	this.addEventListener( 'axischanged', onAxisChanged );
-	this.addEventListener( 'gripsdown', onGripsDown );
-
-};
-
-THREE.PaintViveController.prototype = Object.create( THREE.ViveController.prototype );
-THREE.PaintViveController.prototype.constructor = THREE.PaintViveController;

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

@@ -1,128 +0,0 @@
-/**
- * @author mrdoob / http://mrdoob.com
- * @author stewdio / http://stewd.io
- */
-
-THREE.ViveController = function ( id ) {
-
-	THREE.Object3D.call( this );
-
-	var scope = this;
-	var gamepad;
-
-	var axes = [ 0, 0 ];
-	var thumbpadIsPressed = false;
-	var triggerIsPressed = false;
-	var gripsArePressed = false;
-	var menuIsPressed = false;
-
-	function findGamepad( id ) {
-
-		// Iterate across gamepads as Vive Controllers may not be
-		// in position 0 and 1.
-
-		var gamepads = navigator.getGamepads && navigator.getGamepads();
-
-		for ( var i = 0, j = 0; i < gamepads.length; i ++ ) {
-
-			var gamepad = gamepads[ i ];
-
-			if ( gamepad && ( gamepad.id === 'OpenVR Gamepad' || gamepad.id.startsWith( 'Oculus Touch' ) || gamepad.id.startsWith( 'Spatial Controller' ) ) ) {
-
-				if ( j === id ) return gamepad;
-
-				j ++;
-
-			}
-
-		}
-
-	}
-
-	this.matrixAutoUpdate = false;
-	this.standingMatrix = new THREE.Matrix4();
-
-	this.getGamepad = function () {
-
-		return gamepad;
-
-	};
-
-	this.getButtonState = function ( button ) {
-
-		if ( button === 'thumbpad' ) return thumbpadIsPressed;
-		if ( button === 'trigger' ) return triggerIsPressed;
-		if ( button === 'grips' ) return gripsArePressed;
-		if ( button === 'menu' ) return menuIsPressed;
-
-	};
-
-	this.update = function () {
-
-		gamepad = findGamepad( id );
-
-		if ( gamepad !== undefined && gamepad.pose !== undefined ) {
-
-			if ( gamepad.pose === null ) return; // No user action yet
-
-			//  Position and orientation.
-
-			var pose = gamepad.pose;
-
-			if ( pose.position !== null ) scope.position.fromArray( pose.position );
-			if ( pose.orientation !== null ) scope.quaternion.fromArray( pose.orientation );
-			scope.matrix.compose( scope.position, scope.quaternion, scope.scale );
-			scope.matrix.premultiply( scope.standingMatrix );
-			scope.matrixWorldNeedsUpdate = true;
-			scope.visible = true;
-
-			//  Thumbpad and Buttons.
-
-			if ( axes[ 0 ] !== gamepad.axes[ 0 ] || axes[ 1 ] !== gamepad.axes[ 1 ] ) {
-
-				axes[ 0 ] = gamepad.axes[ 0 ]; //  X axis: -1 = Left, +1 = Right.
-				axes[ 1 ] = gamepad.axes[ 1 ]; //  Y axis: -1 = Bottom, +1 = Top.
-				scope.dispatchEvent( { type: 'axischanged', axes: axes } );
-
-			}
-
-			if ( thumbpadIsPressed !== gamepad.buttons[ 0 ].pressed ) {
-
-				thumbpadIsPressed = gamepad.buttons[ 0 ].pressed;
-				scope.dispatchEvent( { type: thumbpadIsPressed ? 'thumbpaddown' : 'thumbpadup', axes: axes } );
-
-			}
-
-			if ( triggerIsPressed !== gamepad.buttons[ 1 ].pressed ) {
-
-				triggerIsPressed = gamepad.buttons[ 1 ].pressed;
-				scope.dispatchEvent( { type: triggerIsPressed ? 'triggerdown' : 'triggerup' } );
-
-			}
-
-			if ( gripsArePressed !== gamepad.buttons[ 2 ].pressed ) {
-
-				gripsArePressed = gamepad.buttons[ 2 ].pressed;
-				scope.dispatchEvent( { type: gripsArePressed ? 'gripsdown' : 'gripsup' } );
-
-			}
-
-			if ( menuIsPressed !== gamepad.buttons[ 3 ].pressed ) {
-
-				menuIsPressed = gamepad.buttons[ 3 ].pressed;
-				scope.dispatchEvent( { type: menuIsPressed ? 'menudown' : 'menuup' } );
-
-			}
-
-		} else {
-
-			scope.visible = false;
-
-		}
-
-	};
-
-};
-
-THREE.ViveController.prototype = Object.create( THREE.Object3D.prototype );
-THREE.ViveController.prototype.constructor = THREE.ViveController;

+ 3 - 1
examples/js/vr/WebVR.js

@@ -9,6 +9,8 @@ THREE.WEBVR = {
 
 
 	createButton: function ( renderer, options ) {
 	createButton: function ( renderer, options ) {
 
 
+		console.warn( 'WEBVR.js has been deprecated. Use VRButton.js instead.' );
+
 		if ( options && options.referenceSpaceType ) {
 		if ( options && options.referenceSpaceType ) {
 
 
 			renderer.vr.setReferenceSpaceType( options.referenceSpaceType );
 			renderer.vr.setReferenceSpaceType( options.referenceSpaceType );
@@ -169,7 +171,7 @@ THREE.WEBVR = {
 
 
 		}
 		}
 
 
-		if ( 'xr' in navigator && 'isSessionSupported' in navigator.xr ) {
+		if ( 'xr' in navigator ) {
 
 
 			var button = document.createElement( 'button' );
 			var button = document.createElement( 'button' );
 			button.style.display = 'none';
 			button.style.display = 'none';

+ 0 - 118
examples/js/vr/deprecated/DaydreamController.js

@@ -1,118 +0,0 @@
-/**
- * @author Mugen87 / https://github.com/Mugen87
- */
-
-THREE.DaydreamController = function () {
-
-	THREE.Object3D.call( this );
-
-	var scope = this;
-	var gamepad;
-
-	var axes = [ 0, 0 ];
-	var touchpadIsPressed = false;
-	var angularVelocity = new THREE.Vector3();
-
-	this.matrixAutoUpdate = false;
-
-	function findGamepad() {
-
-		// iterate across gamepads as the Daydream Controller may not be
-		// in position 0
-
-		var gamepads = navigator.getGamepads && navigator.getGamepads();
-
-		for ( var i = 0; i < 4; i ++ ) {
-
-			var gamepad = gamepads[ i ];
-
-			if ( gamepad && ( gamepad.id === 'Daydream Controller' ) ) {
-
-				return gamepad;
-
-			}
-
-		}
-
-	}
-
-	this.getGamepad = function () {
-
-		return gamepad;
-
-	};
-
-	this.getTouchpadState = function () {
-
-		return touchpadIsPressed;
-
-	};
-
-	this.update = function () {
-
-		gamepad = findGamepad();
-
-		if ( gamepad !== undefined && gamepad.pose !== undefined ) {
-
-			var pose = gamepad.pose;
-
-			if ( pose === null ) return; // no user action yet
-
-			//  orientation
-
-			if ( pose.orientation !== null ) scope.quaternion.fromArray( pose.orientation );
-
-			scope.updateMatrix();
-			scope.visible = true;
-
-			// angular velocity
-
-			if ( pose.angularVelocity !== null && ! angularVelocity.equals( pose.angularVelocity ) ) {
-
-				angularVelocity.fromArray( pose.angularVelocity );
-				scope.dispatchEvent( { type: 'angularvelocitychanged', angularVelocity: angularVelocity } );
-
-			}
-
-			// axes (touchpad)
-
-			if ( axes[ 0 ] !== gamepad.axes[ 0 ] || axes[ 1 ] !== gamepad.axes[ 1 ] ) {
-
-				axes[ 0 ] = gamepad.axes[ 0 ];
-				axes[ 1 ] = gamepad.axes[ 1 ];
-				scope.dispatchEvent( { type: 'axischanged', axes: axes } );
-
-			}
-
-			// button (touchpad)
-
-			if ( touchpadIsPressed !== gamepad.buttons[ 0 ].pressed ) {
-
-				touchpadIsPressed = gamepad.buttons[ 0 ].pressed;
-				scope.dispatchEvent( { type: touchpadIsPressed ? 'touchpaddown' : 'touchpadup' } );
-
-			}
-
-			// app button not available, reserved for use by the browser
-
-		} else {
-
-			scope.visible = false;
-
-		}
-
-	};
-
-	// 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.constructor = THREE.DaydreamController;

+ 0 - 132
examples/js/vr/deprecated/GearVRController.js

@@ -1,132 +0,0 @@
-/**
- * @author servinlp
- */
-
-THREE.GearVRController = function () {
-
-	THREE.Object3D.call( this );
-
-	var scope = this;
-	var gamepad;
-
-	var axes = [ 0, 0 ];
-	var touchpadIsPressed = false;
-	var triggerIsPressed = false;
-	var angularVelocity = new THREE.Vector3();
-
-	this.matrixAutoUpdate = true;
-
-	function findGamepad() {
-
-		var gamepads = navigator.getGamepads && navigator.getGamepads();
-
-		for ( var i = 0; i < 4; i ++ ) {
-
-			var gamepad = gamepads[ i ];
-
-			if ( gamepad && ( gamepad.id === 'Gear VR Controller' || gamepad.id === 'Oculus Go Controller' ) ) {
-
-				return gamepad;
-
-			}
-
-		}
-
-	}
-
-	this.getGamepad = function () {
-
-		return gamepad;
-
-	};
-
-	this.getTouchpadState = function () {
-
-		return touchpadIsPressed;
-
-	};
-
-	this.update = function () {
-
-		gamepad = findGamepad();
-
-		if ( gamepad !== undefined && gamepad.pose !== undefined ) {
-
-			var pose = gamepad.pose;
-
-			if ( pose === null ) return; // no user action yet
-
-			//  orientation
-
-			if ( pose.orientation !== null ) scope.quaternion.fromArray( pose.orientation );
-
-			scope.updateMatrix();
-			scope.visible = true;
-
-			// angular velocity
-
-			if ( pose.angularVelocity !== null && ! angularVelocity.equals( pose.angularVelocity ) ) {
-
-				angularVelocity.fromArray( pose.angularVelocity );
-				scope.dispatchEvent( { type: 'angularvelocitychanged', angularVelocity: angularVelocity } );
-
-			}
-
-			// axes (touchpad)
-
-			if ( axes[ 0 ] !== gamepad.axes[ 0 ] || axes[ 1 ] !== gamepad.axes[ 1 ] ) {
-
-				axes[ 0 ] = gamepad.axes[ 0 ];
-				axes[ 1 ] = gamepad.axes[ 1 ];
-				scope.dispatchEvent( { type: 'axischanged', axes: axes } );
-
-			}
-
-			// button (touchpad)
-
-			if ( touchpadIsPressed !== gamepad.buttons[ 0 ].pressed ) {
-
-				touchpadIsPressed = gamepad.buttons[ 0 ].pressed;
-				scope.dispatchEvent( { type: touchpadIsPressed ? 'touchpaddown' : 'touchpadup', axes: axes } );
-
-			}
-
-
-			// trigger
-
-			if ( triggerIsPressed !== gamepad.buttons[ 1 ].pressed ) {
-
-				triggerIsPressed = gamepad.buttons[ 1 ].pressed;
-				scope.dispatchEvent( { type: triggerIsPressed ? 'triggerdown' : 'triggerup' } );
-
-			}
-
-			// app button not available, reserved for use by the browser
-
-		} else {
-
-			scope.visible = false;
-
-		}
-
-	};
-
-	// DEPRECATED
-
-	this.getTouchPadState = function () {
-
-		console.warn( 'THREE.GearVRController: getTouchPadState() is now getTouchpadState()' );
-		return touchpadIsPressed;
-
-	};
-
-	this.setHand = function () {
-
-		console.warn( 'THREE.GearVRController: setHand() has been removed.' );
-
-	};
-
-};
-
-THREE.GearVRController.prototype = Object.create( THREE.Object3D.prototype );
-THREE.GearVRController.prototype.constructor = THREE.GearVRController;

+ 25 - 2
examples/jsm/controls/DeviceOrientationControls.js

@@ -68,8 +68,31 @@ var DeviceOrientationControls = function ( object ) {
 
 
 		onScreenOrientationChangeEvent(); // run once on load
 		onScreenOrientationChangeEvent(); // run once on load
 
 
-		window.addEventListener( 'orientationchange', onScreenOrientationChangeEvent, false );
-		window.addEventListener( 'deviceorientation', onDeviceOrientationChangeEvent, false );
+		// iOS 13+
+
+		if ( window.DeviceOrientationEvent !== undefined && typeof window.DeviceOrientationEvent.requestPermission === 'function' ) {
+
+			window.DeviceOrientationEvent.requestPermission().then( function ( response ) {
+
+				if ( response == 'granted' ) {
+
+					window.addEventListener( 'orientationchange', onScreenOrientationChangeEvent, false );
+					window.addEventListener( 'deviceorientation', onDeviceOrientationChangeEvent, false );
+
+				}
+
+			} ).catch( function ( error ) {
+
+				console.error( 'THREE.DeviceOrientationControls: Unable to use DeviceOrientation API:', error );
+
+			} );
+
+		} else {
+
+			window.addEventListener( 'orientationchange', onScreenOrientationChangeEvent, false );
+			window.addEventListener( 'deviceorientation', onDeviceOrientationChangeEvent, false );
+
+		}
 
 
 		scope.enabled = true;
 		scope.enabled = true;
 
 

+ 98 - 107
examples/jsm/effects/OutlineEffect.js

@@ -54,16 +54,14 @@
  * 	visible: true,
  * 	visible: true,
  * 	keepAlive: true
  * 	keepAlive: true
  * };
  * };
- *
- * TODO
- *  - support shader material without objectNormal in its vertexShader
  */
  */
 
 
 import {
 import {
 	BackSide,
 	BackSide,
 	Color,
 	Color,
-	ShaderLib,
-	ShaderMaterial
+	ShaderMaterial,
+	UniformsLib,
+	UniformsUtils
 } from "../../../build/three.module.js";
 } from "../../../build/three.module.js";
 
 
 var OutlineEffect = function ( renderer, parameters ) {
 var OutlineEffect = function ( renderer, parameters ) {
@@ -97,58 +95,57 @@ var OutlineEffect = function ( renderer, parameters ) {
 
 
 	//this.cache = cache;  // for debug
 	//this.cache = cache;  // for debug
 
 
-	// copied from WebGLPrograms and removed some materials
-	var shaderIDs = {
-		MeshBasicMaterial: 'basic',
-		MeshLambertMaterial: 'lambert',
-		MeshPhongMaterial: 'phong',
-		MeshToonMaterial: 'phong',
-		MeshStandardMaterial: 'physical',
-		MeshPhysicalMaterial: 'physical'
-	};
-
-	var uniformsChunk = {
+	var uniformsOutline = {
 		outlineThickness: { value: defaultThickness },
 		outlineThickness: { value: defaultThickness },
 		outlineColor: { value: defaultColor },
 		outlineColor: { value: defaultColor },
 		outlineAlpha: { value: defaultAlpha }
 		outlineAlpha: { value: defaultAlpha }
 	};
 	};
 
 
-	var vertexShaderChunk = [
+	var vertexShader = [
+		"#include <common>",
+		"#include <uv_pars_vertex>",
+		"#include <displacementmap_pars_vertex>",
+		"#include <fog_pars_vertex>",
+		"#include <morphtarget_pars_vertex>",
+		"#include <skinning_pars_vertex>",
+		"#include <logdepthbuf_pars_vertex>",
+		"#include <clipping_planes_pars_vertex>",
 
 
 		"uniform float outlineThickness;",
 		"uniform float outlineThickness;",
 
 
-		"vec4 calculateOutline( vec4 pos, vec3 objectNormal, vec4 skinned ) {",
-
+		"vec4 calculateOutline( vec4 pos, vec3 normal, vec4 skinned ) {",
 		"	float thickness = outlineThickness;",
 		"	float thickness = outlineThickness;",
 		"	const float ratio = 1.0;", // TODO: support outline thickness ratio for each vertex
 		"	const float ratio = 1.0;", // TODO: support outline thickness ratio for each vertex
-		"	vec4 pos2 = projectionMatrix * modelViewMatrix * vec4( skinned.xyz + objectNormal, 1.0 );",
+		"	vec4 pos2 = projectionMatrix * modelViewMatrix * vec4( skinned.xyz + normal, 1.0 );",
 		// NOTE: subtract pos2 from pos because BackSide objectNormal is negative
 		// NOTE: subtract pos2 from pos because BackSide objectNormal is negative
 		"	vec4 norm = normalize( pos - pos2 );",
 		"	vec4 norm = normalize( pos - pos2 );",
 		"	return pos + norm * thickness * pos.w * ratio;",
 		"	return pos + norm * thickness * pos.w * ratio;",
+		"}",
 
 
-		"}"
+		"void main() {",
 
 
-	].join( "\n" );
+		"	#include <uv_vertex>",
 
 
-	var vertexShaderChunk2 = [
+		"	#include <beginnormal_vertex>",
+		"	#include <morphnormal_vertex>",
+		"	#include <skinbase_vertex>",
+		"	#include <skinnormal_vertex>",
 
 
-		"#if ! defined( LAMBERT ) && ! defined( PHONG ) && ! defined( TOON ) && ! defined( STANDARD )",
-		"	#ifndef USE_ENVMAP",
-		"		vec3 objectNormal = normalize( normal );",
-		"	#endif",
-		"#endif",
+		"	#include <begin_vertex>",
+		"	#include <morphtarget_vertex>",
+		"	#include <skinning_vertex>",
+		"	#include <displacementmap_vertex>",
+		"	#include <project_vertex>",
 
 
-		"#ifdef FLIP_SIDED",
-		"	objectNormal = -objectNormal;",
-		"#endif",
+		"	vec3 outlineNormal = - objectNormal;", // the outline material is always rendered with BackSide
 
 
-		"#ifdef DECLARE_TRANSFORMED",
-		"	vec3 transformed = vec3( position );",
-		"#endif",
+		"	gl_Position = calculateOutline( gl_Position, outlineNormal, vec4( transformed, 1.0 ) );",
 
 
-		"gl_Position = calculateOutline( gl_Position, objectNormal, vec4( transformed, 1.0 ) );",
+		"	#include <logdepthbuf_vertex>",
+		"	#include <clipping_planes_vertex>",
+		"	#include <fog_vertex>",
 
 
-		"#include <fog_vertex>"
+		"}",
 
 
 	].join( "\n" );
 	].join( "\n" );
 
 
@@ -156,92 +153,40 @@ var OutlineEffect = function ( renderer, parameters ) {
 
 
 		"#include <common>",
 		"#include <common>",
 		"#include <fog_pars_fragment>",
 		"#include <fog_pars_fragment>",
+		"#include <logdepthbuf_pars_fragment>",
+		"#include <clipping_planes_pars_fragment>",
 
 
 		"uniform vec3 outlineColor;",
 		"uniform vec3 outlineColor;",
 		"uniform float outlineAlpha;",
 		"uniform float outlineAlpha;",
 
 
 		"void main() {",
 		"void main() {",
 
 
+		"	#include <clipping_planes_fragment>",
+		"	#include <logdepthbuf_fragment>",
+
 		"	gl_FragColor = vec4( outlineColor, outlineAlpha );",
 		"	gl_FragColor = vec4( outlineColor, outlineAlpha );",
 
 
+		"	#include <premultiplied_alpha_fragment>",
+		"	#include <tonemapping_fragment>",
+		"	#include <encodings_fragment>",
 		"	#include <fog_fragment>",
 		"	#include <fog_fragment>",
 
 
 		"}"
 		"}"
 
 
 	].join( "\n" );
 	].join( "\n" );
 
 
-	function createInvisibleMaterial() {
-
-		return new ShaderMaterial( { name: 'invisible', visible: false } );
-
-	}
-
-	function createMaterial( originalMaterial ) {
-
-		var shaderID = shaderIDs[ originalMaterial.type ];
-		var originalUniforms, originalVertexShader;
-
-		if ( shaderID !== undefined ) {
-
-			var shader = ShaderLib[ shaderID ];
-			originalUniforms = shader.uniforms;
-			originalVertexShader = shader.vertexShader;
-
-		} else if ( originalMaterial.isRawShaderMaterial === true ) {
-
-			originalUniforms = originalMaterial.uniforms;
-			originalVertexShader = originalMaterial.vertexShader;
-
-			if ( ! /attribute\s+vec3\s+position\s*;/.test( originalVertexShader ) ||
-			     ! /attribute\s+vec3\s+normal\s*;/.test( originalVertexShader ) ) {
-
-				console.warn( 'THREE.OutlineEffect requires both vec3 position and normal attributes in vertex shader, ' +
-				              'does not draw outline for ' + originalMaterial.name + '(uuid:' + originalMaterial.uuid + ') material.' );
-
-				return createInvisibleMaterial();
-
-			}
-
-		} else if ( originalMaterial.isShaderMaterial === true ) {
-
-			originalUniforms = originalMaterial.uniforms;
-			originalVertexShader = originalMaterial.vertexShader;
-
-		} else {
-
-			return createInvisibleMaterial();
-
-		}
-
-		var uniforms = Object.assign( {}, originalUniforms, uniformsChunk );
-
-		var vertexShader = originalVertexShader
-			// put vertexShaderChunk right before "void main() {...}"
-			.replace( /void\s+main\s*\(\s*\)/, vertexShaderChunk + '\nvoid main()' )
-			// put vertexShaderChunk2 the end of "void main() {...}"
-			// Note: here assums originalVertexShader ends with "}" of "void main() {...}"
-			.replace( /\}\s*$/, vertexShaderChunk2 + '\n}' )
-			// remove any light related lines
-			// Note: here is very sensitive to originalVertexShader
-			// TODO: consider safer way
-			.replace( /#include\s+<[\w_]*light[\w_]*>/g, '' );
-
-		var defines = {};
-
-		if ( ! /vec3\s+transformed\s*=/.test( originalVertexShader ) &&
-		     ! /#include\s+<begin_vertex>/.test( originalVertexShader ) ) defines.DECLARE_TRANSFORMED = true;
+	function createMaterial() {
 
 
 		return new ShaderMaterial( {
 		return new ShaderMaterial( {
-			defines: defines,
-			uniforms: uniforms,
+			type: 'OutlineEffect',
+			uniforms: UniformsUtils.merge( [
+				UniformsLib[ 'fog' ],
+				UniformsLib[ 'displacementmap' ],
+				uniformsOutline
+			] ),
 			vertexShader: vertexShader,
 			vertexShader: vertexShader,
 			fragmentShader: fragmentShader,
 			fragmentShader: fragmentShader,
-			side: BackSide,
-			//wireframe: true,
-			skinning: false,
-			morphTargets: false,
-			morphNormals: false,
-			fog: false
+			side: BackSide
 		} );
 		} );
 
 
 	}
 	}
@@ -253,7 +198,7 @@ var OutlineEffect = function ( renderer, parameters ) {
 		if ( data === undefined ) {
 		if ( data === undefined ) {
 
 
 			data = {
 			data = {
-				material: createMaterial( originalMaterial ),
+				material: createMaterial(),
 				used: true,
 				used: true,
 				keepAlive: defaultKeepAlive,
 				keepAlive: defaultKeepAlive,
 				count: 0
 				count: 0
@@ -281,9 +226,32 @@ var OutlineEffect = function ( renderer, parameters ) {
 
 
 	}
 	}
 
 
+	function isCompatible( object ) {
+
+		var geometry = object.geometry;
+		var hasNormals = false;
+
+		if ( object.geometry !== undefined ) {
+
+			if ( geometry.isBufferGeometry ) {
+
+				hasNormals = geometry.attributes.normal !== undefined;
+
+			} else {
+
+				hasNormals = true; // the renderer always produces a normal attribute for Geometry
+
+			}
+
+		}
+
+		return ( object.isMesh === true && object.material !== undefined && hasNormals === true );
+
+	}
+
 	function setOutlineMaterial( object ) {
 	function setOutlineMaterial( object ) {
 
 
-		if ( object.material === undefined ) return;
+		if ( isCompatible( object ) === false ) return;
 
 
 		if ( Array.isArray( object.material ) ) {
 		if ( Array.isArray( object.material ) ) {
 
 
@@ -306,7 +274,7 @@ var OutlineEffect = function ( renderer, parameters ) {
 
 
 	function restoreOriginalMaterial( object ) {
 	function restoreOriginalMaterial( object ) {
 
 
-		if ( object.material === undefined ) return;
+		if ( isCompatible( object ) === false ) return;
 
 
 		if ( Array.isArray( object.material ) ) {
 		if ( Array.isArray( object.material ) ) {
 
 
@@ -351,6 +319,14 @@ var OutlineEffect = function ( renderer, parameters ) {
 
 
 		}
 		}
 
 
+		if ( originalMaterial.displacementMap ) {
+
+			material.uniforms.displacementMap.value = originalMaterial.displacementMap;
+			material.uniforms.displacementScale.value = originalMaterial.displacementScale;
+			material.uniforms.displacementBias.value = originalMaterial.displacementBias;
+
+		}
+
 	}
 	}
 
 
 	function updateOutlineMaterial( material, originalMaterial ) {
 	function updateOutlineMaterial( material, originalMaterial ) {
@@ -363,6 +339,9 @@ var OutlineEffect = function ( renderer, parameters ) {
 		material.morphTargets = originalMaterial.morphTargets;
 		material.morphTargets = originalMaterial.morphTargets;
 		material.morphNormals = originalMaterial.morphNormals;
 		material.morphNormals = originalMaterial.morphNormals;
 		material.fog = originalMaterial.fog;
 		material.fog = originalMaterial.fog;
+		material.toneMapped = originalMaterial.toneMapped;
+		material.premultipliedAlpha = originalMaterial.premultipliedAlpha;
+		material.displacementMap = originalMaterial.displacementMap;
 
 
 		if ( outlineParameters !== undefined ) {
 		if ( outlineParameters !== undefined ) {
 
 
@@ -389,6 +368,18 @@ var OutlineEffect = function ( renderer, parameters ) {
 
 
 		if ( originalMaterial.wireframe === true || originalMaterial.depthTest === false ) material.visible = false;
 		if ( originalMaterial.wireframe === true || originalMaterial.depthTest === false ) material.visible = false;
 
 
+		if ( originalMaterial.clippingPlanes ) {
+
+			material.clipping = true;
+
+			material.clippingPlanes = originalMaterial.clippingPlanes;
+			material.clipIntersection = originalMaterial.clipIntersection;
+			material.clipShadows = originalMaterial.clipShadows;
+
+		}
+
+		material.version = originalMaterial.version; // update outline material if necessary
+
 	}
 	}
 
 
 	function cleanupCache() {
 	function cleanupCache() {

+ 12 - 8
examples/jsm/exporters/GLTFExporter.js

@@ -1363,14 +1363,18 @@ GLTFExporter.prototype = {
 						// Clones attribute not to override
 						// Clones attribute not to override
 						var relativeAttribute = attribute.clone();
 						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 )
-							);
+						if ( ! geometry.morphTargetsRelative ) {
+
+							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 )
+									);
+
+							}
 
 
 						}
 						}
 
 

+ 1 - 1
examples/jsm/exporters/OBJExporter.js

@@ -115,7 +115,7 @@ OBJExporter.prototype = {
 						normal.z = normals.getZ( i );
 						normal.z = normals.getZ( i );
 
 
 						// transfrom the normal to world space
 						// transfrom the normal to world space
-						normal.applyMatrix3( normalMatrixWorld );
+						normal.applyMatrix3( normalMatrixWorld ).normalize();
 
 
 						// transform the normal to export format
 						// transform the normal to export format
 						output += 'vn ' + normal.x + ' ' + normal.y + ' ' + normal.z + '\n';
 						output += 'vn ' + normal.x + ' ' + normal.y + ' ' + normal.z + '\n';

+ 2 - 2
examples/jsm/exporters/PLYExporter.js

@@ -282,7 +282,7 @@ PLYExporter.prototype = {
 							vertex.y = normals.getY( i );
 							vertex.y = normals.getY( i );
 							vertex.z = normals.getZ( i );
 							vertex.z = normals.getZ( i );
 
 
-							vertex.applyMatrix3( normalMatrixWorld );
+							vertex.applyMatrix3( normalMatrixWorld ).normalize();
 
 
 							output.setFloat32( vOffset, vertex.x );
 							output.setFloat32( vOffset, vertex.x );
 							vOffset += 4;
 							vOffset += 4;
@@ -458,7 +458,7 @@ PLYExporter.prototype = {
 							vertex.y = normals.getY( i );
 							vertex.y = normals.getY( i );
 							vertex.z = normals.getZ( i );
 							vertex.z = normals.getZ( i );
 
 
-							vertex.applyMatrix3( normalMatrixWorld );
+							vertex.applyMatrix3( normalMatrixWorld ).normalize();
 
 
 							line += ' ' +
 							line += ' ' +
 								vertex.x + ' ' +
 								vertex.x + ' ' +

+ 3 - 1
examples/jsm/lines/LineMaterial.js

@@ -254,7 +254,9 @@ var LineMaterial = function ( parameters ) {
 		uniforms: UniformsUtils.clone( ShaderLib[ 'line' ].uniforms ),
 		uniforms: UniformsUtils.clone( ShaderLib[ 'line' ].uniforms ),
 
 
 		vertexShader: ShaderLib[ 'line' ].vertexShader,
 		vertexShader: ShaderLib[ 'line' ].vertexShader,
-		fragmentShader: ShaderLib[ 'line' ].fragmentShader
+		fragmentShader: ShaderLib[ 'line' ].fragmentShader,
+
+		clipping: true // required for clipping support
 
 
 	} );
 	} );
 
 

+ 195 - 8
examples/jsm/loaders/3MFLoader.js

@@ -14,12 +14,15 @@
  *
  *
  * - Texture 2D
  * - Texture 2D
  * - Texture 2D Groups
  * - Texture 2D Groups
+ * - Color Groups (Vertex Colors)
+ * - Metallic Display Properties (PBR)
  */
  */
 
 
 import {
 import {
 	BufferAttribute,
 	BufferAttribute,
 	BufferGeometry,
 	BufferGeometry,
 	ClampToEdgeWrapping,
 	ClampToEdgeWrapping,
+	Color,
 	FileLoader,
 	FileLoader,
 	Float32BufferAttribute,
 	Float32BufferAttribute,
 	Group,
 	Group,
@@ -30,10 +33,12 @@ import {
 	Matrix4,
 	Matrix4,
 	Mesh,
 	Mesh,
 	MeshPhongMaterial,
 	MeshPhongMaterial,
+	MeshStandardMaterial,
 	MirroredRepeatWrapping,
 	MirroredRepeatWrapping,
 	NearestFilter,
 	NearestFilter,
 	RepeatWrapping,
 	RepeatWrapping,
 	TextureLoader,
 	TextureLoader,
+	VertexColors,
 	sRGBEncoding
 	sRGBEncoding
 } from "../../../build/three.module.js";
 } from "../../../build/three.module.js";
 
 
@@ -281,6 +286,7 @@ ThreeMFLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
 
 
 				var basematerialNode = basematerialNodes[ i ];
 				var basematerialNode = basematerialNodes[ i ];
 				var basematerialData = parseBasematerialNode( basematerialNode );
 				var basematerialData = parseBasematerialNode( basematerialNode );
+				basematerialData.index = i; // the order and count of the material nodes form an implicit 0-based index
 				basematerialsData.basematerials.push( basematerialData );
 				basematerialsData.basematerials.push( basematerialData );
 
 
 			}
 			}
@@ -304,7 +310,7 @@ ThreeMFLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
 
 
 		}
 		}
 
 
-		function parseTextures2DGroupNodes( texture2DGroupNode ) {
+		function parseTextures2DGroupNode( texture2DGroupNode ) {
 
 
 			var texture2DGroupData = {
 			var texture2DGroupData = {
 				id: texture2DGroupNode.getAttribute( 'id' ), // required
 				id: texture2DGroupNode.getAttribute( 'id' ), // required
@@ -332,12 +338,71 @@ ThreeMFLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
 
 
 		}
 		}
 
 
+		function parseColorGroupNode( colorGroupNode ) {
+
+			var colorGroupData = {
+				id: colorGroupNode.getAttribute( 'id' ), // required
+				displaypropertiesid: colorGroupNode.getAttribute( 'displaypropertiesid' )
+			};
+
+			var colorNodes = colorGroupNode.querySelectorAll( 'color' );
+
+			var colors = [];
+			var colorObject = new Color();
+
+			for ( var i = 0; i < colorNodes.length; i ++ ) {
+
+				var colorNode = colorNodes[ i ];
+				var color = colorNode.getAttribute( 'color' );
+
+				colorObject.setStyle( color.substring( 0, 7 ) );
+				colorObject.convertSRGBToLinear(); // color is in sRGB
+
+				colors.push( colorObject.r, colorObject.g, colorObject.b );
+
+			}
+
+			colorGroupData[ 'colors' ] = new Float32Array( colors );
+
+			return colorGroupData;
+
+		}
+
+		function parseMetallicDisplaypropertiesNode( metallicDisplaypropetiesNode ) {
+
+			var metallicDisplaypropertiesData = {
+				id: metallicDisplaypropetiesNode.getAttribute( 'id' ) // required
+			};
+
+			var metallicNodes = metallicDisplaypropetiesNode.querySelectorAll( 'pbmetallic' );
+
+			var metallicData = [];
+
+			for ( var i = 0; i < metallicNodes.length; i ++ ) {
+
+				var metallicNode = metallicNodes[ i ];
+
+				metallicData.push( {
+					name: metallicNode.getAttribute( 'name' ), // required
+					metallicness: parseFloat( metallicNode.getAttribute( 'metallicness' ) ), // required
+					roughness: parseFloat( metallicNode.getAttribute( 'roughness' ) ) // required
+				} );
+
+			}
+
+			metallicDisplaypropertiesData.data = metallicData;
+
+			return metallicDisplaypropertiesData;
+
+		}
+
 		function parseBasematerialNode( basematerialNode ) {
 		function parseBasematerialNode( basematerialNode ) {
 
 
 			var basematerialData = {};
 			var basematerialData = {};
 
 
 			basematerialData[ 'name' ] = basematerialNode.getAttribute( 'name' ); // required
 			basematerialData[ 'name' ] = basematerialNode.getAttribute( 'name' ); // required
 			basematerialData[ 'displaycolor' ] = basematerialNode.getAttribute( 'displaycolor' ); // required
 			basematerialData[ 'displaycolor' ] = basematerialNode.getAttribute( 'displaycolor' ); // required
+			basematerialData[ 'displaypropertiesid' ] = basematerialNode.getAttribute( 'displaypropertiesid' );
 
 
 			return basematerialData;
 			return basematerialData;
 
 
@@ -588,13 +653,39 @@ ThreeMFLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
 
 
 			//
 			//
 
 
+			resourcesData[ 'colorgroup' ] = {};
+			var colorGroupNodes = resourcesNode.querySelectorAll( 'colorgroup' );
+
+			for ( var i = 0; i < colorGroupNodes.length; i ++ ) {
+
+				var colorGroupNode = colorGroupNodes[ i ];
+				var colorGroupData = parseColorGroupNode( colorGroupNode );
+				resourcesData[ 'colorgroup' ][ colorGroupData[ 'id' ] ] = colorGroupData;
+
+			}
+
+			//
+
+			resourcesData[ 'pbmetallicdisplayproperties' ] = {};
+			var pbmetallicdisplaypropertiesNodes = resourcesNode.querySelectorAll( 'pbmetallicdisplayproperties' );
+
+			for ( var i = 0; i < pbmetallicdisplaypropertiesNodes.length; i ++ ) {
+
+				var pbmetallicdisplaypropertiesNode = pbmetallicdisplaypropertiesNodes[ i ];
+				var pbmetallicdisplaypropertiesData = parseMetallicDisplaypropertiesNode( pbmetallicdisplaypropertiesNode );
+				resourcesData[ 'pbmetallicdisplayproperties' ][ pbmetallicdisplaypropertiesData[ 'id' ] ] = pbmetallicdisplaypropertiesData;
+
+			}
+
+			//
+
 			resourcesData[ 'texture2dgroup' ] = {};
 			resourcesData[ 'texture2dgroup' ] = {};
 			var textures2DGroupNodes = resourcesNode.querySelectorAll( 'texture2dgroup' );
 			var textures2DGroupNodes = resourcesNode.querySelectorAll( 'texture2dgroup' );
 
 
 			for ( var i = 0; i < textures2DGroupNodes.length; i ++ ) {
 			for ( var i = 0; i < textures2DGroupNodes.length; i ++ ) {
 
 
 				var textures2DGroupNode = textures2DGroupNodes[ i ];
 				var textures2DGroupNode = textures2DGroupNodes[ i ];
-				var textures2DGroupData = parseTextures2DGroupNodes( textures2DGroupNode );
+				var textures2DGroupData = parseTextures2DGroupNode( textures2DGroupNode );
 				resourcesData[ 'texture2dgroup' ][ textures2DGroupData[ 'id' ] ] = textures2DGroupData;
 				resourcesData[ 'texture2dgroup' ][ textures2DGroupData[ 'id' ] ] = textures2DGroupData;
 
 
 			}
 			}
@@ -898,6 +989,73 @@ ThreeMFLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
 
 
 		}
 		}
 
 
+		function buildVertexColorMesh( colorgroup, triangleProperties, modelData, meshData ) {
+
+			// geometry
+
+			var geometry = new BufferGeometry();
+
+			var positionData = [];
+			var colorData = [];
+
+			var vertices = meshData.vertices;
+			var colors = colorgroup.colors;
+
+			for ( var i = 0, l = triangleProperties.length; i < l; i ++ ) {
+
+				var triangleProperty = triangleProperties[ i ];
+
+				var v1 = triangleProperty.v1;
+				var v2 = triangleProperty.v2;
+				var v3 = triangleProperty.v3;
+
+				positionData.push( vertices[ ( v1 * 3 ) + 0 ] );
+				positionData.push( vertices[ ( v1 * 3 ) + 1 ] );
+				positionData.push( vertices[ ( v1 * 3 ) + 2 ] );
+
+				positionData.push( vertices[ ( v2 * 3 ) + 0 ] );
+				positionData.push( vertices[ ( v2 * 3 ) + 1 ] );
+				positionData.push( vertices[ ( v2 * 3 ) + 2 ] );
+
+				positionData.push( vertices[ ( v3 * 3 ) + 0 ] );
+				positionData.push( vertices[ ( v3 * 3 ) + 1 ] );
+				positionData.push( vertices[ ( v3 * 3 ) + 2 ] );
+
+				//
+
+				var p1 = triangleProperty.p1;
+				var p2 = triangleProperty.p2;
+				var p3 = triangleProperty.p3;
+
+				colorData.push( colors[ ( p1 * 3 ) + 0 ] );
+				colorData.push( colors[ ( p1 * 3 ) + 1 ] );
+				colorData.push( colors[ ( p1 * 3 ) + 2 ] );
+
+				colorData.push( colors[ ( ( p2 || p1 ) * 3 ) + 0 ] );
+				colorData.push( colors[ ( ( p2 || p1 ) * 3 ) + 1 ] );
+				colorData.push( colors[ ( ( p2 || p1 ) * 3 ) + 2 ] );
+
+				colorData.push( colors[ ( ( p3 || p1 ) * 3 ) + 0 ] );
+				colorData.push( colors[ ( ( p3 || p1 ) * 3 ) + 1 ] );
+				colorData.push( colors[ ( ( p3 || p1 ) * 3 ) + 2 ] );
+
+			}
+
+			geometry.setAttribute( 'position', new Float32BufferAttribute( positionData, 3 ) );
+			geometry.setAttribute( 'color', new Float32BufferAttribute( colorData, 3 ) );
+
+			// material
+
+			var material = new MeshPhongMaterial( { vertexColors: VertexColors, flatShading: true } );
+
+			// mesh
+
+			var mesh = new Mesh( geometry, material );
+
+			return mesh;
+
+		}
+
 		function buildDefaultMesh( meshData ) {
 		function buildDefaultMesh( meshData ) {
 
 
 			var geometry = new BufferGeometry();
 			var geometry = new BufferGeometry();
@@ -917,7 +1075,7 @@ ThreeMFLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
 			var keys = Object.keys( resourceMap );
 			var keys = Object.keys( resourceMap );
 			var meshes = [];
 			var meshes = [];
 
 
-			for ( var i = 0; i < keys.length; i ++ ) {
+			for ( var i = 0, il = keys.length; i < il; i ++ ) {
 
 
 				var resourceId = keys[ i ];
 				var resourceId = keys[ i ];
 				var triangleProperties = resourceMap[ resourceId ];
 				var triangleProperties = resourceMap[ resourceId ];
@@ -929,16 +1087,21 @@ ThreeMFLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
 						var basematerials = modelData.resources.basematerials[ resourceId ];
 						var basematerials = modelData.resources.basematerials[ resourceId ];
 						var newMeshes = buildBasematerialsMeshes( basematerials, triangleProperties, modelData, meshData, textureData, objectData );
 						var newMeshes = buildBasematerialsMeshes( basematerials, triangleProperties, modelData, meshData, textureData, objectData );
 
 
-						for ( var i = 0, l = newMeshes.length; i < l; i ++ ) {
+						for ( var j = 0, jl = newMeshes.length; j < jl; j ++ ) {
 
 
-							meshes.push( newMeshes[ i ] );
+							meshes.push( newMeshes[ j ] );
 
 
 						}
 						}
 						break;
 						break;
 
 
 					case 'texture':
 					case 'texture':
 						var texture2dgroup = modelData.resources.texture2dgroup[ resourceId ];
 						var texture2dgroup = modelData.resources.texture2dgroup[ resourceId ];
-						meshes.push( buildTexturedMesh( texture2dgroup, triangleProperties, modelData, meshData, textureData ) );
+						meshes.push( buildTexturedMesh( texture2dgroup, triangleProperties, modelData, meshData, textureData, objectData ) );
+						break;
+
+					case 'vertexColors':
+						var colorgroup = modelData.resources.colorgroup[ resourceId ];
+						meshes.push( buildVertexColorMesh( colorgroup, triangleProperties, modelData, meshData ) );
 						break;
 						break;
 
 
 					case 'default':
 					case 'default':
@@ -966,6 +1129,10 @@ ThreeMFLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
 
 
 				return 'material';
 				return 'material';
 
 
+			} else if ( modelData.resources.colorgroup[ pid ] !== undefined ) {
+
+				return 'vertexColors';
+
 			} else if ( pid === 'default' ) {
 			} else if ( pid === 'default' ) {
 
 
 				return 'default';
 				return 'default';
@@ -1068,9 +1235,29 @@ ThreeMFLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
 
 
 		}
 		}
 
 
-		function buildBasematerial( materialData ) {
+		function buildBasematerial( materialData, objects, modelData ) {
+
+			var material;
+
+			var displaypropertiesid = materialData.displaypropertiesid;
+			var pbmetallicdisplayproperties = modelData.resources.pbmetallicdisplayproperties;
+
+			if ( displaypropertiesid !== null && pbmetallicdisplayproperties[ displaypropertiesid ] !== undefined ) {
+
+				// metallic display property, use StandardMaterial
+
+				var pbmetallicdisplayproperty = pbmetallicdisplayproperties[ displaypropertiesid ];
+				var metallicData = pbmetallicdisplayproperty.data[ materialData.index ];
 
 
-			var material = new MeshPhongMaterial( { flatShading: true } );
+				material = new MeshStandardMaterial( { flatShading: true, roughness: metallicData.roughness, metalness: metallicData.metallicness } );
+
+			} else {
+
+				// otherwise use PhongMaterial
+
+				material = new MeshPhongMaterial( { flatShading: true } );
+
+			}
 
 
 			material.name = materialData.name;
 			material.name = materialData.name;
 
 

+ 1 - 0
examples/jsm/loaders/DRACOLoader.d.ts

@@ -12,6 +12,7 @@ export class DRACOLoader extends Loader {
 	setDecoderPath( path: string ): DRACOLoader;
 	setDecoderPath( path: string ): DRACOLoader;
 	setDecoderConfig( config: object ): DRACOLoader;
 	setDecoderConfig( config: object ): DRACOLoader;
 	setWorkerLimit( workerLimit: number ): DRACOLoader;
 	setWorkerLimit( workerLimit: number ): DRACOLoader;
+	preload(): DRACOLoader;
 	dispose(): DRACOLoader;
 	dispose(): DRACOLoader;
 
 
 }
 }

+ 8 - 0
examples/jsm/loaders/DRACOLoader.js

@@ -227,6 +227,14 @@ DRACOLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
 
 
 	},
 	},
 
 
+	preload: function () {
+
+		this._initDecoder();
+
+		return this;
+
+	},
+
 	_initDecoder: function () {
 	_initDecoder: function () {
 
 
 		if ( this.decoderPending ) return this.decoderPending;
 		if ( this.decoderPending ) return this.decoderPending;

+ 293 - 92
examples/jsm/loaders/EXRLoader.js

@@ -1,8 +1,9 @@
 /**
 /**
  * @author Richard M. / https://github.com/richardmonette
  * @author Richard M. / https://github.com/richardmonette
+ * @author ScieCode / http://github.com/sciecode
  *
  *
- * OpenEXR loader which, currently, supports reading 16 bit half data, in either
- * uncompressed or PIZ wavelet compressed form.
+ * OpenEXR loader which, currently, supports uncompressed, ZIP(S), RLE and PIZ wavelet compression.
+ * Supports reading 16 and 32 bit data format, except for PIZ compression which only reads 16-bit data.
  *
  *
  * Referred to the original Industrial Light & Magic OpenEXR implementation and the TinyEXR / Syoyo Fujita
  * Referred to the original Industrial Light & Magic OpenEXR implementation and the TinyEXR / Syoyo Fujita
  * implementation, so I have preserved their copyright notices.
  * implementation, so I have preserved their copyright notices.
@@ -17,6 +18,7 @@ import {
 	RGBAFormat,
 	RGBAFormat,
 	RGBFormat
 	RGBFormat
 } from "../../../build/three.module.js";
 } from "../../../build/three.module.js";
+import { Zlib } from "../libs/inflate.module.min.js";
 
 
 // /*
 // /*
 // Copyright (c) 2014 - 2017, Syoyo Fujita
 // Copyright (c) 2014 - 2017, Syoyo Fujita
@@ -700,7 +702,134 @@ EXRLoader.prototype = Object.assign( Object.create( DataTextureLoader.prototype
 
 
 		}
 		}
 
 
-		function decompressPIZ( outBuffer, outOffset, uInt8Array, inDataView, inOffset, tmpBufSize, num_channels, exrChannelInfos, dataWidth, num_lines ) {
+		function predictor( source ) {
+
+			for ( var t = 1; t < source.length; t ++ ) {
+
+				var d = source[ t - 1 ] + source[ t ] - 128;
+				source[ t ] = d;
+
+			}
+
+		}
+
+		function interleaveScalar( source, out ) {
+
+			var t1 = 0;
+			var t2 = Math.floor( ( source.length + 1 ) / 2 );
+			var s = 0;
+			var stop = source.length - 1;
+
+			while ( true ) {
+
+				if ( s > stop ) break;
+				out[ s ++ ] = source[ t1 ++ ];
+
+				if ( s > stop ) break;
+				out[ s ++ ] = source[ t2 ++ ];
+
+			}
+
+		}
+
+		function decodeRunLength( source ) {
+
+			var size = source.byteLength;
+			var out = new Array();
+			var p = 0;
+
+			var reader = new DataView( source );
+
+			while ( size > 0 ) {
+
+				var l = reader.getInt8( p ++ );
+
+				if ( l < 0 ) {
+
+					var count = - l;
+					size -= count + 1;
+
+					for ( var i = 0; i < count; i ++ ) {
+
+						out.push( reader.getUint8( p ++ ) );
+
+					}
+
+
+				} else {
+
+					var count = l;
+					size -= 2;
+
+					var value = reader.getUint8( p ++ );
+
+					for ( var i = 0; i < count + 1; i ++ ) {
+
+						out.push( value );
+
+					}
+
+
+				}
+
+			}
+
+			return out;
+
+		}
+
+		function uncompressRaw( info ) {
+
+			return new DataView( info.array.buffer, info.offset.value, info.size );
+
+		}
+
+		function uncompressRLE( info ) {
+
+			var compressed = info.viewer.buffer.slice( info.offset.value, info.offset.value + info.size );
+
+			var rawBuffer = new Uint8Array( decodeRunLength( compressed ) );
+			var tmpBuffer = new Uint8Array( rawBuffer.length );
+
+			predictor( rawBuffer ); // revert predictor
+
+			interleaveScalar( rawBuffer, tmpBuffer ); // interleave pixels
+
+			return new DataView( tmpBuffer.buffer );
+
+		}
+
+		function uncompressZIP( info ) {
+
+			var compressed = info.array.slice( info.offset.value, info.offset.value + info.size );
+
+			if ( typeof Zlib === 'undefined' ) {
+
+				console.error( 'THREE.EXRLoader: External library Inflate.min.js required, obtain or import from https://github.com/imaya/zlib.js' );
+
+			}
+
+			var inflate = new Zlib.Inflate( compressed, { resize: true, verify: true } ); // eslint-disable-line no-undef
+
+			var rawBuffer = new Uint8Array( inflate.decompress().buffer );
+			var tmpBuffer = new Uint8Array( rawBuffer.length );
+
+			predictor( rawBuffer ); // revert predictor
+
+			interleaveScalar( rawBuffer, tmpBuffer ); // interleave pixels
+
+			return new DataView( tmpBuffer.buffer );
+
+		}
+
+		function uncompressPIZ( info ) {
+
+			var inDataView = info.viewer;
+			var inOffset = { value: info.offset.value };
+
+			var tmpBufSize = info.width * scanlineBlockSize * ( EXRHeader.channels.length * BYTES_PER_HALF );
+			var outBuffer = new Uint16Array( tmpBufSize );
+			var outOffset = { value: 0 };
 
 
 			var bitmap = new Uint8Array( BITMAP_SIZE );
 			var bitmap = new Uint8Array( BITMAP_SIZE );
 
 
@@ -728,19 +857,19 @@ EXRLoader.prototype = Object.assign( Object.create( DataTextureLoader.prototype
 
 
 			var length = parseUint32( inDataView, inOffset );
 			var length = parseUint32( inDataView, inOffset );
 
 
-			hufUncompress( uInt8Array, inDataView, inOffset, length, outBuffer, outOffset, tmpBufSize );
+			hufUncompress( info.array, inDataView, inOffset, length, outBuffer, outOffset, tmpBufSize );
 
 
-			var pizChannelData = new Array( num_channels );
+			var pizChannelData = new Array( info.channels );
 
 
 			var outBufferEnd = 0;
 			var outBufferEnd = 0;
 
 
-			for ( var i = 0; i < num_channels; i ++ ) {
+			for ( var i = 0; i < info.channels; i ++ ) {
 
 
 				pizChannelData[ i ] = {};
 				pizChannelData[ i ] = {};
 				pizChannelData[ i ][ 'start' ] = outBufferEnd;
 				pizChannelData[ i ][ 'start' ] = outBufferEnd;
 				pizChannelData[ i ][ 'end' ] = pizChannelData[ i ][ 'start' ];
 				pizChannelData[ i ][ 'end' ] = pizChannelData[ i ][ 'start' ];
-				pizChannelData[ i ][ 'nx' ] = dataWidth;
-				pizChannelData[ i ][ 'ny' ] = num_lines;
+				pizChannelData[ i ][ 'nx' ] = info.width;
+				pizChannelData[ i ][ 'ny' ] = info.lines;
 				pizChannelData[ i ][ 'size' ] = 1;
 				pizChannelData[ i ][ 'size' ] = 1;
 
 
 				outBufferEnd += pizChannelData[ i ].nx * pizChannelData[ i ].ny * pizChannelData[ i ].size;
 				outBufferEnd += pizChannelData[ i ].nx * pizChannelData[ i ].ny * pizChannelData[ i ].size;
@@ -749,7 +878,7 @@ EXRLoader.prototype = Object.assign( Object.create( DataTextureLoader.prototype
 
 
 			var fooOffset = 0;
 			var fooOffset = 0;
 
 
-			for ( var i = 0; i < num_channels; i ++ ) {
+			for ( var i = 0; i < info.channels; i ++ ) {
 
 
 				for ( var j = 0; j < pizChannelData[ i ].size; ++ j ) {
 				for ( var j = 0; j < pizChannelData[ i ].size; ++ j ) {
 
 
@@ -768,7 +897,25 @@ EXRLoader.prototype = Object.assign( Object.create( DataTextureLoader.prototype
 
 
 			applyLut( lut, outBuffer, outBufferEnd );
 			applyLut( lut, outBuffer, outBufferEnd );
 
 
-			return true;
+			var tmpBuffer = new Uint8Array( outBuffer.buffer.byteLength );
+			var tmpOffset = 0;
+			var n = info.width * 2;
+
+			for ( var y = 0; y < info.lines; y ++ ) {
+
+				for ( var c = 0; c < info.channels; c ++ ) {
+
+					var cd = pizChannelData[ c ];
+					var cp = new Uint8Array( outBuffer.buffer, cd.end * 2 + y * n, n );
+
+					tmpBuffer.set( cp, tmpOffset );
+					tmpOffset += n;
+
+				}
+
+			}
+
+			return new DataView( tmpBuffer.buffer );
 
 
 		}
 		}
 
 
@@ -1069,147 +1216,205 @@ EXRLoader.prototype = Object.assign( Object.create( DataTextureLoader.prototype
 		}
 		}
 
 
 		// offsets
 		// offsets
-
 		var dataWindowHeight = EXRHeader.dataWindow.yMax + 1;
 		var dataWindowHeight = EXRHeader.dataWindow.yMax + 1;
-		var scanlineBlockSize = 1; // 1 for NO_COMPRESSION
-
-		if ( EXRHeader.compression === 'PIZ_COMPRESSION' ) {
-
-			scanlineBlockSize = 32;
 
 
-		}
+		var uncompress;
+		var scanlineBlockSize;
 
 
-		var numBlocks = dataWindowHeight / scanlineBlockSize;
+		switch ( EXRHeader.compression ) {
 
 
-		for ( var i = 0; i < numBlocks; i ++ ) {
+			case 'NO_COMPRESSION':
 
 
-			parseUlong( bufferDataView, offset ); // scanlineOffset
+				scanlineBlockSize = 1;
+				uncompress = uncompressRaw;
+				break;
 
 
-		}
+			case 'RLE_COMPRESSION':
 
 
-		// we should be passed the scanline offset table, start reading pixel data
+				scanlineBlockSize = 1;
+				uncompress = uncompressRLE;
+				break;
 
 
-		var width = EXRHeader.dataWindow.xMax - EXRHeader.dataWindow.xMin + 1;
-		var height = EXRHeader.dataWindow.yMax - EXRHeader.dataWindow.yMin + 1;
-		var numChannels = EXRHeader.channels.length;
+			case 'ZIPS_COMPRESSION':
 
 
-		switch ( this.type ) {
+				scanlineBlockSize = 1;
+				uncompress = uncompressZIP;
+				break;
 
 
-			case FloatType:
+			case 'ZIP_COMPRESSION':
 
 
-				var byteArray = new Float32Array( width * height * numChannels );
+				scanlineBlockSize = 16;
+				uncompress = uncompressZIP;
 				break;
 				break;
 
 
-			case HalfFloatType:
+			case 'PIZ_COMPRESSION':
 
 
-				var byteArray = new Uint16Array( width * height * numChannels );
+				scanlineBlockSize = 32;
+				uncompress = uncompressPIZ;
 				break;
 				break;
 
 
 			default:
 			default:
 
 
-				console.error( 'THREE.EXRLoader: unsupported type: ', this.type );
-				break;
+				throw 'EXRLoader.parse: ' + EXRHeader.compression + ' is unsupported';
 
 
 		}
 		}
 
 
-		var channelOffsets = {
-			R: 0,
-			G: 1,
-			B: 2,
-			A: 3
-		};
+		var size_t;
+		var getValue;
 
 
-		if ( EXRHeader.compression === 'NO_COMPRESSION' ) {
+		// mixed pixelType not supported
+		var pixelType = EXRHeader.channels[ 0 ].pixelType;
 
 
-			for ( var y = 0; y < height; y ++ ) {
+		if ( pixelType === 1 ) { // half
 
 
-				var y_scanline = parseUint32( bufferDataView, offset );
-				parseUint32( bufferDataView, offset ); // dataSize
+			switch ( this.type ) {
 
 
-				for ( var channelID = 0; channelID < EXRHeader.channels.length; channelID ++ ) {
+				case FloatType:
 
 
-					var cOff = channelOffsets[ EXRHeader.channels[ channelID ].name ];
+					getValue = parseFloat16;
+					size_t = INT16_SIZE;
+					break;
 
 
-					if ( EXRHeader.channels[ channelID ].pixelType === 1 ) { // half
+				case HalfFloatType:
 
 
-						for ( var x = 0; x < width; x ++ ) {
+					getValue = parseUint16;
+					size_t = INT16_SIZE;
+					break;
 
 
-							switch ( this.type ) {
+			}
 
 
-								case FloatType:
+		} else if ( pixelType === 2 ) { // float
 
 
-									var val = parseFloat16( bufferDataView, offset );
-									break;
+			switch ( this.type ) {
 
 
-								case HalfFloatType:
+				case FloatType:
 
 
-									var val = parseUint16( bufferDataView, offset );
-									break;
+					getValue = parseFloat32;
+					size_t = FLOAT32_SIZE;
+					break;
 
 
-							}
+				case HalfFloatType:
 
 
-							byteArray[ ( ( ( height - y_scanline ) * ( width * numChannels ) ) + ( x * numChannels ) ) + cOff ] = val;
+					throw 'EXRLoader.parse: unsupported HalfFloatType texture for FloatType image file.';
 
 
-						}
+			}
 
 
-					} else {
+		} else {
 
 
-						throw 'EXRLoader._parser: unsupported pixelType ' + EXRHeader.channels[ channelID ].pixelType + '. Only pixelType is 1 (HALF) is supported.';
+			throw 'EXRLoader.parse: unsupported pixelType ' + pixelType + ' for ' + EXRHeader.compression + '.';
 
 
-					}
+		}
+
+		var numBlocks = dataWindowHeight / scanlineBlockSize;
+
+		for ( var i = 0; i < numBlocks; i ++ ) {
+
+			parseUlong( bufferDataView, offset ); // scanlineOffset
+
+		}
+
+		// we should be passed the scanline offset table, start reading pixel data
+
+		var width = EXRHeader.dataWindow.xMax - EXRHeader.dataWindow.xMin + 1;
+		var height = EXRHeader.dataWindow.yMax - EXRHeader.dataWindow.yMin + 1;
+		// Firefox only supports RGBA (half) float textures
+		// var numChannels = EXRHeader.channels.length;
+		var numChannels = 4;
+		var size = width * height * numChannels;
+
+		// Fill initially with 1s for the alpha value if the texture is not RGBA, RGB values will be overwritten
+		switch ( this.type ) {
+
+			case FloatType:
+
+				var byteArray = new Float32Array( size );
+
+				if ( EXRHeader.channels.length < numChannels ) {
+
+					byteArray.fill( 1, 0, size );
 
 
 				}
 				}
 
 
-			}
+				break;
 
 
-		} else if ( EXRHeader.compression === 'PIZ_COMPRESSION' ) {
+			case HalfFloatType:
 
 
-			for ( var scanlineBlockIdx = 0; scanlineBlockIdx < height / scanlineBlockSize; scanlineBlockIdx ++ ) {
+				var byteArray = new Uint16Array( size );
 
 
-				parseUint32( bufferDataView, offset ); // line_no
-				parseUint32( bufferDataView, offset ); // data_len
+				if ( EXRHeader.channels.length < numChannels ) {
 
 
-				var tmpBufferSize = width * scanlineBlockSize * ( EXRHeader.channels.length * BYTES_PER_HALF );
-				var tmpBuffer = new Uint16Array( tmpBufferSize );
-				var tmpOffset = { value: 0 };
+					byteArray.fill( 0x3C00, 0, size ); // Uint16Array holds half float data, 0x3C00 is 1
 
 
-				decompressPIZ( tmpBuffer, tmpOffset, uInt8Array, bufferDataView, offset, tmpBufferSize, numChannels, EXRHeader.channels, width, scanlineBlockSize );
+				}
 
 
-				for ( var line_y = 0; line_y < scanlineBlockSize; line_y ++ ) {
+				break;
 
 
-					for ( var channelID = 0; channelID < EXRHeader.channels.length; channelID ++ ) {
+			default:
 
 
-						var cOff = channelOffsets[ EXRHeader.channels[ channelID ].name ];
+				console.error( 'THREE.EXRLoader: unsupported type: ', this.type );
+				break;
+
+		}
+
+		var channelOffsets = {
+			R: 0,
+			G: 1,
+			B: 2,
+			A: 3
+		};
 
 
-						if ( EXRHeader.channels[ channelID ].pixelType === 1 ) { // half
+		var compressionInfo = {
 
 
-							for ( var x = 0; x < width; x ++ ) {
+			array: uInt8Array,
+			viewer: bufferDataView,
+			offset: offset,
+			channels: EXRHeader.channels.length,
+			width: width,
+			lines: scanlineBlockSize,
+			size: 0
 
 
-								var idx = ( channelID * ( scanlineBlockSize * width ) ) + ( line_y * width ) + x;
+		};
 
 
-								switch ( this.type ) {
+		if ( EXRHeader.compression === 'NO_COMPRESSION' ||
+			EXRHeader.compression === 'ZIP_COMPRESSION' ||
+			EXRHeader.compression === 'ZIPS_COMPRESSION' ||
+			EXRHeader.compression === 'RLE_COMPRESSION' ||
+			EXRHeader.compression === 'PIZ_COMPRESSION' ) {
 
 
-									case FloatType:
+			var size;
+			var viewer;
+			var tmpOffset = { value: 0 };
 
 
-										var val = decodeFloat16( tmpBuffer[ idx ] );
-										break;
+			for ( var scanlineBlockIdx = 0; scanlineBlockIdx < height / scanlineBlockSize; scanlineBlockIdx ++ ) {
 
 
-									case HalfFloatType:
+				parseUint32( bufferDataView, offset ); // line_no
+				size = parseUint32( bufferDataView, offset ); // data_len
 
 
-										var val = tmpBuffer[ idx ];
-										break;
+				compressionInfo.offset = offset;
+				compressionInfo.size = size;
 
 
-								}
+				viewer = uncompress( compressionInfo );
 
 
-								var true_y = line_y + ( scanlineBlockIdx * scanlineBlockSize );
+				offset.value += size;
 
 
-								byteArray[ ( ( ( height - true_y ) * ( width * numChannels ) ) + ( x * numChannels ) ) + cOff ] = val;
+				for ( var line_y = 0; line_y < scanlineBlockSize; line_y ++ ) {
 
 
-							}
+					var true_y = line_y + ( scanlineBlockIdx * scanlineBlockSize );
 
 
-						} else {
+					if ( true_y >= height ) break;
 
 
-							throw 'EXRLoader._parser: unsupported pixelType ' + EXRHeader.channels[ channelID ].pixelType + '. Only pixelType is 1 (HALF) is supported.';
+					for ( var channelID = 0; channelID < EXRHeader.channels.length; channelID ++ ) {
+
+						var cOff = channelOffsets[ EXRHeader.channels[ channelID ].name ];
+
+						for ( var x = 0; x < width; x ++ ) {
+
+							var idx = ( line_y * ( EXRHeader.channels.length * width ) ) + ( channelID * width ) + x;
+							tmpOffset.value = idx * size_t;
+
+							var val = getValue( viewer, tmpOffset );
+
+							byteArray[ ( ( ( height - 1 - true_y ) * ( width * numChannels ) ) + ( x * numChannels ) ) + cOff ] = val;
 
 
 						}
 						}
 
 
@@ -1219,10 +1424,6 @@ EXRLoader.prototype = Object.assign( Object.create( DataTextureLoader.prototype
 
 
 			}
 			}
 
 
-		} else {
-
-			throw 'EXRLoader._parser: ' + EXRHeader.compression + ' is unsupported';
-
 		}
 		}
 
 
 		return {
 		return {
@@ -1230,7 +1431,7 @@ EXRLoader.prototype = Object.assign( Object.create( DataTextureLoader.prototype
 			width: width,
 			width: width,
 			height: height,
 			height: height,
 			data: byteArray,
 			data: byteArray,
-			format: EXRHeader.channels.length == 4 ? RGBAFormat : RGBFormat,
+			format: numChannels === 4 ? RGBAFormat : RGBFormat,
 			type: this.type
 			type: this.type
 		};
 		};
 
 

+ 12 - 14
examples/jsm/loaders/FBXLoader.js

@@ -2106,10 +2106,12 @@ var FBXLoader = ( function () {
 
 
 			if ( morphTargets.length === 0 ) return;
 			if ( morphTargets.length === 0 ) return;
 
 
+			parentGeo.morphTargetsRelative = true;
+
 			parentGeo.morphAttributes.position = [];
 			parentGeo.morphAttributes.position = [];
 			// parentGeo.morphAttributes.normal = []; // not implemented
 			// parentGeo.morphAttributes.normal = []; // not implemented
 
 
-			 var self = this;
+			var self = this;
 			morphTargets.forEach( function ( morphTarget ) {
 			morphTargets.forEach( function ( morphTarget ) {
 
 
 				morphTarget.rawTargets.forEach( function ( rawTarget ) {
 				morphTarget.rawTargets.forEach( function ( rawTarget ) {
@@ -2134,33 +2136,29 @@ var FBXLoader = ( function () {
 		// Normal and position attributes only have data for the vertices that are affected by the morph
 		// Normal and position attributes only have data for the vertices that are affected by the morph
 		genMorphGeometry: function ( parentGeo, parentGeoNode, morphGeoNode, preTransform, name ) {
 		genMorphGeometry: function ( parentGeo, parentGeoNode, morphGeoNode, preTransform, name ) {
 
 
-			var morphGeo = new BufferGeometry();
-			if ( morphGeoNode.attrName ) morphGeo.name = morphGeoNode.attrName;
-
 			var vertexIndices = ( parentGeoNode.PolygonVertexIndex !== undefined ) ? parentGeoNode.PolygonVertexIndex.a : [];
 			var vertexIndices = ( parentGeoNode.PolygonVertexIndex !== undefined ) ? parentGeoNode.PolygonVertexIndex.a : [];
 
 
-			// make a copy of the parent's vertex positions
-			var vertexPositions = ( parentGeoNode.Vertices !== undefined ) ? parentGeoNode.Vertices.a.slice() : [];
-
-			var morphPositions = ( morphGeoNode.Vertices !== undefined ) ? morphGeoNode.Vertices.a : [];
+			var morphPositionsSparse = ( morphGeoNode.Vertices !== undefined ) ? morphGeoNode.Vertices.a : [];
 			var indices = ( morphGeoNode.Indexes !== undefined ) ? morphGeoNode.Indexes.a : [];
 			var indices = ( morphGeoNode.Indexes !== undefined ) ? morphGeoNode.Indexes.a : [];
 
 
+			var length = parentGeo.attributes.position.count * 3;
+			var morphPositions = new Float32Array( length );
+
 			for ( var i = 0; i < indices.length; i ++ ) {
 			for ( var i = 0; i < indices.length; i ++ ) {
 
 
 				var morphIndex = indices[ i ] * 3;
 				var morphIndex = indices[ i ] * 3;
 
 
-				// FBX format uses blend shapes rather than morph targets. This can be converted
-				// by additively combining the blend shape positions with the original geometry's positions
-				vertexPositions[ morphIndex ] += morphPositions[ i * 3 ];
-				vertexPositions[ morphIndex + 1 ] += morphPositions[ i * 3 + 1 ];
-				vertexPositions[ morphIndex + 2 ] += morphPositions[ i * 3 + 2 ];
+				morphPositions[ morphIndex ] = morphPositionsSparse[ i * 3 ];
+				morphPositions[ morphIndex + 1 ] = morphPositionsSparse[ i * 3 + 1 ];
+				morphPositions[ morphIndex + 2 ] = morphPositionsSparse[ i * 3 + 2 ];
 
 
 			}
 			}
 
 
 			// TODO: add morph normal support
 			// TODO: add morph normal support
 			var morphGeoInfo = {
 			var morphGeoInfo = {
 				vertexIndices: vertexIndices,
 				vertexIndices: vertexIndices,
-				vertexPositions: vertexPositions,
+				vertexPositions: morphPositions,
+
 			};
 			};
 
 
 			var morphBuffers = this.genBuffers( morphGeoInfo );
 			var morphBuffers = this.genBuffers( morphGeoInfo );

+ 91 - 114
examples/jsm/loaders/GLTFLoader.js

@@ -9,6 +9,7 @@
 import {
 import {
 	AnimationClip,
 	AnimationClip,
 	Bone,
 	Bone,
+	Box3,
 	BufferAttribute,
 	BufferAttribute,
 	BufferGeometry,
 	BufferGeometry,
 	ClampToEdgeWrapping,
 	ClampToEdgeWrapping,
@@ -59,12 +60,14 @@ import {
 	ShaderMaterial,
 	ShaderMaterial,
 	Skeleton,
 	Skeleton,
 	SkinnedMesh,
 	SkinnedMesh,
+	Sphere,
 	SpotLight,
 	SpotLight,
 	TextureLoader,
 	TextureLoader,
 	TriangleFanDrawMode,
 	TriangleFanDrawMode,
 	TriangleStripDrawMode,
 	TriangleStripDrawMode,
 	UniformsUtils,
 	UniformsUtils,
 	Vector2,
 	Vector2,
+	Vector3,
 	VectorKeyframeTrack,
 	VectorKeyframeTrack,
 	VertexColors,
 	VertexColors,
 	sRGBEncoding
 	sRGBEncoding
@@ -214,7 +217,7 @@ var GLTFLoader = ( function () {
 
 
 			if ( json.asset === undefined || json.asset.version[ 0 ] < 2 ) {
 			if ( json.asset === undefined || json.asset.version[ 0 ] < 2 ) {
 
 
-				if ( onError ) onError( new Error( 'THREE.GLTFLoader: Unsupported asset. glTF versions >=2.0 are supported. Use LegacyGLTFLoader instead.' ) );
+				if ( onError ) onError( new Error( 'THREE.GLTFLoader: Unsupported asset. glTF versions >=2.0 are supported.' ) );
 				return;
 				return;
 
 
 			}
 			}
@@ -252,6 +255,10 @@ var GLTFLoader = ( function () {
 							extensions[ extensionName ] = new GLTFTextureTransformExtension();
 							extensions[ extensionName ] = new GLTFTextureTransformExtension();
 							break;
 							break;
 
 
+						case EXTENSIONS.KHR_MESH_QUANTIZATION:
+							extensions[ extensionName ] = new GLTFMeshQuantizationExtension();
+							break;
+
 						default:
 						default:
 
 
 							if ( extensionsRequired.indexOf( extensionName ) >= 0 ) {
 							if ( extensionsRequired.indexOf( extensionName ) >= 0 ) {
@@ -327,6 +334,7 @@ var GLTFLoader = ( function () {
 		KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS: 'KHR_materials_pbrSpecularGlossiness',
 		KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS: 'KHR_materials_pbrSpecularGlossiness',
 		KHR_MATERIALS_UNLIT: 'KHR_materials_unlit',
 		KHR_MATERIALS_UNLIT: 'KHR_materials_unlit',
 		KHR_TEXTURE_TRANSFORM: 'KHR_texture_transform',
 		KHR_TEXTURE_TRANSFORM: 'KHR_texture_transform',
+		KHR_MESH_QUANTIZATION: 'KHR_mesh_quantization',
 		MSFT_TEXTURE_DDS: 'MSFT_texture_dds'
 		MSFT_TEXTURE_DDS: 'MSFT_texture_dds'
 	};
 	};
 
 
@@ -492,7 +500,7 @@ var GLTFLoader = ( function () {
 
 
 		} else if ( this.header.version < 2.0 ) {
 		} else if ( this.header.version < 2.0 ) {
 
 
-			throw new Error( 'THREE.GLTFLoader: Legacy binary file detected. Use LegacyGLTFLoader instead.' );
+			throw new Error( 'THREE.GLTFLoader: Legacy binary file detected.' );
 
 
 		}
 		}
 
 
@@ -1045,6 +1053,17 @@ var GLTFLoader = ( function () {
 
 
 	}
 	}
 
 
+	/**
+	 * Mesh Quantization Extension
+	 *
+	 * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_mesh_quantization
+	 */
+	function GLTFMeshQuantizationExtension() {
+
+		this.name = EXTENSIONS.KHR_MESH_QUANTIZATION;
+
+	}
+
 	/*********************************/
 	/*********************************/
 	/********** INTERPOLATION ********/
 	/********** INTERPOLATION ********/
 	/*********************************/
 	/*********************************/
@@ -1373,95 +1392,9 @@ var GLTFLoader = ( function () {
 			var morphPositions = accessors[ 0 ];
 			var morphPositions = accessors[ 0 ];
 			var morphNormals = accessors[ 1 ];
 			var morphNormals = accessors[ 1 ];
 
 
-			// Clone morph target accessors before modifying them.
-
-			for ( var i = 0, il = morphPositions.length; i < il; i ++ ) {
-
-				if ( geometry.attributes.position === morphPositions[ i ] ) continue;
-
-				morphPositions[ i ] = cloneBufferAttribute( morphPositions[ i ] );
-
-			}
-
-			for ( var i = 0, il = morphNormals.length; i < il; i ++ ) {
-
-				if ( geometry.attributes.normal === morphNormals[ i ] ) continue;
-
-				morphNormals[ i ] = cloneBufferAttribute( morphNormals[ i ] );
-
-			}
-
-			for ( var i = 0, il = targets.length; i < il; i ++ ) {
-
-				var target = targets[ i ];
-				var attributeName = 'morphTarget' + i;
-
-				if ( hasMorphPosition ) {
-
-					// Three.js morph position is absolute value. The formula is
-					//   basePosition
-					//     + weight0 * ( morphPosition0 - basePosition )
-					//     + weight1 * ( morphPosition1 - basePosition )
-					//     ...
-					// while the glTF one is relative
-					//   basePosition
-					//     + weight0 * glTFmorphPosition0
-					//     + weight1 * glTFmorphPosition1
-					//     ...
-					// then we need to convert from relative to absolute here.
-
-					if ( target.POSITION !== undefined ) {
-
-						var positionAttribute = morphPositions[ i ];
-						positionAttribute.name = attributeName;
-
-						var position = geometry.attributes.position;
-
-						for ( var j = 0, jl = positionAttribute.count; j < jl; j ++ ) {
-
-							positionAttribute.setXYZ(
-								j,
-								positionAttribute.getX( j ) + position.getX( j ),
-								positionAttribute.getY( j ) + position.getY( j ),
-								positionAttribute.getZ( j ) + position.getZ( j )
-							);
-
-						}
-
-					}
-
-				}
-
-				if ( hasMorphNormal ) {
-
-					// see target.POSITION's comment
-
-					if ( target.NORMAL !== undefined ) {
-
-						var normalAttribute = morphNormals[ i ];
-						normalAttribute.name = attributeName;
-
-						var normal = geometry.attributes.normal;
-
-						for ( var j = 0, jl = normalAttribute.count; j < jl; j ++ ) {
-
-							normalAttribute.setXYZ(
-								j,
-								normalAttribute.getX( j ) + normal.getX( j ),
-								normalAttribute.getY( j ) + normal.getY( j ),
-								normalAttribute.getZ( j ) + normal.getZ( j )
-							);
-
-						}
-
-					}
-
-				}
-
-			}
-
 			if ( hasMorphPosition ) geometry.morphAttributes.position = morphPositions;
 			if ( hasMorphPosition ) geometry.morphAttributes.position = morphPositions;
 			if ( hasMorphNormal ) geometry.morphAttributes.normal = morphNormals;
 			if ( hasMorphNormal ) geometry.morphAttributes.normal = morphNormals;
+			geometry.morphTargetsRelative = true;
 
 
 			return geometry;
 			return geometry;
 
 
@@ -1549,31 +1482,6 @@ var GLTFLoader = ( function () {
 
 
 	}
 	}
 
 
-	function cloneBufferAttribute( attribute ) {
-
-		if ( attribute.isInterleavedBufferAttribute ) {
-
-			var count = attribute.count;
-			var itemSize = attribute.itemSize;
-			var array = attribute.array.slice( 0, count * itemSize );
-
-			for ( var i = 0, j = 0; i < count; ++ i ) {
-
-				array[ j ++ ] = attribute.getX( i );
-				if ( itemSize >= 2 ) array[ j ++ ] = attribute.getY( i );
-				if ( itemSize >= 3 ) array[ j ++ ] = attribute.getZ( i );
-				if ( itemSize >= 4 ) array[ j ++ ] = attribute.getW( i );
-
-			}
-
-			return new BufferAttribute( array, itemSize, attribute.normalized );
-
-		}
-
-		return attribute.clone();
-
-	}
-
 	/* GLTF PARSER */
 	/* GLTF PARSER */
 
 
 	function GLTFParser( json, extensions, options ) {
 	function GLTFParser( json, extensions, options ) {
@@ -2426,6 +2334,73 @@ var GLTFLoader = ( function () {
 
 
 	};
 	};
 
 
+	/**
+	 * @param {BufferGeometry} geometry
+	 * @param {GLTF.Primitive} primitiveDef
+	 * @param {GLTFParser} parser
+	 */
+	function computeBounds( geometry, primitiveDef, parser ) {
+
+		var attributes = primitiveDef.attributes;
+
+		var box = new Box3();
+
+		if ( attributes.POSITION !== undefined ) {
+
+			var accessor = parser.json.accessors[ attributes.POSITION ];
+			var min = accessor.min;
+			var max = accessor.max;
+
+			box.set(
+				new Vector3( min[ 0 ], min[ 1 ], min[ 2 ] ),
+				new Vector3( max[ 0 ], max[ 1 ], max[ 2 ] ) );
+
+		} else {
+
+			return;
+
+		}
+
+		var targets = primitiveDef.targets;
+
+		if ( targets !== undefined ) {
+
+			var vector = new Vector3();
+
+			for ( var i = 0, il = targets.length; i < il; i ++ ) {
+
+				var target = targets[ i ];
+
+				if ( target.POSITION !== undefined ) {
+
+					var accessor = parser.json.accessors[ target.POSITION ];
+					var min = accessor.min;
+					var max = accessor.max;
+
+					// we need to get max of absolute components because target weight is [-1,1]
+					vector.setX( Math.max( Math.abs( min[ 0 ] ), Math.abs( max[ 0 ] ) ) );
+					vector.setY( Math.max( Math.abs( min[ 1 ] ), Math.abs( max[ 1 ] ) ) );
+					vector.setZ( Math.max( Math.abs( min[ 2 ] ), Math.abs( max[ 2 ] ) ) );
+
+					box.expandByVector( vector );
+
+				}
+
+			}
+
+		}
+
+		geometry.boundingBox = box;
+
+		var sphere = new Sphere();
+
+		box.getCenter( sphere.center );
+		sphere.radius = box.min.distanceTo( box.max ) / 2;
+
+		geometry.boundingSphere = sphere;
+
+	}
+
 	/**
 	/**
 	 * @param {BufferGeometry} geometry
 	 * @param {BufferGeometry} geometry
 	 * @param {GLTF.Primitive} primitiveDef
 	 * @param {GLTF.Primitive} primitiveDef
@@ -2474,6 +2449,8 @@ var GLTFLoader = ( function () {
 
 
 		assignExtrasToUserData( geometry, primitiveDef );
 		assignExtrasToUserData( geometry, primitiveDef );
 
 
+		computeBounds( geometry, primitiveDef, parser );
+
 		return Promise.all( pending ).then( function () {
 		return Promise.all( pending ).then( function () {
 
 
 			return primitiveDef.targets !== undefined
 			return primitiveDef.targets !== undefined

+ 2 - 0
examples/jsm/loaders/LWOLoader.js

@@ -3042,6 +3042,8 @@ GeometryParser.prototype = {
 
 
 		}
 		}
 
 
+		geometry.morphTargetsRelative = false;
+
 	},
 	},
 
 
 };
 };

+ 1 - 0
examples/jsm/loaders/MD2Loader.js

@@ -375,6 +375,7 @@ MD2Loader.prototype = Object.assign( Object.create( Loader.prototype ), {
 
 
 			geometry.morphAttributes.position = morphPositions;
 			geometry.morphAttributes.position = morphPositions;
 			geometry.morphAttributes.normal = morphNormals;
 			geometry.morphAttributes.normal = morphNormals;
+			geometry.morphTargetsRelative = false;
 
 
 			geometry.animations = AnimationClip.CreateClipsFromMorphTargetSequences( frames, 10 );
 			geometry.animations = AnimationClip.CreateClipsFromMorphTargetSequences( frames, 10 );
 
 

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

@@ -958,6 +958,7 @@ var MMDLoader = ( function () {
 
 
 			geometry.morphTargets = morphTargets;
 			geometry.morphTargets = morphTargets;
 			geometry.morphAttributes.position = morphPositions;
 			geometry.morphAttributes.position = morphPositions;
+			geometry.morphTargetsRelative = false;
 
 
 			geometry.userData.MMD = {
 			geometry.userData.MMD = {
 				bones: bones,
 				bones: bones,

+ 9 - 0
examples/jsm/loaders/OBJLoader.js

@@ -27,6 +27,8 @@ var OBJLoader = ( function () {
 	var material_library_pattern = /^mtllib /;
 	var material_library_pattern = /^mtllib /;
 	// usemtl material_name
 	// usemtl material_name
 	var material_use_pattern = /^usemtl /;
 	var material_use_pattern = /^usemtl /;
+	// usemap map_name
+	var map_use_pattern = /^usemap /;
 
 
 	function ParserState() {
 	function ParserState() {
 
 
@@ -587,6 +589,13 @@ var OBJLoader = ( function () {
 
 
 					state.materialLibraries.push( line.substring( 7 ).trim() );
 					state.materialLibraries.push( line.substring( 7 ).trim() );
 
 
+				} else if ( map_use_pattern.test( line ) ) {
+
+					// the line is parsed but ignored since the loader assumes textures are defined MTL files
+					// (according to https://www.okino.com/conv/imp_wave.htm, 'usemap' is the old-style Wavefront texture reference method)
+
+					console.warn( 'THREE.OBJLoader: Rendering identifier "usemap" not supported. Textures must be defined in MTL files.' );
+
 				} else if ( lineFirstChar === 's' ) {
 				} else if ( lineFirstChar === 's' ) {
 
 
 					result = line.split( ' ' );
 					result = line.split( ' ' );

+ 0 - 3
examples/jsm/loaders/PCDLoader.js

@@ -3,9 +3,6 @@
  * @author Mugen87 / https://github.com/Mugen87
  * @author Mugen87 / https://github.com/Mugen87
  *
  *
  * Description: A THREE loader for PCD ascii and binary files.
  * Description: A THREE loader for PCD ascii and binary files.
- *
- * Limitations: Compressed binary files are not supported.
- *
  */
  */
 
 
 import {
 import {

+ 282 - 59
examples/jsm/loaders/VRMLLoader.js

@@ -11,6 +11,7 @@ import {
 	Color,
 	Color,
 	ConeBufferGeometry,
 	ConeBufferGeometry,
 	CylinderBufferGeometry,
 	CylinderBufferGeometry,
+	DataTexture,
 	DoubleSide,
 	DoubleSide,
 	FileLoader,
 	FileLoader,
 	Float32BufferAttribute,
 	Float32BufferAttribute,
@@ -26,6 +27,8 @@ import {
 	Object3D,
 	Object3D,
 	Points,
 	Points,
 	PointsMaterial,
 	PointsMaterial,
+	RGBAFormat,
+	RGBFormat,
 	RepeatWrapping,
 	RepeatWrapping,
 	Scene,
 	Scene,
 	SphereBufferGeometry,
 	SphereBufferGeometry,
@@ -180,6 +183,7 @@ var VRMLLoader = ( function () {
 				//
 				//
 
 
 				var StringLiteral = createToken( { name: "StringLiteral", pattern: /"(:?[^\\"\n\r]+|\\(:?[bfnrtv"\\/]|u[0-9a-fA-F]{4}))*"/ } );
 				var StringLiteral = createToken( { name: "StringLiteral", pattern: /"(:?[^\\"\n\r]+|\\(:?[bfnrtv"\\/]|u[0-9a-fA-F]{4}))*"/ } );
+				var HexLiteral = createToken( { name: 'HexLiteral', pattern: /0[xX][0-9a-fA-F]+/ } );
 				var NumberLiteral = createToken( { name: 'NumberLiteral', pattern: /[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?/ } );
 				var NumberLiteral = createToken( { name: 'NumberLiteral', pattern: /[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?/ } );
 				var TrueLiteral = createToken( { name: 'TrueLiteral', pattern: /TRUE/ } );
 				var TrueLiteral = createToken( { name: 'TrueLiteral', pattern: /TRUE/ } );
 				var FalseLiteral = createToken( { name: 'FalseLiteral', pattern: /FALSE/ } );
 				var FalseLiteral = createToken( { name: 'FalseLiteral', pattern: /FALSE/ } );
@@ -218,6 +222,7 @@ var VRMLLoader = ( function () {
 					Identifier,
 					Identifier,
 					RouteIdentifier,
 					RouteIdentifier,
 					StringLiteral,
 					StringLiteral,
+					HexLiteral,
 					NumberLiteral,
 					NumberLiteral,
 					LSquare,
 					LSquare,
 					RSquare,
 					RSquare,
@@ -459,6 +464,20 @@ var VRMLLoader = ( function () {
 
 
 					}
 					}
 
 
+					if ( ctx.HexLiteral ) {
+
+						field.type = 'hex';
+
+						for ( var i = 0, l = ctx.HexLiteral.length; i < l; i ++ ) {
+
+							var hexLiteral = ctx.HexLiteral[ i ];
+
+							field.values.push( hexLiteral.image );
+
+						}
+
+					}
+
 					if ( ctx.TrueLiteral ) {
 					if ( ctx.TrueLiteral ) {
 
 
 						field.type = 'boolean';
 						field.type = 'boolean';
@@ -612,7 +631,7 @@ var VRMLLoader = ( function () {
 						break;
 						break;
 
 
 					case 'Appearance':
 					case 'Appearance':
-						build = buildApperanceNode( node );
+						build = buildAppearanceNode( node );
 						break;
 						break;
 
 
 					case 'Material':
 					case 'Material':
@@ -623,6 +642,10 @@ var VRMLLoader = ( function () {
 						build = buildImageTextureNode( node );
 						build = buildImageTextureNode( node );
 						break;
 						break;
 
 
+					case 'PixelTexture':
+						build = buildPixelTextureNode( node );
+						break;
+
 					case 'TextureTransform':
 					case 'TextureTransform':
 						build = buildTextureTransformNode( node );
 						build = buildTextureTransformNode( node );
 						break;
 						break;
@@ -692,7 +715,6 @@ var VRMLLoader = ( function () {
 
 
 					case 'FontStyle':
 					case 'FontStyle':
 					case 'MovieTexture':
 					case 'MovieTexture':
-					case 'PixelTexture':
 
 
 					case 'ColorInterpolator':
 					case 'ColorInterpolator':
 					case 'CoordinateInterpolator':
 					case 'CoordinateInterpolator':
@@ -844,12 +866,12 @@ var VRMLLoader = ( function () {
 
 
 				}
 				}
 
 
+				var radius = 10000;
+
 				// sky
 				// sky
 
 
 				if ( skyColor ) {
 				if ( skyColor ) {
 
 
-					var radius = 10000;
-
 					var skyGeometry = new SphereBufferGeometry( radius, 32, 16 );
 					var skyGeometry = new SphereBufferGeometry( radius, 32, 16 );
 					var skyMaterial = new MeshBasicMaterial( { fog: false, side: BackSide, depthWrite: false, depthTest: false } );
 					var skyMaterial = new MeshBasicMaterial( { fog: false, side: BackSide, depthWrite: false, depthTest: false } );
 
 
@@ -1024,7 +1046,7 @@ var VRMLLoader = ( function () {
 
 
 			}
 			}
 
 
-			function buildApperanceNode( node ) {
+			function buildAppearanceNode( node ) {
 
 
 				var material = new MeshPhongMaterial();
 				var material = new MeshPhongMaterial();
 				var transformData;
 				var transformData;
@@ -1064,13 +1086,13 @@ var VRMLLoader = ( function () {
 							var textureNode = fieldValues[ 0 ];
 							var textureNode = fieldValues[ 0 ];
 							if ( textureNode !== null ) {
 							if ( textureNode !== null ) {
 
 
-								if ( textureNode.name === 'ImageTexture' ) {
+								if ( textureNode.name === 'ImageTexture' || textureNode.name === 'PixelTexture' ) {
 
 
 									material.map = getNode( textureNode );
 									material.map = getNode( textureNode );
 
 
 								} else {
 								} else {
 
 
-									// MovieTexture and PixelTexture not supported yet
+									// MovieTexture not supported yet
 
 
 								}
 								}
 
 
@@ -1095,12 +1117,45 @@ var VRMLLoader = ( function () {
 
 
 				// only apply texture transform data if a texture was defined
 				// only apply texture transform data if a texture was defined
 
 
-				if ( material.map && transformData ) {
+				if ( material.map ) {
+
+					// respect VRML lighting model
+
+					if ( material.map.__type ) {
+
+						switch ( material.map.__type ) {
+
+							case TEXTURE_TYPE.INTENSITY_ALPHA:
+								material.opacity = 1; // ignore transparency
+								break;
+
+							case TEXTURE_TYPE.RGB:
+								material.color.set( 0xffffff ); // ignore material color
+								break;
 
 
-					material.map.center.copy( transformData.center );
-					material.map.rotation = transformData.rotation;
-					material.map.repeat.copy( transformData.scale );
-					material.map.offset.copy( transformData.translation );
+							case TEXTURE_TYPE.RGBA:
+								material.color.set( 0xffffff ); // ignore material color
+								material.opacity = 1; // ignore transparency
+								break;
+
+							default:
+
+						}
+
+						delete material.map.__type;
+
+					}
+
+					// apply texture transform
+
+					if ( transformData ) {
+
+						material.map.center.copy( transformData.center );
+						material.map.rotation = transformData.rotation;
+						material.map.repeat.copy( transformData.scale );
+						material.map.offset.copy( transformData.translation );
+
+					}
 
 
 				}
 				}
 
 
@@ -1158,6 +1213,163 @@ var VRMLLoader = ( function () {
 
 
 			}
 			}
 
 
+			function parseHexColor( hex, textureType, color ) {
+
+				switch ( textureType ) {
+
+					case TEXTURE_TYPE.INTENSITY:
+						// Intensity texture: A one-component image specifies one-byte hexadecimal or integer values representing the intensity of the image
+						var value = parseInt( hex );
+						color.r = value;
+						color.g = value;
+						color.b = value;
+						break;
+
+					case TEXTURE_TYPE.INTENSITY_ALPHA:
+						// Intensity+Alpha texture: A two-component image specifies the intensity in the first (high) byte and the alpha opacity in the second (low) byte.
+						var value = parseInt( "0x" + hex.substring( 2, 4 ) );
+						color.r = value;
+						color.g = value;
+						color.b = value;
+						color.a = parseInt( "0x" + hex.substring( 4, 6 ) );
+						break;
+
+					case TEXTURE_TYPE.RGB:
+						// RGB texture: Pixels in a three-component image specify the red component in the first (high) byte, followed by the green and blue components
+						color.r = parseInt( "0x" + hex.substring( 2, 4 ) );
+						color.g = parseInt( "0x" + hex.substring( 4, 6 ) );
+						color.b = parseInt( "0x" + hex.substring( 6, 8 ) );
+						break;
+
+					case TEXTURE_TYPE.RGBA:
+						// RGBA texture: Four-component images specify the alpha opacity byte after red/green/blue
+						color.r = parseInt( "0x" + hex.substring( 2, 4 ) );
+						color.g = parseInt( "0x" + hex.substring( 4, 6 ) );
+						color.b = parseInt( "0x" + hex.substring( 6, 8 ) );
+						color.a = parseInt( "0x" + hex.substring( 8, 10 ) );
+						break;
+
+					default:
+
+				}
+
+			}
+
+			function getTextureType( num_components ) {
+
+				var type;
+
+				switch ( num_components ) {
+
+					case 1:
+						type = TEXTURE_TYPE.INTENSITY;
+						break;
+
+					case 2:
+						type = TEXTURE_TYPE.INTENSITY_ALPHA;
+						break;
+
+					case 3:
+						type = TEXTURE_TYPE.RGB;
+						break;
+
+					case 4:
+						type = TEXTURE_TYPE.RGBA;
+						break;
+
+					default:
+
+				}
+
+				return type;
+
+			}
+
+			function buildPixelTextureNode( node ) {
+
+				var texture;
+				var wrapS = RepeatWrapping;
+				var wrapT = RepeatWrapping;
+
+				var fields = node.fields;
+
+				for ( var i = 0, l = fields.length; i < l; i ++ ) {
+
+					var field = fields[ i ];
+					var fieldName = field.name;
+					var fieldValues = field.values;
+
+					switch ( fieldName ) {
+
+						case 'image':
+							var width = fieldValues[ 0 ];
+							var height = fieldValues[ 1 ];
+							var num_components = fieldValues[ 2 ];
+
+							var useAlpha = ( num_components === 2 || num_components === 4 );
+							var textureType = getTextureType( num_components );
+
+							var size = ( ( useAlpha === true ) ? 4 : 3 ) * ( width * height );
+							var data = new Uint8Array( size );
+
+							var color = { r: 0, g: 0, b: 0, a: 0 };
+
+							for ( var j = 3, k = 0, jl = fieldValues.length; j < jl; j ++, k ++ ) {
+
+								parseHexColor( fieldValues[ j ], textureType, color );
+
+								if ( useAlpha === true ) {
+
+									var stride = k * 4;
+
+									data[ stride + 0 ] = color.r;
+									data[ stride + 1 ] = color.g;
+									data[ stride + 2 ] = color.b;
+									data[ stride + 3 ] = color.a;
+
+								} else {
+
+									var stride = k * 3;
+
+									data[ stride + 0 ] = color.r;
+									data[ stride + 1 ] = color.g;
+									data[ stride + 2 ] = color.b;
+
+								}
+
+							}
+
+							texture = new DataTexture( data, width, height, ( useAlpha === true ) ? RGBAFormat : RGBFormat );
+							texture.__type = textureType; // needed for material modifications
+							break;
+
+						case 'repeatS':
+							if ( fieldValues[ 0 ] === false ) wrapS = ClampToEdgeWrapping;
+							break;
+
+						case 'repeatT':
+							if ( fieldValues[ 0 ] === false ) wrapT = ClampToEdgeWrapping;
+							break;
+
+						default:
+							console.warn( 'THREE.VRMLLoader: Unknown field:', fieldName );
+							break;
+
+					}
+
+				}
+
+				if ( texture ) {
+
+					texture.wrapS = wrapS;
+					texture.wrapT = wrapT;
+
+				}
+
+				return texture;
+
+			}
+
 			function buildImageTextureNode( node ) {
 			function buildImageTextureNode( node ) {
 
 
 				var texture;
 				var texture;
@@ -2257,83 +2469,69 @@ var VRMLLoader = ( function () {
 			 */
 			 */
 			function paintFaces( geometry, radius, angles, colors, topDown ) {
 			function paintFaces( geometry, radius, angles, colors, topDown ) {
 
 
-				var direction = ( topDown === true ) ? 1 : - 1;
+				// compute threshold values
 
 
-				var coord = [], A = {}, B = {}, applyColor = false;
+				var thresholds = [];
+				var startAngle = ( topDown === true ) ? 0 : Math.PI;
 
 
-				for ( var k = 0; k < angles.length; k ++ ) {
+				for ( var i = 0, l = colors.length; i < l; i ++ ) {
 
 
-					// push the vector at which the color changes
+					var angle = ( i === 0 ) ? 0 : angles[ i - 1 ];
+					angle = ( topDown === true ) ? angle : ( startAngle - angle );
 
 
-					var vec = {
-						x: direction * ( Math.cos( angles[ k ] ) * radius ),
-						y: direction * ( Math.sin( angles[ k ] ) * radius )
-					};
+					var point = new Vector3();
+					point.setFromSphericalCoords( radius, angle, 0 );
 
 
-					coord.push( vec );
+					thresholds.push( point );
 
 
 				}
 				}
 
 
-				var index = geometry.index;
+				// generate vertex colors
+
+				var indices = geometry.index;
 				var positionAttribute = geometry.attributes.position;
 				var positionAttribute = geometry.attributes.position;
 				var colorAttribute = new BufferAttribute( new Float32Array( geometry.attributes.position.count * 3 ), 3 );
 				var colorAttribute = new BufferAttribute( new Float32Array( geometry.attributes.position.count * 3 ), 3 );
 
 
 				var position = new Vector3();
 				var position = new Vector3();
 				var color = new Color();
 				var color = new Color();
 
 
-				for ( var i = 0; i < index.count; i ++ ) {
-
-					var vertexIndex = index.getX( i );
-
-					position.fromBufferAttribute( positionAttribute, vertexIndex );
-
-					for ( var j = 0; j < colors.length; j ++ ) {
-
-						// linear interpolation between aColor and bColor, calculate proportion
-						// A is previous point (angle)
-
-						if ( j === 0 ) {
-
-							A.x = 0;
-							A.y = ( topDown === true ) ? radius : - 1 * radius;
+				for ( var i = 0; i < indices.count; i ++ ) {
 
 
-						} else {
-
-							A.x = coord[ j - 1 ].x;
-							A.y = coord[ j - 1 ].y;
+					var index = indices.getX( i );
+					position.fromBufferAttribute( positionAttribute, index );
 
 
-						}
+					var thresholdIndexA, thresholdIndexB;
+					var t = 1;
 
 
-						// B is current point (angle)
+					for ( var j = 1; j < thresholds.length; j ++ ) {
 
 
-						B = coord[ j ];
+						thresholdIndexA = j - 1;
+						thresholdIndexB = j;
 
 
-						if ( B !== undefined ) {
+						var thresholdA = thresholds[ thresholdIndexA ];
+						var thresholdB = thresholds[ thresholdIndexB ];
 
 
-							// p has to be between the points A and B which we interpolate
+						if ( topDown === true ) {
 
 
-							applyColor = ( topDown === true ) ? ( position.y <= A.y && position.y > B.y ) : ( position.y >= A.y && position.y < B.y );
+							// interpolation for sky color
 
 
-							if ( applyColor === true ) {
+							if ( position.y <= thresholdA.y && position.y > thresholdB.y ) {
 
 
-								var aColor = colors[ j ];
-								var bColor = colors[ j + 1 ];
+								t = Math.abs( thresholdA.y - position.y ) / Math.abs( thresholdA.y - thresholdB.y );
 
 
-								// below is simple linear interpolation
+								break;
 
 
-								var t = Math.abs( position.y - A.y ) / ( A.y - B.y );
+							}
 
 
-								// to make it faster, you can only calculate this if the y coord changes, the color is the same for points with the same y
+						} else {
 
 
-								color.copy( aColor ).lerp( bColor, t );
+							// interpolation for ground color
 
 
-								colorAttribute.setXYZ( vertexIndex, color.r, color.g, color.b );
+							if ( position.y >= thresholdA.y && position.y < thresholdB.y ) {
 
 
-							} else {
+								t = Math.abs( thresholdA.y - position.y ) / Math.abs( thresholdA.y - thresholdB.y );
 
 
-								var colorIndex = ( topDown === true ) ? colors.length - 1 : 0;
-								var c = colors[ colorIndex ];
-								colorAttribute.setXYZ( vertexIndex, c.r, c.g, c.b );
+								break;
 
 
 							}
 							}
 
 
@@ -2341,6 +2539,13 @@ var VRMLLoader = ( function () {
 
 
 					}
 					}
 
 
+					var colorA = colors[ thresholdIndexA ];
+					var colorB = colors[ thresholdIndexB ];
+
+					color.copy( colorA ).lerp( colorB, t );
+
+					colorAttribute.setXYZ( index, color.r, color.g, color.b );
+
 				}
 				}
 
 
 				geometry.setAttribute( 'color', colorAttribute );
 				geometry.setAttribute( 'color', colorAttribute );
@@ -2416,6 +2621,7 @@ var VRMLLoader = ( function () {
 		var Identifier = tokenVocabulary[ 'Identifier' ];
 		var Identifier = tokenVocabulary[ 'Identifier' ];
 		var RouteIdentifier = tokenVocabulary[ 'RouteIdentifier' ];
 		var RouteIdentifier = tokenVocabulary[ 'RouteIdentifier' ];
 		var StringLiteral = tokenVocabulary[ 'StringLiteral' ];
 		var StringLiteral = tokenVocabulary[ 'StringLiteral' ];
+		var HexLiteral = tokenVocabulary[ 'HexLiteral' ];
 		var NumberLiteral = tokenVocabulary[ 'NumberLiteral' ];
 		var NumberLiteral = tokenVocabulary[ 'NumberLiteral' ];
 		var TrueLiteral = tokenVocabulary[ 'TrueLiteral' ];
 		var TrueLiteral = tokenVocabulary[ 'TrueLiteral' ];
 		var FalseLiteral = tokenVocabulary[ 'FalseLiteral' ];
 		var FalseLiteral = tokenVocabulary[ 'FalseLiteral' ];
@@ -2519,6 +2725,11 @@ var VRMLLoader = ( function () {
 
 
 						$.CONSUME( StringLiteral );
 						$.CONSUME( StringLiteral );
 
 
+					} },
+					{ ALT: function () {
+
+						$.CONSUME( HexLiteral );
+
 					} },
 					} },
 					{ ALT: function () {
 					{ ALT: function () {
 
 
@@ -2567,6 +2778,11 @@ var VRMLLoader = ( function () {
 
 
 						$.CONSUME( StringLiteral );
 						$.CONSUME( StringLiteral );
 
 
+					} },
+					{ ALT: function () {
+
+						$.CONSUME( HexLiteral );
+
 					} },
 					} },
 					{ ALT: function () {
 					{ ALT: function () {
 
 
@@ -2610,6 +2826,13 @@ var VRMLLoader = ( function () {
 
 
 	}
 	}
 
 
+	var TEXTURE_TYPE = {
+		INTENSITY: 1,
+		INTENSITY_ALPHA: 2,
+		RGB: 3,
+		RGBA: 4
+	};
+
 	return VRMLLoader;
 	return VRMLLoader;
 
 
 } )();
 } )();

+ 0 - 23
examples/jsm/loaders/deprecated/LegacyGLTFLoader.d.ts

@@ -1,23 +0,0 @@
-import {
-	AnimationClip,
-	Camera,
-	Loader,
-	LoadingManager,
-	Scene
-} from '../../../../src/Three';
-
-export interface GLTF {
-	animations: AnimationClip[];
-	scene: Scene;
-	scenes: Scene[];
-	cameras: Camera[];
-}
-
-export class LegacyGLTFLoader extends Loader {
-
-	constructor( manager?: LoadingManager );
-
-	load( url: string, onLoad: ( gltf: GLTF ) => void, onProgress?: ( event: ProgressEvent ) => void, onError?: ( event: ErrorEvent ) => void ): void;
-	parse( data: ArrayBuffer | string, path: string, callback: ( gltf: GLTF ) => void ): void;
-
-}

+ 0 - 2311
examples/jsm/loaders/deprecated/LegacyGLTFLoader.js

@@ -1,2311 +0,0 @@
-/**
- * @author Rich Tibbett / https://github.com/richtr
- * @author mrdoob / http://mrdoob.com/
- * @author Tony Parisi / http://www.tonyparisi.com/
- * @author Takahiro / https://github.com/takahirox
- */
-
-import {
-	AddEquation,
-	AlphaFormat,
-	AlwaysDepth,
-	AmbientLight,
-	AnimationClip,
-	AnimationUtils,
-	BackSide,
-	Bone,
-	BufferAttribute,
-	BufferGeometry,
-	ClampToEdgeWrapping,
-	Color,
-	CustomBlending,
-	DirectionalLight,
-	DoubleSide,
-	DstAlphaFactor,
-	DstColorFactor,
-	EqualDepth,
-	FileLoader,
-	FrontSide,
-	GreaterEqualDepth,
-	Group,
-	InterleavedBuffer,
-	InterleavedBufferAttribute,
-	InterpolateDiscrete,
-	InterpolateLinear,
-	LessDepth,
-	LessEqualDepth,
-	Line,
-	LineLoop,
-	LineSegments,
-	LinearFilter,
-	LinearMipmapLinearFilter,
-	LinearMipmapNearestFilter,
-	Loader,
-	LoaderUtils,
-	LuminanceAlphaFormat,
-	LuminanceFormat,
-	Math as _Math,
-	Matrix3,
-	Matrix4,
-	Mesh,
-	MeshBasicMaterial,
-	MeshLambertMaterial,
-	MeshPhongMaterial,
-	MirroredRepeatWrapping,
-	NearestFilter,
-	NearestMipmapLinearFilter,
-	NearestMipmapNearestFilter,
-	NeverDepth,
-	NoBlending,
-	NotEqualDepth,
-	Object3D,
-	OneFactor,
-	OneMinusDstAlphaFactor,
-	OneMinusDstColorFactor,
-	OneMinusSrcAlphaFactor,
-	OneMinusSrcColorFactor,
-	OrthographicCamera,
-	PerspectiveCamera,
-	PointLight,
-	QuaternionKeyframeTrack,
-	RGBAFormat,
-	RGBFormat,
-	RawShaderMaterial,
-	RepeatWrapping,
-	ReverseSubtractEquation,
-	Scene,
-	Skeleton,
-	SkinnedMesh,
-	SpotLight,
-	SrcAlphaFactor,
-	SrcAlphaSaturateFactor,
-	SrcColorFactor,
-	SubtractEquation,
-	Texture,
-	TextureLoader,
-	UniformsUtils,
-	UnsignedByteType,
-	UnsignedShort4444Type,
-	UnsignedShort5551Type,
-	UnsignedShort565Type,
-	Vector2,
-	Vector3,
-	Vector4,
-	VectorKeyframeTrack,
-	ZeroFactor
-} from "../../../../build/three.module.js";
-
-var LegacyGLTFLoader = ( function () {
-
-	function LegacyGLTFLoader( manager ) {
-
-		Loader.call( this, manager );
-
-	}
-
-	LegacyGLTFLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
-
-		constructor: LegacyGLTFLoader,
-
-		load: function ( url, onLoad, onProgress, onError ) {
-
-			var scope = this;
-
-			var resourcePath;
-
-			if ( this.resourcePath !== '' ) {
-
-				resourcePath = this.resourcePath;
-
-			} else if ( this.path !== '' ) {
-
-				resourcePath = this.path;
-
-			} else {
-
-				resourcePath = LoaderUtils.extractUrlBase( url );
-
-			}
-
-			var loader = new FileLoader( scope.manager );
-
-			loader.setPath( this.path );
-			loader.setResponseType( 'arraybuffer' );
-
-			loader.load( url, function ( data ) {
-
-				scope.parse( data, resourcePath, onLoad );
-
-			}, onProgress, onError );
-
-		},
-
-		parse: function ( data, path, callback ) {
-
-			var content;
-			var extensions = {};
-
-			var magic = LoaderUtils.decodeText( new Uint8Array( data, 0, 4 ) );
-
-			if ( magic === BINARY_EXTENSION_HEADER_DEFAULTS.magic ) {
-
-				extensions[ EXTENSIONS.KHR_BINARY_GLTF ] = new GLTFBinaryExtension( data );
-				content = extensions[ EXTENSIONS.KHR_BINARY_GLTF ].content;
-
-			} else {
-
-				content = LoaderUtils.decodeText( new Uint8Array( data ) );
-
-			}
-
-			var json = JSON.parse( content );
-
-			if ( json.extensionsUsed && json.extensionsUsed.indexOf( EXTENSIONS.KHR_MATERIALS_COMMON ) >= 0 ) {
-
-				extensions[ EXTENSIONS.KHR_MATERIALS_COMMON ] = new GLTFMaterialsCommonExtension( json );
-
-			}
-
-			var parser = new GLTFParser( json, extensions, {
-
-				crossOrigin: this.crossOrigin,
-				manager: this.manager,
-				path: path || this.resourcePath || ''
-
-			} );
-
-			parser.parse( function ( scene, scenes, cameras, animations ) {
-
-				var glTF = {
-					"scene": scene,
-					"scenes": scenes,
-					"cameras": cameras,
-					"animations": animations
-				};
-
-				callback( glTF );
-
-			} );
-
-		}
-
-	} );
-
-	/* GLTFREGISTRY */
-
-	function GLTFRegistry() {
-
-		var objects = {};
-
-		return	{
-
-			get: function ( key ) {
-
-				return objects[ key ];
-
-			},
-
-			add: function ( key, object ) {
-
-				objects[ key ] = object;
-
-			},
-
-			remove: function ( key ) {
-
-				delete objects[ key ];
-
-			},
-
-			removeAll: function () {
-
-				objects = {};
-
-			},
-
-			update: function ( scene, camera ) {
-
-				for ( var name in objects ) {
-
-					var object = objects[ name ];
-
-					if ( object.update ) {
-
-						object.update( scene, camera );
-
-					}
-
-				}
-
-			}
-
-		};
-
-	}
-
-	/* GLTFSHADERS */
-
-	LegacyGLTFLoader.Shaders = {
-
-		update: function () {
-
-			console.warn( 'THREE.LegacyGLTFLoader.Shaders has been deprecated, and now updates automatically.' );
-
-		}
-
-	};
-
-	/* GLTFSHADER */
-
-	function GLTFShader( targetNode, allNodes ) {
-
-		var boundUniforms = {};
-
-		// bind each uniform to its source node
-
-		var uniforms = targetNode.material.uniforms;
-
-		for ( var uniformId in uniforms ) {
-
-			var uniform = uniforms[ uniformId ];
-
-			if ( uniform.semantic ) {
-
-				var sourceNodeRef = uniform.node;
-
-				var sourceNode = targetNode;
-
-				if ( sourceNodeRef ) {
-
-					sourceNode = allNodes[ sourceNodeRef ];
-
-				}
-
-				boundUniforms[ uniformId ] = {
-					semantic: uniform.semantic,
-					sourceNode: sourceNode,
-					targetNode: targetNode,
-					uniform: uniform
-				};
-
-			}
-
-		}
-
-		this.boundUniforms = boundUniforms;
-		this._m4 = new Matrix4();
-
-	}
-
-	// Update - update all the uniform values
-	GLTFShader.prototype.update = function ( scene, camera ) {
-
-		var boundUniforms = this.boundUniforms;
-
-		for ( var name in boundUniforms ) {
-
-			var boundUniform = boundUniforms[ name ];
-
-			switch ( boundUniform.semantic ) {
-
-				case "MODELVIEW":
-
-					var m4 = boundUniform.uniform.value;
-					m4.multiplyMatrices( camera.matrixWorldInverse, boundUniform.sourceNode.matrixWorld );
-					break;
-
-				case "MODELVIEWINVERSETRANSPOSE":
-
-					var m3 = boundUniform.uniform.value;
-					this._m4.multiplyMatrices( camera.matrixWorldInverse, boundUniform.sourceNode.matrixWorld );
-					m3.getNormalMatrix( this._m4 );
-					break;
-
-				case "PROJECTION":
-
-					var m4 = boundUniform.uniform.value;
-					m4.copy( camera.projectionMatrix );
-					break;
-
-				case "JOINTMATRIX":
-
-					var m4v = boundUniform.uniform.value;
-
-					for ( var mi = 0; mi < m4v.length; mi ++ ) {
-
-						// So it goes like this:
-						// SkinnedMesh world matrix is already baked into MODELVIEW;
-						// transform joints to local space,
-						// then transform using joint's inverse
-						m4v[ mi ]
-							.getInverse( boundUniform.sourceNode.matrixWorld )
-							.multiply( boundUniform.targetNode.skeleton.bones[ mi ].matrixWorld )
-							.multiply( boundUniform.targetNode.skeleton.boneInverses[ mi ] )
-							.multiply( boundUniform.targetNode.bindMatrix );
-
-					}
-
-					break;
-
-				default :
-
-					console.warn( "Unhandled shader semantic: " + boundUniform.semantic );
-					break;
-
-			}
-
-		}
-
-	};
-
-
-	/* ANIMATION */
-
-	LegacyGLTFLoader.Animations = {
-
-		update: function () {
-
-			console.warn( 'THREE.LegacyGLTFLoader.Animation has been deprecated. Use THREE.AnimationMixer instead.' );
-
-		}
-
-	};
-
-	/*********************************/
-	/********** EXTENSIONS ***********/
-	/*********************************/
-
-	var EXTENSIONS = {
-		KHR_BINARY_GLTF: 'KHR_binary_glTF',
-		KHR_MATERIALS_COMMON: 'KHR_materials_common'
-	};
-
-	/* MATERIALS COMMON EXTENSION */
-
-	function GLTFMaterialsCommonExtension( json ) {
-
-		this.name = EXTENSIONS.KHR_MATERIALS_COMMON;
-
-		this.lights = {};
-
-		var extension = ( json.extensions && json.extensions[ EXTENSIONS.KHR_MATERIALS_COMMON ] ) || {};
-		var lights = extension.lights || {};
-
-		for ( var lightId in lights ) {
-
-			var light = lights[ lightId ];
-			var lightNode;
-
-			var lightParams = light[ light.type ];
-			var color = new Color().fromArray( lightParams.color );
-
-			switch ( light.type ) {
-
-				case "directional":
-					lightNode = new DirectionalLight( color );
-					lightNode.position.set( 0, 0, 1 );
-					break;
-
-				case "point":
-					lightNode = new PointLight( color );
-					break;
-
-				case "spot":
-					lightNode = new SpotLight( color );
-					lightNode.position.set( 0, 0, 1 );
-					break;
-
-				case "ambient":
-					lightNode = new AmbientLight( color );
-					break;
-
-			}
-
-			if ( lightNode ) {
-
-				this.lights[ lightId ] = lightNode;
-
-			}
-
-		}
-
-	}
-
-	/* BINARY EXTENSION */
-
-	var BINARY_EXTENSION_BUFFER_NAME = 'binary_glTF';
-
-	var BINARY_EXTENSION_HEADER_DEFAULTS = { magic: 'glTF', version: 1, contentFormat: 0 };
-
-	var BINARY_EXTENSION_HEADER_LENGTH = 20;
-
-	function GLTFBinaryExtension( data ) {
-
-		this.name = EXTENSIONS.KHR_BINARY_GLTF;
-
-		var headerView = new DataView( data, 0, BINARY_EXTENSION_HEADER_LENGTH );
-
-		var header = {
-			magic: LoaderUtils.decodeText( new Uint8Array( data.slice( 0, 4 ) ) ),
-			version: headerView.getUint32( 4, true ),
-			length: headerView.getUint32( 8, true ),
-			contentLength: headerView.getUint32( 12, true ),
-			contentFormat: headerView.getUint32( 16, true )
-		};
-
-		for ( var key in BINARY_EXTENSION_HEADER_DEFAULTS ) {
-
-			var value = BINARY_EXTENSION_HEADER_DEFAULTS[ key ];
-
-			if ( header[ key ] !== value ) {
-
-				throw new Error( 'Unsupported glTF-Binary header: Expected "%s" to be "%s".', key, value );
-
-			}
-
-		}
-
-		var contentArray = new Uint8Array( data, BINARY_EXTENSION_HEADER_LENGTH, header.contentLength );
-
-		this.header = header;
-		this.content = LoaderUtils.decodeText( contentArray );
-		this.body = data.slice( BINARY_EXTENSION_HEADER_LENGTH + header.contentLength, header.length );
-
-	}
-
-	GLTFBinaryExtension.prototype.loadShader = function ( shader, bufferViews ) {
-
-		var bufferView = bufferViews[ shader.extensions[ EXTENSIONS.KHR_BINARY_GLTF ].bufferView ];
-		var array = new Uint8Array( bufferView );
-
-		return LoaderUtils.decodeText( array );
-
-	};
-
-	/*********************************/
-	/********** INTERNALS ************/
-	/*********************************/
-
-	/* CONSTANTS */
-
-	var WEBGL_CONSTANTS = {
-		FLOAT: 5126,
-		//FLOAT_MAT2: 35674,
-		FLOAT_MAT3: 35675,
-		FLOAT_MAT4: 35676,
-		FLOAT_VEC2: 35664,
-		FLOAT_VEC3: 35665,
-		FLOAT_VEC4: 35666,
-		LINEAR: 9729,
-		REPEAT: 10497,
-		SAMPLER_2D: 35678,
-		TRIANGLES: 4,
-		LINES: 1,
-		UNSIGNED_BYTE: 5121,
-		UNSIGNED_SHORT: 5123,
-
-		VERTEX_SHADER: 35633,
-		FRAGMENT_SHADER: 35632
-	};
-
-	var WEBGL_TYPE = {
-		5126: Number,
-		//35674: Matrix2,
-		35675: Matrix3,
-		35676: Matrix4,
-		35664: Vector2,
-		35665: Vector3,
-		35666: Vector4,
-		35678: Texture
-	};
-
-	var WEBGL_COMPONENT_TYPES = {
-		5120: Int8Array,
-		5121: Uint8Array,
-		5122: Int16Array,
-		5123: Uint16Array,
-		5125: Uint32Array,
-		5126: Float32Array
-	};
-
-	var WEBGL_FILTERS = {
-		9728: NearestFilter,
-		9729: LinearFilter,
-		9984: NearestMipmapNearestFilter,
-		9985: LinearMipmapNearestFilter,
-		9986: NearestMipmapLinearFilter,
-		9987: LinearMipmapLinearFilter
-	};
-
-	var WEBGL_WRAPPINGS = {
-		33071: ClampToEdgeWrapping,
-		33648: MirroredRepeatWrapping,
-		10497: RepeatWrapping
-	};
-
-	var WEBGL_TEXTURE_FORMATS = {
-		6406: AlphaFormat,
-		6407: RGBFormat,
-		6408: RGBAFormat,
-		6409: LuminanceFormat,
-		6410: LuminanceAlphaFormat
-	};
-
-	var WEBGL_TEXTURE_DATATYPES = {
-		5121: UnsignedByteType,
-		32819: UnsignedShort4444Type,
-		32820: UnsignedShort5551Type,
-		33635: UnsignedShort565Type
-	};
-
-	var WEBGL_SIDES = {
-		1028: BackSide, // Culling front
-		1029: FrontSide // Culling back
-		//1032: NoSide   // Culling front and back, what to do?
-	};
-
-	var WEBGL_DEPTH_FUNCS = {
-		512: NeverDepth,
-		513: LessDepth,
-		514: EqualDepth,
-		515: LessEqualDepth,
-		516: GreaterEqualDepth,
-		517: NotEqualDepth,
-		518: GreaterEqualDepth,
-		519: AlwaysDepth
-	};
-
-	var WEBGL_BLEND_EQUATIONS = {
-		32774: AddEquation,
-		32778: SubtractEquation,
-		32779: ReverseSubtractEquation
-	};
-
-	var WEBGL_BLEND_FUNCS = {
-		0: ZeroFactor,
-		1: OneFactor,
-		768: SrcColorFactor,
-		769: OneMinusSrcColorFactor,
-		770: SrcAlphaFactor,
-		771: OneMinusSrcAlphaFactor,
-		772: DstAlphaFactor,
-		773: OneMinusDstAlphaFactor,
-		774: DstColorFactor,
-		775: OneMinusDstColorFactor,
-		776: SrcAlphaSaturateFactor
-		// The followings are not supported by Three.js yet
-		//32769: CONSTANT_COLOR,
-		//32770: ONE_MINUS_CONSTANT_COLOR,
-		//32771: CONSTANT_ALPHA,
-		//32772: ONE_MINUS_CONSTANT_COLOR
-	};
-
-	var WEBGL_TYPE_SIZES = {
-		'SCALAR': 1,
-		'VEC2': 2,
-		'VEC3': 3,
-		'VEC4': 4,
-		'MAT2': 4,
-		'MAT3': 9,
-		'MAT4': 16
-	};
-
-	var PATH_PROPERTIES = {
-		scale: 'scale',
-		translation: 'position',
-		rotation: 'quaternion'
-	};
-
-	var INTERPOLATION = {
-		LINEAR: InterpolateLinear,
-		STEP: InterpolateDiscrete
-	};
-
-	var STATES_ENABLES = {
-		2884: 'CULL_FACE',
-		2929: 'DEPTH_TEST',
-		3042: 'BLEND',
-		3089: 'SCISSOR_TEST',
-		32823: 'POLYGON_OFFSET_FILL',
-		32926: 'SAMPLE_ALPHA_TO_COVERAGE'
-	};
-
-	/* UTILITY FUNCTIONS */
-
-	function _each( object, callback, thisObj ) {
-
-		if ( ! object ) {
-
-			return Promise.resolve();
-
-		}
-
-		var results;
-		var fns = [];
-
-		if ( Object.prototype.toString.call( object ) === '[object Array]' ) {
-
-			results = [];
-
-			var length = object.length;
-
-			for ( var idx = 0; idx < length; idx ++ ) {
-
-				var value = callback.call( thisObj || this, object[ idx ], idx );
-
-				if ( value ) {
-
-					fns.push( value );
-
-					if ( value instanceof Promise ) {
-
-						value.then( function ( key, value ) {
-
-							results[ key ] = value;
-
-						}.bind( this, idx ) );
-
-					} else {
-
-						results[ idx ] = value;
-
-					}
-
-				}
-
-			}
-
-		} else {
-
-			results = {};
-
-			for ( var key in object ) {
-
-				if ( object.hasOwnProperty( key ) ) {
-
-					var value = callback.call( thisObj || this, object[ key ], key );
-
-					if ( value ) {
-
-						fns.push( value );
-
-						if ( value instanceof Promise ) {
-
-							value.then( function ( key, value ) {
-
-								results[ key ] = value;
-
-							}.bind( this, key ) );
-
-						} else {
-
-							results[ key ] = value;
-
-						}
-
-					}
-
-				}
-
-			}
-
-		}
-
-		return Promise.all( fns ).then( function () {
-
-			return results;
-
-		} );
-
-	}
-
-	function resolveURL( url, path ) {
-
-		// Invalid URL
-		if ( typeof url !== 'string' || url === '' )
-			return '';
-
-		// Absolute URL http://,https://,//
-		if ( /^(https?:)?\/\//i.test( url ) ) {
-
-			return url;
-
-		}
-
-		// Data URI
-		if ( /^data:.*,.*$/i.test( url ) ) {
-
-			return url;
-
-		}
-
-		// Blob URL
-		if ( /^blob:.*$/i.test( url ) ) {
-
-			return url;
-
-		}
-
-		// Relative URL
-		return ( path || '' ) + url;
-
-	}
-
-	// Three.js seems too dependent on attribute names so globally
-	// replace those in the shader code
-	function replaceTHREEShaderAttributes( shaderText, technique ) {
-
-		// Expected technique attributes
-		var attributes = {};
-
-		for ( var attributeId in technique.attributes ) {
-
-			var pname = technique.attributes[ attributeId ];
-
-			var param = technique.parameters[ pname ];
-			var atype = param.type;
-			var semantic = param.semantic;
-
-			attributes[ attributeId ] = {
-				type: atype,
-				semantic: semantic
-			};
-
-		}
-
-		// Figure out which attributes to change in technique
-
-		var shaderParams = technique.parameters;
-		var shaderAttributes = technique.attributes;
-		var params = {};
-
-		for ( var attributeId in attributes ) {
-
-			var pname = shaderAttributes[ attributeId ];
-			var shaderParam = shaderParams[ pname ];
-			var semantic = shaderParam.semantic;
-			if ( semantic ) {
-
-				params[ attributeId ] = shaderParam;
-
-			}
-
-		}
-
-		for ( var pname in params ) {
-
-			var param = params[ pname ];
-			var semantic = param.semantic;
-
-			var regEx = new RegExp( "\\b" + pname + "\\b", "g" );
-
-			switch ( semantic ) {
-
-				case "POSITION":
-
-					shaderText = shaderText.replace( regEx, 'position' );
-					break;
-
-				case "NORMAL":
-
-					shaderText = shaderText.replace( regEx, 'normal' );
-					break;
-
-				case 'TEXCOORD_0':
-				case 'TEXCOORD0':
-				case 'TEXCOORD':
-
-					shaderText = shaderText.replace( regEx, 'uv' );
-					break;
-
-				case 'TEXCOORD_1':
-
-					shaderText = shaderText.replace( regEx, 'uv2' );
-					break;
-
-				case 'COLOR_0':
-				case 'COLOR0':
-				case 'COLOR':
-
-					shaderText = shaderText.replace( regEx, 'color' );
-					break;
-
-				case "WEIGHT":
-
-					shaderText = shaderText.replace( regEx, 'skinWeight' );
-					break;
-
-				case "JOINT":
-
-					shaderText = shaderText.replace( regEx, 'skinIndex' );
-					break;
-
-			}
-
-		}
-
-		return shaderText;
-
-	}
-
-	function createDefaultMaterial() {
-
-		return new MeshPhongMaterial( {
-			color: 0x00000,
-			emissive: 0x888888,
-			specular: 0x000000,
-			shininess: 0,
-			transparent: false,
-			depthTest: true,
-			side: FrontSide
-		} );
-
-	}
-
-	// Deferred constructor for RawShaderMaterial types
-	function DeferredShaderMaterial( params ) {
-
-		this.isDeferredShaderMaterial = true;
-
-		this.params = params;
-
-	}
-
-	DeferredShaderMaterial.prototype.create = function () {
-
-		var uniforms = UniformsUtils.clone( this.params.uniforms );
-
-		for ( var uniformId in this.params.uniforms ) {
-
-			var originalUniform = this.params.uniforms[ uniformId ];
-
-			if ( originalUniform.value instanceof Texture ) {
-
-				uniforms[ uniformId ].value = originalUniform.value;
-				uniforms[ uniformId ].value.needsUpdate = true;
-
-			}
-
-			uniforms[ uniformId ].semantic = originalUniform.semantic;
-			uniforms[ uniformId ].node = originalUniform.node;
-
-		}
-
-		this.params.uniforms = uniforms;
-
-		return new RawShaderMaterial( this.params );
-
-	};
-
-	/* GLTF PARSER */
-
-	function GLTFParser( json, extensions, options ) {
-
-		this.json = json || {};
-		this.extensions = extensions || {};
-		this.options = options || {};
-
-		// loader object cache
-		this.cache = new GLTFRegistry();
-
-	}
-
-	GLTFParser.prototype._withDependencies = function ( dependencies ) {
-
-		var _dependencies = {};
-
-		for ( var i = 0; i < dependencies.length; i ++ ) {
-
-			var dependency = dependencies[ i ];
-			var fnName = "load" + dependency.charAt( 0 ).toUpperCase() + dependency.slice( 1 );
-
-			var cached = this.cache.get( dependency );
-
-			if ( cached !== undefined ) {
-
-				_dependencies[ dependency ] = cached;
-
-			} else if ( this[ fnName ] ) {
-
-				var fn = this[ fnName ]();
-				this.cache.add( dependency, fn );
-
-				_dependencies[ dependency ] = fn;
-
-			}
-
-		}
-
-		return _each( _dependencies, function ( dependency ) {
-
-			return dependency;
-
-		} );
-
-	};
-
-	GLTFParser.prototype.parse = function ( callback ) {
-
-		var json = this.json;
-
-		// Clear the loader cache
-		this.cache.removeAll();
-
-		// Fire the callback on complete
-		this._withDependencies( [
-
-			"scenes",
-			"cameras",
-			"animations"
-
-		] ).then( function ( dependencies ) {
-
-			var scenes = [];
-
-			for ( var name in dependencies.scenes ) {
-
-				scenes.push( dependencies.scenes[ name ] );
-
-			}
-
-			var scene = json.scene !== undefined ? dependencies.scenes[ json.scene ] : scenes[ 0 ];
-
-			var cameras = [];
-
-			for ( var name in dependencies.cameras ) {
-
-				var camera = dependencies.cameras[ name ];
-				cameras.push( camera );
-
-			}
-
-			var animations = [];
-
-			for ( var name in dependencies.animations ) {
-
-				animations.push( dependencies.animations[ name ] );
-
-			}
-
-			callback( scene, scenes, cameras, animations );
-
-		} );
-
-	};
-
-	GLTFParser.prototype.loadShaders = function () {
-
-		var json = this.json;
-		var extensions = this.extensions;
-		var options = this.options;
-
-		return this._withDependencies( [
-
-			"bufferViews"
-
-		] ).then( function ( dependencies ) {
-
-			return _each( json.shaders, function ( shader ) {
-
-				if ( shader.extensions && shader.extensions[ EXTENSIONS.KHR_BINARY_GLTF ] ) {
-
-					return extensions[ EXTENSIONS.KHR_BINARY_GLTF ].loadShader( shader, dependencies.bufferViews );
-
-				}
-
-				return new Promise( function ( resolve ) {
-
-					var loader = new FileLoader( options.manager );
-					loader.setResponseType( 'text' );
-					loader.load( resolveURL( shader.uri, options.path ), function ( shaderText ) {
-
-						resolve( shaderText );
-
-					} );
-
-				} );
-
-			} );
-
-		} );
-
-	};
-
-	GLTFParser.prototype.loadBuffers = function () {
-
-		var json = this.json;
-		var extensions = this.extensions;
-		var options = this.options;
-
-		return _each( json.buffers, function ( buffer, name ) {
-
-			if ( name === BINARY_EXTENSION_BUFFER_NAME ) {
-
-				return extensions[ EXTENSIONS.KHR_BINARY_GLTF ].body;
-
-			}
-
-			if ( buffer.type === 'arraybuffer' || buffer.type === undefined ) {
-
-				return new Promise( function ( resolve ) {
-
-					var loader = new FileLoader( options.manager );
-					loader.setResponseType( 'arraybuffer' );
-					loader.load( resolveURL( buffer.uri, options.path ), function ( buffer ) {
-
-						resolve( buffer );
-
-					} );
-
-				} );
-
-			} else {
-
-				console.warn( 'THREE.LegacyGLTFLoader: ' + buffer.type + ' buffer type is not supported' );
-
-			}
-
-		} );
-
-	};
-
-	GLTFParser.prototype.loadBufferViews = function () {
-
-		var json = this.json;
-
-		return this._withDependencies( [
-
-			"buffers"
-
-		] ).then( function ( dependencies ) {
-
-			return _each( json.bufferViews, function ( bufferView ) {
-
-				var arraybuffer = dependencies.buffers[ bufferView.buffer ];
-
-				var byteLength = bufferView.byteLength !== undefined ? bufferView.byteLength : 0;
-
-				return arraybuffer.slice( bufferView.byteOffset, bufferView.byteOffset + byteLength );
-
-			} );
-
-		} );
-
-	};
-
-	GLTFParser.prototype.loadAccessors = function () {
-
-		var json = this.json;
-
-		return this._withDependencies( [
-
-			"bufferViews"
-
-		] ).then( function ( dependencies ) {
-
-			return _each( json.accessors, function ( accessor ) {
-
-				var arraybuffer = dependencies.bufferViews[ accessor.bufferView ];
-				var itemSize = WEBGL_TYPE_SIZES[ accessor.type ];
-				var TypedArray = WEBGL_COMPONENT_TYPES[ accessor.componentType ];
-
-				// For VEC3: itemSize is 3, elementBytes is 4, itemBytes is 12.
-				var elementBytes = TypedArray.BYTES_PER_ELEMENT;
-				var itemBytes = elementBytes * itemSize;
-
-				// The buffer is not interleaved if the stride is the item size in bytes.
-				if ( accessor.byteStride && accessor.byteStride !== itemBytes ) {
-
-					// Use the full buffer if it's interleaved.
-					var array = new TypedArray( arraybuffer );
-
-					// Integer parameters to IB/IBA are in array elements, not bytes.
-					var ib = new InterleavedBuffer( array, accessor.byteStride / elementBytes );
-
-					return new InterleavedBufferAttribute( ib, itemSize, accessor.byteOffset / elementBytes );
-
-				} else {
-
-					array = new TypedArray( arraybuffer, accessor.byteOffset, accessor.count * itemSize );
-
-					return new BufferAttribute( array, itemSize );
-
-				}
-
-			} );
-
-		} );
-
-	};
-
-	GLTFParser.prototype.loadTextures = function () {
-
-		var json = this.json;
-		var options = this.options;
-
-		return this._withDependencies( [
-
-			"bufferViews"
-
-		] ).then( function ( dependencies ) {
-
-			return _each( json.textures, function ( texture ) {
-
-				if ( texture.source ) {
-
-					return new Promise( function ( resolve ) {
-
-						var source = json.images[ texture.source ];
-						var sourceUri = source.uri;
-						var isObjectURL = false;
-
-						if ( source.extensions && source.extensions[ EXTENSIONS.KHR_BINARY_GLTF ] ) {
-
-							var metadata = source.extensions[ EXTENSIONS.KHR_BINARY_GLTF ];
-							var bufferView = dependencies.bufferViews[ metadata.bufferView ];
-							var blob = new Blob( [ bufferView ], { type: metadata.mimeType } );
-							sourceUri = URL.createObjectURL( blob );
-							isObjectURL = true;
-
-						}
-
-						var textureLoader = options.manager.getHandler( sourceUri );
-
-						if ( textureLoader === null ) {
-
-							textureLoader = new TextureLoader( options.manager );
-
-						}
-
-						textureLoader.setCrossOrigin( options.crossOrigin );
-
-						textureLoader.load( resolveURL( sourceUri, options.path ), function ( _texture ) {
-
-							if ( isObjectURL ) URL.revokeObjectURL( sourceUri );
-
-							_texture.flipY = false;
-
-							if ( texture.name !== undefined ) _texture.name = texture.name;
-
-							_texture.format = texture.format !== undefined ? WEBGL_TEXTURE_FORMATS[ texture.format ] : RGBAFormat;
-
-							if ( texture.internalFormat !== undefined && _texture.format !== WEBGL_TEXTURE_FORMATS[ texture.internalFormat ] ) {
-
-								console.warn( 'THREE.LegacyGLTFLoader: Three.js doesn\'t support texture internalFormat which is different from texture format. ' +
-															'internalFormat will be forced to be the same value as format.' );
-
-							}
-
-							_texture.type = texture.type !== undefined ? WEBGL_TEXTURE_DATATYPES[ texture.type ] : UnsignedByteType;
-
-							if ( texture.sampler ) {
-
-								var sampler = json.samplers[ texture.sampler ];
-
-								_texture.magFilter = WEBGL_FILTERS[ sampler.magFilter ] || LinearFilter;
-								_texture.minFilter = WEBGL_FILTERS[ sampler.minFilter ] || NearestMipmapLinearFilter;
-								_texture.wrapS = WEBGL_WRAPPINGS[ sampler.wrapS ] || RepeatWrapping;
-								_texture.wrapT = WEBGL_WRAPPINGS[ sampler.wrapT ] || RepeatWrapping;
-
-							}
-
-							resolve( _texture );
-
-						}, undefined, function () {
-
-							if ( isObjectURL ) URL.revokeObjectURL( sourceUri );
-
-							resolve();
-
-						} );
-
-					} );
-
-				}
-
-			} );
-
-		} );
-
-	};
-
-	GLTFParser.prototype.loadMaterials = function () {
-
-		var json = this.json;
-
-		return this._withDependencies( [
-
-			"shaders",
-			"textures"
-
-		] ).then( function ( dependencies ) {
-
-			return _each( json.materials, function ( material ) {
-
-				var materialType;
-				var materialValues = {};
-				var materialParams = {};
-
-				var khr_material;
-
-				if ( material.extensions && material.extensions[ EXTENSIONS.KHR_MATERIALS_COMMON ] ) {
-
-					khr_material = material.extensions[ EXTENSIONS.KHR_MATERIALS_COMMON ];
-
-				}
-
-				if ( khr_material ) {
-
-					// don't copy over unused values to avoid material warning spam
-					var keys = [ 'ambient', 'emission', 'transparent', 'transparency', 'doubleSided' ];
-
-					switch ( khr_material.technique ) {
-
-						case 'BLINN' :
-						case 'PHONG' :
-							materialType = MeshPhongMaterial;
-							keys.push( 'diffuse', 'specular', 'shininess' );
-							break;
-
-						case 'LAMBERT' :
-							materialType = MeshLambertMaterial;
-							keys.push( 'diffuse' );
-							break;
-
-						case 'CONSTANT' :
-						default :
-							materialType = MeshBasicMaterial;
-							break;
-
-					}
-
-					keys.forEach( function ( v ) {
-
-						if ( khr_material.values[ v ] !== undefined ) materialValues[ v ] = khr_material.values[ v ];
-
-					} );
-
-					if ( khr_material.doubleSided || materialValues.doubleSided ) {
-
-						materialParams.side = DoubleSide;
-
-					}
-
-					if ( khr_material.transparent || materialValues.transparent ) {
-
-						materialParams.transparent = true;
-						materialParams.opacity = ( materialValues.transparency !== undefined ) ? materialValues.transparency : 1;
-
-					}
-
-				} else if ( material.technique === undefined ) {
-
-					materialType = MeshPhongMaterial;
-
-					Object.assign( materialValues, material.values );
-
-				} else {
-
-					materialType = DeferredShaderMaterial;
-
-					var technique = json.techniques[ material.technique ];
-
-					materialParams.uniforms = {};
-
-					var program = json.programs[ technique.program ];
-
-					if ( program ) {
-
-						materialParams.fragmentShader = dependencies.shaders[ program.fragmentShader ];
-
-						if ( ! materialParams.fragmentShader ) {
-
-							console.warn( "ERROR: Missing fragment shader definition:", program.fragmentShader );
-							materialType = MeshPhongMaterial;
-
-						}
-
-						var vertexShader = dependencies.shaders[ program.vertexShader ];
-
-						if ( ! vertexShader ) {
-
-							console.warn( "ERROR: Missing vertex shader definition:", program.vertexShader );
-							materialType = MeshPhongMaterial;
-
-						}
-
-						// IMPORTANT: FIX VERTEX SHADER ATTRIBUTE DEFINITIONS
-						materialParams.vertexShader = replaceTHREEShaderAttributes( vertexShader, technique );
-
-						var uniforms = technique.uniforms;
-
-						for ( var uniformId in uniforms ) {
-
-							var pname = uniforms[ uniformId ];
-							var shaderParam = technique.parameters[ pname ];
-
-							var ptype = shaderParam.type;
-
-							if ( WEBGL_TYPE[ ptype ] ) {
-
-								var pcount = shaderParam.count;
-								var value;
-
-								if ( material.values !== undefined ) value = material.values[ pname ];
-
-								var uvalue = new WEBGL_TYPE[ ptype ]();
-								var usemantic = shaderParam.semantic;
-								var unode = shaderParam.node;
-
-								switch ( ptype ) {
-
-									case WEBGL_CONSTANTS.FLOAT:
-
-										uvalue = shaderParam.value;
-
-										if ( pname == "transparency" ) {
-
-											materialParams.transparent = true;
-
-										}
-
-										if ( value !== undefined ) {
-
-											uvalue = value;
-
-										}
-
-										break;
-
-									case WEBGL_CONSTANTS.FLOAT_VEC2:
-									case WEBGL_CONSTANTS.FLOAT_VEC3:
-									case WEBGL_CONSTANTS.FLOAT_VEC4:
-									case WEBGL_CONSTANTS.FLOAT_MAT3:
-
-										if ( shaderParam && shaderParam.value ) {
-
-											uvalue.fromArray( shaderParam.value );
-
-										}
-
-										if ( value ) {
-
-											uvalue.fromArray( value );
-
-										}
-
-										break;
-
-									case WEBGL_CONSTANTS.FLOAT_MAT2:
-
-										// what to do?
-										console.warn( "FLOAT_MAT2 is not a supported uniform type" );
-										break;
-
-									case WEBGL_CONSTANTS.FLOAT_MAT4:
-
-										if ( pcount ) {
-
-											uvalue = new Array( pcount );
-
-											for ( var mi = 0; mi < pcount; mi ++ ) {
-
-												uvalue[ mi ] = new WEBGL_TYPE[ ptype ]();
-
-											}
-
-											if ( shaderParam && shaderParam.value ) {
-
-												var m4v = shaderParam.value;
-												uvalue.fromArray( m4v );
-
-											}
-
-											if ( value ) {
-
-												uvalue.fromArray( value );
-
-											}
-
-										} else {
-
-											if ( shaderParam && shaderParam.value ) {
-
-												var m4 = shaderParam.value;
-												uvalue.fromArray( m4 );
-
-											}
-
-											if ( value ) {
-
-												uvalue.fromArray( value );
-
-											}
-
-										}
-
-										break;
-
-									case WEBGL_CONSTANTS.SAMPLER_2D:
-
-										if ( value !== undefined ) {
-
-											uvalue = dependencies.textures[ value ];
-
-										} else if ( shaderParam.value !== undefined ) {
-
-											uvalue = dependencies.textures[ shaderParam.value ];
-
-										} else {
-
-											uvalue = null;
-
-										}
-
-										break;
-
-								}
-
-								materialParams.uniforms[ uniformId ] = {
-									value: uvalue,
-									semantic: usemantic,
-									node: unode
-								};
-
-							} else {
-
-								throw new Error( "Unknown shader uniform param type: " + ptype );
-
-							}
-
-						}
-
-						var states = technique.states || {};
-						var enables = states.enable || [];
-						var functions = states.functions || {};
-
-						var enableCullFace = false;
-						var enableDepthTest = false;
-						var enableBlend = false;
-
-						for ( var i = 0, il = enables.length; i < il; i ++ ) {
-
-							var enable = enables[ i ];
-
-							switch ( STATES_ENABLES[ enable ] ) {
-
-								case 'CULL_FACE':
-
-									enableCullFace = true;
-
-									break;
-
-								case 'DEPTH_TEST':
-
-									enableDepthTest = true;
-
-									break;
-
-								case 'BLEND':
-
-									enableBlend = true;
-
-									break;
-
-								// TODO: implement
-								case 'SCISSOR_TEST':
-								case 'POLYGON_OFFSET_FILL':
-								case 'SAMPLE_ALPHA_TO_COVERAGE':
-
-									break;
-
-								default:
-
-									throw new Error( "Unknown technique.states.enable: " + enable );
-
-							}
-
-						}
-
-						if ( enableCullFace ) {
-
-							materialParams.side = functions.cullFace !== undefined ? WEBGL_SIDES[ functions.cullFace ] : FrontSide;
-
-						} else {
-
-							materialParams.side = DoubleSide;
-
-						}
-
-						materialParams.depthTest = enableDepthTest;
-						materialParams.depthFunc = functions.depthFunc !== undefined ? WEBGL_DEPTH_FUNCS[ functions.depthFunc ] : LessDepth;
-						materialParams.depthWrite = functions.depthMask !== undefined ? functions.depthMask[ 0 ] : true;
-
-						materialParams.blending = enableBlend ? CustomBlending : NoBlending;
-						materialParams.transparent = enableBlend;
-
-						var blendEquationSeparate = functions.blendEquationSeparate;
-
-						if ( blendEquationSeparate !== undefined ) {
-
-							materialParams.blendEquation = WEBGL_BLEND_EQUATIONS[ blendEquationSeparate[ 0 ] ];
-							materialParams.blendEquationAlpha = WEBGL_BLEND_EQUATIONS[ blendEquationSeparate[ 1 ] ];
-
-						} else {
-
-							materialParams.blendEquation = AddEquation;
-							materialParams.blendEquationAlpha = AddEquation;
-
-						}
-
-						var blendFuncSeparate = functions.blendFuncSeparate;
-
-						if ( blendFuncSeparate !== undefined ) {
-
-							materialParams.blendSrc = WEBGL_BLEND_FUNCS[ blendFuncSeparate[ 0 ] ];
-							materialParams.blendDst = WEBGL_BLEND_FUNCS[ blendFuncSeparate[ 1 ] ];
-							materialParams.blendSrcAlpha = WEBGL_BLEND_FUNCS[ blendFuncSeparate[ 2 ] ];
-							materialParams.blendDstAlpha = WEBGL_BLEND_FUNCS[ blendFuncSeparate[ 3 ] ];
-
-						} else {
-
-							materialParams.blendSrc = OneFactor;
-							materialParams.blendDst = ZeroFactor;
-							materialParams.blendSrcAlpha = OneFactor;
-							materialParams.blendDstAlpha = ZeroFactor;
-
-						}
-
-					}
-
-				}
-
-				if ( Array.isArray( materialValues.diffuse ) ) {
-
-					materialParams.color = new Color().fromArray( materialValues.diffuse );
-
-				} else if ( typeof ( materialValues.diffuse ) === 'string' ) {
-
-					materialParams.map = dependencies.textures[ materialValues.diffuse ];
-
-				}
-
-				delete materialParams.diffuse;
-
-				if ( typeof ( materialValues.reflective ) === 'string' ) {
-
-					materialParams.envMap = dependencies.textures[ materialValues.reflective ];
-
-				}
-
-				if ( typeof ( materialValues.bump ) === 'string' ) {
-
-					materialParams.bumpMap = dependencies.textures[ materialValues.bump ];
-
-				}
-
-				if ( Array.isArray( materialValues.emission ) ) {
-
-					if ( materialType === MeshBasicMaterial ) {
-
-						materialParams.color = new Color().fromArray( materialValues.emission );
-
-					} else {
-
-						materialParams.emissive = new Color().fromArray( materialValues.emission );
-
-					}
-
-				} else if ( typeof ( materialValues.emission ) === 'string' ) {
-
-					if ( materialType === MeshBasicMaterial ) {
-
-						materialParams.map = dependencies.textures[ materialValues.emission ];
-
-					} else {
-
-						materialParams.emissiveMap = dependencies.textures[ materialValues.emission ];
-
-					}
-
-				}
-
-				if ( Array.isArray( materialValues.specular ) ) {
-
-					materialParams.specular = new Color().fromArray( materialValues.specular );
-
-				} else if ( typeof ( materialValues.specular ) === 'string' ) {
-
-					materialParams.specularMap = dependencies.textures[ materialValues.specular ];
-
-				}
-
-				if ( materialValues.shininess !== undefined ) {
-
-					materialParams.shininess = materialValues.shininess;
-
-				}
-
-				var _material = new materialType( materialParams );
-				if ( material.name !== undefined ) _material.name = material.name;
-
-				return _material;
-
-			} );
-
-		} );
-
-	};
-
-	GLTFParser.prototype.loadMeshes = function () {
-
-		var json = this.json;
-
-		return this._withDependencies( [
-
-			"accessors",
-			"materials"
-
-		] ).then( function ( dependencies ) {
-
-			return _each( json.meshes, function ( mesh ) {
-
-				var group = new Group();
-				if ( mesh.name !== undefined ) group.name = mesh.name;
-
-				if ( mesh.extras ) group.userData = mesh.extras;
-
-				var primitives = mesh.primitives || [];
-
-				for ( var name in primitives ) {
-
-					var primitive = primitives[ name ];
-
-					if ( primitive.mode === WEBGL_CONSTANTS.TRIANGLES || primitive.mode === undefined ) {
-
-						var geometry = new BufferGeometry();
-
-						var attributes = primitive.attributes;
-
-						for ( var attributeId in attributes ) {
-
-							var attributeEntry = attributes[ attributeId ];
-
-							if ( ! attributeEntry ) return;
-
-							var bufferAttribute = dependencies.accessors[ attributeEntry ];
-
-							switch ( attributeId ) {
-
-								case 'POSITION':
-									geometry.setAttribute( 'position', bufferAttribute );
-									break;
-
-								case 'NORMAL':
-									geometry.setAttribute( 'normal', bufferAttribute );
-									break;
-
-								case 'TEXCOORD_0':
-								case 'TEXCOORD0':
-								case 'TEXCOORD':
-									geometry.setAttribute( 'uv', bufferAttribute );
-									break;
-
-								case 'TEXCOORD_1':
-									geometry.setAttribute( 'uv2', bufferAttribute );
-									break;
-
-								case 'COLOR_0':
-								case 'COLOR0':
-								case 'COLOR':
-									geometry.setAttribute( 'color', bufferAttribute );
-									break;
-
-								case 'WEIGHT':
-									geometry.setAttribute( 'skinWeight', bufferAttribute );
-									break;
-
-								case 'JOINT':
-									geometry.setAttribute( 'skinIndex', bufferAttribute );
-									break;
-
-								default:
-
-									if ( ! primitive.material ) break;
-
-									var material = json.materials[ primitive.material ];
-
-									if ( ! material.technique ) break;
-
-									var parameters = json.techniques[ material.technique ].parameters || {};
-
-									for ( var attributeName in parameters ) {
-
-										if ( parameters[ attributeName ][ 'semantic' ] === attributeId ) {
-
-											geometry.setAttribute( attributeName, bufferAttribute );
-
-										}
-
-									}
-
-							}
-
-						}
-
-						if ( primitive.indices ) {
-
-							geometry.setIndex( dependencies.accessors[ primitive.indices ] );
-
-						}
-
-						var material = dependencies.materials !== undefined ? dependencies.materials[ primitive.material ] : createDefaultMaterial();
-
-						var meshNode = new Mesh( geometry, material );
-						meshNode.castShadow = true;
-						meshNode.name = ( name === "0" ? group.name : group.name + name );
-
-						if ( primitive.extras ) meshNode.userData = primitive.extras;
-
-						group.add( meshNode );
-
-					} else if ( primitive.mode === WEBGL_CONSTANTS.LINES ) {
-
-						var geometry = new BufferGeometry();
-
-						var attributes = primitive.attributes;
-
-						for ( var attributeId in attributes ) {
-
-							var attributeEntry = attributes[ attributeId ];
-
-							if ( ! attributeEntry ) return;
-
-							var bufferAttribute = dependencies.accessors[ attributeEntry ];
-
-							switch ( attributeId ) {
-
-								case 'POSITION':
-									geometry.setAttribute( 'position', bufferAttribute );
-									break;
-
-								case 'COLOR_0':
-								case 'COLOR0':
-								case 'COLOR':
-									geometry.setAttribute( 'color', bufferAttribute );
-									break;
-
-							}
-
-						}
-
-						var material = dependencies.materials[ primitive.material ];
-
-						var meshNode;
-
-						if ( primitive.indices ) {
-
-							geometry.setIndex( dependencies.accessors[ primitive.indices ] );
-
-							meshNode = new LineSegments( geometry, material );
-
-						} else {
-
-							meshNode = new Line( geometry, material );
-
-						}
-
-						meshNode.name = ( name === "0" ? group.name : group.name + name );
-
-						if ( primitive.extras ) meshNode.userData = primitive.extras;
-
-						group.add( meshNode );
-
-					} else {
-
-						console.warn( "Only triangular and line primitives are supported" );
-
-					}
-
-				}
-
-				return group;
-
-			} );
-
-		} );
-
-	};
-
-	GLTFParser.prototype.loadCameras = function () {
-
-		var json = this.json;
-
-		return _each( json.cameras, function ( camera ) {
-
-			if ( camera.type == "perspective" && camera.perspective ) {
-
-				var yfov = camera.perspective.yfov;
-				var aspectRatio = camera.perspective.aspectRatio !== undefined ? camera.perspective.aspectRatio : 1;
-
-				// According to COLLADA spec...
-				// aspectRatio = xfov / yfov
-				var xfov = yfov * aspectRatio;
-
-				var _camera = new PerspectiveCamera( _Math.radToDeg( xfov ), aspectRatio, camera.perspective.znear || 1, camera.perspective.zfar || 2e6 );
-				if ( camera.name !== undefined ) _camera.name = camera.name;
-
-				if ( camera.extras ) _camera.userData = camera.extras;
-
-				return _camera;
-
-			} else if ( camera.type == "orthographic" && camera.orthographic ) {
-
-				var _camera = new OrthographicCamera( window.innerWidth / - 2, window.innerWidth / 2, window.innerHeight / 2, window.innerHeight / - 2, camera.orthographic.znear, camera.orthographic.zfar );
-				if ( camera.name !== undefined ) _camera.name = camera.name;
-
-				if ( camera.extras ) _camera.userData = camera.extras;
-
-				return _camera;
-
-			}
-
-		} );
-
-	};
-
-	GLTFParser.prototype.loadSkins = function () {
-
-		var json = this.json;
-
-		return this._withDependencies( [
-
-			"accessors"
-
-		] ).then( function ( dependencies ) {
-
-			return _each( json.skins, function ( skin ) {
-
-				var bindShapeMatrix = new Matrix4();
-
-				if ( skin.bindShapeMatrix !== undefined ) bindShapeMatrix.fromArray( skin.bindShapeMatrix );
-
-				var _skin = {
-					bindShapeMatrix: bindShapeMatrix,
-					jointNames: skin.jointNames,
-					inverseBindMatrices: dependencies.accessors[ skin.inverseBindMatrices ]
-				};
-
-				return _skin;
-
-			} );
-
-		} );
-
-	};
-
-	GLTFParser.prototype.loadAnimations = function () {
-
-		var json = this.json;
-
-		return this._withDependencies( [
-
-			"accessors",
-			"nodes"
-
-		] ).then( function ( dependencies ) {
-
-			return _each( json.animations, function ( animation, animationId ) {
-
-				var tracks = [];
-
-				for ( var channelId in animation.channels ) {
-
-					var channel = animation.channels[ channelId ];
-					var sampler = animation.samplers[ channel.sampler ];
-
-					if ( sampler ) {
-
-						var target = channel.target;
-						var name = target.id;
-						var input = animation.parameters !== undefined ? animation.parameters[ sampler.input ] : sampler.input;
-						var output = animation.parameters !== undefined ? animation.parameters[ sampler.output ] : sampler.output;
-
-						var inputAccessor = dependencies.accessors[ input ];
-						var outputAccessor = dependencies.accessors[ output ];
-
-						var node = dependencies.nodes[ name ];
-
-						if ( node ) {
-
-							node.updateMatrix();
-							node.matrixAutoUpdate = true;
-
-							var TypedKeyframeTrack = PATH_PROPERTIES[ target.path ] === PATH_PROPERTIES.rotation
-								? QuaternionKeyframeTrack
-								: VectorKeyframeTrack;
-
-							var targetName = node.name ? node.name : node.uuid;
-							var interpolation = sampler.interpolation !== undefined ? INTERPOLATION[ sampler.interpolation ] : InterpolateLinear;
-
-							// KeyframeTrack.optimize() will modify given 'times' and 'values'
-							// buffers before creating a truncated copy to keep. Because buffers may
-							// be reused by other tracks, make copies here.
-							tracks.push( new TypedKeyframeTrack(
-								targetName + '.' + PATH_PROPERTIES[ target.path ],
-								AnimationUtils.arraySlice( inputAccessor.array, 0 ),
-								AnimationUtils.arraySlice( outputAccessor.array, 0 ),
-								interpolation
-							) );
-
-						}
-
-					}
-
-				}
-
-				var name = animation.name !== undefined ? animation.name : "animation_" + animationId;
-
-				return new AnimationClip( name, undefined, tracks );
-
-			} );
-
-		} );
-
-	};
-
-	GLTFParser.prototype.loadNodes = function () {
-
-		var json = this.json;
-		var extensions = this.extensions;
-		var scope = this;
-
-		return _each( json.nodes, function ( node ) {
-
-			var matrix = new Matrix4();
-
-			var _node;
-
-			if ( node.jointName ) {
-
-				_node = new Bone();
-				_node.name = node.name !== undefined ? node.name : node.jointName;
-				_node.jointName = node.jointName;
-
-			} else {
-
-				_node = new Object3D();
-				if ( node.name !== undefined ) _node.name = node.name;
-
-			}
-
-			if ( node.extras ) _node.userData = node.extras;
-
-			if ( node.matrix !== undefined ) {
-
-				matrix.fromArray( node.matrix );
-				_node.applyMatrix( matrix );
-
-			} else {
-
-				if ( node.translation !== undefined ) {
-
-					_node.position.fromArray( node.translation );
-
-				}
-
-				if ( node.rotation !== undefined ) {
-
-					_node.quaternion.fromArray( node.rotation );
-
-				}
-
-				if ( node.scale !== undefined ) {
-
-					_node.scale.fromArray( node.scale );
-
-				}
-
-			}
-
-			return _node;
-
-		} ).then( function ( __nodes ) {
-
-			return scope._withDependencies( [
-
-				"meshes",
-				"skins",
-				"cameras"
-
-			] ).then( function ( dependencies ) {
-
-				return _each( __nodes, function ( _node, nodeId ) {
-
-					var node = json.nodes[ nodeId ];
-
-					if ( node.meshes !== undefined ) {
-
-						for ( var meshId in node.meshes ) {
-
-							var mesh = node.meshes[ meshId ];
-							var group = dependencies.meshes[ mesh ];
-
-							if ( group === undefined ) {
-
-								console.warn( 'LegacyGLTFLoader: Couldn\'t find node "' + mesh + '".' );
-								continue;
-
-							}
-
-							for ( var childrenId in group.children ) {
-
-								var child = group.children[ childrenId ];
-
-								// clone Mesh to add to _node
-
-								var originalMaterial = child.material;
-								var originalGeometry = child.geometry;
-								var originalUserData = child.userData;
-								var originalName = child.name;
-
-								var material;
-
-								if ( originalMaterial.isDeferredShaderMaterial ) {
-
-									originalMaterial = material = originalMaterial.create();
-
-								} else {
-
-									material = originalMaterial;
-
-								}
-
-								switch ( child.type ) {
-
-									case 'LineSegments':
-										child = new LineSegments( originalGeometry, material );
-										break;
-
-									case 'LineLoop':
-										child = new LineLoop( originalGeometry, material );
-										break;
-
-									case 'Line':
-										child = new Line( originalGeometry, material );
-										break;
-
-									default:
-										child = new Mesh( originalGeometry, material );
-
-								}
-
-								child.castShadow = true;
-								child.userData = originalUserData;
-								child.name = originalName;
-
-								var skinEntry;
-
-								if ( node.skin ) {
-
-									skinEntry = dependencies.skins[ node.skin ];
-
-								}
-
-								// Replace Mesh with SkinnedMesh in library
-								if ( skinEntry ) {
-
-									var getJointNode = function ( jointId ) {
-
-										var keys = Object.keys( __nodes );
-
-										for ( var i = 0, il = keys.length; i < il; i ++ ) {
-
-											var n = __nodes[ keys[ i ] ];
-
-											if ( n.jointName === jointId ) return n;
-
-										}
-
-										return null;
-
-									};
-
-									var geometry = originalGeometry;
-									var material = originalMaterial;
-									material.skinning = true;
-
-									child = new SkinnedMesh( geometry, material );
-									child.castShadow = true;
-									child.userData = originalUserData;
-									child.name = originalName;
-
-									var bones = [];
-									var boneInverses = [];
-
-									for ( var i = 0, l = skinEntry.jointNames.length; i < l; i ++ ) {
-
-										var jointId = skinEntry.jointNames[ i ];
-										var jointNode = getJointNode( jointId );
-
-										if ( jointNode ) {
-
-											bones.push( jointNode );
-
-											var m = skinEntry.inverseBindMatrices.array;
-											var mat = new Matrix4().fromArray( m, i * 16 );
-											boneInverses.push( mat );
-
-										} else {
-
-											console.warn( "WARNING: joint: '" + jointId + "' could not be found" );
-
-										}
-
-									}
-
-									child.bind( new Skeleton( bones, boneInverses ), skinEntry.bindShapeMatrix );
-
-									var buildBoneGraph = function ( parentJson, parentObject, property ) {
-
-										var children = parentJson[ property ];
-
-										if ( children === undefined ) return;
-
-										for ( var i = 0, il = children.length; i < il; i ++ ) {
-
-											var nodeId = children[ i ];
-											var bone = __nodes[ nodeId ];
-											var boneJson = json.nodes[ nodeId ];
-
-											if ( bone !== undefined && bone.isBone === true && boneJson !== undefined ) {
-
-												parentObject.add( bone );
-												buildBoneGraph( boneJson, bone, 'children' );
-
-											}
-
-										}
-
-									};
-
-									buildBoneGraph( node, child, 'skeletons' );
-
-								}
-
-								_node.add( child );
-
-							}
-
-						}
-
-					}
-
-					if ( node.camera !== undefined ) {
-
-						var camera = dependencies.cameras[ node.camera ];
-
-						_node.add( camera );
-
-					}
-
-					if ( node.extensions
-							 && node.extensions[ EXTENSIONS.KHR_MATERIALS_COMMON ]
-							 && node.extensions[ EXTENSIONS.KHR_MATERIALS_COMMON ].light ) {
-
-						var extensionLights = extensions[ EXTENSIONS.KHR_MATERIALS_COMMON ].lights;
-						var light = extensionLights[ node.extensions[ EXTENSIONS.KHR_MATERIALS_COMMON ].light ];
-
-						_node.add( light );
-
-					}
-
-					return _node;
-
-				} );
-
-			} );
-
-		} );
-
-	};
-
-	GLTFParser.prototype.loadScenes = function () {
-
-		var json = this.json;
-
-		// scene node hierachy builder
-
-		function buildNodeHierachy( nodeId, parentObject, allNodes ) {
-
-			var _node = allNodes[ nodeId ];
-			parentObject.add( _node );
-
-			var node = json.nodes[ nodeId ];
-
-			if ( node.children ) {
-
-				var children = node.children;
-
-				for ( var i = 0, l = children.length; i < l; i ++ ) {
-
-					var child = children[ i ];
-					buildNodeHierachy( child, _node, allNodes );
-
-				}
-
-			}
-
-		}
-
-		return this._withDependencies( [
-
-			"nodes"
-
-		] ).then( function ( dependencies ) {
-
-			return _each( json.scenes, function ( scene ) {
-
-				var _scene = new Scene();
-				if ( scene.name !== undefined ) _scene.name = scene.name;
-
-				if ( scene.extras ) _scene.userData = scene.extras;
-
-				var nodes = scene.nodes || [];
-
-				for ( var i = 0, l = nodes.length; i < l; i ++ ) {
-
-					var nodeId = nodes[ i ];
-					buildNodeHierachy( nodeId, _scene, dependencies.nodes );
-
-				}
-
-				_scene.traverse( function ( child ) {
-
-					// Register raw material meshes with LegacyGLTFLoader.Shaders
-					if ( child.material && child.material.isRawShaderMaterial ) {
-
-						child.gltfShader = new GLTFShader( child, dependencies.nodes );
-						child.onBeforeRender = function ( renderer, scene, camera ) {
-
-							this.gltfShader.update( scene, camera );
-
-						};
-
-					}
-
-				} );
-
-				return _scene;
-
-			} );
-
-		} );
-
-	};
-
-	return LegacyGLTFLoader;
-
-} )();
-
-export { LegacyGLTFLoader };

+ 0 - 21
examples/jsm/loaders/deprecated/LegacyJSONLoader.d.ts

@@ -1,21 +0,0 @@
-import {
-	Geometry,
-	Loader,
-	LoadingManager,
-	Material
-} from '../../../../src/Three';
-
-export interface LegacyJSONLoaderResult {
-	geometry: Geometry;
-	materials: Material[];
-}
-
-export class LegacyJSONLoader extends Loader {
-
-	constructor( manager?: LoadingManager );
-	withCredentials: boolean;
-
-	load( url: string, onLoad: ( geometry: Geometry, materials: Material[] ) => void, onProgress?: ( event: ProgressEvent ) => void, onError?: ( event: ErrorEvent ) => void ): void;
-	parse( json: object, path: string ): LegacyJSONLoaderResult;
-
-}

+ 0 - 851
examples/jsm/loaders/deprecated/LegacyJSONLoader.js

@@ -1,851 +0,0 @@
-/**
- * @author mrdoob / http://mrdoob.com/
- * @author alteredq / http://alteredqualia.com/
- */
-
-import {
-	AdditiveBlending,
-	AnimationClip,
-	BackSide,
-	Color,
-	CustomBlending,
-	DoubleSide,
-	Face3,
-	FaceColors,
-	FileLoader,
-	Geometry,
-	Loader,
-	LoaderUtils,
-	MaterialLoader,
-	Math as _Math,
-	MirroredRepeatWrapping,
-	MultiplyBlending,
-	NoBlending,
-	NormalBlending,
-	RepeatWrapping,
-	SubtractiveBlending,
-	TextureLoader,
-	Vector2,
-	Vector3,
-	Vector4,
-	VertexColors
-} from "../../../../build/three.module.js";
-
-var LegacyJSONLoader = ( function () {
-
-	function LegacyJSONLoader( manager ) {
-
-		if ( typeof manager === 'boolean' ) {
-
-			console.warn( 'THREE.JSONLoader: showStatus parameter has been removed from constructor.' );
-			manager = undefined;
-
-		}
-
-		Loader.call( this, manager );
-
-		this.withCredentials = false;
-
-	}
-
-	LegacyJSONLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
-
-		constructor: LegacyJSONLoader,
-
-		load: function ( url, onLoad, onProgress, onError ) {
-
-			var scope = this;
-
-			var path = ( this.path === '' ) ? LoaderUtils.extractUrlBase( url ) : this.path;
-
-			var loader = new FileLoader( this.manager );
-			loader.setPath( this.path );
-			loader.setWithCredentials( this.withCredentials );
-			loader.load( url, function ( text ) {
-
-				var json = JSON.parse( text );
-				var metadata = json.metadata;
-
-				if ( metadata !== undefined ) {
-
-					var type = metadata.type;
-
-					if ( type !== undefined ) {
-
-						if ( type.toLowerCase() === 'object' ) {
-
-							console.error( 'THREE.JSONLoader: ' + url + ' should be loaded with THREE.ObjectLoader instead.' );
-							return;
-
-						}
-
-					}
-
-				}
-
-				var object = scope.parse( json, path );
-				onLoad( object.geometry, object.materials );
-
-			}, onProgress, onError );
-
-		},
-
-		parse: ( function () {
-
-			var _BlendingMode = {
-				NoBlending: NoBlending,
-				NormalBlending: NormalBlending,
-				AdditiveBlending: AdditiveBlending,
-				SubtractiveBlending: SubtractiveBlending,
-				MultiplyBlending: MultiplyBlending,
-				CustomBlending: CustomBlending
-			};
-
-			var _color = new Color();
-			var _textureLoader = new TextureLoader();
-			var _materialLoader = new MaterialLoader();
-
-			function initMaterials( materials, texturePath, crossOrigin, manager ) {
-
-				var array = [];
-
-				for ( var i = 0; i < materials.length; ++ i ) {
-
-					array[ i ] = createMaterial( materials[ i ], texturePath, crossOrigin, manager );
-
-				}
-
-				return array;
-
-			}
-
-			function createMaterial( m, texturePath, crossOrigin, manager ) {
-
-				// convert from old material format
-
-				var textures = {};
-
-				//
-
-				var json = {
-					uuid: _Math.generateUUID(),
-					type: 'MeshLambertMaterial'
-				};
-
-				for ( var name in m ) {
-
-					var value = m[ name ];
-
-					switch ( name ) {
-
-						case 'DbgColor':
-						case 'DbgIndex':
-						case 'opticalDensity':
-						case 'illumination':
-							break;
-						case 'DbgName':
-							json.name = value;
-							break;
-						case 'blending':
-							json.blending = _BlendingMode[ value ];
-							break;
-						case 'colorAmbient':
-						case 'mapAmbient':
-							console.warn( 'THREE.LegacyJSONLoader.createMaterial:', name, 'is no longer supported.' );
-							break;
-						case 'colorDiffuse':
-							json.color = _color.fromArray( value ).getHex();
-							break;
-						case 'colorSpecular':
-							json.specular = _color.fromArray( value ).getHex();
-							break;
-						case 'colorEmissive':
-							json.emissive = _color.fromArray( value ).getHex();
-							break;
-						case 'specularCoef':
-							json.shininess = value;
-							break;
-						case 'shading':
-							if ( value.toLowerCase() === 'basic' ) json.type = 'MeshBasicMaterial';
-							if ( value.toLowerCase() === 'phong' ) json.type = 'MeshPhongMaterial';
-							if ( value.toLowerCase() === 'standard' ) json.type = 'MeshStandardMaterial';
-							break;
-						case 'mapDiffuse':
-							json.map = loadTexture( value, m.mapDiffuseRepeat, m.mapDiffuseOffset, m.mapDiffuseWrap, m.mapDiffuseAnisotropy, textures, texturePath, crossOrigin, manager );
-							break;
-						case 'mapDiffuseRepeat':
-						case 'mapDiffuseOffset':
-						case 'mapDiffuseWrap':
-						case 'mapDiffuseAnisotropy':
-							break;
-						case 'mapEmissive':
-							json.emissiveMap = loadTexture( value, m.mapEmissiveRepeat, m.mapEmissiveOffset, m.mapEmissiveWrap, m.mapEmissiveAnisotropy, textures, texturePath, crossOrigin, manager );
-							break;
-						case 'mapEmissiveRepeat':
-						case 'mapEmissiveOffset':
-						case 'mapEmissiveWrap':
-						case 'mapEmissiveAnisotropy':
-							break;
-						case 'mapLight':
-							json.lightMap = loadTexture( value, m.mapLightRepeat, m.mapLightOffset, m.mapLightWrap, m.mapLightAnisotropy, textures, texturePath, crossOrigin, manager );
-							break;
-						case 'mapLightRepeat':
-						case 'mapLightOffset':
-						case 'mapLightWrap':
-						case 'mapLightAnisotropy':
-							break;
-						case 'mapAO':
-							json.aoMap = loadTexture( value, m.mapAORepeat, m.mapAOOffset, m.mapAOWrap, m.mapAOAnisotropy, textures, texturePath, crossOrigin, manager );
-							break;
-						case 'mapAORepeat':
-						case 'mapAOOffset':
-						case 'mapAOWrap':
-						case 'mapAOAnisotropy':
-							break;
-						case 'mapBump':
-							json.bumpMap = loadTexture( value, m.mapBumpRepeat, m.mapBumpOffset, m.mapBumpWrap, m.mapBumpAnisotropy, textures, texturePath, crossOrigin, manager );
-							break;
-						case 'mapBumpScale':
-							json.bumpScale = value;
-							break;
-						case 'mapBumpRepeat':
-						case 'mapBumpOffset':
-						case 'mapBumpWrap':
-						case 'mapBumpAnisotropy':
-							break;
-						case 'mapNormal':
-							json.normalMap = loadTexture( value, m.mapNormalRepeat, m.mapNormalOffset, m.mapNormalWrap, m.mapNormalAnisotropy, textures, texturePath, crossOrigin, manager );
-							break;
-						case 'mapNormalFactor':
-							json.normalScale = value;
-							break;
-						case 'mapNormalRepeat':
-						case 'mapNormalOffset':
-						case 'mapNormalWrap':
-						case 'mapNormalAnisotropy':
-							break;
-						case 'mapSpecular':
-							json.specularMap = loadTexture( value, m.mapSpecularRepeat, m.mapSpecularOffset, m.mapSpecularWrap, m.mapSpecularAnisotropy, textures, texturePath, crossOrigin, manager );
-							break;
-						case 'mapSpecularRepeat':
-						case 'mapSpecularOffset':
-						case 'mapSpecularWrap':
-						case 'mapSpecularAnisotropy':
-							break;
-						case 'mapMetalness':
-							json.metalnessMap = loadTexture( value, m.mapMetalnessRepeat, m.mapMetalnessOffset, m.mapMetalnessWrap, m.mapMetalnessAnisotropy, textures, texturePath, crossOrigin, manager );
-							break;
-						case 'mapMetalnessRepeat':
-						case 'mapMetalnessOffset':
-						case 'mapMetalnessWrap':
-						case 'mapMetalnessAnisotropy':
-							break;
-						case 'mapRoughness':
-							json.roughnessMap = loadTexture( value, m.mapRoughnessRepeat, m.mapRoughnessOffset, m.mapRoughnessWrap, m.mapRoughnessAnisotropy, textures, texturePath, crossOrigin, manager );
-							break;
-						case 'mapRoughnessRepeat':
-						case 'mapRoughnessOffset':
-						case 'mapRoughnessWrap':
-						case 'mapRoughnessAnisotropy':
-							break;
-						case 'mapAlpha':
-							json.alphaMap = loadTexture( value, m.mapAlphaRepeat, m.mapAlphaOffset, m.mapAlphaWrap, m.mapAlphaAnisotropy, textures, texturePath, crossOrigin, manager );
-							break;
-						case 'mapAlphaRepeat':
-						case 'mapAlphaOffset':
-						case 'mapAlphaWrap':
-						case 'mapAlphaAnisotropy':
-							break;
-						case 'flipSided':
-							json.side = BackSide;
-							break;
-						case 'doubleSided':
-							json.side = DoubleSide;
-							break;
-						case 'transparency':
-							console.warn( 'THREE.LegacyJSONLoader.createMaterial: transparency has been renamed to opacity' );
-							json.opacity = value;
-							break;
-						case 'depthTest':
-						case 'depthWrite':
-						case 'colorWrite':
-						case 'opacity':
-						case 'reflectivity':
-						case 'transparent':
-						case 'visible':
-						case 'wireframe':
-							json[ name ] = value;
-							break;
-						case 'vertexColors':
-							if ( value === true ) json.vertexColors = VertexColors;
-							if ( value === 'face' ) json.vertexColors = FaceColors;
-							break;
-						default:
-							console.error( 'THREE.LegacyJSONLoader.createMaterial: Unsupported', name, value );
-							break;
-
-					}
-
-				}
-
-				if ( json.type === 'MeshBasicMaterial' ) delete json.emissive;
-				if ( json.type !== 'MeshPhongMaterial' ) delete json.specular;
-
-				if ( json.opacity < 1 ) json.transparent = true;
-
-				_materialLoader.setTextures( textures );
-
-				return _materialLoader.parse( json );
-
-			}
-
-			function loadTexture( path, repeat, offset, wrap, anisotropy, textures, texturePath, crossOrigin, manager ) {
-
-				var fullPath = texturePath + path;
-				var loader = manager.getHandler( fullPath );
-
-				var texture;
-
-				if ( loader !== null ) {
-
-					texture = loader.load( fullPath );
-
-				} else {
-
-					_textureLoader.setCrossOrigin( crossOrigin );
-					texture = _textureLoader.load( fullPath );
-
-				}
-
-				if ( repeat !== undefined ) {
-
-					texture.repeat.fromArray( repeat );
-
-					if ( repeat[ 0 ] !== 1 ) texture.wrapS = RepeatWrapping;
-					if ( repeat[ 1 ] !== 1 ) texture.wrapT = RepeatWrapping;
-
-				}
-
-				if ( offset !== undefined ) {
-
-					texture.offset.fromArray( offset );
-
-				}
-
-				if ( wrap !== undefined ) {
-
-					if ( wrap[ 0 ] === 'repeat' ) texture.wrapS = RepeatWrapping;
-					if ( wrap[ 0 ] === 'mirror' ) texture.wrapS = MirroredRepeatWrapping;
-
-					if ( wrap[ 1 ] === 'repeat' ) texture.wrapT = RepeatWrapping;
-					if ( wrap[ 1 ] === 'mirror' ) texture.wrapT = MirroredRepeatWrapping;
-
-				}
-
-				if ( anisotropy !== undefined ) {
-
-					texture.anisotropy = anisotropy;
-
-				}
-
-				var uuid = _Math.generateUUID();
-
-				textures[ uuid ] = texture;
-
-				return uuid;
-
-			}
-
-			function parseModel( json, geometry ) {
-
-				function isBitSet( value, position ) {
-
-					return value & ( 1 << position );
-
-				}
-
-				var i, j, fi,
-
-					offset, zLength,
-
-					colorIndex, normalIndex, uvIndex, materialIndex,
-
-					type,
-					isQuad,
-					hasMaterial,
-					hasFaceVertexUv,
-					hasFaceNormal, hasFaceVertexNormal,
-					hasFaceColor, hasFaceVertexColor,
-
-					vertex, face, faceA, faceB, hex, normal,
-
-					uvLayer, uv, u, v,
-
-					faces = json.faces,
-					vertices = json.vertices,
-					normals = json.normals,
-					colors = json.colors,
-
-					scale = json.scale,
-
-					nUvLayers = 0;
-
-
-				if ( json.uvs !== undefined ) {
-
-					// disregard empty arrays
-
-					for ( i = 0; i < json.uvs.length; i ++ ) {
-
-						if ( json.uvs[ i ].length ) nUvLayers ++;
-
-					}
-
-					for ( i = 0; i < nUvLayers; i ++ ) {
-
-						geometry.faceVertexUvs[ i ] = [];
-
-					}
-
-				}
-
-				offset = 0;
-				zLength = vertices.length;
-
-				while ( offset < zLength ) {
-
-					vertex = new Vector3();
-
-					vertex.x = vertices[ offset ++ ] * scale;
-					vertex.y = vertices[ offset ++ ] * scale;
-					vertex.z = vertices[ offset ++ ] * scale;
-
-					geometry.vertices.push( vertex );
-
-				}
-
-				offset = 0;
-				zLength = faces.length;
-
-				while ( offset < zLength ) {
-
-					type = faces[ offset ++ ];
-
-					isQuad = isBitSet( type, 0 );
-					hasMaterial = isBitSet( type, 1 );
-					hasFaceVertexUv = isBitSet( type, 3 );
-					hasFaceNormal = isBitSet( type, 4 );
-					hasFaceVertexNormal = isBitSet( type, 5 );
-					hasFaceColor = isBitSet( type, 6 );
-					hasFaceVertexColor = isBitSet( type, 7 );
-
-					// console.log("type", type, "bits", isQuad, hasMaterial, hasFaceVertexUv, hasFaceNormal, hasFaceVertexNormal, hasFaceColor, hasFaceVertexColor);
-
-					if ( isQuad ) {
-
-						faceA = new Face3();
-						faceA.a = faces[ offset ];
-						faceA.b = faces[ offset + 1 ];
-						faceA.c = faces[ offset + 3 ];
-
-						faceB = new Face3();
-						faceB.a = faces[ offset + 1 ];
-						faceB.b = faces[ offset + 2 ];
-						faceB.c = faces[ offset + 3 ];
-
-						offset += 4;
-
-						if ( hasMaterial ) {
-
-							materialIndex = faces[ offset ++ ];
-							faceA.materialIndex = materialIndex;
-							faceB.materialIndex = materialIndex;
-
-						}
-
-						// to get face <=> uv index correspondence
-
-						fi = geometry.faces.length;
-
-						if ( hasFaceVertexUv ) {
-
-							for ( i = 0; i < nUvLayers; i ++ ) {
-
-								uvLayer = json.uvs[ i ];
-
-								geometry.faceVertexUvs[ i ][ fi ] = [];
-								geometry.faceVertexUvs[ i ][ fi + 1 ] = [];
-
-								for ( j = 0; j < 4; j ++ ) {
-
-									uvIndex = faces[ offset ++ ];
-
-									u = uvLayer[ uvIndex * 2 ];
-									v = uvLayer[ uvIndex * 2 + 1 ];
-
-									uv = new Vector2( u, v );
-
-									if ( j !== 2 ) geometry.faceVertexUvs[ i ][ fi ].push( uv );
-									if ( j !== 0 ) geometry.faceVertexUvs[ i ][ fi + 1 ].push( uv );
-
-								}
-
-							}
-
-						}
-
-						if ( hasFaceNormal ) {
-
-							normalIndex = faces[ offset ++ ] * 3;
-
-							faceA.normal.set(
-								normals[ normalIndex ++ ],
-								normals[ normalIndex ++ ],
-								normals[ normalIndex ]
-							);
-
-							faceB.normal.copy( faceA.normal );
-
-						}
-
-						if ( hasFaceVertexNormal ) {
-
-							for ( i = 0; i < 4; i ++ ) {
-
-								normalIndex = faces[ offset ++ ] * 3;
-
-								normal = new Vector3(
-									normals[ normalIndex ++ ],
-									normals[ normalIndex ++ ],
-									normals[ normalIndex ]
-								);
-
-
-								if ( i !== 2 ) faceA.vertexNormals.push( normal );
-								if ( i !== 0 ) faceB.vertexNormals.push( normal );
-
-							}
-
-						}
-
-
-						if ( hasFaceColor ) {
-
-							colorIndex = faces[ offset ++ ];
-							hex = colors[ colorIndex ];
-
-							faceA.color.setHex( hex );
-							faceB.color.setHex( hex );
-
-						}
-
-
-						if ( hasFaceVertexColor ) {
-
-							for ( i = 0; i < 4; i ++ ) {
-
-								colorIndex = faces[ offset ++ ];
-								hex = colors[ colorIndex ];
-
-								if ( i !== 2 ) faceA.vertexColors.push( new Color( hex ) );
-								if ( i !== 0 ) faceB.vertexColors.push( new Color( hex ) );
-
-							}
-
-						}
-
-						geometry.faces.push( faceA );
-						geometry.faces.push( faceB );
-
-					} else {
-
-						face = new Face3();
-						face.a = faces[ offset ++ ];
-						face.b = faces[ offset ++ ];
-						face.c = faces[ offset ++ ];
-
-						if ( hasMaterial ) {
-
-							materialIndex = faces[ offset ++ ];
-							face.materialIndex = materialIndex;
-
-						}
-
-						// to get face <=> uv index correspondence
-
-						fi = geometry.faces.length;
-
-						if ( hasFaceVertexUv ) {
-
-							for ( i = 0; i < nUvLayers; i ++ ) {
-
-								uvLayer = json.uvs[ i ];
-
-								geometry.faceVertexUvs[ i ][ fi ] = [];
-
-								for ( j = 0; j < 3; j ++ ) {
-
-									uvIndex = faces[ offset ++ ];
-
-									u = uvLayer[ uvIndex * 2 ];
-									v = uvLayer[ uvIndex * 2 + 1 ];
-
-									uv = new Vector2( u, v );
-
-									geometry.faceVertexUvs[ i ][ fi ].push( uv );
-
-								}
-
-							}
-
-						}
-
-						if ( hasFaceNormal ) {
-
-							normalIndex = faces[ offset ++ ] * 3;
-
-							face.normal.set(
-								normals[ normalIndex ++ ],
-								normals[ normalIndex ++ ],
-								normals[ normalIndex ]
-							);
-
-						}
-
-						if ( hasFaceVertexNormal ) {
-
-							for ( i = 0; i < 3; i ++ ) {
-
-								normalIndex = faces[ offset ++ ] * 3;
-
-								normal = new Vector3(
-									normals[ normalIndex ++ ],
-									normals[ normalIndex ++ ],
-									normals[ normalIndex ]
-								);
-
-								face.vertexNormals.push( normal );
-
-							}
-
-						}
-
-
-						if ( hasFaceColor ) {
-
-							colorIndex = faces[ offset ++ ];
-							face.color.setHex( colors[ colorIndex ] );
-
-						}
-
-
-						if ( hasFaceVertexColor ) {
-
-							for ( i = 0; i < 3; i ++ ) {
-
-								colorIndex = faces[ offset ++ ];
-								face.vertexColors.push( new Color( colors[ colorIndex ] ) );
-
-							}
-
-						}
-
-						geometry.faces.push( face );
-
-					}
-
-				}
-
-			}
-
-			function parseSkin( json, geometry ) {
-
-				var influencesPerVertex = ( json.influencesPerVertex !== undefined ) ? json.influencesPerVertex : 2;
-
-				if ( json.skinWeights ) {
-
-					for ( var i = 0, l = json.skinWeights.length; i < l; i += influencesPerVertex ) {
-
-						var x = json.skinWeights[ i ];
-						var y = ( influencesPerVertex > 1 ) ? json.skinWeights[ i + 1 ] : 0;
-						var z = ( influencesPerVertex > 2 ) ? json.skinWeights[ i + 2 ] : 0;
-						var w = ( influencesPerVertex > 3 ) ? json.skinWeights[ i + 3 ] : 0;
-
-						geometry.skinWeights.push( new Vector4( x, y, z, w ) );
-
-					}
-
-				}
-
-				if ( json.skinIndices ) {
-
-					for ( var i = 0, l = json.skinIndices.length; i < l; i += influencesPerVertex ) {
-
-						var a = json.skinIndices[ i ];
-						var b = ( influencesPerVertex > 1 ) ? json.skinIndices[ i + 1 ] : 0;
-						var c = ( influencesPerVertex > 2 ) ? json.skinIndices[ i + 2 ] : 0;
-						var d = ( influencesPerVertex > 3 ) ? json.skinIndices[ i + 3 ] : 0;
-
-						geometry.skinIndices.push( new Vector4( a, b, c, d ) );
-
-					}
-
-				}
-
-				geometry.bones = json.bones;
-
-				if ( geometry.bones && geometry.bones.length > 0 && ( geometry.skinWeights.length !== geometry.skinIndices.length || geometry.skinIndices.length !== geometry.vertices.length ) ) {
-
-					console.warn( 'When skinning, number of vertices (' + geometry.vertices.length + '), skinIndices (' +
-						geometry.skinIndices.length + '), and skinWeights (' + geometry.skinWeights.length + ') should match.' );
-
-				}
-
-			}
-
-			function parseMorphing( json, geometry ) {
-
-				var scale = json.scale;
-
-				if ( json.morphTargets !== undefined ) {
-
-					for ( var i = 0, l = json.morphTargets.length; i < l; i ++ ) {
-
-						geometry.morphTargets[ i ] = {};
-						geometry.morphTargets[ i ].name = json.morphTargets[ i ].name;
-						geometry.morphTargets[ i ].vertices = [];
-
-						var dstVertices = geometry.morphTargets[ i ].vertices;
-						var srcVertices = json.morphTargets[ i ].vertices;
-
-						for ( var v = 0, vl = srcVertices.length; v < vl; v += 3 ) {
-
-							var vertex = new Vector3();
-							vertex.x = srcVertices[ v ] * scale;
-							vertex.y = srcVertices[ v + 1 ] * scale;
-							vertex.z = srcVertices[ v + 2 ] * scale;
-
-							dstVertices.push( vertex );
-
-						}
-
-					}
-
-				}
-
-				if ( json.morphColors !== undefined && json.morphColors.length > 0 ) {
-
-					console.warn( 'THREE.JSONLoader: "morphColors" no longer supported. Using them as face colors.' );
-
-					var faces = geometry.faces;
-					var morphColors = json.morphColors[ 0 ].colors;
-
-					for ( var i = 0, l = faces.length; i < l; i ++ ) {
-
-						faces[ i ].color.fromArray( morphColors, i * 3 );
-
-					}
-
-				}
-
-			}
-
-			function parseAnimations( json, geometry ) {
-
-				var outputAnimations = [];
-
-				// parse old style Bone/Hierarchy animations
-				var animations = [];
-
-				if ( json.animation !== undefined ) {
-
-					animations.push( json.animation );
-
-				}
-
-				if ( json.animations !== undefined ) {
-
-					if ( json.animations.length ) {
-
-						animations = animations.concat( json.animations );
-
-					} else {
-
-						animations.push( json.animations );
-
-					}
-
-				}
-
-				for ( var i = 0; i < animations.length; i ++ ) {
-
-					var clip = AnimationClip.parseAnimation( animations[ i ], geometry.bones );
-					if ( clip ) outputAnimations.push( clip );
-
-				}
-
-				// parse implicit morph animations
-				if ( geometry.morphTargets ) {
-
-					// TODO: Figure out what an appropraite FPS is for morph target animations -- defaulting to 10, but really it is completely arbitrary.
-					var morphAnimationClips = AnimationClip.CreateClipsFromMorphTargetSequences( geometry.morphTargets, 10 );
-					outputAnimations = outputAnimations.concat( morphAnimationClips );
-
-				}
-
-				if ( outputAnimations.length > 0 ) geometry.animations = outputAnimations;
-
-			}
-
-			return function parse( json, path ) {
-
-				if ( json.data !== undefined ) {
-
-					// Geometry 4.0 spec
-					json = json.data;
-
-				}
-
-				if ( json.scale !== undefined ) {
-
-					json.scale = 1.0 / json.scale;
-
-				} else {
-
-					json.scale = 1.0;
-
-				}
-
-				var geometry = new Geometry();
-
-				parseModel( json, geometry );
-				parseSkin( json, geometry );
-				parseMorphing( json, geometry );
-				parseAnimations( json, geometry );
-
-				geometry.computeFaceNormals();
-				geometry.computeBoundingSphere();
-
-				if ( json.materials === undefined || json.materials.length === 0 ) {
-
-					return { geometry: geometry };
-
-				} else {
-
-					var materials = initMaterials( json.materials, this.resourcePath || path, this.crossOrigin, this.manager );
-
-					return { geometry: geometry, materials: materials };
-
-				}
-
-			};
-
-		} )()
-
-	} );
-
-	return LegacyJSONLoader;
-
-} )();
-
-export { LegacyJSONLoader };

+ 1 - 1
examples/jsm/misc/MorphAnimMesh.d.ts

@@ -1,5 +1,5 @@
+import { AnimationAction } from '../../../src/animation/AnimationAction'
 import {
 import {
-	AnimationAction,
 	AnimationMixer,
 	AnimationMixer,
 	BufferGeometry,
 	BufferGeometry,
 	Geometry,
 	Geometry,

+ 170 - 0
examples/jsm/misc/TubePainter.js

@@ -0,0 +1,170 @@
+/**
+ * @author mr.doob / http://mrdoob.com/
+ */
+
+import {
+	BufferAttribute,
+	BufferGeometry,
+	Color,
+	DynamicDrawUsage,
+	Mesh,
+	MeshStandardMaterial,
+	Vector3,
+	VertexColors
+} from '../../../build/three.module.js';
+
+function TubePainter() {
+
+	const BUFFER_SIZE = 1000000 * 3;
+
+	let positions = new BufferAttribute( new Float32Array( BUFFER_SIZE ), 3 );
+	positions.usage = DynamicDrawUsage;
+
+	let normals = new BufferAttribute( new Float32Array( BUFFER_SIZE ), 3 );
+	normals.usage = DynamicDrawUsage;
+
+	let colors = new BufferAttribute( new Float32Array( BUFFER_SIZE ), 3 );
+	colors.usage = DynamicDrawUsage;
+
+	let geometry = new BufferGeometry();
+	geometry.setAttribute( 'position', positions );
+	geometry.setAttribute( 'normal', normals );
+	geometry.setAttribute( 'color', colors );
+	geometry.drawRange.count = 0;
+
+	let material = new MeshStandardMaterial( {
+		roughness: 0.9,
+		metalness: 0.0,
+		vertexColors: VertexColors
+	} );
+
+	let mesh = new Mesh( geometry, material );
+	mesh.frustumCulled = false;
+
+	//
+
+	function getPoints( size ) {
+
+		let PI2 = Math.PI * 2;
+
+		let sides = 10;
+		let array = [];
+		let radius = 0.01 * size;
+
+		for ( let i = 0; i < sides; i ++ ) {
+
+			let angle = ( i / sides ) * PI2;
+			array.push( new Vector3( Math.sin( angle ) * radius, Math.cos( angle ) * radius, 0 ) );
+
+		}
+
+		return array;
+
+	}
+
+	let vector1 = new Vector3();
+	let vector2 = new Vector3();
+	let vector3 = new Vector3();
+	let vector4 = new Vector3();
+
+	let color = new Color( 0xffffff );
+	let size = 1;
+
+	function stroke( position1, position2, matrix1, matrix2 ) {
+
+		if ( position1.distanceToSquared( position2 ) === 0 ) return;
+
+		let count = geometry.drawRange.count;
+
+		let points = getPoints( size );
+
+		for ( let i = 0, il = points.length; i < il; i ++ ) {
+
+			let vertex1 = points[ i ];
+			let vertex2 = points[ ( i + 1 ) % il ];
+
+			// positions
+
+			vector1.copy( vertex1 ).applyMatrix4( matrix2 ).add( position2 );
+			vector2.copy( vertex2 ).applyMatrix4( matrix2 ).add( position2 );
+			vector3.copy( vertex2 ).applyMatrix4( matrix1 ).add( position1 );
+			vector4.copy( vertex1 ).applyMatrix4( matrix1 ).add( position1 );
+
+			vector1.toArray( positions.array, ( count + 0 ) * 3 );
+			vector2.toArray( positions.array, ( count + 1 ) * 3 );
+			vector4.toArray( positions.array, ( count + 2 ) * 3 );
+
+			vector2.toArray( positions.array, ( count + 3 ) * 3 );
+			vector3.toArray( positions.array, ( count + 4 ) * 3 );
+			vector4.toArray( positions.array, ( count + 5 ) * 3 );
+
+			// normals
+
+			vector1.copy( vertex1 ).applyMatrix4( matrix2 ).normalize();
+			vector2.copy( vertex2 ).applyMatrix4( matrix2 ).normalize();
+			vector3.copy( vertex2 ).applyMatrix4( matrix1 ).normalize();
+			vector4.copy( vertex1 ).applyMatrix4( matrix1 ).normalize();
+
+			vector1.toArray( normals.array, ( count + 0 ) * 3 );
+			vector2.toArray( normals.array, ( count + 1 ) * 3 );
+			vector4.toArray( normals.array, ( count + 2 ) * 3 );
+
+			vector2.toArray( normals.array, ( count + 3 ) * 3 );
+			vector3.toArray( normals.array, ( count + 4 ) * 3 );
+			vector4.toArray( normals.array, ( count + 5 ) * 3 );
+
+			// colors
+
+			color.toArray( colors.array, ( count + 0 ) * 3 );
+			color.toArray( colors.array, ( count + 1 ) * 3 );
+			color.toArray( colors.array, ( count + 2 ) * 3 );
+
+			color.toArray( colors.array, ( count + 3 ) * 3 );
+			color.toArray( colors.array, ( count + 4 ) * 3 );
+			color.toArray( colors.array, ( count + 5 ) * 3 );
+
+			count += 6;
+
+		}
+
+		geometry.drawRange.count = count;
+
+	}
+
+	function setSize( value ) {
+
+		size = value;
+
+	}
+
+	function updateGeometry( start, end ) {
+
+		if ( start === end ) return;
+
+		let offset = start * 3;
+		let count = ( end - start ) * 3;
+
+		positions.updateRange.offset = offset;
+		positions.updateRange.count = count;
+		positions.needsUpdate = true;
+
+		normals.updateRange.offset = offset;
+		normals.updateRange.count = count;
+		normals.needsUpdate = true;
+
+		colors.updateRange.offset = offset;
+		colors.updateRange.count = count;
+		colors.needsUpdate = true;
+
+	}
+
+	return {
+		mesh: mesh,
+		stroke: stroke,
+		setSize: setSize,
+		updateGeometry: updateGeometry
+	};
+
+}
+
+export { TubePainter };

+ 1 - 1
examples/jsm/misc/Volume.d.ts

@@ -2,7 +2,7 @@ import {
 	Matrix3,
 	Matrix3,
 } from '../../../src/Three';
 } from '../../../src/Three';
 
 
-import { VolumeSlice } from "./VolumeSlice.js";
+import { VolumeSlice } from './VolumeSlice.js';
 
 
 export class Volume {
 export class Volume {
 
 

+ 4 - 3
examples/jsm/nodes/materials/NodeMaterial.js

@@ -30,7 +30,9 @@ function NodeMaterial( vertex, fragment ) {
 
 
 	this.onBeforeCompile = function ( shader, renderer ) {
 	this.onBeforeCompile = function ( shader, renderer ) {
 
 
-		if ( this.needsUpdate ) {
+		var materialProperties = renderer.properties.get( this );
+
+		if ( this.version !== materialProperties.__version ) {
 
 
 			this.build( { renderer: renderer } );
 			this.build( { renderer: renderer } );
 
 
@@ -74,6 +76,7 @@ Object.defineProperties( NodeMaterial.prototype, {
 
 
 		set: function ( value ) {
 		set: function ( value ) {
 
 
+			if ( value === true ) this.version ++;
 			this.needsCompile = value;
 			this.needsCompile = value;
 
 
 		},
 		},
@@ -120,8 +123,6 @@ NodeMaterial.prototype.build = function ( params ) {
 
 
 	this.transparent = builder.requires.transparent || this.blending > NormalBlending;
 	this.transparent = builder.requires.transparent || this.blending > NormalBlending;
 
 
-	this.needsUpdate = false;
-
 	return this;
 	return this;
 
 
 };
 };

+ 1 - 1
examples/jsm/nodes/materials/nodes/MeshStandardNode.d.ts

@@ -5,7 +5,7 @@ import {
 
 
 import { NodeBuilder } from '../../core/NodeBuilder';
 import { NodeBuilder } from '../../core/NodeBuilder';
 import { StandardNode } from './StandardNode';
 import { StandardNode } from './StandardNode';
-import { PropertyNode } from "../../inputs/PropertyNode";
+import { PropertyNode } from '../../inputs/PropertyNode';
 
 
 export class MeshStandardNode extends StandardNode {
 export class MeshStandardNode extends StandardNode {
 
 

+ 2 - 0
examples/jsm/pmrem/PMREMGenerator.js

@@ -167,6 +167,8 @@ var PMREMGenerator = ( function () {
 
 
 			}
 			}
 
 
+			shader.dispose();
+
 		},
 		},
 
 
 	};
 	};

+ 7 - 3
examples/jsm/renderers/CSS2DRenderer.js

@@ -17,11 +17,15 @@ var CSS2DObject = function ( element ) {
 
 
 	this.addEventListener( 'removed', function () {
 	this.addEventListener( 'removed', function () {
 
 
-		if ( this.element.parentNode !== null ) {
+		this.traverse( function ( object ) {
 
 
-			this.element.parentNode.removeChild( this.element );
+			if ( object.element instanceof Element && object.element.parentNode !== null ) {
 
 
-		}
+				object.element.parentNode.removeChild( object.element );
+
+			}
+
+		} );
 
 
 	} );
 	} );
 
 

+ 1 - 1
examples/jsm/renderers/CSS3DRenderer.js

@@ -19,7 +19,7 @@ var CSS3DObject = function ( element ) {
 
 
 	this.addEventListener( 'removed', function () {
 	this.addEventListener( 'removed', function () {
 
 
-		this.traverse( function( object ) {
+		this.traverse( function ( object ) {
 
 
 			if ( object.element instanceof Element && object.element.parentNode !== null ) {
 			if ( object.element instanceof Element && object.element.parentNode !== null ) {
 
 

+ 14 - 3
examples/jsm/renderers/Projector.js

@@ -494,6 +494,7 @@ var Projector = function () {
 						if ( material.morphTargets === true ) {
 						if ( material.morphTargets === true ) {
 
 
 							var morphTargets = geometry.morphAttributes.position;
 							var morphTargets = geometry.morphAttributes.position;
+							var morphTargetsRelative = geometry.morphTargetsRelative;
 							var morphInfluences = object.morphTargetInfluences;
 							var morphInfluences = object.morphTargetInfluences;
 
 
 							for ( var t = 0, tl = morphTargets.length; t < tl; t ++ ) {
 							for ( var t = 0, tl = morphTargets.length; t < tl; t ++ ) {
@@ -504,9 +505,19 @@ var Projector = function () {
 
 
 								var target = morphTargets[ t ];
 								var target = morphTargets[ t ];
 
 
-								x += ( target.getX( i / 3 ) - positions[ i ] ) * influence;
-								y += ( target.getY( i / 3 ) - positions[ i + 1 ] ) * influence;
-								z += ( target.getZ( i / 3 ) - positions[ i + 2 ] ) * influence;
+								if ( morphTargetsRelative ) {
+
+									x += target.getX( i / 3 ) * influence;
+									y += target.getY( i / 3 ) * influence;
+									z += target.getZ( i / 3 ) * influence;
+
+								} else {
+
+									x += ( target.getX( i / 3 ) - positions[ i ] ) * influence;
+									y += ( target.getY( i / 3 ) - positions[ i + 1 ] ) * influence;
+									z += ( target.getZ( i / 3 ) - positions[ i + 2 ] ) * influence;
+
+								}
 
 
 							}
 							}
 
 

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