From d59de8e0dce39c93dc7a1ebfdb2e0747523fea7d Mon Sep 17 00:00:00 2001 From: NoKic233 <74362493+Nokic233@users.noreply.github.com> Date: Tue, 29 Oct 2024 16:46:24 +0800 Subject: [PATCH 01/18] Docs:Manual lights.html typo (#29756) * Docs:Manual lights.html typo * Docs:Manual lights.html code snippet intensity default 5 --- manual/en/lights.html | 10 +++++----- manual/examples/lights-directional.html | 6 +++--- manual/fr/lights.html | 10 +++++----- manual/ja/lights.html | 10 +++++----- manual/ko/lights.html | 10 +++++----- manual/ru/lights.html | 10 +++++----- manual/zh/lights.html | 10 +++++----- 7 files changed, 33 insertions(+), 33 deletions(-) diff --git a/manual/en/lights.html b/manual/en/lights.html index 3a680c7dff3869..6931ce1ca45d09 100644 --- a/manual/en/lights.html +++ b/manual/en/lights.html @@ -149,7 +149,7 @@
And here's our code setting up lil-gui
const gui = new GUI();
gui.addColor(new ColorGUIHelper(light, 'color'), 'value').name('color');
-gui.add(light, 'intensity', 0, 2, 0.01);
+gui.add(light, 'intensity', 0, 5, 0.01);
And here's the result
@@ -188,7 +188,7 @@
The result:
@@ -220,7 +220,7 @@
const gui = new GUI();
gui.addColor(new ColorGUIHelper(light, 'color'), 'value').name('color');
-gui.add(light, 'intensity', 0, 2, 0.01);
+gui.add(light, 'intensity', 0, 5, 0.01);
gui.add(light.target.position, 'x', -10, 10);
gui.add(light.target.position, 'z', -10, 10);
gui.add(light.target.position, 'y', 0, 10);
@@ -266,7 +266,7 @@ const gui = new GUI();
gui.addColor(new ColorGUIHelper(light, 'color'), 'value').name('color');
-gui.add(light, 'intensity', 0, 2, 0.01);
+gui.add(light, 'intensity', 0, 250, 1);
+gui.add(light, 'distance', 0, 40).onChange(updateLight);
makeXYZGUI(gui, light.position, 'position', updateLight);
diff --git a/manual/examples/lights-directional.html b/manual/examples/lights-directional.html
index f3a955e23d8ba6..1e1cea64ccd0c3 100644
--- a/manual/examples/lights-directional.html
+++ b/manual/examples/lights-directional.html
@@ -135,9 +135,9 @@
const gui = new GUI();
gui.addColor( new ColorGUIHelper( light, 'color' ), 'value' ).name( 'color' );
gui.add( light, 'intensity', 0, 5, 0.01 );
- gui.add( light.target.position, 'x', - 10, 10, .01 );
- gui.add( light.target.position, 'z', - 10, 10, .01 );
- gui.add( light.target.position, 'y', 0, 10, .01 );
+ gui.add( light.target.position, 'x', - 10, 10 );
+ gui.add( light.target.position, 'z', - 10, 10 );
+ gui.add( light.target.position, 'y', 0, 10 );
}
diff --git a/manual/fr/lights.html b/manual/fr/lights.html
index 5a411600498717..c80ca1fa38abe8 100644
--- a/manual/fr/lights.html
+++ b/manual/fr/lights.html
@@ -127,7 +127,7 @@ Et voici le code de configuartion de lil-gui
const gui = new GUI();
gui.addColor(new ColorGUIHelper(light, 'color'), 'value').name('color');
-gui.add(light, 'intensity', 0, 2, 0.01);
+gui.add(light, 'intensity', 0, 5, 0.01);
Le résultat :
@@ -157,7 +157,7 @@
Le resultat :
@@ -183,7 +183,7 @@ Faisons en sorte que nous puissions déplacer la cible en l'ajoutant à lil-gui.
const gui = new GUI();
gui.addColor(new ColorGUIHelper(light, 'color'), 'value').name('color');
-gui.add(light, 'intensity', 0, 2, 0.01);
+gui.add(light, 'intensity', 0, 5, 0.01);
gui.add(light.target.position, 'x', -10, 10);
gui.add(light.target.position, 'z', -10, 10);
gui.add(light.target.position, 'y', 0, 10);
@@ -218,7 +218,7 @@ const gui = new GUI();
gui.addColor(new ColorGUIHelper(light, 'color'), 'value').name('color');
-gui.add(light, 'intensity', 0, 2, 0.01);
+gui.add(light, 'intensity', 0, 250, 1);
+gui.add(light, 'distance', 0, 40).onChange(updateLight);
makeXYZGUI(gui, light.position, 'position', updateLight);
diff --git a/manual/ja/lights.html b/manual/ja/lights.html
index b4f4cbd7d176ca..84358067aef0d8 100644
--- a/manual/ja/lights.html
+++ b/manual/ja/lights.html
@@ -138,7 +138,7 @@ AmbientLight(
lil-guiの設定は以下の通りです。
const gui = new GUI();
gui.addColor(new ColorGUIHelper(light, 'color'), 'value').name('color');
-gui.add(light, 'intensity', 0, 2, 0.01);
+gui.add(light, 'intensity', 0, 5, 0.01);
これで以下のような結果になります。
@@ -171,7 +171,7 @@ HemisphereLi
-gui.addColor(new ColorGUIHelper(light, 'color'), 'value').name('color');
+gui.addColor(new ColorGUIHelper(light, 'color'), 'value').name('skyColor');
+gui.addColor(new ColorGUIHelper(light, 'groundColor'), 'value').name('groundColor');
-gui.add(light, 'intensity', 0, 2, 0.01);
+gui.add(light, 'intensity', 0, 5, 0.01);
これが結果です。
@@ -199,7 +199,7 @@ Directional
GUIに追加してlight.targetを動かせるようにしてみましょう。
const gui = new GUI();
gui.addColor(new ColorGUIHelper(light, 'color'), 'value').name('color');
-gui.add(light, 'intensity', 0, 2, 0.01);
+gui.add(light, 'intensity', 0, 5, 0.01);
gui.add(light.target.position, 'x', -10, 10);
gui.add(light.target.position, 'z', -10, 10);
gui.add(light.target.position, 'y', 0, 10);
@@ -238,7 +238,7 @@ Directional
const gui = new GUI();
gui.addColor(new ColorGUIHelper(light, 'color'), 'value').name('color');
-gui.add(light, 'intensity', 0, 2, 0.01);
+gui.add(light, 'intensity', 0, 5, 0.01);
+makeXYZGUI(gui, light.position, 'position', updateLight);
+makeXYZGUI(gui, light.target.position, 'target', updateLight);
@@ -287,7 +287,7 @@ PointLight(点
distanceを調整できるようにGUIを設定してみましょう。
const gui = new GUI();
gui.addColor(new ColorGUIHelper(light, 'color'), 'value').name('color');
-gui.add(light, 'intensity', 0, 2, 0.01);
+gui.add(light, 'intensity', 0, 250, 1);
+gui.add(light, 'distance', 0, 40).onChange(updateLight);
makeXYZGUI(gui, light.position, 'position', updateLight);
diff --git a/manual/ko/lights.html b/manual/ko/lights.html
index b7fe5acf99aab7..5f6d91f7e0c96a 100644
--- a/manual/ko/lights.html
+++ b/manual/ko/lights.html
@@ -139,7 +139,7 @@ 아래는 lil-gui를 만드는 코드입니다.
const gui = new GUI();
gui.addColor(new ColorGUIHelper(light, 'color'), 'value').name('color');
-gui.add(light, 'intensity', 0, 2, 0.01);
+gui.add(light, 'intensity', 0, 5, 0.01);
결과물은 다음과 같죠.
@@ -173,7 +173,7 @@
@@ -202,7 +202,7 @@ 이 역시 GUI를 사용해 목표의 위치를 조정할 수 있도록 만들겠습니다.
const gui = new GUI();
gui.addColor(new ColorGUIHelper(light, 'color'), 'value').name('color');
-gui.add(light, 'intensity', 0, 2, 0.01);
+gui.add(light, 'intensity', 0, 5, 0.01);
gui.add(light.target.position, 'x', -10, 10);
gui.add(light.target.position, 'z', -10, 10);
gui.add(light.target.position, 'y', 0, 10);
@@ -246,7 +246,7 @@ const gui = new GUI();
gui.addColor(new ColorGUIHelper(light, 'color'), 'value').name('color');
-gui.add(light, 'intensity', 0, 2, 0.01);
+gui.add(light, 'intensity', 0, 250, 1);
+gui.add(light, 'distance', 0, 40).onChange(updateLight);
makeXYZGUI(gui, light.position, 'position', updateLight);
diff --git a/manual/ru/lights.html b/manual/ru/lights.html
index 4114667d235142..a7776a5e97f596 100644
--- a/manual/ru/lights.html
+++ b/manual/ru/lights.html
@@ -151,7 +151,7 @@ И вот наш код настройки lil-gui
const gui = new GUI();
gui.addColor(new ColorGUIHelper(light, 'color'), 'value').name('color');
-gui.add(light, 'intensity', 0, 2, 0.01);
+gui.add(light, 'intensity', 0, 5, 0.01);
И вот результат
@@ -188,7 +188,7 @@
Результат:
@@ -219,7 +219,7 @@
const gui = new GUI();
gui.addColor(new ColorGUIHelper(light, 'color'), 'value').name('color');
-gui.add(light, 'intensity', 0, 2, 0.01);
+gui.add(light, 'intensity', 0, 5, 0.01);
gui.add(light.target.position, 'x', -10, 10);
gui.add(light.target.position, 'z', -10, 10);
gui.add(light.target.position, 'y', 0, 10);
@@ -265,7 +265,7 @@ const gui = new GUI();
gui.addColor(new ColorGUIHelper(light, 'color'), 'value').name('color');
-gui.add(light, 'intensity', 0, 2, 0.01);
+gui.add(light, 'intensity', 0, 250, 1);
+gui.add(light, 'distance', 0, 40).onChange(updateLight);
makeXYZGUI(gui, light.position, 'position', updateLight);
diff --git a/manual/zh/lights.html b/manual/zh/lights.html
index e15bf07f677040..1a1bca77205289 100644
--- a/manual/zh/lights.html
+++ b/manual/zh/lights.html
@@ -123,7 +123,7 @@ 环境光(
以及创建 lil-gui 的代码:
const gui = new GUI();
gui.addColor(new ColorGUIHelper(light, 'color'), 'value').name('color');
-gui.add(light, 'intensity', 0, 2, 0.01);
+gui.add(light, 'intensity', 0, 5, 0.01);
结果如下所示:
@@ -154,7 +154,7 @@ 半球光(
@@ -179,7 +179,7 @@ 方向光(lil-gui,使得我们可以控制目标位置
const gui = new GUI();
gui.addColor(new ColorGUIHelper(light, 'color'), 'value').name('color');
-gui.add(light, 'intensity', 0, 2, 0.01);
+gui.add(light, 'intensity', 0, 5, 0.01);
gui.add(light.target.position, 'x', -10, 10);
gui.add(light.target.position, 'z', -10, 10);
gui.add(light.target.position, 'y', 0, 10);
@@ -213,7 +213,7 @@ 方向光(点光源(下面是添加对 distance 参数控制的代码:
const gui = new GUI();
gui.addColor(new ColorGUIHelper(light, 'color'), 'value').name('color');
-gui.add(light, 'intensity', 0, 2, 0.01);
+gui.add(light, 'intensity', 0, 250, 1);
+gui.add(light, 'distance', 0, 40).onChange(updateLight);
makeXYZGUI(gui, light.position, 'position', updateLight);
From bbfdeaca8f0d5567b600dfbce2921911a60ed87c Mon Sep 17 00:00:00 2001
From: Kristi K
Date: Tue, 29 Oct 2024 09:52:02 +0100
Subject: [PATCH 02/18] Add `Vector4.divide`, to match Vector3 and Vector2
function set (#29759)
---
docs/api/en/math/Vector4.html | 3 +++
src/math/Vector4.js | 11 +++++++++++
test/unit/src/math/Vector4.tests.js | 13 +++++++++++++
3 files changed, 27 insertions(+)
diff --git a/docs/api/en/math/Vector4.html b/docs/api/en/math/Vector4.html
index 91175c3759dfe5..8e8cee31d0b1b8 100644
--- a/docs/api/en/math/Vector4.html
+++ b/docs/api/en/math/Vector4.html
@@ -157,6 +157,9 @@ [method:this copy]( [param:Vector4 v] )
[page:.z z] and [page:.w w] properties to this Vector4.
+ [method:this divide]( [param:Vector4 v] )
+ Divides this vector by [page:Vector4 v].
+
[method:this divideScalar]( [param:Float s] )
Divides this vector by scalar [page:Float s].
diff --git a/src/math/Vector4.js b/src/math/Vector4.js
index 6553ceff56ae40..4e02716a950c33 100644
--- a/src/math/Vector4.js
+++ b/src/math/Vector4.js
@@ -249,6 +249,17 @@ class Vector4 {
}
+ divide( v ) {
+
+ this.x /= v.x;
+ this.y /= v.y;
+ this.z /= v.z;
+ this.w /= v.w;
+
+ return this;
+
+ }
+
divideScalar( scalar ) {
return this.multiplyScalar( 1 / scalar );
diff --git a/test/unit/src/math/Vector4.tests.js b/test/unit/src/math/Vector4.tests.js
index 160f466527c2bd..34bc529cd3b221 100644
--- a/test/unit/src/math/Vector4.tests.js
+++ b/test/unit/src/math/Vector4.tests.js
@@ -272,6 +272,19 @@ export default QUnit.module( 'Maths', () => {
} );
+ QUnit.test( 'divide', ( assert) => {
+
+ const a = new Vector4( 7, 8, 9, 0 );
+ const b = new Vector4( 2, 2, 3, 4 );
+
+ a.divide( b );
+ assert.equal( a.x, 3.5, 'Check divide x' );
+ assert.equal( a.y, 4.0, 'Check divide y' );
+ assert.equal( a.z, 3.0, 'Check divide z' );
+ assert.equal( a.w, 0.0, 'Check divide w' );
+
+ } );
+
QUnit.todo( 'divideScalar', ( assert ) => {
assert.ok( false, 'everything\'s gonna be alright' );
From ff6450a9951ce92af263e361257efbda31c61379 Mon Sep 17 00:00:00 2001
From: Michael Herzog
Date: Tue, 29 Oct 2024 09:59:35 +0100
Subject: [PATCH 03/18] NodeMaterial: Add support for `alphaHash`. (#29757)
* NodeMaterial: Add support for `alphaHash`.
* Clean up.
* E2E: Update exception list.
* Examples: Clean up.
* NodeMaterial: Fix alpha hash check.
---
examples/files.json | 1 +
.../webgpu_materials_alphahash.jpg | Bin 0 -> 29916 bytes
examples/webgpu_materials_alphahash.html | 172 ++++++++++++++++++
src/materials/nodes/NodeMaterial.js | 9 +
.../material/getAlphaHashThreshold.js | 64 +++++++
test/e2e/puppeteer.js | 1 +
6 files changed, 247 insertions(+)
create mode 100644 examples/screenshots/webgpu_materials_alphahash.jpg
create mode 100644 examples/webgpu_materials_alphahash.html
create mode 100644 src/nodes/functions/material/getAlphaHashThreshold.js
diff --git a/examples/files.json b/examples/files.json
index 3f2d170f090034..c359ce4b7da78b 100644
--- a/examples/files.json
+++ b/examples/files.json
@@ -350,6 +350,7 @@
"webgpu_loader_gltf_transmission",
"webgpu_loader_materialx",
"webgpu_materials",
+ "webgpu_materials_alphahash",
"webgpu_materials_arrays",
"webgpu_materials_basic",
"webgpu_materials_displacementmap",
diff --git a/examples/screenshots/webgpu_materials_alphahash.jpg b/examples/screenshots/webgpu_materials_alphahash.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..b352584958005bcad91543ecafb5377d74427a83
GIT binary patch
literal 29916
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
+
+
+ three.js webgpu - materials - alpha hash
+
+
+
+
+
+
+
+
+
+
diff --git a/src/materials/nodes/NodeMaterial.js b/src/materials/nodes/NodeMaterial.js
index da5aca91658db3..d5319a8c2b9d7a 100644
--- a/src/materials/nodes/NodeMaterial.js
+++ b/src/materials/nodes/NodeMaterial.js
@@ -22,6 +22,7 @@ import { depth, perspectiveDepthToLogarithmicDepth, viewZToOrthographicDepth } f
import { cameraFar, cameraNear } from '../../nodes/accessors/Camera.js';
import { clipping, clippingAlpha } from '../../nodes/accessors/ClippingNode.js';
import NodeMaterialObserver from './manager/NodeMaterialObserver.js';
+import getAlphaHashThreshold from '../../nodes/functions/material/getAlphaHashThreshold.js';
class NodeMaterial extends Material {
@@ -367,6 +368,14 @@ class NodeMaterial extends Material {
}
+ // ALPHA HASH
+
+ if ( this.alphaHash === true ) {
+
+ diffuseColor.a.lessThan( getAlphaHashThreshold( positionLocal ) ).discard();
+
+ }
+
if ( this.transparent === false && this.blending === NormalBlending && this.alphaToCoverage === false ) {
diffuseColor.a.assign( 1.0 );
diff --git a/src/nodes/functions/material/getAlphaHashThreshold.js b/src/nodes/functions/material/getAlphaHashThreshold.js
new file mode 100644
index 00000000000000..380327af87b26e
--- /dev/null
+++ b/src/nodes/functions/material/getAlphaHashThreshold.js
@@ -0,0 +1,64 @@
+import { abs, add, ceil, clamp, dFdx, dFdy, exp2, float, floor, Fn, fract, length, log2, max, min, mul, sin, sub, vec2, vec3 } from '../../tsl/TSLBase.js';
+
+/**
+ * See: https://casual-effects.com/research/Wyman2017Hashed/index.html
+ */
+
+const ALPHA_HASH_SCALE = 0.05; // Derived from trials only, and may be changed.
+
+const hash2D = /*@__PURE__*/ Fn( ( [ value ] ) => {
+
+ return fract( mul( 1.0e4, sin( mul( 17.0, value.x ).add( mul( 0.1, value.y ) ) ) ).mul( add( 0.1, abs( sin( mul( 13.0, value.y ).add( value.x ) ) ) ) ) );
+
+} );
+
+const hash3D = /*@__PURE__*/ Fn( ( [ value ] ) => {
+
+ return hash2D( vec2( hash2D( value.xy ), value.z ) );
+
+} );
+
+const getAlphaHashThreshold = /*@__PURE__*/ Fn( ( [ position ] ) => {
+
+ // Find the discretized derivatives of our coordinates
+ const maxDeriv = max(
+ length( dFdx( position.xyz ) ),
+ length( dFdy( position.xyz ) )
+ ).toVar( 'maxDeriv' );
+
+ const pixScale = float( 1 ).div( float( ALPHA_HASH_SCALE ).mul( maxDeriv ) ).toVar( 'pixScale' );
+
+ // Find two nearest log-discretized noise scales
+ const pixScales = vec2(
+ exp2( floor( log2( pixScale ) ) ),
+ exp2( ceil( log2( pixScale ) ) )
+ ).toVar( 'pixScales' );
+
+ // Compute alpha thresholds at our two noise scales
+ const alpha = vec2(
+ hash3D( floor( pixScales.x.mul( position.xyz ) ) ),
+ hash3D( floor( pixScales.y.mul( position.xyz ) ) ),
+ ).toVar( 'alpha' );
+
+ // Factor to interpolate lerp with
+ const lerpFactor = fract( log2( pixScale ) ).toVar( 'lerpFactor' );
+
+ // Interpolate alpha threshold from noise at two scales
+ const x = add( mul( lerpFactor.oneMinus(), alpha.x ), mul( lerpFactor, alpha.y ) ).toVar( 'x' );
+
+ // Pass into CDF to compute uniformly distrib threshold
+ const a = min( lerpFactor, lerpFactor.oneMinus() ).toVar( 'a' );
+ const cases = vec3(
+ x.mul( x ).div( mul( 2.0, a ).mul( sub( 1.0, a ) ) ),
+ x.sub( mul( 0.5, a ) ).div( sub( 1.0, a ) ),
+ sub( 1.0, sub( 1.0, x ).mul( sub( 1.0, x ) ).div( mul( 2.0, a ).mul( sub( 1.0, a ) ) ) ) ).toVar( 'cases' );
+
+ // Find our final, uniformly distributed alpha threshold (ατ)
+ const threshold = x.lessThan( a.oneMinus() ).select( x.lessThan( a ).select( cases.x, cases.y ), cases.z );
+
+ // Avoids ατ == 0. Could also do ατ =1-ατ
+ return clamp( threshold, 1.0e-6, 1.0 );
+
+} );
+
+export default getAlphaHashThreshold;
diff --git a/test/e2e/puppeteer.js b/test/e2e/puppeteer.js
index bbe8ac3a8e627d..a49e55c61e941d 100644
--- a/test/e2e/puppeteer.js
+++ b/test/e2e/puppeteer.js
@@ -89,6 +89,7 @@ const exceptionList = [
'webgl_loader_texture_lottie',
'webgl_loader_texture_pvrtc',
'webgl_materials_alphahash',
+ 'webgpu_materials_alphahash',
'webgl_materials_blending',
'webgl_mirror',
'webgl_morphtargets_face',
From b7ae58056b4fa2450fbfdb1ab462fa51ecfadd64 Mon Sep 17 00:00:00 2001
From: Mugen87
Date: Tue, 29 Oct 2024 10:00:24 +0100
Subject: [PATCH 04/18] Updated builds.
---
build/three.cjs | 19 ++++++--
build/three.module.js | 19 ++++++--
build/three.module.min.js | 2 +-
build/three.webgpu.js | 80 +++++++++++++++++++++++++++++++++
build/three.webgpu.min.js | 2 +-
build/three.webgpu.nodes.js | 80 +++++++++++++++++++++++++++++++++
build/three.webgpu.nodes.min.js | 2 +-
7 files changed, 193 insertions(+), 11 deletions(-)
diff --git a/build/three.cjs b/build/three.cjs
index 853b9d84685649..cb8c9344ca122b 100644
--- a/build/three.cjs
+++ b/build/three.cjs
@@ -2603,6 +2603,17 @@ class Vector4 {
}
+ divide( v ) {
+
+ this.x /= v.x;
+ this.y /= v.y;
+ this.z /= v.z;
+ this.w /= v.w;
+
+ return this;
+
+ }
+
divideScalar( scalar ) {
return this.multiplyScalar( 1 / scalar );
@@ -27149,18 +27160,14 @@ class WebXRManager extends EventDispatcher {
//
const cameraL = new PerspectiveCamera();
- cameraL.layers.enable( 1 );
cameraL.viewport = new Vector4();
const cameraR = new PerspectiveCamera();
- cameraR.layers.enable( 2 );
cameraR.viewport = new Vector4();
const cameras = [ cameraL, cameraR ];
const cameraXR = new ArrayCamera();
- cameraXR.layers.enable( 1 );
- cameraXR.layers.enable( 2 );
let _currentDepthNear = null;
let _currentDepthFar = null;
@@ -27670,6 +27677,10 @@ class WebXRManager extends EventDispatcher {
}
+ cameraL.layers.mask = camera.layers.mask | 0b010;
+ cameraR.layers.mask = camera.layers.mask | 0b100;
+ cameraXR.layers.mask = cameraL.layers.mask | cameraR.layers.mask;
+
const parent = camera.parent;
const cameras = cameraXR.cameras;
diff --git a/build/three.module.js b/build/three.module.js
index f30a68e8d6ebf7..6b7ebaedb1a9d4 100644
--- a/build/three.module.js
+++ b/build/three.module.js
@@ -2601,6 +2601,17 @@ class Vector4 {
}
+ divide( v ) {
+
+ this.x /= v.x;
+ this.y /= v.y;
+ this.z /= v.z;
+ this.w /= v.w;
+
+ return this;
+
+ }
+
divideScalar( scalar ) {
return this.multiplyScalar( 1 / scalar );
@@ -27147,18 +27158,14 @@ class WebXRManager extends EventDispatcher {
//
const cameraL = new PerspectiveCamera();
- cameraL.layers.enable( 1 );
cameraL.viewport = new Vector4();
const cameraR = new PerspectiveCamera();
- cameraR.layers.enable( 2 );
cameraR.viewport = new Vector4();
const cameras = [ cameraL, cameraR ];
const cameraXR = new ArrayCamera();
- cameraXR.layers.enable( 1 );
- cameraXR.layers.enable( 2 );
let _currentDepthNear = null;
let _currentDepthFar = null;
@@ -27668,6 +27675,10 @@ class WebXRManager extends EventDispatcher {
}
+ cameraL.layers.mask = camera.layers.mask | 0b010;
+ cameraR.layers.mask = camera.layers.mask | 0b100;
+ cameraXR.layers.mask = cameraL.layers.mask | cameraR.layers.mask;
+
const parent = camera.parent;
const cameras = cameraXR.cameras;
diff --git a/build/three.module.min.js b/build/three.module.min.js
index 24c774990d54b5..e10f5891fa1ac7 100644
--- a/build/three.module.min.js
+++ b/build/three.module.min.js
@@ -3,4 +3,4 @@
* Copyright 2010-2024 Three.js Authors
* SPDX-License-Identifier: MIT
*/
-const t="170dev",e={LEFT:0,MIDDLE:1,RIGHT:2,ROTATE:0,DOLLY:1,PAN:2},n={ROTATE:0,PAN:1,DOLLY_PAN:2,DOLLY_ROTATE:3},i=0,r=1,s=2,a=3,o=0,l=1,c=2,h=3,u=0,d=1,p=2,m=0,f=1,g=2,v=3,_=4,x=5,y=100,M=101,S=102,b=103,T=104,w=200,E=201,A=202,R=203,C=204,I=205,P=206,L=207,U=208,D=209,N=210,O=211,F=212,B=213,z=214,V=0,k=1,H=2,G=3,W=4,X=5,j=6,q=7,Y=0,Z=1,J=2,K=0,$=1,Q=2,tt=3,et=4,nt=5,it=6,rt=7,st="attached",at="detached",ot=300,lt=301,ct=302,ht=303,ut=304,dt=306,pt=1e3,mt=1001,ft=1002,gt=1003,vt=1004,_t=1004,xt=1005,yt=1005,Mt=1006,St=1007,bt=1007,Tt=1008,wt=1008,Et=1009,At=1010,Rt=1011,Ct=1012,It=1013,Pt=1014,Lt=1015,Ut=1016,Dt=1017,Nt=1018,Ot=1020,Ft=35902,Bt=1021,zt=1022,Vt=1023,kt=1024,Ht=1025,Gt=1026,Wt=1027,Xt=1028,jt=1029,qt=1030,Yt=1031,Zt=1032,Jt=1033,Kt=33776,$t=33777,Qt=33778,te=33779,ee=35840,ne=35841,ie=35842,re=35843,se=36196,ae=37492,oe=37496,le=37808,ce=37809,he=37810,ue=37811,de=37812,pe=37813,me=37814,fe=37815,ge=37816,ve=37817,_e=37818,xe=37819,ye=37820,Me=37821,Se=36492,be=36494,Te=36495,we=36283,Ee=36284,Ae=36285,Re=36286,Ce=2200,Ie=2201,Pe=2202,Le=2300,Ue=2301,De=2302,Ne=2400,Oe=2401,Fe=2402,Be=2500,ze=2501,Ve=0,ke=1,He=2,Ge=3200,We=3201,Xe=3202,je=3203,qe=0,Ye=1,Ze="",Je="srgb",Ke="srgb-linear",$e="linear",Qe="srgb",tn=0,en=7680,nn=7681,rn=7682,sn=7683,an=34055,on=34056,ln=5386,cn=512,hn=513,un=514,dn=515,pn=516,mn=517,fn=518,gn=519,vn=512,_n=513,xn=514,yn=515,Mn=516,Sn=517,bn=518,Tn=519,wn=35044,En=35048,An=35040,Rn=35045,Cn=35049,In=35041,Pn=35046,Ln=35050,Un=35042,Dn="100",Nn="300 es",On=2e3,Fn=2001;class Bn{addEventListener(t,e){void 0===this._listeners&&(this._listeners={});const n=this._listeners;void 0===n[t]&&(n[t]=[]),-1===n[t].indexOf(e)&&n[t].push(e)}hasEventListener(t,e){if(void 0===this._listeners)return!1;const n=this._listeners;return void 0!==n[t]&&-1!==n[t].indexOf(e)}removeEventListener(t,e){if(void 0===this._listeners)return;const n=this._listeners[t];if(void 0!==n){const t=n.indexOf(e);-1!==t&&n.splice(t,1)}}dispatchEvent(t){if(void 0===this._listeners)return;const e=this._listeners[t.type];if(void 0!==e){t.target=this;const n=e.slice(0);for(let e=0,i=n.length;e>8&255]+zn[t>>16&255]+zn[t>>24&255]+"-"+zn[255&e]+zn[e>>8&255]+"-"+zn[e>>16&15|64]+zn[e>>24&255]+"-"+zn[63&n|128]+zn[n>>8&255]+"-"+zn[n>>16&255]+zn[n>>24&255]+zn[255&i]+zn[i>>8&255]+zn[i>>16&255]+zn[i>>24&255]).toLowerCase()}function Wn(t,e,n){return Math.max(e,Math.min(n,t))}function Xn(t,e){return(t%e+e)%e}function jn(t,e,n){return(1-n)*t+n*e}function qn(t,e){switch(e.constructor){case Float32Array:return t;case Uint32Array:return t/4294967295;case Uint16Array:return t/65535;case Uint8Array:return t/255;case Int32Array:return Math.max(t/2147483647,-1);case Int16Array:return Math.max(t/32767,-1);case Int8Array:return Math.max(t/127,-1);default:throw new Error("Invalid component type.")}}function Yn(t,e){switch(e.constructor){case Float32Array:return t;case Uint32Array:return Math.round(4294967295*t);case Uint16Array:return Math.round(65535*t);case Uint8Array:return Math.round(255*t);case Int32Array:return Math.round(2147483647*t);case Int16Array:return Math.round(32767*t);case Int8Array:return Math.round(127*t);default:throw new Error("Invalid component type.")}}const Zn={DEG2RAD:kn,RAD2DEG:Hn,generateUUID:Gn,clamp:Wn,euclideanModulo:Xn,mapLinear:function(t,e,n,i,r){return i+(t-e)*(r-i)/(n-e)},inverseLerp:function(t,e,n){return t!==e?(n-t)/(e-t):0},lerp:jn,damp:function(t,e,n,i){return jn(t,e,1-Math.exp(-n*i))},pingpong:function(t,e=1){return e-Math.abs(Xn(t,2*e)-e)},smoothstep:function(t,e,n){return t<=e?0:t>=n?1:(t=(t-e)/(n-e))*t*(3-2*t)},smootherstep:function(t,e,n){return t<=e?0:t>=n?1:(t=(t-e)/(n-e))*t*t*(t*(6*t-15)+10)},randInt:function(t,e){return t+Math.floor(Math.random()*(e-t+1))},randFloat:function(t,e){return t+Math.random()*(e-t)},randFloatSpread:function(t){return t*(.5-Math.random())},seededRandom:function(t){void 0!==t&&(Vn=t);let e=Vn+=1831565813;return e=Math.imul(e^e>>>15,1|e),e^=e+Math.imul(e^e>>>7,61|e),((e^e>>>14)>>>0)/4294967296},degToRad:function(t){return t*kn},radToDeg:function(t){return t*Hn},isPowerOfTwo:function(t){return 0==(t&t-1)&&0!==t},ceilPowerOfTwo:function(t){return Math.pow(2,Math.ceil(Math.log(t)/Math.LN2))},floorPowerOfTwo:function(t){return Math.pow(2,Math.floor(Math.log(t)/Math.LN2))},setQuaternionFromProperEuler:function(t,e,n,i,r){const s=Math.cos,a=Math.sin,o=s(n/2),l=a(n/2),c=s((e+i)/2),h=a((e+i)/2),u=s((e-i)/2),d=a((e-i)/2),p=s((i-e)/2),m=a((i-e)/2);switch(r){case"XYX":t.set(o*h,l*u,l*d,o*c);break;case"YZY":t.set(l*d,o*h,l*u,o*c);break;case"ZXZ":t.set(l*u,l*d,o*h,o*c);break;case"XZX":t.set(o*h,l*m,l*p,o*c);break;case"YXY":t.set(l*p,o*h,l*m,o*c);break;case"ZYZ":t.set(l*m,l*p,o*h,o*c);break;default:console.warn("THREE.MathUtils: .setQuaternionFromProperEuler() encountered an unknown order: "+r)}},normalize:Yn,denormalize:qn};class Jn{constructor(t=0,e=0){Jn.prototype.isVector2=!0,this.x=t,this.y=e}get width(){return this.x}set width(t){this.x=t}get height(){return this.y}set height(t){this.y=t}set(t,e){return this.x=t,this.y=e,this}setScalar(t){return this.x=t,this.y=t,this}setX(t){return this.x=t,this}setY(t){return this.y=t,this}setComponent(t,e){switch(t){case 0:this.x=e;break;case 1:this.y=e;break;default:throw new Error("index is out of range: "+t)}return this}getComponent(t){switch(t){case 0:return this.x;case 1:return this.y;default:throw new Error("index is out of range: "+t)}}clone(){return new this.constructor(this.x,this.y)}copy(t){return this.x=t.x,this.y=t.y,this}add(t){return this.x+=t.x,this.y+=t.y,this}addScalar(t){return this.x+=t,this.y+=t,this}addVectors(t,e){return this.x=t.x+e.x,this.y=t.y+e.y,this}addScaledVector(t,e){return this.x+=t.x*e,this.y+=t.y*e,this}sub(t){return this.x-=t.x,this.y-=t.y,this}subScalar(t){return this.x-=t,this.y-=t,this}subVectors(t,e){return this.x=t.x-e.x,this.y=t.y-e.y,this}multiply(t){return this.x*=t.x,this.y*=t.y,this}multiplyScalar(t){return this.x*=t,this.y*=t,this}divide(t){return this.x/=t.x,this.y/=t.y,this}divideScalar(t){return this.multiplyScalar(1/t)}applyMatrix3(t){const e=this.x,n=this.y,i=t.elements;return this.x=i[0]*e+i[3]*n+i[6],this.y=i[1]*e+i[4]*n+i[7],this}min(t){return this.x=Math.min(this.x,t.x),this.y=Math.min(this.y,t.y),this}max(t){return this.x=Math.max(this.x,t.x),this.y=Math.max(this.y,t.y),this}clamp(t,e){return this.x=Math.max(t.x,Math.min(e.x,this.x)),this.y=Math.max(t.y,Math.min(e.y,this.y)),this}clampScalar(t,e){return this.x=Math.max(t,Math.min(e,this.x)),this.y=Math.max(t,Math.min(e,this.y)),this}clampLength(t,e){const n=this.length();return this.divideScalar(n||1).multiplyScalar(Math.max(t,Math.min(e,n)))}floor(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this}ceil(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this}round(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this}roundToZero(){return this.x=Math.trunc(this.x),this.y=Math.trunc(this.y),this}negate(){return this.x=-this.x,this.y=-this.y,this}dot(t){return this.x*t.x+this.y*t.y}cross(t){return this.x*t.y-this.y*t.x}lengthSq(){return this.x*this.x+this.y*this.y}length(){return Math.sqrt(this.x*this.x+this.y*this.y)}manhattanLength(){return Math.abs(this.x)+Math.abs(this.y)}normalize(){return this.divideScalar(this.length()||1)}angle(){return Math.atan2(-this.y,-this.x)+Math.PI}angleTo(t){const e=Math.sqrt(this.lengthSq()*t.lengthSq());if(0===e)return Math.PI/2;const n=this.dot(t)/e;return Math.acos(Wn(n,-1,1))}distanceTo(t){return Math.sqrt(this.distanceToSquared(t))}distanceToSquared(t){const e=this.x-t.x,n=this.y-t.y;return e*e+n*n}manhattanDistanceTo(t){return Math.abs(this.x-t.x)+Math.abs(this.y-t.y)}setLength(t){return this.normalize().multiplyScalar(t)}lerp(t,e){return this.x+=(t.x-this.x)*e,this.y+=(t.y-this.y)*e,this}lerpVectors(t,e,n){return this.x=t.x+(e.x-t.x)*n,this.y=t.y+(e.y-t.y)*n,this}equals(t){return t.x===this.x&&t.y===this.y}fromArray(t,e=0){return this.x=t[e],this.y=t[e+1],this}toArray(t=[],e=0){return t[e]=this.x,t[e+1]=this.y,t}fromBufferAttribute(t,e){return this.x=t.getX(e),this.y=t.getY(e),this}rotateAround(t,e){const n=Math.cos(e),i=Math.sin(e),r=this.x-t.x,s=this.y-t.y;return this.x=r*n-s*i+t.x,this.y=r*i+s*n+t.y,this}random(){return this.x=Math.random(),this.y=Math.random(),this}*[Symbol.iterator](){yield this.x,yield this.y}}class Kn{constructor(t,e,n,i,r,s,a,o,l){Kn.prototype.isMatrix3=!0,this.elements=[1,0,0,0,1,0,0,0,1],void 0!==t&&this.set(t,e,n,i,r,s,a,o,l)}set(t,e,n,i,r,s,a,o,l){const c=this.elements;return c[0]=t,c[1]=i,c[2]=a,c[3]=e,c[4]=r,c[5]=o,c[6]=n,c[7]=s,c[8]=l,this}identity(){return this.set(1,0,0,0,1,0,0,0,1),this}copy(t){const e=this.elements,n=t.elements;return e[0]=n[0],e[1]=n[1],e[2]=n[2],e[3]=n[3],e[4]=n[4],e[5]=n[5],e[6]=n[6],e[7]=n[7],e[8]=n[8],this}extractBasis(t,e,n){return t.setFromMatrix3Column(this,0),e.setFromMatrix3Column(this,1),n.setFromMatrix3Column(this,2),this}setFromMatrix4(t){const e=t.elements;return this.set(e[0],e[4],e[8],e[1],e[5],e[9],e[2],e[6],e[10]),this}multiply(t){return this.multiplyMatrices(this,t)}premultiply(t){return this.multiplyMatrices(t,this)}multiplyMatrices(t,e){const n=t.elements,i=e.elements,r=this.elements,s=n[0],a=n[3],o=n[6],l=n[1],c=n[4],h=n[7],u=n[2],d=n[5],p=n[8],m=i[0],f=i[3],g=i[6],v=i[1],_=i[4],x=i[7],y=i[2],M=i[5],S=i[8];return r[0]=s*m+a*v+o*y,r[3]=s*f+a*_+o*M,r[6]=s*g+a*x+o*S,r[1]=l*m+c*v+h*y,r[4]=l*f+c*_+h*M,r[7]=l*g+c*x+h*S,r[2]=u*m+d*v+p*y,r[5]=u*f+d*_+p*M,r[8]=u*g+d*x+p*S,this}multiplyScalar(t){const e=this.elements;return e[0]*=t,e[3]*=t,e[6]*=t,e[1]*=t,e[4]*=t,e[7]*=t,e[2]*=t,e[5]*=t,e[8]*=t,this}determinant(){const t=this.elements,e=t[0],n=t[1],i=t[2],r=t[3],s=t[4],a=t[5],o=t[6],l=t[7],c=t[8];return e*s*c-e*a*l-n*r*c+n*a*o+i*r*l-i*s*o}invert(){const t=this.elements,e=t[0],n=t[1],i=t[2],r=t[3],s=t[4],a=t[5],o=t[6],l=t[7],c=t[8],h=c*s-a*l,u=a*o-c*r,d=l*r-s*o,p=e*h+n*u+i*d;if(0===p)return this.set(0,0,0,0,0,0,0,0,0);const m=1/p;return t[0]=h*m,t[1]=(i*l-c*n)*m,t[2]=(a*n-i*s)*m,t[3]=u*m,t[4]=(c*e-i*o)*m,t[5]=(i*r-a*e)*m,t[6]=d*m,t[7]=(n*o-l*e)*m,t[8]=(s*e-n*r)*m,this}transpose(){let t;const e=this.elements;return t=e[1],e[1]=e[3],e[3]=t,t=e[2],e[2]=e[6],e[6]=t,t=e[5],e[5]=e[7],e[7]=t,this}getNormalMatrix(t){return this.setFromMatrix4(t).invert().transpose()}transposeIntoArray(t){const e=this.elements;return t[0]=e[0],t[1]=e[3],t[2]=e[6],t[3]=e[1],t[4]=e[4],t[5]=e[7],t[6]=e[2],t[7]=e[5],t[8]=e[8],this}setUvTransform(t,e,n,i,r,s,a){const o=Math.cos(r),l=Math.sin(r);return this.set(n*o,n*l,-n*(o*s+l*a)+s+t,-i*l,i*o,-i*(-l*s+o*a)+a+e,0,0,1),this}scale(t,e){return this.premultiply($n.makeScale(t,e)),this}rotate(t){return this.premultiply($n.makeRotation(-t)),this}translate(t,e){return this.premultiply($n.makeTranslation(t,e)),this}makeTranslation(t,e){return t.isVector2?this.set(1,0,t.x,0,1,t.y,0,0,1):this.set(1,0,t,0,1,e,0,0,1),this}makeRotation(t){const e=Math.cos(t),n=Math.sin(t);return this.set(e,-n,0,n,e,0,0,0,1),this}makeScale(t,e){return this.set(t,0,0,0,e,0,0,0,1),this}equals(t){const e=this.elements,n=t.elements;for(let t=0;t<9;t++)if(e[t]!==n[t])return!1;return!0}fromArray(t,e=0){for(let n=0;n<9;n++)this.elements[n]=t[n+e];return this}toArray(t=[],e=0){const n=this.elements;return t[e]=n[0],t[e+1]=n[1],t[e+2]=n[2],t[e+3]=n[3],t[e+4]=n[4],t[e+5]=n[5],t[e+6]=n[6],t[e+7]=n[7],t[e+8]=n[8],t}clone(){return(new this.constructor).fromArray(this.elements)}}const $n=new Kn;function Qn(t){for(let e=t.length-1;e>=0;--e)if(t[e]>=65535)return!0;return!1}const ti={Int8Array:Int8Array,Uint8Array:Uint8Array,Uint8ClampedArray:Uint8ClampedArray,Int16Array:Int16Array,Uint16Array:Uint16Array,Int32Array:Int32Array,Uint32Array:Uint32Array,Float32Array:Float32Array,Float64Array:Float64Array};function ei(t,e){return new ti[t](e)}function ni(t){return document.createElementNS("http://www.w3.org/1999/xhtml",t)}function ii(){const t=ni("canvas");return t.style.display="block",t}const ri={};function si(t){t in ri||(ri[t]=!0,console.warn(t))}const ai={enabled:!0,workingColorSpace:Ke,spaces:{},convert:function(t,e,n){return!1!==this.enabled&&e!==n&&e&&n?(this.spaces[e].transfer===Qe&&(t.r=oi(t.r),t.g=oi(t.g),t.b=oi(t.b)),this.spaces[e].primaries!==this.spaces[n].primaries&&(t.applyMatrix3(this.spaces[e].toXYZ),t.applyMatrix3(this.spaces[n].fromXYZ)),this.spaces[n].transfer===Qe&&(t.r=li(t.r),t.g=li(t.g),t.b=li(t.b)),t):t},fromWorkingColorSpace:function(t,e){return this.convert(t,this.workingColorSpace,e)},toWorkingColorSpace:function(t,e){return this.convert(t,e,this.workingColorSpace)},getPrimaries:function(t){return this.spaces[t].primaries},getTransfer:function(t){return t===Ze?$e:this.spaces[t].transfer},getLuminanceCoefficients:function(t,e=this.workingColorSpace){return t.fromArray(this.spaces[e].luminanceCoefficients)},define:function(t){Object.assign(this.spaces,t)},_getMatrix:function(t,e,n){return t.copy(this.spaces[e].toXYZ).multiply(this.spaces[n].fromXYZ)},_getDrawingBufferColorSpace:function(t){return this.spaces[t].outputColorSpaceConfig.drawingBufferColorSpace},_getUnpackColorSpace:function(t=this.workingColorSpace){return this.spaces[t].workingColorSpaceConfig.unpackColorSpace}};function oi(t){return t<.04045?.0773993808*t:Math.pow(.9478672986*t+.0521327014,2.4)}function li(t){return t<.0031308?12.92*t:1.055*Math.pow(t,.41666)-.055}const ci=[.64,.33,.3,.6,.15,.06],hi=[.2126,.7152,.0722],ui=[.3127,.329],di=(new Kn).set(.4123908,.3575843,.1804808,.212639,.7151687,.0721923,.0193308,.1191948,.9505322),pi=(new Kn).set(3.2409699,-1.5373832,-.4986108,-.9692436,1.8759675,.0415551,.0556301,-.203977,1.0569715);let mi;ai.define({[Ke]:{primaries:ci,whitePoint:ui,transfer:$e,toXYZ:di,fromXYZ:pi,luminanceCoefficients:hi,workingColorSpaceConfig:{unpackColorSpace:Je},outputColorSpaceConfig:{drawingBufferColorSpace:Je}},[Je]:{primaries:ci,whitePoint:ui,transfer:Qe,toXYZ:di,fromXYZ:pi,luminanceCoefficients:hi,outputColorSpaceConfig:{drawingBufferColorSpace:Je}}});class fi{static getDataURL(t){if(/^data:/i.test(t.src))return t.src;if("undefined"==typeof HTMLCanvasElement)return t.src;let e;if(t instanceof HTMLCanvasElement)e=t;else{void 0===mi&&(mi=ni("canvas")),mi.width=t.width,mi.height=t.height;const n=mi.getContext("2d");t instanceof ImageData?n.putImageData(t,0,0):n.drawImage(t,0,0,t.width,t.height),e=mi}return e.width>2048||e.height>2048?(console.warn("THREE.ImageUtils.getDataURL: Image converted to jpg for performance reasons",t),e.toDataURL("image/jpeg",.6)):e.toDataURL("image/png")}static sRGBToLinear(t){if("undefined"!=typeof HTMLImageElement&&t instanceof HTMLImageElement||"undefined"!=typeof HTMLCanvasElement&&t instanceof HTMLCanvasElement||"undefined"!=typeof ImageBitmap&&t instanceof ImageBitmap){const e=ni("canvas");e.width=t.width,e.height=t.height;const n=e.getContext("2d");n.drawImage(t,0,0,t.width,t.height);const i=n.getImageData(0,0,t.width,t.height),r=i.data;for(let t=0;t