super-three 0.170.0 → 0.170.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (172) hide show
  1. package/build/three.cjs +24410 -24422
  2. package/build/three.core.js +37002 -0
  3. package/build/three.core.min.js +6 -0
  4. package/build/three.module.js +10573 -47578
  5. package/build/three.module.min.js +1 -1
  6. package/build/three.tsl.js +533 -0
  7. package/build/three.tsl.min.js +6 -0
  8. package/build/three.webgpu.js +2907 -37975
  9. package/build/three.webgpu.min.js +1 -1
  10. package/build/three.webgpu.nodes.js +2914 -37959
  11. package/build/three.webgpu.nodes.min.js +1 -1
  12. package/examples/jsm/capabilities/WebGPU.js +1 -10
  13. package/examples/jsm/controls/ArcballControls.js +25 -21
  14. package/examples/jsm/controls/OrbitControls.js +41 -9
  15. package/examples/jsm/controls/PointerLockControls.js +2 -5
  16. package/examples/jsm/csm/CSMShadowNode.js +7 -5
  17. package/examples/jsm/geometries/DecalGeometry.js +5 -1
  18. package/examples/jsm/lighting/TiledLighting.js +1 -1
  19. package/examples/jsm/lines/LineGeometry.js +25 -0
  20. package/examples/jsm/lines/LineMaterial.js +1 -7
  21. package/examples/jsm/lines/webgpu/Line2.js +2 -1
  22. package/examples/jsm/lines/webgpu/LineSegments2.js +2 -1
  23. package/examples/jsm/lines/webgpu/Wireframe.js +2 -1
  24. package/examples/jsm/loaders/KTX2Loader.js +3 -0
  25. package/examples/jsm/loaders/MMDLoader.js +2 -6
  26. package/examples/jsm/loaders/MaterialXLoader.js +2 -2
  27. package/examples/jsm/materials/MeshGouraudMaterial.js +2 -6
  28. package/examples/jsm/misc/ProgressiveLightMapGPU.js +2 -2
  29. package/examples/jsm/objects/InstancedPoints.js +2 -4
  30. package/examples/jsm/objects/LensflareMesh.js +4 -2
  31. package/examples/jsm/objects/SkyMesh.js +5 -3
  32. package/examples/jsm/objects/Water2Mesh.js +7 -3
  33. package/examples/jsm/objects/WaterMesh.js +5 -3
  34. package/examples/jsm/transpiler/AST.js +2 -2
  35. package/examples/jsm/transpiler/GLSLDecoder.js +57 -25
  36. package/examples/jsm/transpiler/TSLEncoder.js +11 -6
  37. package/examples/jsm/tsl/display/AfterImageNode.js +3 -3
  38. package/examples/jsm/tsl/display/AnaglyphPassNode.js +2 -2
  39. package/examples/jsm/tsl/display/AnamorphicNode.js +2 -2
  40. package/examples/jsm/tsl/display/BloomNode.js +3 -3
  41. package/examples/jsm/tsl/display/DenoiseNode.js +48 -12
  42. package/examples/jsm/tsl/display/DepthOfFieldNode.js +3 -2
  43. package/examples/jsm/tsl/display/DotScreenNode.js +2 -2
  44. package/examples/jsm/tsl/display/FXAANode.js +3 -3
  45. package/examples/jsm/tsl/display/FilmNode.js +3 -2
  46. package/examples/jsm/tsl/display/GTAONode.js +62 -27
  47. package/examples/jsm/tsl/display/GaussianBlurNode.js +6 -8
  48. package/examples/jsm/tsl/display/LensflareNode.js +3 -3
  49. package/examples/jsm/tsl/display/Lut3DNode.js +3 -2
  50. package/examples/jsm/tsl/display/OutlineNode.js +2 -2
  51. package/examples/jsm/tsl/display/ParallaxBarrierPassNode.js +2 -1
  52. package/examples/jsm/tsl/display/PixelationPassNode.js +4 -4
  53. package/examples/jsm/tsl/display/RGBShiftNode.js +2 -1
  54. package/examples/jsm/tsl/display/SMAANode.js +3 -3
  55. package/examples/jsm/tsl/display/SSAAPassNode.js +2 -2
  56. package/examples/jsm/tsl/display/SSRNode.js +31 -8
  57. package/examples/jsm/tsl/display/SobelOperatorNode.js +3 -3
  58. package/examples/jsm/tsl/display/StereoCompositePassNode.js +4 -4
  59. package/examples/jsm/tsl/display/StereoPassNode.js +2 -2
  60. package/examples/jsm/tsl/display/TRAAPassNode.js +2 -2
  61. package/examples/jsm/tsl/display/TransitionNode.js +3 -2
  62. package/examples/jsm/tsl/lighting/TiledLightsNode.js +6 -9
  63. package/examples/jsm/utils/SceneOptimizer.js +410 -0
  64. package/examples/jsm/utils/UVsDebug.js +1 -1
  65. package/package.json +3 -3
  66. package/src/Three.Core.js +178 -0
  67. package/src/Three.TSL.js +526 -0
  68. package/src/Three.WebGPU.Nodes.js +5 -186
  69. package/src/Three.WebGPU.js +4 -186
  70. package/src/Three.js +1 -177
  71. package/src/animation/AnimationClip.js +2 -2
  72. package/src/animation/AnimationObjectGroup.js +2 -2
  73. package/src/audio/Audio.js +38 -0
  74. package/src/cameras/PerspectiveCamera.js +6 -6
  75. package/src/cameras/StereoCamera.js +2 -2
  76. package/src/constants.js +1 -1
  77. package/src/core/BufferGeometry.js +5 -3
  78. package/src/core/InterleavedBuffer.js +4 -4
  79. package/src/core/Object3D.js +2 -2
  80. package/src/extras/core/Curve.js +3 -3
  81. package/src/extras/core/Shape.js +2 -2
  82. package/src/geometries/EdgesGeometry.js +2 -2
  83. package/src/geometries/LatheGeometry.js +2 -2
  84. package/src/lights/SpotLightShadow.js +2 -2
  85. package/src/materials/LineBasicMaterial.js +2 -6
  86. package/src/materials/LineDashedMaterial.js +1 -6
  87. package/src/materials/Material.js +3 -16
  88. package/src/materials/MeshBasicMaterial.js +2 -6
  89. package/src/materials/MeshDepthMaterial.js +2 -6
  90. package/src/materials/MeshDistanceMaterial.js +2 -6
  91. package/src/materials/MeshLambertMaterial.js +2 -6
  92. package/src/materials/MeshMatcapMaterial.js +2 -6
  93. package/src/materials/MeshNormalMaterial.js +2 -6
  94. package/src/materials/MeshPhongMaterial.js +3 -7
  95. package/src/materials/MeshPhysicalMaterial.js +4 -8
  96. package/src/materials/MeshStandardMaterial.js +2 -6
  97. package/src/materials/MeshToonMaterial.js +2 -6
  98. package/src/materials/PointsMaterial.js +2 -6
  99. package/src/materials/RawShaderMaterial.js +2 -6
  100. package/src/materials/ShaderMaterial.js +2 -6
  101. package/src/materials/ShadowMaterial.js +2 -6
  102. package/src/materials/SpriteMaterial.js +2 -6
  103. package/src/materials/nodes/Line2NodeMaterial.js +32 -13
  104. package/src/materials/nodes/LineDashedNodeMaterial.js +4 -2
  105. package/src/materials/nodes/NodeMaterial.js +64 -16
  106. package/src/materials/nodes/manager/NodeMaterialObserver.js +13 -10
  107. package/src/math/ColorManagement.js +130 -122
  108. package/src/math/Line3.js +2 -2
  109. package/src/math/Quaternion.js +2 -2
  110. package/src/math/Spherical.js +3 -3
  111. package/src/math/Vector2.js +7 -7
  112. package/src/math/Vector3.js +9 -9
  113. package/src/math/Vector4.js +11 -9
  114. package/src/nodes/Nodes.js +1 -0
  115. package/src/nodes/TSL.js +3 -1
  116. package/src/nodes/accessors/Arrays.js +27 -0
  117. package/src/nodes/accessors/BuiltinNode.js +26 -0
  118. package/src/nodes/accessors/ClippingNode.js +76 -42
  119. package/src/nodes/accessors/InstanceNode.js +17 -20
  120. package/src/nodes/accessors/InstancedMeshNode.js +26 -0
  121. package/src/nodes/accessors/Lights.js +32 -0
  122. package/src/nodes/accessors/StorageBufferNode.js +29 -9
  123. package/src/nodes/accessors/StorageTextureNode.js +10 -4
  124. package/src/nodes/accessors/TextureNode.js +1 -1
  125. package/src/nodes/core/NodeBuilder.js +2 -9
  126. package/src/nodes/core/NodeUtils.js +28 -0
  127. package/src/nodes/core/constants.js +6 -0
  128. package/src/nodes/display/BlendModes.js +99 -0
  129. package/src/nodes/display/ToonOutlinePassNode.js +3 -3
  130. package/src/nodes/display/ViewportDepthNode.js +21 -6
  131. package/src/nodes/functions/material/getAlphaHashThreshold.js +13 -7
  132. package/src/nodes/functions/material/getParallaxCorrectNormal.js +1 -1
  133. package/src/nodes/lighting/AnalyticLightNode.js +12 -4
  134. package/src/nodes/lighting/PointLightNode.js +10 -1
  135. package/src/nodes/lighting/PointShadowNode.js +254 -0
  136. package/src/nodes/lighting/ShadowNode.js +176 -67
  137. package/src/nodes/lighting/SpotLightNode.js +14 -2
  138. package/src/nodes/utils/RTTNode.js +9 -1
  139. package/src/nodes/utils/StorageArrayElementNode.js +2 -2
  140. package/src/objects/BatchedMesh.js +54 -95
  141. package/src/objects/ClippingGroup.js +19 -0
  142. package/src/objects/Skeleton.js +2 -2
  143. package/src/renderers/WebGLRenderer.js +94 -23
  144. package/src/renderers/common/Animation.js +23 -11
  145. package/src/renderers/common/Background.js +1 -1
  146. package/src/renderers/common/Bindings.js +20 -4
  147. package/src/renderers/common/ClippingContext.js +77 -85
  148. package/src/renderers/common/RenderList.js +9 -6
  149. package/src/renderers/common/RenderObject.js +27 -27
  150. package/src/renderers/common/RenderObjects.js +12 -6
  151. package/src/renderers/common/Renderer.js +63 -57
  152. package/src/renderers/common/Textures.js +11 -3
  153. package/src/renderers/common/UniformsGroup.js +16 -4
  154. package/src/renderers/common/extras/PMREMGenerator.js +89 -13
  155. package/src/renderers/common/nodes/NodeLibrary.js +2 -2
  156. package/src/renderers/common/nodes/NodeStorageBuffer.js +2 -3
  157. package/src/renderers/common/nodes/NodeUniform.js +42 -0
  158. package/src/renderers/webgl/WebGLBackground.js +20 -1
  159. package/src/renderers/webgl/WebGLGeometries.js +0 -28
  160. package/src/renderers/webgl-fallback/WebGLBackend.js +13 -6
  161. package/src/renderers/webgl-fallback/nodes/GLSLNodeBuilder.js +43 -12
  162. package/src/renderers/webgl-fallback/utils/WebGLState.js +26 -1
  163. package/src/renderers/webgl-fallback/utils/WebGLTextureUtils.js +4 -1
  164. package/src/renderers/webgpu/WebGPUBackend.js +47 -31
  165. package/src/renderers/webgpu/nodes/StandardNodeLibrary.js +13 -26
  166. package/src/renderers/webgpu/nodes/WGSLNodeBuilder.js +184 -74
  167. package/src/renderers/webgpu/utils/WebGPUAttributeUtils.js +15 -2
  168. package/src/renderers/webgpu/utils/WebGPUBindingUtils.js +72 -7
  169. package/src/renderers/webgpu/utils/WebGPUTextureUtils.js +5 -1
  170. package/src/textures/Source.js +2 -2
  171. package/src/textures/Texture.js +2 -2
  172. package/src/nodes/display/BlendMode.js +0 -54
@@ -34,7 +34,7 @@ class ToonOutlinePassNode extends PassNode {
34
34
 
35
35
  const currentRenderObjectFunction = renderer.getRenderObjectFunction();
36
36
 
37
- renderer.setRenderObjectFunction( ( object, scene, camera, geometry, material, group, lightsNode ) => {
37
+ renderer.setRenderObjectFunction( ( object, scene, camera, geometry, material, group, lightsNode, clippingContext ) => {
38
38
 
39
39
  // only render outline for supported materials
40
40
 
@@ -43,7 +43,7 @@ class ToonOutlinePassNode extends PassNode {
43
43
  if ( material.wireframe === false ) {
44
44
 
45
45
  const outlineMaterial = this._getOutlineMaterial( material );
46
- renderer.renderObject( object, scene, camera, geometry, outlineMaterial, group, lightsNode );
46
+ renderer.renderObject( object, scene, camera, geometry, outlineMaterial, group, lightsNode, clippingContext );
47
47
 
48
48
  }
49
49
 
@@ -51,7 +51,7 @@ class ToonOutlinePassNode extends PassNode {
51
51
 
52
52
  // default
53
53
 
54
- renderer.renderObject( object, scene, camera, geometry, material, group, lightsNode );
54
+ renderer.renderObject( object, scene, camera, geometry, material, group, lightsNode, clippingContext );
55
55
 
56
56
  } );
57
57
 
@@ -1,5 +1,5 @@
1
1
  import Node from '../core/Node.js';
2
- import { log2, nodeImmutable, nodeProxy } from '../tsl/TSLBase.js';
2
+ import { float, log, log2, nodeImmutable, nodeProxy } from '../tsl/TSLBase.js';
3
3
  import { cameraNear, cameraFar } from '../accessors/Camera.js';
4
4
  import { positionView } from '../accessors/Position.js';
5
5
  import { viewportDepthTexture } from './ViewportDepthTextureNode.js';
@@ -116,8 +116,10 @@ export const viewZToPerspectiveDepth = ( viewZ, near, far ) => near.add( viewZ )
116
116
  // maps perspective depth in [ 0, 1 ] to viewZ
117
117
  export const perspectiveDepthToViewZ = ( depth, near, far ) => near.mul( far ).div( far.sub( near ).mul( depth ).sub( far ) );
118
118
 
119
- export const perspectiveDepthToLogarithmicDepth = ( perspectiveW, near, far ) => {
119
+ // -near maps to 0; -far maps to 1
120
+ export const viewZToLogarithmicDepth = ( viewZ, near, far ) => {
120
121
 
122
+ // NOTE: viewZ must be negative--see explanation at the end of this comment block.
121
123
  // The final logarithmic depth formula used here is adapted from one described in an
122
124
  // article by Thatcher Ulrich (see http://tulrich.com/geekstuff/log_depth_buffer.txt),
123
125
  // which was an improvement upon an earlier formula one described in an
@@ -139,15 +141,28 @@ export const perspectiveDepthToLogarithmicDepth = ( perspectiveW, near, far ) =>
139
141
  // 1. Clamp the camera near plane so we don't divide by 0.
140
142
  // 2. Use log2 instead of log to avoid an extra multiply (shaders implement log using log2).
141
143
  // 3. Assume K is 1 (K = maximum value in depth buffer; see Ulrich's formula above).
142
- // 4. Add 1 to each division by cameraNear to ensure the depth curve is shifted to the left as cameraNear increases.
143
- // For visual representation of this depth curve, see https://www.desmos.com/calculator/lz5rqfysih
144
+ // 4. To maintain consistency with the functions "viewZToOrthographicDepth" and "viewZToPerspectiveDepth",
145
+ // we modify the formula here to use 'viewZ' instead of 'w'. The other functions expect a negative viewZ,
146
+ // so we do the same here, hence the 'viewZ.negate()' call.
147
+ // For visual representation of this depth curve, see https://www.desmos.com/calculator/uyqk0vex1u
144
148
  near = near.max( 1e-6 ).toVar();
145
- const numerator = log2( perspectiveW.div( near ).add( 1 ) );
146
- const denominator = log2( far.div( near ).add( 1 ) );
149
+ const numerator = log2( viewZ.negate().div( near ) );
150
+ const denominator = log2( far.div( near ) );
147
151
  return numerator.div( denominator );
148
152
 
149
153
  };
150
154
 
155
+ // maps logarithmic depth in [ 0, 1 ] to viewZ
156
+ export const logarithmicDepthToViewZ = ( depth, near, far ) => {
157
+
158
+ // NOTE: we add a 'negate()' call to the return value here to maintain consistency with
159
+ // the functions "orthographicDepthToViewZ" and "perspectiveDepthToViewZ" (they return
160
+ // a negative viewZ).
161
+ const exponent = depth.mul( log( far.div( near ) ) );
162
+ return float( Math.E ).pow( exponent ).mul( near ).negate();
163
+
164
+ };
165
+
151
166
  const depthBase = /*@__PURE__*/ nodeProxy( ViewportDepthNode, ViewportDepthNode.DEPTH_BASE );
152
167
 
153
168
  export const depth = /*@__PURE__*/ nodeImmutable( ViewportDepthNode, ViewportDepthNode.DEPTH );
@@ -24,7 +24,7 @@ const getAlphaHashThreshold = /*@__PURE__*/ Fn( ( [ position ] ) => {
24
24
  const maxDeriv = max(
25
25
  length( dFdx( position.xyz ) ),
26
26
  length( dFdy( position.xyz ) )
27
- ).toVar( 'maxDeriv' );
27
+ );
28
28
 
29
29
  const pixScale = float( 1 ).div( float( ALPHA_HASH_SCALE ).mul( maxDeriv ) ).toVar( 'pixScale' );
30
30
 
@@ -32,26 +32,26 @@ const getAlphaHashThreshold = /*@__PURE__*/ Fn( ( [ position ] ) => {
32
32
  const pixScales = vec2(
33
33
  exp2( floor( log2( pixScale ) ) ),
34
34
  exp2( ceil( log2( pixScale ) ) )
35
- ).toVar( 'pixScales' );
35
+ );
36
36
 
37
37
  // Compute alpha thresholds at our two noise scales
38
38
  const alpha = vec2(
39
39
  hash3D( floor( pixScales.x.mul( position.xyz ) ) ),
40
40
  hash3D( floor( pixScales.y.mul( position.xyz ) ) ),
41
- ).toVar( 'alpha' );
41
+ );
42
42
 
43
43
  // Factor to interpolate lerp with
44
- const lerpFactor = fract( log2( pixScale ) ).toVar( 'lerpFactor' );
44
+ const lerpFactor = fract( log2( pixScale ) );
45
45
 
46
46
  // Interpolate alpha threshold from noise at two scales
47
- const x = add( mul( lerpFactor.oneMinus(), alpha.x ), mul( lerpFactor, alpha.y ) ).toVar( 'x' );
47
+ const x = add( mul( lerpFactor.oneMinus(), alpha.x ), mul( lerpFactor, alpha.y ) );
48
48
 
49
49
  // Pass into CDF to compute uniformly distrib threshold
50
- const a = min( lerpFactor, lerpFactor.oneMinus() ).toVar( 'a' );
50
+ const a = min( lerpFactor, lerpFactor.oneMinus() );
51
51
  const cases = vec3(
52
52
  x.mul( x ).div( mul( 2.0, a ).mul( sub( 1.0, a ) ) ),
53
53
  x.sub( mul( 0.5, a ) ).div( sub( 1.0, a ) ),
54
- sub( 1.0, sub( 1.0, x ).mul( sub( 1.0, x ) ).div( mul( 2.0, a ).mul( sub( 1.0, a ) ) ) ) ).toVar( 'cases' );
54
+ sub( 1.0, sub( 1.0, x ).mul( sub( 1.0, x ) ).div( mul( 2.0, a ).mul( sub( 1.0, a ) ) ) ) );
55
55
 
56
56
  // Find our final, uniformly distributed alpha threshold (ατ)
57
57
  const threshold = x.lessThan( a.oneMinus() ).select( x.lessThan( a ).select( cases.x, cases.y ), cases.z );
@@ -59,6 +59,12 @@ const getAlphaHashThreshold = /*@__PURE__*/ Fn( ( [ position ] ) => {
59
59
  // Avoids ατ == 0. Could also do ατ =1-ατ
60
60
  return clamp( threshold, 1.0e-6, 1.0 );
61
61
 
62
+ } ).setLayout( {
63
+ name: 'getAlphaHashThreshold',
64
+ type: 'float',
65
+ inputs: [
66
+ { name: 'position', type: 'vec3' }
67
+ ]
62
68
  } );
63
69
 
64
70
  export default getAlphaHashThreshold;
@@ -1,4 +1,4 @@
1
- import { positionWorld } from '../../accessors/Position';
1
+ import { positionWorld } from '../../accessors/Position.js';
2
2
  import { float, Fn, min, normalize, sub, vec3 } from '../../tsl/TSLBase.js';
3
3
 
4
4
  // https://devlog-martinsh.blogspot.com/2011/09/box-projected-cube-environment-mapping.html
@@ -19,12 +19,10 @@ class AnalyticLightNode extends LightingNode {
19
19
 
20
20
  super();
21
21
 
22
- this.updateType = NodeUpdateType.FRAME;
23
-
24
22
  this.light = light;
25
23
 
26
24
  this.color = new Color();
27
- this.colorNode = uniform( this.color ).setGroup( renderGroup );
25
+ this.colorNode = ( light && light.colorNode ) || uniform( this.color ).setGroup( renderGroup );
28
26
 
29
27
  this.baseColorNode = null;
30
28
 
@@ -33,6 +31,8 @@ class AnalyticLightNode extends LightingNode {
33
31
 
34
32
  this.isAnalyticLightNode = true;
35
33
 
34
+ this.updateType = NodeUpdateType.FRAME;
35
+
36
36
  }
37
37
 
38
38
  getCacheKey() {
@@ -47,6 +47,12 @@ class AnalyticLightNode extends LightingNode {
47
47
 
48
48
  }
49
49
 
50
+ setupShadowNode() {
51
+
52
+ return shadow( this.light );
53
+
54
+ }
55
+
50
56
  setupShadow( builder ) {
51
57
 
52
58
  const { renderer } = builder;
@@ -67,7 +73,7 @@ class AnalyticLightNode extends LightingNode {
67
73
 
68
74
  } else {
69
75
 
70
- shadowNode = shadow( this.light );
76
+ shadowNode = this.setupShadowNode( builder );
71
77
 
72
78
  }
73
79
 
@@ -100,6 +106,8 @@ class AnalyticLightNode extends LightingNode {
100
106
  } else if ( this.shadowNode !== null ) {
101
107
 
102
108
  this.shadowNode.dispose();
109
+ this.shadowNode = null;
110
+ this.shadowColorNode = null;
103
111
 
104
112
  }
105
113
 
@@ -5,6 +5,7 @@ import { lightViewPosition } from '../accessors/Lights.js';
5
5
  import { positionView } from '../accessors/Position.js';
6
6
  import { Fn } from '../tsl/TSLBase.js';
7
7
  import { renderGroup } from '../core/UniformGroupNode.js';
8
+ import { pointShadow } from './PointShadowNode.js';
8
9
 
9
10
  export const directPointLight = Fn( ( { color, lightViewPosition, cutoffDistance, decayExponent }, builder ) => {
10
11
 
@@ -61,7 +62,15 @@ class PointLightNode extends AnalyticLightNode {
61
62
 
62
63
  }
63
64
 
64
- setup() {
65
+ setupShadowNode() {
66
+
67
+ return pointShadow( this.light );
68
+
69
+ }
70
+
71
+ setup( builder ) {
72
+
73
+ super.setup( builder );
65
74
 
66
75
  directPointLight( {
67
76
  color: this.colorNode,
@@ -0,0 +1,254 @@
1
+ import ShadowNode from './ShadowNode.js';
2
+ import { uniform } from '../core/UniformNode.js';
3
+ import { float, vec2, If, Fn, nodeObject } from '../tsl/TSLBase.js';
4
+ import { reference } from '../accessors/ReferenceNode.js';
5
+ import { texture } from '../accessors/TextureNode.js';
6
+ import { max, abs, sign } from '../math/MathNode.js';
7
+ import { sub, div } from '../math/OperatorNode.js';
8
+ import { renderGroup } from '../core/UniformGroupNode.js';
9
+ import { Vector2 } from '../../math/Vector2.js';
10
+ import { Vector4 } from '../../math/Vector4.js';
11
+ import { Color } from '../../math/Color.js';
12
+ import { BasicShadowMap } from '../../constants.js';
13
+
14
+ const _clearColor = /*@__PURE__*/ new Color();
15
+
16
+ // cubeToUV() maps a 3D direction vector suitable for cube texture mapping to a 2D
17
+ // vector suitable for 2D texture mapping. This code uses the following layout for the
18
+ // 2D texture:
19
+ //
20
+ // xzXZ
21
+ // y Y
22
+ //
23
+ // Y - Positive y direction
24
+ // y - Negative y direction
25
+ // X - Positive x direction
26
+ // x - Negative x direction
27
+ // Z - Positive z direction
28
+ // z - Negative z direction
29
+ //
30
+ // Source and test bed:
31
+ // https://gist.github.com/tschw/da10c43c467ce8afd0c4
32
+
33
+ export const cubeToUV = /*@__PURE__*/ Fn( ( [ pos, texelSizeY ] ) => {
34
+
35
+ const v = pos.toVar();
36
+
37
+ // Number of texels to avoid at the edge of each square
38
+
39
+ const absV = abs( v );
40
+
41
+ // Intersect unit cube
42
+
43
+ const scaleToCube = div( 1.0, max( absV.x, max( absV.y, absV.z ) ) );
44
+ absV.mulAssign( scaleToCube );
45
+
46
+ // Apply scale to avoid seams
47
+
48
+ // two texels less per square (one texel will do for NEAREST)
49
+ v.mulAssign( scaleToCube.mul( texelSizeY.mul( 2 ).oneMinus() ) );
50
+
51
+ // Unwrap
52
+
53
+ // space: -1 ... 1 range for each square
54
+ //
55
+ // #X## dim := ( 4 , 2 )
56
+ // # # center := ( 1 , 1 )
57
+
58
+ const planar = vec2( v.xy ).toVar();
59
+
60
+ const almostATexel = texelSizeY.mul( 1.5 );
61
+ const almostOne = almostATexel.oneMinus();
62
+
63
+ If( absV.z.greaterThanEqual( almostOne ), () => {
64
+
65
+ If( v.z.greaterThan( 0.0 ), () => {
66
+
67
+ planar.x.assign( sub( 4.0, v.x ) );
68
+
69
+ } );
70
+
71
+ } ).ElseIf( absV.x.greaterThanEqual( almostOne ), () => {
72
+
73
+ const signX = sign( v.x );
74
+ planar.x.assign( v.z.mul( signX ).add( signX.mul( 2.0 ) ) );
75
+
76
+ } ).ElseIf( absV.y.greaterThanEqual( almostOne ), () => {
77
+
78
+ const signY = sign( v.y );
79
+ planar.x.assign( v.x.add( signY.mul( 2.0 ) ).add( 2.0 ) );
80
+ planar.y.assign( v.z.mul( signY ).sub( 2.0 ) );
81
+
82
+ } );
83
+
84
+ // Transform to UV space
85
+
86
+ // scale := 0.5 / dim
87
+ // translate := ( center + 0.5 ) / dim
88
+ return vec2( 0.125, 0.25 ).mul( planar ).add( vec2( 0.375, 0.75 ) ).flipY();
89
+
90
+ } ).setLayout( {
91
+ name: 'cubeToUV',
92
+ type: 'vec2',
93
+ inputs: [
94
+ { name: 'pos', type: 'vec3' },
95
+ { name: 'texelSizeY', type: 'float' }
96
+ ]
97
+ } );
98
+
99
+ export const BasicPointShadowFilter = /*@__PURE__*/ Fn( ( { depthTexture, bd3D, dp, texelSize } ) => {
100
+
101
+ return texture( depthTexture, cubeToUV( bd3D, texelSize.y ) ).compare( dp );
102
+
103
+ } );
104
+
105
+ export const PointShadowFilter = /*@__PURE__*/ Fn( ( { depthTexture, bd3D, dp, texelSize, shadow } ) => {
106
+
107
+ const radius = reference( 'radius', 'float', shadow ).setGroup( renderGroup );
108
+ const offset = vec2( - 1.0, 1.0 ).mul( radius ).mul( texelSize.y );
109
+
110
+ return texture( depthTexture, cubeToUV( bd3D.add( offset.xyy ), texelSize.y ) ).compare( dp )
111
+ .add( texture( depthTexture, cubeToUV( bd3D.add( offset.yyy ), texelSize.y ) ).compare( dp ) )
112
+ .add( texture( depthTexture, cubeToUV( bd3D.add( offset.xyx ), texelSize.y ) ).compare( dp ) )
113
+ .add( texture( depthTexture, cubeToUV( bd3D.add( offset.yyx ), texelSize.y ) ).compare( dp ) )
114
+ .add( texture( depthTexture, cubeToUV( bd3D, texelSize.y ) ).compare( dp ) )
115
+ .add( texture( depthTexture, cubeToUV( bd3D.add( offset.xxy ), texelSize.y ) ).compare( dp ) )
116
+ .add( texture( depthTexture, cubeToUV( bd3D.add( offset.yxy ), texelSize.y ) ).compare( dp ) )
117
+ .add( texture( depthTexture, cubeToUV( bd3D.add( offset.xxx ), texelSize.y ) ).compare( dp ) )
118
+ .add( texture( depthTexture, cubeToUV( bd3D.add( offset.yxx ), texelSize.y ) ).compare( dp ) )
119
+ .mul( 1.0 / 9.0 );
120
+
121
+ } );
122
+
123
+ const pointShadowFilter = /*@__PURE__*/ Fn( ( { filterFn, depthTexture, shadowCoord, shadow } ) => {
124
+
125
+ // for point lights, the uniform @vShadowCoord is re-purposed to hold
126
+ // the vector from the light to the world-space position of the fragment.
127
+ const lightToPosition = shadowCoord.xyz.toVar();
128
+ const lightToPositionLength = lightToPosition.length();
129
+
130
+ const cameraNearLocal = uniform( 'float' ).setGroup( renderGroup ).onRenderUpdate( () => shadow.camera.near );
131
+ const cameraFarLocal = uniform( 'float' ).setGroup( renderGroup ).onRenderUpdate( () => shadow.camera.far );
132
+ const bias = reference( 'bias', 'float', shadow ).setGroup( renderGroup );
133
+ const mapSize = uniform( shadow.mapSize ).setGroup( renderGroup );
134
+
135
+ const result = float( 1.0 ).toVar();
136
+
137
+ If( lightToPositionLength.sub( cameraFarLocal ).lessThanEqual( 0.0 ).and( lightToPositionLength.sub( cameraNearLocal ).greaterThanEqual( 0.0 ) ), () => {
138
+
139
+ // dp = normalized distance from light to fragment position
140
+ const dp = lightToPositionLength.sub( cameraNearLocal ).div( cameraFarLocal.sub( cameraNearLocal ) ).toVar(); // need to clamp?
141
+ dp.addAssign( bias );
142
+
143
+ // bd3D = base direction 3D
144
+ const bd3D = lightToPosition.normalize();
145
+ const texelSize = vec2( 1.0 ).div( mapSize.mul( vec2( 4.0, 2.0 ) ) );
146
+
147
+ // percentage-closer filtering
148
+ result.assign( filterFn( { depthTexture, bd3D, dp, texelSize, shadow } ) );
149
+
150
+ } );
151
+
152
+ return result;
153
+
154
+ } );
155
+
156
+ const _viewport = /*@__PURE__*/ new Vector4();
157
+ const _viewportSize = /*@__PURE__*/ new Vector2();
158
+ const _shadowMapSize = /*@__PURE__*/ new Vector2();
159
+
160
+ //
161
+
162
+ class PointShadowNode extends ShadowNode {
163
+
164
+ static get type() {
165
+
166
+ return 'PointShadowNode';
167
+
168
+ }
169
+
170
+ constructor( light, shadow = null ) {
171
+
172
+ super( light, shadow );
173
+
174
+ }
175
+
176
+ getShadowFilterFn( type ) {
177
+
178
+ return type === BasicShadowMap ? BasicPointShadowFilter : PointShadowFilter;
179
+
180
+ }
181
+
182
+ setupShadowCoord( builder, shadowPosition ) {
183
+
184
+ return shadowPosition;
185
+
186
+ }
187
+
188
+ setupShadowFilter( builder, { filterFn, shadowTexture, depthTexture, shadowCoord, shadow } ) {
189
+
190
+ return pointShadowFilter( { filterFn, shadowTexture, depthTexture, shadowCoord, shadow } );
191
+
192
+ }
193
+
194
+ renderShadow( frame ) {
195
+
196
+ const { shadow, shadowMap, light } = this;
197
+ const { renderer, scene } = frame;
198
+
199
+ const shadowFrameExtents = shadow.getFrameExtents();
200
+
201
+ _shadowMapSize.copy( shadow.mapSize );
202
+ _shadowMapSize.multiply( shadowFrameExtents );
203
+
204
+ shadowMap.setSize( _shadowMapSize.width, _shadowMapSize.height );
205
+
206
+ _viewportSize.copy( shadow.mapSize );
207
+
208
+ //
209
+
210
+ const previousAutoClear = renderer.autoClear;
211
+
212
+ const previousClearColor = renderer.getClearColor( _clearColor );
213
+ const previousClearAlpha = renderer.getClearAlpha();
214
+
215
+ renderer.autoClear = false;
216
+ renderer.setClearColor( shadow.clearColor, shadow.clearAlpha );
217
+ renderer.clear();
218
+
219
+ const viewportCount = shadow.getViewportCount();
220
+
221
+ for ( let vp = 0; vp < viewportCount; vp ++ ) {
222
+
223
+ const viewport = shadow.getViewport( vp );
224
+
225
+ const x = _viewportSize.x * viewport.x;
226
+ const y = _shadowMapSize.y - _viewportSize.y - ( _viewportSize.y * viewport.y );
227
+
228
+ _viewport.set(
229
+ x,
230
+ y,
231
+ _viewportSize.x * viewport.z,
232
+ _viewportSize.y * viewport.w
233
+ );
234
+
235
+ shadowMap.viewport.copy( _viewport );
236
+
237
+ shadow.updateMatrices( light, vp );
238
+
239
+ renderer.render( scene, shadow.camera );
240
+
241
+ }
242
+
243
+ //
244
+
245
+ renderer.autoClear = previousAutoClear;
246
+ renderer.setClearColor( previousClearColor, previousClearAlpha );
247
+
248
+ }
249
+
250
+ }
251
+
252
+ export default PointShadowNode;
253
+
254
+ export const pointShadow = ( light, shadow ) => nodeObject( new PointShadowNode( light, shadow ) );