فهرست منبع

Merge branch 'dev' into descriptive-defines-2

arobertson0 6 سال پیش
والد
کامیت
092c5a7318
57فایلهای تغییر یافته به همراه1624 افزوده شده و 1185 حذف شده
  1. 5 5
      build/three.js
  2. 393 394
      build/three.min.js
  3. 5 5
      build/three.module.js
  4. 0 32
      docs/api/en/loaders/Loader.html
  5. 4 4
      docs/api/en/materials/MeshPhysicalMaterial.html
  6. 5 37
      docs/api/zh/loaders/Loader.html
  7. 4 4
      docs/api/zh/materials/MeshPhysicalMaterial.html
  8. 2 2
      docs/scenes/material-browser.html
  9. 50 50
      editor/js/Sidebar.Material.js
  10. 4 4
      editor/js/Strings.js
  11. 1 0
      examples/files.js
  12. 6 15
      examples/js/exporters/ColladaExporter.js
  13. 2 2
      examples/js/loaders/LWOLoader.js
  14. 265 1
      examples/js/loaders/deprecated/LegacyJSONLoader.js
  15. 1 1
      examples/js/shaders/TranslucentShader.js
  16. 6 15
      examples/jsm/exporters/ColladaExporter.js
  17. 2 2
      examples/jsm/loaders/LWOLoader.js
  18. 281 2
      examples/jsm/loaders/deprecated/LegacyJSONLoader.js
  19. 2 2
      examples/jsm/loaders/sea3d/SEA3DLoader.js
  20. 1 1
      examples/jsm/nodes/accessors/NormalNode.js
  21. 48 8
      examples/jsm/nodes/accessors/ReflectNode.js
  22. 2 2
      examples/jsm/nodes/bsdfs/BlinnShininessExponentNode.js
  23. 5 4
      examples/jsm/nodes/materials/StandardNodeMaterial.js
  24. 52 29
      examples/jsm/nodes/materials/nodes/StandardNode.js
  25. 1 1
      examples/jsm/shaders/TranslucentShader.js
  26. BIN
      examples/models/fbx/cloth.fbx
  27. 9 9
      examples/webgl_materials_clearcoat_normalmap.html
  28. 6 3
      examples/webgl_materials_cubemap_mipmaps.html
  29. 20 20
      examples/webgl_materials_nodes.html
  30. 203 0
      examples/webgl_materials_sheen.html
  31. 6 6
      examples/webgl_materials_variations_physical.html
  32. 73 62
      package-lock.json
  33. 3 3
      package.json
  34. 1 41
      src/loaders/Loader.d.ts
  35. 1 292
      src/loaders/Loader.js
  36. 0 27
      src/loaders/LoadingManager.d.ts
  37. 4 4
      src/loaders/MaterialLoader.js
  38. 5 5
      src/materials/Material.js
  39. 12 9
      src/materials/MeshPhysicalMaterial.d.ts
  40. 20 12
      src/materials/MeshPhysicalMaterial.js
  41. 0 2
      src/materials/MeshStandardMaterial.d.ts
  42. 7 6
      src/renderers/WebGLRenderer.js
  43. 31 0
      src/renderers/shaders/ShaderChunk/bsdfs.glsl.js
  44. 1 1
      src/renderers/shaders/ShaderChunk/clearcoat_normal_fragment_begin.glsl.js
  45. 4 4
      src/renderers/shaders/ShaderChunk/clearcoat_normal_fragment_maps.glsl.js
  46. 2 2
      src/renderers/shaders/ShaderChunk/clearcoat_normalmap_pars_fragment.glsl.js
  47. 1 1
      src/renderers/shaders/ShaderChunk/common.glsl.js
  48. 2 2
      src/renderers/shaders/ShaderChunk/lights_fragment_begin.glsl.js
  49. 1 1
      src/renderers/shaders/ShaderChunk/lights_fragment_end.glsl.js
  50. 1 1
      src/renderers/shaders/ShaderChunk/lights_fragment_maps.glsl.js
  51. 9 2
      src/renderers/shaders/ShaderChunk/lights_physical_fragment.glsl.js
  52. 31 20
      src/renderers/shaders/ShaderChunk/lights_physical_pars_fragment.glsl.js
  53. 5 4
      src/renderers/shaders/ShaderLib.js
  54. 6 3
      src/renderers/shaders/ShaderLib/meshphysical_frag.glsl.js
  55. 6 4
      src/renderers/webgl/WebGLProgram.js
  56. 7 4
      src/renderers/webgl/WebGLPrograms.js
  57. 0 13
      test/unit/src/loaders/Loader.tests.js

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 5 - 5
build/three.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 393 - 394
build/three.min.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 5 - 5
build/three.module.js


+ 0 - 32
docs/api/en/loaders/Loader.html

@@ -24,44 +24,12 @@
 
 		<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:Function onLoadProgress]</h3>
-		<p>Will be called while load progresses.</p>
-		<p>The default is a function with empty body.</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 crossOrigin]</h3>
 		<p>
 		The crossOrigin string to implement CORS for loading the url from a different domain that allows CORS.
 		Default is *"anonymous"*.
 		</p>
 
-		<h2>Methods</h2>
-
-		<h3>[method:Material createMaterial]( [param:object m], [param:string texturePath] )</h3>
-		<p>
-		[page:Object m] — The parameters to create the material. <br />
-		[page:String texturePath] — The base path of the textures.
-		</p>
-		<p>
-		Creates the Material based on the parameters m.
-		</p>
-
-		<h3>[method:Array initMaterials]( [param:Array materials], [param:string texturePath] )</h3>
-		<p>
-		[page:Array materials] — an array of parameters to create materials. <br />
-		[page:String texturePath] —  The base path of the textures.
-		</p>
-		<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.
-		</p>
-
 		<h2>Handlers</h2>
 
 		<p>

+ 4 - 4
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>

+ 5 - 37
docs/api/zh/loaders/Loader.html

@@ -24,41 +24,9 @@
 
 		<h2>属性</h2>
 
-		<h3>[property:Function onLoadStart]</h3>
-		<p>当加载开始时,将被调用。</p>
-		<p>默认实现是一个空函数体。</p>
-
-		<h3>[property:Function onLoadProgress]</h3>
-		<p>当进入加载流程中,将被调用。</p>
-		<p>默认实现是一个空函数体。</p>
-
-		<h3>[property:Function onLoadComplete]</h3>
-		<p>当加载完成时,将被调用。</p>
-		<p>默认实现是一个空函数体。</p>
-
 		<h3>[property:string crossOrigin]</h3>
 		<p>
-            跨域字符串,用于实现跨域,以便从允许CORS从其他域加载url。默认为"anonymous"。
-		</p>
-
-		<h2>Methods</h2>
-
-		<h3>[method:Material createMaterial]( [param:object m], [param:string texturePath] )</h3>
-		<p>
-		[page:Object m] — 所要创建的材质的参数。 <br />
-		[page:String texturePath] — 纹理加载路径。
-		</p>
-		<p>
-		基于参数m来创建材质。
-		</p>
-
-		<h3>[method:Array initMaterials]( [param:Array materials], [param:string texturePath] )</h3>
-		<p>
-		[page:Array materials] — 用于创建材质的参数数组。 <br />
-		[page:String texturePath] —  纹理加载路径。
-		</p>
-		<p>
-		基于参数数组m,来创建 [page:Material] 数组. 参数索引与材质的索引一致。
+			跨域字符串,用于实现跨域,以便从允许CORS从其他域加载url。默认为"anonymous"。
 		</p>
 
 		<h2>Handlers</h2>
@@ -67,10 +35,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 +46,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 - 4
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 />

+ 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",

+ 6 - 15
examples/js/exporters/ColladaExporter.js

@@ -220,13 +220,9 @@ THREE.ColladaExporter.prototype = {
 						bufferGeometry.groups :
 						[ { start: 0, count: indexCount, materialIndex: 0 } ];
 
-				var gnode = `<geometry id="${ meshid }"` +
-					(
-						g.name ?
-							` 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`;
@@ -499,15 +495,10 @@ THREE.ColladaExporter.prototype = {
 
 					'</effect>';
 
-				var materialNode = `<material id="${ matid }"` +
-					(
-						m.name ?
-							` 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);
+				libraryMaterials.push( materialNode );
 				libraryEffects.push( effectnode );
 				materialMap.set( m, matid );
 

+ 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 );
 
 			}
 

+ 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" ],

+ 6 - 15
examples/jsm/exporters/ColladaExporter.js

@@ -231,13 +231,9 @@ ColladaExporter.prototype = {
 						bufferGeometry.groups :
 						[ { start: 0, count: indexCount, materialIndex: 0 } ];
 
-				var gnode = `<geometry id="${ meshid }"` +
-					(
-						g.name ?
-						` 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`;
@@ -510,15 +506,10 @@ ColladaExporter.prototype = {
 
 					'</effect>';
 
-				var materialNode = `<material id="${ matid }"` +
-					(
-						m.name ?
-						` 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);
+				libraryMaterials.push( materialNode );
 				libraryEffects.push( effectnode );
 				materialMap.set( m, matid );
 

+ 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 );
 
 			}
 

+ 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 };
 

+ 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 };

+ 52 - 29
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';
@@ -34,9 +35,9 @@ StandardNode.prototype.build = function ( builder ) {
 
 	builder.define('PHYSICAL');
 
-	var useClearCoat = this.clearCoat;
+	var useClearcoat = this.clearcoat;
 
-	if( useClearCoat ){
+	if( useClearcoat ){
 
 		builder.define( 'CLEARCOAT' );
 
@@ -130,6 +131,7 @@ StandardNode.prototype.build = function ( builder ) {
 
 		var contextEnvironment = {
 			bias: RoughnessToBlinnExponentNode,
+			viewNormal: new ExpressionNode('normal', 'v3'),
 			gamma: true
 		};
 
@@ -137,6 +139,11 @@ StandardNode.prototype.build = function ( builder ) {
 			gamma: true
 		};
 
+		var contextClearcoatEnvironment = {
+			bias: RoughnessToBlinnExponentNode,
+			viewNormal: new ExpressionNode('clearcoatNormal', 'v3'),
+			gamma: true
+		};
 
 		// analyze all nodes to reuse generate codes
 
@@ -150,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 );
 
@@ -178,6 +185,8 @@ StandardNode.prototype.build = function ( builder ) {
 
 		}
 
+		if ( this.sheen ) this.sheen.analyze( builder );
+
 		// build code
 
 		var mask = this.mask ? this.mask.flow( builder, 'b' ) : undefined;
@@ -190,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;
 
@@ -219,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;
 
@@ -299,11 +310,11 @@ StandardNode.prototype.build = function ( builder ) {
 
 		}
 
-		if ( clearCoatNormal ) {
+		if ( clearcoatNormal ) {
 
 			output.push(
-				clearCoatNormal.code,
-				'clearCoatNormal = ' + clearCoatNormal.result + ';'
+				clearcoatNormal.code,
+				'clearcoatNormal = ' + clearcoatNormal.result + ';'
 			);
 
 		}
@@ -315,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;' );
+			output.push( 'material.clearcoatRoughness = 0.0;' );
+
+		}
+
+		if ( sheen ) {
+
+			output.push( 'material.sheenColor = ' + sheen.result + ';' );
 
 		}
 
@@ -427,11 +444,11 @@ StandardNode.prototype.build = function ( builder ) {
 
 			}
 
-			if ( clearCoatEnv ) {
+			if ( clearcoatEnv ) {
 
 				output.push(
-					clearCoatEnv.code,
-					"clearCoatRadiance += " + clearCoatEnv.result + ";"
+					clearcoatEnv.code,
+					"clearcoatRadiance += " + clearcoatEnv.result + ";"
 				);
 
 			}
@@ -498,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;
 
@@ -513,6 +531,8 @@ StandardNode.prototype.copy = function ( source ) {
 
 	if ( source.environment ) this.environment = source.environment;
 
+	if ( source.sheen ) this.sheen = source.sheen;
+
 	return this;
 
 };
@@ -541,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;
 
@@ -556,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


+ 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;
 
 					} ) );
 

+ 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>

+ 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 ) );

+ 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": [

+ 1 - 41
src/loaders/Loader.d.ts

@@ -1,60 +1,20 @@
-import { Material } from './../materials/Material';
 import { LoaderHandler } from './FileLoader';
 
 // Loaders //////////////////////////////////////////////////////////////////////////////////
 
 /**
  * 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;
-
-	/**
-	 * Will be called when load completes.
-	 * The default is a function with empty body.
-	 */
-	onLoadComplete: () => void;
-
-	/**
-	 * default — null.
+	 * default — anonymous.
 	 * 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;
-
 	static Handlers: LoaderHandler;
 
 }

+ 1 - 292
src/loaders/Loader.js

@@ -1,42 +1,7 @@
-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';
-
 /**
  * @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 = {
@@ -74,265 +39,9 @@ Loader.Handlers = {
 
 Object.assign( Loader.prototype, {
 
-	crossOrigin: 'anonymous',
-
-	onLoadStart: function () {},
-
-	onLoadProgress: function () {},
-
-	onLoadComplete: function () {},
-
-	initMaterials: function ( materials, texturePath, crossOrigin ) {
-
-		var array = [];
-
-		for ( var i = 0; i < materials.length; ++ i ) {
-
-			array[ i ] = this.createMaterial( materials[ i ], texturePath, crossOrigin );
-
-		}
-
-		return array;
-
-	},
-
-	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;
-
-			}
-
-		}
-
-		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 );
-
-	}
+	crossOrigin: 'anonymous'
 
 } );
 
-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;
-
-}
 
 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;
 
 /**

+ 4 - 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;
@@ -229,8 +229,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;
 

+ 5 - 5
src/materials/Material.js

@@ -172,13 +172,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();
 
 		}
 

+ 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;
 
 }

+ 20 - 12
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> ),
  * }
  */
 
@@ -29,11 +32,13 @@ function MeshPhysicalMaterial( parameters ) {
 
 	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.setValues( parameters );
 
@@ -57,11 +62,14 @@ MeshPhysicalMaterial.prototype.copy = function ( source ) {
 
 	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 );
 
 	return this;
 

+ 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;

+ 7 - 6
src/renderers/WebGLRenderer.js

@@ -2269,17 +2269,18 @@ function WebGLRenderer( parameters ) {
 
 		uniforms.reflectivity.value = material.reflectivity; // also part of uniforms common
 
-		uniforms.clearCoat.value = material.clearCoat;
-		uniforms.clearCoatRoughness.value = material.clearCoatRoughness;
+		uniforms.clearcoat.value = material.clearcoat;
+		uniforms.clearcoatRoughness.value = material.clearcoatRoughness;
+		if ( material.sheen ) uniforms.sheen.value.copy( material.sheen );
 
-		if ( material.clearCoatNormalMap ) {
+		if ( material.clearcoatNormalMap ) {
 
-			uniforms.clearCoatNormalScale.value.copy( material.clearCoatNormalScale );
-			uniforms.clearCoatNormalMap.value = material.clearCoatNormalMap;
+			uniforms.clearcoatNormalScale.value.copy( material.clearcoatNormalScale );
+			uniforms.clearcoatNormalMap.value = material.clearcoatNormalMap;
 
 			if ( material.side === BackSide ) {
 
-				uniforms.clearCoatNormalScale.value.negate();
+				uniforms.clearcoatNormalScale.value.negate();
 
 			}
 

+ 31 - 0
src/renderers/shaders/ShaderChunk/bsdfs.glsl.js

@@ -336,4 +336,35 @@ float GGXRoughnessToBlinnExponent( const in float ggxRoughness ) {
 float BlinnExponentToGGXRoughness( const in float blinnExponent ) {
 	return sqrt( 2.0 / ( blinnExponent + 2.0 ) );
 }
+
+#if defined( USE_SHEEN )
+
+// https://github.com/google/filament/blob/master/shaders/src/brdf.fs#L94
+float D_Charlie(float roughness, float NoH) {
+	// Estevez and Kulla 2017, "Production Friendly Microfacet Sheen BRDF"
+	float invAlpha  = 1.0 / roughness;
+	float cos2h = NoH * NoH;
+	float sin2h = max(1.0 - cos2h, 0.0078125); // 2^(-14/2), so sin2h^2 > 0 in fp16
+	return (2.0 + invAlpha) * pow(sin2h, invAlpha * 0.5) / (2.0 * PI);
+}
+
+// https://github.com/google/filament/blob/master/shaders/src/brdf.fs#L136
+float V_Neubelt(float NoV, float NoL) {
+	// Neubelt and Pettineo 2013, "Crafting a Next-gen Material Pipeline for The Order: 1886"
+	return saturate(1.0 / (4.0 * (NoL + NoV - NoL * NoV)));
+}
+
+vec3 BRDF_Specular_Sheen( const in float roughness, const in vec3 L, const in GeometricContext geometry, vec3 specularColor ) {
+
+	vec3 N = geometry.normal;
+	vec3 V = geometry.viewDir;
+
+	vec3 H = normalize( V + L );
+	float dotNH = saturate( dot( N, H ) );
+
+	return specularColor * D_Charlie( roughness, dotNH ) * V_Neubelt( dot(N, V), dot(N, L) );
+
+}
+
+#endif
 `;

+ 1 - 1
src/renderers/shaders/ShaderChunk/clearcoat_normal_fragment_begin.glsl.js

@@ -1,7 +1,7 @@
 export default /* glsl */`
 #ifdef CLEARCOAT
 
-	vec3 clearCoatNormal = geometryNormal;
+	vec3 clearcoatNormal = geometryNormal;
 
 #endif
 `;

+ 4 - 4
src/renderers/shaders/ShaderChunk/clearcoat_normal_fragment_maps.glsl.js

@@ -3,14 +3,14 @@ export default /* glsl */`
 
 	#ifdef USE_TANGENT
 
-		mat3 vTBN = mat3( tangent, bitangent, clearCoatNormal );
+		mat3 vTBN = mat3( tangent, bitangent, clearcoatNormal );
 		vec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;
-		mapN.xy = clearCoatNormalScale * mapN.xy;
-		clearCoatNormal = normalize( vTBN * mapN );
+		mapN.xy = clearcoatNormalScale * mapN.xy;
+		clearcoatNormal = normalize( vTBN * mapN );
 
 	#else
 
-		clearCoatNormal = perturbNormal2Arb( - vViewPosition, clearCoatNormal, clearCoatNormalScale, clearCoatNormalMap );
+		clearcoatNormal = perturbNormal2Arb( - vViewPosition, clearcoatNormal, clearcoatNormalScale, clearcoatNormalMap );
 
 	#endif
 

+ 2 - 2
src/renderers/shaders/ShaderChunk/clearcoat_normalmap_pars_fragment.glsl.js

@@ -1,8 +1,8 @@
 export default /* glsl */`
 #ifdef USE_CLEARCOAT_NORMALMAP
 
-	uniform sampler2D clearCoatNormalMap;
-	uniform vec2 clearCoatNormalScale;
+	uniform sampler2D clearcoatNormalMap;
+	uniform vec2 clearcoatNormalScale;
 
 #endif
 `;

+ 1 - 1
src/renderers/shaders/ShaderChunk/common.glsl.js

@@ -40,7 +40,7 @@ struct GeometricContext {
 	vec3 normal;
 	vec3 viewDir;
 #ifdef CLEARCOAT
-	vec3 clearCoatNormal;
+	vec3 clearcoatNormal;
 #endif
 };
 

+ 2 - 2
src/renderers/shaders/ShaderChunk/lights_fragment_begin.glsl.js

@@ -22,7 +22,7 @@ geometry.viewDir = normalize( vViewPosition );
 
 #ifdef CLEARCOAT
 
-	geometry.clearCoatNormal = clearCoatNormal;
+	geometry.clearcoatNormal = clearcoatNormal;
 
 #endif
 
@@ -127,7 +127,7 @@ IncidentLight directLight;
 #if defined( RE_IndirectSpecular )
 
 	vec3 radiance = vec3( 0.0 );
-	vec3 clearCoatRadiance = vec3( 0.0 );
+	vec3 clearcoatRadiance = vec3( 0.0 );
 
 #endif
 `;

+ 1 - 1
src/renderers/shaders/ShaderChunk/lights_fragment_end.glsl.js

@@ -7,7 +7,7 @@ export default /* glsl */`
 
 #if defined( RE_IndirectSpecular )
 
-	RE_IndirectSpecular( radiance, irradiance, clearCoatRadiance, geometry, material, reflectedLight );
+	RE_IndirectSpecular( radiance, irradiance, clearcoatRadiance, geometry, material, reflectedLight );
 
 #endif
 `;

+ 1 - 1
src/renderers/shaders/ShaderChunk/lights_fragment_maps.glsl.js

@@ -29,7 +29,7 @@ export default /* glsl */`
 
 	#ifdef CLEARCOAT
 
-		clearCoatRadiance += getLightProbeIndirectRadiance( /*specularLightProbe,*/ geometry.viewDir, geometry.clearCoatNormal, Material_ClearCoat_BlinnShininessExponent( material ), maxMipLevel );
+		clearcoatRadiance += getLightProbeIndirectRadiance( /*specularLightProbe,*/ geometry.viewDir, geometry.clearcoatNormal, Material_Clearcoat_BlinnShininessExponent( material ), maxMipLevel );
 
 	#endif
 

+ 9 - 2
src/renderers/shaders/ShaderChunk/lights_physical_fragment.glsl.js

@@ -14,7 +14,14 @@ material.specularRoughness = clamp( roughnessFactor, 0.04, 1.0 );
 #endif
 
 #ifdef CLEARCOAT
-	material.clearCoat = saturate( clearCoat ); // Burley clearcoat model
-	material.clearCoatRoughness = clamp( clearCoatRoughness, 0.04, 1.0 );
+
+	material.clearcoat = saturate( clearcoat ); // Burley clearcoat model
+	material.clearcoatRoughness = clamp( clearcoatRoughness, 0.04, 1.0 );
+
+#endif
+#ifdef USE_SHEEN
+
+	material.sheenColor = sheen;
+
 #endif
 `;

+ 31 - 20
src/renderers/shaders/ShaderChunk/lights_physical_pars_fragment.glsl.js

@@ -5,10 +5,13 @@ struct PhysicalMaterial {
 	float	specularRoughness;
 	vec3	specularColor;
 
-	#ifdef CLEARCOAT
-		float clearCoat;
-		float clearCoatRoughness;
-	#endif
+#ifdef CLEARCOAT
+	float clearcoat;
+	float clearcoatRoughness;
+#endif
+#ifdef USE_SHEEN
+	vec3 sheenColor;
+#endif
 
 };
 
@@ -16,7 +19,7 @@ struct PhysicalMaterial {
 #define DEFAULT_SPECULAR_COEFFICIENT 0.04
 
 // Clear coat directional hemishperical reflectance (this approximation should be improved)
-float clearCoatDHRApprox( const in float roughness, const in float dotNL ) {
+float clearcoatDHRApprox( const in float roughness, const in float dotNL ) {
 
 	return DEFAULT_SPECULAR_COEFFICIENT + ( 1.0 - DEFAULT_SPECULAR_COEFFICIENT ) * ( pow( 1.0 - dotNL, 5.0 ) * pow( 1.0 - roughness, 2.0 ) );
 
@@ -78,7 +81,7 @@ void RE_Direct_Physical( const in IncidentLight directLight, const in GeometricC
 
 	#ifdef CLEARCOAT
 
-		float ccDotNL = saturate( dot( geometry.clearCoatNormal, directLight.direction ) );
+		float ccDotNL = saturate( dot( geometry.clearcoatNormal, directLight.direction ) );
 
 		vec3 ccIrradiance = ccDotNL * directLight.color;
 
@@ -88,20 +91,28 @@ void RE_Direct_Physical( const in IncidentLight directLight, const in GeometricC
 
 		#endif
 
-		float clearCoatDHR = material.clearCoat * clearCoatDHRApprox( material.clearCoatRoughness, ccDotNL );
+		float clearcoatDHR = material.clearcoat * clearcoatDHRApprox( material.clearcoatRoughness, ccDotNL );
 
-		reflectedLight.directSpecular += ccIrradiance * material.clearCoat * BRDF_Specular_GGX( directLight, geometry.viewDir, geometry.clearCoatNormal, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearCoatRoughness );
+		reflectedLight.directSpecular += ccIrradiance * material.clearcoat * BRDF_Specular_GGX( directLight, geometry.viewDir, geometry.clearcoatNormal, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearcoatRoughness );
 
 	#else
 
-		float clearCoatDHR = 0.0;
+		float clearcoatDHR = 0.0;
 
 	#endif
 
-	reflectedLight.directSpecular += ( 1.0 - clearCoatDHR ) * irradiance * BRDF_Specular_GGX( directLight, geometry.viewDir, geometry.normal, material.specularColor, material.specularRoughness );
-
-	reflectedLight.directDiffuse += ( 1.0 - clearCoatDHR ) * irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );
+	#ifdef USE_SHEEN
+		reflectedLight.directSpecular += ( 1.0 - clearcoatDHR ) * irradiance * BRDF_Specular_Sheen(
+			material.specularRoughness,
+			directLight.direction,
+			geometry,
+			material.sheenColor
+		);
+	#else
+		reflectedLight.directSpecular += ( 1.0 - clearcoatDHR ) * irradiance * BRDF_Specular_GGX( directLight, geometry.viewDir, geometry.normal, material.specularColor, material.specularRoughness);
+	#endif
 
+	reflectedLight.directDiffuse += ( 1.0 - clearcoatDHR ) * irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );
 }
 
 void RE_IndirectDiffuse_Physical( const in vec3 irradiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {
@@ -109,24 +120,24 @@ void RE_IndirectDiffuse_Physical( const in vec3 irradiance, const in GeometricCo
 
 }
 
-void RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 irradiance, const in vec3 clearCoatRadiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight) {
+void RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 irradiance, const in vec3 clearcoatRadiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight) {
 
 	#ifdef CLEARCOAT
 
-		float ccDotNV = saturate( dot( geometry.clearCoatNormal, geometry.viewDir ) );
+		float ccDotNV = saturate( dot( geometry.clearcoatNormal, geometry.viewDir ) );
 
-		reflectedLight.indirectSpecular += clearCoatRadiance * material.clearCoat * BRDF_Specular_GGX_Environment( geometry.viewDir, geometry.clearCoatNormal, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearCoatRoughness );
+		reflectedLight.indirectSpecular += clearcoatRadiance * material.clearcoat * BRDF_Specular_GGX_Environment( geometry.viewDir, geometry.clearcoatNormal, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearcoatRoughness );
 
 		float ccDotNL = ccDotNV;
-		float clearCoatDHR = material.clearCoat * clearCoatDHRApprox( material.clearCoatRoughness, ccDotNL );
+		float clearcoatDHR = material.clearcoat * clearcoatDHRApprox( material.clearcoatRoughness, ccDotNL );
 
 	#else
 
-		float clearCoatDHR = 0.0;
+		float clearcoatDHR = 0.0;
 
 	#endif
 
-	float clearCoatInv = 1.0 - clearCoatDHR;
+	float clearcoatInv = 1.0 - clearcoatDHR;
 
 	// Both indirect specular and diffuse light accumulate here
 	// if energy preservation enabled, and PMREM provided.
@@ -139,7 +150,7 @@ void RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 irradia
 
 	vec3 diffuse = material.diffuseColor * ( 1.0 - ( singleScattering + multiScattering ) );
 
-	reflectedLight.indirectSpecular += clearCoatInv * radiance * singleScattering;
+	reflectedLight.indirectSpecular += clearcoatInv * radiance * singleScattering;
 	reflectedLight.indirectDiffuse += multiScattering * cosineWeightedIrradiance;
 	reflectedLight.indirectDiffuse += diffuse * cosineWeightedIrradiance;
 
@@ -151,7 +162,7 @@ void RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 irradia
 #define RE_IndirectSpecular		RE_IndirectSpecular_Physical
 
 #define Material_BlinnShininessExponent( material )   GGXRoughnessToBlinnExponent( material.specularRoughness )
-#define Material_ClearCoat_BlinnShininessExponent( material )   GGXRoughnessToBlinnExponent( material.clearCoatRoughness )
+#define Material_Clearcoat_BlinnShininessExponent( material )   GGXRoughnessToBlinnExponent( material.clearcoatRoughness )
 
 // ref: https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf
 float computeSpecularOcclusion( const in float dotNV, const in float ambientOcclusion, const in float roughness ) {

+ 5 - 4
src/renderers/shaders/ShaderLib.js

@@ -273,10 +273,11 @@ ShaderLib.physical = {
 	uniforms: mergeUniforms( [
 		ShaderLib.standard.uniforms,
 		{
-			clearCoat: { value: 0 },
-			clearCoatRoughness: { value: 0 },
-			clearCoatNormalScale: { value: new Vector2( 1, 1 ) },
-			clearCoatNormalMap: { value: null },
+			clearcoat: { value: 0 },
+			clearcoatRoughness: { value: 0 },
+			sheen: { value: new Color( 0x000000 ) },
+			clearcoatNormalScale: { value: new Vector2( 1, 1 ) },
+			clearcoatNormalMap: { value: null },
 		}
 	] ),
 

+ 6 - 3
src/renderers/shaders/ShaderLib/meshphysical_frag.glsl.js

@@ -4,7 +4,7 @@ export default /* glsl */`
 #ifdef PHYSICAL
 
 	#define CLEARCOAT
-	// TODO: ANISOTROPY and SHEEN when merged
+
 #endif
 
 #ifdef ADVANCED_PHYSICAL
@@ -23,8 +23,11 @@ uniform float opacity;
 	uniform float reflectivity;
 #endif
 #ifdef CLEARCOAT
-	uniform float clearCoat;
-	uniform float clearCoatRoughness;
+	uniform float clearcoat;
+	uniform float clearcoatRoughness;
+#endif
+#ifdef USE_SHEEN
+	uniform vec3 sheen;
 #endif
 
 varying vec3 vViewPosition;

+ 6 - 4
src/renderers/webgl/WebGLProgram.js

@@ -120,7 +120,7 @@ function generateExtensions( extensions, parameters, rendererExtensions ) {
 	extensions = extensions || {};
 
 	var chunks = [
-		( extensions.derivatives || parameters.envMapCubeUV || parameters.bumpMap || parameters.tangentSpaceNormalMap || parameters.clearCoatNormalMap || parameters.flatShading ) ? '#extension GL_OES_standard_derivatives : enable' : '',
+		( extensions.derivatives || parameters.envMapCubeUV || parameters.bumpMap || parameters.tangentSpaceNormalMap || parameters.clearcoatNormalMap || parameters.flatShading ) ? '#extension GL_OES_standard_derivatives : enable' : '',
 		( extensions.fragDepth || parameters.logarithmicDepthBuffer ) && rendererExtensions.get( 'EXT_frag_depth' ) ? '#extension GL_EXT_frag_depth : enable' : '',
 		( extensions.drawBuffers ) && rendererExtensions.get( 'WEBGL_draw_buffers' ) ? '#extension GL_EXT_draw_buffers : require' : '',
 		( extensions.shaderTextureLOD || parameters.envMap ) && rendererExtensions.get( 'EXT_shader_texture_lod' ) ? '#extension GL_EXT_shader_texture_lod : enable' : ''
@@ -392,8 +392,8 @@ function WebGLProgram( renderer, extensions, code, material, shader, parameters,
 			parameters.normalMap ? '#define USE_NORMALMAP' : '',
 			( parameters.normalMap && parameters.objectSpaceNormalMap ) ? '#define OBJECTSPACE_NORMALMAP' : '',
 			( parameters.normalMap && parameters.tangentSpaceNormalMap ) ? '#define TANGENTSPACE_NORMALMAP' : '',
-
-			parameters.clearCoatNormalMap ? '#define USE_CLEARCOAT_NORMALMAP' : '',
+			
+			parameters.clearcoatNormalMap ? '#define USE_CLEARCOAT_NORMALMAP' : '',
 			parameters.displacementMap && parameters.supportsVertexTextures ? '#define USE_DISPLACEMENTMAP' : '',
 			parameters.specularMap ? '#define USE_SPECULARMAP' : '',
 			parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '',
@@ -512,12 +512,14 @@ function WebGLProgram( renderer, extensions, code, material, shader, parameters,
 			parameters.normalMap ? '#define USE_NORMALMAP' : '',
 			( parameters.normalMap && parameters.objectSpaceNormalMap ) ? '#define OBJECTSPACE_NORMALMAP' : '',
 			( parameters.normalMap && parameters.tangentSpaceNormalMap ) ? '#define TANGENTSPACE_NORMALMAP' : '',
-			parameters.clearCoatNormalMap ? '#define USE_CLEARCOAT_NORMALMAP' : '',
+			parameters.clearcoatNormalMap ? '#define USE_CLEARCOAT_NORMALMAP' : '',
 			parameters.specularMap ? '#define USE_SPECULARMAP' : '',
 			parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '',
 			parameters.metalnessMap ? '#define USE_METALNESSMAP' : '',
 			parameters.alphaMap ? '#define USE_ALPHAMAP' : '',
 
+			parameters.sheen ? '#define USE_SHEEN' : '',
+
 			parameters.vertexTangents ? '#define USE_TANGENT' : '',
 			parameters.vertexColors ? '#define USE_COLOR' : '',
 			parameters.vertexUvs ? '#define USE_UV' : '',

+ 7 - 4
src/renderers/webgl/WebGLPrograms.js

@@ -29,7 +29,7 @@ function WebGLPrograms( renderer, extensions, capabilities ) {
 
 	var parameterNames = [
 		"precision", "supportsVertexTextures", "map", "mapEncoding", "matcap", "matcapEncoding", "envMap", "envMapMode", "envMapEncoding",
-		"lightMap", "aoMap", "emissiveMap", "emissiveMapEncoding", "bumpMap", "normalMap", "objectSpaceNormalMap", "tangentSpaceNormalMap", "clearCoatNormalMap", "displacementMap", "specularMap",
+		"lightMap", "aoMap", "emissiveMap", "emissiveMapEncoding", "bumpMap", "normalMap", "objectSpaceNormalMap", "tangentSpaceNormalMap", "clearcoatNormalMap", "displacementMap", "specularMap",
 		"roughnessMap", "metalnessMap", "gradientMap",
 		"alphaMap", "combine", "vertexColors", "vertexTangents", "fog", "useFog", "fogExp2",
 		"flatShading", "sizeAttenuation", "logarithmicDepthBuffer", "skinning",
@@ -37,7 +37,8 @@ function WebGLPrograms( renderer, extensions, capabilities ) {
 		"maxMorphTargets", "maxMorphNormals", "premultipliedAlpha",
 		"numDirLights", "numPointLights", "numSpotLights", "numHemiLights", "numRectAreaLights",
 		"shadowMapEnabled", "shadowMapType", "toneMapping", 'physicallyCorrectLights',
-		"alphaTest", "doubleSided", "flipSided", "numClippingPlanes", "numClipIntersection", "depthPacking", "dithering"
+		"alphaTest", "doubleSided", "flipSided", "numClippingPlanes", "numClipIntersection", "depthPacking", "dithering",
+		"sheen"
 	];
 
 
@@ -154,7 +155,7 @@ function WebGLPrograms( renderer, extensions, capabilities ) {
 			normalMap: !! material.normalMap,
 			objectSpaceNormalMap: material.normalMapType === ObjectSpaceNormalMap,
 			tangentSpaceNormalMap: material.normalMapType === TangentSpaceNormalMap,
-			clearCoatNormalMap: !! material.clearCoatNormalMap,
+			clearcoatNormalMap: !! material.clearcoatNormalMap,
 			displacementMap: !! material.displacementMap,
 			roughnessMap: !! material.roughnessMap,
 			metalnessMap: !! material.metalnessMap,
@@ -163,11 +164,13 @@ function WebGLPrograms( renderer, extensions, capabilities ) {
 
 			gradientMap: !! material.gradientMap,
 
+			sheen: !! material.sheen,
+
 			combine: material.combine,
 
 			vertexTangents: ( material.normalMap && material.vertexTangents ),
 			vertexColors: material.vertexColors,
-			vertexUvs: !! material.map || !! material.bumpMap || !! material.normalMap || !! material.specularMap || !! material.alphaMap || !! material.emissiveMap || !! material.roughnessMap || !! material.metalnessMap || !! material.clearCoatNormalMap,
+			vertexUvs: !! material.map || !! material.bumpMap || !! material.normalMap || !! material.specularMap || !! material.alphaMap || !! material.emissiveMap || !! material.roughnessMap || !! material.metalnessMap || !! material.clearcoatNormalMap,
 
 			fog: !! fog,
 			useFog: material.fog,

+ 0 - 13
test/unit/src/loaders/Loader.tests.js

@@ -29,19 +29,6 @@ export default QUnit.module( 'Loaders', () => {
 
 		} );
 
-		// PUBLIC STUFF
-		QUnit.todo( "initMaterials", ( assert ) => {
-
-			assert.ok( false, "everything's gonna be alright" );
-
-		} );
-
-		QUnit.todo( "createMaterial", ( assert ) => {
-
-			assert.ok( false, "everything's gonna be alright" );
-
-		} );
-
 	} );
 
 } );

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است