2
0
Эх сурвалжийг харах

Merge remote-tracking branch 'upstream/dev' into geometry-compression-example

LeonYuanYao 5 жил өмнө
parent
commit
fb89b553d0
100 өөрчлөгдсөн 2114 нэмэгдсэн , 1684 устгасан
  1. 3 2
      build/three.js
  2. 445 454
      build/three.min.js
  3. 3 2
      build/three.module.js
  4. 3 0
      docs/api/en/core/InterleavedBufferAttribute.html
  5. 2 2
      docs/api/en/helpers/ArrowHelper.html
  6. 81 0
      docs/api/en/helpers/VertexTangentsHelper.html
  7. 0 1
      docs/api/en/lights/DirectionalLight.html
  8. 2 2
      docs/api/en/materials/MeshStandardMaterial.html
  9. 13 7
      docs/api/en/renderers/WebGLRenderer.html
  10. 6 6
      docs/api/zh/core/Face3.html
  11. 2 2
      docs/api/zh/helpers/ArrowHelper.html
  12. 81 0
      docs/api/zh/helpers/VertexTangentsHelper.html
  13. 0 1
      docs/api/zh/lights/DirectionalLight.html
  14. 1 1
      docs/api/zh/lights/SpotLight.html
  15. 2 2
      docs/api/zh/materials/MeshStandardMaterial.html
  16. 4 8
      docs/api/zh/renderers/WebGLRenderer.html
  17. 1 2
      docs/examples/en/loaders/GLTFLoader.html
  18. 1 2
      docs/examples/zh/loaders/GLTFLoader.html
  19. 4 2
      docs/list.js
  20. 3 3
      docs/manual/en/introduction/Browser-support.html
  21. 3 3
      docs/manual/zh/introduction/Browser-support.html
  22. 3 0
      docs/prettify/threejs.css
  23. 0 2
      editor/index.html
  24. 1 18
      editor/js/Menubar.File.js
  25. 0 14
      editor/js/Sidebar.Project.js
  26. 1 1
      editor/js/Viewport.js
  27. 1 7
      editor/js/libs/app.js
  28. 0 8
      editor/js/libs/tern-threejs/threejs.js
  29. 0 2
      editor/sw.js
  30. 1 0
      examples/files.js
  31. 7 0
      examples/index.html
  32. 29 0
      examples/js/controls/TransformControls.js
  33. 141 1
      examples/js/lines/LineSegments2.js
  34. 2 2
      examples/js/lines/LineSegmentsGeometry.js
  35. 11 9
      examples/js/loaders/BasisTextureLoader.js
  36. 47 4
      examples/js/loaders/DRACOLoader.js
  37. 2 2
      examples/js/loaders/FBXLoader.js
  38. 88 64
      examples/js/loaders/GLTFLoader.js
  39. 17 9
      examples/js/loaders/SVGLoader.js
  40. 1 0
      examples/js/misc/MD2Character.js
  41. 1 0
      examples/js/misc/MD2CharacterComplex.js
  42. 44 5
      examples/js/pmrem/PMREMGenerator.js
  43. 6 0
      examples/js/postprocessing/EffectComposer.js
  44. 4 4
      examples/js/postprocessing/SSAOPass.js
  45. 2 0
      examples/js/renderers/CSS3DRenderer.js
  46. 0 263
      examples/js/vr/WebVR.js
  47. 29 0
      examples/jsm/controls/TransformControls.js
  48. 146 2
      examples/jsm/lines/LineSegments2.js
  49. 2 2
      examples/jsm/lines/LineSegmentsGeometry.js
  50. 11 9
      examples/jsm/loaders/BasisTextureLoader.js
  51. 47 4
      examples/jsm/loaders/DRACOLoader.js
  52. 2 2
      examples/jsm/loaders/FBXLoader.js
  53. 88 64
      examples/jsm/loaders/GLTFLoader.js
  54. 17 9
      examples/jsm/loaders/SVGLoader.js
  55. 1 1
      examples/jsm/math/MeshSurfaceSampler.js
  56. 3 1
      examples/jsm/misc/MD2Character.js
  57. 3 1
      examples/jsm/misc/MD2CharacterComplex.js
  58. 54 14
      examples/jsm/misc/TubePainter.js
  59. 2 2
      examples/jsm/nodes/accessors/ReflectNode.js
  60. 1 1
      examples/jsm/nodes/core/NodeBuilder.d.ts
  61. 2 5
      examples/jsm/nodes/core/NodeBuilder.js
  62. 2 2
      examples/jsm/nodes/inputs/TextureNode.d.ts
  63. 16 0
      examples/jsm/nodes/materials/MeshStandardNodeMaterial.d.ts
  64. 16 0
      examples/jsm/nodes/materials/PhongNodeMaterial.d.ts
  65. 7 0
      examples/jsm/nodes/materials/SpriteNodeMaterial.d.ts
  66. 20 0
      examples/jsm/nodes/materials/StandardNodeMaterial.d.ts
  67. 3 5
      examples/jsm/nodes/materials/nodes/PhongNode.d.ts
  68. 1 2
      examples/jsm/nodes/materials/nodes/SpriteNode.d.ts
  69. 3 5
      examples/jsm/nodes/materials/nodes/StandardNode.d.ts
  70. 9 53
      examples/jsm/nodes/misc/TextureCubeNode.js
  71. 219 146
      examples/jsm/nodes/misc/TextureCubeUVNode.js
  72. 2 0
      examples/jsm/pmrem/PMREMGenerator.d.ts
  73. 44 5
      examples/jsm/pmrem/PMREMGenerator.js
  74. 6 0
      examples/jsm/postprocessing/EffectComposer.js
  75. 1 0
      examples/jsm/postprocessing/Pass.d.ts
  76. 6 0
      examples/jsm/postprocessing/Pass.js
  77. 4 4
      examples/jsm/postprocessing/SSAOPass.js
  78. 2 0
      examples/jsm/renderers/CSS3DRenderer.js
  79. 12 0
      examples/jsm/utils/RoughnessMipmapper.d.ts
  80. 222 0
      examples/jsm/utils/RoughnessMipmapper.js
  81. 0 11
      examples/jsm/vr/WebVR.d.ts
  82. 0 267
      examples/jsm/vr/WebVR.js
  83. 6 14
      examples/jsm/webxr/ARButton.js
  84. 12 101
      examples/jsm/webxr/VRButton.js
  85. 4 2
      examples/misc_controls_transform.html
  86. 3 2
      examples/misc_exporter_collada.html
  87. BIN
      examples/textures/equirectangular/spot1Lux.hdr
  88. 1 2
      examples/webaudio_orientation.html
  89. 2 2
      examples/webgl_animation_cloth.html
  90. 1 2
      examples/webgl_animation_keyframes.html
  91. 1 2
      examples/webgl_animation_multiple.html
  92. 1 2
      examples/webgl_animation_skinning_blending.html
  93. 1 2
      examples/webgl_animation_skinning_morph.html
  94. 1 3
      examples/webgl_buffergeometry.html
  95. 1 3
      examples/webgl_buffergeometry_drawrange.html
  96. 2 2
      examples/webgl_buffergeometry_instancing_lambert.html
  97. 1 3
      examples/webgl_buffergeometry_lines.html
  98. 1 3
      examples/webgl_buffergeometry_lines_indexed.html
  99. 1 3
      examples/webgl_buffergeometry_uint.html
  100. 3 2
      examples/webgl_geometry_teapot.html

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 3 - 2
build/three.js


Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 445 - 454
build/three.min.js


Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 3 - 2
build/three.module.js


+ 3 - 0
docs/api/en/core/InterleavedBufferAttribute.html

@@ -62,6 +62,9 @@
 
 		<h2>Methods</h2>
 
+		<h3>[method:this applyMatrix4]( [param:Matrix4 m] )</h3>
+		<p>Applies matrix [page:Matrix4 m] to every Vector3 element of this InterleavedBufferAttribute.</p>
+
 		<h3>[method:Number getX]( [param:Integer index] ) </h3>
 		<p>Returns the x component of the item at the given index.</p>
 

+ 2 - 2
docs/api/en/helpers/ArrowHelper.html

@@ -47,7 +47,7 @@
 		[page:Number length] -- length of the arrow. Default is *1*.<br />
 		[page:Number hex] -- hexadecimal value to define color. Default is 0xffff00.<br />
 		[page:Number headLength] -- The length of the head of the arrow. Default is 0.2 * length.<br />
-		[page:Number headWidth] -- The length of the width of the arrow. Default is 0.2 * headLength.
+		[page:Number headWidth] -- The width of the head of the arrow. Default is 0.2 * headLength.<br />
 		</p>
 
 		<h2>Properties</h2>
@@ -79,7 +79,7 @@
 		<p>
 		length -- The desired length.<br />
 		headLength -- The length of the head of the arrow.<br />
-		headWidth -- The length of the width of the arrow.<br /><br />
+		headWidth -- The width of the head of the arrow.<br /><br />
 
 		Sets the length of the arrowhelper.
 		</p>

+ 81 - 0
docs/api/en/helpers/VertexTangentsHelper.html

@@ -0,0 +1,81 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<meta charset="utf-8" />
+		<base href="../../../" />
+		<script src="list.js"></script>
+		<script src="page.js"></script>
+		<link type="text/css" rel="stylesheet" href="page.css" />
+	</head>
+	<body>
+		[page:Object3D] &rarr; [page:Line] &rarr; [page:LineSegments] &rarr;
+
+		<h1>[name]</h1>
+
+		<p class="desc">
+			Renders arrows to visualize an object's vertex tangent vectors.
+			Requires that tangents have been specified in a [page:BufferAttribute custom attribute] or
+			have been calculated using [page:BufferGeometryUtils.computeTangents computeTangents].<br /><br />
+
+			This helper supports [page:BufferGeometry] only.
+		</p>
+
+		<h2>Example</h2>
+
+		[example:webgl_helpers WebGL / helpers]
+
+		<code>
+		var geometry = new THREE.BoxBufferGeometry( 10, 10, 10, 2, 2, 2 );
+		var material = new THREE.MeshNormalMaterial();
+		var box = new THREE.Mesh( geometry, material );
+
+		var helper = new THREE.VertexTangentsHelper( box, 1, 0x00ffff, 1 );
+
+		scene.add( box );
+		scene.add( helper );
+		</code>
+
+
+		<h2>Constructor</h2>
+
+
+		<h3>[name]( [param:Object3D object], [param:Number size], [param:Hex color], [param:Number linewidth] )</h3>
+		<p>
+			[page:Object3D object] -- object for which to render vertex tangents.<br />
+			[page:Number size] -- (optional) length of the arrows. Default is *1*.<br />
+			[page:Hex color] -- hex color of the arrows. Default is 0x00ffff.<br />
+			[page:Number linewidth] -- (optional) width of the arrow lines. Default is *1*. (Setting lineWidth is currently not supported.)
+		</p>
+
+
+		<h2>Properties</h2>
+		<p>See the base [page:LineSegments] class for common properties.</p>
+
+		<h3>[property:object matrixAutoUpdate]</h3>
+		<p>
+			See [page:Object3D.matrixAutoUpdate]. Set to *false* here as the helper is using the
+			objects's [page:Object3D.matrixWorld matrixWorld].
+		</p>
+
+		<h3>[property:Object3D object]</h3>
+		<p>The object for which the vertex tangents are being visualized.</p>
+
+		<h3>[property:Number size]</h3>
+		<p>Length of the arrows. Default is *1*.</p>
+
+
+		<h2>Methods</h2>
+		<p>See the base [page:LineSegments] class for common methods.</p>
+
+
+		<h3>[method:null update]()</h3>
+		<p>Updates the vertex tangents preview based on the object's world transform.</p>
+
+
+		<h2>Source</h2>
+
+		<p>
+			[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
+		</p>
+	</body>
+</html>

+ 0 - 1
docs/api/en/lights/DirectionalLight.html

@@ -41,7 +41,6 @@
 		<h2>Example</h2>
 		<p>
 			[example:misc_controls_fly controls / fly ]<br />
-			[example:webvr_cubes cubes ]<br />
 			[example:webgl_effects_parallaxbarrier effects / parallaxbarrier ]<br />
 			[example:webgl_effects_stereo effects / stereo ]<br />
 			[example:webgl_geometry_extrude_splines geometry / extrude / splines ]<br />

+ 2 - 2
docs/api/en/materials/MeshStandardMaterial.html

@@ -201,7 +201,7 @@
 		<h3>[property:Float metalness]</h3>
 		<p>
 			How much the material is like a metal. Non-metallic materials such as wood or stone use 0.0, metallic use 1.0, with nothing
-			(usually) in between. Default is 0.5. A value between 0.0 and 1.0 could be used for a rusty metal look. If metalnessMap is
+			(usually) in between. Default is 0.0. A value between 0.0 and 1.0 could be used for a rusty metal look. If metalnessMap is
 			also provided, both values are multiplied.
 		</p>
 
@@ -245,7 +245,7 @@
 
 		<h3>[property:Float roughness]</h3>
 		<p>
-			How rough the material appears. 0.0 means a smooth mirror reflection, 1.0 means fully diffuse. Default is 0.5.
+			How rough the material appears. 0.0 means a smooth mirror reflection, 1.0 means fully diffuse. Default is 1.0.
 			If roughnessMap is also provided, both values are multiplied.
 		</p>
 

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

@@ -164,13 +164,9 @@
 		<h3>[property:Float gammaFactor]</h3>
 		<p>Default is *2*. </p>
 
-
-		<h3>[property:Boolean gammaInput]</h3>
-		<p>If set, then it expects that all textures and colors are premultiplied gamma. Default is *false*.</p>
-
-
-		<h3>[property:Boolean gammaOutput]</h3>
-		<p>If set, then it expects that all textures and colors need to be outputted in premultiplied gamma. Default is *false*.</p>
+		<h3>[property:number outputEncoding]</h3>
+		<p>Defines the output encoding of the renderer. Default is [page:Textures THREE.LinearEncoding].</p>
+		<p>See the [page:Textures texture constants] page for details of other formats.</p>
 
 		<h3>[property:Object info]</h3>
 		<p>An object with a series of statistical information about the graphics board memory and the rendering process. Useful for debugging or just for the sake of curiosity. The object contains the following fields:</p>
@@ -477,6 +473,16 @@
 			scissor area will be affected by further renderer actions.
 		</p>
 
+		<h3>[method:null setOpaqueSort]( [param:Function method] )</h3>
+		<p>
+		Sets the custom opaque sort function for the WebGLRenderLists. Pass null to use the default painterSortStable function.
+		</p>
+
+		<h3>[method:null setTransparentSort]( [param:Function method] )</h3>
+		<p>
+		Sets the custom transparent sort function for the WebGLRenderLists. Pass null to use the default reversePainterSortStable function.
+		</p>
+
 		<h3>[method:null setSize]( [param:Integer width], [param:Integer height], [param:Boolean updateStyle] )</h3>
 		<p>
 		Resizes the output canvas to (width, height) with device pixel ratio taken into account,

+ 6 - 6
docs/api/zh/core/Face3.html

@@ -11,8 +11,8 @@
 		<h1>[name]</h1>
 
 		<p class="desc">
-			在 [page:Geometry] 中被使用到的三角面。这些三角面会为所有标准几何体自动创建。
-			然而,如果你正在构建一个自定义几何体,你需要手动创建这些三角面
+			在 [page:Geometry] 中被使用到的三角面。这些三角面会为所有标准几何体自动创建。
+			然而,如果你正在构建一个自定义几何体,你需要手动创建这些三角面。
 		</p>
 
 
@@ -26,22 +26,22 @@
 		<code>
 var material = new THREE.MeshStandardMaterial( { color : 0x00cc00 } );
 
-//创建仅有一个三角面的几何体
+// 创建仅有一个三角面的几何体
 var geometry = new THREE.Geometry();
 geometry.vertices.push( new THREE.Vector3( -50, -50, 0 ) );
 geometry.vertices.push( new THREE.Vector3(  50, -50, 0 ) );
 geometry.vertices.push( new THREE.Vector3(  50,  50, 0 ) );
 
-//利用顶点 0, 1, 2 创建一个面
+// 利用顶点 0, 1, 2 创建一个面
 var normal = new THREE.Vector3( 0, 1, 0 ); //optional
 var color = new THREE.Color( 0xffaa00 ); //optional
 var materialIndex = 0; //optional
 var face = new THREE.Face3( 0, 1, 2, normal, color, materialIndex );
 
-//将创建的面添加到几何体的面的队列
+// 将创建的面添加到几何体的面的队列
 geometry.faces.push( face );
 
-//如果没有特别指明,面和顶点的法向量可以通过如下代码自动计算
+// 如果没有特别指明,面和顶点的法向量可以通过如下代码自动计算
 geometry.computeFaceNormals();
 geometry.computeVertexNormals();
 

+ 2 - 2
docs/api/zh/helpers/ArrowHelper.html

@@ -47,7 +47,7 @@
 		[page:Number length] -- 箭头的长度. 默认为 *1*.<br />
 		[page:Number hex] -- 定义的16进制颜色值. 默认为 0xffff00.<br />
 		[page:Number headLength] -- 箭头头部(锥体)的长度. 默认为箭头长度的0.2倍(0.2 * length).<br />
-		[page:Number headWidth] -- 箭头的宽度. 默认为箭头头部(锥体)长度的0.2倍(0.2 * headLength).
+		[page:Number headWidth] -- The width of the head of the arrow. Default is 0.2 * headLength.
 		</p>
 
 		<h2>属性</h2>
@@ -78,7 +78,7 @@
 		<p>
 		length -- 要设置的长度.<br />
 		headLength -- 要设置的箭头头部(锥体)的长度.<br />
-		headWidth -- 要设置的箭头的宽度.<br /><br />
+		headWidth -- The width of the head of the arrow.<br /><br />
 
 		设置箭头辅助对象的长度.
 		</p>

+ 81 - 0
docs/api/zh/helpers/VertexTangentsHelper.html

@@ -0,0 +1,81 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<meta charset="utf-8" />
+		<base href="../../../" />
+		<script src="list.js"></script>
+		<script src="page.js"></script>
+		<link type="text/css" rel="stylesheet" href="page.css" />
+	</head>
+	<body>
+		[page:Object3D] &rarr; [page:Line] &rarr; [page:LineSegments] &rarr;
+
+		<h1>[name]</h1>
+
+		<p class="desc">
+			Renders arrows to visualize an object's vertex tangent vectors.
+			Requires that tangents have been specified in a [page:BufferAttribute custom attribute] or
+			have been calculated using [page:BufferGeometryUtils.computeTangents computeTangents].<br /><br />
+
+			This helper supports [page:BufferGeometry] only.
+		</p>
+
+		<h2>Example</h2>
+
+		[example:webgl_helpers WebGL / helpers]
+
+		<code>
+		var geometry = new THREE.BoxBufferGeometry( 10, 10, 10, 2, 2, 2 );
+		var material = new THREE.MeshNormalMaterial();
+		var box = new THREE.Mesh( geometry, material );
+
+		var helper = new THREE.VertexTangentsHelper( box, 1, 0x00ffff, 1 );
+
+		scene.add( box );
+		scene.add( helper );
+		</code>
+
+
+		<h2>Constructor</h2>
+
+
+		<h3>[name]( [param:Object3D object], [param:Number size], [param:Hex color], [param:Number linewidth] )</h3>
+		<p>
+			[page:Object3D object] -- object for which to render vertex tangents.<br />
+			[page:Number size] -- (optional) length of the arrows. Default is *1*.<br />
+			[page:Hex color] -- hex color of the arrows. Default is 0x00ffff.<br />
+			[page:Number linewidth] -- (optional) width of the arrow lines. Default is *1*. (Setting lineWidth is currently not supported.)
+		</p>
+
+
+		<h2>Properties</h2>
+		<p>See the base [page:LineSegments] class for common properties.</p>
+
+		<h3>[property:object matrixAutoUpdate]</h3>
+		<p>
+			See [page:Object3D.matrixAutoUpdate]. Set to *false* here as the helper is using the
+			objects's [page:Object3D.matrixWorld matrixWorld].
+		</p>
+
+		<h3>[property:Object3D object]</h3>
+		<p>The object for which the vertex tangents are being visualized.</p>
+
+		<h3>[property:Number size]</h3>
+		<p>Length of the arrows. Default is *1*.</p>
+
+
+		<h2>Methods</h2>
+		<p>See the base [page:LineSegments] class for common methods.</p>
+
+
+		<h3>[method:null update]()</h3>
+		<p>Updates the vertex tangents preview based on the object's world transform.</p>
+
+
+		<h2>Source</h2>
+
+		<p>
+			[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
+		</p>
+	</body>
+</html>

+ 0 - 1
docs/api/zh/lights/DirectionalLight.html

@@ -37,7 +37,6 @@
 		<h2>示例</h2>
 		<p>
 			[example:misc_controls_fly controls / fly ]<br />
-			[example:webvr_cubes cubes ]<br />
 			[example:webgl_effects_parallaxbarrier effects / parallaxbarrier ]<br />
 			[example:webgl_effects_stereo effects / stereo ]<br />
 			[example:webgl_geometry_extrude_splines geometry / extrude / splines ]<br />

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

@@ -13,7 +13,7 @@
 		<h1>聚光灯([name])</h1>
 
 		<p class="desc">
-			聚光灯是从一个方向上的一个点发出,沿着一个圆锥体,它离光越远,它的尺寸就越大。 <br /><br />
+			光线从一个点沿一个方向射出,随着光线照射的变远,光线圆锥体的尺寸也逐渐增大。<br /><br />
 
 			该光源可以投射阴影 - 跳转至 [page:SpotLightShadow] 查看更多细节。
 		</p>

+ 2 - 2
docs/api/zh/materials/MeshStandardMaterial.html

@@ -164,7 +164,7 @@
 
 		<h3>[property:Float metalness]</h3>
 		<p> 材质与金属的相似度。非金属材质,如木材或石材,使用0.0,金属使用1.0,通常没有中间值。
-			默认值为0.5。0.0到1.0之间的值可用于生锈金属的外观。如果还提供了metalnessMap,则两个值相乘。
+			默认值为0.0。0.0到1.0之间的值可用于生锈金属的外观。如果还提供了metalnessMap,则两个值相乘。
 		</p>
 
 		<h3>[property:Texture metalnessMap]</h3>
@@ -197,7 +197,7 @@
 		</p>
 
 		<h3>[property:Float roughness]</h3>
-		<p> 材质的粗糙程度。0.0表示平滑的镜面反射,1.0表示完全漫反射。默认值为0.5。如果还提供roughnessMap,则两个值相乘。
+		<p> 材质的粗糙程度。0.0表示平滑的镜面反射,1.0表示完全漫反射。默认值为1.0。如果还提供roughnessMap,则两个值相乘。
 		</p>
 
 		<h3>[property:Texture roughnessMap]</h3>

+ 4 - 8
docs/api/zh/renderers/WebGLRenderer.html

@@ -143,13 +143,9 @@
 		<h3>[property:Float gammaFactor]</h3>
 		<p>默认是 *2*. </p>
 
-
-		<h3>[property:Boolean gammaInput]</h3>
-		<p>如果设置,那么所有的纹理和颜色都会预乘gamma。 默认值是*false*.</p>
-
-
-		<h3>[property:Boolean gammaOutput]</h3>
-		<p>如果设置, 那么它期望所有纹理和颜色需要乘以gamma输出。 默认值*false*.</p>
+		<h3>[property:number outputEncoding]</h3>
+		<p>Defines the output encoding of the renderer. Default is [page:Textures THREE.LinearEncoding].</p>
+		<p>See the [page:Textures texture constants] page for details of other formats.</p>
 
 		<h3>[property:Object info]</h3>
 		<p>一个对象,包含有关图形板内存和渲染过程的一系列统计信息。这些信息可用于调试或仅仅满足下好奇心。改对象包含以下字段:</p>
@@ -218,7 +214,7 @@
 		</p>
 
 		<h3>[property:Boolean shadowMap.enabled]</h3>
-		<p>如果设置, 请在场景中使用阴影贴图。 默认是 *false*</p>
+		<p>如果设置开启,允许在场景中使用阴影贴图。默认是 *false*。</p>
 
 		<h3>[property:Boolean shadowMap.autoUpdate]</h3>
 		<p>启用场景中的阴影自动更新。默认是*true*</p>

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

@@ -111,8 +111,7 @@
 		in linear colorspace, always configure [page:WebGLRenderer] as follows when using glTF:</p>
 
 		<code>
-		renderer.gammaOutput = true;
-		renderer.gammaFactor = 2.2;
+		renderer.outputEncoding = THREE.sRGBEncoding;
 		</code>
 
 		<p>GLTFLoader will automatically configure textures referenced from a .gltf or .glb file correctly, with the

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

@@ -107,8 +107,7 @@
 		颜色空间并显示在屏幕上。除非你需要使用线性颜色空间进行后期处理,否则请在使用glTF的时候将[page:WebGLRenderer]进行如下配置:</p>
 
 		<code>
-		renderer.gammaOutput = true;
-		renderer.gammaFactor = 2.2;
+		renderer.outputEncoding = THREE.sRGBEncoding;
 		</code>
 
 		<p>假设渲染器的配置如上所示,则GLTFLoader将可以正确地自动配置从.gltf或.glb文件中引用的纹理。

+ 4 - 2
docs/list.js

@@ -202,7 +202,8 @@ var list = {
 				"RectAreaLightHelper": "api/en/helpers/RectAreaLightHelper",
 				"SkeletonHelper": "api/en/helpers/SkeletonHelper",
 				"SpotLightHelper": "api/en/helpers/SpotLightHelper",
-				"VertexNormalsHelper": "api/en/helpers/VertexNormalsHelper"
+				"VertexNormalsHelper": "api/en/helpers/VertexNormalsHelper",
+				"VertexTangentsHelper": "api/en/helpers/VertexTangentsHelper"
 			},
 
 			"Lights": {
@@ -646,7 +647,8 @@ var list = {
 				"RectAreaLightHelper": "api/zh/helpers/RectAreaLightHelper",
 				"SkeletonHelper": "api/zh/helpers/SkeletonHelper",
 				"SpotLightHelper": "api/zh/helpers/SpotLightHelper",
-				"VertexNormalsHelper": "api/zh/helpers/VertexNormalsHelper"
+				"VertexNormalsHelper": "api/zh/helpers/VertexNormalsHelper",
+				"VertexTangentsHelper": "api/zh/helpers/VertexTangentsHelper"
 			},
 
 			"灯光": {

+ 3 - 3
docs/manual/en/introduction/Browser-support.html

@@ -52,9 +52,9 @@
 					<td>Audio, AudioContext, AudioListener, etc.</td>
 				</tr>
 				<tr>
-					<td>WebVR API</td>
+					<td>WebXR Device API</td>
 					<td>Source</td>
-					<td>WebVRManager, etc.</td>
+					<td>WebXRManager</td>
 				</tr>
 				<tr>
 					<td>Blob</td>
@@ -64,7 +64,7 @@
 				<tr>
 					<td>Promise</td>
 					<td>Examples</td>
-					<td>GLTFLoader, GLTFExporter, WebVR, VREffect, etc.</td>
+					<td>GLTFLoader, DRACOLoader, BasisTextureLoader, GLTFExporter, VRButton, ARButton, etc.</td>
 				</tr>
 				<tr>
 					<td>Fetch</td>

+ 3 - 3
docs/manual/zh/introduction/Browser-support.html

@@ -54,9 +54,9 @@
 					<td>Audio, AudioContext, AudioListener, etc.</td>
 				</tr>
 				<tr>
-					<td>WebVR API</td>
+					<td>WebXR Device API</td>
 					<td>Source</td>
-					<td>WebVRManager, etc.</td>
+					<td>WebXRManager</td>
 				</tr>
 				<tr>
 					<td>Blob</td>
@@ -66,7 +66,7 @@
 				<tr>
 					<td>Promise</td>
 					<td>Examples</td>
-					<td>GLTFLoader, GLTFExporter, WebVR, VREffect, etc.</td>
+					<td>GLTFLoader, DRACOLoader, BasisTextureLoader, GLTFExporter, VRButton, ARButton, etc.</td>
 				</tr>
 				<tr>
 					<td>Fetch</td>

+ 3 - 0
docs/prettify/threejs.css

@@ -16,6 +16,9 @@ pre.prettyprint, code.prettyprint {
 
 @media (prefers-color-scheme: dark) {
 
+	pre .tag, code .tag { color: #2194ce; } /* HTML tag */
+	pre .atn, code .atn { color: #BB55FF; } /* HTML attribute name */
+	pre .atv, code .atv { color: #30b030; } /* HTML attribute value */
 	pre .str, code .str { color: #BB55FF; } /* string */
 	pre .com, code .com { color: #666666; } /* comment */
 	pre .lit, code .lit { color: #ff3399; } /* literal */

+ 0 - 2
editor/index.html

@@ -86,8 +86,6 @@
 		<script src="js/Player.js"></script>
 		<script src="js/Script.js"></script>
 
-		<script src="../examples/js/vr/WebVR.js"></script>
-
 		<script src="js/EditorControls.js"></script>
 		<script src="js/Storage.js"></script>
 

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

@@ -349,8 +349,6 @@ Menubar.File = function ( editor ) {
 		output.metadata.type = 'App';
 		delete output.history;
 
-		var vr = output.project.vr;
-
 		output = JSON.stringify( output, parseNumber, '\t' );
 		output = output.replace( /[\n\t]+([\d\.e\-\[\]]+)/g, '$1' );
 
@@ -373,12 +371,6 @@ Menubar.File = function ( editor ) {
 
 			var includes = [];
 
-			if ( vr ) {
-
-				includes.push( '<script src="js/WebVR.js"></script>' );
-
-			}
-
 			content = content.replace( '<!-- includes -->', includes.join( '\n\t\t' ) );
 
 			var editButton = '';
@@ -395,6 +387,7 @@ Menubar.File = function ( editor ) {
 					'			document.body.appendChild( button );',
 					''
 				].join( '\n' );
+
 			}
 
 			content = content.replace( '\n\t\t\t/* edit button */\n', editButton );
@@ -413,16 +406,6 @@ Menubar.File = function ( editor ) {
 
 		} );
 
-		if ( vr ) {
-
-			loader.load( '../examples/js/vr/WebVR.js', function ( content ) {
-
-				zip.file( 'js/WebVR.js', content );
-
-			} );
-
-		}
-
 	} );
 	options.add( option );
 

+ 0 - 14
editor/js/Sidebar.Project.js

@@ -52,20 +52,6 @@ Sidebar.Project = function ( editor ) {
 
 	projectsettings.add( editableRow );
 
-	// VR
-
-	var vrRow = new UI.Row();
-	var vr = new UI.Checkbox( config.getKey( 'project/vr' ) ).setLeft( '100px' ).onChange( function () {
-
-		config.setKey( 'project/vr', this.getValue() );
-
-	} );
-
-	vrRow.add( new UI.Text( strings.getKey( 'sidebar/project/vr' ) ).setWidth( '90px' ) );
-	vrRow.add( vr );
-
-	projectsettings.add( vrRow );
-
 	// Renderer
 
 	var options = {};

+ 1 - 1
editor/js/Viewport.js

@@ -313,7 +313,7 @@ var Viewport = function ( editor ) {
 
 		renderer.autoClear = false;
 		renderer.autoUpdateScene = false;
-		renderer.gammaOutput = true;
+		renderer.outputEncoding = THREE.sRGBEncoding;
 		renderer.setPixelRatio( window.devicePixelRatio );
 		renderer.setSize( container.dom.offsetWidth, container.dom.offsetHeight );
 

+ 1 - 7
editor/js/libs/app.js

@@ -21,7 +21,7 @@ var APP = {
 		this.load = function ( json ) {
 
 			renderer = new THREE.WebGLRenderer( { antialias: true } );
-			renderer.gammaOutput = true;
+			renderer.outputEncoding = THREE.sRGBEncoding;
 			renderer.setClearColor( 0x000000 );
 			renderer.setPixelRatio( window.devicePixelRatio );
 
@@ -110,12 +110,6 @@ var APP = {
 			camera.aspect = this.width / this.height;
 			camera.updateProjectionMatrix();
 
-			if ( renderer.xr.enabled ) {
-
-				dom.appendChild( THREE.WEBVR.createButton( renderer ) );
-
-			}
-
 		};
 
 		this.setScene = function ( value ) {

+ 0 - 8
editor/js/libs/tern-threejs/threejs.js

@@ -4661,14 +4661,6 @@
           "!type": "bool",
           "!doc": "Defines whether the renderer should auto update objects. Default is true."
         },
-        "gammaInput": {
-          "!type": "bool",
-          "!doc": "Default is false. If set, then it expects that all textures and colors are premultiplied gamma."
-        },
-        "gammaOutput": {
-          "!type": "bool",
-          "!doc": "Default is false.  If set, then it expects that all textures and colors need to be outputted in premultiplied gamma."
-        },
         "shadowMapEnabled": {
           "!type": "bool",
           "!doc": "Default is false. If set, use shadow maps in the scene."

+ 0 - 2
editor/sw.js

@@ -88,8 +88,6 @@ const assets = [
 	'./js/Player.js',
 	'./js/Script.js',
 
-	'../examples/js/vr/WebVR.js',
-
 	//
 
 	'./css/main.css',

+ 1 - 0
examples/files.js

@@ -386,6 +386,7 @@ var files = {
 	],
 	"tests": [
 		"webgl_furnace_test",
+		"webgl_pmrem_test",
 		"misc_uv_tests"
 	]
 };

+ 7 - 0
examples/index.html

@@ -316,6 +316,13 @@
 		}
 
 		filterInput.value = extractQuery();
+
+		if ( filterInput.value !== '' ) {
+
+			panel.classList.add( 'searchFocused' );
+
+		}
+
 		updateFilter();
 
 		</script>

+ 29 - 0
examples/js/controls/TransformControls.js

@@ -34,6 +34,7 @@ THREE.TransformControls = function ( camera, domElement ) {
 	defineProperty( "mode", "translate" );
 	defineProperty( "translationSnap", null );
 	defineProperty( "rotationSnap", null );
+	defineProperty( "scaleSnap", null );
 	defineProperty( "space", "world" );
 	defineProperty( "size", 1 );
 	defineProperty( "dragging", false );
@@ -459,6 +460,28 @@ THREE.TransformControls = function ( camera, domElement ) {
 
 			object.scale.copy( scaleStart ).multiply( _tempVector2 );
 
+			if ( this.scaleSnap ) {
+
+				if ( axis.search( 'X' ) !== - 1 ) {
+
+					object.scale.x = Math.round( object.scale.x / this.scaleSnap ) * this.scaleSnap || this.scaleSnap;
+
+				}
+
+				if ( axis.search( 'Y' ) !== - 1 ) {
+
+					object.scale.y = Math.round( object.scale.y / this.scaleSnap ) * this.scaleSnap || this.scaleSnap;
+
+				}
+
+				if ( axis.search( 'Z' ) !== - 1 ) {
+
+					object.scale.z = Math.round( object.scale.z / this.scaleSnap ) * this.scaleSnap || this.scaleSnap;
+
+				}
+
+			}
+
 		} else if ( mode === 'rotate' ) {
 
 			offset.copy( pointEnd ).sub( pointStart );
@@ -633,6 +656,12 @@ THREE.TransformControls = function ( camera, domElement ) {
 
 	};
 
+	this.setScaleSnap = function ( scaleSnap ) {
+
+		scope.scaleSnap = scaleSnap;
+
+	};
+
 	this.setSize = function ( size ) {
 
 		scope.size = size;

+ 141 - 1
examples/js/lines/LineSegments2.js

@@ -52,6 +52,146 @@ THREE.LineSegments2.prototype = Object.assign( Object.create( THREE.Mesh.prototy
 
 		};
 
-	}() )
+	}() ),
+
+	raycast: ( function () {
+
+		var start = new THREE.Vector4();
+		var end = new THREE.Vector4();
+
+		var ssOrigin = new THREE.Vector4();
+		var ssOrigin3 = new THREE.Vector3();
+		var mvMatrix = new THREE.Matrix4();
+		var line = new THREE.Line3();
+		var closestPoint = new THREE.Vector3();
+
+		return function raycast( raycaster, intersects ) {
+
+			if ( raycaster.camera === null ) {
+
+				console.error( 'LineSegments2: "Raycaster.camera" needs to be set in order to raycast against LineSegments2.' );
+
+			}
+
+			var ray = raycaster.ray;
+			var camera = raycaster.camera;
+			var projectionMatrix = camera.projectionMatrix;
+
+			var geometry = this.geometry;
+			var material = this.material;
+			var resolution = material.resolution;
+			var lineWidth = material.linewidth;
+
+			var instanceStart = geometry.attributes.instanceStart;
+			var instanceEnd = geometry.attributes.instanceEnd;
+
+			// pick a point 1 unit out along the ray to avoid the ray origin
+			// sitting at the camera origin which will cause "w" to be 0 when
+			// applying the projection matrix.
+			ray.at( 1, ssOrigin );
+
+			// ndc space [ - 1.0, 1.0 ]
+			ssOrigin.w = 1;
+			ssOrigin.applyMatrix4( camera.matrixWorldInverse );
+			ssOrigin.applyMatrix4( projectionMatrix );
+			ssOrigin.multiplyScalar( 1 / ssOrigin.w );
+
+			// screen space
+			ssOrigin.x *= resolution.x / 2;
+			ssOrigin.y *= resolution.y / 2;
+			ssOrigin.z = 0;
+
+			ssOrigin3.copy( ssOrigin );
+
+			var matrixWorld = this.matrixWorld;
+			mvMatrix.multiplyMatrices( camera.matrixWorldInverse, matrixWorld );
+
+			for ( var i = 0, l = instanceStart.count; i < l; i ++ ) {
+
+				start.fromBufferAttribute( instanceStart, i );
+				end.fromBufferAttribute( instanceEnd, i );
+
+				start.w = 1;
+				end.w = 1;
+
+				// camera space
+				start.applyMatrix4( mvMatrix );
+				end.applyMatrix4( mvMatrix );
+
+				// clip space
+				start.applyMatrix4( projectionMatrix );
+				end.applyMatrix4( projectionMatrix );
+
+				// ndc space [ - 1.0, 1.0 ]
+				start.multiplyScalar( 1 / start.w );
+				end.multiplyScalar( 1 / end.w );
+
+				// skip the segment if it's outside the camera near and far planes
+				var isBehindCameraNear = start.z < - 1 && end.z < - 1;
+				var isPastCameraFar = start.z > 1 && end.z > 1;
+				if ( isBehindCameraNear || isPastCameraFar ) {
+
+					continue;
+
+				}
+
+				// screen space
+				start.x *= resolution.x / 2;
+				start.y *= resolution.y / 2;
+
+				end.x *= resolution.x / 2;
+				end.y *= resolution.y / 2;
+
+				// create 2d segment
+				line.start.copy( start );
+				line.start.z = 0;
+
+				line.end.copy( end );
+				line.end.z = 0;
+
+				// get closest point on ray to segment
+				var param = line.closestPointToPointParameter( ssOrigin3, true );
+				line.at( param, closestPoint );
+
+				// check if the intersection point is within clip space
+				var zPos = THREE.Math.lerp( start.z, end.z, param );
+				var isInClipSpace = zPos >= -1 && zPos <= 1;
+
+				var isInside = ssOrigin3.distanceTo( closestPoint ) < lineWidth * 0.5;
+
+				if ( isInClipSpace && isInside ) {
+
+					line.start.fromBufferAttribute( instanceStart, i );
+					line.end.fromBufferAttribute( instanceEnd, i );
+
+					line.start.applyMatrix4( matrixWorld );
+					line.end.applyMatrix4( matrixWorld );
+
+					var pointOnLine = new THREE.Vector3();
+					var point = new THREE.Vector3();
+
+					ray.distanceSqToSegment( line.start, line.end, point, pointOnLine );
+
+					intersects.push( {
+
+						point: point,
+						pointOnLine: pointOnLine,
+						distance: ray.origin.distanceTo( point ),
+
+						object: this,
+						face: null,
+						faceIndex: i,
+						uv: null,
+						uv2: null,
+
+					} );
+
+				}
+
+			}
+
+		}
+
+	} () )
 
 } );

+ 2 - 2
examples/js/lines/LineSegmentsGeometry.js

@@ -32,9 +32,9 @@ THREE.LineSegmentsGeometry.prototype = Object.assign( Object.create( THREE.Insta
 
 		if ( start !== undefined ) {
 
-			matrix.applyToBufferAttribute( start );
+			start.applyMatrix4( matrix );
 
-			matrix.applyToBufferAttribute( end );
+			end.applyMatrix4( matrix );
 
 			start.data.needsUpdate = true;
 

+ 11 - 9
examples/js/loaders/BasisTextureLoader.js

@@ -119,7 +119,9 @@ THREE.BasisTextureLoader.prototype = Object.assign( Object.create( THREE.Loader.
 		var worker;
 		var taskID;
 
-		var texturePending = this._getWorker()
+		var taskCost = buffer.byteLength;
+
+		var texturePending = this._allocateWorker( taskCost )
 			.then( ( _worker ) => {
 
 				worker = _worker;
@@ -128,8 +130,6 @@ THREE.BasisTextureLoader.prototype = Object.assign( Object.create( THREE.Loader.
 				return new Promise( ( resolve, reject ) => {
 
 					worker._callbacks[ taskID ] = { resolve, reject };
-					worker._taskCosts[ taskID ] = buffer.byteLength;
-					worker._taskLoad += worker._taskCosts[ taskID ];
 
 					worker.postMessage( { type: 'transcode', id: taskID, buffer }, [ buffer ] );
 
@@ -181,9 +181,8 @@ THREE.BasisTextureLoader.prototype = Object.assign( Object.create( THREE.Loader.
 
 				if ( worker && taskID ) {
 
-					worker._taskLoad -= worker._taskCosts[ taskID ];
+					worker._taskLoad -= taskCost;
 					delete worker._callbacks[ taskID ];
-					delete worker._taskCosts[ taskID ];
 
 				}
 
@@ -195,7 +194,7 @@ THREE.BasisTextureLoader.prototype = Object.assign( Object.create( THREE.Loader.
 
 	_initTranscoder: function () {
 
-		if ( ! this.transcoderBinary ) {
+		if ( ! this.transcoderPending ) {
 
 			// Load transcoder wrapper.
 			var jsLoader = new THREE.FileLoader( this.manager );
@@ -239,7 +238,7 @@ THREE.BasisTextureLoader.prototype = Object.assign( Object.create( THREE.Loader.
 
 	},
 
-	_getWorker: function () {
+	_allocateWorker: function ( taskCost ) {
 
 		return this._initTranscoder().then( () => {
 
@@ -248,7 +247,6 @@ THREE.BasisTextureLoader.prototype = Object.assign( Object.create( THREE.Loader.
 				var worker = new Worker( this.workerSourceURL );
 
 				worker._callbacks = {};
-				worker._taskCosts = {};
 				worker._taskLoad = 0;
 
 				worker.postMessage( {
@@ -290,7 +288,11 @@ THREE.BasisTextureLoader.prototype = Object.assign( Object.create( THREE.Loader.
 
 			}
 
-			return this.workerPool[ this.workerPool.length - 1 ];
+			var worker = this.workerPool[ this.workerPool.length - 1 ];
+
+			worker._taskLoad += taskCost;
+
+			return worker;
 
 		} );
 

+ 47 - 4
examples/js/loaders/DRACOLoader.js

@@ -124,10 +124,6 @@ THREE.DRACOLoader.prototype = Object.assign( Object.create( THREE.Loader.prototy
 
 	decodeGeometry: function ( buffer, taskConfig ) {
 
-		var worker;
-		var taskID = this.workerNextTaskID ++;
-		var taskCost = buffer.byteLength;
-
 		// TODO: For backward-compatibility, support 'attributeTypes' objects containing
 		// references (rather than names) to typed array constructors. These must be
 		// serialized before sending them to the worker.
@@ -143,6 +139,43 @@ THREE.DRACOLoader.prototype = Object.assign( Object.create( THREE.Loader.prototy
 
 		}
 
+		//
+
+		var taskKey = JSON.stringify( taskConfig );
+
+		// Check for an existing task using this buffer. A transferred buffer cannot be transferred
+		// again from this thread.
+		if ( THREE.DRACOLoader.taskCache.has( buffer ) ) {
+
+			var cachedTask = THREE.DRACOLoader.taskCache.get( buffer );
+
+			if ( cachedTask.key === taskKey ) {
+
+				return cachedTask.promise;
+
+			} else if ( buffer.byteLength === 0 ) {
+
+				// Technically, it would be possible to wait for the previous task to complete,
+				// transfer the buffer back, and decode again with the second configuration. That
+				// is complex, and I don't know of any reason to decode a Draco buffer twice in
+				// different ways, so this is left unimplemented.
+				throw new Error(
+
+					'THREE.DRACOLoader: Unable to re-decode a buffer with different ' +
+					'settings. Buffer has already been transferred.'
+
+				);
+
+			}
+
+		}
+
+		//
+
+		var worker;
+		var taskID = this.workerNextTaskID ++;
+		var taskCost = buffer.byteLength;
+
 		// Obtain a worker and assign a task, and construct a geometry instance
 		// when the task completes.
 		var geometryPending = this._getWorker( taskID, taskCost )
@@ -177,6 +210,14 @@ THREE.DRACOLoader.prototype = Object.assign( Object.create( THREE.Loader.prototy
 
 			} );
 
+		// Cache the task result.
+		THREE.DRACOLoader.taskCache.set( buffer, {
+
+			key: taskKey,
+			promise: geometryPending
+
+		} );
+
 		return geometryPending;
 
 	},
@@ -604,6 +645,8 @@ THREE.DRACOLoader.DRACOWorker = function () {
 
 };
 
+THREE.DRACOLoader.taskCache = new WeakMap();
+
 /** Deprecated static methods */
 
 /** @deprecated */

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

@@ -1590,7 +1590,7 @@ THREE.FBXLoader = ( function () {
 
 			var positionAttribute = new THREE.Float32BufferAttribute( buffers.vertex, 3 );
 
-			preTransform.applyToBufferAttribute( positionAttribute );
+			positionAttribute.applyMatrix4( preTransform );
 
 			geo.setAttribute( 'position', positionAttribute );
 
@@ -2118,7 +2118,7 @@ THREE.FBXLoader = ( function () {
 			var positionAttribute = new THREE.Float32BufferAttribute( morphBuffers.vertex, 3 );
 			positionAttribute.name = name || morphGeoNode.attrName;
 
-			preTransform.applyToBufferAttribute( positionAttribute );
+			positionAttribute.applyMatrix4( preTransform );
 
 			parentGeo.morphAttributes.position.push( positionAttribute );
 

+ 88 - 64
examples/js/loaders/GLTFLoader.js

@@ -2291,12 +2291,25 @@ THREE.GLTFLoader = ( function () {
 		if ( attributes.POSITION !== undefined ) {
 
 			var accessor = parser.json.accessors[ attributes.POSITION ];
+
 			var min = accessor.min;
 			var max = accessor.max;
 
-			box.set(
-				new THREE.Vector3( min[ 0 ], min[ 1 ], min[ 2 ] ),
-				new THREE.Vector3( max[ 0 ], max[ 1 ], max[ 2 ] ) );
+			// glTF requires 'min' and 'max', but VRM (which extends glTF) currently ignores that requirement.
+
+			if ( min !== undefined && max !== undefined ) {
+
+				box.set(
+					new THREE.Vector3( min[ 0 ], min[ 1 ], min[ 2 ] ),
+					new THREE.Vector3( max[ 0 ], max[ 1 ], max[ 2 ] ) );
+
+			} else {
+
+				console.warn( 'THREE.GLTFLoader: Missing min/max properties for accessor POSITION.' );
+
+				return;
+
+			}
 
 		} else {
 
@@ -2320,12 +2333,22 @@ THREE.GLTFLoader = ( function () {
 					var min = accessor.min;
 					var max = accessor.max;
 
-					// we need to get max of absolute components because target weight is [-1,1]
-					vector.setX( Math.max( Math.abs( min[ 0 ] ), Math.abs( max[ 0 ] ) ) );
-					vector.setY( Math.max( Math.abs( min[ 1 ] ), Math.abs( max[ 1 ] ) ) );
-					vector.setZ( Math.max( Math.abs( min[ 2 ] ), Math.abs( max[ 2 ] ) ) );
+					// glTF requires 'min' and 'max', but VRM (which extends glTF) currently ignores that requirement.
+
+					if ( min !== undefined && max !== undefined ) {
+
+						// we need to get max of absolute components because target weight is [-1,1]
+						vector.setX( Math.max( Math.abs( min[ 0 ] ), Math.abs( max[ 0 ] ) ) );
+						vector.setY( Math.max( Math.abs( min[ 1 ] ), Math.abs( max[ 1 ] ) ) );
+						vector.setZ( Math.max( Math.abs( min[ 2 ] ), Math.abs( max[ 2 ] ) ) );
+
+						box.expandByVector( vector );
 
-					box.expandByVector( vector );
+					} else {
+
+						console.warn( 'THREE.GLTFLoader: Missing min/max properties for accessor POSITION.' );
+
+					}
 
 				}
 
@@ -2593,108 +2616,109 @@ THREE.GLTFLoader = ( function () {
 
 		}
 
-		return Promise.all( pending ).then( function ( originalMaterials ) {
+		pending.push( parser.loadGeometries( primitives ) );
 
-			return parser.loadGeometries( primitives ).then( function ( geometries ) {
+		return Promise.all( pending ).then( function ( results ) {
 
-				var meshes = [];
+			var materials = results.slice( 0, results.length - 1 );
+			var geometries = results[ results.length - 1 ];
 
-				for ( var i = 0, il = geometries.length; i < il; i ++ ) {
+			var meshes = [];
 
-					var geometry = geometries[ i ];
-					var primitive = primitives[ i ];
+			for ( var i = 0, il = geometries.length; i < il; i ++ ) {
 
-					// 1. create Mesh
+				var geometry = geometries[ i ];
+				var primitive = primitives[ i ];
 
-					var mesh;
+				// 1. create Mesh
 
-					var material = originalMaterials[ i ];
+				var mesh;
 
-					if ( primitive.mode === WEBGL_CONSTANTS.TRIANGLES ||
-						primitive.mode === WEBGL_CONSTANTS.TRIANGLE_STRIP ||
-						primitive.mode === WEBGL_CONSTANTS.TRIANGLE_FAN ||
-						primitive.mode === undefined ) {
+				var material = materials[ i ];
 
-						// .isSkinnedMesh isn't in glTF spec. See .markDefs()
-						mesh = meshDef.isSkinnedMesh === true
-							? new THREE.SkinnedMesh( geometry, material )
-							: new THREE.Mesh( geometry, material );
+				if ( primitive.mode === WEBGL_CONSTANTS.TRIANGLES ||
+					primitive.mode === WEBGL_CONSTANTS.TRIANGLE_STRIP ||
+					primitive.mode === WEBGL_CONSTANTS.TRIANGLE_FAN ||
+					primitive.mode === undefined ) {
 
-						if ( mesh.isSkinnedMesh === true && ! mesh.geometry.attributes.skinWeight.normalized ) {
+					// .isSkinnedMesh isn't in glTF spec. See .markDefs()
+					mesh = meshDef.isSkinnedMesh === true
+						? new THREE.SkinnedMesh( geometry, material )
+						: new THREE.Mesh( geometry, material );
 
-							// we normalize floating point skin weight array to fix malformed assets (see #15319)
-							// it's important to skip this for non-float32 data since normalizeSkinWeights assumes non-normalized inputs
-							mesh.normalizeSkinWeights();
+					if ( mesh.isSkinnedMesh === true && ! mesh.geometry.attributes.skinWeight.normalized ) {
 
-						}
+						// we normalize floating point skin weight array to fix malformed assets (see #15319)
+						// it's important to skip this for non-float32 data since normalizeSkinWeights assumes non-normalized inputs
+						mesh.normalizeSkinWeights();
 
-						if ( primitive.mode === WEBGL_CONSTANTS.TRIANGLE_STRIP ) {
+					}
 
-							mesh.geometry = toTrianglesDrawMode( mesh.geometry, THREE.TriangleStripDrawMode );
+					if ( primitive.mode === WEBGL_CONSTANTS.TRIANGLE_STRIP ) {
 
-						} else if ( primitive.mode === WEBGL_CONSTANTS.TRIANGLE_FAN ) {
+						mesh.geometry = toTrianglesDrawMode( mesh.geometry, THREE.TriangleStripDrawMode );
 
-							mesh.geometry = toTrianglesDrawMode( mesh.geometry, THREE.TriangleFanDrawMode );
+					} else if ( primitive.mode === WEBGL_CONSTANTS.TRIANGLE_FAN ) {
 
-						}
+						mesh.geometry = toTrianglesDrawMode( mesh.geometry, THREE.TriangleFanDrawMode );
 
-					} else if ( primitive.mode === WEBGL_CONSTANTS.LINES ) {
+					}
 
-						mesh = new THREE.LineSegments( geometry, material );
+				} else if ( primitive.mode === WEBGL_CONSTANTS.LINES ) {
 
-					} else if ( primitive.mode === WEBGL_CONSTANTS.LINE_STRIP ) {
+					mesh = new THREE.LineSegments( geometry, material );
 
-						mesh = new THREE.Line( geometry, material );
+				} else if ( primitive.mode === WEBGL_CONSTANTS.LINE_STRIP ) {
 
-					} else if ( primitive.mode === WEBGL_CONSTANTS.LINE_LOOP ) {
+					mesh = new THREE.Line( geometry, material );
 
-						mesh = new THREE.LineLoop( geometry, material );
+				} else if ( primitive.mode === WEBGL_CONSTANTS.LINE_LOOP ) {
 
-					} else if ( primitive.mode === WEBGL_CONSTANTS.POINTS ) {
+					mesh = new THREE.LineLoop( geometry, material );
 
-						mesh = new THREE.Points( geometry, material );
+				} else if ( primitive.mode === WEBGL_CONSTANTS.POINTS ) {
 
-					} else {
+					mesh = new THREE.Points( geometry, material );
 
-						throw new Error( 'THREE.GLTFLoader: Primitive mode unsupported: ' + primitive.mode );
+				} else {
 
-					}
+					throw new Error( 'THREE.GLTFLoader: Primitive mode unsupported: ' + primitive.mode );
 
-					if ( Object.keys( mesh.geometry.morphAttributes ).length > 0 ) {
+				}
 
-						updateMorphTargets( mesh, meshDef );
+				if ( Object.keys( mesh.geometry.morphAttributes ).length > 0 ) {
 
-					}
+					updateMorphTargets( mesh, meshDef );
 
-					mesh.name = meshDef.name || ( 'mesh_' + meshIndex );
+				}
 
-					if ( geometries.length > 1 ) mesh.name += '_' + i;
+				mesh.name = meshDef.name || ( 'mesh_' + meshIndex );
 
-					assignExtrasToUserData( mesh, meshDef );
+				if ( geometries.length > 1 ) mesh.name += '_' + i;
 
-					parser.assignFinalMaterial( mesh );
+				assignExtrasToUserData( mesh, meshDef );
 
-					meshes.push( mesh );
+				parser.assignFinalMaterial( mesh );
 
-				}
+				meshes.push( mesh );
 
-				if ( meshes.length === 1 ) {
+			}
 
-					return meshes[ 0 ];
+			if ( meshes.length === 1 ) {
 
-				}
+				return meshes[ 0 ];
 
-				var group = new THREE.Group();
+			}
 
-				for ( var i = 0, il = meshes.length; i < il; i ++ ) {
+			var group = new THREE.Group();
 
-					group.add( meshes[ i ] );
+			for ( var i = 0, il = meshes.length; i < il; i ++ ) {
 
-				}
+				group.add( meshes[ i ] );
 
-				return group;
+			}
 
-			} );
+			return group;
 
 		} );
 

+ 17 - 9
examples/js/loaders/SVGLoader.js

@@ -795,7 +795,7 @@ THREE.SVGLoader.prototype = Object.assign( Object.create( THREE.Loader.prototype
 				};
 
 				if ( node.hasAttribute( svgName ) ) style[ jsName ] = adjustFunction( node.getAttribute( svgName ) );
-				if ( node.style[ svgName ] !== '' ) style[ jsName ] = adjustFunction( node.style[ svgName ] );
+				if ( node.style && node.style[ svgName ] !== '' ) style[ jsName ] = adjustFunction( node.style[ svgName ] );
 
 			}
 
@@ -1612,23 +1612,31 @@ THREE.SVGLoader.pointsToStrokeWithBuffers = function () {
 
 			if ( joinIsOnLeftSide ) {
 
-				lastInner.toArray( vertices, 0 * 3 );
-				lastInner.toArray( vertices, 3 * 3 );
+				if ( isMiter || initialJoinIsOnLeftSide ) {
 
-				if ( isMiter ) {
+					lastInner.toArray( vertices, 0 * 3 );
+					lastInner.toArray( vertices, 3 * 3 );
 
-					lastOuter.toArray( vertices, 1 * 3 );
+					if ( isMiter ) {
+
+						lastOuter.toArray( vertices, 1 * 3 );
+
+					}
 
 				}
 
 			} else {
 
-				lastInner.toArray( vertices, 1 * 3 );
-				lastInner.toArray( vertices, 3 * 3 );
+				if ( isMiter || ! initialJoinIsOnLeftSide ) {
 
-				if ( isMiter ) {
+					lastInner.toArray( vertices, 1 * 3 );
+					lastInner.toArray( vertices, 3 * 3 );
 
-					lastOuter.toArray( vertices, 0 * 3 );
+					if ( isMiter ) {
+
+						lastOuter.toArray( vertices, 0 * 3 );
+
+					}
 
 				}
 

+ 1 - 0
examples/js/misc/MD2Character.js

@@ -221,6 +221,7 @@ THREE.MD2Character = function () {
 			textures[ i ] = textureLoader.load( baseUrl + textureUrls[ i ], checkLoadingComplete );
 			textures[ i ].mapping = THREE.UVMapping;
 			textures[ i ].name = textureUrls[ i ];
+			textures[ i ].encoding = THREE.sRGBEncoding;
 
 		}
 

+ 1 - 0
examples/js/misc/MD2CharacterComplex.js

@@ -516,6 +516,7 @@ THREE.MD2CharacterComplex = function () {
 			textures[ i ] = textureLoader.load( baseUrl + textureUrls[ i ], checkLoadingComplete );
 			textures[ i ].mapping = THREE.UVMapping;
 			textures[ i ].name = textureUrls[ i ];
+			textures[ i ].encoding = THREE.sRGBEncoding;
 
 		}
 

+ 44 - 5
examples/js/pmrem/PMREMGenerator.js

@@ -65,6 +65,7 @@ THREE.PMREMGenerator = ( function () {
 	var PMREMGenerator = function ( renderer ) {
 
 		_renderer = renderer;
+		_compileMaterial( _blurMaterial );
 
 	};
 
@@ -128,6 +129,36 @@ THREE.PMREMGenerator = ( function () {
 
 		},
 
+		/**
+		 * Pre-compiles the cubemap shader. You can get faster start-up by invoking this method during
+		 * your texture's network fetch for increased concurrency.
+		 */
+		compileCubemapShader: function () {
+
+			if ( _cubemapShader == null ) {
+
+				_cubemapShader = _getCubemapShader();
+				_compileMaterial( _cubemapShader );
+
+			}
+
+		},
+
+		/**
+		 * Pre-compiles the equirectangular shader. You can get faster start-up by invoking this method during
+		 * your texture's network fetch for increased concurrency.
+		 */
+		compileEquirectangularShader: function () {
+
+			if ( _equirectShader == null ) {
+
+				_equirectShader = _getEquirectShader();
+				_compileMaterial( _equirectShader );
+
+			}
+
+		},
+
 		/**
 		 * Disposes of the PMREMGenerator's internal memory. Note that PMREMGenerator is a static class,
 		 * so you should not need more than one PMREMGenerator object. If you do, calling dispose() on
@@ -261,7 +292,7 @@ THREE.PMREMGenerator = ( function () {
 		var upSign = [ 1, 1, 1, 1, - 1, 1 ];
 		var forwardSign = [ 1, 1, - 1, - 1, - 1, 1 ];
 
-		var gammaOutput = _renderer.gammaOutput;
+		var outputEncoding = _renderer.outputEncoding;
 		var toneMapping = _renderer.toneMapping;
 		var toneMappingExposure = _renderer.toneMappingExposure;
 		var clearColor = _renderer.getClearColor();
@@ -269,7 +300,7 @@ THREE.PMREMGenerator = ( function () {
 
 		_renderer.toneMapping = THREE.LinearToneMapping;
 		_renderer.toneMappingExposure = 1.0;
-		_renderer.gammaOutput = false;
+		_renderer.outputEncoding = THREE.LinearEncoding;
 		scene.scale.z *= - 1;
 
 		var background = scene.background;
@@ -314,7 +345,7 @@ THREE.PMREMGenerator = ( function () {
 
 		_renderer.toneMapping = toneMapping;
 		_renderer.toneMappingExposure = toneMappingExposure;
-		_renderer.gammaOutput = gammaOutput;
+		_renderer.outputEncoding = outputEncoding;
 		_renderer.setClearColor( clearColor, clearAlpha );
 		scene.scale.z *= - 1;
 
@@ -359,6 +390,14 @@ THREE.PMREMGenerator = ( function () {
 
 	}
 
+	function _compileMaterial( material ) {
+
+		var tmpScene = new THREE.Scene();
+		tmpScene.add( new THREE.Mesh( _lodPlanes[ 0 ], material ) );
+		_renderer.compile( tmpScene, _flatCamera );
+
+	}
+
 	function _createRenderTarget( params ) {
 
 		var cubeUVRenderTarget =
@@ -560,8 +599,8 @@ void main() {
         float theta = dTheta * float(dir * i);
         float cosTheta = cos(theta);
         // Rodrigues' axis-angle rotation
-        vec3 sampleDirection = vOutputDirection * cosTheta 
-            + cross(axis, vOutputDirection) * sin(theta) 
+        vec3 sampleDirection = vOutputDirection * cosTheta
+            + cross(axis, vOutputDirection) * sin(theta)
             + axis * dot(axis, vOutputDirection) * (1.0 - cosTheta);
         gl_FragColor.rgb +=
             weights[i] * bilinearCubeUV(envMap, sampleDirection, mipInt);

+ 6 - 0
examples/js/postprocessing/EffectComposer.js

@@ -279,6 +279,12 @@ THREE.Pass.FullScreenQuad = ( function () {
 
 	Object.assign( FullScreenQuad.prototype, {
 
+		dispose: function () {
+
+			this._mesh.geometry.dispose();
+
+		},
+
 		render: function ( renderer ) {
 
 			renderer.render( this._mesh, camera );

+ 4 - 4
examples/js/postprocessing/SSAOPass.js

@@ -153,10 +153,6 @@ THREE.SSAOPass.prototype = Object.assign( Object.create( THREE.Pass.prototype ),
 		this.ssaoRenderTarget.dispose();
 		this.blurRenderTarget.dispose();
 
-		// dispose geometry
-
-		this.quad.geometry.dispose();
-
 		// dispose materials
 
 		this.normalMaterial.dispose();
@@ -164,6 +160,10 @@ THREE.SSAOPass.prototype = Object.assign( Object.create( THREE.Pass.prototype ),
 		this.copyMaterial.dispose();
 		this.depthRenderMaterial.dispose();
 
+		// dipsose full screen quad
+
+		this.fsQuad.dispose();
+
 	},
 
 	render: function ( renderer, writeBuffer /*, readBuffer, deltaTime, maskActive */ ) {

+ 2 - 0
examples/js/renderers/CSS3DRenderer.js

@@ -10,6 +10,7 @@ THREE.CSS3DObject = function ( element ) {
 
 	this.element = element;
 	this.element.style.position = 'absolute';
+	this.element.style.pointerEvents = 'auto';
 
 	this.addEventListener( 'removed', function () {
 
@@ -62,6 +63,7 @@ THREE.CSS3DRenderer = function () {
 
 	cameraElement.style.WebkitTransformStyle = 'preserve-3d';
 	cameraElement.style.transformStyle = 'preserve-3d';
+	cameraElement.style.pointerEvents = 'none';
 
 	domElement.appendChild( cameraElement );
 

+ 0 - 263
examples/js/vr/WebVR.js

@@ -1,263 +0,0 @@
-/**
- * @author mrdoob / http://mrdoob.com
- * @author Mugen87 / https://github.com/Mugen87
- *
- * Based on @tojiro's vr-samples-utils.js
- */
-
-THREE.WEBVR = {
-
-	createButton: function ( renderer, options ) {
-
-		console.warn( 'WEBVR.js has been deprecated. Use VRButton.js instead.' );
-
-		if ( options && options.referenceSpaceType ) {
-
-			renderer.xr.setReferenceSpaceType( options.referenceSpaceType );
-
-		}
-
-		function showEnterVR( device ) {
-
-			button.style.display = '';
-
-			button.style.cursor = 'pointer';
-			button.style.left = 'calc(50% - 50px)';
-			button.style.width = '100px';
-
-			button.textContent = 'ENTER VR';
-
-			button.onmouseenter = function () {
-
-				button.style.opacity = '1.0';
-
-			};
-
-			button.onmouseleave = function () {
-
-				button.style.opacity = '0.5';
-
-			};
-
-			button.onclick = function () {
-
-				device.isPresenting ? device.exitPresent() : device.requestPresent( [ { source: renderer.domElement } ] );
-
-			};
-
-			renderer.xr.setDevice( device );
-
-		}
-
-		function showEnterXR( /*device*/ ) {
-
-			var currentSession = null;
-
-			function onSessionStarted( session ) {
-
-				session.addEventListener( 'end', onSessionEnded );
-
-				renderer.xr.setSession( session );
-				button.textContent = 'EXIT XR';
-
-				currentSession = session;
-
-			}
-
-			function onSessionEnded( /*event*/ ) {
-
-				currentSession.removeEventListener( 'end', onSessionEnded );
-
-				renderer.xr.setSession( null );
-				button.textContent = 'ENTER XR';
-
-				currentSession = null;
-
-			}
-
-			//
-
-			button.style.display = '';
-
-			button.style.cursor = 'pointer';
-			button.style.left = 'calc(50% - 50px)';
-			button.style.width = '100px';
-
-			button.textContent = 'ENTER XR';
-
-			button.onmouseenter = function () {
-
-				button.style.opacity = '1.0';
-
-			};
-
-			button.onmouseleave = function () {
-
-				button.style.opacity = '0.5';
-
-			};
-
-			button.onclick = function () {
-
-				if ( currentSession === null ) {
-
-					// WebXR's requestReferenceSpace only works if the corresponding feature
-					// was requested at session creation time. For simplicity, just ask for
-					// the interesting ones as optional features, but be aware that the
-					// requestReferenceSpace call will fail if it turns out to be unavailable.
-					// ('local' is always available for immersive sessions and doesn't need to
-					// be requested separately.)
-
-					var sessionInit = { optionalFeatures: [ 'local-floor', 'bounded-floor' ] };
-					navigator.xr.requestSession( 'immersive-vr', sessionInit ).then( onSessionStarted );
-
-				} else {
-
-					currentSession.end();
-
-				}
-
-			};
-
-		}
-
-		function disableButton() {
-
-			button.style.display = '';
-
-			button.style.cursor = 'auto';
-			button.style.left = 'calc(50% - 75px)';
-			button.style.width = '150px';
-
-			button.onmouseenter = null;
-			button.onmouseleave = null;
-
-			button.onclick = null;
-
-		}
-
-		function showVRNotFound() {
-
-			disableButton();
-
-			button.textContent = 'VR NOT FOUND';
-
-			renderer.xr.setDevice( null );
-
-		}
-
-		function showXRNotFound() {
-
-			disableButton();
-
-			button.textContent = 'XR NOT FOUND';
-
-		}
-
-		function stylizeElement( element ) {
-
-			element.style.position = 'absolute';
-			element.style.bottom = '20px';
-			element.style.padding = '12px 6px';
-			element.style.border = '1px solid #fff';
-			element.style.borderRadius = '4px';
-			element.style.background = 'rgba(0,0,0,0.1)';
-			element.style.color = '#fff';
-			element.style.font = 'normal 13px sans-serif';
-			element.style.textAlign = 'center';
-			element.style.opacity = '0.5';
-			element.style.outline = 'none';
-			element.style.zIndex = '999';
-
-		}
-
-		if ( 'xr' in navigator ) {
-
-			var button = document.createElement( 'button' );
-			button.style.display = 'none';
-
-			stylizeElement( button );
-
-			navigator.xr.isSessionSupported( 'immersive-vr' ).then( function ( supported ) {
-
-				if ( supported ) {
-
-					showEnterXR();
-
-				} else {
-
-					showXRNotFound();
-
-				}
-
-			} );
-
-			return button;
-
-		} else if ( 'getVRDisplays' in navigator ) {
-
-			var button = document.createElement( 'button' );
-			button.style.display = 'none';
-
-			stylizeElement( button );
-
-			window.addEventListener( 'vrdisplayconnect', function ( event ) {
-
-				showEnterVR( event.display );
-
-			}, false );
-
-			window.addEventListener( 'vrdisplaydisconnect', function ( /*event*/ ) {
-
-				showVRNotFound();
-
-			}, false );
-
-			window.addEventListener( 'vrdisplaypresentchange', function ( event ) {
-
-				button.textContent = event.display.isPresenting ? 'EXIT VR' : 'ENTER VR';
-
-			}, false );
-
-			window.addEventListener( 'vrdisplayactivate', function ( event ) {
-
-				event.display.requestPresent( [ { source: renderer.domElement } ] );
-
-			}, false );
-
-			navigator.getVRDisplays()
-				.then( function ( displays ) {
-
-					if ( displays.length > 0 ) {
-
-						showEnterVR( displays[ 0 ] );
-
-					} else {
-
-						showVRNotFound();
-
-					}
-
-				} ).catch( showVRNotFound );
-
-			return button;
-
-		} else {
-
-			var message = document.createElement( 'a' );
-			message.href = 'https://webvr.info';
-			message.innerHTML = 'WEBVR NOT SUPPORTED';
-
-			message.style.left = 'calc(50% - 90px)';
-			message.style.width = '180px';
-			message.style.textDecoration = 'none';
-
-			stylizeElement( message );
-
-			return message;
-
-		}
-
-	}
-
-};

+ 29 - 0
examples/jsm/controls/TransformControls.js

@@ -57,6 +57,7 @@ var TransformControls = function ( camera, domElement ) {
 	defineProperty( "mode", "translate" );
 	defineProperty( "translationSnap", null );
 	defineProperty( "rotationSnap", null );
+	defineProperty( "scaleSnap", null );
 	defineProperty( "space", "world" );
 	defineProperty( "size", 1 );
 	defineProperty( "dragging", false );
@@ -482,6 +483,28 @@ var TransformControls = function ( camera, domElement ) {
 
 			object.scale.copy( scaleStart ).multiply( _tempVector2 );
 
+			if ( this.scaleSnap ) {
+
+				if ( axis.search( 'X' ) !== - 1 ) {
+
+					object.scale.x = Math.round( object.scale.x / this.scaleSnap ) * this.scaleSnap || this.scaleSnap;
+
+				}
+
+				if ( axis.search( 'Y' ) !== - 1 ) {
+
+					object.scale.y = Math.round( object.scale.y / this.scaleSnap ) * this.scaleSnap || this.scaleSnap;
+
+				}
+
+				if ( axis.search( 'Z' ) !== - 1 ) {
+
+					object.scale.z = Math.round( object.scale.z / this.scaleSnap ) * this.scaleSnap || this.scaleSnap;
+
+				}
+
+			}
+
 		} else if ( mode === 'rotate' ) {
 
 			offset.copy( pointEnd ).sub( pointStart );
@@ -656,6 +679,12 @@ var TransformControls = function ( camera, domElement ) {
 
 	};
 
+	this.setScaleSnap = function ( scaleSnap ) {
+
+		scope.scaleSnap = scaleSnap;
+
+	};
+
 	this.setSize = function ( size ) {
 
 		scope.size = size;

+ 146 - 2
examples/jsm/lines/LineSegments2.js

@@ -6,8 +6,12 @@
 import {
 	InstancedInterleavedBuffer,
 	InterleavedBufferAttribute,
+	Line3,
+	Math as _Math,
+	Matrix4,
 	Mesh,
-	Vector3
+	Vector3,
+	Vector4
 } from "../../../build/three.module.js";
 import { LineSegmentsGeometry } from "../lines/LineSegmentsGeometry.js";
 import { LineMaterial } from "../lines/LineMaterial.js";
@@ -61,7 +65,147 @@ LineSegments2.prototype = Object.assign( Object.create( Mesh.prototype ), {
 
 		};
 
-	}() )
+	}() ),
+
+	raycast: ( function () {
+
+		var start = new Vector4();
+		var end = new Vector4();
+
+		var ssOrigin = new Vector4();
+		var ssOrigin3 = new Vector3();
+		var mvMatrix = new Matrix4();
+		var line = new Line3();
+		var closestPoint = new Vector3();
+
+		return function raycast( raycaster, intersects ) {
+
+			if ( raycaster.camera === null ) {
+
+				console.error( 'LineSegments2: "Raycaster.camera" needs to be set in order to raycast against LineSegments2.' );
+
+			}
+
+			var ray = raycaster.ray;
+			var camera = raycaster.camera;
+			var projectionMatrix = camera.projectionMatrix;
+
+			var geometry = this.geometry;
+			var material = this.material;
+			var resolution = material.resolution;
+			var lineWidth = material.linewidth;
+
+			var instanceStart = geometry.attributes.instanceStart;
+			var instanceEnd = geometry.attributes.instanceEnd;
+
+			// pick a point 1 unit out along the ray to avoid the ray origin
+			// sitting at the camera origin which will cause "w" to be 0 when
+			// applying the projection matrix.
+			ray.at( 1, ssOrigin );
+
+			// ndc space [ - 1.0, 1.0 ]
+			ssOrigin.w = 1;
+			ssOrigin.applyMatrix4( camera.matrixWorldInverse );
+			ssOrigin.applyMatrix4( projectionMatrix );
+			ssOrigin.multiplyScalar( 1 / ssOrigin.w );
+
+			// screen space
+			ssOrigin.x *= resolution.x / 2;
+			ssOrigin.y *= resolution.y / 2;
+			ssOrigin.z = 0;
+
+			ssOrigin3.copy( ssOrigin );
+
+			var matrixWorld = this.matrixWorld;
+			mvMatrix.multiplyMatrices( camera.matrixWorldInverse, matrixWorld );
+
+			for ( var i = 0, l = instanceStart.count; i < l; i ++ ) {
+
+				start.fromBufferAttribute( instanceStart, i );
+				end.fromBufferAttribute( instanceEnd, i );
+
+				start.w = 1;
+				end.w = 1;
+
+				// camera space
+				start.applyMatrix4( mvMatrix );
+				end.applyMatrix4( mvMatrix );
+
+				// clip space
+				start.applyMatrix4( projectionMatrix );
+				end.applyMatrix4( projectionMatrix );
+
+				// ndc space [ - 1.0, 1.0 ]
+				start.multiplyScalar( 1 / start.w );
+				end.multiplyScalar( 1 / end.w );
+
+				// skip the segment if it's outside the camera near and far planes
+				var isBehindCameraNear = start.z < - 1 && end.z < - 1;
+				var isPastCameraFar = start.z > 1 && end.z > 1;
+				if ( isBehindCameraNear || isPastCameraFar ) {
+
+					continue;
+
+				}
+
+				// screen space
+				start.x *= resolution.x / 2;
+				start.y *= resolution.y / 2;
+
+				end.x *= resolution.x / 2;
+				end.y *= resolution.y / 2;
+
+				// create 2d segment
+				line.start.copy( start );
+				line.start.z = 0;
+
+				line.end.copy( end );
+				line.end.z = 0;
+
+				// get closest point on ray to segment
+				var param = line.closestPointToPointParameter( ssOrigin3, true );
+				line.at( param, closestPoint );
+
+				// check if the intersection point is within clip space
+				var zPos = _Math.lerp( start.z, end.z, param );
+				var isInClipSpace = zPos >= -1 && zPos <= 1;
+
+				var isInside = ssOrigin3.distanceTo( closestPoint ) < lineWidth * 0.5;
+
+				if ( isInClipSpace && isInside ) {
+
+					line.start.fromBufferAttribute( instanceStart, i );
+					line.end.fromBufferAttribute( instanceEnd, i );
+
+					line.start.applyMatrix4( matrixWorld );
+					line.end.applyMatrix4( matrixWorld );
+
+					var pointOnLine = new Vector3();
+					var point = new Vector3();
+
+					ray.distanceSqToSegment( line.start, line.end, point, pointOnLine );
+
+					intersects.push( {
+
+						point: point,
+						pointOnLine: pointOnLine,
+						distance: ray.origin.distanceTo( point ),
+
+						object: this,
+						face: null,
+						faceIndex: i,
+						uv: null,
+						uv2: null,
+
+					} );
+
+				}
+
+			}
+
+		}
+
+	} () )
 
 } );
 

+ 2 - 2
examples/jsm/lines/LineSegmentsGeometry.js

@@ -43,9 +43,9 @@ LineSegmentsGeometry.prototype = Object.assign( Object.create( InstancedBufferGe
 
 		if ( start !== undefined ) {
 
-			matrix.applyToBufferAttribute( start );
+			start.applyMatrix4( matrix );
 
-			matrix.applyToBufferAttribute( end );
+			end.applyMatrix4( matrix );
 
 			start.data.needsUpdate = true;
 

+ 11 - 9
examples/jsm/loaders/BasisTextureLoader.js

@@ -132,7 +132,9 @@ BasisTextureLoader.prototype = Object.assign( Object.create( Loader.prototype ),
 		var worker;
 		var taskID;
 
-		var texturePending = this._getWorker()
+		var taskCost = buffer.byteLength;
+
+		var texturePending = this._allocateWorker( taskCost )
 			.then( ( _worker ) => {
 
 				worker = _worker;
@@ -141,8 +143,6 @@ BasisTextureLoader.prototype = Object.assign( Object.create( Loader.prototype ),
 				return new Promise( ( resolve, reject ) => {
 
 					worker._callbacks[ taskID ] = { resolve, reject };
-					worker._taskCosts[ taskID ] = buffer.byteLength;
-					worker._taskLoad += worker._taskCosts[ taskID ];
 
 					worker.postMessage( { type: 'transcode', id: taskID, buffer }, [ buffer ] );
 
@@ -194,9 +194,8 @@ BasisTextureLoader.prototype = Object.assign( Object.create( Loader.prototype ),
 
 				if ( worker && taskID ) {
 
-					worker._taskLoad -= worker._taskCosts[ taskID ];
+					worker._taskLoad -= taskCost;
 					delete worker._callbacks[ taskID ];
-					delete worker._taskCosts[ taskID ];
 
 				}
 
@@ -208,7 +207,7 @@ BasisTextureLoader.prototype = Object.assign( Object.create( Loader.prototype ),
 
 	_initTranscoder: function () {
 
-		if ( ! this.transcoderBinary ) {
+		if ( ! this.transcoderPending ) {
 
 			// Load transcoder wrapper.
 			var jsLoader = new FileLoader( this.manager );
@@ -252,7 +251,7 @@ BasisTextureLoader.prototype = Object.assign( Object.create( Loader.prototype ),
 
 	},
 
-	_getWorker: function () {
+	_allocateWorker: function ( taskCost ) {
 
 		return this._initTranscoder().then( () => {
 
@@ -261,7 +260,6 @@ BasisTextureLoader.prototype = Object.assign( Object.create( Loader.prototype ),
 				var worker = new Worker( this.workerSourceURL );
 
 				worker._callbacks = {};
-				worker._taskCosts = {};
 				worker._taskLoad = 0;
 
 				worker.postMessage( {
@@ -303,7 +301,11 @@ BasisTextureLoader.prototype = Object.assign( Object.create( Loader.prototype ),
 
 			}
 
-			return this.workerPool[ this.workerPool.length - 1 ];
+			var worker = this.workerPool[ this.workerPool.length - 1 ];
+
+			worker._taskLoad += taskCost;
+
+			return worker;
 
 		} );
 

+ 47 - 4
examples/jsm/loaders/DRACOLoader.js

@@ -131,10 +131,6 @@ DRACOLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
 
 	decodeGeometry: function ( buffer, taskConfig ) {
 
-		var worker;
-		var taskID = this.workerNextTaskID ++;
-		var taskCost = buffer.byteLength;
-
 		// TODO: For backward-compatibility, support 'attributeTypes' objects containing
 		// references (rather than names) to typed array constructors. These must be
 		// serialized before sending them to the worker.
@@ -150,6 +146,43 @@ DRACOLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
 
 		}
 
+		//
+
+		var taskKey = JSON.stringify( taskConfig );
+
+		// Check for an existing task using this buffer. A transferred buffer cannot be transferred
+		// again from this thread.
+		if ( DRACOLoader.taskCache.has( buffer ) ) {
+
+			var cachedTask = DRACOLoader.taskCache.get( buffer );
+
+			if ( cachedTask.key === taskKey ) {
+
+				return cachedTask.promise;
+
+			} else if ( buffer.byteLength === 0 ) {
+
+				// Technically, it would be possible to wait for the previous task to complete,
+				// transfer the buffer back, and decode again with the second configuration. That
+				// is complex, and I don't know of any reason to decode a Draco buffer twice in
+				// different ways, so this is left unimplemented.
+				throw new Error(
+
+					'THREE.DRACOLoader: Unable to re-decode a buffer with different ' +
+					'settings. Buffer has already been transferred.'
+
+				);
+
+			}
+
+		}
+
+		//
+
+		var worker;
+		var taskID = this.workerNextTaskID ++;
+		var taskCost = buffer.byteLength;
+
 		// Obtain a worker and assign a task, and construct a geometry instance
 		// when the task completes.
 		var geometryPending = this._getWorker( taskID, taskCost )
@@ -184,6 +217,14 @@ DRACOLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
 
 			} );
 
+		// Cache the task result.
+		DRACOLoader.taskCache.set( buffer, {
+
+			key: taskKey,
+			promise: geometryPending
+
+		} );
+
 		return geometryPending;
 
 	},
@@ -611,6 +652,8 @@ DRACOLoader.DRACOWorker = function () {
 
 };
 
+DRACOLoader.taskCache = new WeakMap();
+
 /** Deprecated static methods */
 
 /** @deprecated */

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

@@ -1638,7 +1638,7 @@ var FBXLoader = ( function () {
 
 			var positionAttribute = new Float32BufferAttribute( buffers.vertex, 3 );
 
-			preTransform.applyToBufferAttribute( positionAttribute );
+			positionAttribute.applyMatrix4( preTransform );
 
 			geo.setAttribute( 'position', positionAttribute );
 
@@ -2166,7 +2166,7 @@ var FBXLoader = ( function () {
 			var positionAttribute = new Float32BufferAttribute( morphBuffers.vertex, 3 );
 			positionAttribute.name = name || morphGeoNode.attrName;
 
-			preTransform.applyToBufferAttribute( positionAttribute );
+			positionAttribute.applyMatrix4( preTransform );
 
 			parentGeo.morphAttributes.position.push( positionAttribute );
 

+ 88 - 64
examples/jsm/loaders/GLTFLoader.js

@@ -2358,12 +2358,25 @@ var GLTFLoader = ( function () {
 		if ( attributes.POSITION !== undefined ) {
 
 			var accessor = parser.json.accessors[ attributes.POSITION ];
+
 			var min = accessor.min;
 			var max = accessor.max;
 
-			box.set(
-				new Vector3( min[ 0 ], min[ 1 ], min[ 2 ] ),
-				new Vector3( max[ 0 ], max[ 1 ], max[ 2 ] ) );
+			// glTF requires 'min' and 'max', but VRM (which extends glTF) currently ignores that requirement.
+
+			if ( min !== undefined && max !== undefined ) {
+
+				box.set(
+					new Vector3( min[ 0 ], min[ 1 ], min[ 2 ] ),
+					new Vector3( max[ 0 ], max[ 1 ], max[ 2 ] ) );
+
+			} else {
+
+				console.warn( 'THREE.GLTFLoader: Missing min/max properties for accessor POSITION.' );
+
+				return;
+
+			}
 
 		} else {
 
@@ -2387,12 +2400,22 @@ var GLTFLoader = ( function () {
 					var min = accessor.min;
 					var max = accessor.max;
 
-					// we need to get max of absolute components because target weight is [-1,1]
-					vector.setX( Math.max( Math.abs( min[ 0 ] ), Math.abs( max[ 0 ] ) ) );
-					vector.setY( Math.max( Math.abs( min[ 1 ] ), Math.abs( max[ 1 ] ) ) );
-					vector.setZ( Math.max( Math.abs( min[ 2 ] ), Math.abs( max[ 2 ] ) ) );
+					// glTF requires 'min' and 'max', but VRM (which extends glTF) currently ignores that requirement.
+
+					if ( min !== undefined && max !== undefined ) {
+
+						// we need to get max of absolute components because target weight is [-1,1]
+						vector.setX( Math.max( Math.abs( min[ 0 ] ), Math.abs( max[ 0 ] ) ) );
+						vector.setY( Math.max( Math.abs( min[ 1 ] ), Math.abs( max[ 1 ] ) ) );
+						vector.setZ( Math.max( Math.abs( min[ 2 ] ), Math.abs( max[ 2 ] ) ) );
+
+						box.expandByVector( vector );
 
-					box.expandByVector( vector );
+					} else {
+
+						console.warn( 'THREE.GLTFLoader: Missing min/max properties for accessor POSITION.' );
+
+					}
 
 				}
 
@@ -2660,108 +2683,109 @@ var GLTFLoader = ( function () {
 
 		}
 
-		return Promise.all( pending ).then( function ( originalMaterials ) {
+		pending.push( parser.loadGeometries( primitives ) );
 
-			return parser.loadGeometries( primitives ).then( function ( geometries ) {
+		return Promise.all( pending ).then( function ( results ) {
 
-				var meshes = [];
+			var materials = results.slice( 0, results.length - 1 );
+			var geometries = results[ results.length - 1 ];
 
-				for ( var i = 0, il = geometries.length; i < il; i ++ ) {
+			var meshes = [];
 
-					var geometry = geometries[ i ];
-					var primitive = primitives[ i ];
+			for ( var i = 0, il = geometries.length; i < il; i ++ ) {
 
-					// 1. create Mesh
+				var geometry = geometries[ i ];
+				var primitive = primitives[ i ];
 
-					var mesh;
+				// 1. create Mesh
 
-					var material = originalMaterials[ i ];
+				var mesh;
 
-					if ( primitive.mode === WEBGL_CONSTANTS.TRIANGLES ||
-						primitive.mode === WEBGL_CONSTANTS.TRIANGLE_STRIP ||
-						primitive.mode === WEBGL_CONSTANTS.TRIANGLE_FAN ||
-						primitive.mode === undefined ) {
+				var material = materials[ i ];
 
-						// .isSkinnedMesh isn't in glTF spec. See .markDefs()
-						mesh = meshDef.isSkinnedMesh === true
-							? new SkinnedMesh( geometry, material )
-							: new Mesh( geometry, material );
+				if ( primitive.mode === WEBGL_CONSTANTS.TRIANGLES ||
+					primitive.mode === WEBGL_CONSTANTS.TRIANGLE_STRIP ||
+					primitive.mode === WEBGL_CONSTANTS.TRIANGLE_FAN ||
+					primitive.mode === undefined ) {
 
-						if ( mesh.isSkinnedMesh === true && ! mesh.geometry.attributes.skinWeight.normalized ) {
+					// .isSkinnedMesh isn't in glTF spec. See .markDefs()
+					mesh = meshDef.isSkinnedMesh === true
+						? new SkinnedMesh( geometry, material )
+						: new Mesh( geometry, material );
 
-							// we normalize floating point skin weight array to fix malformed assets (see #15319)
-							// it's important to skip this for non-float32 data since normalizeSkinWeights assumes non-normalized inputs
-							mesh.normalizeSkinWeights();
+					if ( mesh.isSkinnedMesh === true && ! mesh.geometry.attributes.skinWeight.normalized ) {
 
-						}
+						// we normalize floating point skin weight array to fix malformed assets (see #15319)
+						// it's important to skip this for non-float32 data since normalizeSkinWeights assumes non-normalized inputs
+						mesh.normalizeSkinWeights();
 
-						if ( primitive.mode === WEBGL_CONSTANTS.TRIANGLE_STRIP ) {
+					}
 
-							mesh.geometry = toTrianglesDrawMode( mesh.geometry, TriangleStripDrawMode );
+					if ( primitive.mode === WEBGL_CONSTANTS.TRIANGLE_STRIP ) {
 
-						} else if ( primitive.mode === WEBGL_CONSTANTS.TRIANGLE_FAN ) {
+						mesh.geometry = toTrianglesDrawMode( mesh.geometry, TriangleStripDrawMode );
 
-							mesh.geometry = toTrianglesDrawMode( mesh.geometry, TriangleFanDrawMode );
+					} else if ( primitive.mode === WEBGL_CONSTANTS.TRIANGLE_FAN ) {
 
-						}
+						mesh.geometry = toTrianglesDrawMode( mesh.geometry, TriangleFanDrawMode );
 
-					} else if ( primitive.mode === WEBGL_CONSTANTS.LINES ) {
+					}
 
-						mesh = new LineSegments( geometry, material );
+				} else if ( primitive.mode === WEBGL_CONSTANTS.LINES ) {
 
-					} else if ( primitive.mode === WEBGL_CONSTANTS.LINE_STRIP ) {
+					mesh = new LineSegments( geometry, material );
 
-						mesh = new Line( geometry, material );
+				} else if ( primitive.mode === WEBGL_CONSTANTS.LINE_STRIP ) {
 
-					} else if ( primitive.mode === WEBGL_CONSTANTS.LINE_LOOP ) {
+					mesh = new Line( geometry, material );
 
-						mesh = new LineLoop( geometry, material );
+				} else if ( primitive.mode === WEBGL_CONSTANTS.LINE_LOOP ) {
 
-					} else if ( primitive.mode === WEBGL_CONSTANTS.POINTS ) {
+					mesh = new LineLoop( geometry, material );
 
-						mesh = new Points( geometry, material );
+				} else if ( primitive.mode === WEBGL_CONSTANTS.POINTS ) {
 
-					} else {
+					mesh = new Points( geometry, material );
 
-						throw new Error( 'THREE.GLTFLoader: Primitive mode unsupported: ' + primitive.mode );
+				} else {
 
-					}
+					throw new Error( 'THREE.GLTFLoader: Primitive mode unsupported: ' + primitive.mode );
 
-					if ( Object.keys( mesh.geometry.morphAttributes ).length > 0 ) {
+				}
 
-						updateMorphTargets( mesh, meshDef );
+				if ( Object.keys( mesh.geometry.morphAttributes ).length > 0 ) {
 
-					}
+					updateMorphTargets( mesh, meshDef );
 
-					mesh.name = meshDef.name || ( 'mesh_' + meshIndex );
+				}
 
-					if ( geometries.length > 1 ) mesh.name += '_' + i;
+				mesh.name = meshDef.name || ( 'mesh_' + meshIndex );
 
-					assignExtrasToUserData( mesh, meshDef );
+				if ( geometries.length > 1 ) mesh.name += '_' + i;
 
-					parser.assignFinalMaterial( mesh );
+				assignExtrasToUserData( mesh, meshDef );
 
-					meshes.push( mesh );
+				parser.assignFinalMaterial( mesh );
 
-				}
+				meshes.push( mesh );
 
-				if ( meshes.length === 1 ) {
+			}
 
-					return meshes[ 0 ];
+			if ( meshes.length === 1 ) {
 
-				}
+				return meshes[ 0 ];
 
-				var group = new Group();
+			}
 
-				for ( var i = 0, il = meshes.length; i < il; i ++ ) {
+			var group = new Group();
 
-					group.add( meshes[ i ] );
+			for ( var i = 0, il = meshes.length; i < il; i ++ ) {
 
-				}
+				group.add( meshes[ i ] );
 
-				return group;
+			}
 
-			} );
+			return group;
 
 		} );
 

+ 17 - 9
examples/jsm/loaders/SVGLoader.js

@@ -808,7 +808,7 @@ SVGLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
 				};
 
 				if ( node.hasAttribute( svgName ) ) style[ jsName ] = adjustFunction( node.getAttribute( svgName ) );
-				if ( node.style[ svgName ] !== '' ) style[ jsName ] = adjustFunction( node.style[ svgName ] );
+				if ( node.style && node.style[ svgName ] !== '' ) style[ jsName ] = adjustFunction( node.style[ svgName ] );
 
 			}
 
@@ -1625,23 +1625,31 @@ SVGLoader.pointsToStrokeWithBuffers = function () {
 
 			if ( joinIsOnLeftSide ) {
 
-				lastInner.toArray( vertices, 0 * 3 );
-				lastInner.toArray( vertices, 3 * 3 );
+				if ( isMiter || initialJoinIsOnLeftSide ) {
 
-				if ( isMiter ) {
+					lastInner.toArray( vertices, 0 * 3 );
+					lastInner.toArray( vertices, 3 * 3 );
 
-					lastOuter.toArray( vertices, 1 * 3 );
+					if ( isMiter ) {
+
+						lastOuter.toArray( vertices, 1 * 3 );
+
+					}
 
 				}
 
 			} else {
 
-				lastInner.toArray( vertices, 1 * 3 );
-				lastInner.toArray( vertices, 3 * 3 );
+				if ( isMiter || ! initialJoinIsOnLeftSide ) {
 
-				if ( isMiter ) {
+					lastInner.toArray( vertices, 1 * 3 );
+					lastInner.toArray( vertices, 3 * 3 );
 
-					lastOuter.toArray( vertices, 0 * 3 );
+					if ( isMiter ) {
+
+						lastOuter.toArray( vertices, 0 * 3 );
+
+					}
 
 				}
 

+ 1 - 1
examples/jsm/math/MeshSurfaceSampler.js

@@ -128,7 +128,7 @@ var MeshSurfaceSampler = ( function () {
 
 				var mid = Math.floor( ( start + end ) / 2 );
 
-				if ( dist[ mid - 1 ] <= x && dist[ mid ] > x ) {
+				if ( mid === 0 || dist[ mid - 1 ] <= x && dist[ mid ] > x ) {
 
 					index = mid;
 

+ 3 - 1
examples/jsm/misc/MD2Character.js

@@ -9,7 +9,8 @@ import {
 	MeshLambertMaterial,
 	Object3D,
 	TextureLoader,
-	UVMapping
+	UVMapping,
+	sRGBEncoding
 } from "../../../build/three.module.js";
 import { MD2Loader } from "../loaders/MD2Loader.js";
 
@@ -232,6 +233,7 @@ var MD2Character = function () {
 			textures[ i ] = textureLoader.load( baseUrl + textureUrls[ i ], checkLoadingComplete );
 			textures[ i ].mapping = UVMapping;
 			textures[ i ].name = textureUrls[ i ];
+			textures[ i ].encoding = sRGBEncoding;
 
 		}
 

+ 3 - 1
examples/jsm/misc/MD2CharacterComplex.js

@@ -8,7 +8,8 @@ import {
 	MeshLambertMaterial,
 	Object3D,
 	TextureLoader,
-	UVMapping
+	UVMapping,
+	sRGBEncoding
 } from "../../../build/three.module.js";
 import { MD2Loader } from "../loaders/MD2Loader.js";
 import { MorphBlendMesh } from "../misc/MorphBlendMesh.js";
@@ -527,6 +528,7 @@ var MD2CharacterComplex = function () {
 			textures[ i ] = textureLoader.load( baseUrl + textureUrls[ i ], checkLoadingComplete );
 			textures[ i ].mapping = UVMapping;
 			textures[ i ].name = textureUrls[ i ];
+			textures[ i ].encoding = sRGBEncoding;
 
 		}
 

+ 54 - 14
examples/jsm/misc/TubePainter.js

@@ -7,6 +7,7 @@ import {
 	BufferGeometry,
 	Color,
 	DynamicDrawUsage,
+	Matrix4,
 	Mesh,
 	MeshStandardMaterial,
 	Vector3,
@@ -33,8 +34,6 @@ function TubePainter() {
 	geometry.drawRange.count = 0;
 
 	let material = new MeshStandardMaterial( {
-		roughness: 0.9,
-		metalness: 0.0,
 		vertexColors: VertexColors
 	} );
 
@@ -62,6 +61,8 @@ function TubePainter() {
 
 	}
 
+	//
+
 	let vector1 = new Vector3();
 	let vector2 = new Vector3();
 	let vector3 = new Vector3();
@@ -131,38 +132,77 @@ function TubePainter() {
 
 	}
 
+	//
+
+	let up = new Vector3( 0, 1, 0 );
+
+	let point1 = new Vector3();
+	let point2 = new Vector3();
+
+	let matrix1 = new Matrix4();
+	let matrix2 = new Matrix4();
+
+	function moveTo( position ) {
+
+		point1.copy( position );
+		matrix1.lookAt( point2, point1, up );
+
+		point2.copy( position );
+		matrix2.copy( matrix1 );
+
+	}
+
+	function lineTo( position ) {
+
+		point1.copy( position );
+		matrix1.lookAt( point2, point1, up );
+
+		stroke( point1, point2, matrix1, matrix2 );
+
+		point2.copy( point1 );
+		matrix2.copy( matrix1 );
+
+	}
+
 	function setSize( value ) {
 
 		size = value;
 
 	}
 
-	function updateGeometry( start, end ) {
+	//
 
-		if ( start === end ) return;
+	let count = 0;
+
+	function update() {
 
-		let offset = start * 3;
-		let count = ( end - start ) * 3;
+		let start = count;
+		let end = geometry.drawRange.count;
 
-		positions.updateRange.offset = offset;
-		positions.updateRange.count = count;
+		if ( start === end ) return;
+
+		positions.updateRange.offset = start * 3;
+		positions.updateRange.count = ( end - start ) * 3;
 		positions.needsUpdate = true;
 
-		normals.updateRange.offset = offset;
-		normals.updateRange.count = count;
+		normals.updateRange.offset = start * 3;
+		normals.updateRange.count = ( end - start ) * 3;
 		normals.needsUpdate = true;
 
-		colors.updateRange.offset = offset;
-		colors.updateRange.count = count;
+		colors.updateRange.offset = start * 3;
+		colors.updateRange.count = ( end - start ) * 3;
 		colors.needsUpdate = true;
 
+		count = geometry.drawRange.count;
+
 	}
 
 	return {
 		mesh: mesh,
-		stroke: stroke,
+		moveTo: moveTo,
+		lineTo: lineTo,
 		setSize: setSize,
-		updateGeometry: updateGeometry
+		update: update
 	};
 
 }

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

@@ -54,7 +54,7 @@ ReflectNode.prototype.generate = function ( builder, output ) {
 
 			case ReflectNode.VECTOR:
 
-				var viewNormalNode = builder.context.viewNormal || new NormalNode();
+				var viewNormalNode = builder.context.viewNormal || new NormalNode( NormalNode.VIEW );
 				var roughnessNode = builder.context.roughness;
 
 				var viewNormal = viewNormalNode.build( builder, 'v3' );
@@ -63,7 +63,7 @@ ReflectNode.prototype.generate = function ( builder, output ) {
 
 				var method = `reflect( -normalize( ${viewPosition} ), ${viewNormal} )`;
 
-				if ( viewNormalNode && roughness ) {
+				if ( roughness ) {
 
 					// Mixing the reflection with the normal is more accurate and keeps rough objects from gathering light from behind their tangent plane.
 					method = `normalize( mix( ${method}, ${viewNormal}, ${roughness} * ${roughness} ) )`;

+ 1 - 1
examples/jsm/nodes/core/NodeBuilder.d.ts

@@ -143,6 +143,6 @@ export class NodeBuilder {
 	setShader( shader: string ): this;
 	mergeDefines( defines: object ): object;
 	mergeUniform( uniforms: object ): object;
-	getTextureEncodingFromMap( map: Texture, gammaOverrideLinear?: boolean ): TextureEncoding;
+	getTextureEncodingFromMap( map: Texture ): TextureEncoding;
 
 }

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

@@ -949,9 +949,7 @@ NodeBuilder.prototype = {
 
 	},
 
-	getTextureEncodingFromMap: function ( map, gammaOverrideLinear ) {
-
-		gammaOverrideLinear = gammaOverrideLinear !== undefined ? gammaOverrideLinear : this.context.gamma && ( this.renderer ? this.renderer.gammaInput : false );
+	getTextureEncodingFromMap: function ( map ) {
 
 		var encoding;
 
@@ -970,8 +968,7 @@ NodeBuilder.prototype = {
 
 		}
 
-		// add backwards compatibility for WebGLRenderer.gammaInput/gammaOutput parameter, should probably be removed at some point.
-		if ( encoding === LinearEncoding && gammaOverrideLinear ) {
+		if ( encoding === LinearEncoding && this.context.gamma ) {
 
 			encoding = GammaEncoding;
 

+ 2 - 2
examples/jsm/nodes/inputs/TextureNode.d.ts

@@ -12,9 +12,9 @@ export class TextureNode extends InputNode {
 
 	constructor( value: Texture, uv?: UVNode, bias?: Node, project?: boolean );
 
-	value: Matrix4;
+	value: Texture;
 	uv: UVNode;
-	bias: Matrix4;
+	bias: Node;
 	project: boolean;
 	nodeType: string;
 

+ 16 - 0
examples/jsm/nodes/materials/MeshStandardNodeMaterial.d.ts

@@ -1,7 +1,23 @@
+import { Color } from '../../../../src/math/Color';
+import { Texture } from '../../../../src/textures/Texture';
+import { CubeTexture } from '../../../../src/textures/CubeTexture';
+import { Vector2 } from '../../../../src/math/Vector2';
+
+import { Node } from '../core/Node';
 import { NodeMaterial } from './NodeMaterial';
 
 export class MeshStandardNodeMaterial extends NodeMaterial {
 
 	constructor();
 
+	color: Color | Node;
+	roughness: number | Node;
+	metalness: number | Node;
+	map: Texture | Node;
+	normalMap: Texture | Node;
+	normalScale: Vector2 | Node;
+	metalnessMap: Texture | Node;
+	roughnessMap: Texture | Node;
+	envMap: CubeTexture | Node;
+
 }

+ 16 - 0
examples/jsm/nodes/materials/PhongNodeMaterial.d.ts

@@ -1,7 +1,23 @@
+import { Node } from '../core/Node';
 import { NodeMaterial } from './NodeMaterial';
 
 export class PhongNodeMaterial extends NodeMaterial {
 
 	constructor();
 
+	color: Node;
+	alpha: Node;
+	specular: Node;
+	shininess: Node;
+	normal: Node;
+	emissive: Node;
+	ambient: Node;
+	light: Node;
+	shadow: Node;
+	ao: Node;
+	environment: Node;
+	environmentAlpha: Node;
+	mask: Node;
+	position: Node;
+
 }

+ 7 - 0
examples/jsm/nodes/materials/SpriteNodeMaterial.d.ts

@@ -1,7 +1,14 @@
+import { Node } from '../core/Node';
 import { NodeMaterial } from './NodeMaterial';
 
 export class SpriteNodeMaterial extends NodeMaterial {
 
 	constructor();
 
+	color: Node;
+	alpha: Node;
+	mask: Node;
+	position: Node;
+	spherical: Node;
+
 }

+ 20 - 0
examples/jsm/nodes/materials/StandardNodeMaterial.d.ts

@@ -1,7 +1,27 @@
+import { Node } from '../core/Node';
 import { NodeMaterial } from './NodeMaterial';
 
 export class StandardNodeMaterial extends NodeMaterial {
 
 	constructor();
 
+	color: Node;
+	alpha: Node;
+	roughness: Node;
+	metalness: Node;
+	reflectivity: Node;
+	clearcoat: Node;
+	clearcoatRoughness: Node;
+	clearcoatNormal: Node;
+	normal: Node;
+	emissive: Node;
+	ambient: Node;
+	light: Node;
+	shadow: Node;
+	ao: Node;
+	environment: Node;
+	mask: Node;
+	position: Node;
+	sheen: Node;
+
 }

+ 3 - 5
examples/jsm/nodes/materials/nodes/PhongNode.d.ts

@@ -1,15 +1,13 @@
 import { NodeBuilder } from '../../core/NodeBuilder';
 import { Node } from '../../core/Node';
-import { ColorNode } from '../../inputs/ColorNode';
-import { FloatNode } from '../../inputs/FloatNode';
 
 export class PhongNode extends Node {
 
 	constructor();
 
-	color: ColorNode;
-	specular: ColorNode;
-	shininess: FloatNode;
+	color: Node;
+	specular: Node;
+	shininess: Node;
 	nodeType: string;
 
 	build( builder: NodeBuilder ): string;

+ 1 - 2
examples/jsm/nodes/materials/nodes/SpriteNode.d.ts

@@ -1,12 +1,11 @@
 import { NodeBuilder } from '../../core/NodeBuilder';
 import { Node } from '../../core/Node';
-import { ColorNode } from '../../inputs/ColorNode';
 
 export class SpriteNode extends Node {
 
 	constructor();
 
-	color: ColorNode;
+	color: Node;
 	spherical: true;
 	nodeType: string;
 

+ 3 - 5
examples/jsm/nodes/materials/nodes/StandardNode.d.ts

@@ -1,15 +1,13 @@
 import { NodeBuilder } from '../../core/NodeBuilder';
 import { Node } from '../../core/Node';
-import { ColorNode } from '../../inputs/ColorNode';
-import { FloatNode } from '../../inputs/FloatNode';
 
 export class StandardNode extends Node {
 
 	constructor();
 
-	color: ColorNode;
-	roughness: FloatNode;
-	metalness: FloatNode;
+	color: Node;
+	roughness: Node;
+	metalness: Node;
 	nodeType: string;
 
 	build( builder: NodeBuilder ): string;

+ 9 - 53
examples/jsm/nodes/misc/TextureCubeNode.js

@@ -4,32 +4,28 @@
 
 import { TempNode } from '../core/TempNode.js';
 import { FloatNode } from '../inputs/FloatNode.js';
-import { ExpressionNode } from '../core/ExpressionNode.js';
 import { TextureCubeUVNode } from './TextureCubeUVNode.js';
 import { ReflectNode } from '../accessors/ReflectNode.js';
 import { NormalNode } from '../accessors/NormalNode.js';
-import { ColorSpaceNode } from '../utils/ColorSpaceNode.js';
 
-function TextureCubeNode( value, textureSize, uv, bias ) {
+function TextureCubeNode( value, uv, bias ) {
 
 	TempNode.call( this, 'v4' );
 
 	this.value = value;
 
-	textureSize = textureSize || new FloatNode( 1024 );
-
-	this.radianceCache = { uv: new TextureCubeUVNode(
+	this.radianceNode = new TextureCubeUVNode(
+		this.value,
 		uv || new ReflectNode( ReflectNode.VECTOR ),
-		textureSize,
 		// bias should be replaced in builder.context in build process
 		bias
-	) };
+	);
 
-	this.irradianceCache = { uv: new TextureCubeUVNode(
+	this.irradianceNode = new TextureCubeUVNode(
+		this.value,
 		new NormalNode( NormalNode.WORLD ),
-		textureSize,
 		new FloatNode( 1 ).setReadonly( true )
-	) };
+	);
 
 }
 
@@ -37,45 +33,6 @@ TextureCubeNode.prototype = Object.create( TempNode.prototype );
 TextureCubeNode.prototype.constructor = TextureCubeNode;
 TextureCubeNode.prototype.nodeType = "TextureCube";
 
-TextureCubeNode.prototype.generateTextureCubeUV = function ( builder, cache ) {
-
-	var uv_10 = cache.uv.build( builder ) + '.uv_10',
-		uv_20 = cache.uv.build( builder ) + '.uv_20',
-		t = cache.uv.build( builder ) + '.t';
-
-	var color10 = 'texture2D( ' + this.value.build( builder, 'sampler2D' ) + ', ' + uv_10 + ' )',
-		color20 = 'texture2D( ' + this.value.build( builder, 'sampler2D' ) + ', ' + uv_20 + ' )';
-
-	// add a custom context for fix incompatibility with the core
-	// include ColorSpace function only for vertex shader (in fragment shader color space functions is added automatically by core)
-	// this should be removed in the future
-	// context.include =: is used to include or not functions if used FunctionNode
-	// context.ignoreCache =: not create temp variables nodeT0..9 to optimize the code
-	var context = { include: builder.isShader( 'vertex' ), ignoreCache: true };
-	var outputType = this.getType( builder );
-
-	builder.addContext( context );
-
-	cache.colorSpace10 = cache.colorSpace10 || new ColorSpaceNode( new ExpressionNode( '', outputType ) );
-	cache.colorSpace10.fromDecoding( builder.getTextureEncodingFromMap( this.value.value ) );
-	cache.colorSpace10.input.parse( color10 );
-
-	color10 = cache.colorSpace10.build( builder, outputType );
-
-	cache.colorSpace20 = cache.colorSpace20 || new ColorSpaceNode( new ExpressionNode( '', outputType ) );
-	cache.colorSpace20.fromDecoding( builder.getTextureEncodingFromMap( this.value.value ) );
-	cache.colorSpace20.input.parse( color20 );
-
-	color20 = cache.colorSpace20.build( builder, outputType );
-
-	// end custom context
-
-	builder.removeContext();
-
-	return 'mix( ' + color10 + ', ' + color20 + ', ' + t + ' ).rgb';
-
-};
-
 TextureCubeNode.prototype.generate = function ( builder, output ) {
 
 	if ( builder.isShader( 'fragment' ) ) {
@@ -88,10 +45,9 @@ TextureCubeNode.prototype.generate = function ( builder, output ) {
 
 		}
 
-		var cache = builder.slot === 'irradiance' ? this.irradianceCache : this.radianceCache;
-		var result = this.generateTextureCubeUV( builder, cache );
+		var scopeNode = builder.slot === 'irradiance' ? this.irradianceNode : this.radianceNode;
 
-		return builder.format( 'vec4( ' + result + ', 1.0 )', this.getType( builder ), output );
+		return scopeNode.build( builder, output );
 
 	} else {
 

+ 219 - 146
examples/jsm/nodes/misc/TextureCubeUVNode.js

@@ -6,157 +6,157 @@ import { TempNode } from '../core/TempNode.js';
 import { ConstNode } from '../core/ConstNode.js';
 import { StructNode } from '../core/StructNode.js';
 import { FunctionNode } from '../core/FunctionNode.js';
+import { FunctionCallNode } from '../core/FunctionCallNode.js';
+import { ExpressionNode } from '../core/ExpressionNode.js';
+import { FloatNode } from '../inputs/FloatNode.js';
+import { OperatorNode } from '../math/OperatorNode.js';
+import { MathNode } from '../math/MathNode.js';
+import { ColorSpaceNode } from '../utils/ColorSpaceNode.js';
 
-function TextureCubeUVNode( uv, textureSize, bias ) {
+function TextureCubeUVNode( value, uv, bias ) {
 
-	TempNode.call( this, 'TextureCubeUVData' ); // TextureCubeUVData is type as StructNode
+	TempNode.call( this, 'v4' );
 
+	this.value = value,
 	this.uv = uv;
-	this.textureSize = textureSize;
 	this.bias = bias;
 
 }
 
 TextureCubeUVNode.Nodes = ( function () {
 
-	var TextureCubeUVData = new StructNode( [
-		"struct TextureCubeUVData {",
-		"	vec2 uv_10;",
-		"	vec2 uv_20;",
-		"	float t;",
-		"}"
-	].join( "\n" ) );
-
-	var getFaceFromDirection = new FunctionNode( [
-		"int getFaceFromDirection(vec3 direction) {",
-		"	vec3 absDirection = abs(direction);",
-		"	int face = -1;",
-		"	if( absDirection.x > absDirection.z ) {",
-		"		if(absDirection.x > absDirection.y )",
-		"			face = direction.x > 0.0 ? 0 : 3;",
-		"		else",
-		"			face = direction.y > 0.0 ? 1 : 4;",
-		"	}",
-		"	else {",
-		"		if(absDirection.z > absDirection.y )",
-		"			face = direction.z > 0.0 ? 2 : 5;",
-		"		else",
-		"			face = direction.y > 0.0 ? 1 : 4;",
-		"	}",
-		"	return face;",
-		"}"
-	].join( "\n" ) );
-
-	var cubeUV_maxLods1 = new ConstNode( "#define cubeUV_maxLods1 ( log2( cubeUV_textureSize * 0.25 ) - 1.0 )" );
-	var cubeUV_rangeClamp = new ConstNode( "#define cubeUV_rangeClamp ( exp2( ( 6.0 - 1.0 ) * 2.0 ) )" );
-
-	var MipLevelInfo = new FunctionNode( [
-		"vec2 MipLevelInfo( vec3 vec, float roughnessLevel, float roughness, in float cubeUV_textureSize ) {",
-		"	float scale = exp2(cubeUV_maxLods1 - roughnessLevel);",
-		"	float dxRoughness = dFdx(roughness);",
-		"	float dyRoughness = dFdy(roughness);",
-		"	vec3 dx = dFdx( vec * scale * dxRoughness );",
-		"	vec3 dy = dFdy( vec * scale * dyRoughness );",
-		"	float d = max( dot( dx, dx ), dot( dy, dy ) );",
-		// Clamp the value to the max mip level counts. hard coded to 6 mips"
-		"	d = clamp(d, 1.0, cubeUV_rangeClamp);",
-		"	float mipLevel = 0.5 * log2(d);",
-		"	return vec2(floor(mipLevel), fract(mipLevel));",
-		"}"
-	].join( "\n" ), [ cubeUV_maxLods1, cubeUV_rangeClamp ], { derivatives: true } );
-
-	var cubeUV_maxLods2 = new ConstNode( "#define cubeUV_maxLods2 ( log2( cubeUV_textureSize * 0.25 ) - 2.0 )" );
-	var cubeUV_rcpTextureSize = new ConstNode( "#define cubeUV_rcpTextureSize ( 1.0 / cubeUV_textureSize )" );
-
-	var getCubeUV = new FunctionNode( [
-		"vec2 getCubeUV( vec3 direction, float roughnessLevel, float mipLevel, in float cubeUV_textureSize ) {",
-		"	mipLevel = roughnessLevel > cubeUV_maxLods2 - 3.0 ? 0.0 : mipLevel;",
-		"	float a = 16.0 * cubeUV_rcpTextureSize;",
-		"",
-		"	vec2 exp2_packed = exp2( vec2( roughnessLevel, mipLevel ) );",
-		"	vec2 rcp_exp2_packed = vec2( 1.0 ) / exp2_packed;",
-		// float powScale = exp2(roughnessLevel + mipLevel);"
-		"	float powScale = exp2_packed.x * exp2_packed.y;",
-		// float scale =  1.0 / exp2(roughnessLevel + 2.0 + mipLevel);"
-		"	float scale = rcp_exp2_packed.x * rcp_exp2_packed.y * 0.25;",
-		// float mipOffset = 0.75*(1.0 - 1.0/exp2(mipLevel))/exp2(roughnessLevel);"
-		"	float mipOffset = 0.75*(1.0 - rcp_exp2_packed.y) * rcp_exp2_packed.x;",
-		"",
-		"	bool bRes = mipLevel == 0.0;",
-		"	scale =  bRes && (scale < a) ? a : scale;",
-		"",
-		"	vec3 r;",
-		"	vec2 offset;",
-		"	int face = getFaceFromDirection(direction);",
-		"",
-		"	float rcpPowScale = 1.0 / powScale;",
-		"",
-		"	if( face == 0) {",
-		"		r = vec3(direction.x, -direction.z, direction.y);",
-		"		offset = vec2(0.0+mipOffset,0.75 * rcpPowScale);",
-		"		offset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;",
-		"	}",
-		"	else if( face == 1) {",
-		"		r = vec3(direction.y, direction.x, direction.z);",
-		"		offset = vec2(scale+mipOffset, 0.75 * rcpPowScale);",
-		"		offset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;",
-		"	}",
-		"	else if( face == 2) {",
-		"		r = vec3(direction.z, direction.x, direction.y);",
-		"		offset = vec2(2.0*scale+mipOffset, 0.75 * rcpPowScale);",
-		"		offset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;",
-		"	}",
-		"	else if( face == 3) {",
-		"		r = vec3(direction.x, direction.z, direction.y);",
-		"		offset = vec2(0.0+mipOffset,0.5 * rcpPowScale);",
-		"		offset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;",
-		"	}",
-		"	else if( face == 4) {",
-		"		r = vec3(direction.y, direction.x, -direction.z);",
-		"		offset = vec2(scale+mipOffset, 0.5 * rcpPowScale);",
-		"		offset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;",
-		"	}",
-		"	else {",
-		"		r = vec3(direction.z, -direction.x, direction.y);",
-		"		offset = vec2(2.0*scale+mipOffset, 0.5 * rcpPowScale);",
-		"		offset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;",
-		"	}",
-		"	r = normalize(r);",
-		"	float texelOffset = 0.5 * cubeUV_rcpTextureSize;",
-		"	vec2 s = ( r.yz / abs( r.x ) + vec2( 1.0 ) ) * 0.5;",
-		"	vec2 base = offset + vec2( texelOffset );",
-		"	return base + s * ( scale - 2.0 * texelOffset );",
-		"}"
-	].join( "\n" ), [ cubeUV_maxLods2, cubeUV_rcpTextureSize, getFaceFromDirection ] );
-
-	var cubeUV_maxLods3 = new ConstNode( "#define cubeUV_maxLods3 ( log2( cubeUV_textureSize * 0.25 ) - 3.0 )" );
-
-	var textureCubeUV = new FunctionNode( [
-		"TextureCubeUVData textureCubeUV( vec3 reflectedDirection, float roughness, in float cubeUV_textureSize ) {",
-		"	float roughnessVal = roughness * cubeUV_maxLods3;",
-		"	float r1 = floor(roughnessVal);",
-		"	float r2 = r1 + 1.0;",
-		"	float t = fract(roughnessVal);",
-		"	vec2 mipInfo = MipLevelInfo(reflectedDirection, r1, roughness, cubeUV_textureSize);",
-		"	float s = mipInfo.y;",
-		"	float level0 = mipInfo.x;",
-		"	float level1 = level0 + 1.0;",
-		"	level1 = level1 > 5.0 ? 5.0 : level1;",
-		"",
-		// round to nearest mipmap if we are not interpolating."
-		"	level0 += min( floor( s + 0.5 ), 5.0 );",
-		"",
-		// Tri linear interpolation."
-		"	vec2 uv_10 = getCubeUV(reflectedDirection, r1, level0, cubeUV_textureSize);",
-		"	vec2 uv_20 = getCubeUV(reflectedDirection, r2, level0, cubeUV_textureSize);",
-		"",
-		"	return TextureCubeUVData(uv_10, uv_20, t);",
-		"}"
-	].join( "\n" ), [ TextureCubeUVData, cubeUV_maxLods3, MipLevelInfo, getCubeUV ] );
+	var TextureCubeUVData = new StructNode(
+		`struct TextureCubeUVData {
+			vec4 tl;
+			vec4 tr;
+			vec4 br;
+			vec4 bl;
+			vec2 f;
+		}` );
+
+	var cubeUV_maxMipLevel = new ConstNode( `float cubeUV_maxMipLevel 8.0`, true );
+	var cubeUV_minMipLevel = new ConstNode( `float cubeUV_minMipLevel 4.0`, true );
+	var cubeUV_maxTileSize = new ConstNode( `float cubeUV_maxTileSize 256.0`, true );
+	var cubeUV_minTileSize = new ConstNode( `float cubeUV_minTileSize 16.0`, true );
+
+	// These shader functions convert between the UV coordinates of a single face of
+	// a cubemap, the 0-5 integer index of a cube face, and the direction vector for
+	// sampling a textureCube (not generally normalized).
+
+	var getFace = new FunctionNode(
+		`float getFace(vec3 direction) {
+				vec3 absDirection = abs(direction);
+				float face = -1.0;
+				if (absDirection.x > absDirection.z) {
+					if (absDirection.x > absDirection.y)
+						face = direction.x > 0.0 ? 0.0 : 3.0;
+					else
+						face = direction.y > 0.0 ? 1.0 : 4.0;
+				} else {
+					if (absDirection.z > absDirection.y)
+						face = direction.z > 0.0 ? 2.0 : 5.0;
+					else
+						face = direction.y > 0.0 ? 1.0 : 4.0;
+				}
+				return face;
+		}` );
+	getFace.useKeywords = false;
+
+	var getUV = new FunctionNode(
+		`vec2 getUV(vec3 direction, float face) {
+				vec2 uv;
+				if (face == 0.0) {
+					uv = vec2(-direction.z, direction.y) / abs(direction.x);
+				} else if (face == 1.0) {
+					uv = vec2(direction.x, -direction.z) / abs(direction.y);
+				} else if (face == 2.0) {
+					uv = direction.xy / abs(direction.z);
+				} else if (face == 3.0) {
+					uv = vec2(direction.z, direction.y) / abs(direction.x);
+				} else if (face == 4.0) {
+					uv = direction.xz / abs(direction.y);
+				} else {
+					uv = vec2(-direction.x, direction.y) / abs(direction.z);
+				}
+				return 0.5 * (uv + 1.0);
+		}` );
+	getUV.useKeywords = false;
+
+	var bilinearCubeUV = new FunctionNode(
+		`TextureCubeUVData bilinearCubeUV(sampler2D envMap, vec3 direction, float mipInt) {
+			float face = getFace(direction);
+			float filterInt = max(cubeUV_minMipLevel - mipInt, 0.0);
+			mipInt = max(mipInt, cubeUV_minMipLevel);
+			float faceSize = exp2(mipInt);
+			float texelSize = 1.0 / (3.0 * cubeUV_maxTileSize);
+			vec2 uv = getUV(direction, face) * (faceSize - 1.0);
+			vec2 f = fract(uv);
+			uv += 0.5 - f;
+			if (face > 2.0) {
+				uv.y += faceSize;
+				face -= 3.0;
+			}
+			uv.x += face * faceSize;
+			if(mipInt < cubeUV_maxMipLevel){
+				uv.y += 2.0 * cubeUV_maxTileSize;
+			}
+			uv.y += filterInt * 2.0 * cubeUV_minTileSize;
+			uv.x += 3.0 * max(0.0, cubeUV_maxTileSize - 2.0 * faceSize);
+			uv *= texelSize;
+			vec4 tl = texture2D(envMap, uv);
+			uv.x += texelSize;
+			vec4 tr = texture2D(envMap, uv);
+			uv.y += texelSize;
+			vec4 br = texture2D(envMap, uv);
+			uv.x -= texelSize;
+			vec4 bl = texture2D(envMap, uv);
+
+			return TextureCubeUVData( tl, tr, br, bl, f );
+		}`, [ TextureCubeUVData, getFace, getUV, cubeUV_maxMipLevel, cubeUV_minMipLevel, cubeUV_maxTileSize, cubeUV_minTileSize ] );
+	bilinearCubeUV.useKeywords = false;
+
+	// These defines must match with PMREMGenerator
+
+	var r0 = new ConstNode( `float r0 1.0`, true );
+	var v0 = new ConstNode( `float v0 0.339`, true );
+	var m0 = new ConstNode( `float m0 -2.0`, true );
+	var r1 = new ConstNode( `float r1 0.8`, true );
+	var v1 = new ConstNode( `float v1 0.276`, true );
+	var m1 = new ConstNode( `float m1 -1.0`, true );
+	var r4 = new ConstNode( `float r4 0.4`, true );
+	var v4 = new ConstNode( `float v4 0.046`, true );
+	var m4 = new ConstNode( `float m4 2.0`, true );
+	var r5 = new ConstNode( `float r5 0.305`, true );
+	var v5 = new ConstNode( `float v5 0.016`, true );
+	var m5 = new ConstNode( `float m5 3.0`, true );
+	var r6 = new ConstNode( `float r6 0.21`, true );
+	var v6 = new ConstNode( `float v6 0.0038`, true );
+	var m6 = new ConstNode( `float m6 4.0`, true );
+
+	var defines = [ r0, v0, m0, r1, v1, m1, r4, v4, m4, r5, v5, m5, r6, v6, m6 ];
+
+	var roughnessToMip = new FunctionNode(
+		`float roughnessToMip(float roughness) {
+			float mip = 0.0;
+			if (roughness >= r1) {
+				mip = (r0 - roughness) * (m1 - m0) / (r0 - r1) + m0;
+			} else if (roughness >= r4) {
+				mip = (r1 - roughness) * (m4 - m1) / (r1 - r4) + m1;
+			} else if (roughness >= r5) {
+				mip = (r4 - roughness) * (m5 - m4) / (r4 - r5) + m4;
+			} else if (roughness >= r6) {
+				mip = (r5 - roughness) * (m6 - m5) / (r5 - r6) + m5;
+			} else {
+				mip = -2.0 * log2(1.16 * roughness);// 1.16 = 1.79^0.25
+			}
+			return mip;
+		}`, defines );
 
 	return {
-		TextureCubeUVData: TextureCubeUVData,
-		textureCubeUV: textureCubeUV
+		bilinearCubeUV: bilinearCubeUV,
+		roughnessToMip: roughnessToMip,
+		m0: m0,
+		cubeUV_maxMipLevel: cubeUV_maxMipLevel
 	};
 
 } )();
@@ -165,17 +165,90 @@ TextureCubeUVNode.prototype = Object.create( TempNode.prototype );
 TextureCubeUVNode.prototype.constructor = TextureCubeUVNode;
 TextureCubeUVNode.prototype.nodeType = "TextureCubeUV";
 
+TextureCubeUVNode.prototype.bilinearCubeUV = function ( builder, texture, uv, mipInt ) {
+
+	var bilinearCubeUV = new FunctionCallNode( TextureCubeUVNode.Nodes.bilinearCubeUV, [ texture, uv, mipInt ] );
+
+	this.colorSpaceTL = this.colorSpaceTL || new ColorSpaceNode( new ExpressionNode( '', 'v4' ) );
+	this.colorSpaceTL.fromDecoding( builder.getTextureEncodingFromMap( this.value.value ) );
+	this.colorSpaceTL.input.parse( bilinearCubeUV.build( builder ) + '.tl' );
+
+	this.colorSpaceTR = this.colorSpaceTR || new ColorSpaceNode( new ExpressionNode( '', 'v4' ) );
+	this.colorSpaceTR.fromDecoding( builder.getTextureEncodingFromMap( this.value.value ) );
+	this.colorSpaceTR.input.parse( bilinearCubeUV.build( builder ) + '.tr' );
+
+	this.colorSpaceBL = this.colorSpaceBL || new ColorSpaceNode( new ExpressionNode( '', 'v4' ) );
+	this.colorSpaceBL.fromDecoding( builder.getTextureEncodingFromMap( this.value.value ) );
+	this.colorSpaceBL.input.parse( bilinearCubeUV.build( builder ) + '.bl' );
+
+	this.colorSpaceBR = this.colorSpaceBR || new ColorSpaceNode( new ExpressionNode( '', 'v4' ) );
+	this.colorSpaceBR.fromDecoding( builder.getTextureEncodingFromMap( this.value.value ) );
+	this.colorSpaceBR.input.parse( bilinearCubeUV.build( builder ) + '.br' );
+
+	// add a custom context for fix incompatibility with the core
+	// include ColorSpace function only for vertex shader (in fragment shader color space functions is added automatically by core)
+	// this should be removed in the future
+	// context.include =: is used to include or not functions if used FunctionNode
+	// context.ignoreCache =: not create temp variables nodeT0..9 to optimize the code
+	var context = { include: builder.isShader( 'vertex' ), ignoreCache: true };
+
+	builder.addContext( context );
+
+	this.colorSpaceTLExp = new ExpressionNode( this.colorSpaceTL.build( builder, 'v4' ), 'v4' );
+	this.colorSpaceTRExp = new ExpressionNode( this.colorSpaceTR.build( builder, 'v4' ), 'v4' );
+	this.colorSpaceBLExp = new ExpressionNode( this.colorSpaceBL.build( builder, 'v4' ), 'v4' );
+	this.colorSpaceBRExp = new ExpressionNode( this.colorSpaceBR.build( builder, 'v4' ), 'v4' );
+
+	// end custom context
+
+	builder.removeContext();
+
+	// --
+
+	var output = new ExpressionNode( `mix( mix( cubeUV_TL, cubeUV_TR, cubeUV.f.x ), mix( cubeUV_BL, cubeUV_BR, cubeUV.f.x ), cubeUV.f.y )`, 'v4' );
+	output.keywords[ 'cubeUV_TL' ] = this.colorSpaceTLExp;
+	output.keywords[ 'cubeUV_TR' ] = this.colorSpaceTRExp;
+	output.keywords[ 'cubeUV_BL' ] = this.colorSpaceBLExp;
+	output.keywords[ 'cubeUV_BR' ] = this.colorSpaceBRExp;
+	output.keywords[ 'cubeUV' ] = bilinearCubeUV;
+
+	return output;
+
+};
+
 TextureCubeUVNode.prototype.generate = function ( builder, output ) {
 
 	if ( builder.isShader( 'fragment' ) ) {
 
-		var textureCubeUV = builder.include( TextureCubeUVNode.Nodes.textureCubeUV );
+		var uv = this.uv;
+		var bias = this.bias || builder.context.roughness;
+
+		var mipV = new FunctionCallNode( TextureCubeUVNode.Nodes.roughnessToMip, [ bias ] );
+		var mip = new MathNode( mipV, TextureCubeUVNode.Nodes.m0, TextureCubeUVNode.Nodes.cubeUV_maxMipLevel, MathNode.CLAMP );
+		var mipInt	= new MathNode( mip, MathNode.FLOOR );
+		var mipF	= new MathNode( mip, MathNode.FRACT );
+
+		var color0 = this.bilinearCubeUV( builder, this.value, uv, mipInt );
+		var color1 = this.bilinearCubeUV( builder, this.value, uv, new OperatorNode(
+			mipInt,
+			new FloatNode( 1 ).setReadonly( true ),
+			OperatorNode.ADD
+		) );
+
+		var color1Mix = new MathNode( color0, color1, mipF, MathNode.MIX );
 
-		var biasNode = this.bias || builder.context.roughness;
+		/*
+		// TODO: Optimize this in the future
+		var cond = new CondNode(
+			mipF,
+			new FloatNode( 0 ).setReadonly( true ),
+			CondNode.EQUAL,
+			color0, // if
+			color1Mix	// else
+		);
+		*/
 
-		return builder.format( textureCubeUV + '( ' + this.uv.build( builder, 'v3' ) + ', ' +
-			biasNode.build( builder, 'f' ) + ', ' +
-			this.textureSize.build( builder, 'f' ) + ' )', this.getType( builder ), output );
+		return builder.format( color1Mix.build( builder ), 'v4', output );
 
 	} else {
 
@@ -195,9 +268,9 @@ TextureCubeUVNode.prototype.toJSON = function ( meta ) {
 
 		data = this.createJSONNode( meta );
 
+		data.value = this.value.toJSON( meta ).uuid;
 		data.uv = this.uv.toJSON( meta ).uuid;
-		data.textureSize = this.textureSize.toJSON( meta ).uuid;
-		data.blinnExponentToRoughness = this.blinnExponentToRoughness.toJSON( meta ).uuid;
+		data.bias = this.bias.toJSON( meta ).uuid;
 
 	}
 

+ 2 - 0
examples/jsm/pmrem/PMREMGenerator.d.ts

@@ -12,6 +12,8 @@ export class PMREMGenerator {
 	fromScene( scene:Scene, sigma?:number, near?:number, far?:number ): WebGLRenderTarget;
 	fromEquirectangular( equirectangular:Texture ): WebGLRenderTarget;
 	fromCubemap( cubemap:CubeTexture ): WebGLRenderTarget;
+	compileCubemapShader(): void;
+	compileEquirectangularShader(): void;
 	dispose(): void;
 
 }

+ 44 - 5
examples/jsm/pmrem/PMREMGenerator.js

@@ -91,6 +91,7 @@ var PMREMGenerator = ( function () {
 	var PMREMGenerator = function ( renderer ) {
 
 		_renderer = renderer;
+		_compileMaterial( _blurMaterial );
 
 	};
 
@@ -154,6 +155,36 @@ var PMREMGenerator = ( function () {
 
 		},
 
+		/**
+		 * Pre-compiles the cubemap shader. You can get faster start-up by invoking this method during
+		 * your texture's network fetch for increased concurrency.
+		 */
+		compileCubemapShader: function () {
+
+			if ( _cubemapShader == null ) {
+
+				_cubemapShader = _getCubemapShader();
+				_compileMaterial( _cubemapShader );
+
+			}
+
+		},
+
+		/**
+		 * Pre-compiles the equirectangular shader. You can get faster start-up by invoking this method during
+		 * your texture's network fetch for increased concurrency.
+		 */
+		compileEquirectangularShader: function () {
+
+			if ( _equirectShader == null ) {
+
+				_equirectShader = _getEquirectShader();
+				_compileMaterial( _equirectShader );
+
+			}
+
+		},
+
 		/**
 		 * Disposes of the PMREMGenerator's internal memory. Note that PMREMGenerator is a static class,
 		 * so you should not need more than one PMREMGenerator object. If you do, calling dispose() on
@@ -287,7 +318,7 @@ var PMREMGenerator = ( function () {
 		var upSign = [ 1, 1, 1, 1, - 1, 1 ];
 		var forwardSign = [ 1, 1, - 1, - 1, - 1, 1 ];
 
-		var gammaOutput = _renderer.gammaOutput;
+		var outputEncoding = _renderer.outputEncoding;
 		var toneMapping = _renderer.toneMapping;
 		var toneMappingExposure = _renderer.toneMappingExposure;
 		var clearColor = _renderer.getClearColor();
@@ -295,7 +326,7 @@ var PMREMGenerator = ( function () {
 
 		_renderer.toneMapping = LinearToneMapping;
 		_renderer.toneMappingExposure = 1.0;
-		_renderer.gammaOutput = false;
+		_renderer.outputEncoding = LinearEncoding;
 		scene.scale.z *= - 1;
 
 		var background = scene.background;
@@ -340,7 +371,7 @@ var PMREMGenerator = ( function () {
 
 		_renderer.toneMapping = toneMapping;
 		_renderer.toneMappingExposure = toneMappingExposure;
-		_renderer.gammaOutput = gammaOutput;
+		_renderer.outputEncoding = outputEncoding;
 		_renderer.setClearColor( clearColor, clearAlpha );
 		scene.scale.z *= - 1;
 
@@ -385,6 +416,14 @@ var PMREMGenerator = ( function () {
 
 	}
 
+	function _compileMaterial( material ) {
+
+		var tmpScene = new Scene();
+		tmpScene.add( new Mesh( _lodPlanes[ 0 ], material ) );
+		_renderer.compile( tmpScene, _flatCamera );
+
+	}
+
 	function _createRenderTarget( params ) {
 
 		var cubeUVRenderTarget =
@@ -586,8 +625,8 @@ void main() {
         float theta = dTheta * float(dir * i);
         float cosTheta = cos(theta);
         // Rodrigues' axis-angle rotation
-        vec3 sampleDirection = vOutputDirection * cosTheta 
-            + cross(axis, vOutputDirection) * sin(theta) 
+        vec3 sampleDirection = vOutputDirection * cosTheta
+            + cross(axis, vOutputDirection) * sin(theta)
             + axis * dot(axis, vOutputDirection) * (1.0 - cosTheta);
         gl_FragColor.rgb +=
             weights[i] * bilinearCubeUV(envMap, sampleDirection, mipInt);

+ 6 - 0
examples/jsm/postprocessing/EffectComposer.js

@@ -294,6 +294,12 @@ Pass.FullScreenQuad = ( function () {
 
 	Object.assign( FullScreenQuad.prototype, {
 
+		dispose: function () {
+
+			this._mesh.geometry.dispose();
+
+		},
+
 		render: function ( renderer ) {
 
 			renderer.render( this._mesh, camera );

+ 1 - 0
examples/jsm/postprocessing/Pass.d.ts

@@ -23,6 +23,7 @@ export namespace Pass {
 		constructor( material?: Material );
 
 		render( renderer: WebGLRenderer ): void;
+		dispose(): void;
 
 		material: Material;
 

+ 6 - 0
examples/jsm/postprocessing/Pass.js

@@ -63,6 +63,12 @@ Pass.FullScreenQuad = ( function () {
 
 	Object.assign( FullScreenQuad.prototype, {
 
+		dispose: function () {
+
+			this._mesh.geometry.dispose();
+
+		},
+
 		render: function ( renderer ) {
 
 			renderer.render( this._mesh, camera );

+ 4 - 4
examples/jsm/postprocessing/SSAOPass.js

@@ -183,10 +183,6 @@ SSAOPass.prototype = Object.assign( Object.create( Pass.prototype ), {
 		this.ssaoRenderTarget.dispose();
 		this.blurRenderTarget.dispose();
 
-		// dispose geometry
-
-		this.quad.geometry.dispose();
-
 		// dispose materials
 
 		this.normalMaterial.dispose();
@@ -194,6 +190,10 @@ SSAOPass.prototype = Object.assign( Object.create( Pass.prototype ), {
 		this.copyMaterial.dispose();
 		this.depthRenderMaterial.dispose();
 
+		// dipsose full screen quad
+
+		this.fsQuad.dispose();
+
 	},
 
 	render: function ( renderer, writeBuffer /*, readBuffer, deltaTime, maskActive */ ) {

+ 2 - 0
examples/jsm/renderers/CSS3DRenderer.js

@@ -16,6 +16,7 @@ var CSS3DObject = function ( element ) {
 
 	this.element = element;
 	this.element.style.position = 'absolute';
+	this.element.style.pointerEvents = 'auto';
 
 	this.addEventListener( 'removed', function () {
 
@@ -68,6 +69,7 @@ var CSS3DRenderer = function () {
 
 	cameraElement.style.WebkitTransformStyle = 'preserve-3d';
 	cameraElement.style.transformStyle = 'preserve-3d';
+	cameraElement.style.pointerEvents = 'none';
 
 	domElement.appendChild( cameraElement );
 

+ 12 - 0
examples/jsm/utils/RoughnessMipmapper.d.ts

@@ -0,0 +1,12 @@
+import {
+	WebGLRenderer,
+    MeshStandardMaterial
+} from '../../../src/Three';
+
+export class RoughnessMipmapper {
+
+	constructor( renderer:WebGLRenderer );
+	generateMipmaps( material:MeshStandardMaterial ): void;
+	dispose(): void;
+
+}

+ 222 - 0
examples/jsm/utils/RoughnessMipmapper.js

@@ -0,0 +1,222 @@
+/**
+ * @author Emmett Lalish / elalish
+ *
+ * This class generates custom mipmaps for a roughness map by encoding the lost variation in the
+ * normal map mip levels as increased roughness in the corresponding roughness mip levels. This
+ * helps with rendering accuracy for MeshStandardMaterial, and also helps with anti-aliasing when
+ * using PMREM. If the normal map is larger than the roughness map, the roughness map will be
+ * enlarged to match the dimensions of the normal map.
+ */
+
+import {
+	LinearMipMapLinearFilter,
+	Math as _Math,
+	Mesh,
+	NoBlending,
+	OrthographicCamera,
+	PlaneBufferGeometry,
+	RawShaderMaterial,
+	Scene,
+	Vector2,
+	WebGLRenderTarget
+} from "../../../build/three.module.js";
+
+var RoughnessMipmapper = ( function () {
+
+	var _mipmapMaterial = _getMipmapMaterial();
+	var _scene = new Scene();
+	_scene.add( new Mesh( new PlaneBufferGeometry( 2, 2 ), _mipmapMaterial ) );
+
+	var _flatCamera = new OrthographicCamera( 0, 1, 0, 1, 0, 1 );
+	var _tempTarget = null;
+	var _renderer = null;
+
+	// constructor
+	var RoughnessMipmapper = function ( renderer ) {
+
+		_renderer = renderer;
+		_renderer.compile( _scene, _flatCamera );
+
+	};
+
+	RoughnessMipmapper.prototype = {
+
+		constructor: RoughnessMipmapper,
+
+		generateMipmaps: function ( material ) {
+
+			var { roughnessMap, normalMap } = material;
+			if ( roughnessMap == null || normalMap == null || ! roughnessMap.generateMipmaps ||
+                material.userData.roughnessUpdated ) return;
+
+			material.userData.roughnessUpdated = true;
+
+			var width = Math.max( roughnessMap.image.width, normalMap.image.width );
+			var height = Math.max( roughnessMap.image.height, normalMap.image.height );
+			if ( ! _Math.isPowerOfTwo( width ) || ! _Math.isPowerOfTwo( height ) ) return;
+
+			var autoClear = _renderer.autoClear;
+			_renderer.autoClear = false;
+
+			if ( _tempTarget == null || _tempTarget.width !== width || _tempTarget.height !== height ) {
+
+				if ( _tempTarget != null ) _tempTarget.dispose();
+
+				_tempTarget = new WebGLRenderTarget( width, height, { depthBuffer: false, stencilBuffer: false } );
+
+			}
+
+			if ( width !== roughnessMap.image.width || height !== roughnessMap.image.height ) {
+
+				var newRoughnessTarget = new WebGLRenderTarget( width, height, {
+					minFilter: LinearMipMapLinearFilter,
+					depthBuffer: false,
+					stencilBuffer: false
+				} );
+				newRoughnessTarget.texture.generateMipmaps = true;
+				// Setting the render target causes the memory to be allocated.
+				_renderer.setRenderTarget( newRoughnessTarget );
+				material.roughnessMap = newRoughnessTarget.texture;
+				if ( material.metalnessMap == roughnessMap ) material.metalnessMap = material.roughnessMap;
+				if ( material.aoMap == roughnessMap ) material.aoMap = material.roughnessMap;
+
+			}
+
+			_renderer.setRenderTarget( _tempTarget );
+			_mipmapMaterial.uniforms.roughnessMap.value = roughnessMap;
+			_mipmapMaterial.uniforms.normalMap.value = normalMap;
+
+			var dpr = _renderer.getPixelRatio();
+			var position = new Vector2( 0, 0 );
+			var texelSize = _mipmapMaterial.uniforms.texelSize.value;
+			for ( var mip = 0; width >= 1 && height >= 1;
+				++ mip, width /= 2, height /= 2 ) {
+
+				// Rendering to a mip level is not allowed in webGL1. Instead we must set
+				// up a secondary texture to write the result to, then copy it back to the
+				// proper mipmap level.
+				texelSize.set( 1.0 / width, 1.0 / height );
+				if ( mip == 0 ) texelSize.set( 0.0, 0.0 );
+
+				_renderer.setViewport( position.x, position.y, width / dpr, height / dpr );
+				_renderer.render( _scene, _flatCamera );
+				_renderer.copyFramebufferToTexture( position, material.roughnessMap, mip );
+				_mipmapMaterial.uniforms.roughnessMap.value = material.roughnessMap;
+
+			}
+
+			if ( roughnessMap !== material.roughnessMap ) roughnessMap.dispose();
+
+			_renderer.autoClear = autoClear;
+			_renderer.setRenderTarget( null );
+			var size = _renderer.getSize( new Vector2() );
+			_renderer.setViewport( 0, 0, size.x, size.y );
+
+		},
+
+		dispose: function ( ) {
+
+			_mipmapMaterial.dispose();
+			_scene.children[ 0 ].geometry.dispose();
+			if ( _tempTarget != null ) _tempTarget.dispose();
+
+		}
+
+	};
+
+	function _getMipmapMaterial() {
+
+		var shaderMaterial = new RawShaderMaterial( {
+
+			uniforms: {
+				roughnessMap: { value: null },
+				normalMap: { value: null },
+				texelSize: { value: new Vector2( 1, 1 ) }
+			},
+
+			vertexShader: `
+precision mediump float;
+precision mediump int;
+attribute vec3 position;
+attribute vec2 uv;
+varying vec2 vUv;
+void main() {
+    vUv = uv;
+    gl_Position = vec4( position, 1.0 );
+}
+              `,
+
+			fragmentShader: `
+precision mediump float;
+precision mediump int;
+varying vec2 vUv;
+uniform sampler2D roughnessMap;
+uniform sampler2D normalMap;
+uniform vec2 texelSize;
+
+#define ENVMAP_TYPE_CUBE_UV
+vec4 envMapTexelToLinear(vec4 a){return a;}
+#include <cube_uv_reflection_fragment>
+
+float roughnessToVariance(float roughness) {
+  float variance = 0.0;
+  if (roughness >= r1) {
+    variance = (r0 - roughness) * (v1 - v0) / (r0 - r1) + v0;
+  } else if (roughness >= r4) {
+    variance = (r1 - roughness) * (v4 - v1) / (r1 - r4) + v1;
+  } else if (roughness >= r5) {
+    variance = (r4 - roughness) * (v5 - v4) / (r4 - r5) + v4;
+  } else {
+    float roughness2 = roughness * roughness;
+    variance = 1.79 * roughness2 * roughness2;
+  }
+  return variance;
+}
+float varianceToRoughness(float variance) {
+  float roughness = 0.0;
+  if (variance >= v1) {
+    roughness = (v0 - variance) * (r1 - r0) / (v0 - v1) + r0;
+  } else if (variance >= v4) {
+    roughness = (v1 - variance) * (r4 - r1) / (v1 - v4) + r1;
+  } else if (variance >= v5) {
+    roughness = (v4 - variance) * (r5 - r4) / (v4 - v5) + r4;
+  } else {
+    roughness = pow(0.559 * variance, 0.25);// 0.559 = 1.0 / 1.79
+  }
+  return roughness;
+}
+
+void main() {
+    gl_FragColor = texture2D(roughnessMap, vUv, -1.0);
+    if (texelSize.x == 0.0) return;
+    float roughness = gl_FragColor.g;
+    float variance = roughnessToVariance(roughness);
+    vec3 avgNormal;
+    for (float x = -1.0; x < 2.0; x += 2.0) {
+    for (float y = -1.0; y < 2.0; y += 2.0) {
+        vec2 uv = vUv + vec2(x, y) * 0.25 * texelSize;
+        avgNormal += normalize(texture2D(normalMap, uv, -1.0).xyz - 0.5);
+    }
+    }
+    variance += 1.0 - 0.25 * length(avgNormal);
+    gl_FragColor.g = varianceToRoughness(variance);
+}
+              `,
+
+			blending: NoBlending,
+			depthTest: false,
+			depthWrite: false
+
+		} );
+
+		shaderMaterial.type = 'RoughnessMipmapper';
+
+		return shaderMaterial;
+
+	}
+
+	return RoughnessMipmapper;
+
+} )();
+
+export { RoughnessMipmapper };

+ 0 - 11
examples/jsm/vr/WebVR.d.ts

@@ -1,11 +0,0 @@
-import {
-	WebGLRenderer
-} from '../../../src/Three';
-
-export interface WEBVROptions {
-	referenceSpaceType: string;
-}
-
-export namespace WEBVR {
-	export function createButton( renderer: WebGLRenderer, options?: WEBVROptions ): HTMLElement;
-}

+ 0 - 267
examples/jsm/vr/WebVR.js

@@ -1,267 +0,0 @@
-/**
- * @author mrdoob / http://mrdoob.com
- * @author Mugen87 / https://github.com/Mugen87
- *
- * Based on @tojiro's vr-samples-utils.js
- */
-
-
-
-var WEBVR = {
-
-	createButton: function ( renderer, options ) {
-
-		console.warn( 'WEBVR.js has been deprecated. Use VRButton.js instead.' );
-
-		if ( options && options.referenceSpaceType ) {
-
-			renderer.xr.setReferenceSpaceType( options.referenceSpaceType );
-
-		}
-
-		function showEnterVR( device ) {
-
-			button.style.display = '';
-
-			button.style.cursor = 'pointer';
-			button.style.left = 'calc(50% - 50px)';
-			button.style.width = '100px';
-
-			button.textContent = 'ENTER VR';
-
-			button.onmouseenter = function () {
-
-				button.style.opacity = '1.0';
-
-			};
-
-			button.onmouseleave = function () {
-
-				button.style.opacity = '0.5';
-
-			};
-
-			button.onclick = function () {
-
-				device.isPresenting ? device.exitPresent() : device.requestPresent( [ { source: renderer.domElement } ] );
-
-			};
-
-			renderer.xr.setDevice( device );
-
-		}
-
-		function showEnterXR( /*device*/ ) {
-
-			var currentSession = null;
-
-			function onSessionStarted( session ) {
-
-				session.addEventListener( 'end', onSessionEnded );
-
-				renderer.xr.setSession( session );
-				button.textContent = 'EXIT XR';
-
-				currentSession = session;
-
-			}
-
-			function onSessionEnded( /*event*/ ) {
-
-				currentSession.removeEventListener( 'end', onSessionEnded );
-
-				renderer.xr.setSession( null );
-				button.textContent = 'ENTER XR';
-
-				currentSession = null;
-
-			}
-
-			//
-
-			button.style.display = '';
-
-			button.style.cursor = 'pointer';
-			button.style.left = 'calc(50% - 50px)';
-			button.style.width = '100px';
-
-			button.textContent = 'ENTER XR';
-
-			button.onmouseenter = function () {
-
-				button.style.opacity = '1.0';
-
-			};
-
-			button.onmouseleave = function () {
-
-				button.style.opacity = '0.5';
-
-			};
-
-			button.onclick = function () {
-
-				if ( currentSession === null ) {
-
-					// WebXR's requestReferenceSpace only works if the corresponding feature
-					// was requested at session creation time. For simplicity, just ask for
-					// the interesting ones as optional features, but be aware that the
-					// requestReferenceSpace call will fail if it turns out to be unavailable.
-					// ('local' is always available for immersive sessions and doesn't need to
-					// be requested separately.)
-
-					var sessionInit = { optionalFeatures: [ 'local-floor', 'bounded-floor' ] };
-					navigator.xr.requestSession( 'immersive-vr', sessionInit ).then( onSessionStarted );
-
-				} else {
-
-					currentSession.end();
-
-				}
-
-			};
-
-		}
-
-		function disableButton() {
-
-			button.style.display = '';
-
-			button.style.cursor = 'auto';
-			button.style.left = 'calc(50% - 75px)';
-			button.style.width = '150px';
-
-			button.onmouseenter = null;
-			button.onmouseleave = null;
-
-			button.onclick = null;
-
-		}
-
-		function showVRNotFound() {
-
-			disableButton();
-
-			button.textContent = 'VR NOT FOUND';
-
-			renderer.xr.setDevice( null );
-
-		}
-
-		function showXRNotFound() {
-
-			disableButton();
-
-			button.textContent = 'XR NOT FOUND';
-
-		}
-
-		function stylizeElement( element ) {
-
-			element.style.position = 'absolute';
-			element.style.bottom = '20px';
-			element.style.padding = '12px 6px';
-			element.style.border = '1px solid #fff';
-			element.style.borderRadius = '4px';
-			element.style.background = 'rgba(0,0,0,0.1)';
-			element.style.color = '#fff';
-			element.style.font = 'normal 13px sans-serif';
-			element.style.textAlign = 'center';
-			element.style.opacity = '0.5';
-			element.style.outline = 'none';
-			element.style.zIndex = '999';
-
-		}
-
-		if ( 'xr' in navigator ) {
-
-			var button = document.createElement( 'button' );
-			button.style.display = 'none';
-
-			stylizeElement( button );
-
-			navigator.xr.isSessionSupported( 'immersive-vr' ).then( function ( supported ) {
-
-				if ( supported ) {
-
-					showEnterXR();
-
-				} else {
-
-					showXRNotFound();
-
-				}
-
-			} );
-
-			return button;
-
-		} else if ( 'getVRDisplays' in navigator ) {
-
-			var button = document.createElement( 'button' );
-			button.style.display = 'none';
-
-			stylizeElement( button );
-
-			window.addEventListener( 'vrdisplayconnect', function ( event ) {
-
-				showEnterVR( event.display );
-
-			}, false );
-
-			window.addEventListener( 'vrdisplaydisconnect', function ( /*event*/ ) {
-
-				showVRNotFound();
-
-			}, false );
-
-			window.addEventListener( 'vrdisplaypresentchange', function ( event ) {
-
-				button.textContent = event.display.isPresenting ? 'EXIT VR' : 'ENTER VR';
-
-			}, false );
-
-			window.addEventListener( 'vrdisplayactivate', function ( event ) {
-
-				event.display.requestPresent( [ { source: renderer.domElement } ] );
-
-			}, false );
-
-			navigator.getVRDisplays()
-				.then( function ( displays ) {
-
-					if ( displays.length > 0 ) {
-
-						showEnterVR( displays[ 0 ] );
-
-					} else {
-
-						showVRNotFound();
-
-					}
-
-				} ).catch( showVRNotFound );
-
-			return button;
-
-		} else {
-
-			var message = document.createElement( 'a' );
-			message.href = 'https://webvr.info';
-			message.innerHTML = 'WEBVR NOT SUPPORTED';
-
-			message.style.left = 'calc(50% - 90px)';
-			message.style.width = '180px';
-			message.style.textDecoration = 'none';
-
-			stylizeElement( message );
-
-			return message;
-
-		}
-
-	}
-
-};
-
-export { WEBVR };

+ 6 - 14
examples/jsm/webxr/ARButton.js

@@ -7,7 +7,7 @@ var ARButton = {
 
 	createButton: function ( renderer ) {
 
-		function showEnterXR( /*device*/ ) {
+		function showStartAR( /*device*/ ) {
 
 			var currentSession = null;
 
@@ -93,11 +93,11 @@ var ARButton = {
 
 		}
 
-		function showXRNotFound() {
+		function showARNotSupported() {
 
 			disableButton();
 
-			button.textContent = 'XR NOT FOUND';
+			button.textContent = 'AR NOT SUPPORTED';
 
 		}
 
@@ -127,24 +127,16 @@ var ARButton = {
 
 			navigator.xr.isSessionSupported( 'immersive-ar' ).then( function ( supported ) {
 
-				if ( supported ) {
+				supported ? showStartAR() : showARNotSupported();
 
-					showEnterXR();
-
-				} else {
-
-					showXRNotFound();
-
-				}
-
-			} );
+			} ).catch( showARNotSupported );
 
 			return button;
 
 		} else {
 
 			var message = document.createElement( 'a' );
-			message.href = 'https://immersive-web.github.io/webxr/';
+			message.href = 'https://immersiveweb.dev/';
 
 			if ( window.isSecureContext === false ) {
 

+ 12 - 101
examples/jsm/webxr/VRButton.js

@@ -13,39 +13,7 @@ var VRButton = {
 
 		}
 
-		function showEnterVR( device ) {
-
-			button.style.display = '';
-
-			button.style.cursor = 'pointer';
-			button.style.left = 'calc(50% - 50px)';
-			button.style.width = '100px';
-
-			button.textContent = 'ENTER_VR';
-
-			button.onmouseenter = function () {
-
-				button.style.opacity = '1.0';
-
-			};
-
-			button.onmouseleave = function () {
-
-				button.style.opacity = '0.5';
-
-			};
-
-			button.onclick = function () {
-
-				device.isPresenting ? device.exitPresent() : device.requestPresent( [ { source: renderer.domElement } ] );
-
-			};
-
-			renderer.xr.setDevice( device );
-
-		}
-
-		function showEnterXR( /*device*/ ) {
+		function showEnterVR( /*device*/ ) {
 
 			var currentSession = null;
 
@@ -132,21 +100,11 @@ var VRButton = {
 
 		}
 
-		function showVRNotFound() {
-
-			disableButton();
-
-			button.textContent = 'VR NOT FOUND';
-
-			renderer.xr.setDevice( null );
-
-		}
-
-		function showXRNotFound() {
+		function showWebXRNotFound() {
 
 			disableButton();
 
-			button.textContent = 'VR NOT FOUND';
+			button.textContent = 'VR NOT SUPPORTED';
 
 		}
 
@@ -176,73 +134,26 @@ var VRButton = {
 
 			navigator.xr.isSessionSupported( 'immersive-vr' ).then( function ( supported ) {
 
-				if ( supported ) {
-
-					showEnterXR();
-
-				} else {
-
-					showXRNotFound();
-
-				}
+				supported ? showEnterVR() : showWebXRNotFound();
 
 			} );
 
 			return button;
 
-		} else if ( 'getVRDisplays' in navigator ) {
-
-			var button = document.createElement( 'button' );
-			button.style.display = 'none';
-
-			stylizeElement( button );
-
-			window.addEventListener( 'vrdisplayconnect', function ( event ) {
-
-				showEnterVR( event.display );
-
-			}, false );
-
-			window.addEventListener( 'vrdisplaydisconnect', function ( /*event*/ ) {
-
-				showVRNotFound();
-
-			}, false );
-
-			window.addEventListener( 'vrdisplaypresentchange', function ( event ) {
-
-				button.textContent = event.display.isPresenting ? 'EXIT_VR' : 'ENTER_VR';
-
-			}, false );
-
-			window.addEventListener( 'vrdisplayactivate', function ( event ) {
-
-				event.display.requestPresent( [ { source: renderer.domElement } ] );
-
-			}, false );
-
-			navigator.getVRDisplays()
-				.then( function ( displays ) {
-
-					if ( displays.length > 0 ) {
-
-						showEnterVR( displays[ 0 ] );
-
-					} else {
+		} else {
 
-						showVRNotFound();
+			var message = document.createElement( 'a' );
+			message.href = 'https://immersiveweb.dev/';
 
-					}
+			if ( window.isSecureContext === false ) {
 
-				} ).catch( showVRNotFound );
+				message.innerHTML = 'WEBXR NEEDS HTTPS'; // TODO Improve message
 
-			return button;
+			} else {
 
-		} else {
+				message.innerHTML = 'WEBXR NOT AVAILABLE';
 
-			var message = document.createElement( 'a' );
-			message.href = 'https://immersive-web.github.io/webxr/';
-			message.innerHTML = 'WEBXR NOT SUPPORTED';
+			}
 
 			message.style.left = 'calc(50% - 90px)';
 			message.style.width = '180px';

+ 4 - 2
examples/misc_controls_transform.html

@@ -10,7 +10,7 @@
 
 		<div id="info">
 			"W" translate | "E" rotate | "R" scale | "+" increase size | "-" decrease size<br />
-			"Q" toggle world/local space |  Hold "Ctrl" down to snap to grid<br />
+			"Q" toggle world/local space |  Hold "Shift" down to snap to grid<br />
 			"X" toggle X | "Y" toggle Y | "Z" toggle Z | "Spacebar" toggle enabled
 		</div>
 
@@ -81,9 +81,10 @@
 							control.setSpace( control.space === "local" ? "world" : "local" );
 							break;
 
-						case 17: // Ctrl
+						case 16: // Shift
 							control.setTranslationSnap( 100 );
 							control.setRotationSnap( THREE.Math.degToRad( 15 ) );
+							control.setScaleSnap( 0.25 );
 							break;
 
 						case 87: // W
@@ -135,6 +136,7 @@
 						case 17: // Ctrl
 							control.setTranslationSnap( null );
 							control.setRotationSnap( null );
+							control.setScaleSnap( null );
 							break;
 
 					}

+ 3 - 2
examples/misc_exporter_collada.html

@@ -73,8 +73,7 @@
 				renderer = new THREE.WebGLRenderer( { antialias: true } );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( canvasWidth, canvasHeight );
-				renderer.gammaInput = true;
-				renderer.gammaOutput = true;
+				renderer.outputEncoding = THREE.sRGBEncoding;
 				container.appendChild( renderer.domElement );
 
 				// EVENTS
@@ -88,6 +87,7 @@
 				var textureMap = new THREE.TextureLoader().load( 'textures/uv_grid_opengl.jpg' );
 				textureMap.wrapS = textureMap.wrapT = THREE.RepeatWrapping;
 				textureMap.anisotropy = 16;
+				textureMap.encoding = THREE.sRGBEncoding;
 
 				// REFLECTION MAP
 				var path = "textures/cube/pisa/";
@@ -98,6 +98,7 @@
 				];
 
 				textureCube = new THREE.CubeTextureLoader().load( urls );
+				textureCube.encoding = THREE.sRGBEncoding;
 
 				// MATERIALS
 				var materialColor = new THREE.Color();

BIN
examples/textures/equirectangular/spot1Lux.hdr


+ 1 - 2
examples/webaudio_orientation.html

@@ -144,8 +144,7 @@
 			renderer = new THREE.WebGLRenderer( { antialias: true } );
 			renderer.setSize( window.innerWidth, window.innerHeight );
 			renderer.setPixelRatio( window.devicePixelRatio );
-			renderer.gammaOutput = true;
-			renderer.gammaFactor = 2.2;
+			renderer.outputEncoding = THREE.sRGBEncoding;
 			renderer.shadowMap.enabled = true;
 			container.appendChild( renderer.domElement );
 

+ 2 - 2
examples/webgl_animation_cloth.html

@@ -503,6 +503,7 @@
 				groundTexture.wrapS = groundTexture.wrapT = THREE.RepeatWrapping;
 				groundTexture.repeat.set( 25, 25 );
 				groundTexture.anisotropy = 16;
+				groundTexture.encoding = THREE.sRGBEncoding;
 
 				var groundMaterial = new THREE.MeshLambertMaterial( { map: groundTexture } );
 
@@ -561,8 +562,7 @@
 
 				container.appendChild( renderer.domElement );
 
-				renderer.gammaInput = true;
-				renderer.gammaOutput = true;
+				renderer.outputEncoding = THREE.sRGBEncoding;
 
 				renderer.shadowMap.enabled = true;
 

+ 1 - 2
examples/webgl_animation_keyframes.html

@@ -49,8 +49,7 @@
 			renderer = new THREE.WebGLRenderer( { antialias: true } );
 			renderer.setPixelRatio( window.devicePixelRatio );
 			renderer.setSize( window.innerWidth, window.innerHeight );
-			renderer.gammaOutput = true;
-			renderer.gammaFactor = 2.2;
+			renderer.outputEncoding = THREE.sRGBEncoding;
 			container.appendChild( renderer.domElement );
 
 			scene = new THREE.Scene();

+ 1 - 2
examples/webgl_animation_multiple.html

@@ -320,8 +320,7 @@
 				renderer = new THREE.WebGLRenderer( { antialias: true } );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth, window.innerHeight );
-				renderer.gammaOutput = true;
-				renderer.gammaFactor = 2.2;
+				renderer.outputEncoding = THREE.sRGBEncoding;
 				renderer.shadowMap.enabled = true;
 				renderer.shadowMap.type = THREE.PCFSoftShadowMap;
 				container.appendChild( renderer.domElement );

+ 1 - 2
examples/webgl_animation_skinning_blending.html

@@ -137,8 +137,7 @@
 				renderer = new THREE.WebGLRenderer( { antialias: true } );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth, window.innerHeight );
-				renderer.gammaOutput = true;
-				renderer.gammaFactor = 2.2;
+				renderer.outputEncoding = THREE.sRGBEncoding;
 				renderer.shadowMap.enabled = true;
 				container.appendChild( renderer.domElement );
 

+ 1 - 2
examples/webgl_animation_skinning_morph.html

@@ -106,8 +106,7 @@
 				renderer = new THREE.WebGLRenderer( { antialias: true } );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth, window.innerHeight );
-				renderer.gammaOutput = true;
-				renderer.gammaFactor = 2.2;
+				renderer.outputEncoding = THREE.sRGBEncoding;
 				container.appendChild( renderer.domElement );
 
 				window.addEventListener( 'resize', onWindowResize, false );

+ 1 - 3
examples/webgl_buffergeometry.html

@@ -156,9 +156,7 @@
 				renderer = new THREE.WebGLRenderer();
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth, window.innerHeight );
-
-				renderer.gammaInput = true;
-				renderer.gammaOutput = true;
+				renderer.outputEncoding = THREE.sRGBEncoding;
 
 				container.appendChild( renderer.domElement );
 

+ 1 - 3
examples/webgl_buffergeometry_drawrange.html

@@ -168,9 +168,7 @@
 				renderer = new THREE.WebGLRenderer( { antialias: true } );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth, window.innerHeight );
-
-				renderer.gammaInput = true;
-				renderer.gammaOutput = true;
+				renderer.outputEncoding = THREE.sRGBEncoding;
 
 				container.appendChild( renderer.domElement );
 

+ 2 - 2
examples/webgl_buffergeometry_instancing_lambert.html

@@ -35,7 +35,7 @@
 		import { Curves } from './jsm/curves/CurveExtras.js';
 
 		// this is a cut-and-paste of the depth shader -- modified to accommodate instancing for this app
-		var customDepthVertexShader = 
+		var customDepthVertexShader =
 			`
 			// instanced
 			attribute vec3 instanceOffset;
@@ -165,7 +165,7 @@
 			renderer.shadowMap.enabled = true;
 			document.body.appendChild( renderer.domElement );
 
-			renderer.gammaOutput = true;
+			renderer.outputEncoding = THREE.sRGBEncoding;
 
 			scene = new THREE.Scene();
 

+ 1 - 3
examples/webgl_buffergeometry_lines.html

@@ -82,9 +82,7 @@
 				renderer = new THREE.WebGLRenderer();
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth, window.innerHeight );
-
-				renderer.gammaInput = true;
-				renderer.gammaOutput = true;
+				renderer.outputEncoding = THREE.sRGBEncoding;
 
 				container.appendChild( renderer.domElement );
 

+ 1 - 3
examples/webgl_buffergeometry_lines_indexed.html

@@ -190,9 +190,7 @@
 				renderer = new THREE.WebGLRenderer();
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth, window.innerHeight );
-
-				renderer.gammaInput = true;
-				renderer.gammaOutput = true;
+				renderer.outputEncoding = THREE.sRGBEncoding;
 
 				container.appendChild( renderer.domElement );
 

+ 1 - 3
examples/webgl_buffergeometry_uint.html

@@ -157,9 +157,7 @@
 				renderer = new THREE.WebGLRenderer();
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth, window.innerHeight );
-
-				renderer.gammaInput = true;
-				renderer.gammaOutput = true;
+				renderer.outputEncoding = THREE.sRGBEncoding;
 
 				container.appendChild( renderer.domElement );
 

+ 3 - 2
examples/webgl_geometry_teapot.html

@@ -67,8 +67,7 @@
 				renderer = new THREE.WebGLRenderer( { antialias: true } );
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( canvasWidth, canvasHeight );
-				renderer.gammaInput = true;
-				renderer.gammaOutput = true;
+				renderer.outputEncoding = THREE.sRGBEncoding;
 				container.appendChild( renderer.domElement );
 
 				// EVENTS
@@ -82,6 +81,7 @@
 				var textureMap = new THREE.TextureLoader().load( 'textures/uv_grid_opengl.jpg' );
 				textureMap.wrapS = textureMap.wrapT = THREE.RepeatWrapping;
 				textureMap.anisotropy = 16;
+				textureMap.encoding = THREE.sRGBEncoding;
 
 				// REFLECTION MAP
 				var path = "textures/cube/pisa/";
@@ -92,6 +92,7 @@
 				];
 
 				textureCube = new THREE.CubeTextureLoader().load( urls );
+				textureCube.encoding = THREE.sRGBEncoding;
 
 				// MATERIALS
 				var materialColor = new THREE.Color();

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно