Mr.doob 1 год назад
Родитель
Сommit
fb0849ff8a
100 измененных файлов с 93550 добавлено и 12557 удалено
  1. 368 130
      build/three.cjs
  2. 368 130
      build/three.module.js
  3. 0 0
      build/three.module.min.js
  4. 10916 11015
      build/three.webgpu.js
  5. 0 0
      build/three.webgpu.min.js
  6. 79925 0
      build/three.webgpu.nodes.js
  7. 5 0
      build/three.webgpu.nodes.min.js
  8. 3 1
      docs/api/en/audio/Audio.html
  9. 3 1
      docs/api/en/materials/LineBasicMaterial.html
  10. 14 0
      docs/api/en/math/Triangle.html
  11. 44 1
      docs/api/en/objects/BatchedMesh.html
  12. 9 0
      docs/api/en/objects/LOD.html
  13. 7 3
      docs/api/en/renderers/WebGLRenderer.html
  14. 42 0
      docs/api/zh/extras/TextureUtils.html
  15. 39 11
      docs/api/zh/objects/InstancedMesh.html
  16. 0 15
      docs/examples/en/controls/DragControls.html
  17. 7 22
      docs/examples/en/controls/TransformControls.html
  18. 0 70
      docs/examples/en/geometries/SDFGeometryGenerator.html
  19. 1 2
      docs/examples/en/geometries/TeapotGeometry.html
  20. 65 0
      docs/examples/en/lines/Line2.html
  21. 84 0
      docs/examples/en/lines/LineGeometry.html
  22. 92 0
      docs/examples/en/lines/LineMaterial.html
  23. 69 0
      docs/examples/en/lines/LineSegments2.html
  24. 103 0
      docs/examples/en/lines/LineSegmentsGeometry.html
  25. 122 0
      docs/examples/ko/controls/MapControls.html
  26. 117 0
      docs/examples/ko/webxr/XREstimatedLight.html
  27. 0 15
      docs/examples/zh/controls/DragControls.html
  28. 26 30
      docs/examples/zh/controls/OrbitControls.html
  29. 5 0
      docs/examples/zh/controls/PointerLockControls.html
  30. 9 45
      docs/examples/zh/controls/TrackballControls.html
  31. 11 21
      docs/examples/zh/controls/TransformControls.html
  32. 0 72
      docs/examples/zh/geometries/SDFGeometryGenerator.html
  33. 1 2
      docs/examples/zh/geometries/TeapotGeometry.html
  34. 8 2
      docs/index.html
  35. 17 6
      docs/list.json
  36. 5 5
      docs/manual/ar/introduction/How-to-create-VR-content.html
  37. 1 0
      docs/manual/ar/introduction/Libraries-and-Plugins.html
  38. 5 5
      docs/manual/en/introduction/How-to-create-VR-content.html
  39. 1 1
      docs/manual/en/introduction/How-to-update-things.html
  40. 1 0
      docs/manual/en/introduction/Libraries-and-Plugins.html
  41. 5 5
      docs/manual/fr/introduction/How-to-create-VR-content.html
  42. 10 9
      docs/manual/fr/introduction/How-to-update-things.html
  43. 5 5
      docs/manual/fr/introduction/How-to-use-post-processing.html
  44. 8 7
      docs/manual/fr/introduction/Libraries-and-Plugins.html
  45. 5 5
      docs/manual/it/introduction/How-to-create-VR-content.html
  46. 1 0
      docs/manual/it/introduction/Libraries-and-Plugins.html
  47. 5 5
      docs/manual/ja/introduction/How-to-create-VR-content.html
  48. 1 0
      docs/manual/ja/introduction/Libraries-and-Plugins.html
  49. 2 2
      docs/manual/ko/introduction/Drawing-lines.html
  50. 5 5
      docs/manual/ko/introduction/How-to-create-VR-content.html
  51. 5 5
      docs/manual/pt-br/introduction/How-to-create-VR-content.html
  52. 1 0
      docs/manual/pt-br/introduction/Libraries-and-Plugins.html
  53. 1 0
      docs/manual/ru/introduction/Libraries-and-Plugins.html
  54. 5 5
      docs/manual/zh/introduction/How-to-create-VR-content.html
  55. 1 0
      docs/manual/zh/introduction/Libraries-and-Plugins.html
  56. 4 0
      docs/page.css
  57. 1 1
      editor/js/Viewport.js
  58. 11 3
      examples/files.json
  59. 0 6
      examples/jsm/Addons.js
  60. 32 12
      examples/jsm/controls/TrackballControls.js
  61. 97 62
      examples/jsm/controls/TransformControls.js
  62. 4 2
      examples/jsm/exporters/DRACOExporter.js
  63. 19 11
      examples/jsm/exporters/EXRExporter.js
  64. 21 13
      examples/jsm/exporters/KTX2Exporter.js
  65. 5 1
      examples/jsm/exporters/OBJExporter.js
  66. 9 7
      examples/jsm/exporters/PLYExporter.js
  67. 4 1
      examples/jsm/geometries/DecalGeometry.js
  68. 1 1
      examples/jsm/geometries/InstancedPointsGeometry.js
  69. 0 144
      examples/jsm/geometries/SDFGeometryGenerator.js
  70. 1 1
      examples/jsm/helpers/LightProbeHelper.js
  71. 65 0
      examples/jsm/helpers/LightProbeHelperGPU.js
  72. 5 5
      examples/jsm/libs/basis/basis_transcoder.js
  73. BIN
      examples/jsm/libs/basis/basis_transcoder.wasm
  74. 0 0
      examples/jsm/libs/ktx-parse.module.js
  75. 24 10
      examples/jsm/lights/LightProbeGenerator.js
  76. 9 6
      examples/jsm/loaders/ColladaLoader.js
  77. 3 1
      examples/jsm/loaders/DRACOLoader.js
  78. 30 20
      examples/jsm/loaders/FBXLoader.js
  79. 5 10
      examples/jsm/loaders/GLTFLoader.js
  80. 10 7
      examples/jsm/loaders/KTX2Loader.js
  81. 4 3
      examples/jsm/loaders/MTLLoader.js
  82. 29 10
      examples/jsm/loaders/MaterialXLoader.js
  83. 5 3
      examples/jsm/loaders/OBJLoader.js
  84. 5 4
      examples/jsm/loaders/PCDLoader.js
  85. 3 2
      examples/jsm/loaders/PDBLoader.js
  86. 8 5
      examples/jsm/loaders/PLYLoader.js
  87. 3 2
      examples/jsm/loaders/STLLoader.js
  88. 0 520
      examples/jsm/loaders/TiltLoader.js
  89. 10 10
      examples/jsm/loaders/VRMLLoader.js
  90. 4 3
      examples/jsm/loaders/VTKLoader.js
  91. 3 2
      examples/jsm/loaders/XYZLoader.js
  92. 1 1
      examples/jsm/misc/Timer.js
  93. 233 0
      examples/jsm/modifiers/CurveModifierGPU.js
  94. 322 0
      examples/jsm/objects/LensflareMesh.js
  95. 1 2
      examples/jsm/objects/SkyMesh.js
  96. 2 3
      examples/jsm/objects/Water2Mesh.js
  97. 1 2
      examples/jsm/objects/WaterMesh.js
  98. 1 1
      examples/jsm/physics/JoltPhysics.js
  99. 1 1
      examples/jsm/physics/RapierPhysics.js
  100. 1 1
      examples/jsm/transpiler/GLSLDecoder.js

+ 368 - 130
build/three.cjs

@@ -5,7 +5,7 @@
  */
 'use strict';
 
-const REVISION = '168';
+const REVISION = '169';
 
 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 };
@@ -1594,6 +1594,38 @@ function probeAsync( gl, sync, interval ) {
 
 }
 
+function toNormalizedProjectionMatrix( projectionMatrix ) {
+
+	const m = projectionMatrix.elements;
+
+	// Convert [-1, 1] to [0, 1] projection matrix
+	m[ 2 ] = 0.5 * m[ 2 ] + 0.5 * m[ 3 ];
+	m[ 6 ] = 0.5 * m[ 6 ] + 0.5 * m[ 7 ];
+	m[ 10 ] = 0.5 * m[ 10 ] + 0.5 * m[ 11 ];
+	m[ 14 ] = 0.5 * m[ 14 ] + 0.5 * m[ 15 ];
+
+}
+
+function toReversedProjectionMatrix( projectionMatrix ) {
+
+	const m = projectionMatrix.elements;
+	const isPerspectiveMatrix = m[ 11 ] === - 1;
+
+	// Reverse [0, 1] projection matrix
+	if ( isPerspectiveMatrix ) {
+
+		m[ 10 ] = - m[ 10 ] - 1;
+		m[ 14 ] = - m[ 14 ];
+
+	} else {
+
+		m[ 10 ] = - m[ 10 ];
+		m[ 14 ] = - m[ 14 ] + 1;
+
+	}
+
+}
+
 /**
  * Matrices converting P3 <-> Rec. 709 primaries, without gamut mapping
  * or clipping. Based on W3C specifications for sRGB and Display P3,
@@ -8189,6 +8221,10 @@ const _vap = /*@__PURE__*/ new Vector3();
 const _vbp = /*@__PURE__*/ new Vector3();
 const _vcp = /*@__PURE__*/ new Vector3();
 
+const _v40 = /*@__PURE__*/ new Vector4();
+const _v41 = /*@__PURE__*/ new Vector4();
+const _v42 = /*@__PURE__*/ new Vector4();
+
 class Triangle {
 
 	constructor( a = new Vector3(), b = new Vector3(), c = new Vector3() ) {
@@ -8283,6 +8319,25 @@ class Triangle {
 
 	}
 
+	static getInterpolatedAttribute( attr, i1, i2, i3, barycoord, target ) {
+
+		_v40.setScalar( 0 );
+		_v41.setScalar( 0 );
+		_v42.setScalar( 0 );
+
+		_v40.fromBufferAttribute( attr, i1 );
+		_v41.fromBufferAttribute( attr, i2 );
+		_v42.fromBufferAttribute( attr, i3 );
+
+		target.setScalar( 0 );
+		target.addScaledVector( _v40, barycoord.x );
+		target.addScaledVector( _v41, barycoord.y );
+		target.addScaledVector( _v42, barycoord.z );
+
+		return target;
+
+	}
+
 	static isFrontFacing( a, b, c, direction ) {
 
 		_v0$2.subVectors( c, b );
@@ -9898,7 +9953,6 @@ class BufferAttribute {
 		this.normalized = normalized;
 
 		this.usage = StaticDrawUsage;
-		this._updateRange = { offset: 0, count: - 1 };
 		this.updateRanges = [];
 		this.gpuType = FloatType;
 
@@ -9914,13 +9968,6 @@ class BufferAttribute {
 
 	}
 
-	get updateRange() {
-
-		warnOnce( 'THREE.BufferAttribute: updateRange() is deprecated and will be removed in r169. Use addUpdateRange() instead.' ); // @deprecated, r159
-		return this._updateRange;
-
-	}
-
 	setUsage( value ) {
 
 		this.usage = value;
@@ -11565,14 +11612,6 @@ const _vC$1 = /*@__PURE__*/ new Vector3();
 const _tempA = /*@__PURE__*/ new Vector3();
 const _morphA = /*@__PURE__*/ new Vector3();
 
-const _uvA$1 = /*@__PURE__*/ new Vector2();
-const _uvB$1 = /*@__PURE__*/ new Vector2();
-const _uvC$1 = /*@__PURE__*/ new Vector2();
-
-const _normalA = /*@__PURE__*/ new Vector3();
-const _normalB = /*@__PURE__*/ new Vector3();
-const _normalC = /*@__PURE__*/ new Vector3();
-
 const _intersectionPoint = /*@__PURE__*/ new Vector3();
 const _intersectionPointWorld = /*@__PURE__*/ new Vector3();
 
@@ -11915,33 +11954,24 @@ function checkGeometryIntersection( object, material, raycaster, ray, uv, uv1, n
 
 	if ( intersection ) {
 
-		if ( uv ) {
+		const barycoord = new Vector3();
+		Triangle.getBarycoord( _intersectionPoint, _vA$1, _vB$1, _vC$1, barycoord );
 
-			_uvA$1.fromBufferAttribute( uv, a );
-			_uvB$1.fromBufferAttribute( uv, b );
-			_uvC$1.fromBufferAttribute( uv, c );
+		if ( uv ) {
 
-			intersection.uv = Triangle.getInterpolation( _intersectionPoint, _vA$1, _vB$1, _vC$1, _uvA$1, _uvB$1, _uvC$1, new Vector2() );
+			intersection.uv = Triangle.getInterpolatedAttribute( uv, a, b, c, barycoord, new Vector2() );
 
 		}
 
 		if ( uv1 ) {
 
-			_uvA$1.fromBufferAttribute( uv1, a );
-			_uvB$1.fromBufferAttribute( uv1, b );
-			_uvC$1.fromBufferAttribute( uv1, c );
-
-			intersection.uv1 = Triangle.getInterpolation( _intersectionPoint, _vA$1, _vB$1, _vC$1, _uvA$1, _uvB$1, _uvC$1, new Vector2() );
+			intersection.uv1 = Triangle.getInterpolatedAttribute( uv1, a, b, c, barycoord, new Vector2() );
 
 		}
 
 		if ( normal ) {
 
-			_normalA.fromBufferAttribute( normal, a );
-			_normalB.fromBufferAttribute( normal, b );
-			_normalC.fromBufferAttribute( normal, c );
-
-			intersection.normal = Triangle.getInterpolation( _intersectionPoint, _vA$1, _vB$1, _vC$1, _normalA, _normalB, _normalC, new Vector3() );
+			intersection.normal = Triangle.getInterpolatedAttribute( normal, a, b, c, barycoord, new Vector3() );
 
 			if ( intersection.normal.dot( ray.direction ) > 0 ) {
 
@@ -11962,6 +11992,7 @@ function checkGeometryIntersection( object, material, raycaster, ray, uv, uv1, n
 		Triangle.getNormal( _vA$1, _vB$1, _vC$1, face.normal );
 
 		intersection.face = face;
+		intersection.barycoord = barycoord;
 
 	}
 
@@ -13605,40 +13636,71 @@ function WebGLAttributes( gl ) {
 	function updateBuffer( buffer, attribute, bufferType ) {
 
 		const array = attribute.array;
-		const updateRange = attribute._updateRange; // @deprecated, r159
 		const updateRanges = attribute.updateRanges;
 
 		gl.bindBuffer( bufferType, buffer );
 
-		if ( updateRange.count === - 1 && updateRanges.length === 0 ) {
+		if ( updateRanges.length === 0 ) {
 
 			// Not using update ranges
 			gl.bufferSubData( bufferType, 0, array );
 
-		}
+		} else {
 
-		if ( updateRanges.length !== 0 ) {
+			// Before applying update ranges, we merge any adjacent / overlapping
+			// ranges to reduce load on `gl.bufferSubData`. Empirically, this has led
+			// to performance improvements for applications which make heavy use of
+			// update ranges. Likely due to GPU command overhead.
+			//
+			// Note that to reduce garbage collection between frames, we merge the
+			// update ranges in-place. This is safe because this method will clear the
+			// update ranges once updated.
 
-			for ( let i = 0, l = updateRanges.length; i < l; i ++ ) {
+			updateRanges.sort( ( a, b ) => a.start - b.start );
 
+			// To merge the update ranges in-place, we work from left to right in the
+			// existing updateRanges array, merging ranges. This may result in a final
+			// array which is smaller than the original. This index tracks the last
+			// index representing a merged range, any data after this index can be
+			// trimmed once the merge algorithm is completed.
+			let mergeIndex = 0;
+
+			for ( let i = 1; i < updateRanges.length; i ++ ) {
+
+				const previousRange = updateRanges[ mergeIndex ];
 				const range = updateRanges[ i ];
 
-				gl.bufferSubData( bufferType, range.start * array.BYTES_PER_ELEMENT,
-					array, range.start, range.count );
+				// We add one here to merge adjacent ranges. This is safe because ranges
+				// operate over positive integers.
+				if ( range.start <= previousRange.start + previousRange.count + 1 ) {
+
+					previousRange.count = Math.max(
+						previousRange.count,
+						range.start + range.count - previousRange.start
+					);
+
+				} else {
+
+					++ mergeIndex;
+					updateRanges[ mergeIndex ] = range;
+
+				}
 
 			}
 
-			attribute.clearUpdateRanges();
+			// Trim the array to only contain the merged ranges.
+			updateRanges.length = mergeIndex + 1;
 
-		}
+			for ( let i = 0, l = updateRanges.length; i < l; i ++ ) {
 
-		// @deprecated, r159
-		if ( updateRange.count !== - 1 ) {
+				const range = updateRanges[ i ];
 
-			gl.bufferSubData( bufferType, updateRange.offset * array.BYTES_PER_ELEMENT,
-				array, updateRange.offset, updateRange.count );
+				gl.bufferSubData( bufferType, range.start * array.BYTES_PER_ELEMENT,
+					array, range.start, range.count );
+
+			}
 
-			updateRange.count = - 1; // reset range
+			attribute.clearUpdateRanges();
 
 		}
 
@@ -14099,7 +14161,7 @@ const vertex$2 = "#include <common>\n#include <batching_pars_vertex>\n#include <
 
 const fragment$2 = "uniform vec3 color;\nuniform float opacity;\n#include <common>\n#include <packing>\n#include <fog_pars_fragment>\n#include <bsdfs>\n#include <lights_pars_begin>\n#include <logdepthbuf_pars_fragment>\n#include <shadowmap_pars_fragment>\n#include <shadowmask_pars_fragment>\nvoid main() {\n\t#include <logdepthbuf_fragment>\n\tgl_FragColor = vec4( color, opacity * ( 1.0 - getShadowMask() ) );\n\t#include <tonemapping_fragment>\n\t#include <colorspace_fragment>\n\t#include <fog_fragment>\n}";
 
-const vertex$1 = "uniform float rotation;\nuniform vec2 center;\n#include <common>\n#include <uv_pars_vertex>\n#include <fog_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\tvec4 mvPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );\n\tvec2 scale;\n\tscale.x = length( vec3( modelMatrix[ 0 ].x, modelMatrix[ 0 ].y, modelMatrix[ 0 ].z ) );\n\tscale.y = length( vec3( modelMatrix[ 1 ].x, modelMatrix[ 1 ].y, modelMatrix[ 1 ].z ) );\n\t#ifndef USE_SIZEATTENUATION\n\t\tbool isPerspective = isPerspectiveMatrix( projectionMatrix );\n\t\tif ( isPerspective ) scale *= - mvPosition.z;\n\t#endif\n\tvec2 alignedPosition = ( position.xy - ( center - vec2( 0.5 ) ) ) * scale;\n\tvec2 rotatedPosition;\n\trotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;\n\trotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;\n\tmvPosition.xy += rotatedPosition;\n\tgl_Position = projectionMatrix * mvPosition;\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\t#include <fog_vertex>\n}";
+const vertex$1 = "uniform float rotation;\nuniform vec2 center;\n#include <common>\n#include <uv_pars_vertex>\n#include <fog_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\tvec4 mvPosition = modelViewMatrix[ 3 ];\n\tvec2 scale = vec2( length( modelMatrix[ 0 ].xyz ), length( modelMatrix[ 1 ].xyz ) );\n\t#ifndef USE_SIZEATTENUATION\n\t\tbool isPerspective = isPerspectiveMatrix( projectionMatrix );\n\t\tif ( isPerspective ) scale *= - mvPosition.z;\n\t#endif\n\tvec2 alignedPosition = ( position.xy - ( center - vec2( 0.5 ) ) ) * scale;\n\tvec2 rotatedPosition;\n\trotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;\n\trotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;\n\tmvPosition.xy += rotatedPosition;\n\tgl_Position = projectionMatrix * mvPosition;\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\t#include <fog_vertex>\n}";
 
 const fragment$1 = "uniform vec3 diffuse;\nuniform float opacity;\n#include <common>\n#include <uv_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <alphatest_pars_fragment>\n#include <alphahash_pars_fragment>\n#include <fog_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include <clipping_planes_fragment>\n\tvec3 outgoingLight = vec3( 0.0 );\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <alphahash_fragment>\n\toutgoingLight = diffuseColor.rgb;\n\t#include <opaque_fragment>\n\t#include <tonemapping_fragment>\n\t#include <colorspace_fragment>\n\t#include <fog_fragment>\n}";
 
@@ -15865,6 +15927,14 @@ function WebGLCapabilities( gl, extensions, parameters, utils ) {
 	}
 
 	const logarithmicDepthBuffer = parameters.logarithmicDepthBuffer === true;
+	const reverseDepthBuffer = parameters.reverseDepthBuffer === true && extensions.has( 'EXT_clip_control' );
+
+	if ( reverseDepthBuffer === true ) {
+
+		const ext = extensions.get( 'EXT_clip_control' );
+		ext.clipControlEXT( ext.LOWER_LEFT_EXT, ext.ZERO_TO_ONE_EXT );
+
+	}
 
 	const maxTextures = gl.getParameter( gl.MAX_TEXTURE_IMAGE_UNITS );
 	const maxVertexTextures = gl.getParameter( gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS );
@@ -15892,6 +15962,7 @@ function WebGLCapabilities( gl, extensions, parameters, utils ) {
 
 		precision: precision,
 		logarithmicDepthBuffer: logarithmicDepthBuffer,
+		reverseDepthBuffer: reverseDepthBuffer,
 
 		maxTextures: maxTextures,
 		maxVertexTextures: maxVertexTextures,
@@ -19909,6 +19980,7 @@ function WebGLProgram( renderer, cacheKey, parameters, bindingStates ) {
 			parameters.numLightProbes > 0 ? '#define USE_LIGHT_PROBES' : '',
 
 			parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '',
+			parameters.reverseDepthBuffer ? '#define USE_REVERSEDEPTHBUF' : '',
 
 			'uniform mat4 modelMatrix;',
 			'uniform mat4 modelViewMatrix;',
@@ -20074,6 +20146,7 @@ function WebGLProgram( renderer, cacheKey, parameters, bindingStates ) {
 			parameters.decodeVideoTexture ? '#define DECODE_VIDEO_TEXTURE' : '',
 
 			parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '',
+			parameters.reverseDepthBuffer ? '#define USE_REVERSEDEPTHBUF' : '',
 
 			'uniform mat4 viewMatrix;',
 			'uniform vec3 cameraPosition;',
@@ -20466,6 +20539,7 @@ function WebGLPrograms( renderer, cubemaps, cubeuvmaps, extensions, capabilities
 	const programs = [];
 
 	const logarithmicDepthBuffer = capabilities.logarithmicDepthBuffer;
+	const reverseDepthBuffer = capabilities.reverseDepthBuffer;
 	const SUPPORTS_VERTEX_TEXTURES = capabilities.vertexTextures;
 
 	let precision = capabilities.precision;
@@ -20757,6 +20831,7 @@ function WebGLPrograms( renderer, cubemaps, cubeuvmaps, extensions, capabilities
 
 			sizeAttenuation: material.sizeAttenuation === true,
 			logarithmicDepthBuffer: logarithmicDepthBuffer,
+			reverseDepthBuffer: reverseDepthBuffer,
 
 			skinning: object.isSkinnedMesh === true,
 
@@ -20976,38 +21051,40 @@ function WebGLPrograms( renderer, cubemaps, cubeuvmaps, extensions, capabilities
 			_programLayers.enable( 2 );
 		if ( parameters.logarithmicDepthBuffer )
 			_programLayers.enable( 3 );
-		if ( parameters.skinning )
+		if ( parameters.reverseDepthBuffer )
 			_programLayers.enable( 4 );
-		if ( parameters.morphTargets )
+		if ( parameters.skinning )
 			_programLayers.enable( 5 );
-		if ( parameters.morphNormals )
+		if ( parameters.morphTargets )
 			_programLayers.enable( 6 );
-		if ( parameters.morphColors )
+		if ( parameters.morphNormals )
 			_programLayers.enable( 7 );
-		if ( parameters.premultipliedAlpha )
+		if ( parameters.morphColors )
 			_programLayers.enable( 8 );
-		if ( parameters.shadowMapEnabled )
+		if ( parameters.premultipliedAlpha )
 			_programLayers.enable( 9 );
-		if ( parameters.doubleSided )
+		if ( parameters.shadowMapEnabled )
 			_programLayers.enable( 10 );
-		if ( parameters.flipSided )
+		if ( parameters.doubleSided )
 			_programLayers.enable( 11 );
-		if ( parameters.useDepthPacking )
+		if ( parameters.flipSided )
 			_programLayers.enable( 12 );
-		if ( parameters.dithering )
+		if ( parameters.useDepthPacking )
 			_programLayers.enable( 13 );
-		if ( parameters.transmission )
+		if ( parameters.dithering )
 			_programLayers.enable( 14 );
-		if ( parameters.sheen )
+		if ( parameters.transmission )
 			_programLayers.enable( 15 );
-		if ( parameters.opaque )
+		if ( parameters.sheen )
 			_programLayers.enable( 16 );
-		if ( parameters.pointsUvs )
+		if ( parameters.opaque )
 			_programLayers.enable( 17 );
-		if ( parameters.decodeVideoTexture )
+		if ( parameters.pointsUvs )
 			_programLayers.enable( 18 );
-		if ( parameters.alphaToCoverage )
+		if ( parameters.decodeVideoTexture )
 			_programLayers.enable( 19 );
+		if ( parameters.alphaToCoverage )
+			_programLayers.enable( 20 );
 
 		array.push( _programLayers.mask );
 
@@ -22565,6 +22642,18 @@ function WebGLShadowMap( renderer, objects, capabilities ) {
 
 }
 
+const reversedFuncs = {
+	[ NeverDepth ]: AlwaysDepth,
+	[ LessDepth ]: GreaterDepth,
+	[ EqualDepth ]: NotEqualDepth,
+	[ LessEqualDepth ]: GreaterEqualDepth,
+
+	[ AlwaysDepth ]: NeverDepth,
+	[ GreaterDepth ]: LessDepth,
+	[ NotEqualDepth ]: EqualDepth,
+	[ GreaterEqualDepth ]: LessEqualDepth,
+};
+
 function WebGLState( gl ) {
 
 	function ColorBuffer() {
@@ -22629,6 +22718,7 @@ function WebGLState( gl ) {
 	function DepthBuffer() {
 
 		let locked = false;
+		let reversed = false;
 
 		let currentDepthMask = null;
 		let currentDepthFunc = null;
@@ -22636,6 +22726,12 @@ function WebGLState( gl ) {
 
 		return {
 
+			setReversed: function ( value ) {
+
+				reversed = value;
+
+			},
+
 			setTest: function ( depthTest ) {
 
 				if ( depthTest ) {
@@ -22663,6 +22759,8 @@ function WebGLState( gl ) {
 
 			setFunc: function ( depthFunc ) {
 
+				if ( reversed ) depthFunc = reversedFuncs[ depthFunc ];
+
 				if ( currentDepthFunc !== depthFunc ) {
 
 					switch ( depthFunc ) {
@@ -24204,6 +24302,28 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, utils,
 
 		}
 
+		if ( glFormat === _gl.RGB_INTEGER ) {
+
+			if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = _gl.RGB8UI;
+			if ( glType === _gl.UNSIGNED_SHORT ) internalFormat = _gl.RGB16UI;
+			if ( glType === _gl.UNSIGNED_INT ) internalFormat = _gl.RGB32UI;
+			if ( glType === _gl.BYTE ) internalFormat = _gl.RGB8I;
+			if ( glType === _gl.SHORT ) internalFormat = _gl.RGB16I;
+			if ( glType === _gl.INT ) internalFormat = _gl.RGB32I;
+
+		}
+
+		if ( glFormat === _gl.RGBA_INTEGER ) {
+
+			if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = _gl.RGBA8UI;
+			if ( glType === _gl.UNSIGNED_SHORT ) internalFormat = _gl.RGBA16UI;
+			if ( glType === _gl.UNSIGNED_INT ) internalFormat = _gl.RGBA32UI;
+			if ( glType === _gl.BYTE ) internalFormat = _gl.RGBA8I;
+			if ( glType === _gl.SHORT ) internalFormat = _gl.RGBA16I;
+			if ( glType === _gl.INT ) internalFormat = _gl.RGBA32I;
+
+		}
+
 		if ( glFormat === _gl.RGB ) {
 
 			if ( glType === _gl.UNSIGNED_INT_5_9_9_9_REV ) internalFormat = _gl.RGB9_E5;
@@ -28797,6 +28917,7 @@ class WebGLRenderer {
 
 		// camera matrices cache
 
+		const _currentProjectionMatrix = new Matrix4();
 		const _projScreenMatrix = new Matrix4();
 
 		const _vector3 = new Vector3();
@@ -28892,6 +29013,8 @@ class WebGLRenderer {
 
 			state = new WebGLState( _gl );
 
+			if ( capabilities.reverseDepthBuffer ) state.buffers.depth.setReversed( true );
+
 			info = new WebGLInfo( _gl );
 			properties = new WebGLProperties();
 			textures = new WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info );
@@ -29191,7 +29314,13 @@ class WebGLRenderer {
 
 			}
 
-			if ( depth ) bits |= _gl.DEPTH_BUFFER_BIT;
+			if ( depth ) {
+
+				bits |= _gl.DEPTH_BUFFER_BIT;
+				_gl.clearDepth( this.capabilities.reverseDepthBuffer ? 0 : 1 );
+
+			}
+
 			if ( stencil ) {
 
 				bits |= _gl.STENCIL_BUFFER_BIT;
@@ -29580,6 +29709,12 @@ class WebGLRenderer {
 
 			scene.traverse( function ( object ) {
 
+				if ( ! ( object.isMesh || object.isPoints || object.isLine || object.isSprite ) ) {
+
+					return;
+
+				}
+
 				const material = object.material;
 
 				if ( material ) {
@@ -30566,7 +30701,21 @@ class WebGLRenderer {
 
 				// common camera uniforms
 
-				p_uniforms.setValue( _gl, 'projectionMatrix', camera.projectionMatrix );
+				if ( capabilities.reverseDepthBuffer ) {
+
+					_currentProjectionMatrix.copy( camera.projectionMatrix );
+
+					toNormalizedProjectionMatrix( _currentProjectionMatrix );
+					toReversedProjectionMatrix( _currentProjectionMatrix );
+
+					p_uniforms.setValue( _gl, 'projectionMatrix', _currentProjectionMatrix );
+
+				} else {
+
+					p_uniforms.setValue( _gl, 'projectionMatrix', camera.projectionMatrix );
+
+				}
+
 				p_uniforms.setValue( _gl, 'viewMatrix', camera.matrixWorldInverse );
 
 				const uCamPos = p_uniforms.map.cameraPosition;
@@ -31047,61 +31196,55 @@ class WebGLRenderer {
 
 			if ( framebuffer ) {
 
-				state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
-
-				try {
-
-					const texture = renderTarget.texture;
-					const textureFormat = texture.format;
-					const textureType = texture.type;
-
-					if ( ! capabilities.textureFormatReadable( textureFormat ) ) {
-
-						throw new Error( 'THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in RGBA or implementation defined format.' );
+				const texture = renderTarget.texture;
+				const textureFormat = texture.format;
+				const textureType = texture.type;
 
-					}
+				if ( ! capabilities.textureFormatReadable( textureFormat ) ) {
 
-					if ( ! capabilities.textureTypeReadable( textureType ) ) {
+					throw new Error( 'THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in RGBA or implementation defined format.' );
 
-						throw new Error( 'THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in UnsignedByteType or implementation defined type.' );
+				}
 
-					}
+				if ( ! capabilities.textureTypeReadable( textureType ) ) {
 
-					// the following if statement ensures valid read requests (no out-of-bounds pixels, see #8604)
-					if ( ( x >= 0 && x <= ( renderTarget.width - width ) ) && ( y >= 0 && y <= ( renderTarget.height - height ) ) ) {
+					throw new Error( 'THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in UnsignedByteType or implementation defined type.' );
 
-						const glBuffer = _gl.createBuffer();
-						_gl.bindBuffer( _gl.PIXEL_PACK_BUFFER, glBuffer );
-						_gl.bufferData( _gl.PIXEL_PACK_BUFFER, buffer.byteLength, _gl.STREAM_READ );
-						_gl.readPixels( x, y, width, height, utils.convert( textureFormat ), utils.convert( textureType ), 0 );
-						_gl.flush();
+				}
 
-						// check if the commands have finished every 8 ms
-						const sync = _gl.fenceSync( _gl.SYNC_GPU_COMMANDS_COMPLETE, 0 );
-						await probeAsync( _gl, sync, 4 );
+				// the following if statement ensures valid read requests (no out-of-bounds pixels, see #8604)
+				if ( ( x >= 0 && x <= ( renderTarget.width - width ) ) && ( y >= 0 && y <= ( renderTarget.height - height ) ) ) {
 
-						try {
+					// set the active frame buffer to the one we want to read
+					state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
 
-							_gl.bindBuffer( _gl.PIXEL_PACK_BUFFER, glBuffer );
-							_gl.getBufferSubData( _gl.PIXEL_PACK_BUFFER, 0, buffer );
+					const glBuffer = _gl.createBuffer();
+					_gl.bindBuffer( _gl.PIXEL_PACK_BUFFER, glBuffer );
+					_gl.bufferData( _gl.PIXEL_PACK_BUFFER, buffer.byteLength, _gl.STREAM_READ );
+					_gl.readPixels( x, y, width, height, utils.convert( textureFormat ), utils.convert( textureType ), 0 );
 
-						} finally {
+					// reset the frame buffer to the currently set buffer before waiting
+					const currFramebuffer = _currentRenderTarget !== null ? properties.get( _currentRenderTarget ).__webglFramebuffer : null;
+					state.bindFramebuffer( _gl.FRAMEBUFFER, currFramebuffer );
 
-							_gl.deleteBuffer( glBuffer );
-							_gl.deleteSync( sync );
+					// check if the commands have finished every 8 ms
+					const sync = _gl.fenceSync( _gl.SYNC_GPU_COMMANDS_COMPLETE, 0 );
 
-						}
+					_gl.flush();
 
-						return buffer;
+					await probeAsync( _gl, sync, 4 );
 
-					}
+					// read the data and delete the buffer
+					_gl.bindBuffer( _gl.PIXEL_PACK_BUFFER, glBuffer );
+					_gl.getBufferSubData( _gl.PIXEL_PACK_BUFFER, 0, buffer );
+					_gl.deleteBuffer( glBuffer );
+					_gl.deleteSync( sync );
 
-				} finally {
+					return buffer;
 
-					// restore framebuffer of current render target if necessary
+				} else {
 
-					const framebuffer = ( _currentRenderTarget !== null ) ? properties.get( _currentRenderTarget ).__webglFramebuffer : null;
-					state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
+					throw new Error( 'THREE.WebGLRenderer.readRenderTargetPixelsAsync: requested read bounds are out of range.' );
 
 				}
 
@@ -31587,7 +31730,6 @@ class InterleavedBuffer {
 		this.count = array !== undefined ? array.length / stride : 0;
 
 		this.usage = StaticDrawUsage;
-		this._updateRange = { offset: 0, count: - 1 };
 		this.updateRanges = [];
 
 		this.version = 0;
@@ -31604,13 +31746,6 @@ class InterleavedBuffer {
 
 	}
 
-	get updateRange() {
-
-		warnOnce( 'THREE.InterleavedBuffer: updateRange() is deprecated and will be removed in r169. Use addUpdateRange() instead.' ); // @deprecated, r159
-		return this._updateRange;
-
-	}
-
 	setUsage( value ) {
 
 		this.usage = value;
@@ -32375,6 +32510,27 @@ class LOD extends Object3D {
 
 	}
 
+	removeLevel( distance ) {
+
+		const levels = this.levels;
+
+		for ( let i = 0; i < levels.length; i ++ ) {
+
+			if ( levels[ i ].distance === distance ) {
+
+				const removedElements = levels.splice( i, 1 );
+				this.remove( removedElements[ 0 ].object );
+
+				return true;
+
+			}
+
+		}
+
+		return false;
+
+	}
+
 	getCurrentLevel() {
 
 		return this._currentLevel;
@@ -33494,6 +33650,9 @@ class BatchedMesh extends Mesh {
 		// stores visible, active, and geometry id per object
 		this._drawInfo = [];
 
+		// instance ids that have been set as inactive, and are available to be overwritten
+		this._availableInstanceIds = [];
+
 		// geometry information
 		this._drawRanges = [];
 		this._reservedRanges = [];
@@ -33693,23 +33852,36 @@ class BatchedMesh extends Mesh {
 
 	addInstance( geometryId ) {
 
+		const atCapacity = this._drawInfo.length >= this.maxInstanceCount;
+
 		// ensure we're not over geometry
-		if ( this._drawInfo.length >= this._maxInstanceCount ) {
+		if ( atCapacity && this._availableInstanceIds.length === 0 ) {
 
 			throw new Error( 'BatchedMesh: Maximum item count reached.' );
 
 		}
 
-		this._drawInfo.push( {
-
+		const instanceDrawInfo = {
 			visible: true,
 			active: true,
 			geometryIndex: geometryId,
+		};
 
-		} );
+		let drawId = null;
+
+		// Prioritize using previously freed instance ids
+		if ( this._availableInstanceIds.length > 0 ) {
+
+			drawId = this._availableInstanceIds.pop();
+			this._drawInfo[ drawId ] = instanceDrawInfo;
+
+		} else {
+
+			drawId = this._drawInfo.length;
+			this._drawInfo.push( instanceDrawInfo );
+
+		}
 
-		// initialize the matrix
-		const drawId = this._drawInfo.length - 1;
 		const matricesTexture = this._matricesTexture;
 		const matricesArray = matricesTexture.image.data;
 		_identityMatrix.toArray( matricesArray, drawId * 16 );
@@ -33958,11 +34130,8 @@ class BatchedMesh extends Mesh {
 	}
 	*/
 
-	/*
 	deleteInstance( instanceId ) {
 
-		// Note: User needs to call optimize() afterward to pack the data.
-
 		const drawInfo = this._drawInfo;
 		if ( instanceId >= drawInfo.length || drawInfo[ instanceId ].active === false ) {
 
@@ -33971,12 +34140,12 @@ class BatchedMesh extends Mesh {
 		}
 
 		drawInfo[ instanceId ].active = false;
+		this._availableInstanceIds.push( instanceId );
 		this._visibilityChanged = true;
 
 		return this;
 
 	}
-	*/
 
 	// get bounding box and compute it if it doesn't exist
 	getBoundingBoxAt( geometryId, target ) {
@@ -34181,6 +34350,59 @@ class BatchedMesh extends Mesh {
 
 	}
 
+	setGeometryIdAt( instanceId, geometryId ) {
+
+		// return early if the geometry is out of range or not active
+		const drawInfo = this._drawInfo;
+		if ( instanceId >= drawInfo.length || drawInfo[ instanceId ].active === false ) {
+
+			return null;
+
+		}
+
+		// check if the provided geometryId is within the valid range
+		if ( geometryId < 0 || geometryId >= this._geometryCount ) {
+
+			return null;
+
+		}
+
+		drawInfo[ instanceId ].geometryIndex = geometryId;
+
+		return this;
+
+	}
+
+	getGeometryIdAt( instanceId ) {
+
+		const drawInfo = this._drawInfo;
+		if ( instanceId >= drawInfo.length || drawInfo[ instanceId ].active === false ) {
+
+			return - 1;
+
+		}
+
+		return drawInfo[ instanceId ].geometryIndex;
+
+	}
+
+	getGeometryRangeAt( geometryId, target = {} ) {
+
+		if ( geometryId < 0 || geometryId >= this._geometryCount ) {
+
+			return null;
+
+		}
+
+		const drawRange = this._drawRanges[ geometryId ];
+
+		target.start = drawRange.start;
+		target.count = drawRange.count;
+
+		return target;
+
+	}
+
 	raycast( raycaster, intersects ) {
 
 		const drawInfo = this._drawInfo;
@@ -34732,6 +34954,7 @@ function checkIntersection( object, raycaster, ray, thresholdSq, a, b ) {
 		index: a,
 		face: null,
 		faceIndex: null,
+		barycoord: null,
 		object: object
 
 	};
@@ -34997,6 +35220,8 @@ function testPoint( point, index, localThresholdSq, matrixWorld, raycaster, inte
 			point: intersectPoint,
 			index: index,
 			face: null,
+			faceIndex: null,
+			barycoord: null,
 			object: object
 
 		} );
@@ -37499,12 +37724,19 @@ class CylinderGeometry extends BufferGeometry {
 
 					// faces
 
-					indices.push( a, b, d );
-					indices.push( b, c, d );
+					if ( radiusTop > 0 ) {
 
-					// update group counter
+						indices.push( a, b, d );
+						groupCount += 3;
 
-					groupCount += 6;
+					}
+
+					if ( radiusBottom > 0 ) {
+
+						indices.push( b, c, d );
+						groupCount += 3;
+
+					}
 
 				}
 
@@ -45814,7 +46046,7 @@ class MaterialLoader extends Loader {
 
 		}
 
-		const material = MaterialLoader.createMaterialFromType( json.type );
+		const material = this.createMaterialFromType( json.type );
 
 		if ( json.uuid !== undefined ) material.uuid = json.uuid;
 		if ( json.name !== undefined ) material.name = json.name;
@@ -46070,6 +46302,12 @@ class MaterialLoader extends Loader {
 
 	}
 
+	createMaterialFromType( type ) {
+
+		return MaterialLoader.createMaterialFromType( type );
+
+	}
+
 	static createMaterialFromType( type ) {
 
 		const materialLib = {
@@ -47900,7 +48138,7 @@ class Clock {
 
 function now() {
 
-	return ( typeof performance === 'undefined' ? Date : performance ).now(); // see #10732
+	return performance.now();
 
 }
 
@@ -48192,7 +48430,7 @@ class Audio extends Object3D {
 
 	}
 
-	stop() {
+	stop( delay = 0 ) {
 
 		if ( this.hasPlaybackControl === false ) {
 
@@ -48205,7 +48443,7 @@ class Audio extends Object3D {
 
 		if ( this.source !== null ) {
 
-			this.source.stop();
+			this.source.stop( this.context.currentTime + delay );
 			this.source.onended = null;
 
 		}
@@ -53847,7 +54085,7 @@ class ShapePath {
 
 class Controls extends EventDispatcher {
 
-	constructor( object, domElement ) {
+	constructor( object, domElement = null ) {
 
 		super();
 

+ 368 - 130
build/three.module.js

@@ -3,7 +3,7 @@
  * Copyright 2010-2024 Three.js Authors
  * SPDX-License-Identifier: MIT
  */
-const REVISION = '168';
+const REVISION = '169';
 
 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 };
@@ -1592,6 +1592,38 @@ function probeAsync( gl, sync, interval ) {
 
 }
 
+function toNormalizedProjectionMatrix( projectionMatrix ) {
+
+	const m = projectionMatrix.elements;
+
+	// Convert [-1, 1] to [0, 1] projection matrix
+	m[ 2 ] = 0.5 * m[ 2 ] + 0.5 * m[ 3 ];
+	m[ 6 ] = 0.5 * m[ 6 ] + 0.5 * m[ 7 ];
+	m[ 10 ] = 0.5 * m[ 10 ] + 0.5 * m[ 11 ];
+	m[ 14 ] = 0.5 * m[ 14 ] + 0.5 * m[ 15 ];
+
+}
+
+function toReversedProjectionMatrix( projectionMatrix ) {
+
+	const m = projectionMatrix.elements;
+	const isPerspectiveMatrix = m[ 11 ] === - 1;
+
+	// Reverse [0, 1] projection matrix
+	if ( isPerspectiveMatrix ) {
+
+		m[ 10 ] = - m[ 10 ] - 1;
+		m[ 14 ] = - m[ 14 ];
+
+	} else {
+
+		m[ 10 ] = - m[ 10 ];
+		m[ 14 ] = - m[ 14 ] + 1;
+
+	}
+
+}
+
 /**
  * Matrices converting P3 <-> Rec. 709 primaries, without gamut mapping
  * or clipping. Based on W3C specifications for sRGB and Display P3,
@@ -8187,6 +8219,10 @@ const _vap = /*@__PURE__*/ new Vector3();
 const _vbp = /*@__PURE__*/ new Vector3();
 const _vcp = /*@__PURE__*/ new Vector3();
 
+const _v40 = /*@__PURE__*/ new Vector4();
+const _v41 = /*@__PURE__*/ new Vector4();
+const _v42 = /*@__PURE__*/ new Vector4();
+
 class Triangle {
 
 	constructor( a = new Vector3(), b = new Vector3(), c = new Vector3() ) {
@@ -8281,6 +8317,25 @@ class Triangle {
 
 	}
 
+	static getInterpolatedAttribute( attr, i1, i2, i3, barycoord, target ) {
+
+		_v40.setScalar( 0 );
+		_v41.setScalar( 0 );
+		_v42.setScalar( 0 );
+
+		_v40.fromBufferAttribute( attr, i1 );
+		_v41.fromBufferAttribute( attr, i2 );
+		_v42.fromBufferAttribute( attr, i3 );
+
+		target.setScalar( 0 );
+		target.addScaledVector( _v40, barycoord.x );
+		target.addScaledVector( _v41, barycoord.y );
+		target.addScaledVector( _v42, barycoord.z );
+
+		return target;
+
+	}
+
 	static isFrontFacing( a, b, c, direction ) {
 
 		_v0$2.subVectors( c, b );
@@ -9896,7 +9951,6 @@ class BufferAttribute {
 		this.normalized = normalized;
 
 		this.usage = StaticDrawUsage;
-		this._updateRange = { offset: 0, count: - 1 };
 		this.updateRanges = [];
 		this.gpuType = FloatType;
 
@@ -9912,13 +9966,6 @@ class BufferAttribute {
 
 	}
 
-	get updateRange() {
-
-		warnOnce( 'THREE.BufferAttribute: updateRange() is deprecated and will be removed in r169. Use addUpdateRange() instead.' ); // @deprecated, r159
-		return this._updateRange;
-
-	}
-
 	setUsage( value ) {
 
 		this.usage = value;
@@ -11563,14 +11610,6 @@ const _vC$1 = /*@__PURE__*/ new Vector3();
 const _tempA = /*@__PURE__*/ new Vector3();
 const _morphA = /*@__PURE__*/ new Vector3();
 
-const _uvA$1 = /*@__PURE__*/ new Vector2();
-const _uvB$1 = /*@__PURE__*/ new Vector2();
-const _uvC$1 = /*@__PURE__*/ new Vector2();
-
-const _normalA = /*@__PURE__*/ new Vector3();
-const _normalB = /*@__PURE__*/ new Vector3();
-const _normalC = /*@__PURE__*/ new Vector3();
-
 const _intersectionPoint = /*@__PURE__*/ new Vector3();
 const _intersectionPointWorld = /*@__PURE__*/ new Vector3();
 
@@ -11913,33 +11952,24 @@ function checkGeometryIntersection( object, material, raycaster, ray, uv, uv1, n
 
 	if ( intersection ) {
 
-		if ( uv ) {
+		const barycoord = new Vector3();
+		Triangle.getBarycoord( _intersectionPoint, _vA$1, _vB$1, _vC$1, barycoord );
 
-			_uvA$1.fromBufferAttribute( uv, a );
-			_uvB$1.fromBufferAttribute( uv, b );
-			_uvC$1.fromBufferAttribute( uv, c );
+		if ( uv ) {
 
-			intersection.uv = Triangle.getInterpolation( _intersectionPoint, _vA$1, _vB$1, _vC$1, _uvA$1, _uvB$1, _uvC$1, new Vector2() );
+			intersection.uv = Triangle.getInterpolatedAttribute( uv, a, b, c, barycoord, new Vector2() );
 
 		}
 
 		if ( uv1 ) {
 
-			_uvA$1.fromBufferAttribute( uv1, a );
-			_uvB$1.fromBufferAttribute( uv1, b );
-			_uvC$1.fromBufferAttribute( uv1, c );
-
-			intersection.uv1 = Triangle.getInterpolation( _intersectionPoint, _vA$1, _vB$1, _vC$1, _uvA$1, _uvB$1, _uvC$1, new Vector2() );
+			intersection.uv1 = Triangle.getInterpolatedAttribute( uv1, a, b, c, barycoord, new Vector2() );
 
 		}
 
 		if ( normal ) {
 
-			_normalA.fromBufferAttribute( normal, a );
-			_normalB.fromBufferAttribute( normal, b );
-			_normalC.fromBufferAttribute( normal, c );
-
-			intersection.normal = Triangle.getInterpolation( _intersectionPoint, _vA$1, _vB$1, _vC$1, _normalA, _normalB, _normalC, new Vector3() );
+			intersection.normal = Triangle.getInterpolatedAttribute( normal, a, b, c, barycoord, new Vector3() );
 
 			if ( intersection.normal.dot( ray.direction ) > 0 ) {
 
@@ -11960,6 +11990,7 @@ function checkGeometryIntersection( object, material, raycaster, ray, uv, uv1, n
 		Triangle.getNormal( _vA$1, _vB$1, _vC$1, face.normal );
 
 		intersection.face = face;
+		intersection.barycoord = barycoord;
 
 	}
 
@@ -13603,40 +13634,71 @@ function WebGLAttributes( gl ) {
 	function updateBuffer( buffer, attribute, bufferType ) {
 
 		const array = attribute.array;
-		const updateRange = attribute._updateRange; // @deprecated, r159
 		const updateRanges = attribute.updateRanges;
 
 		gl.bindBuffer( bufferType, buffer );
 
-		if ( updateRange.count === - 1 && updateRanges.length === 0 ) {
+		if ( updateRanges.length === 0 ) {
 
 			// Not using update ranges
 			gl.bufferSubData( bufferType, 0, array );
 
-		}
+		} else {
 
-		if ( updateRanges.length !== 0 ) {
+			// Before applying update ranges, we merge any adjacent / overlapping
+			// ranges to reduce load on `gl.bufferSubData`. Empirically, this has led
+			// to performance improvements for applications which make heavy use of
+			// update ranges. Likely due to GPU command overhead.
+			//
+			// Note that to reduce garbage collection between frames, we merge the
+			// update ranges in-place. This is safe because this method will clear the
+			// update ranges once updated.
 
-			for ( let i = 0, l = updateRanges.length; i < l; i ++ ) {
+			updateRanges.sort( ( a, b ) => a.start - b.start );
 
+			// To merge the update ranges in-place, we work from left to right in the
+			// existing updateRanges array, merging ranges. This may result in a final
+			// array which is smaller than the original. This index tracks the last
+			// index representing a merged range, any data after this index can be
+			// trimmed once the merge algorithm is completed.
+			let mergeIndex = 0;
+
+			for ( let i = 1; i < updateRanges.length; i ++ ) {
+
+				const previousRange = updateRanges[ mergeIndex ];
 				const range = updateRanges[ i ];
 
-				gl.bufferSubData( bufferType, range.start * array.BYTES_PER_ELEMENT,
-					array, range.start, range.count );
+				// We add one here to merge adjacent ranges. This is safe because ranges
+				// operate over positive integers.
+				if ( range.start <= previousRange.start + previousRange.count + 1 ) {
+
+					previousRange.count = Math.max(
+						previousRange.count,
+						range.start + range.count - previousRange.start
+					);
+
+				} else {
+
+					++ mergeIndex;
+					updateRanges[ mergeIndex ] = range;
+
+				}
 
 			}
 
-			attribute.clearUpdateRanges();
+			// Trim the array to only contain the merged ranges.
+			updateRanges.length = mergeIndex + 1;
 
-		}
+			for ( let i = 0, l = updateRanges.length; i < l; i ++ ) {
 
-		// @deprecated, r159
-		if ( updateRange.count !== - 1 ) {
+				const range = updateRanges[ i ];
 
-			gl.bufferSubData( bufferType, updateRange.offset * array.BYTES_PER_ELEMENT,
-				array, updateRange.offset, updateRange.count );
+				gl.bufferSubData( bufferType, range.start * array.BYTES_PER_ELEMENT,
+					array, range.start, range.count );
+
+			}
 
-			updateRange.count = - 1; // reset range
+			attribute.clearUpdateRanges();
 
 		}
 
@@ -14097,7 +14159,7 @@ const vertex$2 = "#include <common>\n#include <batching_pars_vertex>\n#include <
 
 const fragment$2 = "uniform vec3 color;\nuniform float opacity;\n#include <common>\n#include <packing>\n#include <fog_pars_fragment>\n#include <bsdfs>\n#include <lights_pars_begin>\n#include <logdepthbuf_pars_fragment>\n#include <shadowmap_pars_fragment>\n#include <shadowmask_pars_fragment>\nvoid main() {\n\t#include <logdepthbuf_fragment>\n\tgl_FragColor = vec4( color, opacity * ( 1.0 - getShadowMask() ) );\n\t#include <tonemapping_fragment>\n\t#include <colorspace_fragment>\n\t#include <fog_fragment>\n}";
 
-const vertex$1 = "uniform float rotation;\nuniform vec2 center;\n#include <common>\n#include <uv_pars_vertex>\n#include <fog_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\tvec4 mvPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );\n\tvec2 scale;\n\tscale.x = length( vec3( modelMatrix[ 0 ].x, modelMatrix[ 0 ].y, modelMatrix[ 0 ].z ) );\n\tscale.y = length( vec3( modelMatrix[ 1 ].x, modelMatrix[ 1 ].y, modelMatrix[ 1 ].z ) );\n\t#ifndef USE_SIZEATTENUATION\n\t\tbool isPerspective = isPerspectiveMatrix( projectionMatrix );\n\t\tif ( isPerspective ) scale *= - mvPosition.z;\n\t#endif\n\tvec2 alignedPosition = ( position.xy - ( center - vec2( 0.5 ) ) ) * scale;\n\tvec2 rotatedPosition;\n\trotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;\n\trotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;\n\tmvPosition.xy += rotatedPosition;\n\tgl_Position = projectionMatrix * mvPosition;\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\t#include <fog_vertex>\n}";
+const vertex$1 = "uniform float rotation;\nuniform vec2 center;\n#include <common>\n#include <uv_pars_vertex>\n#include <fog_pars_vertex>\n#include <logdepthbuf_pars_vertex>\n#include <clipping_planes_pars_vertex>\nvoid main() {\n\t#include <uv_vertex>\n\tvec4 mvPosition = modelViewMatrix[ 3 ];\n\tvec2 scale = vec2( length( modelMatrix[ 0 ].xyz ), length( modelMatrix[ 1 ].xyz ) );\n\t#ifndef USE_SIZEATTENUATION\n\t\tbool isPerspective = isPerspectiveMatrix( projectionMatrix );\n\t\tif ( isPerspective ) scale *= - mvPosition.z;\n\t#endif\n\tvec2 alignedPosition = ( position.xy - ( center - vec2( 0.5 ) ) ) * scale;\n\tvec2 rotatedPosition;\n\trotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;\n\trotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;\n\tmvPosition.xy += rotatedPosition;\n\tgl_Position = projectionMatrix * mvPosition;\n\t#include <logdepthbuf_vertex>\n\t#include <clipping_planes_vertex>\n\t#include <fog_vertex>\n}";
 
 const fragment$1 = "uniform vec3 diffuse;\nuniform float opacity;\n#include <common>\n#include <uv_pars_fragment>\n#include <map_pars_fragment>\n#include <alphamap_pars_fragment>\n#include <alphatest_pars_fragment>\n#include <alphahash_pars_fragment>\n#include <fog_pars_fragment>\n#include <logdepthbuf_pars_fragment>\n#include <clipping_planes_pars_fragment>\nvoid main() {\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include <clipping_planes_fragment>\n\tvec3 outgoingLight = vec3( 0.0 );\n\t#include <logdepthbuf_fragment>\n\t#include <map_fragment>\n\t#include <alphamap_fragment>\n\t#include <alphatest_fragment>\n\t#include <alphahash_fragment>\n\toutgoingLight = diffuseColor.rgb;\n\t#include <opaque_fragment>\n\t#include <tonemapping_fragment>\n\t#include <colorspace_fragment>\n\t#include <fog_fragment>\n}";
 
@@ -15863,6 +15925,14 @@ function WebGLCapabilities( gl, extensions, parameters, utils ) {
 	}
 
 	const logarithmicDepthBuffer = parameters.logarithmicDepthBuffer === true;
+	const reverseDepthBuffer = parameters.reverseDepthBuffer === true && extensions.has( 'EXT_clip_control' );
+
+	if ( reverseDepthBuffer === true ) {
+
+		const ext = extensions.get( 'EXT_clip_control' );
+		ext.clipControlEXT( ext.LOWER_LEFT_EXT, ext.ZERO_TO_ONE_EXT );
+
+	}
 
 	const maxTextures = gl.getParameter( gl.MAX_TEXTURE_IMAGE_UNITS );
 	const maxVertexTextures = gl.getParameter( gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS );
@@ -15890,6 +15960,7 @@ function WebGLCapabilities( gl, extensions, parameters, utils ) {
 
 		precision: precision,
 		logarithmicDepthBuffer: logarithmicDepthBuffer,
+		reverseDepthBuffer: reverseDepthBuffer,
 
 		maxTextures: maxTextures,
 		maxVertexTextures: maxVertexTextures,
@@ -19907,6 +19978,7 @@ function WebGLProgram( renderer, cacheKey, parameters, bindingStates ) {
 			parameters.numLightProbes > 0 ? '#define USE_LIGHT_PROBES' : '',
 
 			parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '',
+			parameters.reverseDepthBuffer ? '#define USE_REVERSEDEPTHBUF' : '',
 
 			'uniform mat4 modelMatrix;',
 			'uniform mat4 modelViewMatrix;',
@@ -20072,6 +20144,7 @@ function WebGLProgram( renderer, cacheKey, parameters, bindingStates ) {
 			parameters.decodeVideoTexture ? '#define DECODE_VIDEO_TEXTURE' : '',
 
 			parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '',
+			parameters.reverseDepthBuffer ? '#define USE_REVERSEDEPTHBUF' : '',
 
 			'uniform mat4 viewMatrix;',
 			'uniform vec3 cameraPosition;',
@@ -20464,6 +20537,7 @@ function WebGLPrograms( renderer, cubemaps, cubeuvmaps, extensions, capabilities
 	const programs = [];
 
 	const logarithmicDepthBuffer = capabilities.logarithmicDepthBuffer;
+	const reverseDepthBuffer = capabilities.reverseDepthBuffer;
 	const SUPPORTS_VERTEX_TEXTURES = capabilities.vertexTextures;
 
 	let precision = capabilities.precision;
@@ -20755,6 +20829,7 @@ function WebGLPrograms( renderer, cubemaps, cubeuvmaps, extensions, capabilities
 
 			sizeAttenuation: material.sizeAttenuation === true,
 			logarithmicDepthBuffer: logarithmicDepthBuffer,
+			reverseDepthBuffer: reverseDepthBuffer,
 
 			skinning: object.isSkinnedMesh === true,
 
@@ -20974,38 +21049,40 @@ function WebGLPrograms( renderer, cubemaps, cubeuvmaps, extensions, capabilities
 			_programLayers.enable( 2 );
 		if ( parameters.logarithmicDepthBuffer )
 			_programLayers.enable( 3 );
-		if ( parameters.skinning )
+		if ( parameters.reverseDepthBuffer )
 			_programLayers.enable( 4 );
-		if ( parameters.morphTargets )
+		if ( parameters.skinning )
 			_programLayers.enable( 5 );
-		if ( parameters.morphNormals )
+		if ( parameters.morphTargets )
 			_programLayers.enable( 6 );
-		if ( parameters.morphColors )
+		if ( parameters.morphNormals )
 			_programLayers.enable( 7 );
-		if ( parameters.premultipliedAlpha )
+		if ( parameters.morphColors )
 			_programLayers.enable( 8 );
-		if ( parameters.shadowMapEnabled )
+		if ( parameters.premultipliedAlpha )
 			_programLayers.enable( 9 );
-		if ( parameters.doubleSided )
+		if ( parameters.shadowMapEnabled )
 			_programLayers.enable( 10 );
-		if ( parameters.flipSided )
+		if ( parameters.doubleSided )
 			_programLayers.enable( 11 );
-		if ( parameters.useDepthPacking )
+		if ( parameters.flipSided )
 			_programLayers.enable( 12 );
-		if ( parameters.dithering )
+		if ( parameters.useDepthPacking )
 			_programLayers.enable( 13 );
-		if ( parameters.transmission )
+		if ( parameters.dithering )
 			_programLayers.enable( 14 );
-		if ( parameters.sheen )
+		if ( parameters.transmission )
 			_programLayers.enable( 15 );
-		if ( parameters.opaque )
+		if ( parameters.sheen )
 			_programLayers.enable( 16 );
-		if ( parameters.pointsUvs )
+		if ( parameters.opaque )
 			_programLayers.enable( 17 );
-		if ( parameters.decodeVideoTexture )
+		if ( parameters.pointsUvs )
 			_programLayers.enable( 18 );
-		if ( parameters.alphaToCoverage )
+		if ( parameters.decodeVideoTexture )
 			_programLayers.enable( 19 );
+		if ( parameters.alphaToCoverage )
+			_programLayers.enable( 20 );
 
 		array.push( _programLayers.mask );
 
@@ -22563,6 +22640,18 @@ function WebGLShadowMap( renderer, objects, capabilities ) {
 
 }
 
+const reversedFuncs = {
+	[ NeverDepth ]: AlwaysDepth,
+	[ LessDepth ]: GreaterDepth,
+	[ EqualDepth ]: NotEqualDepth,
+	[ LessEqualDepth ]: GreaterEqualDepth,
+
+	[ AlwaysDepth ]: NeverDepth,
+	[ GreaterDepth ]: LessDepth,
+	[ NotEqualDepth ]: EqualDepth,
+	[ GreaterEqualDepth ]: LessEqualDepth,
+};
+
 function WebGLState( gl ) {
 
 	function ColorBuffer() {
@@ -22627,6 +22716,7 @@ function WebGLState( gl ) {
 	function DepthBuffer() {
 
 		let locked = false;
+		let reversed = false;
 
 		let currentDepthMask = null;
 		let currentDepthFunc = null;
@@ -22634,6 +22724,12 @@ function WebGLState( gl ) {
 
 		return {
 
+			setReversed: function ( value ) {
+
+				reversed = value;
+
+			},
+
 			setTest: function ( depthTest ) {
 
 				if ( depthTest ) {
@@ -22661,6 +22757,8 @@ function WebGLState( gl ) {
 
 			setFunc: function ( depthFunc ) {
 
+				if ( reversed ) depthFunc = reversedFuncs[ depthFunc ];
+
 				if ( currentDepthFunc !== depthFunc ) {
 
 					switch ( depthFunc ) {
@@ -24202,6 +24300,28 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, utils,
 
 		}
 
+		if ( glFormat === _gl.RGB_INTEGER ) {
+
+			if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = _gl.RGB8UI;
+			if ( glType === _gl.UNSIGNED_SHORT ) internalFormat = _gl.RGB16UI;
+			if ( glType === _gl.UNSIGNED_INT ) internalFormat = _gl.RGB32UI;
+			if ( glType === _gl.BYTE ) internalFormat = _gl.RGB8I;
+			if ( glType === _gl.SHORT ) internalFormat = _gl.RGB16I;
+			if ( glType === _gl.INT ) internalFormat = _gl.RGB32I;
+
+		}
+
+		if ( glFormat === _gl.RGBA_INTEGER ) {
+
+			if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = _gl.RGBA8UI;
+			if ( glType === _gl.UNSIGNED_SHORT ) internalFormat = _gl.RGBA16UI;
+			if ( glType === _gl.UNSIGNED_INT ) internalFormat = _gl.RGBA32UI;
+			if ( glType === _gl.BYTE ) internalFormat = _gl.RGBA8I;
+			if ( glType === _gl.SHORT ) internalFormat = _gl.RGBA16I;
+			if ( glType === _gl.INT ) internalFormat = _gl.RGBA32I;
+
+		}
+
 		if ( glFormat === _gl.RGB ) {
 
 			if ( glType === _gl.UNSIGNED_INT_5_9_9_9_REV ) internalFormat = _gl.RGB9_E5;
@@ -28795,6 +28915,7 @@ class WebGLRenderer {
 
 		// camera matrices cache
 
+		const _currentProjectionMatrix = new Matrix4();
 		const _projScreenMatrix = new Matrix4();
 
 		const _vector3 = new Vector3();
@@ -28890,6 +29011,8 @@ class WebGLRenderer {
 
 			state = new WebGLState( _gl );
 
+			if ( capabilities.reverseDepthBuffer ) state.buffers.depth.setReversed( true );
+
 			info = new WebGLInfo( _gl );
 			properties = new WebGLProperties();
 			textures = new WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info );
@@ -29189,7 +29312,13 @@ class WebGLRenderer {
 
 			}
 
-			if ( depth ) bits |= _gl.DEPTH_BUFFER_BIT;
+			if ( depth ) {
+
+				bits |= _gl.DEPTH_BUFFER_BIT;
+				_gl.clearDepth( this.capabilities.reverseDepthBuffer ? 0 : 1 );
+
+			}
+
 			if ( stencil ) {
 
 				bits |= _gl.STENCIL_BUFFER_BIT;
@@ -29578,6 +29707,12 @@ class WebGLRenderer {
 
 			scene.traverse( function ( object ) {
 
+				if ( ! ( object.isMesh || object.isPoints || object.isLine || object.isSprite ) ) {
+
+					return;
+
+				}
+
 				const material = object.material;
 
 				if ( material ) {
@@ -30564,7 +30699,21 @@ class WebGLRenderer {
 
 				// common camera uniforms
 
-				p_uniforms.setValue( _gl, 'projectionMatrix', camera.projectionMatrix );
+				if ( capabilities.reverseDepthBuffer ) {
+
+					_currentProjectionMatrix.copy( camera.projectionMatrix );
+
+					toNormalizedProjectionMatrix( _currentProjectionMatrix );
+					toReversedProjectionMatrix( _currentProjectionMatrix );
+
+					p_uniforms.setValue( _gl, 'projectionMatrix', _currentProjectionMatrix );
+
+				} else {
+
+					p_uniforms.setValue( _gl, 'projectionMatrix', camera.projectionMatrix );
+
+				}
+
 				p_uniforms.setValue( _gl, 'viewMatrix', camera.matrixWorldInverse );
 
 				const uCamPos = p_uniforms.map.cameraPosition;
@@ -31045,61 +31194,55 @@ class WebGLRenderer {
 
 			if ( framebuffer ) {
 
-				state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
-
-				try {
-
-					const texture = renderTarget.texture;
-					const textureFormat = texture.format;
-					const textureType = texture.type;
-
-					if ( ! capabilities.textureFormatReadable( textureFormat ) ) {
-
-						throw new Error( 'THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in RGBA or implementation defined format.' );
+				const texture = renderTarget.texture;
+				const textureFormat = texture.format;
+				const textureType = texture.type;
 
-					}
+				if ( ! capabilities.textureFormatReadable( textureFormat ) ) {
 
-					if ( ! capabilities.textureTypeReadable( textureType ) ) {
+					throw new Error( 'THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in RGBA or implementation defined format.' );
 
-						throw new Error( 'THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in UnsignedByteType or implementation defined type.' );
+				}
 
-					}
+				if ( ! capabilities.textureTypeReadable( textureType ) ) {
 
-					// the following if statement ensures valid read requests (no out-of-bounds pixels, see #8604)
-					if ( ( x >= 0 && x <= ( renderTarget.width - width ) ) && ( y >= 0 && y <= ( renderTarget.height - height ) ) ) {
+					throw new Error( 'THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in UnsignedByteType or implementation defined type.' );
 
-						const glBuffer = _gl.createBuffer();
-						_gl.bindBuffer( _gl.PIXEL_PACK_BUFFER, glBuffer );
-						_gl.bufferData( _gl.PIXEL_PACK_BUFFER, buffer.byteLength, _gl.STREAM_READ );
-						_gl.readPixels( x, y, width, height, utils.convert( textureFormat ), utils.convert( textureType ), 0 );
-						_gl.flush();
+				}
 
-						// check if the commands have finished every 8 ms
-						const sync = _gl.fenceSync( _gl.SYNC_GPU_COMMANDS_COMPLETE, 0 );
-						await probeAsync( _gl, sync, 4 );
+				// the following if statement ensures valid read requests (no out-of-bounds pixels, see #8604)
+				if ( ( x >= 0 && x <= ( renderTarget.width - width ) ) && ( y >= 0 && y <= ( renderTarget.height - height ) ) ) {
 
-						try {
+					// set the active frame buffer to the one we want to read
+					state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
 
-							_gl.bindBuffer( _gl.PIXEL_PACK_BUFFER, glBuffer );
-							_gl.getBufferSubData( _gl.PIXEL_PACK_BUFFER, 0, buffer );
+					const glBuffer = _gl.createBuffer();
+					_gl.bindBuffer( _gl.PIXEL_PACK_BUFFER, glBuffer );
+					_gl.bufferData( _gl.PIXEL_PACK_BUFFER, buffer.byteLength, _gl.STREAM_READ );
+					_gl.readPixels( x, y, width, height, utils.convert( textureFormat ), utils.convert( textureType ), 0 );
 
-						} finally {
+					// reset the frame buffer to the currently set buffer before waiting
+					const currFramebuffer = _currentRenderTarget !== null ? properties.get( _currentRenderTarget ).__webglFramebuffer : null;
+					state.bindFramebuffer( _gl.FRAMEBUFFER, currFramebuffer );
 
-							_gl.deleteBuffer( glBuffer );
-							_gl.deleteSync( sync );
+					// check if the commands have finished every 8 ms
+					const sync = _gl.fenceSync( _gl.SYNC_GPU_COMMANDS_COMPLETE, 0 );
 
-						}
+					_gl.flush();
 
-						return buffer;
+					await probeAsync( _gl, sync, 4 );
 
-					}
+					// read the data and delete the buffer
+					_gl.bindBuffer( _gl.PIXEL_PACK_BUFFER, glBuffer );
+					_gl.getBufferSubData( _gl.PIXEL_PACK_BUFFER, 0, buffer );
+					_gl.deleteBuffer( glBuffer );
+					_gl.deleteSync( sync );
 
-				} finally {
+					return buffer;
 
-					// restore framebuffer of current render target if necessary
+				} else {
 
-					const framebuffer = ( _currentRenderTarget !== null ) ? properties.get( _currentRenderTarget ).__webglFramebuffer : null;
-					state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );
+					throw new Error( 'THREE.WebGLRenderer.readRenderTargetPixelsAsync: requested read bounds are out of range.' );
 
 				}
 
@@ -31585,7 +31728,6 @@ class InterleavedBuffer {
 		this.count = array !== undefined ? array.length / stride : 0;
 
 		this.usage = StaticDrawUsage;
-		this._updateRange = { offset: 0, count: - 1 };
 		this.updateRanges = [];
 
 		this.version = 0;
@@ -31602,13 +31744,6 @@ class InterleavedBuffer {
 
 	}
 
-	get updateRange() {
-
-		warnOnce( 'THREE.InterleavedBuffer: updateRange() is deprecated and will be removed in r169. Use addUpdateRange() instead.' ); // @deprecated, r159
-		return this._updateRange;
-
-	}
-
 	setUsage( value ) {
 
 		this.usage = value;
@@ -32373,6 +32508,27 @@ class LOD extends Object3D {
 
 	}
 
+	removeLevel( distance ) {
+
+		const levels = this.levels;
+
+		for ( let i = 0; i < levels.length; i ++ ) {
+
+			if ( levels[ i ].distance === distance ) {
+
+				const removedElements = levels.splice( i, 1 );
+				this.remove( removedElements[ 0 ].object );
+
+				return true;
+
+			}
+
+		}
+
+		return false;
+
+	}
+
 	getCurrentLevel() {
 
 		return this._currentLevel;
@@ -33492,6 +33648,9 @@ class BatchedMesh extends Mesh {
 		// stores visible, active, and geometry id per object
 		this._drawInfo = [];
 
+		// instance ids that have been set as inactive, and are available to be overwritten
+		this._availableInstanceIds = [];
+
 		// geometry information
 		this._drawRanges = [];
 		this._reservedRanges = [];
@@ -33691,23 +33850,36 @@ class BatchedMesh extends Mesh {
 
 	addInstance( geometryId ) {
 
+		const atCapacity = this._drawInfo.length >= this.maxInstanceCount;
+
 		// ensure we're not over geometry
-		if ( this._drawInfo.length >= this._maxInstanceCount ) {
+		if ( atCapacity && this._availableInstanceIds.length === 0 ) {
 
 			throw new Error( 'BatchedMesh: Maximum item count reached.' );
 
 		}
 
-		this._drawInfo.push( {
-
+		const instanceDrawInfo = {
 			visible: true,
 			active: true,
 			geometryIndex: geometryId,
+		};
 
-		} );
+		let drawId = null;
+
+		// Prioritize using previously freed instance ids
+		if ( this._availableInstanceIds.length > 0 ) {
+
+			drawId = this._availableInstanceIds.pop();
+			this._drawInfo[ drawId ] = instanceDrawInfo;
+
+		} else {
+
+			drawId = this._drawInfo.length;
+			this._drawInfo.push( instanceDrawInfo );
+
+		}
 
-		// initialize the matrix
-		const drawId = this._drawInfo.length - 1;
 		const matricesTexture = this._matricesTexture;
 		const matricesArray = matricesTexture.image.data;
 		_identityMatrix.toArray( matricesArray, drawId * 16 );
@@ -33956,11 +34128,8 @@ class BatchedMesh extends Mesh {
 	}
 	*/
 
-	/*
 	deleteInstance( instanceId ) {
 
-		// Note: User needs to call optimize() afterward to pack the data.
-
 		const drawInfo = this._drawInfo;
 		if ( instanceId >= drawInfo.length || drawInfo[ instanceId ].active === false ) {
 
@@ -33969,12 +34138,12 @@ class BatchedMesh extends Mesh {
 		}
 
 		drawInfo[ instanceId ].active = false;
+		this._availableInstanceIds.push( instanceId );
 		this._visibilityChanged = true;
 
 		return this;
 
 	}
-	*/
 
 	// get bounding box and compute it if it doesn't exist
 	getBoundingBoxAt( geometryId, target ) {
@@ -34179,6 +34348,59 @@ class BatchedMesh extends Mesh {
 
 	}
 
+	setGeometryIdAt( instanceId, geometryId ) {
+
+		// return early if the geometry is out of range or not active
+		const drawInfo = this._drawInfo;
+		if ( instanceId >= drawInfo.length || drawInfo[ instanceId ].active === false ) {
+
+			return null;
+
+		}
+
+		// check if the provided geometryId is within the valid range
+		if ( geometryId < 0 || geometryId >= this._geometryCount ) {
+
+			return null;
+
+		}
+
+		drawInfo[ instanceId ].geometryIndex = geometryId;
+
+		return this;
+
+	}
+
+	getGeometryIdAt( instanceId ) {
+
+		const drawInfo = this._drawInfo;
+		if ( instanceId >= drawInfo.length || drawInfo[ instanceId ].active === false ) {
+
+			return - 1;
+
+		}
+
+		return drawInfo[ instanceId ].geometryIndex;
+
+	}
+
+	getGeometryRangeAt( geometryId, target = {} ) {
+
+		if ( geometryId < 0 || geometryId >= this._geometryCount ) {
+
+			return null;
+
+		}
+
+		const drawRange = this._drawRanges[ geometryId ];
+
+		target.start = drawRange.start;
+		target.count = drawRange.count;
+
+		return target;
+
+	}
+
 	raycast( raycaster, intersects ) {
 
 		const drawInfo = this._drawInfo;
@@ -34730,6 +34952,7 @@ function checkIntersection( object, raycaster, ray, thresholdSq, a, b ) {
 		index: a,
 		face: null,
 		faceIndex: null,
+		barycoord: null,
 		object: object
 
 	};
@@ -34995,6 +35218,8 @@ function testPoint( point, index, localThresholdSq, matrixWorld, raycaster, inte
 			point: intersectPoint,
 			index: index,
 			face: null,
+			faceIndex: null,
+			barycoord: null,
 			object: object
 
 		} );
@@ -37497,12 +37722,19 @@ class CylinderGeometry extends BufferGeometry {
 
 					// faces
 
-					indices.push( a, b, d );
-					indices.push( b, c, d );
+					if ( radiusTop > 0 ) {
 
-					// update group counter
+						indices.push( a, b, d );
+						groupCount += 3;
 
-					groupCount += 6;
+					}
+
+					if ( radiusBottom > 0 ) {
+
+						indices.push( b, c, d );
+						groupCount += 3;
+
+					}
 
 				}
 
@@ -45812,7 +46044,7 @@ class MaterialLoader extends Loader {
 
 		}
 
-		const material = MaterialLoader.createMaterialFromType( json.type );
+		const material = this.createMaterialFromType( json.type );
 
 		if ( json.uuid !== undefined ) material.uuid = json.uuid;
 		if ( json.name !== undefined ) material.name = json.name;
@@ -46068,6 +46300,12 @@ class MaterialLoader extends Loader {
 
 	}
 
+	createMaterialFromType( type ) {
+
+		return MaterialLoader.createMaterialFromType( type );
+
+	}
+
 	static createMaterialFromType( type ) {
 
 		const materialLib = {
@@ -47898,7 +48136,7 @@ class Clock {
 
 function now() {
 
-	return ( typeof performance === 'undefined' ? Date : performance ).now(); // see #10732
+	return performance.now();
 
 }
 
@@ -48190,7 +48428,7 @@ class Audio extends Object3D {
 
 	}
 
-	stop() {
+	stop( delay = 0 ) {
 
 		if ( this.hasPlaybackControl === false ) {
 
@@ -48203,7 +48441,7 @@ class Audio extends Object3D {
 
 		if ( this.source !== null ) {
 
-			this.source.stop();
+			this.source.stop( this.context.currentTime + delay );
 			this.source.onended = null;
 
 		}
@@ -53845,7 +54083,7 @@ class ShapePath {
 
 class Controls extends EventDispatcher {
 
-	constructor( object, domElement ) {
+	constructor( object, domElement = null ) {
 
 		super();
 

Разница между файлами не показана из-за своего большого размера
+ 0 - 0
build/three.module.min.js


Разница между файлами не показана из-за своего большого размера
+ 10916 - 11015
build/three.webgpu.js


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
build/three.webgpu.min.js


Разница между файлами не показана из-за своего большого размера
+ 79925 - 0
build/three.webgpu.nodes.js


Разница между файлами не показана из-за своего большого размера
+ 5 - 0
build/three.webgpu.nodes.min.js


+ 3 - 1
docs/api/en/audio/Audio.html

@@ -164,6 +164,7 @@
 
 		<h3>[method:this play]( delay )</h3>
 		<p>
+			delay (optional) - The delay, in seconds, at which the audio should start playing.<br />
 			If [page:Audio.hasPlaybackControl hasPlaybackControl] is true, starts
 			playback.
 		</p>
@@ -244,8 +245,9 @@
 		<h3>[method:this setVolume]( [param:Float value] )</h3>
 		<p>Set the volume.</p>
 
-		<h3>[method:this stop]()</h3>
+		<h3>[method:this stop]( delay )</h3>
 		<p>
+			delay (optional) - The delay, in seconds, at which the audio should stop playing.<br />
 			If [page:Audio.hasPlaybackControl hasPlaybackControl] is enabled, stops
 			playback.
 		</p>

+ 3 - 1
docs/api/en/materials/LineBasicMaterial.html

@@ -69,7 +69,9 @@
 			Due to limitations of the
 			[link:https://www.khronos.org/registry/OpenGL/specs/gl/glspec46.core.pdf OpenGL Core Profile] 
 			with the [page:WebGLRenderer WebGL] renderer on most
-			platforms linewidth will always be `1` regardless of the set value.
+			platforms linewidth will always be `1` regardless of the set value.<br /><br />
+
+			If you need wider lines, consider using [page:Line2] or [page:LineSegments2] with [page:LineMaterial].
 		</p>
 
 		<h3>[property:String linecap]</h3>

+ 14 - 0
docs/api/en/math/Triangle.html

@@ -140,6 +140,20 @@
 			triangle. Returns `null` if the triangle is degenerate.
 		</p>
 
+		<h3>
+			[method:Vector getInterpolatedAttribute]( [param:BufferAttribute attribute], [param:Number i1], [param:Vector3 i2], [param:Number i3], [param:Vector3 barycoord], [param:Vector3 target] )
+		</h3>
+		<p>
+			[page:BufferAttribute attribute] - The attribute to interpolate.<br />
+			p1 - Index of first vertex.<br />
+			p2 - Index of second vertex.<br />
+			p3 - Index of third vertex.<br />
+			barycoord - The barycoordinate value to use to interpolate.<br />
+			[page:Vector target] — Result will be copied into this Vector.<br /><br />
+
+			Returns the value barycentrically interpolated for the given attribute and indices.
+		</p>
+
 		<h3>[method:Boolean intersectsBox]( [param:Box3 box] )</h3>
 		<p>
 			[page:Box3 box] - Box to check for intersection against.<br /><br />

+ 44 - 1
docs/api/en/objects/BatchedMesh.html

@@ -167,7 +167,28 @@
 		<p>
 			[page:Integer instanceId]: The id of an instance to get the visibility state of.
 		</p>
-		<p>Get whether the given instance is marked as "visible" or not.</p>
+		<p>Get whether the given instance is marked as "visible" or not.</p>		
+
+		<h3>
+			[method:Object getGeometryRangeAt]( [param:Integer geometryId], [param:Object target] )
+		</h3>
+		<p>
+			[page:Integer geometryId]: The id of the geometry to get the range of.
+		</p>
+		<p>
+			[page:Object target]: Optional target object to copy the range in to.
+		</p>
+		<p>Get the range representing the subset of triangles related to the attached geometry, indicating the starting offset and count, or `null` if invalid.</p>
+		<p>Return an object of the form:</p>
+		<code>{ start: Integer, count: Integer }</code>
+	
+		<h3>
+			[method:Integer getGeometryIdAt]( [param:Integer instanceId] )
+		</h3>
+		<p>
+			[page:Integer instanceId]: The id of an instance to get the geometryIndex of.
+		</p>
+		<p>Get the geometryIndex of the defined instance.</p>
 
 		<h3>
 			[method:undefined setColorAt]( [param:Integer instanceId], [param:Color color] )
@@ -207,6 +228,19 @@
 			Sets the visibility of the instance at the given index.
 		</p>
 
+		<h3>
+			[method:this setGeometryIdAt]( [param:Integer instanceId], [param:Integer geometryId] )
+		</h3>
+		<p>
+			[page:Integer instanceId]: The id of the instance to set the geometryIndex of.
+		</p>
+		<p>
+			[page:Integer geometryId]: The geometryIndex to be use by the instance.
+		</p>
+		<p>
+			Sets the geometryIndex of the instance at the given index.
+		</p>
+
 		<h3>
 			[method:Integer addGeometry]( [param:BufferGeometry geometry], [param:Integer reservedVertexRange], [param:Integer reservedIndexRange] )
 		</h3>
@@ -237,6 +271,15 @@
 			Adds a new instance to the [name] using the geometry of the given geometryId and returns a new id referring to the new instance to be used
 			by other functions.
 		</p>
+		<h3>
+			[method:Integer deleteInstance]( [param:Integer instanceId] )
+		</h3>
+		<p>
+			[page:Integer instanceId]: The id of an instance to remove from the [name] that was previously added via "addInstance".
+		</p>
+		<p>
+			Removes an existing instance from the [name] using the given instanceId.
+		</p>
 
 		<h3>
 			[method:Integer setGeometryAt]( [param:Integer geometryId], [param:BufferGeometry geometry] )

+ 9 - 0
docs/api/en/objects/LOD.html

@@ -85,6 +85,15 @@
 			Adds a mesh that will display at a certain distance and greater. Typically
 			the further away the distance, the lower the detail on the mesh.
 		</p>
+		<h3>
+			[method:Boolean removeLevel]( [param:Float distance])
+		</h3>
+		<p>
+			distance - Distance of the level to delete.<br /><br />
+
+			Removes an existing level, based on the distance from the camera.
+			Returns `true` when the level has been removed. Otherwise `false`.
+		</p>
 
 		<h3>[method:Integer getCurrentLevel]()</h3>
 		<p>Get the currently active LOD level. As index of the levels array.</p>

+ 7 - 3
docs/api/en/renderers/WebGLRenderer.html

@@ -75,6 +75,9 @@
 			[link:https://www.khronos.org/opengl/wiki/Early_Fragment_Test Early Fragment Test] 
 			optimization and can cause a decrease in performance.
 			Default is `false`. See the [example:webgl_camera_logarithmicdepthbuffer camera / logarithmicdepthbuffer] example.
+
+			[page:Boolean reverseDepthBuffer] - whether to use a reverse depth buffer. Requires the `EXT_clip_control` extension.
+			This is a more faster and accurate version than logarithmic depth buffer. Default is `false`. 
 		</p>
 
 		<h2>Properties</h2>
@@ -119,9 +122,7 @@
 			- [page:Boolean isWebGL2]: `true` if the context in use is a
 			WebGL2RenderingContext object.<br />
 			- [page:Boolean logarithmicDepthBuffer]: `true` if the [page:parameter logarithmicDepthBuffer] 
-			was set to true in the constructor and the context
-			supports the
-			[link:https://developer.mozilla.org/en-US/docs/Web/API/EXT_frag_depth EXT_frag_depth] extension.<br />
+			was set to true in the constructor.<br />
 			- [page:Integer maxAttributes]: The value of `gl.MAX_VERTEX_ATTRIBS`.<br />
 			- [page:Integer maxCubemapSize]: The value of
 			`gl.MAX_CUBE_MAP_TEXTURE_SIZE`. Maximum height * width of cube map
@@ -145,6 +146,9 @@
 			be used in a vertex shader.<br />
 			- [page:String precision]: The shader precision currently being used by
 			the renderer.<br />
+			- [page:Boolean reverseDepthBuffer]: `true` if the [page:parameter reverseDepthBuffer] 
+			was set to `true` in the constructor and the context
+			supports the [link:https://registry.khronos.org/webgl/extensions/EXT_clip_control/ EXT_clip_control] extension.<br />
 			- [page:Boolean vertexTextures]: `true` if [property:Integer maxVertexTextures] 
 			is greater than 0 (i.e. vertex textures can be used).<br />
 		</p>

+ 42 - 0
docs/api/zh/extras/TextureUtils.html

@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<html lang="zh">
+	<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">包含纹理实用函数的类。</p>
+
+		<h2>方法</h2>
+
+		<h3>[method:Texture contain]( [param:Texture texture], [param:Number aspect] )</h3>
+		<p>
+			在不裁剪或拉伸纹理的情况下,将纹理在其表面内缩放到尽可能大。该方法保留了纹理的原始纵横比。类似于 CSS 中的 `object-fit: contain`。
+		</p>
+
+		<h3>[method:Texture cover]( [param:Texture texture], [param:Number aspect] )</h3>
+		<p>
+			将纹理缩放到尽可能小的尺寸以填充表面,不留空白。该方法保留了纹理的原始纵横比。类似于 CSS 中的 `object-fit: cover`。
+		</p>
+
+		<h3>[method:Texture fill]( [param:Texture texture] )</h3>
+		<p>
+			将纹理配置为默认转换。类似于 CSS 中的 `object-fit: fill`。
+		</p>
+
+		<h3>[method:Number getByteLength]( [param:Number width], [param:Number height], [param:Number format], [param:Number type] )</h3>
+		<p>
+			给定纹理的宽度、高度、格式和类型。确定必须使用多少个字节来表示纹理。
+		</p>
+
+		<h2>源代码</h2>
+
+		<p>
+			[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
+		</p>
+	</body>
+</html>

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

@@ -34,7 +34,7 @@
 		</p>
 
 		<h2>属性</h2>
-		<p>See the base [page:Mesh] class for common properties.</p>
+		<p>公共属性请查看基类 [page:Mesh]。</p>
 
 		<h3>[property:Box3 boundingBox]</h3>
 		<p>
@@ -67,14 +67,19 @@
 			如果你要通过 [page:.setMatrixAt]() 来修改实例数据,你必须将它的 [page:BufferAttribute.needsUpdate needsUpdate] 标识为 true 。
 		</p>
 
+		<h3>[property:DataTexture morphTexture]</h3>
+		<p>
+			用于表示所有实例的变形权重。如果你通过 [page:.setMorphAt]() 修改了实例数据,你必须将 [page:Texture.needsUpdate needsUpdate] 标识设置为 true。
+		</p>
+
 		<h3>[property:Boolean isInstancedMesh]</h3>
 		<p>
-			Read-only flag to check if a given object is of type [name].
+			用来检查对象是否属于 [name] 类型的只读标识。
 		</p>
 
 
 		<h2>方法</h2>
-		<p>See the base [page:Mesh] class for common methods.</p>
+		<p>公共方法请查看基类 [page:Mesh]。</p>
 
 		<h3>[method:undefined computeBoundingBox]()</h3>
 		<p>
@@ -90,18 +95,18 @@
 
 		<h3>[method:undefined dispose]()</h3>
 		<p>
-			Frees the internal resources of this instance.
+			释放实例的内部资源。
 		</p>
 
 		<h3>[method:undefined getColorAt]( [param:Integer index], [param:Color color] )</h3>
 		<p>
-			[page:Integer index]: The index of an instance. Values have to be in the range [0, count].
+			[page:Integer index]: 实例的索引。 值必须在 [0, count] 区间。
 		</p>
 		<p>
-			[page:Color color]: This color object will be set to the color of the defined instance.
+			[page:Color color]: 传入的颜色对象将会被设置为指定的实例的颜色。
 		</p>
 		<p>
-			Get the color of the defined instance.
+			获取已定义实例的颜色。
 		</p>
 
 		<h3>[method:undefined getMatrixAt]( [param:Integer index], [param:Matrix4 matrix] )</h3>
@@ -115,16 +120,26 @@
 			获得已定义实例的本地变换矩阵。
 		</p>
 
+		<h3>
+			[method:undefined getMorphAt]( [param:Integer index], [param:Mesh mesh] )
+		</h3>
+		<p>
+			[page:Integer index]: 实例的索引。值必须在 [0, count] 区间。
+		</p>
+		<p>
+			[page:Mesh mesh]: 网格属性 [page:Mesh.morphTargetInfluences .morphTargetInfluences] 将会被填充为已定义实例的变形权重。
+		</p>
+		<p>获取已定义实例的变形权重</p>
+
 		<h3>[method:undefined setColorAt]( [param:Integer index], [param:Color color] )</h3>
 		<p>
-			[page:Integer index]: The index of an instance. Values have to be in the range [0, count].
+			[page:Integer index]: 实例的索引。值必须在 [0, count] 区间。
 		</p>
 		<p>
-			[page:Color color]: The color of a single instance.
+			[page:Color color]: 单个实例的颜色。
 		</p>
 		<p>
-			Sets the given color to the defined instance.
-			Make sure you set [page:.instanceColor][page:BufferAttribute.needsUpdate .needsUpdate] to true after updating all the colors.
+			设置已定义实例的颜色。请确保在更新颜色后将 [page:.instanceColor][page:BufferAttribute.needsUpdate .needsUpdate] 标识设置为 true。
 		</p>
 
 		<h3>[method:undefined setMatrixAt]( [param:Integer index], [param:Matrix4 matrix] )</h3>
@@ -139,6 +154,19 @@
 			请确保在更新所有矩阵后将 [page:.instanceMatrix][page:BufferAttribute.needsUpdate .needsUpdate] 设置为true。
 		</p>
 
+		<h3>
+			[method:undefined setMorphAt]( [param:Integer index], [param:Mesh mesh] )
+		</h3>
+		<p>
+			[page:Integer index]: 实例的索引。值必须在 [0, count] 区间。
+		</p>
+		<p>
+			[page:Mesh mesh]: 网格属性 [page:Mesh.morphTargetInfluences .morphTargetInfluences] 包含了单个实例的变形权重。
+		</p>
+		<p>
+		 设置已定义实例的变形权重。请确保在更新所有变形数据后将 [page:.morphTexture][page:Texture.needsUpdate .needsUpdate] 设置为 true。
+		</p>
+
 		<h2>源代码</h2>
 
 		<p>

+ 0 - 15
docs/examples/en/controls/DragControls.html

@@ -127,21 +127,6 @@
 
 		<p>See the base [page:Controls] class for common methods.</p>
 
-		<h3>[method:undefined connect] ()</h3>
-		<p>
-			Adds the event listeners of the controls.
-		</p>
-
-		<h3>[method:undefined disconnect] ()</h3>
-		<p>
-			Removes the event listeners of the controls.
-		</p>
-
-		<h3>[method:undefined dispose] ()</h3>
-		<p>
-			Should be called if the controls is no longer required.
-		</p>
-
 		<h2>Source</h2>
 
 		<p>

+ 7 - 22
docs/examples/en/controls/TransformControls.html

@@ -7,7 +7,7 @@
 		<link type="text/css" rel="stylesheet" href="page.css" />
 	</head>
 	<body>
-		[page:Object3D] &rarr;
+		[page:Controls] &rarr;
 
 		<h1>[name]</h1>
 
@@ -41,7 +41,7 @@
 				[page:Camera camera]: The camera of the rendered scene.
 			</p>
 			<p>
-				[page:HTMLDOMElement domElement]: The HTML element used for event listeners.
+				[page:HTMLDOMElement domElement]: The HTML element used for event listeners. (optional)
 			</p>
 			<p>
 				Creates a new instance of [name].
@@ -73,7 +73,7 @@
 
 		<h2>Properties</h2>
 
-		<p>See the base [page:Object3D] class for common properties.</p>
+		<p>See the base [page:Controls] class for common properties.</p>
 
 		<h3>[property:String axis]</h3>
 		<p>
@@ -85,32 +85,16 @@
 			The camera of the rendered scene.
 		</p>
 
-		<h3>[property:HTMLDOMElement domElement]</h3>
-		<p>
-			The HTMLDOMElement used to listen for mouse / touch events. This must be passed in the constructor; changing it here will
-			not set up new event listeners.
-		</p>
-
 		<h3>[property:Boolean dragging]</h3>
 		<p>
 			Whether or not dragging is currently performed. Read-only property.
 		</p>
 
-		<h3>[property:Boolean enabled]</h3>
-		<p>
-			Whether or not the controls are enabled.
-		</p>
-
 		<h3>[property:String mode]</h3>
 		<p>
 			The current transformation mode. Possible values are "translate", "rotate" and "scale". Default is `translate`.
 		</p>
 
-		<h3>[property:Object3D object]</h3>
-		<p>
-			The 3D object being controlled.
-		</p>
-
 		<h3>[property:Number rotationSnap]</h3>
 		<p>
 			By default, 3D objects are continuously rotated. If you set this property to a numeric value (radians), you can define in which
@@ -150,7 +134,7 @@
 
 		<h2>Methods</h2>
 
-		<p>See the base [page:Object3D] class for common methods.</p>
+		<p>See the base [page:Controls] class for common methods.</p>
 
 		<h3>[method:TransformControls attach] ( [param:Object3D object] )</h3>
 		<p>
@@ -167,9 +151,10 @@
 			Removes the current 3D object from the controls and makes the helper UI invisible.
 		</p>
 
-		<h3>[method:undefined dispose] ()</h3>
+		<h3>[method:Object3D getHelper] ()</h3>
 		<p>
-			Should be called if the controls is no longer required.
+			Returns the visual representation of the controls. Add the helper to your scene to visually transform the attached 
+			3D object.
 		</p>
 
 		<h3>[method:Raycaster getRaycaster] ()</h3>

+ 0 - 70
docs/examples/en/geometries/SDFGeometryGenerator.html

@@ -1,70 +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">
-			[name] generates instances of [page:BufferGeometry] from a Signed Distance Function</br>
-            Uses <a href="https://www.npmjs.com/package/isosurface" target="_blank" > Mikola Lysenko's Isosurface</a>
-		</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 { SDFGeometryGenerator } from 'three/addons/geometries/SDFGeometryGenerator.js';
-		</code>
-
-		<h2>Code Example</h2>
-
-		<code>
-		const generator = new SDFGeometryGenerator( renderer );
-		const sdf = 'float dist( vec3 p ){ return length(p) - 0.5; }' // glsl
-		const geometry = generator.generate( 64, sdf, 1 ); // ~> THREE.BufferGeometry
-		</code>
-
-		<h2>Examples</h2>
-
-		<p>[example:webgl_geometry_sdf geometry / sdf ]</p>
-
-		<h2>Constructor</h2>
-
-		<h3>[name]( [param:WebGLRenderer renderer] )</h3>
-		
-		<p>
-			[page:WebGLRenderer renderer] -- The renderer used to render the scene. <br />
-		</p>
-
-		<h2>Methods</h2>
-
-		<h3>[method:BufferGeometry generate]( [param:Int resolution], [param:String distanceField], [param:Int bounds] )</h3>
-		
-		<p>
-			<b>resolution</b> - Int [ mandatory ] Amount of 'voxels' used for triangulation. Must be power of 2. <br/>Gets heavy after 256, most machines won't be able to process over 512. Defaults to 64. 
-		</p>
-		<p>
-			<b>distanceField</b> - String [ mandatory ] String with glsl distance function. Name of function must be 'dist', with a vec3 argument. ( see code above ). Defaults to a sphere distance.
-		</p>
-		<p>
-			<b>bounds</b> - Int [ optional ] Bounds in which signed distance field will be evaluated. Defaults to 1.
-		</p>
-
-
-		<h2>Source</h2>
-
-		<p>
-			[link:https://github.com/mrdoob/three.js/blob/master/examples/jsm/geometries/SDFGeometry.js examples/jsm/geometries/SDFGeometryGenerator.js]
-		</p>
-	</body>
-</html>

+ 1 - 2
docs/examples/en/geometries/TeapotGeometry.html

@@ -60,8 +60,7 @@
 		<h2>Source</h2>
 
 		<p>
-			[link:https://github.com/mrdoob/three.js/blob/master/examples/jsm/geometries/TeapotGeometry.js 
-			examples/jsm/geometries/TeapotGeometry.js]
+			[link:https://github.com/mrdoob/three.js/blob/master/examples/jsm/geometries/TeapotGeometry.js examples/jsm/geometries/TeapotGeometry.js]
 		</p>
 	</body>
 </html>

+ 65 - 0
docs/examples/en/lines/Line2.html

@@ -0,0 +1,65 @@
+<!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>
+		[page:Object3D] &rarr; [page:Mesh] &rarr; [page:LineSegments2] &rarr;
+
+		<h1>[name]</h1>
+
+		<p class="desc">
+			A polyline drawn between vertices.
+		</p>
+
+		<p class="desc">
+			This adds functionality beyond [page:Line], like arbitrary line width and changing width to be in world units.
+			It extends [page:LineSegments2], simplifying constructing segments from a chain of points.
+		</p>
+
+		<h2>Import</h2>
+
+		<p>
+			[name] is an add-on, and therefore must be imported explicitly.
+			See [link:#manual/introduction/Installation Installation / Addons].
+		</p>
+
+		<code>
+			import { Line2 } from 'three/addons/lines/Line2.js';
+		</code>
+
+		<h2>Examples</h2>
+
+		<p>
+			[example:webgl_lines_fat WebGL / lines / fat ]<br />
+			[example:webgl_lines_fat_raycasting WebGL / lines / fat / raycasting ]<br />
+			[example:webgpu_lines_fat WebGPU / lines / fat / raycasting ]
+		</p>
+
+		<h2>Constructor</h2>
+
+		<h3>[name]( [param:LineGeometry geometry], [param:LineMaterial material] )</h3>
+		<p>
+			[page:LineGeometry geometry] — (optional) Pair(s) of vertices representing each line segment.<br />
+			[page:Material material] — (optional) Material for the line. Default is a [page:LineMaterial] with random color.
+		</p>
+
+		<h2>Properties</h2>
+		<p>See the base [page:LineSegments2] class for common properties.</p>
+
+		<h3>[property:Boolean isLine2]</h3>
+		<p>Read-only flag to check if a given object is of type [name].</p>
+
+		<h2>Methods</h2>
+		<p>See the base [page:LineSegments2] class for common methods.</p>
+
+		<h2>Source</h2>
+
+		<p>
+			[link:https://github.com/mrdoob/three.js/blob/master/examples/jsm/lines/Line2.js examples/jsm/lines/Line2.js]
+		</p>
+	</body>
+</html>

+ 84 - 0
docs/examples/en/lines/LineGeometry.html

@@ -0,0 +1,84 @@
+<!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>
+		[page:BufferGeometry] &rarr; [page:InstancedBufferGeometry] &rarr; [page:LineSegmentsGeometry] &rarr;
+
+		<h1>[name]</h1>
+
+		<p class="desc">
+			A chain of vertices, forming a polyline.
+		</p>
+
+		<p class="desc">
+			This is used in [page:Line2] to describe the shape.
+		</p>
+
+		<h2>Import</h2>
+
+		<p>
+			[name] is an add-on, and therefore must be imported explicitly.
+			See [link:#manual/introduction/Installation Installation / Addons].
+		</p>
+
+		<code>
+			import { LineGeometry } from 'three/addons/lines/LineGeometry.js';
+		</code>
+
+		<h2>Examples</h2>
+
+		<p>
+			[example:webgl_lines_fat WebGL / lines / fat ]<br />
+			[example:webgl_lines_fat_raycasting WebGL / lines / fat / raycasting ]<br />
+			[example:webgpu_lines_fat WebGPU / lines / fat / raycasting ]
+		</p>
+
+		<h2>Constructor</h2>
+
+		<h3>[name]()</h3>
+		<p>
+			Creates a new geometry.
+			Call [page:LineGeometry.setPositions setPositions] to add segments.
+		</p>
+
+		<h2>Properties</h2>
+		<p>See the base [page:LineSegmentsGeometry] class for common properties.</p>
+
+		<h3>[property:Boolean isLineGeometry]</h3>
+		<p>Read-only flag to check if a given object is of type [name].</p>
+
+		<h2>Methods</h2>
+		<p>See the base [page:LineSegmentsGeometry] class for common methods.</p>
+
+		<h3>[method:this fromLine]( [param:Line line] )</h3>
+		<p>
+			Copy the vertex positions of a [page:Line] object into this geometry.
+			Assumes the source geometry is not using indices.
+		</p>
+
+		<h3>[method:this setColors]( [param:Array array] )</h3>
+		<p>
+			Replace the per-vertex colors.
+			Every triple describes a line vertex: `[r1, g1, b1]`.
+			The array can be an `Array` or `Float32Array`.
+		</p>
+
+		<h3>[method:this setPositions]( [param:Array array] )</h3>
+		<p>
+			Replace the vertex positions with a new set.
+			The array can be an `Array` or `Float32Array`.
+			The length must be a multiple of three.
+		</p>
+
+		<h2>Source</h2>
+
+		<p>
+			[link:https://github.com/mrdoob/three.js/blob/master/examples/jsm/lines/LineGeometry.js examples/jsm/lines/LineGeometry.js]
+		</p>
+	</body>
+</html>

+ 92 - 0
docs/examples/en/lines/LineMaterial.html

@@ -0,0 +1,92 @@
+<!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>
+		[page:Material] &rarr; [page:ShaderMaterial] &rarr;
+
+		<h1>[name]</h1>
+
+		<p class="desc">
+			A material for drawing wireframe-style geometries.
+			Unlike [page:LineBasicMaterial], it supports arbitrary line widths and allows using world units instead of screen space units.
+			This material is used with [page:LineSegments2] and [page:Line2].
+		</p>
+
+		<p class="desc">
+			Lines are always rendered with round caps and round joints.
+		</p>
+
+		<h2>Examples</h2>
+		<p>
+			[example:webgl_lines_fat WebGL / lines / fat ]<br />
+			[example:webgl_lines_fat_raycasting WebGL / lines / fat / raycasting ]<br />
+			[example:webgl_lines_fat_wireframe WebGL / lines / fat / wireframe ]<br />
+			[example:webgpu_lines_fat WebGPU / lines / fat / raycasting ]
+		</p>
+
+		<h2>Constructor</h2>
+		<h3>[name]( [param:Object parameters] )</h3>
+
+		<p>
+			[page:Object parameters] - (optional) an object with one or more properties defining the material's appearance.
+			Any property of the material (including any property inherited from [page:ShaderMaterial]) can be passed in here.
+		</p>
+
+		<p>
+			The exception is the property [page:Hexadecimal color], which can be passed in as a number or hexadecimal string and is `0xffffff` (white) by default.
+			[page:Color.set]( color ) is called internally.
+		</p>
+
+		<h2>Properties</h2>
+		<p>See the base [page:ShaderMaterial] class for common properties.</p>
+
+		<h3>[property:Color color]</h3>
+		<p>[page:Color] of the material, by default set to white (0xffffff).</p>
+
+		<h3>[property:Boolean dashed]</h3>
+		<p>Whether the line is dashed, or solid. Default is `false`.</p>
+
+		<h3>[property:number dashOffset]</h3>
+		<p>Where in the dash cycle the dash starts. Default is `0`.</p>
+
+		<h3>[property:number dashScale]</h3>
+		<p>The scale of the dashes and gaps. Default is `1`.</p>
+
+		<h3>[property:number dashSize]</h3>
+		<p>The size of the dash. Default is `1`.</p>
+
+		<h3>[property:number gapSize]</h3>
+		<p>The size of the gap. Default is `1`.</p>
+
+		<h3>[property:Float linewidth]</h3>
+		<p>Controls line thickness. Default is `1`.</p>
+
+		<h3>[property:Vector2 resolution]</h3>
+		<p>
+			The size of the viewport, in screen pixels.
+			This must be kept updated to make screen-space rendering accurate.
+			The [page:LineSegments2.onBeforeRender] callback performs the update for visible objects.
+			Default is `[1, 1]`.
+		</p>
+
+		<h3>[property:Boolean worldUnits]</h3>
+		<p>
+			Whether the material's sizes (width, dash gaps) are in world units.
+			Default is `false` (screen space units.)
+		</p>
+
+		<h2>Methods</h2>
+		<p>See the base [page:ShaderMaterial] class for common methods.</p>
+
+		<h2>Source</h2>
+
+		<p>
+			[link:https://github.com/mrdoob/three.js/blob/master/examples/jsm/lines/LineMaterial.js examples/jsm/lines/LineMaterial.js]
+		</p>
+	</body>
+</html>

+ 69 - 0
docs/examples/en/lines/LineSegments2.html

@@ -0,0 +1,69 @@
+<!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>
+		[page:Object3D] &rarr; [page:Mesh] &rarr;
+
+		<h1>[name]</h1>
+
+		<p class="desc">
+			A series of lines drawn between pairs of vertices.
+		</p>
+
+		<p class="desc">
+			This adds functionality beyond [page:LineSegments], like arbitrary line width and changing width to be in world units.
+			The [page:Line2] extends this object, forming a polyline instead of individual segments.
+		</p>
+
+		<h2>Import</h2>
+
+		<p>
+			[name] is an add-on, and therefore must be imported explicitly.
+			See [link:#manual/introduction/Installation Installation / Addons].
+		</p>
+
+		<code>
+			import { LineSegments2 } from 'three/addons/lines/LineSegments2.js';
+		</code>
+
+		<h2>Example</h2>
+
+		<p>[example:webgl_lines_fat_raycasting WebGL / lines / fat / raycasting ]</p>
+
+		<h2>Constructor</h2>
+
+		<h3>[name]( [param:LineSegmentsGeometry geometry], [param:LineMaterial material] )</h3>
+		<p>
+			[page:LineSegmentsGeometry geometry] — (optional) Pair(s) of vertices representing each line segment.<br />
+			[page:Material material] — (optional) Material for the line. Default is a [page:LineMaterial] with random color.
+		</p>
+
+		<h2>Properties</h2>
+		<p>See the base [page:Mesh] class for common properties.</p>
+
+		<h3>[property:Boolean isLineSegments2]</h3>
+		<p>Read-only flag to check if a given object is of type [name].</p>
+
+		<h2>Methods</h2>
+		<p>See the base [page:Mesh] class for common methods.</p>
+
+		<h3>[method:undefined onBeforeRender]( [param:WebGLRenderer renderer] )</h3>
+		<p>
+			Called by the framework to update the material's resolution property, needed for screen-scaled widths.
+		</p>
+		<p>
+			If your object is not visible to a camera (e.g. by [page:Object3D.layers layers] or [page:Object3D.visible visible],) you must call this manually whenever the viewport changes.
+		</p>
+
+		<h2>Source</h2>
+
+		<p>
+			[link:https://github.com/mrdoob/three.js/blob/master/examples/jsm/lines/LineSegments2.js examples/jsm/lines/LineSegments2.js]
+		</p>
+	</body>
+</html>

+ 103 - 0
docs/examples/en/lines/LineSegmentsGeometry.html

@@ -0,0 +1,103 @@
+<!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>
+		[page:BufferGeometry] &rarr; [page:InstancedBufferGeometry] &rarr;
+
+		<h1>[name]</h1>
+
+		<p class="desc">
+			A series of vertex pairs, forming line segments.
+		</p>
+
+		<p class="desc">
+			This is used in [page:LineSegments2] to describe the shape.
+		</p>
+
+		<h2>Import</h2>
+
+		<p>
+			[name] is an add-on, and therefore must be imported explicitly.
+			See [link:#manual/introduction/Installation Installation / Addons].
+		</p>
+
+		<code>
+			import { LineSegmentsGeometry } from 'three/addons/lines/LineSegmentsGeometry.js';
+		</code>
+
+		<h2>Example</h2>
+
+		<p>[example:webgl_lines_fat_raycasting WebGL / lines / fat / raycasting ]</p>
+
+		<h2>Constructor</h2>
+
+		<h3>[name]()</h3>
+		<p>
+			Creates a new geometry.
+			Call [page:LineSegmentsGeometry.setPositions setPositions] to add segments.
+		</p>
+
+		<h2>Properties</h2>
+		<p>See the base [page:InstancedBufferGeometry] class for common properties.</p>
+
+		<h3>[property:Boolean isLineSegmentsGeometry]</h3>
+		<p>Read-only flag to check if a given object is of type [name].</p>
+
+		<h2>Methods</h2>
+		<p>See the base [page:Mesh] class for common methods.</p>
+
+		<h3>[method:this fromEdgesGeometry]( [param:EdgesGeometry geometry] )</h3>
+		<p>
+			Copy the vertex positions of an edge geometry into this geometry.
+		</p>
+
+		<h3>[method:this fromLineSegments]( [param:LineSegments lineSegments] )</h3>
+		<p>
+			Copy the vertex positions of a [page:LineSegments] object into this geometry.
+			Assumes the source geometry is not using indices.
+		</p>
+
+		<h3>[method:this fromMesh]( [param:Mesh mesh] )</h3>
+		<p>
+			Copy the vertex positions of a mesh object into this geometry.
+		</p>
+
+		<h3>[method:this fromWireframeGeometry]( [param:WireframeGeometry geometry] )</h3>
+		<p>
+			Copy the vertex positions of a wireframe geometry into this geometry.
+		</p>
+
+		<h3>[method:this setColors]( [param:Array array] )</h3>
+		<p>
+			Replace the per-vertex colors.
+			Every sixtuple describes a segment: `[r1, g1, b1, r2, g2, b2]`.
+			The array can be an `Array` or `Float32Array`.
+		</p>
+
+		<h3>[method:this setPositions]( [param:Array array] )</h3>
+		<p>
+			Replace the vertex positions with a new set.
+			The array can be an `Array` or `Float32Array`.
+			The length must be a multiple of six.
+		</p>
+		<p>
+			See also [page:LineSegmentsGeometry.positions positions].
+		</p>
+
+		<h3>[method:undefined toJSON]()</h3>
+		<p>
+			Unimplemented.
+		</p>
+
+		<h2>Source</h2>
+
+		<p>
+			[link:https://github.com/mrdoob/three.js/blob/master/examples/jsm/lines/LineSegmentsGeometry.js examples/jsm/lines/LineSegmentsGeometry.js]
+		</p>
+	</body>
+</html>

+ 122 - 0
docs/examples/ko/controls/MapControls.html

@@ -0,0 +1,122 @@
+<!DOCTYPE html>
+<html lang="ko">
+
+<head>
+	<meta charset="utf-8" />
+	<base href="../../../" />
+	<script src="page.js"></script>
+	<link type="text/css" rel="stylesheet" href="page.css" />
+</head>
+
+<body>
+	[page:OrbitControls] &rarr;
+
+	<h1>[name]</h1>
+
+	<p class="desc">
+		[name]은 지도 위에서 조망자의 시각으로 카메라를 이동하기 위해 설계되었습니다.
+		이 클래스는 [page:OrbitControls]와 같은 구현을 공유하지만 특정한 마우스/터치 상호작용 프리셋을 사용하고 기본적으로 화면 공간 패닝을 비활성화합니다.
+	</p>
+
+	<h2>가져오기</h2>
+
+	<p>
+		[name]은 애드온으로서 명시적으로 가져와야 합니다.
+		[link:#manual/introduction/Installation 설치 / 애드온]을 참조하십시오.
+	</p>
+
+	<code>
+			import { MapControls } from 'three/addons/controls/MapControls.js';  
+		</code>
+
+	<h2>코드 예제</h2>
+
+	<code>
+		const renderer = new THREE.WebGLRenderer();  
+		renderer.setSize( window.innerWidth, window.innerHeight );  
+		document.body.appendChild( renderer.domElement );  
+  
+		const scene = new THREE.Scene();  
+  
+		const camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 10000 );  
+		camera.position.set( 0, 20, 100 );  
+  
+		const controls = new MapControls( camera, renderer.domElement );  
+		controls.enableDamping = true;  
+  
+		function animate() {  
+  
+			requestAnimationFrame( animate );  
+  
+			// controls.enableDamping 또는 controls.autoRotate가 true로 설정된 경우 필수  
+			controls.update();  
+  
+			renderer.render( scene, camera );  
+  
+		}  
+		</code>
+
+	<h2>예제</h2>
+
+	<p>[example:misc_controls_map misc / controls / map ]</p>
+
+	<h2>생성자</h2>
+
+	<h3>[name]( [param:Camera object], [param:HTMLDOMElement domElement] )</h3>
+	<p>
+		[page:Camera object]: (필수) 제어할 카메라입니다. 카메라는 다른 객체의 자식이어서는 안 되며, 그 객체가 스케인 자체가 아니라면 됩니다.<br><br>
+
+		[page:HTMLDOMElement domElement]: 이벤트 리스너에 사용되는 HTML 요소입니다.
+	</p>
+
+	<h2>이벤트</h2>
+
+	<p>공통 이벤트를 보기 위해 기본 [page:OrbitControls] 클래스를 참조하십시오.</p>
+
+	<h2>속성</h2>
+
+	<p>공통 속성을 보기 위해 기본 [page:OrbitControls] 클래스를 참조하십시오.</p>
+
+	<h3>
+		[property:Object mouseButtons]</h3>
+	<p>
+		이 객체에는 컨트롤에 의해 사용되는 마우스 동작에 대한 참조가 포함되어 있습니다.
+		<code>
+controls.mouseButtons = {  
+	LEFT: THREE.MOUSE.PAN,  
+	MIDDLE: THREE.MOUSE.DOLLY,  
+	RIGHT: THREE.MOUSE.ROTATE  
+}  
+			</code>
+	</p>
+
+	<h3>[property:Boolean screenSpacePanning]</h3>
+	<p>
+		패닝 시 카메라 위치가 어떻게 이동되는지 정의합니다. 만약 true이면, 카메라는 화면 공간에서 패닝합니다.
+		그렇지 않으면, 카메라는 카메라의 위 방향에 수직인 평면에서 패닝합니다.
+		기본값은 `false`입니다.
+	</p>
+
+	<h3>[property:Object touches]</h3>
+	<p>
+		이 객체에는 컨트롤에 의해 사용되는 터치 동작에 대한 참조가 포함되어 있습니다.
+		<code>
+controls.touches = {  
+	ONE: THREE.TOUCH.PAN,  
+	TWO: THREE.TOUCH.DOLLY_ROTATE  
+}  
+			</code>
+	</p>
+
+	<h2>메서드</h2>
+
+	<p>공통 메서드를 보기 위해 기본 [page:OrbitControls] 클래스를 참조하십시오.</p>
+
+	<h2>소스</h2>
+
+	<p>
+		[link:https://github.com/mrdoob/three.js/blob/master/examples/jsm/controls/MapControls.js examples/jsm/controls/MapControls.js]
+	</p>
+</body>
+
+</html>

+ 117 - 0
docs/examples/ko/webxr/XREstimatedLight.html

@@ -0,0 +1,117 @@
+<!DOCTYPE html>
+<html lang="ko">
+
+<head>
+	<meta charset="utf-8" />
+	<base href="../../../" />
+	<script src="page.js"></script>
+	<link type="text/css" rel="stylesheet" href="page.css" />
+</head>
+
+<body>
+	[page:Group] &rarr;
+
+	<h1>[name]</h1>
+
+	<p class="desc">
+		XREstimatedLight은 WebXR의 빛 추정 기능을 사용하여 광도계(light probe), 방향광(directional light) 그리고 (선택적으로) 환경 맵(environment
+		map)을 생성하여 사용자의 현실 세계의 환경과 조명을 모델링합니다.<br>
+		WebXR가 빛과 환경 추정을 업데이트할 때, XREstimatedLight는 자동으로 광도계, 방향광, 그리고 환경 맵을 업데이트합니다.<br><br>
+
+		WebXR 세션을 생성할 때 `light-estimation`을 선택적 또는 필수 기능으로 지정하는 것이 중요합니다. 그렇지 않으면 빛 추정 기능은 작동하지 않습니다.<br><br>
+
+		브라우저 호환성 정보는 여기를 참조하십시오. 이는 아직 WebXR의 실험적 기능입니다. <a
+			href="https://developer.mozilla.org/en-US/docs/Web/API/XRLightProbe#browser_compatibility">여기</a><br><br>
+
+		이를 사용하려면, /examples 디렉토리 내의 모든 파일과 마찬가지로, HTML에 별도로 파일을 포함해야 합니다.
+	</p>
+
+	<h2>가져오기</h2>
+
+	<p>
+		[name]은 애드온이므로 명시적으로 가져와야 합니다.
+		[link:#manual/introduction/Installation 설치 / 애드온]을 참조하십시오.
+	</p>
+
+	<code>
+	import { XREstimatedLight } from 'three/addons/webxr/XREstimatedLight.js';  
+	</code>
+
+	<h2>코드 예제</h2>
+
+	<code>
+	renderer.xr.enabled = true;  
+
+	// XREstimatedLight를 초기 시점에 장면에 추가하지 마세요.  
+	// AR 세션이 시작할 때까지 추정된 조명값이 없기 때문입니다.  
+	const xrLight = new XREstimatedLight( renderer );  
+
+	xrLight.addEventListener( 'estimationstart' , () => {  
+
+		scene.add( xrLight );  
+
+		if ( xrLight.environment ) {  
+
+			scene.environment = xrLight.environment;  
+
+		}  
+
+	} );  
+
+	xrLight.addEventListener( 'estimationend', () => {  
+
+		scene.remove( xrLight );  
+
+		scene.environment = null;  
+
+	} );  
+
+	// 조명 추정 기능을 작동하도록 하려면 'light-estimation'을 선택적 또는 필수 기능으로 포함해야 합니다.  
+	document.body.appendChild( XRButton.createButton( renderer, {  
+		optionalFeatures: [ 'light-estimation' ]  
+	} ) );  
+	</code>
+
+	<h2>예제</h2>
+
+	<p>[example:webxr_ar_lighting webxr / light estimation]</p>
+
+	<h2>생성자</h2>
+
+	<h3>[name]( [param:WebGLRenderer renderer], [param:Boolean environmentEstimation] )</h3>
+	<p>
+		[page:WebGLRenderer renderer]: (필수) 장면을 렌더링하는 렌더러. 주로 WebXRManager와 상호작용하는 데 사용됩니다.<br><br>
+
+		environmentEstimation: `true`로 설정하면 WebXR을 사용하여 환경 맵을 추정합니다.
+	</p>
+
+	<h2>이벤트</h2>
+
+	<h3>estimationstart</h3>
+	<p>
+		추정된 조명값이 업데이트 시작할 때 발생합니다.
+	</p>
+
+	<h3>estimationend</h3>
+	<p>
+		추정된 조명값이 업데이트 중지할 때 발생합니다.
+	</p>
+
+	<h2>속성</h2>
+
+	<h3>[property:Texture environment]</h3>
+	<p>
+		WebXR에 의해 추정된 환경 맵입니다. 이는 environmentEstimation이 `true`로 설정된 경우에만 사용할 수 있습니다.<br><br>
+
+		이는 [page:Scene.environment], [page:MeshStandardMaterial.envMap], 또는 [page:Scene.background]로 사용할 수 있습니다.
+	</p>
+
+	<h2>소스</h2>
+
+	<p>
+		[link:https://github.com/mrdoob/three.js/blob/master/examples/jsm/webxr/XREstimatedLight.js
+		examples/jsm/webxr/XREstimatedLight.js]
+	</p>
+</body>
+
+</html>

+ 0 - 15
docs/examples/zh/controls/DragControls.html

@@ -129,21 +129,6 @@
 
 		<p>共有方法请参见其基类[page:Controls]。</p>
 
-		<h3>[method:undefined connect] ()</h3>
-		<p>
-			添加控制器的事件监听。
-		</p>
-
-		<h3>[method:undefined disconnect] ()</h3>
-		<p>
-			移除控制器的事件监听。
-		</p>
-
-		<h3>[method:undefined dispose] ()</h3>
-		<p>
-			若不再需要该控制器,则应当调用此函数。
-		</p>
-
 		<h2>源代码</h2>
 
 		<p>

+ 26 - 30
docs/examples/zh/controls/OrbitControls.html

@@ -7,6 +7,8 @@
 		<link type="text/css" rel="stylesheet" href="page.css" />
 	</head>
 	<body>
+		[page:Controls] &rarr;
+
 		<h1>轨道控制器([name])</h1>
 
 		<p class="desc">
@@ -67,7 +69,7 @@
 		<p>
 			[page:Camera object]: (必须)将要被控制的相机。该相机不允许是其他任何对象的子级,除非该对象是场景自身。<br><br>
 
-			[page:HTMLDOMElement domElement]: 用于事件监听的HTML元素。
+			[page:HTMLDOMElement domElement]: 用于事件监听的HTML元素。(可选)
 		</p>
 
 		<h2>Events</h2>
@@ -89,12 +91,13 @@
 
 		<h2>属性</h2>
 
+		<p>共有属性请参见其基类[page:Controls]。</p>
+
 		<h3>[property:Boolean autoRotate]</h3>
 		<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]().
+			如果希望自动旋转速度与帧速率(显示器的刷新率)无关,则必须将时间 `deltaTime`(以秒为单位)传递给 [page:.update]()。
 		</p>
 
 		<h3>[property:Float autoRotateSpeed]</h3>
@@ -110,16 +113,6 @@
 			请注意,要使得这一值生效,你必须在你的动画循环里调用[page:.update]()。
 		</p>
 
-		<h3>[property:HTMLDOMElement domElement]</h3>
-		<p>
-			该 HTMLDOMElement 用于监听鼠标/触摸事件,该属性必须在构造函数中传入。在此处改变它将不会设置新的事件监听。
-		</p>
-
-		<h3>[property:Boolean enabled]</h3>
-		<p>
-			当设置为false时,控制器将不会响应用户的操作。默认值为true。
-		</p>
-
 		<h3>[property:Boolean enableDamping]</h3>
 		<p>
 			将其设置为true以启用阻尼(惯性),这将给控制器带来重量感。默认值为false。<br>
@@ -177,6 +170,11 @@ controls.keys = {
 			你能够垂直旋转的角度的上限,范围是0到Math.PI,其默认值为Math.PI。
 		</p>
 
+		<h3>[property:Float maxTargetRadius]</h3>
+		<p>
+			你能够让目标移动离 [page:.cursor] 有多远,其默认值为Infinity。
+		</p>
+
 		<h3>[property:Float maxZoom]</h3>
 		<p>
 			你能够将相机缩小多少(仅适用于[page:OrthographicCamera]),其默认值为Infinity。
@@ -197,6 +195,11 @@ controls.keys = {
 			你能够垂直旋转的角度的下限,范围是0到Math.PI,其默认值为0。
 		</p>
 
+		<h3>[property:Float minTargetRadius]</h3>
+		<p>
+			你能够让目标移动离 [page:.cursor] 有多近,其默认值为0。
+		</p>
+
 		<h3>[property:Float minZoom]</h3>
 		<p>
 			你能够将相机放大多少(仅适用于[page:OrthographicCamera]),其默认值为0。
@@ -215,11 +218,6 @@ controls.mouseButtons = {
 			</code>
 		</p>
 
-		<h3>[property:Camera object]</h3>
-		<p>
-			正被控制的摄像机。
-		</p>
-
 		<h3>[property:Float panSpeed]</h3>
 		<p>
 			位移的速度,其默认值为1。
@@ -253,6 +251,11 @@ controls.mouseButtons = {
 			它可以在任何时候被手动更新,以更改控制器的焦点。
 		</p>
 
+		<h3>[property:Vector3 cursor]</h3>
+		<p>
+			被 [page:.minTargetRadius] 和 [page:.maxTargetRadius] 限制的焦点。可随时手动更新以更改 [page:.target] 的兴趣中心。
+		</p>
+
 		<h3>[property:Object touches]</h3>
 		<p>
 			该对象包含由控件所使用的触摸操作的引用。
@@ -276,15 +279,12 @@ controls.touches = {
 
 		<h3>[property:Boolean zoomToCursor]</h3>
 		<p>
-		Setting this property to `true` allows to zoom to the cursor's position. Default is `false`.
+			将此属性设置为 `true` 可以缩放至光标位置。默认值为 `false`。
 		</p>
 
-		<h2>Methods</h2>
+		<h2>方法</h2>
 
-		<h3>[method:undefined dispose] ()</h3>
-		<p>
-			移除所有的事件监听。
-		</p>
+		<p>共有方法请参见其基类[page:Controls]。</p>
 
 		<h3>[method:radians getAzimuthalAngle] ()</h3>
 		<p>
@@ -298,7 +298,7 @@ controls.touches = {
 
 		<h3>[method:Float getDistance] ()</h3>
 		<p>
-			Returns the distance from the camera to the target.
+			返回从相机到目标的距离。
 		</p>
 
 		<h3>[method:undefined listenToKeyEvents] ( [param:HTMLDOMElement domElement] )</h3>
@@ -323,11 +323,7 @@ controls.touches = {
 
 		<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).
+			更新控制器。必须在摄像机的变换发生任何手动改变后调用,或如果[page:.autoRotate]或[page:.enableDamping]被设置时,在update循环里调用。`deltaTime` 以秒为单位,是可选的,并且仅当您希望自动旋转速度独立于帧速率(显示器的刷新率)时才是必需的。
 		</p>
 
 		<h2>源代码</h2>

+ 5 - 0
docs/examples/zh/controls/PointerLockControls.html

@@ -102,6 +102,11 @@
 			摄像机的俯仰角下限限制。范围为0到Math.PI弧度之间。默认值为0。
 		</p>
 
+		<h3>[property:Float pointerSpeed]</h3>
+		<p>
+			指针移动对相机旋转的影响程度的乘数。默认值为1。
+		</p>
+
 		<h2>方法</h2>
 
 		<p>共有方法请参见其基类[page:Controls]。</p>

+ 9 - 45
docs/examples/zh/controls/TrackballControls.html

@@ -7,7 +7,7 @@
 		<link type="text/css" rel="stylesheet" href="page.css" />
 	</head>
 	<body>
-		[page:EventDispatcher] &rarr;
+		[page:Controls] &rarr;
 
 		<h1>轨迹球控制器([name])</h1>
 
@@ -41,7 +41,7 @@
 				[page:Camera camera]: 渲染场景的摄像机。
 			</p>
 			<p>
-				[page:HTMLDOMElement domElement]: 用于事件监听的HTML元素。
+				[page:HTMLDOMElement domElement]: 用于事件监听的HTML元素。(可选)
 			</p>
 			<p>
 				创建一个新的 [name] 实例。
@@ -67,21 +67,13 @@
 
 		<h2>属性</h2>
 
-		<h3>[property:HTMLDOMElement domElement]</h3>
-		<p>
-			该 HTMLDOMElement 用于监听鼠标/触摸事件,该属性必须在构造函数中传入。在此处改变它将不会设置新的事件监听。
-		</p>
+		<p>共有属性请参见其基类[page:Controls]。</p>
 
 		<h3>[property:Number dynamicDampingFactor]</h3>
 		<p>
 			设置阻尼的强度。仅在[page:.staticMoving staticMoving]设为*false*时考虑。默认为*0.2*。
 		</p>
 
-		<h3>[property:Boolean enabled]</h3>
-		<p>
-			是否启用控制器。
-		</p>
-
 		<h3>[property:Array keys]</h3>
 		<p>
 			该数组包含用于控制交互的按键代码。
@@ -139,11 +131,6 @@
 			是否禁用缩放,默认为*false*。
 		</p>
 
-		<h3>[property:Camera object]</h3>
-		<p>
-			正被控制的摄像机。
-		</p>
-
 		<h3>[property:Number panSpeed]</h3>
 		<p>
 			平移的速度,其默认值为*0.3*。
@@ -170,6 +157,11 @@
 			阻尼是否被禁用。默认为*false*。
 		</p>
 
+		<h3>[property:Vector3 target]</h3>
+		<p>
+			控件的焦点。
+		</p>
+
 		<h3>[property:Number zoomSpeed]</h3>
 		<p>
 			缩放的速度,其默认值为*1.2*。
@@ -177,46 +169,18 @@
 
 		<h2>方法</h2>
 
-		<h3>[method:undefined checkDistances] ()</h3>
-		<p>
-			确保控制器位于 [minDistance, maxDistance] 范围内。由[page:.update update]()调用。
-		</p>
-
-		<h3>[method:undefined dispose] ()</h3>
-		<p>
-			若不再需要该控制器,则应当调用此函数。
-		</p>
+		<p>共有方法请参见其基类[page:Controls]。</p>
 
 		<h3>[method:undefined handleResize] ()</h3>
 		<p>
 			若应用程序窗口大小发生改变,则应当调用此函数。
 		</p>
 
-		<h3>[method:undefined panCamera] ()</h3>
-		<p>
-			如有必要,执行平移。由[page:.update update]()调用。
-		</p>
-
 		<h3>[method:undefined reset] ()</h3>
 		<p>
 			重置控制器到初始状态。
 		</p>
 
-		<h3>[method:undefined rotateCamera] ()</h3>
-		<p>
-			如有必要,旋转相机。由[page:.update update]()调用。
-		</p>
-
-		<h3>[method:undefined update] ()</h3>
-		<p>
-			更新控制器,常被用在动画循环中。
-		</p>
-
-		<h3>[method:undefined zoomCamera] ()</h3>
-		<p>
-			如有必要,执行缩放。由[page:.update update]()调用。
-		</p>
-
 		<h2>源代码</h2>
 
 		<p>

+ 11 - 21
docs/examples/zh/controls/TransformControls.html

@@ -7,7 +7,7 @@
 		<link type="text/css" rel="stylesheet" href="page.css" />
 	</head>
 	<body>
-		[page:Object3D] &rarr;
+		[page:Controls] &rarr;
 
 		<h1>变换控制器([name])</h1>
 
@@ -41,7 +41,7 @@
 				[page:Camera camera]: 被控制的摄像机。
 			</p>
 			<p>
-				[page:HTMLDOMElement domElement]: 用于事件监听的HTML元素。
+				[page:HTMLDOMElement domElement]: 用于事件监听的HTML元素。(可选)
 			</p>
 			<p>
 				创建一个新的 [name] 实例。
@@ -73,7 +73,7 @@
 
 		<h2>属性</h2>
 
-		<p>共有属性请参见其基类[page:Object3D]。</p>
+		<p>共有属性请参见其基类[page:Controls]。</p>
 
 		<h3>[property:String axis]</h3>
 		<p>
@@ -85,31 +85,16 @@
 			渲染场景的摄像机。
 		</p>
 
-		<h3>[property:HTMLDOMElement domElement]</h3>
-		<p>
-			该 HTMLDOMElement 用于监听鼠标/触摸事件,该属性必须在构造函数中传入。在此处改变它将不会设置新的事件监听。
-		</p>
-
 		<h3>[property:Boolean dragging]</h3>
 		<p>
 			当前是否正在拖动。只读属性。
 		</p>
 
-		<h3>[property:Boolean enabled]</h3>
-		<p>
-			是否启用控制器。默认为*true*。
-		</p>
-
 		<h3>[property:String mode]</h3>
 		<p>
 			当前的变换模式。可能的值包括"translate"、"rotate" 和 "scale"。默认为*translate*。
 		</p>
 
-		<h3>[property:Object3D object]</h3>
-		<p>
-			正在被控制的3D对象。
-		</p>
-
 		<h3>[property:Number rotationSnap]</h3>
 		<p>
 			默认情况下,3D对象是可以被连续旋转的。如果你将该值设为一个数值(弧度),则你将可以定义每次旋转3D对象时的步幅。
@@ -149,7 +134,7 @@
 
 		<h2>方法</h2>
 
-		<p>共有方法请参见其基类[page:Object3D]。</p>
+		<p>共有方法请参见其基类[page:Controls]。</p>
 
 		<h3>[method:TransformControls attach] ( [param:Object3D object] )</h3>
 		<p>
@@ -166,9 +151,9 @@
 			从控制器中移除当前3D对象,并确保控制器UI是不可见的。
 		</p>
 
-		<h3>[method:undefined dispose] ()</h3>
+		<h3>[method:Object3D getHelper] ()</h3>
 		<p>
-			若不再需要该控制器,则应当调用此函数
+			返回控件的视觉表示。将辅助对象添加到场景中,以直观地变换附着的3D对象
 		</p>
 
 		<h3>[method:Raycaster getRaycaster] ()</h3>
@@ -182,6 +167,11 @@
 		<p>
 			返回变换模式。
 		</p>
+		
+		<h3>[method:undefined reset] ()</h3>
+		<p>
+			将对象的位置、旋转和缩放重置为当前变换开始时的状态。
+		</p>
 
 		<h3>[method:undefined setMode] ( [param:String mode] )</h3>
 		<p>

+ 0 - 72
docs/examples/zh/geometries/SDFGeometryGenerator.html

@@ -1,72 +0,0 @@
-<!DOCTYPE html>
-<html lang="zh">
-
-<head>
-	<meta charset="utf-8" />
-	<base href="../../../" />
-	<script src="page.js"></script>
-	<link type="text/css" rel="stylesheet" href="page.css" />
-</head>
-
-<body>
-
-	<h1>SDF几何体生成器([name])</h1>
-
-	<p class="desc">
-		[name] 从有符号距离函数 生成 [page:BufferGeometry] 实例。</br>
-		使用 <a href="https://www.npmjs.com/package/isosurface" target="_blank"> Mikola Lysenko 的等值面。</a>
-	</p>
-
-	<h2>导入</h2>
-
-	<p>
-		[name] 是一个附加组件,必须显式导入。请参阅 [link:#manual/introduction/Installation Installation / Addons].
-	</p>
-
-	<code>
-			import { SDFGeometryGenerator } from 'three/addons/geometries/SDFGeometryGenerator.js';
-		</code>
-
-	<h2>代码示例</h2>
-
-	<code>
-		const generator = new SDFGeometryGenerator( renderer );
-		const sdf = 'float dist( vec3 p ){ return length(p) - 0.5; }' // glsl
-		const geometry = generator.generate( 64, sdf, 1 ); // ~> THREE.BufferGeometry
-		</code>
-
-	<h2>例子</h2>
-
-	<p>[example:webgl_geometry_sdf geometry / sdf ]</p>
-
-	<h2>构造函数</h2>
-
-	<h3>[name]( [param:WebGLRenderer renderer] )</h3>
-
-	<p>
-		[page:WebGLRenderer renderer] -- 用于渲染场景的渲染器。<br />
-	</p>
-
-	<h2>方法</h2>
-
-	<h3>[method:BufferGeometry generate]( [param:Int resolution], [param:String distanceField], [param:Int bounds] )</h3>
-
-	<p>
-		<b>resolution</b> - Int [必填项] 用于三角测量的“体素”数量。必须是 2 的幂。256 之后会变得很重,大多数机器将无法处理超过 512 的数据。默认为 64。
-	</p>
-	<p>
-		<b>distanceField</b> - String [必填项] 具有 glsl 距离函数的字符串。函数名称必须是“dist”,带有 vec3 参数。(参见上面的代码)。默认为球体距离。
-	</p>
-	<p>
-		<b>bounds</b> - Int [可选] 将评估有符号距离字段的边界。默认为 1。
-	</p>
-
-
-	<h2>源代码</h2>
-
-	<p>
-		[link:https://github.com/mrdoob/three.js/blob/master/examples/jsm/geometries/SDFGeometry.js examples/jsm/geometries/SDFGeometryGenerator.js]
-	</p>
-</body>
-
-</html>

+ 1 - 2
docs/examples/zh/geometries/TeapotGeometry.html

@@ -63,8 +63,7 @@
 	<h2>源代码</h2>
 
 	<p>
-		[link:https://github.com/mrdoob/three.js/blob/master/examples/jsm/geometries/TeapotGeometry.js
-		examples/jsm/geometries/TeapotGeometry.js]
+		[link:https://github.com/mrdoob/three.js/blob/master/examples/jsm/geometries/TeapotGeometry.js examples/jsm/geometries/TeapotGeometry.js]
 	</p>
 </body>
 

+ 8 - 2
docs/index.html

@@ -538,17 +538,23 @@
 			const oldIframe = iframe;
 			iframe = oldIframe.cloneNode();
 
+			iframe.style.display = 'none';
+
 			if ( hash && titles[ splitHash[ 0 ] ] ) {
 
+				iframe.onload = function () {
+
+					iframe.style.display = 'unset';
+
+				};
+
 				iframe.src = splitHash[ 0 ] + '.html' + splitHash[ 1 ];
 				subtitle = titles[ splitHash[ 0 ] ] + splitHash[ 1 ] + ' – ';
-				iframe.style.display = 'unset';
 
 			} else {
 
 				iframe.src = '';
 				subtitle = '';
-				iframe.style.display = 'none';
 
 			}
 

+ 17 - 6
docs/list.json

@@ -346,7 +346,6 @@
 				"ConvexGeometry": "examples/en/geometries/ConvexGeometry",
 				"DecalGeometry": "examples/en/geometries/DecalGeometry",
 				"ParametricGeometry": "examples/en/geometries/ParametricGeometry",
-				"SDFGeometryGenerator": "examples/en/geometries/SDFGeometryGenerator",
 				"TeapotGeometry": "examples/en/geometries/TeapotGeometry",
 				"TextGeometry": "examples/en/geometries/TextGeometry"
 			},
@@ -363,6 +362,14 @@
 				"LightProbeGenerator": "examples/en/lights/LightProbeGenerator"
 			},
 
+			"Lines": {
+				"Line2": "examples/en/lines/Line2",
+				"LineGeometry": "examples/en/lines/LineGeometry",
+				"LineMaterial": "examples/en/lines/LineMaterial",
+				"LineSegments2": "examples/en/lines/LineSegments2",
+				"LineSegmentsGeometry": "examples/en/lines/LineSegmentsGeometry"
+			},
+
 			"Loaders": {
 				"3DMLoader": "examples/en/loaders/3DMLoader",
 				"DRACOLoader": "examples/en/loaders/DRACOLoader",
@@ -434,7 +441,7 @@
 				"SceneUtils": "examples/en/utils/SceneUtils",
 				"SkeletonUtils": "examples/en/utils/SkeletonUtils"
 			},
-			
+
 			"WebXR": {
 				"XREstimatedLight": "examples/en/webxr/XREstimatedLight"
 			}
@@ -859,7 +866,8 @@
 				"Earcut": "api/zh/extras/Earcut",
 				"ImageUtils": "api/zh/extras/ImageUtils",
 				"PMREMGenerator": "api/zh/extras/PMREMGenerator",
-				"ShapeUtils": "api/zh/extras/ShapeUtils"
+				"ShapeUtils": "api/zh/extras/ShapeUtils",
+				"TextureUtils": "api/zh/extras/TextureUtils"
 			},
 
 			"附件 / 核心": {
@@ -1100,8 +1108,7 @@
 				"DecalGeometry": "examples/zh/geometries/DecalGeometry",
 				"ParametricGeometry": "examples/zh/geometries/ParametricGeometry",
 				"TeapotGeometry": "examples/zh/geometries/TeapotGeometry",
-				"TextGeometry": "examples/zh/geometries/TextGeometry",
-				"SDFGeometryGenerator": "examples/zh/geometries/SDFGeometryGenerator"
+				"TextGeometry": "examples/zh/geometries/TextGeometry"
 			},
 
 			"辅助对象": {
@@ -1362,12 +1369,16 @@
 				"DragControls": "examples/ko/controls/DragControls",
 				"FirstPersonControls": "examples/ko/controls/FirstPersonControls",
 				"FlyControls": "examples/ko/controls/FlyControls",
+				"MapControls": "examples/ko/controls/MapControls",
 				"OrbitControls": "examples/ko/controls/OrbitControls",
 				"PointerLockControls": "examples/ko/controls/PointerLockControls",
 				"TrackballControls": "examples/ko/controls/TrackballControls",
 				"TransformControls": "examples/ko/controls/TransformControls"
-			}
+			},
 
+			"WebXR": {
+				"XREstimatedLight": "examples/ko/webxr/XREstimatedLight"
+			}
 		}
 
 	},

+ 5 - 5
docs/manual/ar/introduction/How-to-create-VR-content.html

@@ -59,15 +59,15 @@ renderer.setAnimationLoop( function () {
 		<p>
 			ألق نظرة على أحد أمثلة WebVR الرسمية لرؤية سير العمل.<br /><br />
 
-			[example:webxr_vr_ballshooter WebXR / VR / ballshooter]<br />
-			[example:webxr_vr_cubes WebXR / VR / cubes]<br />
-			[example:webxr_vr_dragging WebXR / VR / dragging]<br />
-			[example:webxr_vr_paint WebXR / VR / paint]<br />
+			[example:webxr_xr_ballshooter WebXR / XR / ballshooter]<br />
+			[example:webxr_xr_cubes WebXR / XR / cubes]<br />
+			[example:webxr_xr_dragging WebXR / XR / dragging]<br />
+			[example:webxr_xr_paint WebXR / XR / paint]<br />
+			[example:webxr_xr_sculpt WebXR / XR / sculpt]<br />
 			[example:webxr_vr_panorama_depth WebXR / VR / panorama_depth]<br />
 			[example:webxr_vr_panorama WebXR / VR / panorama]<br />
 			[example:webxr_vr_rollercoaster WebXR / VR / rollercoaster]<br />
 			[example:webxr_vr_sandbox WebXR / VR / sandbox]<br />
-			[example:webxr_vr_sculpt WebXR / VR / sculpt]<br />
 			[example:webxr_vr_video WebXR / VR / video]
 		</p>
 

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

@@ -107,6 +107,7 @@
 			<li>[link:https://threlte.xyz/ Threlte] - Svelte components for 3D graphics built on Three.</li>
 			<li>[link:https://needle.tools/ Needle Engine]</li>
 			<li>[link:https://tresjs.org/ tresjs] - Vue components for 3D graphics built on Three.</li>
+			<li>[link:https://giro3d.org Giro3D] - Versatile framework built on Three for visualizing and interacting with Geospatial 2D, 2.5D and 3D data.</li>			
 		</ul>
 
 	</body>

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

@@ -64,15 +64,15 @@ renderer.setAnimationLoop( function () {
 	<p>
 		Have a look at one of the official WebVR examples to see this workflow in action.<br /><br />
 
-		[example:webxr_vr_ballshooter WebXR / VR / ballshooter]<br />
-		[example:webxr_vr_cubes WebXR / VR / cubes]<br />
-		[example:webxr_vr_dragging WebXR / VR / dragging]<br />
-		[example:webxr_vr_paint WebXR / VR / paint]<br />
+		[example:webxr_xr_ballshooter WebXR / XR / ballshooter]<br />
+		[example:webxr_xr_cubes WebXR / XR / cubes]<br />
+		[example:webxr_xr_dragging WebXR / XR / dragging]<br />
+		[example:webxr_xr_paint WebXR / XR / paint]<br />
+		[example:webxr_xr_sculpt WebXR / XR / sculpt]<br />
 		[example:webxr_vr_panorama_depth WebXR / VR / panorama_depth]<br />
 		[example:webxr_vr_panorama WebXR / VR / panorama]<br />
 		[example:webxr_vr_rollercoaster WebXR / VR / rollercoaster]<br />
 		[example:webxr_vr_sandbox WebXR / VR / sandbox]<br />
-		[example:webxr_vr_sculpt WebXR / VR / sculpt]<br />
 		[example:webxr_vr_video WebXR / VR / video]
 	</p>
 

+ 1 - 1
docs/manual/en/introduction/How-to-update-things.html

@@ -62,7 +62,7 @@ const MAX_POINTS = 500;
 const geometry = new THREE.BufferGeometry();
 
 // attributes
-const positions = new Float32Array( MAX_POINTS * 3 ); // 3 vertices per point
+const positions = new Float32Array( MAX_POINTS * 3 ); // 3 floats (x, y and z) per point
 geometry.setAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );
 
 // draw range

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

@@ -111,6 +111,7 @@
 			<li>[link:https://threlte.xyz/ Threlte] - Svelte components for 3D graphics built on Three.</li>
 			<li>[link:https://needle.tools/ Needle Engine]</li>
 			<li>[link:https://tresjs.org/ tresjs] - Vue components for 3D graphics built on Three.</li>
+			<li>[link:https://giro3d.org Giro3D] - Versatile framework built on Three for visualizing and interacting with Geospatial 2D, 2.5D and 3D data.</li>
 		</ul>
 
 	</body>

+ 5 - 5
docs/manual/fr/introduction/How-to-create-VR-content.html

@@ -64,15 +64,15 @@ renderer.setAnimationLoop( function () {
 	<p>
 		Jetez un coup d'oeil à un des exemples officiels WebVR pour voir le workflow en action.<br /><br />
 
-		[example:webxr_vr_ballshooter WebXR / VR / ballshooter]<br />
-		[example:webxr_vr_cubes WebXR / VR / cubes]<br />
-		[example:webxr_vr_dragging WebXR / VR / dragging]<br />
-		[example:webxr_vr_paint WebXR / VR / paint]<br />
+		[example:webxr_xr_ballshooter WebXR / XR / ballshooter]<br />
+		[example:webxr_xr_cubes WebXR / XR / cubes]<br />
+		[example:webxr_xr_dragging WebXR / XR / dragging]<br />
+		[example:webxr_xr_paint WebXR / XR / paint]<br />
+		[example:webxr_xr_sculpt WebXR / XR / sculpt]<br />
 		[example:webxr_vr_panorama_depth WebXR / VR / panorama_depth]<br />
 		[example:webxr_vr_panorama WebXR / VR / panorama]<br />
 		[example:webxr_vr_rollercoaster WebXR / VR / rollercoaster]<br />
 		[example:webxr_vr_sandbox WebXR / VR / sandbox]<br />
-		[example:webxr_vr_sculpt WebXR / VR / sculpt]<br />
 		[example:webxr_vr_video WebXR / VR / video]
 	</p>
 

+ 10 - 9
docs/manual/fr/introduction/How-to-update-things.html

@@ -95,22 +95,23 @@ for ( let i = 0; i < positionAttribute.count; i ++ ) {
 }
 			</code>
 			<p>
-				If you want to change the <em>number of points</em> rendered after the first render, do this:
+				Si vous voulez changer le <em>nombre de points</em> rendus après le premier rendu, faites ainsi :
 			</p>
 			<code>
 line.geometry.setDrawRange( 0, newValue );
 			</code>
 			<p>
-				If you want to change the position data values after the first render, you need to
-				set the needsUpdate flag like so:
+				Si vous voulez changer la valeur des données de position après le premier rendu, vous devez
+				régler le flag needsUpdate ainsi : 
 			</p>
 			<code>
 positionAttribute.needsUpdate = true; // required after the first render
 			</code>
 
 			<p>
-				If you change the position data values after the initial render, you may need to recompute
-				bounding volumes so other features of the engine like view frustum culling or helpers properly work.
+				Si vous changez les valeurs de la donnée de position après le premier rendu, vous devez
+				recalculer les volumes englobants de telle sorte que les autres fonctionnalités du moteur comme
+				le frustrum culling ou les helpers le prenne en compte correctement.
 			</p>
 			<code>
 line.geometry.computeBoundingBox();
@@ -118,10 +119,10 @@ line.geometry.computeBoundingSphere();
 			</code>
 
 			<p>
-				[link:https://jsfiddle.net/t4m85pLr/1/ Here is a fiddle] showing an animated line which you can adapt to your use case.
+				[link:https://jsfiddle.net/t4m85pLr/1/ Voici un fiddle] montrant une ligne animée, que vous pouvez adapter comme vous le souhaitez.
 			</p>
 
-			<h3>Examples</h3>
+			<h3>Exemples</h3>
 
 			<p>
 				[example:webgl_custom_attributes WebGL / custom / attributes]<br />
@@ -130,11 +131,11 @@ line.geometry.computeBoundingSphere();
 
 		</div>
 
-		<h2>Materiaux</h2>
+		<h2>Matériaux</h2>
 		<div>
 			<p>Toutes les valeurs uniformes peuvent être changées librement(e.g. couleurs, textures, opacité, etc), les valeurs sont envoyées aux shaders à chaque frame.</p>
 
-			<p>De plus, les paramètresen relation avec GLstate peuvent changer à tout moment (depthTest, blending, polygonOffset, etc).</p>
+			<p>De plus, les paramètres en relation avec GLstate peuvent changer à tout moment (depthTest, blending, polygonOffset, etc).</p>
 
 			<p>Les propriétés suivantes ne peuvent pas être changées facilement durant l'exécution (une fois que le matériau a été rendu au moins une fois):</p>
 			<ul>

+ 5 - 5
docs/manual/fr/introduction/How-to-use-post-processing.html

@@ -88,11 +88,11 @@
 			[link:https://github.com/mrdoob/three.js/tree/dev/examples/jsm/postprocessing postprocessing].
 		</p>
 
-		<h2>Effets Customisés</h2>
+		<h2>Effets Personnalisés</h2>
 
 		<p>
-			Parfois vous voulez écrire un shader de post-processing customisé et l'inclure dans les effets (passes) de post-processing. Dans ce scénario,
-			vous pouvez utiliser `ShaderPass`. Après avoir importé le fichier et votre shader customisé, vous pouvez utiliser le code suivant pour mettre en place l'effet (pass).
+			Parfois vous voulez écrire un shader de post-processing personnalisé et l'inclure dans les effets (passes) de post-processing. Dans ce scénario,
+			vous pouvez utiliser `ShaderPass`. Après avoir importé le fichier et votre shader personnalisé, vous pouvez utiliser le code suivant pour mettre en place l'effet (pass).
 		</p>
 
 		<code>
@@ -106,8 +106,8 @@
 		</code>
 
 		<p>
-			Ce repository fournit un fichier appelé [link:https://github.com/mrdoob/three.js/blob/master/examples/jsm/shaders/CopyShader.js CopyShader] qui est
-			une bonne base de code pour créer votre propose shader customisé. `CopyShader` copie simplement le contenu de l'image du buffer de l'[page:EffectComposer]
+			Ce dépôt fournit un fichier appelé [link:https://github.com/mrdoob/three.js/blob/master/examples/jsm/shaders/CopyShader.js CopyShader] qui est
+			une bonne base de code pour créer votre propose shader personnalisé. `CopyShader` copie simplement le contenu de l'image du buffer de l'[page:EffectComposer]
 			à son buffer d'écriture sans y appliquer aucun effet.
 		</p>
 

+ 8 - 7
docs/manual/fr/introduction/Libraries-and-Plugins.html

@@ -37,7 +37,7 @@
 			<li>[link:https://github.com/vanruesc/postprocessing postprocessing]</li>
 		</ul>
 
-		<h3>Intersections et Performance de Raycast</h3>
+		<h3>Intersections et lancers de rayon</h3>
 
 		<ul>
 			<li>[link:https://github.com/gkjohnson/three-mesh-bvh three-mesh-bvh]</li>
@@ -91,7 +91,7 @@
 			<li>[link:https://github.com/gkjohnson/closed-chain-ik-js closed-chain-ik]</li>
 		</ul>
 
-		<h3>Jeu IA</h3>
+		<h3>Jeu et IA</h3>
 
 		<ul>
 			<li>[link:https://mugen87.github.io/yuka/ yuka]</li>
@@ -103,13 +103,14 @@
 
 		<ul>
 			<li>[link:https://aframe.io/ A-Frame]</li>
-			<li>[link:https://lume.io/ Lume] - HTML elements for 3D graphics built on Three.</li>
-			<li>[link:https://github.com/pmndrs/react-three-fiber react-three-fiber] - React components for 3D graphics built on Three.</li>
-			<li>[link:https://threepipe.org/ threepipe] - A versatile 3D viewer framework using three.js for rendering.</li>
+			<li>[link:https://lume.io/ Lume] - Éléments HTML pour interface 3D, basé sur Three.</li>
+			<li>[link:https://github.com/pmndrs/react-three-fiber react-three-fiber] - Composants React pour interface 3D, basé sur Three.</li>
+			<li>[link:https://threepipe.org/ threepipe] - Un framework de visualisation 3D polyvalent utilisant Three pour le rendu.</li>
 			<li>[link:https://github.com/ecsyjs/ecsy-three ECSY]</li>
-			<li>[link:https://threlte.xyz/ Threlte] - Svelte components for 3D graphics built on Three.</li>
+			<li>[link:https://threlte.xyz/ Threlte] - Des composants Svelte pour interface 3D, basé sur Three.</li>
 			<li>[link:https://needle.tools/ Needle Engine]</li>
-			<li>[link:https://tresjs.org/ tresjs] - Vue components for 3D graphics built on Three.</li>
+			<li>[link:https://tresjs.org/ tresjs] - Des composants Vue pour interface 3D, basé sur Three.</li>
+			<li>[link:https://giro3d.org Giro3D] - Un framework polyvalent basé sur Three pour la visualisation et l'interaction avec des données géospatiales 2D, 2.5D et 3D.</li>
 		</ul>
 
 	</body>

+ 5 - 5
docs/manual/it/introduction/How-to-create-VR-content.html

@@ -62,15 +62,15 @@ renderer.setAnimationLoop( function () {
 	<p>
     Dai un'occhiata ad uno degli esempi ufficiali di WebVR per vedere questo flusso di lavoro in azione. <br /><br />
 
-		[example:webxr_vr_ballshooter WebXR / VR / ballshooter]<br />
-		[example:webxr_vr_cubes WebXR / VR / cubes]<br />
-		[example:webxr_vr_dragging WebXR / VR / dragging]<br />
-		[example:webxr_vr_paint WebXR / VR / paint]<br />
+		[example:webxr_xr_ballshooter WebXR / XR / ballshooter]<br />
+		[example:webxr_xr_cubes WebXR / XR / cubes]<br />
+		[example:webxr_xr_dragging WebXR / XR / dragging]<br />
+		[example:webxr_xr_paint WebXR / XR / paint]<br />
+		[example:webxr_xr_sculpt WebXR / XR / sculpt]<br />
 		[example:webxr_vr_panorama_depth WebXR / VR / panorama_depth]<br />
 		[example:webxr_vr_panorama WebXR / VR / panorama]<br />
 		[example:webxr_vr_rollercoaster WebXR / VR / rollercoaster]<br />
 		[example:webxr_vr_sandbox WebXR / VR / sandbox]<br />
-		[example:webxr_vr_sculpt WebXR / VR / sculpt]<br />
 		[example:webxr_vr_video WebXR / VR / video]
 	</p>
 

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

@@ -110,6 +110,7 @@
 			<li>[link:https://threlte.xyz/ Threlte] - Svelte components for 3D graphics built on Three.</li>
 			<li>[link:https://needle.tools/ Needle Engine]</li>
 			<li>[link:https://tresjs.org/ tresjs] - Vue components for 3D graphics built on Three.</li>
+			<li>[link:https://giro3d.org Giro3D] - Versatile framework built on Three for visualizing and interacting with Geospatial 2D, 2.5D and 3D data.</li>			
 		</ul>
 
 	</body>

+ 5 - 5
docs/manual/ja/introduction/How-to-create-VR-content.html

@@ -58,15 +58,15 @@ renderer.setAnimationLoop( function () {
 	<p>
 		このワークフローを実際に見るために、公式のWebVRの例を見てみましょう。<br /><br />
 
-		[example:webxr_vr_ballshooter WebXR / VR / ballshooter]<br />
-		[example:webxr_vr_cubes WebXR / VR / cubes]<br />
-		[example:webxr_vr_dragging WebXR / VR / dragging]<br />
-		[example:webxr_vr_paint WebXR / VR / paint]<br />
+		[example:webxr_xr_ballshooter WebXR / XR / ballshooter]<br />
+		[example:webxr_xr_cubes WebXR / XR / cubes]<br />
+		[example:webxr_xr_dragging WebXR / XR / dragging]<br />
+		[example:webxr_xr_paint WebXR / XR / paint]<br />
+		[example:webxr_xr_sculpt WebXR / XR / sculpt]<br />
 		[example:webxr_vr_panorama_depth WebXR / VR / panorama_depth]<br />
 		[example:webxr_vr_panorama WebXR / VR / panorama]<br />
 		[example:webxr_vr_rollercoaster WebXR / VR / rollercoaster]<br />
 		[example:webxr_vr_sandbox WebXR / VR / sandbox]<br />
-		[example:webxr_vr_sculpt WebXR / VR / sculpt]<br />
 		[example:webxr_vr_video WebXR / VR / video]
 	</p>
 

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

@@ -103,6 +103,7 @@
         <li>[link:https://threlte.xyz/ Threlte] - Svelte components for 3D graphics built on Three.</li>
         <li>[link:https://needle.tools/ Needle Engine]</li>
         <li>[link:https://tresjs.org/ tresjs] - Vue components for 3D graphics built on Three.</li>
+		<li>[link:https://giro3d.org Giro3D] - Versatile framework built on Three for visualizing and interacting with Geospatial 2D, 2.5D and 3D data.</li>        
     </ul>
 
 </body>

+ 2 - 2
docs/manual/ko/introduction/Drawing-lines.html

@@ -47,7 +47,7 @@ points.push( new THREE.Vector3( 10, 0, 0 ) );
 const geometry = new THREE.BufferGeometry().setFromPoints( points );
 			</code>
 
-        <p>선은 연속된 꼭짓점 쌍 사이에 그려지고 첫 번와 마지막 꼭짓점에는 그려지지 않습니다. (선은 닫혀있지 않습니다.)</p>
+        <p>선은 연속된 꼭짓점 쌍 사이에 그려지고 첫 번와 마지막 꼭짓점에는 그려지지 않습니다. (선은 닫혀있지 않습니다.)</p>
 
         <p>이제 두 선을 그리기 위한 점과 재질이 있으니, 합쳐서 선을 만들 수 있습니다.</p>
         <code>
@@ -64,4 +64,4 @@ renderer.render( scene, camera );
     </div>
 </body>
 
-</html>
+</html>

+ 5 - 5
docs/manual/ko/introduction/How-to-create-VR-content.html

@@ -62,15 +62,15 @@ renderer.setAnimationLoop( function () {
 	<p>
 		실행을 위한 작업 절차와 관련된 공식 WebVR 예제를 확인하세요.<br /><br />
 
-		[example:webxr_vr_ballshooter WebXR / VR / ballshooter]<br />
-		[example:webxr_vr_cubes WebXR / VR / cubes]<br />
-		[example:webxr_vr_dragging WebXR / VR / dragging]<br />
-		[example:webxr_vr_paint WebXR / VR / paint]<br />
+		[example:webxr_xr_ballshooter WebXR / XR / ballshooter]<br />
+		[example:webxr_xr_cubes WebXR / XR / cubes]<br />
+		[example:webxr_xr_dragging WebXR / XR / dragging]<br />
+		[example:webxr_xr_paint WebXR / XR / paint]<br />
+		[example:webxr_xr_sculpt WebXR / XR / sculpt]<br />
 		[example:webxr_vr_panorama_depth WebXR / VR / panorama_depth]<br />
 		[example:webxr_vr_panorama WebXR / VR / panorama]<br />
 		[example:webxr_vr_rollercoaster WebXR / VR / rollercoaster]<br />
 		[example:webxr_vr_sandbox WebXR / VR / sandbox]<br />
-		[example:webxr_vr_sculpt WebXR / VR / sculpt]<br />
 		[example:webxr_vr_video WebXR / VR / video]
 	</p>
 

+ 5 - 5
docs/manual/pt-br/introduction/How-to-create-VR-content.html

@@ -64,15 +64,15 @@ renderer.setAnimationLoop( function () {
 	<p>
 		Dê uma olhada em um dos exemplos oficiais de WebVR para ver esse workflow em ação<br /><br />
 
-		[example:webxr_vr_ballshooter WebXR / VR / ballshooter]<br />
-		[example:webxr_vr_cubes WebXR / VR / cubes]<br />
-		[example:webxr_vr_dragging WebXR / VR / dragging]<br />
-		[example:webxr_vr_paint WebXR / VR / paint]<br />
+		[example:webxr_xr_ballshooter WebXR / XR / ballshooter]<br />
+		[example:webxr_xr_cubes WebXR / XR / cubes]<br />
+		[example:webxr_xr_dragging WebXR / XR / dragging]<br />
+		[example:webxr_xr_paint WebXR / XR / paint]<br />
+		[example:webxr_xr_sculpt WebXR / XR / sculpt]<br />
 		[example:webxr_vr_panorama_depth WebXR / VR / panorama_depth]<br />
 		[example:webxr_vr_panorama WebXR / VR / panorama]<br />
 		[example:webxr_vr_rollercoaster WebXR / VR / rollercoaster]<br />
 		[example:webxr_vr_sandbox WebXR / VR / sandbox]<br />
-		[example:webxr_vr_sculpt WebXR / VR / sculpt]<br />
 		[example:webxr_vr_video WebXR / VR / video]
 	</p>
 

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

@@ -110,6 +110,7 @@
 			<li>[link:https://threlte.xyz/ Threlte] - Svelte components for 3D graphics built on Three.</li>
 			<li>[link:https://needle.tools/ Needle Engine]</li>
 			<li>[link:https://tresjs.org/ tresjs] - Vue components for 3D graphics built on Three.</li>
+			<li>[link:https://giro3d.org Giro3D] - Versatile framework built on Three for visualizing and interacting with Geospatial 2D, 2.5D and 3D data.</li>			
 		</ul>
 
 	</body>

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

@@ -109,6 +109,7 @@
 			<li>[link:https://threlte.xyz/ Threlte] - Svelte components for 3D graphics built on Three.</li>
 			<li>[link:https://needle.tools/ Needle Engine]</li>
 			<li>[link:https://tresjs.org/ tresjs] - Vue components for 3D graphics built on Three.</li>
+			<li>[link:https://giro3d.org Giro3D] - Versatile framework built on Three for visualizing and interacting with Geospatial 2D, 2.5D and 3D data.</li>
 		</ul>
 
 	</body>

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

@@ -64,15 +64,15 @@ renderer.setAnimationLoop( function () {
 		请查看官方示例中与WebVR相关的示例,了解这一工作流程的实际使用、运行情况。
 		<br /><br />
 
-		[example:webxr_vr_ballshooter WebXR / VR / ballshooter]<br />
-		[example:webxr_vr_cubes WebXR / VR / cubes]<br />
-		[example:webxr_vr_dragging WebXR / VR / dragging]<br />
-		[example:webxr_vr_paint WebXR / VR / paint]<br />
+		[example:webxr_xr_ballshooter WebXR / XR / ballshooter]<br />
+		[example:webxr_xr_cubes WebXR / XR / cubes]<br />
+		[example:webxr_xr_dragging WebXR / XR / dragging]<br />
+		[example:webxr_xr_paint WebXR / XR / paint]<br />
+		[example:webxr_xr_sculpt WebXR / XR / sculpt]<br />
 		[example:webxr_vr_panorama_depth WebXR / VR / panorama_depth]<br />
 		[example:webxr_vr_panorama WebXR / VR / panorama]<br />
 		[example:webxr_vr_rollercoaster WebXR / VR / rollercoaster]<br />
 		[example:webxr_vr_sandbox WebXR / VR / sandbox]<br />
-		[example:webxr_vr_sculpt WebXR / VR / sculpt]<br />
 		[example:webxr_vr_video WebXR / VR / video]
 	</p>
 

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

@@ -106,6 +106,7 @@
 			<li>[link:https://threlte.xyz/ Threlte] - Svelte components for 3D graphics built on Three.</li>
 			<li>[link:https://needle.tools/ Needle Engine]</li>
 			<li>[link:https://tresjs.org/ tresjs] - Vue components for 3D graphics built on Three.</li>
+			<li>[link:https://giro3d.org Giro3D] - Versatile framework built on Three for visualizing and interacting with Geospatial 2D, 2.5D and 3D data.</li>
 		</ul>
 
 	</body>

+ 4 - 0
docs/page.css

@@ -122,6 +122,10 @@ summary {
 	margin-bottom: 16px;
 }
 
+summary:hover {
+	cursor: pointer;
+}
+
 p {
 	padding-right: 16px;
 }

+ 1 - 1
editor/js/Viewport.js

@@ -142,7 +142,7 @@ function Viewport( editor ) {
 
 	} );
 
-	sceneHelpers.add( transformControls );
+	sceneHelpers.add( transformControls.getHelper() );
 
 	//
 

+ 11 - 3
examples/files.json

@@ -34,7 +34,6 @@
 		"webgl_geometry_extrude_splines",
 		"webgl_geometry_minecraft",
 		"webgl_geometry_nurbs",
-		"webgl_geometry_sdf",
 		"webgl_geometry_shapes",
 		"webgl_geometry_spline_editor",
 		"webgl_geometry_teapot",
@@ -114,7 +113,6 @@
 		"webgl_loader_ply",
 		"webgl_loader_stl",
 		"webgl_loader_svg",
-		"webgl_loader_tilt",
 		"webgl_loader_texture_dds",
 		"webgl_loader_texture_exr",
 		"webgl_loader_texture_ultrahdr",
@@ -254,7 +252,6 @@
 		"webgl_buffergeometry",
 		"webgl_buffergeometry_attributes_integer",
 		"webgl_buffergeometry_attributes_none",
-		"webgl_buffergeometry_compression",
 		"webgl_buffergeometry_custom_attributes_particles",
 		"webgl_buffergeometry_drawrange",
 		"webgl_buffergeometry_glbufferattribute",
@@ -302,6 +299,8 @@
 		"webgl_performance"
 	],
 	"webgpu (wip)": [
+		"webgpu_animation_retargeting",
+		"webgpu_animation_retargeting_readyplayer",
 		"webgpu_backdrop",
 		"webgpu_backdrop_area",
 		"webgpu_backdrop_water",
@@ -315,8 +314,10 @@
 		"webgpu_compute_particles_rain",
 		"webgpu_compute_particles_snow",
 		"webgpu_compute_points",
+		"webgpu_compute_sort_bitonic",
 		"webgpu_compute_texture",
 		"webgpu_compute_texture_pingpong",
+		"webgpu_compute_water",
 		"webgpu_cubemap_adjustments",
 		"webgpu_cubemap_dynamic",
 		"webgpu_cubemap_mix",
@@ -329,7 +330,9 @@
 		"webgpu_instance_points",
 		"webgpu_instance_uniform",
 		"webgpu_instancing_morph",
+		"webgpu_lensflares",
 		"webgpu_lightprobe",
+		"webgpu_lightprobe_cubecamera",
 		"webgpu_lights_custom",
 		"webgpu_lights_ies_spotlight",
 		"webgpu_lights_phong",
@@ -345,6 +348,7 @@
 		"webgpu_loader_gltf_transmission",
 		"webgpu_loader_materialx",
 		"webgpu_materials",
+		"webgpu_materials_arrays",
 		"webgpu_materials_basic",
 		"webgpu_materials_displacementmap",
 		"webgpu_materials_envmaps",
@@ -357,6 +361,7 @@
 		"webgpu_materialx_noise",
 		"webgpu_mesh_batch",
 		"webgpu_mirror",
+		"webgpu_modifier_curve",
 		"webgpu_morphtargets",
 		"webgpu_morphtargets_face",
 		"webgpu_mrt",
@@ -399,6 +404,7 @@
 		"webgpu_shadertoy",
 		"webgpu_shadowmap",
 		"webgpu_shadowmap_opacity",
+		"webgpu_shadowmap_vsm",
 		"webgpu_skinning",
 		"webgpu_skinning_instancing",
 		"webgpu_skinning_points",
@@ -410,6 +416,7 @@
 		"webgpu_textures_2d-array_compressed",
 		"webgpu_textures_anisotropy",
 		"webgpu_textures_partialupdate",
+		"webgpu_tonemapping",
 		"webgpu_tsl_angular_slicing",
 		"webgpu_tsl_coffee_smoke",
 		"webgpu_tsl_compute_attractors_particles",
@@ -422,6 +429,7 @@
 		"webgpu_tsl_raging_sea",
 		"webgpu_tsl_transpiler",
 		"webgpu_tsl_vfx_flames",
+		"webgpu_tsl_vfx_linkedparticles",
 		"webgpu_tsl_vfx_tornado",
 		"webgpu_video_panorama",
 		"webgpu_volume_cloud",

+ 0 - 6
examples/jsm/Addons.js

@@ -124,7 +124,6 @@ export * from './loaders/TDSLoader.js';
 export * from './loaders/TGALoader.js';
 export * from './loaders/TIFFLoader.js';
 export * from './loaders/TTFLoader.js';
-export * from './loaders/TiltLoader.js';
 export * from './loaders/USDZLoader.js';
 export * from './loaders/VOXLoader.js';
 export * from './loaders/VRMLLoader.js';
@@ -172,9 +171,6 @@ export * from './objects/ShadowMesh.js';
 export * from './objects/Sky.js';
 export * from './objects/Water.js';
 export { Water as Water2 } from './objects/Water2.js';
-export * from './objects/SkyMesh.js';
-export * from './objects/WaterMesh.js';
-export { WaterMesh as Water2Mesh } from './objects/Water2Mesh.js';
 
 export * from './physics/AmmoPhysics.js';
 export * from './physics/RapierPhysics.js';
@@ -271,11 +267,9 @@ export * from './textures/FlakesTexture.js';
 
 export * as BufferGeometryUtils from './utils/BufferGeometryUtils.js';
 export * as CameraUtils from './utils/CameraUtils.js';
-export * from './utils/GPUStatsPanel.js';
 export * as GeometryCompressionUtils from './utils/GeometryCompressionUtils.js';
 export * as GeometryUtils from './utils/GeometryUtils.js';
 export * from './utils/LDrawUtils.js';
-export * from './utils/PackedPhongMaterial.js';
 export * as SceneUtils from './utils/SceneUtils.js';
 export * from './utils/ShadowMapViewer.js';
 export * as SkeletonUtils from './utils/SkeletonUtils.js';

+ 32 - 12
examples/jsm/controls/TrackballControls.js

@@ -618,23 +618,43 @@ function onKeyDown( event ) {
 
 function onMouseDown( event ) {
 
-	if ( this.state === _STATE.NONE ) {
+	let mouseAction;
 
-		switch ( event.button ) {
+	switch ( event.button ) {
 
-			case this.mouseButtons.LEFT:
-				this.state = _STATE.ROTATE;
-				break;
+		case 0:
+			mouseAction = this.mouseButtons.LEFT;
+			break;
+
+		case 1:
+			mouseAction = this.mouseButtons.MIDDLE;
+			break;
 
-			case this.mouseButtons.MIDDLE:
-				this.state = _STATE.ZOOM;
-				break;
+		case 2:
+			mouseAction = this.mouseButtons.RIGHT;
+			break;
 
-			case this.mouseButtons.RIGHT:
-				this.state = _STATE.PAN;
-				break;
+		default:
+			mouseAction = - 1;
 
-		}
+	}
+
+	switch ( mouseAction ) {
+
+		case MOUSE.DOLLY:
+			this.state = _STATE.ZOOM;
+			break;
+
+		case MOUSE.ROTATE:
+			this.state = _STATE.ROTATE;
+			break;
+
+		case MOUSE.PAN:
+			this.state = _STATE.PAN;
+			break;
+
+		default:
+			this.state = _STATE.NONE;
 
 	}
 

+ 97 - 62
examples/jsm/controls/TransformControls.js

@@ -1,6 +1,7 @@
 import {
 	BoxGeometry,
 	BufferGeometry,
+	Controls,
 	CylinderGeometry,
 	DoubleSide,
 	Euler,
@@ -36,32 +37,22 @@ const _mouseDownEvent = { type: 'mouseDown', mode: null };
 const _mouseUpEvent = { type: 'mouseUp', mode: null };
 const _objectChangeEvent = { type: 'objectChange' };
 
-class TransformControls extends Object3D {
+class TransformControls extends Controls {
 
-	constructor( camera, domElement ) {
+	constructor( camera, domElement = null ) {
 
-		super();
-
-		if ( domElement === undefined ) {
-
-			console.warn( 'THREE.TransformControls: The second parameter "domElement" is now mandatory.' );
-			domElement = document;
+		super( undefined, domElement );
 
-		}
+		const root = new TransformControlsRoot( this );
+		this._root = root;
 
-		this.isTransformControls = true;
+		const gizmo = new TransformControlsGizmo();
+		this._gizmo = gizmo;
+		root.add( gizmo );
 
-		this.visible = false;
-		this.domElement = domElement;
-		this.domElement.style.touchAction = 'none'; // disable touch scroll
-
-		const _gizmo = new TransformControlsGizmo();
-		this._gizmo = _gizmo;
-		this.add( _gizmo );
-
-		const _plane = new TransformControlsPlane();
-		this._plane = _plane;
-		this.add( _plane );
+		const plane = new TransformControlsPlane();
+		this._plane = plane;
+		root.add( plane );
 
 		const scope = this;
 
@@ -83,8 +74,8 @@ class TransformControls extends Object3D {
 					if ( propValue !== value ) {
 
 						propValue = value;
-						_plane[ propName ] = value;
-						_gizmo[ propName ] = value;
+						plane[ propName ] = value;
+						gizmo[ propName ] = value;
 
 						scope.dispatchEvent( { type: propName + '-changed', value: value } );
 						scope.dispatchEvent( _changeEvent );
@@ -96,8 +87,8 @@ class TransformControls extends Object3D {
 			} );
 
 			scope[ propName ] = defaultValue;
-			_plane[ propName ] = defaultValue;
-			_gizmo[ propName ] = defaultValue;
+			plane[ propName ] = defaultValue;
+			gizmo[ propName ] = defaultValue;
 
 		}
 
@@ -172,50 +163,38 @@ class TransformControls extends Object3D {
 		this._onPointerMove = onPointerMove.bind( this );
 		this._onPointerUp = onPointerUp.bind( this );
 
-		this.domElement.addEventListener( 'pointerdown', this._onPointerDown );
-		this.domElement.addEventListener( 'pointermove', this._onPointerHover );
-		this.domElement.addEventListener( 'pointerup', this._onPointerUp );
-
-	}
-
-	// updateMatrixWorld updates key transformation variables
-	updateMatrixWorld( force ) {
-
-		if ( this.object !== undefined ) {
+		if ( domElement !== null ) {
 
-			this.object.updateMatrixWorld();
-
-			if ( this.object.parent === null ) {
-
-				console.error( 'TransformControls: The attached 3D object must be a part of the scene graph.' );
-
-			} else {
+			this.connect();
 
-				this.object.parent.matrixWorld.decompose( this._parentPosition, this._parentQuaternion, this._parentScale );
+		}
 
-			}
+	}
 
-			this.object.matrixWorld.decompose( this.worldPosition, this.worldQuaternion, this._worldScale );
+	connect() {
 
-			this._parentQuaternionInv.copy( this._parentQuaternion ).invert();
-			this._worldQuaternionInv.copy( this.worldQuaternion ).invert();
+		this.domElement.addEventListener( 'pointerdown', this._onPointerDown );
+		this.domElement.addEventListener( 'pointermove', this._onPointerHover );
+		this.domElement.addEventListener( 'pointerup', this._onPointerUp );
 
-		}
+		this.domElement.style.touchAction = 'none'; // disable touch scroll
 
-		this.camera.updateMatrixWorld();
-		this.camera.matrixWorld.decompose( this.cameraPosition, this.cameraQuaternion, this._cameraScale );
+	}
 
-		if ( this.camera.isOrthographicCamera ) {
+	disconnect() {
 
-			this.camera.getWorldDirection( this.eye ).negate();
+		this.domElement.removeEventListener( 'pointerdown', this._onPointerDown );
+		this.domElement.removeEventListener( 'pointermove', this._onPointerHover );
+		this.domElement.removeEventListener( 'pointermove', this._onPointerMove );
+		this.domElement.removeEventListener( 'pointerup', this._onPointerUp );
 
-		} else {
+		this.domElement.style.touchAction = 'auto';
 
-			this.eye.copy( this.cameraPosition ).sub( this.worldPosition ).normalize();
+	}
 
-		}
+	getHelper() {
 
-		super.updateMatrixWorld( force );
+		return this._root;
 
 	}
 
@@ -555,10 +534,7 @@ class TransformControls extends Object3D {
 
 	dispose() {
 
-		this.domElement.removeEventListener( 'pointerdown', this._onPointerDown );
-		this.domElement.removeEventListener( 'pointermove', this._onPointerHover );
-		this.domElement.removeEventListener( 'pointermove', this._onPointerMove );
-		this.domElement.removeEventListener( 'pointerup', this._onPointerUp );
+		this.disconnect();
 
 		this.traverse( function ( child ) {
 
@@ -573,7 +549,7 @@ class TransformControls extends Object3D {
 	attach( object ) {
 
 		this.object = object;
-		this.visible = true;
+		this._root.visible = true;
 
 		return this;
 
@@ -583,9 +559,10 @@ class TransformControls extends Object3D {
 	detach() {
 
 		this.object = undefined;
-		this.visible = false;
 		this.axis = null;
 
+		this._root.visible = false;
+
 		return this;
 
 	}
@@ -778,6 +755,64 @@ const _v1 = new Vector3();
 const _v2 = new Vector3();
 const _v3 = new Vector3();
 
+class TransformControlsRoot extends Object3D {
+
+	constructor( controls ) {
+
+		super();
+
+		this.isTransformControlsRoot = true;
+
+		this.controls = controls;
+		this.visible = false;
+
+	}
+
+	// updateMatrixWorld updates key transformation variables
+	updateMatrixWorld( force ) {
+
+		const controls = this.controls;
+
+		if ( controls.object !== undefined ) {
+
+			controls.object.updateMatrixWorld();
+
+			if ( controls.object.parent === null ) {
+
+				console.error( 'TransformControls: The attached 3D object must be a part of the scene graph.' );
+
+			} else {
+
+				controls.object.parent.matrixWorld.decompose( controls._parentPosition, controls._parentQuaternion, controls._parentScale );
+
+			}
+
+			controls.object.matrixWorld.decompose( controls.worldPosition, controls.worldQuaternion, controls._worldScale );
+
+			controls._parentQuaternionInv.copy( controls._parentQuaternion ).invert();
+			controls._worldQuaternionInv.copy( controls.worldQuaternion ).invert();
+
+		}
+
+		controls.camera.updateMatrixWorld();
+		controls.camera.matrixWorld.decompose( controls.cameraPosition, controls.cameraQuaternion, controls._cameraScale );
+
+		if ( controls.camera.isOrthographicCamera ) {
+
+			controls.camera.getWorldDirection( controls.eye ).negate();
+
+		} else {
+
+			controls.eye.copy( controls.cameraPosition ).sub( controls.worldPosition ).normalize();
+
+		}
+
+		super.updateMatrixWorld( force );
+
+	}
+
+}
+
 class TransformControlsGizmo extends Object3D {
 
 	constructor() {

+ 4 - 2
examples/jsm/exporters/DRACOExporter.js

@@ -1,4 +1,4 @@
-import { Color } from 'three';
+import { Color, ColorManagement, SRGBColorSpace } from 'three';
 
 /**
  * Export draco compressed files from threejs geometry objects.
@@ -227,7 +227,9 @@ function createVertexColorSRGBArray( attribute ) {
 
 	for ( let i = 0, il = count; i < il; i ++ ) {
 
-		_color.fromBufferAttribute( attribute, i ).convertLinearToSRGB();
+		_color.fromBufferAttribute( attribute, i );
+
+		ColorManagement.fromWorkingColorSpace( _color, SRGBColorSpace );
 
 		array[ i * itemSize ] = _color.r;
 		array[ i * itemSize + 1 ] = _color.g;

+ 19 - 11
examples/jsm/exporters/EXRExporter.js

@@ -21,20 +21,20 @@ const ZIP_COMPRESSION = 3;
 
 class EXRExporter {
 
-	parse( arg1, arg2, arg3 ) {
+	async parse( arg1, arg2, arg3 ) {
 
-		if ( ! arg1 || ! ( arg1.isWebGLRenderer || arg1.isDataTexture ) ) {
+		if ( ! arg1 || ! ( arg1.isWebGLRenderer || arg1.isWebGPURenderer || arg1.isDataTexture ) ) {
 
 			throw Error( 'EXRExporter.parse: Unsupported first parameter, expected instance of WebGLRenderer or DataTexture.' );
 
-		} else if ( arg1.isWebGLRenderer ) {
+		} else if ( arg1.isWebGLRenderer || arg1.isWebGPURenderer ) {
 
 			const renderer = arg1, renderTarget = arg2, options = arg3;
 
 			supportedRTT( renderTarget );
 
 			const info = buildInfoRTT( renderTarget, options ),
-				dataBuffer = getPixelData( renderer, renderTarget, info ),
+				dataBuffer = await getPixelData( renderer, renderTarget, info ),
 				rawContentBuffer = reorganizeDataBuffer( dataBuffer, info ),
 				chunks = compressData( rawContentBuffer, info );
 
@@ -61,7 +61,7 @@ class EXRExporter {
 
 function supportedRTT( renderTarget ) {
 
-	if ( ! renderTarget || ! renderTarget.isWebGLRenderTarget ) {
+	if ( ! renderTarget || ! renderTarget.isRenderTarget ) {
 
 		throw Error( 'EXRExporter.parse: Unsupported second parameter, expected instance of WebGLRenderTarget.' );
 
@@ -189,22 +189,30 @@ function buildInfoDT( texture, options = {} ) {
 
 }
 
-function getPixelData( renderer, rtt, info ) {
+async function getPixelData( renderer, rtt, info ) {
 
 	let dataBuffer;
 
-	if ( info.type === FloatType ) {
+	if ( renderer.isWebGLRenderer ) {
 
-		dataBuffer = new Float32Array( info.width * info.height * info.numInputChannels );
+		if ( info.type === FloatType ) {
+
+			dataBuffer = new Float32Array( info.width * info.height * info.numInputChannels );
+
+		} else {
+
+			dataBuffer = new Uint16Array( info.width * info.height * info.numInputChannels );
+
+		}
+
+		await renderer.readRenderTargetPixelsAsync( rtt, 0, 0, info.width, info.height, dataBuffer );
 
 	} else {
 
-		dataBuffer = new Uint16Array( info.width * info.height * info.numInputChannels );
+		dataBuffer = await renderer.readRenderTargetPixelsAsync( rtt, 0, 0, info.width, info.height );
 
 	}
 
-	renderer.readRenderTargetPixels( rtt, 0, 0, info.width, info.height, dataBuffer );
-
 	return dataBuffer;
 
 }

+ 21 - 13
examples/jsm/exporters/KTX2Exporter.js

@@ -111,7 +111,7 @@ const ERROR_COLOR_SPACE = 'THREE.KTX2Exporter: Supported color spaces are SRGBCo
 
 export class KTX2Exporter {
 
-	parse( arg1, arg2 ) {
+	async parse( arg1, arg2 ) {
 
 		let texture;
 
@@ -119,9 +119,9 @@ export class KTX2Exporter {
 
 			texture = arg1;
 
-		} else if ( arg1.isWebGLRenderer && arg2.isWebGLRenderTarget ) {
+		} else if ( ( arg1.isWebGLRenderer || arg1.isWebGPURenderer ) && arg2.isRenderTarget ) {
 
-			texture = toDataTexture( arg1, arg2 );
+			texture = await toDataTexture( arg1, arg2 );
 
 		} else {
 
@@ -235,32 +235,40 @@ export class KTX2Exporter {
 
 }
 
-function toDataTexture( renderer, rtt ) {
+async function toDataTexture( renderer, rtt ) {
 
 	const channelCount = getChannelCount( rtt.texture );
 
 	let view;
 
-	if ( rtt.texture.type === FloatType ) {
+	if ( renderer.isWebGLRenderer ) {
 
-		view = new Float32Array( rtt.width * rtt.height * channelCount );
+		if ( rtt.texture.type === FloatType ) {
 
-	} else if ( rtt.texture.type === HalfFloatType ) {
+			view = new Float32Array( rtt.width * rtt.height * channelCount );
 
-		view = new Uint16Array( rtt.width * rtt.height * channelCount );
+		} else if ( rtt.texture.type === HalfFloatType ) {
 
-	} else if ( rtt.texture.type === UnsignedByteType ) {
+			view = new Uint16Array( rtt.width * rtt.height * channelCount );
 
-		view = new Uint8Array( rtt.width * rtt.height * channelCount );
+		} else if ( rtt.texture.type === UnsignedByteType ) {
+
+			view = new Uint8Array( rtt.width * rtt.height * channelCount );
+
+		} else {
+
+			throw new Error( ERROR_TYPE );
+
+		}
+
+		await renderer.readRenderTargetPixelsAsync( rtt, 0, 0, rtt.width, rtt.height, view );
 
 	} else {
 
-		throw new Error( ERROR_TYPE );
+		view = await renderer.readRenderTargetPixelsAsync( rtt, 0, 0, rtt.width, rtt.height );
 
 	}
 
-	renderer.readRenderTargetPixels( rtt, 0, 0, rtt.width, rtt.height, view );
-
 	return new DataTexture( view, rtt.width, rtt.height, rtt.texture.format, rtt.texture.type );
 
 }

+ 5 - 1
examples/jsm/exporters/OBJExporter.js

@@ -1,6 +1,8 @@
 import {
 	Color,
+	ColorManagement,
 	Matrix3,
+	SRGBColorSpace,
 	Vector2,
 	Vector3
 } from 'three';
@@ -226,7 +228,9 @@ class OBJExporter {
 
 					if ( colors !== undefined ) {
 
-						color.fromBufferAttribute( colors, i ).convertLinearToSRGB();
+						color.fromBufferAttribute( colors, i );
+
+						ColorManagement.fromWorkingColorSpace( color, SRGBColorSpace );
 
 						output += ' ' + color.r + ' ' + color.g + ' ' + color.b;
 

+ 9 - 7
examples/jsm/exporters/PLYExporter.js

@@ -1,7 +1,9 @@
 import {
 	Matrix3,
 	Vector3,
-	Color
+	Color,
+	ColorManagement,
+	SRGBColorSpace
 } from 'three';
 
 /**
@@ -302,9 +304,9 @@ class PLYExporter {
 
 						if ( colors != null ) {
 
-							tempColor
-								.fromBufferAttribute( colors, i )
-								.convertLinearToSRGB();
+							tempColor.fromBufferAttribute( colors, i );
+
+							ColorManagement.fromWorkingColorSpace( tempColor, SRGBColorSpace );
 
 							output.setUint8( vOffset, Math.floor( tempColor.r * 255 ) );
 							vOffset += 1;
@@ -461,9 +463,9 @@ class PLYExporter {
 
 						if ( colors != null ) {
 
-							tempColor
-								.fromBufferAttribute( colors, i )
-								.convertLinearToSRGB();
+							tempColor.fromBufferAttribute( colors, i );
+
+							ColorManagement.fromWorkingColorSpace( tempColor, SRGBColorSpace );
 
 							line += ' ' +
 								Math.floor( tempColor.r * 255 ) + ' ' +

+ 4 - 1
examples/jsm/geometries/DecalGeometry.js

@@ -1,6 +1,7 @@
 import {
 	BufferGeometry,
 	Float32BufferAttribute,
+	Matrix3,
 	Matrix4,
 	Vector3
 } from 'three';
@@ -36,6 +37,8 @@ class DecalGeometry extends BufferGeometry {
 
 		const plane = new Vector3();
 
+		const normalMatrix = new Matrix3().getNormalMatrix( mesh.matrixWorld );
+
 		// this matrix represents the transformation of the decal projector
 
 		const projectorMatrix = new Matrix4();
@@ -146,7 +149,7 @@ class DecalGeometry extends BufferGeometry {
 			vertex.applyMatrix4( mesh.matrixWorld );
 			vertex.applyMatrix4( projectorMatrixInverse );
 
-			normal.transformDirection( mesh.matrixWorld );
+			normal.applyNormalMatrix( normalMatrix );
 
 			decalVertices.push( new DecalVertex( vertex.clone(), normal.clone() ) );
 

+ 1 - 1
examples/jsm/geometries/InstancedPointsGeometry.js

@@ -20,7 +20,7 @@ class InstancedPointsGeometry extends InstancedBufferGeometry {
 		this.type = 'InstancedPointsGeometry';
 
 		const positions = [ - 1, 1, 0, 1, 1, 0, - 1, - 1, 0, 1, - 1, 0 ];
-		const uvs = [ - 1, 1, 1, 1, - 1, - 1, 1, - 1 ];
+		const uvs = [ 0, 1, 1, 1, 0, 0, 1, 0 ];
 		const index = [ 0, 2, 1, 2, 3, 1 ];
 
 		this.setIndex( index );

+ 0 - 144
examples/jsm/geometries/SDFGeometryGenerator.js

@@ -1,144 +0,0 @@
-/**
- * @author santiago / @glitch_life
- * wrapper of https://www.npmjs.com/package/isosurface by https://github.com/mikolalysenko
- *
- * Returns BufferGeometry from SDF
- */
-
-import {
-	BufferAttribute,
-	BufferGeometry,
-	FloatType,
-	Mesh,
-	OrthographicCamera,
-	PlaneGeometry,
-	Scene,
-	ShaderMaterial,
-	Vector2,
-	WebGLRenderTarget
-} from 'three';
-
-import { surfaceNet } from './../libs/surfaceNet.js';
-
-class SDFGeometryGenerator {
-
-	constructor( renderer ) {
-
-		this.renderer = renderer;
-
-	}
-
-	generate( res = 64, distFunc = 'float dist( vec3 p ){ return length(p) - 0.5; }', bounds = 1 ) {
-
-		let w, h;
-		if ( res == 8 ) [ w, h ] = [ 32, 16 ];
-		else if ( res == 16 ) [ w, h ] = [ 64, 64 ];
-		else if ( res == 32 ) [ w, h ] = [ 256, 128 ];
-		else if ( res == 64 ) [ w, h ] = [ 512, 512 ];
-		else if ( res == 128 ) [ w, h ] = [ 2048, 1024 ];
-		else if ( res == 256 ) [ w, h ] = [ 4096, 4096 ];
-		else if ( res == 512 ) [ w, h ] = [ 16384, 8096 ];
-		else if ( res == 1024 ) [ w, h ] = [ 32768, 32768 ];
-		else throw new Error( 'THREE.SDFGeometryGenerator: Resolution must be in range 8 < res < 1024 and must be ^2' );
-
-		const maxTexSize = this.renderer.capabilities.maxTextureSize;
-
-		if ( w > maxTexSize || h > maxTexSize ) throw new Error( 'THREE.SDFGeometryGenerator: Your device does not support this resolution ( ' + res + ' ), decrease [res] param.' );
-
-		const [ tilesX, tilesY ] = [ ( w / res ), ( h / res ) ];
-
-		const sdfCompute = `
-			varying vec2 vUv;
-			uniform float tileNum;
-			uniform float bounds;
-			[#dist#]
-			void main()	{ gl_FragColor=vec4( ( dist( vec3( vUv, tileNum ) * 2.0 * bounds - vec3( bounds ) ) < 0.00001 ) ? 1.0 : 0.0 ); }
-		`;
-
-		const sdfRT = this.computeSDF( w, h, tilesX, tilesY, bounds, sdfCompute.replace( '[#dist#]', distFunc ) );
-
-		const read = new Float32Array( w * h * 4 );
-		this.renderer.readRenderTargetPixels( sdfRT, 0, 0, w, h, read );
-		sdfRT.dispose();
-
-		//
-
-		const mesh = surfaceNet( [ res, res, res ], ( x, y, z ) => {
-
-			x = ( x + bounds ) * ( res / ( bounds * 2 ) );
-			y = ( y + bounds ) * ( res / ( bounds * 2 ) );
-			z = ( z + bounds ) * ( res / ( bounds * 2 ) );
-			let p = ( x + ( z % tilesX ) * res ) + y * w + ( Math.floor( z / tilesX ) * res * w );
-			p *= 4;
-			return ( read[ p + 3 ] > 0 ) ? - 0.000000001 : 1;
-
-		}, [[ - bounds, - bounds, - bounds ], [ bounds, bounds, bounds ]] );
-
-		const ps = [], ids = [];
-		const geometry = new BufferGeometry();
-		mesh.positions.forEach( p => {
-
-			ps.push( p[ 0 ], p[ 1 ], p[ 2 ] );
-
-		} );
-		mesh.cells.forEach( p => ids.push( p[ 0 ], p[ 1 ], p[ 2 ] ) );
-		geometry.setAttribute( 'position', new BufferAttribute( new Float32Array( ps ), 3 ) );
-		geometry.setIndex( ids );
-
-		return geometry;
-
-	}
-
-	computeSDF( width, height, tilesX, tilesY, bounds, shader ) {
-
-		const rt = new WebGLRenderTarget( width, height, { type: FloatType } );
-		const scn = new Scene();
-		const cam = new OrthographicCamera();
-		const tiles = tilesX * tilesY;
-		let currentTile = 0;
-
-		Object.assign( cam, { left: width / - 2, right: width / 2, top: height / 2, bottom: height / - 2 } ).updateProjectionMatrix();
-		cam.position.z = 2;
-
-		const tileSize = width / tilesX;
-		const geometry = new PlaneGeometry( tileSize, tileSize );
-
-		while ( currentTile ++ < tiles ) {
-
-			const c = currentTile - 1;
-			const [ px, py ] = [ ( tileSize ) / 2 + ( c % tilesX ) * ( tileSize ) - width / 2, ( tileSize ) / 2 + Math.floor( c / tilesX ) * ( tileSize ) - height / 2 ];
-			const compPlane = new Mesh( geometry, new ShaderMaterial( {
-				uniforms: {
-					res: { value: new Vector2( width, height ) },
-					tileNum: { value: c / ( tilesX * tilesY - 1 ) },
-					bounds: { value: bounds }
-				},
-				vertexShader: 'varying vec2 vUv;void main(){vUv=uv;gl_Position=projectionMatrix*modelViewMatrix*vec4(position,1.0);}',
-				fragmentShader: shader
-			} ) );
-			compPlane.position.set( px, py, 0 );
-			scn.add( compPlane );
-
-		}
-
-		this.renderer.setRenderTarget( rt );
-		this.renderer.render( scn, cam );
-		this.renderer.setRenderTarget( null );
-
-		//
-
-		geometry.dispose();
-
-		scn.traverse( function ( object ) {
-
-			if ( object.material !== undefined ) object.material.dispose();
-
-		} );
-
-		return rt;
-
-	}
-
-}
-
-export { SDFGeometryGenerator };

+ 1 - 1
examples/jsm/helpers/LightProbeHelper.js

@@ -6,7 +6,7 @@ import {
 
 class LightProbeHelper extends Mesh {
 
-	constructor( lightProbe, size ) {
+	constructor( lightProbe, size = 1 ) {
 
 		const material = new ShaderMaterial( {
 

+ 65 - 0
examples/jsm/helpers/LightProbeHelperGPU.js

@@ -0,0 +1,65 @@
+import {
+	Mesh,
+	NodeMaterial,
+	SphereGeometry
+} from 'three';
+import { float, Fn, getShIrradianceAt, normalWorld, uniformArray, uniform, vec4 } from 'three/tsl';
+
+class LightProbeHelper extends Mesh {
+
+	constructor( lightProbe, size = 1 ) {
+
+		const sh = uniformArray( lightProbe.sh.coefficients );
+		const intensity = uniform( lightProbe.intensity );
+
+		const RECIPROCAL_PI = float( 1 / Math.PI );
+
+		const fragmentNode = Fn( () => {
+
+			const irradiance = getShIrradianceAt( normalWorld, sh );
+
+			const outgoingLight = RECIPROCAL_PI.mul( irradiance ).mul( intensity );
+
+			return vec4( outgoingLight, 1.0 );
+
+		} )();
+
+		const material = new NodeMaterial();
+		material.fragmentNode = fragmentNode;
+
+		const geometry = new SphereGeometry( 1, 32, 16 );
+
+		super( geometry, material );
+
+		this.lightProbe = lightProbe;
+		this.size = size;
+		this.type = 'LightProbeHelper';
+
+		this._intensity = intensity;
+		this._sh = sh;
+
+		this.onBeforeRender();
+
+	}
+
+	dispose() {
+
+		this.geometry.dispose();
+		this.material.dispose();
+
+	}
+
+	onBeforeRender() {
+
+		this.position.copy( this.lightProbe.position );
+
+		this.scale.set( 1, 1, 1 ).multiplyScalar( this.size );
+
+		this._intensity.value = this.lightProbe.intensity;
+		this._sh.array = this.lightProbe.sh.coefficients;
+
+	}
+
+}
+
+export { LightProbeHelper };

Разница между файлами не показана из-за своего большого размера
+ 5 - 5
examples/jsm/libs/basis/basis_transcoder.js


BIN
examples/jsm/libs/basis/basis_transcoder.wasm


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
examples/jsm/libs/ktx-parse.module.js


+ 24 - 10
examples/jsm/lights/LightProbeGenerator.js

@@ -7,7 +7,8 @@ import {
 	SRGBColorSpace,
 	NoColorSpace,
 	HalfFloatType,
-	DataUtils
+	DataUtils,
+	WebGLCoordinateSystem
 } from 'three';
 
 class LightProbeGenerator {
@@ -126,7 +127,9 @@ class LightProbeGenerator {
 
 	}
 
-	static fromCubeRenderTarget( renderer, cubeRenderTarget ) {
+	static async fromCubeRenderTarget( renderer, cubeRenderTarget ) {
+
+		const flip = renderer.coordinateSystem === WebGLCoordinateSystem ? -1 : 1;
 
 		// The renderTarget must be set to RGBA in order to make readRenderTargetPixels works
 		let totalWeight = 0;
@@ -143,12 +146,11 @@ class LightProbeGenerator {
 		const shCoefficients = sh.coefficients;
 
 		const dataType = cubeRenderTarget.texture.type;
+		const imageWidth = cubeRenderTarget.width; // assumed to be square
 
-		for ( let faceIndex = 0; faceIndex < 6; faceIndex ++ ) {
-
-			const imageWidth = cubeRenderTarget.width; // assumed to be square
+		let data;
 
-			let data;
+		if ( renderer.isWebGLRenderer ) {
 
 			if ( dataType === HalfFloatType ) {
 
@@ -162,7 +164,19 @@ class LightProbeGenerator {
 
 			}
 
-			renderer.readRenderTargetPixels( cubeRenderTarget, 0, 0, imageWidth, imageWidth, data, faceIndex );
+		}
+
+		for ( let faceIndex = 0; faceIndex < 6; faceIndex ++ ) {
+
+			if ( renderer.isWebGLRenderer ) {
+
+				await renderer.readRenderTargetPixelsAsync( cubeRenderTarget, 0, 0, imageWidth, imageWidth, data, faceIndex );
+
+			} else {
+
+				data = await renderer.readRenderTargetPixelsAsync( cubeRenderTarget, 0, 0, imageWidth, imageWidth, 0, faceIndex );
+
+			}
 
 			const pixelSize = 2 / imageWidth;
 
@@ -194,15 +208,15 @@ class LightProbeGenerator {
 
 				const pixelIndex = i / 4;
 
-				const col = - 1 + ( pixelIndex % imageWidth + 0.5 ) * pixelSize;
+				const col = ( 1 - ( pixelIndex % imageWidth + 0.5 ) * pixelSize ) * flip;
 
 				const row = 1 - ( Math.floor( pixelIndex / imageWidth ) + 0.5 ) * pixelSize;
 
 				switch ( faceIndex ) {
 
-					case 0: coord.set( 1, row, - col ); break;
+					case 0: coord.set( - 1 * flip, row, col * flip ); break;
 
-					case 1: coord.set( - 1, row, col ); break;
+					case 1: coord.set( 1 * flip, row, - col * flip ); break;
 
 					case 2: coord.set( col, 1, - row ); break;
 

+ 9 - 6
examples/jsm/loaders/ColladaLoader.js

@@ -5,6 +5,7 @@ import {
 	BufferGeometry,
 	ClampToEdgeWrapping,
 	Color,
+	ColorManagement,
 	DirectionalLight,
 	DoubleSide,
 	FileLoader,
@@ -1681,9 +1682,9 @@ class ColladaLoader extends Loader {
 
 			}
 
-			material.color.convertSRGBToLinear();
-			if ( material.specular ) material.specular.convertSRGBToLinear();
-			if ( material.emissive ) material.emissive.convertSRGBToLinear();
+			ColorManagement.toWorkingColorSpace( material.color, SRGBColorSpace );
+			if ( material.specular ) ColorManagement.toWorkingColorSpace( material.specular, SRGBColorSpace );
+			if ( material.emissive ) ColorManagement.toWorkingColorSpace( material.emissive, SRGBColorSpace );
 
 			//
 
@@ -2019,7 +2020,8 @@ class ColladaLoader extends Loader {
 
 					case 'color':
 						const array = parseFloats( child.textContent );
-						data.color = new Color().fromArray( array ).convertSRGBToLinear();
+						data.color = new Color().fromArray( array );
+						ColorManagement.toWorkingColorSpace( data.color, SRGBColorSpace );
 						break;
 
 					case 'falloff_angle':
@@ -2548,8 +2550,9 @@ class ColladaLoader extends Loader {
 					tempColor.setRGB(
 						array[ startIndex + 0 ],
 						array[ startIndex + 1 ],
-						array[ startIndex + 2 ]
-					).convertSRGBToLinear();
+						array[ startIndex + 2 ],
+						SRGBColorSpace
+					);
 
 					array[ startIndex + 0 ] = tempColor.r;
 					array[ startIndex + 1 ] = tempColor.g;

+ 3 - 1
examples/jsm/loaders/DRACOLoader.js

@@ -2,6 +2,7 @@ import {
 	BufferAttribute,
 	BufferGeometry,
 	Color,
+	ColorManagement,
 	FileLoader,
 	Loader,
 	LinearSRGBColorSpace,
@@ -235,7 +236,8 @@ class DRACOLoader extends Loader {
 
 		for ( let i = 0, il = attribute.count; i < il; i ++ ) {
 
-			_color.fromBufferAttribute( attribute, i ).convertSRGBToLinear();
+			_color.fromBufferAttribute( attribute, i );
+			ColorManagement.toWorkingColorSpace( _color, SRGBColorSpace );
 			attribute.setXYZ( i, _color.r, _color.g, _color.b );
 
 		}

+ 30 - 20
examples/jsm/loaders/FBXLoader.js

@@ -5,6 +5,7 @@ import {
 	BufferGeometry,
 	ClampToEdgeWrapping,
 	Color,
+	ColorManagement,
 	DirectionalLight,
 	EquirectangularReflectionMapping,
 	Euler,
@@ -23,13 +24,14 @@ import {
 	MeshPhongMaterial,
 	NumberKeyframeTrack,
 	Object3D,
-	OrthographicCamera,
 	PerspectiveCamera,
 	PointLight,
 	PropertyBinding,
 	Quaternion,
 	QuaternionKeyframeTrack,
 	RepeatWrapping,
+	SRGBColorSpace,
+	ShapeUtils,
 	Skeleton,
 	SkinnedMesh,
 	SpotLight,
@@ -39,10 +41,9 @@ import {
 	Vector2,
 	Vector3,
 	Vector4,
-	VectorKeyframeTrack,
-	SRGBColorSpace,
-	ShapeUtils
+	VectorKeyframeTrack
 } from 'three';
+
 import * as fflate from '../libs/fflate.module.js';
 import { NURBSCurve } from '../curves/NURBSCurve.js';
 
@@ -538,12 +539,12 @@ class FBXTreeParser {
 
 		if ( materialNode.Diffuse ) {
 
-			parameters.color = new Color().fromArray( materialNode.Diffuse.value ).convertSRGBToLinear();
+			parameters.color = ColorManagement.toWorkingColorSpace( new Color().fromArray( materialNode.Diffuse.value ), SRGBColorSpace );
 
 		} else if ( materialNode.DiffuseColor && ( materialNode.DiffuseColor.type === 'Color' || materialNode.DiffuseColor.type === 'ColorRGB' ) ) {
 
 			// The blender exporter exports diffuse here instead of in materialNode.Diffuse
-			parameters.color = new Color().fromArray( materialNode.DiffuseColor.value ).convertSRGBToLinear();
+			parameters.color = ColorManagement.toWorkingColorSpace( new Color().fromArray( materialNode.DiffuseColor.value ), SRGBColorSpace );
 
 		}
 
@@ -555,12 +556,12 @@ class FBXTreeParser {
 
 		if ( materialNode.Emissive ) {
 
-			parameters.emissive = new Color().fromArray( materialNode.Emissive.value ).convertSRGBToLinear();
+			parameters.emissive = ColorManagement.toWorkingColorSpace( new Color().fromArray( materialNode.Emissive.value ), SRGBColorSpace );
 
 		} else if ( materialNode.EmissiveColor && ( materialNode.EmissiveColor.type === 'Color' || materialNode.EmissiveColor.type === 'ColorRGB' ) ) {
 
 			// The blender exporter exports emissive color here instead of in materialNode.Emissive
-			parameters.emissive = new Color().fromArray( materialNode.EmissiveColor.value ).convertSRGBToLinear();
+			parameters.emissive = ColorManagement.toWorkingColorSpace( new Color().fromArray( materialNode.EmissiveColor.value ), SRGBColorSpace );
 
 		}
 
@@ -596,12 +597,12 @@ class FBXTreeParser {
 
 		if ( materialNode.Specular ) {
 
-			parameters.specular = new Color().fromArray( materialNode.Specular.value ).convertSRGBToLinear();
+			parameters.specular = ColorManagement.toWorkingColorSpace( new Color().fromArray( materialNode.Specular.value ), SRGBColorSpace );
 
 		} else if ( materialNode.SpecularColor && materialNode.SpecularColor.type === 'Color' ) {
 
 			// The blender exporter exports specular color here instead of in materialNode.Specular
-			parameters.specular = new Color().fromArray( materialNode.SpecularColor.value ).convertSRGBToLinear();
+			parameters.specular = ColorManagement.toWorkingColorSpace( new Color().fromArray( materialNode.SpecularColor.value ), SRGBColorSpace );
 
 		}
 
@@ -1094,7 +1095,8 @@ class FBXTreeParser {
 					break;
 
 				case 1: // Orthographic
-					model = new OrthographicCamera( - width / 2, width / 2, height / 2, - height / 2, nearClippingPlane, farClippingPlane );
+					console.warn( 'THREE.FBXLoader: Orthographic cameras not supported yet.' );
+					model = new Object3D();
 					break;
 
 				default:
@@ -1151,7 +1153,7 @@ class FBXTreeParser {
 
 			if ( lightAttribute.Color !== undefined ) {
 
-				color = new Color().fromArray( lightAttribute.Color.value ).convertSRGBToLinear();
+				color = ColorManagement.toWorkingColorSpace( new Color().fromArray( lightAttribute.Color.value ), SRGBColorSpace );
 
 			}
 
@@ -1329,7 +1331,7 @@ class FBXTreeParser {
 		if ( 'InheritType' in modelNode ) transformData.inheritType = parseInt( modelNode.InheritType.value );
 
 		if ( 'RotationOrder' in modelNode ) transformData.eulerOrder = getEulerOrder( modelNode.RotationOrder.value );
-		else transformData.eulerOrder = 'ZYX';
+		else transformData.eulerOrder = getEulerOrder( 0 );
 
 		if ( 'Lcl_Translation' in modelNode ) transformData.translation = modelNode.Lcl_Translation.value;
 
@@ -1477,7 +1479,7 @@ class FBXTreeParser {
 
 				if ( r !== 0 || g !== 0 || b !== 0 ) {
 
-					const color = new Color( r, g, b ).convertSRGBToLinear();
+					const color = new Color().setRGB( r, g, b, SRGBColorSpace );
 					sceneGraph.add( new AmbientLight( color, 1 ) );
 
 				}
@@ -2319,7 +2321,9 @@ class GeometryParser {
 
 		for ( let i = 0, c = new Color(); i < buffer.length; i += 4 ) {
 
-			c.fromArray( buffer, i ).convertSRGBToLinear().toArray( buffer, i );
+			c.fromArray( buffer, i );
+			ColorManagement.toWorkingColorSpace( c, SRGBColorSpace );
+			c.toArray( buffer, i );
 
 		}
 
@@ -2809,10 +2813,13 @@ class AnimationParser {
 
 		}
 
+		// For Maya models using "Joint Orient", Euler order only applies to rotation, not pre/post-rotations
+		const defaultEulerOrder = getEulerOrder( 0 );
+
 		if ( preRotation !== undefined ) {
 
 			preRotation = preRotation.map( MathUtils.degToRad );
-			preRotation.push( eulerOrder );
+			preRotation.push( defaultEulerOrder );
 
 			preRotation = new Euler().fromArray( preRotation );
 			preRotation = new Quaternion().setFromEuler( preRotation );
@@ -2822,7 +2829,7 @@ class AnimationParser {
 		if ( postRotation !== undefined ) {
 
 			postRotation = postRotation.map( MathUtils.degToRad );
-			postRotation.push( eulerOrder );
+			postRotation.push( defaultEulerOrder );
 
 			postRotation = new Euler().fromArray( postRotation );
 			postRotation = new Quaternion().setFromEuler( postRotation ).invert();
@@ -4134,10 +4141,13 @@ function generateTransform( transformData ) {
 
 	if ( transformData.translation ) lTranslationM.setPosition( tempVec.fromArray( transformData.translation ) );
 
+	// For Maya models using "Joint Orient", Euler order only applies to rotation, not pre/post-rotations
+	const defaultEulerOrder = getEulerOrder( 0 );
+
 	if ( transformData.preRotation ) {
 
 		const array = transformData.preRotation.map( MathUtils.degToRad );
-		array.push( transformData.eulerOrder || Euler.DEFAULT_ORDER );
+		array.push( defaultEulerOrder );
 		lPreRotationM.makeRotationFromEuler( tempEuler.fromArray( array ) );
 
 	}
@@ -4145,7 +4155,7 @@ function generateTransform( transformData ) {
 	if ( transformData.rotation ) {
 
 		const array = transformData.rotation.map( MathUtils.degToRad );
-		array.push( transformData.eulerOrder || Euler.DEFAULT_ORDER );
+		array.push( transformData.eulerOrder || defaultEulerOrder );
 		lRotationM.makeRotationFromEuler( tempEuler.fromArray( array ) );
 
 	}
@@ -4153,7 +4163,7 @@ function generateTransform( transformData ) {
 	if ( transformData.postRotation ) {
 
 		const array = transformData.postRotation.map( MathUtils.degToRad );
-		array.push( transformData.eulerOrder || Euler.DEFAULT_ORDER );
+		array.push( defaultEulerOrder );
 		lPostRotationM.makeRotationFromEuler( tempEuler.fromArray( array ) );
 		lPostRotationM.invert();
 

+ 5 - 10
examples/jsm/loaders/GLTFLoader.js

@@ -267,16 +267,6 @@ class GLTFLoader extends Loader {
 
 	}
 
-	setDDSLoader() {
-
-		throw new Error(
-
-			'THREE.GLTFLoader: "MSFT_texture_dds" no longer supported. Please update to "KHR_texture_basisu".'
-
-		);
-
-	}
-
 	setKTX2Loader( ktx2Loader ) {
 
 		this.ktx2Loader = ktx2Loader;
@@ -3153,6 +3143,9 @@ class GLTFParser {
 
 				}
 
+				// Ignore normalized since we copy from sparse
+				bufferAttribute.normalized = false;
+
 				for ( let i = 0, il = sparseIndices.length; i < il; i ++ ) {
 
 					const index = sparseIndices[ i ];
@@ -3165,6 +3158,8 @@ class GLTFParser {
 
 				}
 
+				bufferAttribute.normalized = normalized;
+
 			}
 
 			return bufferAttribute;

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

@@ -9,6 +9,7 @@
  * References:
  * - KTX: http://github.khronos.org/KTX-Specification/
  * - DFD: https://www.khronos.org/registry/DataFormat/specs/1.3/dataformat.1.3.html#basicdescriptor
+ * - BasisU HDR: https://github.com/BinomialLLC/basis_universal/wiki/UASTC-HDR-Texture-Specification-v1.0
  */
 
 import {
@@ -63,6 +64,7 @@ import {
 	VK_FORMAT_R8G8_UNORM,
 	VK_FORMAT_R8G8B8A8_SRGB,
 	VK_FORMAT_R8G8B8A8_UNORM,
+	VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK_EXT,
 	VK_FORMAT_ASTC_6x6_SRGB_BLOCK,
 	VK_FORMAT_ASTC_6x6_UNORM_BLOCK,
 	KHR_DF_PRIMARIES_UNSPECIFIED,
@@ -251,7 +253,7 @@ class KTX2Loader extends Loader {
 
 		loader.load( url, ( buffer ) => {
 
-			this.parse( buffer, onLoad, onError);
+			this.parse( buffer, onLoad, onError );
 
 		}, onProgress, onError );
 
@@ -269,15 +271,15 @@ class KTX2Loader extends Loader {
 		// again from this thread.
 		if ( _taskCache.has( buffer ) ) {
 
-				const cachedTask = _taskCache.get( buffer );
+			const cachedTask = _taskCache.get( buffer );
 
-				return cachedTask.promise.then( onLoad ).catch( onError );
+			return cachedTask.promise.then( onLoad ).catch( onError );
 
 		}
 
 		this._createTexture( buffer )
-				.then( ( texture ) => onLoad ? onLoad( texture ) : null )
-				.catch( onError );
+			.then( ( texture ) => onLoad ? onLoad( texture ) : null )
+			.catch( onError );
 
 	}
 
@@ -730,8 +732,7 @@ KTX2Loader.BasisWorker = function () {
 
 };
 
-//
-// Parsing for non-Basis textures. These textures are may have supercompression
+// Parsing for non-Basis textures. These textures may have supercompression
 // like Zstd, but they do not require transcoding.
 
 const UNCOMPRESSED_FORMATS = new Set( [ RGBAFormat, RGFormat, RedFormat ] );
@@ -753,6 +754,7 @@ const FORMAT_MAP = {
 	[ VK_FORMAT_R8_SRGB ]: RedFormat,
 	[ VK_FORMAT_R8_UNORM ]: RedFormat,
 
+	[ VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK_EXT ]: RGBA_ASTC_4x4_Format,
 	[ VK_FORMAT_ASTC_6x6_SRGB_BLOCK ]: RGBA_ASTC_6x6_Format,
 	[ VK_FORMAT_ASTC_6x6_UNORM_BLOCK ]: RGBA_ASTC_6x6_Format,
 
@@ -775,6 +777,7 @@ const TYPE_MAP = {
 	[ VK_FORMAT_R8_SRGB ]: UnsignedByteType,
 	[ VK_FORMAT_R8_UNORM ]: UnsignedByteType,
 
+	[ VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK_EXT ]: HalfFloatType,
 	[ VK_FORMAT_ASTC_6x6_SRGB_BLOCK ]: UnsignedByteType,
 	[ VK_FORMAT_ASTC_6x6_UNORM_BLOCK ]: UnsignedByteType,
 

+ 4 - 3
examples/jsm/loaders/MTLLoader.js

@@ -1,5 +1,6 @@
 import {
 	Color,
+	ColorManagement,
 	DefaultLoadingManager,
 	FileLoader,
 	FrontSide,
@@ -384,21 +385,21 @@ class MaterialCreator {
 
 					// Diffuse color (color under white light) using RGB values
 
-					params.color = new Color().fromArray( value ).convertSRGBToLinear();
+					params.color = ColorManagement.toWorkingColorSpace( new Color().fromArray( value ), SRGBColorSpace );
 
 					break;
 
 				case 'ks':
 
 					// Specular color (color when light is reflected from shiny surface) using RGB values
-					params.specular = new Color().fromArray( value ).convertSRGBToLinear();
+					params.specular = ColorManagement.toWorkingColorSpace( new Color().fromArray( value ), SRGBColorSpace );
 
 					break;
 
 				case 'ke':
 
 					// Emissive using RGB values
-					params.emissive = new Color().fromArray( value ).convertSRGBToLinear();
+					params.emissive = ColorManagement.toWorkingColorSpace( new Color().fromArray( value ), SRGBColorSpace );
 
 					break;
 

+ 29 - 10
examples/jsm/loaders/MaterialXLoader.js

@@ -7,7 +7,7 @@ import {
 	add, sub, mul, div, mod, abs, sign, floor, ceil, round, pow, sin, cos, tan,
 	asin, acos, atan2, sqrt, exp, clamp, min, max, normalize, length, dot, cross, normalMap,
 	remap, smoothstep, luminance, mx_rgbtohsv, mx_hsvtorgb,
-	mix,
+	mix, split,
 	mx_ramplr, mx_ramptb, mx_splitlr, mx_splittb,
 	mx_fractal_noise_float, mx_noise_float, mx_cell_noise_float, mx_worley_noise_float,
 	mx_transform_uv,
@@ -44,6 +44,10 @@ const mx_power = ( in1, in2 = float( 1 ) ) => pow( in1, in2 );
 const mx_atan2 = ( in1 = float( 0 ), in2 = float( 1 ) ) => atan2( in1, in2 );
 const mx_timer = () => timerLocal();
 const mx_frame = () => frameId;
+const mx_invert = ( in1, amount = float( 1 ) ) => sub( amount, in1 );
+
+const separate = ( in1, channel ) => split( in1, channel.at( - 1 ) );
+const extract = ( in1, index ) => in1.element( index );
 
 const MXElements = [
 
@@ -75,6 +79,7 @@ const MXElements = [
 	new MXElement( 'magnitude', length, [ 'in1', 'in2' ] ),
 	new MXElement( 'dotproduct', dot, [ 'in1', 'in2' ] ),
 	new MXElement( 'crossproduct', cross, [ 'in' ] ),
+	new MXElement( 'invert', mx_invert, [ 'in', 'amount' ] ),
 	//new MtlXElement( 'transformpoint', ... ),
 	//new MtlXElement( 'transformvector', ... ),
 	//new MtlXElement( 'transformnormal', ... ),
@@ -127,10 +132,10 @@ const MXElements = [
 	new MXElement( 'contrast', mx_contrast, [ 'in', 'amount', 'pivot' ] ),
 	//new MtlXElement( 'hsvadjust', ... ),
 	new MXElement( 'saturate', saturation, [ 'in', 'amount' ] ),
-	//new MtlXElement( 'extract', ... ),
-	//new MtlXElement( 'separate2', ... ),
-	//new MtlXElement( 'separate3', ... ),
-	//new MtlXElement( 'separate4', ... )
+	new MXElement( 'extract', extract, [ 'in', 'index' ] ),
+	new MXElement( 'separate2', separate, [ 'in' ] ),
+	new MXElement( 'separate3', separate, [ 'in' ] ),
+	new MXElement( 'separate4', separate, [ 'in' ] ),
 
 	new MXElement( 'time', mx_timer ),
 	new MXElement( 'frame', mx_frame )
@@ -369,11 +374,11 @@ class MaterialXNode {
 
 	}
 
-	getNode() {
+	getNode( out = null ) {
 
 		let node = this.node;
 
-		if ( node !== null ) {
+		if ( node !== null && out === null ) {
 
 			return node;
 
@@ -391,7 +396,13 @@ class MaterialXNode {
 
 		} else if ( this.hasReference ) {
 
-			node = this.materialX.getMaterialXNode( this.referencePath ).getNode();
+			if ( this.element === 'output' && this.output && out === null  ) {
+
+				out = this.output;
+
+			}
+
+			node = this.materialX.getMaterialXNode( this.referencePath ).getNode( out );
 
 		} else {
 
@@ -474,7 +485,15 @@ class MaterialXNode {
 
 				const nodeElement = MtlXLibrary[ element ];
 
-				node = nodeElement.nodeFunc( ...this.getNodesByNames( ...nodeElement.params ) );
+				if ( out !== null ) {
+
+					node = nodeElement.nodeFunc( ...this.getNodesByNames( ...nodeElement.params ), out );
+
+				} else {
+
+					node = nodeElement.nodeFunc( ...this.getNodesByNames( ...nodeElement.params ) );
+
+				}
 
 			}
 
@@ -542,7 +561,7 @@ class MaterialXNode {
 
 		const child = this.getChildByName( name );
 
-		return child ? child.getNode() : undefined;
+		return child ? child.getNode( child.output ) : undefined;
 
 	}
 

+ 5 - 3
examples/jsm/loaders/OBJLoader.js

@@ -12,7 +12,8 @@ import {
 	Points,
 	PointsMaterial,
 	Vector3,
-	Color
+	Color,
+	SRGBColorSpace
 } from 'three';
 
 // o object_name | g group_name
@@ -534,8 +535,9 @@ class OBJLoader extends Loader {
 							_color.setRGB(
 								parseFloat( data[ 4 ] ),
 								parseFloat( data[ 5 ] ),
-								parseFloat( data[ 6 ] )
-							).convertSRGBToLinear();
+								parseFloat( data[ 6 ] ),
+								SRGBColorSpace
+							);
 
 							state.colors.push( _color.r, _color.g, _color.b );
 

+ 5 - 4
examples/jsm/loaders/PCDLoader.js

@@ -6,7 +6,8 @@ import {
 	Int32BufferAttribute,
 	Loader,
 	Points,
-	PointsMaterial
+	PointsMaterial,
+	SRGBColorSpace
 } from 'three';
 
 class PCDLoader extends Loader {
@@ -279,7 +280,7 @@ class PCDLoader extends Loader {
 					const g = ( ( rgb >> 8 ) & 0x0000ff ) / 255;
 					const b = ( ( rgb >> 0 ) & 0x0000ff ) / 255;
 
-					c.set( r, g, b ).convertSRGBToLinear();
+					c.setRGB( r, g, b, SRGBColorSpace );
 
 					color.push( c.r, c.g, c.b );
 
@@ -346,7 +347,7 @@ class PCDLoader extends Loader {
 					const g = dataview.getUint8( ( PCDheader.points * offset.rgb ) + PCDheader.size[ rgbIndex ] * i + 1 ) / 255.0;
 					const b = dataview.getUint8( ( PCDheader.points * offset.rgb ) + PCDheader.size[ rgbIndex ] * i + 0 ) / 255.0;
 
-					c.set( r, g, b ).convertSRGBToLinear();
+					c.setRGB( r, g, b, SRGBColorSpace );
 
 					color.push( c.r, c.g, c.b );
 
@@ -404,7 +405,7 @@ class PCDLoader extends Loader {
 					const g = dataview.getUint8( row + offset.rgb + 1 ) / 255.0;
 					const b = dataview.getUint8( row + offset.rgb + 0 ) / 255.0;
 
-					c.set( r, g, b ).convertSRGBToLinear();
+					c.setRGB( r, g, b, SRGBColorSpace );
 
 					color.push( c.r, c.g, c.b );
 

+ 3 - 2
examples/jsm/loaders/PDBLoader.js

@@ -3,7 +3,8 @@ import {
 	FileLoader,
 	Float32BufferAttribute,
 	Loader,
-	Color
+	Color,
+	SRGBColorSpace
 } from 'three';
 
 class PDBLoader extends Loader {
@@ -131,7 +132,7 @@ class PDBLoader extends Loader {
 				const g = atom[ 3 ][ 1 ] / 255;
 				const b = atom[ 3 ][ 2 ] / 255;
 
-				c.set( r, g, b ).convertSRGBToLinear();
+				c.setRGB( r, g, b, SRGBColorSpace );
 
 				colorsAtoms.push( c.r, c.g, c.b );
 

+ 8 - 5
examples/jsm/loaders/PLYLoader.js

@@ -3,7 +3,8 @@ import {
 	FileLoader,
 	Float32BufferAttribute,
 	Loader,
-	Color
+	Color,
+	SRGBColorSpace
 } from 'three';
 
 /**
@@ -468,8 +469,9 @@ class PLYLoader extends Loader {
 					_color.setRGB(
 						element[ cacheEntry.attrR ] / 255.0,
 						element[ cacheEntry.attrG ] / 255.0,
-						element[ cacheEntry.attrB ] / 255.0
-					).convertSRGBToLinear();
+						element[ cacheEntry.attrB ] / 255.0,
+						SRGBColorSpace
+					);
 
 					buffer.colors.push( _color.r, _color.g, _color.b );
 
@@ -516,8 +518,9 @@ class PLYLoader extends Loader {
 					_color.setRGB(
 						element[ cacheEntry.attrR ] / 255.0,
 						element[ cacheEntry.attrG ] / 255.0,
-						element[ cacheEntry.attrB ] / 255.0
-					).convertSRGBToLinear();
+						element[ cacheEntry.attrB ] / 255.0,
+						SRGBColorSpace
+					);
 					buffer.faceVertexColors.push( _color.r, _color.g, _color.b );
 					buffer.faceVertexColors.push( _color.r, _color.g, _color.b );
 					buffer.faceVertexColors.push( _color.r, _color.g, _color.b );

+ 3 - 2
examples/jsm/loaders/STLLoader.js

@@ -5,7 +5,8 @@ import {
 	FileLoader,
 	Float32BufferAttribute,
 	Loader,
-	Vector3
+	Vector3,
+	SRGBColorSpace
 } from 'three';
 
 /**
@@ -242,7 +243,7 @@ class STLLoader extends Loader {
 
 					if ( hasColors ) {
 
-						color.set( r, g, b ).convertSRGBToLinear();
+						color.setRGB( r, g, b, SRGBColorSpace );
 
 						colors[ componentIdx ] = color.r;
 						colors[ componentIdx + 1 ] = color.g;

+ 0 - 520
examples/jsm/loaders/TiltLoader.js

@@ -1,520 +0,0 @@
-import {
-	BufferAttribute,
-	BufferGeometry,
-	Color,
-	DoubleSide,
-	FileLoader,
-	Group,
-	Loader,
-	Mesh,
-	MeshBasicMaterial,
-	RawShaderMaterial,
-	TextureLoader,
-	Quaternion,
-	Vector3
-} from 'three';
-import * as fflate from '../libs/fflate.module.js';
-
-class TiltLoader extends Loader {
-
-	load( url, onLoad, onProgress, onError ) {
-
-		const scope = this;
-
-		const loader = new FileLoader( this.manager );
-		loader.setPath( this.path );
-		loader.setResponseType( 'arraybuffer' );
-		loader.setWithCredentials( this.withCredentials );
-
-		loader.load( url, function ( buffer ) {
-
-			try {
-
-				onLoad( scope.parse( buffer ) );
-
-			} catch ( e ) {
-
-				if ( onError ) {
-
-					onError( e );
-
-				} else {
-
-					console.error( e );
-
-				}
-
-				scope.manager.itemError( url );
-
-			}
-
-		}, onProgress, onError );
-
-	}
-
-	parse( buffer ) {
-
-		const group = new Group();
-		// https://docs.google.com/document/d/11ZsHozYn9FnWG7y3s3WAyKIACfbfwb4PbaS8cZ_xjvo/edit#
-
-		const zip = fflate.unzipSync( new Uint8Array( buffer.slice( 16 ) ) );
-
-		/*
-		const thumbnail = zip[ 'thumbnail.png' ].buffer;
-		const img = document.createElement( 'img' );
-		img.src = URL.createObjectURL( new Blob( [ thumbnail ] ) );
-		document.body.appendChild( img );
-		*/
-
-		const metadata = JSON.parse( fflate.strFromU8( zip[ 'metadata.json' ] ) );
-
-		/*
-		const blob = new Blob( [ zip[ 'data.sketch' ].buffer ], { type: 'application/octet-stream' } );
-		window.open( URL.createObjectURL( blob ) );
-		*/
-
-		const data = new DataView( zip[ 'data.sketch' ].buffer );
-
-		const num_strokes = data.getInt32( 16, true );
-
-		const brushes = {};
-
-		let offset = 20;
-
-		for ( let i = 0; i < num_strokes; i ++ ) {
-
-			const brush_index = data.getInt32( offset, true );
-
-			const brush_color = [
-				data.getFloat32( offset + 4, true ),
-				data.getFloat32( offset + 8, true ),
-				data.getFloat32( offset + 12, true ),
-				data.getFloat32( offset + 16, true )
-			];
-			const brush_size = data.getFloat32( offset + 20, true );
-			const stroke_mask = data.getUint32( offset + 24, true );
-			const controlpoint_mask = data.getUint32( offset + 28, true );
-
-			let offset_stroke_mask = 0;
-			let offset_controlpoint_mask = 0;
-
-			for ( let j = 0; j < 4; j ++ ) {
-
-				// TOFIX: I don't understand these masks yet
-
-				const byte = 1 << j;
-				if ( ( stroke_mask & byte ) > 0 ) offset_stroke_mask += 4;
-				if ( ( controlpoint_mask & byte ) > 0 ) offset_controlpoint_mask += 4;
-
-			}
-
-			// console.log( { brush_index, brush_color, brush_size, stroke_mask, controlpoint_mask } );
-			// console.log( offset_stroke_mask, offset_controlpoint_mask );
-
-			offset = offset + 28 + offset_stroke_mask + 4; // TOFIX: This is wrong
-
-			const num_control_points = data.getInt32( offset, true );
-
-			// console.log( { num_control_points } );
-
-			const positions = new Float32Array( num_control_points * 3 );
-			const quaternions = new Float32Array( num_control_points * 4 );
-
-			offset = offset + 4;
-
-			for ( let j = 0, k = 0; j < positions.length; j += 3, k += 4 ) {
-
-				positions[ j + 0 ] = data.getFloat32( offset + 0, true );
-				positions[ j + 1 ] = data.getFloat32( offset + 4, true );
-				positions[ j + 2 ] = data.getFloat32( offset + 8, true );
-
-				quaternions[ k + 0 ] = data.getFloat32( offset + 12, true );
-				quaternions[ k + 1 ] = data.getFloat32( offset + 16, true );
-				quaternions[ k + 2 ] = data.getFloat32( offset + 20, true );
-				quaternions[ k + 3 ] = data.getFloat32( offset + 24, true );
-
-				offset = offset + 28 + offset_controlpoint_mask; // TOFIX: This is wrong
-
-			}
-
-			if ( brush_index in brushes === false ) {
-
-				brushes[ brush_index ] = [];
-
-			}
-
-			brushes[ brush_index ].push( [ positions, quaternions, brush_size, brush_color ] );
-
-		}
-
-		for ( const brush_index in brushes ) {
-
-			const geometry = new StrokeGeometry( brushes[ brush_index ] );
-			const material = getMaterial( metadata.BrushIndex[ brush_index ] );
-
-			group.add( new Mesh( geometry, material ) );
-
-		}
-
-		return group;
-
-	}
-
-}
-
-class StrokeGeometry extends BufferGeometry {
-
-	constructor( strokes ) {
-
-		super();
-
-		const vertices = [];
-		const colors = [];
-		const uvs = [];
-
-		const position = new Vector3();
-		const prevPosition = new Vector3();
-
-		const quaternion = new Quaternion();
-		const prevQuaternion = new Quaternion();
-
-		const vector1 = new Vector3();
-		const vector2 = new Vector3();
-		const vector3 = new Vector3();
-		const vector4 = new Vector3();
-
-		const color = new Color();
-
-		// size = size / 2;
-
-		for ( const k in strokes ) {
-
-			const stroke = strokes[ k ];
-			const positions = stroke[ 0 ];
-			const quaternions = stroke[ 1 ];
-			const size = stroke[ 2 ];
-			const rgba = stroke[ 3 ];
-			const alpha = stroke[ 3 ][ 3 ];
-
-			color.fromArray( rgba ).convertSRGBToLinear();
-
-			prevPosition.fromArray( positions, 0 );
-			prevQuaternion.fromArray( quaternions, 0 );
-
-			for ( let i = 3, j = 4, l = positions.length; i < l; i += 3, j += 4 ) {
-
-				position.fromArray( positions, i );
-				quaternion.fromArray( quaternions, j );
-
-				vector1.set( - size, 0, 0 );
-				vector1.applyQuaternion( quaternion );
-				vector1.add( position );
-
-				vector2.set( size, 0, 0 );
-				vector2.applyQuaternion( quaternion );
-				vector2.add( position );
-
-				vector3.set( size, 0, 0 );
-				vector3.applyQuaternion( prevQuaternion );
-				vector3.add( prevPosition );
-
-				vector4.set( - size, 0, 0 );
-				vector4.applyQuaternion( prevQuaternion );
-				vector4.add( prevPosition );
-
-				vertices.push( vector1.x, vector1.y, - vector1.z );
-				vertices.push( vector2.x, vector2.y, - vector2.z );
-				vertices.push( vector4.x, vector4.y, - vector4.z );
-
-				vertices.push( vector2.x, vector2.y, - vector2.z );
-				vertices.push( vector3.x, vector3.y, - vector3.z );
-				vertices.push( vector4.x, vector4.y, - vector4.z );
-
-				prevPosition.copy( position );
-				prevQuaternion.copy( quaternion );
-
-				colors.push( ...color, alpha );
-				colors.push( ...color, alpha );
-				colors.push( ...color, alpha );
-
-				colors.push( ...color, alpha );
-				colors.push( ...color, alpha );
-				colors.push( ...color, alpha );
-
-				const p1 = i / l;
-				const p2 = ( i - 3 ) / l;
-
-				uvs.push( p1, 0 );
-				uvs.push( p1, 1 );
-				uvs.push( p2, 0 );
-
-				uvs.push( p1, 1 );
-				uvs.push( p2, 1 );
-				uvs.push( p2, 0 );
-
-			}
-
-		}
-
-		this.setAttribute( 'position', new BufferAttribute( new Float32Array( vertices ), 3 ) );
-		this.setAttribute( 'color', new BufferAttribute( new Float32Array( colors ), 4 ) );
-		this.setAttribute( 'uv', new BufferAttribute( new Float32Array( uvs ), 2 ) );
-
-	}
-
-}
-
-const BRUSH_LIST_ARRAY = {
-	'89d104cd-d012-426b-b5b3-bbaee63ac43c': 'Bubbles',
-	'700f3aa8-9a7c-2384-8b8a-ea028905dd8c': 'CelVinyl',
-	'0f0ff7b2-a677-45eb-a7d6-0cd7206f4816': 'ChromaticWave',
-	'1161af82-50cf-47db-9706-0c3576d43c43': 'CoarseBristles',
-	'79168f10-6961-464a-8be1-57ed364c5600': 'CoarseBristlesSingleSided',
-	'1caa6d7d-f015-3f54-3a4b-8b5354d39f81': 'Comet',
-	'c8313697-2563-47fc-832e-290f4c04b901': 'DiamondHull',
-	'4391aaaa-df73-4396-9e33-31e4e4930b27': 'Disco',
-	'd1d991f2-e7a0-4cf1-b328-f57e915e6260': 'DotMarker',
-	'6a1cf9f9-032c-45ec-9b1d-a6680bee30f7': 'Dots',
-	'0d3889f3-3ede-470c-8af4-f44813306126': 'DoubleTaperedFlat',
-	'0d3889f3-3ede-470c-8af4-de4813306126': 'DoubleTaperedMarker',
-	'd0262945-853c-4481-9cbd-88586bed93cb': 'DuctTape',
-	'3ca16e2f-bdcd-4da2-8631-dcef342f40f1': 'DuctTapeSingleSided',
-	'f6e85de3-6dcc-4e7f-87fd-cee8c3d25d51': 'Electricity',
-	'02ffb866-7fb2-4d15-b761-1012cefb1360': 'Embers',
-	'cb92b597-94ca-4255-b017-0e3f42f12f9e': 'Fire',
-	'2d35bcf0-e4d8-452c-97b1-3311be063130': 'Flat',
-	'55303bc4-c749-4a72-98d9-d23e68e76e18': 'FlatDeprecated',
-	'280c0a7a-aad8-416c-a7d2-df63d129ca70': 'FlatSingleSided',
-	'cf019139-d41c-4eb0-a1d0-5cf54b0a42f3': 'Highlighter',
-	'6a1cf9f9-032c-45ec-9b6e-a6680bee32e9': 'HyperGrid',
-	'dce872c2-7b49-4684-b59b-c45387949c5c': 'Hypercolor',
-	'e8ef32b1-baa8-460a-9c2c-9cf8506794f5': 'HypercolorSingleSided',
-	'2f212815-f4d3-c1a4-681a-feeaf9c6dc37': 'Icing',
-	'f5c336cf-5108-4b40-ade9-c687504385ab': 'Ink',
-	'c0012095-3ffd-4040-8ee1-fc180d346eaa': 'InkSingleSided',
-	'4a76a27a-44d8-4bfe-9a8c-713749a499b0': 'Leaves',
-	'ea19de07-d0c0-4484-9198-18489a3c1487': 'LeavesSingleSided',
-	'2241cd32-8ba2-48a5-9ee7-2caef7e9ed62': 'Light',
-	'4391aaaa-df81-4396-9e33-31e4e4930b27': 'LightWire',
-	'd381e0f5-3def-4a0d-8853-31e9200bcbda': 'Lofted',
-	'429ed64a-4e97-4466-84d3-145a861ef684': 'Marker',
-	'79348357-432d-4746-8e29-0e25c112e3aa': 'MatteHull',
-	'b2ffef01-eaaa-4ab5-aa64-95a2c4f5dbc6': 'NeonPulse',
-	'f72ec0e7-a844-4e38-82e3-140c44772699': 'OilPaint',
-	'c515dad7-4393-4681-81ad-162ef052241b': 'OilPaintSingleSided',
-	'f1114e2e-eb8d-4fde-915a-6e653b54e9f5': 'Paper',
-	'759f1ebd-20cd-4720-8d41-234e0da63716': 'PaperSingleSided',
-	'e0abbc80-0f80-e854-4970-8924a0863dcc': 'Petal',
-	'c33714d1-b2f9-412e-bd50-1884c9d46336': 'Plasma',
-	'ad1ad437-76e2-450d-a23a-e17f8310b960': 'Rainbow',
-	'faaa4d44-fcfb-4177-96be-753ac0421ba3': 'ShinyHull',
-	'70d79cca-b159-4f35-990c-f02193947fe8': 'Smoke',
-	'd902ed8b-d0d1-476c-a8de-878a79e3a34c': 'Snow',
-	'accb32f5-4509-454f-93f8-1df3fd31df1b': 'SoftHighlighter',
-	'cf7f0059-7aeb-53a4-2b67-c83d863a9ffa': 'Spikes',
-	'8dc4a70c-d558-4efd-a5ed-d4e860f40dc3': 'Splatter',
-	'7a1c8107-50c5-4b70-9a39-421576d6617e': 'SplatterSingleSided',
-	'0eb4db27-3f82-408d-b5a1-19ebd7d5b711': 'Stars',
-	'44bb800a-fbc3-4592-8426-94ecb05ddec3': 'Streamers',
-	'0077f88c-d93a-42f3-b59b-b31c50cdb414': 'Taffy',
-	'b468c1fb-f254-41ed-8ec9-57030bc5660c': 'TaperedFlat',
-	'c8ccb53d-ae13-45ef-8afb-b730d81394eb': 'TaperedFlatSingleSided',
-	'd90c6ad8-af0f-4b54-b422-e0f92abe1b3c': 'TaperedMarker',
-	'1a26b8c0-8a07-4f8a-9fac-d2ef36e0cad0': 'TaperedMarker_Flat',
-	'75b32cf0-fdd6-4d89-a64b-e2a00b247b0f': 'ThickPaint',
-	'fdf0326a-c0d1-4fed-b101-9db0ff6d071f': 'ThickPaintSingleSided',
-	'4391385a-df73-4396-9e33-31e4e4930b27': 'Toon',
-	'a8fea537-da7c-4d4b-817f-24f074725d6d': 'UnlitHull',
-	'd229d335-c334-495a-a801-660ac8a87360': 'VelvetInk',
-	'10201aa3-ebc2-42d8-84b7-2e63f6eeb8ab': 'Waveform',
-	'b67c0e81-ce6d-40a8-aeb0-ef036b081aa3': 'WetPaint',
-	'dea67637-cd1a-27e4-c9b1-52f4bbcb84e5': 'WetPaintSingleSided',
-	'5347acf0-a8e2-47b6-8346-30c70719d763': 'WigglyGraphite',
-	'e814fef1-97fd-7194-4a2f-50c2bb918be2': 'WigglyGraphiteSingleSided',
-	'4391385a-cf83-4396-9e33-31e4e4930b27': 'Wire'
-};
-
-const common = {
-
-	'colors': {
-
-		'BloomColor': `
-			vec3 BloomColor(vec3 color, float gain) {
-				// Guarantee that there's at least a little bit of all 3 channels.
-				// This makes fully-saturated strokes (which only have 2 non-zero
-				// color channels) eventually clip to white rather than to a secondary.
-				float cmin = length(color.rgb) * .05;
-				color.rgb = max(color.rgb, vec3(cmin, cmin, cmin));
-				// If we try to remove this pow() from .a, it brightens up
-				// pressure-sensitive strokes; looks better as-is.
-				color = pow(color, vec3(2.2));
-				color.rgb *= 2. * exp(gain * 10.);
-				return color;
-			}
-		`,
-
-		'LinearToSrgb': `
-			vec3 LinearToSrgb(vec3 color) {
-				// Approximation http://chilliant.blogspot.com/2012/08/srgb-approximations-for-hlsl.html
-				vec3 linearColor = color.rgb;
-				vec3 S1 = sqrt(linearColor);
-				vec3 S2 = sqrt(S1);
-				vec3 S3 = sqrt(S2);
-				color.rgb = 0.662002687 * S1 + 0.684122060 * S2 - 0.323583601 * S3 - 0.0225411470 * linearColor;
-				return color;
-			}
-		`,
-
-		'hsv': `
-			// uniform sampler2D lookupTex;
-			vec4 lookup(vec4 textureColor) {
-				return textureColor;
-			}
-
-			vec3 lookup(vec3 textureColor) {
-				return textureColor;
-			}
-
-			vec3 hsv2rgb( vec3 hsv ) {
-				vec3 rgb = clamp( abs(mod(hsv.x*6.0+vec3(0.0,4.0,2.0),6.0)-3.0)-1.0, 0.0, 1.0 );
-				return hsv.z * mix( vec3(1.0), rgb, hsv.y);
-			}
-
-			vec3 rgb2hsv( vec3 rgb ) {
-				vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
-				vec4 p = mix(vec4(rgb.bg, K.wz), vec4(rgb.gb, K.xy), step(rgb.b, rgb.g));
-				vec4 q = mix(vec4(p.xyw, rgb.r), vec4(rgb.r, p.yzx), step(p.x, rgb.r));
-
-				float d = q.x - min(q.w, q.y);
-				float e = 1.0e-10;
-
-				return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
-			}
-		`,
-
-		'SrgbToLinear': `
-			vec3 SrgbToLinear(vec3 color) {
-				// Approximation http://chilliant.blogspot.com/2012/08/srgb-approximations-for-hlsl.html
-				vec3 sRGB = color.rgb;
-				color.rgb = sRGB * (sRGB * (sRGB * 0.305306011 + 0.682171111) + 0.012522878);
-				return color;
-			}
-		`
-
-	}
-
-};
-
-let shaders = null;
-
-function getShaders() {
-
-	if ( shaders === null ) {
-
-		const loader = new TextureLoader().setPath( './textures/tiltbrush/' );
-
-		shaders = {
-			'Light': {
-				uniforms: {
-					mainTex: { value: loader.load( 'Light.webp' ) },
-					alphaTest: { value: 0.067 },
-					emission_gain: { value: 0.45 },
-					alpha: { value: 1 },
-				},
-				vertexShader: `
-					precision highp float;
-					precision highp int;
-
-					attribute vec2 uv;
-					attribute vec4 color;
-					attribute vec3 position;
-
-					uniform mat4 modelMatrix;
-					uniform mat4 modelViewMatrix;
-					uniform mat4 projectionMatrix;
-					uniform mat4 viewMatrix;
-					uniform mat3 normalMatrix;
-					uniform vec3 cameraPosition;
-
-					varying vec2 vUv;
-					varying vec3 vColor;
-
-					${ common.colors.LinearToSrgb }
-					${ common.colors.hsv }
-
-					void main() {
-
-						vUv = uv;
-
-						vColor = lookup(color.rgb);
-
-						vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
-
-						gl_Position = projectionMatrix * mvPosition;
-
-					}
-				`,
-				fragmentShader: `
-					precision highp float;
-					precision highp int;
-
-					uniform float emission_gain;
-
-					uniform sampler2D mainTex;
-					uniform float alphaTest;
-
-					varying vec2 vUv;
-					varying vec3 vColor;
-
-					${ common.colors.BloomColor }
-					${ common.colors.SrgbToLinear }
-
-					void main(){
-						vec4 col = texture2D(mainTex, vUv);
-						vec3 color = vColor;
-						color = BloomColor(color, emission_gain);
-						color = color * col.rgb;
-						color = color * col.a;
-						color = SrgbToLinear(color);
-						gl_FragColor = vec4(color, 1.0);
-					}
-				`,
-				side: 2,
-				transparent: true,
-				depthFunc: 2,
-				depthWrite: true,
-				depthTest: false,
-				blending: 5,
-				blendDst: 201,
-				blendDstAlpha: 201,
-				blendEquation: 100,
-				blendEquationAlpha: 100,
-				blendSrc: 201,
-				blendSrcAlpha: 201,
-			}
-
-		};
-
-	}
-
-	return shaders;
-
-}
-
-function getMaterial( GUID ) {
-
-	const name = BRUSH_LIST_ARRAY[ GUID ];
-
-	switch ( name ) {
-
-		case 'Light':
-			return new RawShaderMaterial( getShaders().Light );
-
-		default:
-			return new MeshBasicMaterial( { vertexColors: true, side: DoubleSide } );
-
-	}
-
-}
-
-export { TiltLoader };

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

@@ -5,6 +5,7 @@ import {
 	BufferGeometry,
 	ClampToEdgeWrapping,
 	Color,
+	ColorManagement,
 	ConeGeometry,
 	CylinderGeometry,
 	DataTexture,
@@ -918,8 +919,7 @@ class VRMLLoader extends Loader {
 
 				} else {
 
-					skyMaterial.color.setRGB( skyColor[ 0 ], skyColor[ 1 ], skyColor[ 2 ] );
-					skyMaterial.color.convertSRGBToLinear();
+					skyMaterial.color.setRGB( skyColor[ 0 ], skyColor[ 1 ], skyColor[ 2 ], SRGBColorSpace );
 
 				}
 
@@ -1240,13 +1240,11 @@ class VRMLLoader extends Loader {
 						break;
 
 					case 'diffuseColor':
-						materialData.diffuseColor = new Color( fieldValues[ 0 ], fieldValues[ 1 ], fieldValues[ 2 ] );
-						materialData.diffuseColor.convertSRGBToLinear();
+						materialData.diffuseColor = new Color().setRGB( fieldValues[ 0 ], fieldValues[ 1 ], fieldValues[ 2 ], SRGBColorSpace );
 						break;
 
 					case 'emissiveColor':
-						materialData.emissiveColor = new Color( fieldValues[ 0 ], fieldValues[ 1 ], fieldValues[ 2 ] );
-						materialData.emissiveColor.convertSRGBToLinear();
+						materialData.emissiveColor = new Color().setRGB( fieldValues[ 0 ], fieldValues[ 1 ], fieldValues[ 2 ], SRGBColorSpace );
 						break;
 
 					case 'shininess':
@@ -1254,8 +1252,7 @@ class VRMLLoader extends Loader {
 						break;
 
 					case 'specularColor':
-						materialData.specularColor = new Color( fieldValues[ 0 ], fieldValues[ 1 ], fieldValues[ 2 ] );
-						materialData.specularColor.convertSRGBToLinear();
+						materialData.specularColor = new Color().setRGB( fieldValues[ 0 ], fieldValues[ 1 ], fieldValues[ 2 ], SRGBColorSpace );
 						break;
 
 					case 'transparency':
@@ -3111,7 +3108,8 @@ class VRMLLoader extends Loader {
 			for ( let i = 0; i < attribute.count; i ++ ) {
 
 				color.fromBufferAttribute( attribute, i );
-				color.convertSRGBToLinear();
+
+				ColorManagement.toWorkingColorSpace( color, SRGBColorSpace );
 
 				attribute.setXYZ( i, color.r, color.g, color.b );
 
@@ -3216,7 +3214,9 @@ class VRMLLoader extends Loader {
 				const colorA = colors[ thresholdIndexA ];
 				const colorB = colors[ thresholdIndexB ];
 
-				color.copy( colorA ).lerp( colorB, t ).convertSRGBToLinear();
+				color.copy( colorA ).lerp( colorB, t );
+
+				ColorManagement.toWorkingColorSpace( color, SRGBColorSpace );
 
 				colorAttribute.setXYZ( index, color.r, color.g, color.b );
 

+ 4 - 3
examples/jsm/loaders/VTKLoader.js

@@ -4,7 +4,8 @@ import {
 	Color,
 	FileLoader,
 	Float32BufferAttribute,
-	Loader
+	Loader,
+	SRGBColorSpace
 } from 'three';
 import * as fflate from '../libs/fflate.module.js';
 
@@ -211,7 +212,7 @@ class VTKLoader extends Loader {
 							const g = parseFloat( result[ 2 ] );
 							const b = parseFloat( result[ 3 ] );
 
-							color.set( r, g, b ).convertSRGBToLinear();
+							color.setRGB( r, g, b, SRGBColorSpace );
 
 							colors.push( color.r, color.g, color.b );
 
@@ -325,7 +326,7 @@ class VTKLoader extends Loader {
 						const g = colors[ 3 * i + 1 ];
 						const b = colors[ 3 * i + 2 ];
 
-						color.set( r, g, b ).convertSRGBToLinear();
+						color.setRGB( r, g, b, SRGBColorSpace );
 
 						newColors.push( color.r, color.g, color.b );
 						newColors.push( color.r, color.g, color.b );

+ 3 - 2
examples/jsm/loaders/XYZLoader.js

@@ -3,7 +3,8 @@ import {
 	Color,
 	FileLoader,
 	Float32BufferAttribute,
-	Loader
+	Loader,
+	SRGBColorSpace
 } from 'three';
 
 class XYZLoader extends Loader {
@@ -80,7 +81,7 @@ class XYZLoader extends Loader {
 				const g = parseFloat( lineValues[ 4 ] ) / 255;
 				const b = parseFloat( lineValues[ 5 ] ) / 255;
 
-				color.set( r, g, b ).convertSRGBToLinear();
+				color.setRGB( r, g, b, SRGBColorSpace );
 
 				colors.push( color.r, color.g, color.b );
 

+ 1 - 1
examples/jsm/misc/Timer.js

@@ -115,7 +115,7 @@ class FixedTimer extends Timer {
 
 function now() {
 
-	return ( typeof performance === 'undefined' ? Date : performance ).now();
+	return performance.now();
 
 }
 

+ 233 - 0
examples/jsm/modifiers/CurveModifierGPU.js

@@ -0,0 +1,233 @@
+// Original src: https://github.com/zz85/threejs-path-flow
+const CHANNELS = 4;
+const TEXTURE_WIDTH = 1024;
+const TEXTURE_HEIGHT = 4;
+
+import {
+	DataTexture,
+	DataUtils,
+	RGBAFormat,
+	HalfFloatType,
+	RepeatWrapping,
+	Mesh,
+	InstancedMesh,
+	LinearFilter
+} from 'three';
+
+import { modelWorldMatrix, normalLocal, vec2, vec3, vec4, mat3, varyingProperty, texture, reference, Fn, select, positionLocal } from 'three/tsl';
+
+/**
+ * Make a new DataTexture to store the descriptions of the curves.
+ *
+ * @param { number } numberOfCurves the number of curves needed to be described by this texture.
+ */
+export function initSplineTexture( numberOfCurves = 1 ) {
+
+	const dataArray = new Uint16Array( TEXTURE_WIDTH * TEXTURE_HEIGHT * numberOfCurves * CHANNELS );
+	const dataTexture = new DataTexture(
+		dataArray,
+		TEXTURE_WIDTH,
+		TEXTURE_HEIGHT * numberOfCurves,
+		RGBAFormat,
+		HalfFloatType
+	);
+
+	dataTexture.wrapS = RepeatWrapping;
+	dataTexture.wrapY = RepeatWrapping;
+	dataTexture.magFilter = LinearFilter;
+	dataTexture.minFilter = LinearFilter;
+	dataTexture.needsUpdate = true;
+
+	return dataTexture;
+
+}
+
+/**
+ * Write the curve description to the data texture
+ *
+ * @param { DataTexture } texture The DataTexture to write to
+ * @param { Curve } splineCurve The curve to describe
+ * @param { number } offset Which curve slot to write to
+ */
+export function updateSplineTexture( texture, splineCurve, offset = 0 ) {
+
+	const numberOfPoints = Math.floor( TEXTURE_WIDTH * ( TEXTURE_HEIGHT / 4 ) );
+	splineCurve.arcLengthDivisions = numberOfPoints / 2;
+	splineCurve.updateArcLengths();
+	const points = splineCurve.getSpacedPoints( numberOfPoints );
+	const frenetFrames = splineCurve.computeFrenetFrames( numberOfPoints, true );
+
+	for ( let i = 0; i < numberOfPoints; i ++ ) {
+
+		const rowOffset = Math.floor( i / TEXTURE_WIDTH );
+		const rowIndex = i % TEXTURE_WIDTH;
+
+		let pt = points[ i ];
+		setTextureValue( texture, rowIndex, pt.x, pt.y, pt.z, 0 + rowOffset + ( TEXTURE_HEIGHT * offset ) );
+		pt = frenetFrames.tangents[ i ];
+		setTextureValue( texture, rowIndex, pt.x, pt.y, pt.z, 1 + rowOffset + ( TEXTURE_HEIGHT * offset ) );
+		pt = frenetFrames.normals[ i ];
+		setTextureValue( texture, rowIndex, pt.x, pt.y, pt.z, 2 + rowOffset + ( TEXTURE_HEIGHT * offset ) );
+		pt = frenetFrames.binormals[ i ];
+		setTextureValue( texture, rowIndex, pt.x, pt.y, pt.z, 3 + rowOffset + ( TEXTURE_HEIGHT * offset ) );
+
+	}
+
+	texture.needsUpdate = true;
+
+}
+
+
+function setTextureValue( texture, index, x, y, z, o ) {
+
+	const image = texture.image;
+	const { data } = image;
+	const i = CHANNELS * TEXTURE_WIDTH * o; // Row Offset
+
+	data[ index * CHANNELS + i + 0 ] = DataUtils.toHalfFloat( x );
+	data[ index * CHANNELS + i + 1 ] = DataUtils.toHalfFloat( y );
+	data[ index * CHANNELS + i + 2 ] = DataUtils.toHalfFloat( z );
+	data[ index * CHANNELS + i + 3 ] = DataUtils.toHalfFloat( 1 );
+
+}
+
+/**
+ * Create a new set of uniforms for describing the curve modifier
+ *
+ * @param { DataTexture } Texture which holds the curve description
+ */
+export function getUniforms( splineTexture ) {
+
+	return {
+		spineTexture: splineTexture,
+		pathOffset: 0, // time of path curve
+		pathSegment: 1, // fractional length of path
+		spineOffset: 161,
+		spineLength: 400,
+		flow: 1, // int
+	};
+
+}
+
+export function modifyShader( material, uniforms, numberOfCurves ) {
+
+	const spineTexture = uniforms.spineTexture;
+
+	const pathOffset = reference( 'pathOffset', 'float', uniforms );
+	const pathSegment = reference( 'pathSegment', 'float', uniforms );
+	const spineOffset = reference( 'spineOffset', 'float', uniforms );
+	const spineLength = reference( 'spineLength', 'float', uniforms );
+	const flow = reference( 'flow', 'float', uniforms );
+
+	material.positionNode = Fn( () => {
+
+		const textureStacks = TEXTURE_HEIGHT / 4;
+		const textureScale = TEXTURE_HEIGHT * numberOfCurves;
+
+		const worldPos = modelWorldMatrix.mul( vec4( positionLocal, 1 ) ).toVar();
+
+		const bend = flow.greaterThan( 0 ).toVar();
+		const xWeight = select( bend, 0, 1 ).toVar();
+
+		const spinePortion = select( bend, worldPos.x.add( spineOffset ).div( spineLength ), 0 );
+		const mt = spinePortion.mul( pathSegment ).add( pathOffset ).mul( textureStacks ).toVar();
+
+		mt.assign( mt.mod( textureStacks ) );
+
+		const rowOffset = mt.floor().toVar();
+
+		const spinePos = texture( spineTexture, vec2( mt, rowOffset.add( 0.5 ).div( textureScale ) ) ).xyz;
+
+		const a = texture( spineTexture, vec2( mt, rowOffset.add( 1.5 ).div( textureScale ) ) ).xyz;
+		const b = texture( spineTexture, vec2( mt, rowOffset.add( 2.5 ).div( textureScale ) ) ).xyz;
+		const c = texture( spineTexture, vec2( mt, rowOffset.add( 3.5 ).div( textureScale ) ) ).xyz;
+
+		const basis = mat3( a, b, c ).toVar();
+
+		varyingProperty( 'vec3', 'curveNormal' ).assign( basis.mul( normalLocal ) );
+
+		return basis.mul( vec3( worldPos.x.mul( xWeight ), worldPos.y, worldPos.z ) ).add( spinePos );
+
+	} )();
+
+	material.normalNode = varyingProperty( 'vec3', 'curveNormal' );
+
+}
+
+/**
+ * A helper class for making meshes bend aroudn curves
+ */
+export class Flow {
+
+	/**
+	 * @param {Mesh} mesh The mesh to clone and modify to bend around the curve
+	 * @param {number} numberOfCurves The amount of space that should preallocated for additional curves
+	 */
+	constructor( mesh, numberOfCurves = 1 ) {
+
+		const obj3D = mesh.clone();
+		const splineTexure = initSplineTexture( numberOfCurves );
+		const uniforms = getUniforms( splineTexure );
+
+		obj3D.traverse( function ( child ) {
+
+			if (
+				child instanceof Mesh ||
+				child instanceof InstancedMesh
+			) {
+
+				if ( Array.isArray( child.material ) ) {
+
+					const materials = [];
+
+					for ( const material of child.material ) {
+
+						const newMaterial = material.clone();
+						modifyShader( newMaterial, uniforms, numberOfCurves );
+						materials.push( newMaterial );
+
+					}
+
+					child.material = materials;
+
+				} else {
+
+					child.material = child.material.clone();
+					modifyShader( child.material, uniforms, numberOfCurves );
+
+				}
+
+			}
+
+		} );
+
+		this.curveArray = new Array( numberOfCurves );
+		this.curveLengthArray = new Array( numberOfCurves );
+
+		this.object3D = obj3D;
+		this.splineTexure = splineTexure;
+		this.uniforms = uniforms;
+
+	}
+
+	updateCurve( index, curve ) {
+
+		if ( index >= this.curveArray.length ) throw Error( 'Index out of range for Flow' );
+
+		const curveLength = curve.getLength();
+
+		this.uniforms.spineLength = curveLength;
+		this.curveLengthArray[ index ] = curveLength;
+		this.curveArray[ index ] = curve;
+
+		updateSplineTexture( this.splineTexure, curve, index );
+
+	}
+
+	moveAlongCurve( amount ) {
+
+		this.uniforms.pathOffset += amount;
+
+	}
+
+}

+ 322 - 0
examples/jsm/objects/LensflareMesh.js

@@ -0,0 +1,322 @@
+import {
+	AdditiveBlending,
+	Box2,
+	BufferGeometry,
+	Color,
+	FramebufferTexture,
+	InterleavedBuffer,
+	InterleavedBufferAttribute,
+	Mesh,
+	MeshBasicNodeMaterial,
+	NodeMaterial,
+	UnsignedByteType,
+	Vector2,
+	Vector3,
+	Vector4 } from 'three';
+
+import { texture, textureLoad, uv, ivec2, vec2, vec4, positionGeometry, reference, varyingProperty, materialReference, Fn, Node } from 'three/tsl';
+
+class LensflareMesh extends Mesh {
+
+	constructor() {
+
+		super( LensflareMesh.Geometry, new MeshBasicNodeMaterial( { opacity: 0, transparent: true } ) );
+
+		this.isLensflare = true;
+
+		this.type = 'LensflareMesh';
+		this.frustumCulled = false;
+		this.renderOrder = Infinity;
+
+		//
+
+		const positionView = new Vector3();
+
+		// textures
+
+		const tempMap = new FramebufferTexture( 16, 16 );
+		const occlusionMap = new FramebufferTexture( 16, 16 );
+
+		let currentType = UnsignedByteType;
+
+		const geometry = LensflareMesh.Geometry;
+
+		// values for shared material uniforms
+
+		const sharedValues = {
+			scale: new Vector2(),
+			positionScreen: new Vector3()
+		};
+
+		// materials
+
+		const scale = reference( 'scale', 'vec2', sharedValues );
+		const screenPosition = reference( 'positionScreen', 'vec3', sharedValues );
+
+		const vertexNode = vec4( positionGeometry.xy.mul( scale ).add( screenPosition.xy ), screenPosition.z, 1.0 );
+
+		const material1a = new NodeMaterial();
+
+		material1a.depthTest = true;
+		material1a.depthWrite = false;
+		material1a.transparent = false;
+		material1a.fog = false;
+		material1a.type = 'Lensflare-1a';
+
+		material1a.vertexNode = vertexNode;
+		material1a.fragmentNode = vec4( 1.0, 0.0, 1.0, 1.0 );
+
+		const material1b = new NodeMaterial();
+
+		material1b.depthTest = false;
+		material1b.depthWrite = false;
+		material1b.transparent = false;
+		material1b.fog = false;
+		material1b.type = 'Lensflare-1b';
+
+		material1b.vertexNode = vertexNode;
+		material1b.fragmentNode = texture( tempMap, vec2( uv().flipY() ) );
+
+		// the following object is used for occlusionMap generation
+
+		const mesh1 = new Mesh( geometry, material1a );
+
+		//
+
+		const elements = [];
+		const elementMeshes = [];
+
+		const material2 = new NodeMaterial();
+
+		material2.transparent = true;
+		material2.blending = AdditiveBlending;
+		material2.depthWrite = false;
+		material2.depthTest = false;
+		material2.fog = false;
+		material2.type = 'Lensflare-2';
+
+		material2.screenPosition = new Vector3();
+		material2.scale = new Vector2();
+		material2.occlusionMap = occlusionMap;
+
+		material2.vertexNode = Fn( ( { material } ) => {
+
+			const scale = materialReference( 'scale', 'vec2' );
+			const screenPosition = materialReference( 'screenPosition', 'vec3' );
+
+			const occlusionMap = material.occlusionMap;
+
+			const pos = positionGeometry.xy.toVar();
+
+			const visibility = textureLoad( occlusionMap, ivec2( 2, 2 ) ).toVar();
+			visibility.addAssign( textureLoad( occlusionMap, ivec2( 8, 2 ) ) );
+			visibility.addAssign( textureLoad( occlusionMap, ivec2( 14, 2 ) ) );
+			visibility.addAssign( textureLoad( occlusionMap, ivec2( 14, 8 ) ) );
+			visibility.addAssign( textureLoad( occlusionMap, ivec2( 14, 14 ) ) );
+			visibility.addAssign( textureLoad( occlusionMap, ivec2( 8, 14 ) ) );
+			visibility.addAssign( textureLoad( occlusionMap, ivec2( 2, 14 ) ) );
+			visibility.addAssign( textureLoad( occlusionMap, ivec2( 2, 8 ) ) );
+			visibility.addAssign( textureLoad( occlusionMap, ivec2( 8, 8 ) ) );
+
+			const vVisibility = varyingProperty( 'float', 'vVisibility' );
+
+			vVisibility.assign( visibility.r.div( 9.0 ) );
+			vVisibility.mulAssign( visibility.g.div( 9.0 ).oneMinus() );
+			vVisibility.mulAssign( visibility.b.div( 9.0 ) );
+
+			return vec4( ( pos.mul( scale ).add( screenPosition.xy ).xy ), screenPosition.z, 1.0 );
+
+		} )();
+
+		material2.fragmentNode = Fn( () => {
+
+			const color = reference( 'color', 'color' );
+			const map = reference( 'map', 'texture' );
+
+			const vVisibility = varyingProperty( 'float', 'vVisibility' );
+
+			const output = map.toVar();
+
+			output.a.mulAssign( vVisibility );
+			output.rgb.mulAssign( color );
+
+			return output;
+
+		} )();
+
+
+		this.addElement = function ( element ) {
+
+			elements.push( element );
+
+		};
+
+		//
+
+		const positionScreen = sharedValues.positionScreen;
+		const screenPositionPixels = new Vector4( 0, 0, 16, 16 );
+		const validArea = new Box2();
+		const viewport = new Vector4();
+
+		// dummy node for renderer.renderObject()
+		const lightsNode = new Node();
+
+		this.onBeforeRender = ( renderer, scene, camera ) => {
+
+			renderer.getViewport( viewport );
+
+			viewport.multiplyScalar( window.devicePixelRatio );
+
+			const renderTarget = renderer.getRenderTarget();
+			const type = ( renderTarget !== null ) ? renderTarget.texture.type : UnsignedByteType;
+
+			if ( currentType !== type ) {
+
+				tempMap.dispose();
+				occlusionMap.dispose();
+
+				tempMap.type = occlusionMap.type = type;
+
+				currentType = type;
+
+			}
+
+			const invAspect = viewport.w / viewport.z;
+			const halfViewportWidth = viewport.z / 2.0;
+			const halfViewportHeight = viewport.w / 2.0;
+
+			const size = 16 / viewport.w;
+
+			sharedValues.scale.set( size * invAspect, size );
+
+			validArea.min.set( viewport.x, viewport.y );
+			validArea.max.set( viewport.x + ( viewport.z - 16 ), viewport.y + ( viewport.w - 16 ) );
+
+			// calculate position in screen space
+
+			positionView.setFromMatrixPosition( this.matrixWorld );
+			positionView.applyMatrix4( camera.matrixWorldInverse );
+
+			if ( positionView.z > 0 ) return; // lensflare is behind the camera
+
+			positionScreen.copy( positionView ).applyMatrix4( camera.projectionMatrix );
+
+			// horizontal and vertical coordinate of the lower left corner of the pixels to copy
+
+			screenPositionPixels.x = viewport.x + ( positionScreen.x * halfViewportWidth ) + halfViewportWidth - 8;
+			screenPositionPixels.y = viewport.y - ( positionScreen.y * halfViewportHeight ) + halfViewportHeight - 8;
+
+			// screen cull
+
+			if ( validArea.containsPoint( screenPositionPixels ) ) {
+
+				// save current RGB to temp texture
+
+				renderer.copyFramebufferToTexture( tempMap, screenPositionPixels );
+
+				// render pink quad
+
+				renderer.renderObject( mesh1, scene, camera, geometry, material1a, null, lightsNode );
+
+				// copy result to occlusionMap
+
+				renderer.copyFramebufferToTexture( occlusionMap, screenPositionPixels );
+
+				// restore graphics
+
+				renderer.renderObject( mesh1, scene, camera, geometry, material1b, null, lightsNode );
+
+				// render elements
+
+				const vecX = - positionScreen.x * 2;
+				const vecY = - positionScreen.y * 2;
+
+				for ( let i = 0, l = elements.length; i < l; i ++ ) {
+
+					const element = elements[ i ];
+
+					let mesh2 = elementMeshes[ i ];
+
+					if ( mesh2 === undefined ) {
+
+						mesh2 = elementMeshes[ i ] = new Mesh( geometry, material2 );
+
+						mesh2.color = element.color.convertSRGBToLinear();
+						mesh2.map = element.texture;
+
+					}
+
+					material2.screenPosition.x = positionScreen.x + vecX * element.distance;
+					material2.screenPosition.y = positionScreen.y - vecY * element.distance;
+					material2.screenPosition.z = positionScreen.z;
+
+					const size = element.size / viewport.w;
+
+					material2.scale.set( size * invAspect, size );
+
+					renderer.renderObject( mesh2, scene, camera, geometry, material2, null, lightsNode );
+
+				}
+
+			}
+
+		};
+
+		this.dispose = function () {
+
+			material1a.dispose();
+			material1b.dispose();
+			material2.dispose();
+
+			tempMap.dispose();
+			occlusionMap.dispose();
+
+			for ( let i = 0, l = elements.length; i < l; i ++ ) {
+
+				elements[ i ].texture.dispose();
+
+			}
+
+		};
+
+	}
+
+}
+
+//
+
+class LensflareElement {
+
+	constructor( texture, size = 1, distance = 0, color = new Color( 0xffffff ) ) {
+
+		this.texture = texture;
+		this.size = size;
+		this.distance = distance;
+		this.color = color;
+
+	}
+
+}
+
+LensflareMesh.Geometry = ( function () {
+
+	const geometry = new BufferGeometry();
+
+	const float32Array = new Float32Array( [
+		- 1, - 1, 0, 0, 0,
+		1, - 1, 0, 1, 0,
+		1, 1, 0, 1, 1,
+		- 1, 1, 0, 0, 1
+	] );
+
+	const interleavedBuffer = new InterleavedBuffer( float32Array, 5 );
+
+	geometry.setIndex( [ 0, 1, 2,	0, 2, 3 ] );
+	geometry.setAttribute( 'position', new InterleavedBufferAttribute( interleavedBuffer, 3, 0, false ) );
+	geometry.setAttribute( 'uv', new InterleavedBufferAttribute( interleavedBuffer, 2, 3, false ) );
+
+	return geometry;
+
+} )();
+
+export { LensflareMesh, LensflareElement };

+ 1 - 2
examples/jsm/objects/SkyMesh.js

@@ -2,10 +2,9 @@ import {
 	BackSide,
 	BoxGeometry,
 	Mesh,
-	NodeMaterial,
 	Vector3
 } from 'three';
-import { float, Fn, vec3, acos, add, mul, clamp, cos, dot, exp, max, mix, modelViewProjection, normalize, positionWorld, pow, smoothstep, sub, varying, varyingProperty, vec4, uniform, cameraPosition } from 'three/tsl';
+import { Fn, NodeMaterial, float, vec3, acos, add, mul, clamp, cos, dot, exp, max, mix, modelViewProjection, normalize, positionWorld, pow, smoothstep, sub, varying, varyingProperty, vec4, uniform, cameraPosition } from 'three/tsl';
 
 /**
  * Based on "A Practical Analytic Model for Daylight"

+ 2 - 3
examples/jsm/objects/Water2Mesh.js

@@ -1,11 +1,10 @@
 import {
 	Color,
 	Mesh,
-	NodeMaterial,
 	Vector2,
 	Vector3
 } from 'three';
-import { vec2, viewportSafeUV, viewportSharedTexture, reflector, pow, float, abs, texture, uniform, TempNode, NodeUpdateType, vec4, Fn, cameraPosition, positionWorld, uv, mix, vec3, normalize, max, dot, viewportUV } from 'three/tsl';
+import { Fn, NodeMaterial, NodeUpdateType, TempNode, vec2, viewportSafeUV, viewportSharedTexture, reflector, pow, float, abs, texture, uniform, vec4, cameraPosition, positionWorld, uv, mix, vec3, normalize, max, dot, screenUV } from 'three/tsl';
 
 /**
  * References:
@@ -141,7 +140,7 @@ class WaterNode extends TempNode {
 			this.waterBody.add( reflectionSampler.target );
 			reflectionSampler.uvNode = reflectionSampler.uvNode.add( offset );
 
-			const refractorUV = viewportUV.add( offset );
+			const refractorUV = screenUV.add( offset );
 			const refractionSampler = viewportSharedTexture( viewportSafeUV( refractorUV ) );
 
 			// calculate final uv coords

+ 1 - 2
examples/jsm/objects/WaterMesh.js

@@ -1,10 +1,9 @@
 import {
 	Color,
 	Mesh,
-	NodeMaterial,
 	Vector3
 } from 'three';
-import { add, cameraPosition, div, normalize, positionWorld, sub, timerLocal, Fn, texture, vec2, vec3, vec4, max, dot, reflect, pow, length, float, uniform, reflector, mul, mix } from 'three/tsl';
+import { Fn, NodeMaterial, add, cameraPosition, div, normalize, positionWorld, sub, timerLocal, texture, vec2, vec3, vec4, max, dot, reflect, pow, length, float, uniform, reflector, mul, mix } from 'three/tsl';
 
 /**
  * Work based on :

+ 1 - 1
examples/jsm/physics/JoltPhysics.js

@@ -61,7 +61,7 @@ async function JoltPhysics() {
 
 	if ( Jolt === null ) {
 
-		const { default: initJolt } = await import( JOLT_PATH );
+		const { default: initJolt } = await import( `${JOLT_PATH}` );
 		Jolt = await initJolt();
 
 	}

+ 1 - 1
examples/jsm/physics/RapierPhysics.js

@@ -58,7 +58,7 @@ async function RapierPhysics() {
 
 	if ( RAPIER === null ) {
 
-		RAPIER = await import( RAPIER_PATH );
+		RAPIER = await import( `${RAPIER_PATH}` );
 		await RAPIER.init();
 
 	}

+ 1 - 1
examples/jsm/transpiler/GLSLDecoder.js

@@ -226,7 +226,7 @@ class GLSLDecoder {
 
 		this._currentFunction = null;
 
-		this.addPolyfill( 'gl_FragCoord', 'vec3 gl_FragCoord = vec3( viewportCoordinate.x, viewportCoordinate.y.oneMinus(), viewportCoordinate.z );' );
+		this.addPolyfill( 'gl_FragCoord', 'vec3 gl_FragCoord = vec3( screenCoordinate.x, screenCoordinate.y.oneMinus(), screenCoordinate.z );' );
 
 	}
 

Некоторые файлы не были показаны из-за большого количества измененных файлов

粤ICP备19079148号