@zephyr3d/scene 0.9.27 → 0.10.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 (502) hide show
  1. package/README.md +60 -27
  2. package/dist/animation/animation_bank.js +634 -0
  3. package/dist/animation/animation_bank.js.map +1 -0
  4. package/dist/animation/animation_bank_gpu.js +256 -0
  5. package/dist/animation/animation_bank_gpu.js.map +1 -0
  6. package/dist/animation/animationset.js +54 -0
  7. package/dist/animation/animationset.js.map +1 -1
  8. package/dist/animation/cloth/gpu_cloth_component.js +406 -0
  9. package/dist/animation/cloth/gpu_cloth_component.js.map +1 -0
  10. package/dist/animation/cloth/gpu_cloth_system.js +332 -202
  11. package/dist/animation/cloth/gpu_cloth_system.js.map +1 -1
  12. package/dist/animation/gpu_animation_driver.js +289 -0
  13. package/dist/animation/gpu_animation_driver.js.map +1 -0
  14. package/dist/animation/joint_dynamics/collision.js +112 -1
  15. package/dist/animation/joint_dynamics/collision.js.map +1 -1
  16. package/dist/animation/joint_dynamics/controller.js +6 -0
  17. package/dist/animation/joint_dynamics/controller.js.map +1 -1
  18. package/dist/animation/joint_dynamics/joint_dynamics_system.js +11 -0
  19. package/dist/animation/joint_dynamics/joint_dynamics_system.js.map +1 -1
  20. package/dist/animation/joint_dynamics/solver.js +50 -12
  21. package/dist/animation/joint_dynamics/solver.js.map +1 -1
  22. package/dist/animation/joint_dynamics/types.js.map +1 -1
  23. package/dist/animation/skeleton.js +279 -55
  24. package/dist/animation/skeleton.js.map +1 -1
  25. package/dist/animation/skin_palette_atlas.js +252 -0
  26. package/dist/animation/skin_palette_atlas.js.map +1 -0
  27. package/dist/animation/spring/multi_chain_spring_system.js +298 -38
  28. package/dist/animation/spring/multi_chain_spring_system.js.map +1 -1
  29. package/dist/animation/spring/spring_chain.js +2 -0
  30. package/dist/animation/spring/spring_chain.js.map +1 -1
  31. package/dist/animation/spring/spring_collider.js +159 -21
  32. package/dist/animation/spring/spring_collider.js.map +1 -1
  33. package/dist/animation/spring/spring_particle.js +1 -0
  34. package/dist/animation/spring/spring_particle.js.map +1 -1
  35. package/dist/animation/spring/spring_solver.js +173 -0
  36. package/dist/animation/spring/spring_solver.js.map +1 -0
  37. package/dist/animation/spring/spring_system.js +249 -24
  38. package/dist/animation/spring/spring_system.js.map +1 -1
  39. package/dist/animation/spring_modifier.js +32 -1
  40. package/dist/animation/spring_modifier.js.map +1 -1
  41. package/dist/app/app.js +26 -0
  42. package/dist/app/app.js.map +1 -1
  43. package/dist/app/engine.js +86 -15
  44. package/dist/app/engine.js.map +1 -1
  45. package/dist/app/gamepad.js +191 -0
  46. package/dist/app/gamepad.js.map +1 -0
  47. package/dist/app/inputactions.js +271 -0
  48. package/dist/app/inputactions.js.map +1 -0
  49. package/dist/app/inputmgr.js +331 -22
  50. package/dist/app/inputmgr.js.map +1 -1
  51. package/dist/app/loading.js +138 -0
  52. package/dist/app/loading.js.map +1 -0
  53. package/dist/app/pipelinecache.js +209 -0
  54. package/dist/app/pipelinecache.js.map +1 -0
  55. package/dist/app/runtimescript.js +25 -0
  56. package/dist/app/runtimescript.js.map +1 -1
  57. package/dist/app/scriptingsystem.js +54 -0
  58. package/dist/app/scriptingsystem.js.map +1 -1
  59. package/dist/app/scriptregistry.js +7 -2
  60. package/dist/app/scriptregistry.js.map +1 -1
  61. package/dist/asset/asset_manifest.js +59 -0
  62. package/dist/asset/asset_manifest.js.map +1 -0
  63. package/dist/asset/asset_preload.js +258 -0
  64. package/dist/asset/asset_preload.js.map +1 -0
  65. package/dist/asset/assetmanager.js +117 -65
  66. package/dist/asset/assetmanager.js.map +1 -1
  67. package/dist/asset/loaders/ktx2/basis/LICENSE +201 -0
  68. package/dist/asset/loaders/ktx2/basis/basis_transcoder.js +2 -0
  69. package/dist/asset/loaders/ktx2/basis/basis_transcoder.wasm +0 -0
  70. package/dist/asset/loaders/ktx2/basis_location.js +17 -0
  71. package/dist/asset/loaders/ktx2/basis_location.js.map +1 -0
  72. package/dist/asset/loaders/ktx2/ktx2_loader.js +88 -0
  73. package/dist/asset/loaders/ktx2/ktx2_loader.js.map +1 -0
  74. package/dist/asset/loaders/ktx2/ktx2_targets.js +118 -0
  75. package/dist/asset/loaders/ktx2/ktx2_targets.js.map +1 -0
  76. package/dist/asset/loaders/ktx2/transcoder_pool.js +259 -0
  77. package/dist/asset/loaders/ktx2/transcoder_pool.js.map +1 -0
  78. package/dist/asset/mesh_lod_builder.js +104 -0
  79. package/dist/asset/mesh_lod_builder.js.map +1 -0
  80. package/dist/asset/mesh_settings.js +111 -0
  81. package/dist/asset/mesh_settings.js.map +1 -0
  82. package/dist/asset/meshopt_decoder.js +18 -0
  83. package/dist/asset/meshopt_decoder.js.map +1 -0
  84. package/dist/asset/meshopt_simplifier.js +26 -0
  85. package/dist/asset/meshopt_simplifier.js.map +1 -0
  86. package/dist/asset/model.js +171 -1
  87. package/dist/asset/model.js.map +1 -1
  88. package/dist/asset/texture_settings.js +231 -0
  89. package/dist/asset/texture_settings.js.map +1 -0
  90. package/dist/asset/zmsh_binary.js +131 -0
  91. package/dist/asset/zmsh_binary.js.map +1 -0
  92. package/dist/asset/zsdf_binary.js +111 -0
  93. package/dist/asset/zsdf_binary.js.map +1 -0
  94. package/dist/blitter/bilateralblur.js +1 -2
  95. package/dist/blitter/bilateralblur.js.map +1 -1
  96. package/dist/blitter/gaussianblur.js +1 -6
  97. package/dist/blitter/gaussianblur.js.map +1 -1
  98. package/dist/camera/base.js +31 -10
  99. package/dist/camera/base.js.map +1 -1
  100. package/dist/camera/camera.js +104 -178
  101. package/dist/camera/camera.js.map +1 -1
  102. package/dist/camera/follow.js +342 -0
  103. package/dist/camera/follow.js.map +1 -0
  104. package/dist/camera/fps.js +9 -7
  105. package/dist/camera/fps.js.map +1 -1
  106. package/dist/camera/orbit.js +46 -19
  107. package/dist/camera/orbit.js.map +1 -1
  108. package/dist/index.d.ts +25436 -15990
  109. package/dist/index.js +65 -11
  110. package/dist/index.js.map +1 -1
  111. package/dist/material/blinn.js +3 -0
  112. package/dist/material/blinn.js.map +1 -1
  113. package/dist/material/eye.js +1 -1
  114. package/dist/material/eye.js.map +1 -1
  115. package/dist/material/hair.js +2 -3
  116. package/dist/material/hair.js.map +1 -1
  117. package/dist/material/lambert.js +4 -1
  118. package/dist/material/lambert.js.map +1 -1
  119. package/dist/material/material.js +66 -4
  120. package/dist/material/material.js.map +1 -1
  121. package/dist/material/meshmaterial.js +118 -45
  122. package/dist/material/meshmaterial.js.map +1 -1
  123. package/dist/material/mixins/lightmodel/blinnphong.js +1 -1
  124. package/dist/material/mixins/lightmodel/blinnphong.js.map +1 -1
  125. package/dist/material/mixins/lightmodel/lambert.js +1 -1
  126. package/dist/material/mixins/lightmodel/lambert.js.map +1 -1
  127. package/dist/material/mixins/lightmodel/pbrblueprintmixin.js +34 -61
  128. package/dist/material/mixins/lightmodel/pbrblueprintmixin.js.map +1 -1
  129. package/dist/material/mixins/lightmodel/pbrmetallicroughness.js +16 -2
  130. package/dist/material/mixins/lightmodel/pbrmetallicroughness.js.map +1 -1
  131. package/dist/material/mixins/lightmodel/pbrspecularglossness.js +2 -1
  132. package/dist/material/mixins/lightmodel/pbrspecularglossness.js.map +1 -1
  133. package/dist/material/mixins/lit.js +191 -83
  134. package/dist/material/mixins/lit.js.map +1 -1
  135. package/dist/material/mixins/pbr/common.js +31 -206
  136. package/dist/material/mixins/pbr/common.js.map +1 -1
  137. package/dist/material/mtoon.js +1 -1
  138. package/dist/material/mtoon.js.map +1 -1
  139. package/dist/material/pbrmr.js +3 -0
  140. package/dist/material/pbrmr.js.map +1 -1
  141. package/dist/material/pbrsg.js +3 -0
  142. package/dist/material/pbrsg.js.map +1 -1
  143. package/dist/material/sdf_debug.js +78 -0
  144. package/dist/material/sdf_debug.js.map +1 -0
  145. package/dist/material/shader/helper.js +333 -191
  146. package/dist/material/shader/helper.js.map +1 -1
  147. package/dist/material/shader/terrain_blend.js +204 -43
  148. package/dist/material/shader/terrain_blend.js.map +1 -1
  149. package/dist/material/skin.js +331 -297
  150. package/dist/material/skin.js.map +1 -1
  151. package/dist/material/skinprofile.js +1058 -0
  152. package/dist/material/skinprofile.js.map +1 -0
  153. package/dist/material/sss.js +353 -0
  154. package/dist/material/sss.js.map +1 -0
  155. package/dist/material/sss_kernel.js +265 -0
  156. package/dist/material/sss_kernel.js.map +1 -0
  157. package/dist/material/sssprofile.js +879 -0
  158. package/dist/material/sssprofile.js.map +1 -0
  159. package/dist/material/subsurfaceprofile.js +4 -8
  160. package/dist/material/subsurfaceprofile.js.map +1 -1
  161. package/dist/material/terrain-cm.js +464 -188
  162. package/dist/material/terrain-cm.js.map +1 -1
  163. package/dist/material/unlit.js +3 -0
  164. package/dist/material/unlit.js.map +1 -1
  165. package/dist/material/water.js +1261 -1438
  166. package/dist/material/water.js.map +1 -1
  167. package/dist/node_modules/meshoptimizer/LICENSE +21 -0
  168. package/dist/node_modules/meshoptimizer/meshopt_decoder.js +197 -0
  169. package/dist/node_modules/meshoptimizer/meshopt_decoder.js.map +1 -0
  170. package/dist/node_modules/meshoptimizer/meshopt_simplifier.js +677 -0
  171. package/dist/node_modules/meshoptimizer/meshopt_simplifier.js.map +1 -0
  172. package/dist/physics/character.js +226 -0
  173. package/dist/physics/character.js.map +1 -0
  174. package/dist/physics/collider.js +209 -0
  175. package/dist/physics/collider.js.map +1 -0
  176. package/dist/physics/events.js +79 -0
  177. package/dist/physics/events.js.map +1 -0
  178. package/dist/physics/joint.js +272 -0
  179. package/dist/physics/joint.js.map +1 -0
  180. package/dist/physics/node_physics.js +234 -0
  181. package/dist/physics/node_physics.js.map +1 -0
  182. package/dist/physics/part.js +91 -0
  183. package/dist/physics/part.js.map +1 -0
  184. package/dist/physics/rigid_body.js +379 -0
  185. package/dist/physics/rigid_body.js.map +1 -0
  186. package/dist/physics/vehicle.js +335 -0
  187. package/dist/physics/vehicle.js.map +1 -0
  188. package/dist/physics/world.js +25 -0
  189. package/dist/physics/world.js.map +1 -0
  190. package/dist/posteffect/bloom.js +49 -14
  191. package/dist/posteffect/bloom.js.map +1 -1
  192. package/dist/posteffect/motionblur.js +106 -106
  193. package/dist/posteffect/motionblur.js.map +1 -1
  194. package/dist/posteffect/postsss.js +572 -0
  195. package/dist/posteffect/postsss.js.map +1 -0
  196. package/dist/posteffect/sao.js +2 -6
  197. package/dist/posteffect/sao.js.map +1 -1
  198. package/dist/posteffect/skinsss.js +605 -355
  199. package/dist/posteffect/skinsss.js.map +1 -1
  200. package/dist/posteffect/ssgi.js +91 -162
  201. package/dist/posteffect/ssgi.js.map +1 -1
  202. package/dist/posteffect/ssr.js +3 -11
  203. package/dist/posteffect/ssr.js.map +1 -1
  204. package/dist/posteffect/sss.js +4 -13
  205. package/dist/posteffect/sss.js.map +1 -1
  206. package/dist/posteffect/taa.js +1 -0
  207. package/dist/posteffect/taa.js.map +1 -1
  208. package/dist/render/abuffer_oit.js +3 -2
  209. package/dist/render/abuffer_oit.js.map +1 -1
  210. package/dist/render/clipmap.js +179 -64
  211. package/dist/render/clipmap.js.map +1 -1
  212. package/dist/render/cluster_light.js +958 -224
  213. package/dist/render/cluster_light.js.map +1 -1
  214. package/dist/render/cull_visitor.js +25 -5
  215. package/dist/render/cull_visitor.js.map +1 -1
  216. package/dist/render/debug_views.js +37 -0
  217. package/dist/render/debug_views.js.map +1 -0
  218. package/dist/render/depthpass.js +5 -1
  219. package/dist/render/depthpass.js.map +1 -1
  220. package/dist/render/drawable_mixin.js +53 -6
  221. package/dist/render/drawable_mixin.js.map +1 -1
  222. package/dist/render/dualdepthpeeling_oit.js +5 -5
  223. package/dist/render/dualdepthpeeling_oit.js.map +1 -1
  224. package/dist/render/envlight.js +196 -113
  225. package/dist/render/envlight.js.map +1 -1
  226. package/dist/render/fbm_wavegenerator.js +5 -10
  227. package/dist/render/fbm_wavegenerator.js.map +1 -1
  228. package/dist/render/fft_wavegenerator.js +247 -157
  229. package/dist/render/fft_wavegenerator.js.map +1 -1
  230. package/dist/render/gerstner_wavegenerator.js +16 -38
  231. package/dist/render/gerstner_wavegenerator.js.map +1 -1
  232. package/dist/render/gi/probe_volume.js +1334 -0
  233. package/dist/render/gi/probe_volume.js.map +1 -0
  234. package/dist/render/gi/scene_gi.js +282 -0
  235. package/dist/render/gi/scene_gi.js.map +1 -0
  236. package/dist/render/gi/voxel_atlas.js +198 -0
  237. package/dist/render/gi/voxel_atlas.js.map +1 -0
  238. package/dist/render/gi/voxel_lighting.js +652 -0
  239. package/dist/render/gi/voxel_lighting.js.map +1 -0
  240. package/dist/render/gi/voxel_scene.js +642 -0
  241. package/dist/render/gi/voxel_scene.js.map +1 -0
  242. package/dist/render/gi/voxelize_pass.js +223 -0
  243. package/dist/render/gi/voxelize_pass.js.map +1 -0
  244. package/dist/render/globalbindgroup_allocator.js +3 -2
  245. package/dist/render/globalbindgroup_allocator.js.map +1 -1
  246. package/dist/render/gpu_picking.js +9 -36
  247. package/dist/render/gpu_picking.js.map +1 -1
  248. package/dist/render/instance_culling.js +499 -0
  249. package/dist/render/instance_culling.js.map +1 -0
  250. package/dist/render/lightpass.js +19 -8
  251. package/dist/render/lightpass.js.map +1 -1
  252. package/dist/render/lod.js +46 -0
  253. package/dist/render/lod.js.map +1 -0
  254. package/dist/render/primitive.js +301 -9
  255. package/dist/render/primitive.js.map +1 -1
  256. package/dist/render/primitive_readback.js +209 -0
  257. package/dist/render/primitive_readback.js.map +1 -0
  258. package/dist/render/render_queue.js +162 -11
  259. package/dist/render/render_queue.js.map +1 -1
  260. package/dist/render/renderer.js +10 -7
  261. package/dist/render/renderer.js.map +1 -1
  262. package/dist/render/rendergraph/blackboard.js +14 -1
  263. package/dist/render/rendergraph/blackboard.js.map +1 -1
  264. package/dist/render/rendergraph/executor.js +136 -0
  265. package/dist/render/rendergraph/executor.js.map +1 -1
  266. package/dist/render/rendergraph/forward_plus_builder.js +272 -55
  267. package/dist/render/rendergraph/forward_plus_builder.js.map +1 -1
  268. package/dist/render/rendergraph/frame_graph_context.js +41 -0
  269. package/dist/render/rendergraph/frame_graph_context.js.map +1 -0
  270. package/dist/render/rendergraph/scene_render_context.js +31 -2
  271. package/dist/render/rendergraph/scene_render_context.js.map +1 -1
  272. package/dist/render/rendergraph/types.js.map +1 -1
  273. package/dist/render/renderpass.js +28 -5
  274. package/dist/render/renderpass.js.map +1 -1
  275. package/dist/render/sdf/box_allocator.js +98 -0
  276. package/dist/render/sdf/box_allocator.js.map +1 -0
  277. package/dist/render/sdf/global_sdf.js +865 -0
  278. package/dist/render/sdf/global_sdf.js.map +1 -0
  279. package/dist/render/sdf/scene_sdf.js +562 -0
  280. package/dist/render/sdf/scene_sdf.js.map +1 -0
  281. package/dist/render/sdf/sdf_atlas.js +227 -0
  282. package/dist/render/sdf/sdf_atlas.js.map +1 -0
  283. package/dist/render/sdf/sdf_programs.js +42 -0
  284. package/dist/render/sdf/sdf_programs.js.map +1 -0
  285. package/dist/render/sdf/sdf_view.js +199 -0
  286. package/dist/render/sdf/sdf_view.js.map +1 -0
  287. package/dist/render/sdf/waterline.js +610 -0
  288. package/dist/render/sdf/waterline.js.map +1 -0
  289. package/dist/render/shadow_mask_pass.js +142 -25
  290. package/dist/render/shadow_mask_pass.js.map +1 -1
  291. package/dist/render/shore_wave_generator.js +1193 -0
  292. package/dist/render/shore_wave_generator.js.map +1 -0
  293. package/dist/render/sky.js +516 -86
  294. package/dist/render/sky.js.map +1 -1
  295. package/dist/render/transmission_thickness_pass.js +477 -0
  296. package/dist/render/transmission_thickness_pass.js.map +1 -0
  297. package/dist/render/underwater.js +58 -158
  298. package/dist/render/underwater.js.map +1 -1
  299. package/dist/render/virtualtexture/virtual_texture.js +1214 -0
  300. package/dist/render/virtualtexture/virtual_texture.js.map +1 -0
  301. package/dist/render/volumetric_cloud/cloud_common.js +472 -0
  302. package/dist/render/volumetric_cloud/cloud_common.js.map +1 -0
  303. package/dist/render/volumetric_cloud/cloud_noise.js +189 -0
  304. package/dist/render/volumetric_cloud/cloud_noise.js.map +1 -0
  305. package/dist/render/volumetric_cloud/debug_view.js +131 -0
  306. package/dist/render/volumetric_cloud/debug_view.js.map +1 -0
  307. package/dist/render/volumetric_cloud/resources.js +380 -0
  308. package/dist/render/volumetric_cloud/resources.js.map +1 -0
  309. package/dist/render/volumetric_cloud/sky_cache.js +380 -0
  310. package/dist/render/volumetric_cloud/sky_cache.js.map +1 -0
  311. package/dist/render/volumetric_cloud/volumetric_cloud.js +318 -0
  312. package/dist/render/volumetric_cloud/volumetric_cloud.js.map +1 -0
  313. package/dist/render/water_caustics.js +134 -319
  314. package/dist/render/water_caustics.js.map +1 -1
  315. package/dist/render/water_foam.js +627 -0
  316. package/dist/render/water_foam.js.map +1 -0
  317. package/dist/render/water_interaction.js +1795 -0
  318. package/dist/render/water_interaction.js.map +1 -0
  319. package/dist/render/weightedblended_oit.js +3 -3
  320. package/dist/render/weightedblended_oit.js.map +1 -1
  321. package/dist/scene/basesprite.js +9 -4
  322. package/dist/scene/basesprite.js.map +1 -1
  323. package/dist/scene/batchgroup.js +108 -12
  324. package/dist/scene/batchgroup.js.map +1 -1
  325. package/dist/scene/environment.js +28 -7
  326. package/dist/scene/environment.js.map +1 -1
  327. package/dist/scene/foliage.js +1020 -0
  328. package/dist/scene/foliage.js.map +1 -0
  329. package/dist/scene/foliage_buckets.js +147 -0
  330. package/dist/scene/foliage_buckets.js.map +1 -0
  331. package/dist/scene/foliage_mask.js +358 -0
  332. package/dist/scene/foliage_mask.js.map +1 -0
  333. package/dist/scene/hair.js +15 -4
  334. package/dist/scene/hair.js.map +1 -1
  335. package/dist/scene/light.js +179 -13
  336. package/dist/scene/light.js.map +1 -1
  337. package/dist/scene/mesh.js +327 -45
  338. package/dist/scene/mesh.js.map +1 -1
  339. package/dist/scene/meshdrawable.js +6 -0
  340. package/dist/scene/meshdrawable.js.map +1 -1
  341. package/dist/scene/msdftext.js +9 -3
  342. package/dist/scene/msdftext.js.map +1 -1
  343. package/dist/scene/msdftextsprite.js +9 -3
  344. package/dist/scene/msdftextsprite.js.map +1 -1
  345. package/dist/scene/particlesys.js +8 -2
  346. package/dist/scene/particlesys.js.map +1 -1
  347. package/dist/scene/physics_settings.js +157 -0
  348. package/dist/scene/physics_settings.js.map +1 -0
  349. package/dist/scene/scene.js +190 -44
  350. package/dist/scene/scene.js.map +1 -1
  351. package/dist/scene/scene_node.js +147 -6
  352. package/dist/scene/scene_node.js.map +1 -1
  353. package/dist/scene/terrain-cm/bladegrassmaterial.js +735 -0
  354. package/dist/scene/terrain-cm/bladegrassmaterial.js.map +1 -0
  355. package/dist/scene/terrain-cm/grass.js +881 -42
  356. package/dist/scene/terrain-cm/grass.js.map +1 -1
  357. package/dist/scene/terrain-cm/grass_gpu.js +929 -0
  358. package/dist/scene/terrain-cm/grass_gpu.js.map +1 -0
  359. package/dist/scene/terrain-cm/grassmaterial.js +180 -9
  360. package/dist/scene/terrain-cm/grassmaterial.js.map +1 -1
  361. package/dist/scene/terrain-cm/terrain-cm.js +465 -36
  362. package/dist/scene/terrain-cm/terrain-cm.js.map +1 -1
  363. package/dist/scene/terrain-cm/terrain_gi_albedo.js +257 -0
  364. package/dist/scene/terrain-cm/terrain_gi_albedo.js.map +1 -0
  365. package/dist/scene/terrain-cm/terrain_rvt.js +395 -0
  366. package/dist/scene/terrain-cm/terrain_rvt.js.map +1 -0
  367. package/dist/scene/update_queue.js +54 -0
  368. package/dist/scene/update_queue.js.map +1 -0
  369. package/dist/scene/water.js +633 -268
  370. package/dist/scene/water.js.map +1 -1
  371. package/dist/scene/water_surface_sampler.js +324 -0
  372. package/dist/scene/water_surface_sampler.js.map +1 -0
  373. package/dist/scene/wind.js +317 -0
  374. package/dist/scene/wind.js.map +1 -0
  375. package/dist/shaders/atmosphere.js +388 -166
  376. package/dist/shaders/atmosphere.js.map +1 -1
  377. package/dist/shaders/fog.js +100 -32
  378. package/dist/shaders/fog.js.map +1 -1
  379. package/dist/shaders/gi.js +365 -0
  380. package/dist/shaders/gi.js.map +1 -0
  381. package/dist/shaders/ltc_rect.js +202 -0
  382. package/dist/shaders/ltc_rect.js.map +1 -0
  383. package/dist/shaders/misc.js +1 -10
  384. package/dist/shaders/misc.js.map +1 -1
  385. package/dist/shaders/noise.js +5 -1
  386. package/dist/shaders/noise.js.map +1 -1
  387. package/dist/shaders/probes.js +309 -0
  388. package/dist/shaders/probes.js.map +1 -0
  389. package/dist/shaders/sdf.js +537 -0
  390. package/dist/shaders/sdf.js.map +1 -0
  391. package/dist/shaders/shadow.js +104 -70
  392. package/dist/shaders/shadow.js.map +1 -1
  393. package/dist/shaders/skin_brdf.js +243 -0
  394. package/dist/shaders/skin_brdf.js.map +1 -0
  395. package/dist/shaders/ssgi.js +63 -0
  396. package/dist/shaders/ssgi.js.map +1 -0
  397. package/dist/shaders/ssgi_reprojection.js +118 -0
  398. package/dist/shaders/ssgi_reprojection.js.map +1 -0
  399. package/dist/shaders/ssr.js +6 -159
  400. package/dist/shaders/ssr.js.map +1 -1
  401. package/dist/shaders/temporal.js +38 -27
  402. package/dist/shaders/temporal.js.map +1 -1
  403. package/dist/shaders/water.js +32 -82
  404. package/dist/shaders/water.js.map +1 -1
  405. package/dist/shaders/water_medium.js +7 -21
  406. package/dist/shaders/water_medium.js.map +1 -1
  407. package/dist/shadow/dom.js +110 -19
  408. package/dist/shadow/dom.js.map +1 -1
  409. package/dist/shadow/esm.js +3 -3
  410. package/dist/shadow/esm.js.map +1 -1
  411. package/dist/shadow/pcf_opt.js +15 -48
  412. package/dist/shadow/pcf_opt.js.map +1 -1
  413. package/dist/shadow/pcf_pd.js +15 -53
  414. package/dist/shadow/pcf_pd.js.map +1 -1
  415. package/dist/shadow/pcss.js +34 -9
  416. package/dist/shadow/pcss.js.map +1 -1
  417. package/dist/shadow/shadow_impl.js +3 -8
  418. package/dist/shadow/shadow_impl.js.map +1 -1
  419. package/dist/shadow/shadow_region.js +40 -2
  420. package/dist/shadow/shadow_region.js.map +1 -1
  421. package/dist/shadow/shadowmapper.js +93 -53
  422. package/dist/shadow/shadowmapper.js.map +1 -1
  423. package/dist/shadow/ssm.js +18 -72
  424. package/dist/shadow/ssm.js.map +1 -1
  425. package/dist/shadow/vsm.js +3 -3
  426. package/dist/shadow/vsm.js.map +1 -1
  427. package/dist/shapes/shape.js +44 -1
  428. package/dist/shapes/shape.js.map +1 -1
  429. package/dist/utility/buoyancy.js +287 -0
  430. package/dist/utility/buoyancy.js.map +1 -0
  431. package/dist/utility/physical.js +10 -1
  432. package/dist/utility/physical.js.map +1 -1
  433. package/dist/utility/pmrem.js +17 -43
  434. package/dist/utility/pmrem.js.map +1 -1
  435. package/dist/utility/sdf/bake.js +435 -0
  436. package/dist/utility/sdf/bake.js.map +1 -0
  437. package/dist/utility/sdf/bvh.js +576 -0
  438. package/dist/utility/sdf/bvh.js.map +1 -0
  439. package/dist/utility/serialization/manager.js +34 -6
  440. package/dist/utility/serialization/manager.js.map +1 -1
  441. package/dist/utility/serialization/scene/animation.js +46 -5
  442. package/dist/utility/serialization/scene/animation.js.map +1 -1
  443. package/dist/utility/serialization/scene/batch.js +11 -4
  444. package/dist/utility/serialization/scene/batch.js.map +1 -1
  445. package/dist/utility/serialization/scene/camera.js +87 -254
  446. package/dist/utility/serialization/scene/camera.js.map +1 -1
  447. package/dist/utility/serialization/scene/cloth.js +25 -0
  448. package/dist/utility/serialization/scene/cloth.js.map +1 -0
  449. package/dist/utility/serialization/scene/common.js +14 -6
  450. package/dist/utility/serialization/scene/common.js.map +1 -1
  451. package/dist/utility/serialization/scene/foliage.js +821 -0
  452. package/dist/utility/serialization/scene/foliage.js.map +1 -0
  453. package/dist/utility/serialization/scene/hair.js +11 -4
  454. package/dist/utility/serialization/scene/hair.js.map +1 -1
  455. package/dist/utility/serialization/scene/light.js +115 -7
  456. package/dist/utility/serialization/scene/light.js.map +1 -1
  457. package/dist/utility/serialization/scene/material.js +388 -220
  458. package/dist/utility/serialization/scene/material.js.map +1 -1
  459. package/dist/utility/serialization/scene/mesh.js +69 -4
  460. package/dist/utility/serialization/scene/mesh.js.map +1 -1
  461. package/dist/utility/serialization/scene/node.js +140 -5
  462. package/dist/utility/serialization/scene/node.js.map +1 -1
  463. package/dist/utility/serialization/scene/node_physics.js +1318 -0
  464. package/dist/utility/serialization/scene/node_physics.js.map +1 -0
  465. package/dist/utility/serialization/scene/particle.js +11 -4
  466. package/dist/utility/serialization/scene/particle.js.map +1 -1
  467. package/dist/utility/serialization/scene/physics.js +120 -0
  468. package/dist/utility/serialization/scene/physics.js.map +1 -0
  469. package/dist/utility/serialization/scene/primitive.js +124 -10
  470. package/dist/utility/serialization/scene/primitive.js.map +1 -1
  471. package/dist/utility/serialization/scene/scene.js +1687 -51
  472. package/dist/utility/serialization/scene/scene.js.map +1 -1
  473. package/dist/utility/serialization/scene/sprite.js +11 -4
  474. package/dist/utility/serialization/scene/sprite.js.map +1 -1
  475. package/dist/utility/serialization/scene/terrain.js +163 -33
  476. package/dist/utility/serialization/scene/terrain.js.map +1 -1
  477. package/dist/utility/serialization/scene/text.js +11 -4
  478. package/dist/utility/serialization/scene/text.js.map +1 -1
  479. package/dist/utility/serialization/scene/water.js +1543 -264
  480. package/dist/utility/serialization/scene/water.js.map +1 -1
  481. package/dist/utility/serialization/types.js.map +1 -1
  482. package/dist/utility/shprojector.js +10 -22
  483. package/dist/utility/shprojector.js.map +1 -1
  484. package/dist/utility/textures/foam.js +170 -0
  485. package/dist/utility/textures/foam.js.map +1 -0
  486. package/dist/utility/textures/ggxlut.js +17 -43
  487. package/dist/utility/textures/ggxlut.js.map +1 -1
  488. package/dist/utility/textures/ltcdata.js +4 -4
  489. package/dist/utility/textures/ltcdata.js.map +1 -1
  490. package/dist/utility/textures/ltclut.js +16 -6
  491. package/dist/utility/textures/ltclut.js.map +1 -1
  492. package/dist/utility/unsupported.js +24 -0
  493. package/dist/utility/unsupported.js.map +1 -0
  494. package/dist/values.js +13 -1
  495. package/dist/values.js.map +1 -1
  496. package/package.json +25 -12
  497. package/src/asset/loaders/ktx2/basis/LICENSE +201 -0
  498. package/src/asset/loaders/ktx2/basis/basis_transcoder.js +2 -0
  499. package/src/asset/loaders/ktx2/basis/basis_transcoder.wasm +0 -0
  500. package/src/asset/meshoptimizer/LICENSE +21 -0
  501. package/dist/animation/joint_dynamics/convex_collider.js +0 -320
  502. package/dist/animation/joint_dynamics/convex_collider.js.map +0 -1
@@ -1,5 +1,11 @@
1
1
  import { Vector3 } from '@zephyr3d/base';
2
2
 
3
+ const COLLISION_DISTANCE_EPSILON_SQ = 1e-12;
4
+ function getCapsuleAxisFallbackNormal(axis, result) {
5
+ const reference = Math.abs(axis.z) < 0.9 ? Vector3.axisPZ() : Vector3.axisPX();
6
+ Vector3.sub(reference, Vector3.scale(axis, Vector3.dot(reference, axis), result), result);
7
+ return result.inplaceNormalize();
8
+ }
3
9
  /**
4
10
  * Creates a sphere collider
5
11
  * @param centerOrOffset - Center position in world space, or local offset if node is provided
@@ -105,21 +111,64 @@ import { Vector3 } from '@zephyr3d/base';
105
111
  };
106
112
  }
107
113
  }
114
+ /**
115
+ * Creates an oriented box collider.
116
+ * @param centerOrOffset - Center position in world space, or local offset if node is provided
117
+ * @param halfExtents - Local/world half extents of the box
118
+ * @param node - Optional scene node to attach to
119
+ *
120
+ * @public
121
+ */ function createBoxCollider(centerOrOffset, halfExtents, node) {
122
+ const localExtents = new Vector3(Math.max(0.0001, Math.abs(halfExtents.x)), Math.max(0.0001, Math.abs(halfExtents.y)), Math.max(0.0001, Math.abs(halfExtents.z)));
123
+ if (node) {
124
+ const worldMatrix = node.worldMatrix;
125
+ const center = worldMatrix.transformPointAffine(centerOrOffset, new Vector3());
126
+ const axes = createWorldAxes(worldMatrix);
127
+ const scales = getAxisScales(worldMatrix);
128
+ return {
129
+ type: 'box',
130
+ center,
131
+ halfExtents: new Vector3(localExtents.x * scales.x, localExtents.y * scales.y, localExtents.z * scales.z),
132
+ axes,
133
+ localOffset: centerOrOffset.clone(),
134
+ localHalfExtents: localExtents,
135
+ node,
136
+ enabled: true
137
+ };
138
+ }
139
+ return {
140
+ type: 'box',
141
+ center: centerOrOffset.clone(),
142
+ halfExtents: localExtents,
143
+ axes: [
144
+ Vector3.axisPX(),
145
+ Vector3.axisPY(),
146
+ Vector3.axisPZ()
147
+ ],
148
+ node: null,
149
+ enabled: true
150
+ };
151
+ }
108
152
  /**
109
153
  * Resolves collision between a particle and a sphere collider
110
154
  * @returns true if collision occurred
111
155
  *
112
156
  * @public
113
- */ function resolveSphereCollision(particlePos, collider) {
157
+ */ function resolveSphereCollision(particlePos, collider, particleRadius = 0) {
114
158
  const toParticle = Vector3.sub(particlePos, collider.center, new Vector3());
115
159
  const distSq = toParticle.magnitudeSq;
116
- const radiusSq = collider.radius * collider.radius;
117
- if (distSq < radiusSq && distSq > 0.0001) {
160
+ const contactRadius = collider.radius + Math.max(0, particleRadius);
161
+ const radiusSq = contactRadius * contactRadius;
162
+ if (distSq < radiusSq) {
118
163
  // Particle is inside sphere, push it out
119
- const dist = Math.sqrt(distSq);
120
- const penetration = collider.radius - dist;
164
+ const dist = distSq > COLLISION_DISTANCE_EPSILON_SQ ? Math.sqrt(distSq) : 0;
165
+ const penetration = contactRadius - dist;
121
166
  // Push particle to sphere surface
122
- Vector3.normalize(toParticle, toParticle);
167
+ if (dist > 0) {
168
+ toParticle.scaleBy(1 / dist);
169
+ } else {
170
+ toParticle.setXYZ(0, 1, 0);
171
+ }
123
172
  toParticle.scaleBy(penetration);
124
173
  Vector3.add(particlePos, toParticle, particlePos);
125
174
  return true;
@@ -131,7 +180,8 @@ import { Vector3 } from '@zephyr3d/base';
131
180
  * @returns true if collision occurred
132
181
  *
133
182
  * @public
134
- */ function resolveCapsuleCollision(particlePos, collider) {
183
+ */ function resolveCapsuleCollision(particlePos, collider, particleRadius = 0) {
184
+ const contactRadius = collider.radius + Math.max(0, particleRadius);
135
185
  // Find closest point on capsule axis
136
186
  const axis = Vector3.sub(collider.end, collider.start, new Vector3());
137
187
  const axisLength = axis.magnitude;
@@ -139,11 +189,15 @@ import { Vector3 } from '@zephyr3d/base';
139
189
  // Degenerate capsule, treat as sphere
140
190
  const toParticle = Vector3.sub(particlePos, collider.start, new Vector3());
141
191
  const distSq = toParticle.magnitudeSq;
142
- const radiusSq = collider.radius * collider.radius;
143
- if (distSq < radiusSq && distSq > 0.0001) {
144
- const dist = Math.sqrt(distSq);
145
- const penetration = collider.radius - dist;
146
- Vector3.normalize(toParticle, toParticle);
192
+ const radiusSq = contactRadius * contactRadius;
193
+ if (distSq < radiusSq) {
194
+ const dist = distSq > COLLISION_DISTANCE_EPSILON_SQ ? Math.sqrt(distSq) : 0;
195
+ const penetration = contactRadius - dist;
196
+ if (dist > 0) {
197
+ toParticle.scaleBy(1 / dist);
198
+ } else {
199
+ toParticle.setXYZ(0, 1, 0);
200
+ }
147
201
  toParticle.scaleBy(penetration);
148
202
  Vector3.add(particlePos, toParticle, particlePos);
149
203
  return true;
@@ -160,11 +214,15 @@ import { Vector3 } from '@zephyr3d/base';
160
214
  // Check distance from closest point
161
215
  const toParticleFromAxis = Vector3.sub(particlePos, closestPoint, new Vector3());
162
216
  const distSq = toParticleFromAxis.magnitudeSq;
163
- const radiusSq = collider.radius * collider.radius;
164
- if (distSq < radiusSq && distSq > 0.0001) {
165
- const dist = Math.sqrt(distSq);
166
- const penetration = collider.radius - dist;
167
- Vector3.normalize(toParticleFromAxis, toParticleFromAxis);
217
+ const radiusSq = contactRadius * contactRadius;
218
+ if (distSq < radiusSq) {
219
+ const dist = distSq > COLLISION_DISTANCE_EPSILON_SQ ? Math.sqrt(distSq) : 0;
220
+ const penetration = contactRadius - dist;
221
+ if (dist > 0) {
222
+ toParticleFromAxis.scaleBy(1 / dist);
223
+ } else {
224
+ getCapsuleAxisFallbackNormal(axis, toParticleFromAxis);
225
+ }
168
226
  toParticleFromAxis.scaleBy(penetration);
169
227
  Vector3.add(particlePos, toParticleFromAxis, particlePos);
170
228
  return true;
@@ -176,17 +234,60 @@ import { Vector3 } from '@zephyr3d/base';
176
234
  * @returns true if collision occurred
177
235
  *
178
236
  * @public
179
- */ function resolvePlaneCollision(particlePos, collider) {
237
+ */ function resolvePlaneCollision(particlePos, collider, particleRadius = 0) {
180
238
  const toParticle = Vector3.sub(particlePos, collider.point, new Vector3());
181
239
  const distance = Vector3.dot(toParticle, collider.normal);
182
- if (distance < 0) {
240
+ const contactDistance = Math.max(0, particleRadius);
241
+ if (distance < contactDistance) {
183
242
  // Particle is below plane, push it up
184
- const correction = Vector3.scale(collider.normal, -distance, new Vector3());
243
+ const correction = Vector3.scale(collider.normal, contactDistance - distance, new Vector3());
185
244
  Vector3.add(particlePos, correction, particlePos);
186
245
  return true;
187
246
  }
188
247
  return false;
189
248
  }
249
+ /**
250
+ * Resolves collision between a particle and an oriented box collider.
251
+ * @returns true if collision occurred
252
+ *
253
+ * @public
254
+ */ function resolveBoxCollision(particlePos, collider, particleRadius = 0) {
255
+ const delta = Vector3.sub(particlePos, collider.center, new Vector3());
256
+ const local = new Vector3(Vector3.dot(delta, collider.axes[0]), Vector3.dot(delta, collider.axes[1]), Vector3.dot(delta, collider.axes[2]));
257
+ const radius = Math.max(0, particleRadius);
258
+ const inside = Math.abs(local.x) <= collider.halfExtents.x && Math.abs(local.y) <= collider.halfExtents.y && Math.abs(local.z) <= collider.halfExtents.z;
259
+ if (!inside) {
260
+ if (radius <= 0) {
261
+ return false;
262
+ }
263
+ const closest = new Vector3(Math.max(-collider.halfExtents.x, Math.min(collider.halfExtents.x, local.x)), Math.max(-collider.halfExtents.y, Math.min(collider.halfExtents.y, local.y)), Math.max(-collider.halfExtents.z, Math.min(collider.halfExtents.z, local.z)));
264
+ const fromClosest = Vector3.sub(local, closest, new Vector3());
265
+ const distanceSq = fromClosest.magnitudeSq;
266
+ if (distanceSq >= radius * radius || distanceSq <= COLLISION_DISTANCE_EPSILON_SQ) {
267
+ return false;
268
+ }
269
+ const distance = Math.sqrt(distanceSq);
270
+ fromClosest.scaleBy((radius - distance) / distance);
271
+ Vector3.add(particlePos, Vector3.add(Vector3.scale(collider.axes[0], fromClosest.x, new Vector3()), Vector3.add(Vector3.scale(collider.axes[1], fromClosest.y, new Vector3()), Vector3.scale(collider.axes[2], fromClosest.z, new Vector3()), new Vector3()), new Vector3()), particlePos);
272
+ return true;
273
+ }
274
+ const penetration = new Vector3(collider.halfExtents.x - Math.abs(local.x) + radius, collider.halfExtents.y - Math.abs(local.y) + radius, collider.halfExtents.z - Math.abs(local.z) + radius);
275
+ let axis = 0;
276
+ let minPenetration = penetration.x;
277
+ if (penetration.y < minPenetration) {
278
+ axis = 1;
279
+ minPenetration = penetration.y;
280
+ }
281
+ if (penetration.z < minPenetration) {
282
+ axis = 2;
283
+ minPenetration = penetration.z;
284
+ }
285
+ const localAxis = axis === 0 ? local.x : axis === 1 ? local.y : local.z;
286
+ const sign = localAxis < 0 ? -1 : 1;
287
+ const correction = Vector3.scale(collider.axes[axis], minPenetration * sign, new Vector3());
288
+ Vector3.add(particlePos, correction, particlePos);
289
+ return true;
290
+ }
190
291
  /**
191
292
  * Updates collider position from its associated node
192
293
  *
@@ -256,8 +357,45 @@ import { Vector3 } from '@zephyr3d/base';
256
357
  }
257
358
  break;
258
359
  }
360
+ case 'box':
361
+ {
362
+ const box = collider;
363
+ if (box.localOffset) {
364
+ worldMatrix.transformPointAffine(box.localOffset, box.center);
365
+ } else {
366
+ box.center.x = worldMatrix.m03;
367
+ box.center.y = worldMatrix.m13;
368
+ box.center.z = worldMatrix.m23;
369
+ }
370
+ const axes = createWorldAxes(worldMatrix);
371
+ box.axes[0].set(axes[0]);
372
+ box.axes[1].set(axes[1]);
373
+ box.axes[2].set(axes[2]);
374
+ if (box.localHalfExtents) {
375
+ const scales = getAxisScales(worldMatrix);
376
+ box.halfExtents.setXYZ(box.localHalfExtents.x * scales.x, box.localHalfExtents.y * scales.y, box.localHalfExtents.z * scales.z);
377
+ }
378
+ break;
379
+ }
259
380
  }
260
381
  }
382
+ function createWorldAxes(worldMatrix) {
383
+ const x = worldMatrix.transformVectorAffine(Vector3.axisPX(), new Vector3()).inplaceNormalize();
384
+ const y = worldMatrix.transformVectorAffine(Vector3.axisPY(), new Vector3()).inplaceNormalize();
385
+ const z = worldMatrix.transformVectorAffine(Vector3.axisPZ(), new Vector3()).inplaceNormalize();
386
+ return [
387
+ x,
388
+ y,
389
+ z
390
+ ];
391
+ }
392
+ function getAxisScales(worldMatrix) {
393
+ return {
394
+ x: Math.max(1e-6, worldMatrix.transformVectorAffine(Vector3.axisPX(), new Vector3()).magnitude),
395
+ y: Math.max(1e-6, worldMatrix.transformVectorAffine(Vector3.axisPY(), new Vector3()).magnitude),
396
+ z: Math.max(1e-6, worldMatrix.transformVectorAffine(Vector3.axisPZ(), new Vector3()).magnitude)
397
+ };
398
+ }
261
399
  function getUniformScale(worldMatrix) {
262
400
  const sx = worldMatrix.transformVectorAffine(Vector3.axisPX(), new Vector3()).magnitude;
263
401
  const sy = worldMatrix.transformVectorAffine(Vector3.axisPY(), new Vector3()).magnitude;
@@ -274,5 +412,5 @@ function getPerpendicularScale(worldMatrix, axisLocal) {
274
412
  return Math.max(1e-6, (su + sv) * 0.5);
275
413
  }
276
414
 
277
- export { createCapsuleCollider, createPlaneCollider, createSphereCollider, resolveCapsuleCollision, resolvePlaneCollision, resolveSphereCollision, updateColliderFromNode };
415
+ export { createBoxCollider, createCapsuleCollider, createPlaneCollider, createSphereCollider, resolveBoxCollision, resolveCapsuleCollision, resolvePlaneCollision, resolveSphereCollision, updateColliderFromNode };
278
416
  //# sourceMappingURL=spring_collider.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"spring_collider.js","sources":["../../../src/animation/spring/spring_collider.ts"],"sourcesContent":["import type { Nullable } from '@zephyr3d/base';\r\nimport { Vector3 } from '@zephyr3d/base';\r\nimport type { SceneNode } from '../../scene/scene_node';\r\n\r\n/**\r\n * Base interface for spring collision shapes\r\n *\r\n * @public\r\n */\r\nexport interface SpringCollider {\r\n /** Type of collider */\r\n type: 'sphere' | 'capsule' | 'plane';\r\n /** Associated scene node (optional, for dynamic colliders) */\r\n node?: Nullable<SceneNode>;\r\n /** Whether this collider is enabled */\r\n enabled: boolean;\r\n}\r\n\r\n/**\r\n * Sphere collider for spring collision detection\r\n *\r\n * @public\r\n */\r\nexport interface SphereCollider extends SpringCollider {\r\n type: 'sphere';\r\n /** Center position in world space */\r\n center: Vector3;\r\n /** Radius of the sphere */\r\n radius: number;\r\n /** Authoring-space radius before node scaling (if node is set) */\r\n localRadius?: number;\r\n /** Baseline world scale captured at creation for backward compatibility */\r\n localRadiusScaleRef?: number;\r\n /** Local offset from node (if node is set) */\r\n localOffset?: Vector3;\r\n}\r\n\r\n/**\r\n * Capsule collider for spring collision detection\r\n *\r\n * @public\r\n */\r\nexport interface CapsuleCollider extends SpringCollider {\r\n type: 'capsule';\r\n /** Start point of the capsule axis in world space */\r\n start: Vector3;\r\n /** End point of the capsule axis in world space */\r\n end: Vector3;\r\n /** Radius of the capsule */\r\n radius: number;\r\n /** Authoring-space radius before node scaling (if node is set) */\r\n localRadius?: number;\r\n /** Baseline perpendicular scale captured at creation for backward compatibility */\r\n localRadiusScaleRef?: number;\r\n /** Local start offset from node (if node is set) */\r\n localStartOffset?: Vector3;\r\n /** Local end offset from node (if node is set) */\r\n localEndOffset?: Vector3;\r\n}\r\n\r\n/**\r\n * Plane collider for spring collision detection\r\n *\r\n * @public\r\n */\r\nexport interface PlaneCollider extends SpringCollider {\r\n type: 'plane';\r\n /** Point on the plane in world space */\r\n point: Vector3;\r\n /** Normal vector of the plane (should be normalized) */\r\n normal: Vector3;\r\n /** Local point offset from node (if node is set) */\r\n localPointOffset?: Vector3;\r\n /** Local normal direction (if node is set) */\r\n localNormal?: Vector3;\r\n}\r\n\r\n/**\r\n * Creates a sphere collider\r\n * @param centerOrOffset - Center position in world space, or local offset if node is provided\r\n * @param radius - Radius of the sphere\r\n * @param node - Optional scene node to attach to (if provided, centerOrOffset is treated as local offset)\r\n *\r\n * @public\r\n */\r\nexport function createSphereCollider(\r\n centerOrOffset: Vector3,\r\n radius: number,\r\n node?: SceneNode\r\n): SphereCollider {\r\n if (node) {\r\n // If node is provided, treat centerOrOffset as local offset\r\n const worldMatrix = node.worldMatrix;\r\n const worldCenter = worldMatrix.transformPointAffine(centerOrOffset, new Vector3());\r\n\r\n return {\r\n type: 'sphere',\r\n center: worldCenter,\r\n radius,\r\n localRadius: radius,\r\n localRadiusScaleRef: getUniformScale(worldMatrix),\r\n node,\r\n enabled: true,\r\n localOffset: centerOrOffset.clone()\r\n };\r\n } else {\r\n // No node, use as world position\r\n return {\r\n type: 'sphere',\r\n center: centerOrOffset.clone(),\r\n radius,\r\n node: null,\r\n enabled: true\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * Creates a capsule collider\r\n * @param startOrOffset - Start point in world space, or local offset if node is provided\r\n * @param endOrOffset - End point in world space, or local offset if node is provided\r\n * @param radius - Radius of the capsule\r\n * @param node - Optional scene node to attach to (if provided, offsets are treated as local)\r\n *\r\n * @public\r\n */\r\nexport function createCapsuleCollider(\r\n startOrOffset: Vector3,\r\n endOrOffset: Vector3,\r\n radius: number,\r\n node?: SceneNode\r\n): CapsuleCollider {\r\n if (node) {\r\n // If node is provided, treat as local offsets\r\n const worldMatrix = node.worldMatrix;\r\n const worldStart = worldMatrix.transformPointAffine(startOrOffset, new Vector3());\r\n const worldEnd = worldMatrix.transformPointAffine(endOrOffset, new Vector3());\r\n\r\n return {\r\n type: 'capsule',\r\n start: worldStart,\r\n end: worldEnd,\r\n radius,\r\n localRadius: radius,\r\n localRadiusScaleRef: getPerpendicularScale(\r\n worldMatrix,\r\n Vector3.sub(endOrOffset, startOrOffset, new Vector3())\r\n ),\r\n node,\r\n enabled: true,\r\n localStartOffset: startOrOffset.clone(),\r\n localEndOffset: endOrOffset.clone()\r\n };\r\n } else {\r\n // No node, use as world positions\r\n return {\r\n type: 'capsule',\r\n start: startOrOffset.clone(),\r\n end: endOrOffset.clone(),\r\n radius,\r\n node: null,\r\n enabled: true\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * Creates a plane collider\r\n * @param pointOrOffset - Point on plane in world space, or local offset if node is provided\r\n * @param normal - Normal vector (will be normalized)\r\n * @param node - Optional scene node to attach to (if provided, pointOrOffset is treated as local offset)\r\n *\r\n * @public\r\n */\r\nexport function createPlaneCollider(\r\n pointOrOffset: Vector3,\r\n normal: Vector3,\r\n node?: SceneNode\r\n): PlaneCollider {\r\n const normalizedNormal = new Vector3();\r\n Vector3.normalize(normal, normalizedNormal);\r\n\r\n if (node) {\r\n // If node is provided, treat as local offset\r\n const worldMatrix = node.worldMatrix;\r\n const worldPoint = worldMatrix.transformPointAffine(pointOrOffset, new Vector3());\r\n\r\n return {\r\n type: 'plane',\r\n point: worldPoint,\r\n normal: normalizedNormal.clone(),\r\n node,\r\n enabled: true,\r\n localPointOffset: pointOrOffset.clone(),\r\n localNormal: normalizedNormal.clone()\r\n };\r\n } else {\r\n // No node, use as world position\r\n return {\r\n type: 'plane',\r\n point: pointOrOffset.clone(),\r\n normal: normalizedNormal,\r\n node: null,\r\n enabled: true\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * Resolves collision between a particle and a sphere collider\r\n * @returns true if collision occurred\r\n *\r\n * @public\r\n */\r\nexport function resolveSphereCollision(particlePos: Vector3, collider: SphereCollider): boolean {\r\n const toParticle = Vector3.sub(particlePos, collider.center, new Vector3());\r\n const distSq = toParticle.magnitudeSq;\r\n const radiusSq = collider.radius * collider.radius;\r\n\r\n if (distSq < radiusSq && distSq > 0.0001) {\r\n // Particle is inside sphere, push it out\r\n const dist = Math.sqrt(distSq);\r\n const penetration = collider.radius - dist;\r\n\r\n // Push particle to sphere surface\r\n Vector3.normalize(toParticle, toParticle);\r\n toParticle.scaleBy(penetration);\r\n Vector3.add(particlePos, toParticle, particlePos);\r\n\r\n return true;\r\n }\r\n\r\n return false;\r\n}\r\n\r\n/**\r\n * Resolves collision between a particle and a capsule collider\r\n * @returns true if collision occurred\r\n *\r\n * @public\r\n */\r\nexport function resolveCapsuleCollision(particlePos: Vector3, collider: CapsuleCollider): boolean {\r\n // Find closest point on capsule axis\r\n const axis = Vector3.sub(collider.end, collider.start, new Vector3());\r\n const axisLength = axis.magnitude;\r\n\r\n if (axisLength < 0.0001) {\r\n // Degenerate capsule, treat as sphere\r\n const toParticle = Vector3.sub(particlePos, collider.start, new Vector3());\r\n const distSq = toParticle.magnitudeSq;\r\n const radiusSq = collider.radius * collider.radius;\r\n\r\n if (distSq < radiusSq && distSq > 0.0001) {\r\n const dist = Math.sqrt(distSq);\r\n const penetration = collider.radius - dist;\r\n Vector3.normalize(toParticle, toParticle);\r\n toParticle.scaleBy(penetration);\r\n Vector3.add(particlePos, toParticle, particlePos);\r\n return true;\r\n }\r\n return false;\r\n }\r\n\r\n Vector3.normalize(axis, axis);\r\n\r\n const toParticle = Vector3.sub(particlePos, collider.start, new Vector3());\r\n const projection = Vector3.dot(toParticle, axis);\r\n\r\n // Clamp projection to capsule length\r\n const t = Math.max(0, Math.min(axisLength, projection));\r\n\r\n // Closest point on capsule axis\r\n const closestPoint = Vector3.add(collider.start, Vector3.scale(axis, t, new Vector3()), new Vector3());\r\n\r\n // Check distance from closest point\r\n const toParticleFromAxis = Vector3.sub(particlePos, closestPoint, new Vector3());\r\n const distSq = toParticleFromAxis.magnitudeSq;\r\n const radiusSq = collider.radius * collider.radius;\r\n\r\n if (distSq < radiusSq && distSq > 0.0001) {\r\n const dist = Math.sqrt(distSq);\r\n const penetration = collider.radius - dist;\r\n Vector3.normalize(toParticleFromAxis, toParticleFromAxis);\r\n toParticleFromAxis.scaleBy(penetration);\r\n Vector3.add(particlePos, toParticleFromAxis, particlePos);\r\n return true;\r\n }\r\n\r\n return false;\r\n}\r\n\r\n/**\r\n * Resolves collision between a particle and a plane collider\r\n * @returns true if collision occurred\r\n *\r\n * @public\r\n */\r\nexport function resolvePlaneCollision(particlePos: Vector3, collider: PlaneCollider): boolean {\r\n const toParticle = Vector3.sub(particlePos, collider.point, new Vector3());\r\n const distance = Vector3.dot(toParticle, collider.normal);\r\n\r\n if (distance < 0) {\r\n // Particle is below plane, push it up\r\n const correction = Vector3.scale(collider.normal, -distance, new Vector3());\r\n Vector3.add(particlePos, correction, particlePos);\r\n return true;\r\n }\r\n\r\n return false;\r\n}\r\n\r\n/**\r\n * Updates collider position from its associated node\r\n *\r\n * @public\r\n */\r\nexport function updateColliderFromNode(collider: SpringCollider, runtimeNode?: Nullable<SceneNode>): void {\r\n const node = runtimeNode ?? collider.node;\r\n if (!node || !collider.enabled) {\r\n return;\r\n }\r\n\r\n const worldMatrix = node.worldMatrix;\r\n\r\n switch (collider.type) {\r\n case 'sphere': {\r\n const sphere = collider as SphereCollider;\r\n if (sphere.localRadius !== undefined) {\r\n const currentScale = getUniformScale(worldMatrix);\r\n const refScale = Math.max(1e-6, sphere.localRadiusScaleRef ?? 1);\r\n sphere.radius = sphere.localRadius * (currentScale / refScale);\r\n }\r\n if (sphere.localOffset) {\r\n // Transform local offset to world space\r\n worldMatrix.transformPointAffine(sphere.localOffset, sphere.center);\r\n } else {\r\n // No local offset, just use node position\r\n sphere.center.x = worldMatrix.m03;\r\n sphere.center.y = worldMatrix.m13;\r\n sphere.center.z = worldMatrix.m23;\r\n }\r\n break;\r\n }\r\n\r\n case 'capsule': {\r\n const capsule = collider as CapsuleCollider;\r\n if (capsule.localRadius !== undefined) {\r\n const axisLocal =\r\n capsule.localStartOffset && capsule.localEndOffset\r\n ? Vector3.sub(capsule.localEndOffset, capsule.localStartOffset, new Vector3())\r\n : Vector3.axisPY();\r\n const currentScale = getPerpendicularScale(worldMatrix, axisLocal);\r\n const refScale = Math.max(1e-6, capsule.localRadiusScaleRef ?? 1);\r\n capsule.radius = capsule.localRadius * (currentScale / refScale);\r\n }\r\n if (capsule.localStartOffset && capsule.localEndOffset) {\r\n // Transform local offsets to world space\r\n worldMatrix.transformPointAffine(capsule.localStartOffset, capsule.start);\r\n worldMatrix.transformPointAffine(capsule.localEndOffset, capsule.end);\r\n } else {\r\n // No local offsets, just use node position for start\r\n capsule.start.x = worldMatrix.m03;\r\n capsule.start.y = worldMatrix.m13;\r\n capsule.start.z = worldMatrix.m23;\r\n }\r\n break;\r\n }\r\n\r\n case 'plane': {\r\n const plane = collider as PlaneCollider;\r\n if (plane.localPointOffset) {\r\n // Transform local offset to world space\r\n worldMatrix.transformPointAffine(plane.localPointOffset, plane.point);\r\n } else {\r\n // No local offset, just use node position\r\n plane.point.x = worldMatrix.m03;\r\n plane.point.y = worldMatrix.m13;\r\n plane.point.z = worldMatrix.m23;\r\n }\r\n\r\n if (plane.localNormal) {\r\n // Transform local normal to world space (rotation only)\r\n worldMatrix.transformVectorAffine(plane.localNormal, plane.normal).inplaceNormalize();\r\n }\r\n break;\r\n }\r\n }\r\n}\r\n\r\nfunction getUniformScale(worldMatrix: any): number {\r\n const sx = worldMatrix.transformVectorAffine(Vector3.axisPX(), new Vector3()).magnitude;\r\n const sy = worldMatrix.transformVectorAffine(Vector3.axisPY(), new Vector3()).magnitude;\r\n const sz = worldMatrix.transformVectorAffine(Vector3.axisPZ(), new Vector3()).magnitude;\r\n return Math.max(1e-6, (sx + sy + sz) / 3);\r\n}\r\n\r\nfunction getPerpendicularScale(worldMatrix: any, axisLocal: Vector3): number {\r\n const axis = axisLocal.magnitudeSq > 1e-8 ? axisLocal.clone().inplaceNormalize() : Vector3.axisPY();\r\n const helper = Math.abs(axis.y) < 0.99 ? Vector3.axisPY() : Vector3.axisPX();\r\n const u = Vector3.cross(axis, helper, new Vector3()).inplaceNormalize();\r\n const v = Vector3.cross(axis, u, new Vector3()).inplaceNormalize();\r\n const su = worldMatrix.transformVectorAffine(u, new Vector3()).magnitude;\r\n const sv = worldMatrix.transformVectorAffine(v, new Vector3()).magnitude;\r\n return Math.max(1e-6, (su + sv) * 0.5);\r\n}\r\n"],"names":["createSphereCollider","centerOrOffset","radius","node","worldMatrix","worldCenter","transformPointAffine","Vector3","type","center","localRadius","localRadiusScaleRef","getUniformScale","enabled","localOffset","clone","createCapsuleCollider","startOrOffset","endOrOffset","worldStart","worldEnd","start","end","getPerpendicularScale","sub","localStartOffset","localEndOffset","createPlaneCollider","pointOrOffset","normal","normalizedNormal","normalize","worldPoint","point","localPointOffset","localNormal","resolveSphereCollision","particlePos","collider","toParticle","distSq","magnitudeSq","radiusSq","dist","Math","sqrt","penetration","scaleBy","add","resolveCapsuleCollision","axis","axisLength","magnitude","projection","dot","t","max","min","closestPoint","scale","toParticleFromAxis","resolvePlaneCollision","distance","correction","updateColliderFromNode","runtimeNode","sphere","undefined","currentScale","refScale","x","m03","y","m13","z","m23","capsule","axisLocal","axisPY","plane","transformVectorAffine","inplaceNormalize","sx","axisPX","sy","sz","axisPZ","helper","abs","u","cross","v","su","sv"],"mappings":"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"}
1
+ {"version":3,"file":"spring_collider.js","sources":["../../../src/animation/spring/spring_collider.ts"],"sourcesContent":["import type { Nullable } from '@zephyr3d/base';\r\nimport { Vector3 } from '@zephyr3d/base';\r\nimport type { SceneNode } from '../../scene/scene_node';\r\n\r\nconst COLLISION_DISTANCE_EPSILON_SQ = 1e-12;\r\n\r\nfunction getCapsuleAxisFallbackNormal(axis: Vector3, result: Vector3): Vector3 {\r\n const reference = Math.abs(axis.z) < 0.9 ? Vector3.axisPZ() : Vector3.axisPX();\r\n Vector3.sub(reference, Vector3.scale(axis, Vector3.dot(reference, axis), result), result);\r\n return result.inplaceNormalize();\r\n}\r\n\r\n/**\r\n * Base interface for spring collision shapes\r\n *\r\n * @public\r\n */\r\nexport interface SpringCollider {\r\n /** Type of collider */\r\n type: 'sphere' | 'capsule' | 'plane' | 'box';\r\n /** Associated scene node (optional, for dynamic colliders) */\r\n node?: Nullable<SceneNode>;\r\n /** Whether this collider is enabled */\r\n enabled: boolean;\r\n}\r\n\r\n/**\r\n * Sphere collider for spring collision detection\r\n *\r\n * @public\r\n */\r\nexport interface SphereCollider extends SpringCollider {\r\n type: 'sphere';\r\n /** Center position in world space */\r\n center: Vector3;\r\n /** Radius of the sphere */\r\n radius: number;\r\n /** Authoring-space radius before node scaling (if node is set) */\r\n localRadius?: number;\r\n /** Baseline world scale captured at creation for backward compatibility */\r\n localRadiusScaleRef?: number;\r\n /** Local offset from node (if node is set) */\r\n localOffset?: Vector3;\r\n}\r\n\r\n/**\r\n * Capsule collider for spring collision detection\r\n *\r\n * @public\r\n */\r\nexport interface CapsuleCollider extends SpringCollider {\r\n type: 'capsule';\r\n /** Start point of the capsule axis in world space */\r\n start: Vector3;\r\n /** End point of the capsule axis in world space */\r\n end: Vector3;\r\n /** Radius of the capsule */\r\n radius: number;\r\n /** Authoring-space radius before node scaling (if node is set) */\r\n localRadius?: number;\r\n /** Baseline perpendicular scale captured at creation for backward compatibility */\r\n localRadiusScaleRef?: number;\r\n /** Local start offset from node (if node is set) */\r\n localStartOffset?: Vector3;\r\n /** Local end offset from node (if node is set) */\r\n localEndOffset?: Vector3;\r\n}\r\n\r\n/**\r\n * Plane collider for spring collision detection\r\n *\r\n * @public\r\n */\r\nexport interface PlaneCollider extends SpringCollider {\r\n type: 'plane';\r\n /** Point on the plane in world space */\r\n point: Vector3;\r\n /** Normal vector of the plane (should be normalized) */\r\n normal: Vector3;\r\n /** Local point offset from node (if node is set) */\r\n localPointOffset?: Vector3;\r\n /** Local normal direction (if node is set) */\r\n localNormal?: Vector3;\r\n}\r\n\r\n/**\r\n * Oriented box collider for spring collision detection.\r\n *\r\n * The three axes are normalized world-space directions and halfExtents are\r\n * measured along the corresponding axes.\r\n *\r\n * @public\r\n */\r\nexport interface BoxCollider extends SpringCollider {\r\n type: 'box';\r\n /** Center position in world space */\r\n center: Vector3;\r\n /** World-space half extents along each local axis */\r\n halfExtents: Vector3;\r\n /** Normalized world-space local X/Y/Z axes */\r\n axes: [Vector3, Vector3, Vector3];\r\n /** Local center offset from node */\r\n localOffset?: Vector3;\r\n /** Authoring-space half extents before node scaling */\r\n localHalfExtents?: Vector3;\r\n}\r\n\r\n/**\r\n * Creates a sphere collider\r\n * @param centerOrOffset - Center position in world space, or local offset if node is provided\r\n * @param radius - Radius of the sphere\r\n * @param node - Optional scene node to attach to (if provided, centerOrOffset is treated as local offset)\r\n *\r\n * @public\r\n */\r\nexport function createSphereCollider(\r\n centerOrOffset: Vector3,\r\n radius: number,\r\n node?: SceneNode\r\n): SphereCollider {\r\n if (node) {\r\n // If node is provided, treat centerOrOffset as local offset\r\n const worldMatrix = node.worldMatrix;\r\n const worldCenter = worldMatrix.transformPointAffine(centerOrOffset, new Vector3());\r\n\r\n return {\r\n type: 'sphere',\r\n center: worldCenter,\r\n radius,\r\n localRadius: radius,\r\n localRadiusScaleRef: getUniformScale(worldMatrix),\r\n node,\r\n enabled: true,\r\n localOffset: centerOrOffset.clone()\r\n };\r\n } else {\r\n // No node, use as world position\r\n return {\r\n type: 'sphere',\r\n center: centerOrOffset.clone(),\r\n radius,\r\n node: null,\r\n enabled: true\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * Creates a capsule collider\r\n * @param startOrOffset - Start point in world space, or local offset if node is provided\r\n * @param endOrOffset - End point in world space, or local offset if node is provided\r\n * @param radius - Radius of the capsule\r\n * @param node - Optional scene node to attach to (if provided, offsets are treated as local)\r\n *\r\n * @public\r\n */\r\nexport function createCapsuleCollider(\r\n startOrOffset: Vector3,\r\n endOrOffset: Vector3,\r\n radius: number,\r\n node?: SceneNode\r\n): CapsuleCollider {\r\n if (node) {\r\n // If node is provided, treat as local offsets\r\n const worldMatrix = node.worldMatrix;\r\n const worldStart = worldMatrix.transformPointAffine(startOrOffset, new Vector3());\r\n const worldEnd = worldMatrix.transformPointAffine(endOrOffset, new Vector3());\r\n\r\n return {\r\n type: 'capsule',\r\n start: worldStart,\r\n end: worldEnd,\r\n radius,\r\n localRadius: radius,\r\n localRadiusScaleRef: getPerpendicularScale(\r\n worldMatrix,\r\n Vector3.sub(endOrOffset, startOrOffset, new Vector3())\r\n ),\r\n node,\r\n enabled: true,\r\n localStartOffset: startOrOffset.clone(),\r\n localEndOffset: endOrOffset.clone()\r\n };\r\n } else {\r\n // No node, use as world positions\r\n return {\r\n type: 'capsule',\r\n start: startOrOffset.clone(),\r\n end: endOrOffset.clone(),\r\n radius,\r\n node: null,\r\n enabled: true\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * Creates a plane collider\r\n * @param pointOrOffset - Point on plane in world space, or local offset if node is provided\r\n * @param normal - Normal vector (will be normalized)\r\n * @param node - Optional scene node to attach to (if provided, pointOrOffset is treated as local offset)\r\n *\r\n * @public\r\n */\r\nexport function createPlaneCollider(\r\n pointOrOffset: Vector3,\r\n normal: Vector3,\r\n node?: SceneNode\r\n): PlaneCollider {\r\n const normalizedNormal = new Vector3();\r\n Vector3.normalize(normal, normalizedNormal);\r\n\r\n if (node) {\r\n // If node is provided, treat as local offset\r\n const worldMatrix = node.worldMatrix;\r\n const worldPoint = worldMatrix.transformPointAffine(pointOrOffset, new Vector3());\r\n\r\n return {\r\n type: 'plane',\r\n point: worldPoint,\r\n normal: normalizedNormal.clone(),\r\n node,\r\n enabled: true,\r\n localPointOffset: pointOrOffset.clone(),\r\n localNormal: normalizedNormal.clone()\r\n };\r\n } else {\r\n // No node, use as world position\r\n return {\r\n type: 'plane',\r\n point: pointOrOffset.clone(),\r\n normal: normalizedNormal,\r\n node: null,\r\n enabled: true\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * Creates an oriented box collider.\r\n * @param centerOrOffset - Center position in world space, or local offset if node is provided\r\n * @param halfExtents - Local/world half extents of the box\r\n * @param node - Optional scene node to attach to\r\n *\r\n * @public\r\n */\r\nexport function createBoxCollider(\r\n centerOrOffset: Vector3,\r\n halfExtents: Vector3,\r\n node?: SceneNode\r\n): BoxCollider {\r\n const localExtents = new Vector3(\r\n Math.max(0.0001, Math.abs(halfExtents.x)),\r\n Math.max(0.0001, Math.abs(halfExtents.y)),\r\n Math.max(0.0001, Math.abs(halfExtents.z))\r\n );\r\n if (node) {\r\n const worldMatrix = node.worldMatrix;\r\n const center = worldMatrix.transformPointAffine(centerOrOffset, new Vector3());\r\n const axes = createWorldAxes(worldMatrix);\r\n const scales = getAxisScales(worldMatrix);\r\n return {\r\n type: 'box',\r\n center,\r\n halfExtents: new Vector3(\r\n localExtents.x * scales.x,\r\n localExtents.y * scales.y,\r\n localExtents.z * scales.z\r\n ),\r\n axes,\r\n localOffset: centerOrOffset.clone(),\r\n localHalfExtents: localExtents,\r\n node,\r\n enabled: true\r\n };\r\n }\r\n return {\r\n type: 'box',\r\n center: centerOrOffset.clone(),\r\n halfExtents: localExtents,\r\n axes: [Vector3.axisPX(), Vector3.axisPY(), Vector3.axisPZ()],\r\n node: null,\r\n enabled: true\r\n };\r\n}\r\n\r\n/**\r\n * Resolves collision between a particle and a sphere collider\r\n * @returns true if collision occurred\r\n *\r\n * @public\r\n */\r\nexport function resolveSphereCollision(\r\n particlePos: Vector3,\r\n collider: SphereCollider,\r\n particleRadius: number = 0\r\n): boolean {\r\n const toParticle = Vector3.sub(particlePos, collider.center, new Vector3());\r\n const distSq = toParticle.magnitudeSq;\r\n const contactRadius = collider.radius + Math.max(0, particleRadius);\r\n const radiusSq = contactRadius * contactRadius;\r\n\r\n if (distSq < radiusSq) {\r\n // Particle is inside sphere, push it out\r\n const dist = distSq > COLLISION_DISTANCE_EPSILON_SQ ? Math.sqrt(distSq) : 0;\r\n const penetration = contactRadius - dist;\r\n\r\n // Push particle to sphere surface\r\n if (dist > 0) {\r\n toParticle.scaleBy(1 / dist);\r\n } else {\r\n toParticle.setXYZ(0, 1, 0);\r\n }\r\n toParticle.scaleBy(penetration);\r\n Vector3.add(particlePos, toParticle, particlePos);\r\n\r\n return true;\r\n }\r\n\r\n return false;\r\n}\r\n\r\n/**\r\n * Resolves collision between a particle and a capsule collider\r\n * @returns true if collision occurred\r\n *\r\n * @public\r\n */\r\nexport function resolveCapsuleCollision(\r\n particlePos: Vector3,\r\n collider: CapsuleCollider,\r\n particleRadius: number = 0\r\n): boolean {\r\n const contactRadius = collider.radius + Math.max(0, particleRadius);\r\n // Find closest point on capsule axis\r\n const axis = Vector3.sub(collider.end, collider.start, new Vector3());\r\n const axisLength = axis.magnitude;\r\n\r\n if (axisLength < 0.0001) {\r\n // Degenerate capsule, treat as sphere\r\n const toParticle = Vector3.sub(particlePos, collider.start, new Vector3());\r\n const distSq = toParticle.magnitudeSq;\r\n const radiusSq = contactRadius * contactRadius;\r\n\r\n if (distSq < radiusSq) {\r\n const dist = distSq > COLLISION_DISTANCE_EPSILON_SQ ? Math.sqrt(distSq) : 0;\r\n const penetration = contactRadius - dist;\r\n if (dist > 0) {\r\n toParticle.scaleBy(1 / dist);\r\n } else {\r\n toParticle.setXYZ(0, 1, 0);\r\n }\r\n toParticle.scaleBy(penetration);\r\n Vector3.add(particlePos, toParticle, particlePos);\r\n return true;\r\n }\r\n return false;\r\n }\r\n\r\n Vector3.normalize(axis, axis);\r\n\r\n const toParticle = Vector3.sub(particlePos, collider.start, new Vector3());\r\n const projection = Vector3.dot(toParticle, axis);\r\n\r\n // Clamp projection to capsule length\r\n const t = Math.max(0, Math.min(axisLength, projection));\r\n\r\n // Closest point on capsule axis\r\n const closestPoint = Vector3.add(collider.start, Vector3.scale(axis, t, new Vector3()), new Vector3());\r\n\r\n // Check distance from closest point\r\n const toParticleFromAxis = Vector3.sub(particlePos, closestPoint, new Vector3());\r\n const distSq = toParticleFromAxis.magnitudeSq;\r\n const radiusSq = contactRadius * contactRadius;\r\n\r\n if (distSq < radiusSq) {\r\n const dist = distSq > COLLISION_DISTANCE_EPSILON_SQ ? Math.sqrt(distSq) : 0;\r\n const penetration = contactRadius - dist;\r\n if (dist > 0) {\r\n toParticleFromAxis.scaleBy(1 / dist);\r\n } else {\r\n getCapsuleAxisFallbackNormal(axis, toParticleFromAxis);\r\n }\r\n toParticleFromAxis.scaleBy(penetration);\r\n Vector3.add(particlePos, toParticleFromAxis, particlePos);\r\n return true;\r\n }\r\n\r\n return false;\r\n}\r\n\r\n/**\r\n * Resolves collision between a particle and a plane collider\r\n * @returns true if collision occurred\r\n *\r\n * @public\r\n */\r\nexport function resolvePlaneCollision(\r\n particlePos: Vector3,\r\n collider: PlaneCollider,\r\n particleRadius: number = 0\r\n): boolean {\r\n const toParticle = Vector3.sub(particlePos, collider.point, new Vector3());\r\n const distance = Vector3.dot(toParticle, collider.normal);\r\n const contactDistance = Math.max(0, particleRadius);\r\n\r\n if (distance < contactDistance) {\r\n // Particle is below plane, push it up\r\n const correction = Vector3.scale(collider.normal, contactDistance - distance, new Vector3());\r\n Vector3.add(particlePos, correction, particlePos);\r\n return true;\r\n }\r\n\r\n return false;\r\n}\r\n\r\n/**\r\n * Resolves collision between a particle and an oriented box collider.\r\n * @returns true if collision occurred\r\n *\r\n * @public\r\n */\r\nexport function resolveBoxCollision(\r\n particlePos: Vector3,\r\n collider: BoxCollider,\r\n particleRadius: number = 0\r\n): boolean {\r\n const delta = Vector3.sub(particlePos, collider.center, new Vector3());\r\n const local = new Vector3(\r\n Vector3.dot(delta, collider.axes[0]),\r\n Vector3.dot(delta, collider.axes[1]),\r\n Vector3.dot(delta, collider.axes[2])\r\n );\r\n const radius = Math.max(0, particleRadius);\r\n const inside =\r\n Math.abs(local.x) <= collider.halfExtents.x &&\r\n Math.abs(local.y) <= collider.halfExtents.y &&\r\n Math.abs(local.z) <= collider.halfExtents.z;\r\n if (!inside) {\r\n if (radius <= 0) {\r\n return false;\r\n }\r\n const closest = new Vector3(\r\n Math.max(-collider.halfExtents.x, Math.min(collider.halfExtents.x, local.x)),\r\n Math.max(-collider.halfExtents.y, Math.min(collider.halfExtents.y, local.y)),\r\n Math.max(-collider.halfExtents.z, Math.min(collider.halfExtents.z, local.z))\r\n );\r\n const fromClosest = Vector3.sub(local, closest, new Vector3());\r\n const distanceSq = fromClosest.magnitudeSq;\r\n if (distanceSq >= radius * radius || distanceSq <= COLLISION_DISTANCE_EPSILON_SQ) {\r\n return false;\r\n }\r\n const distance = Math.sqrt(distanceSq);\r\n fromClosest.scaleBy((radius - distance) / distance);\r\n Vector3.add(\r\n particlePos,\r\n Vector3.add(\r\n Vector3.scale(collider.axes[0], fromClosest.x, new Vector3()),\r\n Vector3.add(\r\n Vector3.scale(collider.axes[1], fromClosest.y, new Vector3()),\r\n Vector3.scale(collider.axes[2], fromClosest.z, new Vector3()),\r\n new Vector3()\r\n ),\r\n new Vector3()\r\n ),\r\n particlePos\r\n );\r\n return true;\r\n }\r\n const penetration = new Vector3(\r\n collider.halfExtents.x - Math.abs(local.x) + radius,\r\n collider.halfExtents.y - Math.abs(local.y) + radius,\r\n collider.halfExtents.z - Math.abs(local.z) + radius\r\n );\r\n let axis = 0;\r\n let minPenetration = penetration.x;\r\n if (penetration.y < minPenetration) {\r\n axis = 1;\r\n minPenetration = penetration.y;\r\n }\r\n if (penetration.z < minPenetration) {\r\n axis = 2;\r\n minPenetration = penetration.z;\r\n }\r\n const localAxis = axis === 0 ? local.x : axis === 1 ? local.y : local.z;\r\n const sign = localAxis < 0 ? -1 : 1;\r\n const correction = Vector3.scale(collider.axes[axis], minPenetration * sign, new Vector3());\r\n Vector3.add(particlePos, correction, particlePos);\r\n return true;\r\n}\r\n\r\n/**\r\n * Updates collider position from its associated node\r\n *\r\n * @public\r\n */\r\nexport function updateColliderFromNode(collider: SpringCollider, runtimeNode?: Nullable<SceneNode>): void {\r\n const node = runtimeNode ?? collider.node;\r\n if (!node || !collider.enabled) {\r\n return;\r\n }\r\n\r\n const worldMatrix = node.worldMatrix;\r\n\r\n switch (collider.type) {\r\n case 'sphere': {\r\n const sphere = collider as SphereCollider;\r\n if (sphere.localRadius !== undefined) {\r\n const currentScale = getUniformScale(worldMatrix);\r\n const refScale = Math.max(1e-6, sphere.localRadiusScaleRef ?? 1);\r\n sphere.radius = sphere.localRadius * (currentScale / refScale);\r\n }\r\n if (sphere.localOffset) {\r\n // Transform local offset to world space\r\n worldMatrix.transformPointAffine(sphere.localOffset, sphere.center);\r\n } else {\r\n // No local offset, just use node position\r\n sphere.center.x = worldMatrix.m03;\r\n sphere.center.y = worldMatrix.m13;\r\n sphere.center.z = worldMatrix.m23;\r\n }\r\n break;\r\n }\r\n\r\n case 'capsule': {\r\n const capsule = collider as CapsuleCollider;\r\n if (capsule.localRadius !== undefined) {\r\n const axisLocal =\r\n capsule.localStartOffset && capsule.localEndOffset\r\n ? Vector3.sub(capsule.localEndOffset, capsule.localStartOffset, new Vector3())\r\n : Vector3.axisPY();\r\n const currentScale = getPerpendicularScale(worldMatrix, axisLocal);\r\n const refScale = Math.max(1e-6, capsule.localRadiusScaleRef ?? 1);\r\n capsule.radius = capsule.localRadius * (currentScale / refScale);\r\n }\r\n if (capsule.localStartOffset && capsule.localEndOffset) {\r\n // Transform local offsets to world space\r\n worldMatrix.transformPointAffine(capsule.localStartOffset, capsule.start);\r\n worldMatrix.transformPointAffine(capsule.localEndOffset, capsule.end);\r\n } else {\r\n // No local offsets, just use node position for start\r\n capsule.start.x = worldMatrix.m03;\r\n capsule.start.y = worldMatrix.m13;\r\n capsule.start.z = worldMatrix.m23;\r\n }\r\n break;\r\n }\r\n\r\n case 'plane': {\r\n const plane = collider as PlaneCollider;\r\n if (plane.localPointOffset) {\r\n // Transform local offset to world space\r\n worldMatrix.transformPointAffine(plane.localPointOffset, plane.point);\r\n } else {\r\n // No local offset, just use node position\r\n plane.point.x = worldMatrix.m03;\r\n plane.point.y = worldMatrix.m13;\r\n plane.point.z = worldMatrix.m23;\r\n }\r\n\r\n if (plane.localNormal) {\r\n // Transform local normal to world space (rotation only)\r\n worldMatrix.transformVectorAffine(plane.localNormal, plane.normal).inplaceNormalize();\r\n }\r\n break;\r\n }\r\n\r\n case 'box': {\r\n const box = collider as BoxCollider;\r\n if (box.localOffset) {\r\n worldMatrix.transformPointAffine(box.localOffset, box.center);\r\n } else {\r\n box.center.x = worldMatrix.m03;\r\n box.center.y = worldMatrix.m13;\r\n box.center.z = worldMatrix.m23;\r\n }\r\n const axes = createWorldAxes(worldMatrix);\r\n box.axes[0].set(axes[0]);\r\n box.axes[1].set(axes[1]);\r\n box.axes[2].set(axes[2]);\r\n if (box.localHalfExtents) {\r\n const scales = getAxisScales(worldMatrix);\r\n box.halfExtents.setXYZ(\r\n box.localHalfExtents.x * scales.x,\r\n box.localHalfExtents.y * scales.y,\r\n box.localHalfExtents.z * scales.z\r\n );\r\n }\r\n break;\r\n }\r\n }\r\n}\r\n\r\nfunction createWorldAxes(worldMatrix: any): [Vector3, Vector3, Vector3] {\r\n const x = worldMatrix.transformVectorAffine(Vector3.axisPX(), new Vector3()).inplaceNormalize();\r\n const y = worldMatrix.transformVectorAffine(Vector3.axisPY(), new Vector3()).inplaceNormalize();\r\n const z = worldMatrix.transformVectorAffine(Vector3.axisPZ(), new Vector3()).inplaceNormalize();\r\n return [x, y, z];\r\n}\r\n\r\nfunction getAxisScales(worldMatrix: any) {\r\n return {\r\n x: Math.max(1e-6, worldMatrix.transformVectorAffine(Vector3.axisPX(), new Vector3()).magnitude),\r\n y: Math.max(1e-6, worldMatrix.transformVectorAffine(Vector3.axisPY(), new Vector3()).magnitude),\r\n z: Math.max(1e-6, worldMatrix.transformVectorAffine(Vector3.axisPZ(), new Vector3()).magnitude)\r\n };\r\n}\r\n\r\nfunction getUniformScale(worldMatrix: any): number {\r\n const sx = worldMatrix.transformVectorAffine(Vector3.axisPX(), new Vector3()).magnitude;\r\n const sy = worldMatrix.transformVectorAffine(Vector3.axisPY(), new Vector3()).magnitude;\r\n const sz = worldMatrix.transformVectorAffine(Vector3.axisPZ(), new Vector3()).magnitude;\r\n return Math.max(1e-6, (sx + sy + sz) / 3);\r\n}\r\n\r\nfunction getPerpendicularScale(worldMatrix: any, axisLocal: Vector3): number {\r\n const axis = axisLocal.magnitudeSq > 1e-8 ? axisLocal.clone().inplaceNormalize() : Vector3.axisPY();\r\n const helper = Math.abs(axis.y) < 0.99 ? Vector3.axisPY() : Vector3.axisPX();\r\n const u = Vector3.cross(axis, helper, new Vector3()).inplaceNormalize();\r\n const v = Vector3.cross(axis, u, new Vector3()).inplaceNormalize();\r\n const su = worldMatrix.transformVectorAffine(u, new Vector3()).magnitude;\r\n const sv = worldMatrix.transformVectorAffine(v, new Vector3()).magnitude;\r\n return Math.max(1e-6, (su + sv) * 0.5);\r\n}\r\n"],"names":["COLLISION_DISTANCE_EPSILON_SQ","getCapsuleAxisFallbackNormal","axis","result","reference","Math","abs","z","Vector3","axisPZ","axisPX","sub","scale","dot","inplaceNormalize","createSphereCollider","centerOrOffset","radius","node","worldMatrix","worldCenter","transformPointAffine","type","center","localRadius","localRadiusScaleRef","getUniformScale","enabled","localOffset","clone","createCapsuleCollider","startOrOffset","endOrOffset","worldStart","worldEnd","start","end","getPerpendicularScale","localStartOffset","localEndOffset","createPlaneCollider","pointOrOffset","normal","normalizedNormal","normalize","worldPoint","point","localPointOffset","localNormal","createBoxCollider","halfExtents","localExtents","max","x","y","axes","createWorldAxes","scales","getAxisScales","localHalfExtents","axisPY","resolveSphereCollision","particlePos","collider","particleRadius","toParticle","distSq","magnitudeSq","contactRadius","radiusSq","dist","sqrt","penetration","scaleBy","setXYZ","add","resolveCapsuleCollision","axisLength","magnitude","projection","t","min","closestPoint","toParticleFromAxis","resolvePlaneCollision","distance","contactDistance","correction","resolveBoxCollision","delta","local","inside","closest","fromClosest","distanceSq","minPenetration","localAxis","sign","updateColliderFromNode","runtimeNode","sphere","undefined","currentScale","refScale","m03","m13","m23","capsule","axisLocal","plane","transformVectorAffine","box","set","sx","sy","sz","helper","u","cross","v","su","sv"],"mappings":"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"}
@@ -11,6 +11,7 @@
11
11
  originalRotation: options?.originalRotation?.clone() ?? null,
12
12
  mass: options?.mass ?? 1.0,
13
13
  damping: options?.damping ?? 0.95,
14
+ collisionRadius: Math.max(0, Number(options?.collisionRadius) || 0),
14
15
  fixed: options?.fixed ?? false,
15
16
  node: options?.node ?? null,
16
17
  anchorNode: options?.anchorNode ?? null,
@@ -1 +1 @@
1
- {"version":3,"file":"spring_particle.js","sources":["../../../src/animation/spring/spring_particle.ts"],"sourcesContent":["import type { Vector3, Quaternion, Nullable } from '@zephyr3d/base';\r\nimport type { SceneNode } from '../../scene/scene_node';\r\n\r\n/**\r\n * Represents a particle in the spring system\r\n *\r\n * @public\r\n */\r\nexport interface SpringParticle {\r\n /** Current position in world space */\r\n position: Vector3;\r\n /** Previous position for Verlet integration */\r\n prevPosition: Vector3;\r\n /** Original position for reset */\r\n originalPosition: Vector3;\r\n /** Animated (target) position for pose preservation */\r\n animPosition: Vector3;\r\n /** Original world rotation (for calculating rotation delta) */\r\n originalRotation: Quaternion | null;\r\n /** Mass of the particle (affects inertia) */\r\n mass: number;\r\n /** Damping coefficient [0-1] (0 = no damping, 1 = full damping) */\r\n damping: number;\r\n /** Whether this particle is fixed (anchor point) */\r\n fixed: boolean;\r\n /** Associated scene node (optional) */\r\n node: Nullable<SceneNode>;\r\n /** Optional alternate anchor node used as the fixed-position source */\r\n anchorNode?: Nullable<SceneNode>;\r\n /** Optional local-space offset evaluated from anchorNode */\r\n anchorOffset?: Nullable<Vector3>;\r\n /** Previous frame position (used to calculate velocity for inertial forces) */\r\n lastFramePosition: Vector3;\r\n /** Position history for rotation center estimation (for fixed particles) */\r\n positionHistory?: Vector3[];\r\n}\r\n\r\n/**\r\n * Creates a new spring particle\r\n *\r\n * @public\r\n */\r\nexport function createSpringParticle(\r\n position: Vector3,\r\n options?: {\r\n mass?: number;\r\n damping?: number;\r\n fixed?: boolean;\r\n node?: SceneNode;\r\n anchorNode?: SceneNode;\r\n anchorOffset?: Vector3;\r\n originalRotation?: Quaternion;\r\n }\r\n): SpringParticle {\r\n return {\r\n position: position.clone(),\r\n prevPosition: position.clone(),\r\n originalPosition: position.clone(),\r\n animPosition: position.clone(),\r\n originalRotation: options?.originalRotation?.clone() ?? null,\r\n mass: options?.mass ?? 1.0,\r\n damping: options?.damping ?? 0.95,\r\n fixed: options?.fixed ?? false,\r\n node: options?.node ?? null,\r\n anchorNode: options?.anchorNode ?? null,\r\n anchorOffset: options?.anchorOffset?.clone() ?? null,\r\n lastFramePosition: position.clone()\r\n };\r\n}\r\n"],"names":["createSpringParticle","position","options","clone","prevPosition","originalPosition","animPosition","originalRotation","mass","damping","fixed","node","anchorNode","anchorOffset","lastFramePosition"],"mappings":"AAqCA;;;;AAIC,IACM,SAASA,oBACdC,CAAAA,QAAiB,EACjBC,OAQC,EAAA;IAED,OAAO;AACLD,QAAAA,QAAAA,EAAUA,SAASE,KAAK,EAAA;AACxBC,QAAAA,YAAAA,EAAcH,SAASE,KAAK,EAAA;AAC5BE,QAAAA,gBAAAA,EAAkBJ,SAASE,KAAK,EAAA;AAChCG,QAAAA,YAAAA,EAAcL,SAASE,KAAK,EAAA;QAC5BI,gBAAkBL,EAAAA,OAAAA,EAASK,kBAAkBJ,KAAW,EAAA,IAAA,IAAA;AACxDK,QAAAA,IAAAA,EAAMN,SAASM,IAAQ,IAAA,GAAA;AACvBC,QAAAA,OAAAA,EAASP,SAASO,OAAW,IAAA,IAAA;AAC7BC,QAAAA,KAAAA,EAAOR,SAASQ,KAAS,IAAA,KAAA;AACzBC,QAAAA,IAAAA,EAAMT,SAASS,IAAQ,IAAA,IAAA;AACvBC,QAAAA,UAAAA,EAAYV,SAASU,UAAc,IAAA,IAAA;QACnCC,YAAcX,EAAAA,OAAAA,EAASW,cAAcV,KAAW,EAAA,IAAA,IAAA;AAChDW,QAAAA,iBAAAA,EAAmBb,SAASE,KAAK;AACnC,KAAA;AACF;;;;"}
1
+ {"version":3,"file":"spring_particle.js","sources":["../../../src/animation/spring/spring_particle.ts"],"sourcesContent":["import type { Vector3, Quaternion, Nullable } from '@zephyr3d/base';\r\nimport type { SceneNode } from '../../scene/scene_node';\r\n\r\n/**\r\n * Represents a particle in the spring system\r\n *\r\n * @public\r\n */\r\nexport interface SpringParticle {\r\n /** Current position in world space */\r\n position: Vector3;\r\n /** Previous position for Verlet integration */\r\n prevPosition: Vector3;\r\n /** Original position for reset */\r\n originalPosition: Vector3;\r\n /** Animated (target) position for pose preservation */\r\n animPosition: Vector3;\r\n /** Original world rotation (for calculating rotation delta) */\r\n originalRotation: Quaternion | null;\r\n /** Mass of the particle (affects inertia) */\r\n mass: number;\r\n /** Velocity retention [0-1] (0 = fully damped, 1 = no damping) */\r\n damping: number;\r\n /** World-space collision radius around the particle center */\r\n collisionRadius: number;\r\n /** Whether this particle is fixed (anchor point) */\r\n fixed: boolean;\r\n /** Associated scene node (optional) */\r\n node: Nullable<SceneNode>;\r\n /** Optional alternate anchor node used as the fixed-position source */\r\n anchorNode?: Nullable<SceneNode>;\r\n /** Optional local-space offset evaluated from anchorNode */\r\n anchorOffset?: Nullable<Vector3>;\r\n /** Previous frame position (used to calculate velocity for inertial forces) */\r\n lastFramePosition: Vector3;\r\n /** Position history for rotation center estimation (for fixed particles) */\r\n positionHistory?: Vector3[];\r\n}\r\n\r\n/**\r\n * Creates a new spring particle\r\n *\r\n * @public\r\n */\r\nexport function createSpringParticle(\r\n position: Vector3,\r\n options?: {\r\n mass?: number;\r\n damping?: number;\r\n collisionRadius?: number;\r\n fixed?: boolean;\r\n node?: SceneNode;\r\n anchorNode?: SceneNode;\r\n anchorOffset?: Vector3;\r\n originalRotation?: Quaternion;\r\n }\r\n): SpringParticle {\r\n return {\r\n position: position.clone(),\r\n prevPosition: position.clone(),\r\n originalPosition: position.clone(),\r\n animPosition: position.clone(),\r\n originalRotation: options?.originalRotation?.clone() ?? null,\r\n mass: options?.mass ?? 1.0,\r\n damping: options?.damping ?? 0.95,\r\n collisionRadius: Math.max(0, Number(options?.collisionRadius) || 0),\r\n fixed: options?.fixed ?? false,\r\n node: options?.node ?? null,\r\n anchorNode: options?.anchorNode ?? null,\r\n anchorOffset: options?.anchorOffset?.clone() ?? null,\r\n lastFramePosition: position.clone()\r\n };\r\n}\r\n"],"names":["createSpringParticle","position","options","clone","prevPosition","originalPosition","animPosition","originalRotation","mass","damping","collisionRadius","Math","max","Number","fixed","node","anchorNode","anchorOffset","lastFramePosition"],"mappings":"AAuCA;;;;AAIC,IACM,SAASA,oBACdC,CAAAA,QAAiB,EACjBC,OASC,EAAA;IAED,OAAO;AACLD,QAAAA,QAAAA,EAAUA,SAASE,KAAK,EAAA;AACxBC,QAAAA,YAAAA,EAAcH,SAASE,KAAK,EAAA;AAC5BE,QAAAA,gBAAAA,EAAkBJ,SAASE,KAAK,EAAA;AAChCG,QAAAA,YAAAA,EAAcL,SAASE,KAAK,EAAA;QAC5BI,gBAAkBL,EAAAA,OAAAA,EAASK,kBAAkBJ,KAAW,EAAA,IAAA,IAAA;AACxDK,QAAAA,IAAAA,EAAMN,SAASM,IAAQ,IAAA,GAAA;AACvBC,QAAAA,OAAAA,EAASP,SAASO,OAAW,IAAA,IAAA;AAC7BC,QAAAA,eAAAA,EAAiBC,KAAKC,GAAG,CAAC,CAAGC,EAAAA,MAAAA,CAAOX,SAASQ,eAAoB,CAAA,IAAA,CAAA,CAAA;AACjEI,QAAAA,KAAAA,EAAOZ,SAASY,KAAS,IAAA,KAAA;AACzBC,QAAAA,IAAAA,EAAMb,SAASa,IAAQ,IAAA,IAAA;AACvBC,QAAAA,UAAAA,EAAYd,SAASc,UAAc,IAAA,IAAA;QACnCC,YAAcf,EAAAA,OAAAA,EAASe,cAAcd,KAAW,EAAA,IAAA,IAAA;AAChDe,QAAAA,iBAAAA,EAAmBjB,SAASE,KAAK;AACnC,KAAA;AACF;;;;"}
@@ -0,0 +1,173 @@
1
+ import { Vector3, Quaternion } from '@zephyr3d/base';
2
+
3
+ const EPSILON = 1e-6;
4
+ const INITIAL_COLLISION_PENETRATION_SLOP = 1e-4;
5
+ const DEFAULT_INITIAL_COLLISION_PENETRATION_RELEASE_TIME = 0.25;
6
+ function clampSpringRatio(value) {
7
+ return Math.max(0, Math.min(1, Number(value) || 0));
8
+ }
9
+ function interpolateSpringValue(root, tip, exponent, index, count) {
10
+ const t = Math.pow(index / Math.max(1, count - 1), Math.max(0.1, exponent));
11
+ return root + (tip - root) * t;
12
+ }
13
+ /**
14
+ * Converts a user-facing per-step strength into a strength that can be applied
15
+ * repeatedly without changing the effective response.
16
+ */ function getIterationStrength(strength, iterations) {
17
+ const value = clampSpringRatio(strength);
18
+ return iterations > 1 ? 1 - Math.pow(1 - value, 1 / iterations) : value;
19
+ }
20
+ /** Smoothly releases startup collider overlap so particles reach the real surface after `duration`. */ function getReleasedCollisionPenetration(initialPenetration, elapsed, duration) {
21
+ if (initialPenetration <= 0 || duration <= 0) {
22
+ return 0;
23
+ }
24
+ const t = Math.max(0, Math.min(1, elapsed / duration));
25
+ const progress = t * t * (3 - 2 * t);
26
+ return initialPenetration * (1 - progress);
27
+ }
28
+ /** Returns the Kawaii-style pose target relative to the simulated parent. */ function getParentRelativePoseTarget(particle, parent, result = new Vector3()) {
29
+ if (!parent) {
30
+ result.set(particle.animPosition);
31
+ return result;
32
+ }
33
+ Vector3.sub(particle.animPosition, parent.animPosition, result);
34
+ return Vector3.add(parent.position, result, result);
35
+ }
36
+ /** Builds a pose-follow direction and falloff measured from the nearest fixed particle. */ function getSpringPoseTopology(particles) {
37
+ const fixedIndices = [];
38
+ for(let i = 0; i < particles.length; i++){
39
+ if (particles[i].fixed) {
40
+ fixedIndices.push(i);
41
+ }
42
+ }
43
+ if (fixedIndices.length === 0) {
44
+ const lastIndex = Math.max(1, particles.length - 1);
45
+ return particles.map((_, index)=>({
46
+ parent: index > 0 ? particles[index - 1] : null,
47
+ nearestAnchor: null,
48
+ normalizedDistance: index / lastIndex
49
+ }));
50
+ }
51
+ const nearestFixedIndices = new Array(particles.length);
52
+ const distances = new Array(particles.length);
53
+ let maxDistance = 1;
54
+ for(let i = 0; i < particles.length; i++){
55
+ let nearestFixedIndex = fixedIndices[0];
56
+ let nearestDistance = Math.abs(i - nearestFixedIndex);
57
+ for(let j = 1; j < fixedIndices.length; j++){
58
+ const distance = Math.abs(i - fixedIndices[j]);
59
+ if (distance < nearestDistance) {
60
+ nearestFixedIndex = fixedIndices[j];
61
+ nearestDistance = distance;
62
+ }
63
+ }
64
+ nearestFixedIndices[i] = nearestFixedIndex;
65
+ distances[i] = nearestDistance;
66
+ maxDistance = Math.max(maxDistance, nearestDistance);
67
+ }
68
+ return particles.map((_, index)=>{
69
+ const nearestFixedIndex = nearestFixedIndices[index];
70
+ return {
71
+ parent: index > 0 ? particles[index - 1] : null,
72
+ nearestAnchor: particles[nearestFixedIndex],
73
+ normalizedDistance: distances[index] / maxDistance
74
+ };
75
+ });
76
+ }
77
+ /** Returns the Kawaii target, blending hierarchy shape with the nearest fixed anchor. */ function getKawaiiPoseTarget(particle, topology, result = new Vector3()) {
78
+ getParentRelativePoseTarget(particle, topology.parent, result);
79
+ if (!topology.nearestAnchor || topology.nearestAnchor === topology.parent) {
80
+ return result;
81
+ }
82
+ const anchorTarget = getParentRelativePoseTarget(particle, topology.nearestAnchor);
83
+ return Vector3.lerp(result, anchorTarget, 1 - topology.normalizedDistance, result);
84
+ }
85
+ /** Position-based distance projection with inverse-mass weighting. */ function solveDistanceConstraint(particleA, particleB, restLength, stiffness) {
86
+ const inverseMassA = particleA.fixed ? 0 : 1 / Math.max(particleA.mass, EPSILON);
87
+ const inverseMassB = particleB.fixed ? 0 : 1 / Math.max(particleB.mass, EPSILON);
88
+ const inverseMassSum = inverseMassA + inverseMassB;
89
+ if (inverseMassSum <= EPSILON) {
90
+ return;
91
+ }
92
+ const delta = Vector3.sub(particleB.position, particleA.position, new Vector3());
93
+ const length = delta.magnitude;
94
+ if (length <= EPSILON) {
95
+ return;
96
+ }
97
+ const correctionScale = (length - restLength) / length * clampSpringRatio(stiffness);
98
+ if (inverseMassA > 0) {
99
+ Vector3.add(particleA.position, Vector3.scale(delta, correctionScale * (inverseMassA / inverseMassSum), new Vector3()), particleA.position);
100
+ }
101
+ if (inverseMassB > 0) {
102
+ Vector3.sub(particleB.position, Vector3.scale(delta, correctionScale * (inverseMassB / inverseMassSum), new Vector3()), particleB.position);
103
+ }
104
+ }
105
+ /** Resolves a contact as an inelastic projection while preserving tangential Verlet velocity. */ function resolveInelasticCollision(particle, collider, resolveCollision, allowedPenetration = 0) {
106
+ const positionBeforeCollision = particle.position.clone();
107
+ const preservedDisplacement = Vector3.sub(positionBeforeCollision, particle.prevPosition, new Vector3());
108
+ if (!resolveCollision(particle.position, collider, particle.collisionRadius)) {
109
+ return false;
110
+ }
111
+ const correction = Vector3.sub(particle.position, positionBeforeCollision, new Vector3());
112
+ const correctionLength = correction.magnitude;
113
+ const excessPenetration = correctionLength - Math.max(0, allowedPenetration);
114
+ if (excessPenetration <= EPSILON) {
115
+ particle.position.set(positionBeforeCollision);
116
+ return false;
117
+ }
118
+ const outwardNormal = correction.scaleBy(1 / correctionLength);
119
+ Vector3.add(positionBeforeCollision, Vector3.scale(outwardNormal, excessPenetration, new Vector3()), particle.position);
120
+ if (correctionLength > EPSILON) {
121
+ const inwardDistance = Vector3.dot(preservedDisplacement, outwardNormal);
122
+ if (inwardDistance < 0) {
123
+ Vector3.sub(preservedDisplacement, Vector3.scale(outwardNormal, inwardDistance, new Vector3()), preservedDisplacement);
124
+ }
125
+ }
126
+ Vector3.sub(particle.position, preservedDisplacement, particle.prevPosition);
127
+ return true;
128
+ }
129
+ /** Returns how far a point is inside a collider according to its resolver. */ function measureCollisionPenetration(position, collider, resolveCollision, particleRadius = 0) {
130
+ const resolvedPosition = position.clone();
131
+ return resolveCollision(resolvedPosition, collider, particleRadius) ? Vector3.distance(position, resolvedPosition) : 0;
132
+ }
133
+ function getFallbackRotationAxis(direction) {
134
+ const reference = Math.abs(direction.x) < 0.8 ? Vector3.axisPX() : Vector3.axisPY();
135
+ return Vector3.cross(direction, reference, new Vector3()).inplaceNormalize();
136
+ }
137
+ /**
138
+ * Limits a child direction around its current animated direction while
139
+ * preserving the current simulated segment length.
140
+ */ function solveAngleLimit(parent, child, maxAngleDegrees, preserveVelocity) {
141
+ if (maxAngleDegrees <= 0 || child.fixed) {
142
+ return;
143
+ }
144
+ const poseDirection = Vector3.sub(child.animPosition, parent.animPosition, new Vector3());
145
+ const simulatedDirection = Vector3.sub(child.position, parent.position, new Vector3());
146
+ const simulatedLength = simulatedDirection.magnitude;
147
+ if (poseDirection.magnitudeSq <= EPSILON || simulatedLength <= EPSILON) {
148
+ return;
149
+ }
150
+ poseDirection.inplaceNormalize();
151
+ simulatedDirection.scaleBy(1 / simulatedLength);
152
+ const dot = Math.max(-1, Math.min(1, Vector3.dot(poseDirection, simulatedDirection)));
153
+ const angle = Math.acos(dot);
154
+ const limit = maxAngleDegrees * Math.PI / 180;
155
+ if (angle <= limit) {
156
+ return;
157
+ }
158
+ let axis = Vector3.cross(poseDirection, simulatedDirection, new Vector3());
159
+ if (axis.magnitudeSq <= EPSILON) {
160
+ axis = getFallbackRotationAxis(poseDirection);
161
+ } else {
162
+ axis.inplaceNormalize();
163
+ }
164
+ const allowedDirection = Quaternion.fromAxisAngle(axis, limit).transform(poseDirection, new Vector3());
165
+ const previousPosition = child.position.clone();
166
+ Vector3.add(parent.position, Vector3.scale(allowedDirection, simulatedLength, allowedDirection), child.position);
167
+ if (preserveVelocity) {
168
+ Vector3.add(child.prevPosition, Vector3.sub(child.position, previousPosition, previousPosition), child.prevPosition);
169
+ }
170
+ }
171
+
172
+ export { DEFAULT_INITIAL_COLLISION_PENETRATION_RELEASE_TIME, INITIAL_COLLISION_PENETRATION_SLOP, clampSpringRatio, getIterationStrength, getKawaiiPoseTarget, getParentRelativePoseTarget, getReleasedCollisionPenetration, getSpringPoseTopology, interpolateSpringValue, measureCollisionPenetration, resolveInelasticCollision, solveAngleLimit, solveDistanceConstraint };
173
+ //# sourceMappingURL=spring_solver.js.map