@gnsx/three 0.185.16 → 0.186.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 (418) hide show
  1. package/build/three.cjs +10 -82600
  2. package/build/three.core.js +1309 -807
  3. package/build/three.module.js +439 -338
  4. package/build/three.tsl.js +74 -44
  5. package/build/three.webgpu.js +6036 -2184
  6. package/build/three.webgpu.nodes.js +6020 -2184
  7. package/examples/jsm/Addons.js +6 -6
  8. package/examples/jsm/controls/ArcballControls.js +1 -1
  9. package/examples/jsm/controls/FirstPersonControls.js +44 -20
  10. package/examples/jsm/controls/OrbitControls.js +9 -0
  11. package/examples/jsm/controls/TrackballControls.js +109 -4
  12. package/examples/jsm/csm/CSMShadowNode.js +13 -0
  13. package/examples/jsm/exporters/GLTFExporter.js +23 -7
  14. package/examples/jsm/exporters/USDZExporter.js +2 -2
  15. package/examples/jsm/generators/CityGenerator.js +377 -45
  16. package/examples/jsm/generators/ForestGenerator.js +12 -12
  17. package/examples/jsm/generators/TerrainGenerator.js +49 -37
  18. package/examples/jsm/generators/TreeGenerator.js +70 -76
  19. package/examples/jsm/generators/city/BenchGenerator.js +127 -0
  20. package/examples/jsm/generators/city/CarGenerator.js +479 -0
  21. package/examples/jsm/generators/city/CityGeneratorUtils.js +31 -0
  22. package/examples/jsm/generators/city/HydrantGenerator.js +106 -0
  23. package/examples/jsm/generators/city/InstancedMeshGenerator.js +86 -0
  24. package/examples/jsm/generators/city/PersonGenerator.js +447 -0
  25. package/examples/jsm/generators/city/SidewalkGenerator.js +33 -38
  26. package/examples/jsm/generators/city/SkyscraperGenerator.js +448 -48
  27. package/examples/jsm/generators/city/StreetTreeGenerator.js +231 -0
  28. package/examples/jsm/generators/city/StreetlightGenerator.js +100 -0
  29. package/examples/jsm/generators/city/TrafficlightGenerator.js +106 -0
  30. package/examples/jsm/generators/city/TrashcanGenerator.js +100 -0
  31. package/examples/jsm/geometries/BoxLineGeometry.js +1 -1
  32. package/examples/jsm/geometries/ParametricGeometry.js +1 -1
  33. package/examples/jsm/geometries/RoundedBoxGeometry.js +1 -1
  34. package/examples/jsm/gpgpu/CountingSort.js +271 -0
  35. package/examples/jsm/helpers/LightProbeGridHelper.js +60 -239
  36. package/examples/jsm/helpers/LightProbeGridHelperWebGL.js +221 -0
  37. package/examples/jsm/inspector/Extension.js +94 -0
  38. package/examples/jsm/inspector/Inspector.js +145 -41
  39. package/examples/jsm/inspector/RendererInspector.js +100 -52
  40. package/examples/jsm/inspector/extensions/color-grading/ColorGrading.js +2609 -0
  41. package/examples/jsm/inspector/extensions/color-grading/ColorWheel.js +352 -0
  42. package/examples/jsm/inspector/extensions/color-grading/CurveEditor.js +599 -0
  43. package/examples/jsm/inspector/extensions/color-grading/LUT3DStyle.js +1201 -0
  44. package/examples/jsm/inspector/extensions/color-grading/LUTMath.js +788 -0
  45. package/examples/jsm/inspector/extensions/color-grading/modules/BrightnessModule.js +72 -0
  46. package/examples/jsm/inspector/extensions/color-grading/modules/ColorWheelModule.js +112 -0
  47. package/examples/jsm/inspector/extensions/color-grading/modules/ContrastModule.js +82 -0
  48. package/examples/jsm/inspector/extensions/color-grading/modules/CurvesModule.js +109 -0
  49. package/examples/jsm/inspector/extensions/color-grading/modules/ExposureHueModule.js +110 -0
  50. package/examples/jsm/inspector/extensions/color-grading/modules/ExposureModule.js +73 -0
  51. package/examples/jsm/inspector/extensions/color-grading/modules/HueModule.js +78 -0
  52. package/examples/jsm/inspector/extensions/color-grading/modules/ImportedCubeModule.js +89 -0
  53. package/examples/jsm/inspector/extensions/color-grading/modules/Module.js +285 -0
  54. package/examples/jsm/inspector/extensions/color-grading/modules/OutputModule.js +101 -0
  55. package/examples/jsm/inspector/extensions/color-grading/modules/RendererModule.js +225 -0
  56. package/examples/jsm/inspector/extensions/color-grading/modules/SatVibranceModule.js +102 -0
  57. package/examples/jsm/inspector/extensions/color-grading/modules/SaturationModule.js +76 -0
  58. package/examples/jsm/inspector/extensions/color-grading/modules/VibranceModule.js +76 -0
  59. package/examples/jsm/inspector/extensions/color-grading/modules/WhiteBalanceModule.js +86 -0
  60. package/examples/jsm/inspector/extensions/tsl-graph/TSLGraphEditor.js +26 -31
  61. package/examples/jsm/inspector/extensions/tsl-graph/TSLGraphLoader.js +1 -0
  62. package/examples/jsm/inspector/tabs/Memory.js +0 -2
  63. package/examples/jsm/inspector/tabs/Settings.js +4 -0
  64. package/examples/jsm/inspector/tabs/Timeline.js +223 -171
  65. package/examples/jsm/inspector/tabs/Viewer.js +515 -21
  66. package/examples/jsm/inspector/ui/List.js +15 -9
  67. package/examples/jsm/inspector/ui/Profiler.js +170 -14
  68. package/examples/jsm/inspector/ui/Style.js +269 -23
  69. package/examples/jsm/inspector/ui/Tab.js +2 -0
  70. package/examples/jsm/inspector/ui/Values.js +14 -2
  71. package/examples/jsm/interactive/HTMLMesh.js +19 -3
  72. package/examples/jsm/lighting/LightProbeGrid.js +484 -889
  73. package/examples/jsm/lighting/LightProbeGridUtils.js +107 -0
  74. package/examples/jsm/lighting/LightProbeGridWebGL.js +841 -0
  75. package/examples/jsm/lighting/vxgi/VXGIConeTracer.js +194 -0
  76. package/examples/jsm/lighting/vxgi/VXGINode.js +660 -0
  77. package/examples/jsm/lighting/vxgi/VXGISceneCollector.js +478 -0
  78. package/examples/jsm/lighting/vxgi/VXGIVolume.js +1430 -0
  79. package/examples/jsm/lights/SunLight.js +95 -0
  80. package/examples/jsm/lights/SunLightNode.js +56 -0
  81. package/examples/jsm/lights/SunLightShadow.js +319 -0
  82. package/examples/jsm/lights/SunShadowNode.js +312 -0
  83. package/examples/jsm/loaders/3DMLoader.js +150 -49
  84. package/examples/jsm/loaders/3MFLoader.js +202 -1
  85. package/examples/jsm/loaders/FBXLoader.js +81 -5
  86. package/examples/jsm/loaders/GLTFGaussianSplatLoaderExtension.js +330 -0
  87. package/examples/jsm/loaders/GLTFLoader.js +79 -14
  88. package/examples/jsm/loaders/GaussianSplatPLYLoader.js +386 -0
  89. package/examples/jsm/loaders/KSPLATLoader.js +463 -0
  90. package/examples/jsm/loaders/MaterialXLoader.js +111 -1010
  91. package/examples/jsm/loaders/PCDLoader.js +1 -1
  92. package/examples/jsm/loaders/SPLATLoader.js +139 -0
  93. package/examples/jsm/loaders/SPZLoader.js +561 -0
  94. package/examples/jsm/loaders/materialx/MaterialXArchive.js +108 -0
  95. package/examples/jsm/loaders/materialx/MaterialXDocument.js +878 -0
  96. package/examples/jsm/loaders/materialx/MaterialXHextile.js +183 -0
  97. package/examples/jsm/loaders/materialx/MaterialXInterfaceValidation.js +376 -0
  98. package/examples/jsm/loaders/materialx/MaterialXLog.js +75 -0
  99. package/examples/jsm/loaders/materialx/MaterialXNodeInterfaceRegistry.js +4 -0
  100. package/examples/jsm/loaders/materialx/MaterialXNodeLibrary.js +1021 -0
  101. package/examples/jsm/loaders/materialx/MaterialXSurfaceMappings.js +661 -0
  102. package/examples/jsm/loaders/materialx/MaterialXUtils.js +57 -0
  103. package/examples/jsm/loaders/materialx/compile/MaterialXCompileRegistry.js +997 -0
  104. package/examples/jsm/loaders/materialx/parse/MaterialXParser.js +28 -0
  105. package/examples/jsm/loaders/usd/USDAParser.js +15 -2
  106. package/examples/jsm/loaders/usd/USDCParser.js +1 -4
  107. package/examples/jsm/loaders/usd/USDComposer.js +80 -42
  108. package/examples/jsm/materials/WoodNodeMaterial.js +6 -108
  109. package/examples/jsm/misc/RollerCoaster.js +2 -2
  110. package/examples/jsm/misc/SculptGL.LICENSE.txt +21 -0
  111. package/examples/jsm/misc/Sculptor.js +1679 -0
  112. package/examples/jsm/misc/SculptorMesh.js +1504 -0
  113. package/examples/jsm/misc/SculptorTools.js +1180 -0
  114. package/examples/jsm/misc/SculptorUtils.js +345 -0
  115. package/examples/jsm/misc/TubePainter.js +28 -16
  116. package/examples/jsm/misc/VolumeSlice.js +24 -24
  117. package/examples/jsm/modifiers/SimplifyModifier.js +63 -556
  118. package/examples/jsm/objects/GaussianSplat.js +1039 -0
  119. package/examples/jsm/objects/Sky.js +66 -45
  120. package/examples/jsm/objects/SkyMesh.js +70 -51
  121. package/examples/jsm/physics/JoltPhysics.js +1 -1
  122. package/examples/jsm/postprocessing/AfterimagePass.js +4 -2
  123. package/examples/jsm/postprocessing/BloomPass.js +2 -2
  124. package/examples/jsm/postprocessing/GTAOPass.js +1 -1
  125. package/examples/jsm/postprocessing/OutlinePass.js +5 -5
  126. package/examples/jsm/postprocessing/SAOPass.js +1 -1
  127. package/examples/jsm/postprocessing/SSAOPass.js +1 -1
  128. package/examples/jsm/postprocessing/SSRPass.js +4 -2
  129. package/examples/jsm/postprocessing/SavePass.js +1 -1
  130. package/examples/jsm/postprocessing/TAARenderPass.js +1 -1
  131. package/examples/jsm/postprocessing/UnrealBloomPass.js +30 -13
  132. package/examples/jsm/renderers/CSS2DRenderer.js +29 -5
  133. package/examples/jsm/shaders/DepthLimitedBlurShader.js +4 -1
  134. package/examples/jsm/shaders/ExposureShader.js +1 -1
  135. package/examples/jsm/shaders/FilmShader.js +2 -1
  136. package/examples/jsm/transpiler/AST.js +21 -2
  137. package/examples/jsm/transpiler/GLSLDecoder.js +498 -8
  138. package/examples/jsm/transpiler/TSLEncoder.js +82 -10
  139. package/examples/jsm/transpiler/WGSLEncoder.js +33 -4
  140. package/examples/jsm/tsl/WebGLNodesHandler.js +29 -39
  141. package/examples/jsm/tsl/display/AfterImageNode.js +2 -0
  142. package/examples/jsm/tsl/display/AnaglyphPassNode.js +3 -2
  143. package/examples/jsm/tsl/display/BilateralBlurNode.js +5 -2
  144. package/examples/jsm/tsl/display/BloomNode.js +55 -30
  145. package/examples/jsm/tsl/display/DenoiseNode.js +21 -1
  146. package/examples/jsm/tsl/display/DepthOfFieldNode.js +24 -6
  147. package/examples/jsm/tsl/display/DotScreenNode.js +11 -11
  148. package/examples/jsm/tsl/display/FSR1Node.js +8 -4
  149. package/examples/jsm/tsl/display/GTAONode.js +199 -86
  150. package/examples/jsm/tsl/display/GaussianBlurNode.js +65 -52
  151. package/examples/jsm/tsl/display/GodraysNode.js +5 -2
  152. package/examples/jsm/tsl/display/ImportanceSampledEnvironment.js +2 -2
  153. package/examples/jsm/tsl/display/LensflareNode.js +5 -2
  154. package/examples/jsm/tsl/display/OITPassNode.js +352 -0
  155. package/examples/jsm/tsl/display/OutlineNode.js +2 -0
  156. package/examples/jsm/tsl/display/ParallaxBarrierPassNode.js +3 -2
  157. package/examples/jsm/tsl/display/RGBShiftNode.js +9 -9
  158. package/examples/jsm/tsl/display/RecurrentDenoiseNode.js +7 -4
  159. package/examples/jsm/tsl/display/RetroPassNode.js +1 -1
  160. package/examples/jsm/tsl/display/SMAANode.js +22 -61
  161. package/examples/jsm/tsl/display/SSAAPassNode.js +2 -4
  162. package/examples/jsm/tsl/display/SSAONode.js +436 -0
  163. package/examples/jsm/tsl/display/SSGINode.js +5 -2
  164. package/examples/jsm/tsl/display/SSRNode.js +7 -2
  165. package/examples/jsm/tsl/display/SSSNode.js +5 -2
  166. package/examples/jsm/tsl/display/SharpenNode.js +5 -4
  167. package/examples/jsm/tsl/display/StereoCompositePassNode.js +1 -3
  168. package/examples/jsm/tsl/display/StereoPassNode.js +1 -3
  169. package/examples/jsm/tsl/display/TAAUNode.js +22 -125
  170. package/examples/jsm/tsl/display/TRAANode.js +16 -142
  171. package/examples/jsm/tsl/display/TemporalReprojectNode.js +21 -15
  172. package/examples/jsm/tsl/display/depthAwareBlur.js +63 -0
  173. package/examples/jsm/tsl/display/hashBlur.js +3 -2
  174. package/examples/jsm/tsl/lighting/ClusteredLightsNode.js +38 -27
  175. package/examples/jsm/tsl/lighting/LightProbeGridNode.js +136 -0
  176. package/examples/jsm/tsl/math/voronoiNoise.js +112 -0
  177. package/examples/jsm/tsl/shadows/TileShadowNode.js +4 -6
  178. package/examples/jsm/tsl/utils/Raymarching.js +5 -5
  179. package/examples/jsm/tsl/utils/SoftParticles.js +60 -0
  180. package/examples/jsm/tsl/utils/TAAUtils.js +195 -0
  181. package/examples/jsm/utils/BufferGeometryUtils.js +14 -14
  182. package/examples/jsm/utils/GaussianSplatUtils.js +229 -0
  183. package/examples/jsm/utils/WebGLTextureUtils.js +1 -1
  184. package/examples/jsm/utils/WebGPUTextureUtils.js +1 -1
  185. package/examples/jsm/webxr/WebGLXRFallback.js +2 -16
  186. package/examples/jsm/webxr/XRControllerModelFactory.js +16 -4
  187. package/package.json +9 -16
  188. package/src/Three.Core.js +2 -1
  189. package/src/Three.TSL.js +73 -43
  190. package/src/Three.WebGPU.Nodes.js +1 -0
  191. package/src/Three.WebGPU.js +1 -0
  192. package/src/animation/AnimationClip.js +15 -2
  193. package/src/animation/AnimationObjectGroup.js +18 -6
  194. package/src/animation/AnimationUtils.js +26 -0
  195. package/src/animation/KeyframeTrack.js +37 -0
  196. package/src/constants.js +23 -1
  197. package/src/core/BufferAttribute.js +3 -2
  198. package/src/core/BufferGeometry.js +1 -1
  199. package/src/core/InterleavedBuffer.js +5 -1
  200. package/src/core/Object3D.js +40 -12
  201. package/src/core/Raycaster.js +4 -0
  202. package/src/core/RenderTarget.js +99 -9
  203. package/src/core/RenderTarget3D.js +12 -8
  204. package/src/extras/Controls.js +0 -8
  205. package/src/extras/PMREMGenerator.js +99 -205
  206. package/src/geometries/TorusGeometry.js +1 -1
  207. package/src/helpers/ArrowHelper.js +2 -0
  208. package/src/helpers/AxesHelper.js +2 -0
  209. package/src/helpers/Box3Helper.js +2 -0
  210. package/src/helpers/BoxHelper.js +2 -0
  211. package/src/helpers/CameraHelper.js +2 -0
  212. package/src/helpers/DirectionalLightHelper.js +2 -0
  213. package/src/helpers/GridHelper.js +2 -0
  214. package/src/helpers/HemisphereLightHelper.js +2 -0
  215. package/src/helpers/PlaneHelper.js +2 -0
  216. package/src/helpers/PointLightHelper.js +2 -0
  217. package/src/helpers/PolarGridHelper.js +2 -0
  218. package/src/helpers/SkeletonHelper.js +2 -0
  219. package/src/helpers/SpotLightHelper.js +2 -0
  220. package/src/lights/Light.js +0 -10
  221. package/src/lights/LightShadow.js +43 -12
  222. package/src/lights/SpotLightShadow.js +18 -0
  223. package/src/loaders/BufferGeometryLoader.js +5 -0
  224. package/src/loaders/ImageBitmapLoader.js +3 -1
  225. package/src/loaders/ObjectLoader.js +8 -5
  226. package/src/materials/Material.js +80 -57
  227. package/src/materials/MeshPhysicalMaterial.js +32 -0
  228. package/src/materials/nodes/Line2NodeMaterial.js +17 -8
  229. package/src/materials/nodes/MeshPhysicalNodeMaterial.js +42 -5
  230. package/src/materials/nodes/NodeMaterial.js +19 -13
  231. package/src/materials/nodes/PointsNodeMaterial.js +2 -1
  232. package/src/materials/nodes/manager/NodeMaterialObserver.js +282 -55
  233. package/src/math/Frustum.js +9 -0
  234. package/src/math/FrustumArray.js +1 -1
  235. package/src/math/MathUtils.js +5 -3
  236. package/src/math/Matrix4.js +2 -9
  237. package/src/math/Plane.js +30 -1
  238. package/src/math/Quaternion.js +0 -10
  239. package/src/math/Ray.js +95 -45
  240. package/src/math/Triangle.js +0 -2
  241. package/src/math/Vector3.js +2 -2
  242. package/src/math/Vector4.js +0 -4
  243. package/src/math/interpolants/BezierInterpolant.js +36 -23
  244. package/src/nodes/Nodes.js +2 -0
  245. package/src/nodes/TSL.js +11 -3
  246. package/src/nodes/accessors/Batch.js +85 -13
  247. package/src/nodes/accessors/BufferAttributeNode.js +1 -1
  248. package/src/nodes/accessors/BuiltinNode.js +1 -1
  249. package/src/nodes/accessors/Instance.js +19 -18
  250. package/src/nodes/accessors/MaterialNode.js +9 -0
  251. package/src/nodes/accessors/ModelNode.js +85 -9
  252. package/src/nodes/accessors/ReferenceBaseNode.js +1 -70
  253. package/src/nodes/accessors/ReferenceElementNode.js +72 -0
  254. package/src/nodes/accessors/ReferenceNode.js +1 -70
  255. package/src/nodes/accessors/Skinning.js +124 -12
  256. package/src/nodes/accessors/StorageTextureNode.js +7 -3
  257. package/src/nodes/accessors/Texture3DNode.js +1 -1
  258. package/src/nodes/accessors/TextureNode.js +51 -21
  259. package/src/nodes/accessors/TextureSizeNode.js +4 -2
  260. package/src/nodes/accessors/UniformArrayNode.js +30 -5
  261. package/src/nodes/code/CodeNode.js +1 -1
  262. package/src/nodes/code/FunctionNode.js +12 -2
  263. package/src/nodes/core/ArrayNode.js +2 -2
  264. package/src/nodes/core/ContextNode.js +57 -4
  265. package/src/nodes/core/IndexNode.js +69 -4
  266. package/src/nodes/core/InspectorNode.js +2 -2
  267. package/src/nodes/core/MRTNode.js +44 -2
  268. package/src/nodes/core/Node.js +6 -3
  269. package/src/nodes/core/NodeBuilder.js +65 -50
  270. package/src/nodes/core/NodeFrame.js +11 -3
  271. package/src/nodes/core/NodeUtils.js +88 -0
  272. package/src/nodes/core/PropertyNode.js +8 -0
  273. package/src/nodes/core/StackNode.js +0 -1
  274. package/src/nodes/core/StructNode.js +4 -3
  275. package/src/nodes/core/UniformGroupNode.js +3 -2
  276. package/src/nodes/core/UniformNode.js +26 -12
  277. package/src/nodes/core/VarNode.js +0 -1
  278. package/src/nodes/display/BumpMapNode.js +2 -2
  279. package/src/nodes/display/ColorAdjustment.js +1 -1
  280. package/src/nodes/display/PassNode.js +76 -15
  281. package/src/nodes/display/ScreenNode.js +22 -65
  282. package/src/nodes/fog/Fog.js +4 -4
  283. package/src/nodes/functions/BSDF/BRDF_GGX.js +6 -6
  284. package/src/nodes/functions/BSDF/BRDF_Sheen.js +1 -1
  285. package/src/nodes/functions/BSDF/DFGLUT.js +2 -1
  286. package/src/nodes/functions/BSDF/LTC.js +1 -1
  287. package/src/nodes/functions/PhongLightingModel.js +1 -1
  288. package/src/nodes/functions/PhysicalLightingModel.js +83 -25
  289. package/src/nodes/functions/ToonLightingModel.js +2 -2
  290. package/src/nodes/functions/material/getParallaxCorrectNormal.js +3 -3
  291. package/src/nodes/gpgpu/AtomicFunctionNode.js +64 -13
  292. package/src/nodes/gpgpu/BarrierNode.js +13 -4
  293. package/src/nodes/gpgpu/ComputeBuiltinNode.js +1 -1
  294. package/src/nodes/gpgpu/ComputeNode.js +20 -17
  295. package/src/nodes/gpgpu/SubgroupFunctionNode.js +165 -37
  296. package/src/nodes/gpgpu/WorkgroupInfoNode.js +44 -6
  297. package/src/nodes/lighting/EnvironmentNode.js +40 -4
  298. package/src/nodes/lighting/LightsNode.js +20 -4
  299. package/src/nodes/lighting/ShadowBaseNode.js +158 -1
  300. package/src/nodes/lighting/ShadowFilterNode.js +2 -106
  301. package/src/nodes/lighting/ShadowNode.js +22 -91
  302. package/src/nodes/materialx/{lib/mx_hsv.js → MaterialXColor.js} +3 -6
  303. package/src/nodes/materialx/{lib/mx_transform_color.js → MaterialXColorTransform.js} +3 -6
  304. package/src/nodes/materialx/MaterialXCore.js +37 -0
  305. package/src/nodes/materialx/MaterialXNodes.js +64 -72
  306. package/src/nodes/materialx/{lib/mx_noise.js → MaterialXNoise.js} +426 -197
  307. package/src/nodes/math/BitcountNode.js +24 -4
  308. package/src/nodes/math/MathNode.js +4 -4
  309. package/src/nodes/math/MathUtils.js +15 -4
  310. package/src/nodes/math/OperatorNode.js +2 -2
  311. package/src/nodes/math/PackFloatNode.js +29 -1
  312. package/src/nodes/math/Packed4x8IntegerNode.js +433 -0
  313. package/src/nodes/math/UnpackFloatNode.js +30 -2
  314. package/src/nodes/parsers/GLSLNodeFunction.js +1 -1
  315. package/src/nodes/pmrem/PMREMNode.js +1 -1
  316. package/src/nodes/pmrem/PMREMUtils.js +31 -74
  317. package/src/nodes/shapes/Shapes.js +1 -1
  318. package/src/nodes/tsl/TSLCore.js +1 -31
  319. package/src/nodes/utils/EventNode.js +75 -0
  320. package/src/nodes/utils/LoopNode.js +54 -13
  321. package/src/nodes/utils/PostProcessingUtils.js +23 -2
  322. package/src/nodes/utils/RTTNode.js +97 -32
  323. package/src/nodes/utils/ReflectorNode.js +8 -4
  324. package/src/nodes/utils/RotateNode.js +85 -8
  325. package/src/nodes/utils/SpriteUtils.js +58 -23
  326. package/src/objects/BatchedMesh.js +6 -0
  327. package/src/objects/InstancedMesh.js +1 -1
  328. package/src/objects/LOD.js +1 -1
  329. package/src/objects/Line.js +12 -0
  330. package/src/objects/Mesh.js +12 -0
  331. package/src/objects/Points.js +12 -0
  332. package/src/objects/Sprite.js +12 -0
  333. package/src/renderers/WebGLRenderer.js +93 -27
  334. package/src/renderers/common/Animation.js +12 -2
  335. package/src/renderers/common/Backend.js +38 -10
  336. package/src/renderers/common/BindGroup.js +0 -1
  337. package/src/renderers/common/Bindings.js +50 -4
  338. package/src/renderers/common/BundleGroup.js +4 -0
  339. package/src/renderers/common/ClippingContext.js +11 -1
  340. package/src/renderers/common/Color4.js +9 -0
  341. package/src/renderers/common/Constants.js +0 -5
  342. package/src/renderers/common/DirectRenderPipeline.js +233 -0
  343. package/src/renderers/common/Geometries.js +24 -3
  344. package/src/renderers/common/Info.js +3 -3
  345. package/src/renderers/common/InspectorBase.js +37 -8
  346. package/src/renderers/common/Lighting.js +11 -4
  347. package/src/renderers/common/Pipelines.js +6 -4
  348. package/src/renderers/common/QuadMesh.js +16 -2
  349. package/src/renderers/common/RenderContext.js +8 -0
  350. package/src/renderers/common/RenderList.js +53 -19
  351. package/src/renderers/common/RenderLists.js +58 -11
  352. package/src/renderers/common/RenderObject.js +14 -0
  353. package/src/renderers/common/RenderObjects.js +14 -9
  354. package/src/renderers/common/RenderPipeline.js +52 -44
  355. package/src/renderers/common/Renderer.js +226 -55
  356. package/src/renderers/common/Storage3DTexture.js +16 -0
  357. package/src/renderers/common/Textures.js +3 -3
  358. package/src/renderers/common/XRManager.js +79 -72
  359. package/src/renderers/common/extras/PMREMGenerator.js +76 -144
  360. package/src/renderers/common/nodes/NodeManager.js +144 -6
  361. package/src/renderers/common/nodes/NodeStorageBuffer.js +3 -1
  362. package/src/renderers/common/nodes/NodeUniformBuffer.js +3 -1
  363. package/src/renderers/shaders/DFGLUTData.js +2 -1
  364. package/src/renderers/shaders/ShaderChunk/defaultnormal_vertex.glsl.js +4 -2
  365. package/src/renderers/shaders/ShaderChunk/envmap_physical_pars_fragment.glsl.js +48 -0
  366. package/src/renderers/shaders/ShaderChunk/lights_fragment_begin.glsl.js +53 -4
  367. package/src/renderers/shaders/ShaderChunk/lights_fragment_maps.glsl.js +20 -2
  368. package/src/renderers/shaders/ShaderChunk/lights_pars_begin.glsl.js +20 -0
  369. package/src/renderers/shaders/ShaderChunk/lights_physical_fragment.glsl.js +6 -0
  370. package/src/renderers/shaders/ShaderChunk/lights_physical_pars_fragment.glsl.js +61 -57
  371. package/src/renderers/shaders/ShaderChunk/shadowmap_pars_fragment.glsl.js +82 -0
  372. package/src/renderers/shaders/ShaderChunk/shadowmap_pars_vertex.glsl.js +9 -0
  373. package/src/renderers/shaders/ShaderChunk/shadowmap_vertex.glsl.js +8 -1
  374. package/src/renderers/shaders/ShaderChunk/shadowmask_pars_fragment.glsl.js +15 -0
  375. package/src/renderers/shaders/ShaderLib/meshphysical.glsl.js +4 -0
  376. package/src/renderers/shaders/ShaderLib.js +1 -0
  377. package/src/renderers/shaders/UniformsLib.js +16 -0
  378. package/src/renderers/webgl/WebGLAnimation.js +2 -2
  379. package/src/renderers/webgl/WebGLCapabilities.js +2 -2
  380. package/src/renderers/webgl/WebGLLights.js +74 -4
  381. package/src/renderers/webgl/WebGLMaterials.js +6 -0
  382. package/src/renderers/webgl/WebGLOutput.js +36 -24
  383. package/src/renderers/webgl/WebGLProgram.js +3 -0
  384. package/src/renderers/webgl/WebGLPrograms.js +8 -0
  385. package/src/renderers/webgl/WebGLRenderLists.js +6 -10
  386. package/src/renderers/webgl/WebGLShadowMap.js +47 -44
  387. package/src/renderers/webgl/WebGLTextures.js +7 -7
  388. package/src/renderers/webgl-fallback/WebGLBackend.js +153 -45
  389. package/src/renderers/webgl-fallback/nodes/GLSLNodeBuilder.js +83 -29
  390. package/src/renderers/webgl-fallback/utils/WebGLState.js +163 -17
  391. package/src/renderers/webgl-fallback/utils/WebGLTextureUtils.js +32 -5
  392. package/src/renderers/webgl-fallback/utils/WebGLTimestampQueryPool.js +11 -4
  393. package/src/renderers/webgpu/WebGPUBackend.js +513 -145
  394. package/src/renderers/webgpu/nodes/WGSLNodeBuilder.js +99 -20
  395. package/src/renderers/webgpu/nodes/WGSLNodeFunction.js +2 -1
  396. package/src/renderers/webgpu/utils/WebGPUAttributeUtils.js +3 -12
  397. package/src/renderers/webgpu/utils/WebGPUBindingUtils.js +24 -14
  398. package/src/renderers/webgpu/utils/WebGPUPipelineUtils.js +80 -14
  399. package/src/renderers/webgpu/utils/WebGPUTextureUtils.js +62 -7
  400. package/src/renderers/webgpu/utils/WebGPUTimestampQueryPool.js +9 -3
  401. package/src/renderers/webgpu/utils/WebGPUUtils.js +16 -4
  402. package/src/renderers/webxr/WebXRManager.js +25 -2
  403. package/src/scenes/Scene.js +3 -3
  404. package/src/textures/CompressedArrayTexture.js +16 -0
  405. package/src/textures/Data3DTexture.js +16 -0
  406. package/src/textures/DataArrayTexture.js +16 -0
  407. package/src/textures/DepthTexture.js +3 -3
  408. package/src/textures/Texture.js +3 -3
  409. package/src/textures/{Source.js → TextureSource.js} +39 -8
  410. package/src/utils.js +6 -79
  411. package/build/three.core.min.js +0 -6
  412. package/build/three.module.min.js +0 -6
  413. package/build/three.tsl.min.js +0 -6
  414. package/build/three.webgpu.min.js +0 -6
  415. package/build/three.webgpu.nodes.min.js +0 -6
  416. package/examples/jsm/libs/ecsy.module.js +0 -1792
  417. package/examples/jsm/loaders/LottieLoader.js +0 -130
  418. package/src/nodes/functions/BSDF/BRDF_GGX_Multiscatter.js +0 -52
@@ -1,5 +1,5 @@
1
1
  import { TempNode, NodeMaterial, NodeUpdateType, RenderTarget, Vector2, HalfFloatType, RedFormat, QuadMesh, RendererUtils } from '@gnsx/three/webgpu';
2
- import { convertToTexture, nodeObject, Fn, uniform, smoothstep, step, texture, max, uniformArray, outputStruct, property, vec4, vec3, uv, Loop, min, mix, float } from '@gnsx/three/tsl';
2
+ import { convertToTexture, nodeObject, Fn, uniform, smoothstep, step, texture, max, uniformArray, outputStruct, property, vec4, vec3, uv, Loop, min, mix, float, context } from '@gnsx/three/tsl';
3
3
  import { gaussianBlur } from './GaussianBlurNode.js';
4
4
 
5
5
  const _quadMesh = /*@__PURE__*/ new QuadMesh();
@@ -190,6 +190,14 @@ class DepthOfFieldNode extends TempNode {
190
190
  */
191
191
  this._CoCTextureNode = texture( this._CoCRT.texture );
192
192
 
193
+ /**
194
+ * The Gaussian blur node used to blur the near field's circle of confusion.
195
+ *
196
+ * @private
197
+ * @type {GaussianBlurNode}
198
+ */
199
+ this._CoCBlurNode = gaussianBlur( this._CoCTextureNode, 1, 2 );
200
+
193
201
  /**
194
202
  * The result of the blur64 pass as a texture node.
195
203
  *
@@ -351,6 +359,8 @@ class DepthOfFieldNode extends TempNode {
351
359
  */
352
360
  setup( builder ) {
353
361
 
362
+ const sharedContext = context( builder.getSharedContext() );
363
+
354
364
  const kernels = this._generateKernels();
355
365
 
356
366
  // CoC, near and far fields
@@ -372,13 +382,14 @@ class DepthOfFieldNode extends TempNode {
372
382
 
373
383
  } );
374
384
 
375
- this._CoCMaterial.colorNode = CoC().context( builder.getSharedContext() );
385
+ this._CoCMaterial.contextNode = sharedContext;
386
+ this._CoCMaterial.colorNode = CoC();
376
387
  this._CoCMaterial.outputNode = outputNode;
377
388
  this._CoCMaterial.needsUpdate = true;
378
389
 
379
390
  // blurred CoC for near field
380
391
 
381
- this._CoCBlurredMaterial.colorNode = gaussianBlur( this._CoCTextureNode, 1, 2 );
392
+ this._CoCBlurredMaterial.colorNode = this._CoCBlurNode;
382
393
  this._CoCBlurredMaterial.needsUpdate = true;
383
394
 
384
395
  // bokeh 64 blur pass
@@ -408,7 +419,8 @@ class DepthOfFieldNode extends TempNode {
408
419
 
409
420
  } );
410
421
 
411
- this._blur64Material.fragmentNode = blur64().context( builder.getSharedContext() );
422
+ this._blur64Material.contextNode = sharedContext;
423
+ this._blur64Material.fragmentNode = blur64();
412
424
  this._blur64Material.needsUpdate = true;
413
425
 
414
426
  // bokeh 16 blur pass
@@ -437,7 +449,8 @@ class DepthOfFieldNode extends TempNode {
437
449
 
438
450
  } );
439
451
 
440
- this._blur16Material.fragmentNode = blur16().context( builder.getSharedContext() );
452
+ this._blur16Material.contextNode = sharedContext;
453
+ this._blur16Material.fragmentNode = blur16();
441
454
  this._blur16Material.needsUpdate = true;
442
455
 
443
456
  // composite
@@ -466,7 +479,8 @@ class DepthOfFieldNode extends TempNode {
466
479
 
467
480
  } );
468
481
 
469
- this._compositeMaterial.fragmentNode = composite().context( builder.getSharedContext() );
482
+ this._compositeMaterial.contextNode = sharedContext;
483
+ this._compositeMaterial.fragmentNode = composite();
470
484
  this._compositeMaterial.needsUpdate = true;
471
485
 
472
486
  return this._textureNode;
@@ -520,6 +534,8 @@ class DepthOfFieldNode extends TempNode {
520
534
  */
521
535
  dispose() {
522
536
 
537
+ super.dispose();
538
+
523
539
  this._CoCRT.dispose();
524
540
  this._CoCBlurredRT.dispose();
525
541
  this._blur64RT.dispose();
@@ -533,6 +549,8 @@ class DepthOfFieldNode extends TempNode {
533
549
  this._blur16Material.dispose();
534
550
  this._compositeMaterial.dispose();
535
551
 
552
+ this._CoCBlurNode.dispose();
553
+
536
554
  }
537
555
 
538
556
  }
@@ -1,5 +1,5 @@
1
1
  import { TempNode } from '@gnsx/three/webgpu';
2
- import { nodeObject, Fn, uv, uniform, vec2, vec3, sin, cos, add, vec4, screenSize } from '@gnsx/three/tsl';
2
+ import { nodeObject, Fn, uv, vec2, vec3, sin, cos, add, vec4, screenSize } from '@gnsx/three/tsl';
3
3
 
4
4
  /**
5
5
  * Post processing node for creating dot-screen effect.
@@ -19,8 +19,8 @@ class DotScreenNode extends TempNode {
19
19
  * Constructs a new dot screen node.
20
20
  *
21
21
  * @param {Node} inputNode - The node that represents the input of the effect.
22
- * @param {number} [angle=1.57] - The rotation of the effect in radians.
23
- * @param {number} [scale=1] - The scale of the effect. A higher value means smaller dots.
22
+ * @param {number|Node<float>} [angle=1.57] - The rotation of the effect in radians.
23
+ * @param {number|Node<float>} [scale=1] - The scale of the effect. A higher value means smaller dots.
24
24
  */
25
25
  constructor( inputNode, angle = 1.57, scale = 1 ) {
26
26
 
@@ -34,18 +34,18 @@ class DotScreenNode extends TempNode {
34
34
  this.inputNode = inputNode;
35
35
 
36
36
  /**
37
- * A uniform node that represents the rotation of the effect in radians.
37
+ * The rotation of the effect in radians.
38
38
  *
39
- * @type {UniformNode<float>}
39
+ * @type {Node<float>}
40
40
  */
41
- this.angle = uniform( angle );
41
+ this.angle = nodeObject( angle );
42
42
 
43
43
  /**
44
- * A uniform node that represents the scale of the effect. A higher value means smaller dots.
44
+ * The scale of the effect. A higher value means smaller dots.
45
45
  *
46
- * @type {UniformNode<float>}
46
+ * @type {Node<float>}
47
47
  */
48
- this.scale = uniform( scale );
48
+ this.scale = nodeObject( scale );
49
49
 
50
50
  }
51
51
 
@@ -97,8 +97,8 @@ export default DotScreenNode;
97
97
  * @tsl
98
98
  * @function
99
99
  * @param {Node<vec4>} node - The node that represents the input of the effect.
100
- * @param {number} [angle=1.57] - The rotation of the effect in radians.
101
- * @param {number} [scale=1] - The scale of the effect. A higher value means smaller dots.
100
+ * @param {number|Node<float>} [angle=1.57] - The rotation of the effect in radians.
101
+ * @param {number|Node<float>} [scale=1] - The scale of the effect. A higher value means smaller dots.
102
102
  * @returns {DotScreenNode}
103
103
  */
104
104
  export const dotScreen = ( node, angle, scale ) => new DotScreenNode( nodeObject( node ), angle, scale );
@@ -1,5 +1,5 @@
1
1
  import { HalfFloatType, RenderTarget, Vector2, NodeMaterial, RendererUtils, QuadMesh, TempNode, NodeUpdateType } from '@gnsx/three/webgpu';
2
- import { Fn, float, vec2, vec3, vec4, ivec2, int, uv, floor, fract, abs, max, min, clamp, saturate, sqrt, select, exp2, nodeObject, passTexture, textureSize, textureLoad, convertToTexture } from '@gnsx/three/tsl';
2
+ import { Fn, float, vec2, vec3, vec4, ivec2, int, uv, floor, fract, abs, max, min, clamp, saturate, sqrt, select, exp2, nodeObject, passTexture, textureSize, textureLoad, convertToTexture, context } from '@gnsx/three/tsl';
3
3
 
4
4
  const _quadMesh = /*@__PURE__*/ new QuadMesh();
5
5
  const _size = /*@__PURE__*/ new Vector2();
@@ -423,15 +423,17 @@ class FSR1Node extends TempNode {
423
423
 
424
424
  //
425
425
 
426
- const context = builder.getSharedContext();
426
+ const sharedContext = context( builder.getSharedContext() );
427
427
 
428
428
  const easuMaterial = this._easuMaterial || ( this._easuMaterial = new NodeMaterial() );
429
- easuMaterial.fragmentNode = easu().context( context );
429
+ easuMaterial.contextNode = sharedContext;
430
+ easuMaterial.fragmentNode = easu();
430
431
  easuMaterial.name = 'FSR1_EASU';
431
432
  easuMaterial.needsUpdate = true;
432
433
 
433
434
  const rcasMaterial = this._rcasMaterial || ( this._rcasMaterial = new NodeMaterial() );
434
- rcasMaterial.fragmentNode = rcas().context( context );
435
+ rcasMaterial.contextNode = sharedContext;
436
+ rcasMaterial.fragmentNode = rcas();
435
437
  rcasMaterial.name = 'FSR1_RCAS';
436
438
  rcasMaterial.needsUpdate = true;
437
439
 
@@ -452,6 +454,8 @@ class FSR1Node extends TempNode {
452
454
  */
453
455
  dispose() {
454
456
 
457
+ super.dispose();
458
+
455
459
  this._easuRT.dispose();
456
460
  this._rcasRT.dispose();
457
461
 
@@ -1,11 +1,12 @@
1
1
  import { DataTexture, RenderTarget, RepeatWrapping, Vector2, Vector3, TempNode, QuadMesh, NodeMaterial, RendererUtils, RedFormat } from '@gnsx/three/webgpu';
2
- import { reference, logarithmicDepthToViewZ, viewZToPerspectiveDepth, getNormalFromDepth, getScreenPosition, getViewPosition, nodeObject, Fn, float, NodeUpdateType, uv, uniform, Loop, vec2, vec3, vec4, int, dot, max, min, pow, abs, If, textureSize, sin, cos, PI, texture, passTexture, mat3, add, normalize, mul, cross, div, mix, acos, clamp } from '@gnsx/three/tsl';
2
+ import { reference, logarithmicDepthToViewZ, viewZToPerspectiveDepth, getNormalFromDepth, getViewPosition, getScreenPositionFromClip, nodeObject, Fn, float, NodeUpdateType, uv, uniform, Loop, vec2, vec3, vec4, int, dot, max, min, pow, abs, If, textureSize, sin, cos, PI, texture, passTexture, mat3, normalize, cross, mix, acos, clamp, interleavedGradientNoise, screenCoordinate, rand, context } from '@gnsx/three/tsl';
3
3
 
4
4
  const _quadMesh = /*@__PURE__*/ new QuadMesh();
5
5
  const _size = /*@__PURE__*/ new Vector2();
6
6
 
7
7
  // From Activision GTAO paper: https://www.activision.com/cdn/research/s2016_pbs_activision_occlusion.pptx
8
8
  const _temporalRotations = [ 60, 300, 180, 240, 120, 0 ];
9
+ const _spatialOffsets = [ 0, 0.5, 0.25, 0.75 ];
9
10
 
10
11
  let _rendererState;
11
12
 
@@ -14,20 +15,30 @@ let _rendererState;
14
15
  * ```js
15
16
  * const renderPipeline = new THREE.RenderPipeline( renderer );
16
17
  *
17
- * const scenePass = pass( scene, camera );
18
- * scenePass.setMRT( mrt( {
19
- * output: output,
20
- * normal: normalView
18
+ * // pre-pass for normals and depth
19
+ *
20
+ * const prePass = pass( scene, camera );
21
+ * prePass.setMRT( mrt( {
22
+ * output: normalView
21
23
  * } ) );
22
24
  *
23
- * const scenePassColor = scenePass.getTextureNode( 'output' );
24
- * const scenePassNormal = scenePass.getTextureNode( 'normal' );
25
- * const scenePassDepth = scenePass.getTextureNode( 'depth' );
25
+ * const prePassNormal = prePass.getTextureNode();
26
+ * const prePassDepth = prePass.getTextureNode( 'depth' );
27
+ *
28
+ * // scene pass
29
+ *
30
+ * const scenePass = pass( scene, camera );
31
+ *
32
+ * // ao
26
33
  *
27
- * const aoPass = ao( scenePassDepth, scenePassNormal, camera );
34
+ * const aoPass = ao( prePassDepth, prePassNormal, camera );
28
35
  * const aoPassOutput = aoPass.getTextureNode();
29
36
  *
30
- * renderPipeline.outputNode = scenePassColor.mul( vec4( vec3( aoPassOutput.r ), 1 ) );
37
+ * // apply the ambient occlusion to the scene
38
+ *
39
+ * scenePass.contextNode = builtinAOContext( aoPassOutput.sample( screenUV ).r );
40
+ *
41
+ * renderPipeline.outputNode = scenePass;
31
42
  * ```
32
43
  *
33
44
  * Reference: [Practical Real-Time Strategies for Accurate Indirect Occlusion](https://www.activision.com/cdn/research/Practical_Real_Time_Strategies_for_Accurate_Indirect_Occlusion_NEW%20VERSION_COLOR.pdf).
@@ -72,9 +83,7 @@ class GTAONode extends TempNode {
72
83
 
73
84
  // WITH_GENESYS
74
85
  /**
75
- * Optional node that marks pixels where GTAO should run. This is sampled only
76
- * for the center pixel, allowing neighbor depth taps to use the raw depth
77
- * texture without repeating an auxiliary validity texture fetch.
86
+ * Optional center-pixel validity node, sampled once before GTAO ray marching.
78
87
  *
79
88
  * @type {?Node<float>}
80
89
  * @default null
@@ -120,9 +129,7 @@ class GTAONode extends TempNode {
120
129
 
121
130
  // WITH_GENESYS
122
131
  /**
123
- * Maximum screen-space radius in pixels. Clamps the projected world-space
124
- * radius when the camera is close to surfaces so sample UVs stay local and
125
- * avoid texture-cache thrashing (Activision GTAO guidance).
132
+ * Max projected AO radius in pixels; clamps near-camera sample stride.
126
133
  *
127
134
  * @type {UniformNode<float>}
128
135
  * @default 64
@@ -130,14 +137,6 @@ class GTAONode extends TempNode {
130
137
  this.maxScreenRadius = uniform( 64 );
131
138
  // !WITH_GENESYS
132
139
 
133
- /**
134
- * The resolution of the effect. Can be scaled via
135
- * `resolutionScale`.
136
- *
137
- * @type {UniformNode<vec2>}
138
- */
139
- this.resolution = uniform( new Vector2() );
140
-
141
140
  /**
142
141
  * The thickness of the ambient occlusion.
143
142
  *
@@ -146,17 +145,16 @@ class GTAONode extends TempNode {
146
145
  this.thickness = uniform( 1 );
147
146
 
148
147
  /**
149
- * Another option to tweak the occlusion. The recommended range is
150
- * `[1,2]` for attenuating the AO.
148
+ * @deprecated since r186. The new distance model "Quadratic Ray Stepping"
149
+ * does not need it anymore.
151
150
  *
152
151
  * @type {UniformNode<float>}
153
152
  */
154
153
  this.distanceExponent = uniform( 1 );
155
154
 
156
155
  /**
157
- * The distance fall off value of the ambient occlusion.
158
- * A lower value leads to a larger AO effect. The value
159
- * should lie in the range `[0,1]`.
156
+ * @deprecated since r186. The new distance model "Quadratic Ray Stepping"
157
+ * does not need it anymore.
160
158
  *
161
159
  * @type {UniformNode<float>}
162
160
  */
@@ -174,6 +172,8 @@ class GTAONode extends TempNode {
174
172
  * A higher value results in better quality but also
175
173
  * in a more expensive runtime behavior.
176
174
  *
175
+ * Note: Changing this member triggers a shader recompilation.
176
+ *
177
177
  * @type {UniformNode<float>}
178
178
  */
179
179
  this.samples = uniform( 16 );
@@ -192,13 +192,29 @@ class GTAONode extends TempNode {
192
192
  */
193
193
  this.useTemporalFiltering = false;
194
194
 
195
+ /**
196
+ * The resolution of the effect. Can be scaled via `resolutionScale`.
197
+ *
198
+ * @private
199
+ * @type {UniformNode<vec2>}
200
+ */
201
+ this._resolution = uniform( new Vector2() );
202
+
203
+ /**
204
+ * The internal noise texture used by the AO.
205
+ *
206
+ * @private
207
+ * @type {DataTexture}
208
+ */
209
+ this._noiseTexture = generateMagicSquareNoise();
210
+
195
211
  /**
196
212
  * The node represents the internal noise texture used by the AO.
197
213
  *
198
214
  * @private
199
215
  * @type {TextureNode}
200
216
  */
201
- this._noiseNode = texture( generateMagicSquareNoise() );
217
+ this._noiseNode = texture( this._noiseTexture );
202
218
 
203
219
  /**
204
220
  * Represents the projection matrix of the scene's camera.
@@ -240,6 +256,48 @@ class GTAONode extends TempNode {
240
256
  */
241
257
  this._temporalDirection = uniform( 0 );
242
258
 
259
+ /**
260
+ * Temporal offset added to the initial ray step.
261
+ *
262
+ * @private
263
+ * @type {UniformNode<float>}
264
+ */
265
+ this._temporalOffset = uniform( 0 );
266
+
267
+ /**
268
+ * Resolution scale uniform.
269
+ *
270
+ * @private
271
+ * @type {UniformNode<float>}
272
+ */
273
+ this._resolutionScale = uniform( 0 );
274
+
275
+ /**
276
+ * The TSL function that computes the AO. Required for rebuild.
277
+ *
278
+ * @private
279
+ * @type {?Function}
280
+ * @default null
281
+ */
282
+ this._ao = null;
283
+
284
+ /**
285
+ * The sample count currently baked into the shader.
286
+ *
287
+ * @private
288
+ * @type {number}
289
+ */
290
+ this._currentSamples = - 1;
291
+
292
+ /**
293
+ * The shared builder context. Required for rebuild.
294
+ *
295
+ * @private
296
+ * @type {?Object}
297
+ * @default null
298
+ */
299
+ this._sharedContext = null;
300
+
243
301
  /**
244
302
  * The material that is used to render the effect.
245
303
  *
@@ -281,7 +339,8 @@ class GTAONode extends TempNode {
281
339
  width = Math.round( this.resolutionScale * width );
282
340
  height = Math.round( this.resolutionScale * height );
283
341
 
284
- this.resolution.value.set( width, height );
342
+ this._resolutionScale.value = this.resolutionScale;
343
+ this._resolution.value.set( width, height );
285
344
  this._aoRenderTarget.setSize( width, height );
286
345
 
287
346
  }
@@ -304,10 +363,24 @@ class GTAONode extends TempNode {
304
363
  const frameId = frame.frameId;
305
364
 
306
365
  this._temporalDirection.value = _temporalRotations[ frameId % 6 ] / 360;
366
+ this._temporalOffset.value = _spatialOffsets[ frameId % 4 ];
307
367
 
308
368
  } else {
309
369
 
310
370
  this._temporalDirection.value = 0;
371
+ this._temporalOffset.value = 1;
372
+
373
+ }
374
+
375
+ // rebuild the material if the sample count has changed
376
+
377
+ if ( this.samples.value !== this._currentSamples ) {
378
+
379
+ this._currentSamples = this.samples.value;
380
+
381
+ this._material.contextNode = context( this._sharedContext );
382
+ this._material.fragmentNode = this._ao();
383
+ this._material.needsUpdate = true;
311
384
 
312
385
  }
313
386
 
@@ -344,9 +417,7 @@ class GTAONode extends TempNode {
344
417
 
345
418
  const uvNode = uv();
346
419
 
347
- const sampleDepth = ( uv ) => {
348
-
349
- const depth = this.depthNode.sample( uv ).r;
420
+ const linearizeDepth = ( depth ) => {
350
421
 
351
422
  if ( builder.renderer.logarithmicDepthBuffer === true ) {
352
423
 
@@ -360,12 +431,25 @@ class GTAONode extends TempNode {
360
431
 
361
432
  };
362
433
 
434
+ const sampleDepth = ( uv ) => linearizeDepth( this.depthNode.sample( uv ).r );
435
+
436
+ const sampleCenterDepth = ( uv ) => {
437
+
438
+ // Sidestep the nearest-rounding during depth access for the unjittered center pixel to avoid banding
439
+
440
+ const g = this.depthNode.gather().sample( uv );
441
+ const depth = min( min( g.x, g.y ), min( g.z, g.w ) );
442
+
443
+ return linearizeDepth( depth );
444
+
445
+ };
446
+
363
447
  const sampleNoise = ( uv ) => this._noiseNode.sample( uv );
364
448
  const sampleNormal = ( uv ) => ( this.normalNode !== null ) ? this.normalNode.sample( uv ).rgb.normalize() : getNormalFromDepth( uv, this.depthNode.value, this._cameraProjectionMatrixInverse );
365
449
 
366
- const ao = Fn( () => {
450
+ this._ao = Fn( () => {
367
451
 
368
- const depth = sampleDepth( uvNode ).toVar();
452
+ const depth = this._resolutionScale.lessThan( 1 ).select( sampleCenterDepth( uvNode ), sampleDepth( uvNode ) ).toConst();
369
453
 
370
454
  // WITH_GENESYS
371
455
  if ( this.validityNode !== null ) {
@@ -377,24 +461,26 @@ class GTAONode extends TempNode {
377
461
 
378
462
  depth.greaterThanEqual( 1.0 ).discard();
379
463
 
380
- const viewPosition = getViewPosition( uvNode, depth, this._cameraProjectionMatrixInverse ).toVar();
381
- const viewNormal = sampleNormal( uvNode ).toVar();
464
+ const viewPosition = getViewPosition( uvNode, depth, this._cameraProjectionMatrixInverse ).toConst();
465
+ const viewNormal = sampleNormal( uvNode ).toConst();
382
466
 
467
+ const clipPosition = this._cameraProjectionMatrix.mul( vec4( viewPosition, 1.0 ) ).toConst();
383
468
  // WITH_GENESYS
384
469
  // Clamp world radius so its screen footprint never exceeds maxScreenRadius
385
470
  // pixels. Without this, near-camera surfaces project a huge UV stride and
386
471
  // the depth/normal taps thrash the texture cache.
387
- const probeScreen = getScreenPosition( viewPosition.add( vec3( this.radius, 0.0, 0.0 ) ), this._cameraProjectionMatrix );
388
- const centerScreen = getScreenPosition( viewPosition, this._cameraProjectionMatrix );
389
- const screenRadiusPx = abs( probeScreen.x.sub( centerScreen.x ) ).mul( this.resolution.x );
472
+ const probeClip = this._cameraProjectionMatrix.mul( vec4( viewPosition.add( vec3( this.radius, 0.0, 0.0 ) ), 1.0 ) );
473
+ const screenRadiusPx = abs( getScreenPositionFromClip( probeClip ).x.sub( getScreenPositionFromClip( clipPosition ).x ) ).mul( this._resolution.x );
390
474
  const radiusScale = min( float( 1.0 ), this.maxScreenRadius.div( max( screenRadiusPx, float( 1e-4 ) ) ) );
391
- const radiusToUse = this.radius.mul( radiusScale );
475
+ const radius = this.radius.mul( radiusScale );
392
476
  // !WITH_GENESYS
393
- // const radiusToUse = this.radius;
477
+ // const radius = this.radius;
478
+ const invRadius = radius.reciprocal().toConst();
479
+ const viewDir = normalize( viewPosition.xyz.negate() ).toConst();
394
480
 
395
481
  const noiseResolution = textureSize( this._noiseNode, 0 );
396
482
  let noiseUv = vec2( uvNode.x, uvNode.y.oneMinus() );
397
- noiseUv = noiseUv.mul( this.resolution.div( noiseResolution ) );
483
+ noiseUv = noiseUv.mul( this._resolution.div( noiseResolution ) );
398
484
 
399
485
  const noiseTexel = sampleNoise( noiseUv );
400
486
  const randomVec = noiseTexel.xyz.mul( 2.0 ).sub( 1.0 );
@@ -402,80 +488,99 @@ class GTAONode extends TempNode {
402
488
  const bitangent = vec3( tangent.y.mul( - 1.0 ), tangent.x, 0.0 );
403
489
  const kernelMatrix = mat3( tangent, bitangent, vec3( 0.0, 0.0, 1.0 ) );
404
490
 
405
- // WITH_GENESYS
406
- // A clamped radius covers less screen space, so proportionally reduce the
407
- // sample budget as well. Keeping all samples only changes tap locality and
408
- // does not address the near-camera shader cost.
409
- const samplesToUse = min( this.samples, max( float( 6 ), this.samples.mul( radiusScale ) ) ).toVar();
410
- const DIRECTIONS = samplesToUse.lessThan( 30 ).select( 3, 5 ).toVar();
411
- const STEPS = add( samplesToUse, DIRECTIONS.sub( 1 ) ).div( DIRECTIONS ).toVar();
412
- // !WITH_GENESYS
413
- // const DIRECTIONS = this.samples.lessThan( 30 ).select( 3, 5 ).toVar();
414
- // const STEPS = add( this.samples, DIRECTIONS.sub( 1 ) ).div( DIRECTIONS ).toVar();
491
+ // The sample count is baked into the shader so loop unrolling works
492
+
493
+ const SAMPLES = this.samples.value;
494
+ const DIRECTIONS = SAMPLES < 30 ? 3 : 5;
495
+ const STEPS = Math.ceil( SAMPLES / DIRECTIONS );
496
+ const invSteps = 1 / STEPS;
415
497
 
416
498
  const ao = float( 0 ).toVar();
417
499
 
418
500
  // Each iteration analyzes one vertical "slice" of the 3D space around the fragment.
419
501
 
420
- Loop( { start: int( 0 ), end: DIRECTIONS, type: 'int', condition: '<' }, ( { i } ) => {
502
+ // Per-step phase jitter for spatio-temporal decorrelation.
503
+ const noiseJitterIdx = this._temporalDirection.mul( 0.02 );
504
+ const stepJitter = interleavedGradientNoise( screenCoordinate.add( this._temporalOffset ) ).add( rand( uvNode.add( noiseJitterIdx ).mul( 2 ).sub( 1 ) ) );
505
+
506
+ Loop( { start: int( 0 ), end: int( DIRECTIONS ), type: 'int', condition: '<' }, ( { i } ) => {
421
507
 
422
- const angle = float( i ).div( float( DIRECTIONS ) ).mul( PI ).add( this._temporalDirection ).toVar();
423
- const sampleDir = vec4( cos( angle ), sin( angle ), 0., add( 0.5, mul( 0.5, noiseTexel.w ) ) );
424
- sampleDir.xyz = normalize( kernelMatrix.mul( sampleDir.xyz ) );
508
+ const angle = float( i ).div( DIRECTIONS ).mul( PI ).add( this._temporalDirection ).toConst();
509
+ const sampleDir = kernelMatrix.mul( vec3( cos( angle ), sin( angle ), 0 ) ).toConst();
510
+ const clipDirRadius = this._cameraProjectionMatrix.mul( vec4( sampleDir, 0.0 ) ).mul( radius ).toConst();
425
511
 
426
- const viewDir = normalize( viewPosition.xyz.negate() ).toVar();
427
- const sliceBitangent = normalize( cross( sampleDir.xyz, viewDir ) ).toVar();
428
- const sliceTangent = cross( sliceBitangent, viewDir ).toVar();
512
+ const sliceBitangent = normalize( cross( sampleDir, viewDir ) ).toConst();
513
+ const sliceTangent = cross( sliceBitangent, viewDir ).toConst();
429
514
 
430
515
  // Project the view normal onto the slice plane (remove component along sliceBitangent).
431
516
  // The unnormalized length is the foreshortening weight applied at slice integration.
432
517
  // (Activision GTAO paper, Section 3.2 "Per-pixel sampling".)
433
- const projNRaw = viewNormal.sub( sliceBitangent.mul( dot( viewNormal, sliceBitangent ) ) ).toVar();
434
- const projNLen = projNRaw.length().toVar();
435
- const projN = projNRaw.div( max( projNLen, float( 0.0001 ) ) ).toVar();
518
+ const projNRaw = viewNormal.sub( sliceBitangent.mul( dot( viewNormal, sliceBitangent ) ) ).toConst();
519
+ const projNLen = projNRaw.length().toConst();
520
+ const projN = projNRaw.div( max( projNLen, float( 0.0001 ) ) ).toConst();
436
521
 
437
522
  // γ — angle of projN within the slice plane, signed by the tangent direction.
438
- const nSin = dot( projN, sliceTangent ).toVar();
439
- const nCos = clamp( dot( projN, viewDir ), 0, 1 ).toVar();
523
+ const nSin = dot( projN, sliceTangent ).toConst();
524
+ const nCos = clamp( dot( projN, viewDir ), 0, 1 ).toConst();
440
525
  const signNSin = nSin.greaterThanEqual( 0 ).select( float( 1 ), float( - 1 ) );
441
- const angleN = signNSin.mul( acos( nCos ) ).toVar();
526
+ const angleN = signNSin.mul( acos( nCos ) ).toConst();
442
527
 
443
- const tangentToNormalInSlice = cross( projN, sliceBitangent ).toVar();
444
- const cosHorizons = vec2( dot( viewDir, tangentToNormalInSlice ), dot( viewDir, tangentToNormalInSlice.negate() ) ).toVar();
528
+ const tangentToNormalInSlice = cross( projN, sliceBitangent ).toConst();
529
+ const cosHorizon = dot( viewDir, tangentToNormalInSlice ).toConst();
530
+ const cosHorizons = vec2( cosHorizon, cosHorizon.negate() ).toVar();
445
531
 
446
532
  // For each slice, the inner loop performs ray marching to find the horizons.
447
533
 
448
- Loop( { end: STEPS, type: 'int', name: 'j', condition: '<' }, ( { j } ) => {
534
+ Loop( { end: int( STEPS ), type: 'int', name: 'j', condition: '<' }, ( { j } ) => {
449
535
 
450
- const sampleViewOffset = sampleDir.xyz.mul( radiusToUse ).mul( sampleDir.w ).mul( pow( div( float( j ).add( 1.0 ), float( STEPS ) ), this.distanceExponent ) );
536
+ // Quadratic step distribution ( sampleDist = t² ) concentrates samples in the
537
+ // near-field. (Blender's Eevee adaptation)
538
+ const t = float( j ).add( 1.0 ).add( stepJitter ).mul( invSteps ).toConst();
539
+ const sampleDist = t.mul( t );
540
+ const clipOffset = clipDirRadius.mul( sampleDist ).toConst();
451
541
 
452
542
  // The loop marches in two opposite directions (x and y) along the slice's line to find the horizon on both sides.
453
543
 
454
544
  // x
455
545
 
456
- const sampleScreenPositionX = getScreenPosition( viewPosition.add( sampleViewOffset ), this._cameraProjectionMatrix ).toVar();
457
- const sampleDepthX = sampleDepth( sampleScreenPositionX ).toVar();
458
- const sampleSceneViewPositionX = getViewPosition( sampleScreenPositionX, sampleDepthX, this._cameraProjectionMatrixInverse ).toVar();
459
- const viewDeltaX = sampleSceneViewPositionX.sub( viewPosition ).toVar();
546
+ const sampleScreenPositionX = getScreenPositionFromClip( clipPosition.add( clipOffset ) ).toConst();
547
+ const sampleDepthX = sampleDepth( sampleScreenPositionX ).toConst();
548
+ const sampleSceneViewPositionX = getViewPosition( sampleScreenPositionX, sampleDepthX, this._cameraProjectionMatrixInverse ).toConst();
549
+ const viewDeltaX = sampleSceneViewPositionX.sub( viewPosition ).toConst();
550
+ const lenX = viewDeltaX.length().toConst();
551
+
552
+ // Manual normalize guards against zero-length delta.
553
+ const sHX = dot( viewDir, viewDeltaX ).div( max( lenX, float( 0.0001 ) ) );
554
+
555
+ // Sphere falloff: ( dist / radius )² fades the sample's horizon contribution
556
+ // back toward the prior horizon as it approaches the radius boundary.
557
+ // (squared variant of the paper's near-field attenuation;
558
+ // Activision GTAO paper, Section 4.3 "Bounding the sampling area")
559
+ const distFacX = min( lenX.mul( invRadius ), 1 );
560
+ const distFacSqX = distFacX.mul( distFacX );
460
561
 
461
562
  If( abs( viewDeltaX.z ).lessThan( this.thickness ), () => {
462
563
 
463
- const sampleCosHorizon = dot( viewDir, normalize( viewDeltaX ) );
464
- cosHorizons.x.addAssign( max( 0, mul( sampleCosHorizon.sub( cosHorizons.x ), mix( 1.0, float( 2.0 ).div( float( j ).add( 2 ) ), this.distanceFallOff ) ) ) );
564
+ cosHorizons.x.assign( mix( max( cosHorizons.x, sHX ), cosHorizons.x, distFacSqX ) );
465
565
 
466
566
  } );
467
567
 
468
568
  // y
469
569
 
470
- const sampleScreenPositionY = getScreenPosition( viewPosition.sub( sampleViewOffset ), this._cameraProjectionMatrix ).toVar();
471
- const sampleDepthY = sampleDepth( sampleScreenPositionY ).toVar();
472
- const sampleSceneViewPositionY = getViewPosition( sampleScreenPositionY, sampleDepthY, this._cameraProjectionMatrixInverse ).toVar();
473
- const viewDeltaY = sampleSceneViewPositionY.sub( viewPosition ).toVar();
570
+ const sampleScreenPositionY = getScreenPositionFromClip( clipPosition.sub( clipOffset ) ).toConst();
571
+ const sampleDepthY = sampleDepth( sampleScreenPositionY ).toConst();
572
+ const sampleSceneViewPositionY = getViewPosition( sampleScreenPositionY, sampleDepthY, this._cameraProjectionMatrixInverse ).toConst();
573
+ const viewDeltaY = sampleSceneViewPositionY.sub( viewPosition ).toConst();
574
+ const lenY = viewDeltaY.length().toConst();
575
+
576
+ const sHY = dot( viewDir, viewDeltaY ).div( max( lenY, float( 0.0001 ) ) );
577
+
578
+ const distFacY = min( lenY.mul( invRadius ), 1 );
579
+ const distFacSqY = distFacY.mul( distFacY );
474
580
 
475
581
  If( abs( viewDeltaY.z ).lessThan( this.thickness ), () => {
476
582
 
477
- const sampleCosHorizon = dot( viewDir, normalize( viewDeltaY ) );
478
- cosHorizons.y.addAssign( max( 0, mul( sampleCosHorizon.sub( cosHorizons.y ), mix( 1.0, float( 2.0 ).div( float( j ).add( 2 ) ), this.distanceFallOff ) ) ) );
583
+ cosHorizons.y.assign( mix( max( cosHorizons.y, sHY ), cosHorizons.y, distFacSqY ) );
479
584
 
480
585
  } );
481
586
 
@@ -490,8 +595,8 @@ class GTAONode extends TempNode {
490
595
  // −T side of the slice and −sampleDir samples (cosHorizons.y) on the +T side.
491
596
  // γ is signed by +T (sliceTangent), so hPos must read from cosHorizons.y.
492
597
 
493
- const hPos = acos( cosHorizons.y ).toVar();
494
- const hNeg = acos( cosHorizons.x ).negate().toVar();
598
+ const hPos = acos( cosHorizons.y ).toConst();
599
+ const hNeg = acos( cosHorizons.x ).negate().toConst();
495
600
 
496
601
  const termPos = cos( hPos.mul( 2 ).sub( angleN ) ).negate().add( nCos ).add( hPos.mul( 2 ).mul( nSin ) );
497
602
  const termNeg = cos( hNeg.mul( 2 ).sub( angleN ) ).negate().add( nCos ).add( hNeg.mul( 2 ).mul( nSin ) );
@@ -509,7 +614,11 @@ class GTAONode extends TempNode {
509
614
 
510
615
  } );
511
616
 
512
- this._material.fragmentNode = ao().context( builder.getSharedContext() );
617
+ this._sharedContext = builder.getSharedContext();
618
+ this._currentSamples = this.samples.value;
619
+
620
+ this._material.contextNode = context( builder.getSharedContext() );
621
+ this._material.fragmentNode = this._ao();
513
622
  this._material.needsUpdate = true;
514
623
 
515
624
  //
@@ -524,8 +633,12 @@ class GTAONode extends TempNode {
524
633
  */
525
634
  dispose() {
526
635
 
636
+ super.dispose();
637
+
527
638
  this._aoRenderTarget.dispose();
528
639
 
640
+ this._noiseTexture.dispose();
641
+
529
642
  this._material.dispose();
530
643
 
531
644
  }