super-three 0.184.0 → 0.185.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 (366) hide show
  1. package/build/three.cjs +1260 -927
  2. package/build/three.core.js +1104 -829
  3. package/build/three.core.min.js +1 -1
  4. package/build/three.module.js +156 -98
  5. package/build/three.module.min.js +1 -1
  6. package/build/three.tsl.js +11 -4
  7. package/build/three.tsl.min.js +1 -1
  8. package/build/three.webgpu.js +7538 -3367
  9. package/build/three.webgpu.min.js +1 -1
  10. package/build/three.webgpu.nodes.js +7538 -3366
  11. package/build/three.webgpu.nodes.min.js +1 -1
  12. package/examples/jsm/Addons.js +3 -0
  13. package/examples/jsm/controls/ArcballControls.js +6 -2
  14. package/examples/jsm/controls/FirstPersonControls.js +79 -42
  15. package/examples/jsm/controls/TransformControls.js +68 -15
  16. package/examples/jsm/csm/CSMFrustum.js +31 -6
  17. package/examples/jsm/csm/CSMShadowNode.js +4 -1
  18. package/examples/jsm/effects/AsciiEffect.js +14 -1
  19. package/examples/jsm/exporters/DRACOExporter.js +27 -6
  20. package/examples/jsm/exporters/GLTFExporter.js +114 -12
  21. package/examples/jsm/exporters/PLYExporter.js +286 -73
  22. package/examples/jsm/exporters/USDZExporter.js +347 -112
  23. package/examples/jsm/generators/CityGenerator.js +346 -0
  24. package/examples/jsm/generators/ForestGenerator.js +347 -0
  25. package/examples/jsm/generators/TerrainGenerator.js +504 -0
  26. package/examples/jsm/generators/TreeGenerator.js +377 -0
  27. package/examples/jsm/generators/city/SidewalkGenerator.js +253 -0
  28. package/examples/jsm/generators/city/SkyscraperGenerator.js +1357 -0
  29. package/examples/jsm/geometries/LoftGeometry.js +355 -0
  30. package/examples/jsm/helpers/LightProbeGridHelper.js +1 -1
  31. package/examples/jsm/helpers/LightProbeHelper.js +5 -4
  32. package/examples/jsm/helpers/ViewHelper.js +16 -6
  33. package/examples/jsm/inspector/Inspector.js +53 -15
  34. package/examples/jsm/inspector/RendererInspector.js +152 -36
  35. package/examples/jsm/inspector/extensions/tsl-graph/TSLGraphEditor.js +1 -1
  36. package/examples/jsm/inspector/extensions/tsl-graph/TSLGraphLoader.js +1 -1
  37. package/examples/jsm/inspector/tabs/Console.js +200 -18
  38. package/examples/jsm/inspector/tabs/Memory.js +8 -0
  39. package/examples/jsm/inspector/tabs/Parameters.js +64 -4
  40. package/examples/jsm/inspector/tabs/Performance.js +21 -6
  41. package/examples/jsm/inspector/tabs/Settings.js +51 -9
  42. package/examples/jsm/inspector/tabs/Timeline.js +178 -93
  43. package/examples/jsm/inspector/tabs/Viewer.js +628 -16
  44. package/examples/jsm/inspector/ui/Graph.js +162 -25
  45. package/examples/jsm/inspector/ui/Item.js +92 -13
  46. package/examples/jsm/inspector/ui/List.js +1 -1
  47. package/examples/jsm/inspector/ui/Profiler.js +90 -45
  48. package/examples/jsm/inspector/ui/Style.js +1788 -1401
  49. package/examples/jsm/inspector/ui/Tab.js +5 -3
  50. package/examples/jsm/inspector/ui/Values.js +71 -6
  51. package/examples/jsm/inspector/ui/utils.js +130 -10
  52. package/examples/jsm/libs/basis/README.md +0 -1
  53. package/examples/jsm/libs/demuxer_mp4.js +3 -3
  54. package/examples/jsm/libs/draco/README.md +0 -1
  55. package/examples/jsm/libs/meshopt_clusterizer.module.js +421 -0
  56. package/examples/jsm/libs/meshopt_simplifier.module.js +627 -0
  57. package/examples/jsm/libs/mikktspace.module.js +34 -9
  58. package/examples/jsm/lighting/ClusteredLighting.js +55 -0
  59. package/examples/jsm/lighting/LightProbeGrid.js +106 -76
  60. package/examples/jsm/lines/LineMaterial.js +38 -15
  61. package/examples/jsm/lines/LineSegments2.js +8 -0
  62. package/examples/jsm/lines/webgpu/LineSegments2.js +8 -0
  63. package/examples/jsm/loaders/3DMLoader.js +1 -1
  64. package/examples/jsm/loaders/DRACOLoader.js +46 -13
  65. package/examples/jsm/loaders/EXRLoader.js +27 -55
  66. package/examples/jsm/loaders/HDRLoader.js +6 -28
  67. package/examples/jsm/loaders/KTX2Loader.js +31 -12
  68. package/examples/jsm/loaders/LDrawLoader.js +8 -8
  69. package/examples/jsm/loaders/LUT3dlLoader.js +2 -2
  70. package/examples/jsm/loaders/LUTCubeLoader.js +2 -2
  71. package/examples/jsm/loaders/LWOLoader.js +4 -0
  72. package/examples/jsm/loaders/LottieLoader.js +1 -1
  73. package/examples/jsm/loaders/MaterialXLoader.js +31 -9
  74. package/examples/jsm/loaders/NRRDLoader.js +3 -3
  75. package/examples/jsm/loaders/PCDLoader.js +7 -7
  76. package/examples/jsm/loaders/PLYLoader.js +218 -55
  77. package/examples/jsm/loaders/SVGLoader.js +547 -495
  78. package/examples/jsm/loaders/TTFLoader.js +1 -1
  79. package/examples/jsm/loaders/USDLoader.js +33 -9
  80. package/examples/jsm/loaders/VRMLLoader.js +1 -1
  81. package/examples/jsm/loaders/usd/USDAParser.js +93 -20
  82. package/examples/jsm/loaders/usd/USDCParser.js +1 -1
  83. package/examples/jsm/loaders/usd/USDComposer.js +52 -19
  84. package/examples/jsm/misc/TileCreasedNormalsPlugin.js +270 -0
  85. package/examples/jsm/misc/Volume.js +2 -2
  86. package/examples/jsm/objects/GroundedSkybox.js +1 -1
  87. package/examples/jsm/objects/Reflector.js +2 -3
  88. package/examples/jsm/objects/Water2Mesh.js +1 -1
  89. package/examples/jsm/physics/AmmoPhysics.js +15 -8
  90. package/examples/jsm/physics/RapierPhysics.js +27 -2
  91. package/examples/jsm/shaders/VolumeShader.js +31 -44
  92. package/examples/jsm/transpiler/GLSLDecoder.js +6 -6
  93. package/examples/jsm/transpiler/Linker.js +1 -1
  94. package/examples/jsm/tsl/display/BloomNode.js +59 -19
  95. package/examples/jsm/tsl/display/DepthOfFieldNode.js +2 -2
  96. package/examples/jsm/tsl/display/FXAANode.js +11 -12
  97. package/examples/jsm/tsl/display/GTAONode.js +34 -13
  98. package/examples/jsm/tsl/display/GodraysNode.js +1 -1
  99. package/examples/jsm/tsl/display/ImportanceSampledEnvironment.js +560 -0
  100. package/examples/jsm/tsl/display/PixelationPassNode.js +2 -2
  101. package/examples/jsm/tsl/display/RecurrentDenoiseNode.js +912 -0
  102. package/examples/jsm/tsl/display/SSAAPassNode.js +13 -25
  103. package/examples/jsm/tsl/display/SSGINode.js +89 -39
  104. package/examples/jsm/tsl/display/SSRNode.js +829 -132
  105. package/examples/jsm/tsl/display/SSSNode.js +2 -2
  106. package/examples/jsm/tsl/display/TemporalReprojectNode.js +1023 -0
  107. package/examples/jsm/tsl/lighting/ClusteredLightsNode.js +622 -0
  108. package/examples/jsm/tsl/lighting/DynamicLightsNode.js +1 -1
  109. package/examples/jsm/tsl/math/curlNoise.js +107 -0
  110. package/examples/jsm/tsl/shadows/TileShadowNode.js +1 -1
  111. package/examples/jsm/tsl/shadows/TileShadowNodeHelper.js +3 -3
  112. package/examples/jsm/tsl/utils/GroundedSkybox.js +62 -0
  113. package/examples/jsm/tsl/utils/RNoise.js +51 -0
  114. package/examples/jsm/tsl/utils/SpecularHelpers.js +325 -0
  115. package/examples/jsm/utils/BufferGeometryUtils.js +126 -59
  116. package/examples/jsm/utils/GeometryCompressionUtils.js +1 -1
  117. package/examples/jsm/utils/SceneOptimizer.js +1 -1
  118. package/examples/jsm/webxr/ARButton.js +1 -1
  119. package/examples/jsm/webxr/WebGLXRFallback.js +89 -0
  120. package/examples/jsm/webxr/XRControllerModelFactory.js +2 -2
  121. package/package.json +7 -7
  122. package/src/Three.TSL.js +10 -3
  123. package/src/Three.WebGPU.js +4 -0
  124. package/src/animation/AnimationAction.js +15 -11
  125. package/src/animation/AnimationClip.js +0 -139
  126. package/src/animation/KeyframeTrack.js +2 -2
  127. package/src/animation/PropertyBinding.js +2 -2
  128. package/src/cameras/Camera.js +2 -2
  129. package/src/cameras/StereoCamera.js +5 -2
  130. package/src/constants.js +1 -1
  131. package/src/core/BufferGeometry.js +29 -7
  132. package/src/core/Object3D.js +17 -7
  133. package/src/core/Raycaster.js +1 -1
  134. package/src/core/RenderTarget.js +15 -2
  135. package/src/extras/PMREMGenerator.js +6 -4
  136. package/src/extras/TextureUtils.js +1 -1
  137. package/src/extras/core/ShapePath.js +149 -160
  138. package/src/geometries/SphereGeometry.js +8 -3
  139. package/src/helpers/DirectionalLightHelper.js +2 -0
  140. package/src/helpers/HemisphereLightHelper.js +2 -0
  141. package/src/helpers/PointLightHelper.js +2 -0
  142. package/src/helpers/SpotLightHelper.js +1 -1
  143. package/src/loaders/DataTextureLoader.js +69 -38
  144. package/src/loaders/LoadingManager.js +5 -0
  145. package/src/loaders/MaterialLoader.js +36 -266
  146. package/src/loaders/ObjectLoader.js +3 -1
  147. package/src/materials/LineBasicMaterial.js +4 -0
  148. package/src/materials/Material.js +196 -1
  149. package/src/materials/MeshBasicMaterial.js +24 -0
  150. package/src/materials/MeshDepthMaterial.js +10 -0
  151. package/src/materials/MeshDistanceMaterial.js +10 -0
  152. package/src/materials/MeshLambertMaterial.js +40 -1
  153. package/src/materials/MeshMatcapMaterial.js +25 -1
  154. package/src/materials/MeshNormalMaterial.js +9 -1
  155. package/src/materials/MeshPhongMaterial.js +40 -1
  156. package/src/materials/MeshPhysicalMaterial.js +38 -0
  157. package/src/materials/MeshStandardMaterial.js +42 -1
  158. package/src/materials/MeshToonMaterial.js +34 -1
  159. package/src/materials/PointsMaterial.js +7 -0
  160. package/src/materials/ShaderMaterial.js +86 -0
  161. package/src/materials/SpriteMaterial.js +7 -0
  162. package/src/materials/nodes/Line2NodeMaterial.js +378 -322
  163. package/src/materials/nodes/MeshBasicNodeMaterial.js +2 -2
  164. package/src/materials/nodes/MeshNormalNodeMaterial.js +2 -2
  165. package/src/materials/nodes/MeshPhongNodeMaterial.js +0 -9
  166. package/src/materials/nodes/MeshPhysicalNodeMaterial.js +0 -30
  167. package/src/materials/nodes/MeshSSSNodeMaterial.js +0 -13
  168. package/src/materials/nodes/MeshStandardNodeMaterial.js +0 -11
  169. package/src/materials/nodes/NodeMaterial.js +115 -71
  170. package/src/materials/nodes/SpriteNodeMaterial.js +0 -10
  171. package/src/materials/nodes/manager/NodeMaterialObserver.js +49 -20
  172. package/src/math/Box3.js +5 -0
  173. package/src/math/FrustumArray.js +103 -133
  174. package/src/math/Interpolant.js +1 -1
  175. package/src/math/MathUtils.js +2 -2
  176. package/src/math/Matrix3.js +11 -0
  177. package/src/math/Matrix4.js +28 -3
  178. package/src/math/Vector2.js +2 -2
  179. package/src/math/Vector3.js +2 -2
  180. package/src/math/Vector4.js +2 -2
  181. package/src/math/interpolants/BezierInterpolant.js +4 -6
  182. package/src/nodes/Nodes.js +2 -5
  183. package/src/nodes/TSL.js +8 -6
  184. package/src/nodes/accessors/Arrays.js +4 -4
  185. package/src/nodes/accessors/Batch.js +108 -0
  186. package/src/nodes/accessors/Bitangent.js +2 -2
  187. package/src/nodes/accessors/BufferAttributeNode.js +13 -2
  188. package/src/nodes/accessors/Camera.js +7 -7
  189. package/src/nodes/accessors/ClippingNode.js +1 -1
  190. package/src/nodes/accessors/Instance.js +264 -0
  191. package/src/nodes/accessors/MaterialNode.js +18 -2
  192. package/src/nodes/accessors/MaterialProperties.js +4 -3
  193. package/src/nodes/accessors/{MorphNode.js → Morph.js} +99 -112
  194. package/src/nodes/accessors/Normal.js +13 -13
  195. package/src/nodes/accessors/Position.js +5 -1
  196. package/src/nodes/accessors/ReferenceNode.js +1 -0
  197. package/src/nodes/accessors/ReflectVector.js +3 -3
  198. package/src/nodes/accessors/SceneProperties.js +1 -1
  199. package/src/nodes/accessors/Skinning.js +263 -0
  200. package/src/nodes/accessors/StorageBufferNode.js +2 -2
  201. package/src/nodes/accessors/StorageTexture3DNode.js +100 -0
  202. package/src/nodes/accessors/StorageTextureNode.js +39 -7
  203. package/src/nodes/accessors/Tangent.js +4 -4
  204. package/src/nodes/accessors/TextureNode.js +60 -5
  205. package/src/nodes/code/FunctionNode.js +2 -16
  206. package/src/nodes/core/MRTNode.js +7 -2
  207. package/src/nodes/core/Node.js +39 -2
  208. package/src/nodes/core/NodeBuilder.js +201 -41
  209. package/src/nodes/core/NodeUtils.js +13 -13
  210. package/src/nodes/core/OutputStructNode.js +1 -1
  211. package/src/nodes/core/OverrideContextNode.js +153 -0
  212. package/src/nodes/core/PropertyNode.js +51 -5
  213. package/src/nodes/core/StackNode.js +56 -34
  214. package/src/nodes/core/StructNode.js +4 -6
  215. package/src/nodes/core/StructTypeNode.js +6 -6
  216. package/src/nodes/core/VarNode.js +8 -0
  217. package/src/nodes/core/VaryingNode.js +12 -2
  218. package/src/nodes/display/BlendModes.js +1 -41
  219. package/src/nodes/display/BumpMapNode.js +6 -1
  220. package/src/nodes/display/ColorAdjustment.js +10 -9
  221. package/src/nodes/display/FrontFacingNode.js +38 -9
  222. package/src/nodes/display/NormalMapNode.js +2 -2
  223. package/src/nodes/display/PassNode.js +35 -43
  224. package/src/nodes/display/PremultiplyAlphaFunctions.js +39 -0
  225. package/src/nodes/display/RenderOutputNode.js +12 -3
  226. package/src/nodes/functions/VolumetricLightingModel.js +40 -7
  227. package/src/nodes/gpgpu/WorkgroupInfoNode.js +1 -1
  228. package/src/nodes/lighting/EnvironmentNode.js +2 -2
  229. package/src/nodes/lighting/IESSpotLightNode.js +40 -2
  230. package/src/nodes/lighting/LightingContextNode.js +10 -2
  231. package/src/nodes/lighting/LightsNode.js +90 -37
  232. package/src/nodes/lighting/PointShadowNode.js +6 -1
  233. package/src/nodes/lighting/ShadowFilterNode.js +21 -52
  234. package/src/nodes/lighting/ShadowNode.js +34 -14
  235. package/src/nodes/materialx/lib/mx_noise.js +2 -2
  236. package/src/nodes/math/ConditionalNode.js +3 -3
  237. package/src/nodes/math/MathNode.js +39 -11
  238. package/src/nodes/math/OperatorNode.js +23 -23
  239. package/src/nodes/parsers/GLSLNodeFunction.js +1 -1
  240. package/src/nodes/pmrem/PMREMNode.js +33 -2
  241. package/src/nodes/tsl/TSLCore.js +63 -18
  242. package/src/nodes/utils/EquirectUV.js +30 -5
  243. package/src/nodes/utils/FunctionOverloadingNode.js +1 -1
  244. package/src/nodes/utils/Packing.js +35 -4
  245. package/src/nodes/utils/RTTNode.js +40 -24
  246. package/src/nodes/utils/ReflectorNode.js +1 -0
  247. package/src/nodes/utils/StorageArrayElementNode.js +1 -1
  248. package/src/objects/BatchedMesh.js +22 -14
  249. package/src/objects/InstancedMesh.js +0 -11
  250. package/src/objects/Skeleton.js +0 -9
  251. package/src/renderers/WebGLRenderer.js +19 -15
  252. package/src/renderers/common/Backend.js +49 -5
  253. package/src/renderers/common/Bindings.js +114 -45
  254. package/src/renderers/common/Buffer.js +9 -0
  255. package/src/renderers/common/ClippingContext.js +10 -2
  256. package/src/renderers/common/Info.js +63 -22
  257. package/src/renderers/common/Lighting.js +53 -5
  258. package/src/renderers/common/RenderList.js +41 -4
  259. package/src/renderers/common/RenderObject.js +73 -13
  260. package/src/renderers/common/Renderer.js +281 -108
  261. package/src/renderers/common/Sampler.js +16 -48
  262. package/src/renderers/common/Textures.js +32 -5
  263. package/src/renderers/common/TimestampQueryPool.js +1 -1
  264. package/src/renderers/common/UniformsGroup.js +31 -9
  265. package/src/renderers/common/XRManager.js +340 -22
  266. package/src/renderers/common/extras/PMREMGenerator.js +15 -38
  267. package/src/renderers/common/nodes/NodeBuilderState.js +9 -1
  268. package/src/renderers/common/nodes/NodeLibrary.js +4 -4
  269. package/src/renderers/common/nodes/NodeManager.js +63 -14
  270. package/src/renderers/common/nodes/NodeUniformBuffer.js +13 -0
  271. package/src/renderers/shaders/ShaderChunk/common.glsl.js +13 -4
  272. package/src/renderers/shaders/ShaderChunk/defaultnormal_vertex.glsl.js +0 -6
  273. package/src/renderers/shaders/ShaderChunk/envmap_fragment.glsl.js +1 -1
  274. package/src/renderers/shaders/ShaderChunk/envmap_physical_pars_fragment.glsl.js +2 -2
  275. package/src/renderers/shaders/ShaderChunk/envmap_vertex.glsl.js +1 -1
  276. package/src/renderers/shaders/ShaderChunk/lights_fragment_begin.glsl.js +1 -1
  277. package/src/renderers/shaders/ShaderChunk/lights_pars_begin.glsl.js +1 -1
  278. package/src/renderers/shaders/ShaderChunk/normal_fragment_begin.glsl.js +2 -2
  279. package/src/renderers/shaders/ShaderChunk/normal_vertex.glsl.js +6 -0
  280. package/src/renderers/shaders/ShaderChunk/shadowmap_vertex.glsl.js +1 -1
  281. package/src/renderers/shaders/ShaderChunk/transmission_fragment.glsl.js +1 -1
  282. package/src/renderers/shaders/ShaderLib/distance.glsl.js +1 -1
  283. package/src/renderers/webgl/WebGLOutput.js +2 -1
  284. package/src/renderers/webgl/WebGLProgram.js +5 -4
  285. package/src/renderers/webgl/WebGLPrograms.js +12 -5
  286. package/src/renderers/webgl/WebGLRenderLists.js +9 -1
  287. package/src/renderers/webgl/WebGLShaderCache.js +5 -11
  288. package/src/renderers/webgl/WebGLTextures.js +20 -7
  289. package/src/renderers/webgl/WebGLUniformsGroups.js +66 -38
  290. package/src/renderers/webgl-fallback/WebGLBackend.js +84 -25
  291. package/src/renderers/webgl-fallback/nodes/GLSLNodeBuilder.js +138 -8
  292. package/src/renderers/webgl-fallback/utils/WebGLAttributeUtils.js +1 -1
  293. package/src/renderers/webgl-fallback/utils/WebGLTextureUtils.js +52 -22
  294. package/src/renderers/webgl-fallback/utils/WebGLUtils.js +4 -2
  295. package/src/renderers/webgpu/WebGPUBackend.js +480 -169
  296. package/src/renderers/webgpu/descriptors/GPUBindGroupDescriptor.js +48 -0
  297. package/src/renderers/webgpu/descriptors/GPUBufferDescriptor.js +57 -0
  298. package/src/renderers/webgpu/descriptors/GPUCommandEncoderDescriptor.js +30 -0
  299. package/src/renderers/webgpu/descriptors/GPUComputePassDescriptor.js +38 -0
  300. package/src/renderers/webgpu/descriptors/GPUComputePipelineDescriptor.js +48 -0
  301. package/src/renderers/webgpu/descriptors/GPUCopyExternalImageDestInfo.js +47 -0
  302. package/src/renderers/webgpu/descriptors/GPUCopyExternalImageSourceInfo.js +50 -0
  303. package/src/renderers/webgpu/descriptors/GPUExtent3D.js +51 -0
  304. package/src/renderers/webgpu/descriptors/GPUPipelineLayoutDescriptor.js +39 -0
  305. package/src/renderers/webgpu/descriptors/GPUQuerySetDescriptor.js +47 -0
  306. package/src/renderers/webgpu/descriptors/GPURenderBundleEncoderDescriptor.js +74 -0
  307. package/src/renderers/webgpu/descriptors/GPURenderPassColorAttachment.js +72 -0
  308. package/src/renderers/webgpu/descriptors/GPURenderPassDepthStencilAttachment.js +99 -0
  309. package/src/renderers/webgpu/descriptors/GPURenderPassDescriptor.js +72 -0
  310. package/src/renderers/webgpu/descriptors/GPURenderPassTimestampWrites.js +49 -0
  311. package/src/renderers/webgpu/descriptors/GPURenderPipelineDescriptor.js +130 -0
  312. package/src/renderers/webgpu/descriptors/GPUSamplerDescriptor.js +119 -0
  313. package/src/renderers/webgpu/descriptors/GPUShaderModuleDescriptor.js +46 -0
  314. package/src/renderers/webgpu/descriptors/GPUTexelCopyBufferInfo.js +57 -0
  315. package/src/renderers/webgpu/descriptors/GPUTexelCopyBufferLayout.js +48 -0
  316. package/src/renderers/webgpu/descriptors/GPUTexelCopyTextureInfo.js +61 -0
  317. package/src/renderers/webgpu/descriptors/GPUTextureDescriptor.js +99 -0
  318. package/src/renderers/webgpu/descriptors/GPUTextureViewDescriptor.js +108 -0
  319. package/src/renderers/webgpu/nodes/StandardNodeLibrary.js +0 -1
  320. package/src/renderers/webgpu/nodes/WGSLNodeBuilder.js +164 -7
  321. package/src/renderers/webgpu/nodes/WGSLNodeFunction.js +1 -1
  322. package/src/renderers/webgpu/utils/WebGPUAttributeUtils.js +98 -38
  323. package/src/renderers/webgpu/utils/WebGPUBindingUtils.js +72 -68
  324. package/src/renderers/webgpu/utils/WebGPUPipelineUtils.js +164 -69
  325. package/src/renderers/webgpu/utils/WebGPUTexturePassUtils.js +158 -95
  326. package/src/renderers/webgpu/utils/WebGPUTextureUtils.js +297 -141
  327. package/src/renderers/webgpu/utils/WebGPUTimestampQueryPool.js +33 -18
  328. package/src/renderers/webgpu/utils/WebGPUUtils.js +38 -3
  329. package/src/textures/DepthTexture.js +1 -1
  330. package/src/textures/ExternalTexture.js +0 -3
  331. package/examples/fonts/LICENSE +0 -13
  332. package/examples/fonts/MPLUSRounded1c/MPLUSRounded1c-Regular.typeface.json.zip +0 -0
  333. package/examples/fonts/MPLUSRounded1c/OFL.txt +0 -91
  334. package/examples/fonts/README.md +0 -11
  335. package/examples/fonts/droid/NOTICE +0 -190
  336. package/examples/fonts/droid/README.txt +0 -18
  337. package/examples/fonts/droid/droid_sans_bold.typeface.json +0 -1
  338. package/examples/fonts/droid/droid_sans_mono_regular.typeface.json +0 -1
  339. package/examples/fonts/droid/droid_sans_regular.typeface.json +0 -1
  340. package/examples/fonts/droid/droid_serif_bold.typeface.json +0 -1
  341. package/examples/fonts/droid/droid_serif_regular.typeface.json +0 -1
  342. package/examples/fonts/gentilis_bold.typeface.json +0 -1
  343. package/examples/fonts/gentilis_regular.typeface.json +0 -1
  344. package/examples/fonts/helvetiker_bold.typeface.json +0 -1
  345. package/examples/fonts/helvetiker_regular.typeface.json +0 -1
  346. package/examples/fonts/optimer_bold.typeface.json +0 -1
  347. package/examples/fonts/optimer_regular.typeface.json +0 -1
  348. package/examples/fonts/ttf/README.md +0 -9
  349. package/examples/fonts/ttf/kenpixel.ttf +0 -0
  350. package/examples/jsm/inspector/extensions/extensions.json +0 -6
  351. package/examples/jsm/libs/ammo.wasm.js +0 -822
  352. package/examples/jsm/libs/ammo.wasm.wasm +0 -0
  353. package/examples/jsm/libs/draco/draco_encoder.js +0 -33
  354. package/examples/jsm/libs/draco/gltf/draco_encoder.js +0 -33
  355. package/examples/jsm/libs/lottie_canvas.module.js +0 -14849
  356. package/examples/jsm/libs/opentype.module.js +0 -14506
  357. package/examples/jsm/libs/rhino3dm/rhino3dm.js +0 -21
  358. package/examples/jsm/libs/rhino3dm/rhino3dm.module.js +0 -16
  359. package/examples/jsm/libs/rhino3dm/rhino3dm.wasm +0 -0
  360. package/examples/jsm/lighting/TiledLighting.js +0 -42
  361. package/examples/jsm/tsl/display/AnamorphicNode.js +0 -293
  362. package/examples/jsm/tsl/lighting/TiledLightsNode.js +0 -442
  363. package/src/nodes/accessors/BatchNode.js +0 -163
  364. package/src/nodes/accessors/InstanceNode.js +0 -349
  365. package/src/nodes/accessors/InstancedMeshNode.js +0 -50
  366. package/src/nodes/accessors/SkinningNode.js +0 -328
@@ -0,0 +1,912 @@
1
+ import { abs, atan, bool, convertToTexture, cos, cross, Discard, dot, EPSILON, exp, float, Fn, getScreenPosition, getViewPosition, If, int, log, Loop, luminance, mat2, max, mix, nodeObject, NodeUpdateType, normalize, passTexture, PI, property, reflect, sin, smoothstep, sqrt, tan, texture, uniform, unpackRGBToNormal, uv, vec2, vec3, vec4 } from 'three/tsl';
2
+ import { HalfFloatType, MathUtils, Matrix4, NodeMaterial, QuadMesh, RendererUtils, RenderTarget, TempNode, Vector2 } from 'three/webgpu';
3
+ import { bindAnalyticNoise } from '../utils/RNoise.js';
4
+ import { ENV_RAY_LENGTH_THRESHOLD } from '../utils/SpecularHelpers.js';
5
+
6
+ const _quadMesh = /*@__PURE__*/ new QuadMesh();
7
+ const _size = /*@__PURE__*/ new Vector2();
8
+
9
+ let _rendererState;
10
+
11
+ const KERNEL_SAMPLES = 8;
12
+ const NOISE_ROTATION_SEED = 83;
13
+ const WORLD_RADIUS_SCALE = 0.1;
14
+
15
+ const AO_EDGE_STOPPING_BIAS = 0.05;
16
+ const AGGRESSIVITY_RADIUS_MIN = 0.001;
17
+ const DIFFUSE_CHROMA_WEIGHT = 2.0;
18
+ // Neighborhood luma coefficient-of-variation thresholds for gating the temporal inverse-luminance
19
+ // (firefly) suppression: below MIN the region is treated as flicker-free, above MAX as noisy.
20
+ const FLICKER_COV_GATE_MIN = 0.1;
21
+ const FLICKER_COV_GATE_MAX = 2;
22
+
23
+ /**
24
+ * Golden-angle Vogel disk offset.
25
+ *
26
+ * @tsl
27
+ */
28
+ const vogelDisk = Fn( ( [ i, radius ] ) => {
29
+
30
+ const sampleCount = 8;
31
+ const theta = i.add( 0.5 ).mul( 2.399827721492203 );
32
+ const r = radius.mul( sqrt( i.add( 0.5 ).div( sampleCount ) ) );
33
+ return vec2( cos( theta ), sin( theta ) ).mul( r );
34
+
35
+ } ).setLayout( {
36
+ name: 'vogelDisk',
37
+ type: 'vec2',
38
+ inputs: [
39
+ { name: 'i', type: 'float' },
40
+ { name: 'radius', type: 'float' }
41
+ ]
42
+ } );
43
+
44
+ /**
45
+ * Chromatic color-similarity distance between two linear base colors (albedo).
46
+ *
47
+ * @tsl
48
+ */
49
+ const diffuseColorDistance = Fn( ( [ a, b, compressLuma ] ) => {
50
+
51
+ const toYCoCg = ( c ) => vec3(
52
+ dot( c, vec3( 0.25, 0.5, 0.25 ) ),
53
+ c.r.sub( c.b ),
54
+ c.g.sub( c.r.add( c.b ).mul( 0.5 ) )
55
+ );
56
+
57
+ const ya = toYCoCg( a );
58
+ const yb = toYCoCg( b );
59
+
60
+ // `compressLuma` (0/1) range-compresses the luma term with log(1+L) so a fixed lumaPhi gives
61
+ // scale-invariant differences across the HDR range. 0 leaves luma linear (used for LDR albedo).
62
+ const compress = ( L ) => mix( L, log( L.add( 1 ) ), compressLuma );
63
+
64
+ const dLuma = abs( compress( ya.x ).sub( compress( yb.x ) ) );
65
+ const dChroma = vec2( ya.y.sub( yb.y ), ya.z.sub( yb.z ) ).length();
66
+
67
+ return dLuma.add( dChroma.mul( DIFFUSE_CHROMA_WEIGHT ) );
68
+
69
+ } ).setLayout( {
70
+ name: 'diffuseColorDistance',
71
+ type: 'float',
72
+ inputs: [
73
+ { name: 'a', type: 'vec3' },
74
+ { name: 'b', type: 'vec3' },
75
+ { name: 'compressLuma', type: 'float' }
76
+ ]
77
+ } );
78
+
79
+ const _temporalWeight = Fn( ( [ x, strength ] ) => float( 1 ).div( x.pow( strength ) ) ).setLayout( {
80
+ name: 'temporalWeight',
81
+ type: 'float',
82
+ inputs: [
83
+ { name: 'x', type: 'float' },
84
+ { name: 'strength', type: 'float' }
85
+ ]
86
+ } );
87
+
88
+ /**
89
+ * Temporal accumulation variance factor in `[0, 1]`. Higher values mean more history confidence.
90
+ *
91
+ * @tsl
92
+ */
93
+ const getTemporalVarianceFactor = Fn( ( [ frameNum, strength ] ) => {
94
+
95
+ return _temporalWeight( frameNum, strength ).max( 0.05 );
96
+
97
+ } ).setLayout( {
98
+ name: 'getTemporalVarianceFactor',
99
+ type: 'float',
100
+ inputs: [
101
+ { name: 'frameNum', type: 'float' },
102
+ { name: 'strength', type: 'float' }
103
+ ]
104
+ } );
105
+
106
+ /**
107
+ * World-space frustum height at `viewZ`. Algorithm originally from REBLUR (NRD).
108
+ * `tanHalfFovY` is `tan( verticalFov / 2 )`, hoisted by the caller since it is loop-invariant.
109
+ *
110
+ * @tsl
111
+ */
112
+ const computeFrustumSize = Fn( ( [ viewZ, tanHalfFovY ] ) => {
113
+
114
+ return float( 2 ).mul( viewZ ).mul( tanHalfFovY );
115
+
116
+ } ).setLayout( {
117
+ name: 'computeFrustumSize',
118
+ type: 'float',
119
+ inputs: [
120
+ { name: 'viewZ', type: 'float' },
121
+ { name: 'tanHalfFovY', type: 'float' }
122
+ ]
123
+ } );
124
+
125
+ /**
126
+ * Maps world-space SSR ray length to `[0, 1]`. Environment rays (`worldRayLength == 0`) map to `1`.
127
+ * Algorithm originally from REBLUR (NRD).
128
+ *
129
+ * @tsl
130
+ */
131
+ const computeHitDistFactor = Fn( ( [ worldRayLength, viewZ, tanHalfFovY ] ) => {
132
+
133
+ const frustumSize = computeFrustumSize( viewZ, tanHalfFovY );
134
+ const factor = worldRayLength.div( frustumSize.max( 1e-6 ) ).clamp( 0, 1 );
135
+
136
+ return factor;
137
+
138
+ } ).setLayout( {
139
+ name: 'computeHitDistFactor',
140
+ type: 'float',
141
+ inputs: [
142
+ { name: 'worldRayLength', type: 'float' },
143
+ { name: 'viewZ', type: 'float' },
144
+ { name: 'tanHalfFovY', type: 'float' }
145
+ ]
146
+ } );
147
+
148
+ /**
149
+ * Maps an AO factor for edge-stopping comparisons.
150
+ *
151
+ * @tsl
152
+ */
153
+ const mapAo = Fn( ( [ aoVal ] ) => aoVal.pow( 0.1 ) );
154
+
155
+ /**
156
+ * Specular dominant direction — smooth surfaces lean toward reflection, rough toward normal.
157
+ *
158
+ * @tsl
159
+ */
160
+ const getSpecularDominantDirection = Fn( ( [ N, V, roughness ] ) => {
161
+
162
+ return normalize( mix( N, reflect( V.negate(), N ), roughness.oneMinus() ) );
163
+
164
+ } ).setLayout( {
165
+ name: 'getSpecularDominantDirection',
166
+ type: 'vec3',
167
+ inputs: [
168
+ { name: 'N', type: 'vec3' },
169
+ { name: 'V', type: 'vec3' },
170
+ { name: 'roughness', type: 'float' }
171
+ ]
172
+ } );
173
+
174
+ /**
175
+ * GGX inverse-CDF: half-angle tangent enclosing `percent` of the specular lobe volume.
176
+ * `roughness` is perceptual (alpha = roughness²).
177
+ *
178
+ * @tsl
179
+ */
180
+ const specularLobeTanHalfAngle = Fn( ( [ roughness, percent ] ) => {
181
+
182
+ const alpha = roughness.mul( roughness );
183
+ return alpha.mul( sqrt( percent.div( float( 1 ).sub( percent ).max( 1e-6 ) ) ) );
184
+
185
+ } ).setLayout( {
186
+ name: 'specularLobeTanHalfAngle',
187
+ type: 'float',
188
+ inputs: [
189
+ { name: 'roughness', type: 'float' },
190
+ { name: 'percent', type: 'float' }
191
+ ]
192
+ } );
193
+
194
+ const EXP_WEIGHT_SCALE = 4;
195
+ const NORMAL_ENCODING_ERROR = 1.5 / 255;
196
+
197
+ /**
198
+ * Loop-invariant part of the adaptive normal edge-stopping weight: the Gaussian falloff
199
+ * constant `2·EXP_WEIGHT_SCALE / lobeHalfAngle²`. `roughness`/`aggressivity`/`invNormalPhi`
200
+ * are constant across the kernel, so this is hoisted out of the tap loop and evaluated once
201
+ * per pixel. Lobe half-angle from REBLUR (NRD).
202
+ *
203
+ * @tsl
204
+ */
205
+ const lobeNormalFalloff = Fn( ( [ roughness, aggressivity, invNormalPhi ] ) => {
206
+
207
+ const percent = mix( invNormalPhi.pow2(), float( 0 ), aggressivity.sqrt() ).clamp( 0.1, 0.99 );
208
+ const tanHalfAngle = specularLobeTanHalfAngle( roughness, percent );
209
+ const lobeHalfAngle = max( atan( tanHalfAngle ), float( NORMAL_ENCODING_ERROR ) );
210
+
211
+ const invHalfAngle = float( 1 ).div( lobeHalfAngle );
212
+ return invHalfAngle.mul( invHalfAngle ).mul( 2 * EXP_WEIGHT_SCALE );
213
+
214
+ } ).setLayout( {
215
+ name: 'lobeNormalFalloff',
216
+ type: 'float',
217
+ inputs: [
218
+ { name: 'roughness', type: 'float' },
219
+ { name: 'aggressivity', type: 'float' },
220
+ { name: 'invNormalPhi', type: 'float' }
221
+ ]
222
+ } );
223
+
224
+ /**
225
+ * Adaptive lobe normal edge-stopping weight
226
+ *
227
+ * Evaluated entirely in cosine space: with `angle² ≈ 2(1 − cosθ)`, the original
228
+ * `exp( −SCALE·angle/halfAngle )` becomes a Gaussian `exp( falloff·(cosθ − 1) )`, so a
229
+ * single `exp` replaces the per-tap `acos`. Matches the original at the half-angle for
230
+ * narrow lobes and is slightly more permissive for wide (diffuse) ones.
231
+ *
232
+ * @tsl
233
+ */
234
+ const lobeNormalWeight = Fn( ( [ viewNormal, nNormalV, lobeFalloff ] ) => {
235
+
236
+ const cosA = dot( viewNormal, nNormalV );
237
+
238
+ return exp( cosA.sub( 1 ).mul( lobeFalloff ) );
239
+
240
+ } ).setLayout( {
241
+ name: 'lobeNormalWeight',
242
+ type: 'float',
243
+ inputs: [
244
+ { name: 'viewNormal', type: 'vec3' },
245
+ { name: 'nNormalV', type: 'vec3' },
246
+ { name: 'lobeFalloff', type: 'float' }
247
+ ]
248
+ } );
249
+
250
+ /**
251
+ * View-space plane distance between two surface points (edge-stopping geometry term).
252
+ *
253
+ * @tsl
254
+ */
255
+ const planeDistance = Fn( ( [ position, nPosition, normal ] ) => {
256
+
257
+ return abs( dot( position.sub( nPosition ), normal ) );
258
+
259
+ } ).setLayout( {
260
+ name: 'planeDistance',
261
+ type: 'float',
262
+ inputs: [
263
+ { name: 'position', type: 'vec3' },
264
+ { name: 'nPosition', type: 'vec3' },
265
+ { name: 'normal', type: 'vec3' },
266
+ ]
267
+ } );
268
+
269
+ /**
270
+ * Inverse-luminance temporal blend with optional adaptive trust (Karis-style).
271
+ *
272
+ * @tsl
273
+ */
274
+ const karisTemporalBlend = Fn( ( [ denoisedRgb, denoisedRaw, a, flickerSuppression, adaptiveTrust, nbhdMeanLuma, nbhdStddevLuma ] ) => {
275
+
276
+ const localCoV = nbhdStddevLuma.div( nbhdMeanLuma.max( 1e-4 ) );
277
+ const trustSuppress = localCoV.mul( adaptiveTrust ).mul( a.oneMinus() ).clamp( 0, 0.9 );
278
+ const aTrust = a.mul( trustSuppress.oneMinus() );
279
+
280
+ // In flicker-free neighborhoods, back off the inverse-luminance weighting so valid bright highlights
281
+ // keep their energy. Scaled by adaptiveTrust so the default (0) path is unchanged.
282
+ const noisy = smoothstep( FLICKER_COV_GATE_MIN, FLICKER_COV_GATE_MAX, localCoV );
283
+ const effFlicker = flickerSuppression.mul( mix( adaptiveTrust.oneMinus(), float( 1 ), noisy ) );
284
+
285
+ const wHist = float( 1 ).sub( aTrust ).div( luminance( denoisedRgb ).mul( effFlicker ).mul( 10 ).add( 1 ) );
286
+ const wRaw = aTrust.div( luminance( denoisedRaw ).mul( effFlicker ).mul( 10 ).add( 1 ) );
287
+ return denoisedRgb.mul( wHist ).add( denoisedRaw.mul( wRaw ) ).div( wHist.add( wRaw ).max( EPSILON ) );
288
+
289
+ } ).setLayout( {
290
+ name: 'karisTemporalBlend',
291
+ type: 'vec3',
292
+ inputs: [
293
+ { name: 'denoisedRgb', type: 'vec3' },
294
+ { name: 'denoisedRaw', type: 'vec3' },
295
+ { name: 'a', type: 'float' },
296
+ { name: 'flickerSuppression', type: 'float' },
297
+ { name: 'adaptiveTrust', type: 'float' },
298
+ { name: 'nbhdMeanLuma', type: 'float' },
299
+ { name: 'nbhdStddevLuma', type: 'float' }
300
+ ]
301
+ } );
302
+
303
+ const toTextureNode = ( value ) => {
304
+
305
+ if ( value === null ) return null;
306
+
307
+ if ( value.isTexture === true ) return texture( value );
308
+
309
+ return convertToTexture( value.getTextureNode?.() ?? value );
310
+
311
+ };
312
+
313
+ /**
314
+ * @typedef {'diffuse'|'specular'} DenoiseMode
315
+ */
316
+
317
+ /**
318
+ * @typedef {'raylength'|'ao'|'none'} DenoiseAlphaSource
319
+ */
320
+
321
+ /**
322
+ * @typedef {Object} RecurrentDenoiseNodeOptions
323
+ * @property {?Node<float>} [depth=null] - Scene depth buffer for view-space edge stopping.
324
+ * @property {?Node<vec3>} [normal=null] - View-space normals for geometric edge stopping.
325
+ * @property {?Node<vec4>} [metalRoughness=null] - Roughness/metalness G-buffer for specular edge stopping.
326
+ * @property {?Node<vec4>} [diffuse=null] - Scene base color (albedo) G-buffer for chromatic edge stopping.
327
+ * @property {?Node<vec4>} [raw=null] - Unfiltered input (e.g. raw SSR/SSGI) for secondary sampling and temporal blend.
328
+ * @property {DenoiseMode} [mode='diffuse'] - Denoising kernel type.
329
+ * @property {boolean} [accumulate=true] - When `true`, temporally blend the spatially-denoised result
330
+ * (Karis-style) and write frame weight to alpha for feedback loops. When `false`, only spatial filtering is applied.
331
+ */
332
+
333
+ /**
334
+ * Post processing node for denoising temporally-accumulated screen-space effects
335
+ * such as SSGI (ambient occlusion / indirect diffuse) and SSR (specular reflections).
336
+ *
337
+ * The denoising kernel is selected at construction time via `mode`:
338
+ * `'diffuse'` (SSGI) or `'specular'` (SSR). The kernel uses a fixed 8-sample Vogel disk.
339
+ *
340
+ * @augments TempNode
341
+ * @three_import import { recurrentDenoise } from 'three/addons/tsl/display/RecurrentDenoiseNode.js';
342
+ */
343
+ class RecurrentDenoiseNode extends TempNode {
344
+
345
+ static get type() {
346
+
347
+ return 'RecurrentDenoiseNode';
348
+
349
+ }
350
+
351
+ /**
352
+ * @param {TextureNode} inputTexture - Temporally filtered input to denoise (e.g. TRAA output).
353
+ * @param {Camera} camera
354
+ * @param {RecurrentDenoiseNodeOptions} [options={}]
355
+ */
356
+ constructor( inputTexture, camera, options = {} ) {
357
+
358
+ super( 'vec4' );
359
+
360
+ const {
361
+ depth = null,
362
+ normal = null,
363
+ metalRoughness = null,
364
+ diffuse = null,
365
+ raw = null,
366
+ mode = 'diffuse',
367
+ accumulate = true,
368
+ } = options;
369
+
370
+ this.isRecurrentDenoiseNode = true;
371
+ this.camera = camera;
372
+
373
+ /**
374
+ * Denoising kernel type.
375
+ *
376
+ * @type {DenoiseMode}
377
+ */
378
+ this.mode = mode;
379
+
380
+ /**
381
+ * When `true`, apply temporal blending after spatial denoising. When `false`, output spatially
382
+ * filtered colour only (alpha is passed through from the input temporal pass).
383
+ *
384
+ * @type {boolean}
385
+ */
386
+ this.accumulate = accumulate;
387
+
388
+ this.textureNode = inputTexture;
389
+ this.depthNode = depth !== null ? nodeObject( depth ) : null;
390
+ this.normalNode = normal !== null ? nodeObject( normal ) : null;
391
+ this.rawNode = toTextureNode( raw );
392
+ this.roughnessMetalnessNode = metalRoughness !== null ? nodeObject( metalRoughness ) : null;
393
+ this.diffuseNode = diffuse !== null ? nodeObject( diffuse ) : null;
394
+
395
+ this._noiseIndex = uniform( 0 );
396
+
397
+ this.lumaPhi = uniform( 5 );
398
+ this.depthPhi = uniform( 5 );
399
+ this.normalPhi = uniform( 5 );
400
+ this.radius = uniform( 5 );
401
+ this.alphaPhi = uniform( 1 );
402
+ this.roughnessPhi = uniform( 100 );
403
+ this.diffusePhi = uniform( 100 );
404
+ this.adapt = uniform( 0.5 );
405
+ this.smoothDisocclusions = uniform( true, 'bool' );
406
+ this.strength = uniform( 0.25 );
407
+ this.maxFrames = uniform( 32 );
408
+
409
+ /**
410
+ * Which channel of the raw texture drives alpha-based edge stopping.
411
+ * `'raylength'` — alpha encodes SSR ray length; `'ao'` — alpha encodes AO factor;
412
+ * `'none'` — skip alpha-based edge stopping.
413
+ *
414
+ * @type {DenoiseAlphaSource}
415
+ * @default 'raylength'
416
+ */
417
+ this.alphaSource = 'raylength';
418
+
419
+ this.flickerSuppression = uniform( 1 );
420
+ this.adaptiveTrust = uniform( 0 );
421
+
422
+ this.updateBeforeType = NodeUpdateType.FRAME;
423
+
424
+ this._resolution = uniform( new Vector2() );
425
+ this._fovY = uniform( MathUtils.degToRad( camera.fov ) );
426
+ this._cameraProjectionMatrixInverse = uniform( new Matrix4().copy( camera.projectionMatrixInverse ) );
427
+ this._cameraProjectionMatrix = uniform( new Matrix4().copy( camera.projectionMatrix ) );
428
+ this._viewMatrix = uniform( new Matrix4().copy( camera.matrixWorldInverse ) );
429
+
430
+ this._renderTarget = new RenderTarget( 1, 1, { depthBuffer: false, type: HalfFloatType } );
431
+ this._renderTarget.texture.name = 'RecurrentDenoiseNode.output';
432
+
433
+ this._material = new NodeMaterial();
434
+ this._material.name = 'RecurrentDenoise';
435
+
436
+ this._textureNode = passTexture( this, this._renderTarget.texture );
437
+
438
+ }
439
+
440
+ setSize( width, height ) {
441
+
442
+ if ( width === null || height === null ) return;
443
+
444
+ this._renderTarget.setSize( width, height );
445
+ this._resolution.value.set( width, height );
446
+
447
+ }
448
+
449
+ getTextureNode() {
450
+
451
+ return this._textureNode;
452
+
453
+ }
454
+
455
+ /**
456
+ * Returns the internal output render target (e.g. for temporal reprojection/SSGI temporal feedback loops).
457
+ *
458
+ * @returns {RenderTarget}
459
+ */
460
+ getRenderTarget() {
461
+
462
+ return this._renderTarget;
463
+
464
+ }
465
+
466
+ updateBefore( frame ) {
467
+
468
+ const { renderer } = frame;
469
+
470
+ const drawingBufferSize = renderer.getDrawingBufferSize( _size );
471
+ const width = drawingBufferSize.width;
472
+ const height = drawingBufferSize.height;
473
+
474
+ const needsRestart = this._renderTarget.width !== width || this._renderTarget.height !== height;
475
+ this.setSize( width, height );
476
+
477
+ this._cameraProjectionMatrix.value.copy( this.camera.projectionMatrix );
478
+ this._cameraProjectionMatrixInverse.value.copy( this.camera.projectionMatrixInverse );
479
+ this._viewMatrix.value.copy( this.camera.matrixWorldInverse );
480
+
481
+ if ( this.camera.isPerspectiveCamera ) {
482
+
483
+ this._fovY.value = MathUtils.degToRad( this.camera.fov );
484
+
485
+ }
486
+
487
+ if ( frame.frameId !== undefined ) this._noiseIndex.value = frame.frameId;
488
+
489
+ // Denoise renders via an internal _quadMesh, not through the RenderPipeline output graph.
490
+ // Upstream passes (e.g. TemporalReprojectNode) referenced by a PassTextureNode input are
491
+ // otherwise never scheduled, their updateBefore() would not run and this pass would sample
492
+ // a stale/empty render target.
493
+ if ( this.textureNode.isPassTextureNode === true ) frame.updateBeforeNode( this.textureNode.passNode );
494
+
495
+ _rendererState = RendererUtils.resetRendererState( renderer, _rendererState );
496
+
497
+ if ( needsRestart === true ) {
498
+
499
+ renderer.initRenderTarget( this._renderTarget );
500
+ renderer.setRenderTarget( this._renderTarget );
501
+ renderer.clear();
502
+ renderer.setRenderTarget( null );
503
+
504
+ }
505
+
506
+ renderer.setRenderTarget( this._renderTarget );
507
+ _quadMesh.material = this._material;
508
+ _quadMesh.name = 'RecurrentDenoise';
509
+ _quadMesh.render( renderer );
510
+ renderer.setRenderTarget( null );
511
+
512
+ RendererUtils.restoreRendererState( renderer, _rendererState );
513
+
514
+ }
515
+
516
+ setup( builder ) {
517
+
518
+ const sampleAnalyticNoise = bindAnalyticNoise( this._resolution, NOISE_ROTATION_SEED );
519
+
520
+ const noiseRotationMatrix = Fn( ( [ r ] ) => {
521
+
522
+ const angle = r.mul( 2 ).mul( PI );
523
+ return mat2( cos( angle ), sin( angle ).negate(), sin( angle ), cos( angle ) );
524
+
525
+ } );
526
+
527
+ const sampleTexture = ( uvCoord ) => texture( this.textureNode, uvCoord ).max( 0 );
528
+ const sampleRaw = ( uvCoord ) => this.rawNode?.sample( uvCoord )?.max( 0 ) ?? vec3( 0 ).max( 0 );
529
+ const sampleDepth = ( uvCoord ) => this.depthNode?.sample( uvCoord )?.x ?? float( 0.5 );
530
+ const sampleNormal = ( uvCoord ) => unpackRGBToNormal( this.normalNode?.sample( uvCoord )?.rgb ?? vec3( 0, 0, 1 ) );
531
+ const sampleRoughnessMetalness = ( uvCoord ) => this.roughnessMetalnessNode?.sample( uvCoord )?.rg ?? vec2( 0, 1 );
532
+ const sampleDiffuse = ( uvCoord ) => this.diffuseNode?.sample( uvCoord )?.rgb ?? vec3( 0 );
533
+
534
+ // Neighborhood luma moments for the adaptive-trust (firefly) gating of the temporal blend.
535
+ const getNeighborhoodStats = Fn( ( [ uvCoord, centerSample ] ) => {
536
+
537
+ const rlSum = float( 0 ).toVar();
538
+ const rlSumW = float( 0 ).toVar();
539
+ const meanLuma = float( 0 ).toVar();
540
+ const m2Luma = float( 0 ).toVar();
541
+ const lumaCount = float( 0 ).toVar();
542
+ const hasEnvRay = bool( false ).toVar();
543
+
544
+ // 4-tap cross (pre-sampled center + 4 axis neighbors) instead of a full 3×3 — about half the fetches.
545
+ // The center tap reuses the caller's already-sampled raw texel.
546
+ const accumulate = ( dx, dy, sample ) => {
547
+
548
+ const neighbor = sample !== undefined
549
+ ? sample
550
+ : texture( this.rawNode, uvCoord.add( vec2( dx, dy ).div( this._resolution ) ) ).max( 0 ).toConst();
551
+
552
+ if ( this.alphaSource === 'raylength' ) {
553
+
554
+ const sampleRl = neighbor.a.toVar();
555
+ If( sampleRl.greaterThan( ENV_RAY_LENGTH_THRESHOLD ), () => {
556
+
557
+ sampleRl.assign( 0.25 );
558
+ hasEnvRay.assign( true );
559
+
560
+ } );
561
+ const w = float( 1 ).div( sampleRl.add( 0.001 ) );
562
+ rlSum.addAssign( sampleRl.mul( w ) );
563
+ rlSumW.addAssign( w );
564
+
565
+ }
566
+
567
+ If( this.adaptiveTrust.greaterThan( 0 ), () => {
568
+
569
+ const nLuma = luminance( neighbor.rgb );
570
+ lumaCount.addAssign( 1 );
571
+ const delta = nLuma.sub( meanLuma ).toConst();
572
+ meanLuma.addAssign( delta.div( lumaCount ) );
573
+ m2Luma.addAssign( delta.mul( nLuma.sub( meanLuma ) ) );
574
+
575
+ } );
576
+
577
+ };
578
+
579
+ accumulate( 0, 0, centerSample );
580
+ accumulate( - 1, 0 );
581
+ accumulate( 1, 0 );
582
+ accumulate( 0, - 1 );
583
+ accumulate( 0, 1 );
584
+
585
+ const avgRayLength = this.alphaSource === 'raylength' ? rlSum.div( rlSumW ) : float( 1 );
586
+ const stddevLuma = sqrt( m2Luma.div( lumaCount.max( 1 ) ) );
587
+
588
+ // vec3( avgRayLength, meanLuma, stddevLuma )
589
+ return vec4( avgRayLength, meanLuma, stddevLuma, hasEnvRay.toFloat() );
590
+
591
+ } ).setLayout( {
592
+ name: 'getNeighborhoodStats',
593
+ type: 'vec4',
594
+ inputs: [
595
+ { name: 'uvCoord', type: 'vec2' },
596
+ { name: 'centerSample', type: 'vec4' }
597
+ ]
598
+ } );
599
+
600
+ const denoiseFn = Fn( ( [ uvCoord ] ) => {
601
+
602
+ const result = property( 'vec4' );
603
+
604
+ const depth = sampleDepth( uvCoord ).toConst();
605
+
606
+ const runDenoise = () => {
607
+
608
+ const viewNormal = sampleNormal( uvCoord ).toConst();
609
+ const worldNormal = viewNormal.transformDirection( this._viewMatrix ).toConst();
610
+ const texel = sampleTexture( uvCoord ).max( 0 ).toConst();
611
+
612
+ const viewPosition = getViewPosition( uvCoord, depth, this._cameraProjectionMatrixInverse ).toConst();
613
+ const roughnessMetalness = sampleRoughnessMetalness( uvCoord ).toConst();
614
+ const roughness = roughnessMetalness.g;
615
+ const metalness = roughnessMetalness.r;
616
+
617
+ const noiseTexel = sampleAnalyticNoise( uvCoord, this._noiseIndex );
618
+ const rotationMatrix = noiseRotationMatrix( noiseTexel.r );
619
+
620
+ const frameNum = float( 1 ).div( texel.a );
621
+ const varianceFactor = getTemporalVarianceFactor( frameNum, this.strength.oneMinus() );
622
+ const aggressivity = varianceFactor.oneMinus();
623
+
624
+ const raw = sampleRaw( uvCoord ).toConst();
625
+
626
+ const viewZ = abs( viewPosition.z );
627
+ const rl = float( 1 ).toVar();
628
+ const nbhdMeanLuma = float( 0 ).toVar();
629
+ const nbhdStddevLuma = float( 0 ).toVar();
630
+ const hasEnvRay = bool( false ).toVar();
631
+
632
+ if ( this.alphaSource === 'raylength' ) {
633
+
634
+ const stats = getNeighborhoodStats( uvCoord, raw );
635
+ rl.assign( stats.x );
636
+ nbhdMeanLuma.assign( stats.y );
637
+ nbhdStddevLuma.assign( stats.z );
638
+ hasEnvRay.assign( stats.w.greaterThan( 0.5 ) );
639
+
640
+ } else {
641
+
642
+ If( this.adaptiveTrust.greaterThan( 0 ), () => {
643
+
644
+ const stats = getNeighborhoodStats( uvCoord, raw );
645
+ nbhdMeanLuma.assign( stats.y );
646
+ nbhdStddevLuma.assign( stats.z );
647
+
648
+ } );
649
+
650
+ }
651
+
652
+ const tanHalfFovY = this.alphaSource === 'raylength' ? tan( this._fovY.mul( 0.5 ) ).toConst() : null;
653
+ const hitDistFactor = this.alphaSource === 'raylength'
654
+ ? computeHitDistFactor( rl, viewZ, tanHalfFovY ).toConst()
655
+ : float( 1 );
656
+
657
+ const denoised = texel.rgb.toVar();
658
+ const totalWeight = float( 1 ).toVar();
659
+ const denoisedFrame = frameNum.toVar();
660
+ const totalFrameWeight = float( 1 ).toVar();
661
+
662
+ const denoisedRaw = raw.rgb.toVar();
663
+ const totalWeightRaw = float( 1 ).toVar();
664
+
665
+ If( raw.rgb.length().lessThan( 0.0001 ), () => {
666
+
667
+ denoisedRaw.assign( vec3( 0 ) );
668
+ totalWeightRaw.assign( 0 );
669
+
670
+ } );
671
+
672
+ const avgAo = this.alphaSource === 'ao' ? raw.a.toConst() : float( 1 );
673
+ const mappedAvgAo = this.alphaSource === 'ao' ? mapAo( avgAo ) : float( 0 );
674
+
675
+ const worldRadius = this.radius.mul( WORLD_RADIUS_SCALE ).toVar();
676
+
677
+ if ( this.mode === 'specular' ) {
678
+
679
+ worldRadius.mulAssign( rl.mul( viewPosition.z.abs() ) );
680
+ worldRadius.mulAssign( roughness.sqrt().max( 0.01 ) );
681
+
682
+ } else {
683
+
684
+ worldRadius.mulAssign( avgAo.pow( 2 ).mul( viewPosition.z.abs() ) );
685
+
686
+ }
687
+
688
+ worldRadius.mulAssign( mix( 1, AGGRESSIVITY_RADIUS_MIN, aggressivity ) );
689
+
690
+ const T = vec3( 0 ).toVar();
691
+ const B = vec3( 0 ).toVar();
692
+
693
+ if ( this.mode === 'specular' ) {
694
+
695
+ const V = normalize( viewPosition ).negate();
696
+ const D = getSpecularDominantDirection( viewNormal, V, roughness );
697
+ const R = reflect( D.negate(), viewNormal );
698
+ const Tv = normalize( cross( viewNormal, R ) );
699
+ const Bv = cross( R, Tv );
700
+ const viewAngle = abs( viewNormal.z ).acos().div( float( Math.PI * 0.5 ) ).clamp( 0, 1 );
701
+ const skewFactor = mix( 1.0, roughness, viewAngle );
702
+ T.assign( Tv.mul( skewFactor ) );
703
+ B.assign( Bv );
704
+
705
+ } else {
706
+
707
+ const up = vec3( 0, 0, 1 );
708
+ const Tv = cross( up, viewNormal ).normalize().toVar();
709
+ If( Tv.length().lessThan( EPSILON ), () => {
710
+
711
+ Tv.assign( cross( vec3( 0, 1, 0 ), viewNormal ).normalize() );
712
+
713
+ } );
714
+ T.assign( Tv );
715
+ B.assign( cross( viewNormal, Tv ).normalize() );
716
+
717
+ }
718
+
719
+ T.mulAssign( worldRadius );
720
+ B.mulAssign( worldRadius );
721
+
722
+ const centerDiffuse = sampleDiffuse( uvCoord ).toConst();
723
+ const radiusShrink = float( 1 ).toVar();
724
+
725
+ // Directional analog of radiusShrink: an accumulated tangent-space shift that skews
726
+ // subsequent taps toward directions that yielded high weight (related geometry).
727
+ const polarBias = vec2( 0 ).toVar();
728
+
729
+ const depthWeightScale = this.depthPhi.mul( 500 ).mul( viewNormal.z.abs() ).div( viewPosition.z.abs() );
730
+
731
+ // Lobe geometry depends only on per-pixel terms, so compute its falloff constant once here.
732
+ const lobeFalloff = lobeNormalFalloff( roughness, aggressivity, this.normalPhi.oneMinus() ).toConst();
733
+
734
+ Loop( { start: int( 0 ), end: int( KERNEL_SAMPLES ), type: 'int', condition: '<', name: 'i' }, ( { i } ) => {
735
+
736
+ const baseOffset = vogelDisk( float( i ), 1 ).toVar();
737
+ const sampleDir = baseOffset.normalize().toConst();
738
+
739
+ // Blend the tap direction toward the polar bias, then restore the Vogel radius and shrink.
740
+ const skewedDir = mix( sampleDir, polarBias.max( EPSILON ).normalize(), this.adapt.mul( aggressivity )
741
+ .mul( polarBias.dot( polarBias ).greaterThan( 0.001 ).select( 1, 0 ) ) );
742
+ const offset = rotationMatrix.mul( skewedDir.mul( baseOffset.length().mul( radiusShrink ) ) ).toVar();
743
+
744
+ // Exact per-sample view-space projection (both paths)
745
+ const sampleViewPos = viewPosition.add( B.mul( offset.x ).add( T.mul( offset.y ) ) );
746
+ const sampleUv = getScreenPosition( sampleViewPos, this._cameraProjectionMatrix ).toVar();
747
+ sampleUv.assign( sampleUv.abs().oneMinus().abs().oneMinus().clamp() );
748
+
749
+ const neighborColor = sampleTexture( sampleUv ).max( 0 ).toConst();
750
+
751
+ // When no raw texture is bound, sampleRaw falls back to the filtered texture at the same UV.
752
+ const rawNeighborColor = sampleRaw( sampleUv ).max( 0 ).toVar();
753
+ // if ( this.mode === 'diffuse' ) rawNeighborColor.rgb.assign( mix( neighborColor.rgb, rawNeighborColor.rgb, neighborColor.a ) );
754
+
755
+ const nDepth = sampleDepth( sampleUv );
756
+ const nViewPosition = getViewPosition( sampleUv, nDepth, this._cameraProjectionMatrixInverse ).toConst();
757
+ const nViewZ = abs( nViewPosition.z ).toConst();
758
+
759
+ const kernelDiff = float( 0 ).toVar();
760
+
761
+ // Luma edge stopping
762
+ kernelDiff.addAssign( luminance( rawNeighborColor.rgb ).sub( luminance( raw.rgb ) ).abs().mul( this.lumaPhi ).mul( 10 ) );
763
+
764
+ // Diffuse edge stopping (only relevant for specular mode)
765
+ if ( this.diffuseNode !== null ) {
766
+
767
+ kernelDiff.addAssign( ( diffuseColorDistance( centerDiffuse, sampleDiffuse( sampleUv ), float( 0 ) ).mul( this.diffusePhi ).mul( metalness ) ) );
768
+
769
+ }
770
+
771
+ // AO edge stopping
772
+ if ( this.alphaSource === 'ao' ) {
773
+
774
+ const neighborMappedAo = mapAo( rawNeighborColor.a );
775
+ // We multiply here with aggressivity as well, since early application of aoW yields noise
776
+ const aoW = mappedAvgAo.div( mappedAvgAo.add( neighborMappedAo ).add( AO_EDGE_STOPPING_BIAS ) ).mul( this.alphaPhi ).mul( aggressivity );
777
+
778
+ kernelDiff.addAssign( ( aoW ) );
779
+
780
+
781
+ } else if ( this.alphaSource === 'raylength' ) {
782
+
783
+ // Ray length edge stopping
784
+
785
+ const neighborHitDistFactor = computeHitDistFactor( rawNeighborColor.a, nViewZ, tanHalfFovY );
786
+ const hdfDiff = hitDistFactor.sub( neighborHitDistFactor ).abs();
787
+
788
+ const rayLengthFactor = hdfDiff.mul( this.alphaPhi ).div( viewPosition.z.abs() );
789
+
790
+ // Env rays are harder to compare so we accept if this sample is an env ray and there is an env ray in the neighborhood
791
+ kernelDiff.addAssign( rawNeighborColor.a.greaterThan( ENV_RAY_LENGTH_THRESHOLD ).and( hasEnvRay ).select( 1, rayLengthFactor ) );
792
+
793
+ }
794
+
795
+ // Roughness edge stopping
796
+ if ( this.mode === 'specular' ) kernelDiff.addAssign( ( abs( roughness.sub( sampleRoughnessMetalness( sampleUv ).g ) ).mul( this.roughnessPhi ) ) );
797
+
798
+ const nViewNormal = sampleNormal( sampleUv );
799
+ const nWorldNormal = nViewNormal.transformDirection( this._viewMatrix );
800
+ const distToPlane = planeDistance( viewPosition, nViewPosition, viewNormal );
801
+
802
+ // Geometric edge stopping (depth and normal)
803
+ const depthDiff = distToPlane.mul( depthWeightScale );
804
+ const normalW = lobeNormalWeight( worldNormal, nWorldNormal, lobeFalloff );
805
+
806
+ // Sum every negative-exponent edge-stopping term (kernel + depth/plane, plus the SSR hit-distance term)
807
+ const w = exp( kernelDiff.mul( aggressivity ).add( depthDiff ).negate() ).mul( normalW ).toVar();
808
+
809
+ // Feedback to shrink radius based on the weight
810
+ radiusShrink.assign( mix( radiusShrink, w, this.adapt ) );
811
+
812
+ // Polar feedback: skew subsequent taps toward high-weight directions (related geometry)
813
+ polarBias.assign( mix( polarBias, sampleDir.mul( w.sub( 0.5 ) ), 0.5 ) );
814
+
815
+ // to mitigate the effect of fireflies and high variance in recently disoccluded regions, we weigh by the inverse luminance for the first 5 frames
816
+ w.mulAssign( mix( float( 1 ).div( luminance( rawNeighborColor.rgb ).pow( 2 ).add( 0.01 ) ), 1, frameNum.div( 5 ).min( 1 ) ) );
817
+
818
+ denoisedRaw.addAssign( rawNeighborColor.rgb.mul( w ) );
819
+ totalWeightRaw.addAssign( w );
820
+
821
+ denoised.addAssign( neighborColor.rgb.mul( w ) );
822
+ totalWeight.addAssign( w );
823
+
824
+ // Denoising the alpha (accumulation speed), to get smoother disocclusion transitions
825
+ If( this.smoothDisocclusions, () => {
826
+
827
+ const neighborAWeight = neighborColor.a.greaterThan( texel.a ).select( w.mul( 0.33 ), 0 );
828
+ denoisedFrame.addAssign( float( 1 ).div( neighborColor.a ).mul( neighborAWeight ) );
829
+ totalFrameWeight.addAssign( neighborAWeight );
830
+
831
+ } );
832
+
833
+ } );
834
+
835
+ denoised.divAssign( totalWeight.max( EPSILON ) );
836
+ denoised.assign( denoised.max( EPSILON ) );
837
+ denoisedRaw.divAssign( totalWeightRaw.max( EPSILON ) );
838
+
839
+ if ( this.accumulate ) {
840
+
841
+ const computedFrame = denoisedFrame.div( totalFrameWeight.max( EPSILON ) );
842
+ const a = float( 1 ).div( computedFrame.max( EPSILON ) ).toConst();
843
+
844
+ if ( this.rawNode !== null ) {
845
+
846
+ const blended = karisTemporalBlend(
847
+ denoised,
848
+ denoisedRaw,
849
+ a,
850
+ this.flickerSuppression,
851
+ this.adaptiveTrust,
852
+ nbhdMeanLuma,
853
+ nbhdStddevLuma
854
+ );
855
+
856
+ result.assign( vec4( blended, a ) );
857
+
858
+ } else {
859
+
860
+ const finalDenoised = mix( denoised, denoisedRaw, a );
861
+ result.assign( vec4( finalDenoised, a ) );
862
+
863
+ }
864
+
865
+ } else {
866
+
867
+ result.assign( vec4( denoised, texel.a ) );
868
+
869
+ }
870
+
871
+ };
872
+
873
+ If( depth.greaterThanEqual( 1.0 ), () => {
874
+
875
+ Discard();
876
+
877
+ } ).Else( runDenoise );
878
+
879
+ return result;
880
+
881
+ } );
882
+
883
+ this._material.fragmentNode = denoiseFn( uv() ).context( builder.getSharedContext() );
884
+ this._material.needsUpdate = true;
885
+
886
+ return this._textureNode;
887
+
888
+ }
889
+
890
+ dispose() {
891
+
892
+ this._renderTarget.dispose();
893
+ this._material.dispose();
894
+
895
+ }
896
+
897
+ }
898
+
899
+ export default RecurrentDenoiseNode;
900
+
901
+ /**
902
+ * @tsl
903
+ * @param {Node} inputTexture - Temporally filtered input to denoise (e.g. TRAA output).
904
+ * @param {Camera} camera
905
+ * @param {RecurrentDenoiseNodeOptions} [options={}]
906
+ * @returns {RecurrentDenoiseNode}
907
+ */
908
+ export const recurrentDenoise = ( inputTexture, camera, options = {} ) => nodeObject( new RecurrentDenoiseNode(
909
+ toTextureNode( inputTexture ),
910
+ camera,
911
+ options
912
+ ) );