@aura3d/rendering 2.0.4 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (374) hide show
  1. package/dist/AtmosphereWetness.d.ts +61 -0
  2. package/dist/AtmosphereWetness.d.ts.map +1 -0
  3. package/dist/AtmosphereWetness.js +99 -0
  4. package/dist/AtmosphereWetness.js.map +1 -0
  5. package/dist/CascadedShadowMaps.d.ts.map +1 -1
  6. package/dist/CascadedShadowMaps.js +3 -1
  7. package/dist/CascadedShadowMaps.js.map +1 -1
  8. package/dist/ClusteredForwardLighting.d.ts +25 -1
  9. package/dist/ClusteredForwardLighting.d.ts.map +1 -1
  10. package/dist/ClusteredForwardLighting.js +80 -3
  11. package/dist/ClusteredForwardLighting.js.map +1 -1
  12. package/dist/DayNightSky.d.ts +63 -0
  13. package/dist/DayNightSky.d.ts.map +1 -0
  14. package/dist/DayNightSky.js +156 -0
  15. package/dist/DayNightSky.js.map +1 -0
  16. package/dist/EnvironmentPresetPack.d.ts +30 -0
  17. package/dist/EnvironmentPresetPack.d.ts.map +1 -0
  18. package/dist/EnvironmentPresetPack.js +49 -0
  19. package/dist/EnvironmentPresetPack.js.map +1 -0
  20. package/dist/ExtensionScalarAtlas.d.ts +18 -0
  21. package/dist/ExtensionScalarAtlas.d.ts.map +1 -0
  22. package/dist/ExtensionScalarAtlas.js +107 -0
  23. package/dist/ExtensionScalarAtlas.js.map +1 -0
  24. package/dist/ForwardPass.d.ts +65 -0
  25. package/dist/ForwardPass.d.ts.map +1 -1
  26. package/dist/ForwardPass.js +196 -2
  27. package/dist/ForwardPass.js.map +1 -1
  28. package/dist/InstancedPBRMaterial.d.ts +1 -0
  29. package/dist/InstancedPBRMaterial.d.ts.map +1 -1
  30. package/dist/InstancedPBRMaterial.js +3 -0
  31. package/dist/InstancedPBRMaterial.js.map +1 -1
  32. package/dist/InstancingDiagnostics.d.ts +69 -0
  33. package/dist/InstancingDiagnostics.d.ts.map +1 -0
  34. package/dist/InstancingDiagnostics.js +98 -0
  35. package/dist/InstancingDiagnostics.js.map +1 -0
  36. package/dist/LeanWebGL2Device.d.ts +265 -0
  37. package/dist/LeanWebGL2Device.d.ts.map +1 -0
  38. package/dist/LeanWebGL2Device.js +4001 -0
  39. package/dist/LeanWebGL2Device.js.map +1 -0
  40. package/dist/LightingRig.d.ts +19 -1
  41. package/dist/LightingRig.d.ts.map +1 -1
  42. package/dist/LightingRig.js +61 -1
  43. package/dist/LightingRig.js.map +1 -1
  44. package/dist/MaterialBinding.js +1 -1
  45. package/dist/MaterialBinding.js.map +1 -1
  46. package/dist/MeshConsolidation.d.ts +12 -0
  47. package/dist/MeshConsolidation.d.ts.map +1 -1
  48. package/dist/MeshConsolidation.js +28 -0
  49. package/dist/MeshConsolidation.js.map +1 -1
  50. package/dist/MorphTargetPlan.d.ts +29 -2
  51. package/dist/MorphTargetPlan.d.ts.map +1 -1
  52. package/dist/MorphTargetPlan.js +23 -4
  53. package/dist/MorphTargetPlan.js.map +1 -1
  54. package/dist/NormalMappedPBRMaterial.d.ts.map +1 -1
  55. package/dist/NormalMappedPBRMaterial.js +22 -2
  56. package/dist/NormalMappedPBRMaterial.js.map +1 -1
  57. package/dist/OceanSurface.d.ts +75 -0
  58. package/dist/OceanSurface.d.ts.map +1 -1
  59. package/dist/OceanSurface.js +211 -0
  60. package/dist/OceanSurface.js.map +1 -1
  61. package/dist/PBRMaterial.d.ts +1 -0
  62. package/dist/PBRMaterial.d.ts.map +1 -1
  63. package/dist/PBRMaterial.js +23 -2
  64. package/dist/PBRMaterial.js.map +1 -1
  65. package/dist/PbrReference.d.ts +48 -0
  66. package/dist/PbrReference.d.ts.map +1 -1
  67. package/dist/PbrReference.js +126 -0
  68. package/dist/PbrReference.js.map +1 -1
  69. package/dist/PlanarReflection.d.ts +221 -0
  70. package/dist/PlanarReflection.d.ts.map +1 -0
  71. package/dist/PlanarReflection.js +541 -0
  72. package/dist/PlanarReflection.js.map +1 -0
  73. package/dist/PostProcessPass.d.ts +32 -0
  74. package/dist/PostProcessPass.d.ts.map +1 -1
  75. package/dist/PostProcessPass.js +79 -36
  76. package/dist/PostProcessPass.js.map +1 -1
  77. package/dist/ProjectionMath.d.ts +3 -0
  78. package/dist/ProjectionMath.d.ts.map +1 -0
  79. package/dist/ProjectionMath.js +26 -0
  80. package/dist/ProjectionMath.js.map +1 -0
  81. package/dist/ReflectionSurfaces.d.ts +17 -0
  82. package/dist/ReflectionSurfaces.d.ts.map +1 -1
  83. package/dist/ReflectionSurfaces.js +103 -1
  84. package/dist/ReflectionSurfaces.js.map +1 -1
  85. package/dist/RenderDevice.d.ts +92 -0
  86. package/dist/RenderDevice.d.ts.map +1 -1
  87. package/dist/RenderDevice.js +85 -0
  88. package/dist/RenderDevice.js.map +1 -1
  89. package/dist/Renderer.d.ts +9 -0
  90. package/dist/Renderer.d.ts.map +1 -1
  91. package/dist/Renderer.js +97 -9
  92. package/dist/Renderer.js.map +1 -1
  93. package/dist/RendererPostprocessPlan.d.ts +64 -3
  94. package/dist/RendererPostprocessPlan.d.ts.map +1 -1
  95. package/dist/RendererPostprocessPlan.js +116 -12
  96. package/dist/RendererPostprocessPlan.js.map +1 -1
  97. package/dist/RendererVisualPipelineReport.d.ts.map +1 -1
  98. package/dist/RendererVisualPipelineReport.js +3 -1
  99. package/dist/RendererVisualPipelineReport.js.map +1 -1
  100. package/dist/Sampler.d.ts +29 -0
  101. package/dist/Sampler.d.ts.map +1 -1
  102. package/dist/Sampler.js +47 -0
  103. package/dist/Sampler.js.map +1 -1
  104. package/dist/ScreenSpaceReflectionPass.d.ts +43 -0
  105. package/dist/ScreenSpaceReflectionPass.d.ts.map +1 -0
  106. package/dist/ScreenSpaceReflectionPass.js +58 -0
  107. package/dist/ScreenSpaceReflectionPass.js.map +1 -0
  108. package/dist/SdfText.d.ts +250 -0
  109. package/dist/SdfText.d.ts.map +1 -0
  110. package/dist/SdfText.js +551 -0
  111. package/dist/SdfText.js.map +1 -0
  112. package/dist/ShaderChunks.d.ts.map +1 -1
  113. package/dist/ShaderChunks.js +30 -12
  114. package/dist/ShaderChunks.js.map +1 -1
  115. package/dist/ShaderLibrary.d.ts.map +1 -1
  116. package/dist/ShaderLibrary.js +601 -186
  117. package/dist/ShaderLibrary.js.map +1 -1
  118. package/dist/ShaderLibraryCore.d.ts +3 -0
  119. package/dist/ShaderLibraryCore.d.ts.map +1 -1
  120. package/dist/ShaderLibraryCore.js +73 -12
  121. package/dist/ShaderLibraryCore.js.map +1 -1
  122. package/dist/ShadowMap.d.ts +24 -0
  123. package/dist/ShadowMap.d.ts.map +1 -1
  124. package/dist/ShadowMap.js +43 -0
  125. package/dist/ShadowMap.js.map +1 -1
  126. package/dist/SkinnedLitMaterial.d.ts.map +1 -1
  127. package/dist/SkinnedLitMaterial.js +2 -0
  128. package/dist/SkinnedLitMaterial.js.map +1 -1
  129. package/dist/SkinningBounds.d.ts +10 -0
  130. package/dist/SkinningBounds.d.ts.map +1 -1
  131. package/dist/SkinningBounds.js +27 -0
  132. package/dist/SkinningBounds.js.map +1 -1
  133. package/dist/SpriteFlipbook.d.ts +60 -0
  134. package/dist/SpriteFlipbook.d.ts.map +1 -0
  135. package/dist/SpriteFlipbook.js +128 -0
  136. package/dist/SpriteFlipbook.js.map +1 -0
  137. package/dist/TemporalHistory.d.ts +37 -0
  138. package/dist/TemporalHistory.d.ts.map +1 -0
  139. package/dist/TemporalHistory.js +135 -0
  140. package/dist/TemporalHistory.js.map +1 -0
  141. package/dist/TemporalMath.d.ts +3 -0
  142. package/dist/TemporalMath.d.ts.map +1 -0
  143. package/dist/TemporalMath.js +9 -0
  144. package/dist/TemporalMath.js.map +1 -0
  145. package/dist/TerrainTiles.d.ts +120 -0
  146. package/dist/TerrainTiles.d.ts.map +1 -0
  147. package/dist/TerrainTiles.js +221 -0
  148. package/dist/TerrainTiles.js.map +1 -0
  149. package/dist/TexturedPBRMaterial.d.ts +4 -0
  150. package/dist/TexturedPBRMaterial.d.ts.map +1 -1
  151. package/dist/TexturedPBRMaterial.js +88 -5
  152. package/dist/TexturedPBRMaterial.js.map +1 -1
  153. package/dist/TexturedUnlitMaterial.d.ts.map +1 -1
  154. package/dist/TexturedUnlitMaterial.js +20 -2
  155. package/dist/TexturedUnlitMaterial.js.map +1 -1
  156. package/dist/UnlitMaterial.d.ts.map +1 -1
  157. package/dist/UnlitMaterial.js +20 -2
  158. package/dist/UnlitMaterial.js.map +1 -1
  159. package/dist/VertexFormat.d.ts +6 -0
  160. package/dist/VertexFormat.d.ts.map +1 -1
  161. package/dist/VertexFormat.js +12 -0
  162. package/dist/VertexFormat.js.map +1 -1
  163. package/dist/VolumetricFog.d.ts +55 -0
  164. package/dist/VolumetricFog.d.ts.map +1 -0
  165. package/dist/VolumetricFog.js +91 -0
  166. package/dist/VolumetricFog.js.map +1 -0
  167. package/dist/WaterSurface.d.ts +77 -0
  168. package/dist/WaterSurface.d.ts.map +1 -0
  169. package/dist/WaterSurface.js +133 -0
  170. package/dist/WaterSurface.js.map +1 -0
  171. package/dist/WebGL2Device.d.ts +73 -0
  172. package/dist/WebGL2Device.d.ts.map +1 -1
  173. package/dist/WebGL2Device.js +836 -79
  174. package/dist/WebGL2Device.js.map +1 -1
  175. package/dist/WebGPUDevice.d.ts +62 -1
  176. package/dist/WebGPUDevice.d.ts.map +1 -1
  177. package/dist/WebGPUDevice.js +844 -51
  178. package/dist/WebGPUDevice.js.map +1 -1
  179. package/dist/WebGPUExtensionAtlas.d.ts +6 -0
  180. package/dist/WebGPUExtensionAtlas.d.ts.map +1 -0
  181. package/dist/WebGPUExtensionAtlas.js +225 -0
  182. package/dist/WebGPUExtensionAtlas.js.map +1 -0
  183. package/dist/WebGPUSkinningLimits.d.ts +40 -0
  184. package/dist/WebGPUSkinningLimits.d.ts.map +1 -1
  185. package/dist/WebGPUSkinningLimits.js +32 -0
  186. package/dist/WebGPUSkinningLimits.js.map +1 -1
  187. package/dist/effects/CollisionModule.d.ts +9 -0
  188. package/dist/effects/CollisionModule.d.ts.map +1 -1
  189. package/dist/effects/CollisionModule.js +10 -0
  190. package/dist/effects/CollisionModule.js.map +1 -1
  191. package/dist/effects/ColorModule.d.ts +7 -0
  192. package/dist/effects/ColorModule.d.ts.map +1 -1
  193. package/dist/effects/ColorModule.js +23 -0
  194. package/dist/effects/ColorModule.js.map +1 -1
  195. package/dist/effects/ForceModule.d.ts +35 -0
  196. package/dist/effects/ForceModule.d.ts.map +1 -1
  197. package/dist/effects/ForceModule.js +49 -0
  198. package/dist/effects/ForceModule.js.map +1 -1
  199. package/dist/effects/GPUParticleBackend.d.ts +188 -0
  200. package/dist/effects/GPUParticleBackend.d.ts.map +1 -1
  201. package/dist/effects/GPUParticleBackend.js +710 -1
  202. package/dist/effects/GPUParticleBackend.js.map +1 -1
  203. package/dist/effects/HeightfieldModule.d.ts +58 -0
  204. package/dist/effects/HeightfieldModule.d.ts.map +1 -0
  205. package/dist/effects/HeightfieldModule.js +129 -0
  206. package/dist/effects/HeightfieldModule.js.map +1 -0
  207. package/dist/effects/LightingModule.d.ts +34 -0
  208. package/dist/effects/LightingModule.d.ts.map +1 -0
  209. package/dist/effects/LightingModule.js +54 -0
  210. package/dist/effects/LightingModule.js.map +1 -0
  211. package/dist/effects/ParticleDiagnostics.d.ts +8 -0
  212. package/dist/effects/ParticleDiagnostics.d.ts.map +1 -1
  213. package/dist/effects/ParticleDiagnostics.js +3 -0
  214. package/dist/effects/ParticleDiagnostics.js.map +1 -1
  215. package/dist/effects/ParticleModule.d.ts +8 -0
  216. package/dist/effects/ParticleModule.d.ts.map +1 -1
  217. package/dist/effects/ParticleModule.js.map +1 -1
  218. package/dist/effects/ParticleRenderer.d.ts +20 -0
  219. package/dist/effects/ParticleRenderer.d.ts.map +1 -1
  220. package/dist/effects/ParticleRenderer.js +57 -7
  221. package/dist/effects/ParticleRenderer.js.map +1 -1
  222. package/dist/effects/ParticleSystem.d.ts +45 -1
  223. package/dist/effects/ParticleSystem.d.ts.map +1 -1
  224. package/dist/effects/ParticleSystem.js +373 -4
  225. package/dist/effects/ParticleSystem.js.map +1 -1
  226. package/dist/effects/ResidentGPUParticleRenderer.d.ts +158 -0
  227. package/dist/effects/ResidentGPUParticleRenderer.d.ts.map +1 -0
  228. package/dist/effects/ResidentGPUParticleRenderer.js +576 -0
  229. package/dist/effects/ResidentGPUParticleRenderer.js.map +1 -0
  230. package/dist/effects/SizeModule.d.ts +4 -0
  231. package/dist/effects/SizeModule.d.ts.map +1 -1
  232. package/dist/effects/SizeModule.js +16 -0
  233. package/dist/effects/SizeModule.js.map +1 -1
  234. package/dist/effects/SubEmitterModule.d.ts +61 -0
  235. package/dist/effects/SubEmitterModule.d.ts.map +1 -0
  236. package/dist/effects/SubEmitterModule.js +119 -0
  237. package/dist/effects/SubEmitterModule.js.map +1 -0
  238. package/dist/effects/TrailModule.d.ts +38 -0
  239. package/dist/effects/TrailModule.d.ts.map +1 -1
  240. package/dist/effects/TrailModule.js +95 -2
  241. package/dist/effects/TrailModule.js.map +1 -1
  242. package/dist/effects/TurbulenceModule.d.ts +43 -0
  243. package/dist/effects/TurbulenceModule.d.ts.map +1 -0
  244. package/dist/effects/TurbulenceModule.js +130 -0
  245. package/dist/effects/TurbulenceModule.js.map +1 -0
  246. package/dist/effects/index.d.ts +4 -0
  247. package/dist/effects/index.d.ts.map +1 -1
  248. package/dist/effects/index.js +4 -0
  249. package/dist/effects/index.js.map +1 -1
  250. package/dist/extension-scalar-atlas.d.ts +3 -0
  251. package/dist/extension-scalar-atlas.d.ts.map +1 -0
  252. package/dist/extension-scalar-atlas.js +2 -0
  253. package/dist/extension-scalar-atlas.js.map +1 -0
  254. package/dist/index.d.ts +58 -19
  255. package/dist/index.d.ts.map +1 -1
  256. package/dist/index.js +32 -10
  257. package/dist/index.js.map +1 -1
  258. package/dist/lean/LeanProductionRenderer.d.ts.map +1 -1
  259. package/dist/lean/LeanProductionRenderer.js +2 -2
  260. package/dist/lean/LeanProductionRenderer.js.map +1 -1
  261. package/dist/lean-core-runtime.d.ts +13 -0
  262. package/dist/lean-core-runtime.d.ts.map +1 -0
  263. package/dist/lean-core-runtime.js +10 -0
  264. package/dist/lean-core-runtime.js.map +1 -0
  265. package/dist/materials/MaterialExtensions.js +3 -3
  266. package/dist/materials/MaterialExtensions.js.map +1 -1
  267. package/dist/postprocess/NativeBloomPyramid.d.ts +44 -0
  268. package/dist/postprocess/NativeBloomPyramid.d.ts.map +1 -0
  269. package/dist/postprocess/NativeBloomPyramid.js +84 -0
  270. package/dist/postprocess/NativeBloomPyramid.js.map +1 -0
  271. package/dist/postprocess/NativeLdrEffectLuts.d.ts +10 -1
  272. package/dist/postprocess/NativeLdrEffectLuts.d.ts.map +1 -1
  273. package/dist/postprocess/NativeLdrEffectLuts.js +19 -2
  274. package/dist/postprocess/NativeLdrEffectLuts.js.map +1 -1
  275. package/dist/postprocess/index.d.ts +2 -0
  276. package/dist/postprocess/index.d.ts.map +1 -1
  277. package/dist/postprocess/index.js +1 -0
  278. package/dist/postprocess/index.js.map +1 -1
  279. package/dist/production-runtime/PBRHDRPipeline.d.ts +22 -0
  280. package/dist/production-runtime/PBRHDRPipeline.d.ts.map +1 -1
  281. package/dist/production-runtime/PBRHDRPipeline.js +125 -0
  282. package/dist/production-runtime/PBRHDRPipeline.js.map +1 -1
  283. package/dist/production-runtime/ProductionRendererTypes.d.ts +1 -0
  284. package/dist/production-runtime/ProductionRendererTypes.d.ts.map +1 -1
  285. package/dist/production-runtime/ProductionRendererTypes.js.map +1 -1
  286. package/dist/production-runtime/ProductionRuntimeRenderer.d.ts +3 -0
  287. package/dist/production-runtime/ProductionRuntimeRenderer.d.ts.map +1 -1
  288. package/dist/production-runtime/ProductionRuntimeRenderer.js +8 -1
  289. package/dist/production-runtime/ProductionRuntimeRenderer.js.map +1 -1
  290. package/dist/production-runtime/ProductionWebGL2Renderer.d.ts +4 -0
  291. package/dist/production-runtime/ProductionWebGL2Renderer.d.ts.map +1 -1
  292. package/dist/production-runtime/ProductionWebGL2Renderer.js +15 -0
  293. package/dist/production-runtime/ProductionWebGL2Renderer.js.map +1 -1
  294. package/dist/production-runtime/ProductionWebGPURenderer.d.ts +58 -0
  295. package/dist/production-runtime/ProductionWebGPURenderer.d.ts.map +1 -1
  296. package/dist/production-runtime/ProductionWebGPURenderer.js +127 -0
  297. package/dist/production-runtime/ProductionWebGPURenderer.js.map +1 -1
  298. package/dist/production-runtime/framegraph/FrameGraph.d.ts +4 -2
  299. package/dist/production-runtime/framegraph/FrameGraph.d.ts.map +1 -1
  300. package/dist/production-runtime/framegraph/FrameGraph.js +62 -4
  301. package/dist/production-runtime/framegraph/FrameGraph.js.map +1 -1
  302. package/dist/production-runtime/framegraph/NativeFrameGraphBindings.d.ts +32 -0
  303. package/dist/production-runtime/framegraph/NativeFrameGraphBindings.d.ts.map +1 -0
  304. package/dist/production-runtime/framegraph/NativeFrameGraphBindings.js +111 -0
  305. package/dist/production-runtime/framegraph/NativeFrameGraphBindings.js.map +1 -0
  306. package/dist/production-runtime/framegraph/RenderPass.d.ts +23 -0
  307. package/dist/production-runtime/framegraph/RenderPass.d.ts.map +1 -1
  308. package/dist/production-runtime/framegraph/RenderPass.js +87 -1
  309. package/dist/production-runtime/framegraph/RenderPass.js.map +1 -1
  310. package/dist/production-runtime/index.d.ts +7 -4
  311. package/dist/production-runtime/index.d.ts.map +1 -1
  312. package/dist/production-runtime/index.js +4 -2
  313. package/dist/production-runtime/index.js.map +1 -1
  314. package/dist/production-runtime/passes/DepthPrepass.d.ts +18 -1
  315. package/dist/production-runtime/passes/DepthPrepass.d.ts.map +1 -1
  316. package/dist/production-runtime/passes/DepthPrepass.js +41 -2
  317. package/dist/production-runtime/passes/DepthPrepass.js.map +1 -1
  318. package/dist/production-runtime/passes/FramegraphTopology.d.ts +13 -0
  319. package/dist/production-runtime/passes/FramegraphTopology.d.ts.map +1 -0
  320. package/dist/production-runtime/passes/FramegraphTopology.js +59 -0
  321. package/dist/production-runtime/passes/FramegraphTopology.js.map +1 -0
  322. package/dist/production-runtime/passes/OpaquePass.d.ts +19 -1
  323. package/dist/production-runtime/passes/OpaquePass.d.ts.map +1 -1
  324. package/dist/production-runtime/passes/OpaquePass.js +43 -2
  325. package/dist/production-runtime/passes/OpaquePass.js.map +1 -1
  326. package/dist/production-runtime/passes/ShadowPass.d.ts +19 -1
  327. package/dist/production-runtime/passes/ShadowPass.d.ts.map +1 -1
  328. package/dist/production-runtime/passes/ShadowPass.js +45 -2
  329. package/dist/production-runtime/passes/ShadowPass.js.map +1 -1
  330. package/dist/production-runtime/passes/SkyboxPass.d.ts +17 -1
  331. package/dist/production-runtime/passes/SkyboxPass.d.ts.map +1 -1
  332. package/dist/production-runtime/passes/SkyboxPass.js +41 -2
  333. package/dist/production-runtime/passes/SkyboxPass.js.map +1 -1
  334. package/dist/production-runtime/passes/ToneMappingPass.d.ts +26 -1
  335. package/dist/production-runtime/passes/ToneMappingPass.d.ts.map +1 -1
  336. package/dist/production-runtime/passes/ToneMappingPass.js +62 -2
  337. package/dist/production-runtime/passes/ToneMappingPass.js.map +1 -1
  338. package/dist/production-runtime/passes/TransparentPass.d.ts +19 -1
  339. package/dist/production-runtime/passes/TransparentPass.d.ts.map +1 -1
  340. package/dist/production-runtime/passes/TransparentPass.js +47 -2
  341. package/dist/production-runtime/passes/TransparentPass.js.map +1 -1
  342. package/dist/reflection-surfaces.d.ts +5 -0
  343. package/dist/reflection-surfaces.d.ts.map +1 -0
  344. package/dist/reflection-surfaces.js +3 -0
  345. package/dist/reflection-surfaces.js.map +1 -0
  346. package/dist/shadows/CascadeHysteresis.d.ts +67 -0
  347. package/dist/shadows/CascadeHysteresis.d.ts.map +1 -0
  348. package/dist/shadows/CascadeHysteresis.js +104 -0
  349. package/dist/shadows/CascadeHysteresis.js.map +1 -0
  350. package/dist/shadows/ContactShadows.d.ts +52 -0
  351. package/dist/shadows/ContactShadows.d.ts.map +1 -1
  352. package/dist/shadows/ContactShadows.js +122 -0
  353. package/dist/shadows/ContactShadows.js.map +1 -1
  354. package/dist/shadows/SpotShadowMaps.d.ts +77 -0
  355. package/dist/shadows/SpotShadowMaps.d.ts.map +1 -0
  356. package/dist/shadows/SpotShadowMaps.js +106 -0
  357. package/dist/shadows/SpotShadowMaps.js.map +1 -0
  358. package/dist/webgpu/WebGPUPostProcess.d.ts +2 -0
  359. package/dist/webgpu/WebGPUPostProcess.d.ts.map +1 -1
  360. package/dist/webgpu/WebGPUPostProcess.js +1 -0
  361. package/dist/webgpu/WebGPUPostProcess.js.map +1 -1
  362. package/dist/webgpu/WebGPUPostShaders.d.ts +77 -0
  363. package/dist/webgpu/WebGPUPostShaders.d.ts.map +1 -0
  364. package/dist/webgpu/WebGPUPostShaders.js +261 -0
  365. package/dist/webgpu/WebGPUPostShaders.js.map +1 -0
  366. package/dist/webgpu/WebGPUTemporal.d.ts +17 -0
  367. package/dist/webgpu/WebGPUTemporal.d.ts.map +1 -0
  368. package/dist/webgpu/WebGPUTemporal.js +64 -0
  369. package/dist/webgpu/WebGPUTemporal.js.map +1 -0
  370. package/dist/webgpu.d.ts +6 -0
  371. package/dist/webgpu.d.ts.map +1 -1
  372. package/dist/webgpu.js +4 -0
  373. package/dist/webgpu.js.map +1 -1
  374. package/package.json +15 -3
@@ -0,0 +1,6 @@
1
+ import type { UniformValue } from "./RenderDevice.js";
2
+ export declare const WEBGPU_ATLAS_MAPS: readonly ["baseColor", "normal", "metallicRoughness", "occlusion", "emissive", "clearcoat", "clearcoatRoughness", "clearcoatNormal", "sheenColor", "sheenRoughness", "anisotropy", "iridescence", "iridescenceThickness"];
3
+ /** Layout mirrors AtlasUniforms: 13 map records of five vec4s, then seven vec4s. */
4
+ export declare function webgpuExtensionAtlasUniforms(uniforms?: ReadonlyMap<string, UniformValue>): Float32Array;
5
+ export declare const WEBGPU_EXTENSION_ATLAS_WGSL = "\nstruct AtlasMap {\n transform: vec4<f32>,\n control: vec4<f32>,\n wrapMode: vec4<f32>,\n rect: vec4<f32>,\n filterMode: vec4<f32>,\n};\nstruct AtlasUniforms {\n maps: array<AtlasMap, 13>,\n coat: vec4<f32>,\n sheen: vec4<f32>,\n iridescence: vec4<f32>,\n factors: vec4<f32>,\n emissive: vec4<f32>,\n substrate: vec4<f32>,\n specularColor: vec4<f32>,\n};\n@group(0) @binding(19) var<uniform> u_atlas: AtlasUniforms;\n@group(0) @binding(20) var u_scalarAtlas: texture_2d<f32>;\n@group(0) @binding(21) var u_coatNormalSampler: sampler;\n@group(0) @binding(22) var u_coatNormalTexture: texture_2d<f32>;\n@group(0) @binding(23) var u_sheenSampler: sampler;\n@group(0) @binding(24) var u_sheenTexture: texture_2d<f32>;\n@group(0) @binding(25) var u_anisotropySampler: sampler;\n@group(0) @binding(26) var u_anisotropyTexture: texture_2d<f32>;\n@group(0) @binding(27) var u_emissiveSampler: sampler;\n@group(0) @binding(28) var u_emissiveTexture: texture_2d<f32>;\nfn atlasUv(index: u32, uv0: vec2<f32>, uv1: vec2<f32>) -> vec2<f32> {\n let map = u_atlas.maps[index];\n let uv = select(uv0,uv1,map.control.y > 0.5) * map.transform.zw;\n let cosine = cos(map.control.x); let sine = sin(map.control.x);\n return vec2<f32>(cosine*uv.x-sine*uv.y,sine*uv.x+cosine*uv.y)+map.transform.xy;\n}\nfn atlasWrapIndex(x: i32, size: i32, mode: f32) -> i32 {\n if (mode<0.5) { return clamp(x,0,size-1); }\n let period=select(size,2*size,mode>1.5);\n let index=((x%period)+period)%period;\n return select(index,period-1-index,mode>1.5 && index>=size);\n}\nfn atlasFetch(point: vec2<i32>, size: vec2<i32>, origin: vec2<i32>, wrapMode: vec2<f32>) -> vec4<f32> {\n let wrapped=vec2<i32>(atlasWrapIndex(point.x,size.x,wrapMode.x),atlasWrapIndex(point.y,size.y,wrapMode.y));\n return textureLoad(u_scalarAtlas,origin+wrapped,0);\n}\nfn atlasLevel(uv: vec2<f32>, map: AtlasMap, level: i32, nearestFilter: bool) -> vec4<f32> {\n var size=vec2<i32>(map.rect.yz); var origin=vec2<i32>(i32(map.rect.x),i32(map.control.w));\n for (var i=0;i<16;i=i+1) { if (i>=level) { break; } origin.y=origin.y+size.y; size=max(size/2,vec2<i32>(1)); }\n let pixel=uv*vec2<f32>(size)-0.5;\n if (nearestFilter) { return atlasFetch(vec2<i32>(floor(pixel+0.5)),size,origin,map.wrapMode.xy); }\n let low=vec2<i32>(floor(pixel)); let fraction=fract(pixel);\n return mix(mix(atlasFetch(low,size,origin,map.wrapMode.xy),atlasFetch(low+vec2<i32>(1,0),size,origin,map.wrapMode.xy),fraction.x),\n mix(atlasFetch(low+vec2<i32>(0,1),size,origin,map.wrapMode.xy),atlasFetch(low+vec2<i32>(1,1),size,origin,map.wrapMode.xy),fraction.x),fraction.y);\n}\nfn atlasSample(index: u32, uv0: vec2<f32>, uv1: vec2<f32>) -> vec4<f32> {\n let map=u_atlas.maps[index]; let uv=atlasUv(index,uv0,uv1);\n let dx=dpdx(uv); let dy=dpdy(uv); let lx=length(dx*map.rect.yz); let ly=length(dy*map.rect.yz);\n let major=max(lx,ly); let minor=max(min(lx,ly),0.000001); let magnify=major<=1.0;\n let taps=select(clamp(ceil(major/max(minor,1.0)),1.0,floor(map.filterMode.w)),1.0,magnify);\n let axis=select(dy,dx,lx>=ly);\n var lod=clamp(log2(max(major/taps,1.0)),0.0,map.rect.w);\n if (map.filterMode.z<0.5) { lod=0.0; } else if (map.filterMode.z<1.5) { lod=floor(lod+0.5); }\n let low=i32(floor(lod)); let high=min(low+1,i32(map.rect.w));\n let nearestFilter=select(map.filterMode.y>0.5,map.filterMode.x>0.5,magnify);\n var total=vec4<f32>(0.0);\n for (var i=0;i<16;i=i+1) { if (f32(i)>=taps) { break; }\n let sampleUv=uv+axis*((f32(i)+0.5)/taps-0.5);\n total=total+mix(atlasLevel(sampleUv,map,low,nearestFilter),atlasLevel(sampleUv,map,high,nearestFilter),fract(lod));\n }\n return total/taps;\n}\n/* Spectral thin-film evaluation adapted from three.js iridescence_fragment (MIT).\nThe MIT License\n\nCopyright \u00A9 2010-2026 three.js authors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n*/\n// Belcour/Barla Fourier-domain CIE XYZ sensitivity, converted to linear Rec.709.\n// Three monochromatic wavelength samples are not RGB tristimulus reflectance.\nfn atlasFilmSensitivity(opd: f32, shift: vec3<f32>) -> vec3<f32> {\n let phase=2.0*3.14159265359*opd*1.0e-9;\n let variance=vec3<f32>(4.3278e9,9.3046e9,6.6121e9);\n var xyz=vec3<f32>(5.4856e-13,4.4201e-13,5.2481e-13)*sqrt(2.0*3.14159265359*variance)\n *cos(vec3<f32>(1.6810e6,1.7953e6,2.2084e6)*phase+shift)*exp(-phase*phase*variance);\n xyz.x=xyz.x+9.7470e-14*sqrt(2.0*3.14159265359*4.5282e9)*cos(2.2399e6*phase+shift.x)*exp(-4.5282e9*phase*phase);\n xyz=xyz/1.0685e-7;\n return mat3x3<f32>(vec3<f32>(3.2404542,-0.9692660,0.0556434),vec3<f32>(-1.5371385,1.8760108,-0.2040259),vec3<f32>(-0.4985314,0.0415560,1.0572252))*xyz;\n}\nfn atlasThinFilm(substrateF0: vec3<f32>, filmIor: f32, thickness: f32, cosine: f32) -> vec3<f32> {\n let c1=clamp(cosine,0.0001,1.0);\n if (thickness<=0.0) { return fresnelSchlick(c1,substrateF0); }\n let n2=mix(1.0,filmIor,smoothstep(0.0,0.03,thickness));\n let c2Squared=1.0-(1.0-c1*c1)/(n2*n2);\n if (c2Squared<0.0) { return vec3<f32>(1.0); }\n let c2=sqrt(c2Squared);\n let f12=(n2-1.0)/(n2+1.0);\n let r12=fresnelSchlick(c1,vec3<f32>(f12*f12)).x;\n let t121=1.0-r12;\n let rootF0=sqrt(clamp(substrateF0,vec3<f32>(0.0),vec3<f32>(0.9999)));\n let n3=(vec3<f32>(1.0)+rootF0)/(vec3<f32>(1.0)-rootF0);\n let f23=(n3-vec3<f32>(n2))/(n3+vec3<f32>(n2));\n let r23=fresnelSchlick(c2,f23*f23);\n let phi21=select(3.14159265359,0.0,n2<1.0);\n let phi=vec3<f32>(phi21)+select(vec3<f32>(0.0),vec3<f32>(3.14159265359),n3<vec3<f32>(n2));\n let opd=2.0*n2*thickness*c2;\n let r123=clamp(r12*r23,vec3<f32>(0.00001),vec3<f32>(0.9999));\n let amplitude=sqrt(r123);\n let rs=t121*t121*r23/(vec3<f32>(1.0)-r123);\n var reflectance=vec3<f32>(r12)+rs;\n var coefficient=rs-vec3<f32>(t121);\n for (var order=1;order<=2;order=order+1) {\n coefficient=coefficient*amplitude;\n reflectance=reflectance+coefficient*2.0*atlasFilmSensitivity(f32(order)*opd,f32(order)*phi);\n }\n return max(reflectance,vec3<f32>(0.0));\n}\n\n// KHR_materials_iridescence: a missing thickness map samples 1.0, and\n// the dielectric base receives inverse-max Fresnel weighting (rgb_mix).\nfn atlasIridescenceFresnel(substrateF0: vec3<f32>, cosine: f32, uv0: vec2<f32>, uv1: vec2<f32>) -> vec3<f32> {\n let strength=clamp(u_atlas.iridescence.y*mix(1.0,atlasSample(11u,uv0,uv1).r,u_atlas.maps[11].control.z),0.0,1.0);\n let thickness=mix(u_atlas.iridescence.w,u_atlas.factors.x,mix(1.0,atlasSample(12u,uv0,uv1).g,u_atlas.maps[12].control.z));\n return mix(fresnelSchlick(cosine,substrateF0),atlasThinFilm(substrateF0,u_atlas.iridescence.z,thickness,cosine),strength);\n}\n\n// Recover the Schlick normal-incidence coefficient before applying the split-sum\n// BRDF LUT. Multiplying an already Fresnel-weighted environment by a Fresnel\n// difference would count Fresnel twice and incorrectly scale the LUT bias term.\nfn atlasIridescenceEnvironmentF0(substrateF0: vec3<f32>, cosine: f32, uv0: vec2<f32>, uv1: vec2<f32>) -> vec3<f32> {\n let strength=clamp(u_atlas.iridescence.y*mix(1.0,atlasSample(11u,uv0,uv1).r,u_atlas.maps[11].control.z),0.0,1.0);\n let thickness=mix(u_atlas.iridescence.w,u_atlas.factors.x,mix(1.0,atlasSample(12u,uv0,uv1).g,u_atlas.maps[12].control.z));\n let grazing=clamp(pow(clamp(1.0-cosine,0.0,1.0),5.0),0.0,0.9999);\n let filmF0=(atlasThinFilm(substrateF0,u_atlas.iridescence.z,thickness,cosine)-vec3<f32>(grazing))/(1.0-grazing);\n return mix(substrateF0,filmF0,strength);\n}\n\nfn atlasExtensionLighting(normal: vec3<f32>, tangent: vec4<f32>, view: vec3<f32>, light: vec3<f32>, uv0: vec2<f32>, uv1: vec2<f32>, shadow: f32, environment: vec3<f32>, substrateF0: vec3<f32>, substrateRoughness: f32) -> vec3<f32> {\n let coatMask=atlasSample(5u,uv0,uv1).r; let coatRoughMask=atlasSample(6u,uv0,uv1).g;\n let sheenRoughMask=atlasSample(9u,uv0,uv1).a; let filmMask=atlasSample(11u,uv0,uv1).r;\n let thicknessMask=atlasSample(12u,uv0,uv1).g;\n let coatNormalSample=textureSample(u_coatNormalTexture,u_coatNormalSampler,atlasUv(7u,uv0,uv1)).rgb;\n let coatNormal=normalize(mix(normal,perturbNormal(normal,tangent,coatNormalSample,u_atlas.coat.z),u_atlas.maps[7].control.z));\n let sheenSample=textureSample(u_sheenTexture,u_sheenSampler,atlasUv(8u,uv0,uv1)).rgb;\n let anisotropySample=textureSample(u_anisotropyTexture,u_anisotropySampler,atlasUv(10u,uv0,uv1));\n let coat=u_atlas.coat.x*mix(1.0,coatMask,u_atlas.maps[5].control.z);\n let coatRough=max(0.045,u_atlas.coat.y*mix(1.0,coatRoughMask,u_atlas.maps[6].control.z));\n let sheen=u_atlas.sheen.rgb*mix(vec3<f32>(1.0),sheenSample,u_atlas.maps[8].control.z);\n let sheenRough=max(0.045,u_atlas.coat.w*mix(1.0,sheenRoughMask,u_atlas.maps[9].control.z));\n let anisotropy=u_atlas.sheen.w*mix(1.0,anisotropySample.b,u_atlas.maps[10].control.z);\n let film=u_atlas.iridescence.y*mix(1.0,filmMask,u_atlas.maps[11].control.z);\n let thickness=mix(u_atlas.iridescence.w,u_atlas.factors.x,mix(1.0,thicknessMask,u_atlas.maps[12].control.z));\n let halfVector=normalize(light+view); let ndl=max(dot(normal,light),0.0); let ndv=max(dot(normal,view),0.001);\n let coatNdl=max(dot(coatNormal,light),0.0); let coatNdv=max(dot(coatNormal,view),0.001); let coatNdh=max(dot(coatNormal,halfVector),0.001);\n let coatBrdf=coat*ggxDistribution(coatNdh,coatRough)*ggxVisibilitySmithCorrelated(coatNdv,coatNdl,coatRough)*fresnelSchlick(max(dot(view,halfVector),0.0),vec3<f32>(0.04));\n let ndh=max(dot(normal,halfVector),0.0); let inverseRoughness=1.0/(sheenRough*sheenRough);\n let charlie=(2.0+inverseRoughness)*pow(max(1.0-ndh*ndh,0.00001),0.5*inverseRoughness)/(2.0*3.14159265);\n let sheenBrdf=sheen*charlie/max(4.0*(ndl+ndv-ndl*ndv),0.0001);\n let tx=normalize(tangent.xyz-normal*dot(tangent.xyz,normal)); let ty=normalize(cross(normal,tx))*tangent.w;\n let mappedDirection=mix(vec2<f32>(1.0,0.0),anisotropySample.rg*2.0-1.0,u_atlas.maps[10].control.z);\n let angle=u_atlas.iridescence.x+atan2(mappedDirection.y,mappedDirection.x);\n let axis=tx*cos(angle)+ty*sin(angle); let crossAxis=-tx*sin(angle)+ty*cos(angle);\n // Anisotropy and iridescence modify the same substrate specular BRDF.\n // KHR anisotropy broadens the tangent alpha; it is not an extra white lobe.\n let alpha=max(substrateRoughness,0.045)*max(substrateRoughness,0.045);\n let ax=mix(alpha,1.0,clamp(anisotropy*anisotropy,0.0,1.0)); let ay=alpha;\n let tangentH=dot(halfVector,axis)/ax; let bitangentH=dot(halfVector,crossAxis)/ay;\n let denominator=tangentH*tangentH+bitangentH*bitangentH+ndh*ndh;\n let anisotropicD=1.0/max(3.14159265*ax*ay*denominator*denominator,0.0000000000000001);\n let lambdaV=ndl*length(vec3<f32>(ax*dot(axis,view),ay*dot(crossAxis,view),ndv));\n let lambdaL=ndv*length(vec3<f32>(ax*dot(axis,light),ay*dot(crossAxis,light),ndl));\n let anisotropicV=0.5/max(lambdaV+lambdaL,0.00001);\n let isotropicDv=ggxDistribution(ndh,substrateRoughness)*ggxVisibilitySmithCorrelated(ndv,ndl,substrateRoughness);\n let substrateDv=select(isotropicDv,anisotropicD*anisotropicV,anisotropy>0.0);\n let vdh=max(dot(view,halfVector),0.0001);\n let substrateFresnel=fresnelSchlick(vdh,substrateF0);\n let anisotropicBrdf=substrateFresnel*(substrateDv-isotropicDv);\n let filmDirect=film*(atlasThinFilm(substrateF0,u_atlas.iridescence.z,thickness,vdh)-substrateFresnel)*substrateDv;\n // Film environment energy is integrated once in shadePbr through the BRDF LUT.\n let filmEnvironment=vec3<f32>(0.0);\n let direct=(coatBrdf*coatNdl+(sheenBrdf+anisotropicBrdf+filmDirect)*ndl)*2.25*shadow;\n return (direct+environment*(coat*0.04+sheen*pow(1.0-ndv,5.0)+filmEnvironment))*u_atlas.factors.z;\n\n}\n";
6
+ //# sourceMappingURL=WebGPUExtensionAtlas.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WebGPUExtensionAtlas.d.ts","sourceRoot":"","sources":["../../../../packages/rendering/src/WebGPUExtensionAtlas.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEnD,eAAO,MAAM,iBAAiB,2NAA4N,CAAC;AAC3P,oFAAoF;AACpF,wBAAgB,4BAA4B,CAAC,QAAQ,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,YAAY,CAAC,GAAG,YAAY,CAqBvG;AAED,eAAO,MAAM,2BAA2B,02YAuMvC,CAAC"}
@@ -0,0 +1,225 @@
1
+ export const WEBGPU_ATLAS_MAPS = ["baseColor", "normal", "metallicRoughness", "occlusion", "emissive", "clearcoat", "clearcoatRoughness", "clearcoatNormal", "sheenColor", "sheenRoughness", "anisotropy", "iridescence", "iridescenceThickness"];
2
+ /** Layout mirrors AtlasUniforms: 13 map records of five vec4s, then seven vec4s. */
3
+ export function webgpuExtensionAtlasUniforms(uniforms) {
4
+ const out = new Float32Array(13 * 20 + 28);
5
+ const number = (key, fallback = 0) => { const value = uniforms?.get(key); return typeof value === "number" ? value : fallback; };
6
+ const vector = (key, fallback) => { const value = uniforms?.get(key); return Array.isArray(value) || value instanceof Float32Array ? value : fallback; };
7
+ WEBGPU_ATLAS_MAPS.forEach((slot, index) => {
8
+ const offset = index * 20;
9
+ out.set(vector(`u_${slot}TextureOffset`, [0, 0]), offset);
10
+ out.set(vector(`u_${slot}TextureScale`, [1, 1]), offset + 2);
11
+ out.set([number(`u_${slot}TextureRotation`), number(`u_${slot}TextureTexCoord`), number(`u_${slot}TextureEnabled`), number(`u_${slot}AtlasY`)], offset + 4);
12
+ out.set(vector(`u_${slot}TextureWrap`, [0, 0]), offset + 8);
13
+ out.set(vector(`u_${slot}AtlasRect`, [0, 1, 1, 0]), offset + 12);
14
+ out.set(vector(`u_${slot}AtlasFilter`, [0, 0, 0, 1]), offset + 16);
15
+ });
16
+ out.set([number("u_clearcoatFactor"), number("u_clearcoatRoughnessFactor"), number("u_clearcoatNormalScale", 1), number("u_sheenRoughnessFactor")], 260);
17
+ out.set([...vector("u_sheenColorFactor", [0, 0, 0]), number("u_anisotropyStrength")], 264);
18
+ out.set([number("u_anisotropyRotation"), number("u_iridescenceFactor"), number("u_iridescenceIor", 1.3), number("u_iridescenceThicknessMinimum", 100)], 268);
19
+ out.set([number("u_iridescenceThicknessMaximum", 400), number("u_emissiveStrength", 1), number("u_materialEnvironmentSpecularScale", 1), 0], 272);
20
+ out.set([...vector("u_emissiveColor", [0, 0, 0]), 0], 276);
21
+ out.set([number("u_ior", 1.5), number("u_specularFactor", 1), 0, 0], 280);
22
+ out.set([...vector("u_specularColorFactor", [1, 1, 1]), 0], 284);
23
+ return out;
24
+ }
25
+ export const WEBGPU_EXTENSION_ATLAS_WGSL = `
26
+ struct AtlasMap {
27
+ transform: vec4<f32>,
28
+ control: vec4<f32>,
29
+ wrapMode: vec4<f32>,
30
+ rect: vec4<f32>,
31
+ filterMode: vec4<f32>,
32
+ };
33
+ struct AtlasUniforms {
34
+ maps: array<AtlasMap, 13>,
35
+ coat: vec4<f32>,
36
+ sheen: vec4<f32>,
37
+ iridescence: vec4<f32>,
38
+ factors: vec4<f32>,
39
+ emissive: vec4<f32>,
40
+ substrate: vec4<f32>,
41
+ specularColor: vec4<f32>,
42
+ };
43
+ @group(0) @binding(19) var<uniform> u_atlas: AtlasUniforms;
44
+ @group(0) @binding(20) var u_scalarAtlas: texture_2d<f32>;
45
+ @group(0) @binding(21) var u_coatNormalSampler: sampler;
46
+ @group(0) @binding(22) var u_coatNormalTexture: texture_2d<f32>;
47
+ @group(0) @binding(23) var u_sheenSampler: sampler;
48
+ @group(0) @binding(24) var u_sheenTexture: texture_2d<f32>;
49
+ @group(0) @binding(25) var u_anisotropySampler: sampler;
50
+ @group(0) @binding(26) var u_anisotropyTexture: texture_2d<f32>;
51
+ @group(0) @binding(27) var u_emissiveSampler: sampler;
52
+ @group(0) @binding(28) var u_emissiveTexture: texture_2d<f32>;
53
+ fn atlasUv(index: u32, uv0: vec2<f32>, uv1: vec2<f32>) -> vec2<f32> {
54
+ let map = u_atlas.maps[index];
55
+ let uv = select(uv0,uv1,map.control.y > 0.5) * map.transform.zw;
56
+ let cosine = cos(map.control.x); let sine = sin(map.control.x);
57
+ return vec2<f32>(cosine*uv.x-sine*uv.y,sine*uv.x+cosine*uv.y)+map.transform.xy;
58
+ }
59
+ fn atlasWrapIndex(x: i32, size: i32, mode: f32) -> i32 {
60
+ if (mode<0.5) { return clamp(x,0,size-1); }
61
+ let period=select(size,2*size,mode>1.5);
62
+ let index=((x%period)+period)%period;
63
+ return select(index,period-1-index,mode>1.5 && index>=size);
64
+ }
65
+ fn atlasFetch(point: vec2<i32>, size: vec2<i32>, origin: vec2<i32>, wrapMode: vec2<f32>) -> vec4<f32> {
66
+ let wrapped=vec2<i32>(atlasWrapIndex(point.x,size.x,wrapMode.x),atlasWrapIndex(point.y,size.y,wrapMode.y));
67
+ return textureLoad(u_scalarAtlas,origin+wrapped,0);
68
+ }
69
+ fn atlasLevel(uv: vec2<f32>, map: AtlasMap, level: i32, nearestFilter: bool) -> vec4<f32> {
70
+ var size=vec2<i32>(map.rect.yz); var origin=vec2<i32>(i32(map.rect.x),i32(map.control.w));
71
+ for (var i=0;i<16;i=i+1) { if (i>=level) { break; } origin.y=origin.y+size.y; size=max(size/2,vec2<i32>(1)); }
72
+ let pixel=uv*vec2<f32>(size)-0.5;
73
+ if (nearestFilter) { return atlasFetch(vec2<i32>(floor(pixel+0.5)),size,origin,map.wrapMode.xy); }
74
+ let low=vec2<i32>(floor(pixel)); let fraction=fract(pixel);
75
+ return mix(mix(atlasFetch(low,size,origin,map.wrapMode.xy),atlasFetch(low+vec2<i32>(1,0),size,origin,map.wrapMode.xy),fraction.x),
76
+ mix(atlasFetch(low+vec2<i32>(0,1),size,origin,map.wrapMode.xy),atlasFetch(low+vec2<i32>(1,1),size,origin,map.wrapMode.xy),fraction.x),fraction.y);
77
+ }
78
+ fn atlasSample(index: u32, uv0: vec2<f32>, uv1: vec2<f32>) -> vec4<f32> {
79
+ let map=u_atlas.maps[index]; let uv=atlasUv(index,uv0,uv1);
80
+ let dx=dpdx(uv); let dy=dpdy(uv); let lx=length(dx*map.rect.yz); let ly=length(dy*map.rect.yz);
81
+ let major=max(lx,ly); let minor=max(min(lx,ly),0.000001); let magnify=major<=1.0;
82
+ let taps=select(clamp(ceil(major/max(minor,1.0)),1.0,floor(map.filterMode.w)),1.0,magnify);
83
+ let axis=select(dy,dx,lx>=ly);
84
+ var lod=clamp(log2(max(major/taps,1.0)),0.0,map.rect.w);
85
+ if (map.filterMode.z<0.5) { lod=0.0; } else if (map.filterMode.z<1.5) { lod=floor(lod+0.5); }
86
+ let low=i32(floor(lod)); let high=min(low+1,i32(map.rect.w));
87
+ let nearestFilter=select(map.filterMode.y>0.5,map.filterMode.x>0.5,magnify);
88
+ var total=vec4<f32>(0.0);
89
+ for (var i=0;i<16;i=i+1) { if (f32(i)>=taps) { break; }
90
+ let sampleUv=uv+axis*((f32(i)+0.5)/taps-0.5);
91
+ total=total+mix(atlasLevel(sampleUv,map,low,nearestFilter),atlasLevel(sampleUv,map,high,nearestFilter),fract(lod));
92
+ }
93
+ return total/taps;
94
+ }
95
+ /* Spectral thin-film evaluation adapted from three.js iridescence_fragment (MIT).
96
+ The MIT License
97
+
98
+ Copyright © 2010-2026 three.js authors
99
+
100
+ Permission is hereby granted, free of charge, to any person obtaining a copy
101
+ of this software and associated documentation files (the "Software"), to deal
102
+ in the Software without restriction, including without limitation the rights
103
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
104
+ copies of the Software, and to permit persons to whom the Software is
105
+ furnished to do so, subject to the following conditions:
106
+
107
+ The above copyright notice and this permission notice shall be included in
108
+ all copies or substantial portions of the Software.
109
+
110
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
111
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
112
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
113
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
114
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
115
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
116
+ THE SOFTWARE.
117
+ */
118
+ // Belcour/Barla Fourier-domain CIE XYZ sensitivity, converted to linear Rec.709.
119
+ // Three monochromatic wavelength samples are not RGB tristimulus reflectance.
120
+ fn atlasFilmSensitivity(opd: f32, shift: vec3<f32>) -> vec3<f32> {
121
+ let phase=2.0*3.14159265359*opd*1.0e-9;
122
+ let variance=vec3<f32>(4.3278e9,9.3046e9,6.6121e9);
123
+ var xyz=vec3<f32>(5.4856e-13,4.4201e-13,5.2481e-13)*sqrt(2.0*3.14159265359*variance)
124
+ *cos(vec3<f32>(1.6810e6,1.7953e6,2.2084e6)*phase+shift)*exp(-phase*phase*variance);
125
+ xyz.x=xyz.x+9.7470e-14*sqrt(2.0*3.14159265359*4.5282e9)*cos(2.2399e6*phase+shift.x)*exp(-4.5282e9*phase*phase);
126
+ xyz=xyz/1.0685e-7;
127
+ return mat3x3<f32>(vec3<f32>(3.2404542,-0.9692660,0.0556434),vec3<f32>(-1.5371385,1.8760108,-0.2040259),vec3<f32>(-0.4985314,0.0415560,1.0572252))*xyz;
128
+ }
129
+ fn atlasThinFilm(substrateF0: vec3<f32>, filmIor: f32, thickness: f32, cosine: f32) -> vec3<f32> {
130
+ let c1=clamp(cosine,0.0001,1.0);
131
+ if (thickness<=0.0) { return fresnelSchlick(c1,substrateF0); }
132
+ let n2=mix(1.0,filmIor,smoothstep(0.0,0.03,thickness));
133
+ let c2Squared=1.0-(1.0-c1*c1)/(n2*n2);
134
+ if (c2Squared<0.0) { return vec3<f32>(1.0); }
135
+ let c2=sqrt(c2Squared);
136
+ let f12=(n2-1.0)/(n2+1.0);
137
+ let r12=fresnelSchlick(c1,vec3<f32>(f12*f12)).x;
138
+ let t121=1.0-r12;
139
+ let rootF0=sqrt(clamp(substrateF0,vec3<f32>(0.0),vec3<f32>(0.9999)));
140
+ let n3=(vec3<f32>(1.0)+rootF0)/(vec3<f32>(1.0)-rootF0);
141
+ let f23=(n3-vec3<f32>(n2))/(n3+vec3<f32>(n2));
142
+ let r23=fresnelSchlick(c2,f23*f23);
143
+ let phi21=select(3.14159265359,0.0,n2<1.0);
144
+ let phi=vec3<f32>(phi21)+select(vec3<f32>(0.0),vec3<f32>(3.14159265359),n3<vec3<f32>(n2));
145
+ let opd=2.0*n2*thickness*c2;
146
+ let r123=clamp(r12*r23,vec3<f32>(0.00001),vec3<f32>(0.9999));
147
+ let amplitude=sqrt(r123);
148
+ let rs=t121*t121*r23/(vec3<f32>(1.0)-r123);
149
+ var reflectance=vec3<f32>(r12)+rs;
150
+ var coefficient=rs-vec3<f32>(t121);
151
+ for (var order=1;order<=2;order=order+1) {
152
+ coefficient=coefficient*amplitude;
153
+ reflectance=reflectance+coefficient*2.0*atlasFilmSensitivity(f32(order)*opd,f32(order)*phi);
154
+ }
155
+ return max(reflectance,vec3<f32>(0.0));
156
+ }
157
+
158
+ // KHR_materials_iridescence: a missing thickness map samples 1.0, and
159
+ // the dielectric base receives inverse-max Fresnel weighting (rgb_mix).
160
+ fn atlasIridescenceFresnel(substrateF0: vec3<f32>, cosine: f32, uv0: vec2<f32>, uv1: vec2<f32>) -> vec3<f32> {
161
+ let strength=clamp(u_atlas.iridescence.y*mix(1.0,atlasSample(11u,uv0,uv1).r,u_atlas.maps[11].control.z),0.0,1.0);
162
+ let thickness=mix(u_atlas.iridescence.w,u_atlas.factors.x,mix(1.0,atlasSample(12u,uv0,uv1).g,u_atlas.maps[12].control.z));
163
+ return mix(fresnelSchlick(cosine,substrateF0),atlasThinFilm(substrateF0,u_atlas.iridescence.z,thickness,cosine),strength);
164
+ }
165
+
166
+ // Recover the Schlick normal-incidence coefficient before applying the split-sum
167
+ // BRDF LUT. Multiplying an already Fresnel-weighted environment by a Fresnel
168
+ // difference would count Fresnel twice and incorrectly scale the LUT bias term.
169
+ fn atlasIridescenceEnvironmentF0(substrateF0: vec3<f32>, cosine: f32, uv0: vec2<f32>, uv1: vec2<f32>) -> vec3<f32> {
170
+ let strength=clamp(u_atlas.iridescence.y*mix(1.0,atlasSample(11u,uv0,uv1).r,u_atlas.maps[11].control.z),0.0,1.0);
171
+ let thickness=mix(u_atlas.iridescence.w,u_atlas.factors.x,mix(1.0,atlasSample(12u,uv0,uv1).g,u_atlas.maps[12].control.z));
172
+ let grazing=clamp(pow(clamp(1.0-cosine,0.0,1.0),5.0),0.0,0.9999);
173
+ let filmF0=(atlasThinFilm(substrateF0,u_atlas.iridescence.z,thickness,cosine)-vec3<f32>(grazing))/(1.0-grazing);
174
+ return mix(substrateF0,filmF0,strength);
175
+ }
176
+
177
+ fn atlasExtensionLighting(normal: vec3<f32>, tangent: vec4<f32>, view: vec3<f32>, light: vec3<f32>, uv0: vec2<f32>, uv1: vec2<f32>, shadow: f32, environment: vec3<f32>, substrateF0: vec3<f32>, substrateRoughness: f32) -> vec3<f32> {
178
+ let coatMask=atlasSample(5u,uv0,uv1).r; let coatRoughMask=atlasSample(6u,uv0,uv1).g;
179
+ let sheenRoughMask=atlasSample(9u,uv0,uv1).a; let filmMask=atlasSample(11u,uv0,uv1).r;
180
+ let thicknessMask=atlasSample(12u,uv0,uv1).g;
181
+ let coatNormalSample=textureSample(u_coatNormalTexture,u_coatNormalSampler,atlasUv(7u,uv0,uv1)).rgb;
182
+ let coatNormal=normalize(mix(normal,perturbNormal(normal,tangent,coatNormalSample,u_atlas.coat.z),u_atlas.maps[7].control.z));
183
+ let sheenSample=textureSample(u_sheenTexture,u_sheenSampler,atlasUv(8u,uv0,uv1)).rgb;
184
+ let anisotropySample=textureSample(u_anisotropyTexture,u_anisotropySampler,atlasUv(10u,uv0,uv1));
185
+ let coat=u_atlas.coat.x*mix(1.0,coatMask,u_atlas.maps[5].control.z);
186
+ let coatRough=max(0.045,u_atlas.coat.y*mix(1.0,coatRoughMask,u_atlas.maps[6].control.z));
187
+ let sheen=u_atlas.sheen.rgb*mix(vec3<f32>(1.0),sheenSample,u_atlas.maps[8].control.z);
188
+ let sheenRough=max(0.045,u_atlas.coat.w*mix(1.0,sheenRoughMask,u_atlas.maps[9].control.z));
189
+ let anisotropy=u_atlas.sheen.w*mix(1.0,anisotropySample.b,u_atlas.maps[10].control.z);
190
+ let film=u_atlas.iridescence.y*mix(1.0,filmMask,u_atlas.maps[11].control.z);
191
+ let thickness=mix(u_atlas.iridescence.w,u_atlas.factors.x,mix(1.0,thicknessMask,u_atlas.maps[12].control.z));
192
+ let halfVector=normalize(light+view); let ndl=max(dot(normal,light),0.0); let ndv=max(dot(normal,view),0.001);
193
+ let coatNdl=max(dot(coatNormal,light),0.0); let coatNdv=max(dot(coatNormal,view),0.001); let coatNdh=max(dot(coatNormal,halfVector),0.001);
194
+ let coatBrdf=coat*ggxDistribution(coatNdh,coatRough)*ggxVisibilitySmithCorrelated(coatNdv,coatNdl,coatRough)*fresnelSchlick(max(dot(view,halfVector),0.0),vec3<f32>(0.04));
195
+ let ndh=max(dot(normal,halfVector),0.0); let inverseRoughness=1.0/(sheenRough*sheenRough);
196
+ let charlie=(2.0+inverseRoughness)*pow(max(1.0-ndh*ndh,0.00001),0.5*inverseRoughness)/(2.0*3.14159265);
197
+ let sheenBrdf=sheen*charlie/max(4.0*(ndl+ndv-ndl*ndv),0.0001);
198
+ let tx=normalize(tangent.xyz-normal*dot(tangent.xyz,normal)); let ty=normalize(cross(normal,tx))*tangent.w;
199
+ let mappedDirection=mix(vec2<f32>(1.0,0.0),anisotropySample.rg*2.0-1.0,u_atlas.maps[10].control.z);
200
+ let angle=u_atlas.iridescence.x+atan2(mappedDirection.y,mappedDirection.x);
201
+ let axis=tx*cos(angle)+ty*sin(angle); let crossAxis=-tx*sin(angle)+ty*cos(angle);
202
+ // Anisotropy and iridescence modify the same substrate specular BRDF.
203
+ // KHR anisotropy broadens the tangent alpha; it is not an extra white lobe.
204
+ let alpha=max(substrateRoughness,0.045)*max(substrateRoughness,0.045);
205
+ let ax=mix(alpha,1.0,clamp(anisotropy*anisotropy,0.0,1.0)); let ay=alpha;
206
+ let tangentH=dot(halfVector,axis)/ax; let bitangentH=dot(halfVector,crossAxis)/ay;
207
+ let denominator=tangentH*tangentH+bitangentH*bitangentH+ndh*ndh;
208
+ let anisotropicD=1.0/max(3.14159265*ax*ay*denominator*denominator,0.0000000000000001);
209
+ let lambdaV=ndl*length(vec3<f32>(ax*dot(axis,view),ay*dot(crossAxis,view),ndv));
210
+ let lambdaL=ndv*length(vec3<f32>(ax*dot(axis,light),ay*dot(crossAxis,light),ndl));
211
+ let anisotropicV=0.5/max(lambdaV+lambdaL,0.00001);
212
+ let isotropicDv=ggxDistribution(ndh,substrateRoughness)*ggxVisibilitySmithCorrelated(ndv,ndl,substrateRoughness);
213
+ let substrateDv=select(isotropicDv,anisotropicD*anisotropicV,anisotropy>0.0);
214
+ let vdh=max(dot(view,halfVector),0.0001);
215
+ let substrateFresnel=fresnelSchlick(vdh,substrateF0);
216
+ let anisotropicBrdf=substrateFresnel*(substrateDv-isotropicDv);
217
+ let filmDirect=film*(atlasThinFilm(substrateF0,u_atlas.iridescence.z,thickness,vdh)-substrateFresnel)*substrateDv;
218
+ // Film environment energy is integrated once in shadePbr through the BRDF LUT.
219
+ let filmEnvironment=vec3<f32>(0.0);
220
+ let direct=(coatBrdf*coatNdl+(sheenBrdf+anisotropicBrdf+filmDirect)*ndl)*2.25*shadow;
221
+ return (direct+environment*(coat*0.04+sheen*pow(1.0-ndv,5.0)+filmEnvironment))*u_atlas.factors.z;
222
+
223
+ }
224
+ `;
225
+ //# sourceMappingURL=WebGPUExtensionAtlas.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WebGPUExtensionAtlas.js","sourceRoot":"","sources":["../../../../packages/rendering/src/WebGPUExtensionAtlas.ts"],"names":[],"mappings":"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"}
@@ -11,4 +11,44 @@
11
11
  */
12
12
  /** Joint-palette capacity of the WebGPU skinning path — parity with the WebGL2 `u_jointMatrices[96]`. */
13
13
  export declare const MAX_WEBGPU_SKINNING_JOINTS = 96;
14
+ /**
15
+ * Machine-readable reason a skinned mesh takes (or avoids) the CPU skinning fallback.
16
+ * Reported in diagnostics so gates can distinguish "too many joints" from "no GPU path
17
+ * available" instead of lumping every fallback together.
18
+ */
19
+ export type SkinningCpuFallbackReason =
20
+ /** Joint count fits the uniform array; no fallback involved. */
21
+ "none-uniform-array"
22
+ /** Joint count exceeds the uniform array but fits the data-texture palette path. */
23
+ | "none-data-texture"
24
+ /** Joint count exceeds even the data-texture ceiling — CPU skinning is the only option. */
25
+ | "joint-count-exceeds-data-texture-limit"
26
+ /** The shader has no data-texture palette uniforms, so palettes above the uniform cap fall back. */
27
+ | "shader-lacks-data-texture-palette"
28
+ /** No joint-palette uniforms at all on this shader — CPU skinning is the only option. */
29
+ | "shader-lacks-skinning-uniforms";
30
+ export interface SkinningPaletteDecision {
31
+ readonly jointCount: number;
32
+ /** `"uniform-array"` | `"data-texture"` — the GPU upload path, or `"cpu"` when neither fits. */
33
+ readonly path: "uniform-array" | "data-texture" | "cpu";
34
+ readonly reason: SkinningCpuFallbackReason;
35
+ /** True when the mesh must be skinned on the CPU for this shader/capability set. */
36
+ readonly cpuFallback: boolean;
37
+ }
38
+ /**
39
+ * Decide the joint-palette upload path for a skinned mesh without touching the GPU.
40
+ * Pure and deterministic: same inputs always produce the same decision, so diagnostics
41
+ * and gates can assert on it in unit tests.
42
+ *
43
+ * Mirrors the runtime rule in the forward pass (uniform array up to the uniform cap,
44
+ * data-texture palette above it when the shader declares the uniforms, CPU otherwise)
45
+ * without importing renderer internals.
46
+ */
47
+ export declare function decideSkinningPalettePath(options: {
48
+ readonly jointCount: number;
49
+ readonly maxUniformJoints?: number;
50
+ readonly maxDataTextureJoints?: number;
51
+ readonly shaderHasDataTexturePalette?: boolean;
52
+ readonly shaderHasSkinningUniforms?: boolean;
53
+ }): SkinningPaletteDecision;
14
54
  //# sourceMappingURL=WebGPUSkinningLimits.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"WebGPUSkinningLimits.d.ts","sourceRoot":"","sources":["../../../../packages/rendering/src/WebGPUSkinningLimits.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,yGAAyG;AACzG,eAAO,MAAM,0BAA0B,KAAK,CAAC"}
1
+ {"version":3,"file":"WebGPUSkinningLimits.d.ts","sourceRoot":"","sources":["../../../../packages/rendering/src/WebGPUSkinningLimits.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,yGAAyG;AACzG,eAAO,MAAM,0BAA0B,KAAK,CAAC;AAE7C;;;;GAIG;AACH,MAAM,MAAM,yBAAyB;AACnC,gEAAgE;AAC9D,oBAAoB;AACtB,oFAAoF;GAClF,mBAAmB;AACrB,2FAA2F;GACzF,wCAAwC;AAC1C,oGAAoG;GAClG,mCAAmC;AACrC,yFAAyF;GACvF,gCAAgC,CAAC;AAErC,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,gGAAgG;IAChG,QAAQ,CAAC,IAAI,EAAE,eAAe,GAAG,cAAc,GAAG,KAAK,CAAC;IACxD,QAAQ,CAAC,MAAM,EAAE,yBAAyB,CAAC;IAC3C,oFAAoF;IACpF,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;CAC/B;AAED;;;;;;;;GAQG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE;IACjD,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,oBAAoB,CAAC,EAAE,MAAM,CAAC;IACvC,QAAQ,CAAC,2BAA2B,CAAC,EAAE,OAAO,CAAC;IAC/C,QAAQ,CAAC,yBAAyB,CAAC,EAAE,OAAO,CAAC;CAC9C,GAAG,uBAAuB,CAsB1B"}
@@ -11,4 +11,36 @@
11
11
  */
12
12
  /** Joint-palette capacity of the WebGPU skinning path — parity with the WebGL2 `u_jointMatrices[96]`. */
13
13
  export const MAX_WEBGPU_SKINNING_JOINTS = 96;
14
+ /**
15
+ * Decide the joint-palette upload path for a skinned mesh without touching the GPU.
16
+ * Pure and deterministic: same inputs always produce the same decision, so diagnostics
17
+ * and gates can assert on it in unit tests.
18
+ *
19
+ * Mirrors the runtime rule in the forward pass (uniform array up to the uniform cap,
20
+ * data-texture palette above it when the shader declares the uniforms, CPU otherwise)
21
+ * without importing renderer internals.
22
+ */
23
+ export function decideSkinningPalettePath(options) {
24
+ const jointCount = options.jointCount;
25
+ if (!Number.isInteger(jointCount) || jointCount < 0) {
26
+ throw new Error("decideSkinningPalettePath jointCount must be a non-negative integer.");
27
+ }
28
+ const maxUniformJoints = options.maxUniformJoints ?? MAX_WEBGPU_SKINNING_JOINTS;
29
+ const maxDataTextureJoints = options.maxDataTextureJoints ?? MAX_WEBGPU_SKINNING_JOINTS;
30
+ const shaderHasSkinningUniforms = options.shaderHasSkinningUniforms ?? true;
31
+ const shaderHasDataTexturePalette = options.shaderHasDataTexturePalette ?? true;
32
+ if (jointCount <= maxUniformJoints && shaderHasSkinningUniforms) {
33
+ return { jointCount, path: "uniform-array", reason: "none-uniform-array", cpuFallback: false };
34
+ }
35
+ if (!shaderHasSkinningUniforms) {
36
+ return { jointCount, path: "cpu", reason: "shader-lacks-skinning-uniforms", cpuFallback: true };
37
+ }
38
+ if (jointCount <= maxDataTextureJoints && shaderHasDataTexturePalette) {
39
+ return { jointCount, path: "data-texture", reason: "none-data-texture", cpuFallback: false };
40
+ }
41
+ if (!shaderHasDataTexturePalette) {
42
+ return { jointCount, path: "cpu", reason: "shader-lacks-data-texture-palette", cpuFallback: true };
43
+ }
44
+ return { jointCount, path: "cpu", reason: "joint-count-exceeds-data-texture-limit", cpuFallback: true };
45
+ }
14
46
  //# sourceMappingURL=WebGPUSkinningLimits.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"WebGPUSkinningLimits.js","sourceRoot":"","sources":["../../../../packages/rendering/src/WebGPUSkinningLimits.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,yGAAyG;AACzG,MAAM,CAAC,MAAM,0BAA0B,GAAG,EAAE,CAAC"}
1
+ {"version":3,"file":"WebGPUSkinningLimits.js","sourceRoot":"","sources":["../../../../packages/rendering/src/WebGPUSkinningLimits.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,yGAAyG;AACzG,MAAM,CAAC,MAAM,0BAA0B,GAAG,EAAE,CAAC;AA4B7C;;;;;;;;GAQG;AACH,MAAM,UAAU,yBAAyB,CAAC,OAMzC;IACC,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;IACtC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,UAAU,GAAG,CAAC,EAAE,CAAC;QACpD,MAAM,IAAI,KAAK,CAAC,sEAAsE,CAAC,CAAC;IAC1F,CAAC;IACD,MAAM,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,IAAI,0BAA0B,CAAC;IAChF,MAAM,oBAAoB,GAAG,OAAO,CAAC,oBAAoB,IAAI,0BAA0B,CAAC;IACxF,MAAM,yBAAyB,GAAG,OAAO,CAAC,yBAAyB,IAAI,IAAI,CAAC;IAC5E,MAAM,2BAA2B,GAAG,OAAO,CAAC,2BAA2B,IAAI,IAAI,CAAC;IAChF,IAAI,UAAU,IAAI,gBAAgB,IAAI,yBAAyB,EAAE,CAAC;QAChE,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,eAAe,EAAE,MAAM,EAAE,oBAAoB,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC;IACjG,CAAC;IACD,IAAI,CAAC,yBAAyB,EAAE,CAAC;QAC/B,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,gCAAgC,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;IAClG,CAAC;IACD,IAAI,UAAU,IAAI,oBAAoB,IAAI,2BAA2B,EAAE,CAAC;QACtE,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,EAAE,mBAAmB,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC;IAC/F,CAAC;IACD,IAAI,CAAC,2BAA2B,EAAE,CAAC;QACjC,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,mCAAmC,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;IACrG,CAAC;IACD,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,wCAAwC,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC;AAC1G,CAAC"}
@@ -6,10 +6,19 @@ export interface CollisionPlane {
6
6
  restitution?: number;
7
7
  mode?: "bounce" | "kill";
8
8
  }
9
+ export interface GPUCollisionPlane {
10
+ readonly normal: Vector3Like;
11
+ readonly constant: number;
12
+ readonly restitution: number;
13
+ readonly killOnContact: boolean;
14
+ }
9
15
  export declare class CollisionModule implements ParticleModule {
10
16
  readonly name = "CollisionModule";
17
+ readonly supportsGPU = true;
11
18
  readonly plane: Required<CollisionPlane>;
12
19
  constructor(plane: CollisionPlane);
20
+ /** Encode this plane for the WGSL compute kernel (analytic-plane slot). */
21
+ toGPUPlane(): GPUCollisionPlane;
13
22
  afterIntegrate(particle: Particle, _context: ParticleUpdateContext): void;
14
23
  }
15
24
  //# sourceMappingURL=CollisionModule.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"CollisionModule.d.ts","sourceRoot":"","sources":["../../../../../packages/rendering/src/effects/CollisionModule.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC3D,OAAO,KAAK,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAEjF,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,WAAW,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC;CAC1B;AAeD,qBAAa,eAAgB,YAAW,cAAc;IACpD,QAAQ,CAAC,IAAI,qBAAqB;IAClC,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,cAAc,CAAC,CAAC;gBAE7B,KAAK,EAAE,cAAc;IAajC,cAAc,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,qBAAqB,GAAG,IAAI;CAuB1E"}
1
+ {"version":3,"file":"CollisionModule.d.ts","sourceRoot":"","sources":["../../../../../packages/rendering/src/effects/CollisionModule.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC3D,OAAO,KAAK,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAEjF,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,WAAW,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC;CAC1B;AAeD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;CACjC;AAED,qBAAa,eAAgB,YAAW,cAAc;IACpD,QAAQ,CAAC,IAAI,qBAAqB;IAClC,QAAQ,CAAC,WAAW,QAAQ;IAC5B,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,cAAc,CAAC,CAAC;gBAE7B,KAAK,EAAE,cAAc;IAajC,2EAA2E;IAC3E,UAAU,IAAI,iBAAiB;IAS/B,cAAc,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,qBAAqB,GAAG,IAAI;CAuB1E"}
@@ -10,6 +10,7 @@ function normalize(value) {
10
10
  }
11
11
  export class CollisionModule {
12
12
  name = "CollisionModule";
13
+ supportsGPU = true;
13
14
  plane;
14
15
  constructor(plane) {
15
16
  this.plane = {
@@ -22,6 +23,15 @@ export class CollisionModule {
22
23
  throw new RangeError("Collision plane constant and restitution must be finite numbers.");
23
24
  }
24
25
  }
26
+ /** Encode this plane for the WGSL compute kernel (analytic-plane slot). */
27
+ toGPUPlane() {
28
+ return {
29
+ normal: { ...this.plane.normal },
30
+ constant: this.plane.constant,
31
+ restitution: this.plane.restitution,
32
+ killOnContact: this.plane.mode === "kill",
33
+ };
34
+ }
25
35
  afterIntegrate(particle, _context) {
26
36
  const distance = dot(this.plane.normal, particle.position) + this.plane.constant;
27
37
  if (distance >= 0) {
@@ -1 +1 @@
1
- {"version":3,"file":"CollisionModule.js","sourceRoot":"","sources":["../../../../../packages/rendering/src/effects/CollisionModule.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"CollisionModule.js","sourceRoot":"","sources":["../../../../../packages/rendering/src/effects/CollisionModule.ts"],"names":[],"mappings":"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"}
@@ -6,10 +6,17 @@ export interface ColorKeyframe {
6
6
  color: ColorLike;
7
7
  }
8
8
  export declare function sampleColorGradient(keyframes: readonly ColorKeyframe[], time: number): ColorLike;
9
+ /**
10
+ * Pack a color/alpha-over-life gradient into a fixed-stop RGBA LUT for the
11
+ * compute kernel. Alpha-over-life travels in the fourth channel.
12
+ */
13
+ export declare function encodeColorGradientLUT(keyframes: readonly ColorKeyframe[], stops?: number): Float32Array;
9
14
  export declare class ColorModule implements ParticleModule {
10
15
  readonly name = "ColorModule";
16
+ readonly supportsGPU = true;
11
17
  readonly gradient: readonly ColorKeyframe[];
12
18
  constructor(gradient: readonly ColorKeyframe[]);
13
19
  update(particle: Particle, context: ParticleUpdateContext): void;
20
+ toGPUColorGradient(stops?: number): Float32Array;
14
21
  }
15
22
  //# sourceMappingURL=ColorModule.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ColorModule.d.ts","sourceRoot":"","sources":["../../../../../packages/rendering/src/effects/ColorModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,KAAK,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AACjF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE9C,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,SAAS,CAAC;CAClB;AAgBD,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,SAAS,aAAa,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,CAsBhG;AAED,qBAAa,WAAY,YAAW,cAAc;IAChD,QAAQ,CAAC,IAAI,iBAAiB;IAC9B,QAAQ,CAAC,QAAQ,EAAE,SAAS,aAAa,EAAE,CAAC;gBAEhC,QAAQ,EAAE,SAAS,aAAa,EAAE;IAK9C,MAAM,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,qBAAqB,GAAG,IAAI;CAGjE"}
1
+ {"version":3,"file":"ColorModule.d.ts","sourceRoot":"","sources":["../../../../../packages/rendering/src/effects/ColorModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,KAAK,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AACjF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE9C,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,SAAS,CAAC;CAClB;AAgBD,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,SAAS,aAAa,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,CAsBhG;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,SAAS,aAAa,EAAE,EAAE,KAAK,SAAK,GAAG,YAAY,CAcpG;AAED,qBAAa,WAAY,YAAW,cAAc;IAChD,QAAQ,CAAC,IAAI,iBAAiB;IAC9B,QAAQ,CAAC,WAAW,QAAQ;IAC5B,QAAQ,CAAC,QAAQ,EAAE,SAAS,aAAa,EAAE,CAAC;gBAEhC,QAAQ,EAAE,SAAS,aAAa,EAAE;IAK9C,MAAM,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,qBAAqB,GAAG,IAAI;IAIhE,kBAAkB,CAAC,KAAK,SAAK,GAAG,YAAY;CAG7C"}
@@ -31,8 +31,28 @@ export function sampleColorGradient(keyframes, time) {
31
31
  }
32
32
  return { ...keyframes[keyframes.length - 1].color };
33
33
  }
34
+ /**
35
+ * Pack a color/alpha-over-life gradient into a fixed-stop RGBA LUT for the
36
+ * compute kernel. Alpha-over-life travels in the fourth channel.
37
+ */
38
+ export function encodeColorGradientLUT(keyframes, stops = 16) {
39
+ validateGradient(keyframes);
40
+ if (!Number.isInteger(stops) || stops < 2 || stops > 64) {
41
+ throw new RangeError("Color gradient LUT stops must be an integer in [2, 64].");
42
+ }
43
+ const lut = new Float32Array(stops * 4);
44
+ for (let index = 0; index < stops; index += 1) {
45
+ const color = sampleColorGradient(keyframes, stops === 1 ? 0 : index / (stops - 1));
46
+ lut[index * 4] = color.r;
47
+ lut[index * 4 + 1] = color.g;
48
+ lut[index * 4 + 2] = color.b;
49
+ lut[index * 4 + 3] = color.a;
50
+ }
51
+ return lut;
52
+ }
34
53
  export class ColorModule {
35
54
  name = "ColorModule";
55
+ supportsGPU = true;
36
56
  gradient;
37
57
  constructor(gradient) {
38
58
  this.gradient = gradient;
@@ -41,5 +61,8 @@ export class ColorModule {
41
61
  update(particle, context) {
42
62
  particle.color = sampleColorGradient(this.gradient, context.normalizedAge);
43
63
  }
64
+ toGPUColorGradient(stops = 16) {
65
+ return encodeColorGradientLUT(this.gradient, stops);
66
+ }
44
67
  }
45
68
  //# sourceMappingURL=ColorModule.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ColorModule.js","sourceRoot":"","sources":["../../../../../packages/rendering/src/effects/ColorModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,MAAM,eAAe,CAAC;AAS/C,SAAS,gBAAgB,CAAC,SAAmC;IAC3D,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3B,MAAM,IAAI,UAAU,CAAC,mDAAmD,CAAC,CAAC;IAC5E,CAAC;IAED,IAAI,QAAQ,GAAG,CAAC,MAAM,CAAC,iBAAiB,CAAC;IACzC,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;QACjC,IAAI,QAAQ,CAAC,IAAI,GAAG,CAAC,IAAI,QAAQ,CAAC,IAAI,GAAG,CAAC,IAAI,QAAQ,CAAC,IAAI,GAAG,QAAQ,EAAE,CAAC;YACvE,MAAM,IAAI,UAAU,CAAC,2EAA2E,CAAC,CAAC;QACpG,CAAC;QACD,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC;IAC3B,CAAC;AACH,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,SAAmC,EAAE,IAAY;IACnF,IAAI,IAAI,IAAI,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC9B,OAAO,EAAE,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC;IACnC,CAAC;IAED,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,SAAS,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QACzD,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;QAC9B,IAAI,IAAI,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YACtB,MAAM,QAAQ,GAAG,SAAS,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;YACtC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,GAAG,QAAQ,CAAC,IAAI,IAAI,CAAC,CAAC;YAC5C,MAAM,KAAK,GAAG,CAAC,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;YAE5C,OAAO;gBACL,CAAC,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK;gBAC/D,CAAC,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK;gBAC/D,CAAC,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK;gBAC/D,CAAC,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK;aAChE,CAAC;QACJ,CAAC;IACH,CAAC;IAED,OAAO,EAAE,GAAG,SAAS,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC;AACtD,CAAC;AAED,MAAM,OAAO,WAAW;IACb,IAAI,GAAG,aAAa,CAAC;IACrB,QAAQ,CAA2B;IAE5C,YAAY,QAAkC;QAC5C,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IAC7B,CAAC;IAED,MAAM,CAAC,QAAkB,EAAE,OAA8B;QACvD,QAAQ,CAAC,KAAK,GAAG,mBAAmB,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;IAC7E,CAAC;CACF"}
1
+ {"version":3,"file":"ColorModule.js","sourceRoot":"","sources":["../../../../../packages/rendering/src/effects/ColorModule.ts"],"names":[],"mappings":"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"}
@@ -8,4 +8,39 @@ export declare class ForceModule implements ParticleModule {
8
8
  update(particle: Particle, context: ParticleUpdateContext): void;
9
9
  }
10
10
  export declare function gravityForce(gravity?: number): ForceModule;
11
+ export interface WindModuleOptions {
12
+ readonly direction: Vector3Like;
13
+ readonly strength?: number;
14
+ /** Gust amplitude as a fraction of strength (0 = steady wind). */
15
+ readonly gustAmplitude?: number;
16
+ readonly gustDirection?: Vector3Like;
17
+ readonly gustFrequency?: number;
18
+ readonly gustSpeed?: number;
19
+ }
20
+ export interface GPUWindParams {
21
+ readonly direction: Vector3Like;
22
+ readonly strength: number;
23
+ readonly gustAmplitude: number;
24
+ readonly gustDirection: Vector3Like;
25
+ readonly gustFrequency: number;
26
+ readonly gustSpeed: number;
27
+ }
28
+ /**
29
+ * Analytic wind field with a traveling sinusoidal gust. The CPU fallback
30
+ * evaluates the same closed form the WGSL kernel implements, so the wind
31
+ * costs zero CPU per-particle work on the GPU path.
32
+ */
33
+ export declare class WindModule implements ParticleModule {
34
+ readonly name = "WindModule";
35
+ readonly supportsGPU = true;
36
+ readonly direction: Vector3Like;
37
+ readonly strength: number;
38
+ readonly gustAmplitude: number;
39
+ readonly gustDirection: Vector3Like;
40
+ readonly gustFrequency: number;
41
+ readonly gustSpeed: number;
42
+ constructor(options: WindModuleOptions);
43
+ update(particle: Particle, context: ParticleUpdateContext): void;
44
+ toGPUWind(): GPUWindParams;
45
+ }
11
46
  //# sourceMappingURL=ForceModule.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ForceModule.d.ts","sourceRoot":"","sources":["../../../../../packages/rendering/src/effects/ForceModule.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC3D,OAAO,KAAK,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAEjF,MAAM,MAAM,YAAY,GAAG,WAAW,GAAG,CAAC,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,qBAAqB,KAAK,WAAW,CAAC,CAAC;AAE/G,qBAAa,WAAY,YAAW,cAAc;IAChD,QAAQ,CAAC,IAAI,iBAAiB;IAC9B,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAC;gBAEjB,KAAK,EAAE,YAAY;IAI/B,MAAM,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,qBAAqB,GAAG,IAAI;CAOjE;AAED,wBAAgB,YAAY,CAAC,OAAO,SAAQ,GAAG,WAAW,CAEzD"}
1
+ {"version":3,"file":"ForceModule.d.ts","sourceRoot":"","sources":["../../../../../packages/rendering/src/effects/ForceModule.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC3D,OAAO,KAAK,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAEjF,MAAM,MAAM,YAAY,GAAG,WAAW,GAAG,CAAC,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,qBAAqB,KAAK,WAAW,CAAC,CAAC;AAE/G,qBAAa,WAAY,YAAW,cAAc;IAChD,QAAQ,CAAC,IAAI,iBAAiB;IAC9B,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAC;gBAEjB,KAAK,EAAE,YAAY;IAI/B,MAAM,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,qBAAqB,GAAG,IAAI;CAOjE;AAED,wBAAgB,YAAY,CAAC,OAAO,SAAQ,GAAG,WAAW,CAEzD;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,SAAS,EAAE,WAAW,CAAC;IAChC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,kEAAkE;IAClE,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,aAAa,CAAC,EAAE,WAAW,CAAC;IACrC,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,SAAS,EAAE,WAAW,CAAC;IAChC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,aAAa,EAAE,WAAW,CAAC;IACpC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED;;;;GAIG;AACH,qBAAa,UAAW,YAAW,cAAc;IAC/C,QAAQ,CAAC,IAAI,gBAAgB;IAC7B,QAAQ,CAAC,WAAW,QAAQ;IAC5B,QAAQ,CAAC,SAAS,EAAE,WAAW,CAAC;IAChC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,aAAa,EAAE,WAAW,CAAC;IACpC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;gBAEf,OAAO,EAAE,iBAAiB;IAgBtC,MAAM,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,qBAAqB,GAAG,IAAI;IAahE,SAAS,IAAI,aAAa;CAU3B"}
@@ -14,4 +14,53 @@ export class ForceModule {
14
14
  export function gravityForce(gravity = -9.81) {
15
15
  return new ForceModule({ x: 0, y: gravity, z: 0 });
16
16
  }
17
+ /**
18
+ * Analytic wind field with a traveling sinusoidal gust. The CPU fallback
19
+ * evaluates the same closed form the WGSL kernel implements, so the wind
20
+ * costs zero CPU per-particle work on the GPU path.
21
+ */
22
+ export class WindModule {
23
+ name = "WindModule";
24
+ supportsGPU = true;
25
+ direction;
26
+ strength;
27
+ gustAmplitude;
28
+ gustDirection;
29
+ gustFrequency;
30
+ gustSpeed;
31
+ constructor(options) {
32
+ this.direction = { ...options.direction };
33
+ this.strength = options.strength ?? 1;
34
+ this.gustAmplitude = options.gustAmplitude ?? 0;
35
+ this.gustDirection = { ...(options.gustDirection ?? { x: 1, y: 0, z: 0 }) };
36
+ this.gustFrequency = options.gustFrequency ?? 0.5;
37
+ this.gustSpeed = options.gustSpeed ?? 0.8;
38
+ if (!Number.isFinite(this.strength) || !Number.isFinite(this.gustAmplitude) ||
39
+ !Number.isFinite(this.gustFrequency) || !Number.isFinite(this.gustSpeed)) {
40
+ throw new RangeError("WindModule strength and gust parameters must be finite numbers.");
41
+ }
42
+ if (this.gustAmplitude < 0) {
43
+ throw new RangeError("WindModule gustAmplitude must be non-negative.");
44
+ }
45
+ }
46
+ update(particle, context) {
47
+ const alongWind = particle.position.x * this.gustDirection.x +
48
+ particle.position.y * this.gustDirection.y +
49
+ particle.position.z * this.gustDirection.z;
50
+ const gust = 1 + this.gustAmplitude * Math.sin(alongWind * this.gustFrequency + context.elapsedTime * this.gustSpeed);
51
+ particle.velocity.x += this.direction.x * this.strength * gust * context.deltaTime;
52
+ particle.velocity.y += this.direction.y * this.strength * gust * context.deltaTime;
53
+ particle.velocity.z += this.direction.z * this.strength * gust * context.deltaTime;
54
+ }
55
+ toGPUWind() {
56
+ return {
57
+ direction: { ...this.direction },
58
+ strength: this.strength,
59
+ gustAmplitude: this.gustAmplitude,
60
+ gustDirection: { ...this.gustDirection },
61
+ gustFrequency: this.gustFrequency,
62
+ gustSpeed: this.gustSpeed,
63
+ };
64
+ }
65
+ }
17
66
  //# sourceMappingURL=ForceModule.js.map