3d-force-graph 1.77.1 → 1.78.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- // Version 1.77.1 3d-force-graph - https://github.com/vasturiano/3d-force-graph
1
+ // Version 1.78.1 3d-force-graph - https://github.com/vasturiano/3d-force-graph
2
2
  (function (global, factory) {
3
3
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
4
4
  typeof define === 'function' && define.amd ? define(factory) :
@@ -108,7 +108,7 @@
108
108
  * Copyright 2010-2025 Three.js Authors
109
109
  * SPDX-License-Identifier: MIT
110
110
  */
111
- const REVISION = '177';
111
+ const REVISION = '178';
112
112
 
113
113
  /**
114
114
  * Represents mouse buttons and interaction types in context of controls.
@@ -3704,7 +3704,7 @@
3704
3704
 
3705
3705
  let r = vFrom.dot( vTo ) + 1;
3706
3706
 
3707
- if ( r < Number.EPSILON ) {
3707
+ if ( r < 1e-8 ) { // the epsilon value has been discussed in #31286
3708
3708
 
3709
3709
  // vFrom and vTo point in opposite directions
3710
3710
 
@@ -12919,7 +12919,7 @@
12919
12919
  const _childaddedEvent = { type: 'childadded', child: null };
12920
12920
 
12921
12921
  /**
12922
- * Fires when a new child object has been added.
12922
+ * Fires when a child object has been removed.
12923
12923
  *
12924
12924
  * @event Object3D#childremoved
12925
12925
  * @type {Object}
@@ -17480,7 +17480,7 @@
17480
17480
  /**
17481
17481
  * Applies to integer data only. Indicates how the underlying data in the buffer maps to
17482
17482
  * the values in the GLSL code. For instance, if `array` is an instance of `UInt16Array`,
17483
- * and `normalized` is `true`, the values `0 -+65535` in the array data will be mapped to
17483
+ * and `normalized` is `true`, the values `0 - +65535` in the array data will be mapped to
17484
17484
  * `0.0f - +1.0f` in the GLSL attribute. If `normalized` is `false`, the values will be converted
17485
17485
  * to floats unmodified, i.e. `65535` becomes `65535.0f`.
17486
17486
  *
@@ -18118,8 +18118,8 @@
18118
18118
  * Convenient class that can be used when creating a `Float16` buffer attribute with
18119
18119
  * a plain `Array` instance.
18120
18120
  *
18121
- * This class automatically converts to and from FP16 since `Float16Array` is not
18122
- * natively supported in JavaScript.
18121
+ * This class automatically converts to and from FP16 via `Uint16Array` since `Float16Array`
18122
+ * browser support is still problematic.
18123
18123
  *
18124
18124
  * @augments BufferAttribute
18125
18125
  */
@@ -24013,6 +24013,7 @@
24013
24013
  }
24014
24014
 
24015
24015
  const _sphere$3 = /*@__PURE__*/ new Sphere();
24016
+ const _defaultSpriteCenter = /*@__PURE__*/ new Vector2( 0.5, 0.5 );
24016
24017
  const _vector$6 = /*@__PURE__*/ new Vector3();
24017
24018
 
24018
24019
  /**
@@ -24170,7 +24171,10 @@
24170
24171
  intersectsSprite( sprite ) {
24171
24172
 
24172
24173
  _sphere$3.center.set( 0, 0, 0 );
24173
- _sphere$3.radius = 0.7071067811865476;
24174
+
24175
+ const offset = _defaultSpriteCenter.distanceTo( sprite.center );
24176
+
24177
+ _sphere$3.radius = 0.7071067811865476 + offset;
24174
24178
  _sphere$3.applyMatrix4( sprite.matrixWorld );
24175
24179
 
24176
24180
  return this.intersectsSphere( _sphere$3 );
@@ -31768,6 +31772,8 @@
31768
31772
  */
31769
31773
  Loader.DEFAULT_MATERIAL_NAME = '__DEFAULT';
31770
31774
 
31775
+ const _loading = new WeakMap();
31776
+
31771
31777
  /**
31772
31778
  * A loader for loading images. The class loads images with the HTML `Image` API.
31773
31779
  *
@@ -31814,19 +31820,36 @@
31814
31820
 
31815
31821
  const scope = this;
31816
31822
 
31817
- const cached = Cache.get( url );
31823
+ const cached = Cache.get( `image:${url}` );
31818
31824
 
31819
31825
  if ( cached !== undefined ) {
31820
31826
 
31821
- scope.manager.itemStart( url );
31827
+ if ( cached.complete === true ) {
31828
+
31829
+ scope.manager.itemStart( url );
31830
+
31831
+ setTimeout( function () {
31832
+
31833
+ if ( onLoad ) onLoad( cached );
31834
+
31835
+ scope.manager.itemEnd( url );
31836
+
31837
+ }, 0 );
31822
31838
 
31823
- setTimeout( function () {
31839
+ } else {
31840
+
31841
+ let arr = _loading.get( cached );
31824
31842
 
31825
- if ( onLoad ) onLoad( cached );
31843
+ if ( arr === undefined ) {
31826
31844
 
31827
- scope.manager.itemEnd( url );
31845
+ arr = [];
31846
+ _loading.set( cached, arr );
31828
31847
 
31829
- }, 0 );
31848
+ }
31849
+
31850
+ arr.push( { onLoad, onError } );
31851
+
31852
+ }
31830
31853
 
31831
31854
  return cached;
31832
31855
 
@@ -31838,10 +31861,21 @@
31838
31861
 
31839
31862
  removeEventListeners();
31840
31863
 
31841
- Cache.add( url, this );
31842
-
31843
31864
  if ( onLoad ) onLoad( this );
31844
31865
 
31866
+ //
31867
+
31868
+ const callbacks = _loading.get( this ) || [];
31869
+
31870
+ for ( let i = 0; i < callbacks.length; i ++ ) {
31871
+
31872
+ const callback = callbacks[ i ];
31873
+ if ( callback.onLoad ) callback.onLoad( this );
31874
+
31875
+ }
31876
+
31877
+ _loading.delete( this );
31878
+
31845
31879
  scope.manager.itemEnd( url );
31846
31880
 
31847
31881
  }
@@ -31852,6 +31886,22 @@
31852
31886
 
31853
31887
  if ( onError ) onError( event );
31854
31888
 
31889
+ Cache.remove( `image:${url}` );
31890
+
31891
+ //
31892
+
31893
+ const callbacks = _loading.get( this ) || [];
31894
+
31895
+ for ( let i = 0; i < callbacks.length; i ++ ) {
31896
+
31897
+ const callback = callbacks[ i ];
31898
+ if ( callback.onError ) callback.onError( event );
31899
+
31900
+ }
31901
+
31902
+ _loading.delete( this );
31903
+
31904
+
31855
31905
  scope.manager.itemError( url );
31856
31906
  scope.manager.itemEnd( url );
31857
31907
 
@@ -31873,6 +31923,7 @@
31873
31923
 
31874
31924
  }
31875
31925
 
31926
+ Cache.add( `image:${url}`, image );
31876
31927
  scope.manager.itemStart( url );
31877
31928
 
31878
31929
  image.src = url;
@@ -33937,7 +33988,7 @@
33937
33988
  */
33938
33989
  start() {
33939
33990
 
33940
- this.startTime = now$3();
33991
+ this.startTime = performance.now();
33941
33992
 
33942
33993
  this.oldTime = this.startTime;
33943
33994
  this.elapsedTime = 0;
@@ -33986,7 +34037,7 @@
33986
34037
 
33987
34038
  if ( this.running ) {
33988
34039
 
33989
- const newTime = now$3();
34040
+ const newTime = performance.now();
33990
34041
 
33991
34042
  diff = ( newTime - this.oldTime ) / 1000;
33992
34043
  this.oldTime = newTime;
@@ -34001,12 +34052,6 @@
34001
34052
 
34002
34053
  }
34003
34054
 
34004
- function now$3() {
34005
-
34006
- return performance.now();
34007
-
34008
- }
34009
-
34010
34055
  /**
34011
34056
  * An instanced version of an interleaved buffer.
34012
34057
  *
@@ -34957,6 +35002,10 @@
34957
35002
 
34958
35003
  type = gl.FLOAT;
34959
35004
 
35005
+ } else if ( typeof Float16Array !== 'undefined' && array instanceof Float16Array ) {
35006
+
35007
+ type = gl.HALF_FLOAT;
35008
+
34960
35009
  } else if ( array instanceof Uint16Array ) {
34961
35010
 
34962
35011
  if ( attribute.isFloat16BufferAttribute ) {
@@ -41934,7 +41983,7 @@
41934
41983
  useFog: material.fog === true,
41935
41984
  fogExp2: ( !! fog && fog.isFogExp2 ),
41936
41985
 
41937
- flatShading: material.flatShading === true,
41986
+ flatShading: ( material.flatShading === true && material.wireframe === false ),
41938
41987
 
41939
41988
  sizeAttenuation: material.sizeAttenuation === true,
41940
41989
  logarithmicDepthBuffer: logarithmicDepthBuffer,
@@ -42147,6 +42196,8 @@
42147
42196
  _programLayers.enable( 20 );
42148
42197
  if ( parameters.batchingColor )
42149
42198
  _programLayers.enable( 21 );
42199
+ if ( parameters.gradientMap )
42200
+ _programLayers.enable( 22 );
42150
42201
 
42151
42202
  array.push( _programLayers.mask );
42152
42203
  _programLayers.disableAll();
@@ -44328,7 +44379,7 @@
44328
44379
  break;
44329
44380
 
44330
44381
  case MultiplyBlending:
44331
- gl.blendFuncSeparate( gl.ZERO, gl.SRC_COLOR, gl.ZERO, gl.SRC_ALPHA );
44382
+ gl.blendFuncSeparate( gl.DST_COLOR, gl.ONE_MINUS_SRC_ALPHA, gl.ZERO, gl.ONE );
44332
44383
  break;
44333
44384
 
44334
44385
  default:
@@ -44346,15 +44397,15 @@
44346
44397
  break;
44347
44398
 
44348
44399
  case AdditiveBlending:
44349
- gl.blendFunc( gl.SRC_ALPHA, gl.ONE );
44400
+ gl.blendFuncSeparate( gl.SRC_ALPHA, gl.ONE, gl.ONE, gl.ONE );
44350
44401
  break;
44351
44402
 
44352
44403
  case SubtractiveBlending:
44353
- gl.blendFuncSeparate( gl.ZERO, gl.ONE_MINUS_SRC_COLOR, gl.ZERO, gl.ONE );
44404
+ console.error( 'THREE.WebGLState: SubtractiveBlending requires material.premultipliedAlpha = true' );
44354
44405
  break;
44355
44406
 
44356
44407
  case MultiplyBlending:
44357
- gl.blendFunc( gl.ZERO, gl.SRC_COLOR );
44408
+ console.error( 'THREE.WebGLState: MultiplyBlending requires material.premultipliedAlpha = true' );
44358
44409
  break;
44359
44410
 
44360
44411
  default:
@@ -51489,6 +51540,9 @@ void main() {
51489
51540
  //
51490
51541
 
51491
51542
  const currentRenderTarget = _this.getRenderTarget();
51543
+ const currentActiveCubeFace = _this.getActiveCubeFace();
51544
+ const currentActiveMipmapLevel = _this.getActiveMipmapLevel();
51545
+
51492
51546
  _this.setRenderTarget( transmissionRenderTarget );
51493
51547
 
51494
51548
  _this.getClearColor( _currentClearColor );
@@ -51558,7 +51612,7 @@ void main() {
51558
51612
 
51559
51613
  }
51560
51614
 
51561
- _this.setRenderTarget( currentRenderTarget );
51615
+ _this.setRenderTarget( currentRenderTarget, currentActiveCubeFace, currentActiveMipmapLevel );
51562
51616
 
51563
51617
  _this.setClearColor( _currentClearColor, _currentClearAlpha );
51564
51618
 
@@ -52488,7 +52542,7 @@ void main() {
52488
52542
 
52489
52543
  if ( ( x >= 0 && x <= ( renderTarget.width - width ) ) && ( y >= 0 && y <= ( renderTarget.height - height ) ) ) {
52490
52544
 
52491
- // when using MRT, select the corect color buffer for the subsequent read command
52545
+ // when using MRT, select the correct color buffer for the subsequent read command
52492
52546
 
52493
52547
  if ( renderTarget.textures.length > 1 ) _gl.readBuffer( _gl.COLOR_ATTACHMENT0 + textureIndex );
52494
52548
 
@@ -60879,6 +60933,11 @@ function InsertStackElement(node, body) {
60879
60933
  triggerUpdate: false
60880
60934
  },
60881
60935
  // in link length ratio per frame
60936
+ linkDirectionalParticleOffset: {
60937
+ "default": 0,
60938
+ triggerUpdate: false
60939
+ },
60940
+ // starting position offset along the link's length, like a pre-delay. Values between [0, 1]
60882
60941
  linkDirectionalParticleWidth: {
60883
60942
  "default": 0.5
60884
60943
  },
@@ -60887,6 +60946,7 @@ function InsertStackElement(node, body) {
60887
60946
  "default": 4
60888
60947
  },
60889
60948
  // how many slice segments in the particle sphere's circumference
60949
+ linkDirectionalParticleThreeObject: {},
60890
60950
  forceEngine: {
60891
60951
  "default": 'd3'
60892
60952
  },
@@ -61229,6 +61289,7 @@ function InsertStackElement(node, body) {
61229
61289
  function updatePhotons() {
61230
61290
  // update link particle positions
61231
61291
  var particleSpeedAccessor = index$1(state.linkDirectionalParticleSpeed);
61292
+ var particleOffsetAccessor = index$1(state.linkDirectionalParticleOffset);
61232
61293
  state.graphData.links.forEach(function (link) {
61233
61294
  var photonsObj = state.particlesDataMapper.getObj(link);
61234
61295
  var cyclePhotons = photonsObj && photonsObj.children;
@@ -61240,6 +61301,7 @@ function InsertStackElement(node, body) {
61240
61301
  if (!start || !end || !start.hasOwnProperty('x') || !end.hasOwnProperty('x')) return; // skip invalid link
61241
61302
 
61242
61303
  var particleSpeed = particleSpeedAccessor(link);
61304
+ var particleOffset = Math.abs(particleOffsetAccessor(link));
61243
61305
  var getPhotonPos = link.__curve ? function (t) {
61244
61306
  return link.__curve.getPoint(t);
61245
61307
  } // interpolate along bezier curve
@@ -61258,7 +61320,7 @@ function InsertStackElement(node, body) {
61258
61320
  photons.forEach(function (photon, idx) {
61259
61321
  var singleHop = photon.parent.__linkThreeObjType === 'singleHopPhotons';
61260
61322
  if (!photon.hasOwnProperty('__progressRatio')) {
61261
- photon.__progressRatio = singleHop ? 0 : idx / cyclePhotons.length;
61323
+ photon.__progressRatio = singleHop ? 0 : (idx + particleOffset) / cyclePhotons.length;
61262
61324
  }
61263
61325
  photon.__progressRatio += particleSpeed;
61264
61326
  if (photon.__progressRatio >= 1) {
@@ -61273,6 +61335,9 @@ function InsertStackElement(node, body) {
61273
61335
  }
61274
61336
  var photonPosRatio = photon.__progressRatio;
61275
61337
  var pos = getPhotonPos(photonPosRatio);
61338
+
61339
+ // Orient asymmetrical particles to target
61340
+ photon.geometry.type !== 'SphereGeometry' && photon.lookAt(pos.x, pos.y, pos.z);
61276
61341
  ['x', 'y', 'z'].forEach(function (dim) {
61277
61342
  return photon.position[dim] = pos[dim];
61278
61343
  });
@@ -61288,23 +61353,31 @@ function InsertStackElement(node, body) {
61288
61353
  link.__singleHopPhotonsObj = obj;
61289
61354
  state.graphScene.add(obj);
61290
61355
  }
61291
- var particleWidthAccessor = index$1(state.linkDirectionalParticleWidth);
61292
- var photonR = Math.ceil(particleWidthAccessor(link) * 10) / 10 / 2;
61293
- var numSegments = state.linkDirectionalParticleResolution;
61294
- var particleGeometry = new three$1$1.SphereGeometry(photonR, numSegments, numSegments);
61295
- var linkColorAccessor = index$1(state.linkColor);
61296
- var particleColorAccessor = index$1(state.linkDirectionalParticleColor);
61297
- var photonColor = particleColorAccessor(link) || linkColorAccessor(link) || '#f0f0f0';
61298
- var materialColor = new three$1$1.Color(colorStr2Hex(photonColor));
61299
- var opacity = state.linkOpacity * 3;
61300
- var particleMaterial = new three$1$1.MeshLambertMaterial({
61301
- color: materialColor,
61302
- transparent: true,
61303
- opacity: opacity
61304
- });
61356
+ var particleObj = index$1(state.linkDirectionalParticleThreeObject)(link);
61357
+ if (particleObj && state.linkDirectionalParticleThreeObject === particleObj) {
61358
+ // clone object if it's a shared object among all links
61359
+ particleObj = particleObj.clone();
61360
+ }
61361
+ if (!particleObj) {
61362
+ var particleWidthAccessor = index$1(state.linkDirectionalParticleWidth);
61363
+ var photonR = Math.ceil(particleWidthAccessor(link) * 10) / 10 / 2;
61364
+ var numSegments = state.linkDirectionalParticleResolution;
61365
+ var particleGeometry = new three$1$1.SphereGeometry(photonR, numSegments, numSegments);
61366
+ var linkColorAccessor = index$1(state.linkColor);
61367
+ var particleColorAccessor = index$1(state.linkDirectionalParticleColor);
61368
+ var photonColor = particleColorAccessor(link) || linkColorAccessor(link) || '#f0f0f0';
61369
+ var materialColor = new three$1$1.Color(colorStr2Hex(photonColor));
61370
+ var opacity = state.linkOpacity * 3;
61371
+ var particleMaterial = new three$1$1.MeshLambertMaterial({
61372
+ color: materialColor,
61373
+ transparent: true,
61374
+ opacity: opacity
61375
+ });
61376
+ particleObj = new three$1$1.Mesh(particleGeometry, particleMaterial);
61377
+ }
61305
61378
 
61306
61379
  // add a single hop particle
61307
- link.__singleHopPhotonsObj.add(new three$1$1.Mesh(particleGeometry, particleMaterial));
61380
+ link.__singleHopPhotonsObj.add(particleObj);
61308
61381
  }
61309
61382
  return this;
61310
61383
  },
@@ -61445,7 +61518,7 @@ function InsertStackElement(node, body) {
61445
61518
  }
61446
61519
 
61447
61520
  // Digest links WebGL objects
61448
- if (state._flushObjects || hasAnyPropChanged(['graphData', 'linkThreeObject', 'linkThreeObjectExtend', 'linkMaterial', 'linkColor', 'linkWidth', 'linkVisibility', 'linkResolution', 'linkOpacity', 'linkDirectionalArrowLength', 'linkDirectionalArrowColor', 'linkDirectionalArrowResolution', 'linkDirectionalParticles', 'linkDirectionalParticleWidth', 'linkDirectionalParticleColor', 'linkDirectionalParticleResolution'])) {
61521
+ if (state._flushObjects || hasAnyPropChanged(['graphData', 'linkThreeObject', 'linkThreeObjectExtend', 'linkMaterial', 'linkColor', 'linkWidth', 'linkVisibility', 'linkResolution', 'linkOpacity', 'linkDirectionalArrowLength', 'linkDirectionalArrowColor', 'linkDirectionalArrowResolution', 'linkDirectionalParticles', 'linkDirectionalParticleWidth', 'linkDirectionalParticleColor', 'linkDirectionalParticleResolution', 'linkDirectionalParticleThreeObject'])) {
61449
61522
  var _customObjectAccessor = index$1(state.linkThreeObject);
61450
61523
  var _customObjectExtendAccessor = index$1(state.linkThreeObjectExtend);
61451
61524
  var customMaterialAccessor = index$1(state.linkMaterial);
@@ -61590,6 +61663,7 @@ function InsertStackElement(node, body) {
61590
61663
  var particlesAccessor = index$1(state.linkDirectionalParticles);
61591
61664
  var particleWidthAccessor = index$1(state.linkDirectionalParticleWidth);
61592
61665
  var particleColorAccessor = index$1(state.linkDirectionalParticleColor);
61666
+ var particleObjectAccessor = index$1(state.linkDirectionalParticleThreeObject);
61593
61667
  var particleMaterials = {}; // indexed by link color
61594
61668
  var particleGeometries = {}; // indexed by particle width
61595
61669
 
@@ -61600,39 +61674,47 @@ function InsertStackElement(node, body) {
61600
61674
  obj.__photonDataMapper = new ThreeDigest(obj);
61601
61675
  return obj;
61602
61676
  }).onUpdateObj(function (obj, link) {
61603
- var numPhotons = Math.round(Math.abs(particlesAccessor(link)));
61604
61677
  var curPhoton = !!obj.children.length && obj.children[0];
61605
- var photonR = Math.ceil(particleWidthAccessor(link) * 10) / 10 / 2;
61606
- var numSegments = state.linkDirectionalParticleResolution;
61607
- var particleGeometry;
61608
- if (curPhoton && curPhoton.geometry.parameters.radius === photonR && curPhoton.geometry.parameters.widthSegments === numSegments) {
61609
- particleGeometry = curPhoton.geometry;
61678
+ var customObj = particleObjectAccessor(link);
61679
+ var particleGeometry, particleMaterial;
61680
+ if (customObj) {
61681
+ particleGeometry = customObj.geometry;
61682
+ particleMaterial = customObj.material;
61610
61683
  } else {
61611
- if (!particleGeometries.hasOwnProperty(photonR)) {
61612
- particleGeometries[photonR] = new three$1$1.SphereGeometry(photonR, numSegments, numSegments);
61684
+ var photonR = Math.ceil(particleWidthAccessor(link) * 10) / 10 / 2;
61685
+ var numSegments = state.linkDirectionalParticleResolution;
61686
+ if (curPhoton && curPhoton.geometry.parameters.radius === photonR && curPhoton.geometry.parameters.widthSegments === numSegments) {
61687
+ particleGeometry = curPhoton.geometry;
61688
+ } else {
61689
+ if (!particleGeometries.hasOwnProperty(photonR)) {
61690
+ particleGeometries[photonR] = new three$1$1.SphereGeometry(photonR, numSegments, numSegments);
61691
+ }
61692
+ particleGeometry = particleGeometries[photonR];
61613
61693
  }
61614
- particleGeometry = particleGeometries[photonR];
61615
- curPhoton && curPhoton.geometry.dispose();
61616
- }
61617
- var photonColor = particleColorAccessor(link) || _colorAccessor(link) || '#f0f0f0';
61618
- var materialColor = new three$1$1.Color(colorStr2Hex(photonColor));
61619
- var opacity = state.linkOpacity * 3;
61620
- var particleMaterial;
61621
- if (curPhoton && curPhoton.material.color.equals(materialColor) && curPhoton.material.opacity === opacity) {
61622
- particleMaterial = curPhoton.material;
61623
- } else {
61624
- if (!particleMaterials.hasOwnProperty(photonColor)) {
61625
- particleMaterials[photonColor] = new three$1$1.MeshLambertMaterial({
61626
- color: materialColor,
61627
- transparent: true,
61628
- opacity: opacity
61629
- });
61694
+ var photonColor = particleColorAccessor(link) || _colorAccessor(link) || '#f0f0f0';
61695
+ var materialColor = new three$1$1.Color(colorStr2Hex(photonColor));
61696
+ var opacity = state.linkOpacity * 3;
61697
+ if (curPhoton && curPhoton.material.color.equals(materialColor) && curPhoton.material.opacity === opacity) {
61698
+ particleMaterial = curPhoton.material;
61699
+ } else {
61700
+ if (!particleMaterials.hasOwnProperty(photonColor)) {
61701
+ particleMaterials[photonColor] = new three$1$1.MeshLambertMaterial({
61702
+ color: materialColor,
61703
+ transparent: true,
61704
+ opacity: opacity
61705
+ });
61706
+ }
61707
+ particleMaterial = particleMaterials[photonColor];
61630
61708
  }
61631
- particleMaterial = particleMaterials[photonColor];
61632
- curPhoton && curPhoton.material.dispose();
61709
+ }
61710
+ if (curPhoton) {
61711
+ // Dispose of previous particles
61712
+ curPhoton.geometry !== particleGeometry && curPhoton.geometry.dispose();
61713
+ curPhoton.material !== particleMaterial && curPhoton.material.dispose();
61633
61714
  }
61634
61715
 
61635
61716
  // digest cycle for each photon
61717
+ var numPhotons = Math.round(Math.abs(particlesAccessor(link)));
61636
61718
  obj.__photonDataMapper.id(function (d) {
61637
61719
  return d.idx;
61638
61720
  }).onCreateObj(function () {
@@ -63452,7 +63534,7 @@ function InsertStackElement(node, body) {
63452
63534
 
63453
63535
  console.warn( 'THREE.Node: Recursion detected.', this );
63454
63536
 
63455
- result = '';
63537
+ result = '/* Recursion detected. */';
63456
63538
 
63457
63539
  }
63458
63540
 
@@ -64827,7 +64909,7 @@ function InsertStackElement(node, body) {
64827
64909
 
64828
64910
  } else if ( type === 'shader' ) {
64829
64911
 
64830
- return Fn( obj );
64912
+ return obj.isFn ? obj : Fn( obj );
64831
64913
 
64832
64914
  }
64833
64915
 
@@ -64977,16 +65059,22 @@ function InsertStackElement(node, body) {
64977
65059
  const { shaderNode, inputNodes } = this;
64978
65060
 
64979
65061
  const properties = builder.getNodeProperties( shaderNode );
64980
- const onceNS = shaderNode.namespace && shaderNode.namespace === builder.namespace ? builder.getNamespace( 'once' ) : 'once';
64981
65062
 
64982
- if ( properties[ onceNS ] ) {
65063
+ const subBuild = builder.getClosestSubBuild( shaderNode.subBuilds ) || '';
65064
+ const subBuildProperty = subBuild || 'default';
64983
65065
 
64984
- return properties[ onceNS ];
65066
+ if ( properties[ subBuildProperty ] ) {
65067
+
65068
+ return properties[ subBuildProperty ];
64985
65069
 
64986
65070
  }
64987
65071
 
64988
65072
  //
64989
65073
 
65074
+ const previousSubBuildFn = builder.subBuildFn;
65075
+
65076
+ builder.subBuildFn = subBuild;
65077
+
64990
65078
  let result = null;
64991
65079
 
64992
65080
  if ( shaderNode.layout ) {
@@ -65024,9 +65112,11 @@ function InsertStackElement(node, body) {
65024
65112
 
65025
65113
  }
65026
65114
 
65115
+ builder.subBuildFn = previousSubBuildFn;
65116
+
65027
65117
  if ( shaderNode.once ) {
65028
65118
 
65029
- properties[ onceNS ] = result;
65119
+ properties[ subBuildProperty ] = result;
65030
65120
 
65031
65121
  }
65032
65122
 
@@ -65047,11 +65137,12 @@ function InsertStackElement(node, body) {
65047
65137
  getOutputNode( builder ) {
65048
65138
 
65049
65139
  const properties = builder.getNodeProperties( this );
65050
- const outputNamespace = builder.getOutputNamespace();
65140
+ const subBuildOutput = builder.getSubBuildOutput( this );
65051
65141
 
65052
- properties[ outputNamespace ] = properties[ outputNamespace ] || this.setupOutput( builder );
65142
+ properties[ subBuildOutput ] = properties[ subBuildOutput ] || this.setupOutput( builder );
65143
+ properties[ subBuildOutput ].subBuild = builder.getClosestSubBuild( this );
65053
65144
 
65054
- return properties[ outputNamespace ];
65145
+ return properties[ subBuildOutput ];
65055
65146
 
65056
65147
  }
65057
65148
 
@@ -65062,23 +65153,45 @@ function InsertStackElement(node, body) {
65062
65153
  const buildStage = builder.getBuildStage();
65063
65154
  const properties = builder.getNodeProperties( this );
65064
65155
 
65065
- const outputNamespace = builder.getOutputNamespace();
65156
+ const subBuildOutput = builder.getSubBuildOutput( this );
65066
65157
  const outputNode = this.getOutputNode( builder );
65067
65158
 
65068
65159
  if ( buildStage === 'setup' ) {
65069
65160
 
65070
- const initializedNamespace = builder.getNamespace( 'initialized' );
65161
+ const subBuildInitialized = builder.getSubBuildProperty( 'initialized', this );
65162
+
65163
+ if ( properties[ subBuildInitialized ] !== true ) {
65164
+
65165
+ properties[ subBuildInitialized ] = true;
65166
+
65167
+ properties[ subBuildOutput ] = this.getOutputNode( builder );
65168
+ properties[ subBuildOutput ].build( builder );
65071
65169
 
65072
- if ( properties[ initializedNamespace ] !== true ) {
65170
+ // If the shaderNode has subBuilds, add them to the chaining nodes
65171
+ // so they can be built later in the build process.
65073
65172
 
65074
- properties[ initializedNamespace ] = true;
65173
+ if ( this.shaderNode.subBuilds ) {
65075
65174
 
65076
- properties[ outputNamespace ] = this.getOutputNode( builder );
65077
- properties[ outputNamespace ].build( builder );
65175
+ for ( const node of builder.chaining ) {
65176
+
65177
+ const nodeData = builder.getDataFromNode( node, 'any' );
65178
+ nodeData.subBuilds = nodeData.subBuilds || new Set();
65179
+
65180
+ for ( const subBuild of this.shaderNode.subBuilds ) {
65181
+
65182
+ nodeData.subBuilds.add( subBuild );
65183
+
65184
+ }
65185
+
65186
+ //builder.getDataFromNode( node ).subBuilds = nodeData.subBuilds;
65187
+
65188
+ }
65189
+
65190
+ }
65078
65191
 
65079
65192
  }
65080
65193
 
65081
- result = properties[ outputNamespace ];
65194
+ result = properties[ subBuildOutput ];
65082
65195
 
65083
65196
  } else if ( buildStage === 'analyze' ) {
65084
65197
 
@@ -65108,7 +65221,6 @@ function InsertStackElement(node, body) {
65108
65221
  this.global = true;
65109
65222
 
65110
65223
  this.once = false;
65111
- this.namespace = null;
65112
65224
 
65113
65225
  }
65114
65226
 
@@ -65176,20 +65288,6 @@ function InsertStackElement(node, body) {
65176
65288
 
65177
65289
  };
65178
65290
 
65179
- const safeGetNodeType = ( node ) => {
65180
-
65181
- try {
65182
-
65183
- return node.getNodeType();
65184
-
65185
- } catch ( _ ) {
65186
-
65187
- return undefined;
65188
-
65189
- }
65190
-
65191
- };
65192
-
65193
65291
  const ConvertType = function ( type, cacheMap = null ) {
65194
65292
 
65195
65293
  return ( ...params ) => {
@@ -65209,7 +65307,7 @@ function InsertStackElement(node, body) {
65209
65307
  if ( params.length === 1 ) {
65210
65308
 
65211
65309
  const node = getConstNode( params[ 0 ], type );
65212
- if ( safeGetNodeType( node ) === type ) return nodeObject( node );
65310
+ if ( node.nodeType === type ) return nodeObject( node );
65213
65311
  return nodeObject( new ConvertNode( node, type ) );
65214
65312
 
65215
65313
  }
@@ -65304,6 +65402,8 @@ function InsertStackElement(node, body) {
65304
65402
  fn.shaderNode = shaderNode;
65305
65403
  fn.id = shaderNode.id;
65306
65404
 
65405
+ fn.isFn = true;
65406
+
65307
65407
  fn.getNodeType = ( ...params ) => shaderNode.getNodeType( ...params );
65308
65408
  fn.getCacheKey = ( ...params ) => shaderNode.getCacheKey( ...params );
65309
65409
 
@@ -65315,10 +65415,10 @@ function InsertStackElement(node, body) {
65315
65415
 
65316
65416
  };
65317
65417
 
65318
- fn.once = ( namespace = null ) => {
65418
+ fn.once = ( subBuilds = null ) => {
65319
65419
 
65320
65420
  shaderNode.once = true;
65321
- shaderNode.namespace = namespace;
65421
+ shaderNode.subBuilds = subBuilds;
65322
65422
 
65323
65423
  return fn;
65324
65424
 
@@ -67316,22 +67416,6 @@ function InsertStackElement(node, body) {
67316
67416
  addMethodChaining( 'increment', increment );
67317
67417
  addMethodChaining( 'decrement', decrement );
67318
67418
 
67319
- /**
67320
- * @tsl
67321
- * @function
67322
- * @deprecated since r168. Use {@link mod} instead.
67323
- *
67324
- * @param {Node} a - The first input.
67325
- * @param {Node} b - The second input.
67326
- * @returns {OperatorNode}
67327
- */
67328
- const remainder = ( a, b ) => { // @deprecated, r168
67329
-
67330
- console.warn( 'THREE.TSL: "remainder()" is deprecated. Use "mod( int( ... ) )" instead.' );
67331
- return mod( a, b );
67332
-
67333
- };
67334
-
67335
67419
  /**
67336
67420
  * @tsl
67337
67421
  * @function
@@ -67348,7 +67432,6 @@ function InsertStackElement(node, body) {
67348
67432
 
67349
67433
  };
67350
67434
 
67351
- addMethodChaining( 'remainder', remainder );
67352
67435
  addMethodChaining( 'modInt', modInt );
67353
67436
 
67354
67437
  /**
@@ -68359,6 +68442,17 @@ function InsertStackElement(node, body) {
68359
68442
  */
68360
68443
  const smoothstepElement = ( x, low, high ) => smoothstep( low, high, x );
68361
68444
 
68445
+ /**
68446
+ * Alias for `step()` with a different parameter order.
68447
+ *
68448
+ * @tsl
68449
+ * @function
68450
+ * @param {Node | number} x - The source value for interpolation.
68451
+ * @param {Node | number} edge - The edge value.
68452
+ * @returns {Node}
68453
+ */
68454
+ const stepElement = ( x, edge ) => step( edge, x );
68455
+
68362
68456
  /**
68363
68457
  * Returns the arc-tangent of the quotient of its parameters.
68364
68458
  *
@@ -68416,7 +68510,7 @@ function InsertStackElement(node, body) {
68416
68510
  addMethodChaining( 'atan2', atan2 );
68417
68511
  addMethodChaining( 'min', min$1 );
68418
68512
  addMethodChaining( 'max', max$1 );
68419
- addMethodChaining( 'step', step );
68513
+ addMethodChaining( 'step', stepElement );
68420
68514
  addMethodChaining( 'reflect', reflect );
68421
68515
  addMethodChaining( 'distance', distance );
68422
68516
  addMethodChaining( 'dot', dot );
@@ -68660,25 +68754,6 @@ function InsertStackElement(node, body) {
68660
68754
 
68661
68755
  addMethodChaining( 'select', select$1 );
68662
68756
 
68663
- // Deprecated
68664
-
68665
- /**
68666
- * @tsl
68667
- * @function
68668
- * @deprecated since r168. Use {@link select} instead.
68669
- *
68670
- * @param {...any} params
68671
- * @returns {ConditionalNode}
68672
- */
68673
- const cond = ( ...params ) => { // @deprecated, r168
68674
-
68675
- console.warn( 'THREE.TSL: cond() has been renamed to select().' );
68676
- return select$1( ...params );
68677
-
68678
- };
68679
-
68680
- addMethodChaining( 'cond', cond );
68681
-
68682
68757
  /**
68683
68758
  * This node can be used as a context management component for another node.
68684
68759
  * {@link NodeBuilder} performs its node building process in a specific context and
@@ -69032,6 +69107,91 @@ function InsertStackElement(node, body) {
69032
69107
 
69033
69108
  addMethodChaining( 'temp', temp );
69034
69109
 
69110
+ /**
69111
+ * This node is used to build a sub-build in the node system.
69112
+ *
69113
+ * @augments Node
69114
+ * @param {Node} node - The node to be built in the sub-build.
69115
+ * @param {string} name - The name of the sub-build.
69116
+ * @param {string|null} [nodeType=null] - The type of the node, if known.
69117
+ */
69118
+ class SubBuildNode extends Node {
69119
+
69120
+ static get type() {
69121
+
69122
+ return 'SubBuild';
69123
+
69124
+ }
69125
+
69126
+ constructor( node, name, nodeType = null ) {
69127
+
69128
+ super( nodeType );
69129
+
69130
+ /**
69131
+ * The node to be built in the sub-build.
69132
+ *
69133
+ * @type {Node}
69134
+ */
69135
+ this.node = node;
69136
+
69137
+ /**
69138
+ * The name of the sub-build.
69139
+ *
69140
+ * @type {string}
69141
+ */
69142
+ this.name = name;
69143
+
69144
+ /**
69145
+ * This flag can be used for type testing.
69146
+ *
69147
+ * @type {boolean}
69148
+ * @readonly
69149
+ * @default true
69150
+ */
69151
+ this.isSubBuildNode = true;
69152
+
69153
+ }
69154
+
69155
+ getNodeType( builder ) {
69156
+
69157
+ if ( this.nodeType !== null ) return this.nodeType;
69158
+
69159
+ builder.addSubBuild( this.name );
69160
+
69161
+ const nodeType = this.node.getNodeType( builder );
69162
+
69163
+ builder.removeSubBuild();
69164
+
69165
+ return nodeType;
69166
+
69167
+ }
69168
+
69169
+ build( builder, ...params ) {
69170
+
69171
+ builder.addSubBuild( this.name );
69172
+
69173
+ const data = this.node.build( builder, ...params );
69174
+
69175
+ builder.removeSubBuild();
69176
+
69177
+ return data;
69178
+
69179
+ }
69180
+
69181
+ }
69182
+
69183
+ /**
69184
+ * Creates a new sub-build node.
69185
+ *
69186
+ * @tsl
69187
+ * @function
69188
+ * @param {Node} node - The node to be built in the sub-build.
69189
+ * @param {string} name - The name of the sub-build.
69190
+ * @param {string|null} [type=null] - The type of the node, if known.
69191
+ * @returns {Node} A node object wrapping the SubBuildNode instance.
69192
+ */
69193
+ const subBuild = ( node, name, type = null ) => nodeObject( new SubBuildNode( nodeObject( node ), name, type ) );
69194
+
69035
69195
  /**
69036
69196
  * Class for representing shader varyings as nodes. Varyings are create from
69037
69197
  * existing nodes like the following:
@@ -69161,7 +69321,7 @@ function InsertStackElement(node, body) {
69161
69321
  const interpolationSampling = this.interpolationSampling;
69162
69322
 
69163
69323
  properties.varying = varying = builder.getVaryingFromNode( this, name, type, interpolationType, interpolationSampling );
69164
- properties.node = this.node;
69324
+ properties.node = subBuild( this.node, 'VERTEX' );
69165
69325
 
69166
69326
  }
69167
69327
 
@@ -69190,18 +69350,19 @@ function InsertStackElement(node, body) {
69190
69350
 
69191
69351
  generate( builder ) {
69192
69352
 
69353
+ const propertyKey = builder.getSubBuildProperty( 'property', builder.currentStack );
69193
69354
  const properties = builder.getNodeProperties( this );
69194
69355
  const varying = this.setupVarying( builder );
69195
69356
 
69196
- if ( properties.propertyName === undefined ) {
69357
+ if ( properties[ propertyKey ] === undefined ) {
69197
69358
 
69198
69359
  const type = this.getNodeType( builder );
69199
69360
  const propertyName = builder.getPropertyName( varying, NodeShaderStage.VERTEX );
69200
69361
 
69201
69362
  // force node run in vertex stage
69202
- builder.flowNodeFromShaderStage( NodeShaderStage.VERTEX, this.node, type, propertyName );
69363
+ builder.flowNodeFromShaderStage( NodeShaderStage.VERTEX, properties.node, type, propertyName );
69203
69364
 
69204
- properties.propertyName = propertyName;
69365
+ properties[ propertyKey ] = propertyName;
69205
69366
 
69206
69367
  }
69207
69368
 
@@ -70616,20 +70777,6 @@ function InsertStackElement(node, body) {
70616
70777
  */
70617
70778
  const cache = ( node, parent ) => nodeObject( new CacheNode( nodeObject( node ), parent ) );
70618
70779
 
70619
- /**
70620
- * Assigns a namespace to the given node by updating its context.
70621
- *
70622
- * Important for TSL functions that use `.once( namespace )` to ensure that the namespace will run twice,
70623
- * once when the node is build in the specific namespace and once when the node is built in the others namespace.
70624
- *
70625
- * This is useful for nodes like `positionWorld` that need to be re-updated if used in `material.positionNode` and outside of it in the same material.
70626
- *
70627
- * @param {Object} node - The node to which the namespace will be assigned.
70628
- * @param {string} namespace - The namespace to be assigned to the node.
70629
- * @returns {Object} The updated node with the new namespace in its context.
70630
- */
70631
- const namespace$1 = ( node, namespace ) => node.context( { namespace } );
70632
-
70633
70780
  addMethodChaining( 'cache', cache );
70634
70781
 
70635
70782
  /**
@@ -71284,7 +71431,7 @@ function InsertStackElement(node, body) {
71284
71431
  * @param {number} [index=0] - The uv index.
71285
71432
  * @return {AttributeNode<vec2>} The uv attribute node.
71286
71433
  */
71287
- const uv = ( index = 0 ) => attribute( 'uv' + ( index > 0 ? index : '' ), 'vec2' );
71434
+ const uv$1 = ( index = 0 ) => attribute( 'uv' + ( index > 0 ? index : '' ), 'vec2' );
71288
71435
 
71289
71436
  /**
71290
71437
  * A node that represents the dimensions of a texture. The texture size is
@@ -71677,7 +71824,7 @@ function InsertStackElement(node, body) {
71677
71824
  */
71678
71825
  getDefaultUV() {
71679
71826
 
71680
- return uv( this.value.channel );
71827
+ return uv$1( this.value.channel );
71681
71828
 
71682
71829
  }
71683
71830
 
@@ -73247,9 +73394,9 @@ function InsertStackElement(node, body) {
73247
73394
  */
73248
73395
  const positionWorld = /*@__PURE__*/ ( Fn( ( builder ) => {
73249
73396
 
73250
- return modelWorldMatrix.mul( positionLocal ).xyz.toVarying( builder.getNamespace( 'v_positionWorld' ) );
73397
+ return modelWorldMatrix.mul( positionLocal ).xyz.toVarying( builder.getSubBuildProperty( 'v_positionWorld' ) );
73251
73398
 
73252
- }, 'vec3' ).once( 'POSITION' ) )();
73399
+ }, 'vec3' ).once( [ 'POSITION' ] ) )();
73253
73400
 
73254
73401
  /**
73255
73402
  * TSL object that represents the position world direction of the current rendered object.
@@ -73257,13 +73404,13 @@ function InsertStackElement(node, body) {
73257
73404
  * @tsl
73258
73405
  * @type {Node<vec3>}
73259
73406
  */
73260
- const positionWorldDirection = /*@__PURE__*/ ( Fn( ( builder ) => {
73407
+ const positionWorldDirection = /*@__PURE__*/ ( Fn( () => {
73261
73408
 
73262
- const vertexPWD = positionLocal.transformDirection( modelWorldMatrix ).toVarying( builder.getNamespace( 'v_positionWorldDirection' ) );
73409
+ const vertexPWD = positionLocal.transformDirection( modelWorldMatrix ).toVarying( 'v_positionWorldDirection' );
73263
73410
 
73264
73411
  return vertexPWD.normalize().toVar( 'positionWorldDirection' );
73265
73412
 
73266
- }, 'vec3' ).once( 'POSITION' ) )();
73413
+ }, 'vec3' ).once( [ 'POSITION' ] ) )();
73267
73414
 
73268
73415
  /**
73269
73416
  * TSL object that represents the vertex position in view space of the current rendered object.
@@ -73273,9 +73420,9 @@ function InsertStackElement(node, body) {
73273
73420
  */
73274
73421
  const positionView = /*@__PURE__*/ ( Fn( ( builder ) => {
73275
73422
 
73276
- return builder.context.setupPositionView().toVarying( builder.getNamespace( 'v_positionView' ) );
73423
+ return builder.context.setupPositionView().toVarying( 'v_positionView' );
73277
73424
 
73278
- }, 'vec3' ).once( 'POSITION' ) )();
73425
+ }, 'vec3' ).once( [ 'POSITION' ] ) )();
73279
73426
 
73280
73427
  /**
73281
73428
  * TSL object that represents the position view direction of the current rendered object.
@@ -73318,6 +73465,10 @@ function InsertStackElement(node, body) {
73318
73465
 
73319
73466
  generate( builder ) {
73320
73467
 
73468
+ if ( builder.shaderStage !== 'fragment' ) return 'true';
73469
+
73470
+ //
73471
+
73321
73472
  const { renderer, material } = builder;
73322
73473
 
73323
73474
  if ( renderer.coordinateSystem === WebGLCoordinateSystem ) {
@@ -73353,6 +73504,34 @@ function InsertStackElement(node, body) {
73353
73504
  */
73354
73505
  const faceDirection = /*@__PURE__*/ float( frontFacing ).mul( 2.0 ).sub( 1.0 );
73355
73506
 
73507
+ /**
73508
+ * Converts a direction vector to a face direction vector based on the material's side.
73509
+ *
73510
+ * If the material is set to `BackSide`, the direction is inverted.
73511
+ * If the material is set to `DoubleSide`, the direction is multiplied by `faceDirection`.
73512
+ *
73513
+ * @tsl
73514
+ * @param {Node<vec3>} direction - The direction vector to convert.
73515
+ * @returns {Node<vec3>} The converted direction vector.
73516
+ */
73517
+ const directionToFaceDirection = /*@__PURE__*/ Fn( ( [ direction ], { material } ) => {
73518
+
73519
+ const side = material.side;
73520
+
73521
+ if ( side === BackSide ) {
73522
+
73523
+ direction = direction.mul( -1 );
73524
+
73525
+ } else if ( side === DoubleSide ) {
73526
+
73527
+ direction = direction.mul( faceDirection );
73528
+
73529
+ }
73530
+
73531
+ return direction;
73532
+
73533
+ } );
73534
+
73356
73535
  /**
73357
73536
  * TSL object that represents the normal attribute of the current rendered object.
73358
73537
  *
@@ -73395,7 +73574,7 @@ function InsertStackElement(node, body) {
73395
73574
  * @tsl
73396
73575
  * @type {Node<vec3>}
73397
73576
  */
73398
- const normalView = /*@__PURE__*/ ( Fn( ( builder ) => {
73577
+ const normalViewGeometry = /*@__PURE__*/ ( Fn( ( builder ) => {
73399
73578
 
73400
73579
  let node;
73401
73580
 
@@ -73405,13 +73584,13 @@ function InsertStackElement(node, body) {
73405
73584
 
73406
73585
  } else {
73407
73586
 
73408
- node = varying( transformNormalToView( normalLocal ), 'v_normalView' ).normalize();
73587
+ node = transformNormalToView( normalLocal ).toVarying( 'v_normalViewGeometry' ).normalize();
73409
73588
 
73410
73589
  }
73411
73590
 
73412
73591
  return node;
73413
73592
 
73414
- }, 'vec3' ).once() )().toVar( 'normalView' );
73593
+ }, 'vec3' ).once() )().toVar( 'normalViewGeometry' );
73415
73594
 
73416
73595
  /**
73417
73596
  * TSL object that represents the vertex normal in world space of the current rendered object.
@@ -73419,19 +73598,19 @@ function InsertStackElement(node, body) {
73419
73598
  * @tsl
73420
73599
  * @type {Node<vec3>}
73421
73600
  */
73422
- const normalWorld = /*@__PURE__*/ ( Fn( ( builder ) => {
73601
+ const normalWorldGeometry = /*@__PURE__*/ ( Fn( ( builder ) => {
73423
73602
 
73424
- let normal = normalView.transformDirection( cameraViewMatrix );
73603
+ let normal = normalViewGeometry.transformDirection( cameraViewMatrix );
73425
73604
 
73426
73605
  if ( builder.material.flatShading !== true ) {
73427
73606
 
73428
- normal = varying( normal, 'v_normalWorld' );
73607
+ normal = normal.toVarying( 'v_normalWorldGeometry' );
73429
73608
 
73430
73609
  }
73431
73610
 
73432
- return normal;
73611
+ return normal.normalize().toVar( 'normalWorldGeometry' );
73433
73612
 
73434
- }, 'vec3' ).once() )().normalize().toVar( 'normalWorld' );
73613
+ }, 'vec3' ).once() )();
73435
73614
 
73436
73615
  /**
73437
73616
  * TSL object that represents the transformed vertex normal in view space of the current rendered object.
@@ -73439,17 +73618,31 @@ function InsertStackElement(node, body) {
73439
73618
  * @tsl
73440
73619
  * @type {Node<vec3>}
73441
73620
  */
73442
- const transformedNormalView = /*@__PURE__*/ ( Fn( ( builder ) => {
73621
+ const normalView = /*@__PURE__*/ ( Fn( ( { subBuildFn, material, context } ) => {
73443
73622
 
73444
- // Use getUV context to avoid side effects from nodes overwriting getUV in the context (e.g. EnvironmentNode)
73623
+ let node;
73445
73624
 
73446
- let node = builder.context.setupNormal().context( { getUV: null } );
73625
+ if ( subBuildFn === 'NORMAL' || subBuildFn === 'VERTEX' ) {
73447
73626
 
73448
- if ( builder.material.flatShading !== true ) node = node.mul( faceDirection );
73627
+ node = normalViewGeometry;
73628
+
73629
+ if ( material.flatShading !== true ) {
73630
+
73631
+ node = directionToFaceDirection( node );
73632
+
73633
+ }
73634
+
73635
+ } else {
73636
+
73637
+ // Use getUV context to avoid side effects from nodes overwriting getUV in the context (e.g. EnvironmentNode)
73638
+
73639
+ node = context.setupNormal().context( { getUV: null } );
73640
+
73641
+ }
73449
73642
 
73450
73643
  return node;
73451
73644
 
73452
- }, 'vec3' ).once() )().toVar( 'transformedNormalView' );
73645
+ }, 'vec3' ).once( [ 'NORMAL', 'VERTEX' ] ) )().toVar( 'normalView' );
73453
73646
 
73454
73647
  /**
73455
73648
  * TSL object that represents the transformed vertex normal in world space of the current rendered object.
@@ -73457,7 +73650,7 @@ function InsertStackElement(node, body) {
73457
73650
  * @tsl
73458
73651
  * @type {Node<vec3>}
73459
73652
  */
73460
- const transformedNormalWorld = /*@__PURE__*/ transformedNormalView.transformDirection( cameraViewMatrix ).toVar( 'transformedNormalWorld' );
73653
+ const normalWorld = /*@__PURE__*/ normalView.transformDirection( cameraViewMatrix ).toVar( 'normalWorld' );
73461
73654
 
73462
73655
  /**
73463
73656
  * TSL object that represents the transformed clearcoat vertex normal in view space of the current rendered object.
@@ -73465,17 +73658,25 @@ function InsertStackElement(node, body) {
73465
73658
  * @tsl
73466
73659
  * @type {Node<vec3>}
73467
73660
  */
73468
- const transformedClearcoatNormalView = /*@__PURE__*/ ( Fn( ( builder ) => {
73661
+ const clearcoatNormalView = /*@__PURE__*/ ( Fn( ( { subBuildFn, context } ) => {
73662
+
73663
+ let node;
73469
73664
 
73470
- // Use getUV context to avoid side effects from nodes overwriting getUV in the context (e.g. EnvironmentNode)
73665
+ if ( subBuildFn === 'NORMAL' || subBuildFn === 'VERTEX' ) {
73471
73666
 
73472
- let node = builder.context.setupClearcoatNormal().context( { getUV: null } );
73667
+ node = normalView;
73473
73668
 
73474
- if ( builder.material.flatShading !== true ) node = node.mul( faceDirection );
73669
+ } else {
73670
+
73671
+ // Use getUV context to avoid side effects from nodes overwriting getUV in the context (e.g. EnvironmentNode)
73672
+
73673
+ node = context.setupClearcoatNormal().context( { getUV: null } );
73674
+
73675
+ }
73475
73676
 
73476
73677
  return node;
73477
73678
 
73478
- }, 'vec3' ).once() )().toVar( 'transformedClearcoatNormalView' );
73679
+ }, 'vec3' ).once( [ 'NORMAL', 'VERTEX' ] ) )().toVar( 'clearcoatNormalView' );
73479
73680
 
73480
73681
  /**
73481
73682
  * Transforms the normal with the given matrix.
@@ -73523,6 +73724,50 @@ function InsertStackElement(node, body) {
73523
73724
 
73524
73725
  } );
73525
73726
 
73727
+ // Deprecated
73728
+
73729
+ /**
73730
+ * TSL object that represents the transformed vertex normal in view space of the current rendered object.
73731
+ *
73732
+ * @tsl
73733
+ * @type {Node<vec3>}
73734
+ * @deprecated since r178. Use `normalView` instead.
73735
+ */
73736
+ ( Fn( () => { // @deprecated, r177
73737
+
73738
+ console.warn( 'THREE.TSL: "transformedNormalView" is deprecated. Use "normalView" instead.' );
73739
+ return normalView;
73740
+
73741
+ } ).once( [ 'NORMAL', 'VERTEX' ] ) )();
73742
+
73743
+ /**
73744
+ * TSL object that represents the transformed vertex normal in world space of the current rendered object.
73745
+ *
73746
+ * @tsl
73747
+ * @type {Node<vec3>}
73748
+ * @deprecated since r178. Use `normalWorld` instead.
73749
+ */
73750
+ ( Fn( () => { // @deprecated, r177
73751
+
73752
+ console.warn( 'THREE.TSL: "transformedNormalWorld" is deprecated. Use "normalWorld" instead.' );
73753
+ return normalWorld;
73754
+
73755
+ } ).once( [ 'NORMAL', 'VERTEX' ] ) )();
73756
+
73757
+ /**
73758
+ * TSL object that represents the transformed clearcoat vertex normal in view space of the current rendered object.
73759
+ *
73760
+ * @tsl
73761
+ * @type {Node<vec3>}
73762
+ * @deprecated since r178. Use `clearcoatNormalView` instead.
73763
+ */
73764
+ ( Fn( () => { // @deprecated, r177
73765
+
73766
+ console.warn( 'THREE.TSL: "transformedClearcoatNormalView" is deprecated. Use "clearcoatNormalView" instead.' );
73767
+ return clearcoatNormalView;
73768
+
73769
+ } ).once( [ 'NORMAL', 'VERTEX' ] ) )();
73770
+
73526
73771
  const _e1$1 = /*@__PURE__*/ new Euler();
73527
73772
  const _m1$1 = /*@__PURE__*/ new Matrix4();
73528
73773
 
@@ -73585,7 +73830,7 @@ function InsertStackElement(node, body) {
73585
73830
  * @tsl
73586
73831
  * @type {Node<vec3>}
73587
73832
  */
73588
- const reflectView = /*@__PURE__*/ positionViewDirection.negate().reflect( transformedNormalView );
73833
+ const reflectView = /*@__PURE__*/ positionViewDirection.negate().reflect( normalView );
73589
73834
 
73590
73835
  /**
73591
73836
  * The refract vector in view space.
@@ -73593,7 +73838,7 @@ function InsertStackElement(node, body) {
73593
73838
  * @tsl
73594
73839
  * @type {Node<vec3>}
73595
73840
  */
73596
- const refractView = /*@__PURE__*/ positionViewDirection.negate().refract( transformedNormalView, materialRefractionRatio );
73841
+ const refractView = /*@__PURE__*/ positionViewDirection.negate().refract( normalView, materialRefractionRatio );
73597
73842
 
73598
73843
  /**
73599
73844
  * Used for sampling cube maps when using cube reflection mapping.
@@ -74258,6 +74503,49 @@ function InsertStackElement(node, body) {
74258
74503
  */
74259
74504
  const materialReference = ( name, type, material = null ) => nodeObject( new MaterialReferenceNode( name, type, material ) );
74260
74505
 
74506
+ // Normal Mapping Without Precomputed Tangents
74507
+ // http://www.thetenthplanet.de/archives/1180
74508
+
74509
+ const uv = uv$1();
74510
+
74511
+ const q0 = positionView.dFdx();
74512
+ const q1 = positionView.dFdy();
74513
+ const st0 = uv.dFdx();
74514
+ const st1 = uv.dFdy();
74515
+
74516
+ const N$1 = normalView;
74517
+
74518
+ const q1perp = q1.cross( N$1 );
74519
+ const q0perp = N$1.cross( q0 );
74520
+
74521
+ const T$1 = q1perp.mul( st0.x ).add( q0perp.mul( st1.x ) );
74522
+ const B$1 = q1perp.mul( st0.y ).add( q0perp.mul( st1.y ) );
74523
+
74524
+ const det = T$1.dot( T$1 ).max( B$1.dot( B$1 ) );
74525
+ const scale = det.equal( 0.0 ).select( 0.0, det.inverseSqrt() );
74526
+
74527
+ /**
74528
+ * Tangent vector in view space, computed dynamically from geometry and UV derivatives.
74529
+ * Useful for normal mapping without precomputed tangents.
74530
+ *
74531
+ * Reference: http://www.thetenthplanet.de/archives/1180
74532
+ *
74533
+ * @tsl
74534
+ * @type {Node<vec3>}
74535
+ */
74536
+ const tangentViewFrame = /*@__PURE__*/ T$1.mul( scale ).toVar( 'tangentViewFrame' );
74537
+
74538
+ /**
74539
+ * Bitangent vector in view space, computed dynamically from geometry and UV derivatives.
74540
+ * Complements the tangentViewFrame for constructing the tangent space basis.
74541
+ *
74542
+ * Reference: http://www.thetenthplanet.de/archives/1180
74543
+ *
74544
+ * @tsl
74545
+ * @type {Node<vec3>}
74546
+ */
74547
+ const bitangentViewFrame = /*@__PURE__*/ B$1.mul( scale ).toVar( 'bitangentViewFrame' );
74548
+
74261
74549
  /**
74262
74550
  * TSL object that represents the tangent attribute of the current rendered object.
74263
74551
  *
@@ -74290,7 +74578,29 @@ function InsertStackElement(node, body) {
74290
74578
  * @tsl
74291
74579
  * @type {Node<vec3>}
74292
74580
  */
74293
- const tangentView = /*@__PURE__*/ modelViewMatrix.mul( vec4( tangentLocal, 0 ) ).xyz.toVarying( 'v_tangentView' ).normalize().toVar( 'tangentView' );
74581
+ const tangentView = /*@__PURE__*/ ( Fn( ( { subBuildFn, geometry, material } ) => {
74582
+
74583
+ let node;
74584
+
74585
+ if ( subBuildFn === 'VERTEX' || geometry.hasAttribute( 'tangent' ) ) {
74586
+
74587
+ node = modelViewMatrix.mul( vec4( tangentLocal, 0 ) ).xyz.toVarying( 'v_tangentView' ).normalize();
74588
+
74589
+ } else {
74590
+
74591
+ node = tangentViewFrame;
74592
+
74593
+ }
74594
+
74595
+ if ( material.flatShading !== true ) {
74596
+
74597
+ node = directionToFaceDirection( node );
74598
+
74599
+ }
74600
+
74601
+ return node;
74602
+
74603
+ }, 'vec3' ).once( [ 'NORMAL', 'VERTEX' ] ) )().toVar( 'tangentView' );
74294
74604
 
74295
74605
  /**
74296
74606
  * Returns the bitangent node and assigns it to a varying if the material is not flat shaded.
@@ -74301,19 +74611,19 @@ function InsertStackElement(node, body) {
74301
74611
  * @param {string} varyingName - The name of the varying to assign the bitangent to.
74302
74612
  * @returns {Node<vec3>} The bitangent node.
74303
74613
  */
74304
- const getBitangent = /*@__PURE__*/ Fn( ( [ crossNormalTangent, varyingName ], builder ) => {
74614
+ const getBitangent = /*@__PURE__*/ Fn( ( [ crossNormalTangent, varyingName ], { subBuildFn, material } ) => {
74305
74615
 
74306
74616
  let bitangent = crossNormalTangent.mul( tangentGeometry.w ).xyz;
74307
74617
 
74308
- if ( builder.material.flatShading !== true ) {
74618
+ if ( subBuildFn === 'NORMAL' && material.flatShading !== true ) {
74309
74619
 
74310
- bitangent = varying( bitangent, varyingName );
74620
+ bitangent = bitangent.toVarying( varyingName );
74311
74621
 
74312
74622
  }
74313
74623
 
74314
74624
  return bitangent;
74315
74625
 
74316
- } ).once();
74626
+ } ).once( [ 'NORMAL' ] );
74317
74627
 
74318
74628
  /**
74319
74629
  * TSL object that represents the vertex bitangent in view space of the current rendered object.
@@ -74321,7 +74631,29 @@ function InsertStackElement(node, body) {
74321
74631
  * @tsl
74322
74632
  * @type {Node<vec3>}
74323
74633
  */
74324
- const bitangentView = getBitangent( normalView.cross( tangentView ), 'v_bitangentView' ).normalize().toVar( 'bitangentView' );
74634
+ const bitangentView = /*@__PURE__*/ ( Fn( ( { subBuildFn, geometry, material } ) => {
74635
+
74636
+ let node;
74637
+
74638
+ if ( subBuildFn === 'VERTEX' || geometry.hasAttribute( 'tangent' ) ) {
74639
+
74640
+ node = getBitangent( normalView.cross( tangentView ), 'v_bitangentView' ).normalize();
74641
+
74642
+ } else {
74643
+
74644
+ node = bitangentViewFrame;
74645
+
74646
+ }
74647
+
74648
+ if ( material.flatShading !== true ) {
74649
+
74650
+ node = directionToFaceDirection( node );
74651
+
74652
+ }
74653
+
74654
+ return node;
74655
+
74656
+ }, 'vec3' ).once( [ 'NORMAL', 'VERTEX' ] ) )().toVar( 'bitangentView' );
74325
74657
 
74326
74658
  /**
74327
74659
  * TSL object that represents the TBN matrix in view space.
@@ -74329,7 +74661,7 @@ function InsertStackElement(node, body) {
74329
74661
  * @tsl
74330
74662
  * @type {Node<mat3>}
74331
74663
  */
74332
- const TBNViewMatrix = /*@__PURE__*/ mat3( tangentView, bitangentView, normalView );
74664
+ const TBNViewMatrix = /*@__PURE__*/ mat3( tangentView, bitangentView, normalView ).toVar( 'TBNViewMatrix' );
74333
74665
 
74334
74666
  /**
74335
74667
  * TSL function for computing bent normals.
@@ -74338,45 +74670,17 @@ function InsertStackElement(node, body) {
74338
74670
  * @function
74339
74671
  * @returns {Node<vec3>} Bent normals.
74340
74672
  */
74341
- const transformedBentNormalView = /*@__PURE__*/ ( () => {
74673
+ const bentNormalView = /*@__PURE__*/ ( Fn( () => {
74342
74674
 
74343
74675
  // https://google.github.io/filament/Filament.md.html#lighting/imagebasedlights/anisotropy
74344
74676
 
74345
74677
  let bentNormal = anisotropyB.cross( positionViewDirection );
74346
74678
  bentNormal = bentNormal.cross( anisotropyB ).normalize();
74347
- bentNormal = mix$2( bentNormal, transformedNormalView, anisotropy.mul( roughness.oneMinus() ).oneMinus().pow2().pow2() ).normalize();
74679
+ bentNormal = mix$2( bentNormal, normalView, anisotropy.mul( roughness.oneMinus() ).oneMinus().pow2().pow2() ).normalize();
74348
74680
 
74349
74681
  return bentNormal;
74350
74682
 
74351
-
74352
- } )();
74353
-
74354
- // Normal Mapping Without Precomputed Tangents
74355
- // http://www.thetenthplanet.de/archives/1180
74356
-
74357
- const perturbNormal2Arb = /*@__PURE__*/ Fn( ( inputs ) => {
74358
-
74359
- const { eye_pos, surf_norm, mapN, uv } = inputs;
74360
-
74361
- const q0 = eye_pos.dFdx();
74362
- const q1 = eye_pos.dFdy();
74363
- const st0 = uv.dFdx();
74364
- const st1 = uv.dFdy();
74365
-
74366
- const N = surf_norm; // normalized
74367
-
74368
- const q1perp = q1.cross( N );
74369
- const q0perp = N.cross( q0 );
74370
-
74371
- const T = q1perp.mul( st0.x ).add( q0perp.mul( st1.x ) );
74372
- const B = q1perp.mul( st0.y ).add( q0perp.mul( st1.y ) );
74373
-
74374
- const det = T.dot( T ).max( B.dot( B ) );
74375
- const scale = faceDirection.mul( det.inverseSqrt() );
74376
-
74377
- return add( T.mul( mapN.x, scale ), B.mul( mapN.y, scale ), N.mul( mapN.z ) ).normalize();
74378
-
74379
- } );
74683
+ } ).once() )();
74380
74684
 
74381
74685
  /**
74382
74686
  * This class can be used for applying normals maps to materials.
@@ -74430,7 +74734,7 @@ function InsertStackElement(node, body) {
74430
74734
 
74431
74735
  }
74432
74736
 
74433
- setup( builder ) {
74737
+ setup( { material } ) {
74434
74738
 
74435
74739
  const { normalMapType, scaleNode } = this;
74436
74740
 
@@ -74438,38 +74742,37 @@ function InsertStackElement(node, body) {
74438
74742
 
74439
74743
  if ( scaleNode !== null ) {
74440
74744
 
74441
- normalMap = vec3( normalMap.xy.mul( scaleNode ), normalMap.z );
74745
+ let scale = scaleNode;
74746
+
74747
+ if ( material.flatShading === true ) {
74748
+
74749
+ scale = directionToFaceDirection( scale );
74750
+
74751
+ }
74752
+
74753
+ normalMap = vec3( normalMap.xy.mul( scale ), normalMap.z );
74442
74754
 
74443
74755
  }
74444
74756
 
74445
- let outputNode = null;
74757
+ let output = null;
74446
74758
 
74447
74759
  if ( normalMapType === ObjectSpaceNormalMap ) {
74448
74760
 
74449
- outputNode = transformNormalToView( normalMap );
74761
+ output = transformNormalToView( normalMap );
74450
74762
 
74451
74763
  } else if ( normalMapType === TangentSpaceNormalMap ) {
74452
74764
 
74453
- const tangent = builder.hasGeometryAttribute( 'tangent' );
74454
-
74455
- if ( tangent === true ) {
74765
+ output = TBNViewMatrix.mul( normalMap ).normalize();
74456
74766
 
74457
- outputNode = TBNViewMatrix.mul( normalMap ).normalize();
74458
-
74459
- } else {
74767
+ } else {
74460
74768
 
74461
- outputNode = perturbNormal2Arb( {
74462
- eye_pos: positionView,
74463
- surf_norm: normalView,
74464
- mapN: normalMap,
74465
- uv: uv()
74466
- } );
74769
+ console.error( `THREE.NodeMaterial: Unsupported normal map type: ${ normalMapType }` );
74467
74770
 
74468
- }
74771
+ output = normalView; // Fallback to default normal view
74469
74772
 
74470
74773
  }
74471
74774
 
74472
- return outputNode;
74775
+ return output;
74473
74776
 
74474
74777
  }
74475
74778
 
@@ -74492,7 +74795,7 @@ function InsertStackElement(node, body) {
74492
74795
  const dHdxy_fwd = Fn( ( { textureNode, bumpScale } ) => {
74493
74796
 
74494
74797
  // It's used to preserve the same TextureNode instance
74495
- const sampleTexture = ( callback ) => textureNode.cache().context( { getUV: ( texNode ) => callback( texNode.uvNode || uv() ), forceUVContext: true } );
74798
+ const sampleTexture = ( callback ) => textureNode.cache().context( { getUV: ( texNode ) => callback( texNode.uvNode || uv$1() ), forceUVContext: true } );
74496
74799
 
74497
74800
  const Hll = float( sampleTexture( ( uvNode ) => uvNode ) );
74498
74801
 
@@ -78133,6 +78436,25 @@ function InsertStackElement(node, body) {
78133
78436
  */
78134
78437
  const vertexColor = ( index = 0 ) => nodeObject( new VertexColorNode( index ) );
78135
78438
 
78439
+ /**
78440
+ * Premultiplies the RGB channels of a color by its alpha channel.
78441
+ *
78442
+ * This function is useful for converting a non-premultiplied alpha color
78443
+ * into a premultiplied alpha format, where the RGB values are scaled
78444
+ * by the alpha value. Premultiplied alpha is often used in graphics
78445
+ * rendering for certain operations, such as compositing and image processing.
78446
+ *
78447
+ * @tsl
78448
+ * @function
78449
+ * @param {Node<vec4>} color - The input color with non-premultiplied alpha.
78450
+ * @return {Node<vec4>} The color with premultiplied alpha.
78451
+ */
78452
+ const premultiplyAlpha = /*@__PURE__*/ Fn( ( [ color ] ) => {
78453
+
78454
+ return vec4( color.rgb.mul( color.a ), color.a );
78455
+
78456
+ }, { color: 'vec4', return: 'vec4' } );
78457
+
78136
78458
  /**
78137
78459
  * Base class for all node materials.
78138
78460
  *
@@ -78552,7 +78874,7 @@ function InsertStackElement(node, body) {
78552
78874
  */
78553
78875
  setup( builder ) {
78554
78876
 
78555
- builder.context.setupNormal = () => this.setupNormal( builder );
78877
+ builder.context.setupNormal = () => subBuild( this.setupNormal( builder ), 'NORMAL', 'vec3' );
78556
78878
  builder.context.setupPositionView = () => this.setupPositionView( builder );
78557
78879
  builder.context.setupModelViewProjection = () => this.setupModelViewProjection( builder );
78558
78880
 
@@ -78563,7 +78885,7 @@ function InsertStackElement(node, body) {
78563
78885
 
78564
78886
  builder.addStack();
78565
78887
 
78566
- const mvp = this.setupVertex( builder );
78888
+ const mvp = subBuild( this.setupVertex( builder ), 'VERTEX' );
78567
78889
 
78568
78890
  const vertexNode = this.vertexNode || mvp;
78569
78891
 
@@ -78875,7 +79197,7 @@ function InsertStackElement(node, body) {
78875
79197
 
78876
79198
  if ( this.positionNode !== null ) {
78877
79199
 
78878
- positionLocal.assign( namespace$1( this.positionNode, 'POSITION' ) );
79200
+ positionLocal.assign( subBuild( this.positionNode, 'POSITION', 'vec3' ) );
78879
79201
 
78880
79202
  }
78881
79203
 
@@ -79185,6 +79507,19 @@ function InsertStackElement(node, body) {
79185
79507
 
79186
79508
  }
79187
79509
 
79510
+ /**
79511
+ * Setups premultiplied alpha.
79512
+ *
79513
+ * @param {NodeBuilder} builder - The current node builder.
79514
+ * @param {Node<vec4>} outputNode - The existing output node.
79515
+ * @return {Node<vec4>} The output node.
79516
+ */
79517
+ setupPremultipliedAlpha( builder, outputNode ) {
79518
+
79519
+ return premultiplyAlpha( outputNode );
79520
+
79521
+ }
79522
+
79188
79523
  /**
79189
79524
  * Setups the output node.
79190
79525
  *
@@ -79202,6 +79537,14 @@ function InsertStackElement(node, body) {
79202
79537
 
79203
79538
  }
79204
79539
 
79540
+ // PREMULTIPLIED ALPHA
79541
+
79542
+ if ( this.premultipliedAlpha === true ) {
79543
+
79544
+ outputNode = this.setupPremultipliedAlpha( builder, outputNode );
79545
+
79546
+ }
79547
+
79205
79548
  return outputNode;
79206
79549
 
79207
79550
  }
@@ -79575,13 +79918,15 @@ function InsertStackElement(node, body) {
79575
79918
 
79576
79919
  // By convention, a normal packed to RGB is in sRGB color space. Convert it to working color space.
79577
79920
 
79578
- diffuseColor.assign( colorSpaceToWorking( vec4( directionToColor( transformedNormalView ), opacityNode ), SRGBColorSpace ) );
79921
+ diffuseColor.assign( colorSpaceToWorking( vec4( directionToColor( normalView ), opacityNode ), SRGBColorSpace ) );
79579
79922
 
79580
79923
  }
79581
79924
 
79582
79925
  }
79583
79926
 
79584
79927
  /**
79928
+ * TSL function for creating an equirect uv node.
79929
+ *
79585
79930
  * Can be used to compute texture coordinates for projecting an
79586
79931
  * equirectangular texture onto a mesh for using it as the scene's
79587
79932
  * background.
@@ -79590,56 +79935,19 @@ function InsertStackElement(node, body) {
79590
79935
  * scene.backgroundNode = texture( equirectTexture, equirectUV() );
79591
79936
  * ```
79592
79937
  *
79593
- * @augments TempNode
79594
- */
79595
- class EquirectUVNode extends TempNode {
79596
-
79597
- static get type() {
79598
-
79599
- return 'EquirectUVNode';
79600
-
79601
- }
79602
-
79603
- /**
79604
- * Constructs a new equirect uv node.
79605
- *
79606
- * @param {Node<vec3>} [dirNode=positionWorldDirection] - A direction vector for sampling which is by default `positionWorldDirection`.
79607
- */
79608
- constructor( dirNode = positionWorldDirection ) {
79609
-
79610
- super( 'vec2' );
79611
-
79612
- /**
79613
- * A direction vector for sampling why is by default `positionWorldDirection`.
79614
- *
79615
- * @type {Node<vec3>}
79616
- */
79617
- this.dirNode = dirNode;
79618
-
79619
- }
79620
-
79621
- setup() {
79622
-
79623
- const dir = this.dirNode;
79624
-
79625
- const u = dir.z.atan( dir.x ).mul( 1 / ( Math.PI * 2 ) ).add( 0.5 );
79626
- const v = dir.y.clamp( -1, 1.0 ).asin().mul( 1 / Math.PI ).add( 0.5 );
79627
-
79628
- return vec2( u, v );
79629
-
79630
- }
79631
-
79632
- }
79633
-
79634
- /**
79635
- * TSL function for creating an equirect uv node.
79636
- *
79637
79938
  * @tsl
79638
79939
  * @function
79639
79940
  * @param {?Node<vec3>} [dirNode=positionWorldDirection] - A direction vector for sampling which is by default `positionWorldDirection`.
79640
- * @returns {EquirectUVNode}
79941
+ * @returns {Node<vec2>}
79641
79942
  */
79642
- const equirectUV = /*@__PURE__*/ nodeProxy( EquirectUVNode ).setParameterLength( 0, 1 );
79943
+ const equirectUV = /*@__PURE__*/ Fn( ( [ dir = positionWorldDirection ] ) => {
79944
+
79945
+ const u = dir.z.atan( dir.x ).mul( 1 / ( Math.PI * 2 ) ).add( 0.5 );
79946
+ const v = dir.y.clamp( -1, 1.0 ).asin().mul( 1 / Math.PI ).add( 0.5 );
79947
+
79948
+ return vec2( u, v );
79949
+
79950
+ } );
79643
79951
 
79644
79952
  // @TODO: Consider rename WebGLCubeRenderTarget to just CubeRenderTarget
79645
79953
 
@@ -80267,13 +80575,13 @@ function InsertStackElement(node, body) {
80267
80575
 
80268
80576
  /**
80269
80577
  * Basic materials are not affected by normal and bump maps so we
80270
- * return by default {@link normalView}.
80578
+ * return by default {@link normalViewGeometry}.
80271
80579
  *
80272
80580
  * @return {Node<vec3>} The normal node.
80273
80581
  */
80274
80582
  setupNormal() {
80275
80583
 
80276
- return normalView; // see #28839
80584
+ return directionToFaceDirection( normalViewGeometry ); // see #28839
80277
80585
 
80278
80586
  }
80279
80587
 
@@ -80369,7 +80677,7 @@ function InsertStackElement(node, body) {
80369
80677
 
80370
80678
  const halfDir = lightDirection.add( positionViewDirection ).normalize();
80371
80679
 
80372
- const dotNH = transformedNormalView.dot( halfDir ).clamp();
80680
+ const dotNH = normalView.dot( halfDir ).clamp();
80373
80681
  const dotVH = positionViewDirection.dot( halfDir ).clamp();
80374
80682
 
80375
80683
  const F = F_Schlick( { f0: specularColor, f90: 1.0, dotVH } );
@@ -80416,7 +80724,7 @@ function InsertStackElement(node, body) {
80416
80724
  */
80417
80725
  direct( { lightDirection, lightColor, reflectedLight } ) {
80418
80726
 
80419
- const dotNL = transformedNormalView.dot( lightDirection ).clamp();
80727
+ const dotNL = normalView.dot( lightDirection ).clamp();
80420
80728
  const irradiance = dotNL.mul( lightColor );
80421
80729
 
80422
80730
  reflectedLight.directDiffuse.addAssign( irradiance.mul( BRDF_Lambert( { diffuseColor: diffuseColor.rgb } ) ) );
@@ -80660,7 +80968,7 @@ function InsertStackElement(node, body) {
80660
80968
 
80661
80969
  }
80662
80970
 
80663
- const dxy = normalView.dFdx().abs().max( normalView.dFdy().abs() );
80971
+ const dxy = normalViewGeometry.dFdx().abs().max( normalViewGeometry.dFdy().abs() );
80664
80972
  const geometryRoughness = dxy.x.max( dxy.y ).max( dxy.z );
80665
80973
 
80666
80974
  return geometryRoughness;
@@ -80773,19 +81081,15 @@ function InsertStackElement(node, body) {
80773
81081
  } );
80774
81082
 
80775
81083
  // GGX Distribution, Schlick Fresnel, GGX_SmithCorrelated Visibility
80776
- const BRDF_GGX = /*@__PURE__*/ Fn( ( inputs ) => {
80777
-
80778
- const { lightDirection, f0, f90, roughness, f, USE_IRIDESCENCE, USE_ANISOTROPY } = inputs;
80779
-
80780
- const normalView = inputs.normalView || transformedNormalView;
81084
+ const BRDF_GGX = /*@__PURE__*/ Fn( ( { lightDirection, f0, f90, roughness, f, normalView: normalView$1 = normalView, USE_IRIDESCENCE, USE_ANISOTROPY } ) => {
80781
81085
 
80782
81086
  const alpha = roughness.pow2(); // UE4's roughness
80783
81087
 
80784
81088
  const halfDir = lightDirection.add( positionViewDirection ).normalize();
80785
81089
 
80786
- const dotNL = normalView.dot( lightDirection ).clamp();
80787
- const dotNV = normalView.dot( positionViewDirection ).clamp(); // @ TODO: Move to core dotNV
80788
- const dotNH = normalView.dot( halfDir ).clamp();
81090
+ const dotNL = normalView$1.dot( lightDirection ).clamp();
81091
+ const dotNV = normalView$1.dot( positionViewDirection ).clamp(); // @ TODO: Move to core dotNV
81092
+ const dotNH = normalView$1.dot( halfDir ).clamp();
80789
81093
  const dotVH = positionViewDirection.dot( halfDir ).clamp();
80790
81094
 
80791
81095
  let F = F_Schlick( { f0, f90, dotVH } );
@@ -80914,9 +81218,9 @@ function InsertStackElement(node, body) {
80914
81218
 
80915
81219
  const halfDir = lightDirection.add( positionViewDirection ).normalize();
80916
81220
 
80917
- const dotNL = transformedNormalView.dot( lightDirection ).clamp();
80918
- const dotNV = transformedNormalView.dot( positionViewDirection ).clamp();
80919
- const dotNH = transformedNormalView.dot( halfDir ).clamp();
81221
+ const dotNL = normalView.dot( lightDirection ).clamp();
81222
+ const dotNV = normalView.dot( positionViewDirection ).clamp();
81223
+ const dotNH = normalView.dot( halfDir ).clamp();
80920
81224
 
80921
81225
  const D = D_Charlie( { roughness: sheenRoughness, dotNH } );
80922
81226
  const V = V_Neubelt( { dotNV, dotNL } );
@@ -81106,10 +81410,10 @@ function InsertStackElement(node, body) {
81106
81410
  * @tsl
81107
81411
  * @function
81108
81412
  * @param {TextureNode} textureNode - The texture node that should be filtered.
81109
- * @param {Node<float>} [lodNode=float(3)] - Defines the LOD to sample from.
81413
+ * @param {Node<float>} lodNode - Defines the LOD to sample from.
81110
81414
  * @return {Node} The filtered texture sample.
81111
81415
  */
81112
- const textureBicubic = /*@__PURE__*/ Fn( ( [ textureNode, lodNode = float( 3 ) ] ) => {
81416
+ const textureBicubicLevel = /*@__PURE__*/ Fn( ( [ textureNode, lodNode ] ) => {
81113
81417
 
81114
81418
  const fLodSize = vec2( textureNode.size( int( lodNode ) ) );
81115
81419
  const cLodSize = vec2( textureNode.size( int( lodNode.add( 1.0 ) ) ) );
@@ -81180,7 +81484,7 @@ function InsertStackElement(node, body) {
81180
81484
 
81181
81485
  const lod = log2( screenSize.x ).mul( applyIorToRoughness( roughness, ior ) );
81182
81486
 
81183
- return textureBicubic( transmissionSample, lod );
81487
+ return textureBicubicLevel( transmissionSample, lod );
81184
81488
 
81185
81489
  } );
81186
81490
 
@@ -81594,7 +81898,7 @@ function InsertStackElement(node, body) {
81594
81898
 
81595
81899
  if ( this.iridescence === true ) {
81596
81900
 
81597
- const dotNVi = transformedNormalView.dot( positionViewDirection ).clamp();
81901
+ const dotNVi = normalView.dot( positionViewDirection ).clamp();
81598
81902
 
81599
81903
  this.iridescenceFresnel = evalIridescence( {
81600
81904
  outsideIOR: float( 1.0 ),
@@ -81612,7 +81916,7 @@ function InsertStackElement(node, body) {
81612
81916
 
81613
81917
  const position = positionWorld;
81614
81918
  const v = cameraPosition.sub( positionWorld ).normalize(); // TODO: Create Node for this, same issue in MaterialX
81615
- const n = transformedNormalWorld;
81919
+ const n = normalWorld;
81616
81920
 
81617
81921
  const context = builder.context;
81618
81922
 
@@ -81650,7 +81954,7 @@ function InsertStackElement(node, body) {
81650
81954
 
81651
81955
  computeMultiscattering( singleScatter, multiScatter, specularF90 ) {
81652
81956
 
81653
- const dotNV = transformedNormalView.dot( positionViewDirection ).clamp(); // @ TODO: Move to core dotNV
81957
+ const dotNV = normalView.dot( positionViewDirection ).clamp(); // @ TODO: Move to core dotNV
81654
81958
 
81655
81959
  const fab = DFGApprox( { roughness, dotNV } );
81656
81960
 
@@ -81677,7 +81981,7 @@ function InsertStackElement(node, body) {
81677
81981
  */
81678
81982
  direct( { lightDirection, lightColor, reflectedLight } ) {
81679
81983
 
81680
- const dotNL = transformedNormalView.dot( lightDirection ).clamp();
81984
+ const dotNL = normalView.dot( lightDirection ).clamp();
81681
81985
  const irradiance = dotNL.mul( lightColor );
81682
81986
 
81683
81987
  if ( this.sheen === true ) {
@@ -81688,10 +81992,10 @@ function InsertStackElement(node, body) {
81688
81992
 
81689
81993
  if ( this.clearcoat === true ) {
81690
81994
 
81691
- const dotNLcc = transformedClearcoatNormalView.dot( lightDirection ).clamp();
81995
+ const dotNLcc = clearcoatNormalView.dot( lightDirection ).clamp();
81692
81996
  const ccIrradiance = dotNLcc.mul( lightColor );
81693
81997
 
81694
- this.clearcoatSpecularDirect.addAssign( ccIrradiance.mul( BRDF_GGX( { lightDirection, f0: clearcoatF0, f90: clearcoatF90, roughness: clearcoatRoughness, normalView: transformedClearcoatNormalView } ) ) );
81998
+ this.clearcoatSpecularDirect.addAssign( ccIrradiance.mul( BRDF_GGX( { lightDirection, f0: clearcoatF0, f90: clearcoatF90, roughness: clearcoatRoughness, normalView: clearcoatNormalView } ) ) );
81695
81999
 
81696
82000
  }
81697
82001
 
@@ -81715,7 +82019,7 @@ function InsertStackElement(node, body) {
81715
82019
  const p2 = lightPosition.sub( halfWidth ).add( halfHeight );
81716
82020
  const p3 = lightPosition.add( halfWidth ).add( halfHeight );
81717
82021
 
81718
- const N = transformedNormalView;
82022
+ const N = normalView;
81719
82023
  const V = positionViewDirection;
81720
82024
  const P = positionView.toVar();
81721
82025
 
@@ -81780,7 +82084,7 @@ function InsertStackElement(node, body) {
81780
82084
  this.sheenSpecularIndirect.addAssign( iblIrradiance.mul(
81781
82085
  sheen,
81782
82086
  IBLSheenBRDF( {
81783
- normal: transformedNormalView,
82087
+ normal: normalView,
81784
82088
  viewDir: positionViewDirection,
81785
82089
  roughness: sheenRoughness
81786
82090
  } )
@@ -81790,7 +82094,7 @@ function InsertStackElement(node, body) {
81790
82094
 
81791
82095
  if ( this.clearcoat === true ) {
81792
82096
 
81793
- const dotNVcc = transformedClearcoatNormalView.dot( positionViewDirection ).clamp();
82097
+ const dotNVcc = clearcoatNormalView.dot( positionViewDirection ).clamp();
81794
82098
 
81795
82099
  const clearcoatEnv = EnvironmentBRDF( {
81796
82100
  dotNV: dotNVcc,
@@ -81831,7 +82135,7 @@ function InsertStackElement(node, body) {
81831
82135
 
81832
82136
  const { ambientOcclusion, reflectedLight } = builder.context;
81833
82137
 
81834
- const dotNV = transformedNormalView.dot( positionViewDirection ).clamp(); // @ TODO: Move to core dotNV
82138
+ const dotNV = normalView.dot( positionViewDirection ).clamp(); // @ TODO: Move to core dotNV
81835
82139
 
81836
82140
  const aoNV = dotNV.add( ambientOcclusion );
81837
82141
  const aoExp = roughness.mul( -16 ).oneMinus().negate().exp2();
@@ -81866,7 +82170,7 @@ function InsertStackElement(node, body) {
81866
82170
 
81867
82171
  if ( this.clearcoat === true ) {
81868
82172
 
81869
- const dotNVcc = transformedClearcoatNormalView.dot( positionViewDirection ).clamp();
82173
+ const dotNVcc = clearcoatNormalView.dot( positionViewDirection ).clamp();
81870
82174
 
81871
82175
  const Fcc = F_Schlick( {
81872
82176
  dotVH: dotNVcc,
@@ -82226,7 +82530,7 @@ function InsertStackElement(node, body) {
82226
82530
  0, 4, 2
82227
82531
  ];
82228
82532
 
82229
- const _direction = /*@__PURE__*/ getDirection( uv(), attribute( 'faceIndex' ) ).normalize();
82533
+ const _direction = /*@__PURE__*/ getDirection( uv$1(), attribute( 'faceIndex' ) ).normalize();
82230
82534
  const _outputDirection = /*@__PURE__*/ vec3( _direction.x, _direction.y, _direction.z );
82231
82535
 
82232
82536
  /**
@@ -83535,10 +83839,10 @@ function InsertStackElement(node, body) {
83535
83839
  //
83536
83840
 
83537
83841
  const useAnisotropy = material.useAnisotropy === true || material.anisotropy > 0;
83538
- const radianceNormalView = useAnisotropy ? transformedBentNormalView : transformedNormalView;
83842
+ const radianceNormalView = useAnisotropy ? bentNormalView : normalView;
83539
83843
 
83540
83844
  const radiance = envNode.context( createRadianceContext( roughness, radianceNormalView ) ).mul( materialEnvIntensity );
83541
- const irradiance = envNode.context( createIrradianceContext( transformedNormalWorld ) ).mul( Math.PI ).mul( materialEnvIntensity );
83845
+ const irradiance = envNode.context( createIrradianceContext( normalWorld ) ).mul( Math.PI ).mul( materialEnvIntensity );
83542
83846
 
83543
83847
  const isolateRadiance = cache( radiance );
83544
83848
  const isolateIrradiance = cache( irradiance );
@@ -83555,7 +83859,7 @@ function InsertStackElement(node, body) {
83555
83859
 
83556
83860
  if ( clearcoatRadiance ) {
83557
83861
 
83558
- const clearcoatRadianceContext = envNode.context( createRadianceContext( clearcoatRoughness, transformedClearcoatNormalView ) ).mul( materialEnvIntensity );
83862
+ const clearcoatRadianceContext = envNode.context( createRadianceContext( clearcoatRoughness, clearcoatNormalView ) ).mul( materialEnvIntensity );
83559
83863
  const isolateClearcoatRadiance = cache( clearcoatRadianceContext );
83560
83864
 
83561
83865
  clearcoatRadiance.addAssign( isolateClearcoatRadiance );
@@ -84256,7 +84560,7 @@ function InsertStackElement(node, body) {
84256
84560
 
84257
84561
  setup( builder ) {
84258
84562
 
84259
- builder.context.setupClearcoatNormal = () => this.setupClearcoatNormal( builder );
84563
+ builder.context.setupClearcoatNormal = () => subBuild( this.setupClearcoatNormal( builder ), 'NORMAL', 'vec3' );
84260
84564
 
84261
84565
  super.setup( builder );
84262
84566
 
@@ -84414,47 +84718,23 @@ function InsertStackElement(node, body) {
84414
84718
  }
84415
84719
 
84416
84720
  /**
84721
+ * TSL function for creating a matcap uv node.
84722
+ *
84417
84723
  * Can be used to compute texture coordinates for projecting a
84418
84724
  * matcap onto a mesh. Used by {@link MeshMatcapNodeMaterial}.
84419
84725
  *
84420
- * @augments TempNode
84726
+ * @tsl
84727
+ * @function
84728
+ * @returns {Node<vec2>} The matcap UV coordinates.
84421
84729
  */
84422
- class MatcapUVNode extends TempNode {
84423
-
84424
- static get type() {
84425
-
84426
- return 'MatcapUVNode';
84427
-
84428
- }
84429
-
84430
- /**
84431
- * Constructs a new matcap uv node.
84432
- */
84433
- constructor() {
84434
-
84435
- super( 'vec2' );
84730
+ const matcapUV = /*@__PURE__*/ Fn( () => {
84436
84731
 
84437
- }
84438
-
84439
- setup() {
84732
+ const x = vec3( positionViewDirection.z, 0, positionViewDirection.x.negate() ).normalize();
84733
+ const y = positionViewDirection.cross( x );
84440
84734
 
84441
- const x = vec3( positionViewDirection.z, 0, positionViewDirection.x.negate() ).normalize();
84442
- const y = positionViewDirection.cross( x );
84735
+ return vec2( x.dot( normalView ), y.dot( normalView ) ).mul( 0.495 ).add( 0.5 ); // 0.495 to remove artifacts caused by undersized matcap disks
84443
84736
 
84444
- return vec2( x.dot( transformedNormalView ), y.dot( transformedNormalView ) ).mul( 0.495 ).add( 0.5 ); // 0.495 to remove artifacts caused by undersized matcap disks
84445
-
84446
- }
84447
-
84448
- }
84449
-
84450
- /**
84451
- * TSL function for creating a matcap uv node.
84452
- *
84453
- * @tsl
84454
- * @function
84455
- * @returns {MatcapUVNode}
84456
- */
84457
- const matcapUV = /*@__PURE__*/ nodeImmutable( MatcapUVNode );
84737
+ } ).once( [ 'NORMAL', 'VERTEX' ] )().toVar( 'matcapUV' );
84458
84738
 
84459
84739
  const _defaultValues$3 = /*@__PURE__*/ new MeshMatcapMaterial();
84460
84740
 
@@ -85488,6 +85768,16 @@ function InsertStackElement(node, body) {
85488
85768
  */
85489
85769
  this.attributes = null;
85490
85770
 
85771
+ /**
85772
+ * An object holding the version of the
85773
+ * attributes. The keys are the attribute names
85774
+ * and the values are the attribute versions.
85775
+ *
85776
+ * @type {?Object<string, number>}
85777
+ * @default null
85778
+ */
85779
+ this.attributesId = null;
85780
+
85491
85781
  /**
85492
85782
  * A reference to a render pipeline the render
85493
85783
  * object is processed with.
@@ -85607,7 +85897,7 @@ function InsertStackElement(node, body) {
85607
85897
 
85608
85898
  /**
85609
85899
  * An event listener which is executed when `dispose()` is called on
85610
- * the render object's material.
85900
+ * the material of this render object.
85611
85901
  *
85612
85902
  * @method
85613
85903
  */
@@ -85617,7 +85907,23 @@ function InsertStackElement(node, body) {
85617
85907
 
85618
85908
  };
85619
85909
 
85910
+ /**
85911
+ * An event listener which is executed when `dispose()` is called on
85912
+ * the geometry of this render object.
85913
+ *
85914
+ * @method
85915
+ */
85916
+ this.onGeometryDispose = () => {
85917
+
85918
+ // clear geometry cache attributes
85919
+
85920
+ this.attributes = null;
85921
+ this.attributesId = null;
85922
+
85923
+ };
85924
+
85620
85925
  this.material.addEventListener( 'dispose', this.onMaterialDispose );
85926
+ this.geometry.addEventListener( 'dispose', this.onGeometryDispose );
85621
85927
 
85622
85928
  }
85623
85929
 
@@ -85756,6 +86062,7 @@ function InsertStackElement(node, body) {
85756
86062
 
85757
86063
  this.geometry = geometry;
85758
86064
  this.attributes = null;
86065
+ this.attributesId = null;
85759
86066
 
85760
86067
  }
85761
86068
 
@@ -85775,9 +86082,25 @@ function InsertStackElement(node, body) {
85775
86082
  const attributes = [];
85776
86083
  const vertexBuffers = new Set();
85777
86084
 
86085
+ const attributesId = {};
86086
+
85778
86087
  for ( const nodeAttribute of nodeAttributes ) {
85779
86088
 
85780
- const attribute = nodeAttribute.node && nodeAttribute.node.attribute ? nodeAttribute.node.attribute : geometry.getAttribute( nodeAttribute.name );
86089
+ let attribute;
86090
+
86091
+ if ( nodeAttribute.node && nodeAttribute.node.attribute ) {
86092
+
86093
+ // node attribute
86094
+ attribute = nodeAttribute.node.attribute;
86095
+
86096
+ } else {
86097
+
86098
+ // geometry attribute
86099
+ attribute = geometry.getAttribute( nodeAttribute.name );
86100
+
86101
+ attributesId[ nodeAttribute.name ] = attribute.version;
86102
+
86103
+ }
85781
86104
 
85782
86105
  if ( attribute === undefined ) continue;
85783
86106
 
@@ -85789,6 +86112,7 @@ function InsertStackElement(node, body) {
85789
86112
  }
85790
86113
 
85791
86114
  this.attributes = attributes;
86115
+ this.attributesId = attributesId;
85792
86116
  this.vertexBuffers = Array.from( vertexBuffers.values() );
85793
86117
 
85794
86118
  return attributes;
@@ -86053,7 +86377,27 @@ function InsertStackElement(node, body) {
86053
86377
  */
86054
86378
  get needsGeometryUpdate() {
86055
86379
 
86056
- return this.geometry.id !== this.object.geometry.id;
86380
+ if ( this.geometry.id !== this.object.geometry.id ) return true;
86381
+
86382
+ if ( this.attributes !== null ) {
86383
+
86384
+ const attributesId = this.attributesId;
86385
+
86386
+ for ( const name in attributesId ) {
86387
+
86388
+ const attribute = this.geometry.getAttribute( name );
86389
+
86390
+ if ( attribute === undefined || attributesId[ name ] !== attribute.id ) {
86391
+
86392
+ return true;
86393
+
86394
+ }
86395
+
86396
+ }
86397
+
86398
+ }
86399
+
86400
+ return false;
86057
86401
 
86058
86402
  }
86059
86403
 
@@ -86131,6 +86475,7 @@ function InsertStackElement(node, body) {
86131
86475
  dispose() {
86132
86476
 
86133
86477
  this.material.removeEventListener( 'dispose', this.onMaterialDispose );
86478
+ this.geometry.removeEventListener( 'dispose', this.onGeometryDispose );
86134
86479
 
86135
86480
  this.onDispose();
86136
86481
 
@@ -89674,10 +90019,13 @@ function InsertStackElement(node, body) {
89674
90019
 
89675
90020
  build( builder, ...params ) {
89676
90021
 
90022
+ const previousBuildStack = builder.currentStack;
89677
90023
  const previousStack = getCurrentStack();
89678
90024
 
89679
90025
  setCurrentStack( this );
89680
90026
 
90027
+ builder.currentStack = this;
90028
+
89681
90029
  const buildStage = builder.buildStage;
89682
90030
 
89683
90031
  for ( const node of this.nodes ) {
@@ -89707,38 +90055,13 @@ function InsertStackElement(node, body) {
89707
90055
 
89708
90056
  }
89709
90057
 
89710
- setCurrentStack( previousStack );
89711
-
89712
- return this.outputNode ? this.outputNode.build( builder, ...params ) : super.build( builder, ...params );
89713
-
89714
- }
89715
-
89716
- // Deprecated
89717
-
89718
- /**
89719
- * @function
89720
- * @deprecated since r168. Use {@link StackNode#Else} instead.
89721
- *
89722
- * @param {...any} params
89723
- * @returns {StackNode}
89724
- */
89725
- else( ...params ) { // @deprecated, r168
89726
-
89727
- console.warn( 'THREE.TSL: .else() has been renamed to .Else().' );
89728
- return this.Else( ...params );
90058
+ const result = this.outputNode ? this.outputNode.build( builder, ...params ) : super.build( builder, ...params );
89729
90059
 
89730
- }
90060
+ setCurrentStack( previousStack );
89731
90061
 
89732
- /**
89733
- * @deprecated since r168. Use {@link StackNode#ElseIf} instead.
89734
- *
89735
- * @param {...any} params
89736
- * @returns {StackNode}
89737
- */
89738
- elseif( ...params ) { // @deprecated, r168
90062
+ builder.currentStack = previousBuildStack;
89739
90063
 
89740
- console.warn( 'THREE.TSL: .elseif() has been renamed to .ElseIf().' );
89741
- return this.ElseIf( ...params );
90064
+ return result;
89742
90065
 
89743
90066
  }
89744
90067
 
@@ -90042,9 +90365,9 @@ function InsertStackElement(node, body) {
90042
90365
 
90043
90366
  const step = 0.01;
90044
90367
 
90045
- const x = texture.sample( uv.add( vec3( -0.01, 0.0, 0.0 ) ) ).r.sub( texture.sample( uv.add( vec3( step, 0.0, 0.0 ) ) ).r );
90046
- const y = texture.sample( uv.add( vec3( 0.0, -0.01, 0.0 ) ) ).r.sub( texture.sample( uv.add( vec3( 0.0, step, 0.0 ) ) ).r );
90047
- const z = texture.sample( uv.add( vec3( 0.0, 0.0, -0.01 ) ) ).r.sub( texture.sample( uv.add( vec3( 0.0, 0.0, step ) ) ).r );
90368
+ const x = texture.sample( uv.add( vec3( - step, 0.0, 0.0 ) ) ).r.sub( texture.sample( uv.add( vec3( step, 0.0, 0.0 ) ) ).r );
90369
+ const y = texture.sample( uv.add( vec3( 0.0, - step, 0.0 ) ) ).r.sub( texture.sample( uv.add( vec3( 0.0, step, 0.0 ) ) ).r );
90370
+ const z = texture.sample( uv.add( vec3( 0.0, 0.0, - step ) ) ).r.sub( texture.sample( uv.add( vec3( 0.0, 0.0, step ) ) ).r );
90048
90371
 
90049
90372
  ret.assign( vec3( x, y, z ) );
90050
90373
 
@@ -90305,7 +90628,16 @@ function InsertStackElement(node, body) {
90305
90628
 
90306
90629
  clone() {
90307
90630
 
90308
- return new this.constructor( this.passNode, this.textureName, this.previousTexture );
90631
+ const newNode = new this.constructor( this.passNode, this.textureName, this.previousTexture );
90632
+ newNode.uvNode = this.uvNode;
90633
+ newNode.levelNode = this.levelNode;
90634
+ newNode.biasNode = this.biasNode;
90635
+ newNode.sampler = this.sampler;
90636
+ newNode.depthNode = this.depthNode;
90637
+ newNode.compareNode = this.compareNode;
90638
+ newNode.gradNode = this.gradNode;
90639
+
90640
+ return newNode;
90309
90641
 
90310
90642
  }
90311
90643
 
@@ -90765,13 +91097,6 @@ function InsertStackElement(node, body) {
90765
91097
 
90766
91098
  this.renderTarget.samples = this.options.samples === undefined ? renderer.samples : this.options.samples;
90767
91099
 
90768
- // TODO: Disable MSAA for WebGL backend for now
90769
- if ( renderer.backend.isWebGLBackend === true ) {
90770
-
90771
- this.renderTarget.samples = 0;
90772
-
90773
- }
90774
-
90775
91100
  this.renderTarget.texture.type = renderer.getColorBufferType();
90776
91101
 
90777
91102
  return this.scope === PassNode.COLOR ? this.getTextureNode() : this.getLinearDepthNode();
@@ -91853,21 +92178,21 @@ function InsertStackElement(node, body) {
91853
92178
  *
91854
92179
  * @type {Node<vec3>}
91855
92180
  */
91856
- this.totalDiffuseNode = vec3().toVar();
92181
+ this.totalDiffuseNode = property( 'vec3', 'totalDiffuse' );
91857
92182
 
91858
92183
  /**
91859
92184
  * A node representing the total specular light.
91860
92185
  *
91861
92186
  * @type {Node<vec3>}
91862
92187
  */
91863
- this.totalSpecularNode = vec3().toVar();
92188
+ this.totalSpecularNode = property( 'vec3', 'totalSpecular' );
91864
92189
 
91865
92190
  /**
91866
92191
  * A node representing the outgoing light.
91867
92192
  *
91868
92193
  * @type {Node<vec3>}
91869
92194
  */
91870
- this.outgoingLightNode = vec3().toVar();
92195
+ this.outgoingLightNode = property( 'vec3', 'outgoingLight' );
91871
92196
 
91872
92197
  /**
91873
92198
  * An array representing the lights in the scene.
@@ -93214,7 +93539,7 @@ function InsertStackElement(node, body) {
93214
93539
  const shadowIntensity = reference( 'intensity', 'float', shadow ).setGroup( renderGroup );
93215
93540
  const normalBias = reference( 'normalBias', 'float', shadow ).setGroup( renderGroup );
93216
93541
 
93217
- const shadowPosition = lightShadowMatrix( light ).mul( shadowPositionWorld.add( transformedNormalWorld.mul( normalBias ) ) );
93542
+ const shadowPosition = lightShadowMatrix( light ).mul( shadowPositionWorld.add( normalWorld.mul( normalBias ) ) );
93218
93543
  const shadowCoord = this.setupShadowCoord( builder, shadowPosition );
93219
93544
 
93220
93545
  //
@@ -94135,7 +94460,7 @@ function InsertStackElement(node, body) {
94135
94460
  * @param {Node<vec2>} coord - The uv to generate the circle.
94136
94461
  * @return {Node<float>} The circle shape.
94137
94462
  */
94138
- Fn( ( [ coord = uv() ], { renderer, material } ) => {
94463
+ Fn( ( [ coord = uv$1() ], { renderer, material } ) => {
94139
94464
 
94140
94465
  const len2 = lengthSq( coord.mul( 2 ).sub( 1 ) );
94141
94466
 
@@ -94264,7 +94589,7 @@ function InsertStackElement(node, body) {
94264
94589
 
94265
94590
  const backgroundMeshNode = context( vec4( backgroundNode ).mul( backgroundIntensity ), {
94266
94591
  // @TODO: Add Texture2D support using node context
94267
- getUV: () => backgroundRotation.mul( normalWorld ),
94592
+ getUV: () => backgroundRotation.mul( normalWorldGeometry ),
94268
94593
  getTextureLevel: () => backgroundBlurriness
94269
94594
  } );
94270
94595
 
@@ -96134,6 +96459,30 @@ function InsertStackElement(node, body) {
96134
96459
  */
96135
96460
  this.buildStage = null;
96136
96461
 
96462
+ /**
96463
+ * The sub-build layers.
96464
+ *
96465
+ * @type {Array<SubBuildNode>}
96466
+ * @default []
96467
+ */
96468
+ this.subBuildLayers = [];
96469
+
96470
+ /**
96471
+ * The current stack of nodes.
96472
+ *
96473
+ * @type {?StackNode}
96474
+ * @default null
96475
+ */
96476
+ this.currentStack = null;
96477
+
96478
+ /**
96479
+ * The current sub-build TSL function(Fn).
96480
+ *
96481
+ * @type {?string}
96482
+ * @default null
96483
+ */
96484
+ this.subBuildFn = null;
96485
+
96137
96486
  }
96138
96487
 
96139
96488
  /**
@@ -97290,7 +97639,23 @@ function InsertStackElement(node, body) {
97290
97639
 
97291
97640
  if ( nodeData[ shaderStage ] === undefined ) nodeData[ shaderStage ] = {};
97292
97641
 
97293
- return nodeData[ shaderStage ];
97642
+ //
97643
+
97644
+ let data = nodeData[ shaderStage ];
97645
+
97646
+ const subBuilds = nodeData.any ? nodeData.any.subBuilds : null;
97647
+ const subBuild = this.getClosestSubBuild( subBuilds );
97648
+
97649
+ if ( subBuild ) {
97650
+
97651
+ if ( data.subBuildsCache === undefined ) data.subBuildsCache = {};
97652
+
97653
+ data = data.subBuildsCache[ subBuild ] || ( data.subBuildsCache[ subBuild ] = {} );
97654
+ data.subBuilds = subBuilds;
97655
+
97656
+ }
97657
+
97658
+ return data;
97294
97659
 
97295
97660
  }
97296
97661
 
@@ -97451,8 +97816,9 @@ function InsertStackElement(node, body) {
97451
97816
  getVarFromNode( node, name = null, type = node.getNodeType( this ), shaderStage = this.shaderStage, readOnly = false ) {
97452
97817
 
97453
97818
  const nodeData = this.getDataFromNode( node, shaderStage );
97819
+ const subBuildVariable = this.getSubBuildProperty( 'variable', nodeData.subBuilds );
97454
97820
 
97455
- let nodeVar = nodeData.variable;
97821
+ let nodeVar = nodeData[ subBuildVariable ];
97456
97822
 
97457
97823
  if ( nodeVar === undefined ) {
97458
97824
 
@@ -97471,6 +97837,14 @@ function InsertStackElement(node, body) {
97471
97837
 
97472
97838
  //
97473
97839
 
97840
+ if ( subBuildVariable !== 'variable' ) {
97841
+
97842
+ name = this.getSubBuildProperty( name, nodeData.subBuilds );
97843
+
97844
+ }
97845
+
97846
+ //
97847
+
97474
97848
  const count = this.getArrayCount( node );
97475
97849
 
97476
97850
  nodeVar = new NodeVar( name, type, readOnly, count );
@@ -97483,7 +97857,7 @@ function InsertStackElement(node, body) {
97483
97857
 
97484
97858
  this.registerDeclaration( nodeVar );
97485
97859
 
97486
- nodeData.variable = nodeVar;
97860
+ nodeData[ subBuildVariable ] = nodeVar;
97487
97861
 
97488
97862
  }
97489
97863
 
@@ -97551,8 +97925,9 @@ function InsertStackElement(node, body) {
97551
97925
  getVaryingFromNode( node, name = null, type = node.getNodeType( this ), interpolationType = null, interpolationSampling = null ) {
97552
97926
 
97553
97927
  const nodeData = this.getDataFromNode( node, 'any' );
97928
+ const subBuildVarying = this.getSubBuildProperty( 'varying', nodeData.subBuilds );
97554
97929
 
97555
- let nodeVarying = nodeData.varying;
97930
+ let nodeVarying = nodeData[ subBuildVarying ];
97556
97931
 
97557
97932
  if ( nodeVarying === undefined ) {
97558
97933
 
@@ -97561,69 +97936,27 @@ function InsertStackElement(node, body) {
97561
97936
 
97562
97937
  if ( name === null ) name = 'nodeVarying' + index;
97563
97938
 
97564
- nodeVarying = new NodeVarying( name, type, interpolationType, interpolationSampling );
97565
-
97566
- varyings.push( nodeVarying );
97567
-
97568
- this.registerDeclaration( nodeVarying );
97569
-
97570
- nodeData.varying = nodeVarying;
97571
-
97572
- }
97573
-
97574
- return nodeVarying;
97575
-
97576
- }
97577
-
97578
- /**
97579
- * Returns the current namespace for the node builder.
97580
- *
97581
- * @return {string} The current namespace.
97582
- */
97583
- get namespace() {
97584
-
97585
- return this.context.namespace;
97586
-
97587
- }
97588
-
97589
- /**
97590
- * Returns the output namespace for the node builder, which is used for the current output node.
97591
- *
97592
- * @return {string} The output namespace.
97593
- */
97594
- getOutputNamespace() {
97595
-
97596
- return this.getNamespace( 'outputNode' );
97939
+ //
97597
97940
 
97598
- }
97941
+ if ( subBuildVarying !== 'varying' ) {
97599
97942
 
97600
- /**
97601
- * Returns the namespace for the given property.
97602
- *
97603
- * If the property name is not set, it returns the namespace only.
97604
- * If the namespace is not set, it returns the property name.
97605
- * If the namespace is set, it returns the namespace concatenated with the property name.
97606
- *
97607
- * @param {string} [property=''] - The property name.
97608
- * @return {string} The namespace for the property.
97609
- */
97610
- getNamespace( property = '' ) {
97943
+ name = this.getSubBuildProperty( name, nodeData.subBuilds );
97611
97944
 
97612
- const ns = this.namespace;
97945
+ }
97613
97946
 
97614
- let nsName;
97947
+ //
97615
97948
 
97616
- if ( ns ) {
97949
+ nodeVarying = new NodeVarying( name, type, interpolationType, interpolationSampling );
97617
97950
 
97618
- nsName = property ? ( ns + '_' + property ) : ns;
97951
+ varyings.push( nodeVarying );
97619
97952
 
97620
- } else {
97953
+ this.registerDeclaration( nodeVarying );
97621
97954
 
97622
- nsName = property;
97955
+ nodeData[ subBuildVarying ] = nodeVarying;
97623
97956
 
97624
97957
  }
97625
97958
 
97626
- return nsName;
97959
+ return nodeVarying;
97627
97960
 
97628
97961
  }
97629
97962
 
@@ -98280,6 +98613,145 @@ function InsertStackElement(node, body) {
98280
98613
 
98281
98614
  }
98282
98615
 
98616
+ /**
98617
+ * Returns the current sub-build layer.
98618
+ *
98619
+ * @return {SubBuildNode} The current sub-build layers.
98620
+ */
98621
+ get subBuild() {
98622
+
98623
+ return this.subBuildLayers[ this.subBuildLayers.length - 1 ] || null;
98624
+
98625
+ }
98626
+
98627
+ /**
98628
+ * Adds a sub-build layer to the node builder.
98629
+ *
98630
+ * @param {SubBuildNode} subBuild - The sub-build layer to add.
98631
+ */
98632
+ addSubBuild( subBuild ) {
98633
+
98634
+ this.subBuildLayers.push( subBuild );
98635
+
98636
+ }
98637
+
98638
+ /**
98639
+ * Removes the last sub-build layer from the node builder.
98640
+ *
98641
+ * @return {SubBuildNode} The removed sub-build layer.
98642
+ */
98643
+ removeSubBuild() {
98644
+
98645
+ return this.subBuildLayers.pop();
98646
+
98647
+ }
98648
+
98649
+ /**
98650
+ * Returns the closest sub-build layer for the given data.
98651
+ *
98652
+ * @param {Node|Set|Array} data - The data to get the closest sub-build layer from.
98653
+ * @return {?string} The closest sub-build name or null if none found.
98654
+ */
98655
+ getClosestSubBuild( data ) {
98656
+
98657
+ let subBuilds;
98658
+
98659
+ if ( data && data.isNode ) {
98660
+
98661
+ if ( data.isShaderCallNodeInternal ) {
98662
+
98663
+ subBuilds = data.shaderNode.subBuilds;
98664
+
98665
+ } else if ( data.isStackNode ) {
98666
+
98667
+ subBuilds = [ data.subBuild ];
98668
+
98669
+ } else {
98670
+
98671
+ subBuilds = this.getDataFromNode( data, 'any' ).subBuilds;
98672
+
98673
+ }
98674
+
98675
+ } else if ( data instanceof Set ) {
98676
+
98677
+ subBuilds = [ ...data ];
98678
+
98679
+ } else {
98680
+
98681
+ subBuilds = data;
98682
+
98683
+ }
98684
+
98685
+ if ( ! subBuilds ) return null;
98686
+
98687
+ const subBuildLayers = this.subBuildLayers;
98688
+
98689
+ for ( let i = subBuilds.length - 1; i >= 0; i -- ) {
98690
+
98691
+ const subBuild = subBuilds[ i ];
98692
+
98693
+ if ( subBuildLayers.includes( subBuild ) ) {
98694
+
98695
+ return subBuild;
98696
+
98697
+ }
98698
+
98699
+ }
98700
+
98701
+ return null;
98702
+
98703
+ }
98704
+
98705
+
98706
+ /**
98707
+ * Returns the output node of a sub-build layer.
98708
+ *
98709
+ * @param {Node} node - The node to get the output from.
98710
+ * @return {string} The output node name.
98711
+ */
98712
+ getSubBuildOutput( node ) {
98713
+
98714
+ return this.getSubBuildProperty( 'outputNode', node );
98715
+
98716
+ }
98717
+
98718
+ /**
98719
+ * Returns the sub-build property name for the given property and node.
98720
+ *
98721
+ * @param {string} [property=''] - The property name.
98722
+ * @param {?Node} [node=null] - The node to get the sub-build from.
98723
+ * @return {string} The sub-build property name.
98724
+ */
98725
+ getSubBuildProperty( property = '', node = null ) {
98726
+
98727
+ let subBuild;
98728
+
98729
+ if ( node !== null ) {
98730
+
98731
+ subBuild = this.getClosestSubBuild( node );
98732
+
98733
+ } else {
98734
+
98735
+ subBuild = this.subBuildFn;
98736
+
98737
+ }
98738
+
98739
+ let result;
98740
+
98741
+ if ( subBuild ) {
98742
+
98743
+ result = property ? ( subBuild + '_' + property ) : subBuild;
98744
+
98745
+ } else {
98746
+
98747
+ result = property;
98748
+
98749
+ }
98750
+
98751
+ return result;
98752
+
98753
+ }
98754
+
98283
98755
  /**
98284
98756
  * Central build method which controls the build for the given object.
98285
98757
  *
@@ -98489,22 +98961,6 @@ function InsertStackElement(node, body) {
98489
98961
  */
98490
98962
  *[ Symbol.iterator ]() { }
98491
98963
 
98492
- // Deprecated
98493
-
98494
- /**
98495
- * @function
98496
- * @deprecated since r168. Use `new NodeMaterial()` instead, with targeted node material name.
98497
- *
98498
- * @param {string} [type='NodeMaterial'] - The node material type.
98499
- * @throws {Error}
98500
- */
98501
- createNodeMaterial( type = 'NodeMaterial' ) { // @deprecated, r168
98502
-
98503
- throw new Error( `THREE.NodeBuilder: createNodeMaterial() was deprecated. Use new ${ type }() instead.` );
98504
-
98505
- }
98506
-
98507
-
98508
98964
  }
98509
98965
 
98510
98966
  /**
@@ -101194,10 +101650,11 @@ function InsertStackElement(node, body) {
101194
101650
  * are defined by external textures. This flag is
101195
101651
  * set to `true` when using the WebXR Layers API.
101196
101652
  *
101653
+ * @private
101197
101654
  * @type {boolean}
101198
101655
  * @default false
101199
101656
  */
101200
- this.hasExternalTextures = false;
101657
+ this._hasExternalTextures = false;
101201
101658
 
101202
101659
  /**
101203
101660
  * Whether a depth buffer should automatically be allocated
@@ -101210,10 +101667,25 @@ function InsertStackElement(node, body) {
101210
101667
  *
101211
101668
  * Reference: {@link https://www.w3.org/TR/webxrlayers-1/#dom-xrprojectionlayer-ignoredepthvalues}.
101212
101669
  *
101670
+ * @private
101213
101671
  * @type {boolean}
101214
101672
  * @default true
101215
101673
  */
101216
- this.autoAllocateDepthBuffer = true;
101674
+ this._autoAllocateDepthBuffer = true;
101675
+
101676
+ /**
101677
+ * Whether this render target is associated with a XRWebGLLayer.
101678
+ *
101679
+ * A XRWebGLLayer points to an opaque framebuffer. Basically,
101680
+ * this means that you don't have access to its bound color,
101681
+ * stencil and depth buffers. We need to handle this framebuffer
101682
+ * differently since its textures are always bound.
101683
+ *
101684
+ * @private
101685
+ * @type {boolean}
101686
+ * @default false
101687
+ * */
101688
+ this._isOpaqueFramebuffer = false;
101217
101689
 
101218
101690
  }
101219
101691
 
@@ -101221,8 +101693,9 @@ function InsertStackElement(node, body) {
101221
101693
 
101222
101694
  super.copy( source );
101223
101695
 
101224
- this.hasExternalTextures = source.hasExternalTextures;
101225
- this.autoAllocateDepthBuffer = source.autoAllocateDepthBuffer;
101696
+ this._hasExternalTextures = source._hasExternalTextures;
101697
+ this._autoAllocateDepthBuffer = source._autoAllocateDepthBuffer;
101698
+ this._isOpaqueFramebuffer = source._isOpaqueFramebuffer;
101226
101699
 
101227
101700
  return this;
101228
101701
 
@@ -101855,7 +102328,7 @@ function InsertStackElement(node, body) {
101855
102328
  resolveStencilBuffer: false
101856
102329
  } );
101857
102330
 
101858
- renderTarget.autoAllocateDepthBuffer = true;
102331
+ renderTarget._autoAllocateDepthBuffer = true;
101859
102332
 
101860
102333
  const material = new MeshBasicMaterial( { color: 0xffffff, side: FrontSide } );
101861
102334
  material.map = renderTarget.texture;
@@ -101946,7 +102419,7 @@ function InsertStackElement(node, body) {
101946
102419
  resolveStencilBuffer: false
101947
102420
  } );
101948
102421
 
101949
- renderTarget.autoAllocateDepthBuffer = true;
102422
+ renderTarget._autoAllocateDepthBuffer = true;
101950
102423
 
101951
102424
  const material = new MeshBasicMaterial( { color: 0xffffff, side: BackSide } );
101952
102425
  material.map = renderTarget.texture;
@@ -102020,7 +102493,7 @@ function InsertStackElement(node, body) {
102020
102493
  for ( const layer of this._layers ) {
102021
102494
 
102022
102495
  layer.renderTarget.isXRRenderTarget = this._session !== null;
102023
- layer.renderTarget.hasExternalTextures = layer.renderTarget.isXRRenderTarget;
102496
+ layer.renderTarget._hasExternalTextures = layer.renderTarget.isXRRenderTarget;
102024
102497
 
102025
102498
  if ( layer.renderTarget.isXRRenderTarget && this._supportsLayers ) {
102026
102499
 
@@ -102188,7 +102661,7 @@ function InsertStackElement(node, body) {
102188
102661
  multiview: this._useMultiview
102189
102662
  } );
102190
102663
 
102191
- this._xrRenderTarget.hasExternalTextures = true;
102664
+ this._xrRenderTarget._hasExternalTextures = true;
102192
102665
  this._xrRenderTarget.depth = this._useMultiview ? 2 : 1;
102193
102666
 
102194
102667
  this._supportsLayers = session.enabledFeatures.includes( 'layers' );
@@ -102250,6 +102723,7 @@ function InsertStackElement(node, body) {
102250
102723
  }
102251
102724
  );
102252
102725
 
102726
+ this._xrRenderTarget._isOpaqueFramebuffer = true;
102253
102727
  this._referenceSpace = await session.requestReferenceSpace( this.getReferenceSpaceType() );
102254
102728
 
102255
102729
  }
@@ -104077,7 +104551,7 @@ function InsertStackElement(node, body) {
104077
104551
  frameBufferTarget.scissorTest = this._scissorTest;
104078
104552
  frameBufferTarget.multiview = outputRenderTarget !== null ? outputRenderTarget.multiview : false;
104079
104553
  frameBufferTarget.resolveDepthBuffer = outputRenderTarget !== null ? outputRenderTarget.resolveDepthBuffer : true;
104080
- frameBufferTarget.autoAllocateDepthBuffer = outputRenderTarget !== null ? outputRenderTarget.autoAllocateDepthBuffer : false;
104554
+ frameBufferTarget._autoAllocateDepthBuffer = outputRenderTarget !== null ? outputRenderTarget._autoAllocateDepthBuffer : false;
104081
104555
 
104082
104556
  return frameBufferTarget;
104083
104557
 
@@ -106929,9 +107403,7 @@ function InsertStackElement(node, body) {
106929
107403
  };
106930
107404
 
106931
107405
  const interpolationModeMap = {
106932
- 'centroid': 'centroid',
106933
- 'flat first': 'flat',
106934
- 'flat either': 'flat'
107406
+ 'centroid': 'centroid'
106935
107407
  };
106936
107408
 
106937
107409
  const defaultPrecisions = `
@@ -109094,6 +109566,10 @@ void main() {
109094
109566
 
109095
109567
  type = gl.FLOAT;
109096
109568
 
109569
+ } else if ( typeof Float16Array !== 'undefined' && array instanceof Float16Array ) {
109570
+
109571
+ type = gl.HALF_FLOAT;
109572
+
109097
109573
  } else if ( array instanceof Uint16Array ) {
109098
109574
 
109099
109575
  if ( attribute.isFloat16BufferAttribute ) {
@@ -109629,7 +110105,7 @@ void main() {
109629
110105
  break;
109630
110106
 
109631
110107
  case MultiplyBlending:
109632
- gl.blendFuncSeparate( gl.ZERO, gl.SRC_COLOR, gl.ZERO, gl.SRC_ALPHA );
110108
+ gl.blendFuncSeparate( gl.DST_COLOR, gl.ONE_MINUS_SRC_ALPHA, gl.ZERO, gl.ONE );
109633
110109
  break;
109634
110110
 
109635
110111
  default:
@@ -109647,15 +110123,15 @@ void main() {
109647
110123
  break;
109648
110124
 
109649
110125
  case AdditiveBlending:
109650
- gl.blendFunc( gl.SRC_ALPHA, gl.ONE );
110126
+ gl.blendFuncSeparate( gl.SRC_ALPHA, gl.ONE, gl.ONE, gl.ONE );
109651
110127
  break;
109652
110128
 
109653
110129
  case SubtractiveBlending:
109654
- gl.blendFuncSeparate( gl.ZERO, gl.ONE_MINUS_SRC_COLOR, gl.ZERO, gl.ONE );
110130
+ console.error( 'THREE.WebGLState: SubtractiveBlending requires material.premultipliedAlpha = true' );
109655
110131
  break;
109656
110132
 
109657
110133
  case MultiplyBlending:
109658
- gl.blendFunc( gl.ZERO, gl.SRC_COLOR );
110134
+ console.error( 'THREE.WebGLState: MultiplyBlending requires material.premultipliedAlpha = true' );
109659
110135
  break;
109660
110136
 
109661
110137
  default:
@@ -111758,6 +112234,8 @@ void main() {
111758
112234
 
111759
112235
  }
111760
112236
 
112237
+ gl.bindRenderbuffer( gl.RENDERBUFFER, null );
112238
+
111761
112239
  }
111762
112240
 
111763
112241
  /**
@@ -112998,13 +113476,13 @@ void main() {
112998
113476
 
112999
113477
  // The multisample_render_to_texture extension doesn't work properly if there
113000
113478
  // are midframe flushes and an external depth texture.
113001
- if ( ( this.extensions.has( 'WEBGL_multisampled_render_to_texture' ) === true ) && renderTarget.autoAllocateDepthBuffer === true && renderTarget.multiview === false ) {
113479
+ if ( ( this.extensions.has( 'WEBGL_multisampled_render_to_texture' ) === true ) && renderTarget._autoAllocateDepthBuffer === true && renderTarget.multiview === false ) {
113002
113480
 
113003
113481
  console.warn( 'THREE.WebGLBackend: Render-to-texture extension was disabled because an external texture was provided' );
113004
113482
 
113005
113483
  }
113006
113484
 
113007
- renderTarget.autoAllocateDepthBuffer = false;
113485
+ renderTarget._autoAllocateDepthBuffer = false;
113008
113486
 
113009
113487
  }
113010
113488
 
@@ -113177,29 +113655,60 @@ void main() {
113177
113655
  }
113178
113656
 
113179
113657
  this._currentContext = previousContext;
113658
+ const renderTarget = renderContext.renderTarget;
113180
113659
 
113181
- if ( renderContext.textures !== null && renderContext.renderTarget ) {
113182
-
113183
- const renderTargetContextData = this.get( renderContext.renderTarget );
113660
+ if ( renderContext.textures !== null && renderTarget ) {
113184
113661
 
113185
- const { resolveDepthBuffer, samples } = renderContext.renderTarget;
113662
+ const renderTargetContextData = this.get( renderTarget );
113186
113663
 
113187
- if ( samples > 0 && this._useMultisampledExtension( renderContext.renderTarget ) === false ) {
113664
+ if ( renderTarget.samples > 0 && this._useMultisampledExtension( renderTarget ) === false ) {
113188
113665
 
113189
113666
  const fb = renderTargetContextData.framebuffers[ renderContext.getCacheKey() ];
113190
113667
 
113191
- const mask = gl.COLOR_BUFFER_BIT;
113668
+ let mask = gl.COLOR_BUFFER_BIT;
113669
+
113670
+ if ( renderTarget.resolveDepthBuffer ) {
113671
+
113672
+ if ( renderTarget.depthBuffer ) mask |= gl.DEPTH_BUFFER_BIT;
113673
+ if ( renderTarget.stencilBuffer && renderTarget.resolveStencilBuffer ) mask |= gl.STENCIL_BUFFER_BIT;
113674
+
113675
+ }
113192
113676
 
113193
113677
  const msaaFrameBuffer = renderTargetContextData.msaaFrameBuffer;
113678
+ const msaaRenderbuffers = renderTargetContextData.msaaRenderbuffers;
113194
113679
 
113195
113680
  const textures = renderContext.textures;
113681
+ const isMRT = textures.length > 1;
113196
113682
 
113197
113683
  state.bindFramebuffer( gl.READ_FRAMEBUFFER, msaaFrameBuffer );
113198
113684
  state.bindFramebuffer( gl.DRAW_FRAMEBUFFER, fb );
113199
113685
 
113686
+ if ( isMRT ) {
113687
+
113688
+ // blitFramebuffer() can only copy/resolve the first color attachment of a framebuffer. When using MRT,
113689
+ // the engine temporarily removes all attachments and then configures each attachment for the resolve.
113690
+
113691
+ for ( let i = 0; i < textures.length; i ++ ) {
113692
+
113693
+ gl.framebufferRenderbuffer( gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + i, gl.RENDERBUFFER, null );
113694
+ gl.framebufferTexture2D( gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + i, gl.TEXTURE_2D, null, 0 );
113695
+
113696
+ }
113697
+
113698
+ }
113699
+
113200
113700
  for ( let i = 0; i < textures.length; i ++ ) {
113201
113701
 
113202
- // TODO Add support for MRT
113702
+ if ( isMRT ) {
113703
+
113704
+ // configure attachment for resolve
113705
+
113706
+ const { textureGPU } = this.get( textures[ i ] );
113707
+
113708
+ gl.framebufferRenderbuffer( gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, msaaRenderbuffers[ i ] );
113709
+ gl.framebufferTexture2D( gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, textureGPU, 0 );
113710
+
113711
+ }
113203
113712
 
113204
113713
  if ( renderContext.scissor ) {
113205
113714
 
@@ -113209,27 +113718,36 @@ void main() {
113209
113718
 
113210
113719
  gl.blitFramebuffer( x, viewY, x + width, viewY + height, x, viewY, x + width, viewY + height, mask, gl.NEAREST );
113211
113720
 
113212
- if ( this._supportsInvalidateFramebuffer === true ) {
113721
+ } else {
113213
113722
 
113214
- gl.invalidateSubFramebuffer( gl.READ_FRAMEBUFFER, renderTargetContextData.invalidationArray, x, viewY, width, height );
113723
+ gl.blitFramebuffer( 0, 0, renderContext.width, renderContext.height, 0, 0, renderContext.width, renderContext.height, mask, gl.NEAREST );
113215
113724
 
113216
- }
113725
+ }
113217
113726
 
113218
- } else {
113727
+ }
113219
113728
 
113220
- gl.blitFramebuffer( 0, 0, renderContext.width, renderContext.height, 0, 0, renderContext.width, renderContext.height, mask, gl.NEAREST );
113729
+ if ( isMRT ) {
113221
113730
 
113222
- if ( this._supportsInvalidateFramebuffer === true ) {
113731
+ // restore attachments
113223
113732
 
113224
- gl.invalidateFramebuffer( gl.READ_FRAMEBUFFER, renderTargetContextData.invalidationArray );
113733
+ for ( let i = 0; i < textures.length; i ++ ) {
113225
113734
 
113226
- }
113735
+ const { textureGPU } = this.get( textures[ i ] );
113736
+
113737
+ gl.framebufferRenderbuffer( gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + i, gl.RENDERBUFFER, msaaRenderbuffers[ i ] );
113738
+ gl.framebufferTexture2D( gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + i, gl.TEXTURE_2D, textureGPU, 0 );
113227
113739
 
113228
113740
  }
113229
113741
 
113230
113742
  }
113231
113743
 
113232
- } else if ( resolveDepthBuffer === false && renderTargetContextData.framebuffers ) {
113744
+ if ( this._supportsInvalidateFramebuffer === true ) {
113745
+
113746
+ gl.invalidateFramebuffer( gl.READ_FRAMEBUFFER, renderTargetContextData.invalidationArray );
113747
+
113748
+ }
113749
+
113750
+ } else if ( renderTarget.resolveDepthBuffer === false && renderTargetContextData.framebuffers ) {
113233
113751
 
113234
113752
  const fb = renderTargetContextData.framebuffers[ renderContext.getCacheKey() ];
113235
113753
  state.bindFramebuffer( gl.DRAW_FRAMEBUFFER, fb );
@@ -113530,7 +114048,7 @@ void main() {
113530
114048
 
113531
114049
  if ( vaoGPU === undefined ) {
113532
114050
 
113533
- this._createVao( attributes );
114051
+ this.vaoCache[ vaoKey ] = this._createVao( attributes );
113534
114052
 
113535
114053
  } else {
113536
114054
 
@@ -113566,7 +114084,7 @@ void main() {
113566
114084
 
113567
114085
  const dualAttributeData = transformBuffers[ i ];
113568
114086
 
113569
- if ( dualAttributeData.pbo ) {
114087
+ if ( dualAttributeData.pbo && this.has( dualAttributeData.pbo ) ) {
113570
114088
 
113571
114089
  this.textureUtils.copyBufferToTexture( dualAttributeData.transformBuffer, dualAttributeData.pbo );
113572
114090
 
@@ -113648,28 +114166,23 @@ void main() {
113648
114166
 
113649
114167
  // vertex state
113650
114168
 
113651
- const renderObjectData = this.get( renderObject );
114169
+ const attributes = renderObject.getAttributes();
114170
+ const attributesData = this.get( attributes );
113652
114171
 
113653
- let vaoGPU = renderObjectData.staticVao;
114172
+ let vaoGPU = attributesData.vaoGPU;
113654
114173
 
113655
- if ( vaoGPU === undefined || renderObjectData.geometryId !== renderObject.geometry.id ) {
114174
+ if ( vaoGPU === undefined ) {
113656
114175
 
113657
- const vaoKey = this._getVaoKey( renderObject.getAttributes() );
114176
+ const vaoKey = this._getVaoKey( attributes );
113658
114177
 
113659
114178
  vaoGPU = this.vaoCache[ vaoKey ];
113660
114179
 
113661
114180
  if ( vaoGPU === undefined ) {
113662
114181
 
113663
- let staticVao;
114182
+ vaoGPU = this._createVao( attributes );
113664
114183
 
113665
- ( { vaoGPU, staticVao } = this._createVao( renderObject.getAttributes() ) );
113666
-
113667
- if ( staticVao ) {
113668
-
113669
- renderObjectData.staticVao = vaoGPU;
113670
- renderObjectData.geometryId = renderObject.geometry.id;
113671
-
113672
- }
114184
+ this.vaoCache[ vaoKey ] = vaoGPU;
114185
+ attributesData.vaoGPU = vaoGPU;
113673
114186
 
113674
114187
  }
113675
114188
 
@@ -114636,7 +115149,7 @@ void main() {
114636
115149
  const isRenderTarget3D = renderTarget.isRenderTarget3D === true;
114637
115150
  const isRenderTargetArray = renderTarget.depth > 1;
114638
115151
  const isXRRenderTarget = renderTarget.isXRRenderTarget === true;
114639
- const hasExternalTextures = ( isXRRenderTarget === true && renderTarget.hasExternalTextures === true );
115152
+ const _hasExternalTextures = ( isXRRenderTarget === true && renderTarget._hasExternalTextures === true );
114640
115153
 
114641
115154
  let msaaFb = renderTargetContextData.msaaFrameBuffer;
114642
115155
  let depthRenderbuffer = renderTargetContextData.depthRenderbuffer;
@@ -114653,7 +115166,7 @@ void main() {
114653
115166
 
114654
115167
  fb = renderTargetContextData.cubeFramebuffers[ cacheKey ];
114655
115168
 
114656
- } else if ( isXRRenderTarget && hasExternalTextures === false ) {
115169
+ } else if ( isXRRenderTarget && _hasExternalTextures === false ) {
114657
115170
 
114658
115171
  fb = this._xrFramebuffer;
114659
115172
 
@@ -114723,13 +115236,11 @@ void main() {
114723
115236
 
114724
115237
  }
114725
115238
 
114726
- state.drawBuffers( descriptor, fb );
114727
-
114728
115239
  }
114729
115240
 
114730
115241
  const depthStyle = stencilBuffer ? gl.DEPTH_STENCIL_ATTACHMENT : gl.DEPTH_ATTACHMENT;
114731
115242
 
114732
- if ( renderTarget.autoAllocateDepthBuffer === true ) {
115243
+ if ( renderTarget._autoAllocateDepthBuffer === true ) {
114733
115244
 
114734
115245
  const renderbuffer = gl.createRenderbuffer();
114735
115246
  this.textureUtils.setupRenderBufferStorage( renderbuffer, descriptor, 0, useMultisampledRTT );
@@ -114754,7 +115265,7 @@ void main() {
114754
115265
 
114755
115266
  multiviewExt.framebufferTextureMultisampleMultiviewOVR( gl.FRAMEBUFFER, depthStyle, textureData.textureGPU, 0, samples, 0, 2 );
114756
115267
 
114757
- } else if ( hasExternalTextures && useMultisampledRTT ) {
115268
+ } else if ( _hasExternalTextures && useMultisampledRTT ) {
114758
115269
 
114759
115270
  multisampledRTTExt.framebufferTexture2DMultisampleEXT( gl.FRAMEBUFFER, depthStyle, gl.TEXTURE_2D, textureData.textureGPU, 0, samples );
114760
115271
 
@@ -114805,7 +115316,7 @@ void main() {
114805
115316
 
114806
115317
  // rebind external XR textures
114807
115318
 
114808
- if ( isXRRenderTarget || useMultisampledRTT || renderTarget.multiview ) {
115319
+ if ( ( isXRRenderTarget || useMultisampledRTT || renderTarget.multiview ) && ( renderTarget._isOpaqueFramebuffer !== true ) ) {
114809
115320
 
114810
115321
  state.bindFramebuffer( gl.FRAMEBUFFER, fb );
114811
115322
 
@@ -114831,7 +115342,7 @@ void main() {
114831
115342
 
114832
115343
  const depthStyle = stencilBuffer ? gl.DEPTH_STENCIL_ATTACHMENT : gl.DEPTH_ATTACHMENT;
114833
115344
 
114834
- if ( renderTarget.autoAllocateDepthBuffer === true ) {
115345
+ if ( renderTarget._autoAllocateDepthBuffer === true ) {
114835
115346
 
114836
115347
  const renderbuffer = renderTargetContextData.xrDepthRenderbuffer;
114837
115348
  gl.bindRenderbuffer( gl.RENDERBUFFER, renderbuffer );
@@ -114883,13 +115394,6 @@ void main() {
114883
115394
 
114884
115395
  invalidationArray.push( gl.COLOR_ATTACHMENT0 + i );
114885
115396
 
114886
- if ( depthBuffer ) {
114887
-
114888
- const depthStyle = stencilBuffer ? gl.DEPTH_STENCIL_ATTACHMENT : gl.DEPTH_ATTACHMENT;
114889
- invalidationArray.push( depthStyle );
114890
-
114891
- }
114892
-
114893
115397
  const texture = descriptor.textures[ i ];
114894
115398
  const textureData = this.get( texture );
114895
115399
 
@@ -114899,10 +115403,12 @@ void main() {
114899
115403
 
114900
115404
  }
114901
115405
 
115406
+ gl.bindRenderbuffer( gl.RENDERBUFFER, null );
115407
+
114902
115408
  renderTargetContextData.msaaFrameBuffer = msaaFb;
114903
115409
  renderTargetContextData.msaaRenderbuffers = msaaRenderbuffers;
114904
115410
 
114905
- if ( depthRenderbuffer === undefined ) {
115411
+ if ( depthBuffer && depthRenderbuffer === undefined ) {
114906
115412
 
114907
115413
  depthRenderbuffer = gl.createRenderbuffer();
114908
115414
  this.textureUtils.setupRenderBufferStorage( depthRenderbuffer, descriptor, samples );
@@ -114926,6 +115432,8 @@ void main() {
114926
115432
 
114927
115433
  }
114928
115434
 
115435
+ state.drawBuffers( descriptor, fb );
115436
+
114929
115437
  }
114930
115438
 
114931
115439
  state.bindFramebuffer( gl.FRAMEBUFFER, currentFrameBuffer );
@@ -114967,9 +115475,6 @@ void main() {
114967
115475
  const { gl } = this;
114968
115476
 
114969
115477
  const vaoGPU = gl.createVertexArray();
114970
- let key = '';
114971
-
114972
- let staticVao = true;
114973
115478
 
114974
115479
  gl.bindVertexArray( vaoGPU );
114975
115480
 
@@ -114978,13 +115483,9 @@ void main() {
114978
115483
  const attribute = attributes[ i ];
114979
115484
  const attributeData = this.get( attribute );
114980
115485
 
114981
- key += ':' + attributeData.id;
114982
-
114983
115486
  gl.bindBuffer( gl.ARRAY_BUFFER, attributeData.bufferGPU );
114984
115487
  gl.enableVertexAttribArray( i );
114985
115488
 
114986
- if ( attribute.isStorageBufferAttribute || attribute.isStorageInstancedBufferAttribute ) staticVao = false;
114987
-
114988
115489
  let stride, offset;
114989
115490
 
114990
115491
  if ( attribute.isInterleavedBufferAttribute === true ) {
@@ -115023,9 +115524,7 @@ void main() {
115023
115524
 
115024
115525
  gl.bindBuffer( gl.ARRAY_BUFFER, null );
115025
115526
 
115026
- this.vaoCache[ key ] = vaoGPU;
115027
-
115028
- return { vaoGPU, staticVao };
115527
+ return vaoGPU;
115029
115528
 
115030
115529
  }
115031
115530
 
@@ -115162,7 +115661,7 @@ void main() {
115162
115661
 
115163
115662
  }
115164
115663
 
115165
- return renderTarget.samples > 0 && this.extensions.has( 'WEBGL_multisampled_render_to_texture' ) === true && renderTarget.autoAllocateDepthBuffer !== false;
115664
+ return renderTarget.samples > 0 && this.extensions.has( 'WEBGL_multisampled_render_to_texture' ) === true && renderTarget._autoAllocateDepthBuffer !== false;
115166
115665
 
115167
115666
  }
115168
115667
 
@@ -115446,20 +115945,26 @@ void main() {
115446
115945
  };
115447
115946
 
115448
115947
  const GPUFeatureName = {
115948
+ CoreFeaturesAndLimits: 'core-features-and-limits',
115449
115949
  DepthClipControl: 'depth-clip-control',
115450
115950
  Depth32FloatStencil8: 'depth32float-stencil8',
115451
115951
  TextureCompressionBC: 'texture-compression-bc',
115952
+ TextureCompressionBCSliced3D: 'texture-compression-bc-sliced-3d',
115452
115953
  TextureCompressionETC2: 'texture-compression-etc2',
115453
115954
  TextureCompressionASTC: 'texture-compression-astc',
115955
+ TextureCompressionASTCSliced3D: 'texture-compression-astc-sliced-3d',
115454
115956
  TimestampQuery: 'timestamp-query',
115455
115957
  IndirectFirstInstance: 'indirect-first-instance',
115456
115958
  ShaderF16: 'shader-f16',
115457
115959
  RG11B10UFloat: 'rg11b10ufloat-renderable',
115458
115960
  BGRA8UNormStorage: 'bgra8unorm-storage',
115459
115961
  Float32Filterable: 'float32-filterable',
115962
+ Float32Blendable: 'float32-blendable',
115460
115963
  ClipDistances: 'clip-distances',
115461
115964
  DualSourceBlending: 'dual-source-blending',
115462
- Subgroups: 'subgroups'
115965
+ Subgroups: 'subgroups',
115966
+ TextureFormatsTier1: 'texture-formats-tier1',
115967
+ TextureFormatsTier2: 'texture-formats-tier2'
115463
115968
  };
115464
115969
 
115465
115970
  /**
@@ -117143,7 +117648,7 @@ fn main( @location( 0 ) vTex : vec2<f32> ) -> @location( 0 ) vec4<f32> {
117143
117648
 
117144
117649
  let dimension;
117145
117650
 
117146
- if ( texture.isData3DTexture ) {
117651
+ if ( texture.is3DTexture || texture.isData3DTexture ) {
117147
117652
 
117148
117653
  dimension = GPUTextureDimension.ThreeD;
117149
117654
 
@@ -119417,24 +119922,29 @@ ${ flowData.code }
119417
119922
 
119418
119923
  }
119419
119924
 
119420
- } else if ( texture.isArrayTexture === true || texture.isDataArrayTexture === true || texture.isCompressedArrayTexture === true ) {
119925
+ } else if ( uniform.node.isStorageTextureNode === true ) {
119421
119926
 
119422
- textureType = 'texture_2d_array<f32>';
119927
+ const format = getFormat( texture );
119928
+ const access = this.getStorageAccess( uniform.node, shaderStage );
119423
119929
 
119424
- } else if ( texture.isVideoTexture === true ) {
119930
+ const is3D = uniform.node.value.is3DTexture;
119931
+ const isArrayTexture = uniform.node.value.isArrayTexture;
119425
119932
 
119426
- textureType = 'texture_external';
119933
+ const dimension = is3D ? '3d' : `2d${ isArrayTexture ? '_array' : '' }`;
119427
119934
 
119428
- } else if ( texture.isData3DTexture === true ) {
119935
+ textureType = `texture_storage_${ dimension }<${ format }, ${ access }>`;
119429
119936
 
119430
- textureType = 'texture_3d<f32>';
119937
+ } else if ( texture.isArrayTexture === true || texture.isDataArrayTexture === true || texture.isCompressedArrayTexture === true ) {
119431
119938
 
119432
- } else if ( uniform.node.isStorageTextureNode === true ) {
119939
+ textureType = 'texture_2d_array<f32>';
119433
119940
 
119434
- const format = getFormat( texture );
119435
- const access = this.getStorageAccess( uniform.node, shaderStage );
119941
+ } else if ( texture.is3DTexture === true || texture.isData3DTexture === true ) {
119942
+
119943
+ textureType = 'texture_3d<f32>';
119436
119944
 
119437
- textureType = `texture_storage_2d<${ format }, ${ access }>`;
119945
+ } else if ( texture.isVideoTexture === true ) {
119946
+
119947
+ textureType = 'texture_external';
119438
119948
 
119439
119949
  } else {
119440
119950
 
@@ -120131,6 +120641,12 @@ var<${access}> ${ name } : ${ structName };`;
120131
120641
  [ Float32Array, [ 'float32', ]],
120132
120642
  ] );
120133
120643
 
120644
+ if ( typeof Float16Array !== 'undefined' ) {
120645
+
120646
+ typedArraysToVertexFormatPrefix.set( Float16Array, [ 'float16' ] );
120647
+
120648
+ }
120649
+
120134
120650
  const typedAttributeToVertexFormatPrefix = new Map( [
120135
120651
  [ Float16BufferAttribute, [ 'float16', ]],
120136
120652
  ] );
@@ -120690,6 +121206,16 @@ var<${access}> ${ name } : ${ structName };`;
120690
121206
 
120691
121207
  }
120692
121208
 
121209
+ if ( binding.texture.isArrayTexture ) {
121210
+
121211
+ storageTexture.viewDimension = GPUTextureViewDimension.TwoDArray;
121212
+
121213
+ } else if ( binding.texture.is3DTexture ) {
121214
+
121215
+ storageTexture.viewDimension = GPUTextureViewDimension.ThreeD;
121216
+
121217
+ }
121218
+
120693
121219
  bindingGPU.storageTexture = storageTexture;
120694
121220
 
120695
121221
  } else if ( binding.isSampledTexture ) {
@@ -121392,7 +121918,7 @@ var<${access}> ${ name } : ${ structName };`;
121392
121918
  break;
121393
121919
 
121394
121920
  case MultiplyBlending:
121395
- setBlend( GPUBlendFactor.Zero, GPUBlendFactor.Src, GPUBlendFactor.Zero, GPUBlendFactor.SrcAlpha );
121921
+ setBlend( GPUBlendFactor.Dst, GPUBlendFactor.OneMinusSrcAlpha, GPUBlendFactor.Zero, GPUBlendFactor.One );
121396
121922
  break;
121397
121923
 
121398
121924
  }
@@ -121406,15 +121932,15 @@ var<${access}> ${ name } : ${ structName };`;
121406
121932
  break;
121407
121933
 
121408
121934
  case AdditiveBlending:
121409
- setBlend( GPUBlendFactor.SrcAlpha, GPUBlendFactor.One, GPUBlendFactor.SrcAlpha, GPUBlendFactor.One );
121935
+ setBlend( GPUBlendFactor.SrcAlpha, GPUBlendFactor.One, GPUBlendFactor.One, GPUBlendFactor.One );
121410
121936
  break;
121411
121937
 
121412
121938
  case SubtractiveBlending:
121413
- setBlend( GPUBlendFactor.Zero, GPUBlendFactor.OneMinusSrc, GPUBlendFactor.Zero, GPUBlendFactor.One );
121939
+ console.error( 'THREE.WebGPURenderer: SubtractiveBlending requires material.premultipliedAlpha = true' );
121414
121940
  break;
121415
121941
 
121416
121942
  case MultiplyBlending:
121417
- setBlend( GPUBlendFactor.Zero, GPUBlendFactor.Src, GPUBlendFactor.Zero, GPUBlendFactor.Src );
121943
+ console.error( 'THREE.WebGPURenderer: MultiplyBlending requires material.premultipliedAlpha = true' );
121418
121944
  break;
121419
121945
 
121420
121946
  }
@@ -124152,7 +124678,15 @@ var<${access}> ${ name } : ${ structName };`;
124152
124678
  */
124153
124679
  createIndexAttribute( attribute ) {
124154
124680
 
124155
- this.attributeUtils.createAttribute( attribute, GPUBufferUsage.INDEX | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST );
124681
+ let usage = GPUBufferUsage.INDEX | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST;
124682
+
124683
+ if ( attribute.isStorageBufferAttribute || attribute.isStorageInstancedBufferAttribute ) {
124684
+
124685
+ usage |= GPUBufferUsage.STORAGE;
124686
+
124687
+ }
124688
+
124689
+ this.attributeUtils.createAttribute( attribute, usage );
124156
124690
 
124157
124691
  }
124158
124692
 
@@ -133257,7 +133791,7 @@ var<${access}> ${ name } : ${ structName };`;
133257
133791
 
133258
133792
  // Expose config from forceGraph
133259
133793
  var bindFG = linkKapsule('forceGraph', threeForcegraph);
133260
- var linkedFGProps = Object.assign.apply(Object, _toConsumableArray$3(['jsonUrl', 'graphData', 'numDimensions', 'dagMode', 'dagLevelDistance', 'dagNodeFilter', 'onDagError', 'nodeRelSize', 'nodeId', 'nodeVal', 'nodeResolution', 'nodeColor', 'nodeAutoColorBy', 'nodeOpacity', 'nodeVisibility', 'nodeThreeObject', 'nodeThreeObjectExtend', 'nodePositionUpdate', 'linkSource', 'linkTarget', 'linkVisibility', 'linkColor', 'linkAutoColorBy', 'linkOpacity', 'linkWidth', 'linkResolution', 'linkCurvature', 'linkCurveRotation', 'linkMaterial', 'linkThreeObject', 'linkThreeObjectExtend', 'linkPositionUpdate', 'linkDirectionalArrowLength', 'linkDirectionalArrowColor', 'linkDirectionalArrowRelPos', 'linkDirectionalArrowResolution', 'linkDirectionalParticles', 'linkDirectionalParticleSpeed', 'linkDirectionalParticleWidth', 'linkDirectionalParticleColor', 'linkDirectionalParticleResolution', 'forceEngine', 'd3AlphaDecay', 'd3VelocityDecay', 'd3AlphaMin', 'ngraphPhysics', 'warmupTicks', 'cooldownTicks', 'cooldownTime', 'onEngineTick', 'onEngineStop'].map(function (p) {
133794
+ var linkedFGProps = Object.assign.apply(Object, _toConsumableArray$3(['jsonUrl', 'graphData', 'numDimensions', 'dagMode', 'dagLevelDistance', 'dagNodeFilter', 'onDagError', 'nodeRelSize', 'nodeId', 'nodeVal', 'nodeResolution', 'nodeColor', 'nodeAutoColorBy', 'nodeOpacity', 'nodeVisibility', 'nodeThreeObject', 'nodeThreeObjectExtend', 'nodePositionUpdate', 'linkSource', 'linkTarget', 'linkVisibility', 'linkColor', 'linkAutoColorBy', 'linkOpacity', 'linkWidth', 'linkResolution', 'linkCurvature', 'linkCurveRotation', 'linkMaterial', 'linkThreeObject', 'linkThreeObjectExtend', 'linkPositionUpdate', 'linkDirectionalArrowLength', 'linkDirectionalArrowColor', 'linkDirectionalArrowRelPos', 'linkDirectionalArrowResolution', 'linkDirectionalParticles', 'linkDirectionalParticleSpeed', 'linkDirectionalParticleOffset', 'linkDirectionalParticleWidth', 'linkDirectionalParticleColor', 'linkDirectionalParticleResolution', 'linkDirectionalParticleThreeObject', 'forceEngine', 'd3AlphaDecay', 'd3VelocityDecay', 'd3AlphaMin', 'ngraphPhysics', 'warmupTicks', 'cooldownTicks', 'cooldownTime', 'onEngineTick', 'onEngineStop'].map(function (p) {
133261
133795
  return _defineProperty$3({}, p, bindFG.linkProp(p));
133262
133796
  })));
133263
133797
  var linkedFGMethods = Object.assign.apply(Object, _toConsumableArray$3(['refresh', 'getGraphBbox', 'd3Force', 'd3ReheatSimulation', 'emitParticle'].map(function (p) {