Mr.doob 3 years ago
parent
commit
a69b8fa163
87 changed files with 1697 additions and 839 deletions
  1. 26 102
      build/three.cjs
  2. 26 102
      build/three.js
  3. 0 0
      build/three.min.js
  4. 32 140
      build/three.module.js
  5. 1 1
      docs/api/en/geometries/LatheGeometry.html
  6. 0 1
      docs/api/en/objects/InstancedMesh.html
  7. 1 1
      docs/api/zh/geometries/LatheGeometry.html
  8. 0 1
      docs/api/zh/objects/InstancedMesh.html
  9. 2 2
      docs/examples/en/postprocessing/EffectComposer.html
  10. 2 2
      docs/examples/zh/postprocessing/EffectComposer.html
  11. 2 7
      docs/manual/ar/introduction/Installation.html
  12. 3 7
      docs/manual/en/introduction/Installation.html
  13. 2 8
      docs/manual/ja/introduction/Installation.html
  14. 2 10
      docs/manual/ko/introduction/Installation.html
  15. 2 6
      docs/manual/zh/introduction/Installation.html
  16. 23 5
      editor/js/Sidebar.Geometry.Modifiers.js
  17. 6 0
      editor/js/Strings.js
  18. 0 2
      editor/sw.js
  19. 7 4
      examples/files.json
  20. 0 2
      examples/js/controls/OrbitControls.js
  21. 0 1
      examples/js/loaders/GLTFLoader.js
  22. 1 1
      examples/js/loaders/SVGLoader.js
  23. 0 2
      examples/jsm/controls/OrbitControls.js
  24. 9 9
      examples/jsm/controls/TransformControls.js
  25. 5 1
      examples/jsm/exporters/USDZExporter.js
  26. 1 1
      examples/jsm/geometries/ConvexGeometry.js
  27. 5 3
      examples/jsm/interactive/SelectionHelper.js
  28. 1 0
      examples/jsm/loaders/ColladaLoader.js
  29. 0 1
      examples/jsm/loaders/GLTFLoader.js
  30. 43 4
      examples/jsm/loaders/PCDLoader.js
  31. 2 2
      examples/jsm/loaders/SVGLoader.js
  32. 6 6
      examples/jsm/nodes/Nodes.js
  33. 4 4
      examples/jsm/nodes/accessors/NormalNode.js
  34. 5 5
      examples/jsm/nodes/accessors/PositionNode.js
  35. 3 3
      examples/jsm/nodes/core/AttributeNode.js
  36. 12 12
      examples/jsm/nodes/core/NodeBuilder.js
  37. 3 3
      examples/jsm/nodes/core/NodeVarying.js
  38. 7 7
      examples/jsm/nodes/core/VaryingNode.js
  39. 2 0
      examples/jsm/nodes/gpgpu/ComputeNode.js
  40. 4 1
      examples/jsm/nodes/materials/Materials.js
  41. 46 0
      examples/jsm/nodes/materials/MeshPhysicalNodeMaterial.js
  42. 0 6
      examples/jsm/nodes/materials/MeshStandardNodeMaterial.js
  43. 2 2
      examples/jsm/nodes/shadernode/ShaderNodeBaseElements.js
  44. 186 0
      examples/jsm/objects/GroundProjectedEnv.js
  45. 93 27
      examples/jsm/renderers/webgl/nodes/WebGLNodeBuilder.js
  46. 6 0
      examples/jsm/renderers/webgpu/WebGPUComputePipelines.js
  47. 8 17
      examples/jsm/renderers/webgpu/WebGPURenderPipeline.js
  48. 16 14
      examples/jsm/renderers/webgpu/WebGPURenderPipelines.js
  49. 33 51
      examples/jsm/renderers/webgpu/WebGPURenderer.js
  50. 81 0
      examples/jsm/renderers/webgpu/WebGPUUtils.js
  51. 20 20
      examples/jsm/renderers/webgpu/nodes/WebGPUNodeBuilder.js
  52. 1 1
      examples/jsm/shaders/LuminosityShader.js
  53. 1 1
      examples/jsm/shaders/ToneMapShader.js
  54. 16 0
      examples/models/svg/tests/roundJoinPrecisionIssue.svg
  55. BIN
      examples/screenshots/webgl2_multisampled_renderbuffers.jpg
  56. BIN
      examples/screenshots/webgl2_ubo.jpg
  57. BIN
      examples/screenshots/webgl_instancing_modified.jpg
  58. BIN
      examples/screenshots/webgl_loader_pcd.jpg
  59. BIN
      examples/screenshots/webgl_loader_texture_ktx.jpg
  60. BIN
      examples/screenshots/webgl_materials_envmaps_groundprojected.jpg
  61. BIN
      examples/screenshots/webgl_materials_standard_nodes.jpg
  62. BIN
      examples/screenshots/webgl_nodes_loader_gltf_sheen.jpg
  63. 0 0
      examples/screenshots/webgl_nodes_materials_instance_uniform.jpg
  64. BIN
      examples/screenshots/webgl_nodes_materials_physical_clearcoat.jpg
  65. BIN
      examples/screenshots/webgl_nodes_materials_standard.jpg
  66. 0 0
      examples/screenshots/webgl_nodes_points.jpg
  67. BIN
      examples/screenshots/webgl_postprocessing_glitch.jpg
  68. BIN
      examples/screenshots/webgl_postprocessing_procedural.jpg
  69. 0 1
      examples/tags.json
  70. BIN
      examples/textures/equirectangular/blouberg_sunrise_2_1k.hdr
  71. 314 0
      examples/webgl2_ubo.html
  72. 5 1
      examples/webgl_animation_skinning_additive_blending.html
  73. 0 208
      examples/webgl_instancing_modified.html
  74. 3 1
      examples/webgl_loader_svg.html
  75. 184 0
      examples/webgl_materials_envmaps_groundprojected.html
  76. 1 1
      examples/webgl_modifier_simplifier.html
  77. 140 0
      examples/webgl_nodes_loader_gltf_sheen.html
  78. 0 0
      examples/webgl_nodes_materials_instance_uniform.html
  79. 256 0
      examples/webgl_nodes_materials_physical_clearcoat.html
  80. 0 0
      examples/webgl_nodes_materials_standard.html
  81. 0 0
      examples/webgl_nodes_points.html
  82. 1 1
      examples/webgl_raycaster_bvh.html
  83. 6 1
      examples/webgl_shaders_ocean.html
  84. 25 14
      examples/webgpu_compute.html
  85. 1 1
      examples/webxr_ar_lighting.html
  86. 1 1
      index.html
  87. 1 1
      manual/zh/optimize-lots-of-objects.html

File diff suppressed because it is too large
+ 26 - 102
build/three.cjs


File diff suppressed because it is too large
+ 26 - 102
build/three.js


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


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


+ 1 - 1
docs/api/en/geometries/LatheGeometry.html

@@ -48,7 +48,7 @@
 
 
 		<h3>[name]([param:Array points], [param:Integer segments], [param:Float phiStart], [param:Float phiLength])</h3>
 		<h3>[name]([param:Array points], [param:Integer segments], [param:Float phiStart], [param:Float phiLength])</h3>
 		<p>
 		<p>
-		points — Array of Vector2s. The x-coordinate of each point must be greater than zero. Default is an array with (0,0.5), (0.5,0) and (0,-0.5) which creates a simple diamond shape.<br />
+		points — Array of Vector2s. The x-coordinate of each point must be greater than zero. Default is an array with (0,-0.5), (0.5,0) and (0,0.5) which creates a simple diamond shape.<br />
 		segments — the number of circumference segments to generate. Default is 12.<br />
 		segments — the number of circumference segments to generate. Default is 12.<br />
 		phiStart — the starting angle in radians. Default is 0.<br />
 		phiStart — the starting angle in radians. Default is 0.<br />
 		phiLength — the radian (0 to 2PI) range of the lathed section 2PI is a closed lathe, less than 2PI is a portion. Default is 2PI.
 		phiLength — the radian (0 to 2PI) range of the lathed section 2PI is a closed lathe, less than 2PI is a portion. Default is 2PI.

+ 0 - 1
docs/api/en/objects/InstancedMesh.html

@@ -21,7 +21,6 @@
 
 
 		<p>
 		<p>
 			[example:webgl_instancing_dynamic WebGL / instancing / dynamic]<br />
 			[example:webgl_instancing_dynamic WebGL / instancing / dynamic]<br />
-			[example:webgl_instancing_modified WebGL / instancing / modified]<br />
 			[example:webgl_instancing_performance WebGL / instancing / performance]<br />
 			[example:webgl_instancing_performance WebGL / instancing / performance]<br />
 			[example:webgl_instancing_scatter WebGL / instancing / scatter]<br />
 			[example:webgl_instancing_scatter WebGL / instancing / scatter]<br />
 			[example:webgl_instancing_raycast WebGL / instancing / raycast]
 			[example:webgl_instancing_raycast WebGL / instancing / raycast]

+ 1 - 1
docs/api/zh/geometries/LatheGeometry.html

@@ -48,7 +48,7 @@
 
 
 		<h3>[name]([param:Array points], [param:Integer segments], [param:Float phiStart], [param:Float phiLength])</h3>
 		<h3>[name]([param:Array points], [param:Integer segments], [param:Float phiStart], [param:Float phiLength])</h3>
 		<p>
 		<p>
-		points — 一个Vector2对象数组。每个点的X坐标必须大于0。 Default is an array with (0,0.5), (0.5,0) and (0,-0.5) which creates a simple diamond shape.<br />
+		points — 一个Vector2对象数组。每个点的X坐标必须大于0。 Default is an array with (0,-0.5), (0.5,0) and (0,0.5) which creates a simple diamond shape.<br />
 		segments — 要生成的车削几何体圆周分段的数量,默认值是12。<br />
 		segments — 要生成的车削几何体圆周分段的数量,默认值是12。<br />
 		phiStart — 以弧度表示的起始角度,默认值为0。<br />
 		phiStart — 以弧度表示的起始角度,默认值为0。<br />
 		phiLength — 车削部分的弧度(0-2PI)范围,2PI将是一个完全闭合的、完整的车削几何体,小于2PI是部分的车削。默认值是2PI。
 		phiLength — 车削部分的弧度(0-2PI)范围,2PI将是一个完全闭合的、完整的车削几何体,小于2PI是部分的车削。默认值是2PI。

+ 0 - 1
docs/api/zh/objects/InstancedMesh.html

@@ -20,7 +20,6 @@
 
 
 		<p>
 		<p>
 			[example:webgl_instancing_dynamic WebGL / instancing / dynamic]<br />
 			[example:webgl_instancing_dynamic WebGL / instancing / dynamic]<br />
-			[example:webgl_instancing_modified WebGL / instancing / modified]<br />
 			[example:webgl_instancing_performance WebGL / instancing / performance]<br />
 			[example:webgl_instancing_performance WebGL / instancing / performance]<br />
 			[example:webgl_instancing_scatter WebGL / instancing / scatter]<br />
 			[example:webgl_instancing_scatter WebGL / instancing / scatter]<br />
 			[example:webgl_instancing_raycast WebGL / instancing / raycast]
 			[example:webgl_instancing_raycast WebGL / instancing / raycast]

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

@@ -59,7 +59,7 @@
 			An array representing the (ordered) chain of post-processing passes.
 			An array representing the (ordered) chain of post-processing passes.
 		</p>
 		</p>
 
 
-		<h3>[property:WebGLRendererTarget readBuffer]</h3>
+		<h3>[property:WebGLRenderTarget readBuffer]</h3>
 		<p>
 		<p>
 			A reference to the internal read buffer. Passes usually read the previous render result from this buffer.
 			A reference to the internal read buffer. Passes usually read the previous render result from this buffer.
 		</p>
 		</p>
@@ -74,7 +74,7 @@
 			Whether the final pass is rendered to the screen (default framebuffer) or not.
 			Whether the final pass is rendered to the screen (default framebuffer) or not.
 		</p>
 		</p>
 
 
-		<h3>[property:WebGLRendererTarget writeBuffer]</h3>
+		<h3>[property:WebGLRenderTarget writeBuffer]</h3>
 		<p>
 		<p>
 			A reference to the internal write buffer. Passes usually write their result into this buffer.
 			A reference to the internal write buffer. Passes usually write their result into this buffer.
 		</p>
 		</p>

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

@@ -58,7 +58,7 @@
 			一个用于表示后期处理过程链(包含顺序)的数组。
 			一个用于表示后期处理过程链(包含顺序)的数组。
 		</p>
 		</p>
 
 
-		<h3>[property:WebGLRendererTarget readBuffer]</h3>
+		<h3>[property:WebGLRenderTarget readBuffer]</h3>
 		<p>
 		<p>
 			内部读缓冲区的引用。过程一般从该缓冲区读取先前的渲染结果。
 			内部读缓冲区的引用。过程一般从该缓冲区读取先前的渲染结果。
 		</p>
 		</p>
@@ -73,7 +73,7 @@
 			最终过程是否被渲染到屏幕(默认帧缓冲区)。
 			最终过程是否被渲染到屏幕(默认帧缓冲区)。
 		</p>
 		</p>
 
 
-		<h3>[property:WebGLRendererTarget writeBuffer]</h3>
+		<h3>[property:WebGLRenderTarget writeBuffer]</h3>
 		<p>
 		<p>
 			内部写缓冲区的引用。过程常将它们的渲染结果写入该缓冲区。
 			内部写缓冲区的引用。过程常将它们的渲染结果写入该缓冲区。
 		</p>
 		</p>

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

@@ -163,16 +163,11 @@
 		<h3>Node.js</h3>
 		<h3>Node.js</h3>
 
 
 		<p>
 		<p>
-			قد يكون استخدام three.js في Node.js أمرًا صعبًا ، وذلك لسببين:
+			Because three.js is built for the web, it depends on browser and DOM APIs that don't always exist in Node.js. Some of these issues can be resolved by using shims like [link:https://github.com/stackgl/headless-gl headless-gl], or by replacing components like [page:TextureLoader] with custom alternatives. Other DOM APIs may be deeply intertwined with the code that uses them, and will be harder to work around. We welcome simple and maintainable pull requests to improve Node.js support, but recommend opening an issue to discuss your improvements first.
 		</p>
 		</p>
 
 
 		<p>
 		<p>
-			أولاً ، نظرًا لأن three.js مصممة للويب ، فإنها تعتمد على المتصفح وواجهات برمجة تطبيقات DOM التي لا تتواجد دائمًا في Node.js. يمكن حل بعض هذه المشكلات باستخدام (shims) مثل [link:https://github.com/stackgl/headless-gl headless-gl]، أو عن طريق استبدال مكونات مثل [page:TextureLoader] ببدائل مخصصة. قد تتشابك واجهات برمجة تطبيقات DOM الأخرى بعمق مع الكود الذي يستخدمها ، وسيكون من الصعب حلها. نرحب بطلبات السحب البسيطة والقابلة للصيانة لتحسين دعم Node.js ، لكننا نوصي بفتح مشكلة لمناقشة التحسينات التي أجريتها أولاً.
-		</p>
-
-		<p>
-			ثانيًا ، دعم Node.js لوحدات ES ... معقد. بدءًا من الإصدار 12 من Node.js ، يمكن استيراد المكتبة الأساسية كوحدة نمطية CommonJS ، مع <em>require('three')</em>. ومع ذلك ، فإن معظم أمثلة المكونات في <em>examples/jsm</em> لا يمكنها ذلك.
-			قد تحل الإصدارات المستقبلية من Node.js هذه المشكلة ، ولكن في هذه الأثناء قد تحتاج إلى استخدام حلول بديلة مثل [link:https://github.com/standard-things/esm esm] لتمكين تطبيق Node.js الخاص بك من التعرف على وحدات ES.
+			Make sure to add `{ "type": "module" }` to your `package.json` to enable ES6 modules in your node project.
 		</p>
 		</p>
 
 
 	</body>
 	</body>

+ 3 - 7
docs/manual/en/introduction/Installation.html

@@ -64,7 +64,7 @@
 
 
 		<p>
 		<p>
 			The three.js library can be used without any build system, either by uploading files to your own web server or by using an existing CDN. Because the library relies on ES modules, any script that references it must use <em>type="module"</em> as shown below.
 			The three.js library can be used without any build system, either by uploading files to your own web server or by using an existing CDN. Because the library relies on ES modules, any script that references it must use <em>type="module"</em> as shown below.
-			It is also require to define an Import Map which resolves the bare module specifier `three`.
+			It is also required to define an Import Map which resolves the bare module specifier `three`.
 		</p>
 		</p>
 
 
 		<code>
 		<code>
@@ -140,15 +140,11 @@
 		<h3>Node.js</h3>
 		<h3>Node.js</h3>
 
 
 		<p>
 		<p>
-			Using three.js in [link:https://eloquentjavascript.net/20_node.html Node.js] can be difficult, for two reasons:
+			Because three.js is built for the web, it depends on browser and DOM APIs that don't always exist in Node.js. Some of these issues can be resolved by using shims like [link:https://github.com/stackgl/headless-gl headless-gl], or by replacing components like [page:TextureLoader] with custom alternatives. Other DOM APIs may be deeply intertwined with the code that uses them, and will be harder to work around. We welcome simple and maintainable pull requests to improve Node.js support, but recommend opening an issue to discuss your improvements first.
 		</p>
 		</p>
 
 
 		<p>
 		<p>
-			First, because three.js is built for the web, it depends on browser and DOM APIs that don't always exist in Node.js. Some of these issues can be resolved by using shims like [link:https://github.com/stackgl/headless-gl headless-gl], or by replacing components like [page:TextureLoader] with custom alternatives. Other DOM APIs may be deeply intertwined with the code that uses them, and will be harder to work around. We welcome simple and maintainable pull requests to improve Node.js support, but recommend opening an issue to discuss your improvements first.
-		</p>
-
-		<p>
-			Second, Node.js support for ES modules is ... complicated. As of Node.js v12, the core library can be imported as a CommonJS module, with <em>require('three')</em>. However, most example components in <em>examples/jsm</em> cannot. Future versions of Node.js may resolve this, but in the meantime you may need to use workarounds like [link:https://github.com/standard-things/esm esm] to enable your Node.js application to recognize ES modules.
+			Make sure to add `{ "type": "module" }` to your `package.json` to enable ES6 modules in your node project.
 		</p>
 		</p>
 
 
 	</body>
 	</body>

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

@@ -144,17 +144,11 @@
     <h3>Node.js</h3>
     <h3>Node.js</h3>
 
 
     <p>
     <p>
-        以下の2つの理由からnode.jsでthree.jsを使用するのは難しくなりがちです。
+        Because three.js is built for the web, it depends on browser and DOM APIs that don't always exist in Node.js. Some of these issues can be resolved by using shims like [link:https://github.com/stackgl/headless-gl headless-gl], or by replacing components like [page:TextureLoader] with custom alternatives. Other DOM APIs may be deeply intertwined with the code that uses them, and will be harder to work around. We welcome simple and maintainable pull requests to improve Node.js support, but recommend opening an issue to discuss your improvements first.
     </p>
     </p>
 
 
     <p>
     <p>
-        まず、three.jsはWeb用に作られているので、Node.jsには必ずしも存在しないブラウザやDOM APIに依存します。これらの問題のいくつかは、[link:https://github.com/stackgl/headless-gl headless-gl] のような補正ツールを使用したり、[page:TextureLoader] のようなコンポーネントをカスタムの代替品で置き換えることで解決できます。他の DOM APIは、それらを使用するコードと深く絡み合っている可能性があり、回避するのが難しくなります。Node.js
-        のサポートを改善するためのシンプルで保守性の高いプルリクエストを歓迎しますが、まず問題を開いて改善点を議論することをお勧めします。
-    </p>
-
-    <p>
-        第二に、Node.jsによるESモジュールのサポートは...複雑です。Node.js v12の時点では、three.jsのコアライブラリは<em>require('three')</em>でCommonJSモジュールとしてインポートすることができます。しかし、<em>examples/jsm</em>にあるほとんどのサンプルコンポーネントはインポートできません。Node.jsの将来のバージョンで解決されるかもしれませんが、それまでの間は、[link:https://github.com/standard-things/esm
-        esm]のような回避策を使用して、Node.jsアプリケーションがESモジュールを認識できるようにする必要があるでしょう。
+        Make sure to add `{ "type": "module" }` to your `package.json` to enable ES6 modules in your node project.
     </p>
     </p>
 
 
 </body>
 </body>

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

@@ -164,19 +164,11 @@
     <h3>Node.js</h3>
     <h3>Node.js</h3>
 
 
     <p>
     <p>
-        three.js 를 [link:https://eloquentjavascript.net/20_node.html Node.js]에서 사용하는기에는 어려움이 있는데, 두 가지 이유가 있습니다.
+        Because three.js is built for the web, it depends on browser and DOM APIs that don't always exist in Node.js. Some of these issues can be resolved by using shims like [link:https://github.com/stackgl/headless-gl headless-gl], or by replacing components like [page:TextureLoader] with custom alternatives. Other DOM APIs may be deeply intertwined with the code that uses them, and will be harder to work around. We welcome simple and maintainable pull requests to improve Node.js support, but recommend opening an issue to discuss your improvements first.
     </p>
     </p>
 
 
     <p>
     <p>
-        첫 번째로, three.js는 웹을 목적으로 만들어졌기때문에, Node.js에서 항상 활용 가능하다고 보증할 수 없는 브라우저와 DOM API에 의존하고 있는 까닭입니다.
-        이러한 문제들은 shims를 통해 [link:https://github.com/stackgl/headless-gl headless-gl]처럼 해결하거나, [page:TextureLoader] 같은 컴포넌트를 커스터마이징 해서 해결 가능합니다. 다른 DOM API는 관련된 코드가 더 복잡하게 연관되어 있어, 수정하기 더 까다롭습니다.
-        Node.js 지원을 향상시키기 위한 더 간단하고, 유지보수 가능한 pull 요청은 언제든지 환영이지만, 본인의 작업을 위한 issue 생성을 더 권장합니다.
-    </p>
-
-    <p>
-        둘째로, Node.js의 ES 모듈 지원은 ... 다소 복잡합니다. Node.js v12에서, 코어 라이브러리는 CommonJS 모듈로, <em>require('three')</em>와 같이 사용 가능합니다.
-        하지만, 대부분의 <em>examples/jsm</em> 안의 예제 컴포넌트들은 불가능합니다. Node.js 향후 버전에서는 이게 해결될 수도 있겠지만, 그 전까지는
-        [link:https://github.com/standard-things/esm esm]처럼 사용해 Node.js 앱이 ES 모듈을 인식할 수 있도록 해줘야 합니다.
+        Make sure to add `{ "type": "module" }` to your `package.json` to enable ES6 modules in your node project.
     </p>
     </p>
 
 
 </body>
 </body>

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

@@ -141,15 +141,11 @@
 		<h3>Node.js</h3>
 		<h3>Node.js</h3>
 
 
 		<p>
 		<p>
-			在 [link:https://eloquentjavascript.net/20_node.html Node.js] 下使用 three.js 较为困难,原因有2条:
+			Because three.js is built for the web, it depends on browser and DOM APIs that don't always exist in Node.js. Some of these issues can be resolved by using shims like [link:https://github.com/stackgl/headless-gl headless-gl], or by replacing components like [page:TextureLoader] with custom alternatives. Other DOM APIs may be deeply intertwined with the code that uses them, and will be harder to work around. We welcome simple and maintainable pull requests to improve Node.js support, but recommend opening an issue to discuss your improvements first.
 		</p>
 		</p>
 
 
 		<p>
 		<p>
-			首先, three.js 是为 web 而构建的,其依赖于浏览器,以及并不总是存在于 Node.js 中的 DOM API。其中的一些问题可使用类似 [link:https://github.com/stackgl/headless-gl headless-gl] 的 shim ,或使用定制的替代品来替换掉一些组件(例如 [page:TextureLoader] )来进行解决。其他的 DOM API 或许和使用它们的代码紧密相连在一起,并且很难解决。我们欢迎简单且可维护的 pull request,以改善对 Node.js 的支持。但建议您首先提出一个 issue 来讨论您的改进。
-		</p>
-
-		<p>
-			第二,Node.js 对于 ES module 的支持可以说……很复杂。在 Node.js v12 中, three.js 的核心库可使用 <em>require('three')</em> 来作为 CommonJS module 进行导入。然而,大多数在 <em>examples/jsm</em> 中的示例组件并不能够这样。未来版本的 Node.js 或许可以解决这个问题,但同时你可能需要一些类似 [link:https://github.com/standard-things/esm esm] 的解决方案,来使得你的 Node.js 应用程序识别 ES module。
+			Make sure to add `{ "type": "module" }` to your `package.json` to enable ES6 modules in your node project.
 		</p>
 		</p>
 
 
 	</body>
 	</body>

+ 23 - 5
editor/js/Sidebar.Geometry.Modifiers.js

@@ -1,7 +1,9 @@
-import { UIDiv, UIButton } from './libs/ui.js';
+import { UIDiv, UIButton, UIRow } from './libs/ui.js';
 
 
 function SidebarGeometryModifiers( editor, object ) {
 function SidebarGeometryModifiers( editor, object ) {
 
 
+	const strings = editor.strings;
+
 	const signals = editor.signals;
 	const signals = editor.signals;
 
 
 	const container = new UIDiv().setPaddingLeft( '90px' );
 	const container = new UIDiv().setPaddingLeft( '90px' );
@@ -10,18 +12,34 @@ function SidebarGeometryModifiers( editor, object ) {
 
 
 	// Compute Vertex Normals
 	// Compute Vertex Normals
 
 
-	const button = new UIButton( 'Compute Vertex Normals' );
-	button.onClick( function () {
+	const computeVertexNormalsButton = new UIButton( strings.getKey( 'sidebar/geometry/compute_vertex_normals' ) );
+	computeVertexNormalsButton.onClick( function () {
 
 
 		geometry.computeVertexNormals();
 		geometry.computeVertexNormals();
 
 
-		geometry.attributes.normal.needsUpdate = true;
+		signals.geometryChanged.dispatch( object );
+
+	} );
+
+	const computeVertexNormalsRow = new UIRow();
+	computeVertexNormalsRow.add( computeVertexNormalsButton );
+	container.add( computeVertexNormalsRow );
+
+
+	// Center Geometry
+
+	const centerButton = new UIButton( strings.getKey( 'sidebar/geometry/center' ) );
+	centerButton.onClick( function () {
+
+		geometry.center();
 
 
 		signals.geometryChanged.dispatch( object );
 		signals.geometryChanged.dispatch( object );
 
 
 	} );
 	} );
 
 
-	container.add( button );
+	const centerRow = new UIRow();
+	centerRow.add( centerButton );
+	container.add( centerRow );
 
 
 	//
 	//
 
 

+ 6 - 0
editor/js/Strings.js

@@ -134,6 +134,8 @@ function Strings( config ) {
 			'sidebar/geometry/name': 'Name',
 			'sidebar/geometry/name': 'Name',
 			'sidebar/geometry/bounds': 'Bounds',
 			'sidebar/geometry/bounds': 'Bounds',
 			'sidebar/geometry/show_vertex_normals': 'Show Vertex Normals',
 			'sidebar/geometry/show_vertex_normals': 'Show Vertex Normals',
+			'sidebar/geometry/compute_vertex_normals': 'Compute Vertex Normals',
+			'sidebar/geometry/center': 'Center',
 
 
 			'sidebar/geometry/box_geometry/width': 'Width',
 			'sidebar/geometry/box_geometry/width': 'Width',
 			'sidebar/geometry/box_geometry/height': 'Height',
 			'sidebar/geometry/box_geometry/height': 'Height',
@@ -476,6 +478,8 @@ function Strings( config ) {
 			'sidebar/geometry/name': 'Nom',
 			'sidebar/geometry/name': 'Nom',
 			'sidebar/geometry/bounds': 'Limites',
 			'sidebar/geometry/bounds': 'Limites',
 			'sidebar/geometry/show_vertex_normals': 'Afficher normales',
 			'sidebar/geometry/show_vertex_normals': 'Afficher normales',
+			'sidebar/geometry/compute_vertex_normals': 'Compute Vertex Normals',
+			'sidebar/geometry/center': 'Center',
 
 
 			'sidebar/geometry/box_geometry/width': 'Largeur',
 			'sidebar/geometry/box_geometry/width': 'Largeur',
 			'sidebar/geometry/box_geometry/height': 'Hauteur',
 			'sidebar/geometry/box_geometry/height': 'Hauteur',
@@ -813,6 +817,8 @@ function Strings( config ) {
 			'sidebar/geometry/name': '名称',
 			'sidebar/geometry/name': '名称',
 			'sidebar/geometry/bounds': '界限',
 			'sidebar/geometry/bounds': '界限',
 			'sidebar/geometry/show_vertex_normals': '显示顶点法线',
 			'sidebar/geometry/show_vertex_normals': '显示顶点法线',
+			'sidebar/geometry/compute_vertex_normals': '计算顶点法线',
+			'sidebar/geometry/center': '居中',
 
 
 			'sidebar/geometry/box_geometry/width': '宽度',
 			'sidebar/geometry/box_geometry/width': '宽度',
 			'sidebar/geometry/box_geometry/height': '高度',
 			'sidebar/geometry/box_geometry/height': '高度',

+ 0 - 2
editor/sw.js

@@ -1,5 +1,3 @@
-// r142
-
 const cacheName = 'threejs-editor';
 const cacheName = 'threejs-editor';
 
 
 const assets = [
 const assets = [

+ 7 - 4
examples/files.json

@@ -141,6 +141,7 @@
 		"webgl_materials_displacementmap",
 		"webgl_materials_displacementmap",
 		"webgl_materials_envmaps",
 		"webgl_materials_envmaps",
 		"webgl_materials_envmaps_exr",
 		"webgl_materials_envmaps_exr",
+		"webgl_materials_envmaps_groundprojected",
 		"webgl_materials_envmaps_hdr",
 		"webgl_materials_envmaps_hdr",
 		"webgl_materials_lightmap",
 		"webgl_materials_lightmap",
 		"webgl_materials_matcap",
 		"webgl_materials_matcap",
@@ -227,10 +228,12 @@
 		"webgl_water_flowmap"
 		"webgl_water_flowmap"
 	],
 	],
 	"webgl / nodes": [
 	"webgl / nodes": [
-		"webgl_materials_instance_uniform_nodes",
-		"webgl_materials_standard_nodes",
+		"webgl_nodes_loader_gltf_sheen",
+		"webgl_nodes_materials_instance_uniform",
+		"webgl_nodes_materials_physical_clearcoat",
+		"webgl_nodes_materials_standard",
 		"webgl_nodes_playground",
 		"webgl_nodes_playground",
-		"webgl_points_nodes"
+		"webgl_nodes_points"
 	],
 	],
 	"webgl / postprocessing": [
 	"webgl / postprocessing": [
 		"webgl_postprocessing",
 		"webgl_postprocessing",
@@ -285,7 +288,6 @@
 		"webgl_gpgpu_birds_gltf",
 		"webgl_gpgpu_birds_gltf",
 		"webgl_gpgpu_water",
 		"webgl_gpgpu_water",
 		"webgl_gpgpu_protoplanet",
 		"webgl_gpgpu_protoplanet",
-		"webgl_instancing_modified",
 		"webgl_lightningstrike",
 		"webgl_lightningstrike",
 		"webgl_materials_modified",
 		"webgl_materials_modified",
 		"webgl_raymarching_reflect",
 		"webgl_raymarching_reflect",
@@ -304,6 +306,7 @@
 		"webgl2_multiple_rendertargets",
 		"webgl2_multiple_rendertargets",
 		"webgl2_multisampled_renderbuffers",
 		"webgl2_multisampled_renderbuffers",
 		"webgl2_rendertarget_texture2darray",
 		"webgl2_rendertarget_texture2darray",
+		"webgl2_ubo",
 		"webgl2_volume_cloud",
 		"webgl2_volume_cloud",
 		"webgl2_volume_instancing",
 		"webgl2_volume_instancing",
 		"webgl2_volume_perlin"
 		"webgl2_volume_perlin"

+ 0 - 2
examples/js/controls/OrbitControls.js

@@ -844,8 +844,6 @@
 
 
 			function onMouseMove( event ) {
 			function onMouseMove( event ) {
 
 
-				if ( scope.enabled === false ) return;
-
 				switch ( state ) {
 				switch ( state ) {
 
 
 					case STATE.ROTATE:
 					case STATE.ROTATE:

+ 0 - 1
examples/js/loaders/GLTFLoader.js

@@ -3481,7 +3481,6 @@
 					const target = targets[ i ];
 					const target = targets[ i ];
 					if ( node === undefined ) continue;
 					if ( node === undefined ) continue;
 					node.updateMatrix();
 					node.updateMatrix();
-					node.matrixAutoUpdate = true;
 					let TypedKeyframeTrack;
 					let TypedKeyframeTrack;
 
 
 					switch ( PATH_PROPERTIES[ target.path ] ) {
 					switch ( PATH_PROPERTIES[ target.path ] ) {

+ 1 - 1
examples/js/loaders/SVGLoader.js

@@ -2089,7 +2089,7 @@
 					tempV2_3.normalize();
 					tempV2_3.normalize();
 					const dot = Math.abs( normal1.dot( tempV2_3 ) ); // If path is straight, don't create join
 					const dot = Math.abs( normal1.dot( tempV2_3 ) ); // If path is straight, don't create join
 
 
-					if ( dot !== 0 ) {
+					if ( dot > Number.EPSILON ) {
 
 
 						// Compute inner and outer segment intersections
 						// Compute inner and outer segment intersections
 						const miterSide = strokeWidth2 / dot;
 						const miterSide = strokeWidth2 / dot;

+ 0 - 2
examples/jsm/controls/OrbitControls.js

@@ -960,8 +960,6 @@ class OrbitControls extends EventDispatcher {
 
 
 		function onMouseMove( event ) {
 		function onMouseMove( event ) {
 
 
-			if ( scope.enabled === false ) return;
-
 			switch ( state ) {
 			switch ( state ) {
 
 
 				case STATE.ROTATE:
 				case STATE.ROTATE:

+ 9 - 9
examples/jsm/controls/TransformControls.js

@@ -563,7 +563,7 @@ class TransformControls extends Object3D {
 
 
 	}
 	}
 
 
-	// Detatch from object
+	// Detach from object
 	detach() {
 	detach() {
 
 
 		this.object = undefined;
 		this.object = undefined;
@@ -1316,12 +1316,12 @@ class TransformControlsGizmo extends Object3D {
 
 
 				// Hide translate and scale axis facing the camera
 				// Hide translate and scale axis facing the camera
 
 
-				const AXIS_HIDE_TRESHOLD = 0.99;
-				const PLANE_HIDE_TRESHOLD = 0.2;
+				const AXIS_HIDE_THRESHOLD = 0.99;
+				const PLANE_HIDE_THRESHOLD = 0.2;
 
 
 				if ( handle.name === 'X' ) {
 				if ( handle.name === 'X' ) {
 
 
-					if ( Math.abs( _alignVector.copy( _unitX ).applyQuaternion( quaternion ).dot( this.eye ) ) > AXIS_HIDE_TRESHOLD ) {
+					if ( Math.abs( _alignVector.copy( _unitX ).applyQuaternion( quaternion ).dot( this.eye ) ) > AXIS_HIDE_THRESHOLD ) {
 
 
 						handle.scale.set( 1e-10, 1e-10, 1e-10 );
 						handle.scale.set( 1e-10, 1e-10, 1e-10 );
 						handle.visible = false;
 						handle.visible = false;
@@ -1332,7 +1332,7 @@ class TransformControlsGizmo extends Object3D {
 
 
 				if ( handle.name === 'Y' ) {
 				if ( handle.name === 'Y' ) {
 
 
-					if ( Math.abs( _alignVector.copy( _unitY ).applyQuaternion( quaternion ).dot( this.eye ) ) > AXIS_HIDE_TRESHOLD ) {
+					if ( Math.abs( _alignVector.copy( _unitY ).applyQuaternion( quaternion ).dot( this.eye ) ) > AXIS_HIDE_THRESHOLD ) {
 
 
 						handle.scale.set( 1e-10, 1e-10, 1e-10 );
 						handle.scale.set( 1e-10, 1e-10, 1e-10 );
 						handle.visible = false;
 						handle.visible = false;
@@ -1343,7 +1343,7 @@ class TransformControlsGizmo extends Object3D {
 
 
 				if ( handle.name === 'Z' ) {
 				if ( handle.name === 'Z' ) {
 
 
-					if ( Math.abs( _alignVector.copy( _unitZ ).applyQuaternion( quaternion ).dot( this.eye ) ) > AXIS_HIDE_TRESHOLD ) {
+					if ( Math.abs( _alignVector.copy( _unitZ ).applyQuaternion( quaternion ).dot( this.eye ) ) > AXIS_HIDE_THRESHOLD ) {
 
 
 						handle.scale.set( 1e-10, 1e-10, 1e-10 );
 						handle.scale.set( 1e-10, 1e-10, 1e-10 );
 						handle.visible = false;
 						handle.visible = false;
@@ -1354,7 +1354,7 @@ class TransformControlsGizmo extends Object3D {
 
 
 				if ( handle.name === 'XY' ) {
 				if ( handle.name === 'XY' ) {
 
 
-					if ( Math.abs( _alignVector.copy( _unitZ ).applyQuaternion( quaternion ).dot( this.eye ) ) < PLANE_HIDE_TRESHOLD ) {
+					if ( Math.abs( _alignVector.copy( _unitZ ).applyQuaternion( quaternion ).dot( this.eye ) ) < PLANE_HIDE_THRESHOLD ) {
 
 
 						handle.scale.set( 1e-10, 1e-10, 1e-10 );
 						handle.scale.set( 1e-10, 1e-10, 1e-10 );
 						handle.visible = false;
 						handle.visible = false;
@@ -1365,7 +1365,7 @@ class TransformControlsGizmo extends Object3D {
 
 
 				if ( handle.name === 'YZ' ) {
 				if ( handle.name === 'YZ' ) {
 
 
-					if ( Math.abs( _alignVector.copy( _unitX ).applyQuaternion( quaternion ).dot( this.eye ) ) < PLANE_HIDE_TRESHOLD ) {
+					if ( Math.abs( _alignVector.copy( _unitX ).applyQuaternion( quaternion ).dot( this.eye ) ) < PLANE_HIDE_THRESHOLD ) {
 
 
 						handle.scale.set( 1e-10, 1e-10, 1e-10 );
 						handle.scale.set( 1e-10, 1e-10, 1e-10 );
 						handle.visible = false;
 						handle.visible = false;
@@ -1376,7 +1376,7 @@ class TransformControlsGizmo extends Object3D {
 
 
 				if ( handle.name === 'XZ' ) {
 				if ( handle.name === 'XZ' ) {
 
 
-					if ( Math.abs( _alignVector.copy( _unitY ).applyQuaternion( quaternion ).dot( this.eye ) ) < PLANE_HIDE_TRESHOLD ) {
+					if ( Math.abs( _alignVector.copy( _unitY ).applyQuaternion( quaternion ).dot( this.eye ) ) < PLANE_HIDE_THRESHOLD ) {
 
 
 						handle.scale.set( 1e-10, 1e-10, 1e-10 );
 						handle.scale.set( 1e-10, 1e-10, 1e-10 );
 						handle.visible = false;
 						handle.visible = false;

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

@@ -1,3 +1,7 @@
+import {
+	DoubleSide
+} from 'three';
+
 import * as fflate from '../libs/fflate.module.js';
 import * as fflate from '../libs/fflate.module.js';
 
 
 class USDZExporter {
 class USDZExporter {
@@ -408,7 +412,7 @@ function buildMaterial( material, textures ) {
 	}
 	}
 
 
 
 
-	if ( material.side === THREE.DoubleSide ) {
+	if ( material.side === DoubleSide ) {
 
 
 		console.warn( 'THREE.USDZExporter: USDZ does not support double sided materials', material );
 		console.warn( 'THREE.USDZExporter: USDZ does not support double sided materials', material );
 
 

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

@@ -17,7 +17,7 @@ class ConvexGeometry extends BufferGeometry {
 
 
 		if ( ConvexHull === undefined ) {
 		if ( ConvexHull === undefined ) {
 
 
-			console.error( 'THREE.ConvexBufferGeometry: ConvexBufferGeometry relies on ConvexHull' );
+			console.error( 'THREE.ConvexGeometry: ConvexGeometry relies on ConvexHull' );
 
 
 		}
 		}
 
 

+ 5 - 3
examples/jsm/interactive/SelectionHelper.js

@@ -1,6 +1,4 @@
-import {
-	Vector2
-} from 'three';
+import { Vector2 } from 'three';
 
 
 class SelectionHelper {
 class SelectionHelper {
 
 
@@ -58,6 +56,8 @@ class SelectionHelper {
 
 
 	onSelectStart( event ) {
 	onSelectStart( event ) {
 
 
+		this.element.style.display = 'none';
+
 		this.renderer.domElement.parentElement.appendChild( this.element );
 		this.renderer.domElement.parentElement.appendChild( this.element );
 
 
 		this.element.style.left = event.clientX + 'px';
 		this.element.style.left = event.clientX + 'px';
@@ -72,6 +72,8 @@ class SelectionHelper {
 
 
 	onSelectMove( event ) {
 	onSelectMove( event ) {
 
 
+		this.element.style.display = 'block';
+
 		this.pointBottomRight.x = Math.max( this.startPoint.x, event.clientX );
 		this.pointBottomRight.x = Math.max( this.startPoint.x, event.clientX );
 		this.pointBottomRight.y = Math.max( this.startPoint.y, event.clientY );
 		this.pointBottomRight.y = Math.max( this.startPoint.y, event.clientY );
 		this.pointTopLeft.x = Math.min( this.startPoint.x, event.clientX );
 		this.pointTopLeft.x = Math.min( this.startPoint.x, event.clientX );

+ 1 - 0
examples/jsm/loaders/ColladaLoader.js

@@ -4066,6 +4066,7 @@ class ColladaLoader extends Loader {
 
 
 		if ( asset.upAxis === 'Z_UP' ) {
 		if ( asset.upAxis === 'Z_UP' ) {
 
 
+			console.warn( 'THREE.ColladaLoader: You are loading an asset with a Z-UP coordinate system. The loader just rotates the asset to transform it into Y-UP. The vertex data are not converted, see #24289.' );
 			scene.quaternion.setFromEuler( new Euler( - Math.PI / 2, 0, 0 ) );
 			scene.quaternion.setFromEuler( new Euler( - Math.PI / 2, 0, 0 ) );
 
 
 		}
 		}

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

@@ -3817,7 +3817,6 @@ class GLTFParser {
 				if ( node === undefined ) continue;
 				if ( node === undefined ) continue;
 
 
 				node.updateMatrix();
 				node.updateMatrix();
-				node.matrixAutoUpdate = true;
 
 
 				let TypedKeyframeTrack;
 				let TypedKeyframeTrack;
 
 

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

@@ -2,6 +2,7 @@ import {
 	BufferGeometry,
 	BufferGeometry,
 	FileLoader,
 	FileLoader,
 	Float32BufferAttribute,
 	Float32BufferAttribute,
+	Int32BufferAttribute,
 	Loader,
 	Loader,
 	LoaderUtils,
 	LoaderUtils,
 	Points,
 	Points,
@@ -229,6 +230,8 @@ class PCDLoader extends Loader {
 		const position = [];
 		const position = [];
 		const normal = [];
 		const normal = [];
 		const color = [];
 		const color = [];
+		const intensity = [];
+		const label = [];
 
 
 		// ascii
 		// ascii
 
 
@@ -285,6 +288,18 @@ class PCDLoader extends Loader {
 
 
 				}
 				}
 
 
+				if ( offset.intensity !== undefined ) {
+
+					intensity.push( parseFloat( line[ offset.intensity ] ) );
+
+				}
+
+				if ( offset.label !== undefined ) {
+
+					label.push( parseInt( line[ offset.label ] ) );
+
+				}
+
 			}
 			}
 
 
 		}
 		}
@@ -338,6 +353,20 @@ class PCDLoader extends Loader {
 
 
 				}
 				}
 
 
+				if ( offset.intensity !== undefined ) {
+
+					const intensityIndex = PCDheader.fields.indexOf( 'intensity' );
+					intensity.push( dataview.getFloat32( ( PCDheader.points * offset.intensity ) + PCDheader.size[ intensityIndex ] * i, this.littleEndian ) );
+
+				}
+
+				if ( offset.label !== undefined ) {
+
+					const labelIndex = PCDheader.fields.indexOf( 'label' );
+					label.push( dataview.getInt32( ( PCDheader.points * offset.label ) + PCDheader.size[ labelIndex ] * i, this.littleEndian ) );
+
+				}
+
 			}
 			}
 
 
 		}
 		}
@@ -375,6 +404,18 @@ class PCDLoader extends Loader {
 
 
 				}
 				}
 
 
+				if ( offset.intensity !== undefined ) {
+
+					intensity.push( dataview.getFloat32( row + offset.intensity, this.littleEndian ) );
+
+				}
+
+				if ( offset.label !== undefined ) {
+
+					label.push( dataview.getInt32( row + offset.label, this.littleEndian ) );
+
+				}
+
 			}
 			}
 
 
 		}
 		}
@@ -386,6 +427,8 @@ class PCDLoader extends Loader {
 		if ( position.length > 0 ) geometry.setAttribute( 'position', new Float32BufferAttribute( position, 3 ) );
 		if ( position.length > 0 ) geometry.setAttribute( 'position', new Float32BufferAttribute( position, 3 ) );
 		if ( normal.length > 0 ) geometry.setAttribute( 'normal', new Float32BufferAttribute( normal, 3 ) );
 		if ( normal.length > 0 ) geometry.setAttribute( 'normal', new Float32BufferAttribute( normal, 3 ) );
 		if ( color.length > 0 ) geometry.setAttribute( 'color', new Float32BufferAttribute( color, 3 ) );
 		if ( color.length > 0 ) geometry.setAttribute( 'color', new Float32BufferAttribute( color, 3 ) );
+		if ( intensity.length > 0 ) geometry.setAttribute( 'intensity', new Float32BufferAttribute( intensity, 1 ) );
+		if ( label.length > 0 ) geometry.setAttribute( 'label', new Int32BufferAttribute( label, 1 ) );
 
 
 		geometry.computeBoundingSphere();
 		geometry.computeBoundingSphere();
 
 
@@ -397,10 +440,6 @@ class PCDLoader extends Loader {
 
 
 			material.vertexColors = true;
 			material.vertexColors = true;
 
 
-		} else {
-
-			material.color.setHex( Math.random() * 0xffffff );
-
 		}
 		}
 
 
 		// build point cloud
 		// build point cloud

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

@@ -2107,7 +2107,7 @@ class SVGLoader extends Loader {
 		simplePaths = simplePaths.filter( sp => sp.points.length > 1 );
 		simplePaths = simplePaths.filter( sp => sp.points.length > 1 );
 
 
 		// check if path is solid or a hole
 		// check if path is solid or a hole
-		const isAHole = simplePaths.map( p => isHoleTo( p, simplePaths, scanlineMinX, scanlineMaxX, shapePath.userData.style.fillRule ) );
+		const isAHole = simplePaths.map( p => isHoleTo( p, simplePaths, scanlineMinX, scanlineMaxX, shapePath.userData?.style.fillRule ) );
 
 
 
 
 		const shapesToReturn = [];
 		const shapesToReturn = [];
@@ -2313,7 +2313,7 @@ class SVGLoader extends Loader {
 				const dot = Math.abs( normal1.dot( tempV2_3 ) );
 				const dot = Math.abs( normal1.dot( tempV2_3 ) );
 
 
 				// If path is straight, don't create join
 				// If path is straight, don't create join
-				if ( dot !== 0 ) {
+				if ( dot > Number.EPSILON ) {
 
 
 					// Compute inner and outer segment intersections
 					// Compute inner and outer segment intersections
 					const miterSide = strokeWidth2 / dot;
 					const miterSide = strokeWidth2 / dot;

+ 6 - 6
examples/jsm/nodes/Nodes.js

@@ -18,12 +18,12 @@ import NodeFunctionInput from './core/NodeFunctionInput.js';
 import NodeKeywords from './core/NodeKeywords.js';
 import NodeKeywords from './core/NodeKeywords.js';
 import NodeUniform from './core/NodeUniform.js';
 import NodeUniform from './core/NodeUniform.js';
 import NodeVar from './core/NodeVar.js';
 import NodeVar from './core/NodeVar.js';
-import NodeVary from './core/NodeVary.js';
+import NodeVarying from './core/NodeVarying.js';
 import PropertyNode from './core/PropertyNode.js';
 import PropertyNode from './core/PropertyNode.js';
 import TempNode from './core/TempNode.js';
 import TempNode from './core/TempNode.js';
 import UniformNode from './core/UniformNode.js';
 import UniformNode from './core/UniformNode.js';
 import VarNode from './core/VarNode.js';
 import VarNode from './core/VarNode.js';
-import VaryNode from './core/VaryNode.js';
+import VaryingNode from './core/VaryingNode.js';
 
 
 // accessors
 // accessors
 import BufferNode from './accessors/BufferNode.js';
 import BufferNode from './accessors/BufferNode.js';
@@ -127,12 +127,12 @@ const nodeLib = {
 	NodeKeywords,
 	NodeKeywords,
 	NodeUniform,
 	NodeUniform,
 	NodeVar,
 	NodeVar,
-	NodeVary,
+	NodeVarying,
 	PropertyNode,
 	PropertyNode,
 	TempNode,
 	TempNode,
 	UniformNode,
 	UniformNode,
 	VarNode,
 	VarNode,
-	VaryNode,
+	VaryingNode,
 
 
 	// geometry
 	// geometry
 	RangeNode,
 	RangeNode,
@@ -235,12 +235,12 @@ export {
 	NodeKeywords,
 	NodeKeywords,
 	NodeUniform,
 	NodeUniform,
 	NodeVar,
 	NodeVar,
-	NodeVary,
+	NodeVarying,
 	PropertyNode,
 	PropertyNode,
 	TempNode,
 	TempNode,
 	UniformNode,
 	UniformNode,
 	VarNode,
 	VarNode,
-	VaryNode,
+	VaryingNode,
 
 
 	// geometry
 	// geometry
 	RangeNode,
 	RangeNode,

+ 4 - 4
examples/jsm/nodes/accessors/NormalNode.js

@@ -1,6 +1,6 @@
 import Node from '../core/Node.js';
 import Node from '../core/Node.js';
 import AttributeNode from '../core/AttributeNode.js';
 import AttributeNode from '../core/AttributeNode.js';
-import VaryNode from '../core/VaryNode.js';
+import VaryingNode from '../core/VaryingNode.js';
 import ModelNode from '../accessors/ModelNode.js';
 import ModelNode from '../accessors/ModelNode.js';
 import CameraNode from '../accessors/CameraNode.js';
 import CameraNode from '../accessors/CameraNode.js';
 import OperatorNode from '../math/OperatorNode.js';
 import OperatorNode from '../math/OperatorNode.js';
@@ -39,18 +39,18 @@ class NormalNode extends Node {
 
 
 		} else if ( scope === NormalNode.LOCAL ) {
 		} else if ( scope === NormalNode.LOCAL ) {
 
 
-			outputNode = new VaryNode( new NormalNode( NormalNode.GEOMETRY ) );
+			outputNode = new VaryingNode( new NormalNode( NormalNode.GEOMETRY ) );
 
 
 		} else if ( scope === NormalNode.VIEW ) {
 		} else if ( scope === NormalNode.VIEW ) {
 
 
 			const vertexNormalNode = new OperatorNode( '*', new ModelNode( ModelNode.NORMAL_MATRIX ), new NormalNode( NormalNode.LOCAL ) );
 			const vertexNormalNode = new OperatorNode( '*', new ModelNode( ModelNode.NORMAL_MATRIX ), new NormalNode( NormalNode.LOCAL ) );
-			outputNode = new MathNode( MathNode.NORMALIZE, new VaryNode( vertexNormalNode ) );
+			outputNode = new MathNode( MathNode.NORMALIZE, new VaryingNode( vertexNormalNode ) );
 
 
 		} else if ( scope === NormalNode.WORLD ) {
 		} else if ( scope === NormalNode.WORLD ) {
 
 
 			// To use INVERSE_TRANSFORM_DIRECTION only inverse the param order like this: MathNode( ..., Vector, Matrix );
 			// To use INVERSE_TRANSFORM_DIRECTION only inverse the param order like this: MathNode( ..., Vector, Matrix );
 			const vertexNormalNode = new MathNode( MathNode.TRANSFORM_DIRECTION, new NormalNode( NormalNode.VIEW ), new CameraNode( CameraNode.VIEW_MATRIX ) );
 			const vertexNormalNode = new MathNode( MathNode.TRANSFORM_DIRECTION, new NormalNode( NormalNode.VIEW ), new CameraNode( CameraNode.VIEW_MATRIX ) );
-			outputNode = new MathNode( MathNode.NORMALIZE, new VaryNode( vertexNormalNode ) );
+			outputNode = new MathNode( MathNode.NORMALIZE, new VaryingNode( vertexNormalNode ) );
 
 
 		}
 		}
 
 

+ 5 - 5
examples/jsm/nodes/accessors/PositionNode.js

@@ -1,6 +1,6 @@
 import Node from '../core/Node.js';
 import Node from '../core/Node.js';
 import AttributeNode from '../core/AttributeNode.js';
 import AttributeNode from '../core/AttributeNode.js';
-import VaryNode from '../core/VaryNode.js';
+import VaryingNode from '../core/VaryingNode.js';
 import ModelNode from '../accessors/ModelNode.js';
 import ModelNode from '../accessors/ModelNode.js';
 import MathNode from '../math/MathNode.js';
 import MathNode from '../math/MathNode.js';
 import OperatorNode from '../math/OperatorNode.js';
 import OperatorNode from '../math/OperatorNode.js';
@@ -39,22 +39,22 @@ class PositionNode extends Node {
 
 
 		} else if ( scope === PositionNode.LOCAL ) {
 		} else if ( scope === PositionNode.LOCAL ) {
 
 
-			outputNode = new VaryNode( new PositionNode( PositionNode.GEOMETRY ) );
+			outputNode = new VaryingNode( new PositionNode( PositionNode.GEOMETRY ) );
 
 
 		} else if ( scope === PositionNode.WORLD ) {
 		} else if ( scope === PositionNode.WORLD ) {
 
 
 			const vertexPositionNode = new MathNode( MathNode.TRANSFORM_DIRECTION, new ModelNode( ModelNode.WORLD_MATRIX ), new PositionNode( PositionNode.LOCAL ) );
 			const vertexPositionNode = new MathNode( MathNode.TRANSFORM_DIRECTION, new ModelNode( ModelNode.WORLD_MATRIX ), new PositionNode( PositionNode.LOCAL ) );
-			outputNode = new VaryNode( vertexPositionNode );
+			outputNode = new VaryingNode( vertexPositionNode );
 
 
 		} else if ( scope === PositionNode.VIEW ) {
 		} else if ( scope === PositionNode.VIEW ) {
 
 
 			const vertexPositionNode = new OperatorNode( '*', new ModelNode( ModelNode.VIEW_MATRIX ), new PositionNode( PositionNode.LOCAL ) );
 			const vertexPositionNode = new OperatorNode( '*', new ModelNode( ModelNode.VIEW_MATRIX ), new PositionNode( PositionNode.LOCAL ) );
-			outputNode = new VaryNode( vertexPositionNode );
+			outputNode = new VaryingNode( vertexPositionNode );
 
 
 		} else if ( scope === PositionNode.VIEW_DIRECTION ) {
 		} else if ( scope === PositionNode.VIEW_DIRECTION ) {
 
 
 			const vertexPositionNode = new MathNode( MathNode.NEGATE, new PositionNode( PositionNode.VIEW ) );
 			const vertexPositionNode = new MathNode( MathNode.NEGATE, new PositionNode( PositionNode.VIEW ) );
-			outputNode = new MathNode( MathNode.NORMALIZE, new VaryNode( vertexPositionNode ) );
+			outputNode = new MathNode( MathNode.NORMALIZE, new VaryingNode( vertexPositionNode ) );
 
 
 		}
 		}
 
 

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

@@ -1,5 +1,5 @@
 import Node from './Node.js';
 import Node from './Node.js';
-import VaryNode from './VaryNode.js';
+import VaryingNode from './VaryingNode.js';
 
 
 class AttributeNode extends Node {
 class AttributeNode extends Node {
 
 
@@ -58,9 +58,9 @@ class AttributeNode extends Node {
 
 
 		} else {
 		} else {
 
 
-			const nodeVary = new VaryNode( this );
+			const nodeVarying = new VaryingNode( this );
 
 
-			return nodeVary.build( builder, attribute.type );
+			return nodeVarying.build( builder, attribute.type );
 
 
 		}
 		}
 
 

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

@@ -1,6 +1,6 @@
 import NodeUniform from './NodeUniform.js';
 import NodeUniform from './NodeUniform.js';
 import NodeAttribute from './NodeAttribute.js';
 import NodeAttribute from './NodeAttribute.js';
-import NodeVary from './NodeVary.js';
+import NodeVarying from './NodeVarying.js';
 import NodeVar from './NodeVar.js';
 import NodeVar from './NodeVar.js';
 import NodeCode from './NodeCode.js';
 import NodeCode from './NodeCode.js';
 import NodeKeywords from './NodeKeywords.js';
 import NodeKeywords from './NodeKeywords.js';
@@ -55,7 +55,7 @@ class NodeBuilder {
 		this.uniforms = { vertex: [], fragment: [], compute: [], index: 0 };
 		this.uniforms = { vertex: [], fragment: [], compute: [], index: 0 };
 		this.codes = { vertex: [], fragment: [], compute: [] };
 		this.codes = { vertex: [], fragment: [], compute: [] };
 		this.attributes = [];
 		this.attributes = [];
-		this.varys = [];
+		this.varyings = [];
 		this.vars = { vertex: [], fragment: [], compute: [] };
 		this.vars = { vertex: [], fragment: [], compute: [] };
 		this.flow = { code: '' };
 		this.flow = { code: '' };
 		this.stack = [];
 		this.stack = [];
@@ -456,26 +456,26 @@ class NodeBuilder {
 
 
 	}
 	}
 
 
-	getVaryFromNode( node, type ) {
+	getVaryingFromNode( node, type ) {
 
 
 		const nodeData = this.getDataFromNode( node, null );
 		const nodeData = this.getDataFromNode( node, null );
 
 
-		let nodeVary = nodeData.vary;
+		let nodeVarying = nodeData.varying;
 
 
-		if ( nodeVary === undefined ) {
+		if ( nodeVarying === undefined ) {
 
 
-			const varys = this.varys;
-			const index = varys.length;
+			const varyings = this.varyings;
+			const index = varyings.length;
 
 
-			nodeVary = new NodeVary( 'nodeVary' + index, type );
+			nodeVarying = new NodeVarying( 'nodeVarying' + index, type );
 
 
-			varys.push( nodeVary );
+			varyings.push( nodeVarying );
 
 
-			nodeData.vary = nodeVary;
+			nodeData.varying = nodeVarying;
 
 
 		}
 		}
 
 
-		return nodeVary;
+		return nodeVarying;
 
 
 	}
 	}
 
 
@@ -572,7 +572,7 @@ class NodeBuilder {
 
 
 	}
 	}
 
 
-	getVarys( /*shaderStage*/ ) {
+	getVaryings( /*shaderStage*/ ) {
 
 
 		console.warn( 'Abstract function.' );
 		console.warn( 'Abstract function.' );
 
 

+ 3 - 3
examples/jsm/nodes/core/NodeVary.js → examples/jsm/nodes/core/NodeVarying.js

@@ -1,8 +1,8 @@
-class NodeVary {
+class NodeVarying {
 
 
 	constructor( name, type ) {
 	constructor( name, type ) {
 
 
-		this.isNodeVary = true;
+		this.isNodeVarying = true;
 
 
 		this.name = name;
 		this.name = name;
 		this.type = type;
 		this.type = type;
@@ -11,4 +11,4 @@ class NodeVary {
 
 
 }
 }
 
 
-export default NodeVary;
+export default NodeVarying;

+ 7 - 7
examples/jsm/nodes/core/VaryNode.js → examples/jsm/nodes/core/VaryingNode.js

@@ -1,7 +1,7 @@
 import Node from './Node.js';
 import Node from './Node.js';
 import { NodeShaderStage } from './constants.js';
 import { NodeShaderStage } from './constants.js';
 
 
-class VaryNode extends Node {
+class VaryingNode extends Node {
 
 
 	constructor( node, name = null ) {
 	constructor( node, name = null ) {
 
 
@@ -20,7 +20,7 @@ class VaryNode extends Node {
 
 
 	getNodeType( builder ) {
 	getNodeType( builder ) {
 
 
-		// VaryNode is auto type
+		// VaryingNode is auto type
 
 
 		return this.node.getNodeType( builder );
 		return this.node.getNodeType( builder );
 
 
@@ -32,23 +32,23 @@ class VaryNode extends Node {
 		const node = this.node;
 		const node = this.node;
 		const name = this.name;
 		const name = this.name;
 
 
-		const nodeVary = builder.getVaryFromNode( this, type );
+		const nodeVarying = builder.getVaryingFromNode( this, type );
 
 
 		if ( name !== null ) {
 		if ( name !== null ) {
 
 
-			nodeVary.name = name;
+			nodeVarying.name = name;
 
 
 		}
 		}
 
 
-		const propertyName = builder.getPropertyName( nodeVary, NodeShaderStage.Vertex );
+		const propertyName = builder.getPropertyName( nodeVarying, NodeShaderStage.Vertex );
 
 
 		// force node run in vertex stage
 		// force node run in vertex stage
 		builder.flowNodeFromShaderStage( NodeShaderStage.Vertex, node, type, propertyName );
 		builder.flowNodeFromShaderStage( NodeShaderStage.Vertex, node, type, propertyName );
 
 
-		return builder.getPropertyName( nodeVary );
+		return builder.getPropertyName( nodeVarying );
 
 
 	}
 	}
 
 
 }
 }
 
 
-export default VaryNode;
+export default VaryingNode;

+ 2 - 0
examples/jsm/nodes/gpgpu/ComputeNode.js

@@ -34,6 +34,8 @@ class ComputeNode extends Node {
 
 
 	}
 	}
 
 
+	onInit() { }
+
 	update( { renderer } ) {
 	update( { renderer } ) {
 
 
 		renderer.compute( this );
 		renderer.compute( this );

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

@@ -2,6 +2,7 @@ import NodeMaterial from './NodeMaterial.js';
 import LineBasicNodeMaterial from './LineBasicNodeMaterial.js';
 import LineBasicNodeMaterial from './LineBasicNodeMaterial.js';
 import MeshBasicNodeMaterial from './MeshBasicNodeMaterial.js';
 import MeshBasicNodeMaterial from './MeshBasicNodeMaterial.js';
 import MeshStandardNodeMaterial from './MeshStandardNodeMaterial.js';
 import MeshStandardNodeMaterial from './MeshStandardNodeMaterial.js';
+import MeshPhysicalNodeMaterial from './MeshPhysicalNodeMaterial.js';
 import PointsNodeMaterial from './PointsNodeMaterial.js';
 import PointsNodeMaterial from './PointsNodeMaterial.js';
 import SpriteNodeMaterial from './SpriteNodeMaterial.js';
 import SpriteNodeMaterial from './SpriteNodeMaterial.js';
 
 
@@ -10,6 +11,7 @@ export {
 	LineBasicNodeMaterial,
 	LineBasicNodeMaterial,
 	MeshBasicNodeMaterial,
 	MeshBasicNodeMaterial,
 	MeshStandardNodeMaterial,
 	MeshStandardNodeMaterial,
+	MeshPhysicalNodeMaterial,
 	PointsNodeMaterial,
 	PointsNodeMaterial,
 	SpriteNodeMaterial
 	SpriteNodeMaterial
 };
 };
@@ -21,8 +23,9 @@ NodeMaterial.fromMaterial = function ( material ) {
 		LineBasicNodeMaterial,
 		LineBasicNodeMaterial,
 		MeshBasicNodeMaterial,
 		MeshBasicNodeMaterial,
 		MeshStandardNodeMaterial,
 		MeshStandardNodeMaterial,
+		MeshPhysicalNodeMaterial,
 		PointsNodeMaterial,
 		PointsNodeMaterial,
-		SpriteNodeMaterial,
+		SpriteNodeMaterial
 	};
 	};
 
 
 	const type = material.type.replace( 'Material', 'NodeMaterial' );
 	const type = material.type.replace( 'Material', 'NodeMaterial' );

+ 46 - 0
examples/jsm/nodes/materials/MeshPhysicalNodeMaterial.js

@@ -0,0 +1,46 @@
+import MeshStandardNodeMaterial from './MeshStandardNodeMaterial.js';
+
+import { MeshPhysicalMaterial } from 'three';
+
+const defaultValues = new MeshPhysicalMaterial();
+
+export default class MeshPhysicalNodeMaterial extends MeshStandardNodeMaterial {
+
+	constructor( parameters ) {
+
+		super();
+
+		this.isMeshPhysicalNodeMaterial = true;
+
+		this.clearcoatNode = null;
+		this.clearcoatRoughnessNode = null;
+		this.clearcoatNormalNode = null;
+
+		this.sheenNode = null;
+		this.sheenRoughnessNode = null;
+
+		this.sheen = 0;
+		this.clearcoat = 0;
+		this.iridescence = 0;
+		this.transmission = 0;
+
+		this.setDefaultValues( defaultValues );
+
+		this.setValues( parameters );
+
+	}
+
+	copy( source ) {
+
+		this.clearcoatNode = source.clearcoatNode;
+		this.clearcoatRoughnessNode = source.clearcoatRoughnessNode;
+		this.clearcoatNormalNode = source.clearcoatNormalNode;
+
+		this.sheenNode = source.sheenNode;
+		this.sheenRoughnessNode = source.sheenRoughnessNode;
+
+		return super.copy( source );
+
+	}
+
+}

+ 0 - 6
examples/jsm/nodes/materials/MeshStandardNodeMaterial.js

@@ -35,9 +35,6 @@ export default class MeshStandardNodeMaterial extends NodeMaterial {
 		this.metalnessNode = null;
 		this.metalnessNode = null;
 		this.roughnessNode = null;
 		this.roughnessNode = null;
 
 
-		this.clearcoatNode = null;
-		this.clearcoatRoughnessNode = null;
-
 		this.envNode = null;
 		this.envNode = null;
 
 
 		this.lightsNode = null;
 		this.lightsNode = null;
@@ -158,9 +155,6 @@ export default class MeshStandardNodeMaterial extends NodeMaterial {
 		this.metalnessNode = source.metalnessNode;
 		this.metalnessNode = source.metalnessNode;
 		this.roughnessNode = source.roughnessNode;
 		this.roughnessNode = source.roughnessNode;
 
 
-		this.clearcoatNode = source.clearcoatNode;
-		this.clearcoatRoughnessNode = source.clearcoatRoughnessNode;
-
 		this.envNode = source.envNode;
 		this.envNode = source.envNode;
 
 
 		this.lightsNode = source.lightsNode;
 		this.lightsNode = source.lightsNode;

+ 2 - 2
examples/jsm/nodes/shadernode/ShaderNodeBaseElements.js

@@ -11,7 +11,7 @@ import InstanceIndexNode from '../core/InstanceIndexNode.js';
 import PropertyNode from '../core/PropertyNode.js';
 import PropertyNode from '../core/PropertyNode.js';
 import UniformNode from '../core/UniformNode.js';
 import UniformNode from '../core/UniformNode.js';
 import VarNode from '../core/VarNode.js';
 import VarNode from '../core/VarNode.js';
-import VaryNode from '../core/VaryNode.js';
+import VaryingNode from '../core/VaryingNode.js';
 
 
 // accessors
 // accessors
 import BufferNode from '../accessors/BufferNode.js';
 import BufferNode from '../accessors/BufferNode.js';
@@ -120,7 +120,7 @@ export const call = nodeProxy( FunctionCallNode );
 export const instanceIndex = nodeImmutable( InstanceIndexNode );
 export const instanceIndex = nodeImmutable( InstanceIndexNode );
 export const label = nodeProxy( VarNode );
 export const label = nodeProxy( VarNode );
 export const temp = label;
 export const temp = label;
-export const vary = nodeProxy( VaryNode );
+export const varying = nodeProxy( VaryingNode );
 
 
 // accesors
 // accesors
 
 

+ 186 - 0
examples/jsm/objects/GroundProjectedEnv.js

@@ -0,0 +1,186 @@
+import { Mesh, IcosahedronGeometry, ShaderMaterial, DoubleSide } from 'three';
+
+/**
+ * Ground projected env map adapted from @react-three/drei.
+ * https://github.com/pmndrs/drei/blob/master/src/core/Environment.tsx
+ */
+export class GroundProjectedEnv extends Mesh {
+
+	constructor( texture, options ) {
+
+		const isCubeMap = texture.isCubeTexture;
+		const w =
+			( isCubeMap ? texture.image[ 0 ]?.width : texture.image.width ) ?? 1024;
+		const cubeSize = w / 4;
+		const _lodMax = Math.floor( Math.log2( cubeSize ) );
+		const _cubeSize = Math.pow( 2, _lodMax );
+		const width = 3 * Math.max( _cubeSize, 16 * 7 );
+		const height = 4 * _cubeSize;
+
+		const defines = [
+			isCubeMap ? '#define ENVMAP_TYPE_CUBE' : '',
+			`#define CUBEUV_TEXEL_WIDTH ${1.0 / width}`,
+			`#define CUBEUV_TEXEL_HEIGHT ${1.0 / height}`,
+			`#define CUBEUV_MAX_MIP ${_lodMax}.0`,
+		];
+
+		const vertexShader = /* glsl */ `
+        varying vec3 vWorldPosition;
+
+        void main() 
+        {
+
+            vec4 worldPosition = ( modelMatrix * vec4( position, 1.0 ) );
+            vWorldPosition = worldPosition.xyz;
+            
+            gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
+
+        }
+        `;
+		const fragmentShader = defines.join( '\n' ) + /* glsl */ `
+        #define ENVMAP_TYPE_CUBE_UV
+
+        varying vec3 vWorldPosition;
+
+        uniform float radius;
+        uniform float height;
+        uniform float angle;
+
+        #ifdef ENVMAP_TYPE_CUBE
+
+            uniform samplerCube map;
+
+        #else
+
+            uniform sampler2D map;
+
+        #endif
+
+        // From: https://www.shadertoy.com/view/4tsBD7
+        float diskIntersectWithBackFaceCulling( vec3 ro, vec3 rd, vec3 c, vec3 n, float r ) 
+        {
+
+            float d = dot ( rd, n );
+            
+            if( d > 0.0 ) { return 1e6; }
+            
+            vec3  o = ro - c;
+            float t = - dot( n, o ) / d;
+            vec3  q = o + rd * t;
+            
+            return ( dot( q, q ) < r * r ) ? t : 1e6;
+
+        }
+
+        // From: https://www.iquilezles.org/www/articles/intersectors/intersectors.htm
+        float sphereIntersect( vec3 ro, vec3 rd, vec3 ce, float ra ) 
+        {
+
+            vec3 oc = ro - ce;
+            float b = dot( oc, rd );
+            float c = dot( oc, oc ) - ra * ra;
+            float h = b * b - c;
+            
+            if( h < 0.0 ) { return -1.0; }
+            
+            h = sqrt( h );
+            
+            return - b + h;
+
+        }
+
+        vec3 project() 
+        {
+
+            vec3 p = normalize( vWorldPosition );
+            vec3 camPos = cameraPosition;
+            camPos.y -= height;
+
+            float intersection = sphereIntersect( camPos, p, vec3( 0.0 ), radius );
+            if( intersection > 0.0 ) {
+                
+                vec3 h = vec3( 0.0, - height, 0.0 );
+                float intersection2 = diskIntersectWithBackFaceCulling( camPos, p, h, vec3( 0.0, 1.0, 0.0 ), radius );
+                p = ( camPos + min( intersection, intersection2 ) * p ) / radius;
+
+            } else {
+
+                p = vec3( 0.0, 1.0, 0.0 );
+
+            }
+
+            return p;
+
+        }
+
+        #include <common>
+        #include <cube_uv_reflection_fragment>
+
+        void main() 
+        {
+
+            vec3 projectedWorldPosition = project();
+            
+            #ifdef ENVMAP_TYPE_CUBE
+
+                vec3 outcolor = textureCube( map, projectedWorldPosition ).rgb;
+
+            #else
+
+                vec3 direction = normalize( projectedWorldPosition );
+                vec2 uv = equirectUv( direction );
+                vec3 outcolor = texture2D( map, uv ).rgb;
+
+            #endif
+
+            gl_FragColor = vec4( outcolor, 1.0 );
+
+            #include <tonemapping_fragment>
+            #include <encodings_fragment>
+
+        }
+        `;
+
+		const uniforms = {
+			map: { value: texture },
+			height: { value: options?.height || 15 },
+			radius: { value: options?.radius || 100 },
+		};
+
+		const geometry = new IcosahedronGeometry( 1, 16 );
+		const material = new ShaderMaterial( {
+			uniforms,
+			fragmentShader,
+			vertexShader,
+			side: DoubleSide,
+		} );
+
+		super( geometry, material );
+
+	}
+
+	set radius( radius ) {
+
+		this.material.uniforms.radius.value = radius;
+
+	}
+
+	get radius() {
+
+		return this.material.uniforms.radius.value;
+
+	}
+
+	set height( height ) {
+
+		this.material.uniforms.height.value = height;
+
+	}
+
+	get height() {
+
+		return this.material.uniforms.height.value;
+
+	}
+
+}

+ 93 - 27
examples/jsm/renderers/webgl/nodes/WebGLNodeBuilder.js

@@ -14,7 +14,8 @@ const nodeShaderLib = {
 	LineBasicNodeMaterial: ShaderLib.basic,
 	LineBasicNodeMaterial: ShaderLib.basic,
 	MeshBasicNodeMaterial: ShaderLib.basic,
 	MeshBasicNodeMaterial: ShaderLib.basic,
 	PointsNodeMaterial: ShaderLib.points,
 	PointsNodeMaterial: ShaderLib.points,
-	MeshStandardNodeMaterial: ShaderLib.standard
+	MeshStandardNodeMaterial: ShaderLib.standard,
+	MeshPhysicalMaterial: ShaderLib.physical
 };
 };
 
 
 function getIncludeSnippet( name ) {
 function getIncludeSnippet( name ) {
@@ -70,7 +71,8 @@ class WebGLNodeBuilder extends NodeBuilder {
 
 
 		// shader lib
 		// shader lib
 
 
-		if ( material.isMeshStandardNodeMaterial ) type = 'MeshStandardNodeMaterial';
+		if ( material.isMeshPhysicalNodeMaterial ) type = 'MeshPhysicalMaterial';
+		else if ( material.isMeshStandardNodeMaterial ) type = 'MeshStandardNodeMaterial';
 		else if ( material.isMeshBasicNodeMaterial ) type = 'MeshBasicNodeMaterial';
 		else if ( material.isMeshBasicNodeMaterial ) type = 'MeshBasicNodeMaterial';
 		else if ( material.isPointsNodeMaterial ) type = 'PointsNodeMaterial';
 		else if ( material.isPointsNodeMaterial ) type = 'PointsNodeMaterial';
 		else if ( material.isLineBasicNodeMaterial ) type = 'LineBasicNodeMaterial';
 		else if ( material.isLineBasicNodeMaterial ) type = 'LineBasicNodeMaterial';
@@ -130,15 +132,49 @@ class WebGLNodeBuilder extends NodeBuilder {
 
 
 		}
 		}
 
 
-		if ( material.clearcoatNode && material.clearcoatNode.isNode ) {
+		if ( material.isMeshPhysicalNodeMaterial ) {
 
 
-			this.addSlot( 'fragment', new SlotNode( material.clearcoatNode, 'CLEARCOAT', 'float' ) );
+			if ( material.clearcoatNode && material.clearcoatNode.isNode ) {
 
 
-		}
+				this.addSlot( 'fragment', new SlotNode( material.clearcoatNode, 'CLEARCOAT', 'float' ) );
+
+				if ( material.clearcoatRoughnessNode && material.clearcoatRoughnessNode.isNode ) {
+
+					this.addSlot( 'fragment', new SlotNode( material.clearcoatRoughnessNode, 'CLEARCOAT_ROUGHNESS', 'float' ) );
+
+				}
+
+				if ( material.clearcoatNormalNode && material.clearcoatNormalNode.isNode ) {
+
+					this.addSlot( 'fragment', new SlotNode( material.clearcoatNormalNode, 'CLEARCOAT_NORMAL', 'vec3' ) );
+
+				}
+
+				material.defines.USE_CLEARCOAT = '';
+
+			} else {
+
+				delete material.defines.USE_CLEARCOAT;
+
+			}
+
+			if ( material.sheenNode && material.sheenNode.isNode ) {
+
+				this.addSlot( 'fragment', new SlotNode( material.sheenNode, 'SHEEN', 'vec3' ) );
+
+				if ( material.sheenRoughnessNode && material.sheenRoughnessNode.isNode ) {
+
+					this.addSlot( 'fragment', new SlotNode( material.sheenRoughnessNode, 'SHEEN_ROUGHNESS', 'float' ) );
+
+				}
+
+				material.defines.USE_SHEEN = '';
+
+			} else {
 
 
-		if ( material.clearcoatRoughnessNode && material.clearcoatRoughnessNode.isNode ) {
+				delete material.defines.USE_SHEEN;
 
 
-			this.addSlot( 'fragment', new SlotNode( material.clearcoatRoughnessNode, 'CLEARCOAT_ROUGHNESS', 'float' ) );
+			}
 
 
 		}
 		}
 
 
@@ -250,9 +286,7 @@ class WebGLNodeBuilder extends NodeBuilder {
 
 
 			const attributes = this.attributes;
 			const attributes = this.attributes;
 
 
-			for ( let index = 0; index < attributes.length; index ++ ) {
-
-				const attribute = attributes[ index ];
+			for ( const attribute of attributes ) {
 
 
 				// ignore common attributes to prevent redefinitions
 				// ignore common attributes to prevent redefinitions
 				if ( attribute.name === 'uv' || attribute.name === 'position' || attribute.name === 'normal' )
 				if ( attribute.name === 'uv' || attribute.name === 'position' || attribute.name === 'normal' )
@@ -268,17 +302,15 @@ class WebGLNodeBuilder extends NodeBuilder {
 
 
 	}
 	}
 
 
-	getVarys( /* shaderStage */ ) {
+	getVaryings( /* shaderStage */ ) {
 
 
 		let snippet = '';
 		let snippet = '';
 
 
-		const varys = this.varys;
-
-		for ( let index = 0; index < varys.length; index ++ ) {
+		const varyings = this.varyings;
 
 
-			const vary = varys[ index ];
+		for ( const varying of varyings ) {
 
 
-			snippet += `varying ${vary.type} ${vary.name}; `;
+			snippet += `varying ${varying.type} ${varying.name}; `;
 
 
 		}
 		}
 
 
@@ -319,7 +351,7 @@ class WebGLNodeBuilder extends NodeBuilder {
 
 
 		const shaderProperty = getShaderStageProperty( shaderStage );
 		const shaderProperty = getShaderStageProperty( shaderStage );
 
 
-		this.shader[ shaderProperty ] = this.shader[ shaderProperty ].replaceAll( source, target );
+		this[ shaderProperty ] = this[ shaderProperty ].replaceAll( source, target );
 
 
 	}
 	}
 
 
@@ -364,7 +396,7 @@ class WebGLNodeBuilder extends NodeBuilder {
 
 
 			const uniforms = this.getUniforms( shaderStage );
 			const uniforms = this.getUniforms( shaderStage );
 			const attributes = this.getAttributes( shaderStage );
 			const attributes = this.getAttributes( shaderStage );
-			const varys = this.getVarys( shaderStage );
+			const varyings = this.getVaryings( shaderStage );
 			const vars = this.getVars( shaderStage );
 			const vars = this.getVars( shaderStage );
 			const codes = this.getCodes( shaderStage );
 			const codes = this.getCodes( shaderStage );
 
 
@@ -377,8 +409,8 @@ ${uniforms}
 // attributes
 // attributes
 ${attributes}
 ${attributes}
 
 
-// varys
-${varys}
+// varyings
+${varyings}
 
 
 // vars
 // vars
 ${vars}
 ${vars}
@@ -433,6 +465,7 @@ ${this.shader[ getShaderStageProperty( shaderStage ) ]}
 	_addSnippets() {
 	_addSnippets() {
 
 
 		this.parseInclude( 'fragment', 'lights_physical_fragment' );
 		this.parseInclude( 'fragment', 'lights_physical_fragment' );
+		this.parseInclude( 'fragment', 'clearcoat_normal_fragment_begin' );
 
 
 		const colorSlot = this.getSlot( 'fragment', 'COLOR' );
 		const colorSlot = this.getSlot( 'fragment', 'COLOR' );
 		const opacityNode = this.getSlot( 'fragment', 'OPACITY' );
 		const opacityNode = this.getSlot( 'fragment', 'OPACITY' );
@@ -442,6 +475,9 @@ ${this.shader[ getShaderStageProperty( shaderStage ) ]}
 		const metalnessNode = this.getSlot( 'fragment', 'METALNESS' );
 		const metalnessNode = this.getSlot( 'fragment', 'METALNESS' );
 		const clearcoatNode = this.getSlot( 'fragment', 'CLEARCOAT' );
 		const clearcoatNode = this.getSlot( 'fragment', 'CLEARCOAT' );
 		const clearcoatRoughnessNode = this.getSlot( 'fragment', 'CLEARCOAT_ROUGHNESS' );
 		const clearcoatRoughnessNode = this.getSlot( 'fragment', 'CLEARCOAT_ROUGHNESS' );
+		const clearcoatNormalNode = this.getSlot( 'fragment', 'CLEARCOAT_NORMAL' );
+		const sheenNode = this.getSlot( 'fragment', 'SHEEN' );
+		const sheenRoughnessNode = this.getSlot( 'fragment', 'SHEEN_ROUGHNESS' );
 		const iridescenceNode = this.getSlot( 'fragment', 'IRIDESCENCE' );
 		const iridescenceNode = this.getSlot( 'fragment', 'IRIDESCENCE' );
 		const iridescenceIORNode = this.getSlot( 'fragment', 'IRIDESCENCE_IOR' );
 		const iridescenceIORNode = this.getSlot( 'fragment', 'IRIDESCENCE_IOR' );
 		const iridescenceThicknessNode = this.getSlot( 'fragment', 'IRIDESCENCE_THICKNESS' );
 		const iridescenceThicknessNode = this.getSlot( 'fragment', 'IRIDESCENCE_THICKNESS' );
@@ -513,25 +549,55 @@ ${this.shader[ getShaderStageProperty( shaderStage ) ]}
 
 
 			this.addCodeAfterSnippet(
 			this.addCodeAfterSnippet(
 				'fragment',
 				'fragment',
-				'material.clearcoatRoughness = clearcoatRoughness;',
+				'material.clearcoat = clearcoat;',
 				`${clearcoatNode.code}\n\tmaterial.clearcoat = ${clearcoatNode.result};`
 				`${clearcoatNode.code}\n\tmaterial.clearcoat = ${clearcoatNode.result};`
 			);
 			);
 
 
+			if ( clearcoatRoughnessNode !== undefined ) {
+
+				this.addCodeAfterSnippet(
+					'fragment',
+					'material.clearcoatRoughness = clearcoatRoughness;',
+					`${clearcoatRoughnessNode.code}\n\tmaterial.clearcoatRoughness = ${clearcoatRoughnessNode.result};`
+				);
+
+			}
+
+			if ( clearcoatNormalNode !== undefined ) {
+
+				this.addCodeAfterSnippet(
+					'fragment',
+					'vec3 clearcoatNormal = geometryNormal;',
+					`${clearcoatNormalNode.code}\n\tclearcoatNormal = ${clearcoatNormalNode.result};`
+				);
+
+			}
+
 		}
 		}
 
 
-		if ( clearcoatRoughnessNode !== undefined ) {
+		if ( sheenNode !== undefined ) {
 
 
 			this.addCodeAfterSnippet(
 			this.addCodeAfterSnippet(
 				'fragment',
 				'fragment',
-				'material.clearcoatRoughness = clearcoatRoughness;',
-				`${clearcoatRoughnessNode.code}\n\tmaterial.clearcoatRoughness = ${clearcoatRoughnessNode.result};`
+				'material.sheenColor = sheenColor;',
+				`${sheenNode.code}\n\tmaterial.sheenColor = ${sheenNode.result};`
 			);
 			);
 
 
+			if ( sheenRoughnessNode !== undefined ) {
+
+				this.replaceCode(
+					'fragment',
+					'material.sheenRoughness = clamp( sheenRoughness, 0.07, 1.0 );',
+					`${sheenRoughnessNode.code}\n\tmaterial.sheenRoughness = clamp( ${sheenRoughnessNode.result}, 0.07, 1.0 );`
+				);
+
+			}
+
 		}
 		}
 
 
 		if ( iridescenceNode !== undefined ) {
 		if ( iridescenceNode !== undefined ) {
 
 
-			this.addCodeAfterSnippet(
+			this.addCodeAfterInclude(
 				'fragment',
 				'fragment',
 				'iridescence_fragment',
 				'iridescence_fragment',
 				`${iridescenceNode.code}\n\tmaterial.iridescence = ${iridescenceNode.result};`
 				`${iridescenceNode.code}\n\tmaterial.iridescence = ${iridescenceNode.result};`
@@ -541,7 +607,7 @@ ${this.shader[ getShaderStageProperty( shaderStage ) ]}
 
 
 		if ( iridescenceIORNode !== undefined ) {
 		if ( iridescenceIORNode !== undefined ) {
 
 
-			this.addCodeAfterSnippet(
+			this.addCodeAfterInclude(
 				'fragment',
 				'fragment',
 				'iridescence_fragment',
 				'iridescence_fragment',
 				`${iridescenceIORNode.code}\n\tmaterial.iridescenceIOR = ${iridescenceIORNode.result};`
 				`${iridescenceIORNode.code}\n\tmaterial.iridescenceIOR = ${iridescenceIORNode.result};`
@@ -551,7 +617,7 @@ ${this.shader[ getShaderStageProperty( shaderStage ) ]}
 
 
 		if ( iridescenceThicknessNode !== undefined ) {
 		if ( iridescenceThicknessNode !== undefined ) {
 
 
-			this.addCodeAfterSnippet(
+			this.addCodeAfterInclude(
 				'fragment',
 				'fragment',
 				'iridescence_fragment',
 				'iridescence_fragment',
 				`${iridescenceThicknessNode.code}\n\tmaterial.iridescenceThickness = ${iridescenceThicknessNode.result};`
 				`${iridescenceThicknessNode.code}\n\tmaterial.iridescenceThickness = ${iridescenceThicknessNode.result};`

+ 6 - 0
examples/jsm/renderers/webgpu/WebGPUComputePipelines.js

@@ -14,6 +14,12 @@ class WebGPUComputePipelines {
 
 
 	}
 	}
 
 
+	has( computeNode ) {
+
+		return this.pipelines.get( computeNode ) !== undefined;
+
+	}
+
 	get( computeNode ) {
 	get( computeNode ) {
 
 
 		let pipeline = this.pipelines.get( computeNode );
 		let pipeline = this.pipelines.get( computeNode );

+ 8 - 17
examples/jsm/renderers/webgpu/WebGPURenderPipeline.js

@@ -1,4 +1,4 @@
-import { GPUPrimitiveTopology, GPUIndexFormat, GPUCompareFunction, GPUFrontFace, GPUCullMode, GPUVertexFormat, GPUBlendFactor, GPUBlendOperation, BlendColorFactor, OneMinusBlendColorFactor, GPUColorWriteFlags, GPUStencilOperation, GPUInputStepMode } from './constants.js';
+import { GPUIndexFormat, GPUCompareFunction, GPUFrontFace, GPUCullMode, GPUVertexFormat, GPUBlendFactor, GPUBlendOperation, BlendColorFactor, OneMinusBlendColorFactor, GPUColorWriteFlags, GPUStencilOperation, GPUInputStepMode } from './constants.js';
 import {
 import {
 	FrontSide, BackSide, DoubleSide,
 	FrontSide, BackSide, DoubleSide,
 	NeverDepth, AlwaysDepth, LessDepth, LessEqualDepth, EqualDepth, GreaterEqualDepth, GreaterDepth, NotEqualDepth,
 	NeverDepth, AlwaysDepth, LessDepth, LessEqualDepth, EqualDepth, GreaterEqualDepth, GreaterDepth, NotEqualDepth,
@@ -11,7 +11,7 @@ import {
 
 
 class WebGPURenderPipeline {
 class WebGPURenderPipeline {
 
 
-	constructor( device, renderer, sampleCount ) {
+	constructor( device, utils ) {
 
 
 		this.cacheKey = null;
 		this.cacheKey = null;
 		this.shaderAttributes = null;
 		this.shaderAttributes = null;
@@ -20,8 +20,7 @@ class WebGPURenderPipeline {
 		this.usedTimes = 0;
 		this.usedTimes = 0;
 
 
 		this._device = device;
 		this._device = device;
-		this._renderer = renderer;
-		this._sampleCount = sampleCount;
+		this._utils = utils;
 
 
 	}
 	}
 
 
@@ -89,8 +88,9 @@ class WebGPURenderPipeline {
 		const primitiveState = this._getPrimitiveState( object, material );
 		const primitiveState = this._getPrimitiveState( object, material );
 		const colorWriteMask = this._getColorWriteMask( material );
 		const colorWriteMask = this._getColorWriteMask( material );
 		const depthCompare = this._getDepthCompare( material );
 		const depthCompare = this._getDepthCompare( material );
-		const colorFormat = this._renderer.getCurrentColorFormat();
-		const depthStencilFormat = this._renderer.getCurrentDepthStencilFormat();
+		const colorFormat = this._utils.getCurrentColorFormat();
+		const depthStencilFormat = this._utils.getCurrentDepthStencilFormat();
+		const sampleCount = this._utils.getSampleCount();
 
 
 		this.pipeline = this._device.createRenderPipeline( {
 		this.pipeline = this._device.createRenderPipeline( {
 			vertex: Object.assign( {}, stageVertex.stage, { buffers: vertexBuffers } ),
 			vertex: Object.assign( {}, stageVertex.stage, { buffers: vertexBuffers } ),
@@ -113,7 +113,7 @@ class WebGPURenderPipeline {
 				stencilWriteMask: material.stencilWriteMask
 				stencilWriteMask: material.stencilWriteMask
 			},
 			},
 			multisample: {
 			multisample: {
-				count: this._sampleCount
+				count: sampleCount
 			},
 			},
 			layout: 'auto'
 			layout: 'auto'
 		} );
 		} );
@@ -430,7 +430,7 @@ class WebGPURenderPipeline {
 
 
 		const descriptor = {};
 		const descriptor = {};
 
 
-		descriptor.topology = this._getPrimitiveTopology( object );
+		descriptor.topology = this._utils.getPrimitiveTopology( object );
 
 
 		if ( object.isLine === true && object.isLineSegments !== true ) {
 		if ( object.isLine === true && object.isLineSegments !== true ) {
 
 
@@ -467,15 +467,6 @@ class WebGPURenderPipeline {
 
 
 	}
 	}
 
 
-	_getPrimitiveTopology( object ) {
-
-		if ( object.isMesh ) return GPUPrimitiveTopology.TriangleList;
-		else if ( object.isPoints ) return GPUPrimitiveTopology.PointList;
-		else if ( object.isLineSegments ) return GPUPrimitiveTopology.LineList;
-		else if ( object.isLine ) return GPUPrimitiveTopology.LineStrip;
-
-	}
-
 	_getStencilCompare( material ) {
 	_getStencilCompare( material ) {
 
 
 		let stencilCompare;
 		let stencilCompare;

+ 16 - 14
examples/jsm/renderers/webgpu/WebGPURenderPipelines.js

@@ -3,13 +3,13 @@ import WebGPUProgrammableStage from './WebGPUProgrammableStage.js';
 
 
 class WebGPURenderPipelines {
 class WebGPURenderPipelines {
 
 
-	constructor( renderer, device, sampleCount, nodes, bindings = null ) {
+	constructor( device, nodes, utils ) {
 
 
-		this.renderer = renderer;
 		this.device = device;
 		this.device = device;
-		this.sampleCount = sampleCount;
 		this.nodes = nodes;
 		this.nodes = nodes;
-		this.bindings = bindings;
+		this.utils = utils;
+
+		this.bindings = null;
 
 
 		this.pipelines = [];
 		this.pipelines = [];
 		this.objectCache = new WeakMap();
 		this.objectCache = new WeakMap();
@@ -125,7 +125,7 @@ class WebGPURenderPipelines {
 
 
 		if ( pipeline === undefined ) {
 		if ( pipeline === undefined ) {
 
 
-			pipeline = new WebGPURenderPipeline( this.device, this.renderer, this.sampleCount );
+			pipeline = new WebGPURenderPipeline( this.device, this.utils );
 			pipeline.init( cacheKey, stageVertex, stageFragment, object, nodeBuilder );
 			pipeline.init( cacheKey, stageVertex, stageFragment, object, nodeBuilder );
 
 
 			pipelines.push( pipeline );
 			pipelines.push( pipeline );
@@ -139,7 +139,7 @@ class WebGPURenderPipelines {
 	_computeCacheKey( stageVertex, stageFragment, object ) {
 	_computeCacheKey( stageVertex, stageFragment, object ) {
 
 
 		const material = object.material;
 		const material = object.material;
-		const renderer = this.renderer;
+		const utils = this.utils;
 
 
 		const parameters = [
 		const parameters = [
 			stageVertex.id, stageFragment.id,
 			stageVertex.id, stageFragment.id,
@@ -152,8 +152,9 @@ class WebGPURenderPipelines {
 			material.stencilFail, material.stencilZFail, material.stencilZPass,
 			material.stencilFail, material.stencilZFail, material.stencilZPass,
 			material.stencilFuncMask, material.stencilWriteMask,
 			material.stencilFuncMask, material.stencilWriteMask,
 			material.side,
 			material.side,
-			this.sampleCount,
-			renderer.getCurrentEncoding(), renderer.getCurrentColorFormat(), renderer.getCurrentDepthStencilFormat()
+			utils.getSampleCount(),
+			utils.getCurrentEncoding(), utils.getCurrentColorFormat(), utils.getCurrentDepthStencilFormat(),
+			utils.getPrimitiveTopology( object )
 		];
 		];
 
 
 		return parameters.join();
 		return parameters.join();
@@ -267,16 +268,17 @@ class WebGPURenderPipelines {
 
 
 		// check renderer state
 		// check renderer state
 
 
-		const renderer = this.renderer;
+		const utils = this.utils;
 
 
-		const encoding = renderer.getCurrentEncoding();
-		const colorFormat = renderer.getCurrentColorFormat();
-		const depthStencilFormat = renderer.getCurrentDepthStencilFormat();
+		const sampleCount = utils.getSampleCount();
+		const encoding = utils.getCurrentEncoding();
+		const colorFormat = utils.getCurrentColorFormat();
+		const depthStencilFormat = utils.getCurrentDepthStencilFormat();
 
 
-		if ( cache.sampleCount !== this.sampleCount || cache.encoding !== encoding ||
+		if ( cache.sampleCount !== sampleCount || cache.encoding !== encoding ||
 			cache.colorFormat !== colorFormat || cache.depthStencilFormat !== depthStencilFormat ) {
 			cache.colorFormat !== colorFormat || cache.depthStencilFormat !== depthStencilFormat ) {
 
 
-			cache.sampleCount = this.sampleCount;
+			cache.sampleCount = sampleCount;
 			cache.encoding = encoding;
 			cache.encoding = encoding;
 			cache.colorFormat = colorFormat;
 			cache.colorFormat = colorFormat;
 			cache.depthStencilFormat = depthStencilFormat;
 			cache.depthStencilFormat = depthStencilFormat;

+ 33 - 51
examples/jsm/renderers/webgpu/WebGPURenderer.js

@@ -12,6 +12,7 @@ import WebGPURenderStates from './WebGPURenderStates.js';
 import WebGPUTextures from './WebGPUTextures.js';
 import WebGPUTextures from './WebGPUTextures.js';
 import WebGPUBackground from './WebGPUBackground.js';
 import WebGPUBackground from './WebGPUBackground.js';
 import WebGPUNodes from './nodes/WebGPUNodes.js';
 import WebGPUNodes from './nodes/WebGPUNodes.js';
+import WebGPUUtils from './WebGPUUtils.js';
 
 
 import { Frustum, Matrix4, Vector3, Color, LinearEncoding } from 'three';
 import { Frustum, Matrix4, Vector3, Color, LinearEncoding } from 'three';
 
 
@@ -57,6 +58,25 @@ Matrix4.prototype.makeOrthographic = function ( left, right, top, bottom, near,
 
 
 };
 };
 
 
+Frustum.prototype.setFromProjectionMatrix = function( m ) {
+
+	const planes = this.planes;
+	const me = m.elements;
+	const me0 = me[ 0 ], me1 = me[ 1 ], me2 = me[ 2 ], me3 = me[ 3 ];
+	const me4 = me[ 4 ], me5 = me[ 5 ], me6 = me[ 6 ], me7 = me[ 7 ];
+	const me8 = me[ 8 ], me9 = me[ 9 ], me10 = me[ 10 ], me11 = me[ 11 ];
+	const me12 = me[ 12 ], me13 = me[ 13 ], me14 = me[ 14 ], me15 = me[ 15 ];
+
+	planes[ 0 ].setComponents( me3 - me0, me7 - me4, me11 - me8, me15 - me12 ).normalize();
+	planes[ 1 ].setComponents( me3 + me0, me7 + me4, me11 + me8, me15 + me12 ).normalize();
+	planes[ 2 ].setComponents( me3 + me1, me7 + me5, me11 + me9, me15 + me13 ).normalize();
+	planes[ 3 ].setComponents( me3 - me1, me7 - me5, me11 - me9, me15 - me13 ).normalize();
+	planes[ 4 ].setComponents( me3 - me2, me7 - me6, me11 - me10, me15 - me14 ).normalize();
+	planes[ 5 ].setComponents( me2, me6, me10, me14 ).normalize();
+
+	return this;
+
+};
 
 
 const _frustum = new Frustum();
 const _frustum = new Frustum();
 const _projScreenMatrix = new Matrix4();
 const _projScreenMatrix = new Matrix4();
@@ -187,9 +207,10 @@ class WebGPURenderer {
 		this._geometries = new WebGPUGeometries( this._attributes, this._info );
 		this._geometries = new WebGPUGeometries( this._attributes, this._info );
 		this._textures = new WebGPUTextures( device, this._properties, this._info );
 		this._textures = new WebGPUTextures( device, this._properties, this._info );
 		this._objects = new WebGPUObjects( this._geometries, this._info );
 		this._objects = new WebGPUObjects( this._geometries, this._info );
+		this._utils = new WebGPUUtils( this );
 		this._nodes = new WebGPUNodes( this, this._properties );
 		this._nodes = new WebGPUNodes( this, this._properties );
 		this._computePipelines = new WebGPUComputePipelines( device, this._nodes );
 		this._computePipelines = new WebGPUComputePipelines( device, this._nodes );
-		this._renderPipelines = new WebGPURenderPipelines( this, device, parameters.sampleCount, this._nodes );
+		this._renderPipelines = new WebGPURenderPipelines( device, this._nodes, this._utils );
 		this._bindings = this._renderPipelines.bindings = new WebGPUBindings( device, this._info, this._properties, this._textures, this._renderPipelines, this._computePipelines, this._attributes, this._nodes );
 		this._bindings = this._renderPipelines.bindings = new WebGPUBindings( device, this._info, this._properties, this._textures, this._renderPipelines, this._computePipelines, this._attributes, this._nodes );
 		this._renderLists = new WebGPURenderLists();
 		this._renderLists = new WebGPURenderLists();
 		this._renderStates = new WebGPURenderStates();
 		this._renderStates = new WebGPURenderStates();
@@ -482,55 +503,6 @@ class WebGPURenderer {
 
 
 	}
 	}
 
 
-	getCurrentEncoding() {
-
-		const renderTarget = this.getRenderTarget();
-		return ( renderTarget !== null ) ? renderTarget.texture.encoding : this.outputEncoding;
-
-	}
-
-	getCurrentColorFormat() {
-
-		let format;
-
-		const renderTarget = this.getRenderTarget();
-
-		if ( renderTarget !== null ) {
-
-			const renderTargetProperties = this._properties.get( renderTarget );
-			format = renderTargetProperties.colorTextureFormat;
-
-		} else {
-
-			format = GPUTextureFormat.BGRA8Unorm; // default context format
-
-		}
-
-		return format;
-
-	}
-
-	getCurrentDepthStencilFormat() {
-
-		let format;
-
-		const renderTarget = this.getRenderTarget();
-
-		if ( renderTarget !== null ) {
-
-			const renderTargetProperties = this._properties.get( renderTarget );
-			format = renderTargetProperties.depthTextureFormat;
-
-		} else {
-
-			format = GPUTextureFormat.Depth24PlusStencil8;
-
-		}
-
-		return format;
-
-	}
-
 	getClearColor( target ) {
 	getClearColor( target ) {
 
 
 		return target.copy( this._clearColor );
 		return target.copy( this._clearColor );
@@ -616,14 +588,24 @@ class WebGPURenderer {
 	compute( ...computeNodes ) {
 	compute( ...computeNodes ) {
 
 
 		const device = this._device;
 		const device = this._device;
+		const computePipelines = this._computePipelines;
+
 		const cmdEncoder = device.createCommandEncoder( {} );
 		const cmdEncoder = device.createCommandEncoder( {} );
 		const passEncoder = cmdEncoder.beginComputePass();
 		const passEncoder = cmdEncoder.beginComputePass();
 
 
 		for ( const computeNode of computeNodes ) {
 		for ( const computeNode of computeNodes ) {
 
 
+			// onInit
+
+			if ( computePipelines.has( computeNode ) === false ) {
+
+				computeNode.onInit( { renderer: this } );
+
+			}
+
 			// pipeline
 			// pipeline
 
 
-			const pipeline = this._computePipelines.get( computeNode );
+			const pipeline = computePipelines.get( computeNode );
 			passEncoder.setPipeline( pipeline );
 			passEncoder.setPipeline( pipeline );
 
 
 			// node
 			// node

+ 81 - 0
examples/jsm/renderers/webgpu/WebGPUUtils.js

@@ -0,0 +1,81 @@
+import { GPUPrimitiveTopology, GPUTextureFormat } from './constants.js';
+
+class WebGPUUtils {
+
+	constructor( renderer ) {
+
+		this.renderer = renderer;
+
+	}
+
+	getCurrentEncoding() {
+
+		const renderer = this.renderer;
+
+		const renderTarget = renderer.getRenderTarget();
+		return ( renderTarget !== null ) ? renderTarget.texture.encoding : renderer.outputEncoding;
+
+	}
+
+	getCurrentColorFormat() {
+
+		let format;
+
+		const renderer = this.renderer;
+		const renderTarget = renderer.getRenderTarget();
+
+		if ( renderTarget !== null ) {
+
+			const renderTargetProperties = renderer._properties.get( renderTarget );
+			format = renderTargetProperties.colorTextureFormat;
+
+		} else {
+
+			format = GPUTextureFormat.BGRA8Unorm; // default context format
+
+		}
+
+		return format;
+
+	}
+
+	getCurrentDepthStencilFormat() {
+
+		let format;
+
+		const renderer = this.renderer;
+		const renderTarget = renderer.getRenderTarget();
+
+		if ( renderTarget !== null ) {
+
+			const renderTargetProperties = renderer._properties.get( renderTarget );
+			format = renderTargetProperties.depthTextureFormat;
+
+		} else {
+
+			format = GPUTextureFormat.Depth24PlusStencil8;
+
+		}
+
+		return format;
+
+	}
+
+	getPrimitiveTopology( object ) {
+
+		if ( object.isMesh ) return GPUPrimitiveTopology.TriangleList;
+		else if ( object.isPoints ) return GPUPrimitiveTopology.PointList;
+		else if ( object.isLineSegments ) return GPUPrimitiveTopology.LineList;
+		else if ( object.isLine ) return GPUPrimitiveTopology.LineStrip;
+
+	}
+
+	getSampleCount() {
+
+		return this.renderer._parameters.sampleCount;
+
+	}
+
+}
+
+export default WebGPUUtils;

+ 20 - 20
examples/jsm/renderers/webgpu/nodes/WebGPUNodeBuilder.js

@@ -203,11 +203,11 @@ class WebGPUNodeBuilder extends NodeBuilder {
 
 
 	getPropertyName( node, shaderStage = this.shaderStage ) {
 	getPropertyName( node, shaderStage = this.shaderStage ) {
 
 
-		if ( node.isNodeVary === true ) {
+		if ( node.isNodeVarying === true ) {
 
 
 			if ( shaderStage === 'vertex' ) {
 			if ( shaderStage === 'vertex' ) {
 
 
-				return `NodeVarys.${ node.name }`;
+				return `NodeVaryings.${ node.name }`;
 
 
 			}
 			}
 
 
@@ -457,7 +457,7 @@ class WebGPUNodeBuilder extends NodeBuilder {
 
 
 	}
 	}
 
 
-	getVarys( shaderStage ) {
+	getVaryings( shaderStage ) {
 
 
 		const snippets = [];
 		const snippets = [];
 
 
@@ -465,25 +465,25 @@ class WebGPUNodeBuilder extends NodeBuilder {
 
 
 			this.getBuiltin( 'position', 'Vertex', 'vec4<f32>', 'vertex' );
 			this.getBuiltin( 'position', 'Vertex', 'vec4<f32>', 'vertex' );
 
 
-			const varys = this.varys;
+			const varyings = this.varyings;
 
 
-			for ( let index = 0; index < varys.length; index ++ ) {
+			for ( let index = 0; index < varyings.length; index ++ ) {
 
 
-				const vary = varys[ index ];
+				const varying = varyings[ index ];
 
 
-				snippets.push( `@location( ${index} ) ${ vary.name } : ${ this.getType( vary.type ) }` );
+				snippets.push( `@location( ${index} ) ${ varying.name } : ${ this.getType( varying.type ) }` );
 
 
 			}
 			}
 
 
 		} else if ( shaderStage === 'fragment' ) {
 		} else if ( shaderStage === 'fragment' ) {
 
 
-			const varys = this.varys;
+			const varyings = this.varyings;
 
 
-			for ( let index = 0; index < varys.length; index ++ ) {
+			for ( let index = 0; index < varyings.length; index ++ ) {
 
 
-				const vary = varys[ index ];
+				const varying = varyings[ index ];
 
 
-				snippets.push( `@location( ${index} ) ${ vary.name } : ${ this.getType( vary.type ) }` );
+				snippets.push( `@location( ${index} ) ${ varying.name } : ${ this.getType( varying.type ) }` );
 
 
 			}
 			}
 
 
@@ -497,7 +497,7 @@ class WebGPUNodeBuilder extends NodeBuilder {
 
 
 		const code = snippets.join( ',\n\t' );
 		const code = snippets.join( ',\n\t' );
 
 
-		return shaderStage === 'vertex' ? this._getWGSLStruct( 'NodeVarysStruct', '\t' + code ) : code;
+		return shaderStage === 'vertex' ? this._getWGSLStruct( 'NodeVaryingsStruct', '\t' + code ) : code;
 
 
 	}
 	}
 
 
@@ -612,7 +612,7 @@ class WebGPUNodeBuilder extends NodeBuilder {
 
 
 					if ( shaderStage === 'vertex' ) {
 					if ( shaderStage === 'vertex' ) {
 
 
-						flow += 'NodeVarys.Vertex = ';
+						flow += 'NodeVaryings.Vertex = ';
 
 
 					} else if ( shaderStage === 'fragment' ) {
 					} else if ( shaderStage === 'fragment' ) {
 
 
@@ -630,7 +630,7 @@ class WebGPUNodeBuilder extends NodeBuilder {
 
 
 			stageData.uniforms = this.getUniforms( shaderStage );
 			stageData.uniforms = this.getUniforms( shaderStage );
 			stageData.attributes = this.getAttributes( shaderStage );
 			stageData.attributes = this.getAttributes( shaderStage );
-			stageData.varys = this.getVarys( shaderStage );
+			stageData.varyings = this.getVaryings( shaderStage );
 			stageData.vars = this.getVars( shaderStage );
 			stageData.vars = this.getVars( shaderStage );
 			stageData.codes = this.getCodes( shaderStage );
 			stageData.codes = this.getCodes( shaderStage );
 			stageData.flow = flow;
 			stageData.flow = flow;
@@ -701,17 +701,17 @@ class WebGPUNodeBuilder extends NodeBuilder {
 // uniforms
 // uniforms
 ${shaderData.uniforms}
 ${shaderData.uniforms}
 
 
-// varys
-${shaderData.varys}
+// varyings
+${shaderData.varyings}
 
 
 // codes
 // codes
 ${shaderData.codes}
 ${shaderData.codes}
 
 
 @vertex
 @vertex
-fn main( ${shaderData.attributes} ) -> NodeVarysStruct {
+fn main( ${shaderData.attributes} ) -> NodeVaryingsStruct {
 
 
 	// system
 	// system
-	var NodeVarys: NodeVarysStruct;
+	var NodeVaryings: NodeVaryingsStruct;
 
 
 	// vars
 	// vars
 	${shaderData.vars}
 	${shaderData.vars}
@@ -719,7 +719,7 @@ fn main( ${shaderData.attributes} ) -> NodeVarysStruct {
 	// flow
 	// flow
 	${shaderData.flow}
 	${shaderData.flow}
 
 
-	return NodeVarys;
+	return NodeVaryings;
 
 
 }
 }
 `;
 `;
@@ -737,7 +737,7 @@ ${shaderData.uniforms}
 ${shaderData.codes}
 ${shaderData.codes}
 
 
 @fragment
 @fragment
-fn main( ${shaderData.varys} ) -> @location( 0 ) vec4<f32> {
+fn main( ${shaderData.varyings} ) -> @location( 0 ) vec4<f32> {
 
 
 	// vars
 	// vars
 	${shaderData.vars}
 	${shaderData.vars}

+ 1 - 1
examples/jsm/shaders/LuminosityShader.js

@@ -35,7 +35,7 @@ const LuminosityShader = {
 
 
 			vec4 texel = texture2D( tDiffuse, vUv );
 			vec4 texel = texture2D( tDiffuse, vUv );
 
 
-			float l = linearToRelativeLuminance( texel.rgb );
+			float l = luminance( texel.rgb );
 
 
 			gl_FragColor = vec4( l, l, l, texel.w );
 			gl_FragColor = vec4( l, l, l, texel.w );
 
 

+ 1 - 1
examples/jsm/shaders/ToneMapShader.js

@@ -51,7 +51,7 @@ const ToneMapShader = {
 			#endif
 			#endif
 
 
 			// Calculate the luminance of the current pixel
 			// Calculate the luminance of the current pixel
-			float fLumPixel = linearToRelativeLuminance( vColor );
+			float fLumPixel = luminance( vColor );
 
 
 			// Apply the modified operator (Eq. 4)
 			// Apply the modified operator (Eq. 4)
 			float fLumScaled = (fLumPixel * middleGrey) / max( minLuminance, fLumAvg );
 			float fLumScaled = (fLumPixel * middleGrey) / max( minLuminance, fLumAvg );

+ 16 - 0
examples/models/svg/tests/roundJoinPrecisionIssue.svg

@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Calque_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 width="5032.201px" height="2480.432px" viewBox="0 0 5032.201 2480.432"
+	 xml:space="preserve">
+<g id="COUPÉ_2_" transform="scale(0.1)">
+	<g id="SPLINE_149_">
+		<path fill="none" stroke="#010101" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="M434.099,631.724
+			c0,7,0,14.001,0,21.001c-7.001,0-14.001,0-21.001,0c0-7,0-14.001,0-21.001C420.099,631.724,427.099,631.724,434.099,631.724z"/>
+	</g>
+	<g id="SPLINE_142_">
+		<path fill="none" stroke="#010101" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="M4598.102,631.724
+			c0,7,0,14.001,0,21.001c7,0,14,0,21,0c0-7,0-14.001,0-21.001C4612.102,631.724,4605.102,631.724,4598.102,631.724z"/>
+	</g>
+</g>
+</svg>

BIN
examples/screenshots/webgl2_multisampled_renderbuffers.jpg


BIN
examples/screenshots/webgl2_ubo.jpg


BIN
examples/screenshots/webgl_instancing_modified.jpg


BIN
examples/screenshots/webgl_loader_pcd.jpg


BIN
examples/screenshots/webgl_loader_texture_ktx.jpg


BIN
examples/screenshots/webgl_materials_envmaps_groundprojected.jpg


BIN
examples/screenshots/webgl_materials_standard_nodes.jpg


BIN
examples/screenshots/webgl_nodes_loader_gltf_sheen.jpg


+ 0 - 0
examples/screenshots/webgl_materials_instance_uniform_nodes.jpg → examples/screenshots/webgl_nodes_materials_instance_uniform.jpg


BIN
examples/screenshots/webgl_nodes_materials_physical_clearcoat.jpg


BIN
examples/screenshots/webgl_nodes_materials_standard.jpg


+ 0 - 0
examples/screenshots/webgl_points_nodes.jpg → examples/screenshots/webgl_nodes_points.jpg


BIN
examples/screenshots/webgl_postprocessing_glitch.jpg


BIN
examples/screenshots/webgl_postprocessing_procedural.jpg


+ 0 - 1
examples/tags.json

@@ -72,7 +72,6 @@
 	"webgl_shadowmap_viewer": [ "directional", "spot" ],
 	"webgl_shadowmap_viewer": [ "directional", "spot" ],
 	"webgl_skinning_simple": [ "animation" ],
 	"webgl_skinning_simple": [ "animation" ],
 	"webgl_tonemapping": [ "gltf" ],
 	"webgl_tonemapping": [ "gltf" ],
-	"webgl_loader_nodes": [ "caustics", "displace", "xray" ],
 	"webgl_postprocessing_afterimage": [ "trails" ],
 	"webgl_postprocessing_afterimage": [ "trails" ],
 	"webgl_postprocessing_dof": [ "bokeh" ],
 	"webgl_postprocessing_dof": [ "bokeh" ],
 	"webgl_postprocessing_dof2": [ "bokeh" ],
 	"webgl_postprocessing_dof2": [ "bokeh" ],

BIN
examples/textures/equirectangular/blouberg_sunrise_2_1k.hdr


+ 314 - 0
examples/webgl2_ubo.html

@@ -0,0 +1,314 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<title>three.js WebGL 2 - Uniform Buffer Objects</title>
+		<meta charset="utf-8">
+		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
+		<link type="text/css" rel="stylesheet" href="main.css">
+	</head>
+
+	<body>
+
+		<div id="info">
+			<a href="http://threejs.org" target="_blank" rel="noopener">three.js</a> - Uniform Buffer Objects
+		</div>
+		<div id="container"></div>
+
+		<script id="vertexShader1" type="x-shader/x-vertex">
+
+			uniform ViewData {
+				mat4 projectionMatrix;
+				mat4 viewMatrix;
+			};
+
+			uniform mat4 modelMatrix;
+			uniform mat3 normalMatrix;
+
+			in vec3 position;
+			in vec3 normal;
+
+			out vec3 vPositionEye;
+			out vec3 vNormalEye;
+
+			void main()	{
+
+				vec4 vertexPositionEye = viewMatrix * modelMatrix * vec4( position, 1.0 );
+
+				vPositionEye = vertexPositionEye.xyz;
+				vNormalEye = normalMatrix * normal;
+
+				gl_Position = projectionMatrix * vertexPositionEye;
+
+			}
+
+		</script>
+
+		<script id="fragmentShader1" type="x-shader/x-fragment">
+
+			precision highp float;
+
+			uniform LightingData {
+				vec3 position;
+				vec3 ambientColor;
+				vec3 diffuseColor;
+				vec3 specularColor;
+				float shininess;
+			} Light;
+
+			uniform vec3 color;
+
+			in vec3 vPositionEye;
+			in vec3 vNormalEye;
+
+			out vec4 fragColor;
+
+			void main()	{
+
+				// a very basic lighting equation (Phong reflection model) for testing
+
+				vec3 l = normalize( Light.position - vPositionEye );
+				vec3 n = normalize( vNormalEye );
+				vec3 e = - normalize( vPositionEye );
+				vec3 r = normalize( reflect( - l, n ) );
+
+				float diffuseLightWeighting = max( dot( n, l ), 0.0 );
+				float specularLightWeighting = max( dot( r, e ), 0.0 );
+
+				specularLightWeighting = pow( specularLightWeighting, Light.shininess );
+
+				vec3 lightWeighting = Light.ambientColor +
+					Light.diffuseColor * diffuseLightWeighting +
+					Light.specularColor * specularLightWeighting;
+
+				fragColor = vec4( color.rgb * lightWeighting.rgb, 1.0 );
+
+			}
+
+		</script>
+
+		<script id="vertexShader2" type="x-shader/x-vertex">
+
+			uniform ViewData {
+				mat4 projectionMatrix;
+				mat4 viewMatrix;
+			};
+
+			uniform mat4 modelMatrix;
+
+			in vec3 position;
+			in vec2 uv;
+
+			out vec2 vUv;
+
+			void main()	{
+
+				vUv = uv;
+
+				gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4( position, 1.0 );
+
+			}
+
+		</script>
+
+		<script id="fragmentShader2" type="x-shader/x-fragment">
+
+			precision highp float;
+
+			uniform sampler2D diffuseMap;
+
+			in vec2 vUv;
+
+			out vec4 fragColor;
+
+			void main()	{
+
+				fragColor = texture( diffuseMap, vUv );
+
+			}
+
+		</script>
+
+		<!-- Import maps polyfill -->
+		<!-- Remove this when import maps will be widely supported -->
+		<script async src="https://unpkg.com/[email protected]/dist/es-module-shims.js"></script>
+
+		<script type="importmap">
+			{
+				"imports": {
+					"three": "../build/three.module.js"
+				}
+			}
+		</script>
+
+
+
+		<script type="module">
+
+			import * as THREE from 'three';
+
+			import WebGL from './jsm/capabilities/WebGL.js';
+
+			let camera, scene, renderer, clock;
+
+			init();
+			animate();
+
+			function init() {
+
+				if ( WebGL.isWebGL2Available() === false ) {
+
+					document.body.appendChild( WebGL.getWebGL2ErrorMessage() );
+					return;
+
+				}
+
+				const container = document.getElementById( 'container' );
+
+				camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.1, 100 );
+				camera.position.set( 0, 0, 25 );
+
+				scene = new THREE.Scene();
+				camera.lookAt( scene.position );
+
+				clock = new THREE.Clock();
+
+				// geometry
+
+				const geometry1 = new THREE.TetrahedronGeometry();
+				const geometry2 = new THREE.BoxGeometry();
+
+				// texture
+
+				const texture = new THREE.TextureLoader().load( 'textures/crate.gif' );
+
+				// uniforms groups
+
+				// Camera and lighting related data are perfect examples of using UBOs since you have to store these
+				// data just once. They can be shared across all shader programs.
+
+				const cameraUniformsGroup = new THREE.UniformsGroup();
+				cameraUniformsGroup.setName( 'ViewData' );
+				cameraUniformsGroup.add( new THREE.Uniform( camera.projectionMatrix ) ); // projection matrix
+				cameraUniformsGroup.add( new THREE.Uniform( camera.matrixWorldInverse ) ); // view matrix
+
+				const lightingUniformsGroup = new THREE.UniformsGroup();
+				lightingUniformsGroup.setName( 'LightingData' );
+				lightingUniformsGroup.add( new THREE.Uniform( new THREE.Vector3( 0, 0, 10 ) ) ); // light position
+				lightingUniformsGroup.add( new THREE.Uniform( new THREE.Color( 0x333333 ) ) ); // ambient color
+				lightingUniformsGroup.add( new THREE.Uniform( new THREE.Color( 0xaaaaaa ) ) ); // diffuse color
+				lightingUniformsGroup.add( new THREE.Uniform( new THREE.Color( 0xcccccc ) ) ); // specular color
+				lightingUniformsGroup.add( new THREE.Uniform( 64 ) ); // shininess
+
+				// materials
+
+				const material1 = new THREE.RawShaderMaterial( {
+					uniforms: {
+						modelMatrix: { value: null },
+						normalMatrix: { value: null },
+						color: { value: null }
+					},
+					vertexShader: document.getElementById( 'vertexShader1' ).textContent,
+					fragmentShader: document.getElementById( 'fragmentShader1' ).textContent,
+					glslVersion: THREE.GLSL3
+				} );
+
+				const material2 = new THREE.RawShaderMaterial( {
+					uniforms: {
+						modelMatrix: { value: null },
+						diffuseMap: { value: null },
+					},
+					vertexShader: document.getElementById( 'vertexShader2' ).textContent,
+					fragmentShader: document.getElementById( 'fragmentShader2' ).textContent,
+					glslVersion: THREE.GLSL3
+				} );
+
+				// meshes
+
+				for ( let i = 0; i < 200; i ++ ) {
+
+					let mesh;
+
+					if ( i % 2 === 0 ) {
+
+						mesh = new THREE.Mesh( geometry1, material1.clone() );
+
+						mesh.material.uniformsGroups = [ cameraUniformsGroup, lightingUniformsGroup ];
+						mesh.material.uniforms.modelMatrix.value = mesh.matrixWorld;
+						mesh.material.uniforms.normalMatrix.value = mesh.normalMatrix;
+						mesh.material.uniforms.color.value = new THREE.Color( 0xffffff * Math.random() );
+
+					} else {
+
+						mesh = new THREE.Mesh( geometry2, material2.clone() );
+
+						mesh.material.uniformsGroups = [ cameraUniformsGroup ];
+						mesh.material.uniforms.modelMatrix.value = mesh.matrixWorld;
+						mesh.material.uniforms.diffuseMap.value = texture;
+
+					}
+
+					scene.add( mesh );
+
+					const s = 1 + Math.random() * 0.5;
+
+					mesh.scale.x = s;
+					mesh.scale.y = s;
+					mesh.scale.z = s;
+
+					mesh.rotation.x = Math.random() * Math.PI;
+					mesh.rotation.y = Math.random() * Math.PI;
+					mesh.rotation.z = Math.random() * Math.PI;
+
+					mesh.position.x = Math.random() * 40 - 20;
+					mesh.position.y = Math.random() * 40 - 20;
+					mesh.position.z = Math.random() * 20 - 10;
+
+				}
+
+				//
+
+				renderer = new THREE.WebGLRenderer( { antialias: true } );
+				renderer.setPixelRatio( window.devicePixelRatio );
+				renderer.setSize( window.innerWidth, window.innerHeight );
+				container.appendChild( renderer.domElement );
+
+				window.addEventListener( 'resize', onWindowResize, false );
+
+			}
+
+			function onWindowResize() {
+
+				camera.aspect = window.innerWidth / window.innerHeight;
+				camera.updateProjectionMatrix();
+
+				renderer.setSize( window.innerWidth, window.innerHeight );
+
+			}
+
+			//
+
+			function animate() {
+
+				requestAnimationFrame( animate );
+
+				const delta = clock.getDelta();
+
+				scene.traverse( function ( child ) {
+
+					if ( child.isMesh ) {
+
+						child.rotation.x += delta * 0.5;
+						child.rotation.y += delta * 0.3;
+
+					}
+
+				} );
+
+				renderer.render( scene, camera );
+
+			}
+
+		</script>
+
+	</body>
+</html>

+ 5 - 1
examples/webgl_animation_skinning_additive_blending.html

@@ -203,7 +203,11 @@
 						const currentAction = currentSettings ? currentSettings.action : null;
 						const currentAction = currentSettings ? currentSettings.action : null;
 						const action = settings ? settings.action : null;
 						const action = settings ? settings.action : null;
 
 
-						prepareCrossFade( currentAction, action, 0.35 );
+						if ( currentAction !== action ) { 
+						
+							prepareCrossFade( currentAction, action, 0.35 );
+						
+						}
 
 
 					};
 					};
 
 

+ 0 - 208
examples/webgl_instancing_modified.html

@@ -1,208 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-	<head>
-		<title>three.js webgl - instancing - modified</title>
-		<meta charset="utf-8">
-		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
-		<link type="text/css" rel="stylesheet" href="main.css">
-	</head>
-
-	<body>
-		<div id="info">
-			<a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> - webgl instancing - modified
-		</div>
-
-		<!-- Import maps polyfill -->
-		<!-- Remove this when import maps will be widely supported -->
-		<script async src="https://unpkg.com/[email protected]/dist/es-module-shims.js"></script>
-
-		<script type="importmap">
-			{
-				"imports": {
-					"three": "../build/three.module.js"
-				}
-			}
-		</script>
-
-		<script type="module">
-
-			import * as THREE from 'three';
-
-			import Stats from './jsm/libs/stats.module.js';
-
-			let camera, scene, renderer, stats;
-
-			let mesh;
-
-			const dummy = new THREE.Object3D();
-
-			const amount = 8;
-			const count = Math.pow( amount, 3 );
-
-			init();
-			animate();
-
-			function init() {
-
-				renderer = new THREE.WebGLRenderer( { antialias: false } ); // false improves the frame rate
-				renderer.setPixelRatio( window.devicePixelRatio );
-				renderer.setSize( window.innerWidth, window.innerHeight );
-				document.body.appendChild( renderer.domElement );
-
-				renderer.outputEncoding = THREE.sRGBEncoding;
-
-				scene = new THREE.Scene();
-
-				camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 1, 100 );
-				camera.position.set( 0, 0, 20 );
-
-				new THREE.BufferGeometryLoader().load( 'models/json/suzanne_buffergeometry.json', function ( geometry ) {
-
-					const instanceColors = [];
-
-					for ( let i = 0; i < count; i ++ ) {
-
-						instanceColors.push( Math.random() );
-						instanceColors.push( Math.random() );
-						instanceColors.push( Math.random() );
-
-					}
-
-					geometry.setAttribute( 'instanceColor', new THREE.InstancedBufferAttribute( new Float32Array( instanceColors ), 3 ) );
-
-					geometry.computeVertexNormals();
-
-					geometry.scale( 0.5, 0.5, 0.5 );
-
-					//console.log( geometry );
-
-					//
-
-					new THREE.TextureLoader().load( 'textures/matcaps/matcap-porcelain-white.jpg', function ( texture ) {
-
-						texture.encoding = THREE.sRGBEncoding;
-
-						const material = new THREE.MeshMatcapMaterial( { color: 0xaaaaff, matcap: texture } );
-
-						const colorParsChunk = [
-							'attribute vec3 instanceColor;',
-							'varying vec3 vInstanceColor;',
-							'#include <common>'
-						].join( '\n' );
-
-						const instanceColorChunk = [
-							'#include <begin_vertex>',
-							'\tvInstanceColor = instanceColor;'
-						].join( '\n' );
-
-						const fragmentParsChunk = [
-							'varying vec3 vInstanceColor;',
-							'#include <common>'
-						].join( '\n' );
-
-						const colorChunk = [
-							'vec4 diffuseColor = vec4( diffuse * vInstanceColor, opacity );'
-						].join( '\n' );
-
-						material.onBeforeCompile = function ( shader ) {
-
-							shader.vertexShader = shader.vertexShader
-								.replace( '#include <common>', colorParsChunk )
-								.replace( '#include <begin_vertex>', instanceColorChunk );
-
-							shader.fragmentShader = shader.fragmentShader
-								.replace( '#include <common>', fragmentParsChunk )
-								.replace( 'vec4 diffuseColor = vec4( diffuse, opacity );', colorChunk );
-
-							//console.log( shader.uniforms );
-							//console.log( shader.vertexShader );
-							//console.log( shader.fragmentShader );
-
-						};
-
-						mesh = new THREE.InstancedMesh( geometry, material, count );
-
-						mesh.instanceMatrix.setUsage( THREE.DynamicDrawUsage ); // will be updated every frame
-
-						scene.add( mesh );
-
-					} );
-
-				} );
-
-				//
-
-				stats = new Stats();
-				document.body.appendChild( stats.dom );
-
-				//
-
-				window.addEventListener( 'resize', onWindowResize );
-
-			}
-
-			function onWindowResize() {
-
-				camera.aspect = window.innerWidth / window.innerHeight;
-				camera.updateProjectionMatrix();
-
-				renderer.setSize( window.innerWidth, window.innerHeight );
-
-			}
-
-			//
-
-			function animate() {
-
-				requestAnimationFrame( animate );
-
-				render();
-
-				stats.update();
-
-			}
-
-			function render() {
-
-				if ( mesh ) {
-
-					const time = Date.now() * 0.001;
-
-					mesh.rotation.x = Math.sin( time / 4 );
-					mesh.rotation.y = Math.sin( time / 2 );
-
-					let i = 0;
-					const offset = ( amount - 1 ) / 2;
-
-					for ( let x = 0; x < amount; x ++ ) {
-
-						for ( let y = 0; y < amount; y ++ ) {
-
-							for ( let z = 0; z < amount; z ++ ) {
-
-								dummy.position.set( offset - x, offset - y, offset - z );
-								dummy.rotation.y = ( Math.sin( x / 4 + time ) + Math.sin( y / 4 + time ) + Math.sin( z / 4 + time ) );
-								dummy.rotation.z = dummy.rotation.y * 2;
-
-								dummy.updateMatrix();
-
-								mesh.setMatrixAt( i ++, dummy.matrix );
-
-							}
-
-						}
-
-					}
-
-					mesh.instanceMatrix.needsUpdate = true;
-
-				}
-
-				renderer.render( scene, camera );
-
-			}
-
-		</script>
-
-	</body>
-</html>

+ 3 - 1
examples/webgl_loader_svg.html

@@ -117,7 +117,9 @@
 					'Style CSS inside defs': 'models/svg/style-css-inside-defs.svg',
 					'Style CSS inside defs': 'models/svg/style-css-inside-defs.svg',
 					'Multiple CSS classes': 'models/svg/multiple-css-classes.svg',
 					'Multiple CSS classes': 'models/svg/multiple-css-classes.svg',
 					'Zero Radius': 'models/svg/zero-radius.svg',
 					'Zero Radius': 'models/svg/zero-radius.svg',
-					'Styles in svg tag': 'models/svg/tests/styles.svg'
+					'Styles in svg tag': 'models/svg/tests/styles.svg',
+					'Round join': 'models/svg/tests/roundJoinPrecisionIssue.svg'
+
 
 
 				} ).name( 'SVG File' ).onChange( update );
 				} ).name( 'SVG File' ).onChange( update );
 
 

+ 184 - 0
examples/webgl_materials_envmaps_groundprojected.html

@@ -0,0 +1,184 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<title>
+			threejs webgl - materials - ground projected environment mapping
+		</title>
+		<meta charset="utf-8" />
+		<meta
+			name="viewport"
+			content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"
+		/>
+		<link type="text/css" rel="stylesheet" href="main.css" />
+	</head>
+	<body>
+		<div id="container"></div>
+		<div id="info">
+			<a href="https://threejs.org" target="_blank" rel="noopener">threejs</a> - Ground projected environment mapping. By <a href="https://twitter.com/CantBeFaraz" target="_blank" rel="noopener">Faraz Shaikh</a>.<br>
+			Ferrari 458 Italia model by <a href="https://sketchfab.com/models/57bf6cc56931426e87494f554df1dab6" target="_blank" rel="noopener">vicent091036</a><br>
+			<a href="https://polyhaven.com/a/blouberg_sunrise_2" target="_blank" rel="noopener">Blouberg Sunrise 2</a> by <a href="https://gregzaal.com/" target="_blank" rel="noopener">Greg Zaal</a>
+		</div>
+
+		<!-- Import maps polyfill -->
+		<!-- Remove this when import maps will be widely supported -->
+		<script
+			async
+			src="https://unpkg.com/[email protected]/dist/es-module-shims.js"
+		></script>
+
+		<script type="importmap">
+			{
+				"imports": {
+					"three": "../build/three.module.js"
+				}
+			}
+		</script>
+
+		<script type="module">
+			import * as THREE from 'three';
+
+			import Stats from './jsm/libs/stats.module.js';
+
+			import { GUI } from './jsm/libs/lil-gui.module.min.js';
+			import { OrbitControls } from './jsm/controls/OrbitControls.js';
+			import { GroundProjectedEnv } from './jsm/objects/GroundProjectedEnv.js';
+			import { GLTFLoader } from './jsm/loaders/GLTFLoader.js';
+			import { DRACOLoader } from './jsm/loaders/DRACOLoader.js';
+			import { RGBELoader } from './jsm/loaders/RGBELoader.js';
+
+			const params = {
+				height: 20,
+				radius: 440
+			};
+
+			let camera, scene, renderer, env;
+
+			init().then( render );
+
+			async function init() {
+
+				camera = new THREE.PerspectiveCamera(
+					40,
+					window.innerWidth / window.innerHeight,
+					1,
+					1000
+				);
+				camera.position.set( - 20, 7, 20 );
+				camera.lookAt( 0, 4, 0 );
+
+				scene = new THREE.Scene();
+
+				const hdrLoader = new RGBELoader();
+				const envMap = await hdrLoader.loadAsync( 'textures/equirectangular/blouberg_sunrise_2_1k.hdr' );
+				envMap.mapping = THREE.EquirectangularReflectionMapping;
+
+				env = new GroundProjectedEnv( envMap );
+				env.scale.setScalar( 100 );
+				scene.add( env );
+
+				scene.environment = envMap;
+
+				const dracoLoader = new DRACOLoader();
+				dracoLoader.setDecoderPath( 'js/libs/draco/gltf/' );
+
+				const loader = new GLTFLoader();
+				loader.setDRACOLoader( dracoLoader );
+
+				const shadow = new THREE.TextureLoader().load( 'models/gltf/ferrari_ao.png' );
+
+				loader.load( 'models/gltf/ferrari.glb', function ( gltf ) {
+
+					const bodyMaterial = new THREE.MeshPhysicalMaterial( {
+						color: 0x000000, metalness: 1.0, roughness: 0.8,
+						clearcoat: 1.0, clearcoatRoughness: 0.2
+					} );
+
+					const detailsMaterial = new THREE.MeshStandardMaterial( {
+						color: 0xffffff, metalness: 1.0, roughness: 0.5
+					} );
+
+					const glassMaterial = new THREE.MeshPhysicalMaterial( {
+						color: 0xffffff, metalness: 0.25, roughness: 0, transmission: 1.0
+					} );
+
+					const carModel = gltf.scene.children[ 0 ];
+					carModel.scale.multiplyScalar( 4 );
+					carModel.rotation.y = Math.PI;
+
+					carModel.getObjectByName( 'body' ).material = bodyMaterial;
+
+					carModel.getObjectByName( 'rim_fl' ).material = detailsMaterial;
+					carModel.getObjectByName( 'rim_fr' ).material = detailsMaterial;
+					carModel.getObjectByName( 'rim_rr' ).material = detailsMaterial;
+					carModel.getObjectByName( 'rim_rl' ).material = detailsMaterial;
+					carModel.getObjectByName( 'trim' ).material = detailsMaterial;
+
+					carModel.getObjectByName( 'glass' ).material = glassMaterial;
+
+					// shadow
+					const mesh = new THREE.Mesh(
+						new THREE.PlaneGeometry( 0.655 * 4, 1.3 * 4 ),
+						new THREE.MeshBasicMaterial( {
+							map: shadow, blending: THREE.MultiplyBlending, toneMapped: false, transparent: true
+						} )
+					);
+					mesh.rotation.x = - Math.PI / 2;
+					mesh.renderOrder = 2;
+					carModel.add( mesh );
+
+					scene.add( carModel );
+
+					render();
+
+				} );
+
+				//
+
+				renderer = new THREE.WebGLRenderer( { antialias: true } );
+				renderer.setPixelRatio( window.devicePixelRatio );
+				renderer.setSize( window.innerWidth, window.innerHeight );
+				renderer.outputEncoding = THREE.sRGBEncoding;
+				renderer.toneMapping = THREE.ACESFilmicToneMapping;
+
+				//
+
+				const controls = new OrbitControls( camera, renderer.domElement );
+				controls.addEventListener( 'change', render );
+				controls.target.set( 0, 2, 0 );
+				controls.maxPolarAngle = THREE.MathUtils.degToRad( 90 );
+				controls.maxDistance = 80;
+				controls.minDistance = 20;
+				controls.enablePan = false;
+				controls.update();
+
+				const gui = new GUI();
+				gui.add( params, 'height', 20, 50, 0.1 ).onChange( render );
+				gui.add( params, 'radius', 200, 600, 0.1 ).onChange( render );
+
+				//
+
+				document.body.appendChild( renderer.domElement );
+				window.addEventListener( 'resize', onWindowResize );
+
+			}
+
+			function onWindowResize() {
+
+				camera.aspect = window.innerWidth / window.innerHeight;
+				camera.updateProjectionMatrix();
+
+				renderer.setSize( window.innerWidth, window.innerHeight );
+
+			}
+
+			function render() {
+
+				renderer.render( scene, camera );
+
+				env.radius = params.radius;
+				env.height = params.height;
+
+			}
+		</script>
+	</body>
+</html>

+ 1 - 1
examples/webgl_modifier_simplifier.html

@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <!DOCTYPE html>
 <html lang="en">
 <html lang="en">
 	<head>
 	<head>
-		<title>three.js webgl - modifier - Subdivisions using Loop Subdivision Scheme</title>
+		<title>three.js webgl - modifier - simplify modifier</title>
 		<meta charset="utf-8">
 		<meta charset="utf-8">
 		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
 		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
 		<link type="text/css" rel="stylesheet" href="main.css">
 		<link type="text/css" rel="stylesheet" href="main.css">

+ 140 - 0
examples/webgl_nodes_loader_gltf_sheen.html

@@ -0,0 +1,140 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<title>three.js webgl - GLTFloader + Sheen + Nodes</title>
+		<meta charset="utf-8">
+		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
+		<link type="text/css" rel="stylesheet" href="main.css">
+		<style>
+			body {
+				background: #bbbbbb;
+			}
+		</style>
+	</head>
+
+	<body>
+		<div id="info">
+			<a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> - GLTFLoader + <a href="https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_sheen" target="_blank" rel="noopener">KHR_materials_sheen</a> + Nodes<br />
+			Sheen Chair from <a href="https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/SheenChair" target="_blank" rel="noopener">glTF-Sample-Models</a>
+		</div>
+
+		<!-- Import maps polyfill -->
+		<!-- Remove this when import maps will be widely supported -->
+		<script async src="https://unpkg.com/[email protected]/dist/es-module-shims.js"></script>
+
+		<script type="importmap">
+			{
+				"imports": {
+					"three": "../build/three.module.js",
+					"three-nodes/": "./jsm/nodes/"
+				}
+			}
+		</script>
+
+		<script type="module">
+
+			import * as THREE from 'three';
+
+			import { NodeMaterial, color, uv, mix, mul, checker } from 'three-nodes/Nodes.js';
+
+			import { nodeFrame } from './jsm/renderers/webgl/nodes/WebGLNodes.js';
+
+			import { OrbitControls } from './jsm/controls/OrbitControls.js';
+			import { GLTFLoader } from './jsm/loaders/GLTFLoader.js';
+			import { RoomEnvironment } from './jsm/environments/RoomEnvironment.js';
+
+			let camera, scene, renderer, controls;
+
+			init();
+			animate();
+
+			function init() {
+
+				const container = document.createElement( 'div' );
+				document.body.appendChild( container );
+
+				camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.1, 20 );
+				camera.position.set( - 0.75, 0.7, 1.25 );
+
+				scene = new THREE.Scene();
+
+				// model
+
+				new GLTFLoader()
+					.setPath( 'models/gltf/' )
+					.load( 'SheenChair.glb', function ( gltf ) {
+
+						scene.add( gltf.scene );
+
+						const object = gltf.scene.getObjectByName( 'SheenChair_fabric' );
+
+						// Convert to NodeMaterial
+						const material = NodeMaterial.fromMaterial( object.material );
+
+						const checkerNode = checker( mul( uv(), 5 ) );
+
+						material.sheenNode = mix( color( 0x00ffff ), color( 0xffff00 ), checkerNode );
+						material.sheenRoughnessNode = checkerNode;
+
+						object.material = material;
+
+					} );
+
+				renderer = new THREE.WebGLRenderer( { antialias: true } );
+				renderer.setPixelRatio( window.devicePixelRatio );
+				renderer.setSize( window.innerWidth, window.innerHeight );
+				renderer.toneMapping = THREE.ACESFilmicToneMapping;
+				renderer.toneMappingExposure = 1;
+				renderer.outputEncoding = THREE.sRGBEncoding;
+				container.appendChild( renderer.domElement );
+
+				const environment = new RoomEnvironment();
+				const pmremGenerator = new THREE.PMREMGenerator( renderer );
+
+				scene.background = new THREE.Color( 0xbbbbbb );
+				scene.environment = pmremGenerator.fromScene( environment ).texture;
+
+				controls = new OrbitControls( camera, renderer.domElement );
+				controls.enableDamping = true;
+				controls.minDistance = 1;
+				controls.maxDistance = 10;
+				controls.target.set( 0, 0.35, 0 );
+				controls.update();
+
+				window.addEventListener( 'resize', onWindowResize );
+
+			}
+
+			function onWindowResize() {
+
+				camera.aspect = window.innerWidth / window.innerHeight;
+				camera.updateProjectionMatrix();
+
+				renderer.setSize( window.innerWidth, window.innerHeight );
+
+			}
+
+			//
+
+			function animate() {
+
+				requestAnimationFrame( animate );
+
+				nodeFrame.update();
+
+				controls.update(); // required if damping enabled
+
+				render();
+
+			}
+
+			function render() {
+
+				renderer.render( scene, camera );
+
+			}
+
+		</script>
+
+	</body>
+</html>

+ 0 - 0
examples/webgl_materials_instance_uniform_nodes.html → examples/webgl_nodes_materials_instance_uniform.html


+ 256 - 0
examples/webgl_nodes_materials_physical_clearcoat.html

@@ -0,0 +1,256 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<title>three.js webgl - materials - clearcoat nodes</title>
+		<meta charset="utf-8">
+		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
+		<link type="text/css" rel="stylesheet" href="main.css">
+	</head>
+	<body>
+		<div id="info">
+			<a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> webgl - materials - clearcoat nodes
+		</div>
+
+		<!-- Import maps polyfill -->
+		<!-- Remove this when import maps will be widely supported -->
+		<script async src="https://unpkg.com/[email protected]/dist/es-module-shims.js"></script>
+
+		<script type="importmap">
+			{
+				"imports": {
+					"three": "../build/three.module.js",
+					"three-nodes/": "./jsm/nodes/"
+				}
+			}
+		</script>
+
+		<script type="module">
+
+			import * as THREE from 'three';
+			import * as Nodes from 'three-nodes/Nodes.js';
+
+			import { color, float, vec2, texture, normalMap, uv, mul } from 'three-nodes/Nodes.js';
+
+			import { nodeFrame } from './jsm/renderers/webgl/nodes/WebGLNodes.js';
+
+			import Stats from './jsm/libs/stats.module.js';
+
+			import { OrbitControls } from './jsm/controls/OrbitControls.js';
+			import { HDRCubeTextureLoader } from './jsm/loaders/HDRCubeTextureLoader.js';
+
+			import { FlakesTexture } from './jsm/textures/FlakesTexture.js';
+
+			let container, stats;
+
+			let camera, scene, renderer;
+
+			let particleLight;
+			let group;
+
+			init();
+			animate();
+
+			function init() {
+
+				container = document.createElement( 'div' );
+				document.body.appendChild( container );
+
+				camera = new THREE.PerspectiveCamera( 27, window.innerWidth / window.innerHeight, 1, 10000 );
+				camera.position.z = 1000;
+
+				scene = new THREE.Scene();
+
+				group = new THREE.Group();
+				scene.add( group );
+
+				new HDRCubeTextureLoader()
+					.setPath( 'textures/cube/pisaHDR/' )
+					.load( [ 'px.hdr', 'nx.hdr', 'py.hdr', 'ny.hdr', 'pz.hdr', 'nz.hdr' ],
+						  function ( hdrTexture ) {
+
+							const geometry = new THREE.SphereGeometry( 80, 64, 32 );
+
+							const textureLoader = new THREE.TextureLoader();
+
+							const diffuse = textureLoader.load( 'textures/carbon/Carbon.png' );
+							diffuse.encoding = THREE.sRGBEncoding;
+							diffuse.wrapS = THREE.RepeatWrapping;
+							diffuse.wrapT = THREE.RepeatWrapping;
+
+							const normalMap1 = textureLoader.load( 'textures/carbon/Carbon_Normal.png' );
+							normalMap1.wrapS = THREE.RepeatWrapping;
+							normalMap1.wrapT = THREE.RepeatWrapping;
+
+							const normalMap2 = textureLoader.load( 'textures/water/Water_1_M_Normal.jpg' );
+
+							const normalMap3 = new THREE.CanvasTexture( new FlakesTexture() );
+							normalMap3.wrapS = THREE.RepeatWrapping;
+							normalMap3.wrapT = THREE.RepeatWrapping;
+							normalMap3.anisotropy = 16;
+
+							const normalMap4 = textureLoader.load( 'textures/golfball.jpg' );
+
+							const clearcoatNormalMap = textureLoader.load( 'textures/pbr/Scratched_gold/Scratched_gold_01_1K_Normal.png' );
+
+							// car paint
+
+							const carPaintUV = mul( uv(), vec2( 10, 6 ) );
+							const carPaintNormalScale = vec2( 0.15 );
+
+							let material = new Nodes.MeshPhysicalNodeMaterial();
+							material.clearcoatNode = float( 1 );
+							material.clearcoatRoughnessNode = float( 0.1 );
+							material.metalnessNode = float( 0.9 );
+							material.roughnessNode = float( 0.5 );
+							material.colorNode = color( 0x0000ff );
+							material.normalNode = normalMap( texture( normalMap3, carPaintUV ), carPaintNormalScale );
+
+							let mesh = new THREE.Mesh( geometry, material );
+							mesh.position.x = - 100;
+							mesh.position.y = 100;
+							group.add( mesh );
+
+							// fibers
+
+							const fibersUV = mul( uv(), 10 );
+
+							material = new Nodes.MeshPhysicalNodeMaterial();
+							material.roughnessNode = float( 0.5 );
+							material.clearcoatNode = float( 1 );
+							material.clearcoatRoughnessNode = float( 0.1 );
+							material.colorNode = texture( diffuse, fibersUV );
+							material.normalNode = normalMap( texture( normalMap1, fibersUV ) );
+
+							mesh = new THREE.Mesh( geometry, material );
+							mesh.position.x = 100;
+							mesh.position.y = 100;
+							group.add( mesh );
+
+							// golf
+
+							material = new Nodes.MeshPhysicalNodeMaterial();
+							material.clearcoatNode = float( 1 );
+							material.roughnessNode = float( 0.1 );
+							material.metalnessNode = float( 0 );
+							material.colorNode = color( 0xffffff );
+							material.normalNode = normalMap( texture( normalMap4 ) );
+							// y scale is negated to compensate for normal map handedness.
+							material.clearcoatNormalNode = normalMap( texture( clearcoatNormalMap ), vec2( 2.0, - 2.0 ) );
+
+							mesh = new THREE.Mesh( geometry, material );
+							mesh.position.x = - 100;
+							mesh.position.y = - 100;
+							group.add( mesh );
+
+							// clearcoat + normalmap
+
+							material = new Nodes.MeshPhysicalNodeMaterial();
+							material.clearcoatNode = float( 1 );
+							material.roughnessNode = float( 1 );
+							material.metalnessNode = float( 1 );
+							material.colorNode = color( 0xff0000 );
+							material.normalNode = normalMap( texture( normalMap2 ), vec2( 0.15, 0.15 ) );
+							// y scale is negated to compensate for normal map handedness.
+							material.clearcoatNormalNode = normalMap( texture( clearcoatNormalMap ), vec2( 2.0, - 2.0 ) );
+
+							mesh = new THREE.Mesh( geometry, material );
+							mesh.position.x = 100;
+							mesh.position.y = - 100;
+							group.add( mesh );
+
+							//
+
+							scene.background = hdrTexture;
+							scene.environment = hdrTexture;
+
+						}
+
+						 );
+
+				// LIGHTS
+
+				particleLight = new THREE.Mesh(
+					new THREE.SphereGeometry( 4, 8, 8 ),
+					new THREE.MeshBasicMaterial( { color: 0xffffff } )
+				);
+				scene.add( particleLight );
+
+				particleLight.add( new THREE.PointLight( 0xffffff, 1 ) );
+
+				renderer = new THREE.WebGLRenderer();
+				renderer.setPixelRatio( window.devicePixelRatio );
+				renderer.setSize( window.innerWidth, window.innerHeight );
+				container.appendChild( renderer.domElement );
+
+				//
+
+				renderer.toneMapping = THREE.ACESFilmicToneMapping;
+				renderer.toneMappingExposure = 1.25;
+
+				//
+
+				renderer.outputEncoding = THREE.sRGBEncoding;
+
+				//
+
+				stats = new Stats();
+				container.appendChild( stats.dom );
+
+				// EVENTS
+
+				new OrbitControls( camera, renderer.domElement );
+
+				window.addEventListener( 'resize', onWindowResize );
+
+			}
+
+			//
+
+			function onWindowResize() {
+
+				const width = window.innerWidth;
+				const height = window.innerHeight;
+
+				camera.aspect = width / height;
+				camera.updateProjectionMatrix();
+
+				renderer.setSize( width, height );
+
+			}
+
+			//
+
+			function animate() {
+
+				requestAnimationFrame( animate );
+
+				nodeFrame.update();
+
+				render();
+
+				stats.update();
+
+			}
+
+			function render() {
+
+				const timer = Date.now() * 0.00025;
+
+				particleLight.position.x = Math.sin( timer * 7 ) * 300;
+				particleLight.position.y = Math.cos( timer * 5 ) * 400;
+				particleLight.position.z = Math.cos( timer * 3 ) * 300;
+
+				for ( let i = 0; i < group.children.length; i ++ ) {
+
+					const child = group.children[ i ];
+					child.rotation.y += 0.005;
+
+				}
+
+				renderer.render( scene, camera );
+
+			}
+
+		</script>
+	</body>
+</html>

+ 0 - 0
examples/webgl_materials_standard_nodes.html → examples/webgl_nodes_materials_standard.html


+ 0 - 0
examples/webgl_points_nodes.html → examples/webgl_nodes_points.html


+ 1 - 1
examples/webgl_raycaster_bvh.html

@@ -112,7 +112,7 @@
 				} ) );
 				} ) );
 
 
 				sphereInstance = new THREE.InstancedMesh(
 				sphereInstance = new THREE.InstancedMesh(
-					new THREE.SphereBufferGeometry(),
+					new THREE.SphereGeometry(),
 					new THREE.MeshBasicMaterial( { color: RAY_COLOR } ),
 					new THREE.MeshBasicMaterial( { color: RAY_COLOR } ),
 					2 * MAX_RAYS
 					2 * MAX_RAYS
 				);
 				);

+ 6 - 1
examples/webgl_shaders_ocean.html

@@ -111,6 +111,7 @@
 				};
 				};
 
 
 				const pmremGenerator = new THREE.PMREMGenerator( renderer );
 				const pmremGenerator = new THREE.PMREMGenerator( renderer );
+				let renderTarget;
 
 
 				function updateSun() {
 				function updateSun() {
 
 
@@ -122,7 +123,11 @@
 					sky.material.uniforms[ 'sunPosition' ].value.copy( sun );
 					sky.material.uniforms[ 'sunPosition' ].value.copy( sun );
 					water.material.uniforms[ 'sunDirection' ].value.copy( sun ).normalize();
 					water.material.uniforms[ 'sunDirection' ].value.copy( sun ).normalize();
 
 
-					scene.environment = pmremGenerator.fromScene( sky ).texture;
+					if ( renderTarget !== undefined ) renderTarget.dispose();
+
+					renderTarget = pmremGenerator.fromScene( sky );
+
+					scene.environment = renderTarget.texture;
 
 
 				}
 				}
 
 

+ 25 - 14
examples/webgpu_compute.html

@@ -29,8 +29,8 @@
 
 
 			import {
 			import {
 				ShaderNode, compute,
 				ShaderNode, compute,
-				uniform, element, storage, attribute,
-				temp, assign, add, sub, cond, abs, negate, max, min, length, vec3, color,
+				uniform, element, storage, attribute, mul, sin, cos,
+				temp, assign, add, sub, cond, abs, negate, max, min, length, float, vec2, vec3, color,
 				greaterThanEqual, lessThanEqual, instanceIndex
 				greaterThanEqual, lessThanEqual, instanceIndex
 			} from 'three-nodes/Nodes.js';
 			} from 'three-nodes/Nodes.js';
 
 
@@ -70,16 +70,6 @@
 				const particleArray = new Float32Array( particleNum * particleSize );
 				const particleArray = new Float32Array( particleNum * particleSize );
 				const velocityArray = new Float32Array( particleNum * particleSize );
 				const velocityArray = new Float32Array( particleNum * particleSize );
 
 
-				for ( let i = 0; i < particleNum; i ++ ) {
-
-					const r = Math.random() * 0.01 + 0.005;
-					const degree = Math.random() * 360;
-
-					velocityArray[ i * particleSize + 0 ] = r * Math.sin( degree * Math.PI / 180 ); // x
-					velocityArray[ i * particleSize + 1 ] = r * Math.cos( degree * Math.PI / 180 ); // y
-
-				}
-
 				// create buffers
 				// create buffers
 
 
 				const particleBuffer = new THREE.InstancedBufferAttribute( particleArray, 2 );
 				const particleBuffer = new THREE.InstancedBufferAttribute( particleArray, 2 );
@@ -90,7 +80,7 @@
 
 
 				// create function
 				// create function
 
 
-				const FnNode = new ShaderNode( ( inputs, builder ) => {
+				const computeShaderNode = new ShaderNode( ( inputs, builder ) => {
 
 
 					const particle = element( particleBufferNode, instanceIndex );
 					const particle = element( particleBufferNode, instanceIndex );
 					const velocity = element( velocityBufferNode, instanceIndex );
 					const velocity = element( velocityBufferNode, instanceIndex );
@@ -115,7 +105,28 @@
 
 
 				// compute
 				// compute
 
 
-				computeNode = compute( FnNode, particleNum );
+				computeNode = compute( computeShaderNode, particleNum );
+				computeNode.onInit = ( { renderer } ) => {
+
+					const precomputeShaderNode = new ShaderNode( ( inputs, builder ) => {
+
+						const particleIndex = float( instanceIndex );
+
+						const randomAngle = mul( mul( particleIndex, .005 ), Math.PI * 2 );
+						const randomSpeed = add( mul( particleIndex, 0.00000001 ), 0.0000001 );
+
+						const velX = mul( sin( randomAngle ), randomSpeed );
+						const velY = mul( cos( randomAngle ), randomSpeed );
+
+						const velocity = element( velocityBufferNode, instanceIndex );
+
+						assign( velocity.xy, vec2( velX, velY ) ).build( builder );
+
+					} );
+
+					renderer.compute( compute( precomputeShaderNode, computeNode.count ) );
+
+				};
 
 
 				// use a compute shader to animate the point cloud's vertex data.
 				// use a compute shader to animate the point cloud's vertex data.
 
 

+ 1 - 1
examples/webxr_ar_lighting.html

@@ -114,7 +114,7 @@
 
 
 				//
 				//
 
 
-				const ballGeometry = new THREE.SphereBufferGeometry( 0.175, 32, 32 );
+				const ballGeometry = new THREE.SphereGeometry( 0.175, 32, 32 );
 				const ballGroup = new THREE.Group();
 				const ballGroup = new THREE.Group();
 				ballGroup.position.z = - 2;
 				ballGroup.position.z = - 2;
 
 

+ 1 - 1
index.html

@@ -33,7 +33,7 @@
 		<div id="panel">
 		<div id="panel">
 
 
 			<div id="header">
 			<div id="header">
-				<h1><div>three.js</div><a id="version" href="http://github.com/mrdoob/three.js/releases">r142</a></h1>
+				<h1><div>three.js</div><a id="version" href="http://github.com/mrdoob/three.js/releases">r143</a></h1>
 
 
 				<div id="sections">
 				<div id="sections">
 					<a href="docs/index.html#manual/introduction/Creating-a-scene">docs</a>
 					<a href="docs/index.html#manual/introduction/Creating-a-scene">docs</a>

+ 1 - 1
manual/zh/optimize-lots-of-objects.html

@@ -157,7 +157,7 @@ function hsl(h, s, l) {
 <pre class="prettyprint showlinemods notranslate lang-js" translate="no">{
 <pre class="prettyprint showlinemods notranslate lang-js" translate="no">{
   const loader = new THREE.TextureLoader();
   const loader = new THREE.TextureLoader();
   const texture = loader.load('resources/images/world.jpg', render);
   const texture = loader.load('resources/images/world.jpg', render);
-  const geometry = new THREE.SphereBufferGeometry(1, 64, 32);
+  const geometry = new THREE.SphereGeometry(1, 64, 32);
   const material = new THREE.MeshBasicMaterial({map: texture});
   const material = new THREE.MeshBasicMaterial({map: texture});
   scene.add(new THREE.Mesh(geometry, material));
   scene.add(new THREE.Mesh(geometry, material));
 }
 }

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