Mr.doob 3 years ago
parent
commit
c1e8525913
100 changed files with 1382 additions and 351 deletions
  1. 27 7
      build/three.cjs
  2. 27 7
      build/three.js
  3. 0 0
      build/three.min.js
  4. 37 9
      build/three.module.js
  5. 8 2
      docs/api/en/core/BufferAttribute.html
  6. 1 1
      docs/api/en/core/BufferGeometry.html
  7. 1 1
      docs/api/en/lights/shadows/DirectionalLightShadow.html
  8. 3 0
      docs/api/en/materials/LineBasicMaterial.html
  9. 0 3
      docs/api/en/materials/Material.html
  10. 3 0
      docs/api/en/materials/MeshBasicMaterial.html
  11. 3 0
      docs/api/en/materials/MeshLambertMaterial.html
  12. 3 0
      docs/api/en/materials/MeshMatcapMaterial.html
  13. 3 0
      docs/api/en/materials/MeshPhongMaterial.html
  14. 20 0
      docs/api/en/materials/MeshPhysicalMaterial.html
  15. 3 0
      docs/api/en/materials/MeshStandardMaterial.html
  16. 3 0
      docs/api/en/materials/MeshToonMaterial.html
  17. 4 1
      docs/api/en/materials/PointsMaterial.html
  18. 3 0
      docs/api/en/materials/ShadowMaterial.html
  19. 3 0
      docs/api/en/materials/SpriteMaterial.html
  20. 4 0
      docs/api/en/math/Color.html
  21. 4 0
      docs/api/en/math/Euler.html
  22. 1 1
      docs/api/en/math/Matrix4.html
  23. 4 0
      docs/api/en/math/Quaternion.html
  24. 1 1
      docs/api/en/math/Vector2.html
  25. 1 1
      docs/api/en/math/Vector3.html
  26. 1 1
      docs/api/en/math/Vector4.html
  27. 3 1
      docs/api/en/objects/SkinnedMesh.html
  28. 2 1
      docs/api/en/renderers/WebGLRenderTarget.html
  29. 1 1
      docs/api/en/renderers/WebGLRenderer.html
  30. 7 0
      docs/api/en/renderers/webxr/WebXRManager.html
  31. 1 1
      docs/api/ko/core/BufferGeometry.html
  32. 1 1
      docs/api/zh/core/BufferGeometry.html
  33. 1 1
      docs/api/zh/lights/shadows/DirectionalLightShadow.html
  34. 3 0
      docs/api/zh/materials/LineBasicMaterial.html
  35. 0 3
      docs/api/zh/materials/Material.html
  36. 3 0
      docs/api/zh/materials/MeshBasicMaterial.html
  37. 0 3
      docs/api/zh/materials/MeshDepthMaterial.html
  38. 0 3
      docs/api/zh/materials/MeshDistanceMaterial.html
  39. 3 0
      docs/api/zh/materials/MeshLambertMaterial.html
  40. 3 0
      docs/api/zh/materials/MeshMatcapMaterial.html
  41. 0 3
      docs/api/zh/materials/MeshNormalMaterial.html
  42. 3 0
      docs/api/zh/materials/MeshPhongMaterial.html
  43. 21 0
      docs/api/zh/materials/MeshPhysicalMaterial.html
  44. 3 0
      docs/api/zh/materials/MeshStandardMaterial.html
  45. 3 0
      docs/api/zh/materials/MeshToonMaterial.html
  46. 3 1
      docs/api/zh/materials/PointsMaterial.html
  47. 3 0
      docs/api/zh/materials/ShadowMaterial.html
  48. 3 0
      docs/api/zh/materials/SpriteMaterial.html
  49. 1 1
      docs/api/zh/math/Matrix4.html
  50. 3 1
      docs/api/zh/objects/SkinnedMesh.html
  51. 1 1
      docs/api/zh/renderers/WebGLRenderer.html
  52. 7 0
      docs/api/zh/renderers/webxr/WebXRManager.html
  53. 75 12
      docs/examples/en/animations/CCDIKSolver.html
  54. 1 1
      docs/examples/en/loaders/FontLoader.html
  55. 5 0
      docs/examples/en/loaders/GLTFLoader.html
  56. 8 6
      docs/examples/en/utils/BufferGeometryUtils.html
  57. 77 14
      docs/examples/zh/animations/CCDIKSolver.html
  58. 9 9
      docs/examples/zh/loaders/FontLoader.html
  59. 5 0
      docs/examples/zh/loaders/GLTFLoader.html
  60. 8 6
      docs/examples/zh/utils/BufferGeometryUtils.html
  61. 1 1
      docs/index.html
  62. 2 2
      docs/list.json
  63. 5 0
      docs/manual/ar/introduction/How-to-dispose-of-objects.html
  64. 1 1
      docs/manual/ar/introduction/Installation.html
  65. 1 1
      docs/manual/en/introduction/Color-management.html
  66. 5 0
      docs/manual/en/introduction/How-to-dispose-of-objects.html
  67. 1 1
      docs/manual/en/introduction/Installation.html
  68. 7 0
      docs/manual/en/introduction/Libraries-and-Plugins.html
  69. 3 0
      docs/manual/en/introduction/Useful-links.html
  70. 6 1
      docs/manual/ja/introduction/How-to-dispose-of-objects.html
  71. 1 1
      docs/manual/ja/introduction/Installation.html
  72. 6 1
      docs/manual/ko/introduction/How-to-dispose-of-objects.html
  73. 1 1
      docs/manual/ko/introduction/Installation.html
  74. 5 0
      docs/manual/zh/introduction/How-to-dispose-of-objects.html
  75. 1 1
      docs/manual/zh/introduction/Installation.html
  76. 286 0
      docs/scenes/ccdiksolver-browser.html
  77. 22 20
      docs/scenes/material-browser.html
  78. 2 2
      editor/docs/Implementing additional commands for undo-redo.md
  79. 17 0
      editor/js/Menubar.Add.js
  80. 73 0
      editor/js/Sidebar.Geometry.CapsuleGeometry.js
  81. 56 1
      editor/js/Sidebar.Material.js
  82. 21 0
      editor/js/Strings.js
  83. 8 13
      editor/js/libs/codemirror/codemirror.css
  84. 78 62
      editor/js/libs/codemirror/codemirror.js
  85. 2 1
      editor/sw.js
  86. 3 0
      examples/files.json
  87. 3 1
      examples/js/controls/ArcballControls.js
  88. 49 36
      examples/js/exporters/GLTFExporter.js
  89. 0 19
      examples/js/libs/opentype.min.js
  90. 8 0
      examples/js/loaders/FBXLoader.js
  91. 60 6
      examples/js/loaders/GLTFLoader.js
  92. 17 2
      examples/js/loaders/MMDLoader.js
  93. 3 8
      examples/js/objects/MarchingCubes.js
  94. 4 1
      examples/js/objects/Reflector.js
  95. 4 1
      examples/js/objects/Refractor.js
  96. 0 4
      examples/js/postprocessing/UnrealBloomPass.js
  97. 133 17
      examples/js/utils/BufferGeometryUtils.js
  98. 3 1
      examples/jsm/controls/ArcballControls.js
  99. 49 40
      examples/jsm/exporters/GLTFExporter.js
  100. 0 0
      examples/jsm/libs/mikktspace.module.js

File diff suppressed because it is too large
+ 27 - 7
build/three.cjs


File diff suppressed because it is too large
+ 27 - 7
build/three.js


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


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


+ 8 - 2
docs/api/en/core/BufferAttribute.html

@@ -103,7 +103,9 @@
 		<p>
 			Defines the intended usage pattern of the data store for optimization purposes. Corresponds to the *usage* parameter of
 			[link:https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/bufferData WebGLRenderingContext.bufferData]().
-			Default is [page:BufferAttributeUsage StaticDrawUsage]. See usage [page:BufferAttributeUsage constants] for all possible values.
+			Default is [page:BufferAttributeUsage StaticDrawUsage]. See usage [page:BufferAttributeUsage constants] for all possible values. <br /><br />
+			
+			Note: After the initial use of a buffer, its usage cannot be changed. Instead, instantiate a new one and set the desired usage before the next render.
 		</p>
 
 		<h3>[property:Integer version]</h3>
@@ -185,7 +187,11 @@
 		</p>
 
 		<h3>[method:this setUsage] ( [param:Usage value] ) </h3>
-		<p>Set [page:BufferAttribute.usage usage] to value. See usage [page:BufferAttributeUsage constants] for all possible input values.</p>
+		<p>
+			Set [page:BufferAttribute.usage usage] to value. See usage [page:BufferAttributeUsage constants] for all possible input values.  <br /><br />
+
+			Note: After the initial use of a buffer, its usage cannot be changed. Instead, instantiate a new one and set the desired usage before the next render.
+		</p>
 
 		<h3>[method:this setX]( [param:Integer index], [param:Float x] ) </h3>
 		<p>Sets the x component of the vector at the given index.</p>

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

@@ -217,7 +217,7 @@
 		<p>
 		Calculates and adds a tangent attribute to this geometry.<br />
 		The computation is only supported for indexed geometries and if position, normal, and uv attributes are defined. When using a tangent space normal map, prefer the MikkTSpace algorithm provided by
-		[page:BufferGeometryUtils.computeTangents] instead.
+		[page:BufferGeometryUtils.computeMikkTSpaceTangents] instead.
 		</p>
 
 		<h3>[method:undefined computeVertexNormals]()</h3>

+ 1 - 1
docs/api/en/lights/shadows/DirectionalLightShadow.html

@@ -28,7 +28,7 @@
 		renderer.shadowMap.type = THREE.PCFSoftShadowMap; // default THREE.PCFShadowMap
 
 		//Create a DirectionalLight and turn on shadows for the light
-		const light = new THREE.DirectionalLight( 0xffffff, 1, 100 );
+		const light = new THREE.DirectionalLight( 0xffffff, 1 );
 		light.position.set( 0, 1, 0 ); //default; light shining from top
 		light.castShadow = true; // default false
 		scene.add( light );

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

@@ -61,6 +61,9 @@
 		<h3>[property:Color color]</h3>
 		<p>[page:Color] of the material, by default set to white (0xffffff).</p>
 
+		<h3>[property:Boolean fog]</h3>
+		<p>Whether the material is affected by fog. Default is *true*.</p>
+
 		<h3>[property:Float linewidth]</h3>
 		<p>
 			Controls line thickness. Default is *1*.<br /><br />

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

@@ -173,9 +173,6 @@
 		Which stencil operation to perform when the comparison function returns true and the depth test passes. Default is [page:Materials KeepStencilOp]. See the stencil operations [page:Materials constants] for all possible values.
 		</p>
 
-		<h3>[property:Boolean fog]</h3>
-		<p>Whether the material is affected by fog. Default is *true*.</p>
-
 		<h3>[property:Integer id]</h3>
 		<p>Unique number for this material instance.</p>
 

+ 3 - 0
docs/api/en/materials/MeshBasicMaterial.html

@@ -83,6 +83,9 @@
 		<h3>[property:Texture envMap]</h3>
 		<p>The environment map. Default is null.</p>
 
+		<h3>[property:Boolean fog]</h3>
+		<p>Whether the material is affected by fog. Default is *true*.</p>
+
 		<h3>[property:Texture lightMap]</h3>
 		<p>The light map. Default is null. The lightMap requires a second set of UVs.</p>
 

+ 3 - 0
docs/api/en/materials/MeshLambertMaterial.html

@@ -110,6 +110,9 @@
 		<h3>[property:Texture envMap]</h3>
 		<p>The environment map. Default is null.</p>
 
+		<h3>[property:Boolean fog]</h3>
+		<p>Whether the material is affected by fog. Default is *true*.</p>
+
 		<h3>[property:Texture lightMap]</h3>
 		<p>The light map. Default is null. The lightMap requires a second set of UVs.</p>
 

+ 3 - 0
docs/api/en/materials/MeshMatcapMaterial.html

@@ -100,6 +100,9 @@
 		Define whether the material is rendered with flat shading. Default is false.
 		</p>
 
+		<h3>[property:Boolean fog]</h3>
+		<p>Whether the material is affected by fog. Default is *true*.</p>
+
 		<h3>[property:Texture map]</h3>
 		<p>The color map. Default is null. The texture map color is modulated by the diffuse [page:.color].</p>
 

+ 3 - 0
docs/api/en/materials/MeshPhongMaterial.html

@@ -147,6 +147,9 @@
 		Define whether the material is rendered with flat shading. Default is false.
 		</p>
 
+		<h3>[property:Boolean fog]</h3>
+		<p>Whether the material is affected by fog. Default is *true*.</p>
+
 		<h3>[property:Texture lightMap]</h3>
 		<p>The light map. Default is null. The lightMap requires a second set of UVs.</p>
 

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

@@ -79,6 +79,16 @@
 		<h2>Properties</h2>
 		<p>See the base [page:Material] and [page:MeshStandardMaterial] classes for common properties.</p>
 
+		<h3>[property:Color attenuationColor]</h3>
+		<p>
+		The color that white light turns into due to absorption when reaching the attenuation distance. Default is *white* (0xffffff).
+		</p>
+
+		<h3>[property:Float attenuationDistance]</h3>
+		<p>
+		Density of the medium given as the average distance that light travels in the medium before interacting with a particle. The value is given in world space. Default is *0*.
+		</p>
+
 		<h3>[property:Float clearcoat]</h3>
 		<p>
 		Represents the intensity of the clear coat layer, from *0.0* to *1.0*. Use clear coat related properties to enable multilayer
@@ -180,6 +190,16 @@
 			The RGB channels of this texture are multiplied against [page:.specularColor], for per-pixel control over specular color. Default is *null*.
 		</p>
 
+		<h3>[property:Float thickness]</h3>
+		<p>
+		The thickness of the volume beneath the surface. The value is given in the coordinate space of the mesh. If the value is 0 the material is thin-walled. Otherwise the material is a volume boundary. Default is *0*.
+		</p>
+
+		<h3>[property:Texture thicknessMap]</h3>
+		<p>
+		A texture that defines the thickness, stored in the G channel. This will be multiplied by [page:.thickness]. Default is *null*.
+		</p>
+
 		<h3>[property:Float transmission]</h3>
 		<p>
 		Degree of transmission (or optical transparency), from *0.0* to *1.0*. Default is *0.0*.<br />

+ 3 - 0
docs/api/en/materials/MeshStandardMaterial.html

@@ -177,6 +177,9 @@
 		Define whether the material is rendered with flat shading. Default is false.
 		</p>
 
+		<h3>[property:Boolean fog]</h3>
+		<p>Whether the material is affected by fog. Default is *true*.</p>
+
 		<h3>[property:Boolean isMeshStandardMaterial]</h3>
 		<p>
 			Read-only flag to check if a given object is of type [name].

+ 3 - 0
docs/api/en/materials/MeshToonMaterial.html

@@ -120,6 +120,9 @@
 		<h3>[property:Float emissiveIntensity]</h3>
 		<p>Intensity of the emissive light. Modulates the emissive color. Default is 1.</p>
 
+		<h3>[property:Boolean fog]</h3>
+		<p>Whether the material is affected by fog. Default is *true*.</p>
+
 		<h3>[property:Texture gradientMap]</h3>
 		<p>Gradient map for toon shading. It's required to set [page:Texture.minFilter] and [page:Texture.magFilter] to
 			[page:Textures THREE.NearestFilter] when using this type of texture. Default is *null*.</p>

+ 4 - 1
docs/api/en/materials/PointsMaterial.html

@@ -81,11 +81,14 @@
 		<h3>[property:Color color]</h3>
 		<p>[page:Color] of the material, by default set to white (0xffffff).</p>
 
+		<h3>[property:Boolean fog]</h3>
+		<p>Whether the material is affected by fog. Default is *true*.</p>
+
 		<h3>[property:Texture map]</h3>
 		<p>Sets the color of the points using data from a [page:Texture].</p>
 
 		<h3>[property:Number size]</h3>
-		<p>Sets the size of the points. Default is 1.0.<br/>
+		<p>Defines the size of the points in pixels. Default is 1.0.<br/>
 			Will be capped if it exceeds the hardware dependent parameter [link:https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/getParameter gl.ALIASED_POINT_SIZE_RANGE].</p>
 
 		<h3>[property:Boolean sizeAttenuation]</h3>

+ 3 - 0
docs/api/en/materials/ShadowMaterial.html

@@ -51,6 +51,9 @@
 		<h3>[property:Color color]</h3>
 		<p>[page:Color] of the material, by default set to black (0x000000).</p>
 
+		<h3>[property:Boolean fog]</h3>
+		<p>Whether the material is affected by fog. Default is *true*.</p>
+
 		<h3>[property:Boolean transparent]</h3>
 		<p>Defines whether this material is transparent. Default is *true*.</p>
 

+ 3 - 0
docs/api/en/materials/SpriteMaterial.html

@@ -62,6 +62,9 @@
 		<h3>[property:Color color]</h3>
 		<p>[page:Color] of the material, by default set to white (0xffffff). The [page:.map] is multiplied by the color.</p>
 
+		<h3>[property:Boolean fog]</h3>
+		<p>Whether the material is affected by fog. Default is *true*.</p>
+
 		<h3>[property:Boolean isSpriteMaterial]</h3>
 		<p>
 			Read-only flag to check if a given object is of type [name].

+ 4 - 0
docs/api/en/math/Color.html

@@ -13,6 +13,10 @@
 		Class representing a color.
 		</p>
 
+		<p>
+		Iterating through a [name] instance will yield its components (r, g, b) in the corresponding order.
+		</p>
+
 		<h2>Code Examples</h2>
 
 		<p>

+ 4 - 0
docs/api/en/math/Euler.html

@@ -16,6 +16,10 @@
 			axes in specified amounts per axis, and a specified axis order.
 		</p>
 
+		<p>
+		Iterating through a [name] instance will yield its components (x, y, z, order) in the corresponding order.
+		</p>
+
 		<h2>Code Example</h2>
 
 		<code>const a = new THREE.Euler( 0, 1, 1.57, 'XYZ' );

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

@@ -202,7 +202,7 @@ zAxis = (c, g, k)
 		<h3>[method:this identity]()</h3>
 		<p>Resets this matrix to the [link:https://en.wikipedia.org/wiki/Identity_matrix identity matrix].</p>
 
-		<h3>[method:this lookAt]( [param:Vector3 eye], [param:Vector3 target], [param:Vector3 up], )</h3>
+		<h3>[method:this lookAt]( [param:Vector3 eye], [param:Vector3 target], [param:Vector3 up] )</h3>
 		<p>
 			Constructs a rotation matrix, looking from [page:Vector3 eye] towards [page:Vector3 target]
 			oriented by the [page:Vector3 up] vector.

+ 4 - 0
docs/api/en/math/Quaternion.html

@@ -14,6 +14,10 @@
 			Quaternions are used in three.js to represent [link:https://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation rotations].
 		</p>
 
+		<p>
+		Iterating through a [name] instance will yield its components (x, y, z, w) in the corresponding order.
+		</p>
+
 		<h2>Code Example</h2>
 
 		<code>

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

@@ -37,7 +37,7 @@
 		</p>
 
 		<p>
-			Iterating through a Vector2 instance will yield its components (x, y) in the corresponding order.
+			Iterating through a [name] instance will yield its components (x, y) in the corresponding order.
 		</p>
 
 		<h2>Code Example</h2>

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

@@ -36,7 +36,7 @@
 		</p>
 
 		<p>
-		Iterating through a Vector3 instance will yield its components (x, y, z) in the corresponding order.
+		Iterating through a [name] instance will yield its components (x, y, z) in the corresponding order.
 		</p>
 
 

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

@@ -35,7 +35,7 @@
 		</p>
 
 		<p>
-		Iterating through a Vector4 instance will yield its components (x, y, z, w) in the corresponding order.
+		Iterating through a [name] instance will yield its components (x, y, z, w) in the corresponding order.
 		</p>
 
 		<h2>Code Example</h2>

+ 3 - 1
docs/api/en/objects/SkinnedMesh.html

@@ -12,7 +12,9 @@
 		<h1>[name]</h1>
 
 		<p class="desc">
-			A mesh that has a [page:Skeleton] with [page:Bone bones] that can then be used to animate the vertices of the geometry.
+			A mesh that has a [page:Skeleton] with [page:Bone bones] that can then be used to animate the vertices of the geometry.<br /><br />
+
+			[name] can only be used with WebGL 2. With WebGL 1 *OES_texture_float* and vertex textures support is required.
 		</p>
 
 		<iframe id="scene" src="scenes/bones-browser.html"></iframe>

+ 2 - 1
docs/api/en/renderers/WebGLRenderTarget.html

@@ -41,7 +41,8 @@
 		[page:Number anisotropy] - default is *1*. See [page:Texture.anisotropy]<br />
 		[page:Constant encoding] - default is [page:Textures LinearEncoding]. <br />
 		[page:Boolean depthBuffer] - default is *true*. <br />
-		[page:Boolean stencilBuffer] - default is *false*.<br /><br />
+		[page:Boolean stencilBuffer] - default is *false*.<br />
+		[page:Number samples] - default is 0.<br /><br />
 
 		Creates a new [name]
 		</p>

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

@@ -429,7 +429,7 @@
 		<h3>[method:undefined setRenderTarget]( [param:WebGLRenderTarget renderTarget], [param:Integer activeCubeFace], [param:Integer activeMipmapLevel] )</h3>
 		<p>
 		renderTarget -- The [page:WebGLRenderTarget renderTarget] that needs to be activated. When *null* is given, the canvas is set as the active render target instead.<br />
-		activeCubeFace -- Specifies the active cube side (PX 0, NX 1, PY 2, NY 3, PZ 4, NZ 5) of [page:WebGLCubeRenderTarget] (optional).<br />
+		activeCubeFace -- Specifies the active cube side (PX 0, NX 1, PY 2, NY 3, PZ 4, NZ 5) of [page:WebGLCubeRenderTarget]. When passing a [page:WebGLArrayRenderTarget] or [page:WebGL3DRenderTarget] this indicates the z layer to render in to (optional).<br />
 		activeMipmapLevel -- Specifies the active mipmap level (optional).<br /><br />
 		This method sets the active rendertarget.
 		</p>

+ 7 - 0
docs/api/en/renderers/webxr/WebXRManager.html

@@ -112,6 +112,13 @@
 		Note: It is not possible to change the framebuffer scale factor while presenting XR content.
 		</p>
 
+		<h3>[method:undefined setReferenceSpace]( [param:XRReferenceSpace referenceSpace] )</h3>
+		<p>
+		[page:XRReferenceSpace referenceSpace] — A custom reference space.<br /><br />
+
+		Can be used to configure a custom reference space which overwrites the default reference space.
+		</p>
+
 		<h3>[method:undefined setReferenceSpaceType]( [param:String referenceSpaceType] )</h3>
 		<p>
 		[page:String referenceSpaceType] — The reference space type to set.<br /><br />

+ 1 - 1
docs/api/ko/core/BufferGeometry.html

@@ -209,7 +209,7 @@
 		기하학에 탄젠트 속성을 계산하고 추가합니다.<br />
 		이 계산은 인덱스가 있는 기하학에만 지원되며 위치, 법선, uv 속성이 정의되어야 합니다.
 		When using a tangent space normal map, prefer the MikkTSpace algorithm provided by
-		[page:BufferGeometryUtils.computeTangents] instead.
+		[page:BufferGeometryUtils.computeMikkTSpaceTangents] instead.
 		</p>
 
 		<h3>[method:undefined computeVertexNormals]()</h3>

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

@@ -203,7 +203,7 @@
 		<p>
 		Calculates and adds a tangent attribute to this geometry.<br />
 		The computation is only supported for indexed geometries and if position, normal, and uv attributes are defined. When using a tangent space normal map, prefer the MikkTSpace algorithm provided by
-		[page:BufferGeometryUtils.computeTangents] instead.
+		[page:BufferGeometryUtils.computeMikkTSpaceTangents] instead.
 		</p>
 
 		<h3>[method:undefined computeVertexNormals]()</h3>

+ 1 - 1
docs/api/zh/lights/shadows/DirectionalLightShadow.html

@@ -25,7 +25,7 @@
 		renderer.shadowMap.type = THREE.PCFSoftShadowMap; // default THREE.PCFShadowMap
 
 		//Create a DirectionalLight and turn on shadows for the light
-		const light = new THREE.DirectionalLight( 0xffffff, 1, 100 );
+		const light = new THREE.DirectionalLight( 0xffffff, 1 );
 		light.position.set( 0, 1, 0 ); //default; light shining from top
 		light.castShadow = true; // default false
 		scene.add( light );

+ 3 - 0
docs/api/zh/materials/LineBasicMaterial.html

@@ -58,6 +58,9 @@
 		<h3>[property:Color color]</h3>
 		<p>材质的颜色([page:Color]),默认值为白色 (0xffffff)。</p>
 
+		<h3>[property:Boolean fog]</h3>
+		<p>材质是否受雾影响。默认为*true*。</p>
+
 		<h3>[property:Float linewidth]</h3>
 		<p> 控制线宽。默认值为 *1*。<br /><br />
 			由于[link:https://www.khronos.org/registry/OpenGL/specs/gl/glspec46.core.pdf OpenGL Core Profile]与

+ 0 - 3
docs/api/zh/materials/Material.html

@@ -152,9 +152,6 @@
 当比较函数和深度检测都通过时要执行的模板操作,默认为[page:Materials KeepStencilOp],在模板操作[page:Materials constants] 中查看可用值。
 </p>
 
-<h3>[property:Boolean fog]</h3>
-<p>材质是否受雾影响。默认为*true*。</p>
-
 <h3>[property:Integer id]</h3>
 <p>此材质实例的唯一编号。</p>
 

+ 3 - 0
docs/api/zh/materials/MeshBasicMaterial.html

@@ -73,6 +73,9 @@
 		<h3>[property:Texture envMap]</h3>
 		<p>环境贴图。默认值为null。</p>
 
+		<h3>[property:Boolean fog]</h3>
+		<p>材质是否受雾影响。默认为*true*。</p>
+
 		<h3>[property:Texture lightMap]</h3>
 		<p>光照贴图。默认值为null。lightMap需要第二组UV。</p>
 

+ 0 - 3
docs/api/zh/materials/MeshDepthMaterial.html

@@ -67,9 +67,6 @@
 		<p> 位移贴图在网格顶点上的偏移量。如果没有设置位移贴图,则不会应用此值。默认值为0。
 		</p>
 
-		<h3>[property:Boolean fog]</h3>
-		<p> 材质是否受雾影响。默认值为*false*。</p>
-
 		<h3>[property:Texture map]</h3>
 		<p>颜色贴图。默认为null。</p>
 

+ 0 - 3
docs/api/zh/materials/MeshDistanceMaterial.html

@@ -78,9 +78,6 @@
 			The far value of the point light's internal shadow camera.
 		</p>
 
-		<h3>[property:Boolean fog]</h3>
-		<p> 材质是否受雾影响。默认值为*false*。</p>
-
 		<h3>[property:Texture map]</h3>
 		<p>颜色贴图。默认为null。</p>
 

+ 3 - 0
docs/api/zh/materials/MeshLambertMaterial.html

@@ -92,6 +92,9 @@
 		<h3>[property:Texture envMap]</h3>
 		<p> 环境贴图。默认值为null。</p>
 
+		<h3>[property:Boolean fog]</h3>
+		<p>材质是否受雾影响。默认为*true*。</p>
+
 		<h3>[property:Texture lightMap]</h3>
 		<p>光照贴图。默认值为null。lightMap需要第二组UV。</p>
 

+ 3 - 0
docs/api/zh/materials/MeshMatcapMaterial.html

@@ -84,6 +84,9 @@
 		<p> 定义材质是否使用平面着色进行渲染。默认值为false。
 		</p>
 
+		<h3>[property:Boolean fog]</h3>
+		<p>材质是否受雾影响。默认为*true*。</p>
+
 		<h3>[property:Texture map]</h3>
 		<p>颜色贴图。默认为null。纹理贴图颜色由漫反射颜色[page:.color]调节。</p>
 

+ 0 - 3
docs/api/zh/materials/MeshNormalMaterial.html

@@ -66,9 +66,6 @@
 		<p> 定义材质是否使用平面着色进行渲染。默认值为false。
 		</p>
 
-		<h3>[property:Boolean fog]</h3>
-		<p>材质是否受雾影响。默认值为*false*。</p>
-
 		<h3>[property:Texture normalMap]</h3>
 		<p> 用于创建法线贴图的纹理。RGB值会影响每个像素片段的曲面法线,并更改颜色照亮的方式。法线贴图不会改变曲面的实际形状,只会改变光照。
 			In case the material has a normal map authored using the left handed convention, the y component of normalScale

+ 3 - 0
docs/api/zh/materials/MeshPhongMaterial.html

@@ -116,6 +116,9 @@
 		<p> 定义材质是否使用平面着色进行渲染。默认值为false。
 		</p>
 
+		<h3>[property:Boolean fog]</h3>
+		<p>材质是否受雾影响。默认为*true*。</p>
+
 		<h3>[property:Texture lightMap]</h3>
 		<p>光照贴图。默认值为null。lightMap需要第二组UV。</p>
 

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

@@ -70,6 +70,16 @@
 		<h2>属性(Properties)</h2>
 		<p>共有属性请参见其基类[page:Material]和[page:MeshStandardMaterial]。</p>
 
+		<h3>[property:Color attenuationColor]</h3>
+		<p>
+		The color that white light turns into due to absorption when reaching the attenuation distance. Default is *white* (0xffffff).
+		</p>
+
+		<h3>[property:Float attenuationDistance]</h3>
+		<p>
+		Density of the medium given as the average distance that light travels in the medium before interacting with a particle. The value is given in world space. Default is *0*.
+		</p>
+
 		<h3>[property:Float clearcoat]</h3>
 		<p>
 		表示clear coat层的强度,范围从*0.0*到*1.0*m,当需要在表面加一层薄薄的半透明材质的时候,可以使用与clear coat相关的属性,默认为*0.0*;
@@ -165,6 +175,17 @@
 			此纹理的alpha通道将与[page:.specularColor]相乘,用于逐像素地控制高光颜色。默认值为*null*。
 		</p>
 
+		<h3>[property:Float thickness]</h3>
+		<p>
+		The thickness of the volume beneath the surface. The value is given in the coordinate space of the mesh. If the value is 0 the material is thin-walled. Otherwise the material is a volume boundary. Default is *0*.
+		</p>
+
+		<h3>[property:Texture thicknessMap]</h3>
+		<p>
+		A texture that defines the thickness, stored in the G channel. This will be multiplied by [page:.thickness]. Default is *null*.
+		</p>
+
+
 		<h3>[property:Float transmission]</h3>
 		<p>
 		透光率(或者说透光性),范围从*0.0*到*1.0*。默认值是*0.0*。<br />

+ 3 - 0
docs/api/zh/materials/MeshStandardMaterial.html

@@ -144,6 +144,9 @@
 		<p> 定义材质是否使用平面着色进行渲染。默认值为false。
 		</p>
 
+		<h3>[property:Boolean fog]</h3>
+		<p>材质是否受雾影响。默认为*true*。</p>
+
 		<h3>[property:Boolean isMeshStandardMaterial]</h3>
 		<p>
 			检查当前对象是否为标准网格材质的标记。

+ 3 - 0
docs/api/zh/materials/MeshToonMaterial.html

@@ -120,6 +120,9 @@
 		<h3>[property:Float emissiveIntensity]</h3>
 		<p>Intensity of the emissive light. Modulates the emissive color. Default is 1.</p>
 
+		<h3>[property:Boolean fog]</h3>
+		<p>材质是否受雾影响。默认为*true*。</p>
+
 		<h3>[property:Texture gradientMap]</h3>
 		<p>Gradient map for toon shading. It's required to set [page:Texture.minFilter] and [page:Texture.magFilter] to
 			[page:Textures THREE.NearestFilter] when using this type of texture. Default is *null*.</p>

+ 3 - 1
docs/api/zh/materials/PointsMaterial.html

@@ -78,8 +78,10 @@
 		<h3>[property:Color color]</h3>
 		<p>材质的颜色([page:Color]),默认值为白色 (0xffffff)。</p>
 
-		<h3>[property:Texture map]</h3>
+		<h3>[property:Boolean fog]</h3>
+		<p>材质是否受雾影响。默认为*true*。</p>
 
+		<h3>[property:Texture map]</h3>
 		<p>使用[page:Texture]中的数据设置点的颜色。</p>
 
 		<h3>[property:Number size]</h3>

+ 3 - 0
docs/api/zh/materials/ShadowMaterial.html

@@ -50,6 +50,9 @@
 		<h3>[property:Color color]</h3>
 		<p>[page:Color] of the material, by default set to black (0x000000).</p>
 
+		<h3>[property:Boolean fog]</h3>
+		<p>材质是否受雾影响。默认为*true*。</p>
+
 		<h3>[property:Boolean transparent]</h3>
 		<p>定义此材质是否透明。默认值为 *true*。</p>
 

+ 3 - 0
docs/api/zh/materials/SpriteMaterial.html

@@ -60,6 +60,9 @@
 		<h3>[property:Color color]</h3>
 		<p>材质的颜色([page:Color]),默认值为白色 (0xffffff)。 [page:.map]会和 color 相乘。</p>
 
+		<h3>[property:Boolean fog]</h3>
+		<p>材质是否受雾影响。默认为*true*。</p>
+
 		<h3>[property:Boolean isSpriteMaterial]</h3>
 		<p>
 			Read-only flag to check if a given object is of type [name].

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

@@ -187,7 +187,7 @@ zAxis = (c, g, k)
 		<h3>[method:this identity]()</h3>
 		<p>将当前矩阵重置为单位矩阵[link:https://en.wikipedia.org/wiki/Identity_matrix identity matrix]。</p>
 
-		<h3>[method:this lookAt]( [param:Vector3 eye], [param:Vector3 target], [param:Vector3 up], )</h3>
+		<h3>[method:this lookAt]( [param:Vector3 eye], [param:Vector3 target], [param:Vector3 up] )</h3>
 		<p>
 			构造一个旋转矩阵,从[page:Vector3 eye] 指向 [page:Vector3 target],由向量 [page:Vector3 up] 定向。
 		</p>

+ 3 - 1
docs/api/zh/objects/SkinnedMesh.html

@@ -12,7 +12,9 @@
 		<h1>蒙皮网格([name])</h1>
 
 		<p class="desc">
-			具有[page:Skeleton](骨架)和[page:Bone bones](骨骼)的网格,可用于给几何体上的顶点添加动画。
+			具有[page:Skeleton](骨架)和[page:Bone bones](骨骼)的网格,可用于给几何体上的顶点添加动画。<br /><br />
+
+			[name] can only be used with WebGL 2. With WebGL 1 *OES_texture_float* and vertex textures support is required.
 		</p>
 
 		<iframe id="scene" src="scenes/bones-browser.html"></iframe>

+ 1 - 1
docs/api/zh/renderers/WebGLRenderer.html

@@ -368,7 +368,7 @@
 		<h3>[method:undefined setRenderTarget]( [param:WebGLRenderTarget renderTarget], [param:Integer activeCubeFace], [param:Integer activeMipmapLevel] )</h3>
 		<p>
 		renderTarget -- 需要被激活的[page:WebGLRenderTarget renderTarget](可选)。若此参数为空,则将canvas设置成活跃render target。<br />
-		activeCubeFace -- Specifies the active cube side (PX 0, NX 1, PY 2, NY 3, PZ 4, NZ 5) of [page:WebGLCubeRenderTarget] (optional).<br />
+		activeCubeFace -- Specifies the active cube side (PX 0, NX 1, PY 2, NY 3, PZ 4, NZ 5) of [page:WebGLCubeRenderTarget]. When passing a [page:WebGLArrayRenderTarget] or [page:WebGL3DRenderTarget] this indicates the z layer to render in to (optional).<br />
 		activeMipmapLevel -- Specifies the active mipmap level (optional).<br /><br />
 		该方法设置活跃rendertarget。
 		</p>

+ 7 - 0
docs/api/zh/renderers/webxr/WebXRManager.html

@@ -100,6 +100,13 @@
 		Note: It is not possible to change the framebuffer scale factor while presenting XR content.
 		</p>
 
+		<h3>[method:undefined setReferenceSpace]( [param:XRReferenceSpace referenceSpace] )</h3>
+		<p>
+		[page:XRReferenceSpace referenceSpace] — A custom reference space.<br /><br />
+
+		Can be used to configure a custom reference space which overwrites the default reference space.
+		</p>
+
 		<h3>[method:undefined setReferenceSpaceType]( [param:String referenceSpaceType] )</h3>
 		<p>
 		[page:String referenceSpaceType] — The reference space type to set.<br /><br />

+ 75 - 12
docs/examples/en/animations/CCDIKSolver.html

@@ -11,31 +11,94 @@
 
 		<p class="desc"> A solver for IK with <a href="https://sites.google.com/site/auraliusproject/ccd-algorithm"><em>CCD Algorithm</em></a>. <br /><br />
 		[name] solves Inverse Kinematics Problem with CCD Algorithm.
-		[name] is designed to work with [page:SkinnedMesh] loaded by [page:MMDLoader] but also can be used for generic [page:SkinnedMesh].
+		[name] is designed to work with [page:SkinnedMesh] but also can be used with [page:MMDLoader] or [page:GLTFLoader] skeleton.
 		</p>
 
+		<iframe id="scene" src="scenes/ccdiksolver-browser.html"></iframe>
+
 		<h2>Code Example</h2>
 
 		<code>
 		let ikSolver;
 
-		// Load MMD resources and instantiate CCDIKSolver
-		new MMDLoader().load(
-			'models/mmd/miku.pmd',
-			function ( mesh ) {
+		//
+		// Bones hierarchy:
+		//
+		//   root
+		//     ├── bone0
+		//     │    └── bone1
+		//     │          └── bone2
+		//     │                └── bone3
+		//     └── target
+		//
+		// Positioned as follow on the cylinder:
+		//
+		//        o      <- target      (y =  20)
+		//        
+		//   +----o----+ <- bone3       (y =  12)
+		//   |         |
+		//   |    o    | <- bone2       (y =   4)
+		//   |         |
+		//   |    o    | <- bone1       (y =  -4)
+		//   |         |
+		//   +----oo---+ <- root, bone0 (y = -12)
+		//
+
+		let bones = []
+
+		// "root"
+		let rootBone = new Bone();
+		rootBone.position.y = -12;
+		bones.push( rootBone );
+
+		// "bone0"
+		let prevBone = new Bone();
+		prevBone.position.y = 0;
+		rootBone.add( prevBone );
+		bones.push( prevBone );
+
+		// "bone1", "bone2", "bone3"
+		for ( let i = 1; i <= 3; i ++ ) {
+			const bone = new Bone();
+			bone.position.y = 8;
+			bones.push( bone );
+			
+			prevBone.add( bone );
+			prevBone = bone;
+		}
+
+		// "target"
+		const targetBone = new Bone();
+		targetBone.position.y = 24 + 8
+		rootBone.add( targetBone );
+		bones.push( targetBone );
+
+		//
+		// skinned mesh
+		//
 
-				ikSolver = new CCDIKSolver( mesh, mesh.geometry.iks );
-				scene.add( mesh );
+		const mesh = new SkinnedMesh( geometry,	material );
+		const skeleton = new Skeleton( bones );
 
+		mesh.add( bones[ 0 ] ); // "root" bone
+		mesh.bind( skeleton );
+
+		//
+		// ikSolver
+		//
+
+		const iks = [
+			{
+				target: 5, // "target"
+				effector: 4, // "bone3"
+				links: [ { index: 3 }, { index: 2 }, { index: 1 } ] // "bone2", "bone1", "bone0"
 			}
-		);
+		];
+		ikSolver = new CCDIKSolver( mesh, iks );
 
 		function render() {
-
-			animate(); // update bones
-			if ( ikSolver !== undefined ) ikSolver.update();
+			ikSolver?.update();
 			renderer.render( scene, camera );
-
 		}
 		</code>
 

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

@@ -74,7 +74,7 @@
 		[page:Function onProgress] — Will be called while load progresses. The argument will be the XMLHttpRequest instance, which contains .[page:Integer total] and .[page:Integer loaded] bytes. If the server does not set the Content-Length header; .[page:Integer total] will be 0.<br />
 		[page:Function onError] — Will be called when load errors.<br /><br />
 
-		Begin loading from url and pass the loaded [page:Texture texture] to onLoad.
+		Begin loading from url and pass the loaded font to onLoad.
 		</p>
 
 		<h3>[method:Font parse]( [param:Object json] )</h3>

+ 5 - 0
docs/examples/en/loaders/GLTFLoader.html

@@ -20,6 +20,11 @@
 		textures, skins, skeletons, morph targets, animations, lights, and/or cameras.
 		</p>
 
+		<p>
+			[name] uses [page:ImageBitmapLoader] whenever possible. Be advised that image bitmaps are not automatically GC-collected when they are no longer referenced,
+			and they require special handling during the disposal process. More information in the [link:https://threejs.org/docs/#manual/en/introduction/How-to-dispose-of-objects How to dispose of objects] guide.
+		</p>
+
 		<h2>Extensions</h2>
 
 		<p>

+ 8 - 6
docs/examples/en/utils/BufferGeometryUtils.html

@@ -96,10 +96,12 @@
 
 		</p>
 
-		<h3>[method:Object computeTangents]( [param:BufferGeometry geometry] )</h3>
-		<p>
-		geometry -- Instance of [page:BufferGeometry].
-		</p>
+		<h3>[method:Object computeMikkTSpaceTangents]( [param:BufferGeometry geometry], [param:Object MikkTSpace], [param:Boolean negateSign] = true )</h3>
+		<ul>
+			<li>geometry -- Instance of [page:BufferGeometry].</li>
+			<li>MikkTSpace -- Instance of <i>examples/jsm/libs/mikktspace.module.js</i>, or <i>mikktspace</i> npm package. Await <i>MikkTSpace.ready</i> before use.
+			<li>negateSign -- Whether to negate the sign component (.w) of each tangent. Required for normal map conventions in some formats, including glTF.</li>
+		</ul>
 
 		<p>
 		Computes vertex tangents using the [link:http://www.mikktspace.com/ MikkTSpace] algorithm.
@@ -110,8 +112,8 @@
 		</p>
 
 		<p>
-		In comparison to [page:BufferGeometryUtils.computeTangents], [page:BufferGeometry.computeTangents]
-		(a custom algorithm) generates tangents that probably will not match the tangents
+		In comparison to this method, [page:BufferGeometry.computeTangents] (a
+		custom algorithm) generates tangents that probably will not match the tangents
 		in other software. The custom algorithm is sufficient for general use with a
 		[page:ShaderMaterial], and may be faster than MikkTSpace.
 		</p>

+ 77 - 14
docs/examples/zh/animations/CCDIKSolver.html

@@ -11,31 +11,94 @@
 
 		<p class="desc"> A solver for IK with <a href="https://sites.google.com/site/auraliusproject/ccd-algorithm"><em>CCD Algorithm</em></a>. <br /><br />
 		[name] solves Inverse Kinematics Problem with CCD Algorithm.
-		[name] is designed to work with [page:SkinnedMesh] loaded by [page:MMDLoader] but also can be used for generic [page:SkinnedMesh].
+		[name] is designed to work with [page:SkinnedMesh] but also can be used with [page:MMDLoader] or [page:GLTFLoader] skeleton.
 		</p>
 
+		<iframe id="scene" src="scenes/ccdiksolver-browser.html"></iframe>
+
 		<h2>代码示例</h2>
 
 		<code>
-		const ikSolver;
+		let ikSolver;
+
+		//
+		// Bones hierarchy:
+		//
+		//   root
+		//     ├── bone0
+		//     │    └── bone1
+		//     │          └── bone2
+		//     │                └── bone3
+		//     └── target
+		//
+		// Positioned as follow on the cylinder:
+		//
+		//        o      <- target      (y =  20)
+		//        
+		//   +----o----+ <- bone3       (y =  12)
+		//   |         |
+		//   |    o    | <- bone2       (y =   4)
+		//   |         |
+		//   |    o    | <- bone1       (y =  -4)
+		//   |         |
+		//   +----oo---+ <- root, bone0 (y = -12)
+		//
+
+		let bones = []
+
+		// "root"
+		let rootBone = new Bone();
+		rootBone.position.y = -12;
+		bones.push( rootBone );
+
+		// "bone0"
+		let prevBone = new Bone();
+		prevBone.position.y = 0;
+		rootBone.add( prevBone );
+		bones.push( prevBone );
+
+		// "bone1", "bone2", "bone3"
+		for ( let i = 1; i <= 3; i ++ ) {
+			const bone = new Bone();
+			bone.position.y = 8;
+			bones.push( bone );
+			
+			prevBone.add( bone );
+			prevBone = bone;
+		}
+
+		// "target"
+		const targetBone = new Bone();
+		targetBone.position.y = 24 + 8
+		rootBone.add( targetBone );
+		bones.push( targetBone );
+
+		//
+		// skinned mesh
+		//
 
-		// Load MMD resources and instantiate CCDIKSolver
-		new MMDLoader().load(
-			'models/mmd/miku.pmd',
-			function ( mesh ) {
+		const mesh = new SkinnedMesh( geometry,	material );
+		const skeleton = new Skeleton( bones );
 
-				ikSolver = new CCDIKSolver( mesh, mesh.geometry.iks );
-				scene.add( mesh );
+		mesh.add( bones[ 0 ] ); // "root" bone
+		mesh.bind( skeleton );
 
+		//
+		// ikSolver
+		//
+
+		const iks = [
+			{
+				target: 5, // "target"
+				effector: 4, // "bone3"
+				links: [ { index: 3 }, { index: 2 }, { index: 1 } ] // "bone2", "bone1", "bone0"
 			}
-		);
+		];
+		ikSolver = new CCDIKSolver( mesh, iks );
 
 		function render() {
-
-			animate(); // update bones
-			if ( ikSolver !== undefined ) ikSolver.update();
+			ikSolver?.update();
 			renderer.render( scene, camera );
-
 		}
 		</code>
 
@@ -92,7 +155,7 @@
 
 		<h3>[method:this update]()</h3>
 		<p>
-		Update bones quaternion by solving CCD algorithm.
+		Update IK bones quaternion by solving CCD algorithm.
 		</p>
 
 		<h3>[method:this updateOne]( [param:Object ikParam] )</h3>

+ 9 - 9
docs/examples/zh/loaders/FontLoader.html

@@ -12,10 +12,10 @@
 		<h1>[name]</h1>
 
 		<p class="desc">
-		使用JSON格式中加载字体的一个类。返回font, 返回值是表示字体的[page:Shape Shape]类型的数组。
+		一个用于加载JSON格式的字体的类。。返回font, 返回值是表示字体的[page:Shape Shape]类型的数组。
 		其内部使用[page:FileLoader]来加载文件。 <br /><br />
 
-		你可以使用[link:https://gero3.github.io/facetype.js/ facetype.js]在线转换字体。
+		你可以使用[link:https://gero3.github.io/facetype.js/ facetype.js]在线转换字体。
 		</p>
 
 		<h2>代码示例</h2>
@@ -68,18 +68,18 @@
 		<h3>[method:undefined load]( [param:String url], [param:Function onLoad], [param:Function onProgress], [param:Function onError] )</h3>
 		<p>
 		[page:String url] — 文件的URL或者路径,也可以为
-			[link:https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs Data URI].<br />
-		[page:Function onLoad] — 加载完成时将调用。回调参数是将要被加载的[page:Texture texture].<br />
-		[page:Function onProgress] — 将在加载过程中进行调用。参数为XMLHttpRequest实例,实例包含[page:Integer total]和[page:Integer loaded]字节。<br />
-		[page:Function onError] — 在加载错误时调用。<br /><br />
+			[link:https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs Data URI]<br />
+		[page:Function onLoad] — 将在加载完成时调用。参数是将要被加载的font。<br />
+		[page:Function onProgress] — 将在加载过程中调用。参数是包含[page:Integer total]和[page:Integer loaded]字节的XMLHttpRequest实例。如果server没有设置header的Content-Length,则[page:Integer total]值为0。<br />
+		[page:Function onError] — 在加载错误时调用。<br /><br />
 
-			从URL中进行加载,并将被加载的[page:Texture texture]传递给onLoad。
+		开始加载url,并将加载的font传递给onLoad。
 		</p>
 
 		<h3>[method:Font parse]( [param:Object json] )</h3>
 		<p>
-		[page:Object json] — The <em>JSON</em> structure to parse.<br /><br />
-		以<em>JSON</em>格式进行解析,并返回一个font.
+		[page:Object json] — 用于解析的<em>JSON</em>>格式的对象。<br /><br />
+		解析一个<em>JSON</em>>格式的对象,并返回一个font。
 		</p>
 
 		<h2>源</h2>

+ 5 - 0
docs/examples/zh/loaders/GLTFLoader.html

@@ -19,6 +19,11 @@
 		包括网格、材质、贴图、蒙皮、骨架、变形目标、动画、灯光以及摄像机。
 		</p>
 
+		<p>
+			[name] uses [page:ImageBitmapLoader] whenever possible. Be advised that image bitmaps are not automatically GC-collected when they are no longer referenced,
+			and they require special handling during the disposal process. More information in the [link:https://threejs.org/docs/#manual/en/introduction/How-to-dispose-of-objects How to dispose of objects] guide.
+		</p>
+
 		<h2>扩展</h2>
 
 		<p>

+ 8 - 6
docs/examples/zh/utils/BufferGeometryUtils.html

@@ -91,10 +91,12 @@
 
 		</p>
 
-		<h3>[method:Object computeTangents]( [param:BufferGeometry geometry] )</h3>
-		<p>
-		geometry -- Instance of [page:BufferGeometry].
-		</p>
+		<h3>[method:Object computeMikkTSpaceTangents]( [param:BufferGeometry geometry], [param:Object MikkTSpace], [param:Boolean negateSign] = true )</h3>
+		<ul>
+			<li>geometry -- Instance of [page:BufferGeometry].</li>
+			<li>MikkTSpace -- Instance of <i>examples/jsm/libs/mikktspace.module.js</i>, or <i>mikktspace</i> npm package. Await <i>MikkTSpace.ready</i> before use.
+			<li>negateSign -- Whether to negate the sign component (.w) of each tangent. Required for normal map conventions in some formats, including glTF.</li>
+		</ul>
 
 		<p>
 		Computes vertex tangents using the [link:http://www.mikktspace.com/ MikkTSpace] algorithm.
@@ -105,8 +107,8 @@
 		</p>
 
 		<p>
-		In comparison to [page:BufferGeometryUtils.computeTangents], [page:BufferGeometry.computeTangents]
-		(a custom algorithm) generates tangents that probably will not match the tangents
+		In comparison to this method, [page:BufferGeometry.computeTangents] (a
+		custom algorithm) generates tangents that probably will not match the tangents
 		in other software. The custom algorithm is sufficient for general use with a
 		[page:ShaderMaterial], and may be faster than MikkTSpace.
 		</p>

+ 1 - 1
docs/index.html

@@ -335,7 +335,7 @@
 
 		}
 
-		// Auto change language url. If a reader open a document in English, when he click "zh", the document he read will auto change into Chinese version
+		// Auto change language url. If a reader open a document in English, when they click "zh", the document they read will auto change into Chinese version
 
 		function autoChangeUrlLanguage( language ) {
 

+ 2 - 2
docs/list.json

@@ -12,7 +12,6 @@
 				"Drawing lines": "manual/en/introduction/Drawing-lines",
 				"Creating text": "manual/en/introduction/Creating-text",
 				"Loading 3D models": "manual/en/introduction/Loading-3D-models",
-				"Color management": "manual/en/introduction/Color-management",
 				"Libraries and Plugins": "manual/en/introduction/Libraries-and-Plugins",
 				"FAQ": "manual/en/introduction/FAQ",
 				"Useful links": "manual/en/introduction/Useful-links"
@@ -24,7 +23,8 @@
 				"How to create VR content": "manual/en/introduction/How-to-create-VR-content",
 				"How to use post-processing": "manual/en/introduction/How-to-use-post-processing",
 				"Matrix transformations": "manual/en/introduction/Matrix-transformations",
-				"Animation system": "manual/en/introduction/Animation-system"
+				"Animation system": "manual/en/introduction/Animation-system",
+				"Color management": "manual/en/introduction/Color-management"
 			},
 
 			"Build Tools": {

+ 5 - 0
docs/manual/ar/introduction/How-to-dispose-of-objects.html

@@ -37,6 +37,11 @@
 			على غرار المخازن المؤقتة ، لا يمكن حذف هذا الكائن إلا عن طريق استدعاء [page:Texture.dispose]().
 		</p>
 
+		<p>
+			If you use an *ImageBitmap* as the texture's data source, you have to call [link:https://developer.mozilla.org/en-US/docs/Web/API/ImageBitmap/close ImageBitmap.close]() at the application level to dispose of all CPU-side resources.
+			An automated call of *ImageBitmap.close()* in [page:Texture.dispose]() is not possible, since the image bitmap becomes unusable, and the engine has no way of knowing if the image bitmap is used elsewhere.
+		</p>
+
 		<h2>أهداف العرض</h2>
 
 		<p>

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

@@ -34,7 +34,7 @@
 		</p>
 
 		<code>
-		npm install --save three
+		npm install three
 		</code>
 
 		<p>

+ 1 - 1
docs/manual/en/introduction/Color-management.html

@@ -79,7 +79,7 @@
 			capabilities of available display devices. Colors are expressed as a ratio of the primary colors.
 		</li>
 		<li>
-			<b>White point:</b> Most color spaces are engineed such that an equally weighted sum of
+			<b>White point:</b> Most color spaces are engineered such that an equally weighted sum of
 			primaries <i>R = G = B</i> will appear to be without color, or "achromatic". The appearance
 			of achromatic values (like white or grey) depend on human perception, which in turn depends
 			heavily on the context of the observer. A color space specifies its "white point" to balance

+ 5 - 0
docs/manual/en/introduction/How-to-dispose-of-objects.html

@@ -44,6 +44,11 @@
 		Similar to buffers, this object can only be deleted by calling [page:Texture.dispose]().
 	</p>
 
+	<p>
+		If you use an *ImageBitmap* as the texture's data source, you have to call [link:https://developer.mozilla.org/en-US/docs/Web/API/ImageBitmap/close ImageBitmap.close]() at the application level to dispose of all CPU-side resources.
+		An automated call of *ImageBitmap.close()* in [page:Texture.dispose]() is not possible, since the image bitmap becomes unusable, and the engine has no way of knowing if the image bitmap is used elsewhere.
+	</p>
+
 	<h2>Render Targets</h2>
 
 	<p>

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

@@ -28,7 +28,7 @@
 		</p>
 
 		<code>
-		npm install --save three
+		npm install three
 		</code>
 
 		<p>

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

@@ -41,6 +41,12 @@
 			<li>[link:https://github.com/gkjohnson/three-mesh-bvh three-mesh-bvh]</li>
 		</ul>
 
+		<h3>Path Tracing</h3>
+		
+		<ul>
+			<li>[link:https://github.com/gkjohnson/three-gpu-pathtracer three-gpu-pathtracer]</li>
+		</ul>
+		
 		<h3>File Formats</h3>
 
 		<p>
@@ -79,6 +85,7 @@
 		<ul>
 			<li>[link:https://github.com/jsantell/THREE.IK THREE.IK]</li>
 			<li>[link:https://github.com/lo-th/fullik fullik]</li>
+			<li>[link:https://github.com/gkjohnson/closed-chain-ik-js closed-chain-ik]</li>
 		</ul>
 
 		<h3>Game AI</h3>

+ 3 - 0
docs/manual/en/introduction/Useful-links.html

@@ -42,6 +42,9 @@
 
 		<h3>More extensive / advanced articles and courses</h3>
 		<ul>
+			<li>
+				[link:https://threejs-journey.com/ Three Journey] Course by [link:https://bruno-simon.com/ Bruno Simon] - Teaches beginners how to use Three.js step by step
+			</li>
 			<li>
 				[link:https://discoverthreejs.com/ Discover three.js]
 			</li>

+ 6 - 1
docs/manual/ja/introduction/How-to-dispose-of-objects.html

@@ -50,6 +50,11 @@
 		バッファと同様に、このオブジェクトは[page:Texture.dispose]()を呼ぶことでしか削除できません。
 	</p>
 
+	<p>
+		If you use an *ImageBitmap* as the texture's data source, you have to call [link:https://developer.mozilla.org/en-US/docs/Web/API/ImageBitmap/close ImageBitmap.close]() at the application level to dispose of all CPU-side resources.
+		An automated call of *ImageBitmap.close()* in [page:Texture.dispose]() is not possible, since the image bitmap becomes unusable, and the engine has no way of knowing if the image bitmap is used elsewhere.
+	</p>
+
 	<h2>Render Targets</h2>
 
 	<p>
@@ -127,4 +132,4 @@
 
 </body>
 
-</html>
+</html>

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

@@ -30,7 +30,7 @@
     </p>
 
     <code>
-		npm install --save three
+		npm install three
 		</code>
 
     <p>

+ 6 - 1
docs/manual/ko/introduction/How-to-dispose-of-objects.html

@@ -42,6 +42,11 @@
         buffer와 비슷하게, 이 오브젝트는 [page:Texture.dispose]() 호출로만 삭제가 가능합니다.
 	</p>
 
+	<p>
+        If you use an *ImageBitmap* as the texture's data source, you have to call [link:https://developer.mozilla.org/en-US/docs/Web/API/ImageBitmap/close ImageBitmap.close]() at the application level to dispose of all CPU-side resources.
+        An automated call of *ImageBitmap.close()* in [page:Texture.dispose]() is not possible, since the image bitmap becomes unusable, and the engine has no way of knowing if the image bitmap is used elsewhere.
+	</p>
+
 	<h2>렌더링 대상</h2>
 
 	<p>
@@ -112,4 +117,4 @@
 
 </body>
 
-</html>
+</html>

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

@@ -32,7 +32,7 @@
     </p>
 
     <code>
-		npm install --save three
+		npm install three
 		</code>
 
     <p>

+ 5 - 0
docs/manual/zh/introduction/How-to-dispose-of-objects.html

@@ -44,6 +44,11 @@
 		和buffer相似,该对象只能通过调用[page:Texture.dispose]()来删除。
 	</p>
 
+	<p>
+		If you use an *ImageBitmap* as the texture's data source, you have to call [link:https://developer.mozilla.org/en-US/docs/Web/API/ImageBitmap/close ImageBitmap.close]() at the application level to dispose of all CPU-side resources.
+		An automated call of *ImageBitmap.close()* in [page:Texture.dispose]() is not possible, since the image bitmap becomes unusable, and the engine has no way of knowing if the image bitmap is used elsewhere.
+	</p>
+
 	<h2>渲染目标</h2>
 
 	<p>

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

@@ -28,7 +28,7 @@
 		</p>
 
 		<code>
-		npm install --save three
+		npm install three
 		</code>
 
 		<p>

+ 286 - 0
docs/scenes/ccdiksolver-browser.html

@@ -0,0 +1,286 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<meta charset="utf-8">
+		<title>Three.js CCDIKSolver Browser</title>
+		<link rel="shortcut icon" href="../../files/favicon.ico" />
+		<link rel="stylesheet" type="text/css" href="../../files/main.css">
+		<style>
+			canvas {
+				display: block;
+				width: 100%;
+				height: 100%;
+			}
+
+			#newWindow {
+				display: block;
+				position: absolute;
+				bottom: 0.3em;
+				left: 0.5em;
+				color: #fff;
+			}
+		</style>
+	</head>
+	<body>
+
+		<!-- Import maps polyfill -->
+		<!-- Remove this when import maps will be widely supported -->
+		<script async src="https://unpkg.com/[email protected]/dist/es-module-shims.js"></script>
+
+		<script type="importmap">
+			{
+				"imports": {
+					"three": "../../build/three.module.js"
+				}
+			}
+		</script>
+
+		<a id='newWindow' href='./ccdiksolver-browser.html' target='_blank'>Open in New Window</a>
+
+		<script type="module">
+			//
+			// Forked from /docs/api/en/objects/SkinnedMesh example
+			//
+
+			import {
+				Bone,
+				Color,
+				CylinderGeometry,
+				DoubleSide,
+				Float32BufferAttribute,
+				MeshPhongMaterial,
+				PerspectiveCamera,
+				PointLight,
+				Scene,
+				SkinnedMesh,
+				Skeleton,
+				SkeletonHelper,
+				Vector3,
+				Uint16BufferAttribute,
+				WebGLRenderer
+			} from 'three';
+			import { CCDIKSolver, CCDIKHelper } from "../../examples/jsm/animation/CCDIKSolver.js";
+
+			import { GUI } from '../../examples/jsm/libs/lil-gui.module.min.js';
+			import { OrbitControls } from '../../examples/jsm/controls/OrbitControls.js';
+
+			let gui, scene, camera, renderer, orbit, mesh, bones, skeletonHelper, ikSolver;
+
+			const state = {
+				ikSolverAutoUpdate: true
+			};
+
+			function initScene() {
+
+				gui = new GUI();
+
+				scene = new Scene();
+				scene.background = new Color( 0x444444 );
+
+				camera = new PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 200 );
+				camera.position.z = 30;
+				camera.position.y = 30;
+
+				renderer = new WebGLRenderer( { antialias: true } );
+				renderer.setPixelRatio( window.devicePixelRatio );
+				renderer.setSize( window.innerWidth, window.innerHeight );
+				document.body.appendChild( renderer.domElement );
+
+				orbit = new OrbitControls( camera, renderer.domElement );
+				orbit.enableZoom = false;
+
+				window.addEventListener( 'resize', function () {
+
+					camera.aspect = window.innerWidth / window.innerHeight;
+					camera.updateProjectionMatrix();
+
+					renderer.setSize( window.innerWidth, window.innerHeight );
+
+				}, false );
+
+				initBones();
+				setupDatGui();
+
+			}
+
+			function createGeometry( sizing ) {
+
+				const geometry = new CylinderGeometry(
+					5, // radiusTop
+					5, // radiusBottom
+					sizing.height, // height
+					8, // radiusSegments
+					sizing.segmentCount * 1, // heightSegments
+					true // openEnded
+				);
+
+				const position = geometry.attributes.position;
+
+				const vertex = new Vector3();
+
+				const skinIndices = [];
+				const skinWeights = [];
+
+				for ( let i = 0; i < position.count; i ++ ) {
+
+					vertex.fromBufferAttribute( position, i );
+
+					const y = ( vertex.y + sizing.halfHeight );
+
+					const skinIndex = Math.floor( y / sizing.segmentHeight );
+					const skinWeight = ( y % sizing.segmentHeight ) / sizing.segmentHeight;
+
+					skinIndices.push( skinIndex, skinIndex + 1, 0, 0 );
+					skinWeights.push( 1 - skinWeight, skinWeight, 0, 0 );
+
+				}
+
+				geometry.setAttribute( 'skinIndex', new Uint16BufferAttribute( skinIndices, 4 ) );
+				geometry.setAttribute( 'skinWeight', new Float32BufferAttribute( skinWeights, 4 ) );
+
+				return geometry;
+
+			}
+
+			function createBones( sizing ) {
+
+				bones = [];
+
+				// "root bone"
+				let rootBone = new Bone();
+				rootBone.name = "root";
+				rootBone.position.y = -sizing.halfHeight;
+				bones.push( rootBone );
+
+				//
+				// "bone0", "bone1", "bone2", "bone3"
+				//
+
+				// "bone0"
+				let prevBone = new Bone();
+				prevBone.position.y = 0;
+				rootBone.add(prevBone);
+				bones.push( prevBone );
+
+				// "bone1", "bone2", "bone3"
+				for ( let i = 1; i <= sizing.segmentCount; i ++ ) {
+
+					const bone = new Bone();
+					bone.position.y = sizing.segmentHeight;
+					bones.push( bone );
+					bone.name = `bone${i}`;
+					prevBone.add( bone );
+					prevBone = bone;
+
+				}
+
+				// "target"
+				const targetBone = new Bone();
+				targetBone.name = "target";
+				targetBone.position.y = sizing.height + sizing.segmentHeight; // relative to parent: rootBone
+				rootBone.add( targetBone );
+				bones.push( targetBone );
+
+				return bones;
+
+			}
+
+			function createMesh( geometry, bones ) {
+
+				const material = new MeshPhongMaterial( {
+					color: 0x156289,
+					emissive: 0x072534,
+					side: DoubleSide,
+					flatShading: true,
+					wireframe: true
+				} );
+
+				const mesh = new SkinnedMesh( geometry,	material );
+				const skeleton = new Skeleton( bones );
+
+				mesh.add( bones[ 0 ] );
+
+				mesh.bind( skeleton );
+
+				skeletonHelper = new SkeletonHelper( mesh );
+				skeletonHelper.material.linewidth = 2;
+				scene.add( skeletonHelper );
+
+				return mesh;
+
+			}
+
+			function setupDatGui() {
+
+				gui.add( mesh, 'pose' ).name( 'mesh.pose()' );
+
+				mesh.skeleton.bones
+					.filter((bone) => bone.name === "target")
+					.forEach(function (bone) {
+						const folder = gui.addFolder( bone.name );
+
+						const delta = 20;
+						folder.add( bone.position, 'x', - delta + bone.position.x, delta + bone.position.x );
+						folder.add( bone.position, 'y', - bone.position.y, bone.position.y );
+						folder.add( bone.position, 'z', - delta + bone.position.z, delta + bone.position.z );
+					});
+				
+				gui.add( ikSolver, 'update' ).name( 'ikSolver.update()' );
+				gui.add( state, 'ikSolverAutoUpdate' )
+
+			}
+
+			function initBones() {
+
+				const segmentHeight = 8;
+				const segmentCount = 3;
+				const height = segmentHeight * segmentCount;
+				const halfHeight = height * 0.5;
+
+				const sizing = {
+					segmentHeight,
+					segmentCount,
+					height,
+					halfHeight
+				};
+
+				const geometry = createGeometry( sizing );
+				const bones = createBones( sizing );
+				mesh = createMesh( geometry, bones );
+
+				scene.add( mesh );
+
+				//
+				// ikSolver
+				//
+
+				const iks = [
+					{
+						target: 5,
+						effector: 4,
+						links: [{ index: 3 }, { index: 2 }, { index: 1 }]
+					}
+				];
+				ikSolver = new CCDIKSolver( mesh, iks );
+				scene.add( new CCDIKHelper( mesh, iks ) );
+
+			}
+
+			function render() {
+
+				requestAnimationFrame( render );
+
+				if ( state.ikSolverAutoUpdate ) {
+					ikSolver?.update();
+				}
+
+				renderer.render( scene, camera );
+
+			}
+
+			initScene();
+			render();
+
+		</script>
+	</body>
+</html>

+ 22 - 20
docs/scenes/material-browser.html

@@ -242,7 +242,7 @@
 
 			}
 
-			function handleColorChange( color ) {
+			function handleColorChange( color, converSRGBToLinear = false ) {
 
 				return function ( value ) {
 
@@ -254,6 +254,8 @@
 
 					color.setHex( value );
 
+					if ( converSRGBToLinear === true ) color.convertSRGBToLinear();
+
 				};
 
 			}
@@ -303,7 +305,7 @@
 					'ambient light': ambientLight.color.getHex()
 				};
 
-				folder.addColor( data, 'ambient light' ).onChange( handleColorChange( ambientLight.color ) );
+				folder.addColor( data, 'ambient light' ).onChange( handleColorChange( ambientLight.color, true ) );
 
 				guiSceneFog( folder, scene );
 
@@ -372,10 +374,10 @@
 
 				const folder = gui.addFolder( 'THREE.MeshBasicMaterial' );
 
-				folder.addColor( data, 'color' ).onChange( handleColorChange( material.color ) );
+				folder.addColor( data, 'color' ).onChange( handleColorChange( material.color, true ) );
 				folder.add( material, 'wireframe' );
 				folder.add( material, 'vertexColors' ).onChange( needsUpdate( material, geometry ) );
-				folder.add( material, 'fog' );
+				folder.add( material, 'fog' ).onChange( needsUpdate( material, geometry ) );
 
 				folder.add( data, 'envMaps', envMapKeys ).onChange( updateTexture( material, 'envMap', envMaps ) );
 				folder.add( data, 'map', diffuseMapKeys ).onChange( updateTexture( material, 'map', diffuseMaps ) );
@@ -417,12 +419,12 @@
 
 				const folder = gui.addFolder( 'THREE.LineBasicMaterial' );
 
-				folder.addColor( data, 'color' ).onChange( handleColorChange( material.color ) );
+				folder.addColor( data, 'color' ).onChange( handleColorChange( material.color, true ) );
 				folder.add( material, 'linewidth', 0, 10 );
 				folder.add( material, 'linecap', [ 'butt', 'round', 'square' ] );
 				folder.add( material, 'linejoin', [ 'round', 'bevel', 'miter' ] );
 				folder.add( material, 'vertexColors' ).onChange( needsUpdate( material, geometry ) );
-				folder.add( material, 'fog' );
+				folder.add( material, 'fog' ).onChange( needsUpdate( material, geometry ) );
 
 			}
 
@@ -438,12 +440,12 @@
 
 				const folder = gui.addFolder( 'THREE.MeshLambertMaterial' );
 
-				folder.addColor( data, 'color' ).onChange( handleColorChange( material.color ) );
-				folder.addColor( data, 'emissive' ).onChange( handleColorChange( material.emissive ) );
+				folder.addColor( data, 'color' ).onChange( handleColorChange( material.color, true ) );
+				folder.addColor( data, 'emissive' ).onChange( handleColorChange( material.emissive, true ) );
 
 				folder.add( material, 'wireframe' );
 				folder.add( material, 'vertexColors' ).onChange( needsUpdate( material, geometry ) );
-				folder.add( material, 'fog' );
+				folder.add( material, 'fog' ).onChange( needsUpdate( material, geometry ) );
 
 				folder.add( data, 'envMaps', envMapKeys ).onChange( updateTexture( material, 'envMap', envMaps ) );
 				folder.add( data, 'map', diffuseMapKeys ).onChange( updateTexture( material, 'map', diffuseMaps ) );
@@ -464,7 +466,7 @@
 
 				const folder = gui.addFolder( 'THREE.MeshMatcapMaterial' );
 
-				folder.addColor( data, 'color' ).onChange( handleColorChange( material.color ) );
+				folder.addColor( data, 'color' ).onChange( handleColorChange( material.color, true ) );
 
 				folder.add( material, 'flatShading' ).onChange( needsUpdate( material, geometry ) );
 				folder.add( data, 'matcap', matcapKeys ).onChange( updateTexture( material, 'matcap', matcaps ) );
@@ -485,15 +487,15 @@
 
 				const folder = gui.addFolder( 'THREE.MeshPhongMaterial' );
 
-				folder.addColor( data, 'color' ).onChange( handleColorChange( material.color ) );
-				folder.addColor( data, 'emissive' ).onChange( handleColorChange( material.emissive ) );
+				folder.addColor( data, 'color' ).onChange( handleColorChange( material.color, true ) );
+				folder.addColor( data, 'emissive' ).onChange( handleColorChange( material.emissive, true ) );
 				folder.addColor( data, 'specular' ).onChange( handleColorChange( material.specular ) );
 
 				folder.add( material, 'shininess', 0, 100 );
 				folder.add( material, 'flatShading' ).onChange( needsUpdate( material, geometry ) );
 				folder.add( material, 'wireframe' );
 				folder.add( material, 'vertexColors' ).onChange( needsUpdate( material, geometry ) );
-				folder.add( material, 'fog' );
+				folder.add( material, 'fog' ).onChange( needsUpdate( material, geometry ) );
 				folder.add( data, 'envMaps', envMapKeys ).onChange( updateTexture( material, 'envMap', envMaps ) );
 				folder.add( data, 'map', diffuseMapKeys ).onChange( updateTexture( material, 'map', diffuseMaps ) );
 				folder.add( data, 'alphaMap', alphaMapKeys ).onChange( updateTexture( material, 'alphaMap', alphaMaps ) );
@@ -514,7 +516,7 @@
 
 				const folder = gui.addFolder( 'THREE.MeshToonMaterial' );
 
-				folder.addColor( data, 'color' ).onChange( handleColorChange( material.color ) );
+				folder.addColor( data, 'color' ).onChange( handleColorChange( material.color, true ) );
 				folder.add( data, 'map', diffuseMapKeys ).onChange( updateTexture( material, 'map', diffuseMaps ) );
 				folder.add( data, 'gradientMap', gradientMapKeys ).onChange( updateTexture( material, 'gradientMap', gradientMaps ) );
 				folder.add( data, 'alphaMap', alphaMapKeys ).onChange( updateTexture( material, 'alphaMap', alphaMaps ) );
@@ -534,15 +536,15 @@
 
 				const folder = gui.addFolder( 'THREE.MeshStandardMaterial' );
 
-				folder.addColor( data, 'color' ).onChange( handleColorChange( material.color ) );
-				folder.addColor( data, 'emissive' ).onChange( handleColorChange( material.emissive ) );
+				folder.addColor( data, 'color' ).onChange( handleColorChange( material.color, true ) );
+				folder.addColor( data, 'emissive' ).onChange( handleColorChange( material.emissive, true ) );
 
 				folder.add( material, 'roughness', 0, 1 );
 				folder.add( material, 'metalness', 0, 1 );
 				folder.add( material, 'flatShading' ).onChange( needsUpdate( material, geometry ) );
 				folder.add( material, 'wireframe' );
 				folder.add( material, 'vertexColors' ).onChange( needsUpdate( material, geometry ) );
-				folder.add( material, 'fog' );
+				folder.add( material, 'fog' ).onChange( needsUpdate( material, geometry ) );
 				folder.add( data, 'envMaps', envMapKeysPBR ).onChange( updateTexture( material, 'envMap', envMaps ) );
 				folder.add( data, 'map', diffuseMapKeys ).onChange( updateTexture( material, 'map', diffuseMaps ) );
 				folder.add( data, 'roughnessMap', roughnessMapKeys ).onChange( updateTexture( material, 'roughnessMap', roughnessMaps ) );
@@ -565,8 +567,8 @@
 
 				const folder = gui.addFolder( 'THREE.MeshPhysicalMaterial' );
 
-				folder.addColor( data, 'color' ).onChange( handleColorChange( material.color ) );
-				folder.addColor( data, 'emissive' ).onChange( handleColorChange( material.emissive ) );
+				folder.addColor( data, 'color' ).onChange( handleColorChange( material.color, true ) );
+				folder.addColor( data, 'emissive' ).onChange( handleColorChange( material.emissive, true ) );
 
 				folder.add( material, 'roughness', 0, 1 );
 				folder.add( material, 'metalness', 0, 1 );
@@ -576,7 +578,7 @@
 				folder.add( material, 'flatShading' ).onChange( needsUpdate( material, geometry ) );
 				folder.add( material, 'wireframe' );
 				folder.add( material, 'vertexColors' ).onChange( needsUpdate( material, geometry ) );
-				folder.add( material, 'fog' );
+				folder.add( material, 'fog' ).onChange( needsUpdate( material, geometry ) );
 				folder.add( data, 'envMaps', envMapKeysPBR ).onChange( updateTexture( material, 'envMap', envMaps ) );
 				folder.add( data, 'map', diffuseMapKeys ).onChange( updateTexture( material, 'map', diffuseMaps ) );
 				folder.add( data, 'roughnessMap', roughnessMapKeys ).onChange( updateTexture( material, 'roughnessMap', roughnessMaps ) );

+ 2 - 2
editor/docs/Implementing additional commands for undo-redo.md

@@ -126,7 +126,7 @@ The idea behind 'updatable commands' is that two commands of the same type which
 within a short period of time should be merged into one.
 **For example:** Dragging with your mouse over the x-position field in the sidebar
 leads to hundreds of minor changes to the x-position.
-The user expectation is not to undo every single change that happened while he dragged
-the mouse cursor but rather to go back to the position before he started to drag his mouse.
+The user expectation is not to undo every single change that happened while they dragged
+the mouse cursor but rather to go back to the position before they started to drag their mouse.
 
 When editing a script the changes are also merged into one undo-step.

+ 17 - 0
editor/js/Menubar.Add.js

@@ -55,6 +55,23 @@ function MenubarAdd( editor ) {
 	} );
 	options.add( option );
 
+	// Capsule
+
+	option = new UIRow();
+	option.setClass( 'option' );
+	option.setTextContent( strings.getKey( 'menubar/add/capsule' ) );
+	option.onClick( function () {
+
+		const geometry = new THREE.CapsuleGeometry( 1, 1, 4, 8 );
+		const material = new THREE.MeshStandardMaterial();
+		const mesh = new THREE.Mesh( geometry, material );
+		mesh.name = 'Capsule';
+
+		editor.execute( new AddObjectCommand( editor, mesh ) );
+
+	} );
+	options.add( option );
+
 	// Circle
 
 	option = new UIRow();

+ 73 - 0
editor/js/Sidebar.Geometry.CapsuleGeometry.js

@@ -0,0 +1,73 @@
+import * as THREE from 'three';
+
+import { UIDiv, UIRow, UIText, UINumber, UIInteger } from './libs/ui.js';
+
+import { SetGeometryCommand } from './commands/SetGeometryCommand.js';
+
+function GeometryParametersPanel( editor, object ) {
+
+	const strings = editor.strings;
+
+	const container = new UIDiv();
+
+	const geometry = object.geometry;
+	const parameters = geometry.parameters;
+
+	// radius
+
+	const radiusRow = new UIRow();
+	const radius = new UINumber( parameters.radius ).onChange( update );
+
+	radiusRow.add( new UIText( strings.getKey( 'sidebar/geometry/capsule_geometry/radius' ) ).setWidth( '90px' ) );
+	radiusRow.add( radius );
+
+	container.add( radiusRow );
+
+	// length
+
+	const lengthRow = new UIRow();
+	const length = new UINumber( parameters.height ).onChange( update );
+
+	lengthRow.add( new UIText( strings.getKey( 'sidebar/geometry/capsule_geometry/length' ) ).setWidth( '90px' ) );
+	lengthRow.add( length );
+
+	container.add( lengthRow );
+
+	// capSegments
+
+	const capSegmentsRow = new UIRow();
+	const capSegments = new UINumber( parameters.capSegments ).onChange( update );
+
+	capSegmentsRow.add( new UIText( strings.getKey( 'sidebar/geometry/capsule_geometry/capseg' ) ).setWidth( '90px' ) );
+	capSegmentsRow.add( capSegments );
+
+	container.add( capSegmentsRow );
+
+	// radialSegments
+
+	const radialSegmentsRow = new UIRow();
+	const radialSegments = new UIInteger( parameters.radialSegments ).setRange( 1, Infinity ).onChange( update );
+
+	radialSegmentsRow.add( new UIText( strings.getKey( 'sidebar/geometry/capsule_geometry/radialseg' ) ).setWidth( '90px' ) );
+	radialSegmentsRow.add( radialSegments );
+
+	container.add( radialSegmentsRow );
+
+	//
+
+	function update() {
+
+		editor.execute( new SetGeometryCommand( editor, object, new THREE.CapsuleGeometry(
+			radius.getValue(),
+			length.getValue(),
+			capSegments.getValue(),
+			radialSegments.getValue()
+		) ) );
+
+	}
+
+	return container;
+
+}
+
+export { GeometryParametersPanel };

+ 56 - 1
editor/js/Sidebar.Material.js

@@ -1,6 +1,6 @@
 import * as THREE from 'three';
 
-import { UIButton, UIInput, UIPanel, UIRow, UISelect, UIText } from './libs/ui.js';
+import { UIButton, UIInput, UIPanel, UIRow, UISelect, UIText, UITextArea } from './libs/ui.js';
 
 import { SetMaterialCommand } from './commands/SetMaterialCommand.js';
 import { SetMaterialValueCommand } from './commands/SetMaterialValueCommand.js';
@@ -310,6 +310,33 @@ function SidebarMaterial( editor ) {
 	const materialWireframe = new SidebarMaterialBooleanProperty( editor, 'wireframe', strings.getKey( 'sidebar/material/wireframe' ) );
 	container.add( materialWireframe );
 
+	// userData
+
+	const materialUserDataRow = new UIRow();
+	const materialUserData = new UITextArea().setWidth( '150px' ).setHeight( '40px' ).setFontSize( '12px' ).onChange( update );
+	materialUserData.onKeyUp( function () {
+
+		try {
+
+			JSON.parse( materialUserData.getValue() );
+
+			materialUserData.dom.classList.add( 'success' );
+			materialUserData.dom.classList.remove( 'fail' );
+
+		} catch ( error ) {
+
+			materialUserData.dom.classList.remove( 'success' );
+			materialUserData.dom.classList.add( 'fail' );
+
+		}
+
+	} );
+
+	materialUserDataRow.add( new UIText( strings.getKey( 'sidebar/material/userdata' ) ).setWidth( '90px' ) );
+	materialUserDataRow.add( materialUserData );
+
+	container.add( materialUserDataRow );
+
 	//
 
 	function update() {
@@ -362,6 +389,21 @@ function SidebarMaterial( editor ) {
 
 			}
 
+			try {
+
+				const userData = JSON.parse( materialUserData.getValue() );
+				if ( JSON.stringify( material.userData ) != JSON.stringify( userData ) ) {
+
+					editor.execute( new SetMaterialValueCommand( editor, currentObject, 'userData', userData, currentMaterialSlot ) );
+
+				}
+
+			} catch ( exception ) {
+
+				console.warn( exception );
+
+			}
+
 			refreshUI();
 
 		}
@@ -444,6 +486,19 @@ function SidebarMaterial( editor ) {
 
 		setRowVisibility();
 
+		try {
+
+			materialUserData.setValue( JSON.stringify( material.userData, null, '  ' ) );
+
+		} catch ( error ) {
+
+			console.log( error );
+
+		}
+
+		materialUserData.setBorderColor( 'transparent' );
+		materialUserData.setBackgroundColor( '' );
+
 	}
 
 	// events

+ 21 - 0
editor/js/Strings.js

@@ -37,6 +37,7 @@ function Strings( config ) {
 			'menubar/add/group': 'Group',
 			'menubar/add/plane': 'Plane',
 			'menubar/add/box': 'Box',
+			'menubar/add/capsule': 'Capsule',
 			'menubar/add/circle': 'Circle',
 			'menubar/add/cylinder': 'Cylinder',
 			'menubar/add/ring': 'Ring',
@@ -144,6 +145,11 @@ function Strings( config ) {
 			'sidebar/geometry/buffer_geometry/attributes': 'Attributes',
 			'sidebar/geometry/buffer_geometry/index': 'index',
 
+			'sidebar/geometry/capsule_geometry/radius': 'Radius',
+			'sidebar/geometry/capsule_geometry/length': 'Length',
+			'sidebar/geometry/capsule_geometry/capseg': 'Cap Seg',
+			'sidebar/geometry/capsule_geometry/radialseg': 'Radial Seg',
+
 			'sidebar/geometry/circle_geometry/radius': 'Radius',
 			'sidebar/geometry/circle_geometry/segments': 'Segments',
 			'sidebar/geometry/circle_geometry/thetastart': 'Theta start',
@@ -280,6 +286,7 @@ function Strings( config ) {
 			'sidebar/material/depthtest': 'Depth Test',
 			'sidebar/material/depthwrite': 'Depth Write',
 			'sidebar/material/wireframe': 'Wireframe',
+			'sidebar/material/userdata': 'User data',
 
 			'sidebar/script': 'Script',
 			'sidebar/script/new': 'New',
@@ -365,6 +372,7 @@ function Strings( config ) {
 			'menubar/add/group': 'Groupe',
 			'menubar/add/plane': 'Plan',
 			'menubar/add/box': 'Cube',
+			'menubar/add/capsule': 'Capsule',
 			'menubar/add/circle': 'Cercle',
 			'menubar/add/cylinder': 'Cylindre',
 			'menubar/add/ring': 'Bague',
@@ -472,6 +480,11 @@ function Strings( config ) {
 			'sidebar/geometry/buffer_geometry/attributes': 'Attributs',
 			'sidebar/geometry/buffer_geometry/index': 'index',
 
+			'sidebar/geometry/capsule_geometry/radius': 'Radius',
+			'sidebar/geometry/capsule_geometry/length': 'Length',
+			'sidebar/geometry/capsule_geometry/capseg': 'Cap Seg',
+			'sidebar/geometry/capsule_geometry/radialseg': 'Radial Seg',
+
 			'sidebar/geometry/circle_geometry/radius': 'Rayon',
 			'sidebar/geometry/circle_geometry/segments': 'Segments',
 			'sidebar/geometry/circle_geometry/thetastart': 'Début Thêta (°)',
@@ -608,6 +621,7 @@ function Strings( config ) {
 			'sidebar/material/depthtest': 'Depth Test',
 			'sidebar/material/depthwrite': 'Depth Write',
 			'sidebar/material/wireframe': 'Fil de fer',
+			'sidebar/material/userdata': 'Données utilisateur',
 
 			'sidebar/script': 'Script',
 			'sidebar/script/new': 'Nouveau',
@@ -693,6 +707,7 @@ function Strings( config ) {
 			'menubar/add/group': '组',
 			'menubar/add/plane': '平面',
 			'menubar/add/box': '正方体',
+			'menubar/add/capsule': '胶囊',
 			'menubar/add/circle': '圆',
 			'menubar/add/cylinder': '圆柱体',
 			'menubar/add/ring': '环',
@@ -800,6 +815,11 @@ function Strings( config ) {
 			'sidebar/geometry/buffer_geometry/attributes': '属性',
 			'sidebar/geometry/buffer_geometry/index': '索引',
 
+			'sidebar/geometry/capsule_geometry/radius': '半径',
+			'sidebar/geometry/capsule_geometry/length': '长度',
+			'sidebar/geometry/capsule_geometry/capseg': '胶囊分段',
+			'sidebar/geometry/capsule_geometry/radialseg': '半径分段',
+
 			'sidebar/geometry/circle_geometry/radius': '半径',
 			'sidebar/geometry/circle_geometry/segments': '分段',
 			'sidebar/geometry/circle_geometry/thetastart': '弧度起点',
@@ -936,6 +956,7 @@ function Strings( config ) {
 			'sidebar/material/depthtest': '深度测试',
 			'sidebar/material/depthwrite': '深度缓冲',
 			'sidebar/material/wireframe': '线框',
+			'sidebar/material/userdata': '自定义数据',
 
 			'sidebar/script': '脚本',
 			'sidebar/script/new': '新建',

+ 8 - 13
editor/js/libs/codemirror/codemirror.css

@@ -60,19 +60,13 @@
 .cm-fat-cursor div.CodeMirror-cursors {
   z-index: 1;
 }
-.cm-fat-cursor-mark {
-  background-color: rgba(20, 255, 20, 0.5);
-  -webkit-animation: blink 1.06s steps(1) infinite;
-  -moz-animation: blink 1.06s steps(1) infinite;
-  animation: blink 1.06s steps(1) infinite;
-}
-.cm-animate-fat-cursor {
-  width: auto;
-  -webkit-animation: blink 1.06s steps(1) infinite;
-  -moz-animation: blink 1.06s steps(1) infinite;
-  animation: blink 1.06s steps(1) infinite;
-  background-color: #7e7;
-}
+.cm-fat-cursor .CodeMirror-line::selection,
+.cm-fat-cursor .CodeMirror-line > span::selection, 
+.cm-fat-cursor .CodeMirror-line > span > span::selection { background: transparent; }
+.cm-fat-cursor .CodeMirror-line::-moz-selection,
+.cm-fat-cursor .CodeMirror-line > span::-moz-selection,
+.cm-fat-cursor .CodeMirror-line > span > span::-moz-selection { background: transparent; }
+.cm-fat-cursor { caret-color: transparent; }
 @-moz-keyframes blink {
   0% {}
   50% { background-color: transparent; }
@@ -170,6 +164,7 @@ div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;}
   height: 100%;
   outline: none; /* Prevent dragging from highlighting the element */
   position: relative;
+  z-index: 0;
 }
 .CodeMirror-sizer {
   position: relative;

+ 78 - 62
editor/js/libs/codemirror/codemirror.js

@@ -393,7 +393,7 @@
     return function(str, direction) {
       var outerType = direction == "ltr" ? "L" : "R";
 
-      if (str.length == 0 || direction == "ltr" && !bidiRE.test(str)) { return false; }
+      if (str.length == 0 || direction == "ltr" && !bidiRE.test(str)) { return false }
       var len = str.length, types = [];
       for (var i = 0; i < len; ++i)
         { types.push(charType(str.charCodeAt(i))); }
@@ -511,7 +511,7 @@
         }
       }
 
-      return direction == "rtl" ? order.reverse() : order;
+      return direction == "rtl" ? order.reverse() : order
     }
   })();
 
@@ -677,7 +677,7 @@
         pos = nl + 1;
       }
     }
-    return result;
+    return result
   } : function (string) { return string.split(/\r\n?|\n/); };
 
   var hasSelection = window.getSelection ? function (te) {
@@ -1087,7 +1087,7 @@
           i += 2;
           at = Math.min(end, i_end);
         }
-        if (!style) { return; }
+        if (!style) { return }
         if (overlay.opaque) {
           st.splice(start, i - start, end, "overlay " + style);
           i = start + 2;
@@ -1121,7 +1121,7 @@
       if (updateFrontier === cm.doc.highlightFrontier)
         { cm.doc.modeFrontier = Math.max(cm.doc.modeFrontier, ++cm.doc.highlightFrontier); }
     }
-    return line.styles;
+    return line.styles
   }
 
   function getContextBefore(cm, n, precise) {
@@ -1786,7 +1786,7 @@
     if (builder.pre.className)
       { builder.textClass = joinClasses(builder.pre.className, builder.textClass || ""); }
 
-    return builder;
+    return builder
   }
 
   function defaultSpecialCharPlaceholder(ch) {
@@ -1799,7 +1799,7 @@
   // Build up the DOM representation for a single token, and add it to
   // the line map. Takes care to render special characters separately.
   function buildToken(builder, text, style, startStyle, endStyle, css, attributes) {
-    if (!text) { return; }
+    if (!text) { return }
     var displayText = builder.splitSpaces ? splitSpaces(text, builder.trailingSpace) : text;
     var special = builder.cm.state.specialChars, mustWrap = false;
     var content;
@@ -1824,7 +1824,7 @@
           builder.col += skipped;
           builder.pos += skipped;
         }
-        if (!m) { break; }
+        if (!m) { break }
         pos += skipped + 1;
         var txt$1 = (void 0);
         if (m[0] == "\t") {
@@ -1858,7 +1858,7 @@
         for (var attr in attributes) { if (attributes.hasOwnProperty(attr) && attr != "style" && attr != "class")
           { token.setAttribute(attr, attributes[attr]); } }
       }
-      return builder.content.appendChild(token);
+      return builder.content.appendChild(token)
     }
     builder.content.appendChild(content);
   }
@@ -2351,12 +2351,14 @@
   function mapFromLineView(lineView, line, lineN) {
     if (lineView.line == line)
       { return {map: lineView.measure.map, cache: lineView.measure.cache} }
-    for (var i = 0; i < lineView.rest.length; i++)
-      { if (lineView.rest[i] == line)
-        { return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i]} } }
-    for (var i$1 = 0; i$1 < lineView.rest.length; i$1++)
-      { if (lineNo(lineView.rest[i$1]) > lineN)
-        { return {map: lineView.measure.maps[i$1], cache: lineView.measure.caches[i$1], before: true} } }
+    if (lineView.rest) {
+      for (var i = 0; i < lineView.rest.length; i++)
+        { if (lineView.rest[i] == line)
+          { return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i]} } }
+      for (var i$1 = 0; i$1 < lineView.rest.length; i$1++)
+        { if (lineNo(lineView.rest[i$1]) > lineN)
+          { return {map: lineView.measure.maps[i$1], cache: lineView.measure.caches[i$1], before: true} } }
+    }
   }
 
   // Render a line into the hidden node display.externalMeasured. Used
@@ -2497,7 +2499,7 @@
           { rect = node.parentNode.getBoundingClientRect(); }
         else
           { rect = getUsefulRect(range(node, start, end).getClientRects(), bias); }
-        if (rect.left || rect.right || start == 0) { break; }
+        if (rect.left || rect.right || start == 0) { break }
         end = start;
         start = start - 1;
         collapse = "right";
@@ -2524,7 +2526,7 @@
     var heights = prepared.view.measure.heights;
     var i = 0;
     for (; i < heights.length - 1; i++)
-      { if (mid < heights[i]) { break; } }
+      { if (mid < heights[i]) { break } }
     var top = i ? heights[i - 1] : 0, bot = heights[i];
     var result = {left: (collapse == "right" ? rect.right : rect.left) - prepared.rect.left,
                   right: (collapse == "left" ? rect.left : rect.right) - prepared.rect.left,
@@ -2532,7 +2534,7 @@
     if (!rect.left && !rect.right) { result.bogus = true; }
     if (!cm.options.singleCursorHeightPerLine) { result.rtop = rtop; result.rbottom = rbot; }
 
-    return result;
+    return result
   }
 
   // Work around problem with bounding client rects on ranges being
@@ -2583,9 +2585,11 @@
   }
 
   function widgetTopHeight(lineObj) {
+    var ref = visualLine(lineObj);
+    var widgets = ref.widgets;
     var height = 0;
-    if (lineObj.widgets) { for (var i = 0; i < lineObj.widgets.length; ++i) { if (lineObj.widgets[i].above)
-      { height += widgetHeight(lineObj.widgets[i]); } } }
+    if (widgets) { for (var i = 0; i < widgets.length; ++i) { if (widgets[i].above)
+      { height += widgetHeight(widgets[i]); } } }
     return height
   }
 
@@ -2812,7 +2816,7 @@
     }
 
     ch = skipExtendingChars(lineObj.text, ch, 1);
-    return PosWithInfo(lineNo, ch, sticky, outside, x - baseX);
+    return PosWithInfo(lineNo, ch, sticky, outside, x - baseX)
   }
 
   function coordsBidiPart(cm, lineObj, lineNo, preparedMeasure, order, x, y) {
@@ -3150,13 +3154,19 @@
     var curFragment = result.cursors = document.createDocumentFragment();
     var selFragment = result.selection = document.createDocumentFragment();
 
+    var customCursor = cm.options.$customCursor;
+    if (customCursor) { primary = true; }
     for (var i = 0; i < doc.sel.ranges.length; i++) {
       if (!primary && i == doc.sel.primIndex) { continue }
       var range = doc.sel.ranges[i];
       if (range.from().line >= cm.display.viewTo || range.to().line < cm.display.viewFrom) { continue }
       var collapsed = range.empty();
-      if (collapsed || cm.options.showCursorWhenSelecting)
-        { drawSelectionCursor(cm, range.head, curFragment); }
+      if (customCursor) {
+        var head = customCursor(cm, range);
+        if (head) { drawSelectionCursor(cm, head, curFragment); }
+      } else if (collapsed || cm.options.showCursorWhenSelecting) {
+        drawSelectionCursor(cm, range.head, curFragment);
+      }
       if (!collapsed)
         { drawSelectionRange(cm, range, selFragment); }
     }
@@ -3174,9 +3184,8 @@
 
     if (/\bcm-fat-cursor\b/.test(cm.getWrapperElement().className)) {
       var charPos = charCoords(cm, head, "div", null, null);
-      if (charPos.right - charPos.left > 0) {
-        cursor.style.width = (charPos.right - charPos.left) + "px";
-      }
+      var width = charPos.right - charPos.left;
+      cursor.style.width = (width > 0 ? width : cm.defaultCharWidth()) + "px";
     }
 
     if (pos.other) {
@@ -3357,7 +3366,7 @@
     for (var i = 0; i < display.view.length; i++) {
       var cur = display.view[i], wrapping = cm.options.lineWrapping;
       var height = (void 0), width = 0;
-      if (cur.hidden) { continue; }
+      if (cur.hidden) { continue }
       oldHeight += cur.line.height;
       if (ie && ie_version < 8) {
         var bot = cur.node.offsetTop + cur.node.offsetHeight;
@@ -3421,7 +3430,7 @@
         to = ensureTo;
       }
     }
-    return {from: from, to: Math.max(to, from + 1)};
+    return {from: from, to: Math.max(to, from + 1)}
   }
 
   // SCROLLING THINGS INTO VIEW
@@ -3515,7 +3524,7 @@
       { result.scrollLeft = Math.max(0, rect.left + gutterSpace - (tooWide ? 0 : 10)); }
     else if (rect.right > screenw + screenleft - 3)
       { result.scrollLeft = rect.right + (tooWide ? 0 : 10) - screenw; }
-    return result;
+    return result
   }
 
   // Store a relative adjustment to the scroll position in the current
@@ -3649,6 +3658,7 @@
       this.vert.firstChild.style.height =
         Math.max(0, measure.scrollHeight - measure.clientHeight + totalHeight) + "px";
     } else {
+      this.vert.scrollTop = 0;
       this.vert.style.display = "";
       this.vert.firstChild.style.height = "0";
     }
@@ -3670,7 +3680,7 @@
       this.checkedZeroWidth = true;
     }
 
-    return {right: needsV ? sWidth : 0, bottom: needsH ? sWidth : 0};
+    return {right: needsV ? sWidth : 0, bottom: needsH ? sWidth : 0}
   };
 
   NativeScrollbars.prototype.setScrollLeft = function (pos) {
@@ -4011,7 +4021,7 @@
       }
       if (+new Date > end) {
         startWorker(cm, cm.options.workDelay);
-        return true;
+        return true
       }
     });
     doc.highlightFrontier = context.line;
@@ -4500,6 +4510,12 @@
 
   function onScrollWheel(cm, e) {
     var delta = wheelEventDelta(e), dx = delta.x, dy = delta.y;
+    var pixelsPerUnit = wheelPixelsPerUnit;
+    if (e.deltaMode === 0) {
+      dx = e.deltaX;
+      dy = e.deltaY;
+      pixelsPerUnit = 1;
+    }
 
     var display = cm.display, scroll = display.scroller;
     // Quit if there's nothing to scroll here
@@ -4528,10 +4544,10 @@
     // estimated pixels/delta value, we just handle horizontal
     // scrolling entirely here. It'll be slightly off from native, but
     // better than glitching out.
-    if (dx && !gecko && !presto && wheelPixelsPerUnit != null) {
+    if (dx && !gecko && !presto && pixelsPerUnit != null) {
       if (dy && canScrollY)
-        { updateScrollTop(cm, Math.max(0, scroll.scrollTop + dy * wheelPixelsPerUnit)); }
-      setScrollLeft(cm, Math.max(0, scroll.scrollLeft + dx * wheelPixelsPerUnit));
+        { updateScrollTop(cm, Math.max(0, scroll.scrollTop + dy * pixelsPerUnit)); }
+      setScrollLeft(cm, Math.max(0, scroll.scrollLeft + dx * pixelsPerUnit));
       // Only prevent default scrolling if vertical scrolling is
       // actually possible. Otherwise, it causes vertical scroll
       // jitter on OSX trackpads when deltaX is small and deltaY
@@ -4544,15 +4560,15 @@
 
     // 'Project' the visible viewport to cover the area that is being
     // scrolled into view (if we know enough to estimate it).
-    if (dy && wheelPixelsPerUnit != null) {
-      var pixels = dy * wheelPixelsPerUnit;
+    if (dy && pixelsPerUnit != null) {
+      var pixels = dy * pixelsPerUnit;
       var top = cm.doc.scrollTop, bot = top + display.wrapper.clientHeight;
       if (pixels < 0) { top = Math.max(0, top + pixels - 50); }
       else { bot = Math.min(cm.doc.height, bot + pixels + 50); }
       updateDisplaySimple(cm, {top: top, bottom: bot});
     }
 
-    if (wheelSamples < 20) {
+    if (wheelSamples < 20 && e.deltaMode !== 0) {
       if (display.wheelStartX == null) {
         display.wheelStartX = scroll.scrollLeft; display.wheelStartY = scroll.scrollTop;
         display.wheelDX = dx; display.wheelDY = dy;
@@ -4644,7 +4660,7 @@
         ranges.splice(--i, 2, new Range(inv ? to : from, inv ? from : to));
       }
     }
-    return new Selection(ranges, primIndex);
+    return new Selection(ranges, primIndex)
   }
 
   function simpleSelection(anchor, head) {
@@ -4705,7 +4721,7 @@
         out[i] = new Range(from, from);
       }
     }
-    return new Selection(out, doc.sel.primIndex);
+    return new Selection(out, doc.sel.primIndex)
   }
 
   // Used to get the editor into a consistent state again when options change.
@@ -4805,7 +4821,7 @@
 
   // Attach a document to an editor.
   function attachDoc(cm, doc) {
-    if (doc.cm) { throw new Error("This document is already in use."); }
+    if (doc.cm) { throw new Error("This document is already in use.") }
     cm.doc = doc;
     doc.cm = cm;
     estimateLineHeights(cm);
@@ -5371,7 +5387,7 @@
       change.origin = type;
       if (filter && !filterChange(doc, change, false)) {
         source.length = 0;
-        return {};
+        return {}
       }
 
       antiChanges.push(historyChangeFromChange(doc, change));
@@ -5666,7 +5682,7 @@
           child.removeInner(at, rm);
           this.height -= oldHeight - child.height;
           if (sz == rm) { this.children.splice(i--, 1); child.parent = null; }
-          if ((n -= rm) == 0) { break; }
+          if ((n -= rm) == 0) { break }
           at = 0;
         } else { at -= sz; }
       }
@@ -5705,7 +5721,7 @@
             child.lines = child.lines.slice(0, remaining);
             this.maybeSpill();
           }
-          break;
+          break
         }
         at -= sz;
       }
@@ -5842,7 +5858,7 @@
 
   // Clear the marker.
   TextMarker.prototype.clear = function () {
-    if (this.explicitlyCleared) { return; }
+    if (this.explicitlyCleared) { return }
     var cm = this.doc.cm, withOp = cm && !cm.curOp;
     if (withOp) { startOperation(cm); }
     if (hasHandler(this, "clear")) {
@@ -6095,7 +6111,7 @@
 
   var nextDocId = 0;
   var Doc = function(text, mode, firstLine, lineSep, direction) {
-    if (!(this instanceof Doc)) { return new Doc(text, mode, firstLine, lineSep, direction); }
+    if (!(this instanceof Doc)) { return new Doc(text, mode, firstLine, lineSep, direction) }
     if (firstLine == null) { firstLine = 0; }
 
     BranchChunk.call(this, [new LeafChunk([new Line("", null)])]);
@@ -6467,7 +6483,7 @@
       ; }(this.linked || (this.linked = [])).push({doc: copy, sharedHist: options.sharedHist});
       copy.linked = [{doc: this, isParent: true, sharedHist: options.sharedHist}];
       copySharedMarkers(copy, findSharedMarkers(this));
-      return copy;
+      return copy
     },
     unlinkDoc: function(other) {
       if (other instanceof CodeMirror) { other = other.doc; }
@@ -7071,7 +7087,7 @@
     transposeChars: function (cm) { return runInOp(cm, function () {
       var ranges = cm.listSelections(), newSel = [];
       for (var i = 0; i < ranges.length; i++) {
-        if (!ranges[i].empty()) { continue; }
+        if (!ranges[i].empty()) { continue }
         var cur = ranges[i].head, line = getLine(cm.doc, cur.line).text;
         if (line) {
           if (cur.ch == line.length) { cur = new Pos(cur.line, cur.ch - 1); }
@@ -7505,7 +7521,7 @@
 
     var lastPos = start;
     function extendTo(pos) {
-      if (cmp(lastPos, pos) == 0) { return; }
+      if (cmp(lastPos, pos) == 0) { return }
       lastPos = pos;
 
       if (behavior.unit == "rectangle") {
@@ -7869,7 +7885,7 @@
   function CodeMirror(place, options) {
     var this$1 = this;
 
-    if (!(this instanceof CodeMirror)) { return new CodeMirror(place, options); }
+    if (!(this instanceof CodeMirror)) { return new CodeMirror(place, options) }
 
     this.options = options = options ? copyObj(options) : {};
     // Determine effective options based on given values and defaults.
@@ -8081,7 +8097,7 @@
     } else if (how == "smart") {
       indentation = doc.mode.indent(state, line.text.slice(curSpaceString.length), line.text);
       if (indentation == Pass || indentation > 150) {
-        if (!aggressive) { return; }
+        if (!aggressive) { return }
         how = "prev";
       }
     }
@@ -8105,7 +8121,7 @@
     if (indentString != curSpaceString) {
       replaceRange(doc, indentString, Pos(n, 0), Pos(n, curSpaceString.length), "+input");
       line.stateAfter = null;
-      return true;
+      return true
     } else {
       // Ensure that, if the cursor was in the whitespace at the start
       // of the line, it is moved to the end of that space.
@@ -8114,7 +8130,7 @@
         if (range.head.line == n && range.head.ch < curSpaceString.length) {
           var pos$1 = Pos(n, curSpaceString.length);
           replaceOneSelection(doc, i$1, new Range(pos$1, pos$1));
-          break;
+          break
         }
       }
     }
@@ -8229,7 +8245,7 @@
   }
 
   function hiddenTextarea() {
-    var te = elt("textarea", null, null, "position: absolute; bottom: -1em; padding: 0; width: 1px; height: 1em; outline: none");
+    var te = elt("textarea", null, null, "position: absolute; bottom: -1em; padding: 0; width: 1px; height: 1em; min-height: 1em; outline: none");
     var div = elt("div", [te], null, "overflow: hidden; position: relative; width: 3px; height: 0px;");
     // The textarea is kept positioned near the cursor to prevent the
     // fact that it'll be scrolled into view on input from scrolling
@@ -8570,7 +8586,7 @@
           while (start > 0 && check(line.charAt(start - 1))) { --start; }
           while (end < line.length && check(line.charAt(end))) { ++end; }
         }
-        return new Range(Pos(pos.line, start), Pos(pos.line, end));
+        return new Range(Pos(pos.line, start), Pos(pos.line, end))
       },
 
       toggleOverwrite: function(value) {
@@ -8657,7 +8673,7 @@
         scrollToCoords(this, doc.scrollLeft, doc.scrollTop);
         this.curOp.forceScroll = true;
         signalLater(this, "swapDoc", this, old);
-        return old;
+        return old
       }),
 
       phrase: function(phraseText) {
@@ -9053,7 +9069,7 @@
       { from = Pos(from.line - 1, getLine(cm.doc, from.line - 1).length); }
     if (to.ch == getLine(cm.doc, to.line).text.length && to.line < cm.lastLine())
       { to = Pos(to.line + 1, 0); }
-    if (from.line < display.viewFrom || to.line > display.viewTo - 1) { return false; }
+    if (from.line < display.viewFrom || to.line > display.viewTo - 1) { return false }
 
     var fromIndex, fromLine, fromNode;
     if (from.line == display.viewFrom || (fromIndex = findViewIndex(cm, from.line)) == 0) {
@@ -9073,13 +9089,13 @@
       toNode = display.view[toIndex + 1].node.previousSibling;
     }
 
-    if (!fromNode) { return false; }
+    if (!fromNode) { return false }
     var newText = cm.doc.splitLines(domTextBetween(cm, fromNode, toNode, fromLine, toLine));
     var oldText = getBetween(cm.doc, Pos(fromLine, 0), Pos(toLine, getLine(cm.doc, toLine).text.length));
     while (newText.length > 1 && oldText.length > 1) {
       if (lst(newText) == lst(oldText)) { newText.pop(); oldText.pop(); toLine--; }
       else if (newText[0] == oldText[0]) { newText.shift(); oldText.shift(); fromLine++; }
-      else { break; }
+      else { break }
     }
 
     var cutFront = 0, cutEnd = 0;
@@ -9108,7 +9124,7 @@
     var chTo = Pos(toLine, oldText.length ? lst(oldText).length - cutEnd : 0);
     if (newText.length > 1 || newText[0] || cmp(chFrom, chTo)) {
       replaceRange(cm.doc, newText, chFrom, chTo, "+input");
-      return true;
+      return true
     }
   };
 
@@ -9595,7 +9611,7 @@
     var input = this, cm = input.cm, display = cm.display, te = input.textarea;
     if (input.contextMenuPending) { input.contextMenuPending(); }
     var pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop;
-    if (!pos || presto) { return; } // Opera is difficult.
+    if (!pos || presto) { return } // Opera is difficult.
 
     // Reset the current text selection only if the click is done outside of the selection
     // and 'resetSelectionOnContextMenu' option is true.
@@ -9736,7 +9752,7 @@
     textarea.style.display = "none";
     var cm = CodeMirror(function (node) { return textarea.parentNode.insertBefore(node, textarea.nextSibling); },
       options);
-    return cm;
+    return cm
   }
 
   function addLegacyProps(CodeMirror) {
@@ -9826,7 +9842,7 @@
 
   addLegacyProps(CodeMirror);
 
-  CodeMirror.version = "5.63.0";
+  CodeMirror.version = "5.65.2";
 
   return CodeMirror;
 

+ 2 - 1
editor/sw.js

@@ -1,4 +1,4 @@
-// r139
+// r140
 
 const cacheName = 'threejs-editor';
 
@@ -158,6 +158,7 @@ const assets = [
 	'./js/Sidebar.Geometry.BufferGeometry.js',
 	'./js/Sidebar.Geometry.Modifiers.js',
 	'./js/Sidebar.Geometry.BoxGeometry.js',
+	'./js/Sidebar.Geometry.CapsuleGeometry.js',
 	'./js/Sidebar.Geometry.CircleGeometry.js',
 	'./js/Sidebar.Geometry.CylinderGeometry.js',
 	'./js/Sidebar.Geometry.DodecahedronGeometry.js',

+ 3 - 0
examples/files.json

@@ -309,6 +309,7 @@
 	"webgpu": [
 		"webgpu_compute",
 		"webgpu_depth_texture",
+		"webgpu_instance_mesh",
 		"webgpu_instance_uniform",
 		"webgpu_lights_custom",
 		"webgpu_lights_selective",
@@ -317,6 +318,7 @@
 		"webgpu_rtt",
 		"webgpu_sandbox",
 		"webgpu_skinning",
+		"webgpu_skinning_instancing",
 		"webgpu_skinning_points"
 	],
 	"webaudio": [
@@ -347,6 +349,7 @@
 		"webxr_vr_rollercoaster",
 		"webxr_vr_sandbox",
 		"webxr_vr_sculpt",
+		"webxr_vr_teleport",
 		"webxr_vr_video"
 	],
 	"games": [

+ 3 - 1
examples/js/controls/ArcballControls.js

@@ -845,7 +845,9 @@
 
 									}
 
-									this.applyTransformMatrix( this.scale( size, this._gizmos.position ) );
+									this._v3_1.setFromMatrixPosition( this._gizmoMatrixState );
+
+									this.applyTransformMatrix( this.scale( size, this._v3_1 ) );
 
 								}
 

+ 49 - 36
examples/js/exporters/GLTFExporter.js

@@ -185,23 +185,7 @@
 
 	function stringToArrayBuffer( text ) {
 
-		if ( window.TextEncoder !== undefined ) {
-
-			return new TextEncoder().encode( text ).buffer;
-
-		}
-
-		const array = new Uint8Array( new ArrayBuffer( text.length ) );
-
-		for ( let i = 0, il = text.length; i < il; i ++ ) {
-
-			const value = text.charCodeAt( i ); // Replacing multi-byte character with space(0x20).
-
-			array[ i ] = value > 0xFF ? 0x20 : value;
-
-		}
-
-		return array.buffer;
+		return new TextEncoder().encode( text ).buffer;
 
 	}
 	/**
@@ -312,10 +296,33 @@
 	}
 
 	let cachedCanvas = null;
+
+	function getCanvas() {
+
+		if ( cachedCanvas ) {
+
+			return cachedCanvas;
+
+		}
+
+		if ( typeof OffscreenCanvas !== 'undefined' ) {
+
+			cachedCanvas = new OffscreenCanvas( 1, 1 );
+
+		} else {
+
+			cachedCanvas = document.createElement( 'canvas' );
+
+		}
+
+		return cachedCanvas;
+
+	}
 	/**
  * Writer
  */
 
+
 	class GLTFWriter {
 
 		constructor() {
@@ -402,7 +409,7 @@
 			if ( options.binary === true ) {
 
 				// https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#glb-file-format-specification
-				const reader = new window.FileReader();
+				const reader = new FileReader();
 				reader.readAsArrayBuffer( blob );
 
 				reader.onloadend = function () {
@@ -427,7 +434,7 @@
 					const glbBlob = new Blob( [ header, jsonChunkPrefix, jsonChunk, binaryChunkPrefix, binaryChunk ], {
 						type: 'application/octet-stream'
 					} );
-					const glbReader = new window.FileReader();
+					const glbReader = new FileReader();
 					glbReader.readAsArrayBuffer( glbBlob );
 
 					glbReader.onloadend = function () {
@@ -442,7 +449,7 @@
 
 				if ( json.buffers && json.buffers.length > 0 ) {
 
-					const reader = new window.FileReader();
+					const reader = new FileReader();
 					reader.readAsDataURL( blob );
 
 					reader.onloadend = function () {
@@ -634,7 +641,7 @@
 			const roughness = roughnessMap?.image;
 			const width = Math.max( metalness?.width || 0, roughness?.width || 0 );
 			const height = Math.max( metalness?.height || 0, roughness?.height || 0 );
-			const canvas = document.createElement( 'canvas' );
+			const canvas = getCanvas();
 			canvas.width = width;
 			canvas.height = height;
 			const context = canvas.getContext( '2d' );
@@ -810,7 +817,7 @@
 			if ( ! json.bufferViews ) json.bufferViews = [];
 			return new Promise( function ( resolve ) {
 
-				const reader = new window.FileReader();
+				const reader = new FileReader();
 				reader.readAsArrayBuffer( blob );
 
 				reader.onloadend = function () {
@@ -942,7 +949,7 @@
 
 			if ( options.embedImages ) {
 
-				const canvas = cachedCanvas = cachedCanvas || document.createElement( 'canvas' );
+				const canvas = getCanvas();
 				canvas.width = Math.min( image.width, options.maxTextureSize );
 				canvas.height = Math.min( image.height, options.maxTextureSize );
 				const ctx = canvas.getContext( '2d' );
@@ -954,12 +961,9 @@
 
 				}
 
-				if ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement || typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement || typeof OffscreenCanvas !== 'undefined' && image instanceof OffscreenCanvas || typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) {
-
-					ctx.drawImage( image, 0, 0, canvas.width, canvas.height );
-
-				} else {
+				if ( image.data !== undefined ) {
 
+					// THREE.DataTexture
 					if ( format !== THREE.RGBAFormat ) {
 
 						console.error( 'GLTFExporter: Only THREE.RGBAFormat is supported.' );
@@ -985,24 +989,33 @@
 
 					ctx.putImageData( new ImageData( data, image.width, image.height ), 0, 0 );
 
+				} else {
+
+					ctx.drawImage( image, 0, 0, canvas.width, canvas.height );
+
 				}
 
 				if ( options.binary === true ) {
 
-					pending.push( new Promise( function ( resolve ) {
+					let toBlobPromise;
 
-						canvas.toBlob( function ( blob ) {
+					if ( canvas.toBlob !== undefined ) {
 
-							writer.processBufferViewImage( blob ).then( function ( bufferViewIndex ) {
+						toBlobPromise = new Promise( resolve => canvas.toBlob( resolve, mimeType ) );
 
-								imageDef.bufferView = bufferViewIndex;
-								resolve();
+					} else {
+
+						toBlobPromise = canvas.convertToBlob( {
+							type: mimeType
+						} );
+
+					}
 
-							} );
+					pending.push( toBlobPromise.then( blob => writer.processBufferViewImage( blob ).then( bufferViewIndex => {
 
-						}, mimeType );
+						imageDef.bufferView = bufferViewIndex;
 
-					} ) );
+					} ) ) );
 
 				} else {
 

File diff suppressed because it is too large
+ 0 - 19
examples/js/libs/opentype.min.js


+ 8 - 0
examples/js/loaders/FBXLoader.js

@@ -326,6 +326,14 @@
 
 			}
 
+			if ( 'Translation' in textureNode ) {
+
+				const values = textureNode.Translation.value;
+				texture.offset.x = values[ 0 ];
+				texture.offset.y = values[ 1 ];
+
+			}
+
 			return texture;
 
 		} // load a texture specified as a blob or data URI, or via an external URL using THREE.TextureLoader

+ 60 - 6
examples/js/loaders/GLTFLoader.js

@@ -43,6 +43,11 @@
 
 				return new GLTFMaterialsIorExtension( parser );
 
+			} );
+			this.register( function ( parser ) {
+
+				return new GLTFMaterialsEmissiveStrengthExtension( parser );
+
 			} );
 			this.register( function ( parser ) {
 
@@ -360,6 +365,7 @@
 		KHR_TEXTURE_BASISU: 'KHR_texture_basisu',
 		KHR_TEXTURE_TRANSFORM: 'KHR_texture_transform',
 		KHR_MESH_QUANTIZATION: 'KHR_mesh_quantization',
+		KHR_MATERIALS_EMISSIVE_STRENGTH: 'KHR_materials_emissive_strength',
 		EXT_TEXTURE_WEBP: 'EXT_texture_webp',
 		EXT_MESHOPT_COMPRESSION: 'EXT_meshopt_compression'
 	};
@@ -528,6 +534,46 @@
 
 		}
 
+	}
+	/**
+ * Materials Emissive Strength Extension
+ *
+ * Specification: https://github.com/KhronosGroup/glTF/blob/5768b3ce0ef32bc39cdf1bef10b948586635ead3/extensions/2.0/Khronos/KHR_materials_emissive_strength/README.md
+ */
+
+
+	class GLTFMaterialsEmissiveStrengthExtension {
+
+		constructor( parser ) {
+
+			this.parser = parser;
+			this.name = EXTENSIONS.KHR_MATERIALS_EMISSIVE_STRENGTH;
+
+		}
+
+		extendMaterialParams( materialIndex, materialParams ) {
+
+			const parser = this.parser;
+			const materialDef = parser.json.materials[ materialIndex ];
+
+			if ( ! materialDef.extensions || ! materialDef.extensions[ this.name ] ) {
+
+				return Promise.resolve();
+
+			}
+
+			const emissiveStrength = materialDef.extensions[ this.name ].emissiveStrength;
+
+			if ( emissiveStrength !== undefined ) {
+
+				materialParams.emissiveIntensity = emissiveStrength;
+
+			}
+
+			return Promise.resolve();
+
+		}
+
 	}
 	/**
  * Clearcoat Materials Extension
@@ -989,7 +1035,7 @@
 
 			return this.detectSupport().then( function ( isSupported ) {
 
-				if ( isSupported ) return parser.loadTextureImage( textureIndex, source, loader );
+				if ( isSupported ) return parser.loadTextureImage( textureIndex, extension.source, loader );
 
 				if ( json.extensionsRequired && json.extensionsRequired.indexOf( name ) >= 0 ) {
 
@@ -1521,7 +1567,7 @@
 			material.aoMap = materialParams.aoMap === undefined ? null : materialParams.aoMap;
 			material.aoMapIntensity = 1.0;
 			material.emissive = materialParams.emissive;
-			material.emissiveIntensity = 1.0;
+			material.emissiveIntensity = materialParams.emissiveIntensity === undefined ? 1.0 : materialParams.emissiveIntensity;
 			material.emissiveMap = materialParams.emissiveMap === undefined ? null : materialParams.emissiveMap;
 			material.bumpMap = materialParams.bumpMap === undefined ? null : materialParams.bumpMap;
 			material.bumpScale = 1;
@@ -2021,13 +2067,17 @@
 			this.nodeNamesUsed = {}; // Use an THREE.ImageBitmapLoader if imageBitmaps are supported. Moves much of the
 			// expensive work of uploading a texture to the GPU off the main thread.
 
-			if ( typeof createImageBitmap !== 'undefined' && /^((?!chrome|android).)*safari/i.test( navigator.userAgent ) === false ) {
+			const isSafari = /^((?!chrome|android).)*safari/i.test( navigator.userAgent ) === true;
+			const isFirefox = navigator.userAgent.indexOf( 'Firefox' ) > - 1;
+			const firefoxVersion = isFirefox ? navigator.userAgent.match( /Firefox\/([0-9]+)\./ )[ 1 ] : - 1;
 
-				this.textureLoader = new THREE.ImageBitmapLoader( this.options.manager );
+			if ( typeof createImageBitmap === 'undefined' || isSafari || isFirefox && firefoxVersion < 98 ) {
+
+				this.textureLoader = new THREE.TextureLoader( this.options.manager );
 
 			} else {
 
-				this.textureLoader = new THREE.TextureLoader( this.options.manager );
+				this.textureLoader = new THREE.ImageBitmapLoader( this.options.manager );
 
 			}
 
@@ -2317,7 +2367,11 @@
 						break;
 
 					case 'animation':
-						dependency = this.loadAnimation( index );
+						dependency = this._invokeOne( function ( ext ) {
+
+							return ext.loadAnimation && ext.loadAnimation( index );
+
+						} );
 						break;
 
 					case 'camera':

+ 17 - 2
examples/js/loaders/MMDLoader.js

@@ -1863,7 +1863,7 @@
 			} );
 			this.uniforms = THREE.UniformsUtils.clone( THREE.MMDToonShader.uniforms ); // merged from MeshToon/Phong/MatcapMaterial
 
-			const exposePropertyNames = [ 'specular', 'shininess', 'opacity', 'diffuse', 'map', 'matcap', 'gradientMap', 'lightMap', 'lightMapIntensity', 'aoMap', 'aoMapIntensity', 'emissive', 'emissiveMap', 'bumpMap', 'bumpScale', 'normalMap', 'normalScale', 'displacemantBias', 'displacemantMap', 'displacemantScale', 'specularMap', 'alphaMap', 'envMap', 'reflectivity', 'refractionRatio' ];
+			const exposePropertyNames = [ 'specular', 'opacity', 'diffuse', 'map', 'matcap', 'gradientMap', 'lightMap', 'lightMapIntensity', 'aoMap', 'aoMapIntensity', 'emissive', 'emissiveMap', 'bumpMap', 'bumpScale', 'normalMap', 'normalScale', 'displacemantBias', 'displacemantMap', 'displacemantScale', 'specularMap', 'alphaMap', 'envMap', 'reflectivity', 'refractionRatio' ];
 
 			for ( const propertyName of exposePropertyNames ) {
 
@@ -1880,8 +1880,23 @@
 					}
 				} );
 
-			}
+			} // Special path for shininess to handle zero shininess properly
+
+
+			this._shininess = 30;
+			Object.defineProperty( this, 'shininess', {
+				get: function () {
+
+					return this._shininess;
 
+				},
+				set: function ( value ) {
+
+					this._shininess = value;
+					this.uniforms.shininess.value = Math.max( this._shininess, 1e-4 ); // To prevent pow( 0.0, 0.0 )
+
+				}
+			} );
 			Object.defineProperty( this, 'color', Object.getOwnPropertyDescriptor( this, 'diffuse' ) );
 			this.setValues( parameters );
 

+ 3 - 8
examples/js/objects/MarchingCubes.js

@@ -674,7 +674,7 @@
 
 			};
 
-			this.onBeforeRender = function () {
+			this.update = function () {
 
 				this.count = 0; // Triangulate. Yeah, this is slow.
 
@@ -701,15 +701,10 @@
 
 					}
 
-				} // reset unneeded data
+				} // set the draw range to only the processed triangles
 
 
-				for ( let i = this.count * 3; i < this.positionArray.length; i ++ ) {
-
-					this.positionArray[ i ] = 0.0;
-
-				} // update geometry data
-
+				this.geometry.setDrawRange( 0, this.count ); // update geometry data
 
 				geometry.getAttribute( 'position' ).needsUpdate = true;
 				geometry.getAttribute( 'normal' ).needsUpdate = true;

+ 4 - 1
examples/js/objects/Reflector.js

@@ -6,6 +6,7 @@
 
 			super( geometry );
 			this.type = 'Reflector';
+			this.camera = new THREE.PerspectiveCamera();
 			const scope = this;
 			const color = options.color !== undefined ? new THREE.Color( options.color ) : new THREE.Color( 0x7F7F7F );
 			const textureWidth = options.textureWidth || 512;
@@ -25,7 +26,7 @@
 			const target = new THREE.Vector3();
 			const q = new THREE.Vector4();
 			const textureMatrix = new THREE.Matrix4();
-			const virtualCamera = new THREE.PerspectiveCamera();
+			const virtualCamera = this.camera;
 			const renderTarget = new THREE.WebGLRenderTarget( textureWidth, textureHeight, {
 				samples: multisample
 			} );
@@ -196,6 +197,8 @@
 			vec4 base = texture2DProj( tDiffuse, vUv );
 			gl_FragColor = vec4( blendOverlay( base.rgb, color ), 1.0 );
 
+			#include <encodings_fragment>
+
 		}`
 	};
 

+ 4 - 1
examples/js/objects/Refractor.js

@@ -6,6 +6,7 @@
 
 			super( geometry );
 			this.type = 'Refractor';
+			this.camera = new THREE.PerspectiveCamera();
 			const scope = this;
 			const color = options.color !== undefined ? new THREE.Color( options.color ) : new THREE.Color( 0x7F7F7F );
 			const textureWidth = options.textureWidth || 512;
@@ -14,7 +15,7 @@
 			const shader = options.shader || Refractor.RefractorShader;
 			const multisample = options.multisample !== undefined ? options.multisample : 4; //
 
-			const virtualCamera = new THREE.PerspectiveCamera();
+			const virtualCamera = this.camera;
 			virtualCamera.matrixAutoUpdate = false;
 			virtualCamera.userData.refractor = true; //
 
@@ -244,6 +245,8 @@
 			vec4 base = texture2DProj( tDiffuse, vUv );
 			gl_FragColor = vec4( blendOverlay( base.rgb, color ), 1.0 );
 
+			#include <encodings_fragment>
+
 		}`
 	};
 

+ 0 - 4
examples/js/postprocessing/UnrealBloomPass.js

@@ -302,9 +302,6 @@
 					'blurTexture5': {
 						value: null
 					},
-					'dirtTexture': {
-						value: null
-					},
 					'bloomStrength': {
 						value: 1.0
 					},
@@ -329,7 +326,6 @@
 				uniform sampler2D blurTexture3;
 				uniform sampler2D blurTexture4;
 				uniform sampler2D blurTexture5;
-				uniform sampler2D dirtTexture;
 				uniform float bloomStrength;
 				uniform float bloomRadius;
 				uniform float bloomFactors[NUM_MIPS];

+ 133 - 17
examples/js/utils/BufferGeometryUtils.js

@@ -1,6 +1,24 @@
 ( function () {
 
-	function computeTangents( geometry, negateSign = true ) {
+	function computeTangents() {
+
+		throw new Error( 'BufferGeometryUtils: computeTangents renamed to computeMikkTSpaceTangents.' );
+
+	}
+
+	function computeMikkTSpaceTangents( geometry, MikkTSpace, negateSign = true ) {
+
+		if ( ! MikkTSpace || ! MikkTSpace.isReady ) {
+
+			throw new Error( 'BufferGeometryUtils: Initialized MikkTSpace library required.' );
+
+		}
+
+		if ( ! geometry.hasAttribute( 'position' ) || ! geometry.hasAttribute( 'normal' ) || ! geometry.hasAttribute( 'uv' ) ) {
+
+			throw new Error( 'BufferGeometryUtils: Tangents require "position", "normal", and "uv" attributes.' );
+
+		}
 
 		function getAttributeArray( attribute ) {
 
@@ -40,7 +58,7 @@
 		const _geometry = geometry.index ? geometry.toNonIndexed() : geometry; // Compute vertex tangents.
 
 
-		const tangents = generateTangents( getAttributeArray( _geometry.attributes.position ), getAttributeArray( _geometry.attributes.normal ), getAttributeArray( _geometry.attributes.uv ) ); // Texture coordinate convention of glTF differs from the apparent
+		const tangents = MikkTSpace.generateTangents( getAttributeArray( _geometry.attributes.position ), getAttributeArray( _geometry.attributes.normal ), getAttributeArray( _geometry.attributes.uv ) ); // Texture coordinate convention of glTF differs from the apparent
 		// default of the MikkTSpace library; .w component must be flipped.
 
 		if ( negateSign ) {
@@ -56,7 +74,13 @@
 
 		_geometry.setAttribute( 'tangent', new THREE.BufferAttribute( tangents, 4 ) );
 
-		return geometry.copy( _geometry );
+		if ( geometry !== _geometry ) {
+
+			geometry.copy( _geometry );
+
+		}
+
+		return geometry;
 
 	}
 	/**
@@ -371,13 +395,104 @@
 
 		return res;
 
+	} // returns a new, non-interleaved version of the provided attribute
+
+
+	function deinterleaveAttribute( attribute ) {
+
+		const cons = attribute.data.array.constructor;
+		const count = attribute.count;
+		const itemSize = attribute.itemSize;
+		const normalized = attribute.normalized;
+		const array = new cons( count * itemSize );
+		let newAttribute;
+
+		if ( attribute.isInstancedInterleavedBufferAttribute ) {
+
+			newAttribute = new InstancedBufferAttribute( array, itemSize, normalized, attribute.meshPerAttribute );
+
+		} else {
+
+			newAttribute = new THREE.BufferAttribute( array, itemSize, normalized );
+
+		}
+
+		for ( let i = 0; i < count; i ++ ) {
+
+			newAttribute.setX( i, attribute.getX( i ) );
+
+			if ( itemSize >= 2 ) {
+
+				newAttribute.setY( i, attribute.getY( i ) );
+
+			}
+
+			if ( itemSize >= 3 ) {
+
+				newAttribute.setZ( i, attribute.getZ( i ) );
+
+			}
+
+			if ( itemSize >= 4 ) {
+
+				newAttribute.setW( i, attribute.getW( i ) );
+
+			}
+
+		}
+
+		return newAttribute;
+
+	} // deinterleaves all attributes on the geometry
+
+	function deinterleaveGeometry( geometry ) {
+
+		const attributes = geometry.attributes;
+		const morphTargets = geometry.morphTargets;
+		const attrMap = new Map();
+
+		for ( const key in attributes ) {
+
+			const attr = attributes[ key ];
+
+			if ( attr.isInterleavedBufferAttribute ) {
+
+				if ( ! attrMap.has( attr ) ) {
+
+					attrMap.set( attr, deinterleaveAttribute( attr ) );
+
+				}
+
+				attributes[ key ] = attrMap.get( attr );
+
+			}
+
+		}
+
+		for ( const key in morphTargets ) {
+
+			const attr = morphTargets[ key ];
+
+			if ( attr.isInterleavedBufferAttribute ) {
+
+				if ( ! attrMap.has( attr ) ) {
+
+					attrMap.set( attr, deinterleaveAttribute( attr ) );
+
+				}
+
+				morphTargets[ key ] = attrMap.get( attr );
+
+			}
+
+		}
+
 	}
 	/**
  * @param {Array<BufferGeometry>} geometry
  * @return {number}
  */
 
-
 	function estimateBytesUsed( geometry ) {
 
 		// Return the estimated memory used by this geometry in bytes
@@ -676,7 +791,7 @@
 
 		const _morphC = new THREE.Vector3();
 
-		function _calculateMorphedAttributeData( object, material, attribute, morphAttribute, morphTargetsRelative, a, b, c, modifiedAttributeArray ) {
+		function _calculateMorphedAttributeData( object, attribute, morphAttribute, morphTargetsRelative, a, b, c, modifiedAttributeArray ) {
 
 			_vA.fromBufferAttribute( attribute, a );
 
@@ -686,7 +801,7 @@
 
 			const morphInfluences = object.morphTargetInfluences;
 
-			if ( material.morphTargets && morphAttribute && morphInfluences ) {
+			if ( morphAttribute && morphInfluences ) {
 
 				_morphA.set( 0, 0, 0 );
 
@@ -766,7 +881,7 @@
 		const groups = geometry.groups;
 		const drawRange = geometry.drawRange;
 		let i, j, il, jl;
-		let group, groupMaterial;
+		let group;
 		let start, end;
 		const modifiedPosition = new Float32Array( positionAttribute.count * positionAttribute.itemSize );
 		const modifiedNormal = new Float32Array( normalAttribute.count * normalAttribute.itemSize );
@@ -779,7 +894,6 @@
 				for ( i = 0, il = groups.length; i < il; i ++ ) {
 
 					group = groups[ i ];
-					groupMaterial = material[ group.materialIndex ];
 					start = Math.max( group.start, drawRange.start );
 					end = Math.min( group.start + group.count, drawRange.start + drawRange.count );
 
@@ -789,9 +903,9 @@
 						b = index.getX( j + 1 );
 						c = index.getX( j + 2 );
 
-						_calculateMorphedAttributeData( object, groupMaterial, positionAttribute, morphPosition, morphTargetsRelative, a, b, c, modifiedPosition );
+						_calculateMorphedAttributeData( object, positionAttribute, morphPosition, morphTargetsRelative, a, b, c, modifiedPosition );
 
-						_calculateMorphedAttributeData( object, groupMaterial, normalAttribute, morphNormal, morphTargetsRelative, a, b, c, modifiedNormal );
+						_calculateMorphedAttributeData( object, normalAttribute, morphNormal, morphTargetsRelative, a, b, c, modifiedNormal );
 
 					}
 
@@ -808,9 +922,9 @@
 					b = index.getX( i + 1 );
 					c = index.getX( i + 2 );
 
-					_calculateMorphedAttributeData( object, material, positionAttribute, morphPosition, morphTargetsRelative, a, b, c, modifiedPosition );
+					_calculateMorphedAttributeData( object, positionAttribute, morphPosition, morphTargetsRelative, a, b, c, modifiedPosition );
 
-					_calculateMorphedAttributeData( object, material, normalAttribute, morphNormal, morphTargetsRelative, a, b, c, modifiedNormal );
+					_calculateMorphedAttributeData( object, normalAttribute, morphNormal, morphTargetsRelative, a, b, c, modifiedNormal );
 
 				}
 
@@ -824,7 +938,6 @@
 				for ( i = 0, il = groups.length; i < il; i ++ ) {
 
 					group = groups[ i ];
-					groupMaterial = material[ group.materialIndex ];
 					start = Math.max( group.start, drawRange.start );
 					end = Math.min( group.start + group.count, drawRange.start + drawRange.count );
 
@@ -834,9 +947,9 @@
 						b = j + 1;
 						c = j + 2;
 
-						_calculateMorphedAttributeData( object, groupMaterial, positionAttribute, morphPosition, morphTargetsRelative, a, b, c, modifiedPosition );
+						_calculateMorphedAttributeData( object, positionAttribute, morphPosition, morphTargetsRelative, a, b, c, modifiedPosition );
 
-						_calculateMorphedAttributeData( object, groupMaterial, normalAttribute, morphNormal, morphTargetsRelative, a, b, c, modifiedNormal );
+						_calculateMorphedAttributeData( object, normalAttribute, morphNormal, morphTargetsRelative, a, b, c, modifiedNormal );
 
 					}
 
@@ -853,9 +966,9 @@
 					b = i + 1;
 					c = i + 2;
 
-					_calculateMorphedAttributeData( object, material, positionAttribute, morphPosition, morphTargetsRelative, a, b, c, modifiedPosition );
+					_calculateMorphedAttributeData( object, positionAttribute, morphPosition, morphTargetsRelative, a, b, c, modifiedPosition );
 
-					_calculateMorphedAttributeData( object, material, normalAttribute, morphNormal, morphTargetsRelative, a, b, c, modifiedNormal );
+					_calculateMorphedAttributeData( object, normalAttribute, morphNormal, morphTargetsRelative, a, b, c, modifiedNormal );
 
 				}
 
@@ -965,8 +1078,11 @@
 	}
 
 	THREE.BufferGeometryUtils = {};
+	THREE.BufferGeometryUtils.computeMikkTSpaceTangents = computeMikkTSpaceTangents;
 	THREE.BufferGeometryUtils.computeMorphedAttributes = computeMorphedAttributes;
 	THREE.BufferGeometryUtils.computeTangents = computeTangents;
+	THREE.BufferGeometryUtils.deinterleaveAttribute = deinterleaveAttribute;
+	THREE.BufferGeometryUtils.deinterleaveGeometry = deinterleaveGeometry;
 	THREE.BufferGeometryUtils.estimateBytesUsed = estimateBytesUsed;
 	THREE.BufferGeometryUtils.interleaveAttributes = interleaveAttributes;
 	THREE.BufferGeometryUtils.mergeBufferAttributes = mergeBufferAttributes;

+ 3 - 1
examples/jsm/controls/ArcballControls.js

@@ -1040,7 +1040,9 @@ class ArcballControls extends EventDispatcher {
 
 							}
 
-							this.applyTransformMatrix( this.scale( size, this._gizmos.position ) );
+							this._v3_1.setFromMatrixPosition(this._gizmoMatrixState);
+
+							this.applyTransformMatrix( this.scale( size, this._v3_1 ) );
 
 						}
 

+ 49 - 40
examples/jsm/exporters/GLTFExporter.js

@@ -225,24 +225,7 @@ function equalArray( array1, array2 ) {
  */
 function stringToArrayBuffer( text ) {
 
-	if ( window.TextEncoder !== undefined ) {
-
-		return new TextEncoder().encode( text ).buffer;
-
-	}
-
-	const array = new Uint8Array( new ArrayBuffer( text.length ) );
-
-	for ( let i = 0, il = text.length; i < il; i ++ ) {
-
-		const value = text.charCodeAt( i );
-
-		// Replacing multi-byte character with space(0x20).
-		array[ i ] = value > 0xFF ? 0x20 : value;
-
-	}
-
-	return array.buffer;
+	return new TextEncoder().encode( text ).buffer;
 
 }
 
@@ -356,6 +339,28 @@ function getPaddedArrayBuffer( arrayBuffer, paddingByte = 0 ) {
 
 let cachedCanvas = null;
 
+function getCanvas() {
+
+	if ( cachedCanvas ) {
+
+		return cachedCanvas;
+
+	}
+
+	if ( typeof OffscreenCanvas !== 'undefined' ) {
+
+		cachedCanvas = new OffscreenCanvas( 1, 1 );
+
+	} else {
+
+		cachedCanvas = document.createElement( 'canvas' );
+
+	}
+
+	return cachedCanvas;
+
+}
+
 /**
  * Writer
  */
@@ -454,7 +459,7 @@ class GLTFWriter {
 
 			// https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#glb-file-format-specification
 
-			const reader = new window.FileReader();
+			const reader = new FileReader();
 			reader.readAsArrayBuffer( blob );
 			reader.onloadend = function () {
 
@@ -488,7 +493,7 @@ class GLTFWriter {
 					binaryChunk
 				], { type: 'application/octet-stream' } );
 
-				const glbReader = new window.FileReader();
+				const glbReader = new FileReader();
 				glbReader.readAsArrayBuffer( glbBlob );
 				glbReader.onloadend = function () {
 
@@ -502,7 +507,7 @@ class GLTFWriter {
 
 			if ( json.buffers && json.buffers.length > 0 ) {
 
-				const reader = new window.FileReader();
+				const reader = new FileReader();
 				reader.readAsDataURL( blob );
 				reader.onloadend = function () {
 
@@ -701,7 +706,7 @@ class GLTFWriter {
 		const width = Math.max( metalness?.width || 0, roughness?.width || 0 );
 		const height = Math.max( metalness?.height || 0, roughness?.height || 0 );
 
-		const canvas = document.createElement( 'canvas' );
+		const canvas = getCanvas();
 		canvas.width = width;
 		canvas.height = height;
 
@@ -901,7 +906,7 @@ class GLTFWriter {
 
 		return new Promise( function ( resolve ) {
 
-			const reader = new window.FileReader();
+			const reader = new FileReader();
 			reader.readAsArrayBuffer( blob );
 			reader.onloadend = function () {
 
@@ -1053,7 +1058,7 @@ class GLTFWriter {
 
 		if ( options.embedImages ) {
 
-			const canvas = cachedCanvas = cachedCanvas || document.createElement( 'canvas' );
+			const canvas = getCanvas();
 
 			canvas.width = Math.min( image.width, options.maxTextureSize );
 			canvas.height = Math.min( image.height, options.maxTextureSize );
@@ -1067,14 +1072,7 @@ class GLTFWriter {
 
 			}
 
-			if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) ||
-				( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) ||
-				( typeof OffscreenCanvas !== 'undefined' && image instanceof OffscreenCanvas ) ||
-				( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ) {
-
-				ctx.drawImage( image, 0, 0, canvas.width, canvas.height );
-
-			} else {
+			if ( image.data !== undefined ) { // THREE.DataTexture
 
 				if ( format !== RGBAFormat ) {
 
@@ -1101,24 +1099,35 @@ class GLTFWriter {
 
 				ctx.putImageData( new ImageData( data, image.width, image.height ), 0, 0 );
 
+			} else {
+
+				ctx.drawImage( image, 0, 0, canvas.width, canvas.height );
+
 			}
 
 			if ( options.binary === true ) {
 
-				pending.push( new Promise( function ( resolve ) {
+				let toBlobPromise;
+
+				if ( canvas.toBlob !== undefined ) {
+
+					toBlobPromise = new Promise( ( resolve ) => canvas.toBlob( resolve, mimeType ) );
 
-					canvas.toBlob( function ( blob ) {
+				} else {
+
+					toBlobPromise = canvas.convertToBlob( { type: mimeType } );
+
+				}
 
-						writer.processBufferViewImage( blob ).then( function ( bufferViewIndex ) {
+				pending.push( toBlobPromise.then( blob =>
 
-							imageDef.bufferView = bufferViewIndex;
-							resolve();
+					writer.processBufferViewImage( blob ).then( bufferViewIndex => {
 
-						} );
+						imageDef.bufferView = bufferViewIndex;
 
-					}, mimeType );
+					} )
 
-				} ) );
+				) );
 
 			} else {
 

File diff suppressed because it is too large
+ 0 - 0
examples/jsm/libs/mikktspace.module.js


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