Browse Source

Merge branch 'dev' of https://github.com/mrdoob/three.js into zh_doc

gogoend 6 years ago
parent
commit
f35a47614a
100 changed files with 2917 additions and 2089 deletions
  1. 14 6
      build/three.js
  2. 467 473
      build/three.min.js
  3. 14 6
      build/three.module.js
  4. 1 1
      docs/api/en/core/Object3D.html
  5. 29 47
      docs/api/en/lights/shadows/LightShadow.html
  6. 81 0
      docs/api/en/lights/shadows/PointLightShadow.html
  7. 4 13
      docs/api/en/loaders/AnimationLoader.html
  8. 5 16
      docs/api/en/loaders/AudioLoader.html
  9. 4 14
      docs/api/en/loaders/BufferGeometryLoader.html
  10. 37 22
      docs/api/en/loaders/Loader.html
  11. 4 33
      docs/api/en/loaders/ObjectLoader.html
  12. 5 0
      docs/api/en/materials/Material.html
  13. 10 5
      docs/api/en/materials/MeshPhysicalMaterial.html
  14. 1 1
      docs/api/zh/core/Object3D.html
  15. 4 5
      docs/api/zh/loaders/AnimationLoader.html
  16. 5 8
      docs/api/zh/loaders/AudioLoader.html
  17. 4 6
      docs/api/zh/loaders/BufferGeometryLoader.html
  18. 42 26
      docs/api/zh/loaders/Loader.html
  19. 4 30
      docs/api/zh/loaders/ObjectLoader.html
  20. 10 5
      docs/api/zh/materials/MeshPhysicalMaterial.html
  21. 2 1
      docs/list.js
  22. 2 2
      docs/scenes/material-browser.html
  23. 50 50
      editor/js/Sidebar.Material.js
  24. 4 4
      editor/js/Strings.js
  25. 1 0
      examples/files.js
  26. 5 13
      examples/js/controls/TransformControls.js
  27. 1 1
      examples/js/effects/OutlineEffect.js
  28. 7 2
      examples/js/exporters/ColladaExporter.js
  29. 1 1
      examples/js/loaders/GLTFLoader.js
  30. 2 2
      examples/js/loaders/LWOLoader.js
  31. 1 1
      examples/js/loaders/STLLoader.js
  32. 265 1
      examples/js/loaders/deprecated/LegacyJSONLoader.js
  33. 1 1
      examples/js/shaders/TranslucentShader.js
  34. 5 15
      examples/jsm/controls/TransformControls.js
  35. 1 1
      examples/jsm/effects/OutlineEffect.js
  36. 7 2
      examples/jsm/exporters/ColladaExporter.js
  37. 42 3
      examples/jsm/exporters/GLTFExporter.js
  38. 1 1
      examples/jsm/loaders/GLTFLoader.js
  39. 2 2
      examples/jsm/loaders/LWOLoader.js
  40. 7 22
      examples/jsm/loaders/OBJLoader2.d.ts
  41. 169 316
      examples/jsm/loaders/OBJLoader2.js
  42. 1 1
      examples/jsm/loaders/OBJLoader2Parallel.d.ts
  43. 2 2
      examples/jsm/loaders/OBJLoader2Parallel.js
  44. 1 1
      examples/jsm/loaders/STLLoader.js
  45. 281 2
      examples/jsm/loaders/deprecated/LegacyJSONLoader.js
  46. 7 1
      examples/jsm/loaders/obj2/shared/MaterialHandler.js
  47. 10 12
      examples/jsm/loaders/obj2/shared/MeshReceiver.js
  48. 1 1
      examples/jsm/loaders/obj2/worker/main/WorkerExecutionSupport.js
  49. 11 23
      examples/jsm/loaders/obj2/worker/parallel/OBJLoader2Parser.d.ts
  50. 189 105
      examples/jsm/loaders/obj2/worker/parallel/OBJLoader2Parser.js
  51. 3 3
      examples/jsm/loaders/obj2/worker/parallel/WorkerRunner.js
  52. 2 2
      examples/jsm/loaders/sea3d/SEA3DLoader.js
  53. 1 1
      examples/jsm/nodes/accessors/NormalNode.js
  54. 48 8
      examples/jsm/nodes/accessors/ReflectNode.js
  55. 2 2
      examples/jsm/nodes/bsdfs/BlinnShininessExponentNode.js
  56. 5 4
      examples/jsm/nodes/materials/StandardNodeMaterial.js
  57. 61 31
      examples/jsm/nodes/materials/nodes/StandardNode.js
  58. 1 1
      examples/jsm/shaders/TranslucentShader.js
  59. BIN
      examples/models/fbx/cloth.fbx
  60. 1 1
      examples/webgl_loader_obj2_options.html
  61. 9 9
      examples/webgl_materials_clearcoat_normalmap.html
  62. 6 3
      examples/webgl_materials_cubemap_mipmaps.html
  63. 4 47
      examples/webgl_materials_envmaps_parallax.html
  64. 20 20
      examples/webgl_materials_nodes.html
  65. 203 0
      examples/webgl_materials_sheen.html
  66. 160 85
      examples/webgl_materials_transparency.html
  67. 6 6
      examples/webgl_materials_variations_physical.html
  68. 3 3
      examples/webgl_shadowmap.html
  69. 3 4
      examples/webgl_shadowmap_performance.html
  70. 73 62
      package-lock.json
  71. 3 3
      package.json
  72. 10 2
      src/lights/DirectionalLightShadow.js
  73. 6 0
      src/lights/LightShadow.d.ts
  74. 74 0
      src/lights/LightShadow.js
  75. 2 3
      src/lights/PointLight.js
  76. 8 0
      src/lights/PointLightShadow.d.ts
  77. 89 0
      src/lights/PointLightShadow.js
  78. 0 2
      src/lights/SpotLightShadow.d.ts
  79. 3 1
      src/lights/SpotLightShadow.js
  80. 2 4
      src/loaders/AnimationLoader.d.ts
  81. 5 10
      src/loaders/AnimationLoader.js
  82. 2 1
      src/loaders/AudioLoader.d.ts
  83. 5 10
      src/loaders/AudioLoader.js
  84. 2 3
      src/loaders/BufferGeometryLoader.d.ts
  85. 5 10
      src/loaders/BufferGeometryLoader.js
  86. 14 47
      src/loaders/Loader.d.ts
  87. 36 292
      src/loaders/Loader.js
  88. 0 27
      src/loaders/LoadingManager.d.ts
  89. 7 4
      src/loaders/MaterialLoader.js
  90. 2 7
      src/loaders/ObjectLoader.d.ts
  91. 6 27
      src/loaders/ObjectLoader.js
  92. 13 5
      src/materials/Material.js
  93. 12 9
      src/materials/MeshPhysicalMaterial.d.ts
  94. 36 15
      src/materials/MeshPhysicalMaterial.js
  95. 0 2
      src/materials/MeshStandardMaterial.d.ts
  96. 28 1
      src/math/Color.d.ts
  97. 26 0
      src/math/Matrix3.d.ts
  98. 27 0
      src/math/Matrix4.d.ts
  99. 29 4
      src/math/Quaternion.d.ts
  100. 30 2
      src/math/SphericalHarmonics3.d.ts

File diff suppressed because it is too large
+ 14 - 6
build/three.js


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


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


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

@@ -192,7 +192,7 @@
 			Set to ( 0, 1, 0 ) by default.
 		</p>
 
-		<h3>[property:Vector3 DefaultMatrixAutoUpdate]</h3>
+		<h3>[property:Boolean DefaultMatrixAutoUpdate]</h3>
 		<p>
 			The default setting for [page:.matrixAutoUpdate matrixAutoUpdate] for newly created Object3Ds.<br />
 

+ 29 - 47
docs/api/en/lights/shadows/LightShadow.html

@@ -12,60 +12,18 @@
 		<h1>[name]</h1>
 
 		<p class="desc">
-			This is used internally by [page:PointLight PointLights] for calculating shadows, and also serves as
-			a base class for the other shadow classes.
+			Serves as a base class for the other shadow classes.
 		</p>
 
 
-		<h2>Example</h2>
-		<p>
-			<code>
-//Create a WebGLRenderer and turn on shadows in the renderer
-var renderer = new THREE.WebGLRenderer();
-renderer.shadowMap.enabled = true;
-renderer.shadowMap.type = THREE.PCFSoftShadowMap; // default THREE.PCFShadowMap
-
-//Create a PointLight and turn on shadows for the light
-var light = new THREE.PointLight( 0xffffff, 1, 100 );
-light.position.set( 0, 10, 0 );
-light.castShadow = true;            // default false
-scene.add( light );
-
-//Set up shadow properties for the light
-light.shadow.mapSize.width = 512;  // default
-light.shadow.mapSize.height = 512; // default
-light.shadow.camera.near = 0.5;       // default
-light.shadow.camera.far = 500      // default
-
-//Create a sphere that cast shadows (but does not receive them)
-var sphereGeometry = new THREE.SphereBufferGeometry( 5, 32, 32 );
-var sphereMaterial = new THREE.MeshStandardMaterial( { color: 0xff0000 } );
-var sphere = new THREE.Mesh( sphereGeometry, sphereMaterial );
-sphere.castShadow = true; //default is false
-sphere.receiveShadow = false; //default
-scene.add( sphere );
-
-//Create a plane that receives shadows (but does not cast them)
-var planeGeometry = new THREE.PlaneBufferGeometry( 20, 20, 32, 32 );
-var planeMaterial = new THREE.MeshStandardMaterial( { color: 0x00ff00 } )
-var plane = new THREE.Mesh( planeGeometry, planeMaterial );
-plane.receiveShadow = true;
-scene.add( plane );
-
-//Create a helper for the shadow camera (optional)
-var helper = new THREE.CameraHelper( light.shadow.camera );
-scene.add( helper );
-			</code>
-		</p>
-
 		<h2>Constructor</h2>
 
 		<h3>[name]( [param:Camera camera] )</h3>
 		<p>
 		[page:Camera camera] - the light's view of the world.<br /><br />
 
-		Create a new [name]. This is not intended to be called directly - it is called
-		internally by [page:PointLight] or used as a base class by other light shadows.
+		Create a new [name]. This is not intended to be called directly - it is used as a base class by 
+		other light shadows.
 		</p>
 
 		<h2>Properties</h2>
@@ -88,7 +46,6 @@ scene.add( helper );
 			in shadow. Computed internally during rendering.
 		</p>
 
-
 		<h3>[property:Vector2 mapSize]</h3>
 		<p>
 			A [Page:Vector2] defining the width and height of the shadow map.<br /><br />
@@ -118,10 +75,35 @@ scene.add( helper );
 
 
 		<h2>Methods</h2>
+
+		<h3>[method:Vector2 getFrameExtents]()</h3>
+		<p>
+		Used internally by the renderer to extend the shadow map to contain all viewports
+		</p>
+
+		<h3>[method:null updateMatrices]( [param:Light light], [param:Camera viewCamera], [param:number viewportIndex])</h3>
+		<p>
+		Update the matrices for the camera and shadow, used internally by the renderer.<br /><br />
+
+		light -- the light for which the shadow is being rendered.<br />
+		viewCamera -- the camera view for which the shadow is being rendered.<br />
+		viewportIndex -- calculates the matrix for this viewport
+		</p>
+
+		<h3>[method:Frustum getFrustum]()</h3>
+		<p>
+		Gets the shadow cameras frustum. Used internally by the renderer to cull objects.
+		</p>
+
+		<h3>[method:number getViewportCount]()</h3>
+		<p>
+		Used internally by the renderer to get the number of viewports that need to be rendered for this shadow.
+		</p>
+
 		<h3>[method:LightShadow copy]( [param:LightShadow source] )</h3>
 		<p>
 		Copies value of all the properties from the [page:LightShadow source] to this
-		SpotLight.
+		Light.
 		</p>
 
 		<h3>[method:LightShadow clone]()</h3>

+ 81 - 0
docs/api/en/lights/shadows/PointLightShadow.html

@@ -0,0 +1,81 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<meta charset="utf-8" />
+		<base href="../../../../" />
+		<script src="list.js"></script>
+		<script src="page.js"></script>
+		<link type="text/css" rel="stylesheet" href="page.css" />
+	</head>
+	<body>
+
+		<h1>[name]</h1>
+
+		<p class="desc">
+			This is used internally by [page:PointLight PointLights] for calculating shadows
+		</p>
+
+
+		<h2>Example</h2>
+		<p>
+			<code>
+//Create a WebGLRenderer and turn on shadows in the renderer
+var renderer = new THREE.WebGLRenderer();
+renderer.shadowMap.enabled = true;
+renderer.shadowMap.type = THREE.PCFSoftShadowMap; // default THREE.PCFShadowMap
+
+//Create a PointLight and turn on shadows for the light
+var light = new THREE.PointLight( 0xffffff, 1, 100 );
+light.position.set( 0, 10, 0 );
+light.castShadow = true;            // default false
+scene.add( light );
+
+//Set up shadow properties for the light
+light.shadow.mapSize.width = 512;  // default
+light.shadow.mapSize.height = 512; // default
+light.shadow.camera.near = 0.5;       // default
+light.shadow.camera.far = 500      // default
+
+//Create a sphere that cast shadows (but does not receive them)
+var sphereGeometry = new THREE.SphereBufferGeometry( 5, 32, 32 );
+var sphereMaterial = new THREE.MeshStandardMaterial( { color: 0xff0000 } );
+var sphere = new THREE.Mesh( sphereGeometry, sphereMaterial );
+sphere.castShadow = true; //default is false
+sphere.receiveShadow = false; //default
+scene.add( sphere );
+
+//Create a plane that receives shadows (but does not cast them)
+var planeGeometry = new THREE.PlaneBufferGeometry( 20, 20, 32, 32 );
+var planeMaterial = new THREE.MeshStandardMaterial( { color: 0x00ff00 } )
+var plane = new THREE.Mesh( planeGeometry, planeMaterial );
+plane.receiveShadow = true;
+scene.add( plane );
+
+//Create a helper for the shadow camera (optional)
+var helper = new THREE.CameraHelper( light.shadow.camera );
+scene.add( helper );
+			</code>
+		</p>
+
+		<h2>Constructor</h2>
+		<h3>[name]( )</h3>
+		<p>
+			Creates a new [name]. This is not intended to be called directly - it is called
+			internally by [page:PointLight].
+		</p>
+
+		<h2>Properties</h2>
+		<p>
+			See the base [page:LightShadow LightShadow] class for common properties.
+		</p>
+
+		<h2>Methods</h2>
+		<p>
+			See the base [page:LightShadow LightShadow] class for common methods.
+		</p>
+
+		<h2>Source</h2>
+
+		[link:https://github.com/mrdoob/three.js/blob/master/src/lights/[name].js src/lights/[name].js]
+	</body>
+</html>

+ 4 - 13
docs/api/en/loaders/AnimationLoader.html

@@ -8,6 +8,8 @@
 		<link type="text/css" rel="stylesheet" href="page.css" />
 	</head>
 	<body>
+		[page:Loader] &rarr;
+
 		<h1>[name]</h1>
 
 		<p class="desc">
@@ -53,13 +55,10 @@
 		</p>
 
 		<h2>Properties</h2>
-
-		<h3>[property:LoadingManager manager]</h3>
-		<p>
-			The [page:LoadingManager loadingManager]  the loader is using. Default is [page:DefaultLoadingManager].
-		</p>
+		<p>See the base [page:Loader] class for common properties.</p>
 
 		<h2>Methods</h2>
+		<p>See the base [page:Loader] class for common methods.</p>
 
 		<h3>[method:null load]( [param:String url], [param:Function onLoad], [param:Function onProgress], [param:Function onError] )</h3>
 		<p>
@@ -80,14 +79,6 @@
 		be parsed with [page:AnimationClip.parse].
 		</p>
 
-		<h3>[method:AnimationLoader setPath]( [param:String path] )</h3>
-		<p>
-			[page:String path] — Base path of the file to load.<br /><br />
-
-			Sets the base path or URL from which to load files. This can be useful if
-			you are loading many animations from the same directory.
-		</p>
-
 		<h2>Source</h2>
 
 		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]

+ 5 - 16
docs/api/en/loaders/AudioLoader.html

@@ -8,6 +8,8 @@
 		<link type="text/css" rel="stylesheet" href="page.css" />
 	</head>
 	<body>
+		[page:Loader] &rarr;
+
 		<h1>[name]</h1>
 
 		<p class="desc">
@@ -62,23 +64,18 @@
 
 		<h2>Constructor</h2>
 
-		<h3>[name]( [param:String context], [param:LoadingManager manager] )</h3>
+		<h3>[name]( [param:LoadingManager manager] )</h3>
 		<p>
-		[page:String context] — The [page:String AudioContext] for the loader to use. Default is [page:String window.AudioContext].<br />
 		[page:LoadingManager manager] — The [page:LoadingManager loadingManager] for the loader to use. Default is [page:LoadingManager THREE.DefaultLoadingManager].<br /><br />
 
 		Creates a new [name].
 		</p>
 
 		<h2>Properties</h2>
-
-		<h3>[property:LoadingManager manager]</h3>
-		<p>
-			The [page:LoadingManager loadingManager] the loader is using. Default is [page:DefaultLoadingManager].
-		</p>
-
+		<p>See the base [page:Loader] class for common properties.</p>
 
 		<h2>Methods</h2>
+		<p>See the base [page:Loader] class for common methods.</p>
 
 		<h3>[method:null load]( [param:String url], [param:Function onLoad], [param:Function onProgress], [param:Function onError] )</h3>
 		<p>
@@ -92,14 +89,6 @@
 		Begin loading from url and pass the loaded [page:String AudioBuffer] to onLoad.
 		</p>
 
-		<h3>[method:AudioLoader setPath]( [param:String path] )</h3>
-		<p>
-			[page:String path] — Base path of the file to load.<br /><br />
-			
-			Sets the base path or URL from which to load files. This can be useful if
-			you are loading many audios from the same directory.
-		</p>
-
 		<h2>Source</h2>
 
 		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]

+ 4 - 14
docs/api/en/loaders/BufferGeometryLoader.html

@@ -8,6 +8,8 @@
 		<link type="text/css" rel="stylesheet" href="page.css" />
 	</head>
 	<body>
+		[page:Loader] &rarr;
+
 		<h1>[name]</h1>
 
 		<p class="desc">
@@ -57,15 +59,11 @@
 		Creates a new [name].
 		</p>
 
-
 		<h2>Properties</h2>
-
-		<h3>[property:LoadingManager manager]</h3>
-		<p>
-			The [page:LoadingManager loadingManager] the loader is using. Default is [page:DefaultLoadingManager].
-		</p>
+		<p>See the base [page:Loader] class for common properties.</p>
 
 		<h2>Methods</h2>
+		<p>See the base [page:Loader] class for common methods.</p>
 
 		<h3>[method:null load]( [param:String url], [param:Function onLoad], [param:Function onProgress], [param:Function onError] )</h3>
 		<p>
@@ -85,14 +83,6 @@
 		Parse a <em>JSON</em> structure and return a [page:BufferGeometry].
 		</p>
 
-		<h3>[method:BufferGeometryLoader setPath]( [param:String path] )</h3>
-		<p>
-			[page:String path] — Base path of the file to load.<br /><br />
-
-			Sets the base path or URL from which to load files. This can be useful if
-			you are loading many geometries from the same directory.
-		</p>
-
 		<h2>Source</h2>
 
 		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]

+ 37 - 22
docs/api/en/loaders/Loader.html

@@ -16,50 +16,65 @@
 		<h2>Constructor</h2>
 
 
-		<h3>[name]()</h3>
+		<h3>[name]( [param:LoadingManager manager] )</h3>
 		<p>
-		Creates a new [name]. This should be called as base class.
+			[page:LoadingManager manager] — The [page:LoadingManager loadingManager] for the loader to use. Default is [page:LoadingManager THREE.DefaultLoadingManager].
+		</p>
+		<p>
+			Creates a new [name].
 		</p>
 
 
 		<h2>Properties</h2>
 
-		<h3>[property:Function onLoadStart]</h3>
-		<p>Will be called when load starts.</p>
-		<p>The default is a function with empty body.</p>
+		<h3>[property:string crossOrigin]</h3>
+		<p>
+		The crossOrigin string to implement CORS for loading the url from a different domain that allows CORS.
+		Default is *anonymous*.
+		</p>
 
-		<h3>[property:Function onLoadProgress]</h3>
-		<p>Will be called while load progresses.</p>
-		<p>The default is a function with empty body.</p>
+		<h3>[property:LoadingManager manager]</h3>
+		<p>
+			The [page:LoadingManager loadingManager]  the loader is using. Default is [page:DefaultLoadingManager].
+		</p>
 
-		<h3>[property:Function onLoadComplete]</h3>
-		<p>Will be called when load completes.</p>
-		<p>The default is a function with empty body.</p>
+		<h3>[property:String path]</h3>
+		<p>
+			The base path from which the asset will be loaded.
+			Default is the empty string.
+		</p>
 
-		<h3>[property:string crossOrigin]</h3>
+		<h3>[property:String resourcePath]</h3>
 		<p>
-		The crossOrigin string to implement CORS for loading the url from a different domain that allows CORS.
-		Default is *"anonymous"*.
+			The base path from which additional resources like textures will be loaded.
+			Default is the empty string.
 		</p>
 
 		<h2>Methods</h2>
 
-		<h3>[method:Material createMaterial]( [param:object m], [param:string texturePath] )</h3>
+		<h3>[method:void load]()</h3>
+		<p>
+			This method needs to be implement by all concrete loaders. It holds the logic for loading the asset from the backend.
+		</p>
+
+		<h3>[method:void parse]()</h3>
 		<p>
-		[page:Object m] — The parameters to create the material. <br />
-		[page:String texturePath] — The base path of the textures.
+			This method needs to be implement by all concrete loaders. It holds the logic for parsing the asset into three.js entities.
 		</p>
+
+		<h3>[method:Loader setCrossOrigin]( [param:String crossOrigin] )</h3>
 		<p>
-		Creates the Material based on the parameters m.
+			[page:String crossOrigin] — The crossOrigin string to implement CORS for loading the url from a different domain that allows CORS.
 		</p>
 
-		<h3>[method:Array initMaterials]( [param:Array materials], [param:string texturePath] )</h3>
+		<h3>[method:Loader setPath]( [param:String path] )</h3>
 		<p>
-		[page:Array materials] — an array of parameters to create materials. <br />
-		[page:String texturePath] —  The base path of the textures.
+			[page:String path] — Set the base path for the asset.
 		</p>
+
+		<h3>[method:Loader setResourcePath]( [param:String resourcePath] )</h3>
 		<p>
-		Creates an array of [page:Material] based on the array of parameters m. The index of the parameters decide the correct index of the materials.
+			[page:String resourcePath] — Set the base path for dependent resources like textures.
 		</p>
 
 		<h2>Handlers</h2>

+ 4 - 33
docs/api/en/loaders/ObjectLoader.html

@@ -8,6 +8,8 @@
 		<link type="text/css" rel="stylesheet" href="page.css" />
 	</head>
 	<body>
+		[page:Loader] &rarr;
+
 		<h1>[name]</h1>
 
 		<p class="desc">
@@ -66,27 +68,11 @@
 		Creates a new [name].
 		</p>
 
-
 		<h2>Properties</h2>
-
-		<h3>[property:String crossOrigin]</h3>
-		<p>
-		If set, assigns the [link:https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_settings_attributes crossOrigin]
-	 attribute of the image to the value of *crossOrigin*, prior to starting the load. Default is *"anonymous"*.
-		</p>
-
-		<h3>[property:LoadingManager manager]</h3>
-		<p>
-			The [page:LoadingManager loadingManager]  the loader is using. Default is [page:DefaultLoadingManager].
-		</p>
-
-		<h3>[property:String resourcePath]</h3>
-		<p>
-			The base path or URL from which additional resources like textuures will be loaded. See [page:.setResourcePath].
-			Default is the empty string.
-		</p>
+		<p>See the base [page:Loader] class for common properties.</p>
 
 		<h2>Methods</h2>
+		<p>See the base [page:Loader] class for common methods.</p>
 
 		<h3>[method:null load]( [param:String url], [param:Function onLoad], [param:Function onProgress], [param:Function onError] )</h3>
 		<p>
@@ -206,21 +192,6 @@
 		</ul>
 		</p>
 
-		<h3>[method:ObjectLoader setCrossOrigin]( [param:String value] )</h3>
-		<p>
-		[page:String value] — The crossOrigin string to implement CORS for loading the url from a different domain that allows CORS.
-		</p>
-
-		<h3>[method:ObjectLoader setPath]( [param:String value] )</h3>
-		<p>
-			Set the base path for the original file.
-		</p>
-
-		<h3>[method:ObjectLoader setResourcePath]( [param:String value] )</h3>
-		<p>
-			Set the base path for dependent resources like textures.
-		</p>
-
 		<h2>Source</h2>
 
 		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]

+ 5 - 0
docs/api/en/materials/Material.html

@@ -267,6 +267,11 @@
 		Other options are [page:Materials THREE.BackSide] and [page:Materials THREE.DoubleSide].
 		</p>
 
+		<h3>[property:Boolean toneMapped]</h3>
+		<p>
+		Defines whether this material is tone mapped according to the renderer's [page:WebGLRenderer.toneMapping toneMapping] setting. Default is *true*.
+		</p>
+
 		<h3>[property:Boolean transparent]</h3>
 		<p>
 		Defines whether this material is transparent. This has an effect on rendering

+ 10 - 5
docs/api/en/materials/MeshPhysicalMaterial.html

@@ -55,13 +55,13 @@
 		<h2>Properties</h2>
 		<p>See the base [page:Material] and [page:MeshStandardMaterial] classes for common properties.</p>
 
-		<h3>[property:Float clearCoat]</h3>
+		<h3>[property:Float clearcoat]</h3>
 		<p>
-		ClearCoat level, from *0.0* to *1.0*. Default is *0.0*.
+		Clearcoat level, from *0.0* to *1.0*. Default is *0.0*.
 		</p>
 
-		<h3>[property:Float clearCoatRoughness]</h3>
-		<p>How rough the clearCoat appears, from *0.0* to *1.0*. Default is *0.0*.</p>
+		<h3>[property:Float clearcoatRoughness]</h3>
+		<p>How rough the clearcoat appears, from *0.0* to *1.0*. Default is *0.0*.</p>
 
 		<h3>[property:Boolean isMeshPhysicalMaterial]</h3>
 		<p>
@@ -73,7 +73,12 @@
 		<h3>[property:Object defines]</h3>
 		<p>An object of the form:
 			<code>
-				{ 'PHYSICAL': '' };
+				{
+
+					'STANDARD': ''
+					'PHYSICAL': '',
+			
+				};
 			</code>
 
 			This is used by the [page:WebGLRenderer] for selecting shaders.

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

@@ -182,7 +182,7 @@
 		默认设为( 0, 1, 0 )。
 	</p>
 
-	<h3>[property:Vector3 DefaultMatrixAutoUpdate]</h3>
+	<h3>[property:Boolean DefaultMatrixAutoUpdate]</h3>
 	<p>
 			[page:.matrixAutoUpdate matrixAutoUpdate]的默认设置,用于新创建的Object3D。<br />
 

+ 4 - 5
docs/api/zh/loaders/AnimationLoader.html

@@ -8,6 +8,8 @@
 		<link type="text/css" rel="stylesheet" href="page.css" />
 	</head>
 	<body>
+		[page:Loader] &rarr;
+
 		<h1>[name]</h1>
 
 		<p class="desc">
@@ -53,13 +55,10 @@
 		</p>
 
 		<h2>属性</h2>
-
-		<h3>[property:LoadingManager manager]</h3>
-		<p>
-			加载器正在使用的[page:LoadingManager loadingManager]。默认为[page:DefaultLoadingManager].
-		</p>
+		<p>See the base [page:Loader] class for common properties.</p>
 
 		<h2>方法</h2>
+		<p>See the base [page:Loader] class for common methods.</p>
 
 		<h3>[method:null load]( [param:String url], [param:Function onLoad], [param:Function onProgress], [param:Function onError] )</h3>
 		<p>

+ 5 - 8
docs/api/zh/loaders/AudioLoader.html

@@ -8,6 +8,8 @@
 		<link type="text/css" rel="stylesheet" href="page.css" />
 	</head>
 	<body>
+		[page:Loader] &rarr;
+
 		<h1>[name]</h1>
 
 		<p class="desc">
@@ -62,23 +64,18 @@
 
 		<h2>构造函数</h2>
 
-		<h3>[name]( [param:String context], [param:LoadingManager manager] )</h3>
+		<h3>[name]( [param:LoadingManager manager] )</h3>
 		<p>
-		[page:String context] — 加载器使用的[page:String AudioContext]。 默认为[page:String window.AudioContext].<br />
 		[page:LoadingManager manager] — 加载器使用的[page:LoadingManager loadingManager]。默认为[page:LoadingManager THREE.DefaultLoadingManager].<br /><br />
 
 		创建一个新的[name].
 		</p>
 
 		<h2>属性</h2>
-
-		<h3>[property:LoadingManager manager]</h3>
-		<p>
-			加载器正在使用的[page:LoadingManager loadingManager]。默认为[page:DefaultLoadingManager].
-		</p>
-
+		<p>See the base [page:Loader] class for common properties.</p>
 
 		<h2>方法</h2>
+		<p>See the base [page:Loader] class for common methods.</p>
 
 		<h3>[method:null load]( [param:String url], [param:Function onLoad], [param:Function onProgress], [param:Function onError] )</h3>
 		<p>

+ 4 - 6
docs/api/zh/loaders/BufferGeometryLoader.html

@@ -8,6 +8,8 @@
 		<link type="text/css" rel="stylesheet" href="page.css" />
 	</head>
 	<body>
+		[page:Loader] &rarr;
+
 		<h1>[name]</h1>
 
 		<p class="desc">
@@ -57,15 +59,11 @@
 		创建一个新的[name].
 		</p>
 
-
 		<h2>属性</h2>
-
-		<h3>[property:LoadingManager manager]</h3>
-		<p>
-            正在使用的[page:LoadingManager loadingManager]。默认为[page:DefaultLoadingManager].
-		</p>
+		<p>See the base [page:Loader] class for common properties.</p>
 
 		<h2>方法</h2>
+		<p>See the base [page:Loader] class for common methods.</p>
 
 		<h3>[method:null load]( [param:String url], [param:Function onLoad], [param:Function onProgress], [param:Function onError] )</h3>
 		<p>

+ 42 - 26
docs/api/zh/loaders/Loader.html

@@ -16,49 +16,65 @@
 		<h2>构造方法</h2>
 
 
-		<h3>[name]()</h3>
+		<h3>[name]( [param:LoadingManager manager] )</h3>
 		<p>
-		当创建一个新的 [name], 将调用此基类。
+			[page:LoadingManager manager] — The [page:LoadingManager loadingManager] for the loader to use. Default is [page:LoadingManager THREE.DefaultLoadingManager].
+		</p>
+		<p>
+			Creates a new [name].
 		</p>
 
 
 		<h2>属性</h2>
 
-		<h3>[property:Function onLoadStart]</h3>
-		<p>当加载开始时,将被调用。</p>
-		<p>默认实现是一个空函数体。</p>
+		<h3>[property:string crossOrigin]</h3>
+		<p>
+		The crossOrigin string to implement CORS for loading the url from a different domain that allows CORS.
+		Default is *anonymous*.
+		</p>
 
-		<h3>[property:Function onLoadProgress]</h3>
-		<p>当进入加载流程中,将被调用。</p>
-		<p>默认实现是一个空函数体。</p>
+		<h3>[property:LoadingManager manager]</h3>
+		<p>
+			The [page:LoadingManager loadingManager]  the loader is using. Default is [page:DefaultLoadingManager].
+		</p>
 
-		<h3>[property:Function onLoadComplete]</h3>
-		<p>当加载完成时,将被调用。</p>
-		<p>默认实现是一个空函数体。</p>
+		<h3>[property:String path]</h3>
+		<p>
+			The base path from which the asset will be loaded.
+			Default is the empty string.
+		</p>
 
-		<h3>[property:string crossOrigin]</h3>
+		<h3>[property:String resourcePath]</h3>
 		<p>
-            跨域字符串,用于实现跨域,以便从允许CORS从其他域加载url。默认为"anonymous"。
+			The base path from which additional resources like textures will be loaded.
+			Default is the empty string.
 		</p>
 
-		<h2>Methods</h2>
+		<h2>方法</h2>
 
-		<h3>[method:Material createMaterial]( [param:object m], [param:string texturePath] )</h3>
+		<h3>[method:void load]()</h3>
 		<p>
-		[page:Object m] — 所要创建的材质的参数。 <br />
-		[page:String texturePath] — 纹理加载路径。
+			This method needs to be implement by all concrete loaders. It holds the logic for loading the asset from the backend.
 		</p>
+
+		<h3>[method:void parse]()</h3>
 		<p>
-		基于参数m来创建材质。
+			This method needs to be implement by all concrete loaders. It holds the logic for parsing the asset into three.js entities.
 		</p>
 
-		<h3>[method:Array initMaterials]( [param:Array materials], [param:string texturePath] )</h3>
+		<h3>[method:Loader setCrossOrigin]( [param:String crossOrigin] )</h3>
 		<p>
-		[page:Array materials] — 用于创建材质的参数数组。 <br />
-		[page:String texturePath] —  纹理加载路径。
+			[page:String crossOrigin] — The crossOrigin string to implement CORS for loading the url from a different domain that allows CORS.
 		</p>
+
+		<h3>[method:Loader setPath]( [param:String path] )</h3>
+		<p>
+			[page:String path] — Set the base path for the asset.
+		</p>
+
+		<h3>[method:Loader setResourcePath]( [param:String resourcePath] )</h3>
 		<p>
-		基于参数数组m,来创建 [page:Material] 数组. 参数索引与材质的索引一致。
+			[page:String resourcePath] — Set the base path for dependent resources like textures.
 		</p>
 
 		<h2>Handlers</h2>
@@ -67,10 +83,10 @@
 		*[name].Handlers* is a special object normally used by other loaders like [page:GLTFLoader] or [page:MTLLoader]. It provides an
 		API that allows the definition of special mappings: What loaders should be used in order to load specific files. A typical use case
 		is to overwrite the default loader for textures.<br /><br />
-	
+
 		Note: It's only possible to use *[name].Handlers* if the respective loader support the usage.
 		</p>
-	
+
 		<h3>[method:null add]( [param:Object regex], [param:Loader loader] )</h3>
 		<p>
 		[page:Object regex] — A regular expression.<br />
@@ -78,14 +94,14 @@
 		<p>
 		Registers a loader with the given regular expression.
 		</p>
-	
+
 		<h3>[method:null get]( [param:String file] )</h3>
 		<p>
 		[page:String file] — The file path.
 		<p>
 		Can be used to retrieve the registered loader for the given file path.
 		</p>
-		
+
 		<h2>Source</h2>
 
 		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]

+ 4 - 30
docs/api/zh/loaders/ObjectLoader.html

@@ -8,6 +8,8 @@
 		<link type="text/css" rel="stylesheet" href="page.css" />
 	</head>
 	<body>
+		[page:Loader] &rarr;
+
 		<h1>[name]</h1>
 
 		<p class="desc">
@@ -66,27 +68,11 @@
 		创建一个新的[name].
 		</p>
 
-
 		<h2>属性</h2>
-
-		<h3>[property:String crossOrigin]</h3>
-		<p>
-            如果设置了,在开始加载前, 将为图片分配 [link:https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_settings_attributes crossOrigin]
-            属性,其值为 *crossOrigin*, 默认为"anonymous"。
-		</p>
-
-		<h3>[property:LoadingManager manager]</h3>
-		<p>
-			加载器正在使用的[page:LoadingManager loadingManager],默认值为[page:DefaultLoadingManager]。
-		</p>
-
-		<h3>[property:String texturePath]</h3>
-		<p>
-			将要被加载的纹理的路径或者URL,详情请参考[page:.setTexturePath]。
-			默认值为空字符串。
-		</p>
+		<p>See the base [page:Loader] class for common properties.</p>
 
 		<h2>方法</h2>
+		<p>See the base [page:Loader] class for common methods.</p>
 
 		<h3>[method:null load]( [param:String url], [param:Function onLoad], [param:Function onProgress], [param:Function onError] )</h3>
 		<p>
@@ -204,18 +190,6 @@
 		</ul>
 		</p>
 
-		<h3>[method:ObjectLoader setCrossOrigin]( [param:String value] )</h3>
-		<p>
-		[page:String value] — 在允许CROS时,跨域字段通过实现CORS来加载不同域下的URL。
-		</p>
-
-		<h3>[method:ObjectLoader setTexturePath]( [param:String value] )</h3>
-		<p>
-		[page:String value] — 设置将要加载为纹理的路径或者URL<br /><br />
-
-
-		</p>
-
 		<h2>源</h2>
 
 		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]

+ 10 - 5
docs/api/zh/materials/MeshPhysicalMaterial.html

@@ -50,13 +50,13 @@
 		<h2>属性(Properties)</h2>
 		<p>共有属性请参见其基类[page:Material]。</p>
 
-		<h3>[property:Float clearCoat]</h3>
+		<h3>[property:Float clearcoat]</h3>
 		<p>
-			ClearCoat级别,从*0.0*到*1.0*。默认值为*0.0*。
+			Clearcoat级别,从*0.0*到*1.0*。默认值为*0.0*。
 		</p>
 
-		<h3>[property:Float clearCoatRoughness]</h3>
-		<p> clearCoat看起来的粗糙程度,从*0.0*到*1.0*。默认值为*0.0*。</p>
+		<h3>[property:Float clearcoatRoughness]</h3>
+		<p> clearcoat看起来的粗糙程度,从*0.0*到*1.0*。默认值为*0.0*。</p>
 
 		<h3>[property:Boolean isMeshPhysicalMaterial]</h3>
 		<p> 用于检查此类或派生类是否为Lambert网格材质。默认值为 *true*。<br /><br />
@@ -67,7 +67,12 @@
 		<h3>[property:Object defines]</h3>
 		<p> 如下形式的对象:
 			<code>
-				{ 'PHYSICAL': '' };
+				{
+
+					'STANDARD': ''
+					'PHYSICAL': '',
+			
+				};
 			</code>
 			[page:WebGLRenderer]使用它来选择shaders。
 		</p>

+ 2 - 1
docs/list.js

@@ -217,8 +217,9 @@ var list = {
 			},
 
 			"Lights / Shadows": {
-				"DirectionalLightShadow": "api/en/lights/shadows/DirectionalLightShadow",
 				"LightShadow": "api/en/lights/shadows/LightShadow",
+				"PointLightShadow": "api/en/lights/shadows/PointLightShadow",
+				"DirectionalLightShadow": "api/en/lights/shadows/DirectionalLightShadow",
 				"SpotLightShadow": "api/en/lights/shadows/SpotLightShadow"
 			},
 

+ 2 - 2
docs/scenes/material-browser.html

@@ -595,8 +595,8 @@
 				folder.add( material, 'roughness', 0, 1 );
 				folder.add( material, 'metalness', 0, 1 );
 				folder.add( material, 'reflectivity', 0, 1 );
-				folder.add( material, 'clearCoat', 0, 1 ).step( 0.01 );
-				folder.add( material, 'clearCoatRoughness', 0, 1 ).step( 0.01 );
+				folder.add( material, 'clearcoat', 0, 1 ).step( 0.01 );
+				folder.add( material, 'clearcoatRoughness', 0, 1 ).step( 0.01 );
 				folder.add( material, 'flatShading' ).onChange( needsUpdate( material, geometry ) );
 				folder.add( material, 'wireframe' );
 				folder.add( material, 'wireframeLinewidth', 0, 10 );

+ 50 - 50
editor/js/Sidebar.Material.js

@@ -225,25 +225,25 @@ Sidebar.Material = function ( editor ) {
 
 	container.add( materialShininessRow );
 
-	// clearCoat
+	// clearcoat
 
-	var materialClearCoatRow = new UI.Row();
-	var materialClearCoat = new UI.Number( 1 ).setWidth( '60px' ).setRange( 0, 1 ).onChange( update );
+	var materialClearcoatRow = new UI.Row();
+	var materialClearcoat = new UI.Number( 1 ).setWidth( '60px' ).setRange( 0, 1 ).onChange( update );
 
-	materialClearCoatRow.add( new UI.Text( strings.getKey( 'sidebar/material/clearcoat' ) ).setWidth( '90px' ) );
-	materialClearCoatRow.add( materialClearCoat );
+	materialClearcoatRow.add( new UI.Text( strings.getKey( 'sidebar/material/clearcoat' ) ).setWidth( '90px' ) );
+	materialClearcoatRow.add( materialClearcoat );
 
-	container.add( materialClearCoatRow );
+	container.add( materialClearcoatRow );
 
-	// clearCoatRoughness
+	// clearcoatRoughness
 
-	var materialClearCoatRoughnessRow = new UI.Row();
-	var materialClearCoatRoughness = new UI.Number( 1 ).setWidth( '60px' ).setRange( 0, 1 ).onChange( update );
+	var materialClearcoatRoughnessRow = new UI.Row();
+	var materialClearcoatRoughness = new UI.Number( 1 ).setWidth( '60px' ).setRange( 0, 1 ).onChange( update );
 
-	materialClearCoatRoughnessRow.add( new UI.Text( strings.getKey( 'sidebar/material/clearcoatroughness' ) ).setWidth( '90px' ) );
-	materialClearCoatRoughnessRow.add( materialClearCoatRoughness );
+	materialClearcoatRoughnessRow.add( new UI.Text( strings.getKey( 'sidebar/material/clearcoatroughness' ) ).setWidth( '90px' ) );
+	materialClearcoatRoughnessRow.add( materialClearcoatRoughness );
 
-	container.add( materialClearCoatRoughnessRow );
+	container.add( materialClearcoatRoughnessRow );
 
 	// vertex colors
 
@@ -353,19 +353,19 @@ Sidebar.Material = function ( editor ) {
 
 	// clearcoat normal map
 
-	var materialClearCoatNormalMapRow = new UI.Row();
-	var materialClearCoatNormalMapEnabled = new UI.Checkbox( false ).onChange( update );
-	var materialClearCoatNormalMap = new UI.Texture().onChange( update );
-	var materialClearCoatNormalScaleX = new UI.Number( 1 ).setWidth( '30px' ).onChange( update );
-	var materialClearCoatNormalScaleY = new UI.Number( 1 ).setWidth( '30px' ).onChange( update );
+	var materialClearcoatNormalMapRow = new UI.Row();
+	var materialClearcoatNormalMapEnabled = new UI.Checkbox( false ).onChange( update );
+	var materialClearcoatNormalMap = new UI.Texture().onChange( update );
+	var materialClearcoatNormalScaleX = new UI.Number( 1 ).setWidth( '30px' ).onChange( update );
+	var materialClearcoatNormalScaleY = new UI.Number( 1 ).setWidth( '30px' ).onChange( update );
 
-	materialClearCoatNormalMapRow.add( new UI.Text( strings.getKey( 'sidebar/material/clearcoatnormalmap' ) ).setWidth( '90px' ) );
-	materialClearCoatNormalMapRow.add( materialClearCoatNormalMapEnabled );
-	materialClearCoatNormalMapRow.add( materialClearCoatNormalMap );
-	materialClearCoatNormalMapRow.add( materialClearCoatNormalScaleX );
-	materialClearCoatNormalMapRow.add( materialClearCoatNormalScaleY );
+	materialClearcoatNormalMapRow.add( new UI.Text( strings.getKey( 'sidebar/material/clearcoatnormalmap' ) ).setWidth( '90px' ) );
+	materialClearcoatNormalMapRow.add( materialClearcoatNormalMapEnabled );
+	materialClearcoatNormalMapRow.add( materialClearcoatNormalMap );
+	materialClearcoatNormalMapRow.add( materialClearcoatNormalScaleX );
+	materialClearcoatNormalMapRow.add( materialClearcoatNormalScaleY );
 
-	container.add( materialClearCoatNormalMapRow );
+	container.add( materialClearcoatNormalMapRow );
 
 	// displacement map
 
@@ -654,15 +654,15 @@ Sidebar.Material = function ( editor ) {
 
 			}
 
-			if ( material.clearCoat !== undefined && Math.abs( material.clearCoat - materialClearCoat.getValue() ) >= 0.01 ) {
+			if ( material.clearcoat !== undefined && Math.abs( material.clearcoat - materialClearcoat.getValue() ) >= 0.01 ) {
 
-				editor.execute( new SetMaterialValueCommand( editor, currentObject, 'clearCoat', materialClearCoat.getValue(), currentMaterialSlot ) );
+				editor.execute( new SetMaterialValueCommand( editor, currentObject, 'clearcoat', materialClearcoat.getValue(), currentMaterialSlot ) );
 
 			}
 
-			if ( material.clearCoatRoughness !== undefined && Math.abs( material.clearCoatRoughness - materialClearCoatRoughness.getValue() ) >= 0.01 ) {
+			if ( material.clearcoatRoughness !== undefined && Math.abs( material.clearcoatRoughness - materialClearcoatRoughness.getValue() ) >= 0.01 ) {
 
-				editor.execute( new SetMaterialValueCommand( editor, currentObject, 'clearCoatRoughness', materialClearCoatRoughness.getValue(), currentMaterialSlot ) );
+				editor.execute( new SetMaterialValueCommand( editor, currentObject, 'clearcoatRoughness', materialClearcoatRoughness.getValue(), currentMaterialSlot ) );
 
 			}
 
@@ -817,34 +817,34 @@ Sidebar.Material = function ( editor ) {
 
 			}
 
-			if ( material.clearCoatNormalMap !== undefined ) {
+			if ( material.clearcoatNormalMap !== undefined ) {
 
-				var clearCoatNormalMapEnabled = materialClearCoatNormalMapEnabled.getValue() === true;
+				var clearcoatNormalMapEnabled = materialClearcoatNormalMapEnabled.getValue() === true;
 
 				if ( objectHasUvs ) {
 
-					var clearCoatNormalMap = clearCoatNormalMapEnabled ? materialClearCoatNormalMap.getValue() : null;
+					var clearcoatNormalMap = clearcoatNormalMapEnabled ? materialClearcoatNormalMap.getValue() : null;
 
-					if ( material.clearCoatNormalMap !== clearCoatNormalMap ) {
+					if ( material.clearcoatNormalMap !== clearcoatNormalMap ) {
 
-						editor.execute( new SetMaterialMapCommand( editor, currentObject, 'clearCoatNormalMap', clearCoatNormalMap, currentMaterialSlot ) );
+						editor.execute( new SetMaterialMapCommand( editor, currentObject, 'clearcoatNormalMap', clearcoatNormalMap, currentMaterialSlot ) );
 
 					}
 
-					if ( material.clearCoatNormalScale.x !== materialClearCoatNormalScaleX.getValue() ||
-						material.clearCoatNormalScale.y !== materialClearCoatNormalScaleY.getValue() ) {
+					if ( material.clearcoatNormalScale.x !== materialClearcoatNormalScaleX.getValue() ||
+						material.clearcoatNormalScale.y !== materialClearcoatNormalScaleY.getValue() ) {
 
 						var value = [
-							materialClearCoatNormalScaleX.getValue(),
-							materialClearCoatNormalScaleY.getValue()
+							materialClearcoatNormalScaleX.getValue(),
+							materialClearcoatNormalScaleY.getValue()
 						];
-						editor.execute( new SetMaterialVectorCommand( editor, currentObject, 'clearCoatNormalScale', value, currentMaterialSlot ) );
+						editor.execute( new SetMaterialVectorCommand( editor, currentObject, 'clearcoatNormalScale', value, currentMaterialSlot ) );
 
 					}
 
 				} else {
 
-					if ( clearCoatNormalMapEnabled ) textureWarning = true;
+					if ( clearcoatNormalMapEnabled ) textureWarning = true;
 
 				}
 
@@ -1159,8 +1159,8 @@ Sidebar.Material = function ( editor ) {
 			'emissive': materialEmissiveRow,
 			'specular': materialSpecularRow,
 			'shininess': materialShininessRow,
-			'clearCoat': materialClearCoatRow,
-			'clearCoatRoughness': materialClearCoatRoughnessRow,
+			'clearcoat': materialClearcoatRow,
+			'clearcoatRoughness': materialClearcoatRoughnessRow,
 			'vertexShader': materialProgramRow,
 			'vertexColors': materialVertexColorsRow,
 			'depthPacking': materialDepthPackingRow,
@@ -1287,15 +1287,15 @@ Sidebar.Material = function ( editor ) {
 
 		}
 
-		if ( material.clearCoat !== undefined ) {
+		if ( material.clearcoat !== undefined ) {
 
-			materialClearCoat.setValue( material.clearCoat );
+			materialClearcoat.setValue( material.clearcoat );
 
 		}
 
-		if ( material.clearCoatRoughness !== undefined ) {
+		if ( material.clearcoatRoughness !== undefined ) {
 
-			materialClearCoatRoughness.setValue( material.clearCoatRoughness );
+			materialClearcoatRoughness.setValue( material.clearcoatRoughness );
 
 		}
 
@@ -1382,18 +1382,18 @@ Sidebar.Material = function ( editor ) {
 
 		}
 
-		if ( material.clearCoatNormalMap !== undefined ) {
+		if ( material.clearcoatNormalMap !== undefined ) {
 
-			materialClearCoatNormalMapEnabled.setValue( material.clearCoatNormalMap !== null );
+			materialClearcoatNormalMapEnabled.setValue( material.clearcoatNormalMap !== null );
 
-			if ( material.clearCoatNormalMap !== null || resetTextureSelectors ) {
+			if ( material.clearcoatNormalMap !== null || resetTextureSelectors ) {
 
-				materialClearCoatNormalMap.setValue( material.clearCoatNormalMap );
+				materialClearcoatNormalMap.setValue( material.clearcoatNormalMap );
 
 			}
 
-			materialClearCoatNormalScaleX.setValue( material.clearCoatNormalScale.x );
-			materialClearCoatNormalScaleY.setValue( material.clearCoatNormalScale.y );
+			materialClearcoatNormalScaleX.setValue( material.clearcoatNormalScale.x );
+			materialClearcoatNormalScaleY.setValue( material.clearcoatNormalScale.y );
 
 		}
 

+ 4 - 4
editor/js/Strings.js

@@ -224,8 +224,8 @@ var Strings = function ( config ) {
 			'sidebar/material/emissive': 'Emissive',
 			'sidebar/material/specular': 'Specular',
 			'sidebar/material/shininess': 'Shininess',
-			'sidebar/material/clearcoat': 'ClearCoat',
-			'sidebar/material/clearcoatroughness': 'ClearCoat Roughness',
+			'sidebar/material/clearcoat': 'Clearcoat',
+			'sidebar/material/clearcoatroughness': 'Clearcoat Roughness',
 			'sidebar/material/vertexcolors': 'Vertex Colors',
 			'sidebar/material/vertexcolors/no': 'No',
 			'sidebar/material/vertexcolors/face': 'Face',
@@ -236,7 +236,7 @@ var Strings = function ( config ) {
 			'sidebar/material/alphamap': 'Alpha Map',
 			'sidebar/material/bumpmap': 'Bump Map',
 			'sidebar/material/normalmap': 'Normal Map',
-			'sidebar/material/clearcoatnormalmap': 'ClearCoat Normal Map',
+			'sidebar/material/clearcoatnormalmap': 'Clearcoat Normal Map',
 			'sidebar/material/displacemap': 'Displace Map',
 			'sidebar/material/roughmap': 'Rough. Map',
 			'sidebar/material/metalmap': 'Metal. Map',
@@ -508,7 +508,7 @@ var Strings = function ( config ) {
 			'sidebar/material/alphamap': '透明贴图',
 			'sidebar/material/bumpmap': '凹凸贴图',
 			'sidebar/material/normalmap': '法线贴图',
-			'sidebar/material/clearcoatnormalmap': 'ClearCoat Normal Map',
+			'sidebar/material/clearcoatnormalmap': 'Clearcoat Normal Map',
 			'sidebar/material/displacemap': '置换贴图',
 			'sidebar/material/roughmap': '粗糙贴图',
 			'sidebar/material/metalmap': '金属贴图',

+ 1 - 0
examples/files.js

@@ -166,6 +166,7 @@ var files = {
 		"webgl_materials_parallaxmap",
 		"webgl_materials_reflectivity",
 		"webgl_materials_shaders_fresnel",
+		"webgl_materials_sheen",
 		"webgl_materials_skin",
 		"webgl_materials_standard",
 		"webgl_materials_texture_anisotropy",

+ 5 - 13
examples/js/controls/TransformControls.js

@@ -210,15 +210,7 @@ THREE.TransformControls = function ( camera, domElement ) {
 		this.camera.updateMatrixWorld();
 		this.camera.matrixWorld.decompose( cameraPosition, cameraQuaternion, cameraScale );
 
-		if ( this.camera instanceof THREE.PerspectiveCamera ) {
-
-			eye.copy( cameraPosition ).sub( worldPosition ).normalize();
-
-		} else if ( this.camera instanceof THREE.OrthographicCamera ) {
-
-			eye.copy( cameraPosition ).normalize();
-
-		}
+		eye.copy( cameraPosition ).sub( worldPosition ).normalize();
 
 		THREE.Object3D.prototype.updateMatrixWorld.call( this );
 
@@ -792,20 +784,20 @@ THREE.TransformControlsGizmo = function () {
 			[ new THREE.Line( lineGeometry, matLineBlue ), null, [ 0, - Math.PI / 2, 0 ]]
 		],
 		XYZ: [
-			[ new THREE.Mesh( new THREE.OctahedronBufferGeometry( 0.1, 0 ), matWhiteTransperent ), [ 0, 0, 0 ], [ 0, 0, 0 ]]
+			[ new THREE.Mesh( new THREE.OctahedronBufferGeometry( 0.1, 0 ), matWhiteTransperent.clone() ), [ 0, 0, 0 ], [ 0, 0, 0 ]]
 		],
 		XY: [
-			[ new THREE.Mesh( new THREE.PlaneBufferGeometry( 0.295, 0.295 ), matYellowTransparent ), [ 0.15, 0.15, 0 ]],
+			[ new THREE.Mesh( new THREE.PlaneBufferGeometry( 0.295, 0.295 ), matYellowTransparent.clone() ), [ 0.15, 0.15, 0 ]],
 			[ new THREE.Line( lineGeometry, matLineYellow ), [ 0.18, 0.3, 0 ], null, [ 0.125, 1, 1 ]],
 			[ new THREE.Line( lineGeometry, matLineYellow ), [ 0.3, 0.18, 0 ], [ 0, 0, Math.PI / 2 ], [ 0.125, 1, 1 ]]
 		],
 		YZ: [
-			[ new THREE.Mesh( new THREE.PlaneBufferGeometry( 0.295, 0.295 ), matCyanTransparent ), [ 0, 0.15, 0.15 ], [ 0, Math.PI / 2, 0 ]],
+			[ new THREE.Mesh( new THREE.PlaneBufferGeometry( 0.295, 0.295 ), matCyanTransparent.clone() ), [ 0, 0.15, 0.15 ], [ 0, Math.PI / 2, 0 ]],
 			[ new THREE.Line( lineGeometry, matLineCyan ), [ 0, 0.18, 0.3 ], [ 0, 0, Math.PI / 2 ], [ 0.125, 1, 1 ]],
 			[ new THREE.Line( lineGeometry, matLineCyan ), [ 0, 0.3, 0.18 ], [ 0, - Math.PI / 2, 0 ], [ 0.125, 1, 1 ]]
 		],
 		XZ: [
-			[ new THREE.Mesh( new THREE.PlaneBufferGeometry( 0.295, 0.295 ), matMagentaTransparent ), [ 0.15, 0, 0.15 ], [ - Math.PI / 2, 0, 0 ]],
+			[ new THREE.Mesh( new THREE.PlaneBufferGeometry( 0.295, 0.295 ), matMagentaTransparent.clone() ), [ 0.15, 0, 0.15 ], [ - Math.PI / 2, 0, 0 ]],
 			[ new THREE.Line( lineGeometry, matLineMagenta ), [ 0.18, 0, 0.3 ], null, [ 0.125, 1, 1 ]],
 			[ new THREE.Line( lineGeometry, matLineMagenta ), [ 0.3, 0, 0.18 ], [ 0, - Math.PI / 2, 0 ], [ 0.125, 1, 1 ]]
 		]

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

@@ -125,7 +125,7 @@ THREE.OutlineEffect = function ( renderer, parameters ) {
 
 	var vertexShaderChunk2 = [
 
-		"#if ! defined( LAMBERT ) && ! defined( PHONG ) && ! defined( TOON ) && ! defined( PHYSICAL )",
+		"#if ! defined( LAMBERT ) && ! defined( PHONG ) && ! defined( TOON ) && ! defined( STANDARD )",
 		"	#ifndef USE_ENVMAP",
 		"		vec3 objectNormal = normalize( normal );",
 		"	#endif",

+ 7 - 2
examples/js/exporters/ColladaExporter.js

@@ -220,7 +220,9 @@ THREE.ColladaExporter.prototype = {
 						bufferGeometry.groups :
 						[ { start: 0, count: indexCount, materialIndex: 0 } ];
 
-				var gnode = `<geometry id="${ meshid }" name="${ g.name }"><mesh>`;
+
+				var gname = g.name ? ` name="${ g.name }"` : '';
+				var gnode = `<geometry id="${ meshid }"${ gname }><mesh>`;
 
 				// define the geometry node and the vertices for the geometry
 				var posName = `${ meshid }-position`;
@@ -493,7 +495,10 @@ THREE.ColladaExporter.prototype = {
 
 					'</effect>';
 
-				libraryMaterials.push( `<material id="${ matid }" name="${ m.name }"><instance_effect url="#${ matid }-effect" /></material>` );
+				var materialName = m.name ? ` name="${ m.name }"` : '';
+				var materialNode = `<material id="${ matid }"${ materialName }><instance_effect url="#${ matid }-effect" /></material>`;
+
+				libraryMaterials.push( materialNode );
 				libraryEffects.push( effectnode );
 				materialMap.set( m, matid );
 

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

@@ -726,7 +726,7 @@ THREE.GLTFLoader = ( function () {
 				materialParams.vertexShader = shader.vertexShader;
 				materialParams.fragmentShader = fragmentShader;
 				materialParams.uniforms = uniforms;
-				materialParams.defines = { 'STANDARD': '' };
+				materialParams.defines = { 'STANDARD': '' }
 
 				materialParams.color = new THREE.Color( 1.0, 1.0, 1.0 );
 				materialParams.opacity = 1.0;

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

@@ -2593,11 +2593,11 @@ MaterialParser.prototype = {
 
 		if ( attributes.Clearcoat && attributes.Clearcoat.value > 0 ) {
 
-			params.clearCoat = attributes.Clearcoat.value;
+			params.clearcoat = attributes.Clearcoat.value;
 
 			if ( attributes[ 'Clearcoat Gloss' ] ) {
 
-				params.clearCoatRoughness = 0.5 * ( 1 - attributes[ 'Clearcoat Gloss' ].value );
+				params.clearcoatRoughness = 0.5 * ( 1 - attributes[ 'Clearcoat Gloss' ].value );
 
 			}
 

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

@@ -44,7 +44,7 @@
  *
  *  for (var i = 0; i < nGeometryGroups; i++) {
  *
- *		var material = new THREE.MeshStandardMaterial({
+ *		var material = new THREE.MeshPhongMaterial({
  *			color: colorMap[i],
  *			wireframe: false
  *		});

+ 265 - 1
examples/js/loaders/deprecated/LegacyJSONLoader.js

@@ -85,6 +85,270 @@ THREE.LegacyJSONLoader = ( function () {
 
 		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 ) {
+
+				var array = [];
+
+				for ( var i = 0; i < materials.length; ++ i ) {
+
+					array[ i ] = createMaterial( materials[ i ], texturePath, crossOrigin );
+
+				}
+
+				return array;
+
+			}
+
+			function createMaterial( m, texturePath, crossOrigin ) {
+
+				// 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.Loader.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 );
+							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 );
+							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 );
+							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 );
+							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 );
+							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 );
+							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 );
+							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 );
+							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 );
+							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 );
+							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.Loader.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.Loader.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 ) {
+
+				var fullPath = texturePath + path;
+				var loader = THREE.Loader.Handlers.get( 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 ) {
@@ -561,7 +825,7 @@ THREE.LegacyJSONLoader = ( function () {
 
 				} else {
 
-					var materials = THREE.Loader.prototype.initMaterials( json.materials, this.resourcePath || path, this.crossOrigin );
+					var materials = initMaterials( json.materials, this.resourcePath || path, this.crossOrigin );
 
 					return { geometry: geometry, materials: materials };
 

+ 1 - 1
examples/js/shaders/TranslucentShader.js

@@ -187,7 +187,7 @@ THREE.TranslucentShader = {
 		"	#if defined( RE_IndirectSpecular )",
 
 		"		vec3 radiance = vec3( 0.0 );",
-		"		vec3 clearCoatRadiance = vec3( 0.0 );",
+		"		vec3 clearcoatRadiance = vec3( 0.0 );",
 
 		"	#endif",
 		THREE.ShaderChunk[ "lights_fragment_end" ],

+ 5 - 15
examples/jsm/controls/TransformControls.js

@@ -17,8 +17,6 @@ import {
 	MeshBasicMaterial,
 	Object3D,
 	OctahedronBufferGeometry,
-	OrthographicCamera,
-	PerspectiveCamera,
 	PlaneBufferGeometry,
 	Quaternion,
 	Raycaster,
@@ -235,15 +233,7 @@ var TransformControls = function ( camera, domElement ) {
 		this.camera.updateMatrixWorld();
 		this.camera.matrixWorld.decompose( cameraPosition, cameraQuaternion, cameraScale );
 
-		if ( this.camera instanceof PerspectiveCamera ) {
-
-			eye.copy( cameraPosition ).sub( worldPosition ).normalize();
-
-		} else if ( this.camera instanceof OrthographicCamera ) {
-
-			eye.copy( cameraPosition ).normalize();
-
-		}
+		eye.copy( cameraPosition ).sub( worldPosition ).normalize();
 
 		Object3D.prototype.updateMatrixWorld.call( this );
 
@@ -817,7 +807,7 @@ var TransformControlsGizmo = function () {
 			[ new Line( lineGeometry, matLineBlue ), null, [ 0, - Math.PI / 2, 0 ]]
 		],
 		XYZ: [
-			[ new Mesh( new OctahedronBufferGeometry( 0.1, 0 ), matWhiteTransperent ), [ 0, 0, 0 ], [ 0, 0, 0 ]]
+			[ new Mesh( new OctahedronBufferGeometry( 0.1, 0 ), matWhiteTransperent.clone() ), [ 0, 0, 0 ], [ 0, 0, 0 ]]
 		],
 		XY: [
 			[ new Mesh( new PlaneBufferGeometry( 0.295, 0.295 ), matYellowTransparent ), [ 0.15, 0.15, 0 ]],
@@ -959,13 +949,13 @@ var TransformControlsGizmo = function () {
 			[ new Line( lineGeometry, matLineMagenta ), [ 0.98, 0, 0.855 ], [ 0, - Math.PI / 2, 0 ], [ 0.125, 1, 1 ]]
 		],
 		XYZX: [
-			[ new Mesh( new BoxBufferGeometry( 0.125, 0.125, 0.125 ), matWhiteTransperent ), [ 1.1, 0, 0 ]],
+			[ new Mesh( new BoxBufferGeometry( 0.125, 0.125, 0.125 ), matWhiteTransperent.clone() ), [ 1.1, 0, 0 ]],
 		],
 		XYZY: [
-			[ new Mesh( new BoxBufferGeometry( 0.125, 0.125, 0.125 ), matWhiteTransperent ), [ 0, 1.1, 0 ]],
+			[ new Mesh( new BoxBufferGeometry( 0.125, 0.125, 0.125 ), matWhiteTransperent.clone() ), [ 0, 1.1, 0 ]],
 		],
 		XYZZ: [
-			[ new Mesh( new BoxBufferGeometry( 0.125, 0.125, 0.125 ), matWhiteTransperent ), [ 0, 0, 1.1 ]],
+			[ new Mesh( new BoxBufferGeometry( 0.125, 0.125, 0.125 ), matWhiteTransperent.clone() ), [ 0, 0, 1.1 ]],
 		]
 	};
 

+ 1 - 1
examples/jsm/effects/OutlineEffect.js

@@ -132,7 +132,7 @@ var OutlineEffect = function ( renderer, parameters ) {
 
 	var vertexShaderChunk2 = [
 
-		"#if ! defined( LAMBERT ) && ! defined( PHONG ) && ! defined( TOON ) && ! defined( PHYSICAL )",
+		"#if ! defined( LAMBERT ) && ! defined( PHONG ) && ! defined( TOON ) && ! defined( STANDARD )",
 		"	#ifndef USE_ENVMAP",
 		"		vec3 objectNormal = normalize( normal );",
 		"	#endif",

+ 7 - 2
examples/jsm/exporters/ColladaExporter.js

@@ -231,7 +231,9 @@ ColladaExporter.prototype = {
 						bufferGeometry.groups :
 						[ { start: 0, count: indexCount, materialIndex: 0 } ];
 
-				var gnode = `<geometry id="${ meshid }" name="${ g.name }"><mesh>`;
+
+				var gname = g.name ? ` name="${ g.name }"` : '';
+				var gnode = `<geometry id="${ meshid }"${ gname }><mesh>`;
 
 				// define the geometry node and the vertices for the geometry
 				var posName = `${ meshid }-position`;
@@ -504,7 +506,10 @@ ColladaExporter.prototype = {
 
 					'</effect>';
 
-				libraryMaterials.push( `<material id="${ matid }" name="${ m.name }"><instance_effect url="#${ matid }-effect" /></material>` );
+				var materialName = m.name ? ` name="${ m.name }"` : '';
+				var materialNode = `<material id="${ matid }"${ materialName }><instance_effect url="#${ matid }-effect" /></material>`;
+
+				libraryMaterials.push( materialNode );
 				libraryEffects.push( effectnode );
 				materialMap.set( m, matid );
 

+ 42 - 3
examples/jsm/exporters/GLTFExporter.js

@@ -919,7 +919,7 @@ GLTFExporter.prototype = {
 
 			}
 
-			if ( material.isShaderMaterial ) {
+			if ( material.isShaderMaterial && !material.isGLTFSpecularGlossinessMaterial ) {
 
 				console.warn( 'GLTFExporter: THREE.ShaderMaterial not supported.' );
 				return null;
@@ -939,6 +939,12 @@ GLTFExporter.prototype = {
 
 				extensionsUsed[ 'KHR_materials_unlit' ] = true;
 
+			} else if ( material.isGLTFSpecularGlossinessMaterial ) {
+
+				gltfMaterial.extensions = { KHR_materials_pbrSpecularGlossiness: {} };
+
+				extensionsUsed[ 'KHR_materials_pbrSpecularGlossiness' ] = true;
+
 			} else if ( ! material.isMeshStandardMaterial ) {
 
 				console.warn( 'GLTFExporter: Use MeshStandardMaterial or MeshBasicMaterial for best results.' );
@@ -971,6 +977,23 @@ GLTFExporter.prototype = {
 
 			}
 
+			// pbrSpecularGlossiness diffuse, specular and glossiness factor
+			if ( material.isGLTFSpecularGlossinessMaterial ) {
+				
+				if ( gltfMaterial.pbrMetallicRoughness.baseColorFactor ) {
+
+					gltfMaterial.extensions.KHR_materials_pbrSpecularGlossiness.diffuseFactor = gltfMaterial.pbrMetallicRoughness.baseColorFactor;
+				  
+				}
+
+				var specularFactor = [ 1, 1, 1 ];
+				material.specular.toArray( specularFactor, 0 );
+				gltfMaterial.extensions.KHR_materials_pbrSpecularGlossiness.specularFactor = specularFactor;
+
+				gltfMaterial.extensions.KHR_materials_pbrSpecularGlossiness.glossinessFactor = material.glossiness;
+			
+			}
+
 			// pbrMetallicRoughness.metallicRoughnessTexture
 			if ( material.metalnessMap || material.roughnessMap ) {
 
@@ -988,12 +1011,28 @@ GLTFExporter.prototype = {
 
 			}
 
-			// pbrMetallicRoughness.baseColorTexture
+			// pbrMetallicRoughness.baseColorTexture or pbrSpecularGlossiness diffuseTexture
 			if ( material.map ) {
 
 				var baseColorMapDef = { index: processTexture( material.map ) };
 				applyTextureTransform( baseColorMapDef, material.map );
+
+				if ( material.isGLTFSpecularGlossinessMaterial ) {
+
+					gltfMaterial.extensions.KHR_materials_pbrSpecularGlossiness.diffuseTexture = baseColorMapDef;
+
+				}
+
 				gltfMaterial.pbrMetallicRoughness.baseColorTexture = baseColorMapDef;
+				
+			}
+
+			// pbrSpecularGlossiness specular map
+			if ( material.isGLTFSpecularGlossinessMaterial && material.specularMap ) {
+
+				var specularMapDef = { index: processTexture( material.specularMap ) };
+				applyTextureTransform( specularMapDef, material.specularMap );
+				gltfMaterial.extensions.KHR_materials_pbrSpecularGlossiness.specularGlossinessTexture = specularMapDef;
 
 			}
 
@@ -1028,7 +1067,7 @@ GLTFExporter.prototype = {
 
 				var normalMapDef = { index: processTexture( material.normalMap ) };
 
-				if ( material.normalScale.x !== - 1 ) {
+				if ( material.normalScale && material.normalScale.x !== - 1 ) {
 
 					if ( material.normalScale.x !== material.normalScale.y ) {
 

+ 1 - 1
examples/jsm/loaders/GLTFLoader.js

@@ -791,7 +791,7 @@ var GLTFLoader = ( function () {
 				materialParams.vertexShader = shader.vertexShader;
 				materialParams.fragmentShader = fragmentShader;
 				materialParams.uniforms = uniforms;
-				materialParams.defines = { 'STANDARD': '' };
+				materialParams.defines = { 'STANDARD': '' }
 
 				materialParams.color = new Color( 1.0, 1.0, 1.0 );
 				materialParams.opacity = 1.0;

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

@@ -2622,11 +2622,11 @@ MaterialParser.prototype = {
 
 		if ( attributes.Clearcoat && attributes.Clearcoat.value > 0 ) {
 
-			params.clearCoat = attributes.Clearcoat.value;
+			params.clearcoat = attributes.Clearcoat.value;
 
 			if ( attributes[ 'Clearcoat Gloss' ] ) {
 
-				params.clearCoatRoughness = 0.5 * ( 1 - attributes[ 'Clearcoat Gloss' ].value );
+				params.clearcoatRoughness = 0.5 * ( 1 - attributes[ 'Clearcoat Gloss' ].value );
 
 			}
 

+ 7 - 22
examples/jsm/loaders/OBJLoader2.d.ts

@@ -4,43 +4,28 @@ import {
   Object3D
 } from '../../../src/Three';
 
+import { OBJLoader2Parser } from './obj2/worker/parallel/OBJLoader2Parser';
 import { MaterialHandler } from './obj2/shared/MaterialHandler';
 import { MeshReceiver} from './obj2/shared/MeshReceiver';
 
-export class OBJLoader2 {
+export class OBJLoader2 extends OBJLoader2Parser {
   constructor(manager?: LoadingManager);
   manager: LoadingManager;
-  logging: {
-    enabled: boolean;
-    debug: boolean;
-  };
   modelName: string;
   instanceNo: number;
   path: string;
   resourcePath: string;
-  useIndices: boolean;
-  disregardNormals: boolean;
-  materialPerSmoothingGroup: boolean;
-  useOAsMesh: boolean;
   baseObject3d: Group;
-  callbacks: {
-    onParseProgress: Function;
-    genericErrorHandler: Function;
-  };
   materialHandler: MaterialHandler;
   meshReceiver: MeshReceiver;
 
-  addMaterials(materials: object): void;
-  load(url: string, onLoad: (group: Group) => void, onProgress?: (event: ProgressEvent) => void, onError?: (event: ErrorEvent) => void, onMeshAlter?: (meshData: object) => void): void;
-  parse(content: ArrayBuffer | string): void;
-  setLogging(enabled: boolean, debug: boolean): this;
   setModelName(modelName: string): this;
   setPath(path: string): this;
   setResourcePath(path: string): this;
   setBaseObject3d(baseObject3d: Object3D): this;
-  setUseIndices(useIndices: boolean): this;
-  setDisregardNormals(disregardNormals: boolean): this;
-  setMaterialPerSmoothingGroup(materialPerSmoothingGroup: boolean): this;
-  setUseOAsMesh(useOAsMesh: boolean): this;
-  setGenericErrorHandler(genericErrorHandler: Function): void;
+  addMaterials(materials: object): this;
+  setCallbackOnMeshAlter(onMeshAlter: Function): this;
+  setCallbackOnLoadMaterials(onLoadMaterials: Function): this;
+  load(url: string, onLoad: (group: Group) => void, onProgress?: (event: ProgressEvent) => void, onError?: (event: ErrorEvent) => void, onMeshAlter?: (meshData: object) => void): void;
+  parse(content: ArrayBuffer | string): void;
 }

+ 169 - 316
examples/jsm/loaders/OBJLoader2.js

@@ -21,412 +21,265 @@ import { MaterialHandler } from "./obj2/shared/MaterialHandler.js";
  */
 const OBJLoader2 = function ( manager ) {
 
+	OBJLoader2Parser.call( this );
 	this.manager = ( manager !== undefined && manager !== null ) ? manager : DefaultLoadingManager;
-	this.logging = {
-		enabled: true,
-		debug: false
-	};
 
 	this.modelName = '';
 	this.instanceNo = 0;
 	this.path = undefined;
 	this.resourcePath = undefined;
-	this.useIndices = false;
-	this.disregardNormals = false;
-	this.materialPerSmoothingGroup = false;
-	this.useOAsMesh = false;
 	this.baseObject3d = new Group();
 
-	this.callbacks = {
-		onParseProgress: undefined,
-		genericErrorHandler: undefined
-	};
-
 	this.materialHandler = new MaterialHandler();
 	this.meshReceiver = new MeshReceiver( this.materialHandler );
 
 };
-OBJLoader2.OBJLOADER2_VERSION = '3.0.0-beta2';
+OBJLoader2.OBJLOADER2_VERSION = '3.0.0';
 console.info( 'Using OBJLoader2 version: ' + OBJLoader2.OBJLOADER2_VERSION );
 
-OBJLoader2.prototype = {
-
-	constructor: OBJLoader2,
-
-	/**
-	 * Enable or disable logging in general (except warn and error), plus enable or disable debug logging.
-	 *
-	 * @param {boolean} enabled True or false.
-	 * @param {boolean} debug True or false.
-	 */
-	setLogging: function ( enabled, debug ) {
-
-		this.logging.enabled = enabled === true;
-		this.logging.debug = debug === true;
-		return this;
-
-	},
-
-	/**
-	 * Set the name of the model.
-	 *
-	 * @param {string} modelName
-	 */
-	setModelName: function ( modelName ) {
-
-		this.modelName = modelName ? modelName : this.modelName;
-		return this;
-
-	},
-
-	/**
-	 * The URL of the base path.
-	 *
-	 * @param {string} path URL
-	 */
-	setPath: function ( path ) {
-
-		this.path = path ? path : this.path;
-		return this;
-
-	},
-
+OBJLoader2.prototype = Object.create( OBJLoader2Parser.prototype );
+OBJLoader2.prototype.constructor = OBJLoader2;
 
-	/**
-	 * Allow to specify resourcePath for dependencies of specified resource.
-	 * @param {string} resourcePath
-	 */
-	setResourcePath: function ( resourcePath ) {
 
-		this.resourcePath = resourcePath ? resourcePath : this.resourcePath;
+/**
+ * Set the name of the model.
+ *
+ * @param {string} modelName
+ * @return {OBJLoader2}
+ */
+OBJLoader2.prototype.setModelName = function ( modelName ) {
 
-	},
+	this.modelName = modelName ? modelName : this.modelName;
+	return this;
 
-	/**
-	 * Set the node where the loaded objects will be attached directly.
-	 *
-	 * @param {Object3D} baseObject3d Object already attached to scenegraph where new meshes will be attached to
-	 */
-	setBaseObject3d: function ( baseObject3d ) {
+};
 
-		this.baseObject3d = ( baseObject3d === undefined || baseObject3d === null ) ? this.baseObject3d : baseObject3d;
-		return this;
+/**
+ * The URL of the base path.
+ *
+ * @param {string} path URL
+ * @return {OBJLoader2}
+ */
+OBJLoader2.prototype.setPath = function ( path ) {
 
-	},
+	this.path = path ? path : this.path;
+	return this;
 
-	/**
-	 * Add materials as associated array.
-	 *
-	 * @param materials Object with named {@link Material}
-	 */
-	addMaterials: function ( materials ) {
+};
 
-		this.materialHandler.addMaterials( materials );
+/**
+ * Allow to specify resourcePath for dependencies of specified resource.
+ *
+ * @param {string} resourcePath
+ * @return {OBJLoader2}
+ */
+OBJLoader2.prototype.setResourcePath = function ( resourcePath ) {
 
-	},
+	this.resourcePath = resourcePath ? resourcePath : this.resourcePath;
+	return this;
 
-	/**
-	 * Instructs loaders to create indexed {@link BufferGeometry}.
-	 *
-	 * @param {boolean} useIndices=false
-	 */
-	setUseIndices: function ( useIndices ) {
+};
 
-		this.useIndices = useIndices === true;
-		return this;
+/**
+ * Set the node where the loaded objects will be attached directly.
+ *
+ * @param {Object3D} baseObject3d Object already attached to scenegraph where new meshes will be attached to
+ * @return {OBJLoader2}
+ */
+OBJLoader2.prototype.setBaseObject3d = function ( baseObject3d ) {
 
-	},
+	this.baseObject3d = ( baseObject3d === undefined || baseObject3d === null ) ? this.baseObject3d : baseObject3d;
+	return this;
 
-	/**
-	 * Tells whether normals should be completely disregarded and regenerated.
-	 *
-	 * @param {boolean} disregardNormals=false
-	 */
-	setDisregardNormals: function ( disregardNormals ) {
+};
 
-		this.disregardNormals = disregardNormals === true;
-		return this;
+/**
+ * Add materials as associated array.
+ *
+ * @param {Object} materials Object with named {@link Material}
+ * @return {OBJLoader2}
+ */
+OBJLoader2.prototype.addMaterials = function ( materials ) {
 
-	},
+	this.materialHandler.addMaterials( materials );
+	return this;
 
-	/**
-	 * Tells whether a material shall be created per smoothing group.
-	 *
-	 * @param {boolean} materialPerSmoothingGroup=false
-	 */
-	setMaterialPerSmoothingGroup: function ( materialPerSmoothingGroup ) {
+};
 
-		this.materialPerSmoothingGroup = materialPerSmoothingGroup === true;
-		return this;
+/**
+ * Register a function that is called once a single mesh is available and it could be altered by the supplied function.
+ *
+ * @param {Function} [onMeshAlter]
+ * @return {OBJLoader2}
+ */
+OBJLoader2.prototype.setCallbackOnMeshAlter = function ( onMeshAlter ) {
 
-	},
+	this.meshReceiver._setCallbacks( this.callbacks.onProgress, onMeshAlter );
+	return this;
 
-	/**
-	 * Usually 'o' is meta-information and does not result in creation of new meshes, but mesh creation on occurrence of "o" can be enforced.
-	 *
-	 * @param {boolean} useOAsMesh=false
-	 */
-	setUseOAsMesh: function ( useOAsMesh ) {
+};
 
-		this.useOAsMesh = useOAsMesh === true;
-		return this;
+/**
+ * Register a function that is called once all materials have been loaded and they could be altered by the supplied function.
+ *
+ * @param {Function} [onLoadMaterials]
+ * @return {OBJLoader2}
+ */
+OBJLoader2.prototype.setCallbackOnLoadMaterials = function ( onLoadMaterials ) {
 
-	},
+	this.materialHandler._setCallbacks( onLoadMaterials );
+	return this;
 
-	/**
-	 * Register an generic error handler that is called if available instead of throwing an exception
-	 * @param {Function} genericErrorHandler
-	 */
-	setGenericErrorHandler: function ( genericErrorHandler ) {
+};
 
-		if ( genericErrorHandler !== undefined && genericErrorHandler !== null ) {
+/**
+ * Use this convenient method to load a file at the given URL. By default the fileLoader uses an ArrayBuffer.
+ *
+ * @param {string}  url A string containing the path/URL of the file to be loaded.
+ * @param {function} onLoad A function to be called after loading is successfully completed. The function receives loaded Object3D as an argument.
+ * @param {function} [onFileLoadProgress] A function to be called while the loading is in progress. The argument will be the XMLHttpRequest instance, which contains total and Integer bytes.
+ * @param {function} [onError] A function to be called if an error occurs during loading. The function receives the error as an argument.
+ * @param {function} [onMeshAlter] Called after every single mesh is made available by the parser
+ */
+OBJLoader2.prototype.load = function ( url, onLoad, onFileLoadProgress, onError, onMeshAlter ) {
 
-			this.callbacks.genericErrorHandler = genericErrorHandler;
+	let scope = this;
+	if ( onLoad === null || onLoad === undefined || ! ( onLoad instanceof Function ) ) {
 
-		}
+		let errorMessage = 'onLoad is not a function! Aborting...';
+		scope.callbacks.onError( errorMessage );
+		throw errorMessage
 
-	},
+	}
+	if ( onError === null || onError === undefined || ! ( onError instanceof Function ) ) {
 
-	/**
-	 *
-	 * @private
-	 *
-	 * @param {Function} [onParseProgress]
-	 * @param {Function} [onMeshAlter]
-	 * @param {Function} [onLoadMaterials]
-	 * @private
-	 */
-	_setCallbacks: function ( onParseProgress, onMeshAlter, onLoadMaterials ) {
+		onError = function ( event ) {
 
-		if ( onParseProgress !== undefined && onParseProgress !== null ) {
+			let errorMessage = event;
+			if ( event.currentTarget && event.currentTarget.statusText !== null ) {
 
-			this.callbacks.onParseProgress = onParseProgress;
+				 errorMessage = 'Error occurred while downloading!\nurl: ' + event.currentTarget.responseURL + '\nstatus: ' + event.currentTarget.statusText;
 
-		}
-		this.meshReceiver._setCallbacks( onParseProgress, onMeshAlter );
-		this.materialHandler._setCallbacks( onLoadMaterials );
-
-	},
-
-	/**
-	 * Announce feedback which is give to the registered callbacks.
-	 * @private
-	 *
-	 * @param {string} type The type of event
-	 * @param {string} text Textual description of the event
-	 * @param {number} numericalValue Numerical value describing the progress
-	 */
-	_onProgress: function ( type, text, numericalValue ) {
-
-		let message = text ? text : '';
-		let event = {
-			detail: {
-				type: type,
-				modelName: this.modelName,
-				instanceNo: this.instanceNo,
-				text: message,
-				numericalValue: numericalValue
 			}
-		};
-		if ( this.callbacks.onParseProgress ) {
-
-			this.callbacks.onParseProgress( event );
-
-		}
-		if ( this.logging.enabled && this.logging.debug ) {
-
-			console.log( message );
+			scope.callbacks.onError( errorMessage );
 
-		}
-
-	},
-
-	/**
-	 * Announce error feedback which is given to the generic error handler to the registered callbacks.
-	 * @private
-	 *
-	 * @param {String} errorMessage The event containing the error
-	 */
-	_onError: function ( errorMessage ) {
-
-		if ( this.callbacks.genericErrorHandler ) {
-
-			this.callbacks.genericErrorHandler( errorMessage );
-
-		}
-		if ( this.logging.enabled && this.logging.debug ) {
-
-			console.log( errorMessage );
-
-		}
-
-	},
-
-	/**
-	 * Use this convenient method to load a file at the given URL. By default the fileLoader uses an ArrayBuffer.
-	 *
-	 * @param {string}  url A string containing the path/URL of the file to be loaded.
-	 * @param {function} onLoad A function to be called after loading is successfully completed. The function receives loaded Object3D as an argument.
-	 * @param {function} [onFileLoadProgress] A function to be called while the loading is in progress. The argument will be the XMLHttpRequest instance, which contains total and Integer bytes.
-	 * @param {function} [onError] A function to be called if an error occurs during loading. The function receives the error as an argument.
-	 * @param {function} [onMeshAlter] Called after every single mesh is made available by the parser
-	 */
-	load: function ( url, onLoad, onFileLoadProgress, onError, onMeshAlter ) {
-
-		let scope = this;
-		if ( onError === null || onError === undefined ) {
-
-			onError = function ( event ) {
-
-				let errorMessage = event;
-				if ( event.currentTarget && event.currentTarget.statusText !== null ) {
-
-					 errorMessage = 'Error occurred while downloading!\nurl: ' + event.currentTarget.responseURL + '\nstatus: ' + event.currentTarget.statusText;
-
-				}
-				scope._onError( errorMessage );
-
-			};
-
-		}
-		if ( ! url ) {
-
-			onError( 'An invalid url was provided. Unable to continue!' );
+		};
 
-		}
-		let urlFull = new URL( url, window.location.href ).href;
-		let filename = urlFull;
-		let urlParts = urlFull.split( '/' );
-		if ( urlParts.length > 2 ) {
+	}
+	if ( ! url ) {
 
-			filename = urlParts[ urlParts.length - 1 ];
-			let urlPartsPath = urlParts.slice( 0, urlParts.length - 1 ).join( '/' ) + '/';
-			if ( urlPartsPath !== undefined && urlPartsPath !== null ) this.path = urlPartsPath;
+		onError( 'An invalid url was provided. Unable to continue!' );
 
-		}
-		if ( onFileLoadProgress === null || onFileLoadProgress === undefined ) {
+	}
+	let urlFull = new URL( url, window.location.href ).href;
+	let filename = urlFull;
+	let urlParts = urlFull.split( '/' );
+	if ( urlParts.length > 2 ) {
 
-			let numericalValueRef = 0;
-			let numericalValue = 0;
-			onFileLoadProgress = function ( event ) {
+		filename = urlParts[ urlParts.length - 1 ];
+		let urlPartsPath = urlParts.slice( 0, urlParts.length - 1 ).join( '/' ) + '/';
+		if ( urlPartsPath !== undefined && urlPartsPath !== null ) this.path = urlPartsPath;
 
-				if ( ! event.lengthComputable ) return;
+	}
+	if ( onFileLoadProgress === null || onFileLoadProgress === undefined || ! ( onFileLoadProgress instanceof Function ) ) {
 
-				numericalValue = event.loaded / event.total;
-				if ( numericalValue > numericalValueRef ) {
+		let numericalValueRef = 0;
+		let numericalValue = 0;
+		onFileLoadProgress = function ( event ) {
 
-					numericalValueRef = numericalValue;
-					let output = 'Download of "' + url + '": ' + ( numericalValue * 100 ).toFixed( 2 ) + '%';
-					scope._onProgress( 'progressLoad', output, numericalValue );
+			if ( ! event.lengthComputable ) return;
 
-				}
+			numericalValue = event.loaded / event.total;
+			if ( numericalValue > numericalValueRef ) {
 
-			};
+				numericalValueRef = numericalValue;
+				let output = 'Download of "' + url + '": ' + ( numericalValue * 100 ).toFixed( 2 ) + '%';
+				scope.callbacks.onProgress( 'progressLoad', output, numericalValue );
 
-		}
-		this._setCallbacks( null, onMeshAlter, null );
-		let fileLoaderOnLoad = function ( content ) {
-
-			onLoad( scope.parse( content ) );
+			}
 
 		};
-		let fileLoader = new FileLoader( this.manager );
-		fileLoader.setPath( this.path || this.resourcePath );
-		fileLoader.setResponseType( 'arraybuffer' );
-		fileLoader.load( filename, fileLoaderOnLoad, onFileLoadProgress, onError );
-
-	},
-
-	/**
-	 * Parses OBJ data synchronously from arraybuffer or string.
-	 *
-	 * @param {arraybuffer|string} content OBJ data as Uint8Array or String
-	 */
-	parse: function ( content ) {
 
-		// fast-fail in case of illegal data
-		if ( content === null || content === undefined ) {
+	}
 
-			throw 'Provided content is not a valid ArrayBuffer or String. Unable to continue parsing';
+	this.setCallbackOnMeshAlter( onMeshAlter );
+	let fileLoaderOnLoad = function ( content ) {
 
-		}
-		if ( this.logging.enabled ) {
+		onLoad( scope.parse( content ) );
 
-			console.time( 'OBJLoader parse: ' + this.modelName );
+	};
+	let fileLoader = new FileLoader( this.manager );
+	fileLoader.setPath( this.path || this.resourcePath );
+	fileLoader.setResponseType( 'arraybuffer' );
+	fileLoader.load( filename, fileLoaderOnLoad, onFileLoadProgress, onError );
 
-		}
-		let parser = new OBJLoader2Parser();
-		parser.setLogging( this.logging.enabled, this.logging.debug );
-		parser.setMaterialPerSmoothingGroup( this.materialPerSmoothingGroup );
-		parser.setUseOAsMesh( this.useOAsMesh );
-		parser.setUseIndices( this.useIndices );
-		parser.setDisregardNormals( this.disregardNormals );
-		// sync code works directly on the material references
-		parser.setMaterials( this.materialHandler.getMaterials() );
+};
 
-		let scope = this;
-		let scopedOnAssetAvailable = function ( payload ) {
+/**
+ * Parses OBJ data synchronously from arraybuffer or string.
+ *
+ * @param {arraybuffer|string} content OBJ data as Uint8Array or String
+ */
+OBJLoader2.prototype.parse = function ( content ) {
 
-			scope._onAssetAvailable( payload );
+	// fast-fail in case of illegal data
+	if ( content === null || content === undefined ) {
 
-		};
-		let onProgressScoped = function ( text, numericalValue ) {
+		throw 'Provided content is not a valid ArrayBuffer or String. Unable to continue parsing';
 
-			scope._onProgress( 'progressParse', text, numericalValue );
+	}
+	if ( this.logging.enabled ) {
 
-		};
-		let onErrorScoped = function ( message ) {
+		console.time( 'OBJLoader parse: ' + this.modelName );
 
-			scope._onError( message );
+	}
 
-		};
-		parser.setCallbackOnAssetAvailable( scopedOnAssetAvailable );
-		parser.setCallbackOnProgress( onProgressScoped );
-		parser.setCallbackOnError( onErrorScoped );
-		if ( content instanceof ArrayBuffer || content instanceof Uint8Array ) {
+	// sync code works directly on the material references
+	this._setMaterials( this.materialHandler.getMaterials() );
 
-			if ( this.logging.enabled ) console.info( 'Parsing arrayBuffer...' );
-			parser.parse( content );
+	if ( content instanceof ArrayBuffer || content instanceof Uint8Array ) {
 
-		} else if ( typeof ( content ) === 'string' || content instanceof String ) {
+		if ( this.logging.enabled ) console.info( 'Parsing arrayBuffer...' );
+		this.execute( content );
 
-			if ( this.logging.enabled ) console.info( 'Parsing text...' );
-			parser.parseText( content );
+	} else if ( typeof ( content ) === 'string' || content instanceof String ) {
 
-		} else {
+		if ( this.logging.enabled ) console.info( 'Parsing text...' );
+		this.executeLegacy( content );
 
-			scope._onError( 'Provided content was neither of type String nor Uint8Array! Aborting...' );
+	} else {
 
-		}
-		if ( this.logging.enabled ) {
+		this.callbacks.onError( 'Provided content was neither of type String nor Uint8Array! Aborting...' );
 
-			console.timeEnd( 'OBJLoader parse: ' + this.modelName );
+	}
+	if ( this.logging.enabled ) {
 
-		}
-		return this.baseObject3d;
+		console.timeEnd( 'OBJLoader parse: ' + this.modelName );
 
-	},
+	}
+	return this.baseObject3d;
 
-	_onAssetAvailable: function ( payload ) {
+};
 
-		if ( payload.cmd !== 'assetAvailable' ) return;
+OBJLoader2.prototype._onAssetAvailable = function ( payload ) {
 
-		if ( payload.type === 'mesh' ) {
+	if ( payload.cmd !== 'assetAvailable' ) return;
 
-			let meshes = this.meshReceiver.buildMeshes( payload );
-			for ( let mesh of meshes ) {
+	if ( payload.type === 'mesh' ) {
 
-				this.baseObject3d.add( mesh );
+		let meshes = this.meshReceiver.buildMeshes( payload );
+		for ( let mesh of meshes ) {
 
-			}
+			this.baseObject3d.add( mesh );
 
-		} else if ( payload.type === 'material' ) {
+		}
 
-			this.materialHandler.addPayloadMaterials( payload );
+	} else if ( payload.type === 'material' ) {
 
-		}
+		this.materialHandler.addPayloadMaterials( payload );
 
 	}
+
 };
 
 export { OBJLoader2 };

+ 1 - 1
examples/jsm/loaders/OBJLoader2Parallel.d.ts

@@ -1,7 +1,7 @@
 import {
   LoadingManager
 } from '../../../src/Three';
-import { OBJLoader2 } from './OBJLoader2.js';
+import { OBJLoader2 } from './OBJLoader2';
 
 import { WorkerExecutionSupport} from './obj2/worker/main/WorkerExecutionSupport';
 

+ 2 - 2
examples/jsm/loaders/OBJLoader2Parallel.js

@@ -39,8 +39,8 @@ const OBJLoader2Parallel = function ( manager ) {
 OBJLoader2Parallel.prototype = Object.create( OBJLoader2.prototype );
 OBJLoader2Parallel.prototype.constructor = OBJLoader2Parallel;
 
-OBJLoader2.OBJLOADER2_PARALLEL_VERSION = '3.0.0-beta2';
-console.info( 'Using OBJLoader2Parallel version: ' + OBJLoader2.OBJLOADER2_PARALLEL_VERSION );
+OBJLoader2Parallel.OBJLOADER2_PARALLEL_VERSION = '3.0.0';
+console.info( 'Using OBJLoader2Parallel version: ' + OBJLoader2Parallel.OBJLOADER2_PARALLEL_VERSION );
 
 
 OBJLoader2Parallel.prototype.setPreferJsmWorker = function ( preferJsmWorker ) {

+ 1 - 1
examples/jsm/loaders/STLLoader.js

@@ -44,7 +44,7 @@
  *
  *  for (var i = 0; i < nGeometryGroups; i++) {
  *
- *		var material = new THREE.MeshStandardMaterial({
+ *		var material = new THREE.MeshPhongMaterial({
  *			color: colorMap[i],
  *			wireframe: false
  *		});

+ 281 - 2
examples/jsm/loaders/deprecated/LegacyJSONLoader.js

@@ -4,17 +4,32 @@
  */
 
 import {
+	AdditiveBlending,
 	AnimationClip,
+	BackSide,
 	Color,
+	CustomBlending,
 	DefaultLoadingManager,
+	DoubleSide,
 	Face3,
+	FaceColors,
 	FileLoader,
 	Geometry,
 	Loader,
 	LoaderUtils,
+	MaterialLoader,
+	Math as _Math,
+	MirroredRepeatWrapping,
+	MultiplyBlending,
+	NoBlending,
+	NormalBlending,
+	RepeatWrapping,
+	SubtractiveBlending,
+	TextureLoader,
 	Vector2,
 	Vector3,
-	Vector4
+	Vector4,
+	VertexColors
 } from "../../../../build/three.module.js";
 
 var LegacyJSONLoader = ( function () {
@@ -99,6 +114,270 @@ var LegacyJSONLoader = ( function () {
 
 		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 ) {
+
+				var array = [];
+
+				for ( var i = 0; i < materials.length; ++ i ) {
+
+					array[ i ] = createMaterial( materials[ i ], texturePath, crossOrigin );
+
+				}
+
+				return array;
+
+			}
+
+			function createMaterial( m, texturePath, crossOrigin ) {
+
+				// 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.Loader.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 );
+							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 );
+							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 );
+							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 );
+							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 );
+							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 );
+							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 );
+							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 );
+							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 );
+							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 );
+							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.Loader.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.Loader.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 ) {
+
+				var fullPath = texturePath + path;
+				var loader = Loader.Handlers.get( 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 ) {
@@ -575,7 +854,7 @@ var LegacyJSONLoader = ( function () {
 
 				} else {
 
-					var materials = Loader.prototype.initMaterials( json.materials, this.resourcePath || path, this.crossOrigin );
+					var materials = initMaterials( json.materials, this.resourcePath || path, this.crossOrigin );
 
 					return { geometry: geometry, materials: materials };
 

+ 7 - 1
examples/jsm/loaders/obj2/shared/MaterialHandler.js

@@ -46,7 +46,7 @@ MaterialHandler.prototype = {
 
 	_setCallbacks: function ( onLoadMaterials ) {
 
-		if ( onLoadMaterials !== undefined && onLoadMaterials !== null ) {
+		if ( onLoadMaterials !== undefined && onLoadMaterials !== null && onLoadMaterials instanceof Function ) {
 
 			this.callbacks.onLoadMaterials = onLoadMaterials;
 
@@ -176,6 +176,12 @@ MaterialHandler.prototype = {
 
 			}
 
+		}
+
+		if ( this.callbacks.onLoadMaterials ) {
+
+			this.callbacks.onLoadMaterials( newMaterials );
+
 		}
 		return newMaterials;
 

+ 10 - 12
examples/jsm/loaders/obj2/shared/MeshReceiver.js

@@ -25,7 +25,7 @@ const MeshReceiver = function ( materialHandler ) {
 	};
 
 	this.callbacks = {
-		onParseProgress: null,
+		onProgress: null,
 		onMeshAlter: null
 	};
 	this.materialHandler = materialHandler;
@@ -51,18 +51,18 @@ MeshReceiver.prototype = {
 
 	/**
 	 *
-	 * @param {Function} onParseProgress
+	 * @param {Function} onProgress
 	 * @param {Function} onMeshAlter
 	 * @private
 	 */
-	_setCallbacks: function ( onParseProgress, onMeshAlter ) {
+	_setCallbacks: function ( onProgress, onMeshAlter ) {
 
-		if ( onParseProgress !== undefined && onParseProgress !== null ) {
+		if ( onProgress !== null && onProgress !== undefined && onProgress instanceof Function ) {
 
-			this.callbacks.onParseProgress = onParseProgress;
+			this.callbacks.onProgress = onProgress;
 
 		}
-		if ( onMeshAlter !== undefined && onMeshAlter !== null ) {
+		if ( onMeshAlter !== null && onMeshAlter !== undefined && onMeshAlter instanceof Function ) {
 
 			this.callbacks.onMeshAlter = onMeshAlter;
 
@@ -145,14 +145,13 @@ MeshReceiver.prototype = {
 
 		let meshes = [];
 		let mesh;
-		let callbackOnMeshAlter = this.callbacks.onMeshAlter;
 		let callbackOnMeshAlterResult;
 		let useOrgMesh = true;
 		let geometryType = meshPayload.geometryType === null ? 0 : meshPayload.geometryType;
 
-		if ( callbackOnMeshAlter ) {
+		if ( this.callbacks.onMeshAlter ) {
 
-			callbackOnMeshAlterResult = callbackOnMeshAlter(
+			callbackOnMeshAlterResult = this.callbacks.onMeshAlter(
 				{
 					detail: {
 						meshName: meshName,
@@ -224,10 +223,9 @@ MeshReceiver.prototype = {
 			progressMessage += ' (' + ( meshPayload.progress.numericalValue * 100 ).toFixed( 2 ) + '%)';
 
 		}
-		let callbackOnParseProgress = this.callbacks.onParseProgress;
-		if ( callbackOnParseProgress ) {
+		if ( this.callbacks.onProgress ) {
 
-			callbackOnParseProgress( 'progress', progressMessage, meshPayload.progress.numericalValue );
+			this.callbacks.onProgress( 'progress', progressMessage, meshPayload.progress.numericalValue );
 
 		}
 

+ 1 - 1
examples/jsm/loaders/obj2/worker/main/WorkerExecutionSupport.js

@@ -127,7 +127,7 @@ const WorkerExecutionSupport = function () {
 	this._reset();
 
 };
-WorkerExecutionSupport.WORKER_SUPPORT_VERSION = '3.0.0-beta2';
+WorkerExecutionSupport.WORKER_SUPPORT_VERSION = '3.0.0';
 console.info( 'Using WorkerSupport version: ' + WorkerExecutionSupport.WORKER_SUPPORT_VERSION );
 
 

+ 11 - 23
examples/jsm/loaders/obj2/worker/parallel/OBJLoader2Parser.d.ts

@@ -55,27 +55,15 @@ export class OBJLoader2Parser {
     debug: boolean;
   };
 
-  resetRawMesh(): void;
-  setMaterialPerSmoothingGroup(materialPerSmoothingGroup: boolean): void;
-  setUseOAsMesh(useOAsMesh: boolean): void;
-  setUseIndices(useIndices: boolean): void;
-  setDisregardNormals(disregardNormals: boolean): void;
-  setMaterials(materials: object): void;
-  setCallbackOnAssetAvailable(onAssetAvailable: Function): void;
-  setCallbackOnProgress(onProgress: Function): void;
-  setCallbackOnError(onError: Function): void;
-  setLogging(enabled: boolean, debug: boolean): void;
-  configure(): void;
-  parse(arrayBuffer: Uint8Array): void;
-  parseText(text: string): void;
-  processLine(buffer: string[], bufferPointer: number, slashesCount: number): void;
-  pushSmoothingGroup(smoothingGroup: object): void;
-  checkFaceType(faceType: number): void;
-  checkSubGroup(): void;
-  buildFace(faceIndexV: string, faceIndexU: string, faceIndexN: string): void;
-  createRawMeshReport(inputObjectCount: number): void;
-  finalizeRawMesh(): object;
-  processCompletedMesh(): boolean;
-  buildMesh(result: object): void;
-  finalizeParsing(): void;
+  setMaterialPerSmoothingGroup(materialPerSmoothingGroup: boolean): this;
+  setUseOAsMesh(useOAsMesh: boolean): this;
+  setUseIndices(useIndices: boolean): this;
+  setDisregardNormals(disregardNormals: boolean): this;
+
+  setCallbackOnAssetAvailable(onAssetAvailable: Function): this;
+  setCallbackOnProgress(onProgress: Function): this;
+  setCallbackOnError(onError: Function): this;
+  setLogging(enabled: boolean, debug: boolean): this;
+  execute(arrayBuffer: Uint8Array): void;
+  executeLegacy(text: string): void;
 }

+ 189 - 105
examples/jsm/loaders/obj2/worker/parallel/OBJLoader2Parser.js

@@ -8,10 +8,17 @@
  */
 const OBJLoader2Parser = function () {
 
+	let scope = this;
 	this.callbacks = {
-		onProgress: null,
-		onAssetAvailable: null,
-		onError: null
+		onProgress: function ( type, text, numericalValue ) {
+			scope._onProgress( type, text, numericalValue )
+		},
+		onAssetAvailable: function ( payload ) {
+			scope._onAssetAvailable( payload )
+		},
+		onError: function ( errorMessage ) {
+			scope._onError( errorMessage )
+		}
 	};
 	this.contentRef = null;
 	this.legacyMode = false;
@@ -72,7 +79,7 @@ OBJLoader2Parser.prototype = {
 
 	constructor: OBJLoader2Parser,
 
-	resetRawMesh: function () {
+	_resetRawMesh: function () {
 
 		// faces are stored according combined index of group, material and smoothingGroup (0 or not)
 		this.rawMesh.subGroups = [];
@@ -81,7 +88,7 @@ OBJLoader2Parser.prototype = {
 		this.rawMesh.smoothingGroup.real = - 1;
 
 		// this default index is required as it is possible to define faces without 'g' or 'usemtl'
-		this.pushSmoothingGroup( 1 );
+		this._pushSmoothingGroup( 1 );
 
 		this.rawMesh.counts.doubleIndicesCount = 0;
 		this.rawMesh.counts.faceCount = 0;
@@ -90,31 +97,59 @@ OBJLoader2Parser.prototype = {
 
 	},
 
+	/**
+	 * Tells whether a material shall be created per smoothing group.
+	 *
+	 * @param {boolean} materialPerSmoothingGroup=false
+	 * @return {OBJLoader2Parser}
+	 */
 	setMaterialPerSmoothingGroup: function ( materialPerSmoothingGroup ) {
 
-		this.materialPerSmoothingGroup = materialPerSmoothingGroup;
+		this.materialPerSmoothingGroup = materialPerSmoothingGroup === true;
+		return this;
 
 	},
 
+	/**
+	 * Usually 'o' is meta-information and does not result in creation of new meshes, but mesh creation on occurrence of "o" can be enforced.
+	 *
+	 * @param {boolean} useOAsMesh=false
+	 * @return {OBJLoader2Parser}
+	 */
 	setUseOAsMesh: function ( useOAsMesh ) {
 
-		this.useOAsMesh = useOAsMesh;
+		this.useOAsMesh = useOAsMesh === true;
+		return this;
 
 	},
 
+	/**
+	 * Instructs loaders to create indexed {@link BufferGeometry}.
+	 *
+	 * @param {boolean} useIndices=false
+	 * @return {OBJLoader2Parser}
+	 */
 	setUseIndices: function ( useIndices ) {
 
-		this.useIndices = useIndices;
+		this.useIndices = useIndices === true;
+		return this;
 
 	},
 
+	/**
+	 * Tells whether normals should be completely disregarded and regenerated.
+	 *
+	 * @param {boolean} disregardNormals=false
+	 * @return {OBJLoader2Parser}
+	 */
 	setDisregardNormals: function ( disregardNormals ) {
 
-		this.disregardNormals = disregardNormals;
+		this.disregardNormals = disregardNormals === true;
+		return this;
 
 	},
 
-	setMaterials: function ( materials ) {
+	_setMaterials: function ( materials ) {
 
 		if ( materials === undefined || materials === null ) return;
 
@@ -130,60 +165,129 @@ OBJLoader2Parser.prototype = {
 
 	},
 
+	/**
+	 * Register a function that is called once an asset (mesh/material) becomes available.
+	 *
+	 * @param onAssetAvailable
+	 * @return {OBJLoader2Parser}
+	 */
 	setCallbackOnAssetAvailable: function ( onAssetAvailable ) {
 
-		if ( onAssetAvailable !== null && onAssetAvailable !== undefined ) {
+		if ( onAssetAvailable !== null && onAssetAvailable !== undefined && onAssetAvailable instanceof Function ) {
 
 			this.callbacks.onAssetAvailable = onAssetAvailable;
 
 		}
+		return this;
 
 	},
 
+	/**
+	 * Register a function that is used to report overall processing progress.
+	 *
+	 * @param {Function} onProgress
+	 * @return {OBJLoader2Parser}
+	 */
 	setCallbackOnProgress: function ( onProgress ) {
 
-		if ( onProgress !== null && onProgress !== undefined ) {
+		if ( onProgress !== null && onProgress !== undefined && onProgress instanceof Function ) {
 
 			this.callbacks.onProgress = onProgress;
 
 		}
+		return this;
 
 	},
 
+	/**
+	 * Register an error handler function that is called if errors occur. It can decide to just log or to throw an exception.
+	 *
+	 * @param {Function} onError
+	 * @return {OBJLoader2Parser}
+	 */
 	setCallbackOnError: function ( onError ) {
 
-		if ( onError !== null && onError !== undefined ) {
+		if ( onError !== null && onError !== undefined && onError instanceof Function ) {
 
 			this.callbacks.onError = onError;
 
 		}
+		return this;
 
 	},
 
-	setLogging: function ( enabled, debug ) {
+	/**
+	 * Announce feedback which is give to the registered callbacks.
+	 * @private
+	 *
+	 * @param {string} type The type of event
+	 * @param {string} text Textual description of the event
+	 * @param {number} numericalValue Numerical value describing the progress
+	 */
+	_onProgress: function ( type, text, numericalValue ) {
+
+		let message = text ? text : '';
+		let event = {
+			detail: {
+				type: type,
+				modelName: this.modelName,
+				instanceNo: this.instanceNo,
+				text: message,
+				numericalValue: numericalValue
+			}
+		};
 
-		this.logging.enabled = enabled === true;
-		this.logging.debug = debug === true;
+		if ( this.logging.enabled && this.logging.debug ) {
+
+			console.log( message );
+
+		}
+
+	},
+
+	/**
+	 * Announce error feedback which is given to the generic error handler to the registered callbacks.
+	 * @private
+	 *
+	 * @param {String} errorMessage The event containing the error
+	 */
+	_onError: function ( errorMessage ) {
+
+		if ( this.logging.enabled && this.logging.debug ) {
+
+			console.error( errorMessage );
+
+		}
 
 	},
 
-	configure: function () {
+	_onAssetAvailable: function ( payload ) {
 
-		if ( this.callbacks.onAssetAvailable === null ) {
+		let errorMessage = 'OBJLoader2Parser does not provide implementation for onAssetAvailable. Aborting...';
+		this.callbacks.onError( errorMessage );
+		throw errorMessage;
 
-			let errorMessage = 'Unable to run as no callback for building meshes is set.';
-			if ( this.callbacks.onError !== null ) {
+	},
 
-				this.callbacks.onError( errorMessage );
+	/**
+	 * Enable or disable logging in general (except warn and error), plus enable or disable debug logging.
+	 *
+	 * @param {boolean} enabled True or false.
+	 * @param {boolean} debug True or false.
+	 *
+	 * @return {OBJLoader2Parser}
+	 */
+	setLogging: function ( enabled, debug ) {
 
-			} else {
+		this.logging.enabled = enabled === true;
+		this.logging.debug = debug === true;
+		return this;
 
-				throw errorMessage;
+	},
 
-			}
+	_configure: function () {
 
-		}
-		this.pushSmoothingGroup( 1 );
+		this._pushSmoothingGroup( 1 );
 		if ( this.logging.enabled ) {
 
 			let matKeys = Object.keys( this.materials );
@@ -194,21 +298,9 @@ OBJLoader2Parser.prototype = {
 				+ '\n\tuseOAsMesh: ' + this.useOAsMesh
 				+ '\n\tuseIndices: ' + this.useIndices
 				+ '\n\tdisregardNormals: ' + this.disregardNormals;
-			if ( this.callbacks.onProgress !== null ) {
-
-				printedConfig += '\n\tcallbacks.onProgress: ' + this.callbacks.onProgress.name;
-
-			}
-			if ( this.callbacks.onAssetAvailable !== null ) {
-
-				printedConfig += '\n\tcallbacks.onAssetAvailable: ' + this.callbacks.onAssetAvailable.name;
-
-			}
-			if ( this.callbacks.onError !== null ) {
-
-				printedConfig += '\n\tcallbacks.onError: ' + this.callbacks.onError.name;
-
-			}
+			printedConfig += '\n\tcallbacks.onProgress: ' + this.callbacks.onProgress.name;
+			printedConfig += '\n\tcallbacks.onAssetAvailable: ' + this.callbacks.onAssetAvailable.name;
+			printedConfig += '\n\tcallbacks.onError: ' + this.callbacks.onError.name;
 			console.info( printedConfig );
 
 		}
@@ -220,10 +312,10 @@ OBJLoader2Parser.prototype = {
 	 *
 	 * @param {Uint8Array} arrayBuffer OBJ data as Uint8Array
 	 */
-	parse: function ( arrayBuffer ) {
+	execute: function ( arrayBuffer ) {
 
-		if ( this.logging.enabled ) console.time( 'OBJLoader.Parser.parse' );
-		this.configure();
+		if ( this.logging.enabled ) console.time( 'OBJLoader2Parser.execute' );
+		this._configure();
 
 		let arrayBufferView = new Uint8Array( arrayBuffer );
 		this.contentRef = arrayBufferView;
@@ -254,7 +346,7 @@ OBJLoader2Parser.prototype = {
 					word = '';
 					this.globalCounts.lineByte = this.globalCounts.currentByte;
 					this.globalCounts.currentByte = i;
-					this.processLine( buffer, bufferPointer, slashesCount );
+					this._processLine( buffer, bufferPointer, slashesCount );
 					bufferPointer = 0;
 					slashesCount = 0;
 					break;
@@ -270,8 +362,8 @@ OBJLoader2Parser.prototype = {
 			}
 
 		}
-		this.finalizeParsing();
-		if ( this.logging.enabled ) console.timeEnd( 'OBJLoader.Parser.parse' );
+		this._finalizeParsing();
+		if ( this.logging.enabled ) console.timeEnd( 'OBJLoader2Parser.execute' );
 
 	},
 
@@ -280,10 +372,10 @@ OBJLoader2Parser.prototype = {
 	 *
 	 * @param {string} text OBJ data as string
 	 */
-	parseText: function ( text ) {
+	executeLegacy: function ( text ) {
 
-		if ( this.logging.enabled ) console.time( 'OBJLoader.Parser.parseText' );
-		this.configure();
+		if ( this.logging.enabled ) console.time( 'OBJLoader2Parser.executeLegacy' );
+		this._configure();
 		this.legacyMode = true;
 		this.contentRef = text;
 		let length = text.length;
@@ -311,7 +403,7 @@ OBJLoader2Parser.prototype = {
 					word = '';
 					this.globalCounts.lineByte = this.globalCounts.currentByte;
 					this.globalCounts.currentByte = i;
-					this.processLine( buffer, bufferPointer, slashesCount );
+					this._processLine( buffer, bufferPointer, slashesCount );
 					bufferPointer = 0;
 					slashesCount = 0;
 					break;
@@ -325,12 +417,12 @@ OBJLoader2Parser.prototype = {
 			}
 
 		}
-		this.finalizeParsing();
-		if ( this.logging.enabled ) console.timeEnd( 'OBJLoader.Parser.parseText' );
+		this._finalizeParsing();
+		if ( this.logging.enabled ) console.timeEnd( 'OBJLoader2Parser.executeLegacy' );
 
 	},
 
-	processLine: function ( buffer, bufferPointer, slashesCount ) {
+	_processLine: function ( buffer, bufferPointer, slashesCount ) {
 
 		if ( bufferPointer < 1 ) return;
 
@@ -391,12 +483,12 @@ OBJLoader2Parser.prototype = {
 				// "f vertex ..."
 				if ( slashesCount === 0 ) {
 
-					this.checkFaceType( 0 );
+					this._checkFaceType( 0 );
 					for ( i = 2, length = bufferLength; i < length; i ++ ) {
 
-						this.buildFace( buffer[ 1 ] );
-						this.buildFace( buffer[ i ] );
-						this.buildFace( buffer[ i + 1 ] );
+						this._buildFace( buffer[ 1 ] );
+						this._buildFace( buffer[ i ] );
+						this._buildFace( buffer[ i + 1 ] );
 
 					}
 
@@ -404,12 +496,12 @@ OBJLoader2Parser.prototype = {
 
 				} else if ( bufferLength === slashesCount * 2 ) {
 
-					this.checkFaceType( 1 );
+					this._checkFaceType( 1 );
 					for ( i = 3, length = bufferLength - 2; i < length; i += 2 ) {
 
-						this.buildFace( buffer[ 1 ], buffer[ 2 ] );
-						this.buildFace( buffer[ i ], buffer[ i + 1 ] );
-						this.buildFace( buffer[ i + 2 ], buffer[ i + 3 ] );
+						this._buildFace( buffer[ 1 ], buffer[ 2 ] );
+						this._buildFace( buffer[ i ], buffer[ i + 1 ] );
+						this._buildFace( buffer[ i + 2 ], buffer[ i + 3 ] );
 
 					}
 
@@ -417,12 +509,12 @@ OBJLoader2Parser.prototype = {
 
 				} else if ( bufferLength * 2 === slashesCount * 3 ) {
 
-					this.checkFaceType( 2 );
+					this._checkFaceType( 2 );
 					for ( i = 4, length = bufferLength - 3; i < length; i += 3 ) {
 
-						this.buildFace( buffer[ 1 ], buffer[ 2 ], buffer[ 3 ] );
-						this.buildFace( buffer[ i ], buffer[ i + 1 ], buffer[ i + 2 ] );
-						this.buildFace( buffer[ i + 3 ], buffer[ i + 4 ], buffer[ i + 5 ] );
+						this._buildFace( buffer[ 1 ], buffer[ 2 ], buffer[ 3 ] );
+						this._buildFace( buffer[ i ], buffer[ i + 1 ], buffer[ i + 2 ] );
+						this._buildFace( buffer[ i + 3 ], buffer[ i + 4 ], buffer[ i + 5 ] );
 
 					}
 
@@ -430,12 +522,12 @@ OBJLoader2Parser.prototype = {
 
 				} else {
 
-					this.checkFaceType( 3 );
+					this._checkFaceType( 3 );
 					for ( i = 3, length = bufferLength - 2; i < length; i += 2 ) {
 
-						this.buildFace( buffer[ 1 ], undefined, buffer[ 2 ] );
-						this.buildFace( buffer[ i ], undefined, buffer[ i + 1 ] );
-						this.buildFace( buffer[ i + 2 ], undefined, buffer[ i + 3 ] );
+						this._buildFace( buffer[ 1 ], undefined, buffer[ 2 ] );
+						this._buildFace( buffer[ i ], undefined, buffer[ i + 1 ] );
+						this._buildFace( buffer[ i + 2 ], undefined, buffer[ i + 3 ] );
 
 					}
 
@@ -447,30 +539,30 @@ OBJLoader2Parser.prototype = {
 				bufferLength = bufferPointer - 1;
 				if ( bufferLength === slashesCount * 2 ) {
 
-					this.checkFaceType( 4 );
-					for ( i = 1, length = bufferLength + 1; i < length; i += 2 ) this.buildFace( buffer[ i ], buffer[ i + 1 ] );
+					this._checkFaceType( 4 );
+					for ( i = 1, length = bufferLength + 1; i < length; i += 2 ) this._buildFace( buffer[ i ], buffer[ i + 1 ] );
 
 				} else {
 
-					this.checkFaceType( ( lineDesignation === 'l' ) ? 5 : 6 );
-					for ( i = 1, length = bufferLength + 1; i < length; i ++ ) this.buildFace( buffer[ i ] );
+					this._checkFaceType( ( lineDesignation === 'l' ) ? 5 : 6 );
+					for ( i = 1, length = bufferLength + 1; i < length; i ++ ) this._buildFace( buffer[ i ] );
 
 				}
 				break;
 
 			case 's':
-				this.pushSmoothingGroup( buffer[ 1 ] );
+				this._pushSmoothingGroup( buffer[ 1 ] );
 				break;
 
 			case 'g':
 				// 'g' leads to creation of mesh if valid data (faces declaration was done before), otherwise only groupName gets set
-				this.processCompletedMesh();
+				this._processCompletedMesh();
 				this.rawMesh.groupName = reconstructString( this.contentRef, this.legacyMode, this.globalCounts.lineByte + 2, this.globalCounts.currentByte );
 				break;
 
 			case 'o':
 				// 'o' is meta-information and usually does not result in creation of new meshes, but can be enforced with "useOAsMesh"
-				if ( this.useOAsMesh ) this.processCompletedMesh();
+				if ( this.useOAsMesh ) this._processCompletedMesh();
 				this.rawMesh.objectName = reconstructString( this.contentRef, this.legacyMode, this.globalCounts.lineByte + 2, this.globalCounts.currentByte );
 				break;
 
@@ -484,7 +576,7 @@ OBJLoader2Parser.prototype = {
 
 					this.rawMesh.activeMtlName = mtlName;
 					this.rawMesh.counts.mtlCount ++;
-					this.checkSubGroup();
+					this._checkSubGroup();
 
 				}
 				break;
@@ -496,7 +588,7 @@ OBJLoader2Parser.prototype = {
 
 	},
 
-	pushSmoothingGroup: function ( smoothingGroup ) {
+	_pushSmoothingGroup: function ( smoothingGroup ) {
 
 		let smoothingGroupInt = parseInt( smoothingGroup );
 		if ( isNaN( smoothingGroupInt ) ) {
@@ -512,7 +604,7 @@ OBJLoader2Parser.prototype = {
 		if ( smoothCheck !== smoothingGroupInt ) {
 
 			this.rawMesh.counts.smoothingGroupCount ++;
-			this.checkSubGroup();
+			this._checkSubGroup();
 
 		}
 
@@ -528,19 +620,19 @@ OBJLoader2Parser.prototype = {
 	 * faceType = 5: "l vertex ..."
 	 * faceType = 6: "p vertex ..."
 	 */
-	checkFaceType: function ( faceType ) {
+	_checkFaceType: function ( faceType ) {
 
 		if ( this.rawMesh.faceType !== faceType ) {
 
-			this.processCompletedMesh();
+			this._processCompletedMesh();
 			this.rawMesh.faceType = faceType;
-			this.checkSubGroup();
+			this._checkSubGroup();
 
 		}
 
 	},
 
-	checkSubGroup: function () {
+	_checkSubGroup: function () {
 
 		let index = this.rawMesh.activeMtlName + '|' + this.rawMesh.smoothingGroup.normalized;
 		this.rawMesh.subGroupInUse = this.rawMesh.subGroups[ index ];
@@ -567,7 +659,7 @@ OBJLoader2Parser.prototype = {
 
 	},
 
-	buildFace: function ( faceIndexV, faceIndexU, faceIndexN ) {
+	_buildFace: function ( faceIndexV, faceIndexU, faceIndexN ) {
 
 		let subGroupInUse = this.rawMesh.subGroupInUse;
 		let scope = this;
@@ -640,7 +732,7 @@ OBJLoader2Parser.prototype = {
 
 	},
 
-	createRawMeshReport: function ( inputObjectCount ) {
+	_createRawMeshReport: function ( inputObjectCount ) {
 
 		return 'Input Object number: ' + inputObjectCount +
 			'\n\tObject name: ' + this.rawMesh.objectName +
@@ -658,7 +750,7 @@ OBJLoader2Parser.prototype = {
 	/**
 	 * Clear any empty subGroup and calculate absolute vertex, normal and uv counts
 	 */
-	finalizeRawMesh: function () {
+	_finalizeRawMesh: function () {
 
 		let meshOutputGroupTemp = [];
 		let meshOutputGroup;
@@ -717,33 +809,25 @@ OBJLoader2Parser.prototype = {
 
 	},
 
-	processCompletedMesh: function () {
+	_processCompletedMesh: function () {
 
-		let result = this.finalizeRawMesh();
+		let result = this._finalizeRawMesh();
 		let haveMesh = result !== null;
 		if ( haveMesh ) {
 
 			if ( this.colors.length > 0 && this.colors.length !== this.vertices.length ) {
 
-				if ( this.callbacks.onError !== null ) {
-
-					this.callbacks.onError( 'Vertex Colors were detected, but vertex count and color count do not match!' );
-
-				}
+				this.callbacks.onError( 'Vertex Colors were detected, but vertex count and color count do not match!' );
 
 			}
-			if ( this.logging.enabled && this.logging.debug ) console.debug( this.createRawMeshReport( this.inputObjectCount ) );
+			if ( this.logging.enabled && this.logging.debug ) console.debug( this._createRawMeshReport( this.inputObjectCount ) );
 			this.inputObjectCount ++;
 
-			this.buildMesh( result );
+			this._buildMesh( result );
 			let progressBytesPercent = this.globalCounts.currentByte / this.globalCounts.totalBytes;
-			if ( this.callbacks.onProgress !== null ) {
-
-				this.callbacks.onProgress( 'Completed [o: ' + this.rawMesh.objectName + ' g:' + this.rawMesh.groupName + '' +
+			this._onProgress( 'progressParse', 'Completed [o: ' + this.rawMesh.objectName + ' g:' + this.rawMesh.groupName + '' +
 					'] Total progress: ' + ( progressBytesPercent * 100 ).toFixed( 2 ) + '%', progressBytesPercent );
-
-			}
-			this.resetRawMesh();
+			this._resetRawMesh();
 
 		}
 		return haveMesh;
@@ -756,7 +840,7 @@ OBJLoader2Parser.prototype = {
 	 *
 	 * @param result
 	 */
-	buildMesh: function ( result ) {
+	_buildMesh: function ( result ) {
 
 		let meshOutputGroups = result.subGroups;
 
@@ -965,10 +1049,10 @@ OBJLoader2Parser.prototype = {
 
 	},
 
-	finalizeParsing: function () {
+	_finalizeParsing: function () {
 
 		if ( this.logging.enabled ) console.info( 'Global output object count: ' + this.outputObjectCount );
-		if ( this.processCompletedMesh() && this.logging.enabled ) {
+		if ( this._processCompletedMesh() && this.logging.enabled ) {
 
 			let parserFinalReport = 'Overall counts: ' +
 				'\n\tVertices: ' + this.globalCounts.vertices +

+ 3 - 3
examples/jsm/loaders/obj2/worker/parallel/WorkerRunner.js

@@ -64,15 +64,15 @@ DefaultWorkerPayloadHandler.prototype = {
 
 			}
 
-			let parseFunctionName = 'parse';
-			if ( typeof parser.getParseFunctionName === 'function' ) parseFunctionName = parser.getParseFunctionName();
+			let executeFunctionName = 'execute';
+			if ( typeof parser.getParseFunctionName === 'function' ) executeFunctionName = parser.getParseFunctionName();
 			if ( payload.usesMeshDisassembler ) {
 
 				// TODO: Allow to plug and use generic MeshDisassembler
 
 			} else {
 
-				parser[ parseFunctionName ]( arraybuffer, payload.data.options );
+				parser[ executeFunctionName ]( arraybuffer, payload.data.options );
 
 			}
 			if ( this.logging.enabled ) console.log( 'WorkerRunner: Run complete!' );

+ 2 - 2
examples/jsm/loaders/sea3d/SEA3DLoader.js

@@ -2715,8 +2715,8 @@ SEA3D.prototype.materialTechnique =
 	techniques[ SEA3DSDK.Material.CLEAR_COAT ] =
 	function ( mat, tech ) {
 
-		mat.clearCoat = tech.strength;
-		mat.clearCoatRoughness = tech.roughness;
+		mat.clearcoat = tech.strength;
+		mat.clearcoatRoughness = tech.roughness;
 
 	};
 

+ 1 - 1
examples/jsm/nodes/accessors/NormalNode.js

@@ -87,7 +87,7 @@ NormalNode.prototype.toJSON = function ( meta ) {
 
 };
 
-NodeLib.addKeyword( 'normal', function () {
+NodeLib.addKeyword( 'viewNormal', function () {
 
 	return new NormalNode();
 

+ 48 - 8
examples/jsm/nodes/accessors/ReflectNode.js

@@ -8,7 +8,7 @@ import { NormalNode } from './NormalNode.js';
 
 function ReflectNode( scope ) {
 
-	TempNode.call( this, 'v3', { unique: true } );
+	TempNode.call( this, 'v3' );
 
 	this.scope = scope || ReflectNode.CUBE;
 
@@ -22,6 +22,12 @@ ReflectNode.prototype = Object.create( TempNode.prototype );
 ReflectNode.prototype.constructor = ReflectNode;
 ReflectNode.prototype.nodeType = "Reflect";
 
+ReflectNode.prototype.getUnique = function ( builder ) {
+
+	return !builder.context.viewNormal;
+
+};
+
 ReflectNode.prototype.getType = function ( /* builder */ ) {
 
 	switch ( this.scope ) {
@@ -38,6 +44,8 @@ ReflectNode.prototype.getType = function ( /* builder */ ) {
 
 ReflectNode.prototype.generate = function ( builder, output ) {
 
+	var isUnique = this.getUnique( builder );
+
 	if ( builder.isShader( 'fragment' ) ) {
 
 		var result;
@@ -46,12 +54,24 @@ ReflectNode.prototype.generate = function ( builder, output ) {
 
 			case ReflectNode.VECTOR:
 
-				var viewNormal = new NormalNode().build( builder, 'v3' );
+				var viewNormalNode = builder.context.viewNormal || new NormalNode();
+
+				var viewNormal = viewNormalNode.build( builder, 'v3' );
 				var viewPosition = new PositionNode( PositionNode.VIEW ).build( builder, 'v3' );
 
-				builder.addNodeCode( 'vec3 reflectVec = inverseTransformDirection( reflect( -normalize( ' + viewPosition + ' ), ' + viewNormal + ' ), viewMatrix );' );
+				var code = `inverseTransformDirection( reflect( -normalize( ${viewPosition} ), ${viewNormal} ), viewMatrix )`;
+
+				if ( isUnique ) {
+
+					builder.addNodeCode( `vec3 reflectVec = ${code};` );
+
+					result = 'reflectVec';
+
+				} else {
+
+					result = code;
 
-				result = 'reflectVec';
+				}
 
 				break;
 
@@ -59,9 +79,19 @@ ReflectNode.prototype.generate = function ( builder, output ) {
 
 				var reflectVec = new ReflectNode( ReflectNode.VECTOR ).build( builder, 'v3' );
 
-				builder.addNodeCode( 'vec3 reflectCubeVec = vec3( -1.0 * ' + reflectVec + '.x, ' + reflectVec + '.yz );' );
+				var code = 'vec3( -' + reflectVec + '.x, ' + reflectVec + '.yz )';
 
-				result = 'reflectCubeVec';
+				if ( isUnique ) {
+
+					builder.addNodeCode( `vec3 reflectCubeVec = ${code};` );
+
+					result = 'reflectCubeVec';
+
+				} else {
+
+					result = code;
+
+				}
 
 				break;
 
@@ -69,9 +99,19 @@ ReflectNode.prototype.generate = function ( builder, output ) {
 
 				var reflectVec = new ReflectNode( ReflectNode.VECTOR ).build( builder, 'v3' );
 
-				builder.addNodeCode( 'vec2 reflectSphereVec = normalize( ( viewMatrix * vec4( ' + reflectVec + ', 0.0 ) ).xyz + vec3( 0.0, 0.0, 1.0 ) ).xy * 0.5 + 0.5;' );
+				var code = 'normalize( ( viewMatrix * vec4( ' + reflectVec + ', 0.0 ) ).xyz + vec3( 0.0, 0.0, 1.0 ) ).xy * 0.5 + 0.5';
+
+				if ( isUnique ) {
+
+					builder.addNodeCode( `vec2 reflectSphereVec = ${code};` );
+
+					result = 'reflectSphereVec';
+
+				} else {
+
+					result = code;
 
-				result = 'reflectSphereVec';
+				}
 
 				break;
 

+ 2 - 2
examples/jsm/nodes/bsdfs/BlinnShininessExponentNode.js

@@ -16,9 +16,9 @@ BlinnShininessExponentNode.prototype.nodeType = "BlinnShininessExponent";
 
 BlinnShininessExponentNode.prototype.generate = function ( builder, output ) {
 
-	if ( builder.isCache( 'clearCoat' ) ) {
+	if ( builder.isCache( 'clearcoat' ) ) {
 
-		return builder.format( 'Material_ClearCoat_BlinnShininessExponent( material )', this.type, output );
+		return builder.format( 'Material_Clearcoat_BlinnShininessExponent( material )', this.type, output );
 
 	} else {
 

+ 5 - 4
examples/jsm/nodes/materials/StandardNodeMaterial.js

@@ -25,9 +25,9 @@ NodeUtils.addShortcuts( StandardNodeMaterial.prototype, 'fragment', [
 	'roughness',
 	'metalness',
 	'reflectivity',
-	'clearCoat',
-	'clearCoatRoughness',
-	'clearCoatNormal',
+	'clearcoat',
+	'clearcoatRoughness',
+	'clearcoatNormal',
 	'normal',
 	'emissive',
 	'ambient',
@@ -36,7 +36,8 @@ NodeUtils.addShortcuts( StandardNodeMaterial.prototype, 'fragment', [
 	'ao',
 	'environment',
 	'mask',
-	'position'
+	'position',
+	'sheen'
 ] );
 
 export { StandardNodeMaterial };

+ 61 - 31
examples/jsm/nodes/materials/nodes/StandardNode.js

@@ -8,6 +8,7 @@ import {
 } from '../../../../../build/three.module.js';
 
 import { Node } from '../../core/Node.js';
+import { ExpressionNode } from '../../core/ExpressionNode.js';
 import { ColorNode } from '../../inputs/ColorNode.js';
 import { FloatNode } from '../../inputs/FloatNode.js';
 import { RoughnessToBlinnExponentNode } from '../../bsdfs/RoughnessToBlinnExponentNode.js';
@@ -32,7 +33,15 @@ StandardNode.prototype.build = function ( builder ) {
 
 	var code;
 
-	builder.define( this.clearCoat || this.clearCoatRoughness || this.clearCoatNormal ? 'PHYSICAL' : 'STANDARD' );
+	builder.define('STANDARD');
+
+	var useClearcoat = this.clearcoat || this.clearcoatRoughness || this.clearCoatNormal;
+
+	if( useClearcoat ){
+
+		builder.define( 'CLEARCOAT' );
+
+	}
 
 	builder.requires.lights = true;
 
@@ -122,6 +131,7 @@ StandardNode.prototype.build = function ( builder ) {
 
 		var contextEnvironment = {
 			bias: RoughnessToBlinnExponentNode,
+			viewNormal: new ExpressionNode('normal', 'v3'),
 			gamma: true
 		};
 
@@ -129,7 +139,11 @@ StandardNode.prototype.build = function ( builder ) {
 			gamma: true
 		};
 
-		var useClearCoat = ! builder.isDefined( 'STANDARD' );
+		var contextClearcoatEnvironment = {
+			bias: RoughnessToBlinnExponentNode,
+			viewNormal: new ExpressionNode('clearcoatNormal', 'v3'),
+			gamma: true
+		};
 
 		// analyze all nodes to reuse generate codes
 
@@ -143,9 +157,9 @@ StandardNode.prototype.build = function ( builder ) {
 
 		if ( this.normal ) this.normal.analyze( builder );
 
-		if ( this.clearCoat ) this.clearCoat.analyze( builder );
-		if ( this.clearCoatRoughness ) this.clearCoatRoughness.analyze( builder );
-		if ( this.clearCoatNormal ) this.clearCoatNormal.analyze( builder );
+		if ( this.clearcoat ) this.clearcoat.analyze( builder );
+		if ( this.clearcoatRoughness ) this.clearcoatRoughness.analyze( builder );
+		if ( this.clearcoatNormal ) this.clearcoatNormal.analyze( builder );
 
 		if ( this.reflectivity ) this.reflectivity.analyze( builder );
 
@@ -161,16 +175,18 @@ StandardNode.prototype.build = function ( builder ) {
 			// isolate environment from others inputs ( see TextureNode, CubeTextureNode )
 			// environment.analyze will detect if there is a need of calculate irradiance
 
-			this.environment.analyze( builder, { cache: 'radiance', context: contextEnvironment, slot: 'radiance' } ); 
+			this.environment.analyze( builder, { cache: 'radiance', context: contextEnvironment, slot: 'radiance' } );
 
 			if ( builder.requires.irradiance ) {
 
-				this.environment.analyze( builder, { cache: 'irradiance', context: contextEnvironment, slot: 'irradiance' } ); 
+				this.environment.analyze( builder, { cache: 'irradiance', context: contextEnvironment, slot: 'irradiance' } );
 
 			}
 
 		}
 
+		if ( this.sheen ) this.sheen.analyze( builder );
+
 		// build code
 
 		var mask = this.mask ? this.mask.flow( builder, 'b' ) : undefined;
@@ -183,9 +199,9 @@ StandardNode.prototype.build = function ( builder ) {
 
 		var normal = this.normal ? this.normal.flow( builder, 'v3' ) : undefined;
 
-		var clearCoat = this.clearCoat ? this.clearCoat.flow( builder, 'f' ) : undefined;
-		var clearCoatRoughness = this.clearCoatRoughness ? this.clearCoatRoughness.flow( builder, 'f' ) : undefined;
-		var clearCoatNormal = this.clearCoatNormal ? this.clearCoatNormal.flow( builder, 'v3' ) : undefined;
+		var clearcoat = this.clearcoat ? this.clearcoat.flow( builder, 'f' ) : undefined;
+		var clearcoatRoughness = this.clearcoatRoughness ? this.clearcoatRoughness.flow( builder, 'f' ) : undefined;
+		var clearcoatNormal = this.clearcoatNormal ? this.clearcoatNormal.flow( builder, 'v3' ) : undefined;
 
 		var reflectivity = this.reflectivity ? this.reflectivity.flow( builder, 'f' ) : undefined;
 
@@ -212,7 +228,9 @@ StandardNode.prototype.build = function ( builder ) {
 
 		}
 
-		var clearCoatEnv = useClearCoat && environment ? this.environment.flow( builder, 'c', { cache: 'clearCoat', context: contextEnvironment, slot: 'environment' } ) : undefined;
+		var clearcoatEnv = useClearcoat && environment ? this.environment.flow( builder, 'c', { cache: 'clearcoat', context: contextClearcoatEnvironment, slot: 'environment' } ) : undefined;
+
+		var sheen = this.sheen ? this.sheen.flow( builder, 'c' ) : undefined;
 
 		builder.requires.transparent = alpha !== undefined;
 
@@ -292,11 +310,11 @@ StandardNode.prototype.build = function ( builder ) {
 
 		}
 
-		if ( clearCoatNormal ) {
+		if ( clearcoatNormal ) {
 
 			output.push(
-				clearCoatNormal.code,
-				'clearCoatNormal = ' + clearCoatNormal.result + ';'
+				clearcoatNormal.code,
+				'clearcoatNormal = ' + clearcoatNormal.result + ';'
 			);
 
 		}
@@ -308,29 +326,35 @@ StandardNode.prototype.build = function ( builder ) {
 			'material.specularRoughness = clamp( roughnessFactor, 0.04, 1.0 );'
 		);
 
-		if ( clearCoat ) {
+		if ( clearcoat ) {
 
 			output.push(
-				clearCoat.code,
-				'material.clearCoat = saturate( ' + clearCoat.result + ' );'
+				clearcoat.code,
+				'material.clearcoat = saturate( ' + clearcoat.result + ' );'
 			);
 
-		} else if ( useClearCoat ) {
+		} else if ( useClearcoat ) {
 
-			output.push( 'material.clearCoat = 0.0;' );
+			output.push( 'material.clearcoat = 0.0;' );
 
 		}
 
-		if ( clearCoatRoughness ) {
+		if ( clearcoatRoughness ) {
 
 			output.push(
-				clearCoatRoughness.code,
-				'material.clearCoatRoughness = clamp( ' + clearCoatRoughness.result + ', 0.04, 1.0 );'
+				clearcoatRoughness.code,
+				'material.clearcoatRoughness = clamp( ' + clearcoatRoughness.result + ', 0.04, 1.0 );'
 			);
 
-		} else if ( useClearCoat ) {
+		} else if ( useClearcoat ) {
+
+			output.push( 'material.clearcoatRoughness = 0.0;' );
+
+		}
+
+		if ( sheen ) {
 
-			output.push( 'material.clearCoatRoughness = 0.0;' );
+			output.push( 'material.sheenColor = ' + sheen.result + ';' );
 
 		}
 
@@ -420,11 +444,11 @@ StandardNode.prototype.build = function ( builder ) {
 
 			}
 
-			if ( clearCoatEnv ) {
+			if ( clearcoatEnv ) {
 
 				output.push(
-					clearCoatEnv.code,
-					"clearCoatRadiance += " + clearCoatEnv.result + ";"
+					clearcoatEnv.code,
+					"clearcoatRadiance += " + clearcoatEnv.result + ";"
 				);
 
 			}
@@ -491,8 +515,9 @@ StandardNode.prototype.copy = function ( source ) {
 
 	if ( source.normal ) this.normal = source.normal;
 
-	if ( source.clearCoat ) this.clearCoat = source.clearCoat;
-	if ( source.clearCoatRoughness ) this.clearCoatRoughness = source.clearCoatRoughness;
+	if ( source.clearcoat ) this.clearcoat = source.clearcoat;
+	if ( source.clearcoatRoughness ) this.clearcoatRoughness = source.clearcoatRoughness;
+	if ( source.clearcoatNormal ) this.clearcoatNormal = source.clearcoatNormal;
 
 	if ( source.reflectivity ) this.reflectivity = source.reflectivity;
 
@@ -506,6 +531,8 @@ StandardNode.prototype.copy = function ( source ) {
 
 	if ( source.environment ) this.environment = source.environment;
 
+	if ( source.sheen ) this.sheen = source.sheen;
+
 	return this;
 
 };
@@ -534,8 +561,9 @@ StandardNode.prototype.toJSON = function ( meta ) {
 
 		if ( this.normal ) data.normal = this.normal.toJSON( meta ).uuid;
 
-		if ( this.clearCoat ) data.clearCoat = this.clearCoat.toJSON( meta ).uuid;
-		if ( this.clearCoatRoughness ) data.clearCoatRoughness = this.clearCoatRoughness.toJSON( meta ).uuid;
+		if ( this.clearcoat ) data.clearcoat = this.clearcoat.toJSON( meta ).uuid;
+		if ( this.clearcoatRoughness ) data.clearcoatRoughness = this.clearcoatRoughness.toJSON( meta ).uuid;
+		if ( this.clearcoatNormal ) data.clearcoatNormal = this.clearcoatNormal.toJSON( meta ).uuid;
 
 		if ( this.reflectivity ) data.reflectivity = this.reflectivity.toJSON( meta ).uuid;
 
@@ -549,6 +577,8 @@ StandardNode.prototype.toJSON = function ( meta ) {
 
 		if ( this.environment ) data.environment = this.environment.toJSON( meta ).uuid;
 
+		if ( this.sheen ) data.sheen = this.sheen.toJSON( meta ).uuid;
+
 	}
 
 	return data;

+ 1 - 1
examples/jsm/shaders/TranslucentShader.js

@@ -194,7 +194,7 @@ var TranslucentShader = {
 		"	#if defined( RE_IndirectSpecular )",
 
 		"		vec3 radiance = vec3( 0.0 );",
-		"		vec3 clearCoatRadiance = vec3( 0.0 );",
+		"		vec3 clearcoatRadiance = vec3( 0.0 );",
 
 		"	#endif",
 		ShaderChunk[ "lights_fragment_end" ],

BIN
examples/models/fbx/cloth.fbx


+ 1 - 1
examples/webgl_loader_obj2_options.html

@@ -286,7 +286,7 @@
 
 						return override;
 					}
-					objLoader2Parallel._setCallbacks( null, callbackMeshAlter );
+					objLoader2Parallel.setCallbackOnMeshAlter( callbackMeshAlter );
 
 					let scope = this;
 					function callbackOnLoad ( message ) {

+ 9 - 9
examples/webgl_materials_clearcoat_normalmap.html

@@ -87,12 +87,12 @@
 
 						var normalMap2 = textureLoader.load( "textures/water/Water_1_M_Normal.jpg" );
 
-						var clearCoatNormaMap = textureLoader.load( "textures/pbr/Scratched_gold/Scratched_gold_01_1K_Normal.png" );
+						var clearcoatNormaMap = textureLoader.load( "textures/pbr/Scratched_gold/Scratched_gold_01_1K_Normal.png" );
 
 						//
 
 						var material = new THREE.MeshPhysicalMaterial( {
-							clearCoat: 1.0,
+							clearcoat: 1.0,
 							envMap: hdrCubeRenderTarget.texture,
 							map: diffuse
 						} );
@@ -105,7 +105,7 @@
 						// normalmap
 
 						var material = new THREE.MeshPhysicalMaterial( {
-							clearCoat: 1.0,
+							clearcoat: 1.0,
 							envMap: hdrCubeRenderTarget.texture,
 							map: diffuse,
 							normalMap: normalMap
@@ -118,12 +118,12 @@
 						// clearcoat
 
 						var material = new THREE.MeshPhysicalMaterial( {
-							clearCoat: 1.0,
+							clearcoat: 1.0,
 							metalness: 0.0,
 							color: 0xff0000,
 							envMap: hdrCubeRenderTarget.texture,
-							clearCoatNormalMap: clearCoatNormaMap,
-							clearCoatNormalScale: new THREE.Vector2( 2.0, 2.0 )
+							clearcoatNormalMap: clearcoatNormaMap,
+							clearcoatNormalScale: new THREE.Vector2( 2.0, 2.0 )
 						} );
 						var mesh = new THREE.Mesh( geometry, material );
 						mesh.position.x = - 100;
@@ -133,14 +133,14 @@
 						// clearcoat + normalmap
 
 						var material = new THREE.MeshPhysicalMaterial( {
-							clearCoat: 1.0,
+							clearcoat: 1.0,
 							metalness: 1.0,
 							color: 0xff0000,
 							envMap: hdrCubeRenderTarget.texture,
 							normalMap: normalMap2,
 							normalScale: new THREE.Vector2( 0.15, 0.15 ),
-							clearCoatNormalMap: clearCoatNormaMap,
-							clearCoatNormalScale: new THREE.Vector2( 2.0, 2.0 )
+							clearcoatNormalMap: clearcoatNormaMap,
+							clearcoatNormalScale: new THREE.Vector2( 2.0, 2.0 )
 						} );
 						var mesh = new THREE.Mesh( geometry, material );
 						mesh.position.x = 100;

+ 6 - 3
examples/webgl_materials_cubemap_mipmaps.html

@@ -28,12 +28,13 @@
 			init();
 			animate();
 
-			//load custmized cube texture
+			//load customized cube texture
 			async function loadCubeTextureWithMipmaps() {
 
 				var path = 'textures/cube/angus/';
 				var format = '.jpg';
 				var mipmaps = [];
+				var maxLevel = 8;
 
 				async function loadCubeTexture( urls ) {
 
@@ -53,7 +54,7 @@
 				// load mipmaps
 				var pendings = [];
 
-				for ( var level = 0; level < 9; ++ level ) {
+				for ( var level = 0; level <= maxLevel; ++ level ) {
 
 					var urls = [];
 
@@ -63,9 +64,11 @@
 
 					}
 
+					let mipmapLevel = level;
+
 					pendings.push( loadCubeTexture( urls ).then( function ( cubeTexture ) {
 
-						mipmaps.push( cubeTexture );
+						mipmaps[ mipmapLevel ] = cubeTexture;
 
 					} ) );
 

+ 4 - 47
examples/webgl_materials_envmaps_parallax.html

@@ -38,17 +38,10 @@
 			#endif
 			`;
 
-			var envmapParsReplace = `
-			#define BOX_PROJECTED_ENV_MAP
-
-			#if defined( USE_ENVMAP ) || defined( PHYSICAL )
-
-				uniform float reflectivity;
-				uniform float envMapIntensity;
-
-			#endif
+			var envmapPhysicalParsReplace = `
+			#if defined( USE_ENVMAP )
 
-			#ifdef USE_ENVMAP
+				#define BOX_PROJECTED_ENV_MAP
 
 				#ifdef BOX_PROJECTED_ENV_MAP
 
@@ -75,41 +68,10 @@
 
 				#endif
 
-				#if ! defined( PHYSICAL ) && ( defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) )
-
-					varying vec3 vWorldPosition;
-
-				#endif
-
-				#ifdef ENVMAP_TYPE_CUBE
-
-					uniform samplerCube envMap;
-
-				#else
-
-					uniform sampler2D envMap;
-
-				#endif
-
-				uniform float flipEnvMap;
-				uniform int maxMipLevel;
-
-				#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) || defined( PHYSICAL )
-
+				#ifdef ENVMAP_MODE_REFRACTION
 					uniform float refractionRatio;
-
-				#else
-
-					varying vec3 vReflect;
-
 				#endif
 
-			#endif
-			`;
-
-			var envmapPhysicalParsReplace = `
-			#if defined( USE_ENVMAP ) && defined( PHYSICAL )
-
 				vec3 getLightProbeIndirectIrradiance( const in GeometricContext geometry, const in int maxMIPLevel ) {
 					vec3 worldNormal = inverseTransformDirection( geometry.normal, viewMatrix );
 					#ifdef ENVMAP_TYPE_CUBE
@@ -349,11 +311,6 @@
 						worldposReplace
 					);
 
-					shader.fragmentShader = shader.fragmentShader.replace(
-						'#include <envmap_pars_fragment>',
-						envmapParsReplace
-					);
-
 					shader.fragmentShader = shader.fragmentShader.replace(
 						'#include <envmap_physical_pars_fragment>',
 						envmapPhysicalParsReplace

+ 20 - 20
examples/webgl_materials_nodes.html

@@ -740,9 +740,9 @@
 						//mtl.roughness = // roughness (float)
 						//mtl.metalness = // metalness (float)
 						//mtl.reflectivity = // reflectivity (float)
-						//mtl.clearCoat = // clearCoat (float)
-						//mtl.clearCoatRoughness = // clearCoatRoughness (float)
-						//mtl.clearCoatNormal = // clearCoatNormal (vec3)
+						//mtl.clearcoat = // clearcoat (float)
+						//mtl.clearcoatRoughness = // clearcoatRoughness (float)
+						//mtl.clearcoatNormal = // clearcoatNormal (vec3)
 						//mtl.normal = // normal (vec3)
 						//mtl.emissive = // emissive color (vec3)
 						//mtl.ambient = // ambient color (vec3)
@@ -755,7 +755,7 @@
 						var mask = new Nodes.SwitchNode( new Nodes.TextureNode( getTexture( "decalDiffuse" ) ), 'w' );
 
 						var normalScale = new Nodes.FloatNode( .3 );
-						var clearCoatNormalScale = new Nodes.FloatNode( .1 );
+						var clearcoatNormalScale = new Nodes.FloatNode( .1 );
 
 						var roughnessA = new Nodes.FloatNode( .5 );
 						var metalnessA = new Nodes.FloatNode( .5 );
@@ -764,8 +764,8 @@
 						var metalnessB = new Nodes.FloatNode( 1 );
 
 						var reflectivity = new Nodes.FloatNode( 0 );
-						var clearCoat = new Nodes.FloatNode( 1 );
-						var clearCoatRoughness = new Nodes.FloatNode( 1 );
+						var clearcoat = new Nodes.FloatNode( 1 );
+						var clearcoatRoughness = new Nodes.FloatNode( 1 );
 
 						var roughness = new Nodes.MathNode(
 							roughnessA,
@@ -787,9 +787,9 @@
 							Nodes.OperatorNode.MUL
 						);
 
-						var clearCoatNormalMask = new Nodes.OperatorNode(
+						var clearcoatNormalMask = new Nodes.OperatorNode(
 							mask,
-							clearCoatNormalScale,
+							clearcoatNormalScale,
 							Nodes.OperatorNode.MUL
 						);
 
@@ -797,10 +797,10 @@
 						mtl.roughness = roughness;
 						mtl.metalness = metalness;
 						mtl.reflectivity = reflectivity;
-						mtl.clearCoat = clearCoat;
-						mtl.clearCoatRoughness = clearCoatRoughness;
-						mtl.clearCoatNormal = new Nodes.NormalMapNode( new Nodes.TextureNode( getTexture( "grassNormal" ) ) );
-						mtl.clearCoatNormal.scale = clearCoatNormalMask;
+						mtl.clearcoat = clearcoat;
+						mtl.clearcoatRoughness = clearcoatRoughness;
+						mtl.clearcoatNormal = new Nodes.NormalMapNode( new Nodes.TextureNode( getTexture( "grassNormal" ) ) );
+						mtl.clearcoatNormal.scale = clearcoatNormalMask;
 						mtl.environment = new Nodes.CubeTextureNode( cubemap );
 						mtl.normal = new Nodes.NormalMapNode( new Nodes.TextureNode( getTexture( "grassNormal" ) ) );
 						mtl.normal.scale = normalMask;
@@ -819,21 +819,21 @@
 
 						}, false, 0, 1 );
 
-						addGui( 'clearCoat', clearCoat.value, function ( val ) {
+						addGui( 'clearcoat', clearcoat.value, function ( val ) {
 
-							clearCoat.value = val;
+							clearcoat.value = val;
 
 						}, false, 0, 1 );
 
-						addGui( 'clearCoatRoughness', clearCoatRoughness.value, function ( val ) {
+						addGui( 'clearcoatRoughness', clearcoatRoughness.value, function ( val ) {
 
-							clearCoatRoughness.value = val;
+							clearcoatRoughness.value = val;
 
 						}, false, 0, 1 );
 
-						addGui( 'clearCoatNormalScale', clearCoatNormalScale.value, function ( val ) {
+						addGui( 'clearcoatNormalScale', clearcoatNormalScale.value, function ( val ) {
 
-							clearCoatNormalScale.value = val;
+							clearcoatNormalScale.value = val;
 
 						}, false, 0, 1 );
 
@@ -2236,8 +2236,8 @@
 							mtl.metalness = new Nodes.FloatNode( 0 );
 							mtl.roughness = new Nodes.FloatNode( 1 );
 							mtl.reflectivity = new Nodes.FloatNode( 0 );
-							mtl.clearCoat = new Nodes.FloatNode( .2 );
-							mtl.clearCoatRoughness = new Nodes.FloatNode( .3 );
+							mtl.clearcoat = new Nodes.FloatNode( .2 );
+							mtl.clearcoatRoughness = new Nodes.FloatNode( .3 );
 							mtl.environment = new Nodes.CubeTextureNode( cubemap );
 
 						} else {

+ 203 - 0
examples/webgl_materials_sheen.html

@@ -0,0 +1,203 @@
+<html lang="en">
+	<head>
+		<title>Sheen demo (material property)</title>
+		<meta charset="utf-8">
+		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
+		<link type="text/css" rel="stylesheet" href="main.css">
+		<style>
+			body {
+				color: #333;
+			}
+		</style>
+	</head>
+	<body>
+		<div id="info">Sheen demo by <a href="https://github.com/DanielSturk">DanielSturk</a></div>
+		<div id="container"></div>
+
+		<script src="js/libs/ammo.js"></script>
+
+		<script type="module">
+
+			import * as THREE from '../build/three.module.js';
+
+			import * as Nodes from './jsm/nodes/Nodes.js';
+
+			import Stats from './jsm/libs/stats.module.js';
+			import { GUI } from './jsm/libs/dat.gui.module.js';
+
+			import { OrbitControls } from './jsm/controls/OrbitControls.js';
+
+			import { FBXLoader } from './jsm/loaders/FBXLoader.js';
+
+			// Graphics variables
+			var camera, controls, scene, renderer, stats;
+			var directionalLight;
+			var mesh, sphere, material, nodeMaterial;
+
+			var params = {
+				nodeMaterial: true,
+				color: new THREE.Color( 255, 0, 127 ),
+				sheenBRDF: true,
+				sheen: new THREE.Color( 10, 10, 10 ), // corresponds to .04 reflectance
+				roughness: .9,
+				exposure: 2,
+			};
+
+			// model
+			new FBXLoader().load( 'models/fbx/cloth.fbx', function ( loadedModel ) {
+
+				mesh = loadedModel.children[0];
+
+				init();
+
+			} );
+
+			function init( ) {
+
+				camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 0.2, 2000 );
+
+				scene = new THREE.Scene();
+				scene.background = new THREE.Color( 0xbfd1e5 );
+
+				mesh.scale.multiplyScalar( .5 );
+				scene.add( mesh );
+
+				//
+
+				material = new THREE.MeshPhysicalMaterial();
+				material.side = THREE.DoubleSide;
+				material.metalness = 0;
+
+				//
+
+				nodeMaterial = new Nodes.StandardNodeMaterial();
+				nodeMaterial.side = THREE.DoubleSide;
+				nodeMaterial.metalness = new Nodes.FloatNode( 0 );
+				nodeMaterial.roughness = new Nodes.FloatNode();
+				nodeMaterial.color = new Nodes.ColorNode( params.color.clone() );
+
+				//
+
+				sphere = new THREE.Mesh(
+					new THREE.SphereBufferGeometry( 1, 100, 100 ),
+					material
+				);
+				scene.add(sphere);
+
+				camera.position.set( - 12, 7, 4 );
+
+				var container = document.getElementById( 'container' );
+				renderer = new THREE.WebGLRenderer();
+				renderer.setPixelRatio( window.devicePixelRatio );
+				renderer.setSize( window.innerWidth, window.innerHeight );
+				renderer.shadowMap.enabled = true;
+				container.appendChild( renderer.domElement );
+
+				controls = new OrbitControls( camera, renderer.domElement );
+				controls.target.set( 0, 2, 0 );
+				controls.update();
+
+				directionalLight = new THREE.DirectionalLight( 0xffffff, .5 );
+				directionalLight.position.set( 0, 10, 0 );
+				directionalLight.castShadow = true;
+				directionalLight.add(
+					new THREE.Mesh(
+						new THREE.SphereBufferGeometry( .5 ),
+						new THREE.MeshBasicMaterial( { color: 0xffffff } )
+					)
+				);
+
+				scene.add( directionalLight );
+
+				stats = new Stats();
+				stats.domElement.style.position = 'absolute';
+				stats.domElement.style.top = '0px';
+				container.appendChild( stats.dom );
+
+				window.addEventListener( 'resize', onWindowResize, false );
+
+				var gui = new GUI();
+
+				function onUpdate() {
+
+					mesh.material = sphere.material = params.nodeMaterial
+					? nodeMaterial
+					: material;
+
+					material.sheen = params.sheenBRDF
+					? new THREE.Color()
+					: null;
+
+					material.needsUpdate = true;
+
+					nodeMaterial.sheen = params.sheenBRDF
+					? new Nodes.ColorNode( material.sheen )
+					: undefined;
+
+					nodeMaterial.needsCompile = true;
+
+				}
+
+				gui.add( params, 'nodeMaterial' ).onChange( onUpdate );
+				gui.addColor( params, 'color' );
+				gui.add( params, 'sheenBRDF' ).onChange( onUpdate );
+				gui.addColor( params, 'sheen' );
+				gui.add( params, 'roughness', 0, 1 );
+				gui.add( params, 'exposure', 0, 3 );
+				gui.open();
+
+				onUpdate();
+
+				animate();
+
+			}
+
+			function onWindowResize() {
+
+				camera.aspect = window.innerWidth / window.innerHeight;
+				camera.updateProjectionMatrix();
+
+				renderer.setSize( window.innerWidth, window.innerHeight );
+
+			}
+
+			function animate() {
+
+				requestAnimationFrame( animate );
+
+				render();
+				stats.update();
+
+			}
+
+			function render() {
+
+				//
+
+				material.color.copy( params.color ).multiplyScalar( 1 / 255 );
+				material.roughness = params.roughness;
+
+				//
+
+				nodeMaterial.color.value.copy( material.color );
+				nodeMaterial.roughness.value = params.roughness;
+
+				//
+
+				if ( params.sheenBRDF ) {
+
+					material.sheen.copy( params.sheen ).multiplyScalar( 1 / 255 );
+
+				}
+
+				//
+
+				renderer.toneMappingExposure = params.exposure;
+				renderer.render( scene, camera );
+
+			}
+
+		</script>
+
+	</body>
+</html>

+ 160 - 85
examples/webgl_materials_transparency.html

@@ -9,7 +9,7 @@
 	<body>
 
 		<div id="container"></div>
-		<div id="info"><a href="http://threejs.org" target="_blank" rel="noopener">threejs</a> - Transparency with Premultiplied Alpha (right) and without (left)<br /> using RGBA8 Buffers by <a href="http://clara.io/" target="_blank" rel="noopener">Ben Houston</a>.</div>
+		<div id="info"><a href="http://threejs.org" target="_blank" rel="noopener">threejs</a> - Transparency with Premultiplied Alpha (right) and without (left)</div>
 
 		<script type="module">
 
@@ -19,120 +19,195 @@
 
 			import { GUI } from './jsm/libs/dat.gui.module.js';
 			import { OrbitControls } from './jsm/controls/OrbitControls.js';
-
-			var params = { opacity: 0.25 };
+			import { HDRCubeTextureLoader } from './jsm/loaders/HDRCubeTextureLoader.js';
+			import { PMREMGenerator } from './jsm/pmrem/PMREMGenerator.js';
+			import { PMREMCubeUVPacker } from './jsm/pmrem/PMREMCubeUVPacker.js';
+
+			var params = {
+				color: 0xffffff,
+				transparency: 0.90,
+				envMapIntensity: 1,
+				lightIntensity: 1,
+				exposure: 1
+			};
 
 			var container, stats;
 			var camera, scene, renderer;
 
-			init();
-			animate();
+			var hdrCubeRenderTarget;
+			var spotLight1, spotLight2;
+			var mesh1, mesh2;
+
+			var hdrUrls = [ 'px.hdr', 'nx.hdr', 'py.hdr', 'ny.hdr', 'pz.hdr', 'nz.hdr' ];
+
+			var hdrCubeMap = new HDRCubeTextureLoader()
+				.setPath( './textures/cube/pisaHDR/' )
+				.setDataType( THREE.UnsignedByteType )
+				.load( hdrUrls, function () {
+
+					init();
+					animate();
+
+				} );
 
 			function init() {
 
 				container = document.createElement( 'div' );
 				document.body.appendChild( container );
 
-				camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 1, 2000 );
-				camera.position.set( 0.0, 40, 40 * 3.5 );
+				renderer = new THREE.WebGLRenderer( { antialias: true } );
+				renderer.setPixelRatio( window.devicePixelRatio );
+				renderer.setSize( window.innerWidth, window.innerHeight );
+				renderer.shadowMap.enabled = true;
+				container.appendChild( renderer.domElement );
+
+				renderer.toneMapping = THREE.ACESFilmicToneMapping;
+				renderer.toneMappingExposure = params.exposure;
+
+				renderer.gammaOutput = true;
 
 				scene = new THREE.Scene();
+				scene.background = hdrCubeMap;
+
+				camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 1, 2000 );
+				camera.position.set( 0, 0, 120 );
 
 				//
 
-				var geometry = new THREE.SphereBufferGeometry( 18, 30, 30 );
+				var pmremGenerator = new PMREMGenerator( hdrCubeMap );
+				pmremGenerator.update( renderer );
 
-				var material1 = new THREE.MeshStandardMaterial( {
-					opacity: params.opacity,
-					transparent: true
-				} );
+				var pmremCubeUVPacker = new PMREMCubeUVPacker( pmremGenerator.cubeLods );
+				pmremCubeUVPacker.update( renderer );
 
-				var material2 = new THREE.MeshStandardMaterial( {
-					opacity: params.opacity,
-					premultipliedAlpha: true,
-					transparent: true
-				} );
+				hdrCubeRenderTarget = pmremCubeUVPacker.CubeUVRenderTarget;
 
-				var textureLoader = new THREE.TextureLoader();
-				textureLoader.load( "textures/hardwood2_diffuse.jpg", function ( map ) {
+				hdrCubeMap.magFilter = THREE.LinearFilter;
+				hdrCubeMap.needsUpdate = true;
 
-					map.anisotropy = 8;
+				pmremGenerator.dispose();
+				pmremCubeUVPacker.dispose();
 
-					material1.map = map;
-					material1.needsUpdate = true;
-					material2.map = map;
-					material2.needsUpdate = true;
+				//
 
+				var geometry = new THREE.SphereBufferGeometry( 20, 64, 32 );
+
+				var texture = new THREE.CanvasTexture( generateTexture() );
+				texture.magFilter = THREE.NearestFilter;
+				texture.wrapT = THREE.RepeatWrapping;
+				texture.wrapS = THREE.RepeatWrapping;
+				texture.repeat.set( 1, 3.5 );
+
+				var material = new THREE.MeshPhysicalMaterial( {
+					color: params.color,
+					metalness: 0,
+					roughness: 0,
+					alphaMap: texture,
+					alphaTest: 0.5,
+					envMap: hdrCubeRenderTarget.texture,
+					envMapIntensity: params.envMapIntensity,
+					depthTest: false,
+					transparency: params.transparency,
+					transparent: true
 				} );
 
-				var textureLoader = new THREE.TextureLoader();
-				textureLoader.load( "textures/hardwood2_roughness.jpg", function ( map ) {
+				var material1 = new THREE.MeshPhysicalMaterial().copy( material );
 
-					map.anisotropy = 8;
+				var material1b = new THREE.MeshPhysicalMaterial().copy( material );
+				material1b.side = THREE.BackSide;
 
-					material1.roughnessMap = map;
-					material1.needsUpdate = true;
-					material2.roughnessMap = map;
-					material2.needsUpdate = true;
+				var material2 = new THREE.MeshPhysicalMaterial().copy( material );
+				material2.premultipliedAlpha = true;
 
-				} );
+				var material2b = new THREE.MeshPhysicalMaterial().copy( material );
+				material2b.premultipliedAlpha = true;
+				material2b.side = THREE.BackSide;
 
-				var mesh = new THREE.Mesh( geometry, material1 );
-				mesh.position.x = - 25.0;
-				scene.add( mesh );
+				mesh1 = new THREE.Mesh( geometry, material1 );
+				mesh1.position.x = - 30.0;
+				scene.add( mesh1 );
 
-				var mesh = new THREE.Mesh( geometry, material2 );
-				mesh.position.x = 25.0;
-				scene.add( mesh );
+				var mesh = new THREE.Mesh( geometry, material1b );
+				mesh.renderOrder = - 1;
+				mesh1.add( mesh );
 
-				//
+				mesh2 = new THREE.Mesh( geometry, material2 );
+				mesh2.position.x = 30.0;
+				scene.add( mesh2 );
 
-				var geometry = new THREE.PlaneBufferGeometry( 800, 800 );
-				var material = new THREE.MeshStandardMaterial( { color: 0x333333 } );
-				var mesh = new THREE.Mesh( geometry, material );
-				mesh.position.y = - 50;
-				mesh.rotation.x = - Math.PI * 0.5;
-				scene.add( mesh );
+				var mesh = new THREE.Mesh( geometry, material2b );
+				mesh.renderOrder = - 1;
+				mesh2.add( mesh );
 
-				// Lights
+				//
 
-				var spotLight = new THREE.SpotLight( 0xff8888 );
-				spotLight.position.set( 100, 200, 100 );
-				spotLight.angle = Math.PI / 6;
-				spotLight.penumbra = 0.9;
-				scene.add( spotLight );
+				spotLight1 = new THREE.SpotLight( 0xffffff, params.lightIntensity );
+				spotLight1.position.set( 100, 200, 100 );
+				spotLight1.angle = Math.PI / 6;
+				scene.add( spotLight1 );
 
-				var spotLight = new THREE.SpotLight( 0x8888ff );
-				spotLight.position.set( - 100, - 200, - 100 );
-				spotLight.angle = Math.PI / 6;
-				spotLight.penumbra = 0.9;
-				scene.add( spotLight );
+				spotLight2 = new THREE.SpotLight( 0xffffff, params.lightIntensity );
+				spotLight2.position.set( - 100, - 200, - 100 );
+				spotLight2.angle = Math.PI / 6;
+				scene.add( spotLight2 );
 
 				//
 
-				renderer = new THREE.WebGLRenderer( { antialias: true } );
-				renderer.setPixelRatio( window.devicePixelRatio );
-				renderer.setSize( window.innerWidth, window.innerHeight );
-				renderer.shadowMap.enabled = true;
-				container.appendChild( renderer.domElement );
-
-				renderer.gammaInput = true;
-				renderer.gammaOutput = true;
-
 				stats = new Stats();
 				container.appendChild( stats.dom );
 
 				var controls = new OrbitControls( camera, renderer.domElement );
+				controls.minDistance = 10;
+				controls.maxDistance = 150;
 
 				window.addEventListener( 'resize', onWindowResize, false );
 
+				//
+
 				var gui = new GUI();
-				gui.add( params, 'opacity', 0, 1 ).onChange( function () {
 
-					material1.opacity = params.opacity;
-					material2.opacity = params.opacity;
+				gui.addColor( params, 'color' )
+					.onChange( function () {
+
+						material1.color.set( params.color );
+						material2.color.set( params.color );
+						material1b.color.set( params.color );
+						material2b.color.set( params.color );
+
+					} );
+
+				gui.add( params, 'transparency', 0, 1 )
+					.onChange( function () {
+
+						material1.transparency = material2.transparency = params.transparency;
+						material1b.transparency = material2b.transparency = params.transparency;
+
+					} );
+
+				gui.add( params, 'envMapIntensity', 0, 1 )
+					.name( 'envMap intensity' )
+					.onChange( function () {
+
+						material1.envMapIntensity = material2.envMapIntensity = params.envMapIntensity;
+						material1b.envMapIntensity = material2b.envMapIntensity = params.envMapIntensity;
+
+					} );
+
+				gui.add( params, 'lightIntensity', 0, 1 )
+					.name( 'light intensity' )
+					.onChange( function () {
+
+						spotLight1.intensity = spotLight2.intensity = params.lightIntensity;
+
+					} );
+
+				gui.add( params, 'exposure', 0, 1 )
+					.onChange( function () {
+
+						renderer.toneMappingExposure = params.exposure;
+
+					} );
 
-				} );
 				gui.open();
 
 			}
@@ -151,32 +226,32 @@
 
 			//
 
-			function animate() {
+			function generateTexture() {
 
-				requestAnimationFrame( animate );
+				var canvas = document.createElement( 'canvas' );
+				canvas.width = 2;
+				canvas.height = 2;
 
-				stats.begin();
-				render();
-				stats.end();
+				var context = canvas.getContext( '2d' );
+				context.fillStyle = 'white';
+				context.fillRect( 0, 1, 2, 1 );
 
-			}
+				return canvas;
 
-			function render() {
-
-				for ( var i = 0, l = scene.children.length; i < l; i ++ ) {
-
-					var object = scene.children[ i ];
+			}
 
-					if ( object.geometry instanceof THREE.SphereBufferGeometry ) {
+			function animate() {
 
-						object.rotation.x = performance.now() * 0.0002;
-						object.rotation.y = - performance.now() * 0.0002;
+				requestAnimationFrame( animate );
 
-					}
+				var t = performance.now();
 
-				}
+				mesh1.rotation.x = mesh2.rotation.x = t * 0.0002;
+				mesh1.rotation.z = mesh2.rotation.z = - t * 0.0002;
 
+				stats.begin();
 				renderer.render( scene, camera );
+				stats.end();
 
 			}
 

+ 6 - 6
examples/webgl_materials_variations_physical.html

@@ -96,8 +96,8 @@
 										color: diffuseColor,
 										metalness: 0,
 										roughness: 0.5,
-										clearCoat: 1.0 - alpha,
-										clearCoatRoughness: 1.0 - beta,
+										clearcoat: 1.0 - alpha,
+										clearcoatRoughness: 1.0 - beta,
 										reflectivity: 1.0 - gamma,
 										envMap: ( index % 2 ) == 1 ? hdrCubeRenderTarget.texture : null
 									} );
@@ -148,11 +148,11 @@
 
 				}
 
-				addLabel( "+clearCoat", new THREE.Vector3( - 350, 0, 0 ) );
-				addLabel( "-clearCoat", new THREE.Vector3( 350, 0, 0 ) );
+				addLabel( "+clearcoat", new THREE.Vector3( - 350, 0, 0 ) );
+				addLabel( "-clearcoat", new THREE.Vector3( 350, 0, 0 ) );
 
-				addLabel( "+clearCoatRoughness", new THREE.Vector3( 0, - 300, 0 ) );
-				addLabel( "-clearCoatRoughness", new THREE.Vector3( 0, 300, 0 ) );
+				addLabel( "+clearcoatRoughness", new THREE.Vector3( 0, - 300, 0 ) );
+				addLabel( "-clearcoatRoughness", new THREE.Vector3( 0, 300, 0 ) );
 
 				addLabel( "+reflectivity", new THREE.Vector3( 0, 0, - 300 ) );
 				addLabel( "-reflectivity", new THREE.Vector3( 0, 0, 300 ) );

+ 3 - 3
examples/webgl_shadowmap.html

@@ -79,13 +79,13 @@
 				var ambient = new THREE.AmbientLight( 0x444444 );
 				scene.add( ambient );
 
-				light = new THREE.SpotLight( 0xffffff, 1, 0, Math.PI / 2 );
+				light = new THREE.SpotLight( 0xffffff, 1, 0, Math.PI / 5, 0.3 );
 				light.position.set( 0, 1500, 1000 );
 				light.target.position.set( 0, 0, 0 );
 
 				light.castShadow = true;
-
-				light.shadow = new THREE.LightShadow( new THREE.PerspectiveCamera( 50, 1, 1200, 2500 ) );
+				light.shadow.camera.near = 1200;
+				light.shadow.camera.far = 2500;
 				light.shadow.bias = 0.0001;
 
 				light.shadow.mapSize.width = SHADOW_MAP_WIDTH;

+ 3 - 4
examples/webgl_shadowmap_performance.html

@@ -76,14 +76,13 @@
 				var ambient = new THREE.AmbientLight( 0x444444 );
 				scene.add( ambient );
 
-				light = new THREE.SpotLight( 0xffffff, 1, 0, Math.PI / 2 );
+				light = new THREE.SpotLight( 0xffffff, 1, 0, Math.PI / 5, 0.3 );
 				light.position.set( 0, 1500, 1000 );
 				light.target.position.set( 0, 0, 0 );
 
 				light.castShadow = true;
-
-				light.shadow = new THREE.LightShadow( new THREE.PerspectiveCamera( 50, 1, 700, FAR ) );
-
+				light.shadow.camera.near = 1200;
+				light.shadow.camera.far = 2500;
 				light.shadow.bias = 0.0001;
 
 				light.shadow.mapSize.width = SHADOW_MAP_WIDTH;

+ 73 - 62
package-lock.json

@@ -114,15 +114,15 @@
       }
     },
     "acorn": {
-      "version": "6.1.1",
-      "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.1.1.tgz",
-      "integrity": "sha512-jPTiwtOxaHNaAPg/dmrJ/beuzLRnXtB0kQPQ8JpotKJgTB6rX6c8mlf315941pyjBSaPg8NHXS9fhP4u17DpGA==",
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.0.0.tgz",
+      "integrity": "sha512-PaF/MduxijYYt7unVGRuds1vBC9bFxbNf+VWqhOClfdgy7RlVkQqt610ig1/yxTgsDIfW1cWDel5EBbOy3jdtQ==",
       "dev": true
     },
     "acorn-jsx": {
-      "version": "5.0.1",
-      "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.0.1.tgz",
-      "integrity": "sha512-HJ7CfNHrfJLlNTzIEUTj43LNWGkqpRLxm3YjAlcD0ACydk9XynzYsCBHxut+iqt+1aBXkx9UP/w/ZqMr13XIzg==",
+      "version": "5.0.2",
+      "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.0.2.tgz",
+      "integrity": "sha512-tiNTrP1MP0QrChmD2DdupCr6HWSFeKVw5d/dHTu4Y7rkAkRhU/Dt7dphAfIUyxtHpl/eBVip5uTNSpQJHylpAw==",
       "dev": true
     },
     "ajv": {
@@ -359,20 +359,20 @@
       "dev": true
     },
     "concurrently": {
-      "version": "4.1.1",
-      "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-4.1.1.tgz",
-      "integrity": "sha512-48+FE5RJ0qc8azwKv4keVQWlni1hZeSjcWr8shBelOBtBHcKj1aJFM9lHRiSc1x7lq416pkvsqfBMhSRja+Lhw==",
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-4.1.2.tgz",
+      "integrity": "sha512-Kim9SFrNr2jd8/0yNYqDTFALzUX1tvimmwFWxmp/D4mRI+kbqIIwE2RkBDrxS2ic25O1UgQMI5AtBqdtX3ynYg==",
       "dev": true,
       "requires": {
-        "chalk": "^2.4.1",
-        "date-fns": "^1.23.0",
-        "lodash": "^4.17.10",
+        "chalk": "^2.4.2",
+        "date-fns": "^1.30.1",
+        "lodash": "^4.17.15",
         "read-pkg": "^4.0.1",
-        "rxjs": "^6.3.3",
+        "rxjs": "^6.5.2",
         "spawn-command": "^0.0.2-1",
         "supports-color": "^4.5.0",
-        "tree-kill": "^1.1.0",
-        "yargs": "^12.0.1"
+        "tree-kill": "^1.2.1",
+        "yargs": "^12.0.5"
       }
     },
     "core-util-is": {
@@ -528,9 +528,9 @@
       "dev": true
     },
     "eslint": {
-      "version": "6.1.0",
-      "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.1.0.tgz",
-      "integrity": "sha512-QhrbdRD7ofuV09IuE2ySWBz0FyXCq0rriLTZXZqaWSI79CVtHVRdkFuFTViiqzZhkCgfOh9USpriuGN2gIpZDQ==",
+      "version": "6.2.1",
+      "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.2.1.tgz",
+      "integrity": "sha512-ES7BzEzr0Q6m5TK9i+/iTpKjclXitOdDK4vT07OqbkBT2/VcN/gO9EL1C4HlK3TAOXYv2ItcmbVR9jO1MR0fJg==",
       "dev": true,
       "requires": {
         "@babel/code-frame": "^7.0.0",
@@ -540,9 +540,9 @@
         "debug": "^4.0.1",
         "doctrine": "^3.0.0",
         "eslint-scope": "^5.0.0",
-        "eslint-utils": "^1.3.1",
-        "eslint-visitor-keys": "^1.0.0",
-        "espree": "^6.0.0",
+        "eslint-utils": "^1.4.2",
+        "eslint-visitor-keys": "^1.1.0",
+        "espree": "^6.1.0",
         "esquery": "^1.0.1",
         "esutils": "^2.0.2",
         "file-entry-cache": "^5.0.1",
@@ -588,6 +588,12 @@
             "estraverse": "^4.1.1"
           }
         },
+        "eslint-visitor-keys": {
+          "version": "1.1.0",
+          "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz",
+          "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==",
+          "dev": true
+        },
         "semver": {
           "version": "6.3.0",
           "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
@@ -631,10 +637,13 @@
       }
     },
     "eslint-utils": {
-      "version": "1.3.1",
-      "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.3.1.tgz",
-      "integrity": "sha512-Z7YjnIldX+2XMcjr7ZkgEsOj/bREONV60qYeB/bjMAqqqZ4zxKyWX+BOUkdmRmA9riiIPVvo5x86m5elviOk0Q==",
-      "dev": true
+      "version": "1.4.2",
+      "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.2.tgz",
+      "integrity": "sha512-eAZS2sEUMlIeCjBeubdj45dmBHQwPHWyBcT1VSYB7o9x9WRRqKxyUoiXlRjyAwzN7YEzHJlYg0NmzDRWx6GP4Q==",
+      "dev": true,
+      "requires": {
+        "eslint-visitor-keys": "^1.0.0"
+      }
     },
     "eslint-visitor-keys": {
       "version": "1.0.0",
@@ -643,14 +652,22 @@
       "dev": true
     },
     "espree": {
-      "version": "6.0.0",
-      "resolved": "https://registry.npmjs.org/espree/-/espree-6.0.0.tgz",
-      "integrity": "sha512-lJvCS6YbCn3ImT3yKkPe0+tJ+mH6ljhGNjHQH9mRtiO6gjhVAOhVXW1yjnwqGwTkK3bGbye+hb00nFNmu0l/1Q==",
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/espree/-/espree-6.1.0.tgz",
+      "integrity": "sha512-boA7CHRLlVWUSg3iL5Kmlt/xT3Q+sXnKoRYYzj1YeM10A76TEJBbotV5pKbnK42hEUIr121zTv+QLRM5LsCPXQ==",
       "dev": true,
       "requires": {
-        "acorn": "^6.0.7",
+        "acorn": "^7.0.0",
         "acorn-jsx": "^5.0.0",
-        "eslint-visitor-keys": "^1.0.0"
+        "eslint-visitor-keys": "^1.1.0"
+      },
+      "dependencies": {
+        "eslint-visitor-keys": {
+          "version": "1.1.0",
+          "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz",
+          "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==",
+          "dev": true
+        }
       }
     },
     "esprima": {
@@ -939,9 +956,9 @@
       "dev": true
     },
     "hosted-git-info": {
-      "version": "2.7.1",
-      "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz",
-      "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==",
+      "version": "2.8.4",
+      "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.4.tgz",
+      "integrity": "sha512-pzXIvANXEFrc5oFFXRMkbLPQ2rXRoDERwDLyrcUxGhaZhgP54BBSl9Oheh7Vv0T090cszWBxPjkQQ5Sq1PbBRQ==",
       "dev": true
     },
     "htmlparser2": {
@@ -1065,12 +1082,6 @@
           "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
           "dev": true
         },
-        "lodash": {
-          "version": "4.17.15",
-          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
-          "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
-          "dev": true
-        },
         "string-width": {
           "version": "4.1.0",
           "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.1.0.tgz",
@@ -1220,9 +1231,9 @@
       }
     },
     "lodash": {
-      "version": "4.17.14",
-      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.14.tgz",
-      "integrity": "sha512-mmKYbW3GLuJeX+iGP+Y7Gp1AiGHGbXHCOh/jZmrawMmsE7MS4znI3RL2FsjbqOyMayHInjOeykW7PEajUk1/xw==",
+      "version": "4.17.15",
+      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
+      "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
       "dev": true
     },
     "lodash.unescape": {
@@ -1413,7 +1424,7 @@
     },
     "os-tmpdir": {
       "version": "1.0.2",
-      "resolved": "http://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
+      "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
       "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
       "dev": true
     },
@@ -1436,9 +1447,9 @@
       "dev": true
     },
     "p-limit": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz",
-      "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==",
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz",
+      "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==",
       "dev": true,
       "requires": {
         "p-try": "^2.0.0"
@@ -1486,7 +1497,7 @@
     },
     "path-is-absolute": {
       "version": "1.0.1",
-      "resolved": "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+      "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
       "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
       "dev": true
     },
@@ -1659,9 +1670,9 @@
       "dev": true
     },
     "resolve": {
-      "version": "1.11.1",
-      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.11.1.tgz",
-      "integrity": "sha512-vIpgF6wfuJOZI7KKKSP+HmiKggadPQAdsp5HiC1mvqnfp0gF1vdwgBWZIdrVft9pgqoMFQN+R7BSWZiBxx+BBw==",
+      "version": "1.12.0",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz",
+      "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==",
       "dev": true,
       "requires": {
         "path-parse": "^1.0.6"
@@ -1742,9 +1753,9 @@
       "dev": true
     },
     "semver": {
-      "version": "5.5.0",
-      "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz",
-      "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==",
+      "version": "5.7.1",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+      "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
       "dev": true
     },
     "set-blocking": {
@@ -1816,7 +1827,7 @@
     "spdx-expression-parse": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz",
-      "integrity": "sha1-meEZt6XaAOBUkcn6M4t5BII7QdA=",
+      "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==",
       "dev": true,
       "requires": {
         "spdx-exceptions": "^2.1.0",
@@ -1824,9 +1835,9 @@
       }
     },
     "spdx-license-ids": {
-      "version": "3.0.4",
-      "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.4.tgz",
-      "integrity": "sha512-7j8LYJLeY/Yb6ACbQ7F76qy5jHkp0U6jgBfJsk97bwWlVUnUWsAgpyaCvo17h0/RQGnQ036tVDomiwoI4pDkQA==",
+      "version": "3.0.5",
+      "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz",
+      "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==",
       "dev": true
     },
     "sprintf-js": {
@@ -1946,7 +1957,7 @@
     },
     "through": {
       "version": "2.3.8",
-      "resolved": "http://registry.npmjs.org/through/-/through-2.3.8.tgz",
+      "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
       "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
       "dev": true
     },
@@ -1996,9 +2007,9 @@
       "dev": true
     },
     "typescript": {
-      "version": "3.5.2",
-      "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.5.2.tgz",
-      "integrity": "sha512-7KxJovlYhTX5RaRbUdkAXN1KUZ8PwWlTzQdHV6xNqvuFOs7+WBo10TQUqT19Q/Jz2hk5v9TQDIhyLhhJY4p5AA==",
+      "version": "3.5.3",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.5.3.tgz",
+      "integrity": "sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g==",
       "dev": true
     },
     "union": {
@@ -2093,7 +2104,7 @@
     },
     "wrap-ansi": {
       "version": "2.1.0",
-      "resolved": "http://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
       "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=",
       "dev": true,
       "requires": {

+ 3 - 3
package.json

@@ -69,8 +69,8 @@
   "devDependencies": {
     "@typescript-eslint/eslint-plugin": "^2.0.0",
     "@typescript-eslint/parser": "^2.0.0",
-    "concurrently": "^4.1.1",
-    "eslint": "^6.1.0",
+    "concurrently": "^4.1.2",
+    "eslint": "^6.2.1",
     "eslint-config-mdcs": "^4.2.3",
     "eslint-plugin-html": "^6.0.0",
     "failonlyreporter": "^1.0.0",
@@ -78,7 +78,7 @@
     "http-server": "^0.11.1",
     "qunit": "^2.9.2",
     "rollup": "^1.19.4",
-    "typescript": "^3.5.2"
+    "typescript": "^3.5.3"
   },
   "jspm": {
     "files": [

+ 10 - 2
src/lights/DirectionalLightShadow.js

@@ -5,7 +5,7 @@ import { OrthographicCamera } from '../cameras/OrthographicCamera.js';
  * @author mrdoob / http://mrdoob.com/
  */
 
-function DirectionalLightShadow( ) {
+function DirectionalLightShadow() {
 
 	LightShadow.call( this, new OrthographicCamera( - 5, 5, 5, - 5, 0.5, 500 ) );
 
@@ -13,7 +13,15 @@ function DirectionalLightShadow( ) {
 
 DirectionalLightShadow.prototype = Object.assign( Object.create( LightShadow.prototype ), {
 
-	constructor: DirectionalLightShadow
+	constructor: DirectionalLightShadow,
+
+	isDirectionalLightShadow: true,
+
+	updateMatrices: function ( light, viewCamera, viewportIndex ) {
+
+		LightShadow.prototype.updateMatrices.call( this, light, viewCamera, viewportIndex );
+
+	}
 
 } );
 

+ 6 - 0
src/lights/LightShadow.d.ts

@@ -1,5 +1,7 @@
 import { Camera } from './../cameras/Camera';
+import { Light } from './../lights/Light';
 import { Vector2 } from './../math/Vector2';
+import { Vector4 } from './../math/Vector4';
 import { Matrix4 } from './../math/Matrix4';
 import { RenderTarget } from '../renderers/webgl/WebGLRenderLists';
 
@@ -17,5 +19,9 @@ export class LightShadow {
 	copy( source: LightShadow ): this;
 	clone( recursive?: boolean ): this;
 	toJSON(): any;
+	getFrustum(): number;
+	updateMatrices( light: Light, viewCamera: Camera, viewportIndex: number ): void;
+	getViewport( viewportIndex: number ): Vector4;
+	getFrameExtents(): Vector2;
 
 }

+ 74 - 0
src/lights/LightShadow.js

@@ -1,5 +1,8 @@
 import { Matrix4 } from '../math/Matrix4.js';
 import { Vector2 } from '../math/Vector2.js';
+import { Vector3 } from '../math/Vector3.js';
+import { Vector4 } from '../math/Vector4.js';
+import { Frustum } from '../math/Frustum.js';
 
 /**
  * @author mrdoob / http://mrdoob.com/
@@ -17,10 +20,81 @@ function LightShadow( camera ) {
 	this.map = null;
 	this.matrix = new Matrix4();
 
+	this._frustum = new Frustum();
+	this._frameExtents = new Vector2( 1, 1 );
+
+	this._viewportCount = 1;
+
+	this._viewports = [
+
+		new Vector4( 0, 0, 1, 1 )
+
+	];
+
 }
 
 Object.assign( LightShadow.prototype, {
 
+	_projScreenMatrix: new Matrix4(),
+
+	_lightPositionWorld: new Vector3(),
+
+	_lookTarget: new Vector3(),
+
+	getViewportCount: function () {
+
+		return this._viewportCount;
+
+	},
+
+	getFrustum: function () {
+
+		return this._frustum;
+
+	},
+
+	updateMatrices: function ( light ) {
+
+		var shadowCamera = this.camera,
+			shadowMatrix = this.matrix,
+			projScreenMatrix = this._projScreenMatrix,
+			lookTarget = this._lookTarget,
+			lightPositionWorld = this._lightPositionWorld;
+
+		lightPositionWorld.setFromMatrixPosition( light.matrixWorld );
+		shadowCamera.position.copy( lightPositionWorld );
+
+		lookTarget.setFromMatrixPosition( light.target.matrixWorld );
+		shadowCamera.lookAt( lookTarget );
+		shadowCamera.updateMatrixWorld();
+
+		projScreenMatrix.multiplyMatrices( shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse );
+		this._frustum.setFromMatrix( projScreenMatrix );
+
+		shadowMatrix.set(
+			0.5, 0.0, 0.0, 0.5,
+			0.0, 0.5, 0.0, 0.5,
+			0.0, 0.0, 0.5, 0.5,
+			0.0, 0.0, 0.0, 1.0
+		);
+
+		shadowMatrix.multiply( shadowCamera.projectionMatrix );
+		shadowMatrix.multiply( shadowCamera.matrixWorldInverse );
+
+	},
+
+	getViewport: function ( viewportIndex ) {
+
+		return this._viewports[ viewportIndex ];
+
+	},
+
+	getFrameExtents: function () {
+
+		return this._frameExtents;
+
+	},
+
 	copy: function ( source ) {
 
 		this.camera = source.camera.clone();

+ 2 - 3
src/lights/PointLight.js

@@ -1,6 +1,5 @@
 import { Light } from './Light.js';
-import { PerspectiveCamera } from '../cameras/PerspectiveCamera.js';
-import { LightShadow } from './LightShadow.js';
+import { PointLightShadow } from './PointLightShadow.js';
 
 /**
  * @author mrdoob / http://mrdoob.com/
@@ -33,7 +32,7 @@ function PointLight( color, intensity, distance, decay ) {
 	this.distance = ( distance !== undefined ) ? distance : 0;
 	this.decay = ( decay !== undefined ) ? decay : 1;	// for physically correct lights, should be 2.
 
-	this.shadow = new LightShadow( new PerspectiveCamera( 90, 1, 0.5, 500 ) );
+	this.shadow = new PointLightShadow();
 
 }
 

+ 8 - 0
src/lights/PointLightShadow.d.ts

@@ -0,0 +1,8 @@
+import { PerspectiveCamera } from './../cameras/PerspectiveCamera';
+import { LightShadow } from './LightShadow';
+
+export class PointLightShadow extends LightShadow {
+
+	camera: PerspectiveCamera;
+
+}

+ 89 - 0
src/lights/PointLightShadow.js

@@ -0,0 +1,89 @@
+import { LightShadow } from './LightShadow.js';
+import { PerspectiveCamera } from '../cameras/PerspectiveCamera.js';
+import { Vector2 } from '../math/Vector2.js';
+import { Vector3 } from '../math/Vector3.js';
+import { Vector4 } from '../math/Vector4.js';
+
+function PointLightShadow() {
+
+	LightShadow.call( this, new PerspectiveCamera( 90, 1, 0.5, 500 ) );
+
+	this._frameExtents = new Vector2( 4, 2 );
+
+	this._viewportCount = 6;
+
+	this._viewports = [
+		// These viewports map a cube-map onto a 2D texture with the
+		// following orientation:
+		//
+		//  xzXZ
+		//   y Y
+		//
+		// X - Positive x direction
+		// x - Negative x direction
+		// Y - Positive y direction
+		// y - Negative y direction
+		// Z - Positive z direction
+		// z - Negative z direction
+
+		// positive X
+		new Vector4( 2, 1, 1, 1 ),
+		// negative X
+		new Vector4( 0, 1, 1, 1 ),
+		// positive Z
+		new Vector4( 3, 1, 1, 1 ),
+		// negative Z
+		new Vector4( 1, 1, 1, 1 ),
+		// positive Y
+		new Vector4( 3, 0, 1, 1 ),
+		// negative Y
+		new Vector4( 1, 0, 1, 1 )
+	];
+
+	this._cubeDirections = [
+		new Vector3( 1, 0, 0 ), new Vector3( - 1, 0, 0 ), new Vector3( 0, 0, 1 ),
+		new Vector3( 0, 0, - 1 ), new Vector3( 0, 1, 0 ), new Vector3( 0, - 1, 0 )
+	];
+
+	this._cubeUps = [
+		new Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ),
+		new Vector3( 0, 1, 0 ), new Vector3( 0, 0, 1 ),	new Vector3( 0, 0, - 1 )
+	];
+
+}
+
+PointLightShadow.prototype = Object.assign( Object.create( LightShadow.prototype ), {
+
+	constructor: PointLightShadow,
+
+	isPointLightShadow: true,
+
+	updateMatrices: function ( light, viewCamera, viewportIndex ) {
+
+		var camera = this.camera,
+			shadowMatrix = this.matrix,
+			lightPositionWorld = this._lightPositionWorld,
+			lookTarget = this._lookTarget,
+			shadowMatrix = this.matrix,
+			projScreenMatrix = this._projScreenMatrix;
+
+		lightPositionWorld.setFromMatrixPosition( light.matrixWorld );
+		camera.position.copy( lightPositionWorld );
+
+		lookTarget.copy( camera.position );
+		lookTarget.add( this._cubeDirections[ viewportIndex ] );
+		camera.up.copy( this._cubeUps[ viewportIndex ] );
+		camera.lookAt( lookTarget );
+		camera.updateMatrixWorld();
+
+		shadowMatrix.makeTranslation( - lightPositionWorld.x, - lightPositionWorld.y, - lightPositionWorld.z );
+
+		projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse );
+		this._frustum.setFromMatrix( projScreenMatrix );
+
+	}
+
+} );
+
+
+export { PointLightShadow };

+ 0 - 2
src/lights/SpotLightShadow.d.ts

@@ -1,10 +1,8 @@
 import { PerspectiveCamera } from './../cameras/PerspectiveCamera';
-import { Light } from './Light';
 import { LightShadow } from './LightShadow';
 
 export class SpotLightShadow extends LightShadow {
 
 	camera: PerspectiveCamera;
-	update( light: Light ): void;
 
 }

+ 3 - 1
src/lights/SpotLightShadow.js

@@ -18,7 +18,7 @@ SpotLightShadow.prototype = Object.assign( Object.create( LightShadow.prototype
 
 	isSpotLightShadow: true,
 
-	update: function ( light ) {
+	updateMatrices: function ( light, viewCamera, viewportIndex ) {
 
 		var camera = this.camera;
 
@@ -35,6 +35,8 @@ SpotLightShadow.prototype = Object.assign( Object.create( LightShadow.prototype
 
 		}
 
+		LightShadow.prototype.updateMatrices.call( this, light, viewCamera, viewportIndex );
+
 	}
 
 } );

+ 2 - 4
src/loaders/AnimationLoader.d.ts

@@ -1,12 +1,11 @@
 import { LoadingManager } from './LoadingManager';
+import { Loader } from './Loader';
 import { AnimationClip } from './../animation/AnimationClip';
 
-export class AnimationLoader {
+export class AnimationLoader extends Loader {
 
 	constructor( manager?: LoadingManager );
 
-	manager: LoadingManager;
-
 	load(
 		url: string,
 		onLoad?: ( response: string | ArrayBuffer ) => void,
@@ -14,6 +13,5 @@ export class AnimationLoader {
 		onError?: ( event: ErrorEvent ) => void
 	): any;
 	parse( json: any ): AnimationClip[];
-	setPath( path: string ): AnimationLoader;
 
 }

+ 5 - 10
src/loaders/AnimationLoader.js

@@ -1,6 +1,6 @@
 import { AnimationClip } from '../animation/AnimationClip.js';
 import { FileLoader } from './FileLoader.js';
-import { DefaultLoadingManager } from './LoadingManager.js';
+import { Loader } from './Loader.js';
 
 /**
  * @author bhouston / http://clara.io/
@@ -8,11 +8,13 @@ import { DefaultLoadingManager } from './LoadingManager.js';
 
 function AnimationLoader( manager ) {
 
-	this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;
+	Loader.call( this, manager );
 
 }
 
-Object.assign( AnimationLoader.prototype, {
+AnimationLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
+
+	constructor: AnimationLoader,
 
 	load: function ( url, onLoad, onProgress, onError ) {
 
@@ -42,13 +44,6 @@ Object.assign( AnimationLoader.prototype, {
 
 		return animations;
 
-	},
-
-	setPath: function ( value ) {
-
-		this.path = value;
-		return this;
-
 	}
 
 } );

+ 2 - 1
src/loaders/AudioLoader.d.ts

@@ -1,6 +1,7 @@
+import { Loader } from './Loader';
 import { LoadingManager } from './LoadingManager';
 
-export class AudioLoader {
+export class AudioLoader extends Loader {
 
 	constructor( manager?: LoadingManager );
 

+ 5 - 10
src/loaders/AudioLoader.js

@@ -1,6 +1,6 @@
 import { AudioContext } from '../audio/AudioContext.js';
 import { FileLoader } from './FileLoader.js';
-import { DefaultLoadingManager } from './LoadingManager.js';
+import { Loader } from './Loader.js';
 
 /**
  * @author Reece Aaron Lecrivain / http://reecenotes.com/
@@ -8,11 +8,13 @@ import { DefaultLoadingManager } from './LoadingManager.js';
 
 function AudioLoader( manager ) {
 
-	this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;
+	Loader.call( this, manager );
 
 }
 
-Object.assign( AudioLoader.prototype, {
+AudioLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
+
+	constructor: AudioLoader,
 
 	load: function ( url, onLoad, onProgress, onError ) {
 
@@ -34,13 +36,6 @@ Object.assign( AudioLoader.prototype, {
 
 		}, onProgress, onError );
 
-	},
-
-	setPath: function ( value ) {
-
-		this.path = value;
-		return this;
-
 	}
 
 } );

+ 2 - 3
src/loaders/BufferGeometryLoader.d.ts

@@ -1,12 +1,11 @@
+import { Loader } from './Loader';
 import { LoadingManager } from './LoadingManager';
 import { BufferGeometry } from './../core/BufferGeometry';
 
-export class BufferGeometryLoader {
+export class BufferGeometryLoader extends Loader {
 
 	constructor( manager?: LoadingManager );
 
-	manager: LoadingManager;
-
 	load(
 		url: string,
 		onLoad: ( bufferGeometry: BufferGeometry ) => void,

+ 5 - 10
src/loaders/BufferGeometryLoader.js

@@ -3,7 +3,7 @@ import { Vector3 } from '../math/Vector3.js';
 import { BufferAttribute } from '../core/BufferAttribute.js';
 import { BufferGeometry } from '../core/BufferGeometry.js';
 import { FileLoader } from './FileLoader.js';
-import { DefaultLoadingManager } from './LoadingManager.js';
+import { Loader } from './Loader.js';
 import { InstancedBufferGeometry } from '../core/InstancedBufferGeometry.js';
 import { InstancedBufferAttribute } from '../core/InstancedBufferAttribute.js';
 
@@ -13,11 +13,13 @@ import { InstancedBufferAttribute } from '../core/InstancedBufferAttribute.js';
 
 function BufferGeometryLoader( manager ) {
 
-	this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;
+	Loader.call( this, manager );
 
 }
 
-Object.assign( BufferGeometryLoader.prototype, {
+BufferGeometryLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
+
+	constructor: BufferGeometryLoader,
 
 	load: function ( url, onLoad, onProgress, onError ) {
 
@@ -121,13 +123,6 @@ Object.assign( BufferGeometryLoader.prototype, {
 
 		return geometry;
 
-	},
-
-	setPath: function ( value ) {
-
-		this.path = value;
-		return this;
-
 	}
 
 } );

+ 14 - 47
src/loaders/Loader.d.ts

@@ -1,59 +1,26 @@
-import { Material } from './../materials/Material';
 import { LoaderHandler } from './FileLoader';
-
-// Loaders //////////////////////////////////////////////////////////////////////////////////
+import { LoadingManager } from './LoadingManager';
 
 /**
  * Base class for implementing loaders.
- *
- * Events:
- *		 load
- *				 Dispatched when the image has completed loading
- *				 content — loaded image
- *
- *		 error
- *
- *					Dispatched when the image can't be loaded
- *					message — error message
  */
 export class Loader {
 
-	constructor();
-
-	/**
-	 * Will be called when load starts.
-	 * The default is a function with empty body.
-	 */
-	onLoadStart: () => void;
-
-	/**
-	 * Will be called while load progresses.
-	 * The default is a function with empty body.
-	 */
-	onLoadProgress: () => void;
+	constructor( manager?: LoadingManager );
 
-	/**
-	 * Will be called when load completes.
-	 * The default is a function with empty body.
-	 */
-	onLoadComplete: () => void;
-
-	/**
-	 * default — null.
-	 * If set, assigns the crossOrigin attribute of the image to the value of crossOrigin, prior to starting the load.
-	 */
 	crossOrigin: string;
-
-	/**
-	 * @deprecated Use THREE.LoaderUtils.extractUrlBase() instead.
-	 */
-	extractUrlBase( url: string ): string;
-	initMaterials( materials: Material[], texturePath: string ): Material[];
-	createMaterial(
-		m: Material,
-		texturePath: string,
-		crossOrigin?: string
-	): boolean;
+	path: string;
+	resourcePath: string;
+	manager: LoadingManager;
+
+	/*
+	load(): void;
+	parse(): void;
+	*/
+
+	setCrossOrigin( crossOrigin: string ): this;
+	setPath( path: string ): this;
+	setResourcePath( resourcePath: string ): this;
 
 	static Handlers: LoaderHandler;
 

+ 36 - 292
src/loaders/Loader.js

@@ -1,338 +1,82 @@
-import {
-	NoBlending,
-	NormalBlending,
-	AdditiveBlending,
-	SubtractiveBlending,
-	MultiplyBlending,
-	CustomBlending,
-
-	FaceColors,
-	VertexColors,
-
-	DoubleSide,
-	BackSide,
-
-	MirroredRepeatWrapping,
-	RepeatWrapping
-} from '../constants.js';
-import { _Math } from '../math/Math.js';
-import { MaterialLoader } from './MaterialLoader.js';
-import { TextureLoader } from './TextureLoader.js';
-import { Color } from '../math/Color.js';
+import { DefaultLoadingManager } from './LoadingManager.js';
 
 /**
  * @author alteredq / http://alteredqualia.com/
  */
 
-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 Loader() {}
-
-Loader.Handlers = {
-
-	handlers: [],
-
-	add: function ( regex, loader ) {
-
-		this.handlers.push( regex, loader );
-
-	},
-
-	get: function ( file ) {
-
-		var handlers = this.handlers;
-
-		for ( var i = 0, l = handlers.length; i < l; i += 2 ) {
+function Loader( manager ) {
 
-			var regex = handlers[ i ];
-			var loader = handlers[ i + 1 ];
-
-			if ( regex.test( file ) ) {
-
-				return loader;
+	this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;
 
-			}
+	this.crossOrigin = 'anonymous';
+	this.path = '';
+	this.resourcePath = '';
 
-		}
-
-		return null;
-
-	}
-
-};
+}
 
 Object.assign( Loader.prototype, {
 
-	crossOrigin: 'anonymous',
-
-	onLoadStart: function () {},
-
-	onLoadProgress: function () {},
-
-	onLoadComplete: function () {},
-
-	initMaterials: function ( materials, texturePath, crossOrigin ) {
+	load: function ( /* url, onLoad, onProgress, onError */ ) {},
 
-		var array = [];
+	parse: function ( /* data */ ) {},
 
-		for ( var i = 0; i < materials.length; ++ i ) {
+	setCrossOrigin: function ( crossOrigin ) {
 
-			array[ i ] = this.createMaterial( materials[ i ], texturePath, crossOrigin );
-
-		}
-
-		return array;
+		this.crossOrigin = crossOrigin;
+		return this;
 
 	},
 
-	createMaterial: function ( m, texturePath, crossOrigin ) {
-
-		// 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.Loader.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 );
-					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 );
-					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 );
-					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 );
-					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 );
-					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 );
-					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 );
-					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 );
-					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 );
-					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 );
-					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.Loader.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.Loader.createMaterial: Unsupported', name, value );
-					break;
-
-			}
-
-		}
+	setPath: function ( path ) {
 
-		if ( json.type === 'MeshBasicMaterial' ) delete json.emissive;
-		if ( json.type !== 'MeshPhongMaterial' ) delete json.specular;
+		this.path = path;
+		return this;
 
-		if ( json.opacity < 1 ) json.transparent = true;
+	},
 
-		_materialLoader.setTextures( textures );
+	setResourcePath: function ( resourcePath ) {
 
-		return _materialLoader.parse( json );
+		this.resourcePath = resourcePath;
+		return this;
 
 	}
 
 } );
 
-function loadTexture( path, repeat, offset, wrap, anisotropy, textures, texturePath, crossOrigin ) {
-
-	var fullPath = texturePath + path;
-	var loader = Loader.Handlers.get( fullPath );
-
-	var texture;
+//
 
-	if ( loader !== null ) {
-
-		texture = loader.load( fullPath );
-
-	} else {
-
-		_textureLoader.setCrossOrigin( crossOrigin );
-		texture = _textureLoader.load( fullPath );
-
-	}
+Loader.Handlers = {
 
-	if ( repeat !== undefined ) {
+	handlers: [],
 
-		texture.repeat.fromArray( repeat );
+	add: function ( regex, loader ) {
 
-		if ( repeat[ 0 ] !== 1 ) texture.wrapS = RepeatWrapping;
-		if ( repeat[ 1 ] !== 1 ) texture.wrapT = RepeatWrapping;
+		this.handlers.push( regex, loader );
 
-	}
+	},
 
-	if ( offset !== undefined ) {
+	get: function ( file ) {
 
-		texture.offset.fromArray( offset );
+		var handlers = this.handlers;
 
-	}
+		for ( var i = 0, l = handlers.length; i < l; i += 2 ) {
 
-	if ( wrap !== undefined ) {
+			var regex = handlers[ i ];
+			var loader = handlers[ i + 1 ];
 
-		if ( wrap[ 0 ] === 'repeat' ) texture.wrapS = RepeatWrapping;
-		if ( wrap[ 0 ] === 'mirror' ) texture.wrapS = MirroredRepeatWrapping;
+			if ( regex.test( file ) ) {
 
-		if ( wrap[ 1 ] === 'repeat' ) texture.wrapT = RepeatWrapping;
-		if ( wrap[ 1 ] === 'mirror' ) texture.wrapT = MirroredRepeatWrapping;
+				return loader;
 
-	}
+			}
 
-	if ( anisotropy !== undefined ) {
+		}
 
-		texture.anisotropy = anisotropy;
+		return null;
 
 	}
 
-	var uuid = _Math.generateUUID();
-
-	textures[ uuid ] = texture;
-
-	return uuid;
+};
 
-}
 
 export { Loader };

+ 0 - 27
src/loaders/LoadingManager.d.ts

@@ -1,30 +1,3 @@
-import { Geometry } from './../core/Geometry';
-import { Material } from './../materials/Material';
-import { Loader } from './Loader';
-/**
- * A loader for loading objects in JSON format.
- */
-export class JSONLoader extends Loader {
-
-	constructor( manager?: LoadingManager );
-
-	manager: LoadingManager;
-	withCredentials: boolean;
-
-	load(
-		url: string,
-		onLoad?: ( geometry: Geometry, materials: Material[] ) => void,
-		onProgress?: ( event: ProgressEvent ) => void,
-		onError?: ( event: ErrorEvent ) => void
-	): void;
-	setTexturePath( value: string ): void;
-	parse(
-		json: any,
-		texturePath?: string
-	): { geometry: Geometry; materials?: Material[] };
-
-}
-
 export const DefaultLoadingManager: LoadingManager;
 
 /**

+ 7 - 4
src/loaders/MaterialLoader.js

@@ -61,8 +61,8 @@ Object.assign( MaterialLoader.prototype, {
 		if ( json.emissive !== undefined ) material.emissive.setHex( json.emissive );
 		if ( json.specular !== undefined ) material.specular.setHex( json.specular );
 		if ( json.shininess !== undefined ) material.shininess = json.shininess;
-		if ( json.clearCoat !== undefined ) material.clearCoat = json.clearCoat;
-		if ( json.clearCoatRoughness !== undefined ) material.clearCoatRoughness = json.clearCoatRoughness;
+		if ( json.clearcoat !== undefined ) material.clearcoat = json.clearcoat;
+		if ( json.clearcoatRoughness !== undefined ) material.clearcoatRoughness = json.clearcoatRoughness;
 		if ( json.vertexColors !== undefined ) material.vertexColors = json.vertexColors;
 		if ( json.fog !== undefined ) material.fog = json.fog;
 		if ( json.flatShading !== undefined ) material.flatShading = json.flatShading;
@@ -97,6 +97,9 @@ Object.assign( MaterialLoader.prototype, {
 		if ( json.dithering !== undefined ) material.dithering = json.dithering;
 
 		if ( json.visible !== undefined ) material.visible = json.visible;
+
+		if ( json.toneMapped !== undefined ) material.toneMapped = json.toneMapped;
+
 		if ( json.userData !== undefined ) material.userData = json.userData;
 
 		// Shader Material
@@ -229,8 +232,8 @@ Object.assign( MaterialLoader.prototype, {
 
 		if ( json.gradientMap !== undefined ) material.gradientMap = getTexture( json.gradientMap );
 
-		if ( json.clearCoatNormalMap !== undefined ) material.clearCoatNormalMap = getTexture( json.clearCoatNormalMap );
-		if ( json.clearCoatNormalScale !== undefined ) material.clearCoatNormalScale = new Vector2().fromArray( json.clearCoatNormalScale );
+		if ( json.clearcoatNormalMap !== undefined ) material.clearcoatNormalMap = getTexture( json.clearcoatNormalMap );
+		if ( json.clearcoatNormalScale !== undefined ) material.clearcoatNormalScale = new Vector2().fromArray( json.clearcoatNormalScale );
 
 		return material;
 

+ 2 - 7
src/loaders/ObjectLoader.d.ts

@@ -1,25 +1,20 @@
+import { Loader } from './Loader';
 import { LoadingManager } from './LoadingManager';
 import { Object3D } from './../core/Object3D';
 import { Texture } from './../textures/Texture';
 import { Material } from './../materials/Material';
 import { AnimationClip } from './../animation/AnimationClip';
 
-export class ObjectLoader {
+export class ObjectLoader extends Loader {
 
 	constructor( manager?: LoadingManager );
 
-	manager: LoadingManager;
-	texturePass: string;
-	crossOrigin: string;
-
 	load(
 		url: string,
 		onLoad?: <ObjectType extends Object3D>( object: ObjectType ) => void,
 		onProgress?: ( event: ProgressEvent ) => void,
 		onError?: ( event: Error | ErrorEvent ) => void
 	): void;
-	setTexturePath( value: string ): void;
-	setCrossOrigin( crossOrigin: string ): void;
 	parse<T extends Object3D>( json: any, onLoad?: ( object: Object3D ) => void ): T;
 	parseGeometries( json: any ): any[]; // Array of BufferGeometry or Geometry or Geometry2.
 	parseMaterials( json: any, textures: Texture[] ): Material[]; // Array of Classes that inherits from Matrial.

+ 6 - 27
src/loaders/ObjectLoader.js

@@ -45,11 +45,12 @@ import { Scene } from '../scenes/Scene.js';
 import { CubeTexture } from '../textures/CubeTexture.js';
 import { Texture } from '../textures/Texture.js';
 import { ImageLoader } from './ImageLoader.js';
-import { LoadingManager, DefaultLoadingManager } from './LoadingManager.js';
+import { LoadingManager } from './LoadingManager.js';
 import { AnimationClip } from '../animation/AnimationClip.js';
 import { MaterialLoader } from './MaterialLoader.js';
 import { LoaderUtils } from './LoaderUtils.js';
 import { BufferGeometryLoader } from './BufferGeometryLoader.js';
+import { Loader } from './Loader.js';
 import { FileLoader } from './FileLoader.js';
 import * as Geometries from '../geometries/Geometries.js';
 import * as Curves from '../extras/curves/Curves.js';
@@ -60,20 +61,19 @@ import * as Curves from '../extras/curves/Curves.js';
 
 function ObjectLoader( manager ) {
 
-	this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;
-	this.resourcePath = '';
+	Loader.call( this, manager );
 
 }
 
-Object.assign( ObjectLoader.prototype, {
+ObjectLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
 
-	crossOrigin: 'anonymous',
+	constructor: ObjectLoader,
 
 	load: function ( url, onLoad, onProgress, onError ) {
 
 		var scope = this;
 
-		var path = ( this.path === undefined ) ? LoaderUtils.extractUrlBase( url ) : this.path;
+		var path = ( this.path === '' ) ? LoaderUtils.extractUrlBase( url ) : this.path;
 		this.resourcePath = this.resourcePath || path;
 
 		var loader = new FileLoader( scope.manager );
@@ -111,27 +111,6 @@ Object.assign( ObjectLoader.prototype, {
 
 	},
 
-	setPath: function ( value ) {
-
-		this.path = value;
-		return this;
-
-	},
-
-	setResourcePath: function ( value ) {
-
-		this.resourcePath = value;
-		return this;
-
-	},
-
-	setCrossOrigin: function ( value ) {
-
-		this.crossOrigin = value;
-		return this;
-
-	},
-
 	parse: function ( json, onLoad ) {
 
 		var shapes = this.parseShape( json.shapes );

+ 13 - 5
src/materials/Material.js

@@ -70,6 +70,8 @@ function Material() {
 
 	this.visible = true;
 
+	this.toneMapped = true;
+
 	this.userData = {};
 
 	this.needsUpdate = true;
@@ -172,13 +174,13 @@ Material.prototype = Object.assign( Object.create( EventDispatcher.prototype ),
 
 		if ( this.specular && this.specular.isColor ) data.specular = this.specular.getHex();
 		if ( this.shininess !== undefined ) data.shininess = this.shininess;
-		if ( this.clearCoat !== undefined ) data.clearCoat = this.clearCoat;
-		if ( this.clearCoatRoughness !== undefined ) data.clearCoatRoughness = this.clearCoatRoughness;
+		if ( this.clearcoat !== undefined ) data.clearcoat = this.clearcoat;
+		if ( this.clearcoatRoughness !== undefined ) data.clearcoatRoughness = this.clearcoatRoughness;
 
-		if ( this.clearCoatNormalMap && this.clearCoatNormalMap.isTexture ) {
+		if ( this.clearcoatNormalMap && this.clearcoatNormalMap.isTexture ) {
 
-			data.clearCoatNormalMap = this.clearCoatNormalMap.toJSON( meta ).uuid;
-			data.clearCoatNormalScale = this.clearCoatNormalScale.toArray();
+			data.clearcoatNormalMap = this.clearcoatNormalMap.toJSON( meta ).uuid;
+			data.clearcoatNormalScale = this.clearcoatNormalScale.toArray();
 
 		}
 
@@ -290,6 +292,9 @@ Material.prototype = Object.assign( Object.create( EventDispatcher.prototype ),
 		if ( this.skinning === true ) data.skinning = true;
 
 		if ( this.visible === false ) data.visible = false;
+
+		if ( this.toneMapped === false ) data.toneMapped = false;
+
 		if ( JSON.stringify( this.userData ) !== '{}' ) data.userData = this.userData;
 
 		// TODO: Copied from Object3D.toJSON
@@ -378,6 +383,9 @@ Material.prototype = Object.assign( Object.create( EventDispatcher.prototype ),
 		this.premultipliedAlpha = source.premultipliedAlpha;
 
 		this.visible = source.visible;
+
+		this.toneMapped = source.toneMapped;
+
 		this.userData = JSON.parse( JSON.stringify( source.userData ) );
 
 		this.clipShadows = source.clipShadows;

+ 12 - 9
src/materials/MeshPhysicalMaterial.d.ts

@@ -4,17 +4,18 @@ import {
 	MeshStandardMaterialParameters,
 	MeshStandardMaterial,
 } from './MeshStandardMaterial';
+import { Color } from './../math/Color';
 
 export interface MeshPhysicalMaterialParameters
 	extends MeshStandardMaterialParameters {
-
 	reflectivity?: number;
-	clearCoat?: number;
-	clearCoatRoughness?: number;
+	clearcoat?: number;
+	clearcoatRoughness?: number;
 
-	clearCoatNormalScale?: Vector2;
-	clearCoatNormalMap?: Texture;
+	sheen?: Color;
 
+	clearcoatNormalScale?: Vector2;
+	clearcoatNormalMap?: Texture;
 }
 
 export class MeshPhysicalMaterial extends MeshStandardMaterial {
@@ -23,10 +24,12 @@ export class MeshPhysicalMaterial extends MeshStandardMaterial {
 
 	defines: any;
 	reflectivity: number;
-	clearCoat: number;
-	clearCoatRoughness: number;
+	clearcoat: number;
+	clearcoatRoughness: number;
+
+	sheen: Color | null;
 
-	clearCoatNormalScale: Vector2;
-	clearCoatNormalMap: Texture | null;
+	clearcoatNormalScale: Vector2;
+	clearcoatNormalMap: Texture | null;
 
 }

+ 36 - 15
src/materials/MeshPhysicalMaterial.js

@@ -1,16 +1,19 @@
 import { Vector2 } from '../math/Vector2.js';
 import { MeshStandardMaterial } from './MeshStandardMaterial.js';
+import { Color } from '../math/Color.js';
 
 /**
  * @author WestLangley / http://github.com/WestLangley
  *
  * parameters = {
  *  reflectivity: <float>
- *  clearCoat: <float>
- *  clearCoatRoughness: <float>
+ *  clearcoat: <float>
+ *  clearcoatRoughness: <float>
  *
- *  clearCoatNormalScale: <Vector2>,
- *  clearCoatNormalMap: new THREE.Texture( <Image> ),
+ *  sheen: <Color>
+ *
+ *  clearcoatNormalScale: <Vector2>,
+ *  clearcoatNormalMap: new THREE.Texture( <Image> ),
  * }
  */
 
@@ -18,17 +21,26 @@ function MeshPhysicalMaterial( parameters ) {
 
 	MeshStandardMaterial.call( this );
 
-	this.defines = { 'PHYSICAL': '' };
+	this.defines = {
+
+		'STANDARD': '',
+		'PHYSICAL': ''
+
+	};
 
 	this.type = 'MeshPhysicalMaterial';
 
 	this.reflectivity = 0.5; // maps to F0 = 0.04
 
-	this.clearCoat = 0.0;
-	this.clearCoatRoughness = 0.0;
+	this.clearcoat = 0.0;
+	this.clearcoatRoughness = 0.0;
+
+	this.sheen = null; // null will disable sheen bsdf
+
+	this.clearcoatNormalScale = new Vector2( 1, 1 );
+	this.clearcoatNormalMap = null;
 
-	this.clearCoatNormalScale = new Vector2( 1, 1 );
-	this.clearCoatNormalMap = null;
+	this.transparency = 0.0;
 
 	this.setValues( parameters );
 
@@ -43,19 +55,28 @@ MeshPhysicalMaterial.prototype.copy = function ( source ) {
 
 	MeshStandardMaterial.prototype.copy.call( this, source );
 
-	this.defines = { 'PHYSICAL': '' };
+	this.defines = {
+
+		'STANDARD': '',
+		'PHYSICAL': ''
+
+	};
 
 	this.reflectivity = source.reflectivity;
 
-	this.clearCoat = source.clearCoat;
-	this.clearCoatRoughness = source.clearCoatRoughness;
+	this.clearcoat = source.clearcoat;
+	this.clearcoatRoughness = source.clearcoatRoughness;
+
+	if ( source.sheen ) this.sheen = ( this.sheen || new Color() ).copy( source.sheen );
+	else this.sheen = null;
 
-	this.clearCoatNormalMap = source.clearCoatNormalMap;
-	this.clearCoatNormalScale.copy( source.clearCoatNormalScale );
+	this.clearcoatNormalMap = source.clearcoatNormalMap;
+	this.clearcoatNormalScale.copy( source.clearcoatNormalScale );
+
+	this.transparency = source.transparency;
 
 	return this;
 
 };
 
-
 export { MeshPhysicalMaterial };

+ 0 - 2
src/materials/MeshStandardMaterial.d.ts

@@ -29,7 +29,6 @@ export interface MeshStandardMaterialParameters extends MaterialParameters {
 	alphaMap?: Texture;
 	envMap?: Texture;
 	envMapIntensity?: number;
-	energyPreservation: boolean;
 	refractionRatio?: number;
 	wireframe?: boolean;
 	wireframeLinewidth?: number;
@@ -67,7 +66,6 @@ export class MeshStandardMaterial extends Material {
 	alphaMap: Texture | null;
 	envMap: Texture | null;
 	envMapIntensity: number;
-	energyPreservation: boolean;
 	refractionRatio: number;
 	wireframe: boolean;
 	wireframeLinewidth: number;

+ 28 - 1
src/math/Color.d.ts

@@ -152,8 +152,35 @@ export class Color {
 	lerp( color: Color, alpha: number ): this;
 	lerpHSL( color: Color, alpha: number ): this;
 	equals( color: Color ): boolean;
-	fromArray( rgb: number[], offset?: number ): this;
+
+	/**
+	 * Sets this color's red, green and blue value from the provided array.
+	 * @param array the source array.
+	 * @param offset (optional) offset into the array. Default is 0.
+	 */
+	fromArray( array: number[], offset?: number ): this;
+
+	/**
+	 * Sets this color's red, green and blue value from the provided array-like.
+	 * @param array the source array-like.
+	 * @param offset (optional) offset into the array-like. Default is 0.
+	 */
+	fromArray( array: ArrayLike<number>, offset?: number ): this;
+
+	/**
+	 * Returns an array [red, green, blue], or copies red, green and blue into the provided array.
+	 * @param array (optional) array to store the color to. If this is not provided, a new array will be created.
+	 * @param offset (optional) optional offset into the array.
+	 * @return The created or provided array.
+	 */
 	toArray( array?: number[], offset?: number ): number[];
+
+	/**
+	 * Copies red, green and blue into the provided array-like.
+	 * @param array array-like to store the color to.
+	 * @param offset (optional) optional offset into the array-like.
+	 * @return The provided array-like.
+	 */
 	toArray( xyz: ArrayLike<number>, offset?: number ): ArrayLike<number>;
 
 }

+ 26 - 0
src/math/Matrix3.d.ts

@@ -111,10 +111,36 @@ export class Matrix3 implements Matrix {
 
 	equals( matrix: Matrix3 ): boolean;
 
+	/**
+	 * Sets the values of this matrix from the provided array.
+	 * @param array the source array.
+	 * @param offset (optional) offset into the array. Default is 0.
+	 */
 	fromArray( array: number[], offset?: number ): Matrix3;
 
+	/**
+	 * Sets the values of this matrix from the provided array-like.
+	 * @param array the source array-like.
+	 * @param offset (optional) offset into the array-like. Default is 0.
+	 */
+	fromArray( array: ArrayLike<number>, offset?: number ): Matrix3;
+
+	/**
+	 * Returns an array with the values of this matrix, or copies them into the provided array.
+	 * @param array (optional) array to store the matrix to. If this is not provided, a new array will be created.
+	 * @param offset (optional) optional offset into the array.
+	 * @return The created or provided array.
+	 */
 	toArray( array?: number[], offset?: number ): number[];
 
+	/**
+	 * Copies he values of this matrix into the provided array-like.
+	 * @param array array-like to store the matrix to.
+	 * @param offset (optional) optional offset into the array-like.
+	 * @return The provided array-like.
+	 */
+	toArray( array?: ArrayLike<number>, offset?: number ): ArrayLike<number>;
+
 	/**
 	 * Multiplies this matrix by m.
 	 */

+ 27 - 0
src/math/Matrix4.d.ts

@@ -226,10 +226,37 @@ export class Matrix4 implements Matrix {
 		far: number
 	): Matrix4;
 	equals( matrix: Matrix4 ): boolean;
+
+	/**
+	 * Sets the values of this matrix from the provided array.
+	 * @param array the source array.
+	 * @param offset (optional) offset into the array. Default is 0.
+	 */
 	fromArray( array: number[], offset?: number ): Matrix4;
 
+	/**
+	 * Sets the values of this matrix from the provided array-like.
+	 * @param array the source array-like.
+	 * @param offset (optional) offset into the array-like. Default is 0.
+	 */
+	fromArray( array: ArrayLike<number>, offset?: number ): Matrix4;
+
+	/**
+	 * Returns an array with the values of this matrix, or copies them into the provided array.
+	 * @param array (optional) array to store the matrix to. If this is not provided, a new array will be created.
+	 * @param offset (optional) optional offset into the array.
+	 * @return The created or provided array.
+	 */
 	toArray( array?: number[], offset?: number ): number[];
 
+	/**
+	 * Copies he values of this matrix into the provided array-like.
+	 * @param array array-like to store the matrix to.
+	 * @param offset (optional) optional offset into the array-like.
+	 * @return The provided array-like.
+	 */
+	toArray( array?: ArrayLike<number>, offset?: number ): ArrayLike<number>;
+
 	/**
 	 * @deprecated Use {@link Matrix4#copyPosition .copyPosition()} instead.
 	 */

+ 29 - 4
src/math/Quaternion.d.ts

@@ -94,11 +94,36 @@ export class Quaternion {
 
 	slerp( qb: Quaternion, t: number ): Quaternion;
 	equals( v: Quaternion ): boolean;
-	fromArray( n: number[] ): Quaternion;
-	toArray(): number[];
 
-	fromArray( xyzw: number[], offset?: number ): Quaternion;
-	toArray( xyzw?: number[], offset?: number ): number[];
+	/**
+	 * Sets this quaternion's x, y, z and w value from the provided array.
+	 * @param array the source array.
+	 * @param offset (optional) offset into the array. Default is 0.
+	 */
+	fromArray( array: number[], offset?: number ): this;
+
+	/**
+	 * Sets this quaternion's x, y, z and w value from the provided array-like.
+	 * @param array the source array-like.
+	 * @param offset (optional) offset into the array-like. Default is 0.
+	 */
+	fromArray( array: ArrayLike<number>, offset?: number ): this;
+
+	/**
+	 * Returns an array [x, y, z, w], or copies x, y, z and w into the provided array.
+	 * @param array (optional) array to store the quaternion to. If this is not provided, a new array will be created.
+	 * @param offset (optional) optional offset into the array.
+	 * @return The created or provided array.
+	 */
+	toArray( array?: number[], offset?: number ): number[];
+
+	/**
+	 * Copies x, y, z and w into the provided array-like.
+	 * @param array array-like to store the quaternion to.
+	 * @param offset (optional) optional offset into the array.
+	 * @return The provided array-like.
+	 */
+	toArray( array: ArrayLike<number>, offset?: number ): ArrayLike<number>;
 
 	_onChange( callback: Function ): Quaternion;
 	_onChangeCallback: Function;

+ 30 - 2
src/math/SphericalHarmonics3.d.ts

@@ -15,8 +15,36 @@ export class SphericalHarmonics3 {
 	equals( sh: SphericalHarmonics3 ): boolean;
 	copy( sh: SphericalHarmonics3 ): SphericalHarmonics3;
 	clone(): SphericalHarmonics3;
-	fromArray( array: number[] ): SphericalHarmonics3;
-	toArray(): number[];
+
+	/**
+	 * Sets the values of this spherical harmonics from the provided array.
+	 * @param array the source array.
+	 * @param offset (optional) offset into the array. Default is 0.
+	 */
+	fromArray( array: number[], offset?: number ): this;
+
+	/**
+	 * Sets the values of this spherical harmonics from the provided array-like.
+	 * @param array the source array-like.
+	 * @param offset (optional) offset into the array-like. Default is 0.
+	 */
+	fromArray( array: ArrayLike<number>, offset?: number ): this;
+
+	/**
+	 * Returns an array with the values of this spherical harmonics, or copies them into the provided array.
+	 * @param array (optional) array to store the spherical harmonics to. If this is not provided, a new array will be created.
+	 * @param offset (optional) optional offset into the array.
+	 * @return The created or provided array.
+	 */
+	toArray( array?: number[], offset?: number ): number[];
+
+	/**
+	 * Returns an array with the values of this spherical harmonics, or copies them into the provided array-like.
+	 * @param array array-like to store the spherical harmonics to.
+	 * @param offset (optional) optional offset into the array-like.
+	 * @return The provided array-like.
+	 */
+	toArray( array: ArrayLike<number>, offset?: number ): ArrayLike<number>;
 
 	getAt( normal: Vector3, target: Vector3 ) : Vector3;
 	getIrradianceAt( normal: Vector3, target: Vector3 ) : Vector3;

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