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].
 		</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>
 		<p>
 		Optional name for this bufferGeometry instance. Default is an empty string.

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

@@ -240,7 +240,7 @@
 		<p>
 		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.
 		</p>
 
@@ -248,7 +248,7 @@
 		<p>
 		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
 		have to set it manually to make use of this method.
 		</p>
@@ -258,7 +258,7 @@
 		name -- the property name to search for. <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>
 
 		<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 />
 			[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_instancing_raycast Raycasting to a InstancedMesh]<br />
 			[example:webgl_interactive_lines Raycasting to a Line]<br />
 			[example:webgl_interactive_raycasting_points Raycasting to Points]<br />
 			[example:webgl_geometry_terrain_raycast Terrain raycasting]<br />
@@ -170,7 +171,8 @@
 			[page:Integer faceIndex] – index of the intersected face<br />
 			[page:Object3D object] – the intersected object<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>
 		*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>
 		<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>
 
 		<h3>[property:Float opacity]</h3>
@@ -296,6 +295,11 @@
 		This gets automatically assigned, so this shouldn't be edited.
 		</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>
 		<p>
 		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 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>
 
 		<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,
 		accounting for the object's, and children's, world transforms.
+		The function may result in a larger box than strictly necessary.
 
 		</p>
 
@@ -247,7 +248,8 @@
 		[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 />
 
-		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>
 
 		<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),
 		accounting for the object's, and children's, world transforms.
+		The function may result in a larger box than strictly necessary.
 
 		</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>
 		<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>
 
 		<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: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>
 
 		<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>
 		[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
-		 (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].
 		</p>
@@ -38,7 +38,7 @@
 		<h3>[property:Vector3 direction]</h3>
 		<p>
 		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>
 
 
@@ -201,8 +201,7 @@
 		This must be normalized (with [page:Vector3.normalize]) for the methods to operate
 		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>
 
 

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

@@ -114,7 +114,8 @@
 			[page:Vector3 center] - center of the sphere.<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>
 
 		<h3>[method:Sphere setFromPoints]( [param:Array points], [param:Vector3 optionalCenter] )</h3>

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

@@ -20,8 +20,8 @@
 		<p>
 		[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 />
-		[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.
 		</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>
 		<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>
 
 		<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.
 		</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>
 		<p>
 		Applies a [page:Quaternion] transform to this vector.

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

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

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

@@ -56,6 +56,7 @@
 			其它示例:<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_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_raycasting_points Raycasting to Points]<br />
 			[example:webgl_geometry_terrain_raycast Terrain raycasting]<br />
@@ -170,7 +171,8 @@
 			[page:Integer faceIndex] —— 相交的面的索引<br />
 			[page:Object3D object] —— 相交的物体<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>
 			当计算这条射线是否和物体相交的时候,*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>
 
 <h3>[property:Boolean needsUpdate]</h3>
-<p>指定需要重新编译材质。<br/>
-	实例化新材质时,此属性自动设置为true。
+<p>指定需要重新编译材质。
 </p>
 
 <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>
 
+<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>
 <p> 是否使用顶点着色。默认值为[page:Materials THREE.NoColors]。
 	其他选项有[page:Materials THREE.VertexColors] 和 [page:Materials THREE.FaceColors]。

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

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

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

@@ -53,6 +53,17 @@
 		<h2>Methods</h2>
 		<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>
 		<p>
 			[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();
 
 		// 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
 		loader.load(
@@ -128,6 +131,11 @@
 		in the application.
 		</p>
 
+		<h3>[method:this preload]()</h3>
+		<p>
+		Requests the decoder libraries, if not already loaded.
+		</p>
+
 		<h3>[method:this dispose]()</h3>
 		<p>
 		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_materials_pbrSpecularGlossiness</li>
 			<li>KHR_materials_unlit</li>
+			<li>KHR_mesh_quantization</li>
 			<li>KHR_lights_punctual<sup>1</sup></li>
 			<li>KHR_texture_transform<sup>2</sup></li>
 			<li>MSFT_texture_dds</li>
@@ -58,7 +59,7 @@
 
 		// Optional: Provide a DRACOLoader instance to decode compressed mesh data
 		var dracoLoader = new THREE.DRACOLoader();
-		dracoLoader.setDecoderPath( '/examples/js/libs/draco' );
+		dracoLoader.setDecoderPath( '/examples/js/libs/draco/' );
 		loader.setDRACOLoader( dracoLoader );
 
 		// Load a glTF resource

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

@@ -12,7 +12,7 @@
 
 		<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
 		(material) properties of objects within one or more .OBJ files.
 		</p>

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

@@ -34,7 +34,10 @@
 		var loader = new THREE.DRACOLoader();
 
 		// 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
 		loader.load(
@@ -128,6 +131,11 @@
 		in the application.
 		</p>
 
+		<h3>[method:this preload]()</h3>
+		<p>
+		Requests the decoder libraries, if not already loaded.
+		</p>
+
 		<h3>[method:this dispose]()</h3>
 		<p>
 		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_materials_pbrSpecularGlossiness</li>
 			<li>KHR_materials_unlit</li>
+			<li>KHR_mesh_quantization</li>
 			<li>KHR_lights_punctual<sup>1</sup></li>
 			<li>KHR_texture_transform<sup>2</sup></li>
 			<li>MSFT_texture_dds</li>
@@ -42,7 +43,7 @@
 			<sup>2</sup>支持UV变换,但存在一些重要的限制。
 			Transforms applied to
 			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 纹理不能被变换。每个材质最多只能使用一次变换。
 			每次对使用具有唯一变换的纹理都会导致一次额外的GPU纹理上传。
 			请参阅#[link:https://github.com/mrdoob/three.js/pull/13831 13831] 和
@@ -57,7 +58,7 @@
 
 		// Optional: Provide a DRACOLoader instance to decode compressed mesh data
 		var dracoLoader = new THREE.DRACOLoader();
-		dracoLoader.setDecoderPath( '/examples/js/libs/draco' );
+		dracoLoader.setDecoderPath( '/examples/js/libs/draco/' );
 		loader.setDRACOLoader( dracoLoader );
 
 		// Load a glTF resource

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

@@ -20,22 +20,22 @@
 	<h2>Workflow</h2>
 
 	<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.
 	</p>
 
 	<code>
-import { WEBVR } from 'three/examples/jsm/vr/WebVR.js';
+import { VRButton } from 'three/examples/jsm/webxr/VRButton.js';
 	</code>
 
 	<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
 		to do is to add the following line of code to your app.
 	</p>
 
 	<code>
-document.body.appendChild( WEBVR.createButton( renderer ) );
+document.body.appendChild( VRButton.createButton( renderer ) );
 	</code>
 
 	<p>
@@ -65,17 +65,18 @@ renderer.setAnimationLoop( function () {
 	<p>
 		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>
 
 </body>

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

@@ -19,21 +19,21 @@
 	<h2>工作流程</h2>
 
 	<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>
 
 	<code>
-import { WEBVR } from 'three/examples/jsm/vr/WebVR.js';
+import { VRButton } from 'three/examples/jsm/webxr/VRButton.js';
 	</code>
 
-	<p>*WEBVR.createButton()*做了两件重要的事情:首先,它创建了一个按钮,指示了VR的兼容性;
+	<p>*VRButton.createButton()*做了两件重要的事情:首先,它创建了一个按钮,指示了VR的兼容性;
 		此外,若用户激活了这个按钮,则它将开启一个VR会话。
 		你所要做的唯一一件事情,便是把下面的这一行代码加入到你的应用程序里。
 	</p>
 
 	<code>
-document.body.appendChild( WEBVR.createButton( renderer ) );
+document.body.appendChild( VRButton.createButton( renderer ) );
 	</code>
 
 	<p>
@@ -65,17 +65,18 @@ renderer.setAnimationLoop( function () {
 		请查看官方示例中与WebVR相关的示例,了解这一工作流程的实际使用、运行情况。
 		<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>
 
 </body>

+ 13 - 0
docs/prettify/threejs.css

@@ -13,3 +13,16 @@ pre.prettyprint, code.prettyprint {
 	background-color: #F5F5F5;
 	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/FBXLoader.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/MD2Loader.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 ) ) {
 
-						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 {
 

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

@@ -21,11 +21,11 @@ Menubar.Examples = function ( editor ) {
 	// Examples
 
 	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();
@@ -38,7 +38,7 @@ Menubar.Examples = function ( editor ) {
 
 			var option = new UI.Row();
 			option.setClass( 'option' );
-			option.setTextContent( item.title );
+			option.setTextContent( strings.getKey( item.title ) );
 			option.onClick( function () {
 
 				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,
 			'bumpMap': materialBumpMapRow,
 			'normalMap': materialNormalMapRow,
+			'clearcoatNormalMap': materialClearcoatNormalMapRow,
 			'displacementMap': materialDisplacementMapRow,
 			'roughnessMap': materialRoughnessMapRow,
 			'metalnessMap': materialMetalnessMapRow,

+ 10 - 0
editor/js/Strings.js

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

+ 1 - 2
editor/sw.js

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

+ 0 - 5
examples/css3d_molecules.html

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

+ 15 - 14
examples/files.js

@@ -47,6 +47,7 @@ var files = {
 		"webgl_geometry_text_shapes",
 		"webgl_geometry_text_stroke",
 		"webgl_helpers",
+		"webgl_instancing_raycast",
 		"webgl_instancing_suzanne",
 		"webgl_interactive_buffergeometry",
 		"webgl_interactive_cubes",
@@ -321,20 +322,20 @@ var files = {
 		"webaudio_timing",
 		"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": [
 		"webgl_physics_cloth",

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

@@ -61,8 +61,31 @@ THREE.DeviceOrientationControls = function ( object ) {
 
 		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;
 

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

@@ -54,9 +54,6 @@
  * 	visible: true,
  * 	keepAlive: true
  * };
- *
- * TODO
- *  - support shader material without objectNormal in its vertexShader
  */
 
 THREE.OutlineEffect = function ( renderer, parameters ) {
@@ -90,58 +87,57 @@ THREE.OutlineEffect = function ( renderer, parameters ) {
 
 	//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 },
 		outlineColor: { value: defaultColor },
 		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;",
 
-		"vec4 calculateOutline( vec4 pos, vec3 objectNormal, vec4 skinned ) {",
-
+		"vec4 calculateOutline( vec4 pos, vec3 normal, vec4 skinned ) {",
 		"	float thickness = outlineThickness;",
 		"	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
 		"	vec4 norm = normalize( pos - pos2 );",
 		"	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" );
 
@@ -149,92 +145,40 @@ THREE.OutlineEffect = function ( renderer, parameters ) {
 
 		"#include <common>",
 		"#include <fog_pars_fragment>",
+		"#include <logdepthbuf_pars_fragment>",
+		"#include <clipping_planes_pars_fragment>",
 
 		"uniform vec3 outlineColor;",
 		"uniform float outlineAlpha;",
 
 		"void main() {",
 
+		"	#include <clipping_planes_fragment>",
+		"	#include <logdepthbuf_fragment>",
+
 		"	gl_FragColor = vec4( outlineColor, outlineAlpha );",
 
+		"	#include <premultiplied_alpha_fragment>",
+		"	#include <tonemapping_fragment>",
+		"	#include <encodings_fragment>",
 		"	#include <fog_fragment>",
 
 		"}"
 
 	].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( {
-			defines: defines,
-			uniforms: uniforms,
+			type: 'OutlineEffect',
+			uniforms: THREE.UniformsUtils.merge( [
+				THREE.UniformsLib[ 'fog' ],
+				THREE.UniformsLib[ 'displacementmap' ],
+				uniformsOutline
+			] ),
 			vertexShader: vertexShader,
 			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 ) {
 
 			data = {
-				material: createMaterial( originalMaterial ),
+				material: createMaterial(),
 				used: true,
 				keepAlive: defaultKeepAlive,
 				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 ) {
 
-		if ( object.material === undefined ) return;
+		if ( isCompatible( object ) === false ) return;
 
 		if ( Array.isArray( object.material ) ) {
 
@@ -299,7 +266,7 @@ THREE.OutlineEffect = function ( renderer, parameters ) {
 
 	function restoreOriginalMaterial( object ) {
 
-		if ( object.material === undefined ) return;
+		if ( isCompatible( object ) === false ) return;
 
 		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 ) {
@@ -356,6 +331,9 @@ THREE.OutlineEffect = function ( renderer, parameters ) {
 		material.morphTargets = originalMaterial.morphTargets;
 		material.morphNormals = originalMaterial.morphNormals;
 		material.fog = originalMaterial.fog;
+		material.toneMapped = originalMaterial.toneMapped;
+		material.premultipliedAlpha = originalMaterial.premultipliedAlpha;
+		material.displacementMap = originalMaterial.displacementMap;
 
 		if ( outlineParameters !== undefined ) {
 
@@ -382,6 +360,18 @@ THREE.OutlineEffect = function ( renderer, parameters ) {
 
 		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() {

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

@@ -1339,14 +1339,18 @@ THREE.GLTFExporter.prototype = {
 						// Clones attribute not to override
 						var relativeAttribute = attribute.clone();
 
-						for ( var j = 0, jl = attribute.count; j < jl; j ++ ) {
-
-							relativeAttribute.setXYZ(
-								j,
-								attribute.getX( j ) - baseAttribute.getX( j ),
-								attribute.getY( j ) - baseAttribute.getY( j ),
-								attribute.getZ( j ) - baseAttribute.getZ( j )
-							);
+						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 );
 
 						// transfrom the normal to world space
-						normal.applyMatrix3( normalMatrixWorld );
+						normal.applyMatrix3( normalMatrixWorld ).normalize();
 
 						// transform the normal to export format
 						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.z = normals.getZ( i );
 
-							vertex.applyMatrix3( normalMatrixWorld );
+							vertex.applyMatrix3( normalMatrixWorld ).normalize();
 
 							output.setFloat32( vOffset, vertex.x );
 							vOffset += 4;
@@ -452,7 +452,7 @@ THREE.PLYExporter.prototype = {
 							vertex.y = normals.getY( i );
 							vertex.z = normals.getZ( i );
 
-							vertex.applyMatrix3( normalMatrixWorld );
+							vertex.applyMatrix3( normalMatrixWorld ).normalize();
 
 							line += ' ' +
 								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 ),
 
 		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 Groups
+ * - Color Groups (Vertex Colors)
+ * - Metallic Display Properties (PBR)
  */
 
 THREE.ThreeMFLoader = function ( manager ) {
@@ -260,6 +262,7 @@ THREE.ThreeMFLoader.prototype = Object.assign( Object.create( THREE.Loader.proto
 
 				var basematerialNode = basematerialNodes[ i ];
 				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 );
 
 			}
@@ -283,7 +286,7 @@ THREE.ThreeMFLoader.prototype = Object.assign( Object.create( THREE.Loader.proto
 
 		}
 
-		function parseTextures2DGroupNodes( texture2DGroupNode ) {
+		function parseTextures2DGroupNode( texture2DGroupNode ) {
 
 			var texture2DGroupData = {
 				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 ) {
 
 			var basematerialData = {};
 
 			basematerialData[ 'name' ] = basematerialNode.getAttribute( 'name' ); // required
 			basematerialData[ 'displaycolor' ] = basematerialNode.getAttribute( 'displaycolor' ); // required
+			basematerialData[ 'displaypropertiesid' ] = basematerialNode.getAttribute( 'displaypropertiesid' );
 
 			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' ] = {};
 			var textures2DGroupNodes = resourcesNode.querySelectorAll( 'texture2dgroup' );
 
 			for ( var i = 0; i < textures2DGroupNodes.length; i ++ ) {
 
 				var textures2DGroupNode = textures2DGroupNodes[ i ];
-				var textures2DGroupData = parseTextures2DGroupNodes( textures2DGroupNode );
+				var textures2DGroupData = parseTextures2DGroupNode( textures2DGroupNode );
 				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 ) {
 
 			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 meshes = [];
 
-			for ( var i = 0; i < keys.length; i ++ ) {
+			for ( var i = 0, il = keys.length; i < il; i ++ ) {
 
 				var resourceId = keys[ i ];
 				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 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;
 
 					case 'texture':
 						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;
 
 					case 'default':
@@ -945,6 +1105,10 @@ THREE.ThreeMFLoader.prototype = Object.assign( Object.create( THREE.Loader.proto
 
 				return 'material';
 
+			} else if ( modelData.resources.colorgroup[ pid ] !== undefined ) {
+
+				return 'vertexColors';
+
 			} else if ( pid === '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;
 

+ 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 () {
 
 		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 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
  * 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 );
 
@@ -718,19 +846,19 @@ THREE.EXRLoader.prototype = Object.assign( Object.create( THREE.DataTextureLoade
 
 			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;
 
-			for ( var i = 0; i < num_channels; i ++ ) {
+			for ( var i = 0; i < info.channels; i ++ ) {
 
 				pizChannelData[ i ] = {};
 				pizChannelData[ i ][ 'start' ] = outBufferEnd;
 				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;
 
 				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;
 
-			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 ) {
 
@@ -758,7 +886,25 @@ THREE.EXRLoader.prototype = Object.assign( Object.create( THREE.DataTextureLoade
 
 			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
-
 		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;
 
-			case THREE.HalfFloatType:
+			case 'PIZ_COMPRESSION':
 
-				var byteArray = new Uint16Array( width * height * numChannels );
+				scanlineBlockSize = 32;
+				uncompress = uncompressPIZ;
 				break;
 
 			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 {
@@ -1220,7 +1420,7 @@ THREE.EXRLoader.prototype = Object.assign( Object.create( THREE.DataTextureLoade
 			width: width,
 			height: height,
 			data: byteArray,
-			format: EXRHeader.channels.length == 4 ? THREE.RGBAFormat : THREE.RGBFormat,
+			format: numChannels === 4 ? THREE.RGBAFormat : THREE.RGBFormat,
 			type: this.type
 		};
 

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

@@ -2058,10 +2058,12 @@ THREE.FBXLoader = ( function () {
 
 			if ( morphTargets.length === 0 ) return;
 
+			parentGeo.morphTargetsRelative = true;
+
 			parentGeo.morphAttributes.position = [];
 			// parentGeo.morphAttributes.normal = []; // not implemented
 
-			 var self = this;
+			var self = this;
 			morphTargets.forEach( function ( morphTarget ) {
 
 				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
 		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 : [];
 
-			// 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 length = parentGeo.attributes.position.count * 3;
+			var morphPositions = new Float32Array( length );
+
 			for ( var i = 0; i < indices.length; i ++ ) {
 
 				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
 			var morphGeoInfo = {
 				vertexIndices: vertexIndices,
-				vertexPositions: vertexPositions,
+				vertexPositions: morphPositions,
+
 			};
 
 			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 ( 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;
 
 			}
@@ -188,6 +188,10 @@ THREE.GLTFLoader = ( function () {
 							extensions[ extensionName ] = new GLTFTextureTransformExtension();
 							break;
 
+						case EXTENSIONS.KHR_MESH_QUANTIZATION:
+							extensions[ extensionName ] = new GLTFMeshQuantizationExtension();
+							break;
+
 						default:
 
 							if ( extensionsRequired.indexOf( extensionName ) >= 0 ) {
@@ -263,6 +267,7 @@ THREE.GLTFLoader = ( function () {
 		KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS: 'KHR_materials_pbrSpecularGlossiness',
 		KHR_MATERIALS_UNLIT: 'KHR_materials_unlit',
 		KHR_TEXTURE_TRANSFORM: 'KHR_texture_transform',
+		KHR_MESH_QUANTIZATION: 'KHR_mesh_quantization',
 		MSFT_TEXTURE_DDS: 'MSFT_texture_dds'
 	};
 
@@ -428,7 +433,7 @@ THREE.GLTFLoader = ( function () {
 
 		} 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 ********/
 	/*********************************/
@@ -1309,95 +1325,9 @@ THREE.GLTFLoader = ( function () {
 			var morphPositions = accessors[ 0 ];
 			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 ( hasMorphNormal ) geometry.morphAttributes.normal = morphNormals;
+			geometry.morphTargetsRelative = true;
 
 			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 */
 
 	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 {GLTF.Primitive} primitiveDef
@@ -2410,6 +2382,8 @@ THREE.GLTFLoader = ( function () {
 
 		assignExtrasToUserData( geometry, primitiveDef );
 
+		computeBounds( geometry, primitiveDef, parser );
+
 		return Promise.all( pending ).then( function () {
 
 			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.normal = morphNormals;
+			geometry.morphTargetsRelative = false;
 
 			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.morphAttributes.position = morphPositions;
+			geometry.morphTargetsRelative = false;
 
 			geometry.userData.MMD = {
 				bones: bones,

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

@@ -10,6 +10,8 @@ THREE.OBJLoader = ( function () {
 	var material_library_pattern = /^mtllib /;
 	// usemtl material_name
 	var material_use_pattern = /^usemtl /;
+	// usemap map_name
+	var map_use_pattern = /^usemap /;
 
 	function ParserState() {
 
@@ -570,6 +572,13 @@ THREE.OBJLoader = ( function () {
 
 					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' ) {
 
 					result = line.split( ' ' );

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

@@ -3,9 +3,6 @@
  * @author Mugen87 / https://github.com/Mugen87
  *
  * Description: A THREE loader for PCD ascii and binary files.
- *
- * Limitations: Compressed binary files are not supported.
- *
  */
 
 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 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 TrueLiteral = createToken( { name: 'TrueLiteral', pattern: /TRUE/ } );
 				var FalseLiteral = createToken( { name: 'FalseLiteral', pattern: /FALSE/ } );
@@ -184,6 +185,7 @@ THREE.VRMLLoader = ( function () {
 					Identifier,
 					RouteIdentifier,
 					StringLiteral,
+					HexLiteral,
 					NumberLiteral,
 					LSquare,
 					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 ) {
 
 						field.type = 'boolean';
@@ -578,7 +594,7 @@ THREE.VRMLLoader = ( function () {
 						break;
 
 					case 'Appearance':
-						build = buildApperanceNode( node );
+						build = buildAppearanceNode( node );
 						break;
 
 					case 'Material':
@@ -589,6 +605,10 @@ THREE.VRMLLoader = ( function () {
 						build = buildImageTextureNode( node );
 						break;
 
+					case 'PixelTexture':
+						build = buildPixelTextureNode( node );
+						break;
+
 					case 'TextureTransform':
 						build = buildTextureTransformNode( node );
 						break;
@@ -658,7 +678,6 @@ THREE.VRMLLoader = ( function () {
 
 					case 'FontStyle':
 					case 'MovieTexture':
-					case 'PixelTexture':
 
 					case 'ColorInterpolator':
 					case 'CoordinateInterpolator':
@@ -810,12 +829,12 @@ THREE.VRMLLoader = ( function () {
 
 				}
 
+				var radius = 10000;
+
 				// sky
 
 				if ( skyColor ) {
 
-					var radius = 10000;
-
 					var skyGeometry = new THREE.SphereBufferGeometry( radius, 32, 16 );
 					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 transformData;
@@ -1030,13 +1049,13 @@ THREE.VRMLLoader = ( function () {
 							var textureNode = fieldValues[ 0 ];
 							if ( textureNode !== null ) {
 
-								if ( textureNode.name === 'ImageTexture' ) {
+								if ( textureNode.name === 'ImageTexture' || textureNode.name === 'PixelTexture' ) {
 
 									material.map = getNode( textureNode );
 
 								} 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
 
-				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 ) {
 
 				var texture;
@@ -2223,83 +2432,69 @@ THREE.VRMLLoader = ( function () {
 			 */
 			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 colorAttribute = new THREE.BufferAttribute( new Float32Array( geometry.attributes.position.count * 3 ), 3 );
 
 				var position = new THREE.Vector3();
 				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 );
@@ -2382,6 +2584,7 @@ THREE.VRMLLoader = ( function () {
 		var Identifier = tokenVocabulary[ 'Identifier' ];
 		var RouteIdentifier = tokenVocabulary[ 'RouteIdentifier' ];
 		var StringLiteral = tokenVocabulary[ 'StringLiteral' ];
+		var HexLiteral = tokenVocabulary[ 'HexLiteral' ];
 		var NumberLiteral = tokenVocabulary[ 'NumberLiteral' ];
 		var TrueLiteral = tokenVocabulary[ 'TrueLiteral' ];
 		var FalseLiteral = tokenVocabulary[ 'FalseLiteral' ];
@@ -2485,6 +2688,11 @@ THREE.VRMLLoader = ( function () {
 
 						$.CONSUME( StringLiteral );
 
+					} },
+					{ ALT: function () {
+
+						$.CONSUME( HexLiteral );
+
 					} },
 					{ ALT: function () {
 
@@ -2533,6 +2741,11 @@ THREE.VRMLLoader = ( function () {
 
 						$.CONSUME( StringLiteral );
 
+					} },
+					{ ALT: function () {
+
+						$.CONSUME( HexLiteral );
+
 					} },
 					{ ALT: function () {
 
@@ -2576,6 +2789,13 @@ THREE.VRMLLoader = ( function () {
 
 	}
 
+	var TEXTURE_TYPE = {
+		INTENSITY: 1,
+		INTENSITY_ALPHA: 2,
+		RGB: 3,
+		RGBA: 4
+	};
+
 	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 () {
 
-		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.traverse( function( object ) {
+		this.traverse( function ( object ) {
 
 			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 ) {
 
 							var morphTargets = geometry.morphAttributes.position;
+							var morphTargetsRelative = geometry.morphTargetsRelative;
 							var morphInfluences = object.morphTargetInfluences;
 
 							for ( var t = 0, tl = morphTargets.length; t < tl; t ++ ) {
@@ -480,9 +481,19 @@ THREE.Projector = function () {
 
 								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 ) {
 
-			_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 );
 

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

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

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

@@ -2,29 +2,24 @@
  * @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
-			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 );
 
@@ -32,154 +27,17 @@ if ( /(Helio)/g.test( navigator.userAgent ) && "xr" in navigator && 'isSessionSu
 
 			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 ) {
 
+		console.warn( 'WEBVR.js has been deprecated. Use VRButton.js instead.' );
+
 		if ( options && 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' );
 			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
 
-		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;
 

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

@@ -54,16 +54,14 @@
  * 	visible: true,
  * 	keepAlive: true
  * };
- *
- * TODO
- *  - support shader material without objectNormal in its vertexShader
  */
 
 import {
 	BackSide,
 	Color,
-	ShaderLib,
-	ShaderMaterial
+	ShaderMaterial,
+	UniformsLib,
+	UniformsUtils
 } from "../../../build/three.module.js";
 
 var OutlineEffect = function ( renderer, parameters ) {
@@ -97,58 +95,57 @@ var OutlineEffect = function ( renderer, parameters ) {
 
 	//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 },
 		outlineColor: { value: defaultColor },
 		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;",
 
-		"vec4 calculateOutline( vec4 pos, vec3 objectNormal, vec4 skinned ) {",
-
+		"vec4 calculateOutline( vec4 pos, vec3 normal, vec4 skinned ) {",
 		"	float thickness = outlineThickness;",
 		"	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
 		"	vec4 norm = normalize( pos - pos2 );",
 		"	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" );
 
@@ -156,92 +153,40 @@ var OutlineEffect = function ( renderer, parameters ) {
 
 		"#include <common>",
 		"#include <fog_pars_fragment>",
+		"#include <logdepthbuf_pars_fragment>",
+		"#include <clipping_planes_pars_fragment>",
 
 		"uniform vec3 outlineColor;",
 		"uniform float outlineAlpha;",
 
 		"void main() {",
 
+		"	#include <clipping_planes_fragment>",
+		"	#include <logdepthbuf_fragment>",
+
 		"	gl_FragColor = vec4( outlineColor, outlineAlpha );",
 
+		"	#include <premultiplied_alpha_fragment>",
+		"	#include <tonemapping_fragment>",
+		"	#include <encodings_fragment>",
 		"	#include <fog_fragment>",
 
 		"}"
 
 	].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( {
-			defines: defines,
-			uniforms: uniforms,
+			type: 'OutlineEffect',
+			uniforms: UniformsUtils.merge( [
+				UniformsLib[ 'fog' ],
+				UniformsLib[ 'displacementmap' ],
+				uniformsOutline
+			] ),
 			vertexShader: vertexShader,
 			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 ) {
 
 			data = {
-				material: createMaterial( originalMaterial ),
+				material: createMaterial(),
 				used: true,
 				keepAlive: defaultKeepAlive,
 				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 ) {
 
-		if ( object.material === undefined ) return;
+		if ( isCompatible( object ) === false ) return;
 
 		if ( Array.isArray( object.material ) ) {
 
@@ -306,7 +274,7 @@ var OutlineEffect = function ( renderer, parameters ) {
 
 	function restoreOriginalMaterial( object ) {
 
-		if ( object.material === undefined ) return;
+		if ( isCompatible( object ) === false ) return;
 
 		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 ) {
@@ -363,6 +339,9 @@ var OutlineEffect = function ( renderer, parameters ) {
 		material.morphTargets = originalMaterial.morphTargets;
 		material.morphNormals = originalMaterial.morphNormals;
 		material.fog = originalMaterial.fog;
+		material.toneMapped = originalMaterial.toneMapped;
+		material.premultipliedAlpha = originalMaterial.premultipliedAlpha;
+		material.displacementMap = originalMaterial.displacementMap;
 
 		if ( outlineParameters !== undefined ) {
 
@@ -389,6 +368,18 @@ var OutlineEffect = function ( renderer, parameters ) {
 
 		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() {

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

@@ -1363,14 +1363,18 @@ GLTFExporter.prototype = {
 						// Clones attribute not to override
 						var relativeAttribute = attribute.clone();
 
-						for ( var j = 0, jl = attribute.count; j < jl; j ++ ) {
-
-							relativeAttribute.setXYZ(
-								j,
-								attribute.getX( j ) - baseAttribute.getX( j ),
-								attribute.getY( j ) - baseAttribute.getY( j ),
-								attribute.getZ( j ) - baseAttribute.getZ( j )
-							);
+						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 );
 
 						// transfrom the normal to world space
-						normal.applyMatrix3( normalMatrixWorld );
+						normal.applyMatrix3( normalMatrixWorld ).normalize();
 
 						// transform the normal to export format
 						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.z = normals.getZ( i );
 
-							vertex.applyMatrix3( normalMatrixWorld );
+							vertex.applyMatrix3( normalMatrixWorld ).normalize();
 
 							output.setFloat32( vOffset, vertex.x );
 							vOffset += 4;
@@ -458,7 +458,7 @@ PLYExporter.prototype = {
 							vertex.y = normals.getY( i );
 							vertex.z = normals.getZ( i );
 
-							vertex.applyMatrix3( normalMatrixWorld );
+							vertex.applyMatrix3( normalMatrixWorld ).normalize();
 
 							line += ' ' +
 								vertex.x + ' ' +

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

@@ -254,7 +254,9 @@ var LineMaterial = function ( parameters ) {
 		uniforms: UniformsUtils.clone( ShaderLib[ 'line' ].uniforms ),
 
 		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 Groups
+ * - Color Groups (Vertex Colors)
+ * - Metallic Display Properties (PBR)
  */
 
 import {
 	BufferAttribute,
 	BufferGeometry,
 	ClampToEdgeWrapping,
+	Color,
 	FileLoader,
 	Float32BufferAttribute,
 	Group,
@@ -30,10 +33,12 @@ import {
 	Matrix4,
 	Mesh,
 	MeshPhongMaterial,
+	MeshStandardMaterial,
 	MirroredRepeatWrapping,
 	NearestFilter,
 	RepeatWrapping,
 	TextureLoader,
+	VertexColors,
 	sRGBEncoding
 } from "../../../build/three.module.js";
 
@@ -281,6 +286,7 @@ ThreeMFLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
 
 				var basematerialNode = basematerialNodes[ i ];
 				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 );
 
 			}
@@ -304,7 +310,7 @@ ThreeMFLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
 
 		}
 
-		function parseTextures2DGroupNodes( texture2DGroupNode ) {
+		function parseTextures2DGroupNode( texture2DGroupNode ) {
 
 			var texture2DGroupData = {
 				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 ) {
 
 			var basematerialData = {};
 
 			basematerialData[ 'name' ] = basematerialNode.getAttribute( 'name' ); // required
 			basematerialData[ 'displaycolor' ] = basematerialNode.getAttribute( 'displaycolor' ); // required
+			basematerialData[ 'displaypropertiesid' ] = basematerialNode.getAttribute( 'displaypropertiesid' );
 
 			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' ] = {};
 			var textures2DGroupNodes = resourcesNode.querySelectorAll( 'texture2dgroup' );
 
 			for ( var i = 0; i < textures2DGroupNodes.length; i ++ ) {
 
 				var textures2DGroupNode = textures2DGroupNodes[ i ];
-				var textures2DGroupData = parseTextures2DGroupNodes( textures2DGroupNode );
+				var textures2DGroupData = parseTextures2DGroupNode( textures2DGroupNode );
 				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 ) {
 
 			var geometry = new BufferGeometry();
@@ -917,7 +1075,7 @@ ThreeMFLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
 			var keys = Object.keys( resourceMap );
 			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 triangleProperties = resourceMap[ resourceId ];
@@ -929,16 +1087,21 @@ ThreeMFLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
 						var basematerials = modelData.resources.basematerials[ resourceId ];
 						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;
 
 					case 'texture':
 						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;
 
 					case 'default':
@@ -966,6 +1129,10 @@ ThreeMFLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
 
 				return 'material';
 
+			} else if ( modelData.resources.colorgroup[ pid ] !== undefined ) {
+
+				return 'vertexColors';
+
 			} else if ( pid === '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;
 

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

@@ -12,6 +12,7 @@ export class DRACOLoader extends Loader {
 	setDecoderPath( path: string ): DRACOLoader;
 	setDecoderConfig( config: object ): DRACOLoader;
 	setWorkerLimit( workerLimit: number ): DRACOLoader;
+	preload(): 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 () {
 
 		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 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
  * implementation, so I have preserved their copyright notices.
@@ -17,6 +18,7 @@ import {
 	RGBAFormat,
 	RGBFormat
 } from "../../../build/three.module.js";
+import { Zlib } from "../libs/inflate.module.min.js";
 
 // /*
 // 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 );
 
@@ -728,19 +857,19 @@ EXRLoader.prototype = Object.assign( Object.create( DataTextureLoader.prototype
 
 			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;
 
-			for ( var i = 0; i < num_channels; i ++ ) {
+			for ( var i = 0; i < info.channels; i ++ ) {
 
 				pizChannelData[ i ] = {};
 				pizChannelData[ i ][ 'start' ] = outBufferEnd;
 				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;
 
 				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;
 
-			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 ) {
 
@@ -768,7 +897,25 @@ EXRLoader.prototype = Object.assign( Object.create( DataTextureLoader.prototype
 
 			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
-
 		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;
 
-			case HalfFloatType:
+			case 'PIZ_COMPRESSION':
 
-				var byteArray = new Uint16Array( width * height * numChannels );
+				scanlineBlockSize = 32;
+				uncompress = uncompressPIZ;
 				break;
 
 			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 {
@@ -1230,7 +1431,7 @@ EXRLoader.prototype = Object.assign( Object.create( DataTextureLoader.prototype
 			width: width,
 			height: height,
 			data: byteArray,
-			format: EXRHeader.channels.length == 4 ? RGBAFormat : RGBFormat,
+			format: numChannels === 4 ? RGBAFormat : RGBFormat,
 			type: this.type
 		};
 

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

@@ -2106,10 +2106,12 @@ var FBXLoader = ( function () {
 
 			if ( morphTargets.length === 0 ) return;
 
+			parentGeo.morphTargetsRelative = true;
+
 			parentGeo.morphAttributes.position = [];
 			// parentGeo.morphAttributes.normal = []; // not implemented
 
-			 var self = this;
+			var self = this;
 			morphTargets.forEach( function ( morphTarget ) {
 
 				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
 		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 : [];
 
-			// 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 length = parentGeo.attributes.position.count * 3;
+			var morphPositions = new Float32Array( length );
+
 			for ( var i = 0; i < indices.length; i ++ ) {
 
 				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
 			var morphGeoInfo = {
 				vertexIndices: vertexIndices,
-				vertexPositions: vertexPositions,
+				vertexPositions: morphPositions,
+
 			};
 
 			var morphBuffers = this.genBuffers( morphGeoInfo );

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

@@ -9,6 +9,7 @@
 import {
 	AnimationClip,
 	Bone,
+	Box3,
 	BufferAttribute,
 	BufferGeometry,
 	ClampToEdgeWrapping,
@@ -59,12 +60,14 @@ import {
 	ShaderMaterial,
 	Skeleton,
 	SkinnedMesh,
+	Sphere,
 	SpotLight,
 	TextureLoader,
 	TriangleFanDrawMode,
 	TriangleStripDrawMode,
 	UniformsUtils,
 	Vector2,
+	Vector3,
 	VectorKeyframeTrack,
 	VertexColors,
 	sRGBEncoding
@@ -214,7 +217,7 @@ var GLTFLoader = ( function () {
 
 			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;
 
 			}
@@ -252,6 +255,10 @@ var GLTFLoader = ( function () {
 							extensions[ extensionName ] = new GLTFTextureTransformExtension();
 							break;
 
+						case EXTENSIONS.KHR_MESH_QUANTIZATION:
+							extensions[ extensionName ] = new GLTFMeshQuantizationExtension();
+							break;
+
 						default:
 
 							if ( extensionsRequired.indexOf( extensionName ) >= 0 ) {
@@ -327,6 +334,7 @@ var GLTFLoader = ( function () {
 		KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS: 'KHR_materials_pbrSpecularGlossiness',
 		KHR_MATERIALS_UNLIT: 'KHR_materials_unlit',
 		KHR_TEXTURE_TRANSFORM: 'KHR_texture_transform',
+		KHR_MESH_QUANTIZATION: 'KHR_mesh_quantization',
 		MSFT_TEXTURE_DDS: 'MSFT_texture_dds'
 	};
 
@@ -492,7 +500,7 @@ var GLTFLoader = ( function () {
 
 		} 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 ********/
 	/*********************************/
@@ -1373,95 +1392,9 @@ var GLTFLoader = ( function () {
 			var morphPositions = accessors[ 0 ];
 			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 ( hasMorphNormal ) geometry.morphAttributes.normal = morphNormals;
+			geometry.morphTargetsRelative = true;
 
 			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 */
 
 	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 {GLTF.Primitive} primitiveDef
@@ -2474,6 +2449,8 @@ var GLTFLoader = ( function () {
 
 		assignExtrasToUserData( geometry, primitiveDef );
 
+		computeBounds( geometry, primitiveDef, parser );
+
 		return Promise.all( pending ).then( function () {
 
 			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.normal = morphNormals;
+			geometry.morphTargetsRelative = false;
 
 			geometry.animations = AnimationClip.CreateClipsFromMorphTargetSequences( frames, 10 );
 

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

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

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

@@ -27,6 +27,8 @@ var OBJLoader = ( function () {
 	var material_library_pattern = /^mtllib /;
 	// usemtl material_name
 	var material_use_pattern = /^usemtl /;
+	// usemap map_name
+	var map_use_pattern = /^usemap /;
 
 	function ParserState() {
 
@@ -587,6 +589,13 @@ var OBJLoader = ( function () {
 
 					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' ) {
 
 					result = line.split( ' ' );

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

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

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

@@ -11,6 +11,7 @@ import {
 	Color,
 	ConeBufferGeometry,
 	CylinderBufferGeometry,
+	DataTexture,
 	DoubleSide,
 	FileLoader,
 	Float32BufferAttribute,
@@ -26,6 +27,8 @@ import {
 	Object3D,
 	Points,
 	PointsMaterial,
+	RGBAFormat,
+	RGBFormat,
 	RepeatWrapping,
 	Scene,
 	SphereBufferGeometry,
@@ -180,6 +183,7 @@ var VRMLLoader = ( function () {
 				//
 
 				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 TrueLiteral = createToken( { name: 'TrueLiteral', pattern: /TRUE/ } );
 				var FalseLiteral = createToken( { name: 'FalseLiteral', pattern: /FALSE/ } );
@@ -218,6 +222,7 @@ var VRMLLoader = ( function () {
 					Identifier,
 					RouteIdentifier,
 					StringLiteral,
+					HexLiteral,
 					NumberLiteral,
 					LSquare,
 					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 ) {
 
 						field.type = 'boolean';
@@ -612,7 +631,7 @@ var VRMLLoader = ( function () {
 						break;
 
 					case 'Appearance':
-						build = buildApperanceNode( node );
+						build = buildAppearanceNode( node );
 						break;
 
 					case 'Material':
@@ -623,6 +642,10 @@ var VRMLLoader = ( function () {
 						build = buildImageTextureNode( node );
 						break;
 
+					case 'PixelTexture':
+						build = buildPixelTextureNode( node );
+						break;
+
 					case 'TextureTransform':
 						build = buildTextureTransformNode( node );
 						break;
@@ -692,7 +715,6 @@ var VRMLLoader = ( function () {
 
 					case 'FontStyle':
 					case 'MovieTexture':
-					case 'PixelTexture':
 
 					case 'ColorInterpolator':
 					case 'CoordinateInterpolator':
@@ -844,12 +866,12 @@ var VRMLLoader = ( function () {
 
 				}
 
+				var radius = 10000;
+
 				// sky
 
 				if ( skyColor ) {
 
-					var radius = 10000;
-
 					var skyGeometry = new SphereBufferGeometry( radius, 32, 16 );
 					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 transformData;
@@ -1064,13 +1086,13 @@ var VRMLLoader = ( function () {
 							var textureNode = fieldValues[ 0 ];
 							if ( textureNode !== null ) {
 
-								if ( textureNode.name === 'ImageTexture' ) {
+								if ( textureNode.name === 'ImageTexture' || textureNode.name === 'PixelTexture' ) {
 
 									material.map = getNode( textureNode );
 
 								} 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
 
-				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 ) {
 
 				var texture;
@@ -2257,83 +2469,69 @@ var VRMLLoader = ( function () {
 			 */
 			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 colorAttribute = new BufferAttribute( new Float32Array( geometry.attributes.position.count * 3 ), 3 );
 
 				var position = new Vector3();
 				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 );
@@ -2416,6 +2621,7 @@ var VRMLLoader = ( function () {
 		var Identifier = tokenVocabulary[ 'Identifier' ];
 		var RouteIdentifier = tokenVocabulary[ 'RouteIdentifier' ];
 		var StringLiteral = tokenVocabulary[ 'StringLiteral' ];
+		var HexLiteral = tokenVocabulary[ 'HexLiteral' ];
 		var NumberLiteral = tokenVocabulary[ 'NumberLiteral' ];
 		var TrueLiteral = tokenVocabulary[ 'TrueLiteral' ];
 		var FalseLiteral = tokenVocabulary[ 'FalseLiteral' ];
@@ -2519,6 +2725,11 @@ var VRMLLoader = ( function () {
 
 						$.CONSUME( StringLiteral );
 
+					} },
+					{ ALT: function () {
+
+						$.CONSUME( HexLiteral );
+
 					} },
 					{ ALT: function () {
 
@@ -2567,6 +2778,11 @@ var VRMLLoader = ( function () {
 
 						$.CONSUME( StringLiteral );
 
+					} },
+					{ ALT: function () {
+
+						$.CONSUME( HexLiteral );
+
 					} },
 					{ ALT: function () {
 
@@ -2610,6 +2826,13 @@ var VRMLLoader = ( function () {
 
 	}
 
+	var TEXTURE_TYPE = {
+		INTENSITY: 1,
+		INTENSITY_ALPHA: 2,
+		RGB: 3,
+		RGBA: 4
+	};
+
 	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 {
-	AnimationAction,
 	AnimationMixer,
 	BufferGeometry,
 	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,
 } from '../../../src/Three';
 
-import { VolumeSlice } from "./VolumeSlice.js";
+import { VolumeSlice } from './VolumeSlice.js';
 
 export class Volume {
 

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

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

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

@@ -5,7 +5,7 @@ import {
 
 import { NodeBuilder } from '../../core/NodeBuilder';
 import { StandardNode } from './StandardNode';
-import { PropertyNode } from "../../inputs/PropertyNode";
+import { PropertyNode } from '../../inputs/PropertyNode';
 
 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 () {
 
-		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.traverse( function( object ) {
+		this.traverse( function ( object ) {
 
 			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 ) {
 
 							var morphTargets = geometry.morphAttributes.position;
+							var morphTargetsRelative = geometry.morphTargetsRelative;
 							var morphInfluences = object.morphTargetInfluences;
 
 							for ( var t = 0, tl = morphTargets.length; t < tl; t ++ ) {
@@ -504,9 +505,19 @@ var Projector = function () {
 
 								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