Mr.doob 1 year ago
parent
commit
2cb20bb3e4
100 changed files with 1283 additions and 333 deletions
  1. 14 6
      build/three.cjs
  2. 14 6
      build/three.module.js
  3. 1 1
      build/three.module.min.js
  4. 1 1
      docs/api/ar/loaders/ObjectLoader.html
  5. 2 2
      docs/api/ar/loaders/managers/LoadingManager.html
  6. 8 1
      docs/api/ar/materials/MeshPhysicalMaterial.html
  7. 0 1
      docs/api/ar/materials/ShaderMaterial.html
  8. 1 2
      docs/api/ar/math/Plane.html
  9. 16 0
      docs/api/ar/renderers/WebGLRenderTarget.html
  10. 3 3
      docs/api/en/core/Object3D.html
  11. 1 1
      docs/api/en/loaders/ObjectLoader.html
  12. 2 2
      docs/api/en/loaders/managers/LoadingManager.html
  13. 8 0
      docs/api/en/materials/MeshPhysicalMaterial.html
  14. 0 1
      docs/api/en/materials/ShaderMaterial.html
  15. 1 1
      docs/api/en/math/Plane.html
  16. 24 0
      docs/api/en/objects/BatchedMesh.html
  17. 16 0
      docs/api/en/renderers/WebGLRenderTarget.html
  18. 8 0
      docs/api/fr/materials/MeshPhysicalMaterial.html
  19. 0 1
      docs/api/fr/materials/ShaderMaterial.html
  20. 1 1
      docs/api/it/loaders/ObjectLoader.html
  21. 2 2
      docs/api/it/loaders/managers/LoadingManager.html
  22. 8 0
      docs/api/it/materials/MeshPhysicalMaterial.html
  23. 0 1
      docs/api/it/materials/ShaderMaterial.html
  24. 1 1
      docs/api/it/math/Plane.html
  25. 16 0
      docs/api/it/renderers/WebGLRenderTarget.html
  26. 1 1
      docs/api/zh/cameras/PerspectiveCamera.html
  27. 4 5
      docs/api/zh/extras/ImageUtils.html
  28. 1 1
      docs/api/zh/loaders/ObjectLoader.html
  29. 2 2
      docs/api/zh/loaders/managers/LoadingManager.html
  30. 8 0
      docs/api/zh/materials/MeshPhysicalMaterial.html
  31. 0 1
      docs/api/zh/materials/ShaderMaterial.html
  32. 1 1
      docs/api/zh/math/Plane.html
  33. 24 0
      docs/api/zh/objects/BatchedMesh.html
  34. 17 1
      docs/api/zh/renderers/WebGLRenderTarget.html
  35. 1 0
      docs/examples/en/exporters/GLTFExporter.html
  36. 3 2
      docs/examples/en/loaders/GLTFLoader.html
  37. 1 1
      docs/examples/en/loaders/KTX2Loader.html
  38. 1 1
      docs/examples/en/postprocessing/EffectComposer.html
  39. 1 0
      docs/examples/zh/exporters/GLTFExporter.html
  40. 2 1
      docs/examples/zh/loaders/GLTFLoader.html
  41. 1 1
      docs/examples/zh/loaders/KTX2Loader.html
  42. 1 1
      docs/examples/zh/postprocessing/EffectComposer.html
  43. 1 0
      docs/manual/ar/introduction/Libraries-and-Plugins.html
  44. 1 1
      docs/manual/en/introduction/How-to-use-post-processing.html
  45. 1 0
      docs/manual/en/introduction/Libraries-and-Plugins.html
  46. 1 0
      docs/manual/fr/introduction/Libraries-and-Plugins.html
  47. 1 0
      docs/manual/it/introduction/Libraries-and-Plugins.html
  48. 1 0
      docs/manual/ja/introduction/Libraries-and-Plugins.html
  49. 2 2
      docs/manual/ko/introduction/Creating-a-scene.html
  50. 1 0
      docs/manual/pt-br/introduction/Libraries-and-Plugins.html
  51. 1 0
      docs/manual/zh/introduction/Libraries-and-Plugins.html
  52. 1 24
      editor/js/Loader.js
  53. 1 1
      editor/js/Menubar.File.js
  54. 2 2
      editor/js/Sidebar.Material.NumberProperty.js
  55. 10 0
      editor/js/Sidebar.Material.js
  56. 12 0
      editor/js/Strings.js
  57. 9 6
      editor/js/Viewport.js
  58. 8 1
      editor/js/libs/app/index.html
  59. 11 14
      examples/files.json
  60. 4 2
      examples/jsm/animation/CCDIKSolver.js
  61. 45 1
      examples/jsm/exporters/GLTFExporter.js
  62. 7 1
      examples/jsm/exporters/USDZExporter.js
  63. 2 2
      examples/jsm/libs/draco/README.md
  64. 283 99
      examples/jsm/loaders/EXRLoader.js
  65. 53 0
      examples/jsm/loaders/GLTFLoader.js
  66. 3 6
      examples/jsm/loaders/KTX2Loader.js
  67. 1 1
      examples/jsm/loaders/VRMLLoader.js
  68. 8 5
      examples/jsm/loaders/lwo/IFFParser.js
  69. 7 1
      examples/jsm/materials/MeshGouraudMaterial.js
  70. 26 20
      examples/jsm/math/Octree.js
  71. 4 3
      examples/jsm/nodes/Nodes.js
  72. 16 1
      examples/jsm/nodes/accessors/AccessorsUtils.js
  73. 3 2
      examples/jsm/nodes/accessors/ClippingNode.js
  74. 107 3
      examples/jsm/nodes/accessors/MaterialNode.js
  75. 9 0
      examples/jsm/nodes/accessors/StorageBufferNode.js
  76. 21 3
      examples/jsm/nodes/accessors/TextureNode.js
  77. 1 1
      examples/jsm/nodes/accessors/TextureSizeNode.js
  78. 0 8
      examples/jsm/nodes/code/FunctionNode.js
  79. 8 0
      examples/jsm/nodes/core/Node.js
  80. 5 9
      examples/jsm/nodes/core/NodeBuilder.js
  81. 2 1
      examples/jsm/nodes/core/OutputStructNode.js
  82. 10 0
      examples/jsm/nodes/core/PropertyNode.js
  83. 7 26
      examples/jsm/nodes/display/BumpMapNode.js
  84. 13 0
      examples/jsm/nodes/display/FrontFacingNode.js
  85. 1 1
      examples/jsm/nodes/display/ViewportDepthNode.js
  86. 4 2
      examples/jsm/nodes/display/ViewportNode.js
  87. 4 1
      examples/jsm/nodes/display/ViewportTextureNode.js
  88. 26 7
      examples/jsm/nodes/functions/BSDF/BRDF_GGX.js
  89. 28 0
      examples/jsm/nodes/functions/BSDF/D_GGX_Anisotropic.js
  90. 1 3
      examples/jsm/nodes/functions/BSDF/V_GGX_SmithCorrelated.js
  91. 29 0
      examples/jsm/nodes/functions/BSDF/V_GGX_SmithCorrelated_Anisotropic.js
  92. 1 1
      examples/jsm/nodes/functions/PhongLightingModel.js
  93. 164 10
      examples/jsm/nodes/functions/PhysicalLightingModel.js
  94. 31 0
      examples/jsm/nodes/functions/ShadowMaskModel.js
  95. 18 4
      examples/jsm/nodes/lighting/AnalyticLightNode.js
  96. 2 1
      examples/jsm/nodes/lighting/DirectionalLightNode.js
  97. 11 2
      examples/jsm/nodes/lighting/EnvironmentNode.js
  98. 24 0
      examples/jsm/nodes/lighting/IrradianceNode.js
  99. 11 1
      examples/jsm/nodes/lighting/LightsNode.js
  100. 2 1
      examples/jsm/nodes/lighting/PointLightNode.js

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


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


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


+ 1 - 1
docs/api/ar/loaders/ObjectLoader.html

@@ -53,7 +53,7 @@
 		 
 		<h2>أمثلة (Examples)</h2>
 		 
-		<p>[example:webgl_materials_lightmap WebGL / materials / lightmap]</p>
+		<p>[example:webgpu_materials_lightmap WebGL / materials / lightmap]</p>
 		 
 		<h2>المنشئ (Constructor)</h2>
 

+ 2 - 2
docs/api/ar/loaders/managers/LoadingManager.html

@@ -44,7 +44,7 @@
 			console.log( 'There was an error loading ' + url );
 		};
 	
-		const loader = new THREE.OBJLoader( manager );
+		const loader = new OBJLoader( manager );
 		loader.load( 'file.obj', function ( object ) {
 			//
 		} );
@@ -74,7 +74,7 @@
 		} );
 	
 		// Load as usual, then revoke the blob URLs.
-		const loader = new THREE.GLTFLoader( manager );
+		const loader = new GLTFLoader( manager );
 		loader.load( 'fish.gltf', (gltf) => {
 	
 			scene.add( gltf.scene );

+ 8 - 1
docs/api/ar/materials/MeshPhysicalMaterial.html

@@ -153,7 +153,14 @@
 		
 		يستخدم هذا بواسطة [page:WebGLRenderer] لتحديد المُظَهِّرات.
 		</p>
-		
+
+		<h3>[property:Float dispersion]</h3>
+		<p>
+			Defines the strength of the angular separation of colors (chromatic aberration) transmitting through a relatively clear volume.
+			Any value zero or larger is valid, the typical range of realistic values is `[0, 1]`.
+			Default is `0` (no dispersion).
+			This property can be only be used with transmissive objects, see [page:.transmission].
+		</p>
 
 		<h3>[property:Float ior]</h3>
 		<p>

+ 0 - 1
docs/api/ar/materials/ShaderMaterial.html

@@ -109,7 +109,6 @@
 		[example:webgl_lights_hemisphere webgl / lights / hemisphere]<br />
 		[example:webgl_marchingcubes webgl / marchingcubes]<br />
 		[example:webgl_materials_envmaps webgl / materials / envmaps]<br />
-		[example:webgl_materials_lightmap webgl / materials / lightmap]<br />
 		[example:webgl_materials_wireframe webgl / materials / wireframe]<br />
 		[example:webgl_modifier_tessellation webgl / modifier / tessellation]<br />
 		[example:webgl_postprocessing_dof2 webgl / postprocessing / dof2]<br />

+ 1 - 2
docs/api/ar/math/Plane.html

@@ -145,8 +145,7 @@
 		<p>
 		[page:Vector3 normal] - وحدة طول [page:Vector3] تحدد الطبيعي
 		من الطائرة. <br />
-		[page:Float constant] - المسافة الموقعة من المنشأ إلى الطائرة.
-		الافتراضي هو `0`. <br /><br />
+		[page:Float constant] - المسافة الموقعة من المنشأ إلى الطائرة. <br /><br />
 	 
 		يضع خصائص [page:.normal normal] و[page:.constant constant]
 		لهذه الطائرة عن طريق نسخ القيم من الطبيعي المعطى.

+ 16 - 0
docs/api/ar/renderers/WebGLRenderTarget.html

@@ -46,8 +46,11 @@
 		[page:Texture.anisotropy]<br />
 		[page:Constant colorSpace] - الافتراضي هو [page:Textures NoColorSpace].
 		<br />
+		[page:String internalFormat] - الافتراضي هو `null`.<br />
 		[page:Boolean depthBuffer] - الافتراضي هو `true`. <br />
 		[page:Boolean stencilBuffer] - الافتراضي هو `false`. <br />
+		[page:Boolean resolveDepthBuffer] - الافتراضي هو `true`. <br />
+		[page:Boolean resolveStencilBuffer] - الافتراضي هو `true`. <br />
 		[page:Number samples] - الافتراضي هو 0. <br /><br />
 		 
 		ينشئ جديدًا [name]
@@ -86,6 +89,19 @@
 	 
 		<h3>[property:Boolean stencilBuffer]</h3>
 		<p>يعرض على مخزن القالب. الافتراضي هو false.</p>
+
+		<h3>[property:Boolean resolveDepthBuffer]</h3>
+		<p>
+			Defines whether the depth buffer should be resolved when rendering into a multisampled render target. 
+			Default is `true`.
+		</p>
+
+		<h3>[property:Boolean resolveStencilBuffer]</h3>
+		<p>
+			Defines whether the stencil buffer should be resolved when rendering into a multisampled render target. 
+			This property has no effect when [page:.resolveDepthBuffer] is set to `false`. 
+			Default is `true`.
+		</p>
 	 
 		<h3>[property:DepthTexture depthTexture]</h3>
 		<p>

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

@@ -325,10 +325,10 @@
 
 		<h3>[method:this copy]( [param:Object3D object], [param:Boolean recursive] )</h3>
 		<p>
-			recursive -- if true, descendants of the object are also copied. Default
-			is true.<br /><br />
+			recursive -- If set to `true`, descendants of the object are copied next to the existing ones. 
+			If set to `false`, descendants are left unchanged. Default is `true`.<br /><br />
 
-			Copy the given object into this object. Note: event listeners and
+			Copies the given object into this object. Note: Event listeners and
 			user-defined callbacks ([page:.onAfterRender] and [page:.onBeforeRender])
 			are not copied.
 		</p>

+ 1 - 1
docs/api/en/loaders/ObjectLoader.html

@@ -53,7 +53,7 @@
 
 		<h2>Examples</h2>
 
-		<p>[example:webgl_materials_lightmap WebGL / materials / lightmap]</p>
+		<p>[example:webgpu_materials_lightmap WebGL / materials / lightmap]</p>
 
 		<h2>Constructor</h2>
 

+ 2 - 2
docs/api/en/loaders/managers/LoadingManager.html

@@ -44,7 +44,7 @@
 			console.log( 'There was an error loading ' + url );
 		};
 
-		const loader = new THREE.OBJLoader( manager );
+		const loader = new OBJLoader( manager );
 		loader.load( 'file.obj', function ( object ) {
 			//
 		} );
@@ -74,7 +74,7 @@
 		} );
 
 		// Load as usual, then revoke the blob URLs.
-		const loader = new THREE.GLTFLoader( manager );
+		const loader = new GLTFLoader( manager );
 		loader.load( 'fish.gltf', (gltf) => {
 
 			scene.add( gltf.scene );

+ 8 - 0
docs/api/en/materials/MeshPhysicalMaterial.html

@@ -187,6 +187,14 @@
 			This is used by the [page:WebGLRenderer] for selecting shaders.
 		</p>
 
+		<h3>[property:Float dispersion]</h3>
+		<p>
+			Defines the strength of the angular separation of colors (chromatic aberration) transmitting through a relatively clear volume.
+			Any value zero or larger is valid, the typical range of realistic values is `[0, 1]`.
+			Default is `0` (no dispersion).
+			This property can be only be used with transmissive objects, see [page:.transmission].
+		</p>
+
 		<h3>[property:Float ior]</h3>
 		<p>
 			Index-of-refraction for non-metallic materials, from `1.0` to `2.333`.

+ 0 - 1
docs/api/en/materials/ShaderMaterial.html

@@ -115,7 +115,6 @@
 			[example:webgl_lights_hemisphere webgl / lights / hemisphere]<br />
 			[example:webgl_marchingcubes webgl / marchingcubes]<br />
 			[example:webgl_materials_envmaps webgl / materials / envmaps]<br />
-			[example:webgl_materials_lightmap webgl / materials / lightmap]<br />
 			[example:webgl_materials_wireframe webgl / materials / wireframe]<br />
 			[example:webgl_modifier_tessellation webgl / modifier / tessellation]<br />
 			[example:webgl_postprocessing_dof2 webgl / postprocessing / dof2]<br />

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

@@ -146,7 +146,7 @@ const optionalNormalMatrix = new THREE.Matrix3().getNormalMatrix( matrix );
 			[page:Vector3 normal] - a unit length [page:Vector3] defining the normal
 			of the plane.<br />
 			[page:Float constant] - the signed distance from the origin to the plane.
-			Default is `0`.<br /><br />
+			<br /><br />
 
 			Sets this plane's [page:.normal normal] and [page:.constant constant]
 			properties by copying the values from the given normal.

+ 24 - 0
docs/api/en/objects/BatchedMesh.html

@@ -213,6 +213,30 @@
 			Replaces the geometry at `index` with the provided geometry. Throws an error if there is not enough space reserved for geometry at the index.
 		</p>
 
+		<h3>
+			[method:Integer getInstanceCountAt]( [param:Integer index] )
+		</h3>
+		<p>
+			[page:Integer index]: The index of an instance. Values have to be in the
+			range [0, count].
+		</p>
+		<p>
+			Gets the instance count of the geometry at `index`. Returns `null` if instance counts are not configured.
+		</p>
+
+		<h3>
+			[method:Integer setInstanceCountAt]( [param:Integer index], [param:Integer instanceCount ] )
+		</h3>
+		<p>
+			[page:Integer index]: Which geometry index to configure an instance count for.
+		</p>
+		<p>
+			[page:Integer instanceCount]: The number of instances to render of the given geometry index.
+		</p>
+		<p>
+			Sets an instance count of the geometry at `index`.
+		</p>
+
 		<h2>Source</h2>
 
 		<p>

+ 16 - 0
docs/api/en/renderers/WebGLRenderTarget.html

@@ -47,8 +47,11 @@
 			[page:Texture.anisotropy]<br />
 			[page:Constant colorSpace] - default is [page:Textures NoColorSpace].
 			<br />
+			[page:String internalFormat] - default is `null`.<br />
 			[page:Boolean depthBuffer] - default is `true`. <br />
 			[page:Boolean stencilBuffer] - default is `false`.<br />
+			[page:Boolean resolveDepthBuffer] - default is `true`.<br />
+			[page:Boolean resolveStencilBuffer] - default is `true`.<br />
 			[page:Number samples] - default is `0`.<br />
 			[page:Number count] - default is `1`.<br /><br />
 
@@ -96,6 +99,19 @@
 		<h3>[property:Boolean stencilBuffer]</h3>
 		<p>Renders to the stencil buffer. Default is false.</p>
 
+		<h3>[property:Boolean resolveDepthBuffer]</h3>
+		<p>
+			Defines whether the depth buffer should be resolved when rendering into a multisampled render target. 
+			Default is `true`.
+		</p>
+
+		<h3>[property:Boolean resolveStencilBuffer]</h3>
+		<p>
+			Defines whether the stencil buffer should be resolved when rendering into a multisampled render target. 
+			This property has no effect when [page:.resolveDepthBuffer] is set to `false`. 
+			Default is `true`.
+		</p>
+
 		<h3>[property:DepthTexture depthTexture]</h3>
 		<p>
 			If set, the scene depth will be rendered to this texture. Default is null.

+ 8 - 0
docs/api/fr/materials/MeshPhysicalMaterial.html

@@ -131,6 +131,14 @@
 			Est utilisé par [page:WebGLRenderer] pour sélectionner les shaders.
 		</p>
 
+		<h3>[property:Float dispersion]</h3>
+		<p>
+			Defines the strength of the angular separation of colors (chromatic aberration) transmitting through a relatively clear volume.
+			Any value zero or larger is valid, the typical range of realistic values is `[0, 1]`.
+			Default is `0` (no dispersion).
+			This property can be only be used with transmissive objects, see [page:.transmission].
+		</p>
+
 		<h3>[property:Float ior]</h3>
 		<p>
 			Indice de réfraction pour les matériaux non métalliques, de "1,0" à "2,333". La valeur par défaut est `1.5`.<br />

+ 0 - 1
docs/api/fr/materials/ShaderMaterial.html

@@ -107,7 +107,6 @@
 			[example:webgl_lights_hemisphere webgl / lights / hemisphere]<br />
 			[example:webgl_marchingcubes webgl / marchingcubes]<br />
 			[example:webgl_materials_envmaps webgl / materials / envmaps]<br />
-			[example:webgl_materials_lightmap webgl / materials / lightmap]<br />
 			[example:webgl_materials_wireframe webgl / materials / wireframe]<br />
 			[example:webgl_modifier_tessellation webgl / modifier / tessellation]<br />
 			[example:webgl_postprocessing_dof2 webgl / postprocessing / dof2]<br />

+ 1 - 1
docs/api/it/loaders/ObjectLoader.html

@@ -56,7 +56,7 @@
 		<h2>Esempi</h2>
 
 		<p>
-			[example:webgl_materials_lightmap WebGL / materials / lightmap]
+			[example:webgpu_materials_lightmap WebGL / materials / lightmap]
 		</p>
 
 		<h2>Costruttore</h2>

+ 2 - 2
docs/api/it/loaders/managers/LoadingManager.html

@@ -51,7 +51,7 @@
 
 		};
 
-		const loader = new THREE.OBJLoader( manager );
+		const loader = new OBJLoader( manager );
 		loader.load( 'file.obj', function ( object ) {
 
 			//
@@ -86,7 +86,7 @@
 		} );
 
 		// Carica come di solito, quindi revoca gli URL dei Blob 
-		const loader = new THREE.GLTFLoader( manager );
+		const loader = new GLTFLoader( manager );
 		loader.load( 'fish.gltf', (gltf) => {
 
 			scene.add( gltf.scene );

+ 8 - 0
docs/api/it/materials/MeshPhysicalMaterial.html

@@ -136,6 +136,14 @@
 			Questo viene utilizzato dal [page:WebGLRenderer] per selezionare gli shader.
 		</p>
 
+		<h3>[property:Float dispersion]</h3>
+		<p>
+			Defines the strength of the angular separation of colors (chromatic aberration) transmitting through a relatively clear volume.
+			Any value zero or larger is valid, the typical range of realistic values is `[0, 1]`.
+			Default is `0` (no dispersion).
+			This property can be only be used with transmissive objects, see [page:.transmission].
+		</p>
+
 		<h3>[property:Float ior]</h3>
 		<p>
 			Indice di rifrazione per materiali non metallici, da `1.0` a `2.333`. Il valore predefinito è `1.5`.<br />

+ 0 - 1
docs/api/it/materials/ShaderMaterial.html

@@ -109,7 +109,6 @@
 			[example:webgl_lights_hemisphere webgl / lights / hemisphere]<br />
 			[example:webgl_marchingcubes webgl / marchingcubes]<br />
 			[example:webgl_materials_envmaps webgl / materials / envmaps]<br />
-			[example:webgl_materials_lightmap webgl / materials / lightmap]<br />
 			[example:webgl_materials_wireframe webgl / materials / wireframe]<br />
 			[example:webgl_modifier_tessellation webgl / modifier / tessellation]<br />
 			[example:webgl_postprocessing_dof2 webgl / postprocessing / dof2]<br />

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

@@ -131,7 +131,7 @@
 		<h3>[method:this set]( [param:Vector3 normal], [param:Float constant] )</h3>
 		<p>
 			[page:Vector3 normal] - un [page:Vector3] di lunghezza unitaria che definisce la normale del piano.<br />
-			[page:Float constant] - la distanza con segno dall'origine al piano. Il valore predefinito è `0`.<br /><br />
+			[page:Float constant] - la distanza con segno dall'origine al piano.<br /><br />
 
 			Imposta le proprietà [page:.normal normal] e [page:.constant constant] del piano copiando i valori dalla normale data.
 		</p>

+ 16 - 0
docs/api/it/renderers/WebGLRenderTarget.html

@@ -40,8 +40,11 @@
 		[page:Constant type] - il valore predefinito è [page:Textures UnsignedByteType]. <br />
 		[page:Number anisotropy] - il valore predefinito è `1`. Vedi [page:Texture.anisotropy]<br />
 		[page:Constant colorSpace] - il valore predefinito è [page:Textures NoColorSpace]. <br />
+		[page:String internalFormat] - il valore predefinito è `null`.<br />
 		[page:Boolean depthBuffer] - il valore predefinito è `true`. <br />
 		[page:Boolean stencilBuffer] - il valore predefinito è `false`.<br />
+		[page:Boolean resolveDepthBuffer] - il valore predefinito è `true`.<br />
+		[page:Boolean resolveStencilBuffer] - il valore predefinito è `true`.<br />
 		[page:Number samples] - il valore predefinito è 0.<br />
 		[page:Number count] - default is `1`.<br /><br />
 
@@ -101,6 +104,19 @@
 			Effettua il rendering al buffer stencil. Il valore predefinito è `false`.
 		</p>
 
+		<h3>[property:Boolean resolveDepthBuffer]</h3>
+		<p>
+			Defines whether the depth buffer should be resolved when rendering into a multisampled render target. 
+			Il valore predefinito è `true`.
+		</p>
+
+		<h3>[property:Boolean resolveStencilBuffer]</h3>
+		<p>
+			Defines whether the stencil buffer should be resolved when rendering into a multisampled render target. 
+			This property has no effect when [page:.resolveDepthBuffer] is set to `false`. 
+			Il valore predefinito è `true`.
+		</p>
+
 		<h3>[property:DepthTexture depthTexture]</h3>
 		<p>
 			Se impostato, la profondità della scena verrà renderizzata su questa texture. Il valore predefinito è `null`.

+ 1 - 1
docs/api/zh/cameras/PerspectiveCamera.html

@@ -82,7 +82,7 @@
 
 		<h3>[property:Boolean isPerspectiveCamera]</h3>
 		<p>
-			Read-only flag to check if a given object is of type [name].
+			只读属性,用于检查给定的对象是否为 [name]。
 		</p>
 
 

+ 4 - 5
docs/api/zh/extras/ImageUtils.html

@@ -10,16 +10,15 @@
 		<h1>[name]</h1>
 
 		<p class="desc">
-		A class containing utility functions for images.
+		包含Image功能函数的工具类
 		</p>
 
-		<h2>Methods</h2>
+		<h2>方法(Methods</h2>
 
 		<h3>[method:String getDataURL]( [param:HTMLCanvasElement image] | [param:HTMLImageElement image] | [param:ImageBitmap image] )</h3>
 		<p>
-		image -- The image object.<br /><br />
-
-		Returns a data URI containing a representation of the given image.
+		image -- Image对象<br /><br />
+		返回Image对象的DataURL<br />
 		</p>
 
 		<h2>Source</h2>

+ 1 - 1
docs/api/zh/loaders/ObjectLoader.html

@@ -54,7 +54,7 @@
 		<h2>例子</h2>
 
 		<p>
-			[example:webgl_materials_lightmap WebGL / materials / lightmap]
+			[example:webgpu_materials_lightmap WebGL / materials / lightmap]
 		</p>
 
 		<h2>构造函数</h2>

+ 2 - 2
docs/api/zh/loaders/managers/LoadingManager.html

@@ -50,7 +50,7 @@
 
 		};
 
-		const loader = new THREE.OBJLoader( manager );
+		const loader = new OBJLoader( manager );
 		loader.load( 'file.obj', function ( object ) {
 
 			//
@@ -83,7 +83,7 @@
 		} );
 
 		// 像通常一样加载,然后撤消blob URL
-		const loader = new THREE.GLTFLoader( manager );
+		const loader = new GLTFLoader( manager );
 		loader.load( 'fish.gltf', (gltf) => {
 
 			scene.add( gltf.scene );

+ 8 - 0
docs/api/zh/materials/MeshPhysicalMaterial.html

@@ -119,6 +119,14 @@
 			[page:WebGLRenderer]使用它来选择shaders。
 		</p>
 
+		<h3>[property:Float dispersion]</h3>
+		<p>
+			Defines the strength of the angular separation of colors (chromatic aberration) transmitting through a relatively clear volume.
+			Any value zero or larger is valid, the typical range of realistic values is `[0, 1]`.
+			Default is `0` (no dispersion).
+			This property can be only be used with transmissive objects, see [page:.transmission].
+		</p>
+
 		<h3>[property:Float ior]</h3>
 		<p>
 			为非金属材质所设置的折射率,范围由*1.0*到*2.333*。默认为*1.5*。

+ 0 - 1
docs/api/zh/materials/ShaderMaterial.html

@@ -97,7 +97,6 @@
 			[example:webgl_lights_hemisphere webgl / lights / hemisphere]<br />
 			[example:webgl_marchingcubes webgl / marchingcubes]<br />
 			[example:webgl_materials_envmaps webgl / materials / envmaps]<br />
-			[example:webgl_materials_lightmap webgl / materials / lightmap]<br />
 			[example:webgl_materials_wireframe webgl / materials / wireframe]<br />
 			[example:webgl_modifier_tessellation webgl / modifier / tessellation]<br />
 			[example:webgl_postprocessing_dof2 webgl / postprocessing / dof2]<br />

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

@@ -125,7 +125,7 @@
 		<h3>[method:this set]( [param:Vector3 normal], [param:Float constant] )</h3>
 		<p>
 			[page:Vector3 normal] - 单位长度的向量表示平面的法向量。<br />
-			[page:Float constant] - 原点到平面有符号距离。默认值为 *0*。<br /><br />
+			[page:Float constant] - 原点到平面有符号距离。<br /><br />
 
 			设置平面 [page:.normal normal] 的法线和常量 [page:.constant constant] 属性值。
 		</p>

+ 24 - 0
docs/api/zh/objects/BatchedMesh.html

@@ -191,6 +191,30 @@
 		用提供的几何图形替换 `index` 的几何图形。如果索引处没有为几何体保留足够的空间,则会引发错误。
 	</p>
 
+	<h3>
+		[method:Integer getInstanceCountAt]( [param:Integer index] )
+	</h3>
+	<p>
+		[page:Integer index]: The index of an instance. Values have to be in the
+		range [0, count].
+	</p>
+	<p>
+		Gets the instance count of the geometry at `index`. Returns `null` if instance counts are not configured.
+	</p>
+
+	<h3>
+		[method:Integer setInstanceCountAt]( [param:Integer index], [param:Integer instanceCount ] )
+	</h3>
+	<p>
+		[page:Integer index]: Which geometry index to configure an instance count for.
+	</p>
+	<p>
+		[page:Integer instanceCount]: The number of instances to render of the given geometry index.
+	</p>
+	<p>
+		Sets an instance count of the geometry at `index`.
+	</p>
+
 	<h2>源代码</h2>
 
 	<p>

+ 17 - 1
docs/api/zh/renderers/WebGLRenderTarget.html

@@ -36,8 +36,11 @@
 		[page:Constant type] - 默认是[page:Textures UnsignedByteType]. <br />
 		[page:Number anisotropy] - 默认是`1`. 参见[page:Texture.anisotropy]<br />
 		[page:Constant colorSpace] - 默认是[page:Textures NoColorSpace]. <br />
+		[page:String internalFormat] -  默认是 `null`.<br />
 		[page:Boolean depthBuffer] - 默认是`true`.<br />
 		[page:Boolean stencilBuffer] - 默认是`false`.<br />
+		[page:Boolean resolveDepthBuffer] - 默认是`true`.<br />
+		[page:Boolean resolveStencilBuffer] - 默认是`true`.<br />
 		[page:Number samples] - 默认是`0`.<br />
 		[page:Number count] - default is `1`.<br /><br />
 
@@ -94,7 +97,20 @@
 
 		<h3>[property:Boolean stencilBuffer]</h3>
 		<p>
-		渲染到模板缓冲区。默认为false
+		渲染到模板缓冲区。默认为false.
+		</p>
+
+		<h3>[property:Boolean resolveDepthBuffer]</h3>
+		<p>
+			Defines whether the depth buffer should be resolved when rendering into a multisampled render target. 
+			默认为`true`.
+		</p>
+
+		<h3>[property:Boolean resolveStencilBuffer]</h3>
+		<p>
+			Defines whether the stencil buffer should be resolved when rendering into a multisampled render target. 
+			This property has no effect when [page:.resolveDepthBuffer] is set to `false`. 
+			默认为`true`.
 		</p>
 
 		<h3>[property:DepthTexture depthTexture]</h3>

+ 1 - 0
docs/examples/en/exporters/GLTFExporter.html

@@ -41,6 +41,7 @@
 		<ul>
 			<li>KHR_lights_punctual</li>
 			<li>KHR_materials_clearcoat</li>
+			<li>KHR_materials_dispersion</li>
 			<li>KHR_materials_emissive_strength</li>
 			<li>KHR_materials_ior</li>
 			<li>KHR_materials_iridescence</li>		

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

@@ -46,6 +46,7 @@
 		<ul>
 			<li>KHR_draco_mesh_compression</li>
 			<li>KHR_materials_clearcoat</li>
+			<li>KHR_materials_dispersion</li>
 			<li>KHR_materials_ior</li>
 			<li>KHR_materials_specular</li>
 			<li>KHR_materials_transmission</li>
@@ -190,7 +191,7 @@
 
 		<h3>[method:this setDRACOLoader]( [param:DRACOLoader dracoLoader] )</h3>
 		<p>
-		[page:DRACOLoader dracoLoader] — Instance of THREE.DRACOLoader, to be used for decoding assets compressed with the KHR_draco_mesh_compression extension.
+		[page:DRACOLoader dracoLoader] — Instance of DRACOLoader, to be used for decoding assets compressed with the KHR_draco_mesh_compression extension.
 		</p>
 		<p>
 		Refer to this [link:https://github.com/mrdoob/three.js/tree/dev/examples/jsm/libs/draco#readme readme] for the details of Draco and its decoder.
@@ -198,7 +199,7 @@
 
 		<h3>[method:this setKTX2Loader]( [param:KTX2Loader ktx2Loader] )</h3>
 		<p>
-		[page:KTX2Loader ktx2Loader] — Instance of THREE.KTX2Loader, to be used for loading KTX2 compressed textures.
+		[page:KTX2Loader ktx2Loader] — Instance of KTX2Loader, to be used for loading KTX2 compressed textures.
 		</p>
 
 		<h3>[method:undefined parse]( [param:ArrayBuffer data], [param:String path], [param:Function onLoad], [param:Function onError] )</h3>

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

@@ -41,7 +41,7 @@
 		<h2>Code Example</h2>
 
 		<code>
-		var ktx2Loader = new THREE.KTX2Loader();
+		var ktx2Loader = new KTX2Loader();
 		ktx2Loader.setTranscoderPath( 'examples/jsm/libs/basis/' );
 		ktx2Loader.detectSupport( renderer );
 		ktx2Loader.load( 'diffuse.ktx2', function ( texture ) {

+ 1 - 1
docs/examples/en/postprocessing/EffectComposer.html

@@ -33,7 +33,7 @@
 			[example:webgl_postprocessing postprocessing]<br />
 			[example:webgl_postprocessing_advanced postprocessing advanced]<br />
 			[example:webgl_postprocessing_backgrounds postprocessing backgrounds]<br />
-			[example:webgl_postprocessing_crossfade postprocessing crossfade]<br />
+			[example:webgl_postprocessing_transition postprocessing transition]<br />
 			[example:webgl_postprocessing_dof postprocessing depth-of-field]<br />
 			[example:webgl_postprocessing_dof2 postprocessing depth-of-field 2]<br />
 			[example:webgl_postprocessing_fxaa postprocessing fxaa]<br />

+ 1 - 0
docs/examples/zh/exporters/GLTFExporter.html

@@ -39,6 +39,7 @@
 	<ul>
 		<li>KHR_lights_punctual</li>
 		<li>KHR_materials_clearcoat</li>
+		<li>KHR_materials_dispersion</li>
 		<li>KHR_materials_emissive_strength</li>
 		<li>KHR_materials_ior</li>
 		<li>KHR_materials_iridescence</li>

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

@@ -45,6 +45,7 @@
 		<ul>
 			<li>KHR_draco_mesh_compression</li>
 			<li>KHR_materials_clearcoat</li>
+			<li>KHR_materials_dispersion</li>
 			<li>KHR_materials_ior</li>
 			<li>KHR_materials_specular</li>
 			<li>KHR_materials_transmission</li>
@@ -196,7 +197,7 @@
 
 		<h3>[method:this setDRACOLoader]( [param:DRACOLoader dracoLoader] )</h3>
 		<p>
-		[page:DRACOLoader dracoLoader] — THREE.DRACOLoader的实例,用于解码使用KHR_draco_mesh_compression扩展压缩过的文件。
+		[page:DRACOLoader dracoLoader] — DRACOLoader的实例,用于解码使用KHR_draco_mesh_compression扩展压缩过的文件。
 		</p>
 		<p>
 		请参阅[link:https://github.com/mrdoob/three.js/tree/dev/examples/jsm/libs/draco#readme readme]来了解Draco及其解码器的详细信息。

+ 1 - 1
docs/examples/zh/loaders/KTX2Loader.html

@@ -38,7 +38,7 @@
 	<h2>代码示例</h2>
 
 	<code>
-		var ktx2Loader = new THREE.KTX2Loader();
+		var ktx2Loader = new KTX2Loader();
 		ktx2Loader.setTranscoderPath( 'examples/jsm/libs/basis/' );
 		ktx2Loader.detectSupport( renderer );
 		ktx2Loader.load( 'diffuse.ktx2', function ( texture ) {

+ 1 - 1
docs/examples/zh/postprocessing/EffectComposer.html

@@ -32,7 +32,7 @@
 			[example:webgl_postprocessing postprocessing]<br />
 			[example:webgl_postprocessing_advanced postprocessing advanced]<br />
 			[example:webgl_postprocessing_backgrounds postprocessing backgrounds]<br />
-			[example:webgl_postprocessing_crossfade postprocessing crossfade]<br />
+			[example:webgl_postprocessing_transition postprocessing transition]<br />
 			[example:webgl_postprocessing_dof postprocessing depth-of-field]<br />
 			[example:webgl_postprocessing_dof2 postprocessing depth-of-field 2]<br />
 			[example:webgl_postprocessing_fxaa postprocessing fxaa]<br />

+ 1 - 0
docs/manual/ar/introduction/Libraries-and-Plugins.html

@@ -102,6 +102,7 @@
 			<li>[link:https://aframe.io/ A-Frame]</li>
 			<li>[link:https://lume.io/ Lume] - HTML elements for 3D graphics built on Three.</li>
 			<li>[link:https://github.com/pmndrs/react-three-fiber react-three-fiber] - React components for 3D graphics built on Three.</li>
+			<li>[link:https://threepipe.org/ threepipe] - A versatile 3D viewer framework using three.js for rendering.</li>
 			<li>[link:https://github.com/ecsyjs/ecsy-three ECSY]</li>
 			<li>[link:https://threlte.xyz/ Threlte] - Svelte components for 3D graphics built on Three.</li>
 			<li>[link:https://needle.tools/ Needle Engine]</li>

+ 1 - 1
docs/manual/en/introduction/How-to-use-post-processing.html

@@ -77,7 +77,7 @@
 
 		<p>
 			`RenderPass` is normally placed at the beginning of the chain in order to provide the rendered scene as an input for the next post-processing step. In our case,
-			`GlitchPass` is going to use these image data to apply a wild glitch effect. `OutputPass` is usually the last pass in the chain which performs sRGB color space conversion and optional tone mapping.
+			`GlitchPass` is going to use these image data to apply a wild glitch effect. `OutputPass` is usually the last pass in the chain which performs sRGB color space conversion and tone mapping.
 			Check out this [link:https://threejs.org/examples/webgl_postprocessing_glitch live example] to see it in action.
 		</p>
 

+ 1 - 0
docs/manual/en/introduction/Libraries-and-Plugins.html

@@ -106,6 +106,7 @@
 			<li>[link:https://aframe.io/ A-Frame]</li>
 			<li>[link:https://lume.io/ Lume] - HTML elements for 3D graphics built on Three.</li>
 			<li>[link:https://github.com/pmndrs/react-three-fiber react-three-fiber] - React components for 3D graphics built on Three.</li>
+			<li>[link:https://threepipe.org/ threepipe] - A versatile 3D viewer framework using three.js for rendering.</li>
 			<li>[link:https://github.com/ecsyjs/ecsy-three ECSY]</li>
 			<li>[link:https://threlte.xyz/ Threlte] - Svelte components for 3D graphics built on Three.</li>
 			<li>[link:https://needle.tools/ Needle Engine]</li>

+ 1 - 0
docs/manual/fr/introduction/Libraries-and-Plugins.html

@@ -105,6 +105,7 @@
 			<li>[link:https://aframe.io/ A-Frame]</li>
 			<li>[link:https://lume.io/ Lume] - HTML elements for 3D graphics built on Three.</li>
 			<li>[link:https://github.com/pmndrs/react-three-fiber react-three-fiber] - React components for 3D graphics built on Three.</li>
+			<li>[link:https://threepipe.org/ threepipe] - A versatile 3D viewer framework using three.js for rendering.</li>
 			<li>[link:https://github.com/ecsyjs/ecsy-three ECSY]</li>
 			<li>[link:https://threlte.xyz/ Threlte] - Svelte components for 3D graphics built on Three.</li>
 			<li>[link:https://needle.tools/ Needle Engine]</li>

+ 1 - 0
docs/manual/it/introduction/Libraries-and-Plugins.html

@@ -105,6 +105,7 @@
 			<li>[link:https://aframe.io/ A-Frame]</li>
 			<li>[link:https://lume.io/ Lume] - HTML elements for 3D graphics built on Three.</li>
 			<li>[link:https://github.com/pmndrs/react-three-fiber react-three-fiber] - React components for 3D graphics built on Three.</li>
+			<li>[link:https://threepipe.org/ threepipe] - A versatile 3D viewer framework using three.js for rendering.</li>
 			<li>[link:https://github.com/ecsyjs/ecsy-three ECSY]</li>
 			<li>[link:https://threlte.xyz/ Threlte] - Svelte components for 3D graphics built on Three.</li>
 			<li>[link:https://needle.tools/ Needle Engine]</li>

+ 1 - 0
docs/manual/ja/introduction/Libraries-and-Plugins.html

@@ -98,6 +98,7 @@
         <li>[link:https://aframe.io/ A-Frame]</li>
         <li>[link:https://lume.io/ Lume] - HTML elements for 3D graphics built on Three.</li>
         <li>[link:https://github.com/pmndrs/react-three-fiber react-three-fiber] - React components for 3D graphics built on Three.</li>
+        <li>[link:https://threepipe.org/ threepipe] - A versatile 3D viewer framework using three.js for rendering.</li>
         <li>[link:https://github.com/ecsyjs/ecsy-three ECSY]</li>
         <li>[link:https://threlte.xyz/ Threlte] - Svelte components for 3D graphics built on Three.</li>
         <li>[link:https://needle.tools/ Needle Engine]</li>

+ 2 - 2
docs/manual/ko/introduction/Creating-a-scene.html

@@ -63,7 +63,7 @@
 
 		<p>다음은 renderer입니다. 마법이 일어나는 곳입니다. 같이 사용하는 WebGLRenderer와 더불어, three.js는 다른 몇가지 renderer를 사용하는데, 오래된 브라우저 혹은 모종의 사유로 WebGL을 지원 안할때의 대비용으로 사용하는 것입니다.</p>
 
-		<p>renderer 인스턴스를 생섬함과 동시에, 렌더링 할 곳의 크기를 설정해줘야 합니다. 렌더링할 구역의 높이와 너비를 설정하는 것은 좋은 방법입니다. 이 경우, 높이와 너비는 각각 브라우저 윈도우의 크기가 됩니다. 성능 개선을 중시하는 앱의 경우, <strong>setSize</strong>를 사용하거나 <strong>window.innerWidth/2</strong>, <strong>window.innerHeight/2</strong>를 사용해서 화면 크기의 절반으로 구현할 수도 잇씁니다.</p>
+		<p>renderer 인스턴스를 생성함과 동시에, 렌더링할 곳의 크기를 설정해줘야 합니다. 렌더링할 구역의 높이와 너비를 설정하는 것은 좋은 방법입니다. 이 경우, 높이와 너비는 각각 브라우저 윈도우의 크기가 됩니다. 성능 개선을 중시하는 앱의 경우, <strong>setSize</strong>를 사용하거나 <strong>window.innerWidth/2</strong>, <strong>window.innerHeight/2</strong>를 사용해서 화면 크기의 절반으로 구현할 수도 있습니다.</p>
 
 		<p>사이즈는 그대로 유지하고 싶지만 더 낮은 해상도로 렌더링하고 싶을 경우, <strong>setSize</strong>의 <strong>updateStyle</strong> (세 번째 인자)를 false로 불러오면 됩니다. <strong>setSize(window.innerWidth/2, window.innerHeight/2, false)</strong>처럼 사용하면 &lt;canvas&gt;가 100%의 높이, 너비로 되어있다는 기준 하에 절반의 해상도로 렌더링 될 것입니다.</p>
 
@@ -90,7 +90,7 @@
 
 		<h2>scene 렌더링</h2>
 
-		<p>맨 처음에 있던 HTML 파일을 복사해서 열어놨다면, 아무것도 보이지 않을 것입니다. 왜냐하면 아직 아무것도 렌더링하지 않았기 때문입니다. 이를 해결하려면 <strong>render or animate loop</strong>라는 것이 필요합니다..</p>
+		<p>맨 처음에 있던 HTML 파일을 복사해서 열어놨다면, 아무것도 보이지 않을 것입니다. 왜냐하면 아직 아무것도 렌더링하지 않았기 때문입니다. 이를 해결하려면 <strong>render or animate loop</strong>라는 것이 필요합니다.</p>
 
 		<code>
 		function animate() {

+ 1 - 0
docs/manual/pt-br/introduction/Libraries-and-Plugins.html

@@ -105,6 +105,7 @@
 			<li>[link:https://aframe.io/ A-Frame]</li>
 			<li>[link:https://lume.io/ Lume] - HTML elements for 3D graphics built on Three.</li>
 			<li>[link:https://github.com/pmndrs/react-three-fiber react-three-fiber] - React components for 3D graphics built on Three.</li>
+			<li>[link:https://threepipe.org/ threepipe] - A versatile 3D viewer framework using three.js for rendering.</li>
 			<li>[link:https://github.com/ecsyjs/ecsy-three ECSY]</li>
 			<li>[link:https://threlte.xyz/ Threlte] - Svelte components for 3D graphics built on Three.</li>
 			<li>[link:https://needle.tools/ Needle Engine]</li>

+ 1 - 0
docs/manual/zh/introduction/Libraries-and-Plugins.html

@@ -101,6 +101,7 @@
 			<li>[link:https://aframe.io/ A-Frame]</li>
 			<li>[link:https://lume.io/ Lume] - HTML elements for 3D graphics built on Three.</li>
 			<li>[link:https://github.com/pmndrs/react-three-fiber react-three-fiber] - React components for 3D graphics built on Three.</li>
+			<li>[link:https://threepipe.org/ threepipe] - A versatile 3D viewer framework using three.js for rendering.</li>
 			<li>[link:https://github.com/ecsyjs/ecsy-three ECSY]</li>
 			<li>[link:https://threlte.xyz/ Threlte] - Svelte components for 3D graphics built on Three.</li>
 			<li>[link:https://needle.tools/ Needle Engine]</li>

+ 1 - 24
editor/js/Loader.js

@@ -376,29 +376,6 @@ function Loader( editor ) {
 
 			}
 
-			case 'ifc':
-
-			{
-
-				reader.addEventListener( 'load', async function ( event ) {
-
-					const { IFCLoader } = await import( 'three/addons/loaders/IFCLoader.js' );
-
-					var loader = new IFCLoader();
-					loader.ifcManager.setWasmPath( 'three/addons/loaders/ifc/' );
-
-					const model = await loader.parse( event.target.result );
-					model.mesh.name = filename;
-
-					editor.execute( new AddObjectCommand( editor, model.mesh ) );
-
-				}, false );
-				reader.readAsArrayBuffer( file );
-
-				break;
-
-			}
-
 			case 'kmz':
 
 			{
@@ -997,7 +974,7 @@ function Loader( editor ) {
 		const dracoLoader = new DRACOLoader();
 		dracoLoader.setDecoderPath( '../examples/jsm/libs/draco/gltf/' );
 
-		const ktx2Loader = new KTX2Loader();
+		const ktx2Loader = new KTX2Loader( manager );
 		ktx2Loader.setTranscoderPath( '../examples/jsm/libs/basis/' );
 
 		editor.signals.rendererDetectKTX2Support.dispatch( ktx2Loader );

+ 1 - 1
editor/js/Menubar.File.js

@@ -278,7 +278,7 @@ function MenubarFile( editor ) {
 
 		const exporter = new USDZExporter();
 
-		saveArrayBuffer( await exporter.parse( editor.scene ), 'model.usdz' );
+		saveArrayBuffer( await exporter.parseAsync( editor.scene ), 'model.usdz' );
 
 	} );
 	options.add( option );

+ 2 - 2
editor/js/Sidebar.Material.NumberProperty.js

@@ -1,14 +1,14 @@
 import { UINumber, UIRow, UIText } from './libs/ui.js';
 import { SetMaterialValueCommand } from './commands/SetMaterialValueCommand.js';
 
-function SidebarMaterialNumberProperty( editor, property, name, range = [ - Infinity, Infinity ] ) {
+function SidebarMaterialNumberProperty( editor, property, name, range = [ - Infinity, Infinity ], precision = 2 ) {
 
 	const signals = editor.signals;
 
 	const container = new UIRow();
 	container.add( new UIText( name ).setClass( 'Label' ) );
 
-	const number = new UINumber().setWidth( '60px' ).setRange( range[ 0 ], range[ 1 ] ).onChange( onChange );
+	const number = new UINumber().setWidth( '60px' ).setRange( range[ 0 ], range[ 1 ] ).setPrecision( precision ).onChange( onChange );
 	container.add( number );
 
 	let object = null;

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

@@ -111,6 +111,11 @@ function SidebarMaterial( editor ) {
 	const materialReflectivity = new SidebarMaterialNumberProperty( editor, 'reflectivity', strings.getKey( 'sidebar/material/reflectivity' ) );
 	container.add( materialReflectivity );
 
+	// ior
+
+	const materialIOR = new SidebarMaterialNumberProperty( editor, 'ior', strings.getKey( 'sidebar/material/ior' ), [ 1, 2.333 ], 3 );
+	container.add( materialIOR );
+
 	// roughness
 
 	const materialRoughness = new SidebarMaterialNumberProperty( editor, 'roughness', strings.getKey( 'sidebar/material/roughness' ), [ 0, 1 ] );
@@ -131,6 +136,11 @@ function SidebarMaterial( editor ) {
 	const materialClearcoatRoughness = new SidebarMaterialNumberProperty( editor, 'clearcoatRoughness', strings.getKey( 'sidebar/material/clearcoatroughness' ), [ 0, 1 ] );
 	container.add( materialClearcoatRoughness );
 
+	// dispersion
+
+	const materialDispersion = new SidebarMaterialNumberProperty( editor, 'dispersion', strings.getKey( 'sidebar/material/dispersion' ), [ 0, 10 ] );
+	container.add( materialDispersion );
+
 	// iridescence
 
 	const materialIridescence = new SidebarMaterialNumberProperty( editor, 'iridescence', strings.getKey( 'sidebar/material/iridescence' ), [ 0, 1 ] );

+ 12 - 0
editor/js/Strings.js

@@ -251,6 +251,8 @@ function Strings( config ) {
 			'sidebar/material/shininess': 'Shininess',
 			'sidebar/material/clearcoat': 'Clearcoat',
 			'sidebar/material/clearcoatroughness': 'Clearcoat Roughness',
+			'sidebar/material/dispersion': 'Dispersion',
+			'sidebar/material/ior': 'IOR',
 			'sidebar/material/iridescence': 'Iridescence',
 			'sidebar/material/iridescenceIOR': 'Thin-Film IOR',
 			'sidebar/material/iridescenceThicknessMax': 'Thin-Film Thickness',
@@ -602,6 +604,8 @@ function Strings( config ) {
 			'sidebar/material/shininess': 'Brillance',
 			'sidebar/material/clearcoat': 'Vernis',
 			'sidebar/material/clearcoatroughness': 'Rugosité du vernis',
+			'sidebar/material/dispersion': 'Dispersion',
+			'sidebar/material/ior': 'IOR',
 			'sidebar/material/iridescence': 'Iridescence',
 			'sidebar/material/iridescenceIOR': 'Thin-Film IOR',
 			'sidebar/material/iridescenceThicknessMax': 'Thin-Film Thickness',
@@ -618,7 +622,9 @@ function Strings( config ) {
 			'sidebar/material/alphamap': 'Texture de transparence',
 			'sidebar/material/bumpmap': 'Texture de relief',
 			'sidebar/material/normalmap': 'Texture de normales',
+			'sidebar/material/clearcoatmap': 'Clearcoat Map',
 			'sidebar/material/clearcoatnormalmap': 'Texture des normales du vernis',
+			'sidebar/material/clearcoatroughnessmap': 'Clearcoat Roughness Map',
 			'sidebar/material/displacementmap': 'Texture de déplacement',
 			'sidebar/material/roughnessmap': 'Texture de rugosité',
 			'sidebar/material/metalnessmap': 'Texture métallique',
@@ -951,6 +957,8 @@ function Strings( config ) {
 			'sidebar/material/shininess': '高光大小',
 			'sidebar/material/clearcoat': '清漆',
 			'sidebar/material/clearcoatroughness': '清漆粗糙度',
+			'sidebar/material/dispersion': 'Dispersion',
+			'sidebar/material/ior': 'IOR',
 			'sidebar/material/iridescence': '彩虹色',
 			'sidebar/material/iridescenceIOR': '彩虹色折射率',
 			'sidebar/material/iridescenceThicknessMax': '彩虹色厚度',
@@ -967,7 +975,9 @@ function Strings( config ) {
 			'sidebar/material/alphamap': '透明贴图',
 			'sidebar/material/bumpmap': '凹凸贴图',
 			'sidebar/material/normalmap': '法线贴图',
+			'sidebar/material/clearcoatmap': 'Clearcoat Map',
 			'sidebar/material/clearcoatnormalmap': '清漆法线贴图',
+			'sidebar/material/clearcoatroughnessmap': 'Clearcoat Roughness Map',
 			'sidebar/material/displacementmap': '置换贴图',
 			'sidebar/material/roughnessmap': '粗糙贴图',
 			'sidebar/material/metalnessmap': '金属贴图',
@@ -1300,6 +1310,8 @@ function Strings( config ) {
 			'sidebar/material/shininess': '光沢',
 			'sidebar/material/clearcoat': 'クリアコート',
 			'sidebar/material/clearcoatroughness': 'クリアコートの粗さ',
+			'sidebar/material/dispersion': 'Dispersion',
+			'sidebar/material/ior': 'IOR',
 			'sidebar/material/iridescence': '遊色効果',
 			'sidebar/material/iridescenceIOR': '遊色効果のIOR',
 			'sidebar/material/iridescenceThicknessMax': '遊色効果の厚さ',

+ 9 - 6
editor/js/Viewport.js

@@ -43,15 +43,18 @@ function Viewport( editor ) {
 
 	// helpers
 
+	const GRID_COLORS_LIGHT = [ 0x999999, 0x777777 ];
+	const GRID_COLORS_DARK = [ 0x555555, 0x888888 ];
+
 	const grid = new THREE.Group();
 
-	const grid1 = new THREE.GridHelper( 30, 30, 0x888888 );
-	grid1.material.color.setHex( 0x888888 );
+	const grid1 = new THREE.GridHelper( 30, 30 );
+	grid1.material.color.setHex( GRID_COLORS_LIGHT[ 0 ] );
 	grid1.material.vertexColors = false;
 	grid.add( grid1 );
 
-	const grid2 = new THREE.GridHelper( 30, 6, 0x222222 );
-	grid2.material.color.setHex( 0x222222 );
+	const grid2 = new THREE.GridHelper( 30, 6 );
+	grid2.material.color.setHex( GRID_COLORS_LIGHT[ 1 ] );
 	grid2.material.vertexColors = false;
 	grid.add( grid2 );
 
@@ -330,14 +333,14 @@ function Viewport( editor ) {
 			mediaQuery.addEventListener( 'change', function ( event ) {
 
 				renderer.setClearColor( event.matches ? 0x333333 : 0xaaaaaa );
-				updateGridColors( grid1, grid2, event.matches ? [ 0x222222, 0x888888 ] : [ 0x888888, 0x282828 ] );
+				updateGridColors( grid1, grid2, event.matches ? GRID_COLORS_DARK : GRID_COLORS_LIGHT );
 
 				render();
 
 			} );
 
 			renderer.setClearColor( mediaQuery.matches ? 0x333333 : 0xaaaaaa );
-			updateGridColors( grid1, grid2, mediaQuery.matches ? [ 0x222222, 0x888888 ] : [ 0x888888, 0x282828 ] );
+			updateGridColors( grid1, grid2, mediaQuery.matches ? GRID_COLORS_DARK : GRID_COLORS_LIGHT );
 
 		}
 

+ 8 - 1
editor/js/libs/app/index.html

@@ -18,9 +18,16 @@
 		</style>
 	</head>
 	<body ontouchstart="">
+		<script type="importmap">
+			{
+				"imports": {
+					"three": "./js/three.module.js"
+				}
+			}
+		</script>
 		<script type="module">
 
-			import * as THREE from './js/three.module.js';
+			import * as THREE from 'three';
 			import { APP } from './js/app.js';
 
 			window.THREE = THREE; // Used by APP Scripts.

+ 11 - 14
examples/files.json

@@ -88,6 +88,7 @@
 		"webgl_loader_gltf",
 		"webgl_loader_gltf_avif",
 		"webgl_loader_gltf_compressed",
+		"webgl_loader_gltf_dispersion",
 		"webgl_loader_gltf_instancing",
 		"webgl_loader_gltf_iridescence",
 		"webgl_loader_gltf_lights",
@@ -152,7 +153,6 @@
 		"webgl_materials_envmaps_exr",
 		"webgl_materials_envmaps_groundprojected",
 		"webgl_materials_envmaps_hdr",
-		"webgl_materials_lightmap",
 		"webgl_materials_matcap",
 		"webgl_materials_normalmap",
 		"webgl_materials_normalmap_object_space",
@@ -224,24 +224,13 @@
 		"webgl_water",
 		"webgl_water_flowmap"
 	],
-	"webgl / nodes": [
-		"webgl_nodes_loader_gltf_iridescence",
-		"webgl_nodes_loader_gltf_transmission",
-		"webgl_nodes_loader_gltf_sheen",
-		"webgl_nodes_loader_materialx",
-		"webgl_nodes_materials_instance_uniform",
-		"webgl_nodes_materials_physical_clearcoat",
-		"webgl_nodes_materials_standard",
-		"webgl_nodes_materialx_noise",
-		"webgl_nodes_points"
-	],
 	"webgl / postprocessing": [
 		"webgl_postprocessing",
 		"webgl_postprocessing_3dlut",
 		"webgl_postprocessing_advanced",
 		"webgl_postprocessing_afterimage",
 		"webgl_postprocessing_backgrounds",
-		"webgl_postprocessing_crossfade",
+		"webgl_postprocessing_transition",
 		"webgl_postprocessing_dof",
 		"webgl_postprocessing_dof2",
 		"webgl_postprocessing_fxaa",
@@ -323,6 +312,7 @@
 		"webgpu_clearcoat",
 		"webgpu_clipping",
 		"webgpu_compute_audio",
+		"webgpu_compute_geometry",
 		"webgpu_compute_particles",
 		"webgpu_compute_particles_rain",
 		"webgpu_compute_particles_snow",
@@ -345,15 +335,20 @@
 		"webgpu_lights_selective",
 		"webgpu_lines_fat",
 		"webgpu_loader_gltf",
+		"webgpu_loader_gltf_anisotropy",
 		"webgpu_loader_gltf_compressed",
 		"webgpu_loader_gltf_iridescence",
 		"webgpu_loader_gltf_sheen",
+		"webgpu_loader_gltf_transmission",
 		"webgpu_loader_materialx",
 		"webgpu_materials",
+		"webgpu_materials_lightmap",
 		"webgpu_materials_sss",
+		"webgpu_materials_transmission",
 		"webgpu_materials_video",
 		"webgpu_materialx_noise",
 		"webgpu_multiple_rendertargets",
+		"webgpu_multiple_rendertargets_readback",
 		"webgpu_morphtargets",
 		"webgpu_morphtargets_face",
 		"webgpu_occlusion",
@@ -384,7 +379,8 @@
 		"webgpu_materials_texture_anisotropy",
 		"webgpu_storage_buffer",
 		"webgpu_mesh_batch",
-		"webgpu_instancing_morph"
+		"webgpu_instancing_morph",
+		"webgpu_texturegrad"
 	],
 	"webaudio": [
 		"webaudio_orientation",
@@ -428,6 +424,7 @@
 		"physics_ammo_rope",
 		"physics_ammo_terrain",
 		"physics_ammo_volume",
+		"physics_jolt_instancing",
 		"physics_rapier_instancing"
 	],
 	"misc": [

+ 4 - 2
examples/jsm/animation/CCDIKSolver.js

@@ -213,11 +213,12 @@ class CCDIKSolver {
 	/**
 	 * Creates Helper
 	 *
+	 * @param {number} sphereSize
 	 * @return {CCDIKHelper}
 	 */
-	createHelper() {
+	createHelper( sphereSize ) {
 
-		return new CCDIKHelper( this.mesh, this.iks );
+		return new CCDIKHelper( this.mesh, this.iks, sphereSize );
 
 	}
 
@@ -280,6 +281,7 @@ function setPositionOfBoneToAttributeArray( array, index, bone, matrixWorldInv )
  *
  * @param {SkinnedMesh} mesh
  * @param {Array<Object>} iks
+ * @param {number} sphereSize
  */
 class CCDIKHelper extends Object3D {
 

+ 45 - 1
examples/jsm/exporters/GLTFExporter.js

@@ -26,6 +26,7 @@ import {
 	Quaternion,
 } from 'three';
 import { decompress } from './../utils/TextureUtils.js';
+import { REVISION } from '../../../src/constants.js';
 
 
 /**
@@ -111,6 +112,12 @@ class GLTFExporter {
 
 		} );
 
+		this.register( function ( writer ) {
+
+			return new GLTFMaterialsDispersionExtension( writer );
+
+		} );
+
 		this.register( function ( writer ) {
 
 			return new GLTFMaterialsIridescenceExtension( writer );
@@ -496,7 +503,7 @@ class GLTFWriter {
 		this.json = {
 			asset: {
 				version: '2.0',
-				generator: 'THREE.GLTFExporter'
+				generator: 'THREE.GLTFExporter r' + REVISION
 			}
 		};
 
@@ -2633,6 +2640,9 @@ class GLTFMaterialsClearcoatExtension {
 				index: writer.processTexture( material.clearcoatNormalMap ),
 				texCoord: material.clearcoatNormalMap.channel
 			};
+
+			if ( material.clearcoatNormalScale.x !== 1 ) clearcoatNormalMapDef.scale = material.clearcoatNormalScale.x;
+
 			writer.applyTextureTransform( clearcoatNormalMapDef, material.clearcoatNormalMap );
 			extensionDef.clearcoatNormalTexture = clearcoatNormalMapDef;
 
@@ -2648,6 +2658,40 @@ class GLTFMaterialsClearcoatExtension {
 
 }
 
+/**
+ * Materials dispersion Extension
+ *
+ * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_dispersion
+ */
+class GLTFMaterialsDispersionExtension {
+
+	constructor( writer ) {
+
+		this.writer = writer;
+		this.name = 'KHR_materials_dispersion';
+
+	}
+
+	writeMaterial( material, materialDef ) {
+
+		if ( ! material.isMeshPhysicalMaterial || material.dispersion === 0 ) return;
+
+		const writer = this.writer;
+		const extensionsUsed = writer.extensionsUsed;
+
+		const extensionDef = {};
+
+		extensionDef.dispersion = material.dispersion;
+
+		materialDef.extensions = materialDef.extensions || {};
+		materialDef.extensions[ this.name ] = extensionDef;
+
+		extensionsUsed[ this.name ] = true;
+
+	}
+
+}
+
 /**
  * Iridescence Materials Extension
  *

+ 7 - 1
examples/jsm/exporters/USDZExporter.js

@@ -12,7 +12,13 @@ import { decompress } from './../utils/TextureUtils.js';
 
 class USDZExporter {
 
-	async parse( scene, options = {} ) {
+	parse( scene, onDone, onError, options ) {
+
+		this.parseAsync( scene, options ).then( onDone ).catch( onError );
+
+	}
+
+	async parseAsync( scene, options = {} ) {
 
 		options = Object.assign( {
 			ar: {

+ 2 - 2
examples/jsm/libs/draco/README.md

@@ -17,10 +17,10 @@ Each file is provided in two variations:
 * **Default:** Latest stable builds, tracking the project's [master branch](https://github.com/google/draco).
 * **glTF:** Builds targeted by the [glTF mesh compression extension](https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_draco_mesh_compression), tracking the [corresponding Draco branch](https://github.com/google/draco/tree/gltf_2.0_draco_extension).
 
-Either variation may be used with `THREE.DRACOLoader`:
+Either variation may be used with `DRACOLoader`:
 
 ```js
-var dracoLoader = new THREE.DRACOLoader();
+var dracoLoader = new DRACOLoader();
 dracoLoader.setDecoderPath('path/to/decoders/');
 dracoLoader.setDecoderConfig({type: 'js'}); // (Optional) Override detection of WASM support.
 ```

+ 283 - 99
examples/jsm/loaders/EXRLoader.js

@@ -1269,18 +1269,18 @@ class EXRLoader extends DataTextureLoader {
 			const inDataView = info.viewer;
 			const inOffset = { value: info.offset.value };
 
-			const outBuffer = new Uint16Array( info.width * info.scanlineBlockSize * ( info.channels * info.type ) );
+			const outBuffer = new Uint16Array( info.columns * info.lines * ( info.inputChannels.length * info.type ) );
 			const bitmap = new Uint8Array( BITMAP_SIZE );
 
 			// Setup channel info
 			let outBufferEnd = 0;
-			const pizChannelData = new Array( info.channels );
-			for ( let i = 0; i < info.channels; i ++ ) {
+			const pizChannelData = new Array( info.inputChannels.length );
+			for ( let i = 0, il = info.inputChannels.length; i < il; i ++ ) {
 
 				pizChannelData[ i ] = {};
 				pizChannelData[ i ][ 'start' ] = outBufferEnd;
 				pizChannelData[ i ][ 'end' ] = pizChannelData[ i ][ 'start' ];
-				pizChannelData[ i ][ 'nx' ] = info.width;
+				pizChannelData[ i ][ 'nx' ] = info.columns;
 				pizChannelData[ i ][ 'ny' ] = info.lines;
 				pizChannelData[ i ][ 'size' ] = info.type;
 
@@ -1319,7 +1319,7 @@ class EXRLoader extends DataTextureLoader {
 			hufUncompress( info.array, inDataView, inOffset, length, outBuffer, outBufferEnd );
 
 			// Wavelet decoding
-			for ( let i = 0; i < info.channels; ++ i ) {
+			for ( let i = 0; i < info.inputChannels.length; ++ i ) {
 
 				const cd = pizChannelData[ i ];
 
@@ -1347,7 +1347,7 @@ class EXRLoader extends DataTextureLoader {
 			const tmpBuffer = new Uint8Array( outBuffer.buffer.byteLength );
 			for ( let y = 0; y < info.lines; y ++ ) {
 
-				for ( let c = 0; c < info.channels; c ++ ) {
+				for ( let c = 0; c < info.inputChannels.length; c ++ ) {
 
 					const cd = pizChannelData[ c ];
 
@@ -1372,8 +1372,9 @@ class EXRLoader extends DataTextureLoader {
 
 			const rawBuffer = fflate.unzlibSync( compressed );
 
-			const sz = info.lines * info.channels * info.width;
-			const tmpBuffer = ( info.type == 1 ) ? new Uint16Array( sz ) : new Uint32Array( sz );
+			const byteSize = info.inputChannels.length * info.lines * info.columns * info.totalBytes;
+			const tmpBuffer = new ArrayBuffer( byteSize );
+			const viewer = new DataView( tmpBuffer );
 
 			let tmpBufferEnd = 0;
 			let writePtr = 0;
@@ -1381,26 +1382,27 @@ class EXRLoader extends DataTextureLoader {
 
 			for ( let y = 0; y < info.lines; y ++ ) {
 
-				for ( let c = 0; c < info.channels; c ++ ) {
+				for ( let c = 0; c < info.inputChannels.length; c ++ ) {
 
 					let pixel = 0;
 
-					switch ( info.type ) {
+					const type = info.inputChannels[ c ].pixelType;
+					switch ( type ) {
 
 						case 1:
 
 							ptr[ 0 ] = tmpBufferEnd;
-							ptr[ 1 ] = ptr[ 0 ] + info.width;
-							tmpBufferEnd = ptr[ 1 ] + info.width;
+							ptr[ 1 ] = ptr[ 0 ] + info.columns;
+							tmpBufferEnd = ptr[ 1 ] + info.columns;
 
-							for ( let j = 0; j < info.width; ++ j ) {
+							for ( let j = 0; j < info.columns; ++ j ) {
 
 								const diff = ( rawBuffer[ ptr[ 0 ] ++ ] << 8 ) | rawBuffer[ ptr[ 1 ] ++ ];
 
 								pixel += diff;
 
-								tmpBuffer[ writePtr ] = pixel;
-								writePtr ++;
+								viewer.setUint16( writePtr, pixel, true );
+								writePtr += 2;
 
 							}
 
@@ -1409,18 +1411,18 @@ class EXRLoader extends DataTextureLoader {
 						case 2:
 
 							ptr[ 0 ] = tmpBufferEnd;
-							ptr[ 1 ] = ptr[ 0 ] + info.width;
-							ptr[ 2 ] = ptr[ 1 ] + info.width;
-							tmpBufferEnd = ptr[ 2 ] + info.width;
+							ptr[ 1 ] = ptr[ 0 ] + info.columns;
+							ptr[ 2 ] = ptr[ 1 ] + info.columns;
+							tmpBufferEnd = ptr[ 2 ] + info.columns;
 
-							for ( let j = 0; j < info.width; ++ j ) {
+							for ( let j = 0; j < info.columns; ++ j ) {
 
 								const diff = ( rawBuffer[ ptr[ 0 ] ++ ] << 24 ) | ( rawBuffer[ ptr[ 1 ] ++ ] << 16 ) | ( rawBuffer[ ptr[ 2 ] ++ ] << 8 );
 
 								pixel += diff;
 
-								tmpBuffer[ writePtr ] = pixel;
-								writePtr ++;
+								viewer.setUint32( writePtr, pixel, true );
+								writePtr += 4;
 
 							}
 
@@ -1432,7 +1434,7 @@ class EXRLoader extends DataTextureLoader {
 
 			}
 
-			return new DataView( tmpBuffer.buffer );
+			return viewer;
 
 		}
 
@@ -1440,7 +1442,7 @@ class EXRLoader extends DataTextureLoader {
 
 			const inDataView = info.viewer;
 			const inOffset = { value: info.offset.value };
-			const outBuffer = new Uint8Array( info.width * info.lines * ( info.channels * info.type * INT16_SIZE ) );
+			const outBuffer = new Uint8Array( info.columns * info.lines * ( info.inputChannels.length * info.type * INT16_SIZE ) );
 
 			// Read compression header information
 			const dwaHeader = {
@@ -1488,9 +1490,9 @@ class EXRLoader extends DataTextureLoader {
 
 			// Classify channels
 			const channels = EXRHeader.channels;
-			const channelData = new Array( info.channels );
+			const channelData = new Array( info.inputChannels.length );
 
-			for ( let i = 0; i < info.channels; ++ i ) {
+			for ( let i = 0; i < info.inputChannels.length; ++ i ) {
 
 				const cd = channelData[ i ] = {};
 				const channel = channels[ i ];
@@ -1500,7 +1502,7 @@ class EXRLoader extends DataTextureLoader {
 				cd.decoded = false;
 				cd.type = channel.pixelType;
 				cd.pLinear = channel.pLinear;
-				cd.width = info.width;
+				cd.width = info.columns;
 				cd.height = info.lines;
 
 			}
@@ -1509,7 +1511,7 @@ class EXRLoader extends DataTextureLoader {
 				idx: new Array( 3 )
 			};
 
-			for ( let offset = 0; offset < info.channels; ++ offset ) {
+			for ( let offset = 0; offset < info.inputChannels.length; ++ offset ) {
 
 				const cd = channelData[ offset ];
 
@@ -1899,7 +1901,8 @@ class EXRLoader extends DataTextureLoader {
 
 			const lineOrders = [
 				'INCREASING_Y',
-				'DECREASING_Y'
+				'DECREASING_Y',
+				'RANDOM_Y',
 			];
 
 			const lineOrder = parseUint8( dataView, offset );
@@ -1908,6 +1911,45 @@ class EXRLoader extends DataTextureLoader {
 
 		}
 
+		function parseEnvmap( dataView, offset ) {
+
+			const envmaps = [
+				'ENVMAP_LATLONG',
+				'ENVMAP_CUBE'
+			];
+
+			const envmap = parseUint8( dataView, offset );
+
+			return envmaps[ envmap ];
+
+		}
+
+		function parseTiledesc( dataView, offset ) {
+
+			const levelModes = [
+				'ONE_LEVEL',
+				'MIPMAP_LEVELS',
+				'RIPMAP_LEVELS',
+			];
+
+			const roundingModes = [
+				'ROUND_DOWN',
+				'ROUND_UP',
+			];
+
+			const xSize = parseUint32( dataView, offset );
+			const ySize = parseUint32( dataView, offset );
+			const modes = parseUint8( dataView, offset );
+
+			return {
+				xSize: xSize,
+				ySize: ySize,
+				levelMode: levelModes[ modes & 0xf ],
+				roundingMode: roundingModes[ modes >> 4 ]
+			};
+
+		}
+
 		function parseV2f( dataView, offset ) {
 
 			const x = parseFloat32( dataView, offset );
@@ -1949,6 +1991,14 @@ class EXRLoader extends DataTextureLoader {
 
 				return parseBox2i( dataView, offset );
 
+			} else if ( type === 'envmap' ) {
+
+				return parseEnvmap( dataView, offset );
+
+			} else if ( type === 'tiledesc' ) {
+
+				return parseTiledesc( dataView, offset );
+
 			} else if ( type === 'lineOrder' ) {
 
 				return parseLineOrder( dataView, offset );
@@ -1991,6 +2041,163 @@ class EXRLoader extends DataTextureLoader {
 
 		}
 
+		function roundLog2( x, mode ) {
+
+			const log2 = Math.log2( x );
+			return mode == 'ROUND_DOWN' ? Math.floor( log2 ) : Math.ceil( log2 );
+
+		}
+
+		function calculateTileLevels( tiledesc, w, h ) {
+
+			let num = 0;
+
+			switch ( tiledesc.levelMode ) {
+
+				case 'ONE_LEVEL':
+					num = 1;
+					break;
+
+				case 'MIPMAP_LEVELS':
+					num = roundLog2( Math.max( w, h ), tiledesc.roundingMode ) + 1;
+					break;
+
+				case 'RIPMAP_LEVELS':
+					throw new Error( 'THREE.EXRLoader: RIPMAP_LEVELS tiles currently unsupported.' );
+
+			}
+
+			return num;
+
+		}
+
+		function calculateTiles( count, dataSize, size, roundingMode ) {
+
+			const tiles = new Array( count );
+
+			for ( let i = 0; i < count; i ++ ) {
+
+				const b = ( 1 << i );
+				let s = ( dataSize / b ) | 0;
+
+				if ( roundingMode == 'ROUND_UP' && s * b < dataSize ) s += 1;
+
+				const l = Math.max( s, 1 );
+
+				tiles[ i ] = ( ( l + size - 1 ) / size ) | 0;
+
+			}
+
+			return tiles;
+
+		}
+
+		function parseTiles() {
+
+			const EXRDecoder = this;
+			const offset = EXRDecoder.offset;
+			const tmpOffset = { value: 0 };
+
+			for ( let tile = 0; tile < EXRDecoder.tileCount; tile ++ ) {
+
+				const tileX = parseInt32( EXRDecoder.viewer, offset );
+				const tileY = parseInt32( EXRDecoder.viewer, offset );
+				offset.value += 8; // skip levels - only parsing top-level
+				EXRDecoder.size = parseUint32( EXRDecoder.viewer, offset );
+
+				const startX = tileX * EXRDecoder.blockWidth;
+				const startY = tileY * EXRDecoder.blockHeight;
+				EXRDecoder.columns = ( startX + EXRDecoder.blockWidth > EXRDecoder.width ) ? EXRDecoder.width - startX : EXRDecoder.blockWidth;
+				EXRDecoder.lines = ( startY + EXRDecoder.blockHeight > EXRDecoder.height ) ? EXRDecoder.height - startY : EXRDecoder.blockHeight;
+
+				const bytesBlockLine = EXRDecoder.columns * EXRDecoder.totalBytes;
+				const isCompressed = EXRDecoder.size < EXRDecoder.lines * bytesBlockLine;
+				const viewer = isCompressed ? EXRDecoder.uncompress( EXRDecoder ) : uncompressRAW( EXRDecoder );
+
+				offset.value += EXRDecoder.size;
+
+				for ( let line = 0; line < EXRDecoder.lines; line ++ ) {
+
+					const lineOffset = line * EXRDecoder.columns * EXRDecoder.totalBytes;
+
+					for ( let channelID = 0; channelID < EXRDecoder.inputChannels.length; channelID ++ ) {
+
+						const name = EXRHeader.channels[ channelID ].name;
+						const lOff = EXRDecoder.channelByteOffsets[ name ] * EXRDecoder.columns;
+						const cOff = EXRDecoder.decodeChannels[ name ];
+
+						if ( cOff === undefined ) continue;
+
+						tmpOffset.value = lineOffset + lOff;
+						const outLineOffset = ( EXRDecoder.height - ( 1 + startY + line ) ) * EXRDecoder.outLineWidth;
+
+						for ( let x = 0; x < EXRDecoder.columns; x ++ ) {
+
+							const outIndex = outLineOffset + ( x + startX ) * EXRDecoder.outputChannels + cOff;
+							EXRDecoder.byteArray[ outIndex ] = EXRDecoder.getter( viewer, tmpOffset );
+
+						}
+
+					}
+
+				}
+
+			}
+
+		}
+
+		function parseScanline() {
+
+			const EXRDecoder = this;
+			const offset = EXRDecoder.offset;
+			const tmpOffset = { value: 0 };
+
+			for ( let scanlineBlockIdx = 0; scanlineBlockIdx < EXRDecoder.height / EXRDecoder.blockHeight; scanlineBlockIdx ++ ) {
+
+				const line = parseInt32( EXRDecoder.viewer, offset ) - EXRHeader.dataWindow.yMin; // line_no
+				EXRDecoder.size = parseUint32( EXRDecoder.viewer, offset ); // data_len
+				EXRDecoder.lines = ( ( line + EXRDecoder.blockHeight > EXRDecoder.height ) ? ( EXRDecoder.height - line ) : EXRDecoder.blockHeight );
+
+				const bytesPerLine = EXRDecoder.columns * EXRDecoder.totalBytes;
+				const isCompressed = EXRDecoder.size < EXRDecoder.lines * bytesPerLine;
+				const viewer = isCompressed ? EXRDecoder.uncompress( EXRDecoder ) : uncompressRAW( EXRDecoder );
+
+				offset.value += EXRDecoder.size;
+
+				for ( let line_y = 0; line_y < EXRDecoder.blockHeight; line_y ++ ) {
+
+					const scan_y = scanlineBlockIdx * EXRDecoder.blockHeight;
+					const true_y = line_y + EXRDecoder.scanOrder( scan_y );
+					if ( true_y >= EXRDecoder.height ) continue;
+
+					const lineOffset = line_y * bytesPerLine;
+					const outLineOffset = ( EXRDecoder.height - 1 - true_y ) * EXRDecoder.outLineWidth;
+
+					for ( let channelID = 0; channelID < EXRDecoder.inputChannels.length; channelID ++ ) {
+
+						const name = EXRHeader.channels[ channelID ].name;
+						const lOff = EXRDecoder.channelByteOffsets[ name ] * EXRDecoder.columns;
+						const cOff = EXRDecoder.decodeChannels[ name ];
+
+						if ( cOff === undefined ) continue;
+
+						tmpOffset.value = lineOffset + lOff;
+
+						for ( let x = 0; x < EXRDecoder.columns; x ++ ) {
+
+							const outIndex = outLineOffset + x * EXRDecoder.outputChannels + cOff;
+							EXRDecoder.byteArray[ outIndex ] = EXRDecoder.getter( viewer, tmpOffset );
+
+						}
+
+					}
+
+				}
+
+			}
+
+		}
+
 		function parseHeader( dataView, buffer, offset ) {
 
 			const EXRHeader = {};
@@ -2046,7 +2253,7 @@ class EXRLoader extends DataTextureLoader {
 
 			}
 
-			if ( ( spec & ~ 0x04 ) != 0 ) { // unsupported tiled, deep-image, multi-part
+			if ( ( spec & ~ 0x06 ) != 0 ) { // unsupported deep-image, multi-part
 
 				console.error( 'THREE.EXRHeader:', EXRHeader );
 				throw new Error( 'THREE.EXRLoader: Provided file is currently unsupported.' );
@@ -2066,12 +2273,12 @@ class EXRLoader extends DataTextureLoader {
 				offset: offset,
 				width: EXRHeader.dataWindow.xMax - EXRHeader.dataWindow.xMin + 1,
 				height: EXRHeader.dataWindow.yMax - EXRHeader.dataWindow.yMin + 1,
-				channels: EXRHeader.channels.length,
-				channelLineOffsets: {},
+				inputChannels: EXRHeader.channels,
+				channelByteOffsets: {},
 				scanOrder: null,
-				bytesPerLine: null,
+				totalBytes: null,
+				columns: null,
 				lines: null,
-				inputSize: null,
 				type: null,
 				uncompress: null,
 				getter: null,
@@ -2082,42 +2289,42 @@ class EXRLoader extends DataTextureLoader {
 			switch ( EXRHeader.compression ) {
 
 				case 'NO_COMPRESSION':
-					EXRDecoder.lines = 1;
+					EXRDecoder.blockHeight = 1;
 					EXRDecoder.uncompress = uncompressRAW;
 					break;
 
 				case 'RLE_COMPRESSION':
-					EXRDecoder.lines = 1;
+					EXRDecoder.blockHeight = 1;
 					EXRDecoder.uncompress = uncompressRLE;
 					break;
 
 				case 'ZIPS_COMPRESSION':
-					EXRDecoder.lines = 1;
+					EXRDecoder.blockHeight = 1;
 					EXRDecoder.uncompress = uncompressZIP;
 					break;
 
 				case 'ZIP_COMPRESSION':
-					EXRDecoder.lines = 16;
+					EXRDecoder.blockHeight = 16;
 					EXRDecoder.uncompress = uncompressZIP;
 					break;
 
 				case 'PIZ_COMPRESSION':
-					EXRDecoder.lines = 32;
+					EXRDecoder.blockHeight = 32;
 					EXRDecoder.uncompress = uncompressPIZ;
 					break;
 
 				case 'PXR24_COMPRESSION':
-					EXRDecoder.lines = 16;
+					EXRDecoder.blockHeight = 16;
 					EXRDecoder.uncompress = uncompressPXR;
 					break;
 
 				case 'DWAA_COMPRESSION':
-					EXRDecoder.lines = 32;
+					EXRDecoder.blockHeight = 32;
 					EXRDecoder.uncompress = uncompressDWA;
 					break;
 
 				case 'DWAB_COMPRESSION':
-					EXRDecoder.lines = 256;
+					EXRDecoder.blockHeight = 256;
 					EXRDecoder.uncompress = uncompressDWA;
 					break;
 
@@ -2126,8 +2333,6 @@ class EXRLoader extends DataTextureLoader {
 
 			}
 
-			EXRDecoder.scanlineBlockSize = EXRDecoder.lines;
-
 			const channels = {};
 			for ( const channel of EXRHeader.channels ) {
 
@@ -2172,12 +2377,10 @@ class EXRLoader extends DataTextureLoader {
 
 					case FloatType:
 						EXRDecoder.getter = parseFloat16;
-						EXRDecoder.inputSize = INT16_SIZE;
 						break;
 
 					case HalfFloatType:
 						EXRDecoder.getter = parseUint16;
-						EXRDecoder.inputSize = INT16_SIZE;
 						break;
 
 				}
@@ -2189,12 +2392,10 @@ class EXRLoader extends DataTextureLoader {
 
 					case FloatType:
 						EXRDecoder.getter = parseFloat32;
-						EXRDecoder.inputSize = FLOAT32_SIZE;
 						break;
 
 					case HalfFloatType:
 						EXRDecoder.getter = decodeFloat32;
-						EXRDecoder.inputSize = FLOAT32_SIZE;
 
 				}
 
@@ -2204,13 +2405,7 @@ class EXRLoader extends DataTextureLoader {
 
 			}
 
-			EXRDecoder.blockCount = EXRDecoder.height / EXRDecoder.scanlineBlockSize;
-
-			for ( let i = 0; i < EXRDecoder.blockCount; i ++ )
-				parseInt64( dataView, offset ); // scanlineOffset
-
-			// we should be passed the scanline offset table, ready to start reading pixel data.
-
+			EXRDecoder.columns = EXRDecoder.width;
 			const size = EXRDecoder.width * EXRDecoder.height * EXRDecoder.outputChannels;
 
 			switch ( outputType ) {
@@ -2243,7 +2438,7 @@ class EXRLoader extends DataTextureLoader {
 
 				if ( EXRDecoder.decodeChannels[ channel.name ] !== undefined ) {
 
-					EXRDecoder.channelLineOffsets[ channel.name ] = byteOffset * EXRDecoder.width;
+					EXRDecoder.channelByteOffsets[ channel.name ] = byteOffset;
 
 				}
 
@@ -2251,7 +2446,7 @@ class EXRLoader extends DataTextureLoader {
 
 			}
 
-			EXRDecoder.bytesPerLine = EXRDecoder.width * byteOffset;
+			EXRDecoder.totalBytes = byteOffset;
 			EXRDecoder.outLineWidth = EXRDecoder.width * EXRDecoder.outputChannels;
 
 			if ( EXRHeader.lineOrder === 'INCREASING_Y' ) {
@@ -2276,66 +2471,55 @@ class EXRLoader extends DataTextureLoader {
 
 			}
 
-			return EXRDecoder;
-
-		}
-
-		// start parsing file [START]
-
-		const bufferDataView = new DataView( buffer );
-		const uInt8Array = new Uint8Array( buffer );
-		const offset = { value: 0 };
-
-		// get header information and validate format.
-		const EXRHeader = parseHeader( bufferDataView, buffer, offset );
-
-		// get input compression information and prepare decoding.
-		const EXRDecoder = setupDecoder( EXRHeader, bufferDataView, uInt8Array, offset, this.type );
-
-		const tmpOffset = { value: 0 };
+			if ( EXRHeader.spec.singleTile ) {
 
-		for ( let scanlineBlockIdx = 0; scanlineBlockIdx < EXRDecoder.height / EXRDecoder.scanlineBlockSize; scanlineBlockIdx ++ ) {
+				EXRDecoder.blockHeight = EXRHeader.tiles.ySize;
+				EXRDecoder.blockWidth = EXRHeader.tiles.xSize;
 
-			const line = parseInt32( bufferDataView, offset ) - EXRHeader.dataWindow.yMin; // line_no
-			EXRDecoder.size = parseUint32( bufferDataView, offset ); // data_len
-			EXRDecoder.lines = ( ( line + EXRDecoder.scanlineBlockSize > EXRDecoder.height ) ? ( EXRDecoder.height - line ) : EXRDecoder.scanlineBlockSize );
+				const numXLevels = calculateTileLevels( EXRHeader.tiles, EXRDecoder.width, EXRDecoder.height );
+				// const numYLevels = calculateTileLevels( EXRHeader.tiles, EXRDecoder.width, EXRDecoder.height );
 
-			const isCompressed = EXRDecoder.size < EXRDecoder.lines * EXRDecoder.bytesPerLine;
-			const viewer = isCompressed ? EXRDecoder.uncompress( EXRDecoder ) : uncompressRAW( EXRDecoder );
+				const numXTiles = calculateTiles( numXLevels, EXRDecoder.width, EXRHeader.tiles.xSize, EXRHeader.tiles.roundingMode );
+				const numYTiles = calculateTiles( numXLevels, EXRDecoder.height, EXRHeader.tiles.ySize, EXRHeader.tiles.roundingMode );
 
-			offset.value += EXRDecoder.size;
+				EXRDecoder.tileCount = numXTiles[ 0 ] * numYTiles[ 0 ];
 
-			for ( let line_y = 0; line_y < EXRDecoder.scanlineBlockSize; line_y ++ ) {
+				for ( let l = 0; l < numXLevels; l ++ )
+					for ( let y = 0; y < numYTiles[ l ]; y ++ )
+						for ( let x = 0; x < numXTiles[ l ]; x ++ )
+							parseInt64( dataView, offset ); // tileOffset
 
-				const scan_y = scanlineBlockIdx * EXRDecoder.scanlineBlockSize;
-				const true_y = line_y + EXRDecoder.scanOrder( scan_y );
-				if ( true_y >= EXRDecoder.height ) continue;
+				EXRDecoder.decode = parseTiles.bind( EXRDecoder );
 
-				const lineOffset = line_y * EXRDecoder.bytesPerLine;
-				const outLineOffset = ( EXRDecoder.height - 1 - true_y ) * EXRDecoder.outLineWidth;
+			} else {
 
-				for ( let channelID = 0; channelID < EXRDecoder.channels; channelID ++ ) {
+				EXRDecoder.blockWidth = EXRDecoder.width;
+				const blockCount = Math.ceil( EXRDecoder.height / EXRDecoder.blockHeight );
 
-					const name = EXRHeader.channels[ channelID ].name;
-					const lOff = EXRDecoder.channelLineOffsets[ name ];
-					const cOff = EXRDecoder.decodeChannels[ name ];
+				for ( let i = 0; i < blockCount; i ++ )
+					parseInt64( dataView, offset ); // scanlineOffset
 
-					if ( cOff === undefined ) continue;
+				EXRDecoder.decode = parseScanline.bind( EXRDecoder );
 
-					tmpOffset.value = lineOffset + lOff;
+			}
 
-					for ( let x = 0; x < EXRDecoder.width; x ++ ) {
+			return EXRDecoder;
 
-						const outIndex = outLineOffset + x * EXRDecoder.outputChannels + cOff;
-						EXRDecoder.byteArray[ outIndex ] = EXRDecoder.getter( viewer, tmpOffset );
+		}
 
-					}
+		// start parsing file [START]
+		const offset = { value: 0 };
+		const bufferDataView = new DataView( buffer );
+		const uInt8Array = new Uint8Array( buffer );
 
-				}
+		// get header information and validate format.
+		const EXRHeader = parseHeader( bufferDataView, buffer, offset );
 
-			}
+		// get input compression information and prepare decoding.
+		const EXRDecoder = setupDecoder( EXRHeader, bufferDataView, uInt8Array, offset, this.type );
 
-		}
+		// parse input data
+		EXRDecoder.decode();
 
 		return {
 			header: EXRHeader,

+ 53 - 0
examples/jsm/loaders/GLTFLoader.js

@@ -85,6 +85,12 @@ class GLTFLoader extends Loader {
 
 		} );
 
+		this.register( function ( parser ) {
+
+			return new GLTFMaterialsDispersionExtension( parser );
+
+		} );
+
 		this.register( function ( parser ) {
 
 			return new GLTFTextureBasisUExtension( parser );
@@ -491,6 +497,7 @@ const EXTENSIONS = {
 	KHR_DRACO_MESH_COMPRESSION: 'KHR_draco_mesh_compression',
 	KHR_LIGHTS_PUNCTUAL: 'KHR_lights_punctual',
 	KHR_MATERIALS_CLEARCOAT: 'KHR_materials_clearcoat',
+	KHR_MATERIALS_DISPERSION: 'KHR_materials_dispersion',
 	KHR_MATERIALS_IOR: 'KHR_materials_ior',
 	KHR_MATERIALS_SHEEN: 'KHR_materials_sheen',
 	KHR_MATERIALS_SPECULAR: 'KHR_materials_specular',
@@ -824,6 +831,52 @@ class GLTFMaterialsClearcoatExtension {
 
 }
 
+/**
+ * Materials dispersion Extension
+ *
+ * Specification: https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_materials_dispersion
+ */
+class GLTFMaterialsDispersionExtension {
+
+	constructor( parser ) {
+
+		this.parser = parser;
+		this.name = EXTENSIONS.KHR_MATERIALS_DISPERSION;
+
+	}
+
+	getMaterialType( materialIndex ) {
+
+		const parser = this.parser;
+		const materialDef = parser.json.materials[ materialIndex ];
+
+		if ( ! materialDef.extensions || ! materialDef.extensions[ this.name ] ) return null;
+
+		return MeshPhysicalMaterial;
+
+	}
+
+	extendMaterialParams( materialIndex, materialParams ) {
+
+		const parser = this.parser;
+		const materialDef = parser.json.materials[ materialIndex ];
+
+		if ( ! materialDef.extensions || ! materialDef.extensions[ this.name ] ) {
+
+			return Promise.resolve();
+
+		}
+
+		const extension = materialDef.extensions[ this.name ];
+
+		materialParams.dispersion = extension.dispersion !== undefined ? extension.dispersion : 0;
+
+		return Promise.resolve();
+
+	}
+
+}
+
 /**
  * Iridescence Materials Extension
  *

+ 3 - 6
examples/jsm/loaders/KTX2Loader.js

@@ -31,13 +31,13 @@ import {
 	RGB_ETC1_Format,
 	RGB_ETC2_Format,
 	RGB_PVRTC_4BPPV1_Format,
-	RGB_S3TC_DXT1_Format,
 	RGBA_ASTC_4x4_Format,
 	RGBA_ASTC_6x6_Format,
 	RGBA_BPTC_Format,
 	RGBA_ETC2_EAC_Format,
 	RGBA_PVRTC_4BPPV1_Format,
 	RGBA_S3TC_DXT5_Format,
+	RGBA_S3TC_DXT1_Format,
 	RGBAFormat,
 	RGFormat,
 	SRGBColorSpace,
@@ -160,9 +160,6 @@ class KTX2Loader extends Loader {
 					|| renderer.extensions.has( 'WEBKIT_WEBGL_compressed_texture_pvrtc' )
 			};
 
-			// https://github.com/mrdoob/three.js/pull/22928
-			this.workerConfig.etc1Supported = false;
-
 		}
 
 		return this;
@@ -387,7 +384,7 @@ KTX2Loader.EngineFormat = {
 	RGB_ETC1_Format: RGB_ETC1_Format,
 	RGB_ETC2_Format: RGB_ETC2_Format,
 	RGB_PVRTC_4BPPV1_Format: RGB_PVRTC_4BPPV1_Format,
-	RGB_S3TC_DXT1_Format: RGB_S3TC_DXT1_Format,
+	RGBA_S3TC_DXT1_Format: RGBA_S3TC_DXT1_Format,
 };
 
 
@@ -603,7 +600,7 @@ KTX2Loader.BasisWorker = function () {
 			if: 'dxtSupported',
 			basisFormat: [ BasisFormat.ETC1S, BasisFormat.UASTC_4x4 ],
 			transcoderFormat: [ TranscoderFormat.BC1, TranscoderFormat.BC3 ],
-			engineFormat: [ EngineFormat.RGB_S3TC_DXT1_Format, EngineFormat.RGBA_S3TC_DXT5_Format ],
+			engineFormat: [ EngineFormat.RGBA_S3TC_DXT1_Format, EngineFormat.RGBA_S3TC_DXT5_Format ],
 			priorityETC1S: 4,
 			priorityUASTC: 5,
 			needsPowerOfTwo: false,

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

@@ -800,7 +800,7 @@ class VRMLLoader extends Loader {
 						break;
 
 					case 'rotation':
-						const axis = new Vector3( fieldValues[ 0 ], fieldValues[ 1 ], fieldValues[ 2 ] );
+						const axis = new Vector3( fieldValues[ 0 ], fieldValues[ 1 ], fieldValues[ 2 ] ).normalize();
 						const angle = fieldValues[ 3 ];
 						object.quaternion.setFromAxisAngle( axis, angle );
 						break;

+ 8 - 5
examples/jsm/loaders/lwo/IFFParser.js

@@ -651,10 +651,13 @@ class IFFParser {
 	// LAYR: number[U2], flags[U2], pivot[VEC12], name[S0], parent[U2]
 	parseLayer( length ) {
 
+		var number = this.reader.getUint16();
+		var flags = this.reader.getUint16(); // If the least significant bit of flags is set, the layer is hidden.
+		var pivot = this.reader.getFloat32Array( 3 ); // Note: this seems to be superflous, as the geometry is translated when pivot is present
 		var layer = {
-			number: this.reader.getUint16(),
-			flags: this.reader.getUint16(), // If the least significant bit of flags is set, the layer is hidden.
-			pivot: this.reader.getFloat32Array( 3 ), // Note: this seems to be superflous, as the geometry is translated when pivot is present
+			number: number,
+			flags: flags, // If the least significant bit of flags is set, the layer is hidden.
+			pivot: [ - pivot[ 0 ], pivot[ 1 ], pivot[ 2 ] ], // Note: this seems to be superflous, as the geometry is translated when pivot is present
 			name: this.reader.getString(),
 		};
 
@@ -676,8 +679,8 @@ class IFFParser {
 		this.currentPoints = [];
 		for ( var i = 0; i < length / 4; i += 3 ) {
 
-			// z -> -z to match three.js right handed coords
-			this.currentPoints.push( this.reader.getFloat32(), this.reader.getFloat32(), - this.reader.getFloat32() );
+			// x -> -x to match three.js right handed coords
+			this.currentPoints.push( - this.reader.getFloat32(), this.reader.getFloat32(), this.reader.getFloat32() );
 
 		}
 

+ 7 - 1
examples/jsm/materials/MeshGouraudMaterial.js

@@ -270,7 +270,13 @@ const GouraudShader = {
 
 			#endif
 
-			#include <lightmap_fragment>
+			#ifdef USE_LIGHTMAP
+
+				vec4 lightMapTexel = texture2D( lightMap, vLightMapUv );
+				vec3 lightMapIrradiance = lightMapTexel.rgb * lightMapIntensity;
+				reflectedLight.indirectDiffuse += lightMapIrradiance;
+
+			#endif
 
 			reflectedLight.indirectDiffuse *= BRDF_Lambert( diffuseColor.rgb );
 

+ 26 - 20
examples/jsm/math/Octree.js

@@ -4,7 +4,8 @@ import {
 	Plane,
 	Sphere,
 	Triangle,
-	Vector3
+	Vector3,
+	Layers
 } from 'three';
 import { Capsule } from '../math/Capsule.js';
 
@@ -89,6 +90,7 @@ class Octree {
 
 		this.subTrees = [];
 		this.triangles = [];
+		this.layers = new Layers();
 
 	}
 
@@ -478,38 +480,42 @@ class Octree {
 
 			if ( obj.isMesh === true ) {
 
-				let geometry, isTemp = false;
+				if ( this.layers.test( obj.layers ) ) {
 
-				if ( obj.geometry.index !== null ) {
+					let geometry, isTemp = false;
 
-					isTemp = true;
-					geometry = obj.geometry.toNonIndexed();
+					if ( obj.geometry.index !== null ) {
 
-				} else {
+						isTemp = true;
+						geometry = obj.geometry.toNonIndexed();
 
-					geometry = obj.geometry;
+					} else {
 
-				}
+						geometry = obj.geometry;
 
-				const positionAttribute = geometry.getAttribute( 'position' );
+					}
 
-				for ( let i = 0; i < positionAttribute.count; i += 3 ) {
+					const positionAttribute = geometry.getAttribute( 'position' );
 
-					const v1 = new Vector3().fromBufferAttribute( positionAttribute, i );
-					const v2 = new Vector3().fromBufferAttribute( positionAttribute, i + 1 );
-					const v3 = new Vector3().fromBufferAttribute( positionAttribute, i + 2 );
+					for ( let i = 0; i < positionAttribute.count; i += 3 ) {
 
-					v1.applyMatrix4( obj.matrixWorld );
-					v2.applyMatrix4( obj.matrixWorld );
-					v3.applyMatrix4( obj.matrixWorld );
+						const v1 = new Vector3().fromBufferAttribute( positionAttribute, i );
+						const v2 = new Vector3().fromBufferAttribute( positionAttribute, i + 1 );
+						const v3 = new Vector3().fromBufferAttribute( positionAttribute, i + 2 );
 
-					this.addTriangle( new Triangle( v1, v2, v3 ) );
+						v1.applyMatrix4( obj.matrixWorld );
+						v2.applyMatrix4( obj.matrixWorld );
+						v3.applyMatrix4( obj.matrixWorld );
 
-				}
+						this.addTriangle( new Triangle( v1, v2, v3 ) );
+
+					}
+
+					if ( isTemp ) {
 
-				if ( isTemp ) {
+						geometry.dispose();
 
-					geometry.dispose();
+					}
 
 				}
 

+ 4 - 3
examples/jsm/nodes/Nodes.js

@@ -26,7 +26,7 @@ export { default as NodeUniform } from './core/NodeUniform.js';
 export { default as NodeVar } from './core/NodeVar.js';
 export { default as NodeVarying } from './core/NodeVarying.js';
 export { default as ParameterNode, parameter } from './core/ParameterNode.js';
-export { default as PropertyNode, property, varyingProperty, output, diffuseColor, roughness, metalness, clearcoat, clearcoatRoughness, sheen, sheenRoughness, iridescence, iridescenceIOR, iridescenceThickness, specularColor, shininess, dashSize, gapSize, pointWidth } from './core/PropertyNode.js';
+export { default as PropertyNode, property, varyingProperty, output, diffuseColor, roughness, metalness, clearcoat, clearcoatRoughness, sheen, sheenRoughness, iridescence, iridescenceIOR, iridescenceThickness, specularColor, shininess, dashSize, gapSize, pointWidth, alphaT, anisotropy, anisotropyB, anisotropyT } from './core/PropertyNode.js';
 export { default as StackNode, stack } from './core/StackNode.js';
 export { default as TempNode } from './core/TempNode.js';
 export { default as UniformGroupNode, uniformGroup, objectGroup, renderGroup, frameGroup } from './core/UniformGroupNode.js';
@@ -75,7 +75,7 @@ export { default as ReflectorNode, reflector } from './utils/ReflectorNode.js';
 export * from './shadernode/ShaderNode.js';
 
 // accessors
-export { TBNViewMatrix, parallaxDirection, parallaxUV } from './accessors/AccessorsUtils.js';
+export { TBNViewMatrix, parallaxDirection, parallaxUV, transformedBentNormalView } from './accessors/AccessorsUtils.js';
 export { default as UniformsNode, uniforms } from './accessors/UniformsNode.js';
 export { default as BitangentNode, bitangentGeometry, bitangentLocal, bitangentView, bitangentWorld, transformedBitangentView, transformedBitangentWorld } from './accessors/BitangentNode.js';
 export { default as BufferAttributeNode, bufferAttribute, dynamicBufferAttribute, instancedBufferAttribute, instancedDynamicBufferAttribute } from './accessors/BufferAttributeNode.js';
@@ -85,7 +85,7 @@ export { default as VertexColorNode, vertexColor } from './accessors/VertexColor
 export { default as CubeTextureNode, cubeTexture } from './accessors/CubeTextureNode.js';
 export { default as InstanceNode, instance } from './accessors/InstanceNode.js';
 export { default as BatchNode, batch } from './accessors/BatchNode.js';
-export { default as MaterialNode, materialAlphaTest, materialColor, materialShininess, materialEmissive, materialOpacity, materialSpecularColor, materialSpecularStrength, materialReflectivity, materialRoughness, materialMetalness, materialNormal, materialClearcoat, materialClearcoatRoughness, materialClearcoatNormal, materialRotation, materialSheen, materialSheenRoughness, materialIridescence, materialIridescenceIOR, materialIridescenceThickness, materialLineScale, materialLineDashSize, materialLineGapSize, materialLineWidth, materialLineDashOffset, materialPointWidth } from './accessors/MaterialNode.js';
+export { default as MaterialNode, materialAlphaTest, materialColor, materialShininess, materialEmissive, materialOpacity, materialSpecular, materialSpecularStrength, materialReflectivity, materialRoughness, materialMetalness, materialNormal, materialClearcoat, materialClearcoatRoughness, materialClearcoatNormal, materialRotation, materialSheen, materialSheenRoughness, materialIridescence, materialIridescenceIOR, materialIridescenceThickness, materialLineScale, materialLineDashSize, materialLineGapSize, materialLineWidth, materialLineDashOffset, materialPointWidth, materialAnisotropy, materialAnisotropyVector } from './accessors/MaterialNode.js';
 export { default as MaterialReferenceNode, materialReference } from './accessors/MaterialReferenceNode.js';
 export { default as RendererReferenceNode, rendererReference } from './accessors/RendererReferenceNode.js';
 export { default as MorphNode, morphReference } from './accessors/MorphNode.js';
@@ -158,6 +158,7 @@ export { default as LightingNode /* @TODO: lighting (abstract), light */ } from
 export { default as LightingContextNode, lightingContext } from './lighting/LightingContextNode.js';
 export { default as HemisphereLightNode } from './lighting/HemisphereLightNode.js';
 export { default as EnvironmentNode } from './lighting/EnvironmentNode.js';
+export { default as IrradianceNode } from './lighting/IrradianceNode.js';
 export { default as AONode } from './lighting/AONode.js';
 export { default as AnalyticLightNode } from './lighting/AnalyticLightNode.js';
 

+ 16 - 1
examples/jsm/nodes/accessors/AccessorsUtils.js

@@ -1,10 +1,25 @@
 import { bitangentView } from './BitangentNode.js';
-import { normalView } from './NormalNode.js';
+import { normalView, transformedNormalView } from './NormalNode.js';
 import { tangentView } from './TangentNode.js';
 import { mat3 } from '../shadernode/ShaderNode.js';
+import { mix } from '../math/MathNode.js';
+import { anisotropy, anisotropyB, roughness } from '../core/PropertyNode.js';
 import { positionViewDirection } from './PositionNode.js';
 
 export const TBNViewMatrix = mat3( tangentView, bitangentView, normalView );
 
 export const parallaxDirection = positionViewDirection.mul( TBNViewMatrix )/*.normalize()*/;
 export const parallaxUV = ( uv, scale ) => uv.sub( parallaxDirection.mul( scale ) );
+
+export const transformedBentNormalView = ( () => {
+
+	// https://google.github.io/filament/Filament.md.html#lighting/imagebasedlights/anisotropy
+
+	let bentNormal = anisotropyB.cross( positionViewDirection );
+	bentNormal = bentNormal.cross( anisotropyB ).normalize();
+	bentNormal = mix( bentNormal, transformedNormalView, anisotropy.mul( roughness.oneMinus() ).oneMinus().pow2().pow2() ).normalize();
+
+	return bentNormal;
+
+
+} )();

+ 3 - 2
examples/jsm/nodes/accessors/ClippingNode.js

@@ -5,7 +5,7 @@ import { positionView } from './PositionNode.js';
 import { diffuseColor, property } from '../core/PropertyNode.js';
 import { tslFn } from '../shadernode/ShaderNode.js';
 import { loop } from '../utils/LoopNode.js';
-import { smoothstep  } from '../math/MathNode.js';
+import { smoothstep } from '../math/MathNode.js';
 import { uniforms } from './UniformsNode.js';
 
 class ClippingNode extends Node {
@@ -78,7 +78,7 @@ class ClippingNode extends Node {
 
 					plane = clippingPlanes.element( i );
 
-					distanceToPlane.assign( positionView.dot(  plane.xyz ).negate().add( plane.w ) );
+					distanceToPlane.assign( positionView.dot( plane.xyz ).negate().add( plane.w ) );
 					distanceGradient.assign( distanceToPlane.fwidth().div( 2.0 ) );
 
 					unionClipOpacity.mulAssign( smoothstep( distanceGradient.negate(), distanceGradient, distanceToPlane ).oneMinus() );
@@ -126,6 +126,7 @@ class ClippingNode extends Node {
 				} );
 
 				clipped.discard();
+
 			}
 
 		} )();

+ 107 - 3
examples/jsm/nodes/accessors/MaterialNode.js

@@ -2,7 +2,9 @@ import Node, { addNodeClass } from '../core/Node.js';
 import { reference } from './ReferenceNode.js';
 import { materialReference } from './MaterialReferenceNode.js';
 import { normalView } from './NormalNode.js';
-import { nodeImmutable, float } from '../shadernode/ShaderNode.js';
+import { nodeImmutable, float, vec2, mat2 } from '../shadernode/ShaderNode.js';
+import { uniform } from '../core/UniformNode.js';
+import { Vector2 } from 'three';
 
 const _propertyCache = new Map();
 
@@ -89,7 +91,7 @@ class MaterialNode extends Node {
 
 			if ( material.specularMap && material.specularMap.isTexture === true ) {
 
-				node = this.getTexture( scope ).r;
+				node = this.getTexture( 'specular' ).r;
 
 			} else {
 
@@ -97,6 +99,34 @@ class MaterialNode extends Node {
 
 			}
 
+		} else if ( scope === MaterialNode.SPECULAR_INTENSITY ) {
+
+			const specularIntensity = this.getFloat( scope );
+
+			if ( material.specularMap ) {
+
+				node = specularIntensity.mul( this.getTexture( scope ).a );
+
+			} else {
+
+				node = specularIntensity;
+
+			}
+
+		} else if ( scope === MaterialNode.SPECULAR_COLOR ) {
+
+			const specularColorNode = this.getColor( scope );
+
+			if ( material.specularColorMap && material.specularColorMap.isTexture === true ) {
+
+				node = specularColorNode.mul( this.getTexture( scope ).rgb );
+
+			} else {
+
+				node = specularColorNode;
+
+			}
+
 		} else if ( scope === MaterialNode.ROUGHNESS ) { // TODO: cleanup similar branches
 
 			const roughnessNode = this.getFloat( scope );
@@ -225,6 +255,21 @@ class MaterialNode extends Node {
 
 			node = node.clamp( 0.07, 1.0 );
 
+		} else if ( scope === MaterialNode.ANISOTROPY ) {
+
+			if ( material.anisotropyMap && material.anisotropyMap.isTexture === true ) {
+
+				const anisotropyPolar = this.getTexture( scope );
+				const anisotropyMat = mat2( materialAnisotropyVector.x, materialAnisotropyVector.y, materialAnisotropyVector.y.negate(), materialAnisotropyVector.x );
+
+				node = anisotropyMat.mul( anisotropyPolar.rg.mul( 2.0 ).sub( vec2( 1.0 ) ).normalize().mul( anisotropyPolar.b ) );
+
+			} else {
+
+				node = materialAnisotropyVector;
+
+			}
+
 		} else if ( scope === MaterialNode.IRIDESCENCE_THICKNESS ) {
 
 			const iridescenceThicknessMaximum = reference( '1', 'float', material.iridescenceThicknessRange );
@@ -241,6 +286,38 @@ class MaterialNode extends Node {
 
 			}
 
+		} else if ( scope === MaterialNode.TRANSMISSION ) {
+
+			const transmissionNode = this.getFloat( scope );
+
+			if ( material.transmissionMap ) {
+
+				node = transmissionNode.mul( this.getTexture( scope ).r );
+
+			} else {
+
+				node = transmissionNode;
+
+			}
+
+		} else if ( scope === MaterialNode.THICKNESS ) {
+
+			const thicknessNode = this.getFloat( scope );
+
+			if ( material.thicknessMap ) {
+
+				node = thicknessNode.mul( this.getTexture( scope ).g );
+
+			} else {
+
+				node = thicknessNode;
+
+			}
+
+		} else if ( scope === MaterialNode.IOR ) {
+
+			node = this.getFloat( scope );
+
 		} else {
 
 			const outputType = this.getNodeType( builder );
@@ -259,8 +336,10 @@ MaterialNode.ALPHA_TEST = 'alphaTest';
 MaterialNode.COLOR = 'color';
 MaterialNode.OPACITY = 'opacity';
 MaterialNode.SHININESS = 'shininess';
-MaterialNode.SPECULAR_COLOR = 'specular';
+MaterialNode.SPECULAR = 'specular';
 MaterialNode.SPECULAR_STRENGTH = 'specularStrength';
+MaterialNode.SPECULAR_INTENSITY = 'specularIntensity';
+MaterialNode.SPECULAR_COLOR = 'specularColor';
 MaterialNode.REFLECTIVITY = 'reflectivity';
 MaterialNode.ROUGHNESS = 'roughness';
 MaterialNode.METALNESS = 'metalness';
@@ -272,9 +351,15 @@ MaterialNode.EMISSIVE = 'emissive';
 MaterialNode.ROTATION = 'rotation';
 MaterialNode.SHEEN = 'sheen';
 MaterialNode.SHEEN_ROUGHNESS = 'sheenRoughness';
+MaterialNode.ANISOTROPY = 'anisotropy';
 MaterialNode.IRIDESCENCE = 'iridescence';
 MaterialNode.IRIDESCENCE_IOR = 'iridescenceIOR';
 MaterialNode.IRIDESCENCE_THICKNESS = 'iridescenceThickness';
+MaterialNode.IOR = 'ior';
+MaterialNode.TRANSMISSION = 'transmission';
+MaterialNode.THICKNESS = 'thickness';
+MaterialNode.ATTENUATION_DISTANCE = 'attenuationDistance';
+MaterialNode.ATTENUATION_COLOR = 'attenuationColor';
 MaterialNode.LINE_SCALE = 'scale';
 MaterialNode.LINE_DASH_SIZE = 'dashSize';
 MaterialNode.LINE_GAP_SIZE = 'gapSize';
@@ -289,7 +374,11 @@ export const materialColor = nodeImmutable( MaterialNode, MaterialNode.COLOR );
 export const materialShininess = nodeImmutable( MaterialNode, MaterialNode.SHININESS );
 export const materialEmissive = nodeImmutable( MaterialNode, MaterialNode.EMISSIVE );
 export const materialOpacity = nodeImmutable( MaterialNode, MaterialNode.OPACITY );
+export const materialSpecular = nodeImmutable( MaterialNode, MaterialNode.SPECULAR );
+
+export const materialSpecularIntensity = nodeImmutable( MaterialNode, MaterialNode.SPECULAR_INTENSITY );
 export const materialSpecularColor = nodeImmutable( MaterialNode, MaterialNode.SPECULAR_COLOR );
+
 export const materialSpecularStrength = nodeImmutable( MaterialNode, MaterialNode.SPECULAR_STRENGTH );
 export const materialReflectivity = nodeImmutable( MaterialNode, MaterialNode.REFLECTIVITY );
 export const materialRoughness = nodeImmutable( MaterialNode, MaterialNode.ROUGHNESS );
@@ -301,14 +390,29 @@ export const materialClearcoatNormal = nodeImmutable( MaterialNode, MaterialNode
 export const materialRotation = nodeImmutable( MaterialNode, MaterialNode.ROTATION );
 export const materialSheen = nodeImmutable( MaterialNode, MaterialNode.SHEEN );
 export const materialSheenRoughness = nodeImmutable( MaterialNode, MaterialNode.SHEEN_ROUGHNESS );
+export const materialAnisotropy = nodeImmutable( MaterialNode, MaterialNode.ANISOTROPY );
 export const materialIridescence = nodeImmutable( MaterialNode, MaterialNode.IRIDESCENCE );
 export const materialIridescenceIOR = nodeImmutable( MaterialNode, MaterialNode.IRIDESCENCE_IOR );
 export const materialIridescenceThickness = nodeImmutable( MaterialNode, MaterialNode.IRIDESCENCE_THICKNESS );
+export const materialTransmission = nodeImmutable( MaterialNode, MaterialNode.TRANSMISSION );
+export const materialThickness = nodeImmutable( MaterialNode, MaterialNode.THICKNESS );
+export const materialIOR = nodeImmutable( MaterialNode, MaterialNode.IOR );
+export const materialAttenuationDistance = nodeImmutable( MaterialNode, MaterialNode.ATTENUATION_DISTANCE );
+export const materialAttenuationColor = nodeImmutable( MaterialNode, MaterialNode.ATTENUATION_COLOR );
 export const materialLineScale = nodeImmutable( MaterialNode, MaterialNode.LINE_SCALE );
 export const materialLineDashSize = nodeImmutable( MaterialNode, MaterialNode.LINE_DASH_SIZE );
 export const materialLineGapSize = nodeImmutable( MaterialNode, MaterialNode.LINE_GAP_SIZE );
 export const materialLineWidth = nodeImmutable( MaterialNode, MaterialNode.LINE_WIDTH );
 export const materialLineDashOffset = nodeImmutable( MaterialNode, MaterialNode.LINE_DASH_OFFSET );
 export const materialPointWidth = nodeImmutable( MaterialNode, MaterialNode.POINT_WIDTH );
+export const materialAnisotropyVector = uniform( new Vector2() ).onReference( function ( frame ) {
+
+	return frame.material;
+
+} ).onRenderUpdate( function ( { material } ) {
+
+	this.value.set( material.anisotropy * Math.cos( material.anisotropyRotation ), material.anisotropy * Math.sin( material.anisotropyRotation ) );
+
+} );
 
 addNodeClass( 'MaterialNode', MaterialNode );

+ 9 - 0
examples/jsm/nodes/accessors/StorageBufferNode.js

@@ -18,6 +18,15 @@ class StorageBufferNode extends BufferNode {
 		this._attribute = null;
 		this._varying = null;
 
+		if ( value.isStorageBufferAttribute !== true && value.isStorageInstancedBufferAttribute !== true ) {
+
+			// TOOD: Improve it, possibly adding a new property to the BufferAttribute to identify it as a storage buffer read-only attribute in Renderer
+
+			if ( value.isInstancedBufferAttribute ) value.isStorageInstancedBufferAttribute = true;
+			else value.isStorageBufferAttribute = true;
+
+		}
+
 	}
 
 	getInputType( /*builder*/ ) {

+ 21 - 3
examples/jsm/nodes/accessors/TextureNode.js

@@ -20,6 +20,7 @@ class TextureNode extends UniformNode {
 		this.levelNode = levelNode;
 		this.compareNode = null;
 		this.depthNode = null;
+		this.gradNode = null;
 
 		this.sampler = true;
 		this.updateMatrix = false;
@@ -155,6 +156,7 @@ class TextureNode extends UniformNode {
 		properties.uvNode = uvNode;
 		properties.levelNode = levelNode;
 		properties.compareNode = this.compareNode;
+		properties.gradNode = this.gradNode;
 		properties.depthNode = this.depthNode;
 
 	}
@@ -165,7 +167,7 @@ class TextureNode extends UniformNode {
 
 	}
 
-	generateSnippet( builder, textureProperty, uvSnippet, levelSnippet, depthSnippet, compareSnippet ) {
+	generateSnippet( builder, textureProperty, uvSnippet, levelSnippet, depthSnippet, compareSnippet, gradSnippet ) {
 
 		const texture = this.value;
 
@@ -175,6 +177,10 @@ class TextureNode extends UniformNode {
 
 			snippet = builder.generateTextureLevel( texture, textureProperty, uvSnippet, levelSnippet, depthSnippet );
 
+		} else if ( gradSnippet ) {
+
+			snippet = builder.generateTextureGrad( texture, textureProperty, uvSnippet, gradSnippet, depthSnippet );
+
 		} else if ( compareSnippet ) {
 
 			snippet = builder.generateTextureCompare( texture, textureProperty, uvSnippet, compareSnippet, depthSnippet );
@@ -223,18 +229,19 @@ class TextureNode extends UniformNode {
 
 			if ( propertyName === undefined ) {
 
-				const { uvNode, levelNode, compareNode, depthNode } = properties;
+				const { uvNode, levelNode, compareNode, depthNode, gradNode } = properties;
 
 				const uvSnippet = this.generateUV( builder, uvNode );
 				const levelSnippet = levelNode ? levelNode.build( builder, 'float' ) : null;
 				const depthSnippet = depthNode ? depthNode.build( builder, 'int' ) : null;
 				const compareSnippet = compareNode ? compareNode.build( builder, 'float' ) : null;
+				const gradSnippet = gradNode ? [ gradNode[ 0 ].build( builder, 'vec2' ), gradNode[ 1 ].build( builder, 'vec2' ) ] : null;
 
 				const nodeVar = builder.getVarFromNode( this );
 
 				propertyName = builder.getPropertyName( nodeVar );
 
-				const snippet = this.generateSnippet( builder, textureProperty, uvSnippet, levelSnippet, depthSnippet, compareSnippet );
+				const snippet = this.generateSnippet( builder, textureProperty, uvSnippet, levelSnippet, depthSnippet, compareSnippet, gradSnippet );
 
 				builder.addLineFlowCode( `${propertyName} = ${snippet}` );
 
@@ -324,6 +331,17 @@ class TextureNode extends UniformNode {
 
 	}
 
+	grad( gradNodeX, gradNodeY ) {
+
+		const textureNode = this.clone();
+		textureNode.gradNode = [ nodeObject( gradNodeX ), nodeObject( gradNodeY ) ];
+
+		textureNode.referenceNode = this;
+
+		return nodeObject( textureNode );
+
+	}
+
 	depth( depthNode ) {
 
 		const textureNode = this.clone();

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

@@ -20,7 +20,7 @@ class TextureSizeNode extends Node {
 		const textureProperty = this.textureNode.build( builder, 'property' );
 		const levelNode = this.levelNode.build( builder, 'int' );
 
-		return builder.format( `${builder.getMethod( 'textureDimensions' )}( ${textureProperty}, ${levelNode} )`, this.getNodeType( builder ), output );
+		return builder.format( `${ builder.getMethod( 'textureDimensions' ) }( ${ textureProperty }, ${ levelNode } )`, this.getNodeType( builder ), output );
 
 	}
 

+ 0 - 8
examples/jsm/nodes/code/FunctionNode.js

@@ -127,12 +127,4 @@ const nativeFn = ( code, includes = [], language = '' ) => {
 export const glslFn = ( code, includes ) => nativeFn( code, includes, 'glsl' );
 export const wgslFn = ( code, includes ) => nativeFn( code, includes, 'wgsl' );
 
-export const func = ( code, includes ) => { // @deprecated, r154
-
-	console.warn( 'TSL: func() is deprecated. Use nativeFn(), wgslFn() or glslFn() instead.' );
-
-	return nodeObject( new FunctionNode( code, includes ) );
-
-};
-
 addNodeClass( 'FunctionNode', FunctionNode );

+ 8 - 0
examples/jsm/nodes/core/Node.js

@@ -74,6 +74,14 @@ class Node extends EventDispatcher {
 
 	}
 
+	onReference( callback ) {
+
+		this.updateReference = callback.bind( this.getSelf() );
+
+		return this;
+
+	}
+
 	getSelf() {
 
 		// Returns non-node object.

+ 5 - 9
examples/jsm/nodes/core/NodeBuilder.js

@@ -72,7 +72,6 @@ class NodeBuilder {
 		this.lightsNode = null;
 		this.environmentNode = null;
 		this.fogNode = null;
-		this.toneMappingNode = null;
 
 		this.clippingContext = null;
 
@@ -1087,21 +1086,18 @@ class NodeBuilder {
 
 	}
 
-	build( convertMaterial = true ) {
+	build() {
 
 		const { object, material } = this;
 
-		if ( convertMaterial ) {
 
-			if ( material !== null ) {
+		if ( material !== null ) {
 
-				NodeMaterial.fromMaterial( material ).build( this );
+			NodeMaterial.fromMaterial( material ).build( this );
 
-			} else {
-
-				this.addFlow( 'compute', object );
+		} else {
 
-			}
+			this.addFlow( 'compute', object );
 
 		}
 

+ 2 - 1
examples/jsm/nodes/core/OutputStructNode.js

@@ -8,9 +8,10 @@ class OutputStructNode extends Node {
 
 		super();
 
-		this.isOutputStructNode = true;
 		this.members = members;
 
+		this.isOutputStructNode = true;
+
 	}
 
 	setup( builder ) {

+ 10 - 0
examples/jsm/nodes/core/PropertyNode.js

@@ -62,11 +62,21 @@ export const sheenRoughness = nodeImmutable( PropertyNode, 'float', 'SheenRoughn
 export const iridescence = nodeImmutable( PropertyNode, 'float', 'Iridescence' );
 export const iridescenceIOR = nodeImmutable( PropertyNode, 'float', 'IridescenceIOR' );
 export const iridescenceThickness = nodeImmutable( PropertyNode, 'float', 'IridescenceThickness' );
+export const alphaT = nodeImmutable( PropertyNode, 'float', 'AlphaT' );
+export const anisotropy = nodeImmutable( PropertyNode, 'float', 'Anisotropy' );
+export const anisotropyT = nodeImmutable( PropertyNode, 'vec3', 'AnisotropyT' );
+export const anisotropyB = nodeImmutable( PropertyNode, 'vec3', 'AnisotropyB' );
 export const specularColor = nodeImmutable( PropertyNode, 'color', 'SpecularColor' );
+export const specularF90 = nodeImmutable( PropertyNode, 'float', 'SpecularF90' );
 export const shininess = nodeImmutable( PropertyNode, 'float', 'Shininess' );
 export const output = nodeImmutable( PropertyNode, 'vec4', 'Output' );
 export const dashSize = nodeImmutable( PropertyNode, 'float', 'dashSize' );
 export const gapSize = nodeImmutable( PropertyNode, 'float', 'gapSize' );
 export const pointWidth = nodeImmutable( PropertyNode, 'float', 'pointWidth' );
+export const ior = nodeImmutable( PropertyNode, 'float', 'IOR' );
+export const transmission = nodeImmutable( PropertyNode, 'float', 'Transmission' );
+export const thickness = nodeImmutable( PropertyNode, 'float', 'Thickness' );
+export const attenuationDistance = nodeImmutable( PropertyNode, 'float', 'AttenuationDistance' );
+export const attenuationColor = nodeImmutable( PropertyNode, 'color', 'AttenuationColor' );
 
 addNodeClass( 'PropertyNode', PropertyNode );

+ 7 - 26
examples/jsm/nodes/display/BumpMapNode.js

@@ -9,41 +9,22 @@ import { addNodeElement, tslFn, nodeProxy, float, vec2 } from '../shadernode/Sha
 // Bump Mapping Unparametrized Surfaces on the GPU by Morten S. Mikkelsen
 // https://mmikk.github.io/papers3d/mm_sfgrad_bump.pdf
 
-// Evaluate the derivative of the height w.r.t. screen-space using forward differencing (listing 2)
-
 const dHdxy_fwd = tslFn( ( { textureNode, bumpScale } ) => {
 
-	let texNode = textureNode;
-
-	if ( texNode.isTextureNode !== true ) {
-
-		texNode.traverse( ( node ) => {
-
-			if ( node.isTextureNode === true ) texNode = node;
-
-		} );
-
-	}
-
-	if ( texNode.isTextureNode !== true ) {
-
-		throw new Error( 'THREE.TSL: dHdxy_fwd() requires a TextureNode.' );
-
-	}
-
-	const Hll = float( textureNode );
-	const uvNode = texNode.uvNode || uv();
-
 	// It's used to preserve the same TextureNode instance
-	const sampleTexture = ( uv ) => textureNode.cache().context( { getUV: () => uv, forceUVContext: true } );
+	const sampleTexture = ( callback ) => textureNode.cache().context( { getUV: ( texNode ) => callback( texNode.uvNode || uv() ), forceUVContext: true } );
+
+	const Hll = float( sampleTexture( ( uvNode ) => uvNode ) );
 
 	return vec2(
-		float( sampleTexture( uvNode.add( uvNode.dFdx() ) ) ).sub( Hll ),
-		float( sampleTexture( uvNode.add( uvNode.dFdy() ) ) ).sub( Hll )
+		float( sampleTexture( ( uvNode ) => uvNode.add( uvNode.dFdx() ) ) ).sub( Hll ),
+		float( sampleTexture( ( uvNode ) => uvNode.add( uvNode.dFdy() ) ) ).sub( Hll )
 	).mul( bumpScale );
 
 } );
 
+// Evaluate the derivative of the height w.r.t. screen-space using forward differencing (listing 2)
+
 const perturbNormalArb = tslFn( ( inputs ) => {
 
 	const { surf_pos, surf_norm, dHdxy } = inputs;

+ 13 - 0
examples/jsm/nodes/display/FrontFacingNode.js

@@ -1,5 +1,6 @@
 import Node, { addNodeClass } from '../core/Node.js';
 import { nodeImmutable, float } from '../shadernode/ShaderNode.js';
+import { BackSide, WebGLCoordinateSystem } from 'three';
 
 class FrontFacingNode extends Node {
 
@@ -13,6 +14,18 @@ class FrontFacingNode extends Node {
 
 	generate( builder ) {
 
+		const { renderer, material } = builder;
+
+		if ( renderer.coordinateSystem === WebGLCoordinateSystem ) {
+
+			if ( material.side === BackSide ) {
+
+				return 'false';
+
+			}
+
+		}
+
 		return builder.getFrontFacing();
 
 	}

+ 1 - 1
examples/jsm/nodes/display/ViewportDepthNode.js

@@ -75,7 +75,7 @@ export const orthographicDepthToViewZ = ( depth, near, far ) => near.sub( far ).
 // NOTE: https://twitter.com/gonnavis/status/1377183786949959682
 
 // -near maps to 0; -far maps to 1
-export const viewZToPerspectiveDepth = ( viewZ, near, far ) => near.add( viewZ ).mul( far ).div( near.sub( far ).mul( viewZ ) );
+export const viewZToPerspectiveDepth = ( viewZ, near, far ) => near.add( viewZ ).mul( far ).div( far.sub( near ).mul( viewZ ) );
 
 // maps perspective depth in [ 0, 1 ] to viewZ
 export const perspectiveDepthToViewZ = ( depth, near, far ) => near.mul( far ).div( far.sub( near ).mul( depth ).sub( far ) );

+ 4 - 2
examples/jsm/nodes/display/ViewportNode.js

@@ -21,7 +21,9 @@ class ViewportNode extends Node {
 
 	getNodeType() {
 
-		return this.scope === ViewportNode.VIEWPORT ? 'vec4' : 'vec2';
+		if ( this.scope === ViewportNode.VIEWPORT ) return 'vec4';
+		else if ( this.scope === ViewportNode.COORDINATE ) return 'vec3';
+		else return 'vec2';
 
 	}
 
@@ -99,7 +101,7 @@ class ViewportNode extends Node {
 
 				const resolution = builder.getNodeProperties( viewportResolution ).outputNode.build( builder );
 
-				coord = `${ builder.getType( 'vec2' ) }( ${ coord }.x, ${ resolution }.y - ${ coord }.y )`;
+				coord = `${ builder.getType( 'vec3' ) }( ${ coord }.x, ${ resolution }.y - ${ coord }.y, ${ coord }.z )`;
 
 			}
 

+ 4 - 1
examples/jsm/nodes/display/ViewportTextureNode.js

@@ -58,7 +58,10 @@ class ViewportTextureNode extends TextureNode {
 
 	clone() {
 
-		return new this.constructor( this.uvNode, this.levelNode, this.value );
+		const viewportTextureNode = new this.constructor( this.uvNode, this.levelNode, this.value );
+		viewportTextureNode.generateMipmaps = this.generateMipmaps;
+
+		return viewportTextureNode;
 
 	}
 

+ 26 - 7
examples/jsm/nodes/functions/BSDF/BRDF_GGX.js

@@ -1,15 +1,17 @@
 import F_Schlick from './F_Schlick.js';
 import V_GGX_SmithCorrelated from './V_GGX_SmithCorrelated.js';
+import V_GGX_SmithCorrelated_Anisotropic from './V_GGX_SmithCorrelated_Anisotropic.js';
 import D_GGX from './D_GGX.js';
+import D_GGX_Anisotropic from './D_GGX_Anisotropic.js';
 import { transformedNormalView } from '../../accessors/NormalNode.js';
 import { positionViewDirection } from '../../accessors/PositionNode.js';
-import { iridescence } from '../../core/PropertyNode.js';
-import { tslFn } from '../../shadernode/ShaderNode.js';
+import { iridescence, alphaT, anisotropyT, anisotropyB } from '../../core/PropertyNode.js';
+import { tslFn, defined } from '../../shadernode/ShaderNode.js';
 
 // GGX Distribution, Schlick Fresnel, GGX_SmithCorrelated Visibility
 const BRDF_GGX = tslFn( ( inputs ) => {
 
-	const { lightDirection, f0, f90, roughness, iridescenceFresnel } = inputs;
+	const { lightDirection, f0, f90, roughness, f, USE_IRIDESCENCE, USE_ANISOTROPY } = inputs;
 
 	const normalView = inputs.normalView || transformedNormalView;
 
@@ -23,15 +25,32 @@ const BRDF_GGX = tslFn( ( inputs ) => {
 	const dotVH = positionViewDirection.dot( halfDir ).clamp();
 
 	let F = F_Schlick( { f0, f90, dotVH } );
+	let V, D;
 
-	if ( iridescenceFresnel ) {
+	if ( defined( USE_IRIDESCENCE ) ) {
 
-		F = iridescence.mix( F, iridescenceFresnel );
+		F = iridescence.mix( F, f );
 
 	}
 
-	const V = V_GGX_SmithCorrelated( { alpha, dotNL, dotNV } );
-	const D = D_GGX( { alpha, dotNH } );
+	if ( defined( USE_ANISOTROPY ) ) {
+
+		const dotTL = anisotropyT.dot( lightDirection );
+		const dotTV = anisotropyT.dot( positionViewDirection );
+		const dotTH = anisotropyT.dot( halfDir );
+		const dotBL = anisotropyB.dot( lightDirection );
+		const dotBV = anisotropyB.dot( positionViewDirection );
+		const dotBH = anisotropyB.dot( halfDir );
+
+		V = V_GGX_SmithCorrelated_Anisotropic( { alphaT, alphaB: alpha, dotTV, dotBV, dotTL, dotBL, dotNV, dotNL } );
+		D = D_GGX_Anisotropic( { alphaT, alphaB: alpha, dotNH, dotTH, dotBH } );
+
+	} else {
+
+		V = V_GGX_SmithCorrelated( { alpha, dotNL, dotNV } );
+		D = D_GGX( { alpha, dotNH } );
+
+	}
 
 	return F.mul( V ).mul( D );
 

+ 28 - 0
examples/jsm/nodes/functions/BSDF/D_GGX_Anisotropic.js

@@ -0,0 +1,28 @@
+import { tslFn, float, vec3 } from '../../shadernode/ShaderNode.js';
+
+const RECIPROCAL_PI = float( 1 / Math.PI );
+
+// https://google.github.io/filament/Filament.md.html#materialsystem/anisotropicmodel/anisotropicspecularbrdf
+
+const D_GGX_Anisotropic = tslFn( ( { alphaT, alphaB, dotNH, dotTH, dotBH } ) => {
+
+	const a2 = alphaT.mul( alphaB );
+	const v = vec3( alphaB.mul( dotTH ), alphaT.mul( dotBH ), a2.mul( dotNH ) );
+	const v2 = v.dot( v );
+	const w2 = a2.div( v2 );
+
+	return RECIPROCAL_PI.mul( a2.mul( w2.pow2() ) );
+
+} ).setLayout( {
+	name: 'D_GGX_Anisotropic',
+	type: 'float',
+	inputs: [
+		{ name: 'alphaT', type: 'float', qualifier: 'in' },
+		{ name: 'alphaB', type: 'float', qualifier: 'in' },
+		{ name: 'dotNH', type: 'float', qualifier: 'in' },
+		{ name: 'dotTH', type: 'float', qualifier: 'in' },
+		{ name: 'dotBH', type: 'float', qualifier: 'in' }
+	]
+} );
+
+export default D_GGX_Anisotropic;

+ 1 - 3
examples/jsm/nodes/functions/BSDF/V_GGX_SmithCorrelated.js

@@ -4,9 +4,7 @@ import { tslFn } from '../../shadernode/ShaderNode.js';
 
 // Moving Frostbite to Physically Based Rendering 3.0 - page 12, listing 2
 // https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf
-const V_GGX_SmithCorrelated = tslFn( ( inputs ) => {
-
-	const { alpha, dotNL, dotNV } = inputs;
+const V_GGX_SmithCorrelated = tslFn( ( { alpha, dotNL, dotNV } ) => {
 
 	const a2 = alpha.pow2();
 

+ 29 - 0
examples/jsm/nodes/functions/BSDF/V_GGX_SmithCorrelated_Anisotropic.js

@@ -0,0 +1,29 @@
+import { div } from '../../math/OperatorNode.js';
+import { tslFn, vec3 } from '../../shadernode/ShaderNode.js';
+
+// https://google.github.io/filament/Filament.md.html#materialsystem/anisotropicmodel/anisotropicspecularbrdf
+
+const V_GGX_SmithCorrelated_Anisotropic = tslFn( ( { alphaT, alphaB, dotTV, dotBV, dotTL, dotBL, dotNV, dotNL } ) => {
+
+	const gv = dotNL.mul( vec3( alphaT.mul( dotTV ), alphaB.mul( dotBV ), dotNV ).length() );
+	const gl = dotNV.mul( vec3( alphaT.mul( dotTL ), alphaB.mul( dotBL ), dotNL ).length() );
+	const v = div( 0.5, gv.add( gl ) );
+
+	return v.saturate();
+
+} ).setLayout( {
+	name: 'V_GGX_SmithCorrelated_Anisotropic',
+	type: 'float',
+	inputs: [
+		{ name: 'alphaT', type: 'float', qualifier: 'in' },
+		{ name: 'alphaB', type: 'float', qualifier: 'in' },
+		{ name: 'dotTV', type: 'float', qualifier: 'in' },
+		{ name: 'dotBV', type: 'float', qualifier: 'in' },
+		{ name: 'dotTL', type: 'float', qualifier: 'in' },
+		{ name: 'dotBL', type: 'float', qualifier: 'in' },
+		{ name: 'dotNV', type: 'float', qualifier: 'in' },
+		{ name: 'dotNL', type: 'float', qualifier: 'in' }
+	]
+} );
+
+export default V_GGX_SmithCorrelated_Anisotropic;

+ 1 - 1
examples/jsm/nodes/functions/PhongLightingModel.js

@@ -12,7 +12,7 @@ const G_BlinnPhong_Implicit = () => float( 0.25 );
 
 const D_BlinnPhong = tslFn( ( { dotNH } ) => {
 
-	return shininess.mul( 0.5 / Math.PI ).add( 1.0 ).mul( dotNH.pow( shininess ) );
+	return shininess.mul( float( 0.5 ) ).add( 1.0 ).mul( float( 1 / Math.PI ) ).mul( dotNH.pow( shininess ) );
 
 } );
 

+ 164 - 10
examples/jsm/nodes/functions/PhysicalLightingModel.js

@@ -6,12 +6,135 @@ import F_Schlick from './BSDF/F_Schlick.js';
 import Schlick_to_F0 from './BSDF/Schlick_to_F0.js';
 import BRDF_Sheen from './BSDF/BRDF_Sheen.js';
 import LightingModel from '../core/LightingModel.js';
-import { diffuseColor, specularColor, roughness, clearcoat, clearcoatRoughness, sheen, sheenRoughness, iridescence, iridescenceIOR, iridescenceThickness } from '../core/PropertyNode.js';
-import { transformedNormalView, transformedClearcoatNormalView } from '../accessors/NormalNode.js';
-import { positionViewDirection } from '../accessors/PositionNode.js';
-import { tslFn, float, vec3, mat3 } from '../shadernode/ShaderNode.js';
+import { diffuseColor, specularColor, specularF90, roughness, clearcoat, clearcoatRoughness, sheen, sheenRoughness, iridescence, iridescenceIOR, iridescenceThickness, ior, thickness, transmission, attenuationDistance, attenuationColor } from '../core/PropertyNode.js';
+import { transformedNormalView, transformedClearcoatNormalView, transformedNormalWorld } from '../accessors/NormalNode.js';
+import { positionViewDirection, positionWorld } from '../accessors/PositionNode.js';
+import { tslFn, float, vec2, vec3, vec4, mat3, If } from '../shadernode/ShaderNode.js';
 import { cond } from '../math/CondNode.js';
-import { mix, smoothstep } from '../math/MathNode.js';
+import { mix, normalize, refract, length, clamp, log2, log, exp, smoothstep } from '../math/MathNode.js';
+import { div } from '../math/OperatorNode.js';
+import { cameraPosition, cameraProjectionMatrix, cameraViewMatrix } from '../accessors/CameraNode.js';
+import { modelWorldMatrix } from '../accessors/ModelNode.js';
+import { viewportResolution } from '../display/ViewportNode.js';
+import { viewportMipTexture } from '../display/ViewportTextureNode.js';
+
+//
+// Transmission
+//
+
+const getVolumeTransmissionRay = tslFn( ( [ n, v, thickness, ior, modelMatrix ] ) => {
+
+	// Direction of refracted light.
+	const refractionVector = vec3( refract( v.negate(), normalize( n ), div( 1.0, ior ) ) );
+
+	// Compute rotation-independant scaling of the model matrix.
+	const modelScale = vec3(
+		length( modelMatrix[ 0 ].xyz ),
+		length( modelMatrix[ 1 ].xyz ),
+		length( modelMatrix[ 2 ].xyz )
+	);
+
+	// The thickness is specified in local space.
+	return normalize( refractionVector ).mul( thickness.mul( modelScale ) );
+
+} ).setLayout( {
+	name: 'getVolumeTransmissionRay',
+	type: 'vec3',
+	inputs: [
+		{ name: 'n', type: 'vec3' },
+		{ name: 'v', type: 'vec3' },
+		{ name: 'thickness', type: 'float' },
+		{ name: 'ior', type: 'float' },
+		{ name: 'modelMatrix', type: 'mat4' }
+	]
+} );
+
+const applyIorToRoughness = tslFn( ( [ roughness, ior ] ) => {
+
+	// Scale roughness with IOR so that an IOR of 1.0 results in no microfacet refraction and
+	// an IOR of 1.5 results in the default amount of microfacet refraction.
+	return roughness.mul( clamp( ior.mul( 2.0 ).sub( 2.0 ), 0.0, 1.0 ) );
+
+} ).setLayout( {
+	name: 'applyIorToRoughness',
+	type: 'float',
+	inputs: [
+		{ name: 'roughness', type: 'float' },
+		{ name: 'ior', type: 'float' }
+	]
+} );
+
+const singleViewportMipTexture = viewportMipTexture();
+
+const getTransmissionSample = tslFn( ( [ fragCoord, roughness, ior ] ) => {
+
+	const transmissionSample = singleViewportMipTexture.uv( fragCoord );
+	//const transmissionSample = viewportMipTexture( fragCoord );
+
+	const lod = log2( float( viewportResolution.x ) ).mul( applyIorToRoughness( roughness, ior ) );
+
+	return transmissionSample.bicubic( lod );
+
+} );
+
+const volumeAttenuation = tslFn( ( [ transmissionDistance, attenuationColor, attenuationDistance ] ) => {
+
+	If( attenuationDistance.notEqual( 0 ), () => {
+
+		// Compute light attenuation using Beer's law.
+		const attenuationCoefficient = log( attenuationColor ).negate().div( attenuationDistance );
+		const transmittance = exp( attenuationCoefficient.negate().mul( transmissionDistance ) );
+
+		return transmittance;
+
+	} );
+
+	// Attenuation distance is +∞, i.e. the transmitted color is not attenuated at all.
+	return vec3( 1.0 );
+
+} ).setLayout( {
+	name: 'volumeAttenuation',
+	type: 'vec3',
+	inputs: [
+		{ name: 'transmissionDistance', type: 'float' },
+		{ name: 'attenuationColor', type: 'vec3' },
+		{ name: 'attenuationDistance', type: 'float' }
+	]
+} );
+
+const getIBLVolumeRefraction = tslFn( ( [ n, v, roughness, diffuseColor, specularColor, specularF90, position, modelMatrix, viewMatrix, projMatrix, ior, thickness, attenuationColor, attenuationDistance ] ) => {
+
+	const transmissionRay = getVolumeTransmissionRay( n, v, thickness, ior, modelMatrix );
+	const refractedRayExit = position.add( transmissionRay );
+
+	// Project refracted vector on the framebuffer, while mapping to normalized device coordinates.
+	const ndcPos = projMatrix.mul( viewMatrix.mul( vec4( refractedRayExit, 1.0 ) ) );
+	const refractionCoords = vec2( ndcPos.xy.div( ndcPos.w ) ).toVar();
+	refractionCoords.addAssign( 1.0 );
+	refractionCoords.divAssign( 2.0 );
+	refractionCoords.assign( vec2( refractionCoords.x, refractionCoords.y.oneMinus() ) ); // webgpu
+
+	// Sample framebuffer to get pixel the refracted ray hits.
+	const transmittedLight = getTransmissionSample( refractionCoords, roughness, ior );
+	const transmittance = diffuseColor.mul( volumeAttenuation( length( transmissionRay ), attenuationColor, attenuationDistance ) );
+	const attenuatedColor = transmittance.rgb.mul( transmittedLight.rgb );
+	const dotNV = n.dot( v ).clamp();
+
+	// Get the specular component.
+	const F = vec3( EnvironmentBRDF( { // n, v, specularColor, specularF90, roughness
+		dotNV,
+		specularColor,
+		specularF90,
+		roughness
+	} ) );
+
+	// As less light is transmitted, the opacity should be increased. This simple approximation does a decent job
+	// of modulating a CSS background, and has no effect when the buffer is opaque, due to a solid object or clear color.
+	const transmittanceFactor = transmittance.r.add( transmittance.g, transmittance.b ).div( 3.0 );
+
+	return vec4( F.oneMinus().mul( attenuatedColor ), transmittedLight.a.oneMinus().mul( transmittanceFactor ).oneMinus() );
+
+} );
 
 //
 // Iridescence
@@ -172,13 +295,15 @@ const clearcoatF90 = vec3( 1 );
 
 class PhysicalLightingModel extends LightingModel {
 
-	constructor( clearcoat = false, sheen = false, iridescence = false ) {
+	constructor( clearcoat = false, sheen = false, iridescence = false, anisotropy = false, transmission = false ) {
 
 		super();
 
 		this.clearcoat = clearcoat;
 		this.sheen = sheen;
 		this.iridescence = iridescence;
+		this.anisotropy = anisotropy;
+		this.transmission = transmission;
 
 		this.clearcoatRadiance = null;
 		this.clearcoatSpecularDirect = null;
@@ -190,7 +315,7 @@ class PhysicalLightingModel extends LightingModel {
 
 	}
 
-	start( /*context*/ ) {
+	start( context ) {
 
 		if ( this.clearcoat === true ) {
 
@@ -223,13 +348,42 @@ class PhysicalLightingModel extends LightingModel {
 
 		}
 
+		if ( this.transmission === true ) {
+
+			const position = positionWorld;
+			const v = cameraPosition.sub( positionWorld ).normalize(); // TODO: Create Node for this, same issue in MaterialX
+			const n = transformedNormalWorld;
+
+			context.backdrop = getIBLVolumeRefraction(
+				n,
+				v,
+				roughness,
+				diffuseColor,
+				specularColor,
+				specularF90, // specularF90
+				position, // positionWorld
+				modelWorldMatrix, // modelMatrix
+				cameraViewMatrix, // viewMatrix
+				cameraProjectionMatrix, // projMatrix
+				ior,
+				thickness,
+				attenuationColor,
+				attenuationDistance
+			);
+
+			context.backdropAlpha = transmission;
+
+			diffuseColor.a.mulAssign( mix( 1, context.backdrop.a, transmission ) );
+
+		}
+
 	}
 
 	// Fdez-Agüera's "Multiple-Scattering Microfacet Model for Real-Time Image Based Lighting"
 	// Approximates multiscattering in order to preserve energy.
 	// http://www.jcgt.org/published/0008/01/03/
 
-	computeMultiscattering( singleScatter, multiScatter, specularF90 = float( 1 ) ) {
+	computeMultiscattering( singleScatter, multiScatter, specularF90 ) {
 
 		const dotNV = transformedNormalView.dot( positionViewDirection ).clamp(); // @ TODO: Move to core dotNV
 
@@ -272,7 +426,7 @@ class PhysicalLightingModel extends LightingModel {
 
 		reflectedLight.directDiffuse.addAssign( irradiance.mul( BRDF_Lambert( { diffuseColor: diffuseColor.rgb } ) ) );
 
-		reflectedLight.directSpecular.addAssign( irradiance.mul( BRDF_GGX( { lightDirection, f0: specularColor, f90: 1, roughness, iridescence: this.iridescence, iridescenceFresnel: this.iridescenceFresnel } ) ) );
+		reflectedLight.directSpecular.addAssign( irradiance.mul( BRDF_GGX( { lightDirection, f0: specularColor, f90: 1, roughness, iridescence: this.iridescence, f: this.iridescenceFresnel, USE_IRIDESCENCE: this.iridescence, USE_ANISOTROPY: this.anisotropy } ) ) );
 
 	}
 
@@ -318,7 +472,7 @@ class PhysicalLightingModel extends LightingModel {
 		const multiScattering = vec3().temp( 'multiScattering' );
 		const cosineWeightedIrradiance = iblIrradiance.mul( 1 / Math.PI );
 
-		this.computeMultiscattering( singleScattering, multiScattering );
+		this.computeMultiscattering( singleScattering, multiScattering, specularF90 );
 
 		const totalScattering = singleScattering.add( multiScattering );
 

+ 31 - 0
examples/jsm/nodes/functions/ShadowMaskModel.js

@@ -0,0 +1,31 @@
+import LightingModel from '../core/LightingModel.js';
+import { diffuseColor } from '../core/PropertyNode.js';
+import { float } from '../shadernode/ShaderNode.js';
+
+class ShadowMaskModel extends LightingModel {
+
+	constructor() {
+
+		super();
+
+		this.shadowNode = float( 1 ).toVar( 'shadowMask' );
+
+	}
+
+	direct( { shadowMask } ) {
+
+		this.shadowNode.mulAssign( shadowMask );
+
+	}
+
+	finish( context ) {
+
+		diffuseColor.a.mulAssign( this.shadowNode.oneMinus() );
+
+		context.outgoingLight.rgb.assign( diffuseColor.rgb ); // TODO: Optimize LightsNode to avoid this assignment
+
+	}
+
+}
+
+export default ShadowMaskModel;

+ 18 - 4
examples/jsm/nodes/lighting/AnalyticLightNode.js

@@ -10,7 +10,7 @@ import { normalWorld } from '../accessors/NormalNode.js';
 import { WebGPUCoordinateSystem } from 'three';
 //import { add } from '../math/OperatorNode.js';
 
-import { Color, DepthTexture, NearestFilter, LessCompare } from 'three';
+import { Color, DepthTexture, NearestFilter, LessCompare, NoToneMapping } from 'three';
 
 let overrideMaterial = null;
 
@@ -26,6 +26,7 @@ class AnalyticLightNode extends LightingNode {
 
 		this.rtt = null;
 		this.shadowNode = null;
+		this.shadowMaskNode = null;
 
 		this.color = new Color();
 		this._defaultColorNode = uniform( this.color );
@@ -50,6 +51,10 @@ class AnalyticLightNode extends LightingNode {
 
 	setupShadow( builder ) {
 
+		const { object } = builder;
+
+		if ( object.receiveShadow === false ) return;
+
 		let shadowNode = this.shadowNode;
 
 		if ( shadowNode === null ) {
@@ -81,7 +86,9 @@ class AnalyticLightNode extends LightingNode {
 			const bias = reference( 'bias', 'float', shadow );
 			const normalBias = reference( 'normalBias', 'float', shadow );
 
-			let shadowCoord = uniform( shadow.matrix ).mul( positionWorld.add( normalWorld.mul( normalBias ) ) );
+			const position = object.material.shadowPositionNode || positionWorld;
+
+			let shadowCoord = uniform( shadow.matrix ).mul( position.add( normalWorld.mul( normalBias ) ) );
 			shadowCoord = shadowCoord.xyz.div( shadowCoord.w );
 
 			const frustumTest = shadowCoord.x.greaterThanEqual( 0 )
@@ -145,15 +152,17 @@ class AnalyticLightNode extends LightingNode {
 				textureCompare( depthTexture, shadowCoord.xy.add( vec2( 0, dy1 ) ), shadowCoord.z ),
 				textureCompare( depthTexture, shadowCoord.xy.add( vec2( dx1, dy1 ) ), shadowCoord.z )
 			).mul( 1 / 17 );
-			*/
+			 */
 			//
 
 			const shadowColor = texture( rtt.texture, shadowCoord );
+			const shadowMaskNode = frustumTest.mix( 1, shadowNode.mix( shadowColor.a.mix( 1, shadowColor ), 1 ) );
 
 			this.rtt = rtt;
-			this.colorNode = this.colorNode.mul( frustumTest.mix( 1, shadowNode.mix( shadowColor.a.mix( 1, shadowColor ), 1 ) ) );
+			this.colorNode = this.colorNode.mul( shadowMaskNode );
 
 			this.shadowNode = shadowNode;
+			this.shadowMaskNode = shadowMaskNode;
 
 			//
 
@@ -183,6 +192,7 @@ class AnalyticLightNode extends LightingNode {
 
 		light.shadow.updateMatrices( light );
 
+		const currentToneMapping = renderer.toneMapping;
 		const currentRenderTarget = renderer.getRenderTarget();
 		const currentRenderObjectFunction = renderer.getRenderObjectFunction();
 
@@ -197,12 +207,15 @@ class AnalyticLightNode extends LightingNode {
 		} );
 
 		renderer.setRenderTarget( rtt );
+		renderer.toneMapping = NoToneMapping;
 
 		renderer.render( scene, light.shadow.camera );
 
 		renderer.setRenderTarget( currentRenderTarget );
 		renderer.setRenderObjectFunction( currentRenderObjectFunction );
 
+		renderer.toneMapping = currentToneMapping;
+
 		scene.overrideMaterial = currentOverrideMaterial;
 
 	}
@@ -212,6 +225,7 @@ class AnalyticLightNode extends LightingNode {
 		this.rtt.dispose();
 
 		this.shadowNode = null;
+		this.shadowMaskNode = null;
 		this.rtt = null;
 
 		this.colorNode = this._defaultColorNode;

+ 2 - 1
examples/jsm/nodes/lighting/DirectionalLightNode.js

@@ -26,7 +26,8 @@ class DirectionalLightNode extends AnalyticLightNode {
 		lightingModel.direct( {
 			lightDirection,
 			lightColor,
-			reflectedLight
+			reflectedLight,
+			shadowMask: this.shadowMaskNode
 		}, builder.stack, builder );
 
 	}

+ 11 - 2
examples/jsm/nodes/lighting/EnvironmentNode.js

@@ -8,6 +8,7 @@ import { positionViewDirection } from '../accessors/PositionNode.js';
 import { addNodeClass } from '../core/Node.js';
 import { float } from '../shadernode/ShaderNode.js';
 import { reference } from '../accessors/ReferenceNode.js';
+import { transformedBentNormalView } from '../accessors/AccessorsUtils.js';
 import { pmremTexture } from '../pmrem/PMREMNode.js';
 
 const envNodeCache = new WeakMap();
@@ -44,10 +45,15 @@ class EnvironmentNode extends LightingNode {
 
 		//
 
-		const envMap = builder.material.envMap;
+		const { material } = builder;
+
+		const envMap = material.envMap;
 		const intensity = envMap ? reference( 'envMapIntensity', 'float', builder.material ) : reference( 'environmentIntensity', 'float', builder.scene ); // @TODO: Add materialEnvIntensity in MaterialNode
 
-		const radiance = context( envNode, createRadianceContext( roughness, transformedNormalView ) ).mul( intensity );
+		const useAnisotropy = material.useAnisotropy === true || material.anisotropy > 0;
+		const radianceNormalView = useAnisotropy ? transformedBentNormalView : transformedNormalView;
+
+		const radiance = context( envNode, createRadianceContext( roughness, radianceNormalView ) ).mul( intensity );
 		const irradiance = context( envNode, createIrradianceContext( transformedNormalWorld ) ).mul( Math.PI ).mul( intensity );
 
 		const isolateRadiance = cache( radiance );
@@ -85,7 +91,10 @@ const createRadianceContext = ( roughnessNode, normalViewNode ) => {
 			if ( reflectVec === null ) {
 
 				reflectVec = positionViewDirection.negate().reflect( normalViewNode );
+
+				// Mixing the reflection with the normal is more accurate and keeps rough objects from gathering light from behind their tangent plane.
 				reflectVec = roughnessNode.mul( roughnessNode ).mix( reflectVec, normalViewNode ).normalize();
+
 				reflectVec = reflectVec.transformDirection( cameraViewMatrix );
 
 			}

+ 24 - 0
examples/jsm/nodes/lighting/IrradianceNode.js

@@ -0,0 +1,24 @@
+import LightingNode from './LightingNode.js';
+import { addNodeClass } from '../core/Node.js';
+
+class IrradianceNode extends LightingNode {
+
+	constructor( node ) {
+
+		super();
+
+		this.node = node;
+
+	}
+
+	setup( builder ) {
+
+		builder.context.irradiance.addAssign( this.node );
+
+	}
+
+}
+
+export default IrradianceNode;
+
+addNodeClass( 'IrradianceNode', IrradianceNode );

+ 11 - 1
examples/jsm/nodes/lighting/LightsNode.js

@@ -95,7 +95,17 @@ class LightsNode extends Node {
 
 			if ( backdrop !== null ) {
 
-				totalDiffuse = vec3( backdropAlpha !== null ? backdropAlpha.mix( totalDiffuse, backdrop ) : backdrop );
+				if ( backdropAlpha !== null ) {
+
+					totalDiffuse = vec3( backdropAlpha.mix( totalDiffuse, backdrop ) );
+
+				} else {
+
+					totalDiffuse = vec3( backdrop );
+
+				}
+
+				context.material.transparent = true;
 
 			}
 

+ 2 - 1
examples/jsm/nodes/lighting/PointLightNode.js

@@ -54,7 +54,8 @@ class PointLightNode extends AnalyticLightNode {
 		lightingModel.direct( {
 			lightDirection,
 			lightColor,
-			reflectedLight
+			reflectedLight,
+			shadowMask: this.shadowMaskNode
 		}, builder.stack, builder );
 
 	}

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