Mr.doob 1 year ago
parent
commit
b3675eb8d4
100 changed files with 2778 additions and 2294 deletions
  1. 107 133
      build/three.cjs
  2. 107 133
      build/three.js
  3. 0 0
      build/three.min.js
  4. 103 133
      build/three.module.js
  5. 0 0
      build/three.module.min.js
  6. 1 1
      docs/api/ar/lights/SpotLight.html
  7. 1 1
      docs/api/ar/materials/MeshPhysicalMaterial.html
  8. 1 1
      docs/api/ar/math/Matrix3.html
  9. 3 3
      docs/api/en/core/Object3D.html
  10. 1 2
      docs/api/en/lights/SpotLight.html
  11. 42 3
      docs/api/en/materials/MeshPhysicalMaterial.html
  12. 1 1
      docs/api/en/math/Matrix3.html
  13. 16 16
      docs/api/en/renderers/WebGLRenderer.html
  14. 1 1
      docs/api/fr/materials/MeshPhysicalMaterial.html
  15. 1 1
      docs/api/it/lights/SpotLight.html
  16. 1 1
      docs/api/it/materials/MeshPhysicalMaterial.html
  17. 1 1
      docs/api/it/math/Matrix3.html
  18. 1 1
      docs/api/zh/lights/SpotLight.html
  19. 1 1
      docs/api/zh/materials/MeshPhysicalMaterial.html
  20. 1 1
      docs/api/zh/math/Matrix3.html
  21. 23 26
      docs/api/zh/textures/CompressedArrayTexture.html
  22. 4 3
      docs/examples/en/controls/OrbitControls.html
  23. 0 96
      docs/examples/en/exporters/ColladaExporter.html
  24. 8 0
      docs/examples/en/math/OBB.html
  25. 1 1
      docs/examples/en/utils/CameraUtils.html
  26. 6 2
      docs/examples/ko/controls/OrbitControls.html
  27. 6 1
      docs/examples/zh/controls/OrbitControls.html
  28. 0 2
      docs/list.json
  29. 2 2
      docs/manual/ar/introduction/Installation.html
  30. 1 1
      docs/manual/en/introduction/Installation.html
  31. 2 2
      docs/manual/fr/introduction/Installation.html
  32. 2 2
      docs/manual/it/introduction/Installation.html
  33. 2 2
      docs/manual/ja/introduction/Installation.html
  34. 2 2
      docs/manual/ko/introduction/Installation.html
  35. 2 2
      docs/manual/pt-br/introduction/Installation.html
  36. 2 2
      docs/manual/ru/introduction/Installation.html
  37. 2 2
      docs/manual/zh/introduction/Installation.html
  38. 1 1
      docs/page.js
  39. 1 1
      docs/scenes/bones-browser.html
  40. 1 1
      docs/scenes/ccdiksolver-browser.html
  41. 1 1
      docs/scenes/geometry-browser.html
  42. 1 1
      docs/scenes/material-browser.html
  43. 168 150
      editor/js/libs/es-module-shims.js
  44. 1 1
      examples/css2d_label.html
  45. 1 1
      examples/css3d_molecules.html
  46. 1 1
      examples/css3d_orthographic.html
  47. 1 1
      examples/css3d_periodictable.html
  48. 1 1
      examples/css3d_sandbox.html
  49. 1 1
      examples/css3d_sprites.html
  50. 1 1
      examples/css3d_youtube.html
  51. 5 1
      examples/files.json
  52. 1 1
      examples/games_fps.html
  53. 0 8
      examples/index.html
  54. 13 5
      examples/jsm/controls/OrbitControls.js
  55. 35 1
      examples/jsm/csm/CSMShader.js
  56. 776 720
      examples/jsm/libs/tween.module.js
  57. 430 413
      examples/jsm/libs/utif.module.js
  58. 46 3
      examples/jsm/loaders/DDSLoader.js
  59. 4 4
      examples/jsm/loaders/EXRLoader.js
  60. 2 0
      examples/jsm/loaders/FBXLoader.js
  61. 15 7
      examples/jsm/loaders/GLTFLoader.js
  62. 128 77
      examples/jsm/loaders/KTX2Loader.js
  63. 2 2
      examples/jsm/loaders/LogLuvLoader.js
  64. 10 7
      examples/jsm/loaders/MMDLoader.js
  65. 48 66
      examples/jsm/loaders/RGBELoader.js
  66. 7 0
      examples/jsm/loaders/STLLoader.js
  67. 3 0
      examples/jsm/nodes/Nodes.js
  68. 28 2
      examples/jsm/nodes/accessors/BufferAttributeNode.js
  69. 18 3
      examples/jsm/nodes/accessors/CubeTextureNode.js
  70. 2 4
      examples/jsm/nodes/accessors/ExtendedMaterialNode.js
  71. 31 0
      examples/jsm/nodes/accessors/LineMaterialNode.js
  72. 55 33
      examples/jsm/nodes/accessors/MaterialNode.js
  73. 3 0
      examples/jsm/nodes/accessors/MaterialReferenceNode.js
  74. 2 2
      examples/jsm/nodes/accessors/Object3DNode.js
  75. 6 2
      examples/jsm/nodes/accessors/TextureNode.js
  76. 29 0
      examples/jsm/nodes/accessors/TextureStoreNode.js
  77. 2 2
      examples/jsm/nodes/core/AttributeNode.js
  78. 17 1
      examples/jsm/nodes/core/Node.js
  79. 94 12
      examples/jsm/nodes/core/NodeBuilder.js
  80. 1 1
      examples/jsm/nodes/core/NodeUniform.js
  81. 58 0
      examples/jsm/nodes/core/OutputStructNode.js
  82. 2 0
      examples/jsm/nodes/core/PropertyNode.js
  83. 4 4
      examples/jsm/nodes/core/StackNode.js
  84. 24 0
      examples/jsm/nodes/core/StructTypeNode.js
  85. 19 5
      examples/jsm/nodes/display/ViewportNode.js
  86. 54 0
      examples/jsm/nodes/materials/LineDashedNodeMaterial.js
  87. 1 0
      examples/jsm/nodes/materials/Materials.js
  88. 12 3
      examples/jsm/nodes/materials/NodeMaterial.js
  89. 35 0
      examples/jsm/nodes/math/HashNode.js
  90. 4 0
      examples/jsm/nodes/shadernode/ShaderNode.js
  91. 1 1
      examples/jsm/nodes/utils/SplitNode.js
  92. 3 5
      examples/jsm/postprocessing/FilmPass.js
  93. 30 12
      examples/jsm/postprocessing/RenderPass.js
  94. 23 98
      examples/jsm/postprocessing/SAOPass.js
  95. 10 30
      examples/jsm/postprocessing/SSAOPass.js
  96. 11 8
      examples/jsm/renderers/common/Backend.js
  97. 6 0
      examples/jsm/renderers/common/Binding.js
  98. 5 4
      examples/jsm/renderers/common/Bindings.js
  99. 2 2
      examples/jsm/renderers/common/Pipelines.js
  100. 26 1
      examples/jsm/renderers/common/RenderContexts.js

+ 107 - 133
build/three.cjs

@@ -5,7 +5,7 @@
  */
 'use strict';
 
-const REVISION = '155';
+const REVISION = '156';
 
 const MOUSE = { LEFT: 0, MIDDLE: 1, RIGHT: 2, ROTATE: 0, DOLLY: 1, PAN: 2 };
 const TOUCH = { ROTATE: 0, PAN: 1, DOLLY_PAN: 2, DOLLY_ROTATE: 3 };
@@ -129,6 +129,8 @@ const RGBA_ASTC_10x10_Format = 37819;
 const RGBA_ASTC_12x10_Format = 37820;
 const RGBA_ASTC_12x12_Format = 37821;
 const RGBA_BPTC_Format = 36492;
+const RGB_BPTC_SIGNED_Format = 36494;
+const RGB_BPTC_UNSIGNED_Format = 36495;
 const RED_RGTC1_Format = 36283;
 const SIGNED_RED_RGTC1_Format = 36284;
 const RED_GREEN_RGTC2_Format = 36285;
@@ -161,6 +163,7 @@ const NoColorSpace = '';
 const SRGBColorSpace = 'srgb';
 const LinearSRGBColorSpace = 'srgb-linear';
 const DisplayP3ColorSpace = 'display-p3';
+const LinearDisplayP3ColorSpace = 'display-p3-linear';
 
 const ZeroStencilOp = 0;
 const KeepStencilOp = 7680;
@@ -921,8 +924,8 @@ class Vector2 {
 
 	roundToZero() {
 
-		this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x );
-		this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y );
+		this.x = Math.trunc( this.x );
+		this.y = Math.trunc( this.y );
 
 		return this;
 
@@ -1530,6 +1533,14 @@ function createElementNS( name ) {
 
 }
 
+function createCanvasElement() {
+
+	const canvas = createElementNS( 'canvas' );
+	canvas.style.display = 'block';
+	return canvas;
+
+}
+
 const _cache = {};
 
 function warnOnce( message ) {
@@ -1921,7 +1932,7 @@ function serializeImage( image ) {
 
 }
 
-let textureId = 0;
+let _textureId = 0;
 
 class Texture extends EventDispatcher {
 
@@ -1931,7 +1942,7 @@ class Texture extends EventDispatcher {
 
 		this.isTexture = true;
 
-		Object.defineProperty( this, 'id', { value: textureId ++ } );
+		Object.defineProperty( this, 'id', { value: _textureId ++ } );
 
 		this.uuid = generateUUID();
 
@@ -2741,10 +2752,10 @@ class Vector4 {
 
 	roundToZero() {
 
-		this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x );
-		this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y );
-		this.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z );
-		this.w = ( this.w < 0 ) ? Math.ceil( this.w ) : Math.floor( this.w );
+		this.x = Math.trunc( this.x );
+		this.y = Math.trunc( this.y );
+		this.z = Math.trunc( this.z );
+		this.w = Math.trunc( this.w );
 
 		return this;
 
@@ -4252,9 +4263,9 @@ class Vector3 {
 
 	roundToZero() {
 
-		this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x );
-		this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y );
-		this.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z );
+		this.x = Math.trunc( this.x );
+		this.y = Math.trunc( this.y );
+		this.z = Math.trunc( this.z );
 
 		return this;
 
@@ -7484,20 +7495,7 @@ class Object3D extends EventDispatcher {
 
 	clear() {
 
-		for ( let i = 0; i < this.children.length; i ++ ) {
-
-			const object = this.children[ i ];
-
-			object.parent = null;
-
-			object.dispatchEvent( _removedEvent );
-
-		}
-
-		this.children.length = 0;
-
-		return this;
-
+		return this.remove( ... this.children );
 
 	}
 
@@ -8388,7 +8386,7 @@ class Triangle {
 
 }
 
-let materialId = 0;
+let _materialId = 0;
 
 class Material extends EventDispatcher {
 
@@ -8398,7 +8396,7 @@ class Material extends EventDispatcher {
 
 		this.isMaterial = true;
 
-		Object.defineProperty( this, 'id', { value: materialId ++ } );
+		Object.defineProperty( this, 'id', { value: _materialId ++ } );
 
 		this.uuid = generateUUID();
 
@@ -10367,7 +10365,7 @@ class Float64BufferAttribute extends BufferAttribute {
 
 }
 
-let _id$1 = 0;
+let _id$2 = 0;
 
 const _m1 = /*@__PURE__*/ new Matrix4();
 const _obj = /*@__PURE__*/ new Object3D();
@@ -10384,7 +10382,7 @@ class BufferGeometry extends EventDispatcher {
 
 		this.isBufferGeometry = true;
 
-		Object.defineProperty( this, 'id', { value: _id$1 ++ } );
+		Object.defineProperty( this, 'id', { value: _id$2 ++ } );
 
 		this.uuid = generateUUID();
 
@@ -11489,7 +11487,7 @@ class Mesh extends Object3D {
 
 		}
 
-		this.material = source.material;
+		this.material = Array.isArray( source.material ) ? source.material.slice() : source.material;
 		this.geometry = source.geometry;
 
 		return this;
@@ -13779,7 +13777,7 @@ var logdepthbuf_pars_vertex = "#ifdef USE_LOGDEPTHBUF\n\t#ifdef USE_LOGDEPTHBUF_
 
 var logdepthbuf_vertex = "#ifdef USE_LOGDEPTHBUF\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvFragDepth = 1.0 + gl_Position.w;\n\t\tvIsPerspective = float( isPerspectiveMatrix( projectionMatrix ) );\n\t#else\n\t\tif ( isPerspectiveMatrix( projectionMatrix ) ) {\n\t\t\tgl_Position.z = log2( max( EPSILON, gl_Position.w + 1.0 ) ) * logDepthBufFC - 1.0;\n\t\t\tgl_Position.z *= gl_Position.w;\n\t\t}\n\t#endif\n#endif";
 
-var map_fragment = "#ifdef USE_MAP\n\tdiffuseColor *= texture2D( map, vMapUv );\n#endif";
+var map_fragment = "#ifdef USE_MAP\n\tvec4 sampledDiffuseColor = texture2D( map, vMapUv );\n\t#ifdef DECODE_VIDEO_TEXTURE\n\t\tsampledDiffuseColor = vec4( mix( pow( sampledDiffuseColor.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), sampledDiffuseColor.rgb * 0.0773993808, vec3( lessThanEqual( sampledDiffuseColor.rgb, vec3( 0.04045 ) ) ) ), sampledDiffuseColor.w );\n\t\n\t#endif\n\tdiffuseColor *= sampledDiffuseColor;\n#endif";
 
 var map_pars_fragment = "#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif";
 
@@ -13873,7 +13871,7 @@ var worldpos_vertex = "#if defined( USE_ENVMAP ) || defined( DISTANCE ) || defin
 
 const vertex$h = "varying vec2 vUv;\nuniform mat3 uvTransform;\nvoid main() {\n\tvUv = ( uvTransform * vec3( uv, 1 ) ).xy;\n\tgl_Position = vec4( position.xy, 1.0, 1.0 );\n}";
 
-const fragment$h = "uniform sampler2D t2D;\nuniform float backgroundIntensity;\nvarying vec2 vUv;\nvoid main() {\n\tvec4 texColor = texture2D( t2D, vUv );\n\ttexColor.rgb *= backgroundIntensity;\n\tgl_FragColor = texColor;\n\t#include <tonemapping_fragment>\n\t#include <colorspace_fragment>\n}";
+const fragment$h = "uniform sampler2D t2D;\nuniform float backgroundIntensity;\nvarying vec2 vUv;\nvoid main() {\n\tvec4 texColor = texture2D( t2D, vUv );\n\t#ifdef DECODE_VIDEO_TEXTURE\n\t\ttexColor = vec4( mix( pow( texColor.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), texColor.rgb * 0.0773993808, vec3( lessThanEqual( texColor.rgb, vec3( 0.04045 ) ) ) ), texColor.w );\n\t#endif\n\ttexColor.rgb *= backgroundIntensity;\n\tgl_FragColor = texColor;\n\t#include <tonemapping_fragment>\n\t#include <colorspace_fragment>\n}";
 
 const vertex$g = "varying vec3 vWorldDirection;\n#include <common>\nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include <begin_vertex>\n\t#include <project_vertex>\n\tgl_Position.z = gl_Position.w;\n}";
 
@@ -14693,24 +14691,15 @@ function WebGLBackground( renderer, cubemaps, cubeuvmaps, state, objects, alpha,
 
 		}
 
-		const xr = renderer.xr;
-		const environmentBlendMode = xr.getEnvironmentBlendMode();
+		const environmentBlendMode = renderer.xr.getEnvironmentBlendMode();
 
-		switch ( environmentBlendMode ) {
+		if ( environmentBlendMode === 'additive' ) {
 
-			case 'opaque':
-				forceClear = true;
-				break;
+			state.buffers.color.setClear( 0, 0, 0, 1, premultipliedAlpha );
 
-			case 'additive':
-				state.buffers.color.setClear( 0, 0, 0, 1, premultipliedAlpha );
-				forceClear = true;
-				break;
+		} else if ( environmentBlendMode === 'alpha-blend' ) {
 
-			case 'alpha-blend':
-				state.buffers.color.setClear( 0, 0, 0, 0, premultipliedAlpha );
-				forceClear = true;
-				break;
+			state.buffers.color.setClear( 0, 0, 0, 0, premultipliedAlpha );
 
 		}
 
@@ -19825,6 +19814,8 @@ function WebGLProgram( renderer, cacheKey, parameters, bindingStates ) {
 
 			parameters.useLegacyLights ? '#define LEGACY_LIGHTS' : '',
 
+			parameters.decodeVideoTexture ? '#define DECODE_VIDEO_TEXTURE' : '',
+
 			parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '',
 			( parameters.logarithmicDepthBuffer && parameters.rendererExtensionFragDepth ) ? '#define USE_LOGDEPTHBUF_EXT' : '',
 
@@ -20059,7 +20050,7 @@ function WebGLProgram( renderer, cacheKey, parameters, bindingStates ) {
 
 }
 
-let _id = 0;
+let _id$1 = 0;
 
 class WebGLShaderCache {
 
@@ -20173,7 +20164,7 @@ class WebGLShaderStage {
 
 	constructor( code ) {
 
-		this.id = _id ++;
+		this.id = _id$1 ++;
 
 		this.code = code;
 		this.usedTimes = 0;
@@ -20512,6 +20503,8 @@ function WebGLPrograms( renderer, cubemaps, cubeuvmaps, extensions, capabilities
 			toneMapping: toneMapping,
 			useLegacyLights: renderer._useLegacyLights,
 
+			decodeVideoTexture: HAS_MAP && ( material.map.isVideoTexture === true ) && ( material.map.colorSpace === SRGBColorSpace ),
+
 			premultipliedAlpha: material.premultipliedAlpha,
 
 			doubleSided: material.side === DoubleSide,
@@ -20713,6 +20706,8 @@ function WebGLPrograms( renderer, cubemaps, cubeuvmaps, extensions, capabilities
 			_programLayers.enable( 17 );
 		if ( parameters.pointsUvs )
 			_programLayers.enable( 18 );
+		if ( parameters.decodeVideoTexture )
+			_programLayers.enable( 19 );
 
 		array.push( _programLayers.mask );
 
@@ -24273,7 +24268,7 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, utils,
 				glFormat = utils.convert( texture.format, texture.colorSpace );
 
 			let glType = utils.convert( texture.type ),
-				glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace );
+				glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace, texture.isVideoTexture );
 
 			setTextureParameters( textureType, texture, supportsMips );
 
@@ -25552,13 +25547,13 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, utils,
 		const format = texture.format;
 		const type = texture.type;
 
-		if ( texture.isCompressedTexture === true || texture.format === _SRGBAFormat ) return image;
+		if ( texture.isCompressedTexture === true || texture.isVideoTexture === true || texture.format === _SRGBAFormat ) return image;
 
 		if ( colorSpace !== LinearSRGBColorSpace && colorSpace !== NoColorSpace ) {
 
 			// sRGB
 
-			if ( colorSpace === SRGBColorSpace ) {
+			if ( colorSpace === SRGBColorSpace || colorSpace === DisplayP3ColorSpace ) {
 
 				if ( isWebGL2 === false ) {
 
@@ -25624,6 +25619,9 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, utils,
 
 }
 
+const LinearTransferFunction = 0;
+const SRGBTransferFunction = 1;
+
 function WebGLUtils( gl, extensions, capabilities ) {
 
 	const isWebGL2 = capabilities.isWebGL2;
@@ -25632,6 +25630,8 @@ function WebGLUtils( gl, extensions, capabilities ) {
 
 		let extension;
 
+		const transferFunction = ( colorSpace === SRGBColorSpace || colorSpace === DisplayP3ColorSpace ) ? SRGBTransferFunction : LinearTransferFunction;
+
 		if ( p === UnsignedByteType ) return gl.UNSIGNED_BYTE;
 		if ( p === UnsignedShort4444Type ) return gl.UNSIGNED_SHORT_4_4_4_4;
 		if ( p === UnsignedShort5551Type ) return gl.UNSIGNED_SHORT_5_5_5_1;
@@ -25698,7 +25698,7 @@ function WebGLUtils( gl, extensions, capabilities ) {
 
 		if ( p === RGB_S3TC_DXT1_Format || p === RGBA_S3TC_DXT1_Format || p === RGBA_S3TC_DXT3_Format || p === RGBA_S3TC_DXT5_Format ) {
 
-			if ( colorSpace === SRGBColorSpace ) {
+			if ( transferFunction === SRGBTransferFunction ) {
 
 				extension = extensions.get( 'WEBGL_compressed_texture_s3tc_srgb' );
 
@@ -25783,8 +25783,8 @@ function WebGLUtils( gl, extensions, capabilities ) {
 
 			if ( extension !== null ) {
 
-				if ( p === RGB_ETC2_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB8_ETC2 : extension.COMPRESSED_RGB8_ETC2;
-				if ( p === RGBA_ETC2_EAC_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB8_ALPHA8_ETC2_EAC : extension.COMPRESSED_RGBA8_ETC2_EAC;
+				if ( p === RGB_ETC2_Format ) return ( transferFunction === SRGBTransferFunction ) ? extension.COMPRESSED_SRGB8_ETC2 : extension.COMPRESSED_RGB8_ETC2;
+				if ( p === RGBA_ETC2_EAC_Format ) return ( transferFunction === SRGBTransferFunction ) ? extension.COMPRESSED_SRGB8_ALPHA8_ETC2_EAC : extension.COMPRESSED_RGBA8_ETC2_EAC;
 
 			} else {
 
@@ -25806,20 +25806,20 @@ function WebGLUtils( gl, extensions, capabilities ) {
 
 			if ( extension !== null ) {
 
-				if ( p === RGBA_ASTC_4x4_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR : extension.COMPRESSED_RGBA_ASTC_4x4_KHR;
-				if ( p === RGBA_ASTC_5x4_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR : extension.COMPRESSED_RGBA_ASTC_5x4_KHR;
-				if ( p === RGBA_ASTC_5x5_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR : extension.COMPRESSED_RGBA_ASTC_5x5_KHR;
-				if ( p === RGBA_ASTC_6x5_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR : extension.COMPRESSED_RGBA_ASTC_6x5_KHR;
-				if ( p === RGBA_ASTC_6x6_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR : extension.COMPRESSED_RGBA_ASTC_6x6_KHR;
-				if ( p === RGBA_ASTC_8x5_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR : extension.COMPRESSED_RGBA_ASTC_8x5_KHR;
-				if ( p === RGBA_ASTC_8x6_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR : extension.COMPRESSED_RGBA_ASTC_8x6_KHR;
-				if ( p === RGBA_ASTC_8x8_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR : extension.COMPRESSED_RGBA_ASTC_8x8_KHR;
-				if ( p === RGBA_ASTC_10x5_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR : extension.COMPRESSED_RGBA_ASTC_10x5_KHR;
-				if ( p === RGBA_ASTC_10x6_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR : extension.COMPRESSED_RGBA_ASTC_10x6_KHR;
-				if ( p === RGBA_ASTC_10x8_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR : extension.COMPRESSED_RGBA_ASTC_10x8_KHR;
-				if ( p === RGBA_ASTC_10x10_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR : extension.COMPRESSED_RGBA_ASTC_10x10_KHR;
-				if ( p === RGBA_ASTC_12x10_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR : extension.COMPRESSED_RGBA_ASTC_12x10_KHR;
-				if ( p === RGBA_ASTC_12x12_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR : extension.COMPRESSED_RGBA_ASTC_12x12_KHR;
+				if ( p === RGBA_ASTC_4x4_Format ) return ( transferFunction === SRGBTransferFunction ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR : extension.COMPRESSED_RGBA_ASTC_4x4_KHR;
+				if ( p === RGBA_ASTC_5x4_Format ) return ( transferFunction === SRGBTransferFunction ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR : extension.COMPRESSED_RGBA_ASTC_5x4_KHR;
+				if ( p === RGBA_ASTC_5x5_Format ) return ( transferFunction === SRGBTransferFunction ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR : extension.COMPRESSED_RGBA_ASTC_5x5_KHR;
+				if ( p === RGBA_ASTC_6x5_Format ) return ( transferFunction === SRGBTransferFunction ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR : extension.COMPRESSED_RGBA_ASTC_6x5_KHR;
+				if ( p === RGBA_ASTC_6x6_Format ) return ( transferFunction === SRGBTransferFunction ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR : extension.COMPRESSED_RGBA_ASTC_6x6_KHR;
+				if ( p === RGBA_ASTC_8x5_Format ) return ( transferFunction === SRGBTransferFunction ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR : extension.COMPRESSED_RGBA_ASTC_8x5_KHR;
+				if ( p === RGBA_ASTC_8x6_Format ) return ( transferFunction === SRGBTransferFunction ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR : extension.COMPRESSED_RGBA_ASTC_8x6_KHR;
+				if ( p === RGBA_ASTC_8x8_Format ) return ( transferFunction === SRGBTransferFunction ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR : extension.COMPRESSED_RGBA_ASTC_8x8_KHR;
+				if ( p === RGBA_ASTC_10x5_Format ) return ( transferFunction === SRGBTransferFunction ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR : extension.COMPRESSED_RGBA_ASTC_10x5_KHR;
+				if ( p === RGBA_ASTC_10x6_Format ) return ( transferFunction === SRGBTransferFunction ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR : extension.COMPRESSED_RGBA_ASTC_10x6_KHR;
+				if ( p === RGBA_ASTC_10x8_Format ) return ( transferFunction === SRGBTransferFunction ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR : extension.COMPRESSED_RGBA_ASTC_10x8_KHR;
+				if ( p === RGBA_ASTC_10x10_Format ) return ( transferFunction === SRGBTransferFunction ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR : extension.COMPRESSED_RGBA_ASTC_10x10_KHR;
+				if ( p === RGBA_ASTC_12x10_Format ) return ( transferFunction === SRGBTransferFunction ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR : extension.COMPRESSED_RGBA_ASTC_12x10_KHR;
+				if ( p === RGBA_ASTC_12x12_Format ) return ( transferFunction === SRGBTransferFunction ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR : extension.COMPRESSED_RGBA_ASTC_12x12_KHR;
 
 			} else {
 
@@ -25831,13 +25831,15 @@ function WebGLUtils( gl, extensions, capabilities ) {
 
 		// BPTC
 
-		if ( p === RGBA_BPTC_Format ) {
+		if ( p === RGBA_BPTC_Format || p === RGB_BPTC_SIGNED_Format || p === RGB_BPTC_UNSIGNED_Format ) {
 
 			extension = extensions.get( 'EXT_texture_compression_bptc' );
 
 			if ( extension !== null ) {
 
-				if ( p === RGBA_BPTC_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT : extension.COMPRESSED_RGBA_BPTC_UNORM_EXT;
+				if ( p === RGBA_BPTC_Format ) return ( transferFunction === SRGBTransferFunction ) ? extension.COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT : extension.COMPRESSED_RGBA_BPTC_UNORM_EXT;
+				if ( p === RGB_BPTC_SIGNED_Format ) return extension.COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT;
+				if ( p === RGB_BPTC_UNSIGNED_Format ) return extension.COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT;
 
 			} else {
 
@@ -26879,14 +26881,6 @@ class WebXRManager extends EventDispatcher {
 			camera.matrix.decompose( camera.position, camera.quaternion, camera.scale );
 			camera.updateMatrixWorld( true );
 
-			const children = camera.children;
-
-			for ( let i = 0, l = children.length; i < l; i ++ ) {
-
-				children[ i ].updateMatrixWorld( true );
-
-			}
-
 			camera.projectionMatrix.copy( cameraXR.projectionMatrix );
 			camera.projectionMatrixInverse.copy( cameraXR.projectionMatrixInverse );
 
@@ -28049,14 +28043,6 @@ function WebGLUniformsGroups( gl, info, capabilities, state ) {
 
 }
 
-function createCanvasElement() {
-
-	const canvas = createElementNS( 'canvas' );
-	canvas.style.display = 'block';
-	return canvas;
-
-}
-
 class WebGLRenderer {
 
 	constructor( parameters = {} ) {
@@ -29782,48 +29768,28 @@ class WebGLRenderer {
 
 			if ( refreshProgram || _currentCamera !== camera ) {
 
-				p_uniforms.setValue( _gl, 'projectionMatrix', camera.projectionMatrix );
-
-				if ( capabilities.logarithmicDepthBuffer ) {
+				// common camera uniforms
 
-					p_uniforms.setValue( _gl, 'logDepthBufFC',
-						2.0 / ( Math.log( camera.far + 1.0 ) / Math.LN2 ) );
-
-				}
-
-				if ( _currentCamera !== camera ) {
+				p_uniforms.setValue( _gl, 'projectionMatrix', camera.projectionMatrix );
+				p_uniforms.setValue( _gl, 'viewMatrix', camera.matrixWorldInverse );
 
-					_currentCamera = camera;
+				const uCamPos = p_uniforms.map.cameraPosition;
 
-					// lighting uniforms depend on the camera so enforce an update
-					// now, in case this material supports lights - or later, when
-					// the next material that does gets activated:
+				if ( uCamPos !== undefined ) {
 
-					refreshMaterial = true;		// set to true on material change
-					refreshLights = true;		// remains set until update done
+					uCamPos.setValue( _gl, _vector3.setFromMatrixPosition( camera.matrixWorld ) );
 
 				}
 
-				// load material specific uniforms
-				// (shader material also gets them for the sake of genericity)
-
-				if ( material.isShaderMaterial ||
-					material.isMeshPhongMaterial ||
-					material.isMeshToonMaterial ||
-					material.isMeshStandardMaterial ||
-					material.envMap ) {
-
-					const uCamPos = p_uniforms.map.cameraPosition;
-
-					if ( uCamPos !== undefined ) {
-
-						uCamPos.setValue( _gl,
-							_vector3.setFromMatrixPosition( camera.matrixWorld ) );
+				if ( capabilities.logarithmicDepthBuffer ) {
 
-					}
+					p_uniforms.setValue( _gl, 'logDepthBufFC',
+						2.0 / ( Math.log( camera.far + 1.0 ) / Math.LN2 ) );
 
 				}
 
+				// consider moving isOrthographic to UniformLib and WebGLMaterials, see https://github.com/mrdoob/three.js/pull/26467#issuecomment-1645185067
+
 				if ( material.isMeshPhongMaterial ||
 					material.isMeshToonMaterial ||
 					material.isMeshLambertMaterial ||
@@ -29835,16 +29801,16 @@ class WebGLRenderer {
 
 				}
 
-				if ( material.isMeshPhongMaterial ||
-					material.isMeshToonMaterial ||
-					material.isMeshLambertMaterial ||
-					material.isMeshBasicMaterial ||
-					material.isMeshStandardMaterial ||
-					material.isShaderMaterial ||
-					material.isShadowMaterial ||
-					object.isSkinnedMesh ) {
+				if ( _currentCamera !== camera ) {
 
-					p_uniforms.setValue( _gl, 'viewMatrix', camera.matrixWorldInverse );
+					_currentCamera = camera;
+
+					// lighting uniforms depend on the camera so enforce an update
+					// now, in case this material supports lights - or later, when
+					// the next material that does gets activated:
+
+					refreshMaterial = true;		// set to true on material change
+					refreshLights = true;		// remains set until update done
 
 				}
 
@@ -32375,7 +32341,7 @@ class Line extends Object3D {
 
 		super.copy( source, recursive );
 
-		this.material = source.material;
+		this.material = Array.isArray( source.material ) ? source.material.slice() : source.material;
 		this.geometry = source.geometry;
 
 		return this;
@@ -32696,7 +32662,7 @@ class Points extends Object3D {
 
 		super.copy( source, recursive );
 
-		this.material = source.material;
+		this.material = Array.isArray( source.material ) ? source.material.slice() : source.material;
 		this.geometry = source.geometry;
 
 		return this;
@@ -42532,8 +42498,6 @@ class DataTextureLoader extends Loader {
 
 			}
 
-			if ( ! texData ) return onError(); // TODO: Remove this when all loaders properly throw errors
-
 			if ( texData.image !== undefined ) {
 
 				texture.image = texData.image;
@@ -45939,6 +45903,12 @@ class Audio extends Object3D {
 
 	disconnect() {
 
+		if ( this._connected === false ) {
+
+			return;
+
+		}
+
 		if ( this.filters.length > 0 ) {
 
 			this.source.disconnect( this.filters[ 0 ] );
@@ -49187,7 +49157,7 @@ class Uniform {
 
 }
 
-let id = 0;
+let _id = 0;
 
 class UniformsGroup extends EventDispatcher {
 
@@ -49197,7 +49167,7 @@ class UniformsGroup extends EventDispatcher {
 
 		this.isUniformsGroup = true;
 
-		Object.defineProperty( this, 'id', { value: id ++ } );
+		Object.defineProperty( this, 'id', { value: _id ++ } );
 
 		this.name = '';
 
@@ -51641,6 +51611,7 @@ exports.LineCurve3 = LineCurve3;
 exports.LineDashedMaterial = LineDashedMaterial;
 exports.LineLoop = LineLoop;
 exports.LineSegments = LineSegments;
+exports.LinearDisplayP3ColorSpace = LinearDisplayP3ColorSpace;
 exports.LinearEncoding = LinearEncoding;
 exports.LinearFilter = LinearFilter;
 exports.LinearInterpolant = LinearInterpolant;
@@ -51757,6 +51728,8 @@ exports.RGBA_PVRTC_4BPPV1_Format = RGBA_PVRTC_4BPPV1_Format;
 exports.RGBA_S3TC_DXT1_Format = RGBA_S3TC_DXT1_Format;
 exports.RGBA_S3TC_DXT3_Format = RGBA_S3TC_DXT3_Format;
 exports.RGBA_S3TC_DXT5_Format = RGBA_S3TC_DXT5_Format;
+exports.RGB_BPTC_SIGNED_Format = RGB_BPTC_SIGNED_Format;
+exports.RGB_BPTC_UNSIGNED_Format = RGB_BPTC_UNSIGNED_Format;
 exports.RGB_ETC1_Format = RGB_ETC1_Format;
 exports.RGB_ETC2_Format = RGB_ETC2_Format;
 exports.RGB_PVRTC_2BPPV1_Format = RGB_PVRTC_2BPPV1_Format;
@@ -51866,4 +51839,5 @@ exports.ZeroFactor = ZeroFactor;
 exports.ZeroSlopeEnding = ZeroSlopeEnding;
 exports.ZeroStencilOp = ZeroStencilOp;
 exports._SRGBAFormat = _SRGBAFormat;
+exports.createCanvasElement = createCanvasElement;
 exports.sRGBEncoding = sRGBEncoding;

+ 107 - 133
build/three.js

@@ -10,7 +10,7 @@ console.warn( 'Scripts "build/three.js" and "build/three.min.js" are deprecated
 	(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.THREE = {}));
 })(this, (function (exports) { 'use strict';
 
-	const REVISION = '155';
+	const REVISION = '156';
 
 	const MOUSE = { LEFT: 0, MIDDLE: 1, RIGHT: 2, ROTATE: 0, DOLLY: 1, PAN: 2 };
 	const TOUCH = { ROTATE: 0, PAN: 1, DOLLY_PAN: 2, DOLLY_ROTATE: 3 };
@@ -134,6 +134,8 @@ console.warn( 'Scripts "build/three.js" and "build/three.min.js" are deprecated
 	const RGBA_ASTC_12x10_Format = 37820;
 	const RGBA_ASTC_12x12_Format = 37821;
 	const RGBA_BPTC_Format = 36492;
+	const RGB_BPTC_SIGNED_Format = 36494;
+	const RGB_BPTC_UNSIGNED_Format = 36495;
 	const RED_RGTC1_Format = 36283;
 	const SIGNED_RED_RGTC1_Format = 36284;
 	const RED_GREEN_RGTC2_Format = 36285;
@@ -166,6 +168,7 @@ console.warn( 'Scripts "build/three.js" and "build/three.min.js" are deprecated
 	const SRGBColorSpace = 'srgb';
 	const LinearSRGBColorSpace = 'srgb-linear';
 	const DisplayP3ColorSpace = 'display-p3';
+	const LinearDisplayP3ColorSpace = 'display-p3-linear';
 
 	const ZeroStencilOp = 0;
 	const KeepStencilOp = 7680;
@@ -926,8 +929,8 @@ console.warn( 'Scripts "build/three.js" and "build/three.min.js" are deprecated
 
 		roundToZero() {
 
-			this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x );
-			this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y );
+			this.x = Math.trunc( this.x );
+			this.y = Math.trunc( this.y );
 
 			return this;
 
@@ -1535,6 +1538,14 @@ console.warn( 'Scripts "build/three.js" and "build/three.min.js" are deprecated
 
 	}
 
+	function createCanvasElement() {
+
+		const canvas = createElementNS( 'canvas' );
+		canvas.style.display = 'block';
+		return canvas;
+
+	}
+
 	const _cache = {};
 
 	function warnOnce( message ) {
@@ -1926,7 +1937,7 @@ console.warn( 'Scripts "build/three.js" and "build/three.min.js" are deprecated
 
 	}
 
-	let textureId = 0;
+	let _textureId = 0;
 
 	class Texture extends EventDispatcher {
 
@@ -1936,7 +1947,7 @@ console.warn( 'Scripts "build/three.js" and "build/three.min.js" are deprecated
 
 			this.isTexture = true;
 
-			Object.defineProperty( this, 'id', { value: textureId ++ } );
+			Object.defineProperty( this, 'id', { value: _textureId ++ } );
 
 			this.uuid = generateUUID();
 
@@ -2746,10 +2757,10 @@ console.warn( 'Scripts "build/three.js" and "build/three.min.js" are deprecated
 
 		roundToZero() {
 
-			this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x );
-			this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y );
-			this.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z );
-			this.w = ( this.w < 0 ) ? Math.ceil( this.w ) : Math.floor( this.w );
+			this.x = Math.trunc( this.x );
+			this.y = Math.trunc( this.y );
+			this.z = Math.trunc( this.z );
+			this.w = Math.trunc( this.w );
 
 			return this;
 
@@ -4257,9 +4268,9 @@ console.warn( 'Scripts "build/three.js" and "build/three.min.js" are deprecated
 
 		roundToZero() {
 
-			this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x );
-			this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y );
-			this.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z );
+			this.x = Math.trunc( this.x );
+			this.y = Math.trunc( this.y );
+			this.z = Math.trunc( this.z );
 
 			return this;
 
@@ -7489,20 +7500,7 @@ console.warn( 'Scripts "build/three.js" and "build/three.min.js" are deprecated
 
 		clear() {
 
-			for ( let i = 0; i < this.children.length; i ++ ) {
-
-				const object = this.children[ i ];
-
-				object.parent = null;
-
-				object.dispatchEvent( _removedEvent );
-
-			}
-
-			this.children.length = 0;
-
-			return this;
-
+			return this.remove( ... this.children );
 
 		}
 
@@ -8393,7 +8391,7 @@ console.warn( 'Scripts "build/three.js" and "build/three.min.js" are deprecated
 
 	}
 
-	let materialId = 0;
+	let _materialId = 0;
 
 	class Material extends EventDispatcher {
 
@@ -8403,7 +8401,7 @@ console.warn( 'Scripts "build/three.js" and "build/three.min.js" are deprecated
 
 			this.isMaterial = true;
 
-			Object.defineProperty( this, 'id', { value: materialId ++ } );
+			Object.defineProperty( this, 'id', { value: _materialId ++ } );
 
 			this.uuid = generateUUID();
 
@@ -10372,7 +10370,7 @@ console.warn( 'Scripts "build/three.js" and "build/three.min.js" are deprecated
 
 	}
 
-	let _id$1 = 0;
+	let _id$2 = 0;
 
 	const _m1 = /*@__PURE__*/ new Matrix4();
 	const _obj = /*@__PURE__*/ new Object3D();
@@ -10389,7 +10387,7 @@ console.warn( 'Scripts "build/three.js" and "build/three.min.js" are deprecated
 
 			this.isBufferGeometry = true;
 
-			Object.defineProperty( this, 'id', { value: _id$1 ++ } );
+			Object.defineProperty( this, 'id', { value: _id$2 ++ } );
 
 			this.uuid = generateUUID();
 
@@ -11494,7 +11492,7 @@ console.warn( 'Scripts "build/three.js" and "build/three.min.js" are deprecated
 
 			}
 
-			this.material = source.material;
+			this.material = Array.isArray( source.material ) ? source.material.slice() : source.material;
 			this.geometry = source.geometry;
 
 			return this;
@@ -13784,7 +13782,7 @@ console.warn( 'Scripts "build/three.js" and "build/three.min.js" are deprecated
 
 	var logdepthbuf_vertex = "#ifdef USE_LOGDEPTHBUF\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvFragDepth = 1.0 + gl_Position.w;\n\t\tvIsPerspective = float( isPerspectiveMatrix( projectionMatrix ) );\n\t#else\n\t\tif ( isPerspectiveMatrix( projectionMatrix ) ) {\n\t\t\tgl_Position.z = log2( max( EPSILON, gl_Position.w + 1.0 ) ) * logDepthBufFC - 1.0;\n\t\t\tgl_Position.z *= gl_Position.w;\n\t\t}\n\t#endif\n#endif";
 
-	var map_fragment = "#ifdef USE_MAP\n\tdiffuseColor *= texture2D( map, vMapUv );\n#endif";
+	var map_fragment = "#ifdef USE_MAP\n\tvec4 sampledDiffuseColor = texture2D( map, vMapUv );\n\t#ifdef DECODE_VIDEO_TEXTURE\n\t\tsampledDiffuseColor = vec4( mix( pow( sampledDiffuseColor.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), sampledDiffuseColor.rgb * 0.0773993808, vec3( lessThanEqual( sampledDiffuseColor.rgb, vec3( 0.04045 ) ) ) ), sampledDiffuseColor.w );\n\t\n\t#endif\n\tdiffuseColor *= sampledDiffuseColor;\n#endif";
 
 	var map_pars_fragment = "#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif";
 
@@ -13878,7 +13876,7 @@ console.warn( 'Scripts "build/three.js" and "build/three.min.js" are deprecated
 
 	const vertex$h = "varying vec2 vUv;\nuniform mat3 uvTransform;\nvoid main() {\n\tvUv = ( uvTransform * vec3( uv, 1 ) ).xy;\n\tgl_Position = vec4( position.xy, 1.0, 1.0 );\n}";
 
-	const fragment$h = "uniform sampler2D t2D;\nuniform float backgroundIntensity;\nvarying vec2 vUv;\nvoid main() {\n\tvec4 texColor = texture2D( t2D, vUv );\n\ttexColor.rgb *= backgroundIntensity;\n\tgl_FragColor = texColor;\n\t#include <tonemapping_fragment>\n\t#include <colorspace_fragment>\n}";
+	const fragment$h = "uniform sampler2D t2D;\nuniform float backgroundIntensity;\nvarying vec2 vUv;\nvoid main() {\n\tvec4 texColor = texture2D( t2D, vUv );\n\t#ifdef DECODE_VIDEO_TEXTURE\n\t\ttexColor = vec4( mix( pow( texColor.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), texColor.rgb * 0.0773993808, vec3( lessThanEqual( texColor.rgb, vec3( 0.04045 ) ) ) ), texColor.w );\n\t#endif\n\ttexColor.rgb *= backgroundIntensity;\n\tgl_FragColor = texColor;\n\t#include <tonemapping_fragment>\n\t#include <colorspace_fragment>\n}";
 
 	const vertex$g = "varying vec3 vWorldDirection;\n#include <common>\nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include <begin_vertex>\n\t#include <project_vertex>\n\tgl_Position.z = gl_Position.w;\n}";
 
@@ -14698,24 +14696,15 @@ console.warn( 'Scripts "build/three.js" and "build/three.min.js" are deprecated
 
 			}
 
-			const xr = renderer.xr;
-			const environmentBlendMode = xr.getEnvironmentBlendMode();
+			const environmentBlendMode = renderer.xr.getEnvironmentBlendMode();
 
-			switch ( environmentBlendMode ) {
+			if ( environmentBlendMode === 'additive' ) {
 
-				case 'opaque':
-					forceClear = true;
-					break;
+				state.buffers.color.setClear( 0, 0, 0, 1, premultipliedAlpha );
 
-				case 'additive':
-					state.buffers.color.setClear( 0, 0, 0, 1, premultipliedAlpha );
-					forceClear = true;
-					break;
+			} else if ( environmentBlendMode === 'alpha-blend' ) {
 
-				case 'alpha-blend':
-					state.buffers.color.setClear( 0, 0, 0, 0, premultipliedAlpha );
-					forceClear = true;
-					break;
+				state.buffers.color.setClear( 0, 0, 0, 0, premultipliedAlpha );
 
 			}
 
@@ -19830,6 +19819,8 @@ console.warn( 'Scripts "build/three.js" and "build/three.min.js" are deprecated
 
 				parameters.useLegacyLights ? '#define LEGACY_LIGHTS' : '',
 
+				parameters.decodeVideoTexture ? '#define DECODE_VIDEO_TEXTURE' : '',
+
 				parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '',
 				( parameters.logarithmicDepthBuffer && parameters.rendererExtensionFragDepth ) ? '#define USE_LOGDEPTHBUF_EXT' : '',
 
@@ -20064,7 +20055,7 @@ console.warn( 'Scripts "build/three.js" and "build/three.min.js" are deprecated
 
 	}
 
-	let _id = 0;
+	let _id$1 = 0;
 
 	class WebGLShaderCache {
 
@@ -20178,7 +20169,7 @@ console.warn( 'Scripts "build/three.js" and "build/three.min.js" are deprecated
 
 		constructor( code ) {
 
-			this.id = _id ++;
+			this.id = _id$1 ++;
 
 			this.code = code;
 			this.usedTimes = 0;
@@ -20517,6 +20508,8 @@ console.warn( 'Scripts "build/three.js" and "build/three.min.js" are deprecated
 				toneMapping: toneMapping,
 				useLegacyLights: renderer._useLegacyLights,
 
+				decodeVideoTexture: HAS_MAP && ( material.map.isVideoTexture === true ) && ( material.map.colorSpace === SRGBColorSpace ),
+
 				premultipliedAlpha: material.premultipliedAlpha,
 
 				doubleSided: material.side === DoubleSide,
@@ -20718,6 +20711,8 @@ console.warn( 'Scripts "build/three.js" and "build/three.min.js" are deprecated
 				_programLayers.enable( 17 );
 			if ( parameters.pointsUvs )
 				_programLayers.enable( 18 );
+			if ( parameters.decodeVideoTexture )
+				_programLayers.enable( 19 );
 
 			array.push( _programLayers.mask );
 
@@ -24278,7 +24273,7 @@ console.warn( 'Scripts "build/three.js" and "build/three.min.js" are deprecated
 					glFormat = utils.convert( texture.format, texture.colorSpace );
 
 				let glType = utils.convert( texture.type ),
-					glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace );
+					glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace, texture.isVideoTexture );
 
 				setTextureParameters( textureType, texture, supportsMips );
 
@@ -25557,13 +25552,13 @@ console.warn( 'Scripts "build/three.js" and "build/three.min.js" are deprecated
 			const format = texture.format;
 			const type = texture.type;
 
-			if ( texture.isCompressedTexture === true || texture.format === _SRGBAFormat ) return image;
+			if ( texture.isCompressedTexture === true || texture.isVideoTexture === true || texture.format === _SRGBAFormat ) return image;
 
 			if ( colorSpace !== LinearSRGBColorSpace && colorSpace !== NoColorSpace ) {
 
 				// sRGB
 
-				if ( colorSpace === SRGBColorSpace ) {
+				if ( colorSpace === SRGBColorSpace || colorSpace === DisplayP3ColorSpace ) {
 
 					if ( isWebGL2 === false ) {
 
@@ -25629,6 +25624,9 @@ console.warn( 'Scripts "build/three.js" and "build/three.min.js" are deprecated
 
 	}
 
+	const LinearTransferFunction = 0;
+	const SRGBTransferFunction = 1;
+
 	function WebGLUtils( gl, extensions, capabilities ) {
 
 		const isWebGL2 = capabilities.isWebGL2;
@@ -25637,6 +25635,8 @@ console.warn( 'Scripts "build/three.js" and "build/three.min.js" are deprecated
 
 			let extension;
 
+			const transferFunction = ( colorSpace === SRGBColorSpace || colorSpace === DisplayP3ColorSpace ) ? SRGBTransferFunction : LinearTransferFunction;
+
 			if ( p === UnsignedByteType ) return gl.UNSIGNED_BYTE;
 			if ( p === UnsignedShort4444Type ) return gl.UNSIGNED_SHORT_4_4_4_4;
 			if ( p === UnsignedShort5551Type ) return gl.UNSIGNED_SHORT_5_5_5_1;
@@ -25703,7 +25703,7 @@ console.warn( 'Scripts "build/three.js" and "build/three.min.js" are deprecated
 
 			if ( p === RGB_S3TC_DXT1_Format || p === RGBA_S3TC_DXT1_Format || p === RGBA_S3TC_DXT3_Format || p === RGBA_S3TC_DXT5_Format ) {
 
-				if ( colorSpace === SRGBColorSpace ) {
+				if ( transferFunction === SRGBTransferFunction ) {
 
 					extension = extensions.get( 'WEBGL_compressed_texture_s3tc_srgb' );
 
@@ -25788,8 +25788,8 @@ console.warn( 'Scripts "build/three.js" and "build/three.min.js" are deprecated
 
 				if ( extension !== null ) {
 
-					if ( p === RGB_ETC2_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB8_ETC2 : extension.COMPRESSED_RGB8_ETC2;
-					if ( p === RGBA_ETC2_EAC_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB8_ALPHA8_ETC2_EAC : extension.COMPRESSED_RGBA8_ETC2_EAC;
+					if ( p === RGB_ETC2_Format ) return ( transferFunction === SRGBTransferFunction ) ? extension.COMPRESSED_SRGB8_ETC2 : extension.COMPRESSED_RGB8_ETC2;
+					if ( p === RGBA_ETC2_EAC_Format ) return ( transferFunction === SRGBTransferFunction ) ? extension.COMPRESSED_SRGB8_ALPHA8_ETC2_EAC : extension.COMPRESSED_RGBA8_ETC2_EAC;
 
 				} else {
 
@@ -25811,20 +25811,20 @@ console.warn( 'Scripts "build/three.js" and "build/three.min.js" are deprecated
 
 				if ( extension !== null ) {
 
-					if ( p === RGBA_ASTC_4x4_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR : extension.COMPRESSED_RGBA_ASTC_4x4_KHR;
-					if ( p === RGBA_ASTC_5x4_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR : extension.COMPRESSED_RGBA_ASTC_5x4_KHR;
-					if ( p === RGBA_ASTC_5x5_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR : extension.COMPRESSED_RGBA_ASTC_5x5_KHR;
-					if ( p === RGBA_ASTC_6x5_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR : extension.COMPRESSED_RGBA_ASTC_6x5_KHR;
-					if ( p === RGBA_ASTC_6x6_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR : extension.COMPRESSED_RGBA_ASTC_6x6_KHR;
-					if ( p === RGBA_ASTC_8x5_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR : extension.COMPRESSED_RGBA_ASTC_8x5_KHR;
-					if ( p === RGBA_ASTC_8x6_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR : extension.COMPRESSED_RGBA_ASTC_8x6_KHR;
-					if ( p === RGBA_ASTC_8x8_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR : extension.COMPRESSED_RGBA_ASTC_8x8_KHR;
-					if ( p === RGBA_ASTC_10x5_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR : extension.COMPRESSED_RGBA_ASTC_10x5_KHR;
-					if ( p === RGBA_ASTC_10x6_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR : extension.COMPRESSED_RGBA_ASTC_10x6_KHR;
-					if ( p === RGBA_ASTC_10x8_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR : extension.COMPRESSED_RGBA_ASTC_10x8_KHR;
-					if ( p === RGBA_ASTC_10x10_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR : extension.COMPRESSED_RGBA_ASTC_10x10_KHR;
-					if ( p === RGBA_ASTC_12x10_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR : extension.COMPRESSED_RGBA_ASTC_12x10_KHR;
-					if ( p === RGBA_ASTC_12x12_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR : extension.COMPRESSED_RGBA_ASTC_12x12_KHR;
+					if ( p === RGBA_ASTC_4x4_Format ) return ( transferFunction === SRGBTransferFunction ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR : extension.COMPRESSED_RGBA_ASTC_4x4_KHR;
+					if ( p === RGBA_ASTC_5x4_Format ) return ( transferFunction === SRGBTransferFunction ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR : extension.COMPRESSED_RGBA_ASTC_5x4_KHR;
+					if ( p === RGBA_ASTC_5x5_Format ) return ( transferFunction === SRGBTransferFunction ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR : extension.COMPRESSED_RGBA_ASTC_5x5_KHR;
+					if ( p === RGBA_ASTC_6x5_Format ) return ( transferFunction === SRGBTransferFunction ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR : extension.COMPRESSED_RGBA_ASTC_6x5_KHR;
+					if ( p === RGBA_ASTC_6x6_Format ) return ( transferFunction === SRGBTransferFunction ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR : extension.COMPRESSED_RGBA_ASTC_6x6_KHR;
+					if ( p === RGBA_ASTC_8x5_Format ) return ( transferFunction === SRGBTransferFunction ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR : extension.COMPRESSED_RGBA_ASTC_8x5_KHR;
+					if ( p === RGBA_ASTC_8x6_Format ) return ( transferFunction === SRGBTransferFunction ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR : extension.COMPRESSED_RGBA_ASTC_8x6_KHR;
+					if ( p === RGBA_ASTC_8x8_Format ) return ( transferFunction === SRGBTransferFunction ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR : extension.COMPRESSED_RGBA_ASTC_8x8_KHR;
+					if ( p === RGBA_ASTC_10x5_Format ) return ( transferFunction === SRGBTransferFunction ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR : extension.COMPRESSED_RGBA_ASTC_10x5_KHR;
+					if ( p === RGBA_ASTC_10x6_Format ) return ( transferFunction === SRGBTransferFunction ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR : extension.COMPRESSED_RGBA_ASTC_10x6_KHR;
+					if ( p === RGBA_ASTC_10x8_Format ) return ( transferFunction === SRGBTransferFunction ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR : extension.COMPRESSED_RGBA_ASTC_10x8_KHR;
+					if ( p === RGBA_ASTC_10x10_Format ) return ( transferFunction === SRGBTransferFunction ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR : extension.COMPRESSED_RGBA_ASTC_10x10_KHR;
+					if ( p === RGBA_ASTC_12x10_Format ) return ( transferFunction === SRGBTransferFunction ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR : extension.COMPRESSED_RGBA_ASTC_12x10_KHR;
+					if ( p === RGBA_ASTC_12x12_Format ) return ( transferFunction === SRGBTransferFunction ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR : extension.COMPRESSED_RGBA_ASTC_12x12_KHR;
 
 				} else {
 
@@ -25836,13 +25836,15 @@ console.warn( 'Scripts "build/three.js" and "build/three.min.js" are deprecated
 
 			// BPTC
 
-			if ( p === RGBA_BPTC_Format ) {
+			if ( p === RGBA_BPTC_Format || p === RGB_BPTC_SIGNED_Format || p === RGB_BPTC_UNSIGNED_Format ) {
 
 				extension = extensions.get( 'EXT_texture_compression_bptc' );
 
 				if ( extension !== null ) {
 
-					if ( p === RGBA_BPTC_Format ) return ( colorSpace === SRGBColorSpace ) ? extension.COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT : extension.COMPRESSED_RGBA_BPTC_UNORM_EXT;
+					if ( p === RGBA_BPTC_Format ) return ( transferFunction === SRGBTransferFunction ) ? extension.COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT : extension.COMPRESSED_RGBA_BPTC_UNORM_EXT;
+					if ( p === RGB_BPTC_SIGNED_Format ) return extension.COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT;
+					if ( p === RGB_BPTC_UNSIGNED_Format ) return extension.COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT;
 
 				} else {
 
@@ -26884,14 +26886,6 @@ console.warn( 'Scripts "build/three.js" and "build/three.min.js" are deprecated
 				camera.matrix.decompose( camera.position, camera.quaternion, camera.scale );
 				camera.updateMatrixWorld( true );
 
-				const children = camera.children;
-
-				for ( let i = 0, l = children.length; i < l; i ++ ) {
-
-					children[ i ].updateMatrixWorld( true );
-
-				}
-
 				camera.projectionMatrix.copy( cameraXR.projectionMatrix );
 				camera.projectionMatrixInverse.copy( cameraXR.projectionMatrixInverse );
 
@@ -28054,14 +28048,6 @@ console.warn( 'Scripts "build/three.js" and "build/three.min.js" are deprecated
 
 	}
 
-	function createCanvasElement() {
-
-		const canvas = createElementNS( 'canvas' );
-		canvas.style.display = 'block';
-		return canvas;
-
-	}
-
 	class WebGLRenderer {
 
 		constructor( parameters = {} ) {
@@ -29787,48 +29773,28 @@ console.warn( 'Scripts "build/three.js" and "build/three.min.js" are deprecated
 
 				if ( refreshProgram || _currentCamera !== camera ) {
 
-					p_uniforms.setValue( _gl, 'projectionMatrix', camera.projectionMatrix );
-
-					if ( capabilities.logarithmicDepthBuffer ) {
+					// common camera uniforms
 
-						p_uniforms.setValue( _gl, 'logDepthBufFC',
-							2.0 / ( Math.log( camera.far + 1.0 ) / Math.LN2 ) );
-
-					}
-
-					if ( _currentCamera !== camera ) {
+					p_uniforms.setValue( _gl, 'projectionMatrix', camera.projectionMatrix );
+					p_uniforms.setValue( _gl, 'viewMatrix', camera.matrixWorldInverse );
 
-						_currentCamera = camera;
+					const uCamPos = p_uniforms.map.cameraPosition;
 
-						// lighting uniforms depend on the camera so enforce an update
-						// now, in case this material supports lights - or later, when
-						// the next material that does gets activated:
+					if ( uCamPos !== undefined ) {
 
-						refreshMaterial = true;		// set to true on material change
-						refreshLights = true;		// remains set until update done
+						uCamPos.setValue( _gl, _vector3.setFromMatrixPosition( camera.matrixWorld ) );
 
 					}
 
-					// load material specific uniforms
-					// (shader material also gets them for the sake of genericity)
-
-					if ( material.isShaderMaterial ||
-						material.isMeshPhongMaterial ||
-						material.isMeshToonMaterial ||
-						material.isMeshStandardMaterial ||
-						material.envMap ) {
-
-						const uCamPos = p_uniforms.map.cameraPosition;
-
-						if ( uCamPos !== undefined ) {
-
-							uCamPos.setValue( _gl,
-								_vector3.setFromMatrixPosition( camera.matrixWorld ) );
+					if ( capabilities.logarithmicDepthBuffer ) {
 
-						}
+						p_uniforms.setValue( _gl, 'logDepthBufFC',
+							2.0 / ( Math.log( camera.far + 1.0 ) / Math.LN2 ) );
 
 					}
 
+					// consider moving isOrthographic to UniformLib and WebGLMaterials, see https://github.com/mrdoob/three.js/pull/26467#issuecomment-1645185067
+
 					if ( material.isMeshPhongMaterial ||
 						material.isMeshToonMaterial ||
 						material.isMeshLambertMaterial ||
@@ -29840,16 +29806,16 @@ console.warn( 'Scripts "build/three.js" and "build/three.min.js" are deprecated
 
 					}
 
-					if ( material.isMeshPhongMaterial ||
-						material.isMeshToonMaterial ||
-						material.isMeshLambertMaterial ||
-						material.isMeshBasicMaterial ||
-						material.isMeshStandardMaterial ||
-						material.isShaderMaterial ||
-						material.isShadowMaterial ||
-						object.isSkinnedMesh ) {
+					if ( _currentCamera !== camera ) {
 
-						p_uniforms.setValue( _gl, 'viewMatrix', camera.matrixWorldInverse );
+						_currentCamera = camera;
+
+						// lighting uniforms depend on the camera so enforce an update
+						// now, in case this material supports lights - or later, when
+						// the next material that does gets activated:
+
+						refreshMaterial = true;		// set to true on material change
+						refreshLights = true;		// remains set until update done
 
 					}
 
@@ -32380,7 +32346,7 @@ console.warn( 'Scripts "build/three.js" and "build/three.min.js" are deprecated
 
 			super.copy( source, recursive );
 
-			this.material = source.material;
+			this.material = Array.isArray( source.material ) ? source.material.slice() : source.material;
 			this.geometry = source.geometry;
 
 			return this;
@@ -32701,7 +32667,7 @@ console.warn( 'Scripts "build/three.js" and "build/three.min.js" are deprecated
 
 			super.copy( source, recursive );
 
-			this.material = source.material;
+			this.material = Array.isArray( source.material ) ? source.material.slice() : source.material;
 			this.geometry = source.geometry;
 
 			return this;
@@ -42537,8 +42503,6 @@ console.warn( 'Scripts "build/three.js" and "build/three.min.js" are deprecated
 
 				}
 
-				if ( ! texData ) return onError(); // TODO: Remove this when all loaders properly throw errors
-
 				if ( texData.image !== undefined ) {
 
 					texture.image = texData.image;
@@ -45944,6 +45908,12 @@ console.warn( 'Scripts "build/three.js" and "build/three.min.js" are deprecated
 
 		disconnect() {
 
+			if ( this._connected === false ) {
+
+				return;
+
+			}
+
 			if ( this.filters.length > 0 ) {
 
 				this.source.disconnect( this.filters[ 0 ] );
@@ -49192,7 +49162,7 @@ console.warn( 'Scripts "build/three.js" and "build/three.min.js" are deprecated
 
 	}
 
-	let id = 0;
+	let _id = 0;
 
 	class UniformsGroup extends EventDispatcher {
 
@@ -49202,7 +49172,7 @@ console.warn( 'Scripts "build/three.js" and "build/three.min.js" are deprecated
 
 			this.isUniformsGroup = true;
 
-			Object.defineProperty( this, 'id', { value: id ++ } );
+			Object.defineProperty( this, 'id', { value: _id ++ } );
 
 			this.name = '';
 
@@ -51646,6 +51616,7 @@ console.warn( 'Scripts "build/three.js" and "build/three.min.js" are deprecated
 	exports.LineDashedMaterial = LineDashedMaterial;
 	exports.LineLoop = LineLoop;
 	exports.LineSegments = LineSegments;
+	exports.LinearDisplayP3ColorSpace = LinearDisplayP3ColorSpace;
 	exports.LinearEncoding = LinearEncoding;
 	exports.LinearFilter = LinearFilter;
 	exports.LinearInterpolant = LinearInterpolant;
@@ -51762,6 +51733,8 @@ console.warn( 'Scripts "build/three.js" and "build/three.min.js" are deprecated
 	exports.RGBA_S3TC_DXT1_Format = RGBA_S3TC_DXT1_Format;
 	exports.RGBA_S3TC_DXT3_Format = RGBA_S3TC_DXT3_Format;
 	exports.RGBA_S3TC_DXT5_Format = RGBA_S3TC_DXT5_Format;
+	exports.RGB_BPTC_SIGNED_Format = RGB_BPTC_SIGNED_Format;
+	exports.RGB_BPTC_UNSIGNED_Format = RGB_BPTC_UNSIGNED_Format;
 	exports.RGB_ETC1_Format = RGB_ETC1_Format;
 	exports.RGB_ETC2_Format = RGB_ETC2_Format;
 	exports.RGB_PVRTC_2BPPV1_Format = RGB_PVRTC_2BPPV1_Format;
@@ -51871,6 +51844,7 @@ console.warn( 'Scripts "build/three.js" and "build/three.min.js" are deprecated
 	exports.ZeroSlopeEnding = ZeroSlopeEnding;
 	exports.ZeroStencilOp = ZeroStencilOp;
 	exports._SRGBAFormat = _SRGBAFormat;
+	exports.createCanvasElement = createCanvasElement;
 	exports.sRGBEncoding = sRGBEncoding;
 
 }));

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


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


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


+ 1 - 1
docs/api/ar/lights/SpotLight.html

@@ -153,7 +153,7 @@
 		[page:Texture] يستخدم لتعديل لون الضوء. يتم خلط لون المصباح
 		مع قيمة RGB لهذه الملمس ، بنسبة
 		تتوافق مع قيمة ألفا. يتم تكرار التأثير المشابه للكعكة باستخدام قِيَم بكسل (0، 0، 0، 1-قِيَم_الكعكة). <b>تحذير</b>:
-		[param:SpotLight map] مُعَطَّلَ إذا كان [param:SpotLight castShadow]
+		[page:.map] مُعَطَّلَ إذا كان [page:.castShadow]
 		<b>خطأ</b>.
 		</p>
 		

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

@@ -199,7 +199,7 @@
 		<p>
 		عدد عائم يُقيِّس كمية الانعكاس العاكس للأشياء غير المعدنية فقط.
 		عند تعيينه على صفر، يصبح النموذج فعالًا كـ Lambertian. من `0.0` إلى
-		`1.0`. الافتراضى هو `0.0`.
+		`1.0`. الافتراضى هو `1.0`.
 		</p>
 		
 		<h3>[property:Texture specularIntensityMap]</h3>

+ 1 - 1
docs/api/ar/math/Matrix3.html

@@ -50,7 +50,7 @@ m.elements = [ 11, 21, 31,
 		<h2>المنشئ (Constructor)</h2>
 		 
 		<h3>[name]( [param:Number n11], [param:Number n12], [param:Number n13],
-		[param:Number n21], [param:Number n22], [param:Number n22],
+		[param:Number n21], [param:Number n22], [param:Number n23],
 		[param:Number n31], [param:Number n32], [param:Number n33] )</h3>
 		<p>
 		ينشئ مصفوفة 3x3 بالوسائط المعطاة بترتيب الصف الرئيسي. إذا لم يتم توفير أية وسائط ، يقوم المنشئ بتهيئة

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

@@ -280,6 +280,9 @@
 			Note: This method does not support scene graphs having
 			non-uniformly-scaled nodes(s).
 		</p>
+		
+		<h3>[method:this clear]()</h3>
+		<p>Removes all child objects.</p>
 
 		<h3>[method:Object3D clone]( [param:Boolean recursive] )</h3>
 		<p>
@@ -412,9 +415,6 @@
 		<h3>[method:this removeFromParent]()</h3>
 		<p>Removes this object from its current parent.</p>
 
-		<h3>[method:this clear]()</h3>
-		<p>Removes all child objects.</p>
-
 		<h3>[method:this rotateOnAxis]( [param:Vector3 axis], [param:Float angle] )</h3>
 		<p>
 			axis -- A normalized vector in object space. <br />

+ 1 - 2
docs/api/en/lights/SpotLight.html

@@ -157,8 +157,7 @@ light.target = targetObject;
 			color is mixed with the RGB value of this texture, with a ratio
 			corresponding to its alpha value. The cookie-like masking effect is
 			reproduced using pixel values (0, 0, 0, 1-cookie_value). *Warning*:
-			[param:SpotLight map] is disabled if [param:SpotLight castShadow] is
-			*false*.
+			[page:.map] is disabled if [page:.castShadow] is *false*.
 		</p>
 
 		<h2>Methods</h2>

+ 42 - 3
docs/api/en/materials/MeshPhysicalMaterial.html

@@ -160,7 +160,7 @@
 		<h3>[property:Float ior]</h3>
 		<p>
 			Index-of-refraction for non-metallic materials, from `1.0` to `2.333`.
-			Default is `1.5`.<br />
+			Default is `1.5`.
 		</p>
 
 		<h3>[property:Float reflectivity]</h3>
@@ -172,6 +172,45 @@
 			when [page:MeshStandardMaterial.metalness metalness] is `1.0`
 		</p>
 
+		<h3>[property:Float iridescence]</h3>
+		<p>
+			The intensity of the [link:https://en.wikipedia.org/wiki/Iridescence iridescence] layer, simulating RGB color shift based on the angle between the surface and the viewer, from `0.0` to `1.0`. Default is `0.0`.
+		</p>
+
+		<h3>[property:Texture iridescenceMap]</h3>
+		<p>
+			The red channel of this texture is multiplied against
+			[page:.iridescence], for per-pixel control over iridescence.
+			Default is `null`.
+		</p>
+
+		<h3>[property:Float iridescenceIOR]</h3>
+		<p>
+			Strength of the iridescence RGB color shift effect, represented by an index-of-refraction. Between `1.0` to `2.333`.
+			Default is `1.3`.
+		</p>
+
+		<h3>[property:Array iridescenceThicknessRange]</h3>
+		<p>
+			Array of exactly 2 elements, specifying minimum and maximum thickness of the iridescence layer.
+			Thickness of iridescence layer has an equivalent effect of the one [page:.thickness] has on [page:.ior].
+			Default is `[100, 400]`.<br />
+
+			If [page:.iridescenceThicknessMap] is not defined, iridescence thickness will use only the second element of the given array.
+		</p>
+
+		<h3>[property:Texture iridescenceThicknessMap]</h3>
+		<p>
+			A texture that defines the thickness of the iridescence layer, stored in the green channel.
+			Minimum and maximum values of thickness are defined by [page:.iridescenceThicknessRange] array:<br/>
+			<ul>
+				<li>`0.0` in the green channel will result in thickness equal to first element of the array.</li>
+				<li>`1.0` in the green channel will result in thickness equal to second element of the array.</li>
+				<li>Values in-between will linearly interpolate between the elements of the array.</li>
+			</ul>
+			Default is `null`.
+		</p>
+
 		<h3>[property:Float sheen]</h3>
 		<p>
 			The intensity of the sheen layer, from `0.0` to `1.0`. Default is `0.0`.
@@ -201,7 +240,7 @@
 		<p>
 			A float that scales the amount of specular reflection for non-metals only.
 			When set to zero, the model is effectively Lambertian. From `0.0` to
-			`1.0`. Default is `0.0`.
+			`1.0`. Default is `1.0`.
 		</p>
 
 		<h3>[property:Texture specularIntensityMap]</h3>
@@ -233,7 +272,7 @@
 
 		<h3>[property:Texture thicknessMap]</h3>
 		<p>
-			A texture that defines the thickness, stored in the G channel. This will
+			A texture that defines the thickness, stored in the green channel. This will
 			be multiplied by [page:.thickness]. Default is `null`.
 		</p>
 

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

@@ -50,7 +50,7 @@ m.elements = [ 11, 21, 31,
 		<h2>Constructor</h2>
 
 		<h3>[name]( [param:Number n11], [param:Number n12], [param:Number n13],
-			[param:Number n21], [param:Number n22], [param:Number n22],
+			[param:Number n21], [param:Number n22], [param:Number n23],
 			[param:Number n31], [param:Number n32], [param:Number n33] )</h3>
 		<p>
 			Creates a 3x3 matrix with the given arguments in row-major order. If no arguments are provided, the constructor initializes

+ 16 - 16
docs/api/en/renderers/WebGLRenderer.html

@@ -103,22 +103,6 @@
 			should clear the stencil buffer. Default is `true`.
 		</p>
 
-		<h3>[property:Object debug]</h3>
-		<p>
-			- [page:Boolean checkShaderErrors]: If it is true, defines whether
-			material shader programs are checked for errors during compilation and
-			linkage process. It may be useful to disable this check in production for
-			performance gain. It is strongly recommended to keep these checks enabled
-			during development. If the shader does not compile and link - it will not
-			work and associated material will not render. Default is `true`.<br />
-			- [page:Function onShaderError]( gl, program, glVertexShader,
-			glFragmentShader ): A callback function that can be used for custom error
-			reporting. The callback receives the WebGL context, an instance of
-			WebGLProgram as well two instances of WebGLShader representing the vertex
-			and fragment shader. Assigning a custom function disables the default
-			error reporting. Default is `null`.
-		</p>
-
 		<h3>[property:Object capabilities]</h3>
 		<p>
 			An object containing details about the capabilities of the current
@@ -172,6 +156,22 @@
 			the plane is negative are cut away. Default is [].
 		</p>
 
+		<h3>[property:Object debug]</h3>
+		<p>
+			- [page:Boolean checkShaderErrors]: If it is true, defines whether
+			material shader programs are checked for errors during compilation and
+			linkage process. It may be useful to disable this check in production for
+			performance gain. It is strongly recommended to keep these checks enabled
+			during development. If the shader does not compile and link - it will not
+			work and associated material will not render. Default is `true`.<br />
+			- [page:Function onShaderError]( gl, program, glVertexShader,
+			glFragmentShader ): A callback function that can be used for custom error
+			reporting. The callback receives the WebGL context, an instance of
+			WebGLProgram as well two instances of WebGLShader representing the vertex
+			and fragment shader. Assigning a custom function disables the default
+			error reporting. Default is `null`.
+		</p>
+		
 		<h3>[property:DOMElement domElement]</h3>
 		<p>
 			A [link:https://developer.mozilla.org/en-US/docs/Web/HTML/Element/canvas canvas] 

+ 1 - 1
docs/api/fr/materials/MeshPhysicalMaterial.html

@@ -172,7 +172,7 @@
 
 		<h3>[property:Float specularIntensity]</h3>
 		<p>
-			Un float qui met à l'échelle la quantité de réflexion spéculaire pour les non-métaux uniquement. Lorsqu'il est défini sur zéro, le modèle est effectivement lambertien. De `0.0` à `1.0`. La valeur par défaut est `0.0`.
+			Un float qui met à l'échelle la quantité de réflexion spéculaire pour les non-métaux uniquement. Lorsqu'il est défini sur zéro, le modèle est effectivement lambertien. De `0.0` à `1.0`. La valeur par défaut est `1.0`.
 		</p>
 
 		<h3>[property:Texture specularIntensityMap]</h3>

+ 1 - 1
docs/api/it/lights/SpotLight.html

@@ -166,7 +166,7 @@ light.target = targetObject;
       Una [page:Texture] utilizzata per modulare il colore della luce. Il colore della luce spot viene mescolato con il valore
       RGB di questa texture, con un rapporto corrispondente al suo valore alfa. L'effetto di mascheramento simile a quello dei cookie
       viene riprodotto utilizzando i valori (0, 0, 0, 1-cookie_value).
-      *Attenzione*: [param:SpotLight map] è disabilitata se [param:SpotLight castShadow] è *false*. 
+      *Attenzione*: [page:.map] è disabilitata se [page:.castShadow] è *false*. 
 		</p>
 
 		<h2>Metodi</h2>

+ 1 - 1
docs/api/it/materials/MeshPhysicalMaterial.html

@@ -178,7 +178,7 @@
 		<h3>[property:Float specularIntensity]</h3>
 		<p>
 			Un float che ridimensiona la quantità di riflessione speculare solo per i non metalli. Quando è impostato su zero, il modello 
-			è effettivamente Lambertiano. Da `0.0` a `1.0`. Il valore predefinito è `0.0`.
+			è effettivamente Lambertiano. Da `0.0` a `1.0`. Il valore predefinito è `1.0`.
 		</p>
 
 		<h3>[property:Texture specularIntensityMap]</h3>

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

@@ -47,7 +47,7 @@ m.elements = [ 11, 21, 31,
 
 
 		<h3>[name]( [param:Number n11], [param:Number n12], [param:Number n13],
-			[param:Number n21], [param:Number n22], [param:Number n22],
+			[param:Number n21], [param:Number n22], [param:Number n23],
 			[param:Number n31], [param:Number n32], [param:Number n33] )</h3>
 		<p>
 			Creates a 3x3 matrix with the given arguments in row-major. If no arguments are provided, the constructor initializes

+ 1 - 1
docs/api/zh/lights/SpotLight.html

@@ -146,7 +146,7 @@ light.target = targetObject;
 		<p>
 			用于调节光线颜色的纹理([page:Texture]),聚光灯颜色会与该纹理的RGB值混合,其比例与其alpha值相对应。<br />
 			The cookie-like masking effect is reproduced using pixel values (0, 0, 0, 1-cookie_value).<br />
-			*注意*: 如果 `castShadow` 值为 `false` 时,`map` 不可用。
+			*注意*: 如果 [page:.castShadow] 值为 `false` 时,[page:.map] 不可用。
 		</p>
 
 

+ 1 - 1
docs/api/zh/materials/MeshPhysicalMaterial.html

@@ -159,7 +159,7 @@
 
 		<h3>[property:Float specularIntensity]</h3>
 		<p>
-			用于控制非金属材质高光反射强度的浮点值。漫反射材质对应的值为0。范围从*0.0*到*1.0*。 默认值为*0.0*。
+			用于控制非金属材质高光反射强度的浮点值。漫反射材质对应的值为0。范围从*0.0*到*1.0*。 默认值为*1.0*。
 		</p>
 
 		<h3>[property:Texture specularIntensityMap]</h3>

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

@@ -44,7 +44,7 @@ m.elements = [ 11, 21, 31,
 
 
 		<h3>[name]( [param:Number n11], [param:Number n12], [param:Number n13],
-			[param:Number n21], [param:Number n22], [param:Number n22],
+			[param:Number n21], [param:Number n22], [param:Number n23],
 			[param:Number n31], [param:Number n32], [param:Number n33] )</h3>
 		<p>
 			Creates a 3x3 matrix with the given arguments in row-major order. If no arguments are provided, the constructor initializes

+ 23 - 26
docs/api/zh/textures/CompressedArrayTexture.html

@@ -1,5 +1,5 @@
 <!DOCTYPE html>
-<html lang="en">
+<html lang="zh">
 	<head>
 		<meta charset="utf-8" />
 		<base href="../../../" />
@@ -12,61 +12,58 @@
 		<h1>[name]</h1>
 
 		<p class="desc">
-		Creates an texture 2D array based on data in compressed form, for example from a [link:https://en.wikipedia.org/wiki/DirectDraw_Surface DDS] file.<br /><br />
+		基于压缩形式的数据(例如从[link:https://en.wikipedia.org/wiki/DirectDraw_Surface DDS]文件)创建纹理2D数组<br /><br />
 
-
-		For use with the [page:CompressedTextureLoader CompressedTextureLoader].
+		用于 [page:CompressedTextureLoader CompressedTextureLoader].
 		</p>
 
 
-		<h2>Constructor</h2>
+		<h2>构造函数</h2>
 
 
 		<h3>[name]( [param:Array mipmaps], [param:Number width], [param:Number height], [param:Constant format], [param:Constant type] )</h3>
 		<p>
-		[page:Array mipmaps] -- The mipmaps array should contain objects with data, width and height. The mipmaps should be of the correct format and type.<br />
+		[page:Array mipmaps] -- mipmaps数组应包含具有数据、宽度和高度的对象。mipmap 应具有正确的格式和类型。<br />
 
-		[page:Number width] -- The width of the biggest mipmap.<br />
+		[page:Number width] -- 最大 mipmap 的宽度<br />
 
-		[page:Number height] -- The height of the biggest mipmap.<br />
+		[page:Number height] -- 最大 mipmap 的高度<br />
 
-		[page:Number depth] -- The number of layers of the 2D array texture.<br />
+		[page:Number depth] -- 二维阵列纹理的层数。<br />
 
-		[page:Constant format] -- The format used in the mipmaps.
-		See [page:Textures ST3C Compressed Texture Formats],
-		[page:Textures PVRTC Compressed Texture Formats] and
-		[page:Textures ETC Compressed Texture Format] for other choices.<br />
+		[page:Constant format] -- mipmap 中使用的格式。 
+			有关其他选择,请参阅[page:Textures ST3C Compressed Texture Formats] 、
+			[page:Textures PVRTC Compressed Texture Formats]和[page:Textures ETC Compressed Texture Format]。
+			<br />
 
-		[page:Constant type] -- Default is [page:Textures THREE.UnsignedByteType].
-		See [page:Textures type constants] for other choices.<br />
+		[page:Constant type] -- 默认值为[page:Textures THREE.UnsignedByteType]。 有关其他选择,请参阅[page:Textures type constants]。<br />
 
 		</p>
 
 
-		<h2>Properties</h2>
-
-		See the base [page:CompressedTexture CompressedTexture] class for common properties.
+		<h2>属性</h2>
+		有关常见属性,请参阅基本[page:CompressedTexture CompressedTexture]类。
 
 		<h3>[property:number wrapR]</h3>
 		<p>
-		This defines how the texture is wrapped in the depth direction.<br />
-		The default is [page:Textures THREE.ClampToEdgeWrapping], where the edge is clamped to the outer edge texels.
-		The other two choices are [page:Textures THREE.RepeatWrapping] and [page:Textures THREE.MirroredRepeatWrapping].
-		See the [page:Textures texture constants] page for details.
+		这定义了纹理在深度方向上的包裹方式。<br />
+		默认值为[page:Textures THREE.ClampToEdgeWrapping],其中边缘被紧贴到外边缘纹素上。 
+		另外两个选择是[page:Textures THREE.RepeatWrapping]和[page:Textures THREE.MirroredRepeatWrapping]。 
+		有关详细信息,请参阅[page:Textures texture constants]页面。
 		</p>
 
 		<h3>[property:Boolean isCompressedArrayTexture]</h3>
 		<p>
-			Read-only flag to check if a given object is of type [name].
+			只读标志,用于检查给定对象是否为[name]类型。
 		</p>
 
-		<h2>Methods</h2>
+		<h2>函数</h2>
 
 		<p>
-		See the base [page:CompressedTexture CompressedTexture] class for common methods.
+		有关常用方法,请参阅基本[page:CompressedTexture CompressedTexture]类。
 		</p>
 
-		<h2>Source</h2>
+		<h2>源代码</h2>
 
 		<p>
 			[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]

+ 4 - 3
docs/examples/en/controls/OrbitControls.html

@@ -91,7 +91,7 @@
 		<h3>[property:Boolean autoRotate]</h3>
 		<p>
 			Set to true to automatically rotate around the target.<br> Note that if this is enabled, you must call [page:.update]
-			() in your animation loop.
+			() in your animation loop. If you want the auto-rotate speed to be independent of the frame rate (the refresh rate of the display), you must pass the time `deltaTime`, in seconds, to [page:.update]().
 		</p>
 
 		<h3>[property:Float autoRotateSpeed]</h3>
@@ -320,10 +320,11 @@ controls.touches = {
 			Removes the key event listener previously defined with [page:.listenToKeyEvents]().
 		</p>
 
-		<h3>[method:Boolean update] ()</h3>
+		<h3>[method:Boolean update] ( [param:Number deltaTime] )</h3>
 		<p>
 			Update the controls. Must be called after any manual changes to the camera's transform,
-			or in the update loop if [page:.autoRotate] or [page:.enableDamping] are set.
+			or in the update loop if [page:.autoRotate] or [page:.enableDamping] are set. `deltaTime`, in seconds, is optional,
+			and is only required if you want the auto-rotate speed to be independent of the frame rate (the refresh rate of the display).
 		</p>
 
 		<h2>Source</h2>

+ 0 - 96
docs/examples/en/exporters/ColladaExporter.html

@@ -1,96 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-	<head>
-		<meta charset="utf-8" />
-		<base href="../../../" />
-		<script src="page.js"></script>
-		<link type="text/css" rel="stylesheet" href="page.css" />
-	</head>
-	<body>
-		<h1>[name]</h1>
-
-		<p class="desc">
-		An exporter for `Collada`.
-		<br /><br />
-		[link:https://www.khronos.org/collada/ Collada] is a
-		file format for robust representation of scenes, materials, animations, and other 3D content in an xml format.
-		This exporter only supports exporting geometry, materials, textures, and scene hierarchy.
-		</p>
-
-		<h2>Import</h2>
-
-		<p>
-			[name] is an add-on, and must be imported explicitly.
-			See [link:#manual/introduction/Installation Installation / Addons].
-		</p>
-
-		<code>
-			import { ColladaExporter } from 'three/addons/exporters/ColladaExporter.js';
-		</code>
-
-		<h2>Code Example</h2>
-
-		<code>
-		// Instantiate an exporter
-		const exporter = new ColladaExporter();
-
-		// Parse the input and generate the collada ( .dae ) output
-		const data = exporter.parse( scene, null, options );
-		downloadFile( data );
-		</code>
-
-		<h2>Constructor</h2>
-
-		<h3>[name]()</h3>
-		<p>
-		</p>
-		<p>
-		Creates a new [name].
-		</p>
-
-		<h2>Methods</h2>
-
-		<h3>[method:Object parse]( [param:Object3D input], [param:Function onCompleted], [param:Object options] )</h3>
-		<p>
-		[page:Object input] — Object3D to be exported<br />
-		[page:Function onCompleted] — Will be called when the export completes. Optional. The same data is immediately returned from the function.<br />
-		[page:Options options] — Export options<br />
-		</p>
-		<ul>
-			<li>version - string. Which version of Collada to export. The options are "1.4.1" or "1.5.0". Defaults to "1.4.1".</li>
-			<li>author - string. The name to include in the author field. Author field is excluded by default.</li>
-			<li>textureDirectory - string. The directory relative to the Collada file to save the textures to.</li>
-			<li>upAxis - string. Either Y_UP (default), Z_UP or X_UP.</li>
-			<li>unitName - string. Name of the unit. Can be any string, but could be for example "meter", "inch", or "parsec".</li>
-			<li>unitMeter - number. Length of the unit in meters.</li>
-		</ul>
-		<p>
-		Generates an object with Collada file and texture data. This object is returned from the function and passed into the "onCompleted" callback.
-		<code>
-		{
-			// Collada file content
-			data: "",
-
-			// List of referenced textures
-			textures: [{
-
-				// File directory, name, and extension of the texture data
-				directory: "",
-				name: "",
-				ext: "",
-
-				// The texture data and original texture object
-				data: [],
-				original: &ltTHREE.Texture&gt
-			}, ...]
-		}
-		</code>
-		</p>
-
-		<h2>Source</h2>
-
-		<p>
-			[link:https://github.com/mrdoob/three.js/blob/master/examples/jsm/exporters/ColladaExporter.js examples/jsm/exporters/ColladaExporter.js]
-		</p>
-	</body>
-</html>

+ 8 - 0
docs/examples/en/math/OBB.html

@@ -148,6 +148,14 @@
 			Whether the given [name] intersects this [name] or not.
 		</p>
 
+		<h3>[method:Boolean intersectsPlane]( [param:Plane plane] )</h3>
+		<p>
+			[page:Plane plane] — The plane to test.
+		</p>
+		<p>
+			Whether the given plane intersects this [name] or not.
+		</p>
+
 		<h3>[method:Boolean intersectsRay]( [param:Ray ray] )</h3>
 		<p>
 			[page:Ray ray] — The ray to test.

+ 1 - 1
docs/examples/en/utils/CameraUtils.html

@@ -21,7 +21,7 @@
 		</p>
 
 		<code>
-			import { CameraUtils } from 'three/addons/utils/CameraUtils.js';
+			import * as CameraUtils from 'three/addons/utils/CameraUtils.js';
 		</code>
 
 		<h2>Methods</h2>

+ 6 - 2
docs/examples/ko/controls/OrbitControls.html

@@ -91,7 +91,8 @@
 		<h3>[property:Boolean autoRotate]</h3>
 		<p>
 			대상 주위를 자동으로 회전하려면 true로 설정합니다.<br> autoRotate를 활성할 경우, 애니메이션 루프에서 [page:.update()]를 호출해야 합니다.
-
+			Set to true to automatically rotate around the target.<br> Note that if this is enabled, you must call [page:.update]
+			() in your animation loop. If you want the auto-rotate speed to be independent of the frame rate (the refresh rate of the display), you must pass the time `deltaTime`, in seconds, to [page:.update]().
 		</p>
 
 		<h3>[property:Float autoRotateSpeed]</h3>
@@ -317,9 +318,12 @@ controls.touches = {
 			Removes the key event listener previously defined with [page:.listenToKeyEvents]().
 		</p>
 
-		<h3>[method:Boolean update] ()</h3>
+		<h3>[method:Boolean update] (  [param:Number deltaTime]  )</h3>
 		<p>
 			컨트롤을 업데이트합니다. 카메라를 수동으로 변환하거나, [page:.autoRotate] 또는 [page:.enableDamping]을 설정할 경우 업데이트 루프에서 호출해야 합니다.
+			Update the controls. Must be called after any manual changes to the camera's transform,
+			or in the update loop if [page:.autoRotate] or [page:.enableDamping] are set. `deltaTime`, in seconds, is optional,
+			and is only required if you want the auto-rotate speed to be independent of the frame rate (the refresh rate of the display).
 		</p>
 
 		<h2>Source</h2>

+ 6 - 1
docs/examples/zh/controls/OrbitControls.html

@@ -93,6 +93,8 @@
 		<p>
 			将其设为true,以自动围绕目标旋转。<br>
 			请注意,如果它被启用,你必须在你的动画循环里调用[page:.update]()。
+			Set to true to automatically rotate around the target.<br> Note that if this is enabled, you must call [page:.update]
+			() in your animation loop. If you want the auto-rotate speed to be independent of the frame rate (the refresh rate of the display), you must pass the time `deltaTime`, in seconds, to [page:.update]().
 		</p>
 
 		<h3>[property:Float autoRotateSpeed]</h3>
@@ -319,10 +321,13 @@ controls.touches = {
 			Removes the key event listener previously defined with [page:.listenToKeyEvents]().
 		</p>
 
-		<h3>[method:Boolean update] ()</h3>
+		<h3>[method:Boolean update] ( [param:Number deltaTime] )</h3>
 		<p>
 			更新控制器。必须在摄像机的变换发生任何手动改变后调用,
 			或如果[page:.autoRotate]或[page:.enableDamping]被设置时,在update循环里调用。
+			Update the controls. Must be called after any manual changes to the camera's transform,
+			or in the update loop if [page:.autoRotate] or [page:.enableDamping] are set. `deltaTime`, in seconds, is optional,
+			and is only required if you want the auto-rotate speed to be independent of the frame rate (the refresh rate of the display).
 		</p>
 
 		<h2>源代码</h2>

+ 0 - 2
docs/list.json

@@ -386,7 +386,6 @@
 			},
 
 			"Exporters": {
-				"ColladaExporter": "examples/en/exporters/ColladaExporter",
 				"DRACOExporter": "examples/en/exporters/DRACOExporter",
 				"EXRExporter": "examples/en/exporters/EXRExporter",
 				"GLTFExporter": "examples/en/exporters/GLTFExporter",
@@ -2247,7 +2246,6 @@
 			},
 
 			"Exporters": {
-				"ColladaExporter": "examples/en/exporters/ColladaExporter",
 				"EXRExporter": "examples/en/exporters/EXRExporter",
 				"GLTFExporter": "examples/en/exporters/GLTFExporter",
 				"OBJExporter": "examples/en/exporters/OBJExporter",

+ 2 - 2
docs/manual/ar/introduction/Installation.html

@@ -85,7 +85,7 @@
 		</p>
 
 		<code>
-		&lt;script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js">&lt;/script>
+		&lt;script async src="https://unpkg.com/es-module-shims@1.8.0/dist/es-module-shims.js">&lt;/script>
 
 		&lt;script type="importmap">
 			{
@@ -126,7 +126,7 @@
 		</p>
 
 		<code>
-		&lt;script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js">&lt;/script>
+		&lt;script async src="https://unpkg.com/es-module-shims@1.8.0/dist/es-module-shims.js">&lt;/script>
 
 		&lt;script type="importmap">
 			{

+ 1 - 1
docs/manual/en/introduction/Installation.html

@@ -149,7 +149,7 @@ npm install --save-dev vite
 					We imported code from 'three' (an npm package) in <i>main.js</i>, and web browsers don't know what that means. In <i>index.html</i> we'll need to add an [link:https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/importmap import map] defining where to get the package. Put the code below inside the <i>&lt;head>&lt/head></i> tag, after the styles.
 				</p>
 				<code>
-&lt;script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js">&lt;/script>
+&lt;script async src="https://unpkg.com/es-module-shims@1.8.0/dist/es-module-shims.js">&lt;/script>
 
 &lt;script type="importmap">
   {

+ 2 - 2
docs/manual/fr/introduction/Installation.html

@@ -68,7 +68,7 @@
 		</p>
 
 		<code>
-		&lt;script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js">&lt;/script>
+		&lt;script async src="https://unpkg.com/es-module-shims@1.8.0/dist/es-module-shims.js">&lt;/script>
 
 		&lt;script type="importmap">
 		  {
@@ -113,7 +113,7 @@
 		</p>
 
 		<code>
-		&lt;script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js">&lt;/script>
+		&lt;script async src="https://unpkg.com/es-module-shims@1.8.0/dist/es-module-shims.js">&lt;/script>
 
 		&lt;script type="importmap">
 			{

+ 2 - 2
docs/manual/it/introduction/Installation.html

@@ -69,7 +69,7 @@
 		</p>
 
 		<code>
-		&lt;script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js">&lt;/script>
+		&lt;script async src="https://unpkg.com/es-module-shims@1.8.0/dist/es-module-shims.js">&lt;/script>
 
 		&lt;script type="importmap">
 		  {
@@ -113,7 +113,7 @@
 		</p>
 
 		<code>
-		&lt;script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js">&lt;/script>
+		&lt;script async src="https://unpkg.com/es-module-shims@1.8.0/dist/es-module-shims.js">&lt;/script>
 
 		&lt;script type="importmap">
 			{

+ 2 - 2
docs/manual/ja/introduction/Installation.html

@@ -69,7 +69,7 @@
     </p>
 
     <code>
-&lt;script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js">&lt;/script>
+&lt;script async src="https://unpkg.com/es-module-shims@1.8.0/dist/es-module-shims.js">&lt;/script>
 
 &lt;script type="importmap">
     {
@@ -110,7 +110,7 @@
     </p>
 
     <code>
-&lt;script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js">&lt;/script>
+&lt;script async src="https://unpkg.com/es-module-shims@1.8.0/dist/es-module-shims.js">&lt;/script>
 
 &lt;script type="importmap">
     {

+ 2 - 2
docs/manual/ko/introduction/Installation.html

@@ -77,7 +77,7 @@
     </p>
 
     <code>
-&lt;script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js">&lt;/script>
+&lt;script async src="https://unpkg.com/es-module-shims@1.8.0/dist/es-module-shims.js">&lt;/script>
 
 &lt;script type="importmap">
     {
@@ -122,7 +122,7 @@
     </p>
 
     <code>
-&lt;script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js">&lt;/script>
+&lt;script async src="https://unpkg.com/es-module-shims@1.8.0/dist/es-module-shims.js">&lt;/script>
 
 &lt;script type="importmap">
     {

+ 2 - 2
docs/manual/pt-br/introduction/Installation.html

@@ -53,7 +53,7 @@
 		<p>A biblioteca three.js pode ser utilizada sem nenhum sistema de build, seja fazendo o upload dos arquivos para seu próprio servidor web ou usando um CDN existente. Como a biblioteca depende dos ES modules, qualquer script que faça referência a eles deve usar <em>type="module"</em> como mostrado abaixo. Também é necessário definir um mapa de importação que resolva a importação direta do `three`.</p>
 
 		<code>
-		&lt;script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js">&lt;/script>
+		&lt;script async src="https://unpkg.com/es-module-shims@1.8.0/dist/es-module-shims.js">&lt;/script>
 
 		&lt;script type="importmap">
 		  {
@@ -99,7 +99,7 @@
 		<p>Se o three.js foi instalado de um CDN, use o mesmo CDN para instalar outros componentes:</p>
 
 		<code>
-		&lt;script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js">&lt;/script>
+		&lt;script async src="https://unpkg.com/es-module-shims@1.8.0/dist/es-module-shims.js">&lt;/script>
 
 		&lt;script type="importmap">
 			{

+ 2 - 2
docs/manual/ru/introduction/Installation.html

@@ -92,7 +92,7 @@
 	</p>
 
 	<code>
-		&lt;script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js">&lt;/script>
+		&lt;script async src="https://unpkg.com/es-module-shims@1.8.0/dist/es-module-shims.js">&lt;/script>
 
 		&lt;script type="importmap">
 		{
@@ -143,7 +143,7 @@
 	</p>
 
 	<code>
-		&lt;script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js">&lt;/script>
+		&lt;script async src="https://unpkg.com/es-module-shims@1.8.0/dist/es-module-shims.js">&lt;/script>
 
 		&lt;script type="importmap">
 		{

+ 2 - 2
docs/manual/zh/introduction/Installation.html

@@ -67,7 +67,7 @@
 		</p>
 
 		<code>
-		&lt;script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js">&lt;/script>
+		&lt;script async src="https://unpkg.com/es-module-shims@1.8.0/dist/es-module-shims.js">&lt;/script>
 
 		&lt;script type="importmap">
 			{
@@ -108,7 +108,7 @@
 		</p>
 
 		<code>
-		&lt;script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js">&lt;/script>
+		&lt;script async src="https://unpkg.com/es-module-shims@1.8.0/dist/es-module-shims.js">&lt;/script>
 
 		&lt;script type="importmap">
 			{

+ 1 - 1
docs/page.js

@@ -67,7 +67,7 @@ function onDocumentLoad() {
 	text = text.replace( /\[link:([\w\:\/\.\-\_\(\)\?\#\=\!\~]+)\]/gi, '<a href="$1" target="_blank">$1</a>' ); // [link:url]
 	text = text.replace( /\[link:([\w:/.\-_()?#=!~]+) ([\w\p{L}:/.\-_'\s]+)\]/giu, '<a href="$1" target="_blank">$2</a>' ); // [link:url title]
 	text = text.replace( /\*([\u4e00-\u9fa5\w\d\-\(\"\(\“][\u4e00-\u9fa5\w\d\ \/\+\-\(\)\=\,\.\(\)\,\。"]*[\u4e00-\u9fa5\w\d\"\)\”\)]|\w)\*/gi, '<strong>$1</strong>' ); // *text*
-	text = text.replace( /\`(.*?)\`/gi, '<code class="inline">$1</code>' ); // `code`
+	text = text.replace( /\`(.*?)\`/gs, '<code class="inline">$1</code>' ); // `code`
 
 	text = text.replace( /\[example:([\w\_]+)\]/gi, '[example:$1 $1]' ); // [example:name] to [example:name title]
 	text = text.replace( /\[example:([\w\_]+) ([\w\:\/\.\-\_ \s]+)\]/gi, '<a href="../examples/#$1" target="_blank">$2</a>' ); // [example:name title]

+ 1 - 1
docs/scenes/bones-browser.html

@@ -25,7 +25,7 @@
 
 		<!-- Import maps polyfill -->
 		<!-- Remove this when import maps will be widely supported -->
-		<script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>
+		<script async src="https://unpkg.com/es-module-shims@1.8.0/dist/es-module-shims.js"></script>
 
 		<script type="importmap">
 			{

+ 1 - 1
docs/scenes/ccdiksolver-browser.html

@@ -25,7 +25,7 @@
 
 		<!-- Import maps polyfill -->
 		<!-- Remove this when import maps will be widely supported -->
-		<script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>
+		<script async src="https://unpkg.com/es-module-shims@1.8.0/dist/es-module-shims.js"></script>
 
 		<script type="importmap">
 			{

+ 1 - 1
docs/scenes/geometry-browser.html

@@ -25,7 +25,7 @@
 
 		<!-- Import maps polyfill -->
 		<!-- Remove this when import maps will be widely supported -->
-		<script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>
+		<script async src="https://unpkg.com/es-module-shims@1.8.0/dist/es-module-shims.js"></script>
 
 		<script type="importmap">
 			{

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

@@ -25,7 +25,7 @@
 
 		<!-- Import maps polyfill -->
 		<!-- Remove this when import maps will be widely supported -->
-		<script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>
+		<script async src="https://unpkg.com/es-module-shims@1.8.0/dist/es-module-shims.js"></script>
 
 		<script type="importmap">
 			{

File diff suppressed because it is too large
+ 168 - 150
editor/js/libs/es-module-shims.js


+ 1 - 1
examples/css2d_label.html

@@ -19,7 +19,7 @@
 
 		<!-- Import maps polyfill -->
 		<!-- Remove this when import maps will be widely supported -->
-		<script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>
+		<script async src="https://unpkg.com/es-module-shims@1.8.0/dist/es-module-shims.js"></script>
 
 		<script type="importmap">
 			{

+ 1 - 1
examples/css3d_molecules.html

@@ -24,7 +24,7 @@
 
 		<!-- Import maps polyfill -->
 		<!-- Remove this when import maps will be widely supported -->
-		<script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>
+		<script async src="https://unpkg.com/es-module-shims@1.8.0/dist/es-module-shims.js"></script>
 
 		<script type="importmap">
 			{

+ 1 - 1
examples/css3d_orthographic.html

@@ -22,7 +22,7 @@
 
 		<!-- Import maps polyfill -->
 		<!-- Remove this when import maps will be widely supported -->
-		<script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>
+		<script async src="https://unpkg.com/es-module-shims@1.8.0/dist/es-module-shims.js"></script>
 
 		<script type="importmap">
 			{

+ 1 - 1
examples/css3d_periodictable.html

@@ -93,7 +93,7 @@
 
 		<!-- Import maps polyfill -->
 		<!-- Remove this when import maps will be widely supported -->
-		<script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>
+		<script async src="https://unpkg.com/es-module-shims@1.8.0/dist/es-module-shims.js"></script>
 
 		<script type="importmap">
 			{

+ 1 - 1
examples/css3d_sandbox.html

@@ -18,7 +18,7 @@
 
 		<!-- Import maps polyfill -->
 		<!-- Remove this when import maps will be widely supported -->
-		<script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>
+		<script async src="https://unpkg.com/es-module-shims@1.8.0/dist/es-module-shims.js"></script>
 
 		<script type="importmap">
 			{

+ 1 - 1
examples/css3d_sprites.html

@@ -22,7 +22,7 @@
 
 		<!-- Import maps polyfill -->
 		<!-- Remove this when import maps will be widely supported -->
-		<script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>
+		<script async src="https://unpkg.com/es-module-shims@1.8.0/dist/es-module-shims.js"></script>
 
 		<script type="importmap">
 			{

+ 1 - 1
examples/css3d_youtube.html

@@ -25,7 +25,7 @@
 
 		<!-- Import maps polyfill -->
 		<!-- Remove this when import maps will be widely supported -->
-		<script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>
+		<script async src="https://unpkg.com/es-module-shims@1.8.0/dist/es-module-shims.js"></script>
 
 		<script type="importmap">
 			{

+ 5 - 1
examples/files.json

@@ -306,12 +306,14 @@
 		"webgl2_volume_instancing",
 		"webgl2_volume_perlin"
 	],
-	"webgpu": [
+	"webgpu (wip)": [
 		"webgpu_audio_processing",
 		"webgpu_backdrop",
 		"webgpu_backdrop_area",
 		"webgpu_clearcoat",
 		"webgpu_compute",
+		"webgpu_compute_particles",
+		"webgpu_compute_texture",
 		"webgpu_cubemap_adjustments",
 		"webgpu_cubemap_dynamic",
 		"webgpu_cubemap_mix",
@@ -329,7 +331,9 @@
 		"webgpu_loader_gltf_sheen",
 		"webgpu_materials",
 		"webgpu_materials_video",
+		"webgpu_multiple_rendertargets",
 		"webgpu_morphtargets",
+		"webgpu_occlusion",
 		"webgpu_particles",
 		"webgpu_rtt",
 		"webgpu_sandbox",

+ 1 - 1
examples/games_fps.html

@@ -16,7 +16,7 @@
 
 		<!-- Import maps polyfill -->
 		<!-- Remove this when import maps will be widely supported -->
-		<script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>
+		<script async src="https://unpkg.com/es-module-shims@1.8.0/dist/es-module-shims.js"></script>
 
 		<script type="importmap">
 			{

+ 0 - 8
examples/index.html

@@ -10,14 +10,6 @@
 	</head>
 	<body>
 
-		<script async src="https://www.googletagmanager.com/gtag/js?id=G-JPPX9MZGZ4"></script>
-		<script>
-			window.dataLayer = window.dataLayer || [];
-			function gtag(){dataLayer.push(arguments);}
-			gtag('js', new Date());
-			gtag('config', 'G-JPPX9MZGZ4');
-		</script>
-
 		<div id="panel">
 
 			<div id="header">

+ 13 - 5
examples/jsm/controls/OrbitControls.js

@@ -176,7 +176,7 @@ class OrbitControls extends EventDispatcher {
 
 			const twoPI = 2 * Math.PI;
 
-			return function update() {
+			return function update( deltaTime = null ) {
 
 				const position = scope.object.position;
 
@@ -190,7 +190,7 @@ class OrbitControls extends EventDispatcher {
 
 				if ( scope.autoRotate && state === STATE.NONE ) {
 
-					rotateLeft( getAutoRotationAngle() );
+					rotateLeft( getAutoRotationAngle( deltaTime ) );
 
 				}
 
@@ -469,9 +469,17 @@ class OrbitControls extends EventDispatcher {
 		const pointers = [];
 		const pointerPositions = {};
 
-		function getAutoRotationAngle() {
+		function getAutoRotationAngle( deltaTime ) {
 
-			return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed;
+			if ( deltaTime !== null ) {
+
+				return ( 2 * Math.PI / 60 * scope.autoRotateSpeed ) * deltaTime;
+
+			} else {
+
+				return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed;
+
+			}
 
 		}
 
@@ -623,7 +631,7 @@ class OrbitControls extends EventDispatcher {
 			mouse.x = ( x / w ) * 2 - 1;
 			mouse.y = - ( y / h ) * 2 + 1;
 
-			dollyDirection.set( mouse.x, mouse.y, 1 ).unproject( object ).sub( object.position ).normalize();
+			dollyDirection.set( mouse.x, mouse.y, 1 ).unproject( scope.object ).sub( scope.object.position ).normalize();
 
 		}
 

+ 35 - 1
examples/jsm/csm/CSMShader.js

@@ -8,12 +8,26 @@ geometry.position = - vViewPosition;
 geometry.normal = normal;
 geometry.viewDir = ( isOrthographic ) ? vec3( 0, 0, 1 ) : normalize( vViewPosition );
 
-#ifdef CLEARCOAT
+#ifdef USE_CLEARCOAT
 
 	geometry.clearcoatNormal = clearcoatNormal;
 
 #endif
 
+#ifdef USE_IRIDESCENCE
+	float dotNVi = saturate( dot( normal, geometry.viewDir ) );
+	if ( material.iridescenceThickness == 0.0 ) {
+		material.iridescence = 0.0;
+	} else {
+		material.iridescence = saturate( material.iridescence );
+	}
+	if ( material.iridescence > 0.0 ) {
+		material.iridescenceFresnel = evalIridescence( 1.0, material.iridescenceIOR, dotNVi, material.iridescenceThickness, material.specularColor );
+		// Iridescence F0 approximation
+		material.iridescenceF0 = Schlick_to_F0( material.iridescenceFresnel, 1.0, dotNVi );
+	}
+#endif
+
 IncidentLight directLight;
 
 #if ( NUM_POINT_LIGHTS > 0 ) && defined( RE_Direct )
@@ -45,6 +59,10 @@ IncidentLight directLight;
 #if ( NUM_SPOT_LIGHTS > 0 ) && defined( RE_Direct )
 
 	SpotLight spotLight;
+ 	vec4 spotColor;
+	vec3 spotLightCoord;
+	bool inSpotLightMap;
+ 
 	#if defined( USE_SHADOWMAP ) && NUM_SPOT_LIGHT_SHADOWS > 0
 	SpotLightShadow spotLightShadow;
 	#endif
@@ -56,6 +74,22 @@ IncidentLight directLight;
 
 		getSpotLightInfo( spotLight, geometry, directLight );
 
+  		// spot lights are ordered [shadows with maps, shadows without maps, maps without shadows, none]
+		#if ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS )
+		#define SPOT_LIGHT_MAP_INDEX UNROLLED_LOOP_INDEX
+		#elif ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )
+		#define SPOT_LIGHT_MAP_INDEX NUM_SPOT_LIGHT_MAPS
+		#else
+		#define SPOT_LIGHT_MAP_INDEX ( UNROLLED_LOOP_INDEX - NUM_SPOT_LIGHT_SHADOWS + NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS )
+		#endif
+		#if ( SPOT_LIGHT_MAP_INDEX < NUM_SPOT_LIGHT_MAPS )
+			spotLightCoord = vSpotLightCoord[ i ].xyz / vSpotLightCoord[ i ].w;
+			inSpotLightMap = all( lessThan( abs( spotLightCoord * 2. - 1. ), vec3( 1.0 ) ) );
+			spotColor = texture2D( spotLightMap[ SPOT_LIGHT_MAP_INDEX ], spotLightCoord.xy );
+			directLight.color = inSpotLightMap ? directLight.color * spotColor.rgb : directLight.color;
+		#endif
+		#undef SPOT_LIGHT_MAP_INDEX
+
 		#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )
 		spotLightShadow = spotLightShadows[ i ];
 		directLight.color *= ( directLight.visible && receiveShadow ) ? getShadow( spotShadowMap[ i ], spotLightShadow.shadowMapSize, spotLightShadow.shadowBias, spotLightShadow.shadowRadius, vSpotLightCoord[ i ] ) : 1.0;

File diff suppressed because it is too large
+ 776 - 720
examples/jsm/libs/tween.module.js


File diff suppressed because it is too large
+ 430 - 413
examples/jsm/libs/utif.module.js


+ 46 - 3
examples/jsm/loaders/DDSLoader.js

@@ -4,7 +4,9 @@ import {
 	RGBA_S3TC_DXT3_Format,
 	RGBA_S3TC_DXT5_Format,
 	RGB_ETC1_Format,
-	RGB_S3TC_DXT1_Format
+	RGB_S3TC_DXT1_Format,
+	RGB_BPTC_SIGNED_Format,
+	RGB_BPTC_UNSIGNED_Format
 } from 'three';
 
 class DDSLoader extends CompressedTextureLoader {
@@ -56,6 +58,9 @@ class DDSLoader extends CompressedTextureLoader {
 		// const DDPF_YUV = 0x200;
 		// const DDPF_LUMINANCE = 0x20000;
 
+		const DXGI_FORMAT_BC6H_UF16 = 95;
+		const DXGI_FORMAT_BC6H_SF16 = 96;
+
 		function fourCCToInt32( value ) {
 
 			return value.charCodeAt( 0 ) +
@@ -108,8 +113,10 @@ class DDSLoader extends CompressedTextureLoader {
 		const FOURCC_DXT3 = fourCCToInt32( 'DXT3' );
 		const FOURCC_DXT5 = fourCCToInt32( 'DXT5' );
 		const FOURCC_ETC1 = fourCCToInt32( 'ETC1' );
+		const FOURCC_DX10 = fourCCToInt32( 'DX10' );
 
 		const headerLengthInt = 31; // The header length in 32 bit ints
+		const extendedHeaderLengthInt = 5; // The extended header length in 32 bit ints
 
 		// Offsets into the header array
 
@@ -135,6 +142,9 @@ class DDSLoader extends CompressedTextureLoader {
 		// const off_caps3 = 29;
 		// const off_caps4 = 30;
 
+		// If fourCC = DX10, the extended header starts after 32
+		const off_dxgiFormat = 0;
+
 		// Parse header
 
 		const header = new Int32Array( buffer, 0, headerLengthInt );
@@ -152,6 +162,8 @@ class DDSLoader extends CompressedTextureLoader {
 
 		let isRGBAUncompressed = false;
 
+		let dataOffset = header[ off_size ] + 4;
+
 		switch ( fourCC ) {
 
 			case FOURCC_DXT1:
@@ -178,6 +190,39 @@ class DDSLoader extends CompressedTextureLoader {
 				dds.format = RGB_ETC1_Format;
 				break;
 
+			case FOURCC_DX10:
+
+				dataOffset += extendedHeaderLengthInt * 4;
+				const extendedHeader = new Int32Array( buffer, ( headerLengthInt + 1 ) * 4, extendedHeaderLengthInt );
+				const dxgiFormat = extendedHeader[ off_dxgiFormat ];
+				switch ( dxgiFormat ) {
+
+					case DXGI_FORMAT_BC6H_SF16: {
+
+						blockBytes = 16;
+						dds.format = RGB_BPTC_SIGNED_Format;
+						break;
+
+					}
+
+					case DXGI_FORMAT_BC6H_UF16: {
+
+						blockBytes = 16;
+						dds.format = RGB_BPTC_UNSIGNED_Format;
+						break;
+
+					}
+
+					default: {
+
+						console.error( 'THREE.DDSLoader.parse: Unsupported DXGI_FORMAT code ', dxgiFormat );
+						return dds;
+
+					}
+
+				}
+				break;
+
 			default:
 
 				if ( header[ off_RGBBitCount ] === 32
@@ -226,8 +271,6 @@ class DDSLoader extends CompressedTextureLoader {
 		dds.width = header[ off_width ];
 		dds.height = header[ off_height ];
 
-		let dataOffset = header[ off_size ] + 4;
-
 		// Extract mipmaps buffers
 
 		const faces = dds.isCubemap ? 6 : 1;

+ 4 - 4
examples/jsm/loaders/EXRLoader.js

@@ -1996,7 +1996,7 @@ class EXRLoader extends DataTextureLoader {
 
 			if ( dataView.getUint32( 0, true ) != 20000630 ) { // magic
 
-				throw new Error( 'THREE.EXRLoader: provided file doesn\'t appear to be in OpenEXR format.' );
+				throw new Error( 'THREE.EXRLoader: Provided file doesn\'t appear to be in OpenEXR format.' );
 
 			}
 
@@ -2033,7 +2033,7 @@ class EXRLoader extends DataTextureLoader {
 
 					if ( attributeValue === undefined ) {
 
-						console.warn( `EXRLoader.parse: skipped unknown header attribute type \'${attributeType}\'.` );
+						console.warn( `THREE.EXRLoader: Skipped unknown header attribute type \'${attributeType}\'.` );
 
 					} else {
 
@@ -2047,8 +2047,8 @@ class EXRLoader extends DataTextureLoader {
 
 			if ( ( spec & ~ 0x04 ) != 0 ) { // unsupported tiled, deep-image, multi-part
 
-				console.error( 'EXRHeader:', EXRHeader );
-				throw new Error( 'THREE.EXRLoader: provided file is currently unsupported.' );
+				console.error( 'THREE.EXRHeader:', EXRHeader );
+				throw new Error( 'THREE.EXRLoader: Provided file is currently unsupported.' );
 
 			}
 

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

@@ -961,6 +961,7 @@ class FBXTreeParser {
 				}
 
 				model.name = node.attrName ? PropertyBinding.sanitizeNodeName( node.attrName ) : '';
+				model.userData.originalName = node.attrName;
 
 				model.ID = id;
 
@@ -997,6 +998,7 @@ class FBXTreeParser {
 						// set name and id here - otherwise in cases where "subBone" is created it will not have a name / id
 
 						bone.name = name ? PropertyBinding.sanitizeNodeName( name ) : '';
+						bone.userData.originalName = name;
 						bone.ID = id;
 
 						skeleton.bones[ i ] = bone;

+ 15 - 7
examples/jsm/loaders/GLTFLoader.js

@@ -6,6 +6,7 @@ import {
 	BufferGeometry,
 	ClampToEdgeWrapping,
 	Color,
+	ColorManagement,
 	DirectionalLight,
 	DoubleSide,
 	FileLoader,
@@ -25,6 +26,7 @@ import {
 	LinearFilter,
 	LinearMipmapLinearFilter,
 	LinearMipmapNearestFilter,
+	LinearSRGBColorSpace,
 	Loader,
 	LoaderUtils,
 	Material,
@@ -545,7 +547,7 @@ class GLTFLightsExtension {
 
 		const color = new Color( 0xffffff );
 
-		if ( lightDef.color !== undefined ) color.fromArray( lightDef.color );
+		if ( lightDef.color !== undefined ) color.setRGB( ...lightDef.color, LinearSRGBColorSpace );
 
 		const range = lightDef.range !== undefined ? lightDef.range : 0;
 
@@ -663,7 +665,7 @@ class GLTFMaterialsUnlitExtension {
 
 				const array = metallicRoughness.baseColorFactor;
 
-				materialParams.color.fromArray( array );
+				materialParams.color.setRGB( ...array, LinearSRGBColorSpace );
 				materialParams.opacity = array[ 3 ];
 
 			}
@@ -939,7 +941,7 @@ class GLTFMaterialsSheenExtension {
 
 		if ( extension.sheenColorFactor !== undefined ) {
 
-			materialParams.sheenColor.fromArray( extension.sheenColorFactor );
+			materialParams.sheenColor.setRGB( ...extension.sheenColorFactor, LinearSRGBColorSpace );
 
 		}
 
@@ -1077,7 +1079,7 @@ class GLTFMaterialsVolumeExtension {
 		materialParams.attenuationDistance = extension.attenuationDistance || Infinity;
 
 		const colorArray = extension.attenuationColor || [ 1, 1, 1 ];
-		materialParams.attenuationColor = new Color( colorArray[ 0 ], colorArray[ 1 ], colorArray[ 2 ] );
+		materialParams.attenuationColor = new Color().setRGB( ...colorArray, LinearSRGBColorSpace );
 
 		return Promise.all( pending );
 
@@ -1180,7 +1182,7 @@ class GLTFMaterialsSpecularExtension {
 		}
 
 		const colorArray = extension.specularColorFactor || [ 1, 1, 1 ];
-		materialParams.specularColor = new Color( colorArray[ 0 ], colorArray[ 1 ], colorArray[ 2 ] );
+		materialParams.specularColor = new Color().setRGB( ...colorArray, LinearSRGBColorSpace );
 
 		if ( extension.specularColorTexture !== undefined ) {
 
@@ -3386,7 +3388,7 @@ class GLTFParser {
 
 				const array = metallicRoughness.baseColorFactor;
 
-				materialParams.color.fromArray( array );
+				materialParams.color.setRGB( array[ 0 ], array[ 1 ], array[ 2 ], LinearSRGBColorSpace );
 				materialParams.opacity = array[ 3 ];
 
 			}
@@ -3478,7 +3480,7 @@ class GLTFParser {
 
 		if ( materialDef.emissiveFactor !== undefined && materialType !== MeshBasicMaterial ) {
 
-			materialParams.emissive = new Color().fromArray( materialDef.emissiveFactor );
+			materialParams.emissive = new Color().setRGB( ...materialDef.emissiveFactor, LinearSRGBColorSpace );
 
 		}
 
@@ -4559,6 +4561,12 @@ function addPrimitiveAttributes( geometry, primitiveDef, parser ) {
 
 	}
 
+	if ( ColorManagement.workingColorSpace !== LinearSRGBColorSpace && 'COLOR_0' in attributes ) {
+
+		console.warn( `THREE.GLTFLoader: Converting vertex colors from "srgb-linear" to "${ColorManagement.workingColorSpace}" not supported.` );
+
+	}
+
 	assignExtrasToUserData( geometry, primitiveDef );
 
 	computeBounds( geometry, primitiveDef, parser );

+ 128 - 77
examples/jsm/loaders/KTX2Loader.js

@@ -17,12 +17,15 @@ import {
 	CompressedCubeTexture,
 	Data3DTexture,
 	DataTexture,
+	DisplayP3ColorSpace,
 	FileLoader,
 	FloatType,
 	HalfFloatType,
 	NoColorSpace,
 	LinearFilter,
 	LinearMipmapLinearFilter,
+	LinearDisplayP3ColorSpace,
+	LinearSRGBColorSpace,
 	Loader,
 	RedFormat,
 	RGB_ETC1_Format,
@@ -30,6 +33,7 @@ import {
 	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,
@@ -59,6 +63,11 @@ import {
 	VK_FORMAT_R8G8_UNORM,
 	VK_FORMAT_R8G8B8A8_SRGB,
 	VK_FORMAT_R8G8B8A8_UNORM,
+	VK_FORMAT_ASTC_6x6_SRGB_BLOCK,
+	VK_FORMAT_ASTC_6x6_UNORM_BLOCK,
+	KHR_DF_PRIMARIES_UNSPECIFIED,
+	KHR_DF_PRIMARIES_BT709,
+	KHR_DF_PRIMARIES_DISPLAYP3
 } from '../libs/ktx-parse.module.js';
 import { ZSTDDecoder } from '../libs/zstddec.module.js';
 
@@ -254,7 +263,7 @@ class KTX2Loader extends Loader {
 
 	_createTextureFrom( transcodeResult, container ) {
 
-		const { faces, width, height, format, type, error, dfdTransferFn, dfdFlags } = transcodeResult;
+		const { faces, width, height, format, type, error, dfdFlags } = transcodeResult;
 
 		if ( type === 'error' ) return Promise.reject( error );
 
@@ -279,8 +288,7 @@ class KTX2Loader extends Loader {
 		texture.generateMipmaps = false;
 
 		texture.needsUpdate = true;
-		// TODO: Detect NoColorSpace vs. LinearSRGBColorSpace based on primaries.
-		texture.colorSpace = dfdTransferFn === KHR_DF_TRANSFER_SRGB ? SRGBColorSpace : NoColorSpace;
+		texture.colorSpace = parseColorSpace( container );
 		texture.premultiplyAlpha = !! ( dfdFlags & KHR_DF_FLAG_ALPHA_PREMULTIPLIED );
 
 		return texture;
@@ -298,33 +306,7 @@ class KTX2Loader extends Loader {
 
 		if ( container.vkFormat !== VK_FORMAT_UNDEFINED ) {
 
-			const mipmaps = [];
-			const pendings = [];
-
-			for ( let levelIndex = 0; levelIndex < container.levels.length; levelIndex ++ ) {
-
-				pendings.push( createDataTexture( container, levelIndex ).then( function ( dataTexture ) {
-
-					mipmaps[ levelIndex ] = dataTexture;
-
-				} ) );
-
-			}
-
-			await Promise.all( pendings );
-
-			const texture = mipmaps[ 0 ];
-			texture.mipmaps = mipmaps.map( dt => {
-
-				return {
-					data: dt.source.data,
-					width: dt.source.data.width,
-					height: dt.source.data.height,
-					depth: dt.source.data.depth
-				};
-
-			} );
-			return texture;
+			return createRawTexture( container );
 
 		}
 
@@ -426,9 +408,9 @@ KTX2Loader.BasisWorker = function () {
 
 					try {
 
-						const { faces, buffers, width, height, hasAlpha, format, dfdTransferFn, dfdFlags } = transcode( message.buffer );
+						const { faces, buffers, width, height, hasAlpha, format, dfdFlags } = transcode( message.buffer );
 
-						self.postMessage( { type: 'transcode', id: message.id, faces, width, height, hasAlpha, format, dfdTransferFn, dfdFlags }, buffers );
+						self.postMessage( { type: 'transcode', id: message.id, faces, width, height, hasAlpha, format, dfdFlags }, buffers );
 
 					} catch ( error ) {
 
@@ -491,7 +473,6 @@ KTX2Loader.BasisWorker = function () {
 		const levelCount = ktx2File.getLevels();
 		const faceCount = ktx2File.getFaces();
 		const hasAlpha = ktx2File.getHasAlpha();
-		const dfdTransferFn = ktx2File.getDFDTransferFunc();
 		const dfdFlags = ktx2File.getDFDFlags();
 
 		const { transcoderFormat, engineFormat } = getTranscoderFormat( basisFormat, width, height, hasAlpha );
@@ -575,7 +556,7 @@ KTX2Loader.BasisWorker = function () {
 
 		cleanup();
 
-		return { faces, buffers, width, height, hasAlpha, format: engineFormat, dfdTransferFn, dfdFlags };
+		return { faces, buffers, width, height, hasAlpha, format: engineFormat, dfdFlags };
 
 	}
 
@@ -730,7 +711,10 @@ KTX2Loader.BasisWorker = function () {
 };
 
 //
-// DataTexture and Data3DTexture parsing.
+// Parsing for non-Basis textures. These textures are may have supercompression
+// like Zstd, but they do not require transcoding.
+
+const UNCOMPRESSED_FORMATS = new Set( [ RGBAFormat, RGFormat, RedFormat ] );
 
 const FORMAT_MAP = {
 
@@ -749,6 +733,9 @@ const FORMAT_MAP = {
 	[ VK_FORMAT_R8_SRGB ]: RedFormat,
 	[ VK_FORMAT_R8_UNORM ]: RedFormat,
 
+	[ VK_FORMAT_ASTC_6x6_SRGB_BLOCK ]: RGBA_ASTC_6x6_Format,
+	[ VK_FORMAT_ASTC_6x6_UNORM_BLOCK ]: RGBA_ASTC_6x6_Format,
+
 };
 
 const TYPE_MAP = {
@@ -768,22 +755,14 @@ const TYPE_MAP = {
 	[ VK_FORMAT_R8_SRGB ]: UnsignedByteType,
 	[ VK_FORMAT_R8_UNORM ]: UnsignedByteType,
 
-};
-
-const COLOR_SPACE_MAP = {
-
-	[ VK_FORMAT_R8G8B8A8_SRGB ]: SRGBColorSpace,
-	[ VK_FORMAT_R8G8_SRGB ]: SRGBColorSpace,
-	[ VK_FORMAT_R8_SRGB ]: SRGBColorSpace,
+	[ VK_FORMAT_ASTC_6x6_SRGB_BLOCK ]: UnsignedByteType,
+	[ VK_FORMAT_ASTC_6x6_UNORM_BLOCK ]: UnsignedByteType,
 
 };
 
-async function createDataTexture( container, levelIndex = 0 ) {
+async function createRawTexture( container ) {
 
 	const { vkFormat } = container;
-	const pixelWidth = Math.max( 1, container.pixelWidth >> levelIndex );
-	const pixelHeight = Math.max( 1, container.pixelHeight >> levelIndex );
-	const pixelDepth = Math.max( 1, container.pixelDepth >> levelIndex );
 
 	if ( FORMAT_MAP[ vkFormat ] === undefined ) {
 
@@ -791,16 +770,11 @@ async function createDataTexture( container, levelIndex = 0 ) {
 
 	}
 
-	const level = container.levels[ levelIndex ];
-
-	let levelData;
-	let view;
-
-	if ( container.supercompressionScheme === KHR_SUPERCOMPRESSION_NONE ) {
+	//
 
-		levelData = level.levelData;
+	let zstd;
 
-	} else if ( container.supercompressionScheme === KHR_SUPERCOMPRESSION_ZSTD ) {
+	if ( container.supercompressionScheme === KHR_SUPERCOMPRESSION_ZSTD ) {
 
 		if ( ! _zstd ) {
 
@@ -814,49 +788,101 @@ async function createDataTexture( container, levelIndex = 0 ) {
 
 		}
 
-		levelData = ( await _zstd ).decode( level.levelData, level.uncompressedByteLength );
+		zstd = await _zstd;
 
-	} else {
+	}
 
-		throw new Error( 'THREE.KTX2Loader: Unsupported supercompressionScheme.' );
+	//
 
-	}
+	const mipmaps = [];
 
-	if ( TYPE_MAP[ vkFormat ] === FloatType ) {
 
-		view = new Float32Array(
+	for ( let levelIndex = 0; levelIndex < container.levels.length; levelIndex ++ ) {
 
-			levelData.buffer,
-			levelData.byteOffset,
-			levelData.byteLength / Float32Array.BYTES_PER_ELEMENT
+		const levelWidth = Math.max( 1, container.pixelWidth >> levelIndex );
+		const levelHeight = Math.max( 1, container.pixelHeight >> levelIndex );
+		const levelDepth = container.pixelDepth ? Math.max( 1, container.pixelDepth >> levelIndex ) : 0;
 
-		);
+		const level = container.levels[ levelIndex ];
 
-	} else if ( TYPE_MAP[ vkFormat ] === HalfFloatType ) {
+		let levelData;
 
-		view = new Uint16Array(
+		if ( container.supercompressionScheme === KHR_SUPERCOMPRESSION_NONE ) {
+
+			levelData = level.levelData;
+
+		} else if ( container.supercompressionScheme === KHR_SUPERCOMPRESSION_ZSTD ) {
+
+			levelData = zstd.decode( level.levelData, level.uncompressedByteLength );
+
+		} else {
+
+			throw new Error( 'THREE.KTX2Loader: Unsupported supercompressionScheme.' );
+
+		}
+
+		let data;
+
+		if ( TYPE_MAP[ vkFormat ] === FloatType ) {
+
+			data = new Float32Array(
+
+				levelData.buffer,
+				levelData.byteOffset,
+				levelData.byteLength / Float32Array.BYTES_PER_ELEMENT
+
+			);
 
-			levelData.buffer,
-			levelData.byteOffset,
-			levelData.byteLength / Uint16Array.BYTES_PER_ELEMENT
+		} else if ( TYPE_MAP[ vkFormat ] === HalfFloatType ) {
 
-		);
+			data = new Uint16Array(
+
+				levelData.buffer,
+				levelData.byteOffset,
+				levelData.byteLength / Uint16Array.BYTES_PER_ELEMENT
+
+			);
+
+		} else {
+
+			data = levelData;
+
+		}
+
+		mipmaps.push( {
+
+			data: data,
+			width: levelWidth,
+			height: levelHeight,
+			depth: levelDepth,
+
+		} );
+
+	}
+
+	let texture;
+
+	if ( UNCOMPRESSED_FORMATS.has( FORMAT_MAP[ vkFormat ] ) ) {
+
+		texture = container.pixelDepth === 0
+		? new DataTexture( mipmaps, container.pixelWidth, container.pixelHeight )
+		: new Data3DTexture( mipmaps, container.pixelWidth, container.pixelHeight, container.pixelDepth );
 
 	} else {
 
-		view = levelData;
+		if ( container.pixelDepth > 0 ) throw new Error( 'THREE.KTX2Loader: Unsupported pixelDepth.' );
+
+		texture = new CompressedTexture( mipmaps, container.pixelWidth, container.pixelHeight );
+
+
 
 	}
-	//
 
-	const texture = pixelDepth === 0
-		? new DataTexture( view, pixelWidth, pixelHeight )
-		: new Data3DTexture( view, pixelWidth, pixelHeight, pixelDepth );
+	texture.mipmaps = mipmaps;
 
 	texture.type = TYPE_MAP[ vkFormat ];
 	texture.format = FORMAT_MAP[ vkFormat ];
-	texture.colorSpace = COLOR_SPACE_MAP[ vkFormat ] || NoColorSpace;
-
+	texture.colorSpace = parseColorSpace( container );
 	texture.needsUpdate = true;
 
 	//
@@ -865,4 +891,29 @@ async function createDataTexture( container, levelIndex = 0 ) {
 
 }
 
+function parseColorSpace( container ) {
+
+	const dfd = container.dataFormatDescriptor[ 0 ];
+
+	if ( dfd.colorPrimaries === KHR_DF_PRIMARIES_BT709 ) {
+
+		return dfd.transferFunction === KHR_DF_TRANSFER_SRGB ? SRGBColorSpace : LinearSRGBColorSpace;
+
+	} else if ( dfd.colorPrimaries === KHR_DF_PRIMARIES_DISPLAYP3 ) {
+
+		return dfd.transferFunction === KHR_DF_TRANSFER_SRGB ? DisplayP3ColorSpace : LinearDisplayP3ColorSpace;
+
+	} else if ( dfd.colorPrimaries === KHR_DF_PRIMARIES_UNSPECIFIED ) {
+
+		return NoColorSpace;
+
+	} else {
+
+		console.warn( `THREE.KTX2Loader: Unsupported color primaries, "${ dfd.colorPrimaries }"` );
+		return NoColorSpace;
+
+	}
+
+}
+
 export { KTX2Loader };

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

@@ -393,7 +393,7 @@ UTIF.toRGBA = function ( out, type ) {
 			break;
 
 		default:
-			console.error( 'THREE.LogLuvLoader: Unsupported texture data type:', type );
+			throw new Error( 'THREE.LogLuvLoader: Unsupported texture data type: ' + type );
 
 	}
 
@@ -451,7 +451,7 @@ UTIF.toRGBA = function ( out, type ) {
 
 	} else {
 
-		console.log( 'Unsupported Photometric interpretation: ' + intp );
+		throw new Error( 'THREE.LogLuvLoader: Unsupported Photometric interpretation: ' + intp );
 
 	}
 

+ 10 - 7
examples/jsm/loaders/MMDLoader.js

@@ -27,6 +27,7 @@ import {
 	Skeleton,
 	SkinnedMesh,
 	SrcAlphaFactor,
+	SRGBColorSpace,
 	TextureLoader,
 	Uint16BufferAttribute,
 	Vector3,
@@ -1133,17 +1134,18 @@ class MaterialBuilder {
 				 * MMDToonMaterial doesn't have ambient. Set it to emissive instead.
 				 * It'll be too bright if material has map texture so using coef 0.2.
 				 */
-			params.diffuse = new Color().fromArray( material.diffuse );
+			params.diffuse = new Color().setRGB(
+				material.diffuse[ 0 ],
+				material.diffuse[ 1 ],
+				material.diffuse[ 2 ],
+				SRGBColorSpace
+			);
 			params.opacity = material.diffuse[ 3 ];
-			params.specular = new Color().fromArray( material.specular );
+			params.specular = new Color().setRGB( ...material.specular, SRGBColorSpace );
 			params.shininess = material.shininess;
-			params.emissive = new Color().fromArray( material.ambient );
+			params.emissive = new Color().setRGB( ...material.ambient, SRGBColorSpace );
 			params.transparent = params.opacity !== 1.0;
 
-			params.diffuse.convertSRGBToLinear();
-			params.specular.convertSRGBToLinear();
-			params.emissive.convertSRGBToLinear();
-
 			//
 
 			params.fog = true;
@@ -1452,6 +1454,7 @@ class MaterialBuilder {
 			t.flipY = false;
 			t.wrapS = RepeatWrapping;
 			t.wrapT = RepeatWrapping;
+			t.colorSpace = SRGBColorSpace;
 
 			for ( let i = 0; i < texture.readyCallbacks.length; i ++ ) {
 

+ 48 - 66
examples/jsm/loaders/RGBELoader.js

@@ -25,10 +25,6 @@ class RGBELoader extends DataTextureLoader {
 	parse( buffer ) {
 
 		const
-			/* return codes for rgbe routines */
-			//RGBE_RETURN_SUCCESS = 0,
-			RGBE_RETURN_FAILURE = - 1,
-
 			/* default error routine.  change this to change error handling */
 			rgbe_read_error = 1,
 			rgbe_write_error = 2,
@@ -38,19 +34,14 @@ class RGBELoader extends DataTextureLoader {
 
 				switch ( rgbe_error_code ) {
 
-					case rgbe_read_error: console.error( 'THREE.RGBELoader Read Error: ' + ( msg || '' ) );
-						break;
-					case rgbe_write_error: console.error( 'THREE.RGBELoader Write Error: ' + ( msg || '' ) );
-						break;
-					case rgbe_format_error: console.error( 'THREE.RGBELoader Bad File Format: ' + ( msg || '' ) );
-						break;
+					case rgbe_read_error: throw new Error( 'THREE.RGBELoader: Read Error: ' + ( msg || '' ) );
+					case rgbe_write_error: throw new Error( 'THREE.RGBELoader: Write Error: ' + ( msg || '' ) );
+					case rgbe_format_error: throw new Error( 'THREE.RGBELoader: Bad File Format: ' + ( msg || '' ) );
 					default:
-					case rgbe_memory_error: console.error( 'THREE.RGBELoader: Error: ' + ( msg || '' ) );
+					case rgbe_memory_error: throw new Error( 'THREE.RGBELoader: Memory Error: ' + ( msg || '' ) );
 
 				}
 
-				return RGBE_RETURN_FAILURE;
-
 			},
 
 			/* offsets to red, green, and blue components in a data (float) pixel */
@@ -138,14 +129,14 @@ class RGBELoader extends DataTextureLoader {
 
 				if ( buffer.pos >= buffer.byteLength || ! ( line = fgets( buffer ) ) ) {
 
-					return rgbe_error( rgbe_read_error, 'no header found' );
+					rgbe_error( rgbe_read_error, 'no header found' );
 
 				}
 
 				/* if you want to require the magic token then uncomment the next line */
 				if ( ! ( match = line.match( magic_token_re ) ) ) {
 
-					return rgbe_error( rgbe_format_error, 'bad initial token' );
+					rgbe_error( rgbe_format_error, 'bad initial token' );
 
 				}
 
@@ -199,13 +190,13 @@ class RGBELoader extends DataTextureLoader {
 
 				if ( ! ( header.valid & RGBE_VALID_FORMAT ) ) {
 
-					return rgbe_error( rgbe_format_error, 'missing format specifier' );
+					rgbe_error( rgbe_format_error, 'missing format specifier' );
 
 				}
 
 				if ( ! ( header.valid & RGBE_VALID_DIMENSIONS ) ) {
 
-					return rgbe_error( rgbe_format_error, 'missing image size specifier' );
+					rgbe_error( rgbe_format_error, 'missing image size specifier' );
 
 				}
 
@@ -231,7 +222,7 @@ class RGBELoader extends DataTextureLoader {
 
 				if ( scanline_width !== ( ( buffer[ 2 ] << 8 ) | buffer[ 3 ] ) ) {
 
-					return rgbe_error( rgbe_format_error, 'wrong scanline width' );
+					rgbe_error( rgbe_format_error, 'wrong scanline width' );
 
 				}
 
@@ -239,7 +230,7 @@ class RGBELoader extends DataTextureLoader {
 
 				if ( ! data_rgba.length ) {
 
-					return rgbe_error( rgbe_memory_error, 'unable to allocate buffer space' );
+					rgbe_error( rgbe_memory_error, 'unable to allocate buffer space' );
 
 				}
 
@@ -255,7 +246,7 @@ class RGBELoader extends DataTextureLoader {
 
 					if ( pos + 4 > buffer.byteLength ) {
 
-						return rgbe_error( rgbe_read_error );
+						rgbe_error( rgbe_read_error );
 
 					}
 
@@ -266,7 +257,7 @@ class RGBELoader extends DataTextureLoader {
 
 					if ( ( 2 != rgbeStart[ 0 ] ) || ( 2 != rgbeStart[ 1 ] ) || ( ( ( rgbeStart[ 2 ] << 8 ) | rgbeStart[ 3 ] ) != scanline_width ) ) {
 
-						return rgbe_error( rgbe_format_error, 'bad rgbe scanline format' );
+						rgbe_error( rgbe_format_error, 'bad rgbe scanline format' );
 
 					}
 
@@ -282,7 +273,7 @@ class RGBELoader extends DataTextureLoader {
 
 						if ( ( 0 === count ) || ( ptr + count > ptr_end ) ) {
 
-							return rgbe_error( rgbe_format_error, 'bad scanline data' );
+							rgbe_error( rgbe_format_error, 'bad scanline data' );
 
 						}
 
@@ -362,70 +353,61 @@ class RGBELoader extends DataTextureLoader {
 		byteArray.pos = 0;
 		const rgbe_header_info = RGBE_ReadHeader( byteArray );
 
-		if ( RGBE_RETURN_FAILURE !== rgbe_header_info ) {
-
-			const w = rgbe_header_info.width,
-				h = rgbe_header_info.height,
-				image_rgba_data = RGBE_ReadPixels_RLE( byteArray.subarray( byteArray.pos ), w, h );
-
-			if ( RGBE_RETURN_FAILURE !== image_rgba_data ) {
-
-				let data, type;
-				let numElements;
-
-				switch ( this.type ) {
-
-					case FloatType:
+		const w = rgbe_header_info.width,
+			h = rgbe_header_info.height,
+			image_rgba_data = RGBE_ReadPixels_RLE( byteArray.subarray( byteArray.pos ), w, h );
 
-						numElements = image_rgba_data.length / 4;
-						const floatArray = new Float32Array( numElements * 4 );
 
-						for ( let j = 0; j < numElements; j ++ ) {
+		let data, type;
+		let numElements;
 
-							RGBEByteToRGBFloat( image_rgba_data, j * 4, floatArray, j * 4 );
+		switch ( this.type ) {
 
-						}
+			case FloatType:
 
-						data = floatArray;
-						type = FloatType;
-						break;
+				numElements = image_rgba_data.length / 4;
+				const floatArray = new Float32Array( numElements * 4 );
 
-					case HalfFloatType:
+				for ( let j = 0; j < numElements; j ++ ) {
 
-						numElements = image_rgba_data.length / 4;
-						const halfArray = new Uint16Array( numElements * 4 );
+					RGBEByteToRGBFloat( image_rgba_data, j * 4, floatArray, j * 4 );
 
-						for ( let j = 0; j < numElements; j ++ ) {
+				}
 
-							RGBEByteToRGBHalf( image_rgba_data, j * 4, halfArray, j * 4 );
+				data = floatArray;
+				type = FloatType;
+				break;
 
-						}
+			case HalfFloatType:
 
-						data = halfArray;
-						type = HalfFloatType;
-						break;
+				numElements = image_rgba_data.length / 4;
+				const halfArray = new Uint16Array( numElements * 4 );
 
-					default:
+				for ( let j = 0; j < numElements; j ++ ) {
 
-						console.error( 'THREE.RGBELoader: unsupported type: ', this.type );
-						break;
+					RGBEByteToRGBHalf( image_rgba_data, j * 4, halfArray, j * 4 );
 
 				}
 
-				return {
-					width: w, height: h,
-					data: data,
-					header: rgbe_header_info.string,
-					gamma: rgbe_header_info.gamma,
-					exposure: rgbe_header_info.exposure,
-					type: type
-				};
+				data = halfArray;
+				type = HalfFloatType;
+				break;
 
-			}
+			default:
+
+				throw new Error( 'THREE.RGBELoader: unsupported type: ', this.type );
+				break;
 
 		}
 
-		return null;
+		return {
+			width: w, height: h,
+			data: data,
+			header: rgbe_header_info.string,
+			gamma: rgbe_header_info.gamma,
+			exposure: rgbe_header_info.exposure,
+			type: type
+		};
 
 	}
 

+ 7 - 0
examples/jsm/loaders/STLLoader.js

@@ -274,6 +274,7 @@ class STLLoader extends Loader {
 			const geometry = new BufferGeometry();
 			const patternSolid = /solid([\s\S]*?)endsolid/g;
 			const patternFace = /facet([\s\S]*?)endfacet/g;
+			const patternName = /solid\s(.+)/;
 			let faceCounter = 0;
 
 			const patternFloat = /[\s]+([+-]?(?:\d*)(?:\.\d*)?(?:[eE][+-]?\d+)?)/.source;
@@ -282,6 +283,7 @@ class STLLoader extends Loader {
 
 			const vertices = [];
 			const normals = [];
+			const groupNames = [];
 
 			const normal = new Vector3();
 
@@ -297,6 +299,9 @@ class STLLoader extends Loader {
 
 				const solid = result[ 0 ];
 
+				const name = ( result = patternName.exec( solid ) ) !== null ? result[ 1 ] : '';
+				groupNames.push( name );
+
 				while ( ( result = patternFace.exec( solid ) ) !== null ) {
 
 					let vertexCountPerFace = 0;
@@ -345,6 +350,8 @@ class STLLoader extends Loader {
 				const start = startVertex;
 				const count = endVertex - startVertex;
 
+				geometry.userData.groupNames = groupNames;
+
 				geometry.addGroup( start, count, groupCount );
 				groupCount ++;
 

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

@@ -30,6 +30,7 @@ export { default as TempNode } from './core/TempNode.js';
 export { default as UniformNode, uniform } from './core/UniformNode.js';
 export { default as VarNode, temp } from './core/VarNode.js';
 export { default as VaryingNode, varying } from './core/VaryingNode.js';
+export { default as OutputStructNode, outputStruct } from './core/OutputStructNode.js';
 
 import * as NodeUtils from './core/NodeUtils.js';
 export { NodeUtils };
@@ -38,6 +39,7 @@ export { NodeUtils };
 export { default as MathNode, EPSILON, INFINITY, radians, degrees, exp, exp2, log, log2, sqrt, inverseSqrt, floor, ceil, normalize, fract, sin, cos, tan, asin, acos, atan, abs, sign, length, negate, oneMinus, dFdx, dFdy, round, reciprocal, trunc, fwidth, atan2, min, max, mod, step, reflect, distance, difference, dot, cross, pow, pow2, pow3, pow4, transformDirection, mix, clamp, saturate, refract, smoothstep, faceForward } from './math/MathNode.js';
 export { default as OperatorNode, add, sub, mul, div, remainder, equal, assign, lessThan, greaterThan, lessThanEqual, greaterThanEqual, and, or, xor, bitAnd, bitOr, bitXor, shiftLeft, shiftRight } from './math/OperatorNode.js';
 export { default as CondNode, cond } from './math/CondNode.js';
+export { default as HashNode, hash } from './math/HashNode.js';
 
 // utils
 export { default as ArrayElementNode } from './utils/ArrayElementNode.js';
@@ -86,6 +88,7 @@ export { default as SceneNode, backgroundBlurriness, backgroundIntensity } from
 export { default as StorageBufferNode, storage } from './accessors/StorageBufferNode.js';
 export { default as TangentNode, tangentGeometry, tangentLocal, tangentView, tangentWorld, transformedTangentView, transformedTangentWorld } from './accessors/TangentNode.js';
 export { default as TextureNode, texture, /*textureLevel,*/ sampler } from './accessors/TextureNode.js';
+export { default as TextureStoreNode, textureStore } from './accessors/TextureStoreNode.js';
 export { default as UVNode, uv } from './accessors/UVNode.js';
 export { default as UserDataNode, userData } from './accessors/UserDataNode.js';
 

+ 28 - 2
examples/jsm/nodes/accessors/BufferAttributeNode.js

@@ -1,12 +1,12 @@
 import InputNode from '../core/InputNode.js';
 import { addNodeClass } from '../core/Node.js';
 import { varying } from '../core/VaryingNode.js';
-import { nodeObject } from '../shadernode/ShaderNode.js';
+import { nodeObject, addNodeElement } from '../shadernode/ShaderNode.js';
 import { InterleavedBufferAttribute, InterleavedBuffer, StaticDrawUsage, DynamicDrawUsage } from 'three';
 
 class BufferAttributeNode extends InputNode {
 
-	constructor( value, bufferType, bufferStride = 0, bufferOffset = 0 ) {
+	constructor( value, bufferType = null, bufferStride = 0, bufferOffset = 0 ) {
 
 		super( value, bufferType );
 
@@ -19,10 +19,34 @@ class BufferAttributeNode extends InputNode {
 		this.usage = StaticDrawUsage;
 		this.instanced = false;
 
+		this.attribute = null;
+
+		if ( value && value.isBufferAttribute === true ) {
+
+			this.attribute = value;
+			this.usage = value.usage;
+			this.instanced = value.isInstancedBufferAttribute;
+
+		}
+
+	}
+
+	getNodeType( builder ) {
+
+		if ( this.bufferType === null ) {
+
+			this.bufferType = builder.getTypeFromAttribute( this.attribute );
+
+		}
+
+		return this.bufferType;
+
 	}
 
 	construct( builder ) {
 
+		if ( this.attribute !== null ) return;
+
 		const type = this.getNodeType( builder );
 		const array = this.value;
 		const itemSize = builder.getTypeLength( type );
@@ -96,4 +120,6 @@ export const dynamicBufferAttribute = ( array, type, stride, offset ) => bufferA
 export const instancedBufferAttribute = ( array, type, stride, offset ) => bufferAttribute( array, type, stride, offset ).setInstanced( true );
 export const instancedDynamicBufferAttribute = ( array, type, stride, offset ) => dynamicBufferAttribute( array, type, stride, offset ).setInstanced( true );
 
+addNodeElement( 'toAttribute', ( bufferNode ) => bufferAttribute( bufferNode.value ) );
+
 addNodeClass( BufferAttributeNode );

+ 18 - 3
examples/jsm/nodes/accessors/CubeTextureNode.js

@@ -2,6 +2,8 @@ import TextureNode from './TextureNode.js';
 import UniformNode from '../core/UniformNode.js';
 import { reflectVector } from './ReflectVectorNode.js';
 import { addNodeClass } from '../core/Node.js';
+import { colorSpaceToLinear } from '../display/ColorSpaceNode.js';
+import { expression } from '../code/ExpressionNode.js';
 import { addNodeElement, nodeProxy, vec3 } from '../shadernode/ShaderNode.js';
 
 class CubeTextureNode extends TextureNode {
@@ -52,6 +54,7 @@ class CubeTextureNode extends TextureNode {
 
 		} else {
 
+			const nodeType = this.getNodeType( builder );
 			const nodeData = builder.getDataFromNode( this );
 
 			let propertyName = nodeData.propertyName;
@@ -81,12 +84,24 @@ class CubeTextureNode extends TextureNode {
 
 				builder.addLineFlowCode( `${propertyName} = ${snippet}` );
 
-				nodeData.snippet = snippet;
-				nodeData.propertyName = propertyName;
+				if ( builder.context.tempWrite !== false ) {
+
+					nodeData.snippet = snippet;
+					nodeData.propertyName = propertyName;
+
+				}
+
+			}
+
+			let snippet = propertyName;
+
+			if ( builder.needsColorSpaceToLinear( this.value ) ) {
+
+				snippet = colorSpaceToLinear( expression( snippet, nodeType ), this.value.colorSpace ).construct( builder ).build( builder, nodeType );
 
 			}
 
-			return builder.format( propertyName, 'vec4', output );
+			return builder.format( snippet, 'vec4', output );
 
 		}
 

+ 2 - 4
examples/jsm/nodes/accessors/ExtendedMaterialNode.js

@@ -1,5 +1,3 @@
-// @TODO: Is this needed? Can it be moved in MaterialNode?
-
 import MaterialNode from './MaterialNode.js';
 import { materialReference } from './MaterialReferenceNode.js';
 import { normalView } from './NormalNode.js';
@@ -42,7 +40,7 @@ class ExtendedMaterialNode extends MaterialNode {
 
 			if ( material.normalMap ) {
 
-				node = normalMap( this.getTexture( 'normalMap' ), materialReference( 'normalScale', 'vec2' ) );
+				node = normalMap( this.getTexture( builder, 'normalMap' ), materialReference( 'normalScale', 'vec2' ) );
 
 			} else if ( material.bumpMap ) {
 
@@ -56,7 +54,7 @@ class ExtendedMaterialNode extends MaterialNode {
 
 		} else if ( scope === ExtendedMaterialNode.CLEARCOAT_NORMAL ) {
 
-			node = material.clearcoatNormalMap ? normalMap( this.getTexture( 'clearcoatNormalMap' ), materialReference( 'clearcoatNormalScale', 'vec2' ) ) : normalView;
+			node = material.clearcoatNormalMap ? normalMap( this.getTexture( builder, 'clearcoatNormalMap' ), materialReference( 'clearcoatNormalScale', 'vec2' ) ) : normalView;
 
 		}
 

+ 31 - 0
examples/jsm/nodes/accessors/LineMaterialNode.js

@@ -0,0 +1,31 @@
+import MaterialNode from './MaterialNode.js';
+import { addNodeClass } from '../core/Node.js';
+import { nodeImmutable } from '../shadernode/ShaderNode.js';
+
+class LineMaterialNode extends MaterialNode {
+
+	constructor( scope ) {
+
+		super( scope );
+
+	}
+
+	construct( builder ) {
+
+		return this.getFloat( builder, this.scope );
+
+	}
+
+}
+
+LineMaterialNode.SCALE = 'scale';
+LineMaterialNode.DASH_SIZE = 'dashSize';
+LineMaterialNode.GAP_SIZE = 'gapSize';
+
+export default LineMaterialNode;
+
+export const materialLineScale = nodeImmutable( LineMaterialNode, LineMaterialNode.SCALE );
+export const materialLineDashSize = nodeImmutable( LineMaterialNode, LineMaterialNode.DASH_SIZE );
+export const materialLineGapSize = nodeImmutable( LineMaterialNode, LineMaterialNode.GAP_SIZE );
+
+addNodeClass( LineMaterialNode );

+ 55 - 33
examples/jsm/nodes/accessors/MaterialNode.js

@@ -3,6 +3,8 @@ import { reference } from './ReferenceNode.js';
 import { materialReference } from './MaterialReferenceNode.js';
 import { nodeImmutable, float } from '../shadernode/ShaderNode.js';
 
+const cache = new WeakMap();
+
 class MaterialNode extends Node {
 
 	constructor( scope ) {
@@ -13,29 +15,49 @@ class MaterialNode extends Node {
 
 	}
 
-	getFloat( property ) {
+	getCache( builder, property, type ) {
 
-		//@TODO: Check if it can be cached by property name.
+		const material = builder.context.material;
 
-		return materialReference( property, 'float' );
+		let cacheMaterial = cache.get( material );
 
-	}
+		if ( cacheMaterial === undefined ) {
+
+			cacheMaterial = {};
+
+			cache.set( material, cacheMaterial );
+
+		}
+
+		let node = cacheMaterial[ property ];
+
+		if ( node === undefined ) {
 
-	getColor( property ) {
+			node = materialReference( property, type );
 
-		//@TODO: Check if it can be cached by property name.
+			cacheMaterial[ property ] = node;
 
-		return materialReference( property, 'color' );
+		}
+
+		return node;
 
 	}
 
-	getTexture( property ) {
+	getFloat( builder, property ) {
 
-		//@TODO: Check if it can be cached by property name.
+		return this.getCache( builder, property, 'float' );
+
+	}
+
+	getColor( builder, property ) {
+
+		return this.getCache( builder, property, 'color' );
+
+	}
 
-		const textureRefNode = materialReference( property, 'texture' );
+	getTexture( builder, property ) {
 
-		return textureRefNode;
+		return this.getCache( builder, property, 'texture' );
 
 	}
 
@@ -48,19 +70,19 @@ class MaterialNode extends Node {
 
 		if ( scope === MaterialNode.ALPHA_TEST || scope === MaterialNode.SHININESS || scope === MaterialNode.REFLECTIVITY || scope === MaterialNode.ROTATION || scope === MaterialNode.IRIDESCENCE || scope === MaterialNode.IRIDESCENCE_IOR ) {
 
-			node = this.getFloat( scope );
+			node = this.getFloat( builder, scope );
 
 		} else if ( scope === MaterialNode.SPECULAR_COLOR ) {
 
-			node = this.getColor( 'specular' );
+			node = this.getColor( builder, 'specular' );
 
 		} else if ( scope === MaterialNode.COLOR ) {
 
-			const colorNode = this.getColor( 'color' );
+			const colorNode = this.getColor( builder, 'color' );
 
 			if ( material.map && material.map.isTexture === true ) {
 
-				node = colorNode.mul( this.getTexture( 'map' ) );
+				node = colorNode.mul( this.getTexture( builder, 'map' ) );
 
 			} else {
 
@@ -70,11 +92,11 @@ class MaterialNode extends Node {
 
 		} else if ( scope === MaterialNode.OPACITY ) {
 
-			const opacityNode = this.getFloat( 'opacity' );
+			const opacityNode = this.getFloat( builder, 'opacity' );
 
 			if ( material.alphaMap && material.alphaMap.isTexture === true ) {
 
-				node = opacityNode.mul( this.getTexture( 'alphaMap' ) );
+				node = opacityNode.mul( this.getTexture( builder, 'alphaMap' ) );
 
 			} else {
 
@@ -86,7 +108,7 @@ class MaterialNode extends Node {
 
 			if ( material.specularMap && material.specularMap.isTexture === true ) {
 
-				node = this.getTexture( 'specularMap' ).r;
+				node = this.getTexture( builder, 'specularMap' ).r;
 
 			} else {
 
@@ -96,11 +118,11 @@ class MaterialNode extends Node {
 
 		} else if ( scope === MaterialNode.ROUGHNESS ) {
 
-			const roughnessNode = this.getFloat( 'roughness' );
+			const roughnessNode = this.getFloat( builder, 'roughness' );
 
 			if ( material.roughnessMap && material.roughnessMap.isTexture === true ) {
 
-				node = roughnessNode.mul( this.getTexture( 'roughnessMap' ).g );
+				node = roughnessNode.mul( this.getTexture( builder, 'roughnessMap' ).g );
 
 			} else {
 
@@ -110,11 +132,11 @@ class MaterialNode extends Node {
 
 		} else if ( scope === MaterialNode.METALNESS ) {
 
-			const metalnessNode = this.getFloat( 'metalness' );
+			const metalnessNode = this.getFloat( builder, 'metalness' );
 
 			if ( material.metalnessMap && material.metalnessMap.isTexture === true ) {
 
-				node = metalnessNode.mul( this.getTexture( 'metalnessMap' ).b );
+				node = metalnessNode.mul( this.getTexture( builder, 'metalnessMap' ).b );
 
 			} else {
 
@@ -124,11 +146,11 @@ class MaterialNode extends Node {
 
 		} else if ( scope === MaterialNode.EMISSIVE ) {
 
-			const emissiveNode = this.getColor( 'emissive' );
+			const emissiveNode = this.getColor( builder, 'emissive' );
 
 			if ( material.emissiveMap && material.emissiveMap.isTexture === true ) {
 
-				node = emissiveNode.mul( this.getTexture( 'emissiveMap' ) );
+				node = emissiveNode.mul( this.getTexture( builder, 'emissiveMap' ) );
 
 			} else {
 
@@ -138,11 +160,11 @@ class MaterialNode extends Node {
 
 		} else if ( scope === MaterialNode.CLEARCOAT ) {
 
-			const clearcoatNode = this.getFloat( 'clearcoat' );
+			const clearcoatNode = this.getFloat( builder, 'clearcoat' );
 
 			if ( material.clearcoatMap && material.clearcoatMap.isTexture === true ) {
 
-				node = clearcoatNode.mul( this.getTexture( 'clearcoatMap' ).r );
+				node = clearcoatNode.mul( this.getTexture( builder, 'clearcoatMap' ).r );
 
 			} else {
 
@@ -152,11 +174,11 @@ class MaterialNode extends Node {
 
 		} else if ( scope === MaterialNode.CLEARCOAT_ROUGHNESS ) {
 
-			const clearcoatRoughnessNode = this.getFloat( 'clearcoatRoughness' );
+			const clearcoatRoughnessNode = this.getFloat( builder, 'clearcoatRoughness' );
 
 			if ( material.clearcoatRoughnessMap && material.clearcoatRoughnessMap.isTexture === true ) {
 
-				node = clearcoatRoughnessNode.mul( this.getTexture( 'clearcoatRoughnessMap' ).r );
+				node = clearcoatRoughnessNode.mul( this.getTexture( builder, 'clearcoatRoughnessMap' ).r );
 
 			} else {
 
@@ -166,11 +188,11 @@ class MaterialNode extends Node {
 
 		} else if ( scope === MaterialNode.SHEEN ) {
 
-			const sheenNode = this.getColor( 'sheenColor' ).mul( this.getFloat( 'sheen' ) ); // Move this mul() to CPU
+			const sheenNode = this.getColor( builder, 'sheenColor' ).mul( this.getFloat( builder, 'sheen' ) ); // Move this mul() to CPU
 
 			if ( material.sheenColorMap && material.sheenColorMap.isTexture === true ) {
 
-				node = sheenNode.mul( this.getTexture( 'sheenColorMap' ).rgb );
+				node = sheenNode.mul( this.getTexture( builder, 'sheenColorMap' ).rgb );
 
 			} else {
 
@@ -180,11 +202,11 @@ class MaterialNode extends Node {
 
 		} else if ( scope === MaterialNode.SHEEN_ROUGHNESS ) {
 
-			const sheenRoughnessNode = this.getFloat( 'sheenRoughness' );
+			const sheenRoughnessNode = this.getFloat( builder, 'sheenRoughness' );
 
 			if ( material.sheenRoughnessMap && material.sheenRoughnessMap.isTexture === true ) {
 
-				node = sheenRoughnessNode.mul( this.getTexture( 'sheenRoughnessMap' ).a );
+				node = sheenRoughnessNode.mul( this.getTexture( builder, 'sheenRoughnessMap' ).a );
 
 			} else {
 
@@ -202,7 +224,7 @@ class MaterialNode extends Node {
 
 				const iridescenceThicknessMinimum = reference( 0, 'float', material.iridescenceThicknessRange );
 
-				node = iridescenceThicknessMaximum.sub( iridescenceThicknessMinimum ).mul( this.getTexture( 'iridescenceThicknessMap' ).g ).add( iridescenceThicknessMinimum );
+				node = iridescenceThicknessMaximum.sub( iridescenceThicknessMinimum ).mul( this.getTexture( builder, 'iridescenceThicknessMap' ).g ).add( iridescenceThicknessMinimum );
 
 			} else {
 

+ 3 - 0
examples/jsm/nodes/accessors/MaterialReferenceNode.js

@@ -1,4 +1,5 @@
 import ReferenceNode from './ReferenceNode.js';
+import { NodeUpdateType } from '../core/constants.js';
 import { addNodeClass } from '../core/Node.js';
 import { nodeObject } from '../shadernode/ShaderNode.js';
 
@@ -10,6 +11,8 @@ class MaterialReferenceNode extends ReferenceNode {
 
 		this.material = material;
 
+		this.updateType = NodeUpdateType.RENDER;
+
 	}
 
 	construct( builder ) {

+ 2 - 2
examples/jsm/nodes/accessors/Object3DNode.js

@@ -1,6 +1,6 @@
 import Node, { addNodeClass } from '../core/Node.js';
 import { NodeUpdateType } from '../core/constants.js';
-import { uniform } from '../core/UniformNode.js';
+import UniformNode from '../core/UniformNode.js';
 import { nodeProxy } from '../shadernode/ShaderNode.js';
 
 import { Vector3 } from 'three';
@@ -16,7 +16,7 @@ class Object3DNode extends Node {
 
 		this.updateType = NodeUpdateType.OBJECT;
 
-		this._uniformNode = uniform( null );
+		this._uniformNode = new UniformNode( null );
 
 	}
 

+ 6 - 2
examples/jsm/nodes/accessors/TextureNode.js

@@ -168,8 +168,12 @@ class TextureNode extends UniformNode {
 
 				builder.addLineFlowCode( `${propertyName} = ${snippet}` );
 
-				nodeData.snippet = snippet;
-				nodeData.propertyName = propertyName;
+				if ( builder.context.tempWrite !== false ) {
+
+					nodeData.snippet = snippet;
+					nodeData.propertyName = propertyName;
+
+				}
 
 			}
 

+ 29 - 0
examples/jsm/nodes/accessors/TextureStoreNode.js

@@ -0,0 +1,29 @@
+import { addNodeClass } from '../core/Node.js';
+import TextureNode from './TextureNode.js';
+import { nodeProxy } from '../shadernode/ShaderNode.js';
+
+class TextureStoreNode extends TextureNode {
+
+	constructor( value, uvNode, storeNode = null ) {
+
+		super( value, uvNode );
+
+		this.storeNode = storeNode;
+
+		this.isStoreTextureNode = true;
+
+	}
+
+	getNodeType( /*builder*/ ) {
+
+		return 'void';
+
+	}
+
+}
+
+export default TextureStoreNode;
+
+export const textureStore = nodeProxy( TextureStoreNode );
+
+addNodeClass( TextureStoreNode );

+ 2 - 2
examples/jsm/nodes/core/AttributeNode.js

@@ -20,12 +20,12 @@ class AttributeNode extends Node {
 
 	getNodeType( builder ) {
 
-		const attributeName = this.getAttributeName( builder );
-
 		let nodeType = super.getNodeType( builder );
 
 		if ( nodeType === null ) {
 
+			const attributeName = this.getAttributeName( builder );
+
 			if ( builder.hasGeometryAttribute( attributeName ) ) {
 
 				const attribute = builder.geometry.getAttribute( attributeName );

+ 17 - 1
examples/jsm/nodes/core/Node.js

@@ -32,6 +32,14 @@ class Node extends EventDispatcher {
 
 	}
 
+	getSelf() {
+
+		// Returns non-node object.
+
+		return this.self || this;
+
+	}
+
 	isGlobal( /*builder*/ ) {
 
 		return false;
@@ -97,7 +105,15 @@ class Node extends EventDispatcher {
 
 	}
 
-	getNodeType( /*builder*/ ) {
+	getNodeType( builder ) {
+
+		const nodeProperties = builder.getNodeProperties( this );
+
+		if ( nodeProperties.outputNode ) {
+
+			return nodeProperties.outputNode.getNodeType( builder );
+
+		}
 
 		return this.nodeType;
 

+ 94 - 12
examples/jsm/nodes/core/NodeBuilder.js

@@ -8,11 +8,18 @@ import NodeCache from './NodeCache.js';
 import { createNodeMaterialFromType } from '../materials/NodeMaterial.js';
 import { NodeUpdateType, defaultBuildStages, shaderStages } from './constants.js';
 
-import { REVISION, NoColorSpace, LinearEncoding, sRGBEncoding, SRGBColorSpace, Color, Vector2, Vector3, Vector4, Float16BufferAttribute } from 'three';
+import {
+	FloatNodeUniform, Vector2NodeUniform, Vector3NodeUniform, Vector4NodeUniform,
+	ColorNodeUniform, Matrix3NodeUniform, Matrix4NodeUniform
+} from '../../renderers/common/nodes/NodeUniform.js';
+
+import { REVISION, RenderTarget, NoColorSpace, LinearEncoding, sRGBEncoding, SRGBColorSpace, Color, Vector2, Vector3, Vector4, Float16BufferAttribute } from 'three';
 
 import { stack } from './StackNode.js';
 import { maxMipLevel } from '../utils/MaxMipLevelNode.js';
 
+import CubeRenderTarget from '../../renderers/common/CubeRenderTarget.js';
+
 const typeFromLength = new Map( [
 	[ 2, 'vec2' ],
 	[ 3, 'vec3' ],
@@ -69,6 +76,7 @@ class NodeBuilder {
 		this.flowNodes = { vertex: [], fragment: [], compute: [] };
 		this.flowCode = { vertex: '', fragment: '', compute: [] };
 		this.uniforms = { vertex: [], fragment: [], compute: [], index: 0 };
+		this.structs = { vertex: [], fragment: [], compute: [], index: 0 };
 		this.codes = { vertex: [], fragment: [], compute: [] };
 		this.bindings = { vertex: [], fragment: [], compute: [] };
 		this.bindingsOffset = { vertex: 0, fragment: 0, compute: 0 };
@@ -98,12 +106,38 @@ class NodeBuilder {
 
 	}
 
+	getRenderTarget( width, height, options ) {
+
+		return new RenderTarget( width, height, options );
+
+	}
+
+	getCubeRenderTarget( size, options ) {
+
+		return new CubeRenderTarget( size, options );
+
+	}
+
 	includes( node ) {
 
 		return this.nodes.includes( node );
 
 	}
 
+	createBindings() {
+
+		const bindingsArray = [];
+
+		for ( const binding of this.getBindings() ) {
+
+			bindingsArray.push( binding.clone() );
+
+		}
+
+		return bindingsArray;
+
+	}
+
 	getBindings() {
 
 		let bindingsArray = this.bindingsArray;
@@ -128,14 +162,26 @@ class NodeBuilder {
 
 	addNode( node ) {
 
-		if ( this.nodes.indexOf( node ) === - 1 ) {
+		if ( this.nodes.includes( node ) === false ) {
+
+			this.nodes.push( node );
+
+			this.setHashNode( node, node.getHash( this ) );
+
+		}
+
+	}
+
+	buildUpdateNodes() {
+
+		for ( const node of this.nodes ) {
 
 			const updateType = node.getUpdateType();
 			const updateBeforeType = node.getUpdateBeforeType();
 
 			if ( updateType !== NodeUpdateType.NONE ) {
 
-				this.updateNodes.push( node );
+				this.updateNodes.push( node.getSelf() );
 
 			}
 
@@ -145,10 +191,6 @@ class NodeBuilder {
 
 			}
 
-			this.nodes.push( node );
-
-			this.setHashNode( node, node.getHash( this ) );
-
 		}
 
 	}
@@ -331,6 +373,8 @@ class NodeBuilder {
 
 	getType( type ) {
 
+		if ( type === 'color' ) return 'vec3';
+
 		return type;
 
 	}
@@ -561,17 +605,19 @@ class NodeBuilder {
 
 		if ( nodeData === undefined ) {
 
-			nodeData = { vertex: {}, fragment: {}, compute: {} };
+			nodeData = {};
 
 			cache.setNodeData( node, nodeData );
 
 		}
 
-		return shaderStage !== null ? nodeData[ shaderStage ] : nodeData;
+		if ( nodeData[ shaderStage ] === undefined ) nodeData[ shaderStage ] = {};
+
+		return nodeData[ shaderStage ];
 
 	}
 
-	getNodeProperties( node, shaderStage = this.shaderStage ) {
+	getNodeProperties( node, shaderStage = 'any' ) {
 
 		const nodeData = this.getDataFromNode( node, shaderStage );
 
@@ -601,6 +647,27 @@ class NodeBuilder {
 
 	}
 
+	getStructTypeFromNode( node, shaderStage = this.shaderStage, name = null ) {
+
+		const nodeData = this.getDataFromNode( node, shaderStage );
+
+		let nodeStruct = nodeData.structType;
+
+		if ( nodeStruct === undefined ) {
+
+			const index = this.structs.index ++;
+
+			node.name = `StructType${index}`;
+			this.structs[ shaderStage ].push( node );
+
+			nodeData.structType = node;
+
+		}
+
+		return node;
+
+	}
+
 	getUniformFromNode( node, type, shaderStage = this.shaderStage, name = null ) {
 
 		const nodeData = this.getDataFromNode( node, shaderStage );
@@ -648,7 +715,7 @@ class NodeBuilder {
 
 	getVaryingFromNode( node, type ) {
 
-		const nodeData = this.getDataFromNode( node, null );
+		const nodeData = this.getDataFromNode( node, 'any' );
 
 		let nodeVarying = nodeData.varying;
 
@@ -812,7 +879,7 @@ class NodeBuilder {
 
 	getVar( type, name ) {
 
-		return `${type} ${name}`;
+		return `${ this.getType( type ) } ${ name }`;
 
 	}
 
@@ -936,11 +1003,26 @@ class NodeBuilder {
 		// stage 4: build code for a specific output
 
 		this.buildCode();
+		this.buildUpdateNodes();
 
 		return this;
 
 	}
 
+	getNodeUniform( uniformNode, type ) {
+
+		if ( type === 'float' ) return new FloatNodeUniform( uniformNode );
+		if ( type === 'vec2' ) return new Vector2NodeUniform( uniformNode );
+		if ( type === 'vec3' ) return new Vector3NodeUniform( uniformNode );
+		if ( type === 'vec4' ) return new Vector4NodeUniform( uniformNode );
+		if ( type === 'color' ) return new ColorNodeUniform( uniformNode );
+		if ( type === 'mat3' ) return new Matrix3NodeUniform( uniformNode );
+		if ( type === 'mat4' ) return new Matrix4NodeUniform( uniformNode );
+
+		throw new Error( `Uniform "${type}" not declared.` );
+
+	}
+
 	createNodeMaterial( type ) {
 
 		return createNodeMaterialFromType( type );

+ 1 - 1
examples/jsm/nodes/core/NodeUniform.js

@@ -6,7 +6,7 @@ class NodeUniform {
 
 		this.name = name;
 		this.type = type;
-		this.node = node;
+		this.node = node.getSelf();
 		this.needsUpdate = needsUpdate;
 
 	}

+ 58 - 0
examples/jsm/nodes/core/OutputStructNode.js

@@ -0,0 +1,58 @@
+import Node, { addNodeClass } from './Node.js';
+import StructTypeNode from './StructTypeNode.js';
+import { nodeProxy } from '../shadernode/ShaderNode.js';
+
+class OutputStructNode extends Node {
+
+	constructor( ...members ) {
+
+		super();
+
+		this.isOutputStructNode = true;
+		this.members = members;
+
+	}
+
+	construct( builder ) {
+
+		super.construct( builder );
+
+		const members = this.members;
+		const types = [];
+
+		for ( let i = 0; i < members.length; i++ ) {
+
+			types.push( members[ i ].getNodeType( builder ) );
+
+		}
+
+		this.nodeType = builder.getStructTypeFromNode( new StructTypeNode( types ) ).name;
+
+	}
+
+	generate( builder, output ) {
+
+		const nodeVar = builder.getVarFromNode( this, this.nodeType );
+		const propertyName = builder.getPropertyName( nodeVar );
+
+		const members = this.members;
+
+		for ( let i = 0; i < members.length; i++ ) {
+
+			const snippet = members[ i ].build( builder, output );
+
+			builder.addLineFlowCode( `${propertyName}.m${i} = ${snippet}` );
+
+		}
+
+		return propertyName;
+
+	}
+
+}
+
+export default OutputStructNode;
+
+export const outputStruct = nodeProxy( OutputStructNode );
+
+addNodeClass( OutputStructNode );

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

@@ -57,5 +57,7 @@ export const iridescenceThickness = nodeImmutable( PropertyNode, 'float', 'Iride
 export const specularColor = nodeImmutable( PropertyNode, 'color', 'SpecularColor' );
 export const shininess = nodeImmutable( PropertyNode, 'float', 'Shininess' );
 export const output = nodeImmutable( PropertyNode, 'vec4', 'Output' );
+export const dashSize = nodeImmutable( PropertyNode, 'float', 'dashScale' );
+export const gapSize= nodeImmutable( PropertyNode, 'float', 'gapSize' );
 
 addNodeClass( PropertyNode );

+ 4 - 4
examples/jsm/nodes/core/StackNode.js

@@ -4,7 +4,7 @@ import { bypass } from '../core/BypassNode.js';
 import { expression } from '../code/ExpressionNode.js';
 import { cond } from '../math/CondNode.js';
 import { loop } from '../utils/LoopNode.js';
-import { nodeProxy, shader } from '../shadernode/ShaderNode.js';
+import { ShaderNode, nodeProxy } from '../shadernode/ShaderNode.js';
 
 class StackNode extends Node {
 
@@ -39,7 +39,7 @@ class StackNode extends Node {
 
 	if( boolNode, method ) {
 
-		const methodNode = shader( method );
+		const methodNode = new ShaderNode( method );
 		this._currentCond = cond( boolNode, methodNode );
 
 		return this.add( this._currentCond );
@@ -48,7 +48,7 @@ class StackNode extends Node {
 
 	elseif( boolNode, method ) {
 
-		const methodNode = shader( method );
+		const methodNode = new ShaderNode( method );
 		const ifNode = cond( boolNode, methodNode );
 
 		this._currentCond.elseNode = ifNode;
@@ -60,7 +60,7 @@ class StackNode extends Node {
 
 	else( method ) {
 
-		this._currentCond.elseNode = shader( method );
+		this._currentCond.elseNode = new ShaderNode( method );
 
 		return this;
 

+ 24 - 0
examples/jsm/nodes/core/StructTypeNode.js

@@ -0,0 +1,24 @@
+import Node, { addNodeClass } from './Node.js';
+
+class StructTypeNode extends Node {
+
+	constructor( types ) {
+
+		super();
+
+        this.types = types;
+		this.isStructTypeNode = true;
+
+	}
+
+    getMemberTypes() {
+
+        return this.types;
+
+    }
+
+}
+
+export default StructTypeNode;
+
+addNodeClass( StructTypeNode );

+ 19 - 5
examples/jsm/nodes/display/ViewportNode.js

@@ -3,9 +3,9 @@ import { NodeUpdateType } from '../core/constants.js';
 import { uniform } from '../core/UniformNode.js';
 import { nodeImmutable, vec2 } from '../shadernode/ShaderNode.js';
 
-import { Vector2 } from 'three';
+import { Vector2, Vector4 } from 'three';
 
-let resolution;
+let resolution, viewportResult;
 
 class ViewportNode extends Node {
 
@@ -21,7 +21,7 @@ class ViewportNode extends Node {
 
 	getNodeType() {
 
-		return this.scope === ViewportNode.COORDINATE ? 'vec4' : 'vec2';
+		return this.scope === ViewportNode.COORDINATE || this.scope === ViewportNode.VIEWPORT ? 'vec4' : 'vec2';
 
 	}
 
@@ -29,7 +29,7 @@ class ViewportNode extends Node {
 
 		let updateType = NodeUpdateType.NONE;
 
-		if ( this.scope === ViewportNode.RESOLUTION ) {
+		if ( this.scope === ViewportNode.RESOLUTION || this.scope === ViewportNode.VIEWPORT ) {
 
 			updateType = NodeUpdateType.FRAME;
 
@@ -43,7 +43,15 @@ class ViewportNode extends Node {
 
 	update( { renderer } ) {
 
-		renderer.getDrawingBufferSize( resolution );
+		if ( this.scope === ViewportNode.VIEWPORT ) {
+
+			renderer.getViewport( viewportResult );
+
+		} else {
+
+			renderer.getDrawingBufferSize( resolution );
+
+		}
 
 	}
 
@@ -59,6 +67,10 @@ class ViewportNode extends Node {
 
 			output = uniform( resolution || ( resolution = new Vector2() ) );
 
+		} else if ( scope === ViewportNode.VIEWPORT ) {
+
+			output = uniform( viewportResult || ( viewportResult = new Vector4() ) );
+
 		} else {
 
 			const coordinateNode = vec2( new ViewportNode( ViewportNode.COORDINATE ) );
@@ -98,6 +110,7 @@ class ViewportNode extends Node {
 
 ViewportNode.COORDINATE = 'coordinate';
 ViewportNode.RESOLUTION = 'resolution';
+ViewportNode.VIEWPORT = 'viewport';
 ViewportNode.TOP_LEFT = 'topLeft';
 ViewportNode.BOTTOM_LEFT = 'bottomLeft';
 ViewportNode.TOP_RIGHT = 'topRight';
@@ -107,6 +120,7 @@ export default ViewportNode;
 
 export const viewportCoordinate = nodeImmutable( ViewportNode, ViewportNode.COORDINATE );
 export const viewportResolution = nodeImmutable( ViewportNode, ViewportNode.RESOLUTION );
+export const viewport = nodeImmutable( ViewportNode, ViewportNode.VIEWPORT );
 export const viewportTopLeft = nodeImmutable( ViewportNode, ViewportNode.TOP_LEFT );
 export const viewportBottomLeft = nodeImmutable( ViewportNode, ViewportNode.BOTTOM_LEFT );
 export const viewportTopRight = nodeImmutable( ViewportNode, ViewportNode.TOP_RIGHT );

+ 54 - 0
examples/jsm/nodes/materials/LineDashedNodeMaterial.js

@@ -0,0 +1,54 @@
+import NodeMaterial, { addNodeMaterial } from './NodeMaterial.js';
+import { attribute } from '../core/AttributeNode.js';
+import { varying } from '../core/VaryingNode.js';
+import { materialLineDashSize, materialLineGapSize, materialLineScale } from '../accessors/LineMaterialNode.js';
+import { dashSize, gapSize } from '../core/PropertyNode.js';
+import { float } from '../shadernode/ShaderNode.js';
+import { LineDashedMaterial } from 'three';
+
+const defaultValues = new LineDashedMaterial();
+
+class LineDashedNodeMaterial extends NodeMaterial {
+
+	constructor( parameters ) {
+
+		super();
+
+		this.isLineDashedNodeMaterial = true;
+
+		this.lights = false;
+		this.normals = false;
+
+		this.setDefaultValues( defaultValues );
+
+		this.offsetNode = null;
+		this.dashScaleNode = null;
+		this.dashSizeNode = null;
+		this.gapSizeNode = null;
+
+		this.setValues( parameters );
+
+	}
+
+	constructVariants( { stack } ) {
+
+		const offsetNode = this.offsetNode;
+		const dashScaleNode = this.dashScaleNode ? float( this.dashScaleNode ) : materialLineScale;
+		const dashSizeNode = this.dashSizeNode ? float( this.dashSizeNode ) : materialLineDashSize;
+		const gapSizeNode = this.dashSizeNode ? float( this.dashGapNode ) : materialLineGapSize;
+
+		stack.assign( dashSize, dashSizeNode );
+		stack.assign( gapSize, gapSizeNode );
+
+		const vLineDistance = varying( attribute( 'lineDistance' ).mul( dashScaleNode ) );
+		const vLineDistanceOffset = offsetNode ? vLineDistance.add( offsetNode ) : vLineDistance;
+
+		stack.add( vLineDistanceOffset.mod( dashSize.add( gapSize ) ).greaterThan( dashSize ).discard() );
+
+	}
+
+}
+
+export default LineDashedNodeMaterial;
+
+addNodeMaterial( LineDashedNodeMaterial );

+ 1 - 0
examples/jsm/nodes/materials/Materials.js

@@ -2,6 +2,7 @@
 
 export { default as NodeMaterial, addNodeMaterial, createNodeMaterialFromType } from './NodeMaterial.js';
 export { default as LineBasicNodeMaterial } from './LineBasicNodeMaterial.js';
+export { default as LineDashedNodeMaterial } from './LineDashedNodeMaterial.js';
 export { default as MeshNormalNodeMaterial } from './MeshNormalNodeMaterial.js';
 export { default as MeshBasicNodeMaterial } from './MeshBasicNodeMaterial.js';
 export { default as MeshLambertNodeMaterial } from './MeshLambertNodeMaterial.js';

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

@@ -16,6 +16,7 @@ import { lightsWithoutWrap } from '../lighting/LightsNode.js';
 import { mix, dFdx, dFdy } from '../math/MathNode.js';
 import { float, vec3, vec4 } from '../shadernode/ShaderNode.js';
 import AONode from '../lighting/AONode.js';
+import { lightingContext } from '../lighting/LightingContextNode.js';
 import EnvironmentNode from '../lighting/EnvironmentNode.js';
 
 const NodeMaterials = new Map();
@@ -290,7 +291,7 @@ class NodeMaterial extends ShaderMaterial {
 
 			const lightingModelNode = this.constructLightingModel( builder );
 
-			outgoingLightNode = lightsNode.lightingContext( lightingModelNode, backdropNode, backdropAlphaNode );
+			outgoingLightNode = lightingContext( lightsNode, lightingModelNode, backdropNode, backdropAlphaNode );
 
 		} else if ( backdropNode !== null ) {
 
@@ -302,7 +303,7 @@ class NodeMaterial extends ShaderMaterial {
 
 		if ( ( emissiveNode && emissiveNode.isNode === true ) || ( material.emissive && material.emissive.isColor === true ) ) {
 
-			outgoingLightNode = outgoingLightNode.add( emissiveNode ? vec3( emissiveNode ) : materialEmissive );
+			outgoingLightNode = outgoingLightNode.add( vec3( emissiveNode ? emissiveNode : materialEmissive ) );
 
 		}
 
@@ -344,7 +345,15 @@ class NodeMaterial extends ShaderMaterial {
 
 			if ( renderTarget !== null ) {
 
-				outputColorSpace = renderTarget.texture.colorSpace;
+				if ( Array.isArray( renderTarget.texture ) ) {
+
+					outputColorSpace = renderTarget.texture[ 0 ].colorSpace;
+
+				} else {
+
+					outputColorSpace = renderTarget.texture.colorSpace;
+
+				}
 
 			} else {
 

+ 35 - 0
examples/jsm/nodes/math/HashNode.js

@@ -0,0 +1,35 @@
+import Node, { addNodeClass } from '../core/Node.js';
+import { add, mul, bitXor, shiftRight } from './OperatorNode.js';
+import { addNodeElement, nodeProxy, uint } from '../shadernode/ShaderNode.js';
+
+class HashNode extends Node {
+
+	constructor( seedNode ) {
+
+		super();
+
+		this.seedNode = seedNode;
+
+	}
+
+	construct( /*builder*/ ) {
+
+		const seed = this.seedNode;
+
+		const state = add( mul( uint( seed ), 747796405 ), 2891336453 );
+		const word = mul( bitXor( shiftRight( state, add( shiftRight( state, 28 ), 4 ) ), state ), 277803737 );
+		const uintResult = bitXor( shiftRight( word, 22 ), word );
+
+		return mul( 1 / 2 ** 32, uintResult ); // Convert to range [0, 1)
+
+	}
+
+}
+
+export default HashNode;
+
+export const hash = nodeProxy( HashNode );
+
+addNodeElement( 'hash', hash );
+
+addNodeClass( HashNode );

+ 4 - 0
examples/jsm/nodes/shadernode/ShaderNode.js

@@ -37,6 +37,10 @@ const shaderNodeHandler = {
 
 				return ( ...params ) => nodeElement( nodeObj, ...params );
 
+			} else if ( prop === 'self' ) {
+
+				return node;
+
 			} else if ( prop.endsWith( 'Assign' ) && NodeElements.has( prop.slice( 0, prop.length - 'Assign'.length ) ) ) {
 
 				const nodeElement = NodeElements.get( prop.slice( 0, prop.length - 'Assign'.length ) );

+ 1 - 1
examples/jsm/nodes/utils/SplitNode.js

@@ -59,7 +59,7 @@ class SplitNode extends Node {
 
 			if ( this.components.length === nodeTypeLength && this.components === stringVectorComponents.slice( 0, this.components.length ) ) {
 
-				// unecessary swizzle
+				// unnecessary swizzle
 
 				snippet = builder.format( nodeSnippet, type, output );
 

+ 3 - 5
examples/jsm/postprocessing/FilmPass.js

@@ -7,7 +7,7 @@ import { FilmShader } from '../shaders/FilmShader.js';
 
 class FilmPass extends Pass {
 
-	constructor( noiseIntensity, scanlinesIntensity, scanlinesCount, grayscale ) {
+	constructor( intensity = 0.5, grayscale = false ) {
 
 		super();
 
@@ -24,10 +24,8 @@ class FilmPass extends Pass {
 
 		} );
 
-		if ( grayscale !== undefined )	this.uniforms.grayscale.value = grayscale;
-		if ( noiseIntensity !== undefined ) this.uniforms.nIntensity.value = noiseIntensity;
-		if ( scanlinesIntensity !== undefined ) this.uniforms.sIntensity.value = scanlinesIntensity;
-		if ( scanlinesCount !== undefined ) this.uniforms.sCount.value = scanlinesCount;
+		this.uniforms.intensity.value = intensity; // (0 = no effect, 1 = full effect)
+		this.uniforms.grayscale.value = grayscale;
 
 		this.fsQuad = new FullScreenQuad( this.material );
 

+ 30 - 12
examples/jsm/postprocessing/RenderPass.js

@@ -5,7 +5,7 @@ import { Pass } from './Pass.js';
 
 class RenderPass extends Pass {
 
-	constructor( scene, camera, overrideMaterial, clearColor, clearAlpha ) {
+	constructor( scene, camera, overrideMaterial = null, clearColor = null, clearAlpha = null ) {
 
 		super();
 
@@ -15,7 +15,7 @@ class RenderPass extends Pass {
 		this.overrideMaterial = overrideMaterial;
 
 		this.clearColor = clearColor;
-		this.clearAlpha = ( clearAlpha !== undefined ) ? clearAlpha : 0;
+		this.clearAlpha = clearAlpha;
 
 		this.clear = true;
 		this.clearDepth = false;
@@ -31,7 +31,7 @@ class RenderPass extends Pass {
 
 		let oldClearAlpha, oldOverrideMaterial;
 
-		if ( this.overrideMaterial !== undefined ) {
+		if ( this.overrideMaterial !== null ) {
 
 			oldOverrideMaterial = this.scene.overrideMaterial;
 
@@ -39,16 +39,21 @@ class RenderPass extends Pass {
 
 		}
 
-		if ( this.clearColor ) {
+		if ( this.clearColor !== null ) {
 
 			renderer.getClearColor( this._oldClearColor );
-			oldClearAlpha = renderer.getClearAlpha();
+			renderer.setClearColor( this.clearColor );
+
+		}
 
-			renderer.setClearColor( this.clearColor, this.clearAlpha );
+		if ( this.clearAlpha !== null ) {
+
+			oldClearAlpha = renderer.getClearAlpha();
+			renderer.setClearAlpha( this.clearAlpha );
 
 		}
 
-		if ( this.clearDepth ) {
+		if ( this.clearDepth == true ) {
 
 			renderer.clearDepth();
 
@@ -56,17 +61,30 @@ class RenderPass extends Pass {
 
 		renderer.setRenderTarget( this.renderToScreen ? null : readBuffer );
 
-		// TODO: Avoid using autoClear properties, see https://github.com/mrdoob/three.js/pull/15571#issuecomment-465669600
-		if ( this.clear ) renderer.clear( renderer.autoClearColor, renderer.autoClearDepth, renderer.autoClearStencil );
+		if ( this.clear === true ) {
+
+			// TODO: Avoid using autoClear properties, see https://github.com/mrdoob/three.js/pull/15571#issuecomment-465669600
+			renderer.clear( renderer.autoClearColor, renderer.autoClearDepth, renderer.autoClearStencil );
+
+		}
+
 		renderer.render( this.scene, this.camera );
 
-		if ( this.clearColor ) {
+		// restore
+
+		if ( this.clearColor !== null ) {
+
+			renderer.setClearColor( this._oldClearColor );
+
+		}
+
+		if ( this.clearAlpha !== null ) {
 
-			renderer.setClearColor( this._oldClearColor, oldClearAlpha );
+			renderer.setClearAlpha( oldClearAlpha );
 
 		}
 
-		if ( this.overrideMaterial !== undefined ) {
+		if ( this.overrideMaterial !== null ) {
 
 			this.scene.overrideMaterial = oldOverrideMaterial;
 

+ 23 - 98
examples/jsm/postprocessing/SAOPass.js

@@ -6,14 +6,13 @@ import {
 	DstAlphaFactor,
 	DstColorFactor,
 	HalfFloatType,
-	MeshDepthMaterial,
 	MeshNormalMaterial,
 	NearestFilter,
 	NoBlending,
-	RGBADepthPacking,
 	ShaderMaterial,
 	UniformsUtils,
-	UnsignedShortType,
+	DepthStencilFormat,
+	UnsignedInt248Type,
 	Vector2,
 	WebGLRenderTarget,
 	ZeroFactor
@@ -23,7 +22,6 @@ import { SAOShader } from '../shaders/SAOShader.js';
 import { DepthLimitedBlurShader } from '../shaders/DepthLimitedBlurShader.js';
 import { BlurShaderUtils } from '../shaders/DepthLimitedBlurShader.js';
 import { CopyShader } from '../shaders/CopyShader.js';
-import { UnpackDepthRGBAShader } from '../shaders/UnpackDepthRGBAShader.js';
 
 /**
  * SAO implementation inspired from bhouston previous SAO work
@@ -31,7 +29,7 @@ import { UnpackDepthRGBAShader } from '../shaders/UnpackDepthRGBAShader.js';
 
 class SAOPass extends Pass {
 
-	constructor( scene, camera, useDepthTexture = false, useNormals = false, resolution = new Vector2( 256, 256 ) ) {
+	constructor( scene, camera, resolution = new Vector2( 256, 256 ) ) {
 
 		super();
 
@@ -41,9 +39,6 @@ class SAOPass extends Pass {
 		this.clear = true;
 		this.needsSwap = false;
 
-		this.supportsDepthTextureExtension = useDepthTexture;
-		this.supportsNormalTexture = useNormals;
-
 		this.originalClearColor = new Color();
 		this._oldClearColor = new Color();
 		this.oldClearAlpha = 1;
@@ -65,30 +60,17 @@ class SAOPass extends Pass {
 
 		this.saoRenderTarget = new WebGLRenderTarget( this.resolution.x, this.resolution.y, { type: HalfFloatType } );
 		this.blurIntermediateRenderTarget = this.saoRenderTarget.clone();
-		this.beautyRenderTarget = this.saoRenderTarget.clone();
+
+		const depthTexture = new DepthTexture();
+		depthTexture.format = DepthStencilFormat;
+		depthTexture.type = UnsignedInt248Type;
 
 		this.normalRenderTarget = new WebGLRenderTarget( this.resolution.x, this.resolution.y, {
 			minFilter: NearestFilter,
 			magFilter: NearestFilter,
-			type: HalfFloatType
+			type: HalfFloatType,
+			depthTexture: depthTexture
 		} );
-		this.depthRenderTarget = this.normalRenderTarget.clone();
-
-		let depthTexture;
-
-		if ( this.supportsDepthTextureExtension ) {
-
-			depthTexture = new DepthTexture();
-			depthTexture.type = UnsignedShortType;
-
-			this.beautyRenderTarget.depthTexture = depthTexture;
-			this.beautyRenderTarget.depthBuffer = true;
-
-		}
-
-		this.depthMaterial = new MeshDepthMaterial();
-		this.depthMaterial.depthPacking = RGBADepthPacking;
-		this.depthMaterial.blending = NoBlending;
 
 		this.normalMaterial = new MeshNormalMaterial();
 		this.normalMaterial.blending = NoBlending;
@@ -100,10 +82,8 @@ class SAOPass extends Pass {
 			uniforms: UniformsUtils.clone( SAOShader.uniforms )
 		} );
 		this.saoMaterial.extensions.derivatives = true;
-		this.saoMaterial.defines[ 'DEPTH_PACKING' ] = this.supportsDepthTextureExtension ? 0 : 1;
-		this.saoMaterial.defines[ 'NORMAL_TEXTURE' ] = this.supportsNormalTexture ? 1 : 0;
 		this.saoMaterial.defines[ 'PERSPECTIVE_CAMERA' ] = this.camera.isPerspectiveCamera ? 1 : 0;
-		this.saoMaterial.uniforms[ 'tDepth' ].value = ( this.supportsDepthTextureExtension ) ? depthTexture : this.depthRenderTarget.texture;
+		this.saoMaterial.uniforms[ 'tDepth' ].value = depthTexture;
 		this.saoMaterial.uniforms[ 'tNormal' ].value = this.normalRenderTarget.texture;
 		this.saoMaterial.uniforms[ 'size' ].value.set( this.resolution.x, this.resolution.y );
 		this.saoMaterial.uniforms[ 'cameraInverseProjectionMatrix' ].value.copy( this.camera.projectionMatrixInverse );
@@ -116,10 +96,10 @@ class SAOPass extends Pass {
 			vertexShader: DepthLimitedBlurShader.vertexShader,
 			fragmentShader: DepthLimitedBlurShader.fragmentShader
 		} );
-		this.vBlurMaterial.defines[ 'DEPTH_PACKING' ] = this.supportsDepthTextureExtension ? 0 : 1;
+		this.vBlurMaterial.defines[ 'DEPTH_PACKING' ] = 0;
 		this.vBlurMaterial.defines[ 'PERSPECTIVE_CAMERA' ] = this.camera.isPerspectiveCamera ? 1 : 0;
 		this.vBlurMaterial.uniforms[ 'tDiffuse' ].value = this.saoRenderTarget.texture;
-		this.vBlurMaterial.uniforms[ 'tDepth' ].value = ( this.supportsDepthTextureExtension ) ? depthTexture : this.depthRenderTarget.texture;
+		this.vBlurMaterial.uniforms[ 'tDepth' ].value = depthTexture;
 		this.vBlurMaterial.uniforms[ 'size' ].value.set( this.resolution.x, this.resolution.y );
 		this.vBlurMaterial.blending = NoBlending;
 
@@ -129,10 +109,10 @@ class SAOPass extends Pass {
 			vertexShader: DepthLimitedBlurShader.vertexShader,
 			fragmentShader: DepthLimitedBlurShader.fragmentShader
 		} );
-		this.hBlurMaterial.defines[ 'DEPTH_PACKING' ] = this.supportsDepthTextureExtension ? 0 : 1;
+		this.hBlurMaterial.defines[ 'DEPTH_PACKING' ] = 0;
 		this.hBlurMaterial.defines[ 'PERSPECTIVE_CAMERA' ] = this.camera.isPerspectiveCamera ? 1 : 0;
 		this.hBlurMaterial.uniforms[ 'tDiffuse' ].value = this.blurIntermediateRenderTarget.texture;
-		this.hBlurMaterial.uniforms[ 'tDepth' ].value = ( this.supportsDepthTextureExtension ) ? depthTexture : this.depthRenderTarget.texture;
+		this.hBlurMaterial.uniforms[ 'tDepth' ].value = depthTexture;
 		this.hBlurMaterial.uniforms[ 'size' ].value.set( this.resolution.x, this.resolution.y );
 		this.hBlurMaterial.blending = NoBlending;
 
@@ -153,13 +133,6 @@ class SAOPass extends Pass {
 		this.materialCopy.blendDstAlpha = ZeroFactor;
 		this.materialCopy.blendEquationAlpha = AddEquation;
 
-		this.depthCopy = new ShaderMaterial( {
-			uniforms: UniformsUtils.clone( UnpackDepthRGBAShader.uniforms ),
-			vertexShader: UnpackDepthRGBAShader.vertexShader,
-			fragmentShader: UnpackDepthRGBAShader.fragmentShader,
-			blending: NoBlending
-		} );
-
 		this.fsQuad = new FullScreenQuad( null );
 
 	}
@@ -176,20 +149,11 @@ class SAOPass extends Pass {
 
 		}
 
-		if ( this.params.output === 1 ) {
-
-			return;
-
-		}
-
 		renderer.getClearColor( this._oldClearColor );
 		this.oldClearAlpha = renderer.getClearAlpha();
 		const oldAutoClear = renderer.autoClear;
 		renderer.autoClear = false;
 
-		renderer.setRenderTarget( this.depthRenderTarget );
-		renderer.clear();
-
 		this.saoMaterial.uniforms[ 'bias' ].value = this.params.saoBias;
 		this.saoMaterial.uniforms[ 'intensity' ].value = this.params.saoIntensity;
 		this.saoMaterial.uniforms[ 'scale' ].value = this.params.saoScale;
@@ -218,26 +182,8 @@ class SAOPass extends Pass {
 
 		}
 
-		// Rendering scene to depth texture
-		renderer.setClearColor( 0x000000 );
-		renderer.setRenderTarget( this.beautyRenderTarget );
-		renderer.clear();
-		renderer.render( this.scene, this.camera );
-
-		// Re-render scene if depth texture extension is not supported
-		if ( ! this.supportsDepthTextureExtension ) {
-
-			// Clear rule : far clipping plane in both RGBA and Basic encoding
-			this.renderOverride( renderer, this.depthMaterial, this.depthRenderTarget, 0x000000, 1.0 );
-
-		}
-
-		if ( this.supportsNormalTexture ) {
-
-			// Clear rule : default normal is facing the camera
-			this.renderOverride( renderer, this.normalMaterial, this.normalRenderTarget, 0x7777ff, 1.0 );
-
-		}
+		// render normal and depth
+		this.renderOverride( renderer, this.normalMaterial, this.normalRenderTarget, 0x7777ff, 1.0 );
 
 		// Rendering SAO texture
 		this.renderPass( renderer, this.saoMaterial, this.saoRenderTarget, 0xffffff, 1.0 );
@@ -250,24 +196,10 @@ class SAOPass extends Pass {
 
 		}
 
-		let outputMaterial = this.materialCopy;
-		// Setting up SAO rendering
-		if ( this.params.output === 3 ) {
-
-			if ( this.supportsDepthTextureExtension ) {
-
-				this.materialCopy.uniforms[ 'tDiffuse' ].value = this.beautyRenderTarget.depthTexture;
-				this.materialCopy.needsUpdate = true;
+		const outputMaterial = this.materialCopy;
 
-			} else {
-
-				this.depthCopy.uniforms[ 'tDiffuse' ].value = this.depthRenderTarget.texture;
-				this.depthCopy.needsUpdate = true;
-				outputMaterial = this.depthCopy;
-
-			}
-
-		} else if ( this.params.output === 4 ) {
+		// Setting up SAO rendering
+		if ( this.params.output === SAOPass.OUTPUT.Normal ) {
 
 			this.materialCopy.uniforms[ 'tDiffuse' ].value = this.normalRenderTarget.texture;
 			this.materialCopy.needsUpdate = true;
@@ -279,8 +211,8 @@ class SAOPass extends Pass {
 
 		}
 
-		// Blending depends on output, only want a CustomBlending when showing SAO
-		if ( this.params.output === 0 ) {
+		// Blending depends on output
+		if ( this.params.output === SAOPass.OUTPUT.Default ) {
 
 			outputMaterial.blending = CustomBlending;
 
@@ -359,11 +291,9 @@ class SAOPass extends Pass {
 
 	setSize( width, height ) {
 
-		this.beautyRenderTarget.setSize( width, height );
 		this.saoRenderTarget.setSize( width, height );
 		this.blurIntermediateRenderTarget.setSize( width, height );
 		this.normalRenderTarget.setSize( width, height );
-		this.depthRenderTarget.setSize( width, height );
 
 		this.saoMaterial.uniforms[ 'size' ].value.set( width, height );
 		this.saoMaterial.uniforms[ 'cameraInverseProjectionMatrix' ].value.copy( this.camera.projectionMatrixInverse );
@@ -382,9 +312,7 @@ class SAOPass extends Pass {
 
 		this.saoRenderTarget.dispose();
 		this.blurIntermediateRenderTarget.dispose();
-		this.beautyRenderTarget.dispose();
 		this.normalRenderTarget.dispose();
-		this.depthRenderTarget.dispose();
 
 		this.depthMaterial.dispose();
 		this.normalMaterial.dispose();
@@ -392,7 +320,6 @@ class SAOPass extends Pass {
 		this.vBlurMaterial.dispose();
 		this.hBlurMaterial.dispose();
 		this.materialCopy.dispose();
-		this.depthCopy.dispose();
 
 		this.fsQuad.dispose();
 
@@ -401,11 +328,9 @@ class SAOPass extends Pass {
 }
 
 SAOPass.OUTPUT = {
-	'Beauty': 1,
 	'Default': 0,
-	'SAO': 2,
-	'Depth': 3,
-	'Normal': 4
+	'SAO': 1,
+	'Normal': 2
 };
 
 export { SAOPass };

+ 10 - 30
examples/jsm/postprocessing/SSAOPass.js

@@ -32,7 +32,7 @@ import { CopyShader } from '../shaders/CopyShader.js';
 
 class SSAOPass extends Pass {
 
-	constructor( scene, camera, width, height ) {
+	constructor( scene, camera, width, height, kernelSize = 32 ) {
 
 		super();
 
@@ -45,7 +45,6 @@ class SSAOPass extends Pass {
 		this.scene = scene;
 
 		this.kernelRadius = 8;
-		this.kernelSize = 32;
 		this.kernel = [];
 		this.noiseTexture = null;
 		this.output = 0;
@@ -57,17 +56,15 @@ class SSAOPass extends Pass {
 
 		//
 
-		this.generateSampleKernel();
+		this.generateSampleKernel( kernelSize );
 		this.generateRandomKernelRotations();
 
-		// beauty render target
+		// depth texture
 
 		const depthTexture = new DepthTexture();
 		depthTexture.format = DepthStencilFormat;
 		depthTexture.type = UnsignedInt248Type;
 
-		this.beautyRenderTarget = new WebGLRenderTarget( this.width, this.height, { type: HalfFloatType } );
-
 		// normal render target with depth buffer
 
 		this.normalRenderTarget = new WebGLRenderTarget( this.width, this.height, {
@@ -93,7 +90,8 @@ class SSAOPass extends Pass {
 			blending: NoBlending
 		} );
 
-		this.ssaoMaterial.uniforms[ 'tDiffuse' ].value = this.beautyRenderTarget.texture;
+		this.ssaoMaterial.defines[ 'KERNEL_SIZE' ] = kernelSize;
+
 		this.ssaoMaterial.uniforms[ 'tNormal' ].value = this.normalRenderTarget.texture;
 		this.ssaoMaterial.uniforms[ 'tDepth' ].value = this.normalRenderTarget.depthTexture;
 		this.ssaoMaterial.uniforms[ 'tNoise' ].value = this.noiseTexture;
@@ -160,7 +158,6 @@ class SSAOPass extends Pass {
 
 		// dispose render targets
 
-		this.beautyRenderTarget.dispose();
 		this.normalRenderTarget.dispose();
 		this.ssaoRenderTarget.dispose();
 		this.blurRenderTarget.dispose();
@@ -178,16 +175,10 @@ class SSAOPass extends Pass {
 
 	}
 
-	render( renderer, writeBuffer /*, readBuffer, deltaTime, maskActive */ ) {
+	render( renderer, writeBuffer, readBuffer /*, deltaTime, maskActive */ ) {
 
 		if ( renderer.capabilities.isWebGL2 === false ) this.noiseTexture.format = LuminanceFormat;
 
-		// render beauty
-
-		renderer.setRenderTarget( this.beautyRenderTarget );
-		renderer.clear();
-		renderer.render( this.scene, this.camera );
-
 		// render normals and depth (honor only meshes, points and lines do not contribute to SSAO)
 
 		this.overrideVisibility();
@@ -225,14 +216,6 @@ class SSAOPass extends Pass {
 
 				break;
 
-			case SSAOPass.OUTPUT.Beauty:
-
-				this.copyMaterial.uniforms[ 'tDiffuse' ].value = this.beautyRenderTarget.texture;
-				this.copyMaterial.blending = NoBlending;
-				this.renderPass( renderer, this.copyMaterial, this.renderToScreen ? null : writeBuffer );
-
-				break;
-
 			case SSAOPass.OUTPUT.Depth:
 
 				this.renderPass( renderer, this.depthRenderMaterial, this.renderToScreen ? null : writeBuffer );
@@ -249,7 +232,7 @@ class SSAOPass extends Pass {
 
 			case SSAOPass.OUTPUT.Default:
 
-				this.copyMaterial.uniforms[ 'tDiffuse' ].value = this.beautyRenderTarget.texture;
+				this.copyMaterial.uniforms[ 'tDiffuse' ].value = readBuffer.texture;
 				this.copyMaterial.blending = NoBlending;
 				this.renderPass( renderer, this.copyMaterial, this.renderToScreen ? null : writeBuffer );
 
@@ -332,7 +315,6 @@ class SSAOPass extends Pass {
 		this.width = width;
 		this.height = height;
 
-		this.beautyRenderTarget.setSize( width, height );
 		this.ssaoRenderTarget.setSize( width, height );
 		this.normalRenderTarget.setSize( width, height );
 		this.blurRenderTarget.setSize( width, height );
@@ -345,9 +327,8 @@ class SSAOPass extends Pass {
 
 	}
 
-	generateSampleKernel() {
+	generateSampleKernel( kernelSize ) {
 
-		const kernelSize = this.kernelSize;
 		const kernel = this.kernel;
 
 		for ( let i = 0; i < kernelSize; i ++ ) {
@@ -432,9 +413,8 @@ SSAOPass.OUTPUT = {
 	'Default': 0,
 	'SSAO': 1,
 	'Blur': 2,
-	'Beauty': 3,
-	'Depth': 4,
-	'Normal': 5
+	'Depth': 3,
+	'Normal': 4
 };
 
 export { SSAOPass };

+ 11 - 8
examples/jsm/renderers/common/Backend.js

@@ -1,7 +1,7 @@
 let vector2 = null;
 let vector4 = null;
 
-import { Vector2, Vector4 } from 'three';
+import { Vector2, Vector4, REVISION, createCanvasElement } from 'three';
 
 class Backend {
 
@@ -118,7 +118,12 @@ class Backend {
 
 		if ( domElement === null ) {
 
-			this.domElement = domElement = ( this.parameters.canvas !== undefined ) ? this.parameters.canvas : this.createCanvasElement();
+			domElement = ( this.parameters.canvas !== undefined ) ? this.parameters.canvas : createCanvasElement();
+
+			// OffscreenCanvas does not have setAttribute, see #22811
+			if ( 'setAttribute' in domElement ) domElement.setAttribute( 'data-engine', `three.js r${REVISION}` );
+
+			this.domElement = domElement;
 
 		}
 
@@ -126,16 +131,14 @@ class Backend {
 
 	}
 
-	createCanvasElement() {
+	// resource properties
+
+	set( object, value ) {
 
-		const canvas = document.createElementNS( 'http://www.w3.org/1999/xhtml', 'canvas' );
-		canvas.style.display = 'block';
-		return canvas;
+		this.data.set( object, value );
 
 	}
 
-	// resource properties
-
 	get( object ) {
 
 		let map = this.data.get( object );

+ 6 - 0
examples/jsm/renderers/common/Binding.js

@@ -14,6 +14,12 @@ class Binding {
 
 	}
 
+	clone() {
+
+		return Object.assign( new this.constructor(), this );
+
+	}
+
 }
 
 export default Binding;

+ 5 - 4
examples/jsm/renderers/common/Bindings.js

@@ -80,9 +80,11 @@ class Bindings extends DataMap {
 
 		for ( const binding of bindings ) {
 
-			if ( binding.isSampler || binding.isSampledTexture ) {
+			if ( binding.isSampledTexture ) {
 
-				this.textures.updateTexture( binding.texture );
+				const store = binding.store === true;
+
+				this.textures.updateTexture( binding.texture, { store } );
 
 			} else if ( binding.isStorageBuffer ) {
 
@@ -109,10 +111,9 @@ class Bindings extends DataMap {
 
 		for ( const binding of bindings ) {
 
-			const isShared = binding.isShared;
 			const isUpdated = updateMap.get( binding ) === frame;
 
-			if ( isShared && isUpdated ) continue;
+			if ( isUpdated ) continue;
 
 			if ( binding.isUniformBuffer ) {
 

+ 2 - 2
examples/jsm/renderers/common/Pipelines.js

@@ -343,7 +343,7 @@ class Pipelines extends DataMap {
 			data.stencilWrite !== material.stencilWrite || data.stencilFunc !== material.stencilFunc ||
 			data.stencilFail !== material.stencilFail || data.stencilZFail !== material.stencilZFail || data.stencilZPass !== material.stencilZPass ||
 			data.stencilFuncMask !== material.stencilFuncMask || data.stencilWriteMask !== material.stencilWriteMask ||
-			data.side !== material.side
+			data.side !== material.side || data.alphaToCoverage !== material.alphaToCoverage
 		) {
 
 			data.material = material; data.materialVersion = material.version;
@@ -355,7 +355,7 @@ class Pipelines extends DataMap {
 			data.stencilWrite = material.stencilWrite; data.stencilFunc = material.stencilFunc;
 			data.stencilFail = material.stencilFail; data.stencilZFail = material.stencilZFail; data.stencilZPass = material.stencilZPass;
 			data.stencilFuncMask = material.stencilFuncMask; data.stencilWriteMask = material.stencilWriteMask;
-			data.side = material.side;
+			data.side = material.side; data.alphaToCoverage = material.alphaToCoverage;
 
 			needsUpdate = true;
 

+ 26 - 1
examples/jsm/renderers/common/RenderContexts.js

@@ -12,7 +12,32 @@ class RenderContexts {
 	get( scene, camera, renderTarget = null ) {
 
 		const chainKey = [ scene, camera ];
-		const attachmentState = renderTarget === null ? 'default' : `${renderTarget.texture.format}:${renderTarget.samples}:${renderTarget.depthBuffer}:${renderTarget.stencilBuffer}`;
+
+		let attachmentState;
+
+		if ( renderTarget === null ) {
+
+			attachmentState = 'default';
+
+		} else {
+
+			let format, count;
+
+			if ( renderTarget.isWebGLMultipleRenderTargets ) {
+
+				format = renderTarget.texture[ 0 ].format;
+				count = renderTarget.texture.length;
+
+			} else {
+
+				format = renderTarget.texture.format;
+				count = 1;
+
+			}
+
+			attachmentState = `${count}:${format}:${renderTarget.samples}:${renderTarget.depthBuffer}:${renderTarget.stencilBuffer}`;
+
+		}
 
 		const chainMap = this.getChainMap( attachmentState );
 

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