@plastic-software/three 0.181.2 → 0.182.0

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 (253) hide show
  1. package/README.md +3 -4
  2. package/build/three.cjs +1192 -522
  3. package/build/three.core.js +345 -219
  4. package/build/three.core.min.js +1 -1
  5. package/build/three.module.js +864 -328
  6. package/build/three.module.min.js +1 -1
  7. package/build/three.tsl.js +15 -3
  8. package/build/three.tsl.min.js +1 -1
  9. package/build/three.webgpu.js +3660 -1545
  10. package/build/three.webgpu.min.js +1 -1
  11. package/build/three.webgpu.nodes.js +3659 -1544
  12. package/build/three.webgpu.nodes.min.js +1 -1
  13. package/examples/jsm/controls/MapControls.js +55 -1
  14. package/examples/jsm/controls/OrbitControls.js +6 -6
  15. package/examples/jsm/controls/TrackballControls.js +6 -6
  16. package/examples/jsm/csm/CSM.js +2 -1
  17. package/examples/jsm/environments/RoomEnvironment.js +2 -0
  18. package/examples/jsm/geometries/DecalGeometry.js +1 -1
  19. package/examples/jsm/helpers/LightProbeHelperGPU.js +1 -1
  20. package/examples/jsm/helpers/TextureHelperGPU.js +1 -1
  21. package/examples/jsm/inspector/Inspector.js +53 -9
  22. package/examples/jsm/inspector/RendererInspector.js +12 -2
  23. package/examples/jsm/inspector/tabs/Console.js +2 -2
  24. package/examples/jsm/inspector/tabs/Parameters.js +2 -2
  25. package/examples/jsm/inspector/tabs/Performance.js +2 -2
  26. package/examples/jsm/inspector/tabs/Viewer.js +4 -4
  27. package/examples/jsm/inspector/ui/Profiler.js +1836 -31
  28. package/examples/jsm/inspector/ui/Style.js +948 -13
  29. package/examples/jsm/inspector/ui/Tab.js +188 -1
  30. package/examples/jsm/inspector/ui/Values.js +17 -1
  31. package/examples/jsm/loaders/3DMLoader.js +5 -4
  32. package/examples/jsm/loaders/DRACOLoader.js +5 -5
  33. package/examples/jsm/loaders/FBXLoader.js +0 -2
  34. package/examples/jsm/loaders/HDRLoader.js +0 -1
  35. package/examples/jsm/loaders/KTX2Loader.js +16 -0
  36. package/examples/jsm/loaders/LDrawLoader.js +2 -3
  37. package/examples/jsm/loaders/PCDLoader.js +1 -0
  38. package/examples/jsm/loaders/SVGLoader.js +1 -1
  39. package/examples/jsm/loaders/TDSLoader.js +0 -2
  40. package/examples/jsm/loaders/TGALoader.js +0 -2
  41. package/examples/jsm/loaders/UltraHDRLoader.js +110 -137
  42. package/examples/jsm/loaders/VOXLoader.js +660 -117
  43. package/examples/jsm/loaders/VRMLLoader.js +2 -2
  44. package/examples/jsm/loaders/usd/USDCParser.js +1 -1
  45. package/examples/jsm/materials/LDrawConditionalLineNodeMaterial.js +1 -1
  46. package/examples/jsm/materials/MeshGouraudMaterial.js +0 -1
  47. package/examples/jsm/materials/WoodNodeMaterial.js +11 -11
  48. package/examples/jsm/math/Octree.js +131 -1
  49. package/examples/jsm/misc/Volume.js +0 -1
  50. package/examples/jsm/misc/VolumeSlice.js +0 -1
  51. package/examples/jsm/objects/SkyMesh.js +13 -3
  52. package/examples/jsm/physics/AmmoPhysics.js +12 -7
  53. package/examples/jsm/physics/JoltPhysics.js +3 -1
  54. package/examples/jsm/physics/RapierPhysics.js +3 -1
  55. package/examples/jsm/postprocessing/OutputPass.js +9 -0
  56. package/examples/jsm/postprocessing/RenderPass.js +10 -0
  57. package/examples/jsm/postprocessing/UnrealBloomPass.js +48 -18
  58. package/examples/jsm/renderers/Projector.js +268 -30
  59. package/examples/jsm/renderers/SVGRenderer.js +191 -58
  60. package/examples/jsm/shaders/UnpackDepthRGBAShader.js +2 -4
  61. package/examples/jsm/transpiler/AST.js +44 -0
  62. package/examples/jsm/transpiler/GLSLDecoder.js +61 -4
  63. package/examples/jsm/transpiler/ShaderToyDecoder.js +2 -0
  64. package/examples/jsm/transpiler/TSLEncoder.js +46 -3
  65. package/examples/jsm/transpiler/TranspilerUtils.js +3 -3
  66. package/examples/jsm/transpiler/WGSLEncoder.js +27 -0
  67. package/examples/jsm/tsl/display/AnaglyphPassNode.js +2 -0
  68. package/examples/jsm/tsl/display/BloomNode.js +11 -1
  69. package/examples/jsm/tsl/display/GTAONode.js +3 -2
  70. package/examples/jsm/tsl/display/PixelationPassNode.js +2 -1
  71. package/examples/jsm/tsl/display/SSGINode.js +7 -19
  72. package/examples/jsm/tsl/display/SSRNode.js +1 -1
  73. package/examples/jsm/tsl/display/SSSNode.js +4 -2
  74. package/examples/jsm/tsl/display/StereoCompositePassNode.js +8 -1
  75. package/examples/jsm/tsl/display/TRAANode.js +265 -114
  76. package/examples/jsm/tsl/display/radialBlur.js +68 -0
  77. package/examples/jsm/utils/ShadowMapViewer.js +24 -10
  78. package/examples/jsm/utils/ShadowMapViewerGPU.js +1 -1
  79. package/examples/jsm/utils/WebGPUTextureUtils.js +1 -1
  80. package/package.json +14 -12
  81. package/src/Three.Core.js +1 -0
  82. package/src/Three.TSL.js +14 -2
  83. package/src/animation/AnimationUtils.js +1 -12
  84. package/src/animation/KeyframeTrack.js +1 -1
  85. package/src/animation/tracks/BooleanKeyframeTrack.js +1 -1
  86. package/src/animation/tracks/ColorKeyframeTrack.js +1 -1
  87. package/src/animation/tracks/NumberKeyframeTrack.js +1 -1
  88. package/src/animation/tracks/QuaternionKeyframeTrack.js +1 -1
  89. package/src/animation/tracks/StringKeyframeTrack.js +1 -1
  90. package/src/animation/tracks/VectorKeyframeTrack.js +1 -1
  91. package/src/constants.js +61 -5
  92. package/src/core/BufferGeometry.js +14 -2
  93. package/src/core/Raycaster.js +2 -2
  94. package/src/extras/PMREMGenerator.js +3 -10
  95. package/src/extras/TextureUtils.js +5 -1
  96. package/src/geometries/ExtrudeGeometry.js +2 -2
  97. package/src/geometries/PolyhedronGeometry.js +1 -1
  98. package/src/helpers/PointLightHelper.js +1 -1
  99. package/src/lights/DirectionalLight.js +13 -0
  100. package/src/lights/HemisphereLight.js +10 -0
  101. package/src/lights/Light.js +1 -11
  102. package/src/lights/LightProbe.js +0 -15
  103. package/src/lights/LightShadow.js +0 -3
  104. package/src/lights/PointLight.js +15 -0
  105. package/src/lights/PointLightShadow.js +0 -86
  106. package/src/lights/SpotLight.js +22 -1
  107. package/src/loaders/MaterialLoader.js +2 -1
  108. package/src/loaders/ObjectLoader.js +3 -1
  109. package/src/loaders/nodes/NodeLoader.js +2 -2
  110. package/src/materials/Material.js +2 -0
  111. package/src/materials/ShaderMaterial.js +20 -1
  112. package/src/materials/nodes/Line2NodeMaterial.js +2 -2
  113. package/src/materials/nodes/MeshPhysicalNodeMaterial.js +3 -2
  114. package/src/materials/nodes/MeshStandardNodeMaterial.js +5 -4
  115. package/src/materials/nodes/NodeMaterial.js +59 -3
  116. package/src/materials/nodes/manager/NodeMaterialObserver.js +1 -1
  117. package/src/math/Matrix4.js +40 -40
  118. package/src/math/Sphere.js +1 -1
  119. package/src/math/Vector3.js +0 -2
  120. package/src/nodes/TSL.js +4 -1
  121. package/src/nodes/accessors/BatchNode.js +10 -10
  122. package/src/nodes/accessors/BufferAttributeNode.js +98 -12
  123. package/src/nodes/accessors/BufferNode.js +29 -2
  124. package/src/nodes/accessors/ClippingNode.js +4 -4
  125. package/src/nodes/accessors/CubeTextureNode.js +20 -1
  126. package/src/nodes/accessors/InstanceNode.js +69 -29
  127. package/src/nodes/accessors/MaterialNode.js +9 -1
  128. package/src/nodes/accessors/MaterialReferenceNode.js +1 -2
  129. package/src/nodes/accessors/ModelNode.js +1 -1
  130. package/src/nodes/accessors/Normal.js +2 -2
  131. package/src/nodes/accessors/ReferenceBaseNode.js +4 -4
  132. package/src/nodes/accessors/ReferenceNode.js +4 -4
  133. package/src/nodes/accessors/RendererReferenceNode.js +1 -2
  134. package/src/nodes/accessors/SkinningNode.js +15 -2
  135. package/src/nodes/accessors/StorageBufferNode.js +4 -2
  136. package/src/nodes/accessors/Tangent.js +1 -11
  137. package/src/nodes/accessors/Texture3DNode.js +26 -1
  138. package/src/nodes/accessors/UniformArrayNode.js +2 -2
  139. package/src/nodes/accessors/UserDataNode.js +1 -2
  140. package/src/nodes/accessors/VertexColorNode.js +1 -2
  141. package/src/nodes/code/FunctionNode.js +1 -2
  142. package/src/nodes/core/ArrayNode.js +20 -1
  143. package/src/nodes/core/AssignNode.js +2 -2
  144. package/src/nodes/core/AttributeNode.js +2 -2
  145. package/src/nodes/core/ContextNode.js +103 -4
  146. package/src/nodes/core/NodeBuilder.js +56 -14
  147. package/src/nodes/core/NodeFrame.js +12 -4
  148. package/src/nodes/core/NodeUtils.js +5 -5
  149. package/src/nodes/core/ParameterNode.js +1 -2
  150. package/src/nodes/core/PropertyNode.js +19 -3
  151. package/src/nodes/core/StackNode.js +56 -8
  152. package/src/nodes/core/StructNode.js +1 -2
  153. package/src/nodes/core/StructTypeNode.js +11 -17
  154. package/src/nodes/core/UniformNode.js +19 -4
  155. package/src/nodes/core/VarNode.js +46 -21
  156. package/src/nodes/display/NormalMapNode.js +37 -2
  157. package/src/nodes/display/PassNode.js +77 -7
  158. package/src/nodes/display/ScreenNode.js +1 -0
  159. package/src/nodes/functions/BSDF/BRDF_GGX_Multiscatter.js +3 -3
  160. package/src/nodes/functions/BSDF/DFGLUT.js +56 -0
  161. package/src/nodes/functions/BSDF/EnvironmentBRDF.js +2 -2
  162. package/src/nodes/functions/BSDF/V_GGX_SmithCorrelated_Anisotropic.js +1 -1
  163. package/src/nodes/functions/PhysicalLightingModel.js +102 -43
  164. package/src/nodes/gpgpu/ComputeBuiltinNode.js +1 -2
  165. package/src/nodes/gpgpu/SubgroupFunctionNode.js +1 -1
  166. package/src/nodes/gpgpu/WorkgroupInfoNode.js +2 -3
  167. package/src/nodes/lighting/AnalyticLightNode.js +53 -0
  168. package/src/nodes/lighting/LightsNode.js +2 -2
  169. package/src/nodes/lighting/PointShadowNode.js +141 -140
  170. package/src/nodes/lighting/ShadowFilterNode.js +53 -37
  171. package/src/nodes/lighting/ShadowNode.js +53 -19
  172. package/src/nodes/math/BitcountNode.js +433 -0
  173. package/src/nodes/math/PackFloatNode.js +98 -0
  174. package/src/nodes/math/UnpackFloatNode.js +96 -0
  175. package/src/nodes/pmrem/PMREMNode.js +1 -1
  176. package/src/nodes/tsl/TSLCore.js +4 -4
  177. package/src/nodes/utils/ArrayElementNode.js +13 -0
  178. package/src/nodes/utils/EventNode.js +1 -2
  179. package/src/nodes/utils/Packing.js +13 -1
  180. package/src/nodes/utils/PostProcessingUtils.js +33 -1
  181. package/src/nodes/utils/ReflectorNode.js +1 -1
  182. package/src/nodes/utils/SampleNode.js +1 -1
  183. package/src/nodes/utils/UVUtils.js +26 -0
  184. package/src/objects/BatchedMesh.js +5 -2
  185. package/src/objects/Line.js +1 -1
  186. package/src/objects/Mesh.js +1 -1
  187. package/src/objects/Points.js +1 -1
  188. package/src/objects/Skeleton.js +9 -0
  189. package/src/renderers/WebGLRenderer.js +145 -33
  190. package/src/renderers/common/Backend.js +8 -0
  191. package/src/renderers/common/Background.js +19 -9
  192. package/src/renderers/common/Binding.js +11 -0
  193. package/src/renderers/common/Bindings.js +7 -7
  194. package/src/renderers/common/Buffer.js +40 -0
  195. package/src/renderers/common/ChainMap.js +30 -6
  196. package/src/renderers/common/Geometries.js +12 -0
  197. package/src/renderers/common/RenderContexts.js +8 -1
  198. package/src/renderers/common/RenderObject.js +14 -1
  199. package/src/renderers/common/Renderer.js +53 -35
  200. package/src/renderers/common/Textures.js +1 -1
  201. package/src/renderers/common/UniformsGroup.js +1 -0
  202. package/src/renderers/common/XRManager.js +1 -0
  203. package/src/renderers/common/extras/PMREMGenerator.js +2 -8
  204. package/src/renderers/common/nodes/NodeUniformBuffer.js +52 -0
  205. package/src/renderers/shaders/DFGLUTData.js +19 -34
  206. package/src/renderers/shaders/ShaderChunk/lights_fragment_begin.glsl.js +5 -2
  207. package/src/renderers/shaders/ShaderChunk/lights_physical_fragment.glsl.js +8 -4
  208. package/src/renderers/shaders/ShaderChunk/lights_physical_pars_fragment.glsl.js +90 -51
  209. package/src/renderers/shaders/ShaderChunk/shadowmap_pars_fragment.glsl.js +194 -186
  210. package/src/renderers/shaders/ShaderChunk/shadowmask_pars_fragment.glsl.js +1 -1
  211. package/src/renderers/shaders/ShaderChunk/transmission_fragment.glsl.js +1 -1
  212. package/src/renderers/shaders/ShaderChunk.js +3 -3
  213. package/src/renderers/shaders/ShaderLib/depth.glsl.js +3 -0
  214. package/src/renderers/shaders/ShaderLib/{distanceRGBA.glsl.js → distance.glsl.js} +1 -2
  215. package/src/renderers/shaders/ShaderLib/meshlambert.glsl.js +0 -1
  216. package/src/renderers/shaders/ShaderLib/meshnormal.glsl.js +1 -2
  217. package/src/renderers/shaders/ShaderLib/meshphong.glsl.js +0 -1
  218. package/src/renderers/shaders/ShaderLib/meshphysical.glsl.js +4 -9
  219. package/src/renderers/shaders/ShaderLib/meshtoon.glsl.js +0 -1
  220. package/src/renderers/shaders/ShaderLib/shadow.glsl.js +0 -1
  221. package/src/renderers/shaders/ShaderLib/vsm.glsl.js +4 -6
  222. package/src/renderers/shaders/ShaderLib.js +3 -3
  223. package/src/renderers/webgl/WebGLCapabilities.js +3 -4
  224. package/src/renderers/webgl/WebGLLights.js +18 -1
  225. package/src/renderers/webgl/WebGLOutput.js +267 -0
  226. package/src/renderers/webgl/WebGLProgram.js +43 -107
  227. package/src/renderers/webgl/WebGLPrograms.js +35 -45
  228. package/src/renderers/webgl/WebGLShadowMap.js +188 -25
  229. package/src/renderers/webgl/WebGLState.js +20 -20
  230. package/src/renderers/webgl/WebGLTextures.js +89 -28
  231. package/src/renderers/webgl/WebGLUniforms.js +40 -3
  232. package/src/renderers/webgl/WebGLUtils.js +6 -2
  233. package/src/renderers/webgl-fallback/WebGLBackend.js +79 -13
  234. package/src/renderers/webgl-fallback/nodes/GLSLNodeBuilder.js +59 -7
  235. package/src/renderers/webgl-fallback/utils/WebGLState.js +18 -3
  236. package/src/renderers/webgl-fallback/utils/WebGLTextureUtils.js +5 -3
  237. package/src/renderers/webgl-fallback/utils/WebGLTimestampQueryPool.js +9 -9
  238. package/src/renderers/webgl-fallback/utils/WebGLUtils.js +6 -2
  239. package/src/renderers/webgpu/WebGPUBackend.js +61 -4
  240. package/src/renderers/webgpu/WebGPURenderer.js +1 -1
  241. package/src/renderers/webgpu/nodes/WGSLNodeBuilder.js +65 -23
  242. package/src/renderers/webgpu/utils/WebGPUAttributeUtils.js +4 -17
  243. package/src/renderers/webgpu/utils/WebGPUBindingUtils.js +354 -186
  244. package/src/renderers/webgpu/utils/WebGPUConstants.js +2 -0
  245. package/src/renderers/webgpu/utils/WebGPUPipelineUtils.js +20 -7
  246. package/src/renderers/webgpu/utils/WebGPUTextureUtils.js +40 -17
  247. package/src/renderers/webgpu/utils/WebGPUTimestampQueryPool.js +7 -7
  248. package/src/renderers/webgpu/utils/WebGPUUtils.js +7 -5
  249. package/src/textures/CubeDepthTexture.js +76 -0
  250. package/src/textures/Source.js +1 -1
  251. package/src/textures/Texture.js +1 -1
  252. package/src/utils.js +13 -1
  253. package/src/nodes/functions/BSDF/DFGApprox.js +0 -71
@@ -1,122 +1,95 @@
1
1
  import ShadowNode from './ShadowNode.js';
2
2
  import { uniform } from '../core/UniformNode.js';
3
- import { float, vec2, If, Fn, nodeObject } from '../tsl/TSLBase.js';
3
+ import { float, vec3, If, Fn } from '../tsl/TSLBase.js';
4
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';
5
+ import { cubeTexture } from '../accessors/CubeTextureNode.js';
8
6
  import { renderGroup } from '../core/UniformGroupNode.js';
9
- import { Vector2 } from '../../math/Vector2.js';
10
- import { Vector4 } from '../../math/Vector4.js';
7
+ import { Matrix4 } from '../../math/Matrix4.js';
8
+ import { Vector3 } from '../../math/Vector3.js';
11
9
  import { Color } from '../../math/Color.js';
12
- import { BasicShadowMap } from '../../constants.js';
10
+ import { BasicShadowMap, LessCompare, WebGPUCoordinateSystem } from '../../constants.js';
11
+ import { CubeDepthTexture } from '../../textures/CubeDepthTexture.js';
12
+ import { screenCoordinate } from '../display/ScreenNode.js';
13
+ import { interleavedGradientNoise, vogelDiskSample } from '../utils/PostProcessingUtils.js';
14
+ import { abs, normalize, cross } from '../math/MathNode.js';
13
15
 
14
16
  const _clearColor = /*@__PURE__*/ new Color();
17
+ const _projScreenMatrix = /*@__PURE__*/ new Matrix4();
18
+ const _lightPositionWorld = /*@__PURE__*/ new Vector3();
19
+ const _lookTarget = /*@__PURE__*/ new Vector3();
20
+
21
+ // Cube map face directions and up vectors for point light shadows
22
+ // Face order: +X, -X, +Y, -Y, +Z, -Z
23
+ // WebGPU coordinate system - Y faces swapped to match texture sampling convention
24
+ const _cubeDirectionsWebGPU = [
25
+ /*@__PURE__*/ new Vector3( 1, 0, 0 ), /*@__PURE__*/ new Vector3( - 1, 0, 0 ), /*@__PURE__*/ new Vector3( 0, - 1, 0 ),
26
+ /*@__PURE__*/ new Vector3( 0, 1, 0 ), /*@__PURE__*/ new Vector3( 0, 0, 1 ), /*@__PURE__*/ new Vector3( 0, 0, - 1 )
27
+ ];
28
+
29
+ const _cubeUpsWebGPU = [
30
+ /*@__PURE__*/ new Vector3( 0, - 1, 0 ), /*@__PURE__*/ new Vector3( 0, - 1, 0 ), /*@__PURE__*/ new Vector3( 0, 0, - 1 ),
31
+ /*@__PURE__*/ new Vector3( 0, 0, 1 ), /*@__PURE__*/ new Vector3( 0, - 1, 0 ), /*@__PURE__*/ new Vector3( 0, - 1, 0 )
32
+ ];
33
+
34
+ // WebGL coordinate system - standard OpenGL convention
35
+ const _cubeDirectionsWebGL = [
36
+ /*@__PURE__*/ new Vector3( 1, 0, 0 ), /*@__PURE__*/ new Vector3( - 1, 0, 0 ), /*@__PURE__*/ new Vector3( 0, 1, 0 ),
37
+ /*@__PURE__*/ new Vector3( 0, - 1, 0 ), /*@__PURE__*/ new Vector3( 0, 0, 1 ), /*@__PURE__*/ new Vector3( 0, 0, - 1 )
38
+ ];
39
+
40
+ const _cubeUpsWebGL = [
41
+ /*@__PURE__*/ new Vector3( 0, - 1, 0 ), /*@__PURE__*/ new Vector3( 0, - 1, 0 ), /*@__PURE__*/ new Vector3( 0, 0, 1 ),
42
+ /*@__PURE__*/ new Vector3( 0, 0, - 1 ), /*@__PURE__*/ new Vector3( 0, - 1, 0 ), /*@__PURE__*/ new Vector3( 0, - 1, 0 )
43
+ ];
44
+
45
+ export const BasicPointShadowFilter = /*@__PURE__*/ Fn( ( { depthTexture, bd3D, dp } ) => {
46
+
47
+ return cubeTexture( depthTexture, bd3D ).compare( dp );
15
48
 
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
49
+ } );
85
50
 
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();
51
+ /**
52
+ * A shadow filtering function for point lights using Vogel disk sampling and IGN.
53
+ *
54
+ * Uses 5 samples distributed via Vogel disk pattern in tangent space around the
55
+ * sample direction, rotated per-pixel using Interleaved Gradient Noise (IGN).
56
+ *
57
+ * @method
58
+ * @param {Object} inputs - The input parameter object.
59
+ * @param {CubeDepthTexture} inputs.depthTexture - A reference to the shadow cube map.
60
+ * @param {Node<vec3>} inputs.bd3D - The normalized direction from light to fragment.
61
+ * @param {Node<float>} inputs.dp - The depth value to compare against.
62
+ * @param {LightShadow} inputs.shadow - The light shadow.
63
+ * @return {Node<float>} The filtering result.
64
+ */
65
+ export const PointShadowFilter = /*@__PURE__*/ Fn( ( { depthTexture, bd3D, dp, shadow } ) => {
89
66
 
90
- } ).setLayout( {
91
- name: 'cubeToUV',
92
- type: 'vec2',
93
- inputs: [
94
- { name: 'pos', type: 'vec3' },
95
- { name: 'texelSizeY', type: 'float' }
96
- ]
97
- } );
67
+ const radius = reference( 'radius', 'float', shadow ).setGroup( renderGroup );
68
+ const mapSize = reference( 'mapSize', 'vec2', shadow ).setGroup( renderGroup );
98
69
 
99
- export const BasicPointShadowFilter = /*@__PURE__*/ Fn( ( { depthTexture, bd3D, dp, texelSize } ) => {
70
+ const texelSize = radius.div( mapSize.x );
100
71
 
101
- return texture( depthTexture, cubeToUV( bd3D, texelSize.y ) ).compare( dp );
72
+ // Build a tangent-space coordinate system for applying offsets
73
+ const absDir = abs( bd3D );
74
+ const tangent = normalize( cross( bd3D, absDir.x.greaterThan( absDir.z ).select( vec3( 0, 1, 0 ), vec3( 1, 0, 0 ) ) ) );
75
+ const bitangent = cross( bd3D, tangent );
102
76
 
103
- } );
77
+ // Use IGN to rotate sampling pattern per pixel (phi = IGN * 2π)
78
+ const phi = interleavedGradientNoise( screenCoordinate.xy ).mul( 6.28318530718 );
104
79
 
105
- export const PointShadowFilter = /*@__PURE__*/ Fn( ( { depthTexture, bd3D, dp, texelSize, shadow } ) => {
80
+ // 5 samples using Vogel disk distribution in tangent space
81
+ const sample0 = vogelDiskSample( 0, 5, phi );
82
+ const sample1 = vogelDiskSample( 1, 5, phi );
83
+ const sample2 = vogelDiskSample( 2, 5, phi );
84
+ const sample3 = vogelDiskSample( 3, 5, phi );
85
+ const sample4 = vogelDiskSample( 4, 5, phi );
106
86
 
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 );
87
+ return cubeTexture( depthTexture, bd3D.add( tangent.mul( sample0.x ).add( bitangent.mul( sample0.y ) ).mul( texelSize ) ) ).compare( dp )
88
+ .add( cubeTexture( depthTexture, bd3D.add( tangent.mul( sample1.x ).add( bitangent.mul( sample1.y ) ).mul( texelSize ) ) ).compare( dp ) )
89
+ .add( cubeTexture( depthTexture, bd3D.add( tangent.mul( sample2.x ).add( bitangent.mul( sample2.y ) ).mul( texelSize ) ) ).compare( dp ) )
90
+ .add( cubeTexture( depthTexture, bd3D.add( tangent.mul( sample3.x ).add( bitangent.mul( sample3.y ) ).mul( texelSize ) ) ).compare( dp ) )
91
+ .add( cubeTexture( depthTexture, bd3D.add( tangent.mul( sample4.x ).add( bitangent.mul( sample4.y ) ).mul( texelSize ) ) ).compare( dp ) )
92
+ .mul( 1.0 / 5.0 );
120
93
 
121
94
  } );
122
95
 
@@ -130,7 +103,6 @@ const pointShadowFilter = /*@__PURE__*/ Fn( ( { filterFn, depthTexture, shadowCo
130
103
  const cameraNearLocal = uniform( 'float' ).setGroup( renderGroup ).onRenderUpdate( () => shadow.camera.near );
131
104
  const cameraFarLocal = uniform( 'float' ).setGroup( renderGroup ).onRenderUpdate( () => shadow.camera.far );
132
105
  const bias = reference( 'bias', 'float', shadow ).setGroup( renderGroup );
133
- const mapSize = uniform( shadow.mapSize ).setGroup( renderGroup );
134
106
 
135
107
  const result = float( 1.0 ).toVar();
136
108
 
@@ -140,12 +112,11 @@ const pointShadowFilter = /*@__PURE__*/ Fn( ( { filterFn, depthTexture, shadowCo
140
112
  const dp = lightToPositionLength.sub( cameraNearLocal ).div( cameraFarLocal.sub( cameraNearLocal ) ).toVar(); // need to clamp?
141
113
  dp.addAssign( bias );
142
114
 
143
- // bd3D = base direction 3D
115
+ // bd3D = base direction 3D (direction from light to fragment)
144
116
  const bd3D = lightToPosition.normalize();
145
- const texelSize = vec2( 1.0 ).div( mapSize.mul( vec2( 4.0, 2.0 ) ) );
146
117
 
147
- // percentage-closer filtering
148
- result.assign( filterFn( { depthTexture, bd3D, dp, texelSize, shadow } ) );
118
+ // percentage-closer filtering using cube texture sampling
119
+ result.assign( filterFn( { depthTexture, bd3D, dp, shadow } ) );
149
120
 
150
121
  } );
151
122
 
@@ -153,10 +124,6 @@ const pointShadowFilter = /*@__PURE__*/ Fn( ( { filterFn, depthTexture, shadowCo
153
124
 
154
125
  } );
155
126
 
156
- const _viewport = /*@__PURE__*/ new Vector4();
157
- const _viewportSize = /*@__PURE__*/ new Vector2();
158
- const _shadowMapSize = /*@__PURE__*/ new Vector2();
159
-
160
127
 
161
128
  /**
162
129
  * Represents the shadow implementation for point light nodes.
@@ -216,15 +183,35 @@ class PointShadowNode extends ShadowNode {
216
183
  * @param {NodeBuilder} builder - A reference to the current node builder.
217
184
  * @param {Object} inputs - A configuration object that defines the shadow filtering.
218
185
  * @param {Function} inputs.filterFn - This function defines the filtering type of the shadow map e.g. PCF.
219
- * @param {Texture} inputs.shadowTexture - A reference to the shadow map's texture.
220
- * @param {DepthTexture} inputs.depthTexture - A reference to the shadow map's texture data.
186
+ * @param {DepthTexture} inputs.depthTexture - A reference to the shadow map's depth texture.
221
187
  * @param {Node<vec3>} inputs.shadowCoord - Shadow coordinates which are used to sample from the shadow map.
222
188
  * @param {LightShadow} inputs.shadow - The light shadow.
223
189
  * @return {Node<float>} The result node of the shadow filtering.
224
190
  */
225
- setupShadowFilter( builder, { filterFn, shadowTexture, depthTexture, shadowCoord, shadow } ) {
191
+ setupShadowFilter( builder, { filterFn, depthTexture, shadowCoord, shadow } ) {
192
+
193
+ return pointShadowFilter( { filterFn, depthTexture, shadowCoord, shadow } );
194
+
195
+ }
196
+
197
+ /**
198
+ * Overwrites the default implementation to create a CubeRenderTarget with CubeDepthTexture.
199
+ *
200
+ * @param {LightShadow} shadow - The light shadow object.
201
+ * @param {NodeBuilder} builder - A reference to the current node builder.
202
+ * @return {Object} An object containing the shadow map and depth texture.
203
+ */
204
+ setupRenderTarget( shadow, builder ) {
205
+
206
+ const depthTexture = new CubeDepthTexture( shadow.mapSize.width );
207
+ depthTexture.name = 'PointShadowDepthTexture';
208
+ depthTexture.compareFunction = LessCompare;
209
+
210
+ const shadowMap = builder.createCubeRenderTarget( shadow.mapSize.width );
211
+ shadowMap.texture.name = 'PointShadowMap';
212
+ shadowMap.depthTexture = depthTexture;
226
213
 
227
- return pointShadowFilter( { filterFn, shadowTexture, depthTexture, shadowCoord, shadow } );
214
+ return { shadowMap, depthTexture };
228
215
 
229
216
  }
230
217
 
@@ -239,14 +226,15 @@ class PointShadowNode extends ShadowNode {
239
226
  const { shadow, shadowMap, light } = this;
240
227
  const { renderer, scene } = frame;
241
228
 
242
- const shadowFrameExtents = shadow.getFrameExtents();
229
+ const camera = shadow.camera;
230
+ const shadowMatrix = shadow.matrix;
243
231
 
244
- _shadowMapSize.copy( shadow.mapSize );
245
- _shadowMapSize.multiply( shadowFrameExtents );
232
+ // Select cube directions/ups based on coordinate system
233
+ const isWebGPU = renderer.coordinateSystem === WebGPUCoordinateSystem;
234
+ const cubeDirections = isWebGPU ? _cubeDirectionsWebGPU : _cubeDirectionsWebGL;
235
+ const cubeUps = isWebGPU ? _cubeUpsWebGPU : _cubeUpsWebGL;
246
236
 
247
- shadowMap.setSize( _shadowMapSize.width, _shadowMapSize.height );
248
-
249
- _viewportSize.copy( shadow.mapSize );
237
+ shadowMap.setSize( shadow.mapSize.width, shadow.mapSize.width );
250
238
 
251
239
  //
252
240
 
@@ -257,33 +245,46 @@ class PointShadowNode extends ShadowNode {
257
245
 
258
246
  renderer.autoClear = false;
259
247
  renderer.setClearColor( shadow.clearColor, shadow.clearAlpha );
260
- renderer.clear();
261
248
 
262
- const viewportCount = shadow.getViewportCount();
249
+ // Render each cube face
250
+ for ( let face = 0; face < 6; face ++ ) {
251
+
252
+ // Set render target to the specific cube face
253
+ renderer.setRenderTarget( shadowMap, face );
254
+ renderer.clear();
255
+
256
+ // Update shadow camera matrices for this face
257
+
258
+ const far = light.distance || camera.far;
259
+
260
+ if ( far !== camera.far ) {
261
+
262
+ camera.far = far;
263
+ camera.updateProjectionMatrix();
263
264
 
264
- for ( let vp = 0; vp < viewportCount; vp ++ ) {
265
+ }
265
266
 
266
- const viewport = shadow.getViewport( vp );
267
+ _lightPositionWorld.setFromMatrixPosition( light.matrixWorld );
268
+ camera.position.copy( _lightPositionWorld );
267
269
 
268
- const x = _viewportSize.x * viewport.x;
269
- const y = _shadowMapSize.y - _viewportSize.y - ( _viewportSize.y * viewport.y );
270
+ _lookTarget.copy( camera.position );
271
+ _lookTarget.add( cubeDirections[ face ] );
272
+ camera.up.copy( cubeUps[ face ] );
273
+ camera.lookAt( _lookTarget );
274
+ camera.updateMatrixWorld();
270
275
 
271
- _viewport.set(
272
- x,
273
- y,
274
- _viewportSize.x * viewport.z,
275
- _viewportSize.y * viewport.w
276
- );
276
+ shadowMatrix.makeTranslation( - _lightPositionWorld.x, - _lightPositionWorld.y, - _lightPositionWorld.z );
277
277
 
278
- shadowMap.viewport.copy( _viewport );
278
+ _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse );
279
+ shadow._frustum.setFromProjectionMatrix( _projScreenMatrix, camera.coordinateSystem, camera.reversedDepth );
279
280
 
280
- shadow.updateMatrices( light, vp );
281
+ //
281
282
 
282
283
  const currentSceneName = scene.name;
283
284
 
284
- scene.name = `Point Light Shadow [ ${ light.name || 'ID: ' + light.id } ] - Face ${ vp + 1 }`;
285
+ scene.name = `Point Light Shadow [ ${ light.name || 'ID: ' + light.id } ] - Face ${ face + 1 }`;
285
286
 
286
- renderer.render( scene, shadow.camera );
287
+ renderer.render( scene, camera );
287
288
 
288
289
  scene.name = currentSceneName;
289
290
 
@@ -309,4 +310,4 @@ export default PointShadowNode;
309
310
  * @param {?PointLightShadow} [shadow=null] - An optional point light shadow.
310
311
  * @return {PointShadowNode} The created point shadow node.
311
312
  */
312
- export const pointShadow = ( light, shadow ) => nodeObject( new PointShadowNode( light, shadow ) );
313
+ export const pointShadow = ( light, shadow ) => new PointShadowNode( light, shadow );
@@ -7,6 +7,8 @@ import { renderGroup } from '../core/UniformGroupNode.js';
7
7
  import NodeMaterial from '../../materials/nodes/NodeMaterial.js';
8
8
  import { objectPosition } from '../accessors/Object3DNode.js';
9
9
  import { positionWorld } from '../accessors/Position.js';
10
+ import { screenCoordinate } from '../display/ScreenNode.js';
11
+ import { interleavedGradientNoise, vogelDiskSample } from '../utils/PostProcessingUtils.js';
10
12
 
11
13
  const shadowMaterialLib = /*@__PURE__*/ new WeakMap();
12
14
 
@@ -35,7 +37,11 @@ export const BasicShadowFilter = /*@__PURE__*/ Fn( ( { depthTexture, shadowCoord
35
37
  } );
36
38
 
37
39
  /**
38
- * A shadow filtering function performing PCF filtering.
40
+ * A shadow filtering function performing PCF filtering with Vogel disk sampling and IGN.
41
+ *
42
+ * Uses 5 samples distributed via Vogel disk pattern, rotated per-pixel using Interleaved
43
+ * Gradient Noise (IGN) to break up banding artifacts. Combined with hardware PCF (4-tap
44
+ * filtering per sample), this effectively provides 20 filtered taps with better distribution.
39
45
  *
40
46
  * @method
41
47
  * @param {Object} inputs - The input parameter object.
@@ -64,34 +70,19 @@ export const PCFShadowFilter = /*@__PURE__*/ Fn( ( { depthTexture, shadowCoord,
64
70
  const radius = reference( 'radius', 'float', shadow ).setGroup( renderGroup );
65
71
 
66
72
  const texelSize = vec2( 1 ).div( mapSize );
67
- const dx0 = texelSize.x.negate().mul( radius );
68
- const dy0 = texelSize.y.negate().mul( radius );
69
- const dx1 = texelSize.x.mul( radius );
70
- const dy1 = texelSize.y.mul( radius );
71
- const dx2 = dx0.div( 2 );
72
- const dy2 = dy0.div( 2 );
73
- const dx3 = dx1.div( 2 );
74
- const dy3 = dy1.div( 2 );
73
+ const radiusScaled = radius.mul( texelSize.x );
74
+
75
+ // Use IGN to rotate sampling pattern per pixel (phi = IGN * 2π)
76
+ const phi = interleavedGradientNoise( screenCoordinate.xy ).mul( 6.28318530718 );
75
77
 
78
+ // 5 samples using Vogel disk distribution
76
79
  return add(
77
- depthCompare( shadowCoord.xy.add( vec2( dx0, dy0 ) ), shadowCoord.z ),
78
- depthCompare( shadowCoord.xy.add( vec2( 0, dy0 ) ), shadowCoord.z ),
79
- depthCompare( shadowCoord.xy.add( vec2( dx1, dy0 ) ), shadowCoord.z ),
80
- depthCompare( shadowCoord.xy.add( vec2( dx2, dy2 ) ), shadowCoord.z ),
81
- depthCompare( shadowCoord.xy.add( vec2( 0, dy2 ) ), shadowCoord.z ),
82
- depthCompare( shadowCoord.xy.add( vec2( dx3, dy2 ) ), shadowCoord.z ),
83
- depthCompare( shadowCoord.xy.add( vec2( dx0, 0 ) ), shadowCoord.z ),
84
- depthCompare( shadowCoord.xy.add( vec2( dx2, 0 ) ), shadowCoord.z ),
85
- depthCompare( shadowCoord.xy, shadowCoord.z ),
86
- depthCompare( shadowCoord.xy.add( vec2( dx3, 0 ) ), shadowCoord.z ),
87
- depthCompare( shadowCoord.xy.add( vec2( dx1, 0 ) ), shadowCoord.z ),
88
- depthCompare( shadowCoord.xy.add( vec2( dx2, dy3 ) ), shadowCoord.z ),
89
- depthCompare( shadowCoord.xy.add( vec2( 0, dy3 ) ), shadowCoord.z ),
90
- depthCompare( shadowCoord.xy.add( vec2( dx3, dy3 ) ), shadowCoord.z ),
91
- depthCompare( shadowCoord.xy.add( vec2( dx0, dy1 ) ), shadowCoord.z ),
92
- depthCompare( shadowCoord.xy.add( vec2( 0, dy1 ) ), shadowCoord.z ),
93
- depthCompare( shadowCoord.xy.add( vec2( dx1, dy1 ) ), shadowCoord.z )
94
- ).mul( 1 / 17 );
80
+ depthCompare( shadowCoord.xy.add( vogelDiskSample( 0, 5, phi ).mul( radiusScaled ) ), shadowCoord.z ),
81
+ depthCompare( shadowCoord.xy.add( vogelDiskSample( 1, 5, phi ).mul( radiusScaled ) ), shadowCoord.z ),
82
+ depthCompare( shadowCoord.xy.add( vogelDiskSample( 2, 5, phi ).mul( radiusScaled ) ), shadowCoord.z ),
83
+ depthCompare( shadowCoord.xy.add( vogelDiskSample( 3, 5, phi ).mul( radiusScaled ) ), shadowCoord.z ),
84
+ depthCompare( shadowCoord.xy.add( vogelDiskSample( 4, 5, phi ).mul( radiusScaled ) ), shadowCoord.z )
85
+ ).mul( 1 / 5 );
95
86
 
96
87
  } );
97
88
 
@@ -185,8 +176,6 @@ export const PCFSoftShadowFilter = /*@__PURE__*/ Fn( ( { depthTexture, shadowCoo
185
176
  */
186
177
  export const VSMShadowFilter = /*@__PURE__*/ Fn( ( { depthTexture, shadowCoord, depthLayer } ) => {
187
178
 
188
- const occlusion = float( 1 ).toVar();
189
-
190
179
  let distribution = texture( depthTexture ).sample( shadowCoord.xy );
191
180
 
192
181
  if ( depthTexture.isArrayTexture ) {
@@ -197,19 +186,28 @@ export const VSMShadowFilter = /*@__PURE__*/ Fn( ( { depthTexture, shadowCoord,
197
186
 
198
187
  distribution = distribution.rg;
199
188
 
200
- const hardShadow = step( shadowCoord.z, distribution.x );
189
+ const mean = distribution.x;
190
+ const variance = max( 0.0000001, distribution.y.mul( distribution.y ) );
201
191
 
202
- If( hardShadow.notEqual( float( 1.0 ) ), () => {
192
+ const hardShadow = step( shadowCoord.z, mean );
203
193
 
204
- const distance = shadowCoord.z.sub( distribution.x );
205
- const variance = max( 0, distribution.y.mul( distribution.y ) );
206
- let softnessProbability = variance.div( variance.add( distance.mul( distance ) ) ); // Chebeyshevs inequality
207
- softnessProbability = clamp( sub( softnessProbability, 0.3 ).div( 0.95 - 0.3 ) );
208
- occlusion.assign( clamp( max( hardShadow, softnessProbability ) ) );
194
+ // Early return if fully lit
195
+ If( hardShadow.equal( 1.0 ), () => {
196
+
197
+ return float( 1.0 );
209
198
 
210
199
  } );
211
200
 
212
- return occlusion;
201
+ // Distance from mean
202
+ const d = shadowCoord.z.sub( mean );
203
+
204
+ // Chebyshev's inequality for upper bound on probability
205
+ let p_max = variance.div( variance.add( d.mul( d ) ) );
206
+
207
+ // Reduce light bleeding by remapping [amount, 1] to [0, 1]
208
+ p_max = clamp( sub( p_max, 0.3 ).div( 0.65 ) );
209
+
210
+ return max( hardShadow, p_max );
213
211
 
214
212
  } );
215
213
 
@@ -274,3 +272,21 @@ export const getShadowMaterial = ( light ) => {
274
272
  return material;
275
273
 
276
274
  };
275
+
276
+ /**
277
+ * Disposes the shadow material for the given light source.
278
+ *
279
+ * @param {Light} light - The light source.
280
+ */
281
+ export const disposeShadowMaterial = ( light ) => {
282
+
283
+ const material = shadowMaterialLib.get( light );
284
+
285
+ if ( material !== undefined ) {
286
+
287
+ material.dispose();
288
+ shadowMaterialLib.delete( light );
289
+
290
+ }
291
+
292
+ };
@@ -1,7 +1,8 @@
1
1
  import ShadowBaseNode, { shadowPositionWorld } from './ShadowBaseNode.js';
2
- import { float, vec2, vec3, int, Fn, nodeObject } from '../tsl/TSLBase.js';
2
+ import { float, vec2, vec3, int, Fn } from '../tsl/TSLBase.js';
3
3
  import { reference } from '../accessors/ReferenceNode.js';
4
4
  import { texture, textureLoad } from '../accessors/TextureNode.js';
5
+ import { cubeTexture } from '../accessors/CubeTextureNode.js';
5
6
  import { normalWorld } from '../accessors/Normal.js';
6
7
  import { mix, sqrt } from '../math/MathNode.js';
7
8
  import { add } from '../math/OperatorNode.js';
@@ -16,7 +17,7 @@ import { viewZToLogarithmicDepth } from '../display/ViewportDepthNode.js';
16
17
  import { lightShadowMatrix } from '../accessors/Lights.js';
17
18
  import { resetRendererAndSceneState, restoreRendererAndSceneState } from '../../renderers/common/RendererUtils.js';
18
19
  import { getDataFromObject } from '../core/NodeUtils.js';
19
- import { getShadowMaterial, BasicShadowFilter, PCFShadowFilter, PCFSoftShadowFilter, VSMShadowFilter } from './ShadowFilterNode.js';
20
+ import { getShadowMaterial, disposeShadowMaterial, BasicShadowFilter, PCFShadowFilter, PCFSoftShadowFilter, VSMShadowFilter } from './ShadowFilterNode.js';
20
21
  import ChainMap from '../../renderers/common/ChainMap.js';
21
22
  import { warn } from '../../utils.js';
22
23
  import { textureSize } from '../accessors/TextureSizeNode.js';
@@ -36,16 +37,7 @@ const _shadowRenderObjectKeys = [];
36
37
  * @param {LightShadow} shadow - The light shadow object containing shadow properties.
37
38
  * @param {number} shadowType - The type of shadow map (e.g., BasicShadowMap).
38
39
  * @param {boolean} useVelocity - Whether to use velocity data for rendering.
39
- * @return {Function} A function that renders shadow objects.
40
- *
41
- * The returned function has the following parameters:
42
- * @param {Object3D} object - The 3D object to render.
43
- * @param {Scene} scene - The scene containing the object.
44
- * @param {Camera} _camera - The camera used for rendering.
45
- * @param {BufferGeometry} geometry - The geometry of the object.
46
- * @param {Material} material - The material of the object.
47
- * @param {Group} group - The group the object belongs to.
48
- * @param {...any} params - Additional parameters for rendering.
40
+ * @return {shadowRenderObjectFunction} A function that renders shadow objects.
49
41
  */
50
42
  export const getShadowRenderObjectFunction = ( renderer, shadow, shadowType, useVelocity ) => {
51
43
 
@@ -93,6 +85,7 @@ export const getShadowRenderObjectFunction = ( renderer, shadow, shadowType, use
93
85
  /**
94
86
  * Represents the shader code for the first VSM render pass.
95
87
  *
88
+ * @private
96
89
  * @method
97
90
  * @param {Object} inputs - The input parameter object.
98
91
  * @param {Node<float>} inputs.samples - The number of samples
@@ -131,7 +124,7 @@ const VSMPassVertical = /*@__PURE__*/ Fn( ( { samples, radius, size, shadowPass,
131
124
  mean.divAssign( samples );
132
125
  squaredMean.divAssign( samples );
133
126
 
134
- const std_dev = sqrt( squaredMean.sub( mean.mul( mean ) ) );
127
+ const std_dev = sqrt( squaredMean.sub( mean.mul( mean ) ).max( 0 ) );
135
128
  return vec2( mean, std_dev );
136
129
 
137
130
  } );
@@ -139,6 +132,7 @@ const VSMPassVertical = /*@__PURE__*/ Fn( ( { samples, radius, size, shadowPass,
139
132
  /**
140
133
  * Represents the shader code for the second VSM render pass.
141
134
  *
135
+ * @private
142
136
  * @method
143
137
  * @param {Object} inputs - The input parameter object.
144
138
  * @param {Node<float>} inputs.samples - The number of samples
@@ -175,7 +169,7 @@ const VSMPassHorizontal = /*@__PURE__*/ Fn( ( { samples, radius, size, shadowPas
175
169
  mean.divAssign( samples );
176
170
  squaredMean.divAssign( samples );
177
171
 
178
- const std_dev = sqrt( squaredMean.sub( mean.mul( mean ) ) );
172
+ const std_dev = sqrt( squaredMean.sub( mean.mul( mean ) ).max( 0 ) );
179
173
  return vec2( mean, std_dev );
180
174
 
181
175
  } );
@@ -523,11 +517,22 @@ class ShadowNode extends ShadowBaseNode {
523
517
 
524
518
  const shadowNode = this.setupShadowFilter( builder, { filterFn, shadowTexture: shadowMap.texture, depthTexture: shadowDepthTexture, shadowCoord, shadow, depthLayer: this.depthLayer } );
525
519
 
526
- let shadowColor = texture( shadowMap.texture, shadowCoord );
520
+ let shadowColor;
527
521
 
528
- if ( depthTexture.isArrayTexture ) {
522
+ if ( shadowMap.texture.isCubeTexture ) {
529
523
 
530
- shadowColor = shadowColor.depth( this.depthLayer );
524
+ // For cube shadow maps (point lights), use cubeTexture with vec3 coordinates
525
+ shadowColor = cubeTexture( shadowMap.texture, shadowCoord.xyz );
526
+
527
+ } else {
528
+
529
+ shadowColor = texture( shadowMap.texture, shadowCoord );
530
+
531
+ if ( depthTexture.isArrayTexture ) {
532
+
533
+ shadowColor = shadowColor.depth( this.depthLayer );
534
+
535
+ }
531
536
 
532
537
  }
533
538
 
@@ -542,11 +547,25 @@ class ShadowNode extends ShadowBaseNode {
542
547
 
543
548
  return shadowOutput.toInspector( `${ inspectName } / Color`, () => {
544
549
 
550
+ if ( this.shadowMap.texture.isCubeTexture ) {
551
+
552
+ return cubeTexture( this.shadowMap.texture );
553
+
554
+ }
555
+
545
556
  return texture( this.shadowMap.texture );
546
557
 
547
558
  } ).toInspector( `${ inspectName } / Depth`, () => {
548
559
 
549
- return textureLoad( this.shadowMap.depthTexture, uv().mul( textureSize( texture( this.shadowMap.depthTexture ) ) ) ).x.oneMinus();
560
+ // TODO: Use linear depth
561
+
562
+ if ( this.shadowMap.texture.isCubeTexture ) {
563
+
564
+ return cubeTexture( this.shadowMap.texture ).r.oneMinus();
565
+
566
+ }
567
+
568
+ return textureLoad( this.shadowMap.depthTexture, uv().mul( textureSize( texture( this.shadowMap.depthTexture ) ) ) ).r.oneMinus();
550
569
 
551
570
  } );
552
571
 
@@ -729,6 +748,8 @@ class ShadowNode extends ShadowBaseNode {
729
748
 
730
749
  this._currentShadowType = null;
731
750
 
751
+ disposeShadowMaterial( this.light );
752
+
732
753
  if ( this.shadowMap ) {
733
754
 
734
755
  this.shadowMap.dispose();
@@ -799,6 +820,19 @@ class ShadowNode extends ShadowBaseNode {
799
820
 
800
821
  export default ShadowNode;
801
822
 
823
+ /**
824
+ * Shadow Render Object Function.
825
+ *
826
+ * @function shadowRenderObjectFunction
827
+ * @param {Object3D} object - The 3D object to render.
828
+ * @param {Scene} scene - The scene containing the object.
829
+ * @param {Camera} _camera - The camera used for rendering.
830
+ * @param {BufferGeometry} geometry - The geometry of the object.
831
+ * @param {Material} material - The material of the object.
832
+ * @param {Group} group - The group the object belongs to.
833
+ * @param {...any} params - Additional parameters for rendering.
834
+ */
835
+
802
836
  /**
803
837
  * TSL function for creating an instance of `ShadowNode`.
804
838
  *
@@ -808,4 +842,4 @@ export default ShadowNode;
808
842
  * @param {?LightShadow} [shadow] - The light shadow.
809
843
  * @return {ShadowNode} The created shadow node.
810
844
  */
811
- export const shadow = ( light, shadow ) => nodeObject( new ShadowNode( light, shadow ) );
845
+ export const shadow = ( light, shadow ) => new ShadowNode( light, shadow );