three-cad-viewer 4.3.6 → 4.3.8

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.
@@ -9,7 +9,7 @@
9
9
  * Copyright 2010-2026 Three.js Authors
10
10
  * SPDX-License-Identifier: MIT
11
11
  */
12
- const REVISION = '183';
12
+ const REVISION = '184';
13
13
 
14
14
  /**
15
15
  * Represents mouse buttons and interaction types in context of controls.
@@ -3011,13 +3011,7 @@
3011
3011
  */
3012
3012
  class Vector2 {
3013
3013
 
3014
- /**
3015
- * Constructs a new 2D vector.
3016
- *
3017
- * @param {number} [x=0] - The x value of this vector.
3018
- * @param {number} [y=0] - The y value of this vector.
3019
- */
3020
- constructor( x = 0, y = 0 ) {
3014
+ static {
3021
3015
 
3022
3016
  /**
3023
3017
  * This flag can be used for type testing.
@@ -3028,6 +3022,16 @@
3028
3022
  */
3029
3023
  Vector2.prototype.isVector2 = true;
3030
3024
 
3025
+ }
3026
+
3027
+ /**
3028
+ * Constructs a new 2D vector.
3029
+ *
3030
+ * @param {number} [x=0] - The x value of this vector.
3031
+ * @param {number} [y=0] - The y value of this vector.
3032
+ */
3033
+ constructor( x = 0, y = 0 ) {
3034
+
3031
3035
  /**
3032
3036
  * The x value of this vector.
3033
3037
  *
@@ -4788,14 +4792,7 @@
4788
4792
  */
4789
4793
  class Vector3 {
4790
4794
 
4791
- /**
4792
- * Constructs a new 3D vector.
4793
- *
4794
- * @param {number} [x=0] - The x value of this vector.
4795
- * @param {number} [y=0] - The y value of this vector.
4796
- * @param {number} [z=0] - The z value of this vector.
4797
- */
4798
- constructor( x = 0, y = 0, z = 0 ) {
4795
+ static {
4799
4796
 
4800
4797
  /**
4801
4798
  * This flag can be used for type testing.
@@ -4806,6 +4803,17 @@
4806
4803
  */
4807
4804
  Vector3.prototype.isVector3 = true;
4808
4805
 
4806
+ }
4807
+
4808
+ /**
4809
+ * Constructs a new 3D vector.
4810
+ *
4811
+ * @param {number} [x=0] - The x value of this vector.
4812
+ * @param {number} [y=0] - The y value of this vector.
4813
+ * @param {number} [z=0] - The z value of this vector.
4814
+ */
4815
+ constructor( x = 0, y = 0, z = 0 ) {
4816
+
4809
4817
  /**
4810
4818
  * The x value of this vector.
4811
4819
  *
@@ -6046,6 +6054,19 @@
6046
6054
  */
6047
6055
  class Matrix3 {
6048
6056
 
6057
+ static {
6058
+
6059
+ /**
6060
+ * This flag can be used for type testing.
6061
+ *
6062
+ * @type {boolean}
6063
+ * @readonly
6064
+ * @default true
6065
+ */
6066
+ Matrix3.prototype.isMatrix3 = true;
6067
+
6068
+ }
6069
+
6049
6070
  /**
6050
6071
  * Constructs a new 3x3 matrix. The arguments are supposed to be
6051
6072
  * in row-major order. If no arguments are provided, the constructor
@@ -6063,15 +6084,6 @@
6063
6084
  */
6064
6085
  constructor( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) {
6065
6086
 
6066
- /**
6067
- * This flag can be used for type testing.
6068
- *
6069
- * @type {boolean}
6070
- * @readonly
6071
- * @default true
6072
- */
6073
- Matrix3.prototype.isMatrix3 = true;
6074
-
6075
6087
  /**
6076
6088
  * A column-major list of matrix values.
6077
6089
  *
@@ -7061,7 +7073,7 @@
7061
7073
 
7062
7074
  } else if ( ( typeof VideoFrame !== 'undefined' ) && ( data instanceof VideoFrame ) ) {
7063
7075
 
7064
- target.set( data.displayHeight, data.displayWidth, 0 );
7076
+ target.set( data.displayWidth, data.displayHeight, 0 );
7065
7077
 
7066
7078
  } else if ( data !== null ) {
7067
7079
 
@@ -7549,6 +7561,15 @@
7549
7561
  */
7550
7562
  this.pmremVersion = 0;
7551
7563
 
7564
+ /**
7565
+ * Whether the texture should use one of the 16 bit integer formats which are normalized
7566
+ * to [0, 1] or [-1, 1] (depending on signed/unsigned) when sampled.
7567
+ *
7568
+ * @type {boolean}
7569
+ * @default false
7570
+ */
7571
+ this.normalized = false;
7572
+
7552
7573
  }
7553
7574
 
7554
7575
  /**
@@ -7589,14 +7610,14 @@
7589
7610
 
7590
7611
  }
7591
7612
 
7592
- set image( value = null ) {
7613
+ set image( value ) {
7593
7614
 
7594
7615
  this.source.data = value;
7595
7616
 
7596
7617
  }
7597
7618
 
7598
7619
  /**
7599
- * Updates the texture transformation matrix from the from the properties {@link Texture#offset},
7620
+ * Updates the texture transformation matrix from the properties {@link Texture#offset},
7600
7621
  * {@link Texture#repeat}, {@link Texture#rotation}, and {@link Texture#center}.
7601
7622
  */
7602
7623
  updateMatrix() {
@@ -7664,6 +7685,7 @@
7664
7685
  this.format = source.format;
7665
7686
  this.internalFormat = source.internalFormat;
7666
7687
  this.type = source.type;
7688
+ this.normalized = source.normalized;
7667
7689
 
7668
7690
  this.offset.copy( source.offset );
7669
7691
  this.repeat.copy( source.repeat );
@@ -7782,6 +7804,7 @@
7782
7804
  format: this.format,
7783
7805
  internalFormat: this.internalFormat,
7784
7806
  type: this.type,
7807
+ normalized: this.normalized,
7785
7808
  colorSpace: this.colorSpace,
7786
7809
 
7787
7810
  minFilter: this.minFilter,
@@ -8005,15 +8028,7 @@
8005
8028
  */
8006
8029
  class Vector4 {
8007
8030
 
8008
- /**
8009
- * Constructs a new 4D vector.
8010
- *
8011
- * @param {number} [x=0] - The x value of this vector.
8012
- * @param {number} [y=0] - The y value of this vector.
8013
- * @param {number} [z=0] - The z value of this vector.
8014
- * @param {number} [w=1] - The w value of this vector.
8015
- */
8016
- constructor( x = 0, y = 0, z = 0, w = 1 ) {
8031
+ static {
8017
8032
 
8018
8033
  /**
8019
8034
  * This flag can be used for type testing.
@@ -8024,6 +8039,18 @@
8024
8039
  */
8025
8040
  Vector4.prototype.isVector4 = true;
8026
8041
 
8042
+ }
8043
+
8044
+ /**
8045
+ * Constructs a new 4D vector.
8046
+ *
8047
+ * @param {number} [x=0] - The x value of this vector.
8048
+ * @param {number} [y=0] - The y value of this vector.
8049
+ * @param {number} [z=0] - The z value of this vector.
8050
+ * @param {number} [w=1] - The w value of this vector.
8051
+ */
8052
+ constructor( x = 0, y = 0, z = 0, w = 1 ) {
8053
+
8027
8054
  /**
8028
8055
  * The x value of this vector.
8029
8056
  *
@@ -9404,6 +9431,7 @@
9404
9431
  if ( source.depthTexture !== null ) this.depthTexture = source.depthTexture.clone();
9405
9432
 
9406
9433
  this.samples = source.samples;
9434
+ this.multiview = source.multiview;
9407
9435
 
9408
9436
  return this;
9409
9437
 
@@ -9820,6 +9848,19 @@
9820
9848
  */
9821
9849
  class Matrix4 {
9822
9850
 
9851
+ static {
9852
+
9853
+ /**
9854
+ * This flag can be used for type testing.
9855
+ *
9856
+ * @type {boolean}
9857
+ * @readonly
9858
+ * @default true
9859
+ */
9860
+ Matrix4.prototype.isMatrix4 = true;
9861
+
9862
+ }
9863
+
9823
9864
  /**
9824
9865
  * Constructs a new 4x4 matrix. The arguments are supposed to be
9825
9866
  * in row-major order. If no arguments are provided, the constructor
@@ -9844,15 +9885,6 @@
9844
9885
  */
9845
9886
  constructor( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) {
9846
9887
 
9847
- /**
9848
- * This flag can be used for type testing.
9849
- *
9850
- * @type {boolean}
9851
- * @readonly
9852
- * @default true
9853
- */
9854
- Matrix4.prototype.isMatrix4 = true;
9855
-
9856
9888
  /**
9857
9889
  * A column-major list of matrix values.
9858
9890
  *
@@ -13232,11 +13264,7 @@
13232
13264
  this.quaternion.copy( source.quaternion );
13233
13265
  this.scale.copy( source.scale );
13234
13266
 
13235
- if ( source.pivot !== null ) {
13236
-
13237
- this.pivot = source.pivot.clone();
13238
-
13239
- }
13267
+ this.pivot = ( source.pivot !== null ) ? source.pivot.clone() : null;
13240
13268
 
13241
13269
  this.matrix.copy( source.matrix );
13242
13270
  this.matrixWorld.copy( source.matrixWorld );
@@ -13454,6 +13482,7 @@
13454
13482
  this._grip.linearVelocity = new Vector3();
13455
13483
  this._grip.hasAngularVelocity = false;
13456
13484
  this._grip.angularVelocity = new Vector3();
13485
+ this._grip.eventsEnabled = false;
13457
13486
 
13458
13487
  }
13459
13488
 
@@ -13666,6 +13695,17 @@
13666
13695
 
13667
13696
  }
13668
13697
 
13698
+ // grip update event if enabled
13699
+ if ( grip.eventsEnabled ) {
13700
+
13701
+ grip.dispatchEvent( {
13702
+ type: 'gripUpdated',
13703
+ data: inputSource,
13704
+ target: this
13705
+ } );
13706
+
13707
+ }
13708
+
13669
13709
  }
13670
13710
 
13671
13711
  }
@@ -15296,7 +15336,7 @@
15296
15336
  _v1$5.subVectors( a, b );
15297
15337
 
15298
15338
  // strictly front facing
15299
- return ( _v0$2.cross( _v1$5 ).dot( direction ) < 0 ) ? true : false;
15339
+ return _v0$2.cross( _v1$5 ).dot( direction ) < 0;
15300
15340
 
15301
15341
  }
15302
15342
 
@@ -16628,7 +16668,7 @@
16628
16668
  * When working with vector-like data, the `fromBufferAttribute( attribute, index )`
16629
16669
  * helper methods on vector and color class might be helpful. E.g. {@link Vector3#fromBufferAttribute}.
16630
16670
  */
16631
- class BufferAttribute {
16671
+ class BufferAttribute extends EventDispatcher {
16632
16672
 
16633
16673
  /**
16634
16674
  * Constructs a new buffer attribute.
@@ -16639,6 +16679,8 @@
16639
16679
  */
16640
16680
  constructor( array, itemSize, normalized = false ) {
16641
16681
 
16682
+ super();
16683
+
16642
16684
  if ( Array.isArray( array ) ) {
16643
16685
 
16644
16686
  throw new TypeError( 'THREE.BufferAttribute: array should be a Typed Array.' );
@@ -17285,6 +17327,15 @@
17285
17327
 
17286
17328
  }
17287
17329
 
17330
+ /**
17331
+ * Disposes of the buffer attribute. Available only in {@link WebGPURenderer}.
17332
+ */
17333
+ dispose() {
17334
+
17335
+ this.dispatchEvent( { type: 'dispose' } );
17336
+
17337
+ }
17338
+
17288
17339
  }
17289
17340
 
17290
17341
  /**
@@ -23408,12 +23459,12 @@
23408
23459
 
23409
23460
  }
23410
23461
 
23411
- const _basePosition = /*@__PURE__*/ new Vector3();
23462
+ const _baseVector = /*@__PURE__*/ new Vector4();
23412
23463
 
23413
23464
  const _skinIndex = /*@__PURE__*/ new Vector4();
23414
23465
  const _skinWeight = /*@__PURE__*/ new Vector4();
23415
23466
 
23416
- const _vector3$1 = /*@__PURE__*/ new Vector3();
23467
+ const _vector4 = /*@__PURE__*/ new Vector4();
23417
23468
  const _matrix4 = /*@__PURE__*/ new Matrix4();
23418
23469
  const _vertex = /*@__PURE__*/ new Vector3();
23419
23470
 
@@ -23709,12 +23760,12 @@
23709
23760
 
23710
23761
  /**
23711
23762
  * Applies the bone transform associated with the given index to the given
23712
- * vertex position. Returns the updated vector.
23763
+ * vector. Can be used to transform positions or direction vectors by providing
23764
+ * a Vector4 with 1 or 0 in the w component respectively. Returns the updated vector.
23713
23765
  *
23714
23766
  * @param {number} index - The vertex index.
23715
- * @param {Vector3} target - The target object that is used to store the method's result.
23716
- * the skinned mesh's world matrix will be used instead.
23717
- * @return {Vector3} The updated vertex position.
23767
+ * @param {Vector3|Vector4} target - The target object that is used to store the method's result.
23768
+ * @return {Vector3|Vector4} The updated vertex attribute data.
23718
23769
  */
23719
23770
  applyBoneTransform( index, target ) {
23720
23771
 
@@ -23724,9 +23775,19 @@
23724
23775
  _skinIndex.fromBufferAttribute( geometry.attributes.skinIndex, index );
23725
23776
  _skinWeight.fromBufferAttribute( geometry.attributes.skinWeight, index );
23726
23777
 
23727
- _basePosition.copy( target ).applyMatrix4( this.bindMatrix );
23778
+ if ( target.isVector4 ) {
23779
+
23780
+ _baseVector.copy( target );
23781
+ target.set( 0, 0, 0, 0 );
23728
23782
 
23729
- target.set( 0, 0, 0 );
23783
+ } else {
23784
+
23785
+ _baseVector.set( ...target, 1 );
23786
+ target.set( 0, 0, 0 );
23787
+
23788
+ }
23789
+
23790
+ _baseVector.applyMatrix4( this.bindMatrix );
23730
23791
 
23731
23792
  for ( let i = 0; i < 4; i ++ ) {
23732
23793
 
@@ -23738,12 +23799,19 @@
23738
23799
 
23739
23800
  _matrix4.multiplyMatrices( skeleton.bones[ boneIndex ].matrixWorld, skeleton.boneInverses[ boneIndex ] );
23740
23801
 
23741
- target.addScaledVector( _vector3$1.copy( _basePosition ).applyMatrix4( _matrix4 ), weight );
23802
+ target.addScaledVector( _vector4.copy( _baseVector ).applyMatrix4( _matrix4 ), weight );
23742
23803
 
23743
23804
  }
23744
23805
 
23745
23806
  }
23746
23807
 
23808
+ if ( target.isVector4 ) {
23809
+
23810
+ // ensure the homogenous coordinate remains unchanged after vector operations
23811
+ target.w = _baseVector.w;
23812
+
23813
+ }
23814
+
23747
23815
  return target.applyMatrix4( this.bindMatrixInverse );
23748
23816
 
23749
23817
  }
@@ -24524,10 +24592,19 @@
24524
24592
  *
24525
24593
  * @param {number} index - The instance index.
24526
24594
  * @param {Color} color - The target object that is used to store the method's result.
24595
+ * @return {Color} A reference to the target color.
24527
24596
  */
24528
24597
  getColorAt( index, color ) {
24529
24598
 
24530
- color.fromArray( this.instanceColor.array, index * 3 );
24599
+ if ( this.instanceColor === null ) {
24600
+
24601
+ return color.setRGB( 1, 1, 1 );
24602
+
24603
+ } else {
24604
+
24605
+ return color.fromArray( this.instanceColor.array, index * 3 );
24606
+
24607
+ }
24531
24608
 
24532
24609
  }
24533
24610
 
@@ -24536,10 +24613,11 @@
24536
24613
  *
24537
24614
  * @param {number} index - The instance index.
24538
24615
  * @param {Matrix4} matrix - The target object that is used to store the method's result.
24616
+ * @return {Matrix4} A reference to the target matrix.
24539
24617
  */
24540
24618
  getMatrixAt( index, matrix ) {
24541
24619
 
24542
- matrix.fromArray( this.instanceMatrix.array, index * 16 );
24620
+ return matrix.fromArray( this.instanceMatrix.array, index * 16 );
24543
24621
 
24544
24622
  }
24545
24623
 
@@ -24625,6 +24703,7 @@
24625
24703
  *
24626
24704
  * @param {number} index - The instance index.
24627
24705
  * @param {Color} color - The instance color.
24706
+ * @return {InstancedMesh} A reference to this instanced mesh.
24628
24707
  */
24629
24708
  setColorAt( index, color ) {
24630
24709
 
@@ -24635,19 +24714,22 @@
24635
24714
  }
24636
24715
 
24637
24716
  color.toArray( this.instanceColor.array, index * 3 );
24717
+ return this;
24638
24718
 
24639
24719
  }
24640
24720
 
24641
24721
  /**
24642
24722
  * Sets the given local transformation matrix to the defined instance. Make sure you set the `needsUpdate` flag of
24643
- * {@link InstancedMesh#instanceMatrix} to `true` after updating all the colors.
24723
+ * {@link InstancedMesh#instanceMatrix} to `true` after updating all the matrices.
24644
24724
  *
24645
24725
  * @param {number} index - The instance index.
24646
24726
  * @param {Matrix4} matrix - The local transformation.
24727
+ * @return {InstancedMesh} A reference to this instanced mesh.
24647
24728
  */
24648
24729
  setMatrixAt( index, matrix ) {
24649
24730
 
24650
24731
  matrix.toArray( this.instanceMatrix.array, index * 16 );
24732
+ return this;
24651
24733
 
24652
24734
  }
24653
24735
 
@@ -24658,6 +24740,7 @@
24658
24740
  * @param {number} index - The instance index.
24659
24741
  * @param {Mesh} object - A mesh which `morphTargetInfluences` property containing the morph target weights
24660
24742
  * of a single instance.
24743
+ * @return {InstancedMesh} A reference to this instanced mesh.
24661
24744
  */
24662
24745
  setMorphAt( index, object ) {
24663
24746
 
@@ -24688,6 +24771,7 @@
24688
24771
  array[ dataIndex ] = morphBaseInfluence;
24689
24772
 
24690
24773
  array.set( objectInfluences, dataIndex + 1 );
24774
+ return this;
24691
24775
 
24692
24776
  }
24693
24777
 
@@ -24923,9 +25007,10 @@
24923
25007
  *
24924
25008
  * @param {Line3} line - The line to compute the intersection for.
24925
25009
  * @param {Vector3} target - The target vector that is used to store the method's result.
24926
- * @return {?Vector3} The intersection point.
25010
+ * @param {boolean} [clampToLine=true] - Whether to clamp the intersection to the line segment.
25011
+ * @return {?Vector3} The intersection point. Returns `null` if no intersection is detected.
24927
25012
  */
24928
- intersectLine( line, target ) {
25013
+ intersectLine( line, target, clampToLine = true ) {
24929
25014
 
24930
25015
  const direction = line.delta( _vector1 );
24931
25016
 
@@ -24947,7 +25032,7 @@
24947
25032
 
24948
25033
  const t = - ( line.start.dot( this.normal ) + this.constant ) / denominator;
24949
25034
 
24950
- if ( t < 0 || t > 1 ) {
25035
+ if ( ( clampToLine === true ) && ( t < 0 || t > 1 ) ) {
24951
25036
 
24952
25037
  return null;
24953
25038
 
@@ -25867,7 +25952,6 @@
25867
25952
  this._multiDrawCounts = new Int32Array( maxInstanceCount );
25868
25953
  this._multiDrawStarts = new Int32Array( maxInstanceCount );
25869
25954
  this._multiDrawCount = 0;
25870
- this._multiDrawInstances = null;
25871
25955
 
25872
25956
  // Local matrix per geometry by using data texture
25873
25957
  this._matricesTexture = null;
@@ -26728,7 +26812,23 @@
26728
26812
  getColorAt( instanceId, color ) {
26729
26813
 
26730
26814
  this.validateInstanceId( instanceId );
26731
- return color.fromArray( this._colorsTexture.image.data, instanceId * 4 );
26815
+ if ( this._colorsTexture === null ) {
26816
+
26817
+ if ( color.isVector4 ) {
26818
+
26819
+ return color.set( 1, 1, 1, 1 );
26820
+
26821
+ } else {
26822
+
26823
+ return color.setRGB( 1, 1, 1 );
26824
+
26825
+ }
26826
+
26827
+ } else {
26828
+
26829
+ return color.fromArray( this._colorsTexture.image.data, instanceId * 4 );
26830
+
26831
+ }
26732
26832
 
26733
26833
  }
26734
26834
 
@@ -28755,6 +28855,77 @@
28755
28855
 
28756
28856
  }
28757
28857
 
28858
+ /**
28859
+ * Creates a texture from an HTML element.
28860
+ *
28861
+ * This is almost the same as the base texture class, except that it sets {@link Texture#needsUpdate}
28862
+ * to `true` immediately and listens for the parent canvas's paint events to trigger updates.
28863
+ *
28864
+ * @augments Texture
28865
+ */
28866
+ class HTMLTexture extends Texture {
28867
+
28868
+ /**
28869
+ * Constructs a new texture.
28870
+ *
28871
+ * @param {HTMLElement} [element] - The HTML element.
28872
+ * @param {number} [mapping=Texture.DEFAULT_MAPPING] - The texture mapping.
28873
+ * @param {number} [wrapS=ClampToEdgeWrapping] - The wrapS value.
28874
+ * @param {number} [wrapT=ClampToEdgeWrapping] - The wrapT value.
28875
+ * @param {number} [magFilter=LinearFilter] - The mag filter value.
28876
+ * @param {number} [minFilter=LinearMipmapLinearFilter] - The min filter value.
28877
+ * @param {number} [format=RGBAFormat] - The texture format.
28878
+ * @param {number} [type=UnsignedByteType] - The texture type.
28879
+ * @param {number} [anisotropy=Texture.DEFAULT_ANISOTROPY] - The anisotropy value.
28880
+ */
28881
+ constructor( element, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) {
28882
+
28883
+ super( element, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );
28884
+
28885
+ /**
28886
+ * This flag can be used for type testing.
28887
+ *
28888
+ * @type {boolean}
28889
+ * @readonly
28890
+ * @default true
28891
+ */
28892
+ this.isHTMLTexture = true;
28893
+ this.generateMipmaps = false;
28894
+
28895
+ this.needsUpdate = true;
28896
+
28897
+ const parent = element ? element.parentNode : null;
28898
+
28899
+ if ( parent !== null && 'requestPaint' in parent ) {
28900
+
28901
+ parent.onpaint = () => {
28902
+
28903
+ this.needsUpdate = true;
28904
+
28905
+ };
28906
+
28907
+ parent.requestPaint();
28908
+
28909
+ }
28910
+
28911
+ }
28912
+
28913
+ dispose() {
28914
+
28915
+ const parent = this.image ? this.image.parentNode : null;
28916
+
28917
+ if ( parent !== null && 'onpaint' in parent ) {
28918
+
28919
+ parent.onpaint = null;
28920
+
28921
+ }
28922
+
28923
+ super.dispose();
28924
+
28925
+ }
28926
+
28927
+ }
28928
+
28758
28929
  /**
28759
28930
  * This class can be used to automatically save the depth information of a
28760
28931
  * rendering into a texture.
@@ -31420,6 +31591,7 @@
31420
31591
  //
31421
31592
 
31422
31593
  const tmp = /*@__PURE__*/ new Vector3();
31594
+ const tmp2 = /*@__PURE__*/ new Vector3();
31423
31595
  const px$1 = /*@__PURE__*/ new CubicPoly();
31424
31596
  const py = /*@__PURE__*/ new CubicPoly();
31425
31597
  const pz = /*@__PURE__*/ new CubicPoly();
@@ -31544,8 +31716,8 @@
31544
31716
  } else {
31545
31717
 
31546
31718
  // extrapolate first point
31547
- tmp.subVectors( points[ 0 ], points[ 1 ] ).add( points[ 0 ] );
31548
- p0 = tmp;
31719
+ tmp2.subVectors( points[ 0 ], points[ 1 ] ).add( points[ 0 ] );
31720
+ p0 = tmp2;
31549
31721
 
31550
31722
  }
31551
31723
 
@@ -37128,10 +37300,7 @@
37128
37300
 
37129
37301
  const property = src[ u ][ p ];
37130
37302
 
37131
- if ( property && ( property.isColor ||
37132
- property.isMatrix3 || property.isMatrix4 ||
37133
- property.isVector2 || property.isVector3 || property.isVector4 ||
37134
- property.isTexture || property.isQuaternion ) ) {
37303
+ if ( isThreeObject( property ) ) {
37135
37304
 
37136
37305
  if ( property.isRenderTargetTexture ) {
37137
37306
 
@@ -37146,7 +37315,23 @@
37146
37315
 
37147
37316
  } else if ( Array.isArray( property ) ) {
37148
37317
 
37149
- dst[ u ][ p ] = property.slice();
37318
+ if ( isThreeObject( property[ 0 ] ) ) {
37319
+
37320
+ const clonedProperty = [];
37321
+
37322
+ for ( let i = 0, l = property.length; i < l; i ++ ) {
37323
+
37324
+ clonedProperty[ i ] = property[ i ].clone();
37325
+
37326
+ }
37327
+
37328
+ dst[ u ][ p ] = clonedProperty;
37329
+
37330
+ } else {
37331
+
37332
+ dst[ u ][ p ] = property.slice();
37333
+
37334
+ }
37150
37335
 
37151
37336
  } else {
37152
37337
 
@@ -37190,6 +37375,15 @@
37190
37375
 
37191
37376
  }
37192
37377
 
37378
+ function isThreeObject( property ) {
37379
+
37380
+ return ( property && ( property.isColor ||
37381
+ property.isMatrix3 || property.isMatrix4 ||
37382
+ property.isVector2 || property.isVector3 || property.isVector4 ||
37383
+ property.isTexture || property.isQuaternion ) );
37384
+
37385
+ }
37386
+
37193
37387
  function cloneUniformsGroups( src ) {
37194
37388
 
37195
37389
  const dst = [];
@@ -39084,7 +39278,7 @@
39084
39278
 
39085
39279
  /**
39086
39280
  * Gradient map for toon shading. It's required to set
39087
- * {@link Texture#minFilter} and {@link Texture#magFilter} to {@linkNearestFilter}
39281
+ * {@link Texture#minFilter} and {@link Texture#magFilter} to {@link NearestFilter}
39088
39282
  * when using this type of texture.
39089
39283
  *
39090
39284
  * @type {?Texture}
@@ -43884,7 +44078,6 @@
43884
44078
  * @param {function(any)} onLoad - Executed when the loading process has been finished.
43885
44079
  * @param {onProgressCallback} [onProgress] - Executed while the loading is in progress.
43886
44080
  * @param {onErrorCallback} [onError] - Executed when errors occur.
43887
- * @return {any|undefined} The cached resource if available.
43888
44081
  */
43889
44082
  load( url, onLoad, onProgress, onError ) {
43890
44083
 
@@ -43908,7 +44101,7 @@
43908
44101
 
43909
44102
  }, 0 );
43910
44103
 
43911
- return cached;
44104
+ return;
43912
44105
 
43913
44106
  }
43914
44107
 
@@ -44725,19 +44918,20 @@
44725
44918
 
44726
44919
  texData = scope.parse( buffer );
44727
44920
 
44728
- } catch ( error ) {
44921
+ } catch ( e ) {
44729
44922
 
44730
44923
  if ( onError !== undefined ) {
44731
44924
 
44732
- onError( error );
44925
+ onError( e );
44733
44926
 
44734
44927
  } else {
44735
44928
 
44736
- error( error );
44737
- return;
44929
+ error( e );
44738
44930
 
44739
44931
  }
44740
44932
 
44933
+ return;
44934
+
44741
44935
  }
44742
44936
 
44743
44937
  if ( texData.image !== undefined ) {
@@ -47471,7 +47665,7 @@
47471
47665
 
47472
47666
  if ( typeof json.vertexColors === 'number' ) {
47473
47667
 
47474
- material.vertexColors = ( json.vertexColors > 0 ) ? true : false;
47668
+ material.vertexColors = json.vertexColors > 0;
47475
47669
 
47476
47670
  } else {
47477
47671
 
@@ -48037,6 +48231,8 @@
48037
48231
 
48038
48232
  }
48039
48233
 
48234
+ const _customGeometries = {};
48235
+
48040
48236
  /**
48041
48237
  * A loader for loading a JSON resource in the [JSON Object/Scene format](https://github.com/mrdoob/three.js/wiki/JSON-Object-Scene-format-4).
48042
48238
  * The files are internally loaded via {@link FileLoader}.
@@ -48093,11 +48289,11 @@
48093
48289
 
48094
48290
  json = JSON.parse( text );
48095
48291
 
48096
- } catch ( error ) {
48292
+ } catch ( e ) {
48097
48293
 
48098
- if ( onError !== undefined ) onError( error );
48294
+ if ( onError !== undefined ) onError( e );
48099
48295
 
48100
- error( 'ObjectLoader: Can\'t parse ' + url + '.', error.message );
48296
+ error( 'ObjectLoader: Can\'t parse ' + url + '.', e.message );
48101
48297
 
48102
48298
  return;
48103
48299
 
@@ -48247,6 +48443,20 @@
48247
48443
 
48248
48444
  }
48249
48445
 
48446
+ /**
48447
+ * Registers the given geometry at the internal
48448
+ * geometry library.
48449
+ *
48450
+ * @static
48451
+ * @param {string} type - The geometry type.
48452
+ * @param {BufferGeometry.constructor} geometryClass - The geometry class.
48453
+ */
48454
+ static registerGeometry( type, geometryClass ) {
48455
+
48456
+ _customGeometries[ type ] = geometryClass;
48457
+
48458
+ }
48459
+
48250
48460
  // internals
48251
48461
 
48252
48462
  parseShapes( json ) {
@@ -48327,9 +48537,13 @@
48327
48537
 
48328
48538
  geometry = Geometries[ data.type ].fromJSON( data, shapes );
48329
48539
 
48540
+ } else if ( data.type in _customGeometries ) {
48541
+
48542
+ geometry = _customGeometries[ data.type ].fromJSON( data, shapes );
48543
+
48330
48544
  } else {
48331
48545
 
48332
- warn( `ObjectLoader: Unsupported geometry type "${ data.type }"` );
48546
+ warn( `ObjectLoader: Unknown geometry type "${ data.type }". Use .registerGeometry() before starting the deserialization process.` );
48333
48547
 
48334
48548
  }
48335
48549
 
@@ -48709,6 +48923,7 @@
48709
48923
  if ( data.premultiplyAlpha !== undefined ) texture.premultiplyAlpha = data.premultiplyAlpha;
48710
48924
  if ( data.unpackAlignment !== undefined ) texture.unpackAlignment = data.unpackAlignment;
48711
48925
  if ( data.compareFunction !== undefined ) texture.compareFunction = data.compareFunction;
48926
+ if ( data.normalized !== undefined ) texture.normalized = data.normalized;
48712
48927
 
48713
48928
  if ( data.userData !== undefined ) texture.userData = data.userData;
48714
48929
 
@@ -49336,6 +49551,9 @@
49336
49551
  * Sets the given loader options. The structure of the object must match the `options` parameter of
49337
49552
  * [createImageBitmap](https://developer.mozilla.org/en-US/docs/Web/API/Window/createImageBitmap).
49338
49553
  *
49554
+ * Note: When caching is enabled, the cache key is based on the URL only. Loading the same URL with
49555
+ * different options will return the cached result of the first request.
49556
+ *
49339
49557
  * @param {Object} options - The loader options to set.
49340
49558
  * @return {ImageBitmapLoader} A reference to this image bitmap loader.
49341
49559
  */
@@ -49354,7 +49572,6 @@
49354
49572
  * @param {function(ImageBitmap)} onLoad - Executed when the loading process has been finished.
49355
49573
  * @param {onProgressCallback} onProgress - Unsupported in this loader.
49356
49574
  * @param {onErrorCallback} onError - Executed when errors occur.
49357
- * @return {ImageBitmap|undefined} The image bitmap.
49358
49575
  */
49359
49576
  load( url, onLoad, onProgress, onError ) {
49360
49577
 
@@ -49392,8 +49609,6 @@
49392
49609
 
49393
49610
  scope.manager.itemEnd( url );
49394
49611
 
49395
- return imageBitmap;
49396
-
49397
49612
  }
49398
49613
 
49399
49614
  } );
@@ -49411,7 +49626,7 @@
49411
49626
 
49412
49627
  }, 0 );
49413
49628
 
49414
- return cached;
49629
+ return;
49415
49630
 
49416
49631
  }
49417
49632
 
@@ -49436,8 +49651,6 @@
49436
49651
 
49437
49652
  scope.manager.itemEnd( url );
49438
49653
 
49439
- return imageBitmap;
49440
-
49441
49654
  } ).catch( function ( e ) {
49442
49655
 
49443
49656
  if ( onError ) onError( e );
@@ -49484,7 +49697,7 @@
49484
49697
  /**
49485
49698
  * Returns the global native audio context.
49486
49699
  *
49487
- * @return {AudioContext} The native audio context.
49700
+ * @return {Window.AudioContext} The native audio context.
49488
49701
  */
49489
49702
  static getContext() {
49490
49703
 
@@ -49501,7 +49714,7 @@
49501
49714
  /**
49502
49715
  * Allows to set the global native audio context from outside.
49503
49716
  *
49504
- * @param {AudioContext} value - The native context to set.
49717
+ * @param {Window.AudioContext} value - The native context to set.
49505
49718
  */
49506
49719
  static setContext( value ) {
49507
49720
 
@@ -49568,11 +49781,21 @@
49568
49781
  const bufferCopy = buffer.slice( 0 );
49569
49782
 
49570
49783
  const context = AudioContext.getContext();
49784
+
49785
+ const decodeUrl = url + '#decode';
49786
+ scope.manager.itemStart( decodeUrl ); // prevent loading manager from completing too early, see #33378
49787
+
49571
49788
  context.decodeAudioData( bufferCopy, function ( audioBuffer ) {
49572
49789
 
49573
49790
  onLoad( audioBuffer );
49791
+ scope.manager.itemEnd( decodeUrl );
49792
+
49793
+ } ).catch( function ( e ) {
49574
49794
 
49575
- } ).catch( handleError );
49795
+ handleError( e );
49796
+ scope.manager.itemEnd( decodeUrl );
49797
+
49798
+ } );
49576
49799
 
49577
49800
  } catch ( e ) {
49578
49801
 
@@ -50049,135 +50272,186 @@
50049
50272
  }
50050
50273
 
50051
50274
  /**
50052
- * Class for keeping track of time.
50275
+ * This class is an alternative to {@link Clock} with a different API design and behavior.
50276
+ * The goal is to avoid the conceptual flaws that became apparent in `Clock` over time.
50053
50277
  *
50054
- * @deprecated since r183.
50278
+ * - `Timer` has an `update()` method that updates its internal state. That makes it possible to
50279
+ * call `getDelta()` and `getElapsed()` multiple times per simulation step without getting different values.
50280
+ * - The class can make use of the Page Visibility API to avoid large time delta values when the app
50281
+ * is inactive (e.g. tab switched or browser hidden).
50282
+ *
50283
+ * ```js
50284
+ * const timer = new Timer();
50285
+ * timer.connect( document ); // use Page Visibility API
50286
+ * ```
50055
50287
  */
50056
- class Clock {
50288
+ let Timer$2 = class Timer {
50057
50289
 
50058
50290
  /**
50059
- * Constructs a new clock.
50291
+ * Constructs a new timer.
50292
+ */
50293
+ constructor() {
50294
+
50295
+ this._previousTime = 0;
50296
+ this._currentTime = 0;
50297
+ this._startTime = performance.now();
50298
+
50299
+ this._delta = 0;
50300
+ this._elapsed = 0;
50301
+
50302
+ this._timescale = 1;
50303
+
50304
+ this._document = null;
50305
+ this._pageVisibilityHandler = null;
50306
+
50307
+ }
50308
+
50309
+ /**
50310
+ * Connect the timer to the given document.Calling this method is not mandatory to
50311
+ * use the timer but enables the usage of the Page Visibility API to avoid large time
50312
+ * delta values.
50060
50313
  *
50061
- * @deprecated since 183.
50062
- * @param {boolean} [autoStart=true] - Whether to automatically start the clock when
50063
- * `getDelta()` is called for the first time.
50314
+ * @param {Document} document - The document.
50064
50315
  */
50065
- constructor( autoStart = true ) {
50316
+ connect( document ) {
50066
50317
 
50067
- /**
50068
- * If set to `true`, the clock starts automatically when `getDelta()` is called
50069
- * for the first time.
50070
- *
50071
- * @type {boolean}
50072
- * @default true
50073
- */
50074
- this.autoStart = autoStart;
50318
+ this._document = document;
50075
50319
 
50076
- /**
50077
- * Holds the time at which the clock's `start()` method was last called.
50078
- *
50079
- * @type {number}
50080
- * @default 0
50081
- */
50082
- this.startTime = 0;
50320
+ // use Page Visibility API to avoid large time delta values
50083
50321
 
50084
- /**
50085
- * Holds the time at which the clock's `start()`, `getElapsedTime()` or
50086
- * `getDelta()` methods were last called.
50087
- *
50088
- * @type {number}
50089
- * @default 0
50090
- */
50091
- this.oldTime = 0;
50322
+ if ( document.hidden !== undefined ) {
50092
50323
 
50093
- /**
50094
- * Keeps track of the total time that the clock has been running.
50095
- *
50096
- * @type {number}
50097
- * @default 0
50098
- */
50099
- this.elapsedTime = 0;
50324
+ this._pageVisibilityHandler = handleVisibilityChange.bind( this );
50100
50325
 
50101
- /**
50102
- * Whether the clock is running or not.
50103
- *
50104
- * @type {boolean}
50105
- * @default true
50106
- */
50107
- this.running = false;
50326
+ document.addEventListener( 'visibilitychange', this._pageVisibilityHandler, false );
50108
50327
 
50109
- warn( 'THREE.Clock: This module has been deprecated. Please use THREE.Timer instead.' ); // @deprecated, r183
50328
+ }
50110
50329
 
50111
50330
  }
50112
50331
 
50113
50332
  /**
50114
- * Starts the clock. When `autoStart` is set to `true`, the method is automatically
50115
- * called by the class.
50333
+ * Disconnects the timer from the DOM and also disables the usage of the Page Visibility API.
50116
50334
  */
50117
- start() {
50335
+ disconnect() {
50118
50336
 
50119
- this.startTime = performance.now();
50337
+ if ( this._pageVisibilityHandler !== null ) {
50120
50338
 
50121
- this.oldTime = this.startTime;
50122
- this.elapsedTime = 0;
50123
- this.running = true;
50339
+ this._document.removeEventListener( 'visibilitychange', this._pageVisibilityHandler );
50340
+ this._pageVisibilityHandler = null;
50341
+
50342
+ }
50343
+
50344
+ this._document = null;
50124
50345
 
50125
50346
  }
50126
50347
 
50127
50348
  /**
50128
- * Stops the clock.
50349
+ * Returns the time delta in seconds.
50350
+ *
50351
+ * @return {number} The time delta in second.
50129
50352
  */
50130
- stop() {
50353
+ getDelta() {
50131
50354
 
50132
- this.getElapsedTime();
50133
- this.running = false;
50134
- this.autoStart = false;
50355
+ return this._delta / 1000;
50135
50356
 
50136
50357
  }
50137
50358
 
50138
50359
  /**
50139
50360
  * Returns the elapsed time in seconds.
50140
50361
  *
50141
- * @return {number} The elapsed time.
50362
+ * @return {number} The elapsed time in second.
50142
50363
  */
50143
- getElapsedTime() {
50364
+ getElapsed() {
50144
50365
 
50145
- this.getDelta();
50146
- return this.elapsedTime;
50366
+ return this._elapsed / 1000;
50147
50367
 
50148
50368
  }
50149
50369
 
50150
50370
  /**
50151
- * Returns the delta time in seconds.
50371
+ * Returns the timescale.
50152
50372
  *
50153
- * @return {number} The delta time.
50373
+ * @return {number} The timescale.
50154
50374
  */
50155
- getDelta() {
50375
+ getTimescale() {
50156
50376
 
50157
- let diff = 0;
50377
+ return this._timescale;
50158
50378
 
50159
- if ( this.autoStart && ! this.running ) {
50379
+ }
50160
50380
 
50161
- this.start();
50162
- return 0;
50381
+ /**
50382
+ * Sets the given timescale which scale the time delta computation
50383
+ * in `update()`.
50384
+ *
50385
+ * @param {number} timescale - The timescale to set.
50386
+ * @return {Timer} A reference to this timer.
50387
+ */
50388
+ setTimescale( timescale ) {
50163
50389
 
50164
- }
50390
+ this._timescale = timescale;
50165
50391
 
50166
- if ( this.running ) {
50392
+ return this;
50167
50393
 
50168
- const newTime = performance.now();
50394
+ }
50169
50395
 
50170
- diff = ( newTime - this.oldTime ) / 1000;
50171
- this.oldTime = newTime;
50396
+ /**
50397
+ * Resets the time computation for the current simulation step.
50398
+ *
50399
+ * @return {Timer} A reference to this timer.
50400
+ */
50401
+ reset() {
50172
50402
 
50173
- this.elapsedTime += diff;
50403
+ this._currentTime = performance.now() - this._startTime;
50404
+
50405
+ return this;
50406
+
50407
+ }
50408
+
50409
+ /**
50410
+ * Can be used to free all internal resources. Usually called when
50411
+ * the timer instance isn't required anymore.
50412
+ */
50413
+ dispose() {
50414
+
50415
+ this.disconnect();
50416
+
50417
+ }
50418
+
50419
+ /**
50420
+ * Updates the internal state of the timer. This method should be called
50421
+ * once per simulation step and before you perform queries against the timer
50422
+ * (e.g. via `getDelta()`).
50423
+ *
50424
+ * @param {number} timestamp - The current time in milliseconds. Can be obtained
50425
+ * from the `requestAnimationFrame` callback argument. If not provided, the current
50426
+ * time will be determined with `performance.now`.
50427
+ * @return {Timer} A reference to this timer.
50428
+ */
50429
+ update( timestamp ) {
50430
+
50431
+ if ( this._pageVisibilityHandler !== null && this._document.hidden === true ) {
50432
+
50433
+ this._delta = 0;
50434
+
50435
+ } else {
50436
+
50437
+ this._previousTime = this._currentTime;
50438
+ this._currentTime = ( timestamp !== undefined ? timestamp : performance.now() ) - this._startTime;
50439
+
50440
+ this._delta = ( this._currentTime - this._previousTime ) * this._timescale;
50441
+ this._elapsed += this._delta; // _elapsed is the accumulation of all previous deltas
50174
50442
 
50175
50443
  }
50176
50444
 
50177
- return diff;
50445
+ return this;
50178
50446
 
50179
50447
  }
50180
50448
 
50449
+ };
50450
+
50451
+ function handleVisibilityChange() {
50452
+
50453
+ if ( this._document.hidden === false ) this.reset();
50454
+
50181
50455
  }
50182
50456
 
50183
50457
  const _position$1 = /*@__PURE__*/ new Vector3();
@@ -50247,7 +50521,7 @@
50247
50521
 
50248
50522
  // private
50249
50523
 
50250
- this._clock = new Clock();
50524
+ this._timer = new Timer$2();
50251
50525
 
50252
50526
  }
50253
50527
 
@@ -50352,9 +50626,11 @@
50352
50626
 
50353
50627
  super.updateMatrixWorld( force );
50354
50628
 
50629
+ this._timer.update();
50630
+
50355
50631
  const listener = this.context.listener;
50356
50632
 
50357
- this.timeDelta = this._clock.getDelta();
50633
+ this.timeDelta = this._timer.getDelta();
50358
50634
 
50359
50635
  this.matrixWorld.decompose( _position$1, _quaternion$1$1, _scale$1 );
50360
50636
 
@@ -53126,6 +53402,15 @@
53126
53402
 
53127
53403
  const interpolant = tracks[ i ].createInterpolant( null );
53128
53404
  interpolants[ i ] = interpolant;
53405
+
53406
+ // preserve interpolant settings (like tangent data from BezierInterpolant)
53407
+
53408
+ if ( interpolant.settings ) {
53409
+
53410
+ Object.assign( interpolantSettings, interpolant.settings );
53411
+
53412
+ }
53413
+
53129
53414
  interpolant.settings = interpolantSettings;
53130
53415
 
53131
53416
  }
@@ -53932,6 +54217,7 @@
53932
54217
 
53933
54218
  } else {
53934
54219
 
54220
+ this._loopCount = loopCount;
53935
54221
  this.time = time;
53936
54222
 
53937
54223
  }
@@ -53979,7 +54265,7 @@
53979
54265
 
53980
54266
  } else {
53981
54267
 
53982
- settings.endingEnd = WrapAroundEnding;
54268
+ settings.endingEnd = WrapAroundEnding;
53983
54269
 
53984
54270
  }
53985
54271
 
@@ -55627,186 +55913,135 @@
55627
55913
  }
55628
55914
 
55629
55915
  /**
55630
- * This class is an alternative to {@link Clock} with a different API design and behavior.
55631
- * The goal is to avoid the conceptual flaws that became apparent in `Clock` over time.
55632
- *
55633
- * - `Timer` has an `update()` method that updates its internal state. That makes it possible to
55634
- * call `getDelta()` and `getElapsed()` multiple times per simulation step without getting different values.
55635
- * - The class can make use of the Page Visibility API to avoid large time delta values when the app
55636
- * is inactive (e.g. tab switched or browser hidden).
55916
+ * Class for keeping track of time.
55637
55917
  *
55638
- * ```js
55639
- * const timer = new Timer();
55640
- * timer.connect( document ); // use Page Visibility API
55641
- * ```
55918
+ * @deprecated since r183.
55642
55919
  */
55643
- let Timer$2 = class Timer {
55644
-
55645
- /**
55646
- * Constructs a new timer.
55647
- */
55648
- constructor() {
55649
-
55650
- this._previousTime = 0;
55651
- this._currentTime = 0;
55652
- this._startTime = performance.now();
55653
-
55654
- this._delta = 0;
55655
- this._elapsed = 0;
55656
-
55657
- this._timescale = 1;
55658
-
55659
- this._document = null;
55660
- this._pageVisibilityHandler = null;
55661
-
55662
- }
55920
+ class Clock {
55663
55921
 
55664
55922
  /**
55665
- * Connect the timer to the given document.Calling this method is not mandatory to
55666
- * use the timer but enables the usage of the Page Visibility API to avoid large time
55667
- * delta values.
55923
+ * Constructs a new clock.
55668
55924
  *
55669
- * @param {Document} document - The document.
55925
+ * @deprecated since 183.
55926
+ * @param {boolean} [autoStart=true] - Whether to automatically start the clock when
55927
+ * `getDelta()` is called for the first time.
55670
55928
  */
55671
- connect( document ) {
55929
+ constructor( autoStart = true ) {
55672
55930
 
55673
- this._document = document;
55931
+ /**
55932
+ * If set to `true`, the clock starts automatically when `getDelta()` is called
55933
+ * for the first time.
55934
+ *
55935
+ * @type {boolean}
55936
+ * @default true
55937
+ */
55938
+ this.autoStart = autoStart;
55674
55939
 
55675
- // use Page Visibility API to avoid large time delta values
55940
+ /**
55941
+ * Holds the time at which the clock's `start()` method was last called.
55942
+ *
55943
+ * @type {number}
55944
+ * @default 0
55945
+ */
55946
+ this.startTime = 0;
55676
55947
 
55677
- if ( document.hidden !== undefined ) {
55948
+ /**
55949
+ * Holds the time at which the clock's `start()`, `getElapsedTime()` or
55950
+ * `getDelta()` methods were last called.
55951
+ *
55952
+ * @type {number}
55953
+ * @default 0
55954
+ */
55955
+ this.oldTime = 0;
55678
55956
 
55679
- this._pageVisibilityHandler = handleVisibilityChange.bind( this );
55957
+ /**
55958
+ * Keeps track of the total time that the clock has been running.
55959
+ *
55960
+ * @type {number}
55961
+ * @default 0
55962
+ */
55963
+ this.elapsedTime = 0;
55680
55964
 
55681
- document.addEventListener( 'visibilitychange', this._pageVisibilityHandler, false );
55965
+ /**
55966
+ * Whether the clock is running or not.
55967
+ *
55968
+ * @type {boolean}
55969
+ * @default true
55970
+ */
55971
+ this.running = false;
55682
55972
 
55683
- }
55973
+ warn( 'Clock: This module has been deprecated. Please use THREE.Timer instead.' ); // @deprecated, r183
55684
55974
 
55685
55975
  }
55686
55976
 
55687
55977
  /**
55688
- * Disconnects the timer from the DOM and also disables the usage of the Page Visibility API.
55978
+ * Starts the clock. When `autoStart` is set to `true`, the method is automatically
55979
+ * called by the class.
55689
55980
  */
55690
- disconnect() {
55691
-
55692
- if ( this._pageVisibilityHandler !== null ) {
55693
-
55694
- this._document.removeEventListener( 'visibilitychange', this._pageVisibilityHandler );
55695
- this._pageVisibilityHandler = null;
55981
+ start() {
55696
55982
 
55697
- }
55983
+ this.startTime = performance.now();
55698
55984
 
55699
- this._document = null;
55985
+ this.oldTime = this.startTime;
55986
+ this.elapsedTime = 0;
55987
+ this.running = true;
55700
55988
 
55701
55989
  }
55702
55990
 
55703
55991
  /**
55704
- * Returns the time delta in seconds.
55705
- *
55706
- * @return {number} The time delta in second.
55992
+ * Stops the clock.
55707
55993
  */
55708
- getDelta() {
55994
+ stop() {
55709
55995
 
55710
- return this._delta / 1000;
55996
+ this.getElapsedTime();
55997
+ this.running = false;
55998
+ this.autoStart = false;
55711
55999
 
55712
56000
  }
55713
56001
 
55714
56002
  /**
55715
56003
  * Returns the elapsed time in seconds.
55716
56004
  *
55717
- * @return {number} The elapsed time in second.
55718
- */
55719
- getElapsed() {
55720
-
55721
- return this._elapsed / 1000;
55722
-
55723
- }
55724
-
55725
- /**
55726
- * Returns the timescale.
55727
- *
55728
- * @return {number} The timescale.
55729
- */
55730
- getTimescale() {
55731
-
55732
- return this._timescale;
55733
-
55734
- }
55735
-
55736
- /**
55737
- * Sets the given timescale which scale the time delta computation
55738
- * in `update()`.
55739
- *
55740
- * @param {number} timescale - The timescale to set.
55741
- * @return {Timer} A reference to this timer.
56005
+ * @return {number} The elapsed time.
55742
56006
  */
55743
- setTimescale( timescale ) {
55744
-
55745
- this._timescale = timescale;
56007
+ getElapsedTime() {
55746
56008
 
55747
- return this;
56009
+ this.getDelta();
56010
+ return this.elapsedTime;
55748
56011
 
55749
56012
  }
55750
56013
 
55751
56014
  /**
55752
- * Resets the time computation for the current simulation step.
56015
+ * Returns the delta time in seconds.
55753
56016
  *
55754
- * @return {Timer} A reference to this timer.
55755
- */
55756
- reset() {
55757
-
55758
- this._currentTime = performance.now() - this._startTime;
55759
-
55760
- return this;
55761
-
55762
- }
55763
-
55764
- /**
55765
- * Can be used to free all internal resources. Usually called when
55766
- * the timer instance isn't required anymore.
56017
+ * @return {number} The delta time.
55767
56018
  */
55768
- dispose() {
56019
+ getDelta() {
55769
56020
 
55770
- this.disconnect();
56021
+ let diff = 0;
55771
56022
 
55772
- }
56023
+ if ( this.autoStart && ! this.running ) {
55773
56024
 
55774
- /**
55775
- * Updates the internal state of the timer. This method should be called
55776
- * once per simulation step and before you perform queries against the timer
55777
- * (e.g. via `getDelta()`).
55778
- *
55779
- * @param {number} timestamp - The current time in milliseconds. Can be obtained
55780
- * from the `requestAnimationFrame` callback argument. If not provided, the current
55781
- * time will be determined with `performance.now`.
55782
- * @return {Timer} A reference to this timer.
55783
- */
55784
- update( timestamp ) {
56025
+ this.start();
56026
+ return 0;
55785
56027
 
55786
- if ( this._pageVisibilityHandler !== null && this._document.hidden === true ) {
56028
+ }
55787
56029
 
55788
- this._delta = 0;
56030
+ if ( this.running ) {
55789
56031
 
55790
- } else {
56032
+ const newTime = performance.now();
55791
56033
 
55792
- this._previousTime = this._currentTime;
55793
- this._currentTime = ( timestamp !== undefined ? timestamp : performance.now() ) - this._startTime;
56034
+ diff = ( newTime - this.oldTime ) / 1000;
56035
+ this.oldTime = newTime;
55794
56036
 
55795
- this._delta = ( this._currentTime - this._previousTime ) * this._timescale;
55796
- this._elapsed += this._delta; // _elapsed is the accumulation of all previous deltas
56037
+ this.elapsedTime += diff;
55797
56038
 
55798
56039
  }
55799
56040
 
55800
- return this;
56041
+ return diff;
55801
56042
 
55802
56043
  }
55803
56044
 
55804
- };
55805
-
55806
- function handleVisibilityChange() {
55807
-
55808
- if ( this._document.hidden === false ) this.reset();
55809
-
55810
56045
  }
55811
56046
 
55812
56047
  /**
@@ -56100,6 +56335,19 @@
56100
56335
  */
56101
56336
  class Matrix2 {
56102
56337
 
56338
+ static {
56339
+
56340
+ /**
56341
+ * This flag can be used for type testing.
56342
+ *
56343
+ * @type {boolean}
56344
+ * @readonly
56345
+ * @default true
56346
+ */
56347
+ Matrix2.prototype.isMatrix2 = true;
56348
+
56349
+ }
56350
+
56103
56351
  /**
56104
56352
  * Constructs a new 2x2 matrix. The arguments are supposed to be
56105
56353
  * in row-major order. If no arguments are provided, the constructor
@@ -56112,15 +56360,6 @@
56112
56360
  */
56113
56361
  constructor( n11, n12, n21, n22 ) {
56114
56362
 
56115
- /**
56116
- * This flag can be used for type testing.
56117
- *
56118
- * @type {boolean}
56119
- * @readonly
56120
- * @default true
56121
- */
56122
- Matrix2.prototype.isMatrix2 = true;
56123
-
56124
56363
  /**
56125
56364
  * A column-major list of matrix values.
56126
56365
  *
@@ -56716,6 +56955,9 @@
56716
56955
  _startEnd.subVectors( this.end, this.start );
56717
56956
 
56718
56957
  const startEnd2 = _startEnd.dot( _startEnd );
56958
+
56959
+ if ( startEnd2 === 0 ) return 0;
56960
+
56719
56961
  const startEnd_startP = _startEnd.dot( _startP );
56720
56962
 
56721
56963
  let t = startEnd_startP / startEnd2;
@@ -59498,6 +59740,7 @@
59498
59740
 
59499
59741
  if ( isAnimating === true ) return;
59500
59742
  if ( animationLoop === null ) return;
59743
+ if ( context === null ) return;
59501
59744
 
59502
59745
  requestId = context.requestAnimationFrame( onAnimationFrame );
59503
59746
 
@@ -59507,7 +59750,7 @@
59507
59750
 
59508
59751
  stop: function () {
59509
59752
 
59510
- context.cancelAnimationFrame( requestId );
59753
+ if ( context !== null ) context.cancelAnimationFrame( requestId );
59511
59754
 
59512
59755
  isAnimating = false;
59513
59756
 
@@ -59828,9 +60071,9 @@
59828
60071
 
59829
60072
  var colorspace_pars_fragment = "vec4 LinearTransferOETF( in vec4 value ) {\n\treturn value;\n}\nvec4 sRGBTransferEOTF( in vec4 value ) {\n\treturn vec4( mix( pow( value.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), value.rgb * 0.0773993808, vec3( lessThanEqual( value.rgb, vec3( 0.04045 ) ) ) ), value.a );\n}\nvec4 sRGBTransferOETF( in vec4 value ) {\n\treturn vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.a );\n}";
59830
60073
 
59831
- var envmap_fragment = "#ifdef USE_ENVMAP\n\t#ifdef ENV_WORLDPOS\n\t\tvec3 cameraToFrag;\n\t\tif ( isOrthographic ) {\n\t\t\tcameraToFrag = normalize( vec3( - viewMatrix[ 0 ][ 2 ], - viewMatrix[ 1 ][ 2 ], - viewMatrix[ 2 ][ 2 ] ) );\n\t\t} else {\n\t\t\tcameraToFrag = normalize( vWorldPosition - cameraPosition );\n\t\t}\n\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvec3 reflectVec = reflect( cameraToFrag, worldNormal );\n\t\t#else\n\t\t\tvec3 reflectVec = refract( cameraToFrag, worldNormal, refractionRatio );\n\t\t#endif\n\t#else\n\t\tvec3 reflectVec = vReflect;\n\t#endif\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tvec4 envColor = textureCube( envMap, envMapRotation * vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );\n\t\t#ifdef ENVMAP_BLENDING_MULTIPLY\n\t\t\toutgoingLight = mix( outgoingLight, outgoingLight * envColor.xyz, specularStrength * reflectivity );\n\t\t#elif defined( ENVMAP_BLENDING_MIX )\n\t\t\toutgoingLight = mix( outgoingLight, envColor.xyz, specularStrength * reflectivity );\n\t\t#elif defined( ENVMAP_BLENDING_ADD )\n\t\t\toutgoingLight += envColor.xyz * specularStrength * reflectivity;\n\t\t#endif\n\t#endif\n#endif";
60074
+ var envmap_fragment = "#ifdef USE_ENVMAP\n\t#ifdef ENV_WORLDPOS\n\t\tvec3 cameraToFrag;\n\t\tif ( isOrthographic ) {\n\t\t\tcameraToFrag = normalize( vec3( - viewMatrix[ 0 ][ 2 ], - viewMatrix[ 1 ][ 2 ], - viewMatrix[ 2 ][ 2 ] ) );\n\t\t} else {\n\t\t\tcameraToFrag = normalize( vWorldPosition - cameraPosition );\n\t\t}\n\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvec3 reflectVec = reflect( cameraToFrag, worldNormal );\n\t\t#else\n\t\t\tvec3 reflectVec = refract( cameraToFrag, worldNormal, refractionRatio );\n\t\t#endif\n\t#else\n\t\tvec3 reflectVec = vReflect;\n\t#endif\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tvec4 envColor = textureCube( envMap, envMapRotation * reflectVec );\n\t\t#ifdef ENVMAP_BLENDING_MULTIPLY\n\t\t\toutgoingLight = mix( outgoingLight, outgoingLight * envColor.xyz, specularStrength * reflectivity );\n\t\t#elif defined( ENVMAP_BLENDING_MIX )\n\t\t\toutgoingLight = mix( outgoingLight, envColor.xyz, specularStrength * reflectivity );\n\t\t#elif defined( ENVMAP_BLENDING_ADD )\n\t\t\toutgoingLight += envColor.xyz * specularStrength * reflectivity;\n\t\t#endif\n\t#endif\n#endif";
59832
60075
 
59833
- var envmap_common_pars_fragment = "#ifdef USE_ENVMAP\n\tuniform float envMapIntensity;\n\tuniform float flipEnvMap;\n\tuniform mat3 envMapRotation;\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tuniform samplerCube envMap;\n\t#else\n\t\tuniform sampler2D envMap;\n\t#endif\n#endif";
60076
+ var envmap_common_pars_fragment = "#ifdef USE_ENVMAP\n\tuniform float envMapIntensity;\n\tuniform mat3 envMapRotation;\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tuniform samplerCube envMap;\n\t#else\n\t\tuniform sampler2D envMap;\n\t#endif\n#endif";
59834
60077
 
59835
60078
  var envmap_pars_fragment = "#ifdef USE_ENVMAP\n\tuniform float reflectivity;\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) || defined( LAMBERT )\n\t\t#define ENV_WORLDPOS\n\t#endif\n\t#ifdef ENV_WORLDPOS\n\t\tvarying vec3 vWorldPosition;\n\t\tuniform float refractionRatio;\n\t#else\n\t\tvarying vec3 vReflect;\n\t#endif\n#endif";
59836
60079
 
@@ -59854,7 +60097,7 @@
59854
60097
 
59855
60098
  var lights_lambert_pars_fragment = "varying vec3 vViewPosition;\nstruct LambertMaterial {\n\tvec3 diffuseColor;\n\tfloat specularStrength;\n};\nvoid RE_Direct_Lambert( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in LambertMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometryNormal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Lambert( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in LambertMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_Lambert\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Lambert";
59856
60099
 
59857
- var lights_pars_begin = "uniform bool receiveShadow;\nuniform vec3 ambientLightColor;\n#if defined( USE_LIGHT_PROBES )\n\tuniform vec3 lightProbe[ 9 ];\n#endif\nvec3 shGetIrradianceAt( in vec3 normal, in vec3 shCoefficients[ 9 ] ) {\n\tfloat x = normal.x, y = normal.y, z = normal.z;\n\tvec3 result = shCoefficients[ 0 ] * 0.886227;\n\tresult += shCoefficients[ 1 ] * 2.0 * 0.511664 * y;\n\tresult += shCoefficients[ 2 ] * 2.0 * 0.511664 * z;\n\tresult += shCoefficients[ 3 ] * 2.0 * 0.511664 * x;\n\tresult += shCoefficients[ 4 ] * 2.0 * 0.429043 * x * y;\n\tresult += shCoefficients[ 5 ] * 2.0 * 0.429043 * y * z;\n\tresult += shCoefficients[ 6 ] * ( 0.743125 * z * z - 0.247708 );\n\tresult += shCoefficients[ 7 ] * 2.0 * 0.429043 * x * z;\n\tresult += shCoefficients[ 8 ] * 0.429043 * ( x * x - y * y );\n\treturn result;\n}\nvec3 getLightProbeIrradiance( const in vec3 lightProbe[ 9 ], const in vec3 normal ) {\n\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\tvec3 irradiance = shGetIrradianceAt( worldNormal, lightProbe );\n\treturn irradiance;\n}\nvec3 getAmbientLightIrradiance( const in vec3 ambientLightColor ) {\n\tvec3 irradiance = ambientLightColor;\n\treturn irradiance;\n}\nfloat getDistanceAttenuation( const in float lightDistance, const in float cutoffDistance, const in float decayExponent ) {\n\tfloat distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), 0.01 );\n\tif ( cutoffDistance > 0.0 ) {\n\t\tdistanceFalloff *= pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) );\n\t}\n\treturn distanceFalloff;\n}\nfloat getSpotAttenuation( const in float coneCosine, const in float penumbraCosine, const in float angleCosine ) {\n\treturn smoothstep( coneCosine, penumbraCosine, angleCosine );\n}\n#if NUM_DIR_LIGHTS > 0\n\tstruct DirectionalLight {\n\t\tvec3 direction;\n\t\tvec3 color;\n\t};\n\tuniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ];\n\tvoid getDirectionalLightInfo( const in DirectionalLight directionalLight, out IncidentLight light ) {\n\t\tlight.color = directionalLight.color;\n\t\tlight.direction = directionalLight.direction;\n\t\tlight.visible = true;\n\t}\n#endif\n#if NUM_POINT_LIGHTS > 0\n\tstruct PointLight {\n\t\tvec3 position;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t};\n\tuniform PointLight pointLights[ NUM_POINT_LIGHTS ];\n\tvoid getPointLightInfo( const in PointLight pointLight, const in vec3 geometryPosition, out IncidentLight light ) {\n\t\tvec3 lVector = pointLight.position - geometryPosition;\n\t\tlight.direction = normalize( lVector );\n\t\tfloat lightDistance = length( lVector );\n\t\tlight.color = pointLight.color;\n\t\tlight.color *= getDistanceAttenuation( lightDistance, pointLight.distance, pointLight.decay );\n\t\tlight.visible = ( light.color != vec3( 0.0 ) );\n\t}\n#endif\n#if NUM_SPOT_LIGHTS > 0\n\tstruct SpotLight {\n\t\tvec3 position;\n\t\tvec3 direction;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t\tfloat coneCos;\n\t\tfloat penumbraCos;\n\t};\n\tuniform SpotLight spotLights[ NUM_SPOT_LIGHTS ];\n\tvoid getSpotLightInfo( const in SpotLight spotLight, const in vec3 geometryPosition, out IncidentLight light ) {\n\t\tvec3 lVector = spotLight.position - geometryPosition;\n\t\tlight.direction = normalize( lVector );\n\t\tfloat angleCos = dot( light.direction, spotLight.direction );\n\t\tfloat spotAttenuation = getSpotAttenuation( spotLight.coneCos, spotLight.penumbraCos, angleCos );\n\t\tif ( spotAttenuation > 0.0 ) {\n\t\t\tfloat lightDistance = length( lVector );\n\t\t\tlight.color = spotLight.color * spotAttenuation;\n\t\t\tlight.color *= getDistanceAttenuation( lightDistance, spotLight.distance, spotLight.decay );\n\t\t\tlight.visible = ( light.color != vec3( 0.0 ) );\n\t\t} else {\n\t\t\tlight.color = vec3( 0.0 );\n\t\t\tlight.visible = false;\n\t\t}\n\t}\n#endif\n#if NUM_RECT_AREA_LIGHTS > 0\n\tstruct RectAreaLight {\n\t\tvec3 color;\n\t\tvec3 position;\n\t\tvec3 halfWidth;\n\t\tvec3 halfHeight;\n\t};\n\tuniform sampler2D ltc_1;\tuniform sampler2D ltc_2;\n\tuniform RectAreaLight rectAreaLights[ NUM_RECT_AREA_LIGHTS ];\n#endif\n#if NUM_HEMI_LIGHTS > 0\n\tstruct HemisphereLight {\n\t\tvec3 direction;\n\t\tvec3 skyColor;\n\t\tvec3 groundColor;\n\t};\n\tuniform HemisphereLight hemisphereLights[ NUM_HEMI_LIGHTS ];\n\tvec3 getHemisphereLightIrradiance( const in HemisphereLight hemiLight, const in vec3 normal ) {\n\t\tfloat dotNL = dot( normal, hemiLight.direction );\n\t\tfloat hemiDiffuseWeight = 0.5 * dotNL + 0.5;\n\t\tvec3 irradiance = mix( hemiLight.groundColor, hemiLight.skyColor, hemiDiffuseWeight );\n\t\treturn irradiance;\n\t}\n#endif";
60100
+ var lights_pars_begin = "uniform bool receiveShadow;\nuniform vec3 ambientLightColor;\n#if defined( USE_LIGHT_PROBES )\n\tuniform vec3 lightProbe[ 9 ];\n#endif\nvec3 shGetIrradianceAt( in vec3 normal, in vec3 shCoefficients[ 9 ] ) {\n\tfloat x = normal.x, y = normal.y, z = normal.z;\n\tvec3 result = shCoefficients[ 0 ] * 0.886227;\n\tresult += shCoefficients[ 1 ] * 2.0 * 0.511664 * y;\n\tresult += shCoefficients[ 2 ] * 2.0 * 0.511664 * z;\n\tresult += shCoefficients[ 3 ] * 2.0 * 0.511664 * x;\n\tresult += shCoefficients[ 4 ] * 2.0 * 0.429043 * x * y;\n\tresult += shCoefficients[ 5 ] * 2.0 * 0.429043 * y * z;\n\tresult += shCoefficients[ 6 ] * ( 0.743125 * z * z - 0.247708 );\n\tresult += shCoefficients[ 7 ] * 2.0 * 0.429043 * x * z;\n\tresult += shCoefficients[ 8 ] * 0.429043 * ( x * x - y * y );\n\treturn result;\n}\nvec3 getLightProbeIrradiance( const in vec3 lightProbe[ 9 ], const in vec3 normal ) {\n\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\tvec3 irradiance = shGetIrradianceAt( worldNormal, lightProbe );\n\treturn irradiance;\n}\nvec3 getAmbientLightIrradiance( const in vec3 ambientLightColor ) {\n\tvec3 irradiance = ambientLightColor;\n\treturn irradiance;\n}\nfloat getDistanceAttenuation( const in float lightDistance, const in float cutoffDistance, const in float decayExponent ) {\n\tfloat distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), 0.01 );\n\tif ( cutoffDistance > 0.0 ) {\n\t\tdistanceFalloff *= pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) );\n\t}\n\treturn distanceFalloff;\n}\nfloat getSpotAttenuation( const in float coneCosine, const in float penumbraCosine, const in float angleCosine ) {\n\treturn smoothstep( coneCosine, penumbraCosine, angleCosine );\n}\n#if NUM_DIR_LIGHTS > 0\n\tstruct DirectionalLight {\n\t\tvec3 direction;\n\t\tvec3 color;\n\t};\n\tuniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ];\n\tvoid getDirectionalLightInfo( const in DirectionalLight directionalLight, out IncidentLight light ) {\n\t\tlight.color = directionalLight.color;\n\t\tlight.direction = directionalLight.direction;\n\t\tlight.visible = true;\n\t}\n#endif\n#if NUM_POINT_LIGHTS > 0\n\tstruct PointLight {\n\t\tvec3 position;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t};\n\tuniform PointLight pointLights[ NUM_POINT_LIGHTS ];\n\tvoid getPointLightInfo( const in PointLight pointLight, const in vec3 geometryPosition, out IncidentLight light ) {\n\t\tvec3 lVector = pointLight.position - geometryPosition;\n\t\tlight.direction = normalize( lVector );\n\t\tfloat lightDistance = length( lVector );\n\t\tlight.color = pointLight.color;\n\t\tlight.color *= getDistanceAttenuation( lightDistance, pointLight.distance, pointLight.decay );\n\t\tlight.visible = ( light.color != vec3( 0.0 ) );\n\t}\n#endif\n#if NUM_SPOT_LIGHTS > 0\n\tstruct SpotLight {\n\t\tvec3 position;\n\t\tvec3 direction;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t\tfloat coneCos;\n\t\tfloat penumbraCos;\n\t};\n\tuniform SpotLight spotLights[ NUM_SPOT_LIGHTS ];\n\tvoid getSpotLightInfo( const in SpotLight spotLight, const in vec3 geometryPosition, out IncidentLight light ) {\n\t\tvec3 lVector = spotLight.position - geometryPosition;\n\t\tlight.direction = normalize( lVector );\n\t\tfloat angleCos = dot( light.direction, spotLight.direction );\n\t\tfloat spotAttenuation = getSpotAttenuation( spotLight.coneCos, spotLight.penumbraCos, angleCos );\n\t\tif ( spotAttenuation > 0.0 ) {\n\t\t\tfloat lightDistance = length( lVector );\n\t\t\tlight.color = spotLight.color * spotAttenuation;\n\t\t\tlight.color *= getDistanceAttenuation( lightDistance, spotLight.distance, spotLight.decay );\n\t\t\tlight.visible = ( light.color != vec3( 0.0 ) );\n\t\t} else {\n\t\t\tlight.color = vec3( 0.0 );\n\t\t\tlight.visible = false;\n\t\t}\n\t}\n#endif\n#if NUM_RECT_AREA_LIGHTS > 0\n\tstruct RectAreaLight {\n\t\tvec3 color;\n\t\tvec3 position;\n\t\tvec3 halfWidth;\n\t\tvec3 halfHeight;\n\t};\n\tuniform sampler2D ltc_1;\tuniform sampler2D ltc_2;\n\tuniform RectAreaLight rectAreaLights[ NUM_RECT_AREA_LIGHTS ];\n#endif\n#if NUM_HEMI_LIGHTS > 0\n\tstruct HemisphereLight {\n\t\tvec3 direction;\n\t\tvec3 skyColor;\n\t\tvec3 groundColor;\n\t};\n\tuniform HemisphereLight hemisphereLights[ NUM_HEMI_LIGHTS ];\n\tvec3 getHemisphereLightIrradiance( const in HemisphereLight hemiLight, const in vec3 normal ) {\n\t\tfloat dotNL = dot( normal, hemiLight.direction );\n\t\tfloat hemiDiffuseWeight = 0.5 * dotNL + 0.5;\n\t\tvec3 irradiance = mix( hemiLight.groundColor, hemiLight.skyColor, hemiDiffuseWeight );\n\t\treturn irradiance;\n\t}\n#endif\n#include <lightprobes_pars_fragment>";
59858
60101
 
59859
60102
  var envmap_physical_pars_fragment = "#ifdef USE_ENVMAP\n\tvec3 getIBLIrradiance( const in vec3 normal ) {\n\t\t#ifdef ENVMAP_TYPE_CUBE_UV\n\t\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\t\t\tvec4 envMapColor = textureCubeUV( envMap, envMapRotation * worldNormal, 1.0 );\n\t\t\treturn PI * envMapColor.rgb * envMapIntensity;\n\t\t#else\n\t\t\treturn vec3( 0.0 );\n\t\t#endif\n\t}\n\tvec3 getIBLRadiance( const in vec3 viewDir, const in vec3 normal, const in float roughness ) {\n\t\t#ifdef ENVMAP_TYPE_CUBE_UV\n\t\t\tvec3 reflectVec = reflect( - viewDir, normal );\n\t\t\treflectVec = normalize( mix( reflectVec, normal, pow4( roughness ) ) );\n\t\t\treflectVec = inverseTransformDirection( reflectVec, viewMatrix );\n\t\t\tvec4 envMapColor = textureCubeUV( envMap, envMapRotation * reflectVec, roughness );\n\t\t\treturn envMapColor.rgb * envMapIntensity;\n\t\t#else\n\t\t\treturn vec3( 0.0 );\n\t\t#endif\n\t}\n\t#ifdef USE_ANISOTROPY\n\t\tvec3 getIBLAnisotropyRadiance( const in vec3 viewDir, const in vec3 normal, const in float roughness, const in vec3 bitangent, const in float anisotropy ) {\n\t\t\t#ifdef ENVMAP_TYPE_CUBE_UV\n\t\t\t\tvec3 bentNormal = cross( bitangent, viewDir );\n\t\t\t\tbentNormal = normalize( cross( bentNormal, bitangent ) );\n\t\t\t\tbentNormal = normalize( mix( bentNormal, normal, pow2( pow2( 1.0 - anisotropy * ( 1.0 - roughness ) ) ) ) );\n\t\t\t\treturn getIBLRadiance( viewDir, bentNormal, roughness );\n\t\t\t#else\n\t\t\t\treturn vec3( 0.0 );\n\t\t\t#endif\n\t\t}\n\t#endif\n#endif";
59860
60103
 
@@ -59868,14 +60111,16 @@
59868
60111
 
59869
60112
  var lights_physical_fragment = "PhysicalMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.diffuseContribution = diffuseColor.rgb * ( 1.0 - metalnessFactor );\nmaterial.metalness = metalnessFactor;\nvec3 dxy = max( abs( dFdx( nonPerturbedNormal ) ), abs( dFdy( nonPerturbedNormal ) ) );\nfloat geometryRoughness = max( max( dxy.x, dxy.y ), dxy.z );\nmaterial.roughness = max( roughnessFactor, 0.0525 );material.roughness += geometryRoughness;\nmaterial.roughness = min( material.roughness, 1.0 );\n#ifdef IOR\n\tmaterial.ior = ior;\n\t#ifdef USE_SPECULAR\n\t\tfloat specularIntensityFactor = specularIntensity;\n\t\tvec3 specularColorFactor = specularColor;\n\t\t#ifdef USE_SPECULAR_COLORMAP\n\t\t\tspecularColorFactor *= texture2D( specularColorMap, vSpecularColorMapUv ).rgb;\n\t\t#endif\n\t\t#ifdef USE_SPECULAR_INTENSITYMAP\n\t\t\tspecularIntensityFactor *= texture2D( specularIntensityMap, vSpecularIntensityMapUv ).a;\n\t\t#endif\n\t\tmaterial.specularF90 = mix( specularIntensityFactor, 1.0, metalnessFactor );\n\t#else\n\t\tfloat specularIntensityFactor = 1.0;\n\t\tvec3 specularColorFactor = vec3( 1.0 );\n\t\tmaterial.specularF90 = 1.0;\n\t#endif\n\tmaterial.specularColor = min( pow2( ( material.ior - 1.0 ) / ( material.ior + 1.0 ) ) * specularColorFactor, vec3( 1.0 ) ) * specularIntensityFactor;\n\tmaterial.specularColorBlended = mix( material.specularColor, diffuseColor.rgb, metalnessFactor );\n#else\n\tmaterial.specularColor = vec3( 0.04 );\n\tmaterial.specularColorBlended = mix( material.specularColor, diffuseColor.rgb, metalnessFactor );\n\tmaterial.specularF90 = 1.0;\n#endif\n#ifdef USE_CLEARCOAT\n\tmaterial.clearcoat = clearcoat;\n\tmaterial.clearcoatRoughness = clearcoatRoughness;\n\tmaterial.clearcoatF0 = vec3( 0.04 );\n\tmaterial.clearcoatF90 = 1.0;\n\t#ifdef USE_CLEARCOATMAP\n\t\tmaterial.clearcoat *= texture2D( clearcoatMap, vClearcoatMapUv ).x;\n\t#endif\n\t#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\t\tmaterial.clearcoatRoughness *= texture2D( clearcoatRoughnessMap, vClearcoatRoughnessMapUv ).y;\n\t#endif\n\tmaterial.clearcoat = saturate( material.clearcoat );\tmaterial.clearcoatRoughness = max( material.clearcoatRoughness, 0.0525 );\n\tmaterial.clearcoatRoughness += geometryRoughness;\n\tmaterial.clearcoatRoughness = min( material.clearcoatRoughness, 1.0 );\n#endif\n#ifdef USE_DISPERSION\n\tmaterial.dispersion = dispersion;\n#endif\n#ifdef USE_IRIDESCENCE\n\tmaterial.iridescence = iridescence;\n\tmaterial.iridescenceIOR = iridescenceIOR;\n\t#ifdef USE_IRIDESCENCEMAP\n\t\tmaterial.iridescence *= texture2D( iridescenceMap, vIridescenceMapUv ).r;\n\t#endif\n\t#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\t\tmaterial.iridescenceThickness = (iridescenceThicknessMaximum - iridescenceThicknessMinimum) * texture2D( iridescenceThicknessMap, vIridescenceThicknessMapUv ).g + iridescenceThicknessMinimum;\n\t#else\n\t\tmaterial.iridescenceThickness = iridescenceThicknessMaximum;\n\t#endif\n#endif\n#ifdef USE_SHEEN\n\tmaterial.sheenColor = sheenColor;\n\t#ifdef USE_SHEEN_COLORMAP\n\t\tmaterial.sheenColor *= texture2D( sheenColorMap, vSheenColorMapUv ).rgb;\n\t#endif\n\tmaterial.sheenRoughness = clamp( sheenRoughness, 0.0001, 1.0 );\n\t#ifdef USE_SHEEN_ROUGHNESSMAP\n\t\tmaterial.sheenRoughness *= texture2D( sheenRoughnessMap, vSheenRoughnessMapUv ).a;\n\t#endif\n#endif\n#ifdef USE_ANISOTROPY\n\t#ifdef USE_ANISOTROPYMAP\n\t\tmat2 anisotropyMat = mat2( anisotropyVector.x, anisotropyVector.y, - anisotropyVector.y, anisotropyVector.x );\n\t\tvec3 anisotropyPolar = texture2D( anisotropyMap, vAnisotropyMapUv ).rgb;\n\t\tvec2 anisotropyV = anisotropyMat * normalize( 2.0 * anisotropyPolar.rg - vec2( 1.0 ) ) * anisotropyPolar.b;\n\t#else\n\t\tvec2 anisotropyV = anisotropyVector;\n\t#endif\n\tmaterial.anisotropy = length( anisotropyV );\n\tif( material.anisotropy == 0.0 ) {\n\t\tanisotropyV = vec2( 1.0, 0.0 );\n\t} else {\n\t\tanisotropyV /= material.anisotropy;\n\t\tmaterial.anisotropy = saturate( material.anisotropy );\n\t}\n\tmaterial.alphaT = mix( pow2( material.roughness ), 1.0, pow2( material.anisotropy ) );\n\tmaterial.anisotropyT = tbn[ 0 ] * anisotropyV.x + tbn[ 1 ] * anisotropyV.y;\n\tmaterial.anisotropyB = tbn[ 1 ] * anisotropyV.x - tbn[ 0 ] * anisotropyV.y;\n#endif";
59870
60113
 
59871
- var lights_physical_pars_fragment = "uniform sampler2D dfgLUT;\nstruct PhysicalMaterial {\n\tvec3 diffuseColor;\n\tvec3 diffuseContribution;\n\tvec3 specularColor;\n\tvec3 specularColorBlended;\n\tfloat roughness;\n\tfloat metalness;\n\tfloat specularF90;\n\tfloat dispersion;\n\t#ifdef USE_CLEARCOAT\n\t\tfloat clearcoat;\n\t\tfloat clearcoatRoughness;\n\t\tvec3 clearcoatF0;\n\t\tfloat clearcoatF90;\n\t#endif\n\t#ifdef USE_IRIDESCENCE\n\t\tfloat iridescence;\n\t\tfloat iridescenceIOR;\n\t\tfloat iridescenceThickness;\n\t\tvec3 iridescenceFresnel;\n\t\tvec3 iridescenceF0;\n\t\tvec3 iridescenceFresnelDielectric;\n\t\tvec3 iridescenceFresnelMetallic;\n\t#endif\n\t#ifdef USE_SHEEN\n\t\tvec3 sheenColor;\n\t\tfloat sheenRoughness;\n\t#endif\n\t#ifdef IOR\n\t\tfloat ior;\n\t#endif\n\t#ifdef USE_TRANSMISSION\n\t\tfloat transmission;\n\t\tfloat transmissionAlpha;\n\t\tfloat thickness;\n\t\tfloat attenuationDistance;\n\t\tvec3 attenuationColor;\n\t#endif\n\t#ifdef USE_ANISOTROPY\n\t\tfloat anisotropy;\n\t\tfloat alphaT;\n\t\tvec3 anisotropyT;\n\t\tvec3 anisotropyB;\n\t#endif\n};\nvec3 clearcoatSpecularDirect = vec3( 0.0 );\nvec3 clearcoatSpecularIndirect = vec3( 0.0 );\nvec3 sheenSpecularDirect = vec3( 0.0 );\nvec3 sheenSpecularIndirect = vec3(0.0 );\nvec3 Schlick_to_F0( const in vec3 f, const in float f90, const in float dotVH ) {\n float x = clamp( 1.0 - dotVH, 0.0, 1.0 );\n float x2 = x * x;\n float x5 = clamp( x * x2 * x2, 0.0, 0.9999 );\n return ( f - vec3( f90 ) * x5 ) / ( 1.0 - x5 );\n}\nfloat V_GGX_SmithCorrelated( const in float alpha, const in float dotNL, const in float dotNV ) {\n\tfloat a2 = pow2( alpha );\n\tfloat gv = dotNL * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\n\tfloat gl = dotNV * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\n\treturn 0.5 / max( gv + gl, EPSILON );\n}\nfloat D_GGX( const in float alpha, const in float dotNH ) {\n\tfloat a2 = pow2( alpha );\n\tfloat denom = pow2( dotNH ) * ( a2 - 1.0 ) + 1.0;\n\treturn RECIPROCAL_PI * a2 / pow2( denom );\n}\n#ifdef USE_ANISOTROPY\n\tfloat V_GGX_SmithCorrelated_Anisotropic( const in float alphaT, const in float alphaB, const in float dotTV, const in float dotBV, const in float dotTL, const in float dotBL, const in float dotNV, const in float dotNL ) {\n\t\tfloat gv = dotNL * length( vec3( alphaT * dotTV, alphaB * dotBV, dotNV ) );\n\t\tfloat gl = dotNV * length( vec3( alphaT * dotTL, alphaB * dotBL, dotNL ) );\n\t\tfloat v = 0.5 / ( gv + gl );\n\t\treturn v;\n\t}\n\tfloat D_GGX_Anisotropic( const in float alphaT, const in float alphaB, const in float dotNH, const in float dotTH, const in float dotBH ) {\n\t\tfloat a2 = alphaT * alphaB;\n\t\thighp vec3 v = vec3( alphaB * dotTH, alphaT * dotBH, a2 * dotNH );\n\t\thighp float v2 = dot( v, v );\n\t\tfloat w2 = a2 / v2;\n\t\treturn RECIPROCAL_PI * a2 * pow2 ( w2 );\n\t}\n#endif\n#ifdef USE_CLEARCOAT\n\tvec3 BRDF_GGX_Clearcoat( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in PhysicalMaterial material) {\n\t\tvec3 f0 = material.clearcoatF0;\n\t\tfloat f90 = material.clearcoatF90;\n\t\tfloat roughness = material.clearcoatRoughness;\n\t\tfloat alpha = pow2( roughness );\n\t\tvec3 halfDir = normalize( lightDir + viewDir );\n\t\tfloat dotNL = saturate( dot( normal, lightDir ) );\n\t\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\t\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\t\tfloat dotVH = saturate( dot( viewDir, halfDir ) );\n\t\tvec3 F = F_Schlick( f0, f90, dotVH );\n\t\tfloat V = V_GGX_SmithCorrelated( alpha, dotNL, dotNV );\n\t\tfloat D = D_GGX( alpha, dotNH );\n\t\treturn F * ( V * D );\n\t}\n#endif\nvec3 BRDF_GGX( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in PhysicalMaterial material ) {\n\tvec3 f0 = material.specularColorBlended;\n\tfloat f90 = material.specularF90;\n\tfloat roughness = material.roughness;\n\tfloat alpha = pow2( roughness );\n\tvec3 halfDir = normalize( lightDir + viewDir );\n\tfloat dotNL = saturate( dot( normal, lightDir ) );\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\tfloat dotVH = saturate( dot( viewDir, halfDir ) );\n\tvec3 F = F_Schlick( f0, f90, dotVH );\n\t#ifdef USE_IRIDESCENCE\n\t\tF = mix( F, material.iridescenceFresnel, material.iridescence );\n\t#endif\n\t#ifdef USE_ANISOTROPY\n\t\tfloat dotTL = dot( material.anisotropyT, lightDir );\n\t\tfloat dotTV = dot( material.anisotropyT, viewDir );\n\t\tfloat dotTH = dot( material.anisotropyT, halfDir );\n\t\tfloat dotBL = dot( material.anisotropyB, lightDir );\n\t\tfloat dotBV = dot( material.anisotropyB, viewDir );\n\t\tfloat dotBH = dot( material.anisotropyB, halfDir );\n\t\tfloat V = V_GGX_SmithCorrelated_Anisotropic( material.alphaT, alpha, dotTV, dotBV, dotTL, dotBL, dotNV, dotNL );\n\t\tfloat D = D_GGX_Anisotropic( material.alphaT, alpha, dotNH, dotTH, dotBH );\n\t#else\n\t\tfloat V = V_GGX_SmithCorrelated( alpha, dotNL, dotNV );\n\t\tfloat D = D_GGX( alpha, dotNH );\n\t#endif\n\treturn F * ( V * D );\n}\nvec2 LTC_Uv( const in vec3 N, const in vec3 V, const in float roughness ) {\n\tconst float LUT_SIZE = 64.0;\n\tconst float LUT_SCALE = ( LUT_SIZE - 1.0 ) / LUT_SIZE;\n\tconst float LUT_BIAS = 0.5 / LUT_SIZE;\n\tfloat dotNV = saturate( dot( N, V ) );\n\tvec2 uv = vec2( roughness, sqrt( 1.0 - dotNV ) );\n\tuv = uv * LUT_SCALE + LUT_BIAS;\n\treturn uv;\n}\nfloat LTC_ClippedSphereFormFactor( const in vec3 f ) {\n\tfloat l = length( f );\n\treturn max( ( l * l + f.z ) / ( l + 1.0 ), 0.0 );\n}\nvec3 LTC_EdgeVectorFormFactor( const in vec3 v1, const in vec3 v2 ) {\n\tfloat x = dot( v1, v2 );\n\tfloat y = abs( x );\n\tfloat a = 0.8543985 + ( 0.4965155 + 0.0145206 * y ) * y;\n\tfloat b = 3.4175940 + ( 4.1616724 + y ) * y;\n\tfloat v = a / b;\n\tfloat theta_sintheta = ( x > 0.0 ) ? v : 0.5 * inversesqrt( max( 1.0 - x * x, 1e-7 ) ) - v;\n\treturn cross( v1, v2 ) * theta_sintheta;\n}\nvec3 LTC_Evaluate( const in vec3 N, const in vec3 V, const in vec3 P, const in mat3 mInv, const in vec3 rectCoords[ 4 ] ) {\n\tvec3 v1 = rectCoords[ 1 ] - rectCoords[ 0 ];\n\tvec3 v2 = rectCoords[ 3 ] - rectCoords[ 0 ];\n\tvec3 lightNormal = cross( v1, v2 );\n\tif( dot( lightNormal, P - rectCoords[ 0 ] ) < 0.0 ) return vec3( 0.0 );\n\tvec3 T1, T2;\n\tT1 = normalize( V - N * dot( V, N ) );\n\tT2 = - cross( N, T1 );\n\tmat3 mat = mInv * transpose( mat3( T1, T2, N ) );\n\tvec3 coords[ 4 ];\n\tcoords[ 0 ] = mat * ( rectCoords[ 0 ] - P );\n\tcoords[ 1 ] = mat * ( rectCoords[ 1 ] - P );\n\tcoords[ 2 ] = mat * ( rectCoords[ 2 ] - P );\n\tcoords[ 3 ] = mat * ( rectCoords[ 3 ] - P );\n\tcoords[ 0 ] = normalize( coords[ 0 ] );\n\tcoords[ 1 ] = normalize( coords[ 1 ] );\n\tcoords[ 2 ] = normalize( coords[ 2 ] );\n\tcoords[ 3 ] = normalize( coords[ 3 ] );\n\tvec3 vectorFormFactor = vec3( 0.0 );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 0 ], coords[ 1 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 1 ], coords[ 2 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 2 ], coords[ 3 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 3 ], coords[ 0 ] );\n\tfloat result = LTC_ClippedSphereFormFactor( vectorFormFactor );\n\treturn vec3( result );\n}\n#if defined( USE_SHEEN )\nfloat D_Charlie( float roughness, float dotNH ) {\n\tfloat alpha = pow2( roughness );\n\tfloat invAlpha = 1.0 / alpha;\n\tfloat cos2h = dotNH * dotNH;\n\tfloat sin2h = max( 1.0 - cos2h, 0.0078125 );\n\treturn ( 2.0 + invAlpha ) * pow( sin2h, invAlpha * 0.5 ) / ( 2.0 * PI );\n}\nfloat V_Neubelt( float dotNV, float dotNL ) {\n\treturn saturate( 1.0 / ( 4.0 * ( dotNL + dotNV - dotNL * dotNV ) ) );\n}\nvec3 BRDF_Sheen( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, vec3 sheenColor, const in float sheenRoughness ) {\n\tvec3 halfDir = normalize( lightDir + viewDir );\n\tfloat dotNL = saturate( dot( normal, lightDir ) );\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\tfloat D = D_Charlie( sheenRoughness, dotNH );\n\tfloat V = V_Neubelt( dotNV, dotNL );\n\treturn sheenColor * ( D * V );\n}\n#endif\nfloat IBLSheenBRDF( const in vec3 normal, const in vec3 viewDir, const in float roughness ) {\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat r2 = roughness * roughness;\n\tfloat rInv = 1.0 / ( roughness + 0.1 );\n\tfloat a = -1.9362 + 1.0678 * roughness + 0.4573 * r2 - 0.8469 * rInv;\n\tfloat b = -0.6014 + 0.5538 * roughness - 0.4670 * r2 - 0.1255 * rInv;\n\tfloat DG = exp( a * dotNV + b );\n\treturn saturate( DG );\n}\nvec3 EnvironmentBRDF( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float roughness ) {\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tvec2 fab = texture2D( dfgLUT, vec2( roughness, dotNV ) ).rg;\n\treturn specularColor * fab.x + specularF90 * fab.y;\n}\n#ifdef USE_IRIDESCENCE\nvoid computeMultiscatteringIridescence( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float iridescence, const in vec3 iridescenceF0, const in float roughness, inout vec3 singleScatter, inout vec3 multiScatter ) {\n#else\nvoid computeMultiscattering( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float roughness, inout vec3 singleScatter, inout vec3 multiScatter ) {\n#endif\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tvec2 fab = texture2D( dfgLUT, vec2( roughness, dotNV ) ).rg;\n\t#ifdef USE_IRIDESCENCE\n\t\tvec3 Fr = mix( specularColor, iridescenceF0, iridescence );\n\t#else\n\t\tvec3 Fr = specularColor;\n\t#endif\n\tvec3 FssEss = Fr * fab.x + specularF90 * fab.y;\n\tfloat Ess = fab.x + fab.y;\n\tfloat Ems = 1.0 - Ess;\n\tvec3 Favg = Fr + ( 1.0 - Fr ) * 0.047619;\tvec3 Fms = FssEss * Favg / ( 1.0 - Ems * Favg );\n\tsingleScatter += FssEss;\n\tmultiScatter += Fms * Ems;\n}\nvec3 BRDF_GGX_Multiscatter( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in PhysicalMaterial material ) {\n\tvec3 singleScatter = BRDF_GGX( lightDir, viewDir, normal, material );\n\tfloat dotNL = saturate( dot( normal, lightDir ) );\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tvec2 dfgV = texture2D( dfgLUT, vec2( material.roughness, dotNV ) ).rg;\n\tvec2 dfgL = texture2D( dfgLUT, vec2( material.roughness, dotNL ) ).rg;\n\tvec3 FssEss_V = material.specularColorBlended * dfgV.x + material.specularF90 * dfgV.y;\n\tvec3 FssEss_L = material.specularColorBlended * dfgL.x + material.specularF90 * dfgL.y;\n\tfloat Ess_V = dfgV.x + dfgV.y;\n\tfloat Ess_L = dfgL.x + dfgL.y;\n\tfloat Ems_V = 1.0 - Ess_V;\n\tfloat Ems_L = 1.0 - Ess_L;\n\tvec3 Favg = material.specularColorBlended + ( 1.0 - material.specularColorBlended ) * 0.047619;\n\tvec3 Fms = FssEss_V * FssEss_L * Favg / ( 1.0 - Ems_V * Ems_L * Favg + EPSILON );\n\tfloat compensationFactor = Ems_V * Ems_L;\n\tvec3 multiScatter = Fms * compensationFactor;\n\treturn singleScatter + multiScatter;\n}\n#if NUM_RECT_AREA_LIGHTS > 0\n\tvoid RE_Direct_RectArea_Physical( const in RectAreaLight rectAreaLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\t\tvec3 normal = geometryNormal;\n\t\tvec3 viewDir = geometryViewDir;\n\t\tvec3 position = geometryPosition;\n\t\tvec3 lightPos = rectAreaLight.position;\n\t\tvec3 halfWidth = rectAreaLight.halfWidth;\n\t\tvec3 halfHeight = rectAreaLight.halfHeight;\n\t\tvec3 lightColor = rectAreaLight.color;\n\t\tfloat roughness = material.roughness;\n\t\tvec3 rectCoords[ 4 ];\n\t\trectCoords[ 0 ] = lightPos + halfWidth - halfHeight;\t\trectCoords[ 1 ] = lightPos - halfWidth - halfHeight;\n\t\trectCoords[ 2 ] = lightPos - halfWidth + halfHeight;\n\t\trectCoords[ 3 ] = lightPos + halfWidth + halfHeight;\n\t\tvec2 uv = LTC_Uv( normal, viewDir, roughness );\n\t\tvec4 t1 = texture2D( ltc_1, uv );\n\t\tvec4 t2 = texture2D( ltc_2, uv );\n\t\tmat3 mInv = mat3(\n\t\t\tvec3( t1.x, 0, t1.y ),\n\t\t\tvec3( 0, 1, 0 ),\n\t\t\tvec3( t1.z, 0, t1.w )\n\t\t);\n\t\tvec3 fresnel = ( material.specularColorBlended * t2.x + ( material.specularF90 - material.specularColorBlended ) * t2.y );\n\t\treflectedLight.directSpecular += lightColor * fresnel * LTC_Evaluate( normal, viewDir, position, mInv, rectCoords );\n\t\treflectedLight.directDiffuse += lightColor * material.diffuseContribution * LTC_Evaluate( normal, viewDir, position, mat3( 1.0 ), rectCoords );\n\t\t#ifdef USE_CLEARCOAT\n\t\t\tvec3 Ncc = geometryClearcoatNormal;\n\t\t\tvec2 uvClearcoat = LTC_Uv( Ncc, viewDir, material.clearcoatRoughness );\n\t\t\tvec4 t1Clearcoat = texture2D( ltc_1, uvClearcoat );\n\t\t\tvec4 t2Clearcoat = texture2D( ltc_2, uvClearcoat );\n\t\t\tmat3 mInvClearcoat = mat3(\n\t\t\t\tvec3( t1Clearcoat.x, 0, t1Clearcoat.y ),\n\t\t\t\tvec3( 0, 1, 0 ),\n\t\t\t\tvec3( t1Clearcoat.z, 0, t1Clearcoat.w )\n\t\t\t);\n\t\t\tvec3 fresnelClearcoat = material.clearcoatF0 * t2Clearcoat.x + ( material.clearcoatF90 - material.clearcoatF0 ) * t2Clearcoat.y;\n\t\t\tclearcoatSpecularDirect += lightColor * fresnelClearcoat * LTC_Evaluate( Ncc, viewDir, position, mInvClearcoat, rectCoords );\n\t\t#endif\n\t}\n#endif\nvoid RE_Direct_Physical( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometryNormal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\t#ifdef USE_CLEARCOAT\n\t\tfloat dotNLcc = saturate( dot( geometryClearcoatNormal, directLight.direction ) );\n\t\tvec3 ccIrradiance = dotNLcc * directLight.color;\n\t\tclearcoatSpecularDirect += ccIrradiance * BRDF_GGX_Clearcoat( directLight.direction, geometryViewDir, geometryClearcoatNormal, material );\n\t#endif\n\t#ifdef USE_SHEEN\n \n \t\tsheenSpecularDirect += irradiance * BRDF_Sheen( directLight.direction, geometryViewDir, geometryNormal, material.sheenColor, material.sheenRoughness );\n \n \t\tfloat sheenAlbedoV = IBLSheenBRDF( geometryNormal, geometryViewDir, material.sheenRoughness );\n \t\tfloat sheenAlbedoL = IBLSheenBRDF( geometryNormal, directLight.direction, material.sheenRoughness );\n \n \t\tfloat sheenEnergyComp = 1.0 - max3( material.sheenColor ) * max( sheenAlbedoV, sheenAlbedoL );\n \n \t\tirradiance *= sheenEnergyComp;\n \n \t#endif\n\treflectedLight.directSpecular += irradiance * BRDF_GGX_Multiscatter( directLight.direction, geometryViewDir, geometryNormal, material );\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseContribution );\n}\nvoid RE_IndirectDiffuse_Physical( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\tvec3 diffuse = irradiance * BRDF_Lambert( material.diffuseContribution );\n\t#ifdef USE_SHEEN\n\t\tfloat sheenAlbedo = IBLSheenBRDF( geometryNormal, geometryViewDir, material.sheenRoughness );\n\t\tfloat sheenEnergyComp = 1.0 - max3( material.sheenColor ) * sheenAlbedo;\n\t\tdiffuse *= sheenEnergyComp;\n\t#endif\n\treflectedLight.indirectDiffuse += diffuse;\n}\nvoid RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 irradiance, const in vec3 clearcoatRadiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight) {\n\t#ifdef USE_CLEARCOAT\n\t\tclearcoatSpecularIndirect += clearcoatRadiance * EnvironmentBRDF( geometryClearcoatNormal, geometryViewDir, material.clearcoatF0, material.clearcoatF90, material.clearcoatRoughness );\n\t#endif\n\t#ifdef USE_SHEEN\n\t\tsheenSpecularIndirect += irradiance * material.sheenColor * IBLSheenBRDF( geometryNormal, geometryViewDir, material.sheenRoughness ) * RECIPROCAL_PI;\n \t#endif\n\tvec3 singleScatteringDielectric = vec3( 0.0 );\n\tvec3 multiScatteringDielectric = vec3( 0.0 );\n\tvec3 singleScatteringMetallic = vec3( 0.0 );\n\tvec3 multiScatteringMetallic = vec3( 0.0 );\n\t#ifdef USE_IRIDESCENCE\n\t\tcomputeMultiscatteringIridescence( geometryNormal, geometryViewDir, material.specularColor, material.specularF90, material.iridescence, material.iridescenceFresnelDielectric, material.roughness, singleScatteringDielectric, multiScatteringDielectric );\n\t\tcomputeMultiscatteringIridescence( geometryNormal, geometryViewDir, material.diffuseColor, material.specularF90, material.iridescence, material.iridescenceFresnelMetallic, material.roughness, singleScatteringMetallic, multiScatteringMetallic );\n\t#else\n\t\tcomputeMultiscattering( geometryNormal, geometryViewDir, material.specularColor, material.specularF90, material.roughness, singleScatteringDielectric, multiScatteringDielectric );\n\t\tcomputeMultiscattering( geometryNormal, geometryViewDir, material.diffuseColor, material.specularF90, material.roughness, singleScatteringMetallic, multiScatteringMetallic );\n\t#endif\n\tvec3 singleScattering = mix( singleScatteringDielectric, singleScatteringMetallic, material.metalness );\n\tvec3 multiScattering = mix( multiScatteringDielectric, multiScatteringMetallic, material.metalness );\n\tvec3 totalScatteringDielectric = singleScatteringDielectric + multiScatteringDielectric;\n\tvec3 diffuse = material.diffuseContribution * ( 1.0 - totalScatteringDielectric );\n\tvec3 cosineWeightedIrradiance = irradiance * RECIPROCAL_PI;\n\tvec3 indirectSpecular = radiance * singleScattering;\n\tindirectSpecular += multiScattering * cosineWeightedIrradiance;\n\tvec3 indirectDiffuse = diffuse * cosineWeightedIrradiance;\n\t#ifdef USE_SHEEN\n\t\tfloat sheenAlbedo = IBLSheenBRDF( geometryNormal, geometryViewDir, material.sheenRoughness );\n\t\tfloat sheenEnergyComp = 1.0 - max3( material.sheenColor ) * sheenAlbedo;\n\t\tindirectSpecular *= sheenEnergyComp;\n\t\tindirectDiffuse *= sheenEnergyComp;\n\t#endif\n\treflectedLight.indirectSpecular += indirectSpecular;\n\treflectedLight.indirectDiffuse += indirectDiffuse;\n}\n#define RE_Direct\t\t\t\tRE_Direct_Physical\n#define RE_Direct_RectArea\t\tRE_Direct_RectArea_Physical\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Physical\n#define RE_IndirectSpecular\t\tRE_IndirectSpecular_Physical\nfloat computeSpecularOcclusion( const in float dotNV, const in float ambientOcclusion, const in float roughness ) {\n\treturn saturate( pow( dotNV + ambientOcclusion, exp2( - 16.0 * roughness - 1.0 ) ) - 1.0 + ambientOcclusion );\n}";
60114
+ var lights_physical_pars_fragment = "uniform sampler2D dfgLUT;\nstruct PhysicalMaterial {\n\tvec3 diffuseColor;\n\tvec3 diffuseContribution;\n\tvec3 specularColor;\n\tvec3 specularColorBlended;\n\tfloat roughness;\n\tfloat metalness;\n\tfloat specularF90;\n\tfloat dispersion;\n\t#ifdef USE_CLEARCOAT\n\t\tfloat clearcoat;\n\t\tfloat clearcoatRoughness;\n\t\tvec3 clearcoatF0;\n\t\tfloat clearcoatF90;\n\t#endif\n\t#ifdef USE_IRIDESCENCE\n\t\tfloat iridescence;\n\t\tfloat iridescenceIOR;\n\t\tfloat iridescenceThickness;\n\t\tvec3 iridescenceFresnel;\n\t\tvec3 iridescenceF0;\n\t\tvec3 iridescenceFresnelDielectric;\n\t\tvec3 iridescenceFresnelMetallic;\n\t#endif\n\t#ifdef USE_SHEEN\n\t\tvec3 sheenColor;\n\t\tfloat sheenRoughness;\n\t#endif\n\t#ifdef IOR\n\t\tfloat ior;\n\t#endif\n\t#ifdef USE_TRANSMISSION\n\t\tfloat transmission;\n\t\tfloat transmissionAlpha;\n\t\tfloat thickness;\n\t\tfloat attenuationDistance;\n\t\tvec3 attenuationColor;\n\t#endif\n\t#ifdef USE_ANISOTROPY\n\t\tfloat anisotropy;\n\t\tfloat alphaT;\n\t\tvec3 anisotropyT;\n\t\tvec3 anisotropyB;\n\t#endif\n};\nvec3 clearcoatSpecularDirect = vec3( 0.0 );\nvec3 clearcoatSpecularIndirect = vec3( 0.0 );\nvec3 sheenSpecularDirect = vec3( 0.0 );\nvec3 sheenSpecularIndirect = vec3(0.0 );\nvec3 Schlick_to_F0( const in vec3 f, const in float f90, const in float dotVH ) {\n float x = clamp( 1.0 - dotVH, 0.0, 1.0 );\n float x2 = x * x;\n float x5 = clamp( x * x2 * x2, 0.0, 0.9999 );\n return ( f - vec3( f90 ) * x5 ) / ( 1.0 - x5 );\n}\nfloat V_GGX_SmithCorrelated( const in float alpha, const in float dotNL, const in float dotNV ) {\n\tfloat a2 = pow2( alpha );\n\tfloat gv = dotNL * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\n\tfloat gl = dotNV * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\n\treturn 0.5 / max( gv + gl, EPSILON );\n}\nfloat D_GGX( const in float alpha, const in float dotNH ) {\n\tfloat a2 = pow2( alpha );\n\tfloat denom = pow2( dotNH ) * ( a2 - 1.0 ) + 1.0;\n\treturn RECIPROCAL_PI * a2 / pow2( denom );\n}\n#ifdef USE_ANISOTROPY\n\tfloat V_GGX_SmithCorrelated_Anisotropic( const in float alphaT, const in float alphaB, const in float dotTV, const in float dotBV, const in float dotTL, const in float dotBL, const in float dotNV, const in float dotNL ) {\n\t\tfloat gv = dotNL * length( vec3( alphaT * dotTV, alphaB * dotBV, dotNV ) );\n\t\tfloat gl = dotNV * length( vec3( alphaT * dotTL, alphaB * dotBL, dotNL ) );\n\t\treturn 0.5 / max( gv + gl, EPSILON );\n\t}\n\tfloat D_GGX_Anisotropic( const in float alphaT, const in float alphaB, const in float dotNH, const in float dotTH, const in float dotBH ) {\n\t\tfloat a2 = alphaT * alphaB;\n\t\thighp vec3 v = vec3( alphaB * dotTH, alphaT * dotBH, a2 * dotNH );\n\t\thighp float v2 = dot( v, v );\n\t\tfloat w2 = a2 / v2;\n\t\treturn RECIPROCAL_PI * a2 * pow2 ( w2 );\n\t}\n#endif\n#ifdef USE_CLEARCOAT\n\tvec3 BRDF_GGX_Clearcoat( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in PhysicalMaterial material) {\n\t\tvec3 f0 = material.clearcoatF0;\n\t\tfloat f90 = material.clearcoatF90;\n\t\tfloat roughness = material.clearcoatRoughness;\n\t\tfloat alpha = pow2( roughness );\n\t\tvec3 halfDir = normalize( lightDir + viewDir );\n\t\tfloat dotNL = saturate( dot( normal, lightDir ) );\n\t\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\t\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\t\tfloat dotVH = saturate( dot( viewDir, halfDir ) );\n\t\tvec3 F = F_Schlick( f0, f90, dotVH );\n\t\tfloat V = V_GGX_SmithCorrelated( alpha, dotNL, dotNV );\n\t\tfloat D = D_GGX( alpha, dotNH );\n\t\treturn F * ( V * D );\n\t}\n#endif\nvec3 BRDF_GGX( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in PhysicalMaterial material ) {\n\tvec3 f0 = material.specularColorBlended;\n\tfloat f90 = material.specularF90;\n\tfloat roughness = material.roughness;\n\tfloat alpha = pow2( roughness );\n\tvec3 halfDir = normalize( lightDir + viewDir );\n\tfloat dotNL = saturate( dot( normal, lightDir ) );\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\tfloat dotVH = saturate( dot( viewDir, halfDir ) );\n\tvec3 F = F_Schlick( f0, f90, dotVH );\n\t#ifdef USE_IRIDESCENCE\n\t\tF = mix( F, material.iridescenceFresnel, material.iridescence );\n\t#endif\n\t#ifdef USE_ANISOTROPY\n\t\tfloat dotTL = dot( material.anisotropyT, lightDir );\n\t\tfloat dotTV = dot( material.anisotropyT, viewDir );\n\t\tfloat dotTH = dot( material.anisotropyT, halfDir );\n\t\tfloat dotBL = dot( material.anisotropyB, lightDir );\n\t\tfloat dotBV = dot( material.anisotropyB, viewDir );\n\t\tfloat dotBH = dot( material.anisotropyB, halfDir );\n\t\tfloat V = V_GGX_SmithCorrelated_Anisotropic( material.alphaT, alpha, dotTV, dotBV, dotTL, dotBL, dotNV, dotNL );\n\t\tfloat D = D_GGX_Anisotropic( material.alphaT, alpha, dotNH, dotTH, dotBH );\n\t#else\n\t\tfloat V = V_GGX_SmithCorrelated( alpha, dotNL, dotNV );\n\t\tfloat D = D_GGX( alpha, dotNH );\n\t#endif\n\treturn F * ( V * D );\n}\nvec2 LTC_Uv( const in vec3 N, const in vec3 V, const in float roughness ) {\n\tconst float LUT_SIZE = 64.0;\n\tconst float LUT_SCALE = ( LUT_SIZE - 1.0 ) / LUT_SIZE;\n\tconst float LUT_BIAS = 0.5 / LUT_SIZE;\n\tfloat dotNV = saturate( dot( N, V ) );\n\tvec2 uv = vec2( roughness, sqrt( 1.0 - dotNV ) );\n\tuv = uv * LUT_SCALE + LUT_BIAS;\n\treturn uv;\n}\nfloat LTC_ClippedSphereFormFactor( const in vec3 f ) {\n\tfloat l = length( f );\n\treturn max( ( l * l + f.z ) / ( l + 1.0 ), 0.0 );\n}\nvec3 LTC_EdgeVectorFormFactor( const in vec3 v1, const in vec3 v2 ) {\n\tfloat x = dot( v1, v2 );\n\tfloat y = abs( x );\n\tfloat a = 0.8543985 + ( 0.4965155 + 0.0145206 * y ) * y;\n\tfloat b = 3.4175940 + ( 4.1616724 + y ) * y;\n\tfloat v = a / b;\n\tfloat theta_sintheta = ( x > 0.0 ) ? v : 0.5 * inversesqrt( max( 1.0 - x * x, 1e-7 ) ) - v;\n\treturn cross( v1, v2 ) * theta_sintheta;\n}\nvec3 LTC_Evaluate( const in vec3 N, const in vec3 V, const in vec3 P, const in mat3 mInv, const in vec3 rectCoords[ 4 ] ) {\n\tvec3 v1 = rectCoords[ 1 ] - rectCoords[ 0 ];\n\tvec3 v2 = rectCoords[ 3 ] - rectCoords[ 0 ];\n\tvec3 lightNormal = cross( v1, v2 );\n\tif( dot( lightNormal, P - rectCoords[ 0 ] ) < 0.0 ) return vec3( 0.0 );\n\tvec3 T1, T2;\n\tT1 = normalize( V - N * dot( V, N ) );\n\tT2 = - cross( N, T1 );\n\tmat3 mat = mInv * transpose( mat3( T1, T2, N ) );\n\tvec3 coords[ 4 ];\n\tcoords[ 0 ] = mat * ( rectCoords[ 0 ] - P );\n\tcoords[ 1 ] = mat * ( rectCoords[ 1 ] - P );\n\tcoords[ 2 ] = mat * ( rectCoords[ 2 ] - P );\n\tcoords[ 3 ] = mat * ( rectCoords[ 3 ] - P );\n\tcoords[ 0 ] = normalize( coords[ 0 ] );\n\tcoords[ 1 ] = normalize( coords[ 1 ] );\n\tcoords[ 2 ] = normalize( coords[ 2 ] );\n\tcoords[ 3 ] = normalize( coords[ 3 ] );\n\tvec3 vectorFormFactor = vec3( 0.0 );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 0 ], coords[ 1 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 1 ], coords[ 2 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 2 ], coords[ 3 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 3 ], coords[ 0 ] );\n\tfloat result = LTC_ClippedSphereFormFactor( vectorFormFactor );\n\treturn vec3( result );\n}\n#if defined( USE_SHEEN )\nfloat D_Charlie( float roughness, float dotNH ) {\n\tfloat alpha = pow2( roughness );\n\tfloat invAlpha = 1.0 / alpha;\n\tfloat cos2h = dotNH * dotNH;\n\tfloat sin2h = max( 1.0 - cos2h, 0.0078125 );\n\treturn ( 2.0 + invAlpha ) * pow( sin2h, invAlpha * 0.5 ) / ( 2.0 * PI );\n}\nfloat V_Neubelt( float dotNV, float dotNL ) {\n\treturn saturate( 1.0 / ( 4.0 * ( dotNL + dotNV - dotNL * dotNV ) ) );\n}\nvec3 BRDF_Sheen( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, vec3 sheenColor, const in float sheenRoughness ) {\n\tvec3 halfDir = normalize( lightDir + viewDir );\n\tfloat dotNL = saturate( dot( normal, lightDir ) );\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\tfloat D = D_Charlie( sheenRoughness, dotNH );\n\tfloat V = V_Neubelt( dotNV, dotNL );\n\treturn sheenColor * ( D * V );\n}\n#endif\nfloat IBLSheenBRDF( const in vec3 normal, const in vec3 viewDir, const in float roughness ) {\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat r2 = roughness * roughness;\n\tfloat rInv = 1.0 / ( roughness + 0.1 );\n\tfloat a = -1.9362 + 1.0678 * roughness + 0.4573 * r2 - 0.8469 * rInv;\n\tfloat b = -0.6014 + 0.5538 * roughness - 0.4670 * r2 - 0.1255 * rInv;\n\tfloat DG = exp( a * dotNV + b );\n\treturn saturate( DG );\n}\nvec3 EnvironmentBRDF( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float roughness ) {\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tvec2 fab = texture2D( dfgLUT, vec2( roughness, dotNV ) ).rg;\n\treturn specularColor * fab.x + specularF90 * fab.y;\n}\n#ifdef USE_IRIDESCENCE\nvoid computeMultiscatteringIridescence( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float iridescence, const in vec3 iridescenceF0, const in float roughness, inout vec3 singleScatter, inout vec3 multiScatter ) {\n#else\nvoid computeMultiscattering( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float roughness, inout vec3 singleScatter, inout vec3 multiScatter ) {\n#endif\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tvec2 fab = texture2D( dfgLUT, vec2( roughness, dotNV ) ).rg;\n\t#ifdef USE_IRIDESCENCE\n\t\tvec3 Fr = mix( specularColor, iridescenceF0, iridescence );\n\t#else\n\t\tvec3 Fr = specularColor;\n\t#endif\n\tvec3 FssEss = Fr * fab.x + specularF90 * fab.y;\n\tfloat Ess = fab.x + fab.y;\n\tfloat Ems = 1.0 - Ess;\n\tvec3 Favg = Fr + ( 1.0 - Fr ) * 0.047619;\tvec3 Fms = FssEss * Favg / ( 1.0 - Ems * Favg );\n\tsingleScatter += FssEss;\n\tmultiScatter += Fms * Ems;\n}\nvec3 BRDF_GGX_Multiscatter( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in PhysicalMaterial material ) {\n\tvec3 singleScatter = BRDF_GGX( lightDir, viewDir, normal, material );\n\tfloat dotNL = saturate( dot( normal, lightDir ) );\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tvec2 dfgV = texture2D( dfgLUT, vec2( material.roughness, dotNV ) ).rg;\n\tvec2 dfgL = texture2D( dfgLUT, vec2( material.roughness, dotNL ) ).rg;\n\tvec3 FssEss_V = material.specularColorBlended * dfgV.x + material.specularF90 * dfgV.y;\n\tvec3 FssEss_L = material.specularColorBlended * dfgL.x + material.specularF90 * dfgL.y;\n\tfloat Ess_V = dfgV.x + dfgV.y;\n\tfloat Ess_L = dfgL.x + dfgL.y;\n\tfloat Ems_V = 1.0 - Ess_V;\n\tfloat Ems_L = 1.0 - Ess_L;\n\tvec3 Favg = material.specularColorBlended + ( 1.0 - material.specularColorBlended ) * 0.047619;\n\tvec3 Fms = FssEss_V * FssEss_L * Favg / ( 1.0 - Ems_V * Ems_L * Favg + EPSILON );\n\tfloat compensationFactor = Ems_V * Ems_L;\n\tvec3 multiScatter = Fms * compensationFactor;\n\treturn singleScatter + multiScatter;\n}\n#if NUM_RECT_AREA_LIGHTS > 0\n\tvoid RE_Direct_RectArea_Physical( const in RectAreaLight rectAreaLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\t\tvec3 normal = geometryNormal;\n\t\tvec3 viewDir = geometryViewDir;\n\t\tvec3 position = geometryPosition;\n\t\tvec3 lightPos = rectAreaLight.position;\n\t\tvec3 halfWidth = rectAreaLight.halfWidth;\n\t\tvec3 halfHeight = rectAreaLight.halfHeight;\n\t\tvec3 lightColor = rectAreaLight.color;\n\t\tfloat roughness = material.roughness;\n\t\tvec3 rectCoords[ 4 ];\n\t\trectCoords[ 0 ] = lightPos + halfWidth - halfHeight;\t\trectCoords[ 1 ] = lightPos - halfWidth - halfHeight;\n\t\trectCoords[ 2 ] = lightPos - halfWidth + halfHeight;\n\t\trectCoords[ 3 ] = lightPos + halfWidth + halfHeight;\n\t\tvec2 uv = LTC_Uv( normal, viewDir, roughness );\n\t\tvec4 t1 = texture2D( ltc_1, uv );\n\t\tvec4 t2 = texture2D( ltc_2, uv );\n\t\tmat3 mInv = mat3(\n\t\t\tvec3( t1.x, 0, t1.y ),\n\t\t\tvec3( 0, 1, 0 ),\n\t\t\tvec3( t1.z, 0, t1.w )\n\t\t);\n\t\tvec3 fresnel = ( material.specularColorBlended * t2.x + ( material.specularF90 - material.specularColorBlended ) * t2.y );\n\t\treflectedLight.directSpecular += lightColor * fresnel * LTC_Evaluate( normal, viewDir, position, mInv, rectCoords );\n\t\treflectedLight.directDiffuse += lightColor * material.diffuseContribution * LTC_Evaluate( normal, viewDir, position, mat3( 1.0 ), rectCoords );\n\t\t#ifdef USE_CLEARCOAT\n\t\t\tvec3 Ncc = geometryClearcoatNormal;\n\t\t\tvec2 uvClearcoat = LTC_Uv( Ncc, viewDir, material.clearcoatRoughness );\n\t\t\tvec4 t1Clearcoat = texture2D( ltc_1, uvClearcoat );\n\t\t\tvec4 t2Clearcoat = texture2D( ltc_2, uvClearcoat );\n\t\t\tmat3 mInvClearcoat = mat3(\n\t\t\t\tvec3( t1Clearcoat.x, 0, t1Clearcoat.y ),\n\t\t\t\tvec3( 0, 1, 0 ),\n\t\t\t\tvec3( t1Clearcoat.z, 0, t1Clearcoat.w )\n\t\t\t);\n\t\t\tvec3 fresnelClearcoat = material.clearcoatF0 * t2Clearcoat.x + ( material.clearcoatF90 - material.clearcoatF0 ) * t2Clearcoat.y;\n\t\t\tclearcoatSpecularDirect += lightColor * fresnelClearcoat * LTC_Evaluate( Ncc, viewDir, position, mInvClearcoat, rectCoords );\n\t\t#endif\n\t}\n#endif\nvoid RE_Direct_Physical( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometryNormal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\t#ifdef USE_CLEARCOAT\n\t\tfloat dotNLcc = saturate( dot( geometryClearcoatNormal, directLight.direction ) );\n\t\tvec3 ccIrradiance = dotNLcc * directLight.color;\n\t\tclearcoatSpecularDirect += ccIrradiance * BRDF_GGX_Clearcoat( directLight.direction, geometryViewDir, geometryClearcoatNormal, material );\n\t#endif\n\t#ifdef USE_SHEEN\n \n \t\tsheenSpecularDirect += irradiance * BRDF_Sheen( directLight.direction, geometryViewDir, geometryNormal, material.sheenColor, material.sheenRoughness );\n \n \t\tfloat sheenAlbedoV = IBLSheenBRDF( geometryNormal, geometryViewDir, material.sheenRoughness );\n \t\tfloat sheenAlbedoL = IBLSheenBRDF( geometryNormal, directLight.direction, material.sheenRoughness );\n \n \t\tfloat sheenEnergyComp = 1.0 - max3( material.sheenColor ) * max( sheenAlbedoV, sheenAlbedoL );\n \n \t\tirradiance *= sheenEnergyComp;\n \n \t#endif\n\treflectedLight.directSpecular += irradiance * BRDF_GGX_Multiscatter( directLight.direction, geometryViewDir, geometryNormal, material );\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseContribution );\n}\nvoid RE_IndirectDiffuse_Physical( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\tvec3 diffuse = irradiance * BRDF_Lambert( material.diffuseContribution );\n\t#ifdef USE_SHEEN\n\t\tfloat sheenAlbedo = IBLSheenBRDF( geometryNormal, geometryViewDir, material.sheenRoughness );\n\t\tfloat sheenEnergyComp = 1.0 - max3( material.sheenColor ) * sheenAlbedo;\n\t\tdiffuse *= sheenEnergyComp;\n\t#endif\n\treflectedLight.indirectDiffuse += diffuse;\n}\nvoid RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 irradiance, const in vec3 clearcoatRadiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight) {\n\t#ifdef USE_CLEARCOAT\n\t\tclearcoatSpecularIndirect += clearcoatRadiance * EnvironmentBRDF( geometryClearcoatNormal, geometryViewDir, material.clearcoatF0, material.clearcoatF90, material.clearcoatRoughness );\n\t#endif\n\t#ifdef USE_SHEEN\n\t\tsheenSpecularIndirect += irradiance * material.sheenColor * IBLSheenBRDF( geometryNormal, geometryViewDir, material.sheenRoughness ) * RECIPROCAL_PI;\n \t#endif\n\tvec3 singleScatteringDielectric = vec3( 0.0 );\n\tvec3 multiScatteringDielectric = vec3( 0.0 );\n\tvec3 singleScatteringMetallic = vec3( 0.0 );\n\tvec3 multiScatteringMetallic = vec3( 0.0 );\n\t#ifdef USE_IRIDESCENCE\n\t\tcomputeMultiscatteringIridescence( geometryNormal, geometryViewDir, material.specularColor, material.specularF90, material.iridescence, material.iridescenceFresnelDielectric, material.roughness, singleScatteringDielectric, multiScatteringDielectric );\n\t\tcomputeMultiscatteringIridescence( geometryNormal, geometryViewDir, material.diffuseColor, material.specularF90, material.iridescence, material.iridescenceFresnelMetallic, material.roughness, singleScatteringMetallic, multiScatteringMetallic );\n\t#else\n\t\tcomputeMultiscattering( geometryNormal, geometryViewDir, material.specularColor, material.specularF90, material.roughness, singleScatteringDielectric, multiScatteringDielectric );\n\t\tcomputeMultiscattering( geometryNormal, geometryViewDir, material.diffuseColor, material.specularF90, material.roughness, singleScatteringMetallic, multiScatteringMetallic );\n\t#endif\n\tvec3 singleScattering = mix( singleScatteringDielectric, singleScatteringMetallic, material.metalness );\n\tvec3 multiScattering = mix( multiScatteringDielectric, multiScatteringMetallic, material.metalness );\n\tvec3 totalScatteringDielectric = singleScatteringDielectric + multiScatteringDielectric;\n\tvec3 diffuse = material.diffuseContribution * ( 1.0 - totalScatteringDielectric );\n\tvec3 cosineWeightedIrradiance = irradiance * RECIPROCAL_PI;\n\tvec3 indirectSpecular = radiance * singleScattering;\n\tindirectSpecular += multiScattering * cosineWeightedIrradiance;\n\tvec3 indirectDiffuse = diffuse * cosineWeightedIrradiance;\n\t#ifdef USE_SHEEN\n\t\tfloat sheenAlbedo = IBLSheenBRDF( geometryNormal, geometryViewDir, material.sheenRoughness );\n\t\tfloat sheenEnergyComp = 1.0 - max3( material.sheenColor ) * sheenAlbedo;\n\t\tindirectSpecular *= sheenEnergyComp;\n\t\tindirectDiffuse *= sheenEnergyComp;\n\t#endif\n\treflectedLight.indirectSpecular += indirectSpecular;\n\treflectedLight.indirectDiffuse += indirectDiffuse;\n}\n#define RE_Direct\t\t\t\tRE_Direct_Physical\n#define RE_Direct_RectArea\t\tRE_Direct_RectArea_Physical\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Physical\n#define RE_IndirectSpecular\t\tRE_IndirectSpecular_Physical\nfloat computeSpecularOcclusion( const in float dotNV, const in float ambientOcclusion, const in float roughness ) {\n\treturn saturate( pow( dotNV + ambientOcclusion, exp2( - 16.0 * roughness - 1.0 ) ) - 1.0 + ambientOcclusion );\n}";
59872
60115
 
59873
- var lights_fragment_begin = "\nvec3 geometryPosition = - vViewPosition;\nvec3 geometryNormal = normal;\nvec3 geometryViewDir = ( isOrthographic ) ? vec3( 0, 0, 1 ) : normalize( vViewPosition );\nvec3 geometryClearcoatNormal = vec3( 0.0 );\n#ifdef USE_CLEARCOAT\n\tgeometryClearcoatNormal = clearcoatNormal;\n#endif\n#ifdef USE_IRIDESCENCE\n\tfloat dotNVi = saturate( dot( normal, geometryViewDir ) );\n\tif ( material.iridescenceThickness == 0.0 ) {\n\t\tmaterial.iridescence = 0.0;\n\t} else {\n\t\tmaterial.iridescence = saturate( material.iridescence );\n\t}\n\tif ( material.iridescence > 0.0 ) {\n\t\tmaterial.iridescenceFresnelDielectric = evalIridescence( 1.0, material.iridescenceIOR, dotNVi, material.iridescenceThickness, material.specularColor );\n\t\tmaterial.iridescenceFresnelMetallic = evalIridescence( 1.0, material.iridescenceIOR, dotNVi, material.iridescenceThickness, material.diffuseColor );\n\t\tmaterial.iridescenceFresnel = mix( material.iridescenceFresnelDielectric, material.iridescenceFresnelMetallic, material.metalness );\n\t\tmaterial.iridescenceF0 = Schlick_to_F0( material.iridescenceFresnel, 1.0, dotNVi );\n\t}\n#endif\nIncidentLight directLight;\n#if ( NUM_POINT_LIGHTS > 0 ) && defined( RE_Direct )\n\tPointLight pointLight;\n\t#if defined( USE_SHADOWMAP ) && NUM_POINT_LIGHT_SHADOWS > 0\n\tPointLightShadow pointLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tpointLight = pointLights[ i ];\n\t\tgetPointLightInfo( pointLight, geometryPosition, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_POINT_LIGHT_SHADOWS ) && ( defined( SHADOWMAP_TYPE_PCF ) || defined( SHADOWMAP_TYPE_BASIC ) )\n\t\tpointLightShadow = pointLightShadows[ i ];\n\t\tdirectLight.color *= ( directLight.visible && receiveShadow ) ? getPointShadow( pointShadowMap[ i ], pointLightShadow.shadowMapSize, pointLightShadow.shadowIntensity, pointLightShadow.shadowBias, pointLightShadow.shadowRadius, vPointShadowCoord[ i ], pointLightShadow.shadowCameraNear, pointLightShadow.shadowCameraFar ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_SPOT_LIGHTS > 0 ) && defined( RE_Direct )\n\tSpotLight spotLight;\n\tvec4 spotColor;\n\tvec3 spotLightCoord;\n\tbool inSpotLightMap;\n\t#if defined( USE_SHADOWMAP ) && NUM_SPOT_LIGHT_SHADOWS > 0\n\tSpotLightShadow spotLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tspotLight = spotLights[ i ];\n\t\tgetSpotLightInfo( spotLight, geometryPosition, directLight );\n\t\t#if ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS )\n\t\t#define SPOT_LIGHT_MAP_INDEX UNROLLED_LOOP_INDEX\n\t\t#elif ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\t#define SPOT_LIGHT_MAP_INDEX NUM_SPOT_LIGHT_MAPS\n\t\t#else\n\t\t#define SPOT_LIGHT_MAP_INDEX ( UNROLLED_LOOP_INDEX - NUM_SPOT_LIGHT_SHADOWS + NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS )\n\t\t#endif\n\t\t#if ( SPOT_LIGHT_MAP_INDEX < NUM_SPOT_LIGHT_MAPS )\n\t\t\tspotLightCoord = vSpotLightCoord[ i ].xyz / vSpotLightCoord[ i ].w;\n\t\t\tinSpotLightMap = all( lessThan( abs( spotLightCoord * 2. - 1. ), vec3( 1.0 ) ) );\n\t\t\tspotColor = texture2D( spotLightMap[ SPOT_LIGHT_MAP_INDEX ], spotLightCoord.xy );\n\t\t\tdirectLight.color = inSpotLightMap ? directLight.color * spotColor.rgb : directLight.color;\n\t\t#endif\n\t\t#undef SPOT_LIGHT_MAP_INDEX\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\tspotLightShadow = spotLightShadows[ i ];\n\t\tdirectLight.color *= ( directLight.visible && receiveShadow ) ? getShadow( spotShadowMap[ i ], spotLightShadow.shadowMapSize, spotLightShadow.shadowIntensity, spotLightShadow.shadowBias, spotLightShadow.shadowRadius, vSpotLightCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_DIR_LIGHTS > 0 ) && defined( RE_Direct )\n\tDirectionalLight directionalLight;\n\t#if defined( USE_SHADOWMAP ) && NUM_DIR_LIGHT_SHADOWS > 0\n\tDirectionalLightShadow directionalLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tdirectionalLight = directionalLights[ i ];\n\t\tgetDirectionalLightInfo( directionalLight, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_DIR_LIGHT_SHADOWS )\n\t\tdirectionalLightShadow = directionalLightShadows[ i ];\n\t\tdirectLight.color *= ( directLight.visible && receiveShadow ) ? getShadow( directionalShadowMap[ i ], directionalLightShadow.shadowMapSize, directionalLightShadow.shadowIntensity, directionalLightShadow.shadowBias, directionalLightShadow.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_RECT_AREA_LIGHTS > 0 ) && defined( RE_Direct_RectArea )\n\tRectAreaLight rectAreaLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_RECT_AREA_LIGHTS; i ++ ) {\n\t\trectAreaLight = rectAreaLights[ i ];\n\t\tRE_Direct_RectArea( rectAreaLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if defined( RE_IndirectDiffuse )\n\tvec3 iblIrradiance = vec3( 0.0 );\n\tvec3 irradiance = getAmbientLightIrradiance( ambientLightColor );\n\t#if defined( USE_LIGHT_PROBES )\n\t\tirradiance += getLightProbeIrradiance( lightProbe, geometryNormal );\n\t#endif\n\t#if ( NUM_HEMI_LIGHTS > 0 )\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\t\tirradiance += getHemisphereLightIrradiance( hemisphereLights[ i ], geometryNormal );\n\t\t}\n\t\t#pragma unroll_loop_end\n\t#endif\n#endif\n#if defined( RE_IndirectSpecular )\n\tvec3 radiance = vec3( 0.0 );\n\tvec3 clearcoatRadiance = vec3( 0.0 );\n#endif";
60116
+ var lights_fragment_begin = "\nvec3 geometryPosition = - vViewPosition;\nvec3 geometryNormal = normal;\nvec3 geometryViewDir = ( isOrthographic ) ? vec3( 0, 0, 1 ) : normalize( vViewPosition );\nvec3 geometryClearcoatNormal = vec3( 0.0 );\n#ifdef USE_CLEARCOAT\n\tgeometryClearcoatNormal = clearcoatNormal;\n#endif\n#ifdef USE_IRIDESCENCE\n\tfloat dotNVi = saturate( dot( normal, geometryViewDir ) );\n\tif ( material.iridescenceThickness == 0.0 ) {\n\t\tmaterial.iridescence = 0.0;\n\t} else {\n\t\tmaterial.iridescence = saturate( material.iridescence );\n\t}\n\tif ( material.iridescence > 0.0 ) {\n\t\tmaterial.iridescenceFresnelDielectric = evalIridescence( 1.0, material.iridescenceIOR, dotNVi, material.iridescenceThickness, material.specularColor );\n\t\tmaterial.iridescenceFresnelMetallic = evalIridescence( 1.0, material.iridescenceIOR, dotNVi, material.iridescenceThickness, material.diffuseColor );\n\t\tmaterial.iridescenceFresnel = mix( material.iridescenceFresnelDielectric, material.iridescenceFresnelMetallic, material.metalness );\n\t\tmaterial.iridescenceF0 = Schlick_to_F0( material.iridescenceFresnel, 1.0, dotNVi );\n\t}\n#endif\nIncidentLight directLight;\n#if ( NUM_POINT_LIGHTS > 0 ) && defined( RE_Direct )\n\tPointLight pointLight;\n\t#if defined( USE_SHADOWMAP ) && NUM_POINT_LIGHT_SHADOWS > 0\n\tPointLightShadow pointLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tpointLight = pointLights[ i ];\n\t\tgetPointLightInfo( pointLight, geometryPosition, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_POINT_LIGHT_SHADOWS ) && ( defined( SHADOWMAP_TYPE_PCF ) || defined( SHADOWMAP_TYPE_BASIC ) )\n\t\tpointLightShadow = pointLightShadows[ i ];\n\t\tdirectLight.color *= ( directLight.visible && receiveShadow ) ? getPointShadow( pointShadowMap[ i ], pointLightShadow.shadowMapSize, pointLightShadow.shadowIntensity, pointLightShadow.shadowBias, pointLightShadow.shadowRadius, vPointShadowCoord[ i ], pointLightShadow.shadowCameraNear, pointLightShadow.shadowCameraFar ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_SPOT_LIGHTS > 0 ) && defined( RE_Direct )\n\tSpotLight spotLight;\n\tvec4 spotColor;\n\tvec3 spotLightCoord;\n\tbool inSpotLightMap;\n\t#if defined( USE_SHADOWMAP ) && NUM_SPOT_LIGHT_SHADOWS > 0\n\tSpotLightShadow spotLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tspotLight = spotLights[ i ];\n\t\tgetSpotLightInfo( spotLight, geometryPosition, directLight );\n\t\t#if ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS )\n\t\t#define SPOT_LIGHT_MAP_INDEX UNROLLED_LOOP_INDEX\n\t\t#elif ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\t#define SPOT_LIGHT_MAP_INDEX NUM_SPOT_LIGHT_MAPS\n\t\t#else\n\t\t#define SPOT_LIGHT_MAP_INDEX ( UNROLLED_LOOP_INDEX - NUM_SPOT_LIGHT_SHADOWS + NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS )\n\t\t#endif\n\t\t#if ( SPOT_LIGHT_MAP_INDEX < NUM_SPOT_LIGHT_MAPS )\n\t\t\tspotLightCoord = vSpotLightCoord[ i ].xyz / vSpotLightCoord[ i ].w;\n\t\t\tinSpotLightMap = all( lessThan( abs( spotLightCoord * 2. - 1. ), vec3( 1.0 ) ) );\n\t\t\tspotColor = texture2D( spotLightMap[ SPOT_LIGHT_MAP_INDEX ], spotLightCoord.xy );\n\t\t\tdirectLight.color = inSpotLightMap ? directLight.color * spotColor.rgb : directLight.color;\n\t\t#endif\n\t\t#undef SPOT_LIGHT_MAP_INDEX\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\tspotLightShadow = spotLightShadows[ i ];\n\t\tdirectLight.color *= ( directLight.visible && receiveShadow ) ? getShadow( spotShadowMap[ i ], spotLightShadow.shadowMapSize, spotLightShadow.shadowIntensity, spotLightShadow.shadowBias, spotLightShadow.shadowRadius, vSpotLightCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_DIR_LIGHTS > 0 ) && defined( RE_Direct )\n\tDirectionalLight directionalLight;\n\t#if defined( USE_SHADOWMAP ) && NUM_DIR_LIGHT_SHADOWS > 0\n\tDirectionalLightShadow directionalLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tdirectionalLight = directionalLights[ i ];\n\t\tgetDirectionalLightInfo( directionalLight, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_DIR_LIGHT_SHADOWS )\n\t\tdirectionalLightShadow = directionalLightShadows[ i ];\n\t\tdirectLight.color *= ( directLight.visible && receiveShadow ) ? getShadow( directionalShadowMap[ i ], directionalLightShadow.shadowMapSize, directionalLightShadow.shadowIntensity, directionalLightShadow.shadowBias, directionalLightShadow.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_RECT_AREA_LIGHTS > 0 ) && defined( RE_Direct_RectArea )\n\tRectAreaLight rectAreaLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_RECT_AREA_LIGHTS; i ++ ) {\n\t\trectAreaLight = rectAreaLights[ i ];\n\t\tRE_Direct_RectArea( rectAreaLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if defined( RE_IndirectDiffuse )\n\tvec3 iblIrradiance = vec3( 0.0 );\n\tvec3 irradiance = getAmbientLightIrradiance( ambientLightColor );\n\t#if defined( USE_LIGHT_PROBES )\n\t\tirradiance += getLightProbeIrradiance( lightProbe, geometryNormal );\n\t#endif\n\t#if ( NUM_HEMI_LIGHTS > 0 )\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\t\tirradiance += getHemisphereLightIrradiance( hemisphereLights[ i ], geometryNormal );\n\t\t}\n\t\t#pragma unroll_loop_end\n\t#endif\n\t#ifdef USE_LIGHT_PROBES_GRID\n\t\tvec3 probeWorldPos = ( ( vec4( geometryPosition, 1.0 ) - viewMatrix[ 3 ] ) * viewMatrix ).xyz;\n\t\tvec3 probeWorldNormal = inverseTransformDirection( geometryNormal, viewMatrix );\n\t\tirradiance += getLightProbeGridIrradiance( probeWorldPos, probeWorldNormal );\n\t#endif\n#endif\n#if defined( RE_IndirectSpecular )\n\tvec3 radiance = vec3( 0.0 );\n\tvec3 clearcoatRadiance = vec3( 0.0 );\n#endif";
59874
60117
 
59875
60118
  var lights_fragment_maps = "#if defined( RE_IndirectDiffuse )\n\t#ifdef USE_LIGHTMAP\n\t\tvec4 lightMapTexel = texture2D( lightMap, vLightMapUv );\n\t\tvec3 lightMapIrradiance = lightMapTexel.rgb * lightMapIntensity;\n\t\tirradiance += lightMapIrradiance;\n\t#endif\n\t#if defined( USE_ENVMAP ) && defined( ENVMAP_TYPE_CUBE_UV )\n\t\t#if defined( STANDARD ) || defined( LAMBERT ) || defined( PHONG )\n\t\t\tiblIrradiance += getIBLIrradiance( geometryNormal );\n\t\t#endif\n\t#endif\n#endif\n#if defined( USE_ENVMAP ) && defined( RE_IndirectSpecular )\n\t#ifdef USE_ANISOTROPY\n\t\tradiance += getIBLAnisotropyRadiance( geometryViewDir, geometryNormal, material.roughness, material.anisotropyB, material.anisotropy );\n\t#else\n\t\tradiance += getIBLRadiance( geometryViewDir, geometryNormal, material.roughness );\n\t#endif\n\t#ifdef USE_CLEARCOAT\n\t\tclearcoatRadiance += getIBLRadiance( geometryViewDir, geometryClearcoatNormal, material.clearcoatRoughness );\n\t#endif\n#endif";
59876
60119
 
59877
60120
  var lights_fragment_end = "#if defined( RE_IndirectDiffuse )\n\t#if defined( LAMBERT ) || defined( PHONG )\n\t\tirradiance += iblIrradiance;\n\t#endif\n\tRE_IndirectDiffuse( irradiance, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n#endif\n#if defined( RE_IndirectSpecular )\n\tRE_IndirectSpecular( radiance, iblIrradiance, clearcoatRadiance, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n#endif";
59878
60121
 
60122
+ var lightprobes_pars_fragment = "#ifdef USE_LIGHT_PROBES_GRID\nuniform highp sampler3D probesSH;\nuniform vec3 probesMin;\nuniform vec3 probesMax;\nuniform vec3 probesResolution;\nvec3 getLightProbeGridIrradiance( vec3 worldPos, vec3 worldNormal ) {\n\tvec3 res = probesResolution;\n\tvec3 gridRange = probesMax - probesMin;\n\tvec3 resMinusOne = res - 1.0;\n\tvec3 probeSpacing = gridRange / resMinusOne;\n\tvec3 samplePos = worldPos + worldNormal * probeSpacing * 0.5;\n\tvec3 uvw = clamp( ( samplePos - probesMin ) / gridRange, 0.0, 1.0 );\n\tuvw = uvw * resMinusOne / res + 0.5 / res;\n\tfloat nz = res.z;\n\tfloat paddedSlices = nz + 2.0;\n\tfloat atlasDepth = 7.0 * paddedSlices;\n\tfloat uvZBase = uvw.z * nz + 1.0;\n\tvec4 s0 = texture( probesSH, vec3( uvw.xy, ( uvZBase ) / atlasDepth ) );\n\tvec4 s1 = texture( probesSH, vec3( uvw.xy, ( uvZBase + paddedSlices ) / atlasDepth ) );\n\tvec4 s2 = texture( probesSH, vec3( uvw.xy, ( uvZBase + 2.0 * paddedSlices ) / atlasDepth ) );\n\tvec4 s3 = texture( probesSH, vec3( uvw.xy, ( uvZBase + 3.0 * paddedSlices ) / atlasDepth ) );\n\tvec4 s4 = texture( probesSH, vec3( uvw.xy, ( uvZBase + 4.0 * paddedSlices ) / atlasDepth ) );\n\tvec4 s5 = texture( probesSH, vec3( uvw.xy, ( uvZBase + 5.0 * paddedSlices ) / atlasDepth ) );\n\tvec4 s6 = texture( probesSH, vec3( uvw.xy, ( uvZBase + 6.0 * paddedSlices ) / atlasDepth ) );\n\tvec3 c0 = s0.xyz;\n\tvec3 c1 = vec3( s0.w, s1.xy );\n\tvec3 c2 = vec3( s1.zw, s2.x );\n\tvec3 c3 = s2.yzw;\n\tvec3 c4 = s3.xyz;\n\tvec3 c5 = vec3( s3.w, s4.xy );\n\tvec3 c6 = vec3( s4.zw, s5.x );\n\tvec3 c7 = s5.yzw;\n\tvec3 c8 = s6.xyz;\n\tfloat x = worldNormal.x, y = worldNormal.y, z = worldNormal.z;\n\tvec3 result = c0 * 0.886227;\n\tresult += c1 * 2.0 * 0.511664 * y;\n\tresult += c2 * 2.0 * 0.511664 * z;\n\tresult += c3 * 2.0 * 0.511664 * x;\n\tresult += c4 * 2.0 * 0.429043 * x * y;\n\tresult += c5 * 2.0 * 0.429043 * y * z;\n\tresult += c6 * ( 0.743125 * z * z - 0.247708 );\n\tresult += c7 * 2.0 * 0.429043 * x * z;\n\tresult += c8 * 0.429043 * ( x * x - y * y );\n\treturn max( result, vec3( 0.0 ) );\n}\n#endif";
60123
+
59879
60124
  var logdepthbuf_fragment = "#if defined( USE_LOGARITHMIC_DEPTH_BUFFER )\n\tgl_FragDepth = vIsPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;\n#endif";
59880
60125
 
59881
60126
  var logdepthbuf_pars_fragment = "#if defined( USE_LOGARITHMIC_DEPTH_BUFFER )\n\tuniform float logDepthBufFC;\n\tvarying float vFragDepth;\n\tvarying float vIsPerspective;\n#endif";
@@ -59908,7 +60153,7 @@
59908
60153
 
59909
60154
  var normal_fragment_begin = "float faceDirection = gl_FrontFacing ? 1.0 : - 1.0;\n#ifdef FLAT_SHADED\n\tvec3 fdx = dFdx( vViewPosition );\n\tvec3 fdy = dFdy( vViewPosition );\n\tvec3 normal = normalize( cross( fdx, fdy ) );\n#else\n\tvec3 normal = normalize( vNormal );\n\t#ifdef DOUBLE_SIDED\n\t\tnormal *= faceDirection;\n\t#endif\n#endif\n#if defined( USE_NORMALMAP_TANGENTSPACE ) || defined( USE_CLEARCOAT_NORMALMAP ) || defined( USE_ANISOTROPY )\n\t#ifdef USE_TANGENT\n\t\tmat3 tbn = mat3( normalize( vTangent ), normalize( vBitangent ), normal );\n\t#else\n\t\tmat3 tbn = getTangentFrame( - vViewPosition, normal,\n\t\t#if defined( USE_NORMALMAP )\n\t\t\tvNormalMapUv\n\t\t#elif defined( USE_CLEARCOAT_NORMALMAP )\n\t\t\tvClearcoatNormalMapUv\n\t\t#else\n\t\t\tvUv\n\t\t#endif\n\t\t);\n\t#endif\n\t#if defined( DOUBLE_SIDED ) && ! defined( FLAT_SHADED )\n\t\ttbn[0] *= faceDirection;\n\t\ttbn[1] *= faceDirection;\n\t#endif\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\t#ifdef USE_TANGENT\n\t\tmat3 tbn2 = mat3( normalize( vTangent ), normalize( vBitangent ), normal );\n\t#else\n\t\tmat3 tbn2 = getTangentFrame( - vViewPosition, normal, vClearcoatNormalMapUv );\n\t#endif\n\t#if defined( DOUBLE_SIDED ) && ! defined( FLAT_SHADED )\n\t\ttbn2[0] *= faceDirection;\n\t\ttbn2[1] *= faceDirection;\n\t#endif\n#endif\nvec3 nonPerturbedNormal = normal;";
59910
60155
 
59911
- var normal_fragment_maps = "#ifdef USE_NORMALMAP_OBJECTSPACE\n\tnormal = texture2D( normalMap, vNormalMapUv ).xyz * 2.0 - 1.0;\n\t#ifdef FLIP_SIDED\n\t\tnormal = - normal;\n\t#endif\n\t#ifdef DOUBLE_SIDED\n\t\tnormal = normal * faceDirection;\n\t#endif\n\tnormal = normalize( normalMatrix * normal );\n#elif defined( USE_NORMALMAP_TANGENTSPACE )\n\tvec3 mapN = texture2D( normalMap, vNormalMapUv ).xyz * 2.0 - 1.0;\n\tmapN.xy *= normalScale;\n\tnormal = normalize( tbn * mapN );\n#elif defined( USE_BUMPMAP )\n\tnormal = perturbNormalArb( - vViewPosition, normal, dHdxy_fwd(), faceDirection );\n#endif";
60156
+ var normal_fragment_maps = "#ifdef USE_NORMALMAP_OBJECTSPACE\n\tnormal = texture2D( normalMap, vNormalMapUv ).xyz * 2.0 - 1.0;\n\t#ifdef FLIP_SIDED\n\t\tnormal = - normal;\n\t#endif\n\t#ifdef DOUBLE_SIDED\n\t\tnormal = normal * faceDirection;\n\t#endif\n\tnormal = normalize( normalMatrix * normal );\n#elif defined( USE_NORMALMAP_TANGENTSPACE )\n\tvec3 mapN = texture2D( normalMap, vNormalMapUv ).xyz * 2.0 - 1.0;\n\t#if defined( USE_PACKED_NORMALMAP )\n\t\tmapN = vec3( mapN.xy, sqrt( saturate( 1.0 - dot( mapN.xy, mapN.xy ) ) ) );\n\t#endif\n\tmapN.xy *= normalScale;\n\tnormal = normalize( tbn * mapN );\n#elif defined( USE_BUMPMAP )\n\tnormal = perturbNormalArb( - vViewPosition, normal, dHdxy_fwd(), faceDirection );\n#endif";
59912
60157
 
59913
60158
  var normal_pars_fragment = "#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n\t#ifdef USE_TANGENT\n\t\tvarying vec3 vTangent;\n\t\tvarying vec3 vBitangent;\n\t#endif\n#endif";
59914
60159
 
@@ -59946,7 +60191,7 @@
59946
60191
 
59947
60192
  var shadowmap_pars_vertex = "#if NUM_SPOT_LIGHT_COORDS > 0\n\tuniform mat4 spotLightMatrix[ NUM_SPOT_LIGHT_COORDS ];\n\tvarying vec4 vSpotLightCoord[ NUM_SPOT_LIGHT_COORDS ];\n#endif\n#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\tuniform mat4 directionalShadowMatrix[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tstruct DirectionalLightShadow {\n\t\t\tfloat shadowIntensity;\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform DirectionalLightShadow directionalLightShadows[ NUM_DIR_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\t\tstruct SpotLightShadow {\n\t\t\tfloat shadowIntensity;\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform SpotLightShadow spotLightShadows[ NUM_SPOT_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\tuniform mat4 pointShadowMatrix[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tstruct PointLightShadow {\n\t\t\tfloat shadowIntensity;\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t\tfloat shadowCameraNear;\n\t\t\tfloat shadowCameraFar;\n\t\t};\n\t\tuniform PointLightShadow pointLightShadows[ NUM_POINT_LIGHT_SHADOWS ];\n\t#endif\n#endif";
59948
60193
 
59949
- var shadowmap_vertex = "#if ( defined( USE_SHADOWMAP ) && ( NUM_DIR_LIGHT_SHADOWS > 0 || NUM_POINT_LIGHT_SHADOWS > 0 ) ) || ( NUM_SPOT_LIGHT_COORDS > 0 )\n\tvec3 shadowWorldNormal = inverseTransformDirection( transformedNormal, viewMatrix );\n\tvec4 shadowWorldPosition;\n#endif\n#if defined( USE_SHADOWMAP )\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) {\n\t\t\tshadowWorldPosition = worldPosition + vec4( shadowWorldNormal * directionalLightShadows[ i ].shadowNormalBias, 0 );\n\t\t\tvDirectionalShadowCoord[ i ] = directionalShadowMatrix[ i ] * shadowWorldPosition;\n\t\t}\n\t\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) {\n\t\t\tshadowWorldPosition = worldPosition + vec4( shadowWorldNormal * pointLightShadows[ i ].shadowNormalBias, 0 );\n\t\t\tvPointShadowCoord[ i ] = pointShadowMatrix[ i ] * shadowWorldPosition;\n\t\t}\n\t\t#pragma unroll_loop_end\n\t#endif\n#endif\n#if NUM_SPOT_LIGHT_COORDS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHT_COORDS; i ++ ) {\n\t\tshadowWorldPosition = worldPosition;\n\t\t#if ( defined( USE_SHADOWMAP ) && UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\t\tshadowWorldPosition.xyz += shadowWorldNormal * spotLightShadows[ i ].shadowNormalBias;\n\t\t#endif\n\t\tvSpotLightCoord[ i ] = spotLightMatrix[ i ] * shadowWorldPosition;\n\t}\n\t#pragma unroll_loop_end\n#endif";
60194
+ var shadowmap_vertex = "#if ( defined( USE_SHADOWMAP ) && ( NUM_DIR_LIGHT_SHADOWS > 0 || NUM_POINT_LIGHT_SHADOWS > 0 ) ) || ( NUM_SPOT_LIGHT_COORDS > 0 )\n\t#ifdef HAS_NORMAL\n\t\tvec3 shadowWorldNormal = inverseTransformDirection( transformedNormal, viewMatrix );\n\t#else\n\t\tvec3 shadowWorldNormal = vec3( 0.0 );\n\t#endif\n\tvec4 shadowWorldPosition;\n#endif\n#if defined( USE_SHADOWMAP )\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) {\n\t\t\tshadowWorldPosition = worldPosition + vec4( shadowWorldNormal * directionalLightShadows[ i ].shadowNormalBias, 0 );\n\t\t\tvDirectionalShadowCoord[ i ] = directionalShadowMatrix[ i ] * shadowWorldPosition;\n\t\t}\n\t\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) {\n\t\t\tshadowWorldPosition = worldPosition + vec4( shadowWorldNormal * pointLightShadows[ i ].shadowNormalBias, 0 );\n\t\t\tvPointShadowCoord[ i ] = pointShadowMatrix[ i ] * shadowWorldPosition;\n\t\t}\n\t\t#pragma unroll_loop_end\n\t#endif\n#endif\n#if NUM_SPOT_LIGHT_COORDS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHT_COORDS; i ++ ) {\n\t\tshadowWorldPosition = worldPosition;\n\t\t#if ( defined( USE_SHADOWMAP ) && UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\t\tshadowWorldPosition.xyz += shadowWorldNormal * spotLightShadows[ i ].shadowNormalBias;\n\t\t#endif\n\t\tvSpotLightCoord[ i ] = spotLightMatrix[ i ] * shadowWorldPosition;\n\t}\n\t#pragma unroll_loop_end\n#endif";
59950
60195
 
59951
60196
  var shadowmask_pars_fragment = "float getShadowMask() {\n\tfloat shadow = 1.0;\n\t#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\tDirectionalLightShadow directionalLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) {\n\t\tdirectionalLight = directionalLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowIntensity, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\tSpotLightShadow spotLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHT_SHADOWS; i ++ ) {\n\t\tspotLight = spotLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowIntensity, spotLight.shadowBias, spotLight.shadowRadius, vSpotLightCoord[ i ] ) : 1.0;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0 && ( defined( SHADOWMAP_TYPE_PCF ) || defined( SHADOWMAP_TYPE_BASIC ) )\n\tPointLightShadow pointLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) {\n\t\tpointLight = pointLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowIntensity, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ], pointLight.shadowCameraNear, pointLight.shadowCameraFar ) : 1.0;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#endif\n\treturn shadow;\n}";
59952
60197
 
@@ -59984,7 +60229,7 @@
59984
60229
 
59985
60230
  const vertex$g = "varying vec3 vWorldDirection;\n#include <common>\nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include <begin_vertex>\n\t#include <project_vertex>\n\tgl_Position.z = gl_Position.w;\n}";
59986
60231
 
59987
- const fragment$g = "#ifdef ENVMAP_TYPE_CUBE\n\tuniform samplerCube envMap;\n#elif defined( ENVMAP_TYPE_CUBE_UV )\n\tuniform sampler2D envMap;\n#endif\nuniform float flipEnvMap;\nuniform float backgroundBlurriness;\nuniform float backgroundIntensity;\nuniform mat3 backgroundRotation;\nvarying vec3 vWorldDirection;\n#include <cube_uv_reflection_fragment>\nvoid main() {\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tvec4 texColor = textureCube( envMap, backgroundRotation * vec3( flipEnvMap * vWorldDirection.x, vWorldDirection.yz ) );\n\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\tvec4 texColor = textureCubeUV( envMap, backgroundRotation * vWorldDirection, backgroundBlurriness );\n\t#else\n\t\tvec4 texColor = vec4( 0.0, 0.0, 0.0, 1.0 );\n\t#endif\n\ttexColor.rgb *= backgroundIntensity;\n\tgl_FragColor = texColor;\n\t#include <tonemapping_fragment>\n\t#include <colorspace_fragment>\n}";
60232
+ const fragment$g = "#ifdef ENVMAP_TYPE_CUBE\n\tuniform samplerCube envMap;\n#elif defined( ENVMAP_TYPE_CUBE_UV )\n\tuniform sampler2D envMap;\n#endif\nuniform float backgroundBlurriness;\nuniform float backgroundIntensity;\nuniform mat3 backgroundRotation;\nvarying vec3 vWorldDirection;\n#include <cube_uv_reflection_fragment>\nvoid main() {\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tvec4 texColor = textureCube( envMap, backgroundRotation * vWorldDirection );\n\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\tvec4 texColor = textureCubeUV( envMap, backgroundRotation * vWorldDirection, backgroundBlurriness );\n\t#else\n\t\tvec4 texColor = vec4( 0.0, 0.0, 0.0, 1.0 );\n\t#endif\n\ttexColor.rgb *= backgroundIntensity;\n\tgl_FragColor = texColor;\n\t#include <tonemapping_fragment>\n\t#include <colorspace_fragment>\n}";
59988
60233
 
59989
60234
  const vertex$f = "varying vec3 vWorldDirection;\n#include <common>\nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include <begin_vertex>\n\t#include <project_vertex>\n\tgl_Position.z = gl_Position.w;\n}";
59990
60235
 
@@ -60103,6 +60348,7 @@
60103
60348
  lights_fragment_begin: lights_fragment_begin,
60104
60349
  lights_fragment_maps: lights_fragment_maps,
60105
60350
  lights_fragment_end: lights_fragment_end,
60351
+ lightprobes_pars_fragment: lightprobes_pars_fragment,
60106
60352
  logdepthbuf_fragment: logdepthbuf_fragment,
60107
60353
  logdepthbuf_pars_fragment: logdepthbuf_pars_fragment,
60108
60354
  logdepthbuf_pars_vertex: logdepthbuf_pars_vertex,
@@ -60220,7 +60466,6 @@
60220
60466
 
60221
60467
  envMap: { value: null },
60222
60468
  envMapRotation: { value: /*@__PURE__*/ new Matrix3() },
60223
- flipEnvMap: { value: -1 },
60224
60469
  reflectivity: { value: 1.0 }, // basic, lambert, phong
60225
60470
  ior: { value: 1.5 }, // physical
60226
60471
  refractionRatio: { value: 0.98 }, // basic, lambert, phong
@@ -60381,7 +60626,12 @@
60381
60626
  } },
60382
60627
 
60383
60628
  ltc_1: { value: null },
60384
- ltc_2: { value: null }
60629
+ ltc_2: { value: null },
60630
+
60631
+ probesSH: { value: null },
60632
+ probesMin: { value: /*@__PURE__*/ new Vector3() },
60633
+ probesMax: { value: /*@__PURE__*/ new Vector3() },
60634
+ probesResolution: { value: /*@__PURE__*/ new Vector3() }
60385
60635
 
60386
60636
  },
60387
60637
 
@@ -60641,7 +60891,6 @@
60641
60891
 
60642
60892
  uniforms: {
60643
60893
  envMap: { value: null },
60644
- flipEnvMap: { value: -1 },
60645
60894
  backgroundBlurriness: { value: 0 },
60646
60895
  backgroundIntensity: { value: 1 },
60647
60896
  backgroundRotation: { value: /*@__PURE__*/ new Matrix3() }
@@ -60769,8 +61018,10 @@
60769
61018
  };
60770
61019
 
60771
61020
  const _rgb = { r: 0, b: 0, g: 0 };
60772
- const _e1$1 = /*@__PURE__*/ new Euler();
60773
61021
  const _m1$1 = /*@__PURE__*/ new Matrix4();
61022
+ const _m$1 = /*@__PURE__*/ new Matrix3();
61023
+
61024
+ _m$1.set( -1, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0 );
60774
61025
 
60775
61026
  function WebGLBackground( renderer, environments, state, objects, alpha, premultipliedAlpha ) {
60776
61027
 
@@ -60888,24 +61139,22 @@
60888
61139
 
60889
61140
  }
60890
61141
 
60891
- _e1$1.copy( scene.backgroundRotation );
60892
61142
 
60893
- // accommodate left-handed frame
60894
- _e1$1.x *= -1; _e1$1.y *= -1; _e1$1.z *= -1;
61143
+ boxMesh.material.uniforms.envMap.value = background;
61144
+ boxMesh.material.uniforms.backgroundBlurriness.value = scene.backgroundBlurriness;
61145
+ boxMesh.material.uniforms.backgroundIntensity.value = scene.backgroundIntensity;
61146
+
61147
+
61148
+ // note: since the matrix is orthonormal, we can use the more-efficient transpose() in lieu of invert()
61149
+ boxMesh.material.uniforms.backgroundRotation.value.setFromMatrix4( _m1$1.makeRotationFromEuler( scene.backgroundRotation ) ).transpose();
60895
61150
 
60896
61151
  if ( background.isCubeTexture && background.isRenderTargetTexture === false ) {
60897
61152
 
60898
- // environment maps which are not cube render targets or PMREMs follow a different convention
60899
- _e1$1.y *= -1;
60900
- _e1$1.z *= -1;
61153
+ boxMesh.material.uniforms.backgroundRotation.value.premultiply( _m$1 );
60901
61154
 
60902
61155
  }
60903
61156
 
60904
- boxMesh.material.uniforms.envMap.value = background;
60905
- boxMesh.material.uniforms.flipEnvMap.value = ( background.isCubeTexture && background.isRenderTargetTexture === false ) ? -1 : 1;
60906
- boxMesh.material.uniforms.backgroundBlurriness.value = scene.backgroundBlurriness;
60907
- boxMesh.material.uniforms.backgroundIntensity.value = scene.backgroundIntensity;
60908
- boxMesh.material.uniforms.backgroundRotation.value.setFromMatrix4( _m1$1.makeRotationFromEuler( _e1$1 ) );
61157
+
60909
61158
  boxMesh.material.toneMapped = ColorManagement.getTransfer( background.colorSpace ) !== SRGBTransfer;
60910
61159
 
60911
61160
  if ( currentBackground !== background ||
@@ -61765,44 +62014,12 @@
61765
62014
 
61766
62015
  }
61767
62016
 
61768
- function renderMultiDrawInstances( starts, counts, drawCount, primcount ) {
61769
-
61770
- if ( drawCount === 0 ) return;
61771
-
61772
- const extension = extensions.get( 'WEBGL_multi_draw' );
61773
-
61774
- if ( extension === null ) {
61775
-
61776
- for ( let i = 0; i < starts.length; i ++ ) {
61777
-
61778
- renderInstances( starts[ i ], counts[ i ], primcount[ i ] );
61779
-
61780
- }
61781
-
61782
- } else {
61783
-
61784
- extension.multiDrawArraysInstancedWEBGL( mode, starts, 0, counts, 0, primcount, 0, drawCount );
61785
-
61786
- let elementCount = 0;
61787
- for ( let i = 0; i < drawCount; i ++ ) {
61788
-
61789
- elementCount += counts[ i ] * primcount[ i ];
61790
-
61791
- }
61792
-
61793
- info.update( elementCount, mode, 1 );
61794
-
61795
- }
61796
-
61797
- }
61798
-
61799
62017
  //
61800
62018
 
61801
62019
  this.setMode = setMode;
61802
62020
  this.render = render;
61803
62021
  this.renderInstances = renderInstances;
61804
62022
  this.renderMultiDraw = renderMultiDraw;
61805
- this.renderMultiDrawInstances = renderMultiDrawInstances;
61806
62023
 
61807
62024
  }
61808
62025
 
@@ -61900,6 +62117,12 @@
61900
62117
  const logarithmicDepthBuffer = parameters.logarithmicDepthBuffer === true;
61901
62118
  const reversedDepthBuffer = parameters.reversedDepthBuffer === true && extensions.has( 'EXT_clip_control' );
61902
62119
 
62120
+ if ( parameters.reversedDepthBuffer === true && reversedDepthBuffer === false ) {
62121
+
62122
+ warn( 'WebGLRenderer: Unable to use reversed depth buffer due to missing EXT_clip_control extension. Fallback to default depth buffer.' );
62123
+
62124
+ }
62125
+
61903
62126
  const maxTextures = gl.getParameter( gl.MAX_TEXTURE_IMAGE_UNITS );
61904
62127
  const maxVertexTextures = gl.getParameter( gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS );
61905
62128
  const maxTextureSize = gl.getParameter( gl.MAX_TEXTURE_SIZE );
@@ -63941,37 +64164,6 @@
63941
64164
 
63942
64165
  }
63943
64166
 
63944
- function renderMultiDrawInstances( starts, counts, drawCount, primcount ) {
63945
-
63946
- if ( drawCount === 0 ) return;
63947
-
63948
- const extension = extensions.get( 'WEBGL_multi_draw' );
63949
-
63950
- if ( extension === null ) {
63951
-
63952
- for ( let i = 0; i < starts.length; i ++ ) {
63953
-
63954
- renderInstances( starts[ i ] / bytesPerElement, counts[ i ], primcount[ i ] );
63955
-
63956
- }
63957
-
63958
- } else {
63959
-
63960
- extension.multiDrawElementsInstancedWEBGL( mode, counts, 0, type, starts, 0, primcount, 0, drawCount );
63961
-
63962
- let elementCount = 0;
63963
- for ( let i = 0; i < drawCount; i ++ ) {
63964
-
63965
- elementCount += counts[ i ] * primcount[ i ];
63966
-
63967
- }
63968
-
63969
- info.update( elementCount, mode, 1 );
63970
-
63971
- }
63972
-
63973
- }
63974
-
63975
64167
  //
63976
64168
 
63977
64169
  this.setMode = setMode;
@@ -63979,7 +64171,6 @@
63979
64171
  this.render = render;
63980
64172
  this.renderInstances = renderInstances;
63981
64173
  this.renderMultiDraw = renderMultiDraw;
63982
- this.renderMultiDrawInstances = renderMultiDrawInstances;
63983
64174
 
63984
64175
  }
63985
64176
 
@@ -64321,7 +64512,8 @@
64321
64512
  const targetA = new WebGLRenderTarget( width, height, {
64322
64513
  type: type,
64323
64514
  depthBuffer: depth,
64324
- stencilBuffer: stencil
64515
+ stencilBuffer: stencil,
64516
+ depthTexture: depth ? new DepthTexture( width, height ) : undefined
64325
64517
  } );
64326
64518
 
64327
64519
  const targetB = new WebGLRenderTarget( width, height, {
@@ -64542,6 +64734,7 @@
64542
64734
 
64543
64735
  this.dispose = function () {
64544
64736
 
64737
+ if ( targetA.depthTexture ) targetA.depthTexture.dispose();
64545
64738
  targetA.dispose();
64546
64739
  targetB.dispose();
64547
64740
  geometry.dispose();
@@ -66314,6 +66507,7 @@
66314
66507
  //
66315
66508
 
66316
66509
  parameters.vertexTangents && parameters.flatShading === false ? '#define USE_TANGENT' : '',
66510
+ parameters.vertexNormals ? '#define HAS_NORMAL' : '',
66317
66511
  parameters.vertexColors ? '#define USE_COLOR' : '',
66318
66512
  parameters.vertexAlphas ? '#define USE_COLOR_ALPHA' : '',
66319
66513
  parameters.vertexUv1s ? '#define USE_UV1' : '',
@@ -66447,6 +66641,7 @@
66447
66641
  parameters.normalMap ? '#define USE_NORMALMAP' : '',
66448
66642
  parameters.normalMapObjectSpace ? '#define USE_NORMALMAP_OBJECTSPACE' : '',
66449
66643
  parameters.normalMapTangentSpace ? '#define USE_NORMALMAP_TANGENTSPACE' : '',
66644
+ parameters.packedNormalMap ? '#define USE_PACKED_NORMALMAP' : '',
66450
66645
  parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '',
66451
66646
 
66452
66647
  parameters.anisotropy ? '#define USE_ANISOTROPY' : '',
@@ -66505,6 +66700,8 @@
66505
66700
 
66506
66701
  parameters.numLightProbes > 0 ? '#define USE_LIGHT_PROBES' : '',
66507
66702
 
66703
+ parameters.numLightProbeGrids > 0 ? '#define USE_LIGHT_PROBES_GRID' : '',
66704
+
66508
66705
  parameters.decodeVideoTexture ? '#define DECODE_VIDEO_TEXTURE' : '',
66509
66706
  parameters.decodeVideoTextureEmissive ? '#define DECODE_VIDEO_TEXTURE_EMISSIVE' : '',
66510
66707
 
@@ -66898,6 +67095,12 @@
66898
67095
 
66899
67096
  }
66900
67097
 
67098
+ function isPackedRGFormat( format ) {
67099
+
67100
+ return format === RGFormat || format === RG11_EAC_Format || format === RED_GREEN_RGTC2_Format;
67101
+
67102
+ }
67103
+
66901
67104
  function WebGLPrograms( renderer, environments, extensions, capabilities, bindingStates, clipping ) {
66902
67105
 
66903
67106
  const _programLayers = new Layers();
@@ -66938,7 +67141,7 @@
66938
67141
 
66939
67142
  }
66940
67143
 
66941
- function getParameters( material, lights, shadows, scene, object ) {
67144
+ function getParameters( material, lights, shadows, scene, object, lightProbeGrids ) {
66942
67145
 
66943
67146
  const fog = scene.fog;
66944
67147
  const geometry = object.geometry;
@@ -67091,7 +67294,7 @@
67091
67294
  instancingColor: IS_INSTANCEDMESH && object.instanceColor !== null,
67092
67295
  instancingMorph: IS_INSTANCEDMESH && object.morphTexture !== null,
67093
67296
 
67094
- outputColorSpace: ( currentRenderTarget === null ) ? renderer.outputColorSpace : ( currentRenderTarget.isXRRenderTarget === true ? currentRenderTarget.texture.colorSpace : LinearSRGBColorSpace ),
67297
+ outputColorSpace: ( currentRenderTarget === null ) ? renderer.outputColorSpace : ( currentRenderTarget.isXRRenderTarget === true ? currentRenderTarget.texture.colorSpace : ColorManagement.workingColorSpace ),
67095
67298
  alphaToCoverage: !! material.alphaToCoverage,
67096
67299
 
67097
67300
  map: HAS_MAP,
@@ -67108,6 +67311,7 @@
67108
67311
 
67109
67312
  normalMapObjectSpace: HAS_NORMALMAP && material.normalMapType === ObjectSpaceNormalMap,
67110
67313
  normalMapTangentSpace: HAS_NORMALMAP && material.normalMapType === TangentSpaceNormalMap,
67314
+ packedNormalMap: HAS_NORMALMAP && material.normalMapType === TangentSpaceNormalMap && isPackedRGFormat( material.normalMap.format ),
67111
67315
 
67112
67316
  metalnessMap: HAS_METALNESSMAP,
67113
67317
  roughnessMap: HAS_ROUGHNESSMAP,
@@ -67185,6 +67389,7 @@
67185
67389
  //
67186
67390
 
67187
67391
  vertexTangents: !! geometry.attributes.tangent && ( HAS_NORMALMAP || HAS_ANISOTROPY ),
67392
+ vertexNormals: !! geometry.attributes.normal,
67188
67393
  vertexColors: material.vertexColors,
67189
67394
  vertexAlphas: material.vertexColors === true && !! geometry.attributes.color && geometry.attributes.color.itemSize === 4,
67190
67395
 
@@ -67227,6 +67432,8 @@
67227
67432
 
67228
67433
  numLightProbes: lights.numLightProbes,
67229
67434
 
67435
+ numLightProbeGrids: lightProbeGrids.length,
67436
+
67230
67437
  numClippingPlanes: clipping.numPlanes,
67231
67438
  numClipIntersection: clipping.numIntersection,
67232
67439
 
@@ -67412,6 +67619,10 @@
67412
67619
  _programLayers.enable( 20 );
67413
67620
  if ( parameters.gradientMap )
67414
67621
  _programLayers.enable( 21 );
67622
+ if ( parameters.packedNormalMap )
67623
+ _programLayers.enable( 22 );
67624
+ if ( parameters.vertexNormals )
67625
+ _programLayers.enable( 23 );
67415
67626
 
67416
67627
  array.push( _programLayers.mask );
67417
67628
  _programLayers.disableAll();
@@ -67460,6 +67671,8 @@
67460
67671
  _programLayers.enable( 20 );
67461
67672
  if ( parameters.alphaToCoverage )
67462
67673
  _programLayers.enable( 21 );
67674
+ if ( parameters.numLightProbeGrids > 0 )
67675
+ _programLayers.enable( 22 );
67463
67676
 
67464
67677
  array.push( _programLayers.mask );
67465
67678
 
@@ -68436,6 +68649,7 @@
68436
68649
 
68437
68650
  const lightsArray = [];
68438
68651
  const shadowsArray = [];
68652
+ const lightProbeGridArray = [];
68439
68653
 
68440
68654
  function init( camera ) {
68441
68655
 
@@ -68443,6 +68657,7 @@
68443
68657
 
68444
68658
  lightsArray.length = 0;
68445
68659
  shadowsArray.length = 0;
68660
+ lightProbeGridArray.length = 0;
68446
68661
 
68447
68662
  }
68448
68663
 
@@ -68458,6 +68673,12 @@
68458
68673
 
68459
68674
  }
68460
68675
 
68676
+ function pushLightProbeGrid( volume ) {
68677
+
68678
+ lightProbeGridArray.push( volume );
68679
+
68680
+ }
68681
+
68461
68682
  function setupLights() {
68462
68683
 
68463
68684
  lights.setup( lightsArray );
@@ -68473,12 +68694,14 @@
68473
68694
  const state = {
68474
68695
  lightsArray: lightsArray,
68475
68696
  shadowsArray: shadowsArray,
68697
+ lightProbeGridArray: lightProbeGridArray,
68476
68698
 
68477
68699
  camera: null,
68478
68700
 
68479
68701
  lights: lights,
68480
68702
 
68481
- transmissionRenderTarget: {}
68703
+ transmissionRenderTarget: {},
68704
+ textureUnits: 0
68482
68705
  };
68483
68706
 
68484
68707
  return {
@@ -68488,7 +68711,8 @@
68488
68711
  setupLightsView: setupLightsView,
68489
68712
 
68490
68713
  pushLight: pushLight,
68491
- pushShadow: pushShadow
68714
+ pushShadow: pushShadow,
68715
+ pushLightProbeGrid: pushLightProbeGrid
68492
68716
  };
68493
68717
 
68494
68718
  }
@@ -69471,6 +69695,7 @@
69471
69695
  const uboProgramMap = new WeakMap();
69472
69696
 
69473
69697
  let enabledCapabilities = {};
69698
+ let parameters = {};
69474
69699
 
69475
69700
  let currentBoundFramebuffers = {};
69476
69701
  let currentDrawbuffers = new WeakMap();
@@ -70230,6 +70455,31 @@
70230
70455
 
70231
70456
  }
70232
70457
 
70458
+ function getParameter( name ) {
70459
+
70460
+ if ( parameters[ name ] !== undefined ) {
70461
+
70462
+ return parameters[ name ];
70463
+
70464
+ } else {
70465
+
70466
+ return gl.getParameter( name );
70467
+
70468
+ }
70469
+
70470
+ }
70471
+
70472
+ function pixelStorei( name, value ) {
70473
+
70474
+ if ( parameters[ name ] !== value ) {
70475
+
70476
+ gl.pixelStorei( name, value );
70477
+ parameters[ name ] = value;
70478
+
70479
+ }
70480
+
70481
+ }
70482
+
70233
70483
  //
70234
70484
 
70235
70485
  function scissor( scissor ) {
@@ -70346,9 +70596,24 @@
70346
70596
  gl.scissor( 0, 0, gl.canvas.width, gl.canvas.height );
70347
70597
  gl.viewport( 0, 0, gl.canvas.width, gl.canvas.height );
70348
70598
 
70599
+ gl.pixelStorei( gl.PACK_ALIGNMENT, 4 );
70600
+ gl.pixelStorei( gl.UNPACK_ALIGNMENT, 4 );
70601
+ gl.pixelStorei( gl.UNPACK_FLIP_Y_WEBGL, false );
70602
+ gl.pixelStorei( gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false );
70603
+ gl.pixelStorei( gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.BROWSER_DEFAULT_WEBGL );
70604
+ gl.pixelStorei( gl.PACK_ROW_LENGTH, 0 );
70605
+ gl.pixelStorei( gl.PACK_SKIP_PIXELS, 0 );
70606
+ gl.pixelStorei( gl.PACK_SKIP_ROWS, 0 );
70607
+ gl.pixelStorei( gl.UNPACK_ROW_LENGTH, 0 );
70608
+ gl.pixelStorei( gl.UNPACK_IMAGE_HEIGHT, 0 );
70609
+ gl.pixelStorei( gl.UNPACK_SKIP_PIXELS, 0 );
70610
+ gl.pixelStorei( gl.UNPACK_SKIP_ROWS, 0 );
70611
+ gl.pixelStorei( gl.UNPACK_SKIP_IMAGES, 0 );
70612
+
70349
70613
  // reset internals
70350
70614
 
70351
70615
  enabledCapabilities = {};
70616
+ parameters = {};
70352
70617
 
70353
70618
  currentTextureSlot = null;
70354
70619
  currentBoundTextures = {};
@@ -70422,6 +70687,8 @@
70422
70687
  compressedTexImage3D: compressedTexImage3D,
70423
70688
  texImage2D: texImage2D,
70424
70689
  texImage3D: texImage3D,
70690
+ pixelStorei: pixelStorei,
70691
+ getParameter: getParameter,
70425
70692
 
70426
70693
  updateUBOMapping: updateUBOMapping,
70427
70694
  uniformBlockBinding: uniformBlockBinding,
@@ -70449,6 +70716,7 @@
70449
70716
 
70450
70717
  const _imageDimensions = new Vector2();
70451
70718
  const _videoTextures = new WeakMap();
70719
+ const _htmlTextures = new Set();
70452
70720
  let _canvas;
70453
70721
 
70454
70722
  const _sources = new WeakMap(); // maps WebglTexture objects to instances of Source
@@ -70563,7 +70831,7 @@
70563
70831
 
70564
70832
  }
70565
70833
 
70566
- function getInternalFormat( internalFormatName, glFormat, glType, colorSpace, forceLinearTransfer = false ) {
70834
+ function getInternalFormat( internalFormatName, glFormat, glType, normalized, colorSpace, forceLinearTransfer = false ) {
70567
70835
 
70568
70836
  if ( internalFormatName !== null ) {
70569
70837
 
@@ -70573,6 +70841,20 @@
70573
70841
 
70574
70842
  }
70575
70843
 
70844
+ let ext_texture_norm16;
70845
+
70846
+ if ( normalized ) {
70847
+
70848
+ ext_texture_norm16 = extensions.get( 'EXT_texture_norm16' );
70849
+
70850
+ if ( ! ext_texture_norm16 ) {
70851
+
70852
+ warn( 'WebGLRenderer: Unable to use normalized textures without EXT_texture_norm16 extension' );
70853
+
70854
+ }
70855
+
70856
+ }
70857
+
70576
70858
  let internalFormat = glFormat;
70577
70859
 
70578
70860
  if ( glFormat === _gl.RED ) {
@@ -70580,6 +70862,8 @@
70580
70862
  if ( glType === _gl.FLOAT ) internalFormat = _gl.R32F;
70581
70863
  if ( glType === _gl.HALF_FLOAT ) internalFormat = _gl.R16F;
70582
70864
  if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = _gl.R8;
70865
+ if ( glType === _gl.UNSIGNED_SHORT && ext_texture_norm16 ) internalFormat = ext_texture_norm16.R16_EXT;
70866
+ if ( glType === _gl.SHORT && ext_texture_norm16 ) internalFormat = ext_texture_norm16.R16_SNORM_EXT;
70583
70867
 
70584
70868
  }
70585
70869
 
@@ -70599,6 +70883,8 @@
70599
70883
  if ( glType === _gl.FLOAT ) internalFormat = _gl.RG32F;
70600
70884
  if ( glType === _gl.HALF_FLOAT ) internalFormat = _gl.RG16F;
70601
70885
  if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = _gl.RG8;
70886
+ if ( glType === _gl.UNSIGNED_SHORT && ext_texture_norm16 ) internalFormat = ext_texture_norm16.RG16_EXT;
70887
+ if ( glType === _gl.SHORT && ext_texture_norm16 ) internalFormat = ext_texture_norm16.RG16_SNORM_EXT;
70602
70888
 
70603
70889
  }
70604
70890
 
@@ -70637,6 +70923,8 @@
70637
70923
 
70638
70924
  if ( glFormat === _gl.RGB ) {
70639
70925
 
70926
+ if ( glType === _gl.UNSIGNED_SHORT && ext_texture_norm16 ) internalFormat = ext_texture_norm16.RGB16_EXT;
70927
+ if ( glType === _gl.SHORT && ext_texture_norm16 ) internalFormat = ext_texture_norm16.RGB16_SNORM_EXT;
70640
70928
  if ( glType === _gl.UNSIGNED_INT_5_9_9_9_REV ) internalFormat = _gl.RGB9_E5;
70641
70929
  if ( glType === _gl.UNSIGNED_INT_10F_11F_11F_REV ) internalFormat = _gl.R11F_G11F_B10F;
70642
70930
 
@@ -70649,6 +70937,8 @@
70649
70937
  if ( glType === _gl.FLOAT ) internalFormat = _gl.RGBA32F;
70650
70938
  if ( glType === _gl.HALF_FLOAT ) internalFormat = _gl.RGBA16F;
70651
70939
  if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = ( transfer === SRGBTransfer ) ? _gl.SRGB8_ALPHA8 : _gl.RGBA8;
70940
+ if ( glType === _gl.UNSIGNED_SHORT && ext_texture_norm16 ) internalFormat = ext_texture_norm16.RGBA16_EXT;
70941
+ if ( glType === _gl.SHORT && ext_texture_norm16 ) internalFormat = ext_texture_norm16.RGBA16_SNORM_EXT;
70652
70942
  if ( glType === _gl.UNSIGNED_SHORT_4_4_4_4 ) internalFormat = _gl.RGBA4;
70653
70943
  if ( glType === _gl.UNSIGNED_SHORT_5_5_5_1 ) internalFormat = _gl.RGB5_A1;
70654
70944
 
@@ -70750,6 +71040,12 @@
70750
71040
 
70751
71041
  }
70752
71042
 
71043
+ if ( texture.isHTMLTexture ) {
71044
+
71045
+ _htmlTextures.delete( texture );
71046
+
71047
+ }
71048
+
70753
71049
  }
70754
71050
 
70755
71051
  function onRenderTargetDispose( event ) {
@@ -70906,6 +71202,18 @@
70906
71202
 
70907
71203
  }
70908
71204
 
71205
+ function getTextureUnits() {
71206
+
71207
+ return textureUnits;
71208
+
71209
+ }
71210
+
71211
+ function setTextureUnits( value ) {
71212
+
71213
+ textureUnits = value;
71214
+
71215
+ }
71216
+
70909
71217
  function allocateTextureUnit() {
70910
71218
 
70911
71219
  const textureUnit = textureUnits;
@@ -71257,11 +71565,11 @@
71257
71565
  // Trim the array to only contain the merged ranges.
71258
71566
  updateRanges.length = mergeIndex + 1;
71259
71567
 
71260
- const currentUnpackRowLen = _gl.getParameter( _gl.UNPACK_ROW_LENGTH );
71261
- const currentUnpackSkipPixels = _gl.getParameter( _gl.UNPACK_SKIP_PIXELS );
71262
- const currentUnpackSkipRows = _gl.getParameter( _gl.UNPACK_SKIP_ROWS );
71568
+ const currentUnpackRowLen = state.getParameter( _gl.UNPACK_ROW_LENGTH );
71569
+ const currentUnpackSkipPixels = state.getParameter( _gl.UNPACK_SKIP_PIXELS );
71570
+ const currentUnpackSkipRows = state.getParameter( _gl.UNPACK_SKIP_ROWS );
71263
71571
 
71264
- _gl.pixelStorei( _gl.UNPACK_ROW_LENGTH, image.width );
71572
+ state.pixelStorei( _gl.UNPACK_ROW_LENGTH, image.width );
71265
71573
 
71266
71574
  for ( let i = 0, l = updateRanges.length; i < l; i ++ ) {
71267
71575
 
@@ -71277,8 +71585,8 @@
71277
71585
  const width = pixelCount;
71278
71586
  const height = 1;
71279
71587
 
71280
- _gl.pixelStorei( _gl.UNPACK_SKIP_PIXELS, x );
71281
- _gl.pixelStorei( _gl.UNPACK_SKIP_ROWS, y );
71588
+ state.pixelStorei( _gl.UNPACK_SKIP_PIXELS, x );
71589
+ state.pixelStorei( _gl.UNPACK_SKIP_ROWS, y );
71282
71590
 
71283
71591
  state.texSubImage2D( _gl.TEXTURE_2D, 0, x, y, width, height, glFormat, glType, image.data );
71284
71592
 
@@ -71286,9 +71594,9 @@
71286
71594
 
71287
71595
  texture.clearUpdateRanges();
71288
71596
 
71289
- _gl.pixelStorei( _gl.UNPACK_ROW_LENGTH, currentUnpackRowLen );
71290
- _gl.pixelStorei( _gl.UNPACK_SKIP_PIXELS, currentUnpackSkipPixels );
71291
- _gl.pixelStorei( _gl.UNPACK_SKIP_ROWS, currentUnpackSkipRows );
71597
+ state.pixelStorei( _gl.UNPACK_ROW_LENGTH, currentUnpackRowLen );
71598
+ state.pixelStorei( _gl.UNPACK_SKIP_PIXELS, currentUnpackSkipPixels );
71599
+ state.pixelStorei( _gl.UNPACK_SKIP_ROWS, currentUnpackSkipRows );
71292
71600
 
71293
71601
  }
71294
71602
 
@@ -71312,14 +71620,21 @@
71312
71620
 
71313
71621
  state.activeTexture( _gl.TEXTURE0 + slot );
71314
71622
 
71315
- const workingPrimaries = ColorManagement.getPrimaries( ColorManagement.workingColorSpace );
71316
- const texturePrimaries = texture.colorSpace === NoColorSpace ? null : ColorManagement.getPrimaries( texture.colorSpace );
71317
- const unpackConversion = texture.colorSpace === NoColorSpace || workingPrimaries === texturePrimaries ? _gl.NONE : _gl.BROWSER_DEFAULT_WEBGL;
71623
+ const isImageBitmap = ( typeof ImageBitmap !== 'undefined' && texture.image instanceof ImageBitmap );
71624
+
71625
+ if ( isImageBitmap === false ) {
71626
+
71627
+ const workingPrimaries = ColorManagement.getPrimaries( ColorManagement.workingColorSpace );
71628
+ const texturePrimaries = texture.colorSpace === NoColorSpace ? null : ColorManagement.getPrimaries( texture.colorSpace );
71629
+ const unpackConversion = texture.colorSpace === NoColorSpace || workingPrimaries === texturePrimaries ? _gl.NONE : _gl.BROWSER_DEFAULT_WEBGL;
71630
+
71631
+ state.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY );
71632
+ state.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha );
71633
+ state.pixelStorei( _gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, unpackConversion );
71318
71634
 
71319
- _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY );
71320
- _gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha );
71321
- _gl.pixelStorei( _gl.UNPACK_ALIGNMENT, texture.unpackAlignment );
71322
- _gl.pixelStorei( _gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, unpackConversion );
71635
+ }
71636
+
71637
+ state.pixelStorei( _gl.UNPACK_ALIGNMENT, texture.unpackAlignment );
71323
71638
 
71324
71639
  let image = resizeImage( texture.image, false, capabilities.maxTextureSize );
71325
71640
  image = verifyColorSpace( texture, image );
@@ -71327,7 +71642,7 @@
71327
71642
  const glFormat = utils.convert( texture.format, texture.colorSpace );
71328
71643
 
71329
71644
  const glType = utils.convert( texture.type );
71330
- let glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace, texture.isVideoTexture );
71645
+ let glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.normalized, texture.colorSpace, texture.isVideoTexture );
71331
71646
 
71332
71647
  setTextureParameters( textureType, texture );
71333
71648
 
@@ -71644,6 +71959,59 @@
71644
71959
 
71645
71960
  }
71646
71961
 
71962
+ } else if ( texture.isHTMLTexture ) {
71963
+
71964
+ if ( 'texElementImage2D' in _gl ) {
71965
+
71966
+ const canvas = _gl.canvas;
71967
+
71968
+ // Ensure the canvas supports HTML-in-Canvas and the element is a child.
71969
+ if ( ! canvas.hasAttribute( 'layoutsubtree' ) ) {
71970
+
71971
+ canvas.setAttribute( 'layoutsubtree', 'true' );
71972
+
71973
+ }
71974
+
71975
+ if ( image.parentNode !== canvas ) {
71976
+
71977
+ canvas.appendChild( image );
71978
+
71979
+ // Register and set up a shared paint callback for all HTMLTextures.
71980
+ _htmlTextures.add( texture );
71981
+
71982
+ canvas.onpaint = ( event ) => {
71983
+
71984
+ const changed = event.changedElements;
71985
+
71986
+ for ( const t of _htmlTextures ) {
71987
+
71988
+ if ( changed.includes( t.image ) ) {
71989
+
71990
+ t.needsUpdate = true;
71991
+
71992
+ }
71993
+
71994
+ }
71995
+
71996
+ };
71997
+
71998
+ canvas.requestPaint();
71999
+ return;
72000
+
72001
+ }
72002
+
72003
+ const level = 0;
72004
+ const internalFormat = _gl.RGBA;
72005
+ const srcFormat = _gl.RGBA;
72006
+ const srcType = _gl.UNSIGNED_BYTE;
72007
+
72008
+ _gl.texElementImage2D( _gl.TEXTURE_2D, level, internalFormat, srcFormat, srcType, image );
72009
+ _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_MIN_FILTER, _gl.LINEAR );
72010
+ _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE );
72011
+ _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE );
72012
+
72013
+ }
72014
+
71647
72015
  } else {
71648
72016
 
71649
72017
  // regular Texture (image, video, canvas)
@@ -71747,10 +72115,10 @@
71747
72115
  const texturePrimaries = texture.colorSpace === NoColorSpace ? null : ColorManagement.getPrimaries( texture.colorSpace );
71748
72116
  const unpackConversion = texture.colorSpace === NoColorSpace || workingPrimaries === texturePrimaries ? _gl.NONE : _gl.BROWSER_DEFAULT_WEBGL;
71749
72117
 
71750
- _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY );
71751
- _gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha );
71752
- _gl.pixelStorei( _gl.UNPACK_ALIGNMENT, texture.unpackAlignment );
71753
- _gl.pixelStorei( _gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, unpackConversion );
72118
+ state.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY );
72119
+ state.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha );
72120
+ state.pixelStorei( _gl.UNPACK_ALIGNMENT, texture.unpackAlignment );
72121
+ state.pixelStorei( _gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, unpackConversion );
71754
72122
 
71755
72123
  const isCompressed = ( texture.isCompressedTexture || texture.image[ 0 ].isCompressedTexture );
71756
72124
  const isDataTexture = ( texture.image[ 0 ] && texture.image[ 0 ].isDataTexture );
@@ -71776,7 +72144,7 @@
71776
72144
  const image = cubeImage[ 0 ],
71777
72145
  glFormat = utils.convert( texture.format, texture.colorSpace ),
71778
72146
  glType = utils.convert( texture.type ),
71779
- glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace );
72147
+ glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.normalized, texture.colorSpace );
71780
72148
 
71781
72149
  const useTexStorage = ( texture.isVideoTexture !== true );
71782
72150
  const allocateMemory = ( sourceProperties.__version === undefined ) || ( forceUpload === true );
@@ -71972,7 +72340,7 @@
71972
72340
 
71973
72341
  const glFormat = utils.convert( texture.format, texture.colorSpace );
71974
72342
  const glType = utils.convert( texture.type );
71975
- const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace );
72343
+ const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.normalized, texture.colorSpace );
71976
72344
  const renderTargetProperties = properties.get( renderTarget );
71977
72345
  const textureProperties = properties.get( texture );
71978
72346
 
@@ -72051,7 +72419,7 @@
72051
72419
 
72052
72420
  const glFormat = utils.convert( texture.format, texture.colorSpace );
72053
72421
  const glType = utils.convert( texture.type );
72054
- const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace );
72422
+ const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.normalized, texture.colorSpace );
72055
72423
 
72056
72424
  if ( useMultisampledRTT( renderTarget ) ) {
72057
72425
 
@@ -72441,7 +72809,7 @@
72441
72809
 
72442
72810
  const glFormat = utils.convert( texture.format, texture.colorSpace );
72443
72811
  const glType = utils.convert( texture.type );
72444
- const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace, renderTarget.isXRRenderTarget === true );
72812
+ const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.normalized, texture.colorSpace, renderTarget.isXRRenderTarget === true );
72445
72813
  const samples = getRenderTargetSamples( renderTarget );
72446
72814
  _gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height );
72447
72815
 
@@ -72817,6 +73185,8 @@
72817
73185
 
72818
73186
  this.allocateTextureUnit = allocateTextureUnit;
72819
73187
  this.resetTextureUnits = resetTextureUnits;
73188
+ this.getTextureUnits = getTextureUnits;
73189
+ this.setTextureUnits = setTextureUnits;
72820
73190
 
72821
73191
  this.setTexture2D = setTexture2D;
72822
73192
  this.setTexture2DArray = setTexture2DArray;
@@ -74285,8 +74655,10 @@ void main() {
74285
74655
 
74286
74656
  }
74287
74657
 
74288
- const _e1 = /*@__PURE__*/ new Euler();
74289
74658
  const _m1 = /*@__PURE__*/ new Matrix4();
74659
+ const _m = /*@__PURE__*/ new Matrix3();
74660
+
74661
+ _m.set( -1, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0 );
74290
74662
 
74291
74663
  function WebGLMaterials( renderer, properties ) {
74292
74664
 
@@ -74321,7 +74693,11 @@ void main() {
74321
74693
 
74322
74694
  function refreshMaterialUniforms( uniforms, material, pixelRatio, height, transmissionRenderTarget ) {
74323
74695
 
74324
- if ( material.isMeshBasicMaterial ) {
74696
+ if ( material.isNodeMaterial ) {
74697
+
74698
+ material.uniformsNeedUpdate = false;
74699
+
74700
+ } else if ( material.isMeshBasicMaterial ) {
74325
74701
 
74326
74702
  refreshUniformsCommon( uniforms, material );
74327
74703
 
@@ -74517,23 +74893,16 @@ void main() {
74517
74893
 
74518
74894
  uniforms.envMap.value = envMap;
74519
74895
 
74520
- _e1.copy( envMapRotation );
74896
+ // note: since the matrix is orthonormal, we can use the more-efficient transpose() in lieu of invert()
74897
+ uniforms.envMapRotation.value.setFromMatrix4( _m1.makeRotationFromEuler( envMapRotation ) ).transpose();
74521
74898
 
74522
- // accommodate left-handed frame
74523
- _e1.x *= -1; _e1.y *= -1; _e1.z *= -1;
74524
74899
 
74525
74900
  if ( envMap.isCubeTexture && envMap.isRenderTargetTexture === false ) {
74526
74901
 
74527
- // environment maps which are not cube render targets or PMREMs follow a different convention
74528
- _e1.y *= -1;
74529
- _e1.z *= -1;
74902
+ uniforms.envMapRotation.value.premultiply( _m );
74530
74903
 
74531
74904
  }
74532
74905
 
74533
- uniforms.envMapRotation.value.setFromMatrix4( _m1.makeRotationFromEuler( _e1 ) );
74534
-
74535
- uniforms.flipEnvMap.value = ( envMap.isCubeTexture && envMap.isRenderTargetTexture === false ) ? -1 : 1;
74536
-
74537
74906
  uniforms.reflectivity.value = material.reflectivity;
74538
74907
  uniforms.ior.value = material.ior;
74539
74908
  uniforms.refractionRatio.value = material.refractionRatio;
@@ -75023,6 +75392,11 @@ void main() {
75023
75392
  uniform.__data[ 10 ] = value.elements[ 8 ];
75024
75393
  uniform.__data[ 11 ] = 0;
75025
75394
 
75395
+ } else if ( ArrayBuffer.isView( value ) ) {
75396
+
75397
+ // copy the buffer data using "set"
75398
+ uniform.__data.set( new value.constructor( value.buffer, value.byteOffset, uniform.__data.length ) );
75399
+
75026
75400
  } else {
75027
75401
 
75028
75402
  value.toArray( uniform.__data, arrayOffset );
@@ -75058,6 +75432,10 @@ void main() {
75058
75432
 
75059
75433
  cache[ indexString ] = value;
75060
75434
 
75435
+ } else if ( ArrayBuffer.isView( value ) ) {
75436
+
75437
+ cache[ indexString ] = value.slice();
75438
+
75061
75439
  } else {
75062
75440
 
75063
75441
  cache[ indexString ] = value.clone();
@@ -75081,6 +75459,11 @@ void main() {
75081
75459
 
75082
75460
  }
75083
75461
 
75462
+ } else if ( ArrayBuffer.isView( value ) ) {
75463
+
75464
+ // always update the array buffers
75465
+ return true;
75466
+
75084
75467
  } else {
75085
75468
 
75086
75469
  if ( cachedObject.equals( value ) === false ) {
@@ -75221,6 +75604,11 @@ void main() {
75221
75604
 
75222
75605
  warn( 'WebGLRenderer: Texture samplers can not be part of an uniforms group.' );
75223
75606
 
75607
+ } else if ( ArrayBuffer.isView( value ) ) {
75608
+
75609
+ info.boundary = 16;
75610
+ info.storage = value.byteLength;
75611
+
75224
75612
  } else {
75225
75613
 
75226
75614
  warn( 'WebGLRenderer: Unsupported uniform value type.', value );
@@ -75395,6 +75783,7 @@ void main() {
75395
75783
 
75396
75784
  const uintClearColor = new Uint32Array( 4 );
75397
75785
  const intClearColor = new Int32Array( 4 );
75786
+ const objectPosition = new Vector3();
75398
75787
 
75399
75788
  let currentRenderList = null;
75400
75789
  let currentRenderState = null;
@@ -75557,6 +75946,7 @@ void main() {
75557
75946
  const _this = this;
75558
75947
 
75559
75948
  let _isContextLost = false;
75949
+ let _nodesHandler = null;
75560
75950
 
75561
75951
  // internal state cache
75562
75952
 
@@ -75991,7 +76381,7 @@ void main() {
75991
76381
 
75992
76382
  if ( _outputBufferType === UnsignedByteType ) {
75993
76383
 
75994
- console.error( 'THREE.WebGLRenderer: setEffects() requires outputBufferType set to HalfFloatType or FloatType.' );
76384
+ error( 'THREE.WebGLRenderer: setEffects() requires outputBufferType set to HalfFloatType or FloatType.' );
75995
76385
  return;
75996
76386
 
75997
76387
  }
@@ -76002,7 +76392,7 @@ void main() {
76002
76392
 
76003
76393
  if ( effects[ i ].isOutputPass === true ) {
76004
76394
 
76005
- console.warn( 'THREE.WebGLRenderer: OutputPass is not needed in setEffects(). Tone mapping and color space conversion are applied automatically.' );
76395
+ warn( 'THREE.WebGLRenderer: OutputPass is not needed in setEffects(). Tone mapping and color space conversion are applied automatically.' );
76006
76396
  break;
76007
76397
 
76008
76398
  }
@@ -76262,6 +76652,7 @@ void main() {
76262
76652
  if ( depth ) {
76263
76653
 
76264
76654
  bits |= _gl.DEPTH_BUFFER_BIT;
76655
+ this.state.buffers.depth.setMask( true );
76265
76656
 
76266
76657
  }
76267
76658
 
@@ -76307,6 +76698,20 @@ void main() {
76307
76698
 
76308
76699
  };
76309
76700
 
76701
+ /**
76702
+ * Sets a compatibility node builder for rendering node materials with WebGLRenderer.
76703
+ * This enables using TSL (Three.js Shading Language) node materials to prepare
76704
+ * for migration to WebGPURenderer.
76705
+ *
76706
+ * @param {WebGLNodesHandler} nodesHandler - The node builder instance.
76707
+ */
76708
+ this.setNodesHandler = function ( nodesHandler ) {
76709
+
76710
+ nodesHandler.setRenderer( this );
76711
+ _nodesHandler = nodesHandler;
76712
+
76713
+ };
76714
+
76310
76715
  /**
76311
76716
  * Frees the GPU-related resources allocated by this instance. Call this
76312
76717
  * method whenever this instance is no longer used in your app.
@@ -76542,33 +76947,23 @@ void main() {
76542
76947
 
76543
76948
  if ( object.isBatchedMesh ) {
76544
76949
 
76545
- if ( object._multiDrawInstances !== null ) {
76546
-
76547
- // @deprecated, r174
76548
- warnOnce( 'WebGLRenderer: renderMultiDrawInstances has been deprecated and will be removed in r184. Append to renderMultiDraw arguments and use indirection.' );
76549
- renderer.renderMultiDrawInstances( object._multiDrawStarts, object._multiDrawCounts, object._multiDrawCount, object._multiDrawInstances );
76550
-
76551
- } else {
76552
-
76553
- if ( ! extensions.get( 'WEBGL_multi_draw' ) ) {
76950
+ if ( ! extensions.get( 'WEBGL_multi_draw' ) ) {
76554
76951
 
76555
- const starts = object._multiDrawStarts;
76556
- const counts = object._multiDrawCounts;
76557
- const drawCount = object._multiDrawCount;
76558
- const bytesPerElement = index ? attributes.get( index ).bytesPerElement : 1;
76559
- const uniforms = properties.get( material ).currentProgram.getUniforms();
76560
- for ( let i = 0; i < drawCount; i ++ ) {
76952
+ const starts = object._multiDrawStarts;
76953
+ const counts = object._multiDrawCounts;
76954
+ const drawCount = object._multiDrawCount;
76955
+ const bytesPerElement = index ? attributes.get( index ).bytesPerElement : 1;
76956
+ const uniforms = properties.get( material ).currentProgram.getUniforms();
76957
+ for ( let i = 0; i < drawCount; i ++ ) {
76561
76958
 
76562
- uniforms.setValue( _gl, '_gl_DrawID', i );
76563
- renderer.render( starts[ i ] / bytesPerElement, counts[ i ] );
76959
+ uniforms.setValue( _gl, '_gl_DrawID', i );
76960
+ renderer.render( starts[ i ] / bytesPerElement, counts[ i ] );
76564
76961
 
76565
- }
76566
-
76567
- } else {
76962
+ }
76568
76963
 
76569
- renderer.renderMultiDraw( object._multiDrawStarts, object._multiDrawCounts, object._multiDrawCount );
76964
+ } else {
76570
76965
 
76571
- }
76966
+ renderer.renderMultiDraw( object._multiDrawStarts, object._multiDrawCounts, object._multiDrawCount );
76572
76967
 
76573
76968
  }
76574
76969
 
@@ -76867,6 +77262,13 @@ void main() {
76867
77262
 
76868
77263
  if ( _isContextLost === true ) return;
76869
77264
 
77265
+ // update node builder if available
77266
+ if ( _nodesHandler !== null ) {
77267
+
77268
+ _nodesHandler.renderStart( scene, camera );
77269
+
77270
+ }
77271
+
76870
77272
  // use internal render target for HalfFloatType color buffer (only when tone mapping is enabled)
76871
77273
 
76872
77274
  const isXRPresenting = xr.enabled === true && xr.isPresenting === true;
@@ -76895,6 +77297,7 @@ void main() {
76895
77297
  currentRenderState = renderStates.get( scene, renderStateStack.length );
76896
77298
  currentRenderState.init( camera );
76897
77299
 
77300
+ currentRenderState.state.textureUnits = textures.getTextureUnits();
76898
77301
  renderStateStack.push( currentRenderState );
76899
77302
 
76900
77303
  _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse );
@@ -77040,6 +77443,8 @@ void main() {
77040
77443
 
77041
77444
  currentRenderState = renderStateStack[ renderStateStack.length - 1 ];
77042
77445
 
77446
+ textures.setTextureUnits( currentRenderState.state.textureUnits );
77447
+
77043
77448
  if ( _clippingEnabled === true ) clipping.setGlobalState( _this.clippingPlanes, currentRenderState.state.camera );
77044
77449
 
77045
77450
  } else {
@@ -77060,6 +77465,12 @@ void main() {
77060
77465
 
77061
77466
  }
77062
77467
 
77468
+ if ( _nodesHandler !== null ) {
77469
+
77470
+ _nodesHandler.renderEnd();
77471
+
77472
+ }
77473
+
77063
77474
  };
77064
77475
 
77065
77476
  function projectObject( object, camera, groupOrder, sortObjects ) {
@@ -77078,6 +77489,10 @@ void main() {
77078
77489
 
77079
77490
  if ( object.autoUpdate === true ) object.update( camera );
77080
77491
 
77492
+ } else if ( object.isLightProbeGrid ) {
77493
+
77494
+ currentRenderState.pushLightProbeGrid( object );
77495
+
77081
77496
  } else if ( object.isLight ) {
77082
77497
 
77083
77498
  currentRenderState.pushLight( object );
@@ -77218,7 +77633,7 @@ void main() {
77218
77633
  generateMipmaps: true,
77219
77634
  type: hasHalfFloatSupport ? HalfFloatType : UnsignedByteType,
77220
77635
  minFilter: LinearMipmapLinearFilter,
77221
- samples: capabilities.samples,
77636
+ samples: Math.max( 4, capabilities.samples ), // to avoid feedback loops, the transmission render target requires a resolve, see #26177
77222
77637
  stencilBuffer: stencil,
77223
77638
  resolveDepthBuffer: false,
77224
77639
  resolveStencilBuffer: false,
@@ -77393,7 +77808,7 @@ void main() {
77393
77808
 
77394
77809
  const lightsStateVersion = lights.state.version;
77395
77810
 
77396
- const parameters = programCache.getParameters( material, lights.state, shadowsArray, scene, object );
77811
+ const parameters = programCache.getParameters( material, lights.state, shadowsArray, scene, object, currentRenderState.state.lightProbeGridArray );
77397
77812
  const programCacheKey = programCache.getProgramCacheKey( parameters );
77398
77813
 
77399
77814
  let programs = materialProperties.programs;
@@ -77436,6 +77851,13 @@ void main() {
77436
77851
 
77437
77852
  parameters.uniforms = programCache.getUniforms( material );
77438
77853
 
77854
+ // Use node builder for node materials if available
77855
+ if ( _nodesHandler !== null && material.isNodeMaterial ) {
77856
+
77857
+ _nodesHandler.build( material, object, parameters );
77858
+
77859
+ }
77860
+
77439
77861
  material.onBeforeCompile( parameters, _this );
77440
77862
 
77441
77863
  program = programCache.acquireProgram( parameters, programCacheKey );
@@ -77485,6 +77907,8 @@ void main() {
77485
77907
 
77486
77908
  }
77487
77909
 
77910
+ materialProperties.lightProbeGrid = currentRenderState.state.lightProbeGridArray.length > 0;
77911
+
77488
77912
  materialProperties.currentProgram = program;
77489
77913
  materialProperties.uniformsList = null;
77490
77914
 
@@ -77528,6 +77952,30 @@ void main() {
77528
77952
 
77529
77953
  }
77530
77954
 
77955
+ function findLightProbeGrid( volumes, object ) {
77956
+
77957
+ if ( volumes.length === 0 ) return null;
77958
+
77959
+ if ( volumes.length === 1 ) {
77960
+
77961
+ return volumes[ 0 ].texture !== null ? volumes[ 0 ] : null;
77962
+
77963
+ }
77964
+
77965
+ objectPosition.setFromMatrixPosition( object.matrixWorld );
77966
+
77967
+ for ( let i = 0, l = volumes.length; i < l; i ++ ) {
77968
+
77969
+ const v = volumes[ i ];
77970
+
77971
+ if ( v.texture !== null && v.boundingBox.containsPoint( objectPosition ) ) return v;
77972
+
77973
+ }
77974
+
77975
+ return null;
77976
+
77977
+ }
77978
+
77531
77979
  function setProgram( camera, scene, geometry, material, object ) {
77532
77980
 
77533
77981
  if ( scene.isScene !== true ) scene = _emptyScene; // scene could be a Mesh, Line, Points, ...
@@ -77536,7 +77984,7 @@ void main() {
77536
77984
 
77537
77985
  const fog = scene.fog;
77538
77986
  const environment = ( material.isMeshStandardMaterial || material.isMeshLambertMaterial || material.isMeshPhongMaterial ) ? scene.environment : null;
77539
- const colorSpace = ( _currentRenderTarget === null ) ? _this.outputColorSpace : ( _currentRenderTarget.isXRRenderTarget === true ? _currentRenderTarget.texture.colorSpace : LinearSRGBColorSpace );
77987
+ const colorSpace = ( _currentRenderTarget === null ) ? _this.outputColorSpace : ( _currentRenderTarget.isXRRenderTarget === true ? _currentRenderTarget.texture.colorSpace : ColorManagement.workingColorSpace );
77540
77988
  const usePMREM = material.isMeshStandardMaterial || ( material.isMeshLambertMaterial && ! material.envMap ) || ( material.isMeshPhongMaterial && ! material.envMap );
77541
77989
  const envMap = environments.get( material.envMap || environment, usePMREM );
77542
77990
  const vertexAlphas = material.vertexColors === true && !! geometry.attributes.color && geometry.attributes.color.itemSize === 4;
@@ -77684,6 +78132,10 @@ void main() {
77684
78132
 
77685
78133
  needsProgramChange = true;
77686
78134
 
78135
+ } else if ( !! materialProperties.lightProbeGrid !== ( currentRenderState.state.lightProbeGridArray.length > 0 ) ) {
78136
+
78137
+ needsProgramChange = true;
78138
+
77687
78139
  }
77688
78140
 
77689
78141
  } else {
@@ -77701,6 +78153,14 @@ void main() {
77701
78153
 
77702
78154
  program = getProgram( material, scene, object );
77703
78155
 
78156
+ // notify the node builder that the program has changed so uniforms and update nodes can
78157
+ // be cached and triggered.
78158
+ if ( _nodesHandler && material.isNodeMaterial ) {
78159
+
78160
+ _nodesHandler.onUpdateProgram( material, program, materialProperties );
78161
+
78162
+ }
78163
+
77704
78164
  }
77705
78165
 
77706
78166
  let refreshProgram = false;
@@ -77726,6 +78186,19 @@ void main() {
77726
78186
 
77727
78187
  }
77728
78188
 
78189
+ if ( materialProperties.needsLights ) {
78190
+
78191
+ const objectVolume = findLightProbeGrid( currentRenderState.state.lightProbeGridArray, object );
78192
+
78193
+ if ( materialProperties.lightProbeGrid !== objectVolume ) {
78194
+
78195
+ materialProperties.lightProbeGrid = objectVolume;
78196
+ refreshMaterial = true;
78197
+
78198
+ }
78199
+
78200
+ }
78201
+
77729
78202
  if ( refreshProgram || _currentCamera !== camera ) {
77730
78203
 
77731
78204
  // common camera uniforms
@@ -77905,6 +78378,19 @@ void main() {
77905
78378
 
77906
78379
  materials.refreshMaterialUniforms( m_uniforms, material, _pixelRatio, _height, currentRenderState.state.transmissionRenderTarget[ camera.id ] );
77907
78380
 
78381
+ // light probe volume
78382
+
78383
+ if ( materialProperties.needsLights && materialProperties.lightProbeGrid ) {
78384
+
78385
+ const volume = materialProperties.lightProbeGrid;
78386
+
78387
+ m_uniforms.probesSH.value = volume.texture;
78388
+ m_uniforms.probesMin.value.copy( volume.boundingBox.min );
78389
+ m_uniforms.probesMax.value.copy( volume.boundingBox.max );
78390
+ m_uniforms.probesResolution.value.copy( volume.resolution );
78391
+
78392
+ }
78393
+
77908
78394
  WebGLUniforms.upload( _gl, getUniformList( materialProperties ), m_uniforms, textures );
77909
78395
 
77910
78396
  }
@@ -77930,7 +78416,7 @@ void main() {
77930
78416
 
77931
78417
  // UBOs
77932
78418
 
77933
- if ( material.isShaderMaterial || material.isRawShaderMaterial ) {
78419
+ if ( material.uniformsGroups !== undefined ) {
77934
78420
 
77935
78421
  const groups = material.uniformsGroups;
77936
78422
 
@@ -78506,22 +78992,24 @@ void main() {
78506
78992
 
78507
78993
  }
78508
78994
 
78509
- _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, dstTexture.flipY );
78510
- _gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, dstTexture.premultiplyAlpha );
78511
- _gl.pixelStorei( _gl.UNPACK_ALIGNMENT, dstTexture.unpackAlignment );
78995
+ state.activeTexture( _gl.TEXTURE0 ); // see #33153
78996
+
78997
+ state.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, dstTexture.flipY );
78998
+ state.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, dstTexture.premultiplyAlpha );
78999
+ state.pixelStorei( _gl.UNPACK_ALIGNMENT, dstTexture.unpackAlignment );
78512
79000
 
78513
79001
  // used for copying data from cpu
78514
- const currentUnpackRowLen = _gl.getParameter( _gl.UNPACK_ROW_LENGTH );
78515
- const currentUnpackImageHeight = _gl.getParameter( _gl.UNPACK_IMAGE_HEIGHT );
78516
- const currentUnpackSkipPixels = _gl.getParameter( _gl.UNPACK_SKIP_PIXELS );
78517
- const currentUnpackSkipRows = _gl.getParameter( _gl.UNPACK_SKIP_ROWS );
78518
- const currentUnpackSkipImages = _gl.getParameter( _gl.UNPACK_SKIP_IMAGES );
78519
-
78520
- _gl.pixelStorei( _gl.UNPACK_ROW_LENGTH, image.width );
78521
- _gl.pixelStorei( _gl.UNPACK_IMAGE_HEIGHT, image.height );
78522
- _gl.pixelStorei( _gl.UNPACK_SKIP_PIXELS, minX );
78523
- _gl.pixelStorei( _gl.UNPACK_SKIP_ROWS, minY );
78524
- _gl.pixelStorei( _gl.UNPACK_SKIP_IMAGES, minZ );
79002
+ const currentUnpackRowLen = state.getParameter( _gl.UNPACK_ROW_LENGTH );
79003
+ const currentUnpackImageHeight = state.getParameter( _gl.UNPACK_IMAGE_HEIGHT );
79004
+ const currentUnpackSkipPixels = state.getParameter( _gl.UNPACK_SKIP_PIXELS );
79005
+ const currentUnpackSkipRows = state.getParameter( _gl.UNPACK_SKIP_ROWS );
79006
+ const currentUnpackSkipImages = state.getParameter( _gl.UNPACK_SKIP_IMAGES );
79007
+
79008
+ state.pixelStorei( _gl.UNPACK_ROW_LENGTH, image.width );
79009
+ state.pixelStorei( _gl.UNPACK_IMAGE_HEIGHT, image.height );
79010
+ state.pixelStorei( _gl.UNPACK_SKIP_PIXELS, minX );
79011
+ state.pixelStorei( _gl.UNPACK_SKIP_ROWS, minY );
79012
+ state.pixelStorei( _gl.UNPACK_SKIP_IMAGES, minZ );
78525
79013
 
78526
79014
  // set up the src texture
78527
79015
  const isSrc3D = srcTexture.isDataArrayTexture || srcTexture.isData3DTexture;
@@ -78647,11 +79135,11 @@ void main() {
78647
79135
  }
78648
79136
 
78649
79137
  // reset values
78650
- _gl.pixelStorei( _gl.UNPACK_ROW_LENGTH, currentUnpackRowLen );
78651
- _gl.pixelStorei( _gl.UNPACK_IMAGE_HEIGHT, currentUnpackImageHeight );
78652
- _gl.pixelStorei( _gl.UNPACK_SKIP_PIXELS, currentUnpackSkipPixels );
78653
- _gl.pixelStorei( _gl.UNPACK_SKIP_ROWS, currentUnpackSkipRows );
78654
- _gl.pixelStorei( _gl.UNPACK_SKIP_IMAGES, currentUnpackSkipImages );
79138
+ state.pixelStorei( _gl.UNPACK_ROW_LENGTH, currentUnpackRowLen );
79139
+ state.pixelStorei( _gl.UNPACK_IMAGE_HEIGHT, currentUnpackImageHeight );
79140
+ state.pixelStorei( _gl.UNPACK_SKIP_PIXELS, currentUnpackSkipPixels );
79141
+ state.pixelStorei( _gl.UNPACK_SKIP_ROWS, currentUnpackSkipRows );
79142
+ state.pixelStorei( _gl.UNPACK_SKIP_IMAGES, currentUnpackSkipImages );
78655
79143
 
78656
79144
  // Generate mipmaps only when copying level 0
78657
79145
  if ( dstLevel === 0 && dstTexture.generateMipmaps ) {
@@ -78915,6 +79403,7 @@ void main() {
78915
79403
  GreaterStencilFunc: GreaterStencilFunc,
78916
79404
  GridHelper: GridHelper$1,
78917
79405
  Group: Group,
79406
+ HTMLTexture: HTMLTexture,
78918
79407
  HalfFloatType: HalfFloatType,
78919
79408
  HemisphereLight: HemisphereLight,
78920
79409
  HemisphereLightHelper: HemisphereLightHelper,
@@ -80145,7 +80634,7 @@ void main() {
80145
80634
 
80146
80635
  /**
80147
80636
  * The size of the viewport, in screen pixels. This must be kept updated to make
80148
- * screen-space rendering accurate.The `LineSegments2.onBeforeRender` callback
80637
+ * screen-space rendering accurate. The `LineSegments2.onBeforeRender` callback
80149
80638
  * performs the update for visible objects.
80150
80639
  *
80151
80640
  * @type {Vector2}
@@ -83914,8 +84403,9 @@ float metalnessFactor = metalness;
83914
84403
  // Uniform values (captured by closure, per-object)
83915
84404
  const offset = bb.min.clone();
83916
84405
  const scale = 1.0 / maxDim;
83917
- // Read texture repeat from the material's map (all textures share same repeat)
83918
- const repeat = material.map?.repeat?.clone() ?? new Vector2(1, 1);
84406
+ // Read texture repeat from the first available texture map
84407
+ const repeat = (material.map ?? material.roughnessMap ?? material.normalMap ??
84408
+ material.metalnessMap ?? material.emissiveMap ?? material.aoMap)?.repeat?.clone() ?? new Vector2(1, 1);
83919
84409
  material.onBeforeCompile = (shader) => {
83920
84410
  // Custom uniforms
83921
84411
  shader.uniforms.triplanarOffset = { value: offset };
@@ -89069,7 +89559,7 @@ float metalnessFactor = metalness;
89069
89559
  const document = this.domElement.getRootNode(); // offscreen canvas compatibility
89070
89560
  document.addEventListener( 'keydown', this._interceptControlDown, { passive: true, capture: true } );
89071
89561
 
89072
- this.domElement.style.touchAction = 'none'; // disable touch scroll
89562
+ this.domElement.style.touchAction = 'none'; // Disable touch scroll
89073
89563
 
89074
89564
  }
89075
89565
 
@@ -89088,7 +89578,7 @@ float metalnessFactor = metalness;
89088
89578
  const document = this.domElement.getRootNode(); // offscreen canvas compatibility
89089
89579
  document.removeEventListener( 'keydown', this._interceptControlDown, { capture: true } );
89090
89580
 
89091
- this.domElement.style.touchAction = 'auto';
89581
+ this.domElement.style.touchAction = ''; // Restore touch scroll
89092
89582
 
89093
89583
  }
89094
89584
 
@@ -90596,9 +91086,10 @@ float metalnessFactor = metalness;
90596
91086
  */
90597
91087
  dispose() {
90598
91088
  if (this.domElement && this._onCADPointerDown && this._onCADPointerUp) {
90599
- this.domElement.removeEventListener("pointerdown", this._onCADPointerDown);
90600
- this.domElement.removeEventListener("pointerup", this._onCADPointerUp);
90601
- this.domElement.removeEventListener("pointercancel", this._onCADPointerUp);
91089
+ const el = this.domElement;
91090
+ el.removeEventListener("pointerdown", this._onCADPointerDown);
91091
+ el.removeEventListener("pointerup", this._onCADPointerUp);
91092
+ el.removeEventListener("pointercancel", this._onCADPointerUp);
90602
91093
  }
90603
91094
  super.dispose();
90604
91095
  }
@@ -90998,7 +91489,7 @@ float metalnessFactor = metalness;
90998
91489
  this.domElement.addEventListener( 'wheel', this._onMouseWheel, { passive: false } );
90999
91490
  this.domElement.addEventListener( 'contextmenu', this._onContextMenu );
91000
91491
 
91001
- this.domElement.style.touchAction = 'none'; // disable touch scroll
91492
+ this.domElement.style.touchAction = 'none'; // Disable touch scroll
91002
91493
 
91003
91494
  }
91004
91495
 
@@ -91014,7 +91505,7 @@ float metalnessFactor = metalness;
91014
91505
  this.domElement.removeEventListener( 'wheel', this._onMouseWheel );
91015
91506
  this.domElement.removeEventListener( 'contextmenu', this._onContextMenu );
91016
91507
 
91017
- this.domElement.style.touchAction = 'auto'; // disable touch scroll
91508
+ this.domElement.style.touchAction = ''; // Restore touch scroll
91018
91509
 
91019
91510
  }
91020
91511
 
@@ -91938,11 +92429,12 @@ float metalnessFactor = metalness;
91938
92429
  this._holroydPointerMove &&
91939
92430
  this._holroydPointerUp &&
91940
92431
  this._holroydWheel) {
91941
- this.domElement.removeEventListener("pointerdown", this._holroydPointerDown);
91942
- this.domElement.removeEventListener("pointermove", this._holroydPointerMove);
91943
- this.domElement.removeEventListener("pointerup", this._holroydPointerUp);
91944
- this.domElement.removeEventListener("pointercancel", this._holroydPointerUp);
91945
- this.domElement.removeEventListener("wheel", this._holroydWheel);
92432
+ const el = this.domElement;
92433
+ el.removeEventListener("pointerdown", this._holroydPointerDown);
92434
+ el.removeEventListener("pointermove", this._holroydPointerMove);
92435
+ el.removeEventListener("pointerup", this._holroydPointerUp);
92436
+ el.removeEventListener("pointercancel", this._holroydPointerUp);
92437
+ el.removeEventListener("wheel", this._holroydWheel);
91946
92438
  }
91947
92439
  super.dispose();
91948
92440
  }
@@ -94309,7 +94801,7 @@ float metalnessFactor = metalness;
94309
94801
  }
94310
94802
  }
94311
94803
 
94312
- const version = "4.3.6";
94804
+ const version = "4.3.8";
94313
94805
 
94314
94806
  /**
94315
94807
  * Clean room environment for Studio mode PMREM generation.
@@ -94543,7 +95035,7 @@ float metalnessFactor = metalness;
94543
95035
 
94544
95036
  s += chunk; len += chunk.length;
94545
95037
  p += chunkSize;
94546
- chunk += String.fromCharCode.apply( null, new Uint16Array( buffer.subarray( p, p + chunkSize ) ) );
95038
+ chunk = String.fromCharCode.apply( null, new Uint16Array( buffer.subarray( p, p + chunkSize ) ) );
94547
95039
 
94548
95040
  }
94549
95041
 
@@ -95292,6 +95784,14 @@ float metalnessFactor = metalness;
95292
95784
  constructor(options = {}) {
95293
95785
  /** Cached PMREM render targets keyed by environment name or URL */
95294
95786
  this._cache = new Map();
95787
+ /**
95788
+ * Cached raw equirectangular HDR textures keyed by the same name/URL.
95789
+ * Preserved (not disposed after PMREM generation) so `scene.background`
95790
+ * can sample the original HDR at full source resolution instead of the
95791
+ * 256² PMREM cubemap. Only populated by `_loadHdr` — procedural
95792
+ * environments have no source HDR.
95793
+ */
95794
+ this._hdrCache = new Map();
95295
95795
  /** Cached light detection results keyed by environment name or URL */
95296
95796
  this._lightDetectionCache = new Map();
95297
95797
  /** In-flight load promises keyed by environment name or URL */
@@ -95306,6 +95806,13 @@ float metalnessFactor = metalness;
95306
95806
  this._hdrLoader = null;
95307
95807
  /** The last loaded PMREM texture (stateful — used by apply() for IBL) */
95308
95808
  this._currentTexture = null;
95809
+ /**
95810
+ * Raw HDR texture corresponding to `_currentTexture`, used for
95811
+ * `scene.background` to keep the backdrop at source resolution. Null when
95812
+ * the current environment is procedural ("studio" RoomEnvironment) — in
95813
+ * that case the background falls back to `_currentTexture` (the PMREM).
95814
+ */
95815
+ this._currentBackgroundTexture = null;
95309
95816
  /** Whether this manager has been disposed */
95310
95817
  this._disposed = false;
95311
95818
  /**
@@ -95359,6 +95866,7 @@ float metalnessFactor = metalness;
95359
95866
  }
95360
95867
  if (name === "none") {
95361
95868
  this._currentTexture = null;
95869
+ this._currentBackgroundTexture = null;
95362
95870
  return null;
95363
95871
  }
95364
95872
  // Check cache first (name is the cache key for presets; URL string for custom)
@@ -95367,6 +95875,7 @@ float metalnessFactor = metalness;
95367
95875
  if (cached) {
95368
95876
  logger.debug(`Environment "${cacheKey}" loaded from cache`);
95369
95877
  this._currentTexture = cached.texture;
95878
+ this._currentBackgroundTexture = this._hdrCache.get(cacheKey) ?? null;
95370
95879
  return cached.texture;
95371
95880
  }
95372
95881
  // Check in-flight promise — await and set _currentTexture
@@ -95375,6 +95884,7 @@ float metalnessFactor = metalness;
95375
95884
  logger.debug(`Environment "${cacheKey}" already loading, reusing promise`);
95376
95885
  const texture = await inflight;
95377
95886
  this._currentTexture = texture;
95887
+ this._currentBackgroundTexture = this._hdrCache.get(cacheKey) ?? null;
95378
95888
  return texture;
95379
95889
  }
95380
95890
  // Start new load
@@ -95383,6 +95893,7 @@ float metalnessFactor = metalness;
95383
95893
  try {
95384
95894
  const texture = await promise;
95385
95895
  this._currentTexture = texture;
95896
+ this._currentBackgroundTexture = this._hdrCache.get(cacheKey) ?? null;
95386
95897
  // Self-healing: if apply() was called with "environment" background
95387
95898
  // while texture was null, re-apply now that the texture is ready.
95388
95899
  if (this._deferredApply) {
@@ -95460,9 +95971,13 @@ float metalnessFactor = metalness;
95460
95971
  break;
95461
95972
  case "environment":
95462
95973
  if (this._currentTexture) {
95974
+ // Prefer the raw HDR for the background so the backdrop samples
95975
+ // at source resolution (2K/4K) rather than the 256² PMREM cubemap.
95976
+ // Falls back to PMREM for procedural "studio" (no source HDR).
95977
+ const bgTex = this._currentBackgroundTexture ?? this._currentTexture;
95463
95978
  // Always use render-to-texture with a fixed-FOV bgCamera so the
95464
95979
  // background zoom level is identical in perspective and ortho modes.
95465
- this._setupEnvBackground(scene, this._currentTexture, upIsZ, rotY);
95980
+ this._setupEnvBackground(scene, bgTex, upIsZ, rotY);
95466
95981
  this._deferredApply = null;
95467
95982
  }
95468
95983
  else {
@@ -95547,6 +96062,12 @@ float metalnessFactor = metalness;
95547
96062
  this._lightDetectionCache.delete(slug);
95548
96063
  logger.debug(`Evicted cached environment "${slug}" for resolution switch`);
95549
96064
  }
96065
+ const cachedHdr = this._hdrCache.get(slug);
96066
+ if (cachedHdr) {
96067
+ gpuTracker.untrack("texture", cachedHdr);
96068
+ cachedHdr.dispose();
96069
+ this._hdrCache.delete(slug);
96070
+ }
95550
96071
  }
95551
96072
  // Reload the current environment at the new resolution
95552
96073
  if (currentEnvName && currentEnvName !== "none" && currentEnvName !== "studio") {
@@ -95645,6 +96166,7 @@ float metalnessFactor = metalness;
95645
96166
  dispose() {
95646
96167
  this._disposed = true;
95647
96168
  this._currentTexture = null;
96169
+ this._currentBackgroundTexture = null;
95648
96170
  this._deferredApply = null;
95649
96171
  this._teardownEnvBackground();
95650
96172
  this._bgScene = null;
@@ -95660,6 +96182,13 @@ float metalnessFactor = metalness;
95660
96182
  logger.debug(`Disposed cached environment render target: ${key}`);
95661
96183
  }
95662
96184
  this._cache.clear();
96185
+ // Dispose all cached raw HDR textures
96186
+ for (const [key, hdrTexture] of this._hdrCache) {
96187
+ gpuTracker.untrack("texture", hdrTexture);
96188
+ hdrTexture.dispose();
96189
+ logger.debug(`Disposed cached HDR background: ${key}`);
96190
+ }
96191
+ this._hdrCache.clear();
95663
96192
  this._lightDetectionCache.clear();
95664
96193
  // Clear in-flight promises (they'll resolve but won't be cached)
95665
96194
  this._inflight.clear();
@@ -95814,9 +96343,10 @@ float metalnessFactor = metalness;
95814
96343
  * Load an HDR file and generate a PMREM texture from it.
95815
96344
  *
95816
96345
  * Uses HDRLoader to fetch the .hdr file, then PMREMGenerator.fromEquirectangular()
95817
- * to create the PMREM cubemap. The source equirectangular texture is disposed
95818
- * after PMREM generation. The PMREM texture itself serves as both the IBL
95819
- * environment and the background (in "environment" mode).
96346
+ * to create the PMREM cubemap for IBL. The source equirectangular HDR is
96347
+ * preserved and cached separately (in `_hdrCache`) so that "environment"
96348
+ * background mode can sample the full-resolution equirectangular texture
96349
+ * instead of the 256² PMREM cubemap.
95820
96350
  *
95821
96351
  * @param url - URL of the .hdr file
95822
96352
  * @param cacheKey - Cache key for the resulting PMREM render target
@@ -95846,11 +96376,15 @@ float metalnessFactor = metalness;
95846
96376
  const result = detectDominantLights(hdrTexture.image.data, hdrTexture.image.width, hdrTexture.image.height);
95847
96377
  this._lightDetectionCache.set(cacheKey, result);
95848
96378
  }
95849
- // Dispose the source equirectangular texture (PMREM is now in GPU memory).
95850
- hdrTexture.dispose();
95851
- // Cache render target and track its texture
96379
+ // Preserve the equirectangular HDR for use as `scene.background` at
96380
+ // source resolution. PMREM's base mip is a 256² cubemap — good for IBL
96381
+ // (roughness-weighted prefilter) but visibly soft as a backdrop.
96382
+ hdrTexture.mapping = EquirectangularReflectionMapping;
96383
+ // Cache render target and HDR; track both.
95852
96384
  this._cache.set(cacheKey, renderTarget);
96385
+ this._hdrCache.set(cacheKey, hdrTexture);
95853
96386
  gpuTracker.trackTexture(renderTarget.texture, `PMREM environment: ${cacheKey}`);
96387
+ gpuTracker.trackTexture(hdrTexture, `HDR background: ${cacheKey}`);
95854
96388
  logger.debug(`Loaded HDR environment from "${url}", cached as "${cacheKey}"`);
95855
96389
  return renderTarget.texture;
95856
96390
  }
@@ -95958,104 +96492,12 @@ float metalnessFactor = metalness;
95958
96492
  }
95959
96493
 
95960
96494
  /**
95961
- * postprocessing v6.38.3 build Thu Feb 19 2026
96495
+ * postprocessing v6.39.0 build Fri Mar 20 2026
95962
96496
  * https://github.com/pmndrs/postprocessing
95963
96497
  * Copyright 2015-2026 Raoul van Rüschen
95964
96498
  * @license Zlib
95965
96499
  */
95966
96500
 
95967
-
95968
- // src/core/Timer.js
95969
- var MILLISECONDS_TO_SECONDS = 1 / 1e3;
95970
- var SECONDS_TO_MILLISECONDS = 1e3;
95971
- var Timer = class {
95972
- /**
95973
- * Constructs a new timer.
95974
- */
95975
- constructor() {
95976
- this.startTime = performance.now();
95977
- this.previousTime = 0;
95978
- this.currentTime = 0;
95979
- this._delta = 0;
95980
- this._elapsed = 0;
95981
- this._fixedDelta = 1e3 / 60;
95982
- this.timescale = 1;
95983
- this.useFixedDelta = false;
95984
- this._autoReset = false;
95985
- }
95986
- /**
95987
- * Enables or disables auto reset based on page visibility.
95988
- *
95989
- * If enabled, the timer will be reset when the page becomes visible. This effectively pauses the timer when the page
95990
- * is hidden. Has no effect if the API is not supported.
95991
- *
95992
- * @type {Boolean}
95993
- * @see https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibility_API
95994
- */
95995
- get autoReset() {
95996
- return this._autoReset;
95997
- }
95998
- set autoReset(value) {
95999
- if (typeof document !== "undefined" && document.hidden !== void 0) {
96000
- if (value) {
96001
- document.addEventListener("visibilitychange", this);
96002
- } else {
96003
- document.removeEventListener("visibilitychange", this);
96004
- }
96005
- this._autoReset = value;
96006
- }
96007
- }
96008
- get delta() {
96009
- return this._delta * MILLISECONDS_TO_SECONDS;
96010
- }
96011
- get fixedDelta() {
96012
- return this._fixedDelta * MILLISECONDS_TO_SECONDS;
96013
- }
96014
- set fixedDelta(value) {
96015
- this._fixedDelta = value * SECONDS_TO_MILLISECONDS;
96016
- }
96017
- get elapsed() {
96018
- return this._elapsed * MILLISECONDS_TO_SECONDS;
96019
- }
96020
- /**
96021
- * Updates this timer.
96022
- *
96023
- * @param {Boolean} [timestamp] - The current time in milliseconds.
96024
- */
96025
- update(timestamp) {
96026
- if (this.useFixedDelta) {
96027
- this._delta = this.fixedDelta;
96028
- } else {
96029
- this.previousTime = this.currentTime;
96030
- this.currentTime = (timestamp !== void 0 ? timestamp : performance.now()) - this.startTime;
96031
- this._delta = this.currentTime - this.previousTime;
96032
- }
96033
- this._delta *= this.timescale;
96034
- this._elapsed += this._delta;
96035
- }
96036
- /**
96037
- * Resets this timer.
96038
- */
96039
- reset() {
96040
- this._delta = 0;
96041
- this._elapsed = 0;
96042
- this.currentTime = performance.now() - this.startTime;
96043
- }
96044
- getDelta() {
96045
- return this.delta;
96046
- }
96047
- getElapsed() {
96048
- return this.elapsed;
96049
- }
96050
- handleEvent(e) {
96051
- if (!document.hidden) {
96052
- this.currentTime = performance.now() - this.startTime;
96053
- }
96054
- }
96055
- dispose() {
96056
- this.autoReset = false;
96057
- }
96058
- };
96059
96501
  var fullscreenGeometry = /* @__PURE__ */ (() => {
96060
96502
  const vertices = new Float32Array([-1, -1, 0, 3, -1, 0, -1, 3, 0]);
96061
96503
  const uvs = new Float32Array([0, 0, 2, 0, 0, 2]);
@@ -96091,6 +96533,7 @@ float metalnessFactor = metalness;
96091
96533
  this.screen = null;
96092
96534
  this.rtt = true;
96093
96535
  this.needsSwap = true;
96536
+ this.needsDepthBlit = false;
96094
96537
  this.needsDepthTexture = false;
96095
96538
  this.enabled = true;
96096
96539
  }
@@ -96817,6 +97260,98 @@ gl_FragDepth=readDepth(vUv);
96817
97260
  }
96818
97261
  };
96819
97262
 
97263
+ // src/core/Timer.js
97264
+ var MILLISECONDS_TO_SECONDS = 1 / 1e3;
97265
+ var SECONDS_TO_MILLISECONDS = 1e3;
97266
+ var Timer = class {
97267
+ /**
97268
+ * Constructs a new timer.
97269
+ */
97270
+ constructor() {
97271
+ this.startTime = performance.now();
97272
+ this.previousTime = 0;
97273
+ this.currentTime = 0;
97274
+ this._delta = 0;
97275
+ this._elapsed = 0;
97276
+ this._fixedDelta = 1e3 / 60;
97277
+ this.timescale = 1;
97278
+ this.useFixedDelta = false;
97279
+ this._autoReset = false;
97280
+ }
97281
+ /**
97282
+ * Enables or disables auto reset based on page visibility.
97283
+ *
97284
+ * If enabled, the timer will be reset when the page becomes visible. This effectively pauses the timer when the page
97285
+ * is hidden. Has no effect if the API is not supported.
97286
+ *
97287
+ * @type {Boolean}
97288
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibility_API
97289
+ */
97290
+ get autoReset() {
97291
+ return this._autoReset;
97292
+ }
97293
+ set autoReset(value) {
97294
+ if (typeof document !== "undefined" && document.hidden !== void 0) {
97295
+ if (value) {
97296
+ document.addEventListener("visibilitychange", this);
97297
+ } else {
97298
+ document.removeEventListener("visibilitychange", this);
97299
+ }
97300
+ this._autoReset = value;
97301
+ }
97302
+ }
97303
+ get delta() {
97304
+ return this._delta * MILLISECONDS_TO_SECONDS;
97305
+ }
97306
+ get fixedDelta() {
97307
+ return this._fixedDelta * MILLISECONDS_TO_SECONDS;
97308
+ }
97309
+ set fixedDelta(value) {
97310
+ this._fixedDelta = value * SECONDS_TO_MILLISECONDS;
97311
+ }
97312
+ get elapsed() {
97313
+ return this._elapsed * MILLISECONDS_TO_SECONDS;
97314
+ }
97315
+ /**
97316
+ * Updates this timer.
97317
+ *
97318
+ * @param {Boolean} [timestamp] - The current time in milliseconds.
97319
+ */
97320
+ update(timestamp) {
97321
+ if (this.useFixedDelta) {
97322
+ this._delta = this.fixedDelta;
97323
+ } else {
97324
+ this.previousTime = this.currentTime;
97325
+ this.currentTime = (timestamp !== void 0 ? timestamp : performance.now()) - this.startTime;
97326
+ this._delta = this.currentTime - this.previousTime;
97327
+ }
97328
+ this._delta *= this.timescale;
97329
+ this._elapsed += this._delta;
97330
+ }
97331
+ /**
97332
+ * Resets this timer.
97333
+ */
97334
+ reset() {
97335
+ this._delta = 0;
97336
+ this._elapsed = 0;
97337
+ this.currentTime = performance.now() - this.startTime;
97338
+ }
97339
+ getDelta() {
97340
+ return this.delta;
97341
+ }
97342
+ getElapsed() {
97343
+ return this.elapsed;
97344
+ }
97345
+ handleEvent(e) {
97346
+ if (!document.hidden) {
97347
+ this.currentTime = performance.now() - this.startTime;
97348
+ }
97349
+ }
97350
+ dispose() {
97351
+ this.autoReset = false;
97352
+ }
97353
+ };
97354
+
96820
97355
  // src/core/EffectComposer.js
96821
97356
  var EffectComposer = class {
96822
97357
  /**
@@ -96826,7 +97361,6 @@ gl_FragDepth=readDepth(vUv);
96826
97361
  * @param {Object} [options] - The options.
96827
97362
  * @param {Boolean} [options.depthBuffer=true] - Whether the main render targets should have a depth buffer.
96828
97363
  * @param {Boolean} [options.stencilBuffer=false] - Whether the main render targets should have a stencil buffer.
96829
- * @param {Boolean} [options.alpha] - Deprecated. Buffers are always RGBA since three r137.
96830
97364
  * @param {Number} [options.multisampling=0] - The number of samples used for multisample antialiasing. Requires WebGL 2.
96831
97365
  * @param {Number} [options.frameBufferType] - The type of the internal frame buffers. It's recommended to use HalfFloatType if possible.
96832
97366
  */
@@ -96841,6 +97375,7 @@ gl_FragDepth=readDepth(vUv);
96841
97375
  this.outputBuffer = this.inputBuffer.clone();
96842
97376
  this.copyPass = new CopyPass();
96843
97377
  this.depthTexture = null;
97378
+ this.depthRenderTarget = null;
96844
97379
  this.passes = [];
96845
97380
  this.timer = new Timer();
96846
97381
  this.autoRenderToScreen = true;
@@ -96852,7 +97387,7 @@ gl_FragDepth=readDepth(vUv);
96852
97387
  * @type {Number}
96853
97388
  */
96854
97389
  get multisampling() {
96855
- return this.inputBuffer.samples || 0;
97390
+ return this.inputBuffer.samples;
96856
97391
  }
96857
97392
  /**
96858
97393
  * Sets the amount of MSAA samples.
@@ -96878,7 +97413,6 @@ gl_FragDepth=readDepth(vUv);
96878
97413
  buffer.texture.type,
96879
97414
  value
96880
97415
  );
96881
- this.inputBuffer.depthTexture = this.depthTexture;
96882
97416
  this.outputBuffer = this.inputBuffer.clone();
96883
97417
  }
96884
97418
  }
@@ -96949,23 +97483,65 @@ gl_FragDepth=readDepth(vUv);
96949
97483
  /**
96950
97484
  * Creates a depth texture attachment that will be provided to all passes.
96951
97485
  *
96952
- * Note: When a shader reads from a depth texture and writes to a render target that uses the same depth texture
96953
- * attachment, the depth information will be lost. This happens even if `depthWrite` is disabled.
97486
+ * To prevent errors or incorrect behavior when the same depth buffer is attached to the input and output buffers,
97487
+ * a separate stable depth target is created alongside the ping-pong buffers. All passes receive the stable target's
97488
+ * depth texture, which is never used as a render output and therefore cannot create a feedback loop. The stable
97489
+ * texture is populated each frame via blitFramebuffer immediately before the first buffer swap.
96954
97490
  *
96955
97491
  * @private
96956
- * @return {DepthTexture} The depth texture.
97492
+ * @return {DepthTexture} The stable depth texture distributed to passes.
96957
97493
  */
96958
97494
  createDepthTexture() {
96959
- const depthTexture = this.depthTexture = new DepthTexture();
96960
- this.inputBuffer.depthTexture = depthTexture;
96961
- this.inputBuffer.dispose();
96962
- if (this.inputBuffer.stencilBuffer) {
97495
+ const inputBuffer = this.inputBuffer;
97496
+ const depthTexture = new DepthTexture();
97497
+ this.depthTexture = depthTexture;
97498
+ if (inputBuffer.stencilBuffer) {
96963
97499
  depthTexture.format = DepthStencilFormat;
96964
97500
  depthTexture.type = UnsignedInt248Type;
96965
97501
  } else {
96966
- depthTexture.type = UnsignedIntType;
96967
- }
96968
- return depthTexture;
97502
+ depthTexture.type = FloatType;
97503
+ }
97504
+ const stableDepthTexture = depthTexture.clone();
97505
+ stableDepthTexture.name = "EffectComposer.StableDepth";
97506
+ this.depthRenderTarget = new WebGLRenderTarget(inputBuffer.width, inputBuffer.height, {
97507
+ depthBuffer: true,
97508
+ stencilBuffer: inputBuffer.stencilBuffer,
97509
+ depthTexture: stableDepthTexture
97510
+ });
97511
+ return stableDepthTexture;
97512
+ }
97513
+ /**
97514
+ * Copies the depth buffer from the src render target into the stable depth target.
97515
+ *
97516
+ * @private
97517
+ * @param {WebGLRenderTarget} renderTarget - The render target whose depth buffer should be copied.
97518
+ */
97519
+ blitDepthBuffer(renderTarget) {
97520
+ const renderer = this.renderer;
97521
+ const depthRenderTarget = this.depthRenderTarget;
97522
+ const props = renderer.properties;
97523
+ const gl = renderer.getContext();
97524
+ renderer.setRenderTarget(depthRenderTarget);
97525
+ const srcFBO = props.get(renderTarget).__webglFramebuffer;
97526
+ const dstFBO = props.get(depthRenderTarget).__webglFramebuffer;
97527
+ const blitMask = renderTarget.stencilBuffer ? gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT : gl.DEPTH_BUFFER_BIT;
97528
+ gl.bindFramebuffer(gl.READ_FRAMEBUFFER, srcFBO);
97529
+ gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, dstFBO);
97530
+ gl.blitFramebuffer(
97531
+ 0,
97532
+ 0,
97533
+ renderTarget.width,
97534
+ renderTarget.height,
97535
+ 0,
97536
+ 0,
97537
+ depthRenderTarget.width,
97538
+ depthRenderTarget.height,
97539
+ blitMask,
97540
+ gl.NEAREST
97541
+ );
97542
+ gl.bindFramebuffer(gl.READ_FRAMEBUFFER, null);
97543
+ gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null);
97544
+ renderer.setRenderTarget(null);
96969
97545
  }
96970
97546
  /**
96971
97547
  * Deletes the current depth texture.
@@ -96976,8 +97552,10 @@ gl_FragDepth=readDepth(vUv);
96976
97552
  if (this.depthTexture !== null) {
96977
97553
  this.depthTexture.dispose();
96978
97554
  this.depthTexture = null;
97555
+ this.depthRenderTarget.dispose();
97556
+ this.depthRenderTarget = null;
96979
97557
  this.inputBuffer.depthTexture = null;
96980
- this.inputBuffer.dispose();
97558
+ this.outputBuffer.depthTexture = null;
96981
97559
  for (const pass of this.passes) {
96982
97560
  pass.setDepthTexture(null);
96983
97561
  }
@@ -96986,7 +97564,7 @@ gl_FragDepth=readDepth(vUv);
96986
97564
  /**
96987
97565
  * Creates a new render target.
96988
97566
  *
96989
- * @deprecated Create buffers manually via WebGLRenderTarget instead.
97567
+ * @private
96990
97568
  * @param {Boolean} depthBuffer - Whether the render target should have a depth buffer.
96991
97569
  * @param {Boolean} stencilBuffer - Whether the render target should have a stencil buffer.
96992
97570
  * @param {Number} type - The frame buffer type.
@@ -97046,7 +97624,7 @@ gl_FragDepth=readDepth(vUv);
97046
97624
  const drawingBufferSize = renderer.getDrawingBufferSize(new Vector2());
97047
97625
  const alpha = renderer.getContext().getContextAttributes().alpha;
97048
97626
  const frameBufferType = this.inputBuffer.texture.type;
97049
- pass.setRenderer(renderer);
97627
+ pass.renderer = renderer;
97050
97628
  pass.setSize(drawingBufferSize.width, drawingBufferSize.height);
97051
97629
  pass.initialize(renderer, alpha, frameBufferType);
97052
97630
  if (this.autoRenderToScreen) {
@@ -97067,12 +97645,13 @@ gl_FragDepth=readDepth(vUv);
97067
97645
  }
97068
97646
  if (pass.needsDepthTexture || this.depthTexture !== null) {
97069
97647
  if (this.depthTexture === null) {
97070
- const depthTexture = this.createDepthTexture();
97648
+ const stableDepthTexture = this.createDepthTexture();
97071
97649
  for (pass of passes) {
97072
- pass.setDepthTexture(depthTexture);
97650
+ pass.setDepthTexture(stableDepthTexture);
97073
97651
  }
97074
97652
  } else {
97075
- pass.setDepthTexture(this.depthTexture);
97653
+ const stableDepthTexture = this.depthRenderTarget.depthTexture;
97654
+ pass.setDepthTexture(stableDepthTexture);
97076
97655
  }
97077
97656
  }
97078
97657
  }
@@ -97091,7 +97670,8 @@ gl_FragDepth=readDepth(vUv);
97091
97670
  const reducer = (a, b) => a || b.needsDepthTexture;
97092
97671
  const depthTextureRequired = passes.reduce(reducer, false);
97093
97672
  if (!depthTextureRequired) {
97094
- if (pass.getDepthTexture() === this.depthTexture) {
97673
+ const stableDepthTexture = this.depthRenderTarget.depthTexture;
97674
+ if (pass.getDepthTexture() === stableDepthTexture) {
97095
97675
  pass.setDepthTexture(null);
97096
97676
  }
97097
97677
  this.deleteDepthTexture();
@@ -97130,34 +97710,42 @@ gl_FragDepth=readDepth(vUv);
97130
97710
  const copyPass = this.copyPass;
97131
97711
  let inputBuffer = this.inputBuffer;
97132
97712
  let outputBuffer = this.outputBuffer;
97713
+ let buffer;
97133
97714
  let stencilTest = false;
97134
- let context, stencil, buffer;
97135
97715
  if (deltaTime === void 0) {
97136
97716
  this.timer.update();
97137
97717
  deltaTime = this.timer.getDelta();
97138
97718
  }
97139
97719
  for (const pass of this.passes) {
97140
- if (pass.enabled) {
97141
- pass.render(renderer, inputBuffer, outputBuffer, deltaTime, stencilTest);
97142
- if (pass.needsSwap) {
97143
- if (stencilTest) {
97144
- copyPass.renderToScreen = pass.renderToScreen;
97145
- context = renderer.getContext();
97146
- stencil = renderer.state.buffers.stencil;
97147
- stencil.setFunc(context.NOTEQUAL, 1, 4294967295);
97148
- copyPass.render(renderer, inputBuffer, outputBuffer, deltaTime, stencilTest);
97149
- stencil.setFunc(context.EQUAL, 1, 4294967295);
97150
- }
97151
- buffer = inputBuffer;
97152
- inputBuffer = outputBuffer;
97153
- outputBuffer = buffer;
97154
- }
97155
- if (pass instanceof MaskPass) {
97156
- stencilTest = true;
97157
- } else if (pass instanceof ClearMaskPass) {
97158
- stencilTest = false;
97720
+ if (!pass.enabled) {
97721
+ continue;
97722
+ }
97723
+ inputBuffer.depthTexture = this.depthTexture;
97724
+ outputBuffer.depthTexture = null;
97725
+ pass.render(renderer, inputBuffer, outputBuffer, deltaTime, stencilTest);
97726
+ if (pass.needsDepthBlit) {
97727
+ if (this.depthRenderTarget !== null) {
97728
+ this.blitDepthBuffer(inputBuffer);
97159
97729
  }
97160
97730
  }
97731
+ if (pass.needsSwap) {
97732
+ if (stencilTest) {
97733
+ copyPass.renderToScreen = pass.renderToScreen;
97734
+ const context = renderer.getContext();
97735
+ const stencil = renderer.state.buffers.stencil;
97736
+ stencil.setFunc(context.NOTEQUAL, 1, 4294967295);
97737
+ copyPass.render(renderer, inputBuffer, outputBuffer, deltaTime, stencilTest);
97738
+ stencil.setFunc(context.EQUAL, 1, 4294967295);
97739
+ }
97740
+ buffer = inputBuffer;
97741
+ inputBuffer = outputBuffer;
97742
+ outputBuffer = buffer;
97743
+ }
97744
+ if (pass instanceof MaskPass) {
97745
+ stencilTest = true;
97746
+ } else if (pass instanceof ClearMaskPass) {
97747
+ stencilTest = false;
97748
+ }
97161
97749
  }
97162
97750
  }
97163
97751
  /**
@@ -97180,6 +97768,9 @@ gl_FragDepth=readDepth(vUv);
97180
97768
  const drawingBufferSize = renderer.getDrawingBufferSize(new Vector2());
97181
97769
  this.inputBuffer.setSize(drawingBufferSize.width, drawingBufferSize.height);
97182
97770
  this.outputBuffer.setSize(drawingBufferSize.width, drawingBufferSize.height);
97771
+ if (this.depthRenderTarget !== null) {
97772
+ this.depthRenderTarget.setSize(drawingBufferSize.width, drawingBufferSize.height);
97773
+ }
97183
97774
  for (const pass of this.passes) {
97184
97775
  pass.setSize(drawingBufferSize.width, drawingBufferSize.height);
97185
97776
  }
@@ -99106,6 +99697,7 @@ gl_FragColor=vec4(l*mask);
99106
99697
  constructor(scene, camera, overrideMaterial = null) {
99107
99698
  super("RenderPass", scene, camera);
99108
99699
  this.needsSwap = false;
99700
+ this.needsDepthBlit = true;
99109
99701
  this.clearPass = new ClearPass();
99110
99702
  this.overrideMaterialManager = overrideMaterial === null ? null : new OverrideMaterialManager(overrideMaterial);
99111
99703
  this.ignoreBackground = false;
@@ -104417,7 +105009,18 @@ void mainImage(const in vec4 inputColor, const in vec2 uv, const in float depth,
104417
105009
  }
104418
105010
  // 3. Load environment map
104419
105011
  const envName = state.get("studioEnvironment");
104420
- await this.envManager.loadEnvironment(envName, renderer);
105012
+ // Sync envManager's 4K setting with state. updateStudioState() writes
105013
+ // studio4kEnvMaps silently (notify=false), so the subscription that
105014
+ // normally forwards this to envManager never fires on initial load.
105015
+ // Without this sync, envManager keeps its default (2K) and loads the
105016
+ // wrong URL even though the checkbox reads "checked".
105017
+ const want4k = state.get("studio4kEnvMaps");
105018
+ if (want4k !== this.envManager.use4kEnvMaps) {
105019
+ await this.envManager.setUse4kEnvMaps(want4k, envName, renderer);
105020
+ }
105021
+ else {
105022
+ await this.envManager.loadEnvironment(envName, renderer);
105023
+ }
104421
105024
  if (!this._active)
104422
105025
  return;
104423
105026
  // 4. Apply ALL rendering changes atomically
@@ -104828,8 +105431,13 @@ void mainImage(const in vec4 inputColor, const in vec2 uv, const in float depth,
104828
105431
  const nestedGroup = this._ctx.getNestedGroup();
104829
105432
  if (enabled) {
104830
105433
  this._configureShadowLights();
105434
+ // Back-face meshes share geometry with front meshes but use a
105435
+ // MeshBasicMaterial without alphaMap/alphaTest, so letting them cast
105436
+ // shadows overrides the front mesh's alpha-tested silhouette with a
105437
+ // solid one. The front material is DoubleSide when alphaMap is set,
105438
+ // so its shadow pass already covers both sides of the geometry.
104831
105439
  nestedGroup.rootGroup?.traverse((obj) => {
104832
- if (obj instanceof Mesh) {
105440
+ if (obj instanceof Mesh && obj.material.name !== "backMaterial") {
104833
105441
  obj.castShadow = true;
104834
105442
  }
104835
105443
  });
@@ -107054,6 +107662,11 @@ void mainImage(const in vec4 inputColor, const in vec2 uv, const in float depth,
107054
107662
  // leaveStudioMode() runs here, while _rendered and scene are still valid.
107055
107663
  // Do NOT move this after deepDispose(scene).
107056
107664
  this.state.set("activeTab", "tree");
107665
+ // Outer-cycle boundary: drop Material Editor deltas that were just
107666
+ // saved by the switchToTab("tree", "studio") path above. Those deltas
107667
+ // are meant to survive mid-cycle tab switches within one scene, not a
107668
+ // full scene re-render. See Display.clearMaterialEditorSession.
107669
+ this.display.clearMaterialEditorSession();
107057
107670
  // clear render canvas
107058
107671
  this.renderer.clear();
107059
107672
  // deselect measurement tools
@@ -108592,6 +109205,15 @@ void mainImage(const in vec4 inputColor, const in vec2 uv, const in float depth,
108592
109205
  if (flag === isExplodeActive)
108593
109206
  return;
108594
109207
  if (flag) {
109208
+ // Mirror the UI button-group exclusivity: activating explode must
109209
+ // deactivate any active measurement/selection tool. activateTool()
109210
+ // already clears animationMode in the reverse direction; this makes
109211
+ // the API path symmetric with a UI click. Goes through display.setTool
109212
+ // so cadTools/raycaster/picker get fully cleaned up.
109213
+ const currentTool = this.state.get("activeTool");
109214
+ if (currentTool) {
109215
+ this.display.setTool(currentTool, false);
109216
+ }
108595
109217
  if (this.hasAnimation()) {
108596
109218
  this.backupAnimation();
108597
109219
  }
@@ -108620,12 +109242,19 @@ void mainImage(const in vec4 inputColor, const in vec2 uv, const in float depth,
108620
109242
  activateTool(name, flag) {
108621
109243
  const currentTool = this.state.get("activeTool");
108622
109244
  if (flag) {
108623
- // Activating a tool
109245
+ // Activating a tool implicitly turns off explode (animationMode → "none").
109246
+ // Emit the explode=false notification so consumers don't keep a stale
109247
+ // explode=true in their reported state — otherwise the next render that
109248
+ // echoes back combined_config will set explode back on.
109249
+ const wasExplode = this.state.get("animationMode") === "explode";
108624
109250
  this.state.set("animationMode", "none");
108625
109251
  if (this.hasAnimation()) {
108626
109252
  this.backupAnimation();
108627
109253
  }
108628
109254
  this.state.set("activeTool", name);
109255
+ if (wasExplode) {
109256
+ this.checkChanges({ explode: false });
109257
+ }
108629
109258
  }
108630
109259
  else {
108631
109260
  // Deactivating a tool
@@ -111286,6 +111915,17 @@ void mainImage(const in vec4 inputColor, const in vec2 uv, const in float depth,
111286
111915
  }
111287
111916
  this._matEditorClones.clear();
111288
111917
  }
111918
+ /**
111919
+ * Outer-cycle boundary: discard saved Material Editor deltas so they don't
111920
+ * replay on the next Studio entry in a new scene. Unlike viewer preferences
111921
+ * (transparent, axes, grid) which persist across render cycles, Material
111922
+ * Editor edits are per-scene PBR authoring and must reset on scene rebuild.
111923
+ * Mid-cycle (Studio tab leave/enter) and inner-cycle (editor close/reopen)
111924
+ * behavior is unaffected — this is only called from viewer.clear().
111925
+ */
111926
+ clearMaterialEditorSession() {
111927
+ this._savedMatEditorChanges.clear();
111928
+ }
111289
111929
  /** Save material editor property deltas so they survive a Studio mode leave/enter cycle. */
111290
111930
  _saveMatEditorChanges() {
111291
111931
  this._savedMatEditorChanges.clear();