@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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spring_solver.js","sources":["../../../src/animation/spring/spring_solver.ts"],"sourcesContent":["import { Quaternion, Vector3 } from '@zephyr3d/base';\r\nimport type { SpringParticle } from './spring_particle';\r\n\r\n/** Motion model used by the spring integration pipeline. */\r\nexport type SpringMotionModel = 'legacy' | 'kawaii';\r\n\r\nconst EPSILON = 1e-6;\r\nexport const INITIAL_COLLISION_PENETRATION_SLOP = 1e-4;\r\nexport const DEFAULT_INITIAL_COLLISION_PENETRATION_RELEASE_TIME = 0.25;\r\n\r\nexport function clampSpringRatio(value: number): number {\r\n return Math.max(0, Math.min(1, Number(value) || 0));\r\n}\r\n\r\nexport function interpolateSpringValue(\r\n root: number,\r\n tip: number,\r\n exponent: number,\r\n index: number,\r\n count: number\r\n) {\r\n const t = Math.pow(index / Math.max(1, count - 1), Math.max(0.1, exponent));\r\n return root + (tip - root) * t;\r\n}\r\n\r\n/**\r\n * Converts a user-facing per-step strength into a strength that can be applied\r\n * repeatedly without changing the effective response.\r\n */\r\nexport function getIterationStrength(strength: number, iterations: number): number {\r\n const value = clampSpringRatio(strength);\r\n return iterations > 1 ? 1 - Math.pow(1 - value, 1 / iterations) : value;\r\n}\r\n\r\n/** Smoothly releases startup collider overlap so particles reach the real surface after `duration`. */\r\nexport function getReleasedCollisionPenetration(\r\n initialPenetration: number,\r\n elapsed: number,\r\n duration: number\r\n): number {\r\n if (initialPenetration <= 0 || duration <= 0) {\r\n return 0;\r\n }\r\n const t = Math.max(0, Math.min(1, elapsed / duration));\r\n const progress = t * t * (3 - 2 * t);\r\n return initialPenetration * (1 - progress);\r\n}\r\n\r\n/** Returns the Kawaii-style pose target relative to the simulated parent. */\r\nexport function getParentRelativePoseTarget(\r\n particle: SpringParticle,\r\n parent: SpringParticle | null,\r\n result = new Vector3()\r\n): Vector3 {\r\n if (!parent) {\r\n result.set(particle.animPosition);\r\n return result;\r\n }\r\n Vector3.sub(particle.animPosition, parent.animPosition, result);\r\n return Vector3.add(parent.position, result, result);\r\n}\r\n\r\nexport interface SpringPoseTopologyEntry {\r\n parent: SpringParticle | null;\r\n nearestAnchor: SpringParticle | null;\r\n normalizedDistance: number;\r\n}\r\n\r\n/** Builds a pose-follow direction and falloff measured from the nearest fixed particle. */\r\nexport function getSpringPoseTopology(particles: readonly SpringParticle[]): SpringPoseTopologyEntry[] {\r\n const fixedIndices: number[] = [];\r\n for (let i = 0; i < particles.length; i++) {\r\n if (particles[i].fixed) {\r\n fixedIndices.push(i);\r\n }\r\n }\r\n\r\n if (fixedIndices.length === 0) {\r\n const lastIndex = Math.max(1, particles.length - 1);\r\n return particles.map((_, index) => ({\r\n parent: index > 0 ? particles[index - 1] : null,\r\n nearestAnchor: null,\r\n normalizedDistance: index / lastIndex\r\n }));\r\n }\r\n\r\n const nearestFixedIndices = new Array<number>(particles.length);\r\n const distances = new Array<number>(particles.length);\r\n let maxDistance = 1;\r\n for (let i = 0; i < particles.length; i++) {\r\n let nearestFixedIndex = fixedIndices[0];\r\n let nearestDistance = Math.abs(i - nearestFixedIndex);\r\n for (let j = 1; j < fixedIndices.length; j++) {\r\n const distance = Math.abs(i - fixedIndices[j]);\r\n if (distance < nearestDistance) {\r\n nearestFixedIndex = fixedIndices[j];\r\n nearestDistance = distance;\r\n }\r\n }\r\n nearestFixedIndices[i] = nearestFixedIndex;\r\n distances[i] = nearestDistance;\r\n maxDistance = Math.max(maxDistance, nearestDistance);\r\n }\r\n\r\n return particles.map((_, index) => {\r\n const nearestFixedIndex = nearestFixedIndices[index];\r\n return {\r\n parent: index > 0 ? particles[index - 1] : null,\r\n nearestAnchor: particles[nearestFixedIndex],\r\n normalizedDistance: distances[index] / maxDistance\r\n };\r\n });\r\n}\r\n\r\n/** Returns the Kawaii target, blending hierarchy shape with the nearest fixed anchor. */\r\nexport function getKawaiiPoseTarget(\r\n particle: SpringParticle,\r\n topology: SpringPoseTopologyEntry,\r\n result = new Vector3()\r\n): Vector3 {\r\n getParentRelativePoseTarget(particle, topology.parent, result);\r\n if (!topology.nearestAnchor || topology.nearestAnchor === topology.parent) {\r\n return result;\r\n }\r\n const anchorTarget = getParentRelativePoseTarget(particle, topology.nearestAnchor);\r\n return Vector3.lerp(result, anchorTarget, 1 - topology.normalizedDistance, result);\r\n}\r\n\r\n/** Position-based distance projection with inverse-mass weighting. */\r\nexport function solveDistanceConstraint(\r\n particleA: SpringParticle,\r\n particleB: SpringParticle,\r\n restLength: number,\r\n stiffness: number\r\n): void {\r\n const inverseMassA = particleA.fixed ? 0 : 1 / Math.max(particleA.mass, EPSILON);\r\n const inverseMassB = particleB.fixed ? 0 : 1 / Math.max(particleB.mass, EPSILON);\r\n const inverseMassSum = inverseMassA + inverseMassB;\r\n if (inverseMassSum <= EPSILON) {\r\n return;\r\n }\r\n\r\n const delta = Vector3.sub(particleB.position, particleA.position, new Vector3());\r\n const length = delta.magnitude;\r\n if (length <= EPSILON) {\r\n return;\r\n }\r\n\r\n const correctionScale = ((length - restLength) / length) * clampSpringRatio(stiffness);\r\n if (inverseMassA > 0) {\r\n Vector3.add(\r\n particleA.position,\r\n Vector3.scale(delta, correctionScale * (inverseMassA / inverseMassSum), new Vector3()),\r\n particleA.position\r\n );\r\n }\r\n if (inverseMassB > 0) {\r\n Vector3.sub(\r\n particleB.position,\r\n Vector3.scale(delta, correctionScale * (inverseMassB / inverseMassSum), new Vector3()),\r\n particleB.position\r\n );\r\n }\r\n}\r\n\r\n/** Resolves a contact as an inelastic projection while preserving tangential Verlet velocity. */\r\nexport function resolveInelasticCollision<TCollider>(\r\n particle: SpringParticle,\r\n collider: TCollider,\r\n resolveCollision: (position: Vector3, collider: TCollider, particleRadius?: number) => boolean,\r\n allowedPenetration: number = 0\r\n): boolean {\r\n const positionBeforeCollision = particle.position.clone();\r\n const preservedDisplacement = Vector3.sub(positionBeforeCollision, particle.prevPosition, new Vector3());\r\n if (!resolveCollision(particle.position, collider, particle.collisionRadius)) {\r\n return false;\r\n }\r\n\r\n const correction = Vector3.sub(particle.position, positionBeforeCollision, new Vector3());\r\n const correctionLength = correction.magnitude;\r\n const excessPenetration = correctionLength - Math.max(0, allowedPenetration);\r\n if (excessPenetration <= EPSILON) {\r\n particle.position.set(positionBeforeCollision);\r\n return false;\r\n }\r\n\r\n const outwardNormal = correction.scaleBy(1 / correctionLength);\r\n Vector3.add(\r\n positionBeforeCollision,\r\n Vector3.scale(outwardNormal, excessPenetration, new Vector3()),\r\n particle.position\r\n );\r\n if (correctionLength > EPSILON) {\r\n const inwardDistance = Vector3.dot(preservedDisplacement, outwardNormal);\r\n if (inwardDistance < 0) {\r\n Vector3.sub(\r\n preservedDisplacement,\r\n Vector3.scale(outwardNormal, inwardDistance, new Vector3()),\r\n preservedDisplacement\r\n );\r\n }\r\n }\r\n Vector3.sub(particle.position, preservedDisplacement, particle.prevPosition);\r\n return true;\r\n}\r\n\r\n/** Returns how far a point is inside a collider according to its resolver. */\r\nexport function measureCollisionPenetration<TCollider>(\r\n position: Vector3,\r\n collider: TCollider,\r\n resolveCollision: (position: Vector3, collider: TCollider, particleRadius?: number) => boolean,\r\n particleRadius: number = 0\r\n): number {\r\n const resolvedPosition = position.clone();\r\n return resolveCollision(resolvedPosition, collider, particleRadius)\r\n ? Vector3.distance(position, resolvedPosition)\r\n : 0;\r\n}\r\n\r\nfunction getFallbackRotationAxis(direction: Vector3): Vector3 {\r\n const reference = Math.abs(direction.x) < 0.8 ? Vector3.axisPX() : Vector3.axisPY();\r\n return Vector3.cross(direction, reference, new Vector3()).inplaceNormalize();\r\n}\r\n\r\n/**\r\n * Limits a child direction around its current animated direction while\r\n * preserving the current simulated segment length.\r\n */\r\nexport function solveAngleLimit(\r\n parent: SpringParticle,\r\n child: SpringParticle,\r\n maxAngleDegrees: number,\r\n preserveVelocity: boolean\r\n): void {\r\n if (maxAngleDegrees <= 0 || child.fixed) {\r\n return;\r\n }\r\n\r\n const poseDirection = Vector3.sub(child.animPosition, parent.animPosition, new Vector3());\r\n const simulatedDirection = Vector3.sub(child.position, parent.position, new Vector3());\r\n const simulatedLength = simulatedDirection.magnitude;\r\n if (poseDirection.magnitudeSq <= EPSILON || simulatedLength <= EPSILON) {\r\n return;\r\n }\r\n poseDirection.inplaceNormalize();\r\n simulatedDirection.scaleBy(1 / simulatedLength);\r\n\r\n const dot = Math.max(-1, Math.min(1, Vector3.dot(poseDirection, simulatedDirection)));\r\n const angle = Math.acos(dot);\r\n const limit = (maxAngleDegrees * Math.PI) / 180;\r\n if (angle <= limit) {\r\n return;\r\n }\r\n\r\n let axis = Vector3.cross(poseDirection, simulatedDirection, new Vector3());\r\n if (axis.magnitudeSq <= EPSILON) {\r\n axis = getFallbackRotationAxis(poseDirection);\r\n } else {\r\n axis.inplaceNormalize();\r\n }\r\n const allowedDirection = Quaternion.fromAxisAngle(axis, limit).transform(poseDirection, new Vector3());\r\n const previousPosition = child.position.clone();\r\n Vector3.add(\r\n parent.position,\r\n Vector3.scale(allowedDirection, simulatedLength, allowedDirection),\r\n child.position\r\n );\r\n if (preserveVelocity) {\r\n Vector3.add(\r\n child.prevPosition,\r\n Vector3.sub(child.position, previousPosition, previousPosition),\r\n child.prevPosition\r\n );\r\n }\r\n}\r\n"],"names":["EPSILON","INITIAL_COLLISION_PENETRATION_SLOP","DEFAULT_INITIAL_COLLISION_PENETRATION_RELEASE_TIME","clampSpringRatio","value","Math","max","min","Number","interpolateSpringValue","root","tip","exponent","index","count","t","pow","getIterationStrength","strength","iterations","getReleasedCollisionPenetration","initialPenetration","elapsed","duration","progress","getParentRelativePoseTarget","particle","parent","result","Vector3","set","animPosition","sub","add","position","getSpringPoseTopology","particles","fixedIndices","i","length","fixed","push","lastIndex","map","_","nearestAnchor","normalizedDistance","nearestFixedIndices","Array","distances","maxDistance","nearestFixedIndex","nearestDistance","abs","j","distance","getKawaiiPoseTarget","topology","anchorTarget","lerp","solveDistanceConstraint","particleA","particleB","restLength","stiffness","inverseMassA","mass","inverseMassB","inverseMassSum","delta","magnitude","correctionScale","scale","resolveInelasticCollision","collider","resolveCollision","allowedPenetration","positionBeforeCollision","clone","preservedDisplacement","prevPosition","collisionRadius","correction","correctionLength","excessPenetration","outwardNormal","scaleBy","inwardDistance","dot","measureCollisionPenetration","particleRadius","resolvedPosition","getFallbackRotationAxis","direction","reference","x","axisPX","axisPY","cross","inplaceNormalize","solveAngleLimit","child","maxAngleDegrees","preserveVelocity","poseDirection","simulatedDirection","simulatedLength","magnitudeSq","angle","acos","limit","PI","axis","allowedDirection","Quaternion","fromAxisAngle","transform","previousPosition"],"mappings":"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"}
@@ -1,7 +1,8 @@
1
1
  import { Vector3, Quaternion } from '@zephyr3d/base';
2
2
  import { IKUtils } from '../ik/ik_utils.js';
3
- import { updateColliderFromNode, resolveSphereCollision, resolveCapsuleCollision, resolvePlaneCollision } from './spring_collider.js';
3
+ import { updateColliderFromNode, resolveSphereCollision, resolveCapsuleCollision, resolvePlaneCollision, resolveBoxCollision } from './spring_collider.js';
4
4
  import { SpringNodePoseTracker } from './spring_node_pose_tracker.js';
5
+ import { DEFAULT_INITIAL_COLLISION_PENETRATION_RELEASE_TIME, getSpringPoseTopology, getKawaiiPoseTarget, interpolateSpringValue, solveAngleLimit, solveDistanceConstraint, resolveInelasticCollision, measureCollisionPenetration, INITIAL_COLLISION_PENETRATION_SLOP, getReleasedCollisionPenetration, getIterationStrength } from './spring_solver.js';
5
6
 
6
7
  const FIXED_SIMULATION_TIME_STEP = 1 / 60;
7
8
  const MAX_ACCUMULATED_SIMULATION_TIME = 1 / 20;
@@ -35,7 +36,16 @@ const DEFAULT_COLLIDER_SMOOTHING_TIME = 1 / 30;
35
36
  _smoothedSphereCenters;
36
37
  _smoothedCapsuleEndpoints;
37
38
  _smoothedPlaneData;
39
+ _smoothedBoxData;
38
40
  _nodePoseTracker;
41
+ _motionModel;
42
+ _angleLimitRoot;
43
+ _angleLimitTip;
44
+ _constraintVelocityHistoryRetention;
45
+ _preserveInitialCollisionPenetration;
46
+ _initialCollisionPenetrationReleaseTime;
47
+ _initialCollisionPenetrationElapsed;
48
+ _initialCollisionPenetration;
39
49
  constructor(chain, options){
40
50
  this._chain = chain;
41
51
  this._iterations = options?.iterations ?? 5;
@@ -58,7 +68,16 @@ const DEFAULT_COLLIDER_SMOOTHING_TIME = 1 / 30;
58
68
  this._smoothedSphereCenters = new WeakMap();
59
69
  this._smoothedCapsuleEndpoints = new WeakMap();
60
70
  this._smoothedPlaneData = new WeakMap();
71
+ this._smoothedBoxData = new WeakMap();
61
72
  this._nodePoseTracker = new SpringNodePoseTracker();
73
+ this._motionModel = options?.motionModel ?? 'kawaii';
74
+ this._angleLimitRoot = Math.max(0, options?.angleLimitRoot ?? 0);
75
+ this._angleLimitTip = Math.max(0, options?.angleLimitTip ?? this._angleLimitRoot);
76
+ this._constraintVelocityHistoryRetention = Math.max(0, Math.min(1, options?.constraintVelocityHistoryRetention ?? 0.35));
77
+ this._preserveInitialCollisionPenetration = options?.preserveInitialCollisionPenetration ?? this._motionModel === 'kawaii';
78
+ this._initialCollisionPenetrationReleaseTime = Math.max(0, options?.initialCollisionPenetrationReleaseTime ?? DEFAULT_INITIAL_COLLISION_PENETRATION_RELEASE_TIME);
79
+ this._initialCollisionPenetrationElapsed = 0;
80
+ this._initialCollisionPenetration = new WeakMap();
62
81
  }
63
82
  /**
64
83
  * Updates the physics simulation
@@ -76,10 +95,10 @@ const DEFAULT_COLLIDER_SMOOTHING_TIME = 1 / 30;
76
95
  }
77
96
  this._timeAccumulator = Math.max(0, this._timeAccumulator - stepCount * FIXED_SIMULATION_TIME_STEP);
78
97
  for(let i = 0; i < stepCount; i++){
79
- this.simulateStep(FIXED_SIMULATION_TIME_STEP, i === 0 ? frameDt : 0);
98
+ this.simulateStep(FIXED_SIMULATION_TIME_STEP, i === 0 ? frameDt : 0, i, stepCount);
80
99
  }
81
100
  }
82
- simulateStep(dt, inputDeltaTime) {
101
+ simulateStep(dt, inputDeltaTime, stepIndex, stepCount) {
83
102
  // Step 1: Save all particle positions before updating
84
103
  if (this._enableInertialForces) {
85
104
  for (const p of this._chain.particles){
@@ -87,7 +106,8 @@ const DEFAULT_COLLIDER_SMOOTHING_TIME = 1 / 30;
87
106
  }
88
107
  }
89
108
  // Step 2: Update fixed particles from their scene nodes
90
- this.updateFixedParticles(inputDeltaTime);
109
+ const substepBlend = 1 / Math.max(1, stepCount - stepIndex);
110
+ this.updateFixedParticles(inputDeltaTime, substepBlend);
91
111
  // Step 3: Calculate global rotation parameters
92
112
  let rotationCenter = null;
93
113
  let angularVelocity = null;
@@ -125,8 +145,13 @@ const DEFAULT_COLLIDER_SMOOTHING_TIME = 1 / 30;
125
145
  constraint.lambda = 0;
126
146
  }
127
147
  }
148
+ if (this._motionModel === 'kawaii') {
149
+ this.solvePosePreservation(1, true);
150
+ }
128
151
  for(let iter = 0; iter < this._iterations; iter++){
129
- for (const constraint of this._chain.constraints){
152
+ const reverse = this._motionModel === 'kawaii' && !!(iter & 1);
153
+ for(let constraintIndex = 0; constraintIndex < this._chain.constraints.length; constraintIndex++){
154
+ const constraint = this._chain.constraints[reverse ? this._chain.constraints.length - 1 - constraintIndex : constraintIndex];
130
155
  if (this._solver === 'xpbd') {
131
156
  this.solveConstraintXPBD(constraint, dt);
132
157
  } else {
@@ -135,15 +160,56 @@ const DEFAULT_COLLIDER_SMOOTHING_TIME = 1 / 30;
135
160
  }
136
161
  // Pull particles back toward the animated pose to preserve hair silhouette.
137
162
  // Normalize follow strength across solver iterations so tuning stays intuitive.
138
- this.solvePosePreservation(this._iterations);
139
- // Apply collision constraints
140
- this.solveCollisions(inputDeltaTime);
163
+ if (this._motionModel === 'legacy') {
164
+ this.solvePosePreservation(this._iterations, false);
165
+ }
166
+ if (this._motionModel === 'legacy') {
167
+ this.solveCollisions(inputDeltaTime);
168
+ }
141
169
  }
170
+ if (this._motionModel === 'kawaii') {
171
+ this.solveCollisions(inputDeltaTime, substepBlend);
172
+ this.solveAngleLimits();
173
+ if (this._solver === 'xpbd') {
174
+ this.solveCollisions(0, 0);
175
+ for (const constraint of this._chain.constraints){
176
+ constraint.lambda = 0;
177
+ }
178
+ const closureIterations = Math.min(16, Math.max(4, this._iterations));
179
+ for(let iteration = 0; iteration < closureIterations; iteration++){
180
+ const reverse = !!(iteration & 1);
181
+ for(let constraintIndex = 0; constraintIndex < this._chain.constraints.length; constraintIndex++){
182
+ const constraint = this._chain.constraints[reverse ? this._chain.constraints.length - 1 - constraintIndex : constraintIndex];
183
+ this.solveConstraintXPBD(constraint, dt);
184
+ }
185
+ }
186
+ if (this._colliders.some((collider)=>collider.enabled)) {
187
+ for (const constraint of this._chain.constraints){
188
+ constraint.lambda = 0;
189
+ }
190
+ const contactClosureIterations = Math.min(4, closureIterations);
191
+ for(let iteration = 0; iteration < contactClosureIterations; iteration++){
192
+ const reverse = !!(iteration & 1);
193
+ for(let constraintIndex = 0; constraintIndex < this._chain.constraints.length; constraintIndex++){
194
+ const constraint = this._chain.constraints[reverse ? this._chain.constraints.length - 1 - constraintIndex : constraintIndex];
195
+ this.solveConstraintXPBD(constraint, dt);
196
+ }
197
+ this.solveCollisions(0, 0);
198
+ }
199
+ }
200
+ } else {
201
+ for (const constraint of this._chain.constraints){
202
+ this.solveConstraint(constraint);
203
+ }
204
+ this.solveCollisions(0, 0);
205
+ }
206
+ }
207
+ this.advanceInitialCollisionPenetrationRelease(dt);
142
208
  }
143
209
  /**
144
210
  * Updates fixed particles to match their scene node positions
145
- */ updateFixedParticles(deltaTime) {
146
- const blend = this.getTemporalBlendFactor(deltaTime, DEFAULT_PARTICLE_TARGET_SMOOTHING_TIME);
211
+ */ updateFixedParticles(deltaTime, substepBlend) {
212
+ const blend = this._motionModel === 'kawaii' ? substepBlend : this.getTemporalBlendFactor(deltaTime, DEFAULT_PARTICLE_TARGET_SMOOTHING_TIME);
147
213
  for (const particle of this._chain.particles){
148
214
  const sourceNode = particle.anchorNode ?? particle.node;
149
215
  if (!sourceNode) {
@@ -172,35 +238,46 @@ const DEFAULT_COLLIDER_SMOOTHING_TIME = 1 / 30;
172
238
  /**
173
239
  * Solves pose preservation (long-range attachment to animated pose).
174
240
  * This keeps strands close to authored shape while preserving dynamic movement.
175
- */ solvePosePreservation(totalIterations) {
241
+ */ solvePosePreservation(totalIterations, parentRelative) {
176
242
  if (this._poseFollowRoot <= 0 && this._poseFollowTip <= 0) {
177
243
  return;
178
244
  }
179
- const lastIndex = Math.max(1, this._chain.particles.length - 1);
245
+ const topology = getSpringPoseTopology(this._chain.particles);
180
246
  for(let i = 0; i < this._chain.particles.length; i++){
181
247
  const particle = this._chain.particles[i];
182
248
  if (particle.fixed) {
183
249
  continue;
184
250
  }
185
- const t = Math.pow(i / lastIndex, this._poseFollowExponent);
251
+ const t = Math.pow(topology[i].normalizedDistance, this._poseFollowExponent);
186
252
  const particlePoseFollow = this.lerp(this._poseFollowRoot, this._poseFollowTip, t);
187
253
  // Convert user-facing per-frame follow into per-iteration follow:
188
254
  // effective = 1 - (1 - follow)^iterations
189
- const iterationFollow = totalIterations > 1 ? 1 - Math.pow(Math.max(0, 1 - particlePoseFollow), 1 / totalIterations) : particlePoseFollow;
190
- const toAnim = Vector3.sub(particle.animPosition, particle.position, new Vector3());
255
+ const iterationFollow = getIterationStrength(particlePoseFollow, totalIterations);
256
+ const poseTarget = parentRelative ? getKawaiiPoseTarget(particle, topology[i]) : particle.animPosition;
257
+ const toAnim = Vector3.sub(poseTarget, particle.position, new Vector3());
191
258
  const correction = Vector3.scale(toAnim, iterationFollow, new Vector3());
192
259
  Vector3.add(particle.position, correction, particle.position);
193
260
  const particleMaxPoseOffset = this.lerp(this._maxPoseOffsetRoot, this._maxPoseOffsetTip, t);
194
261
  if (particleMaxPoseOffset > 0) {
195
- const offset = Vector3.sub(particle.position, particle.animPosition, new Vector3());
262
+ const offset = Vector3.sub(particle.position, poseTarget, new Vector3());
196
263
  const offsetLen = offset.magnitude;
197
264
  if (offsetLen > particleMaxPoseOffset && offsetLen > 1e-6) {
198
265
  offset.scaleBy(particleMaxPoseOffset / offsetLen);
199
- Vector3.add(particle.animPosition, offset, particle.position);
266
+ Vector3.add(poseTarget, offset, particle.position);
200
267
  }
201
268
  }
202
269
  }
203
270
  }
271
+ solveAngleLimits() {
272
+ if (this._angleLimitRoot <= 0 && this._angleLimitTip <= 0) {
273
+ return;
274
+ }
275
+ const particles = this._chain.particles;
276
+ for(let i = 1; i < particles.length; i++){
277
+ const limit = interpolateSpringValue(this._angleLimitRoot, this._angleLimitTip, this._poseFollowExponent, i, particles.length);
278
+ solveAngleLimit(particles[i - 1], particles[i], limit, this._solver === 'xpbd');
279
+ }
280
+ }
204
281
  lerp(a, b, t) {
205
282
  return a + (b - a) * t;
206
283
  }
@@ -388,11 +465,19 @@ const DEFAULT_COLLIDER_SMOOTHING_TIME = 1 / 30;
388
465
  const n = Vector3.scale(delta, 1.0 / currentLength, new Vector3());
389
466
  if (!pA.fixed) {
390
467
  // deltaX_a = -w_a * deltaLambda * n
391
- Vector3.add(pA.position, Vector3.scale(n, -wA * deltaLambda, new Vector3()), pA.position);
468
+ const correction = Vector3.scale(n, -wA * deltaLambda, new Vector3());
469
+ Vector3.add(pA.position, correction, pA.position);
470
+ if (this._motionModel === 'kawaii') {
471
+ Vector3.add(pA.prevPosition, Vector3.scale(correction, this._constraintVelocityHistoryRetention, new Vector3()), pA.prevPosition);
472
+ }
392
473
  }
393
474
  if (!pB.fixed) {
394
475
  // deltaX_b = +w_b * deltaLambda * n
395
- Vector3.add(pB.position, Vector3.scale(n, wB * deltaLambda, new Vector3()), pB.position);
476
+ const correction = Vector3.scale(n, wB * deltaLambda, new Vector3());
477
+ Vector3.add(pB.position, correction, pB.position);
478
+ if (this._motionModel === 'kawaii') {
479
+ Vector3.add(pB.prevPosition, Vector3.scale(correction, this._constraintVelocityHistoryRetention, new Vector3()), pB.prevPosition);
480
+ }
396
481
  }
397
482
  }
398
483
  /**
@@ -400,6 +485,10 @@ const DEFAULT_COLLIDER_SMOOTHING_TIME = 1 / 30;
400
485
  */ solveConstraint(constraint) {
401
486
  const pA = this._chain.particles[constraint.particleA];
402
487
  const pB = this._chain.particles[constraint.particleB];
488
+ if (this._motionModel === 'kawaii') {
489
+ solveDistanceConstraint(pA, pB, constraint.restLength, constraint.stiffness);
490
+ return;
491
+ }
403
492
  // Calculate current distance
404
493
  const delta = Vector3.sub(pB.position, pA.position, new Vector3());
405
494
  const currentLength = delta.magnitude;
@@ -419,12 +508,13 @@ const DEFAULT_COLLIDER_SMOOTHING_TIME = 1 / 30;
419
508
  }
420
509
  /**
421
510
  * Solves collisions for all particles
422
- */ solveCollisions(deltaTime) {
511
+ */ solveCollisions(deltaTime, blendOverride) {
423
512
  // Update dynamic colliders from their nodes
424
- const blend = this.getTemporalBlendFactor(deltaTime, DEFAULT_COLLIDER_SMOOTHING_TIME);
513
+ const blend = blendOverride ?? this.getTemporalBlendFactor(deltaTime, DEFAULT_COLLIDER_SMOOTHING_TIME);
425
514
  const spheres = [];
426
515
  const capsules = [];
427
516
  const planes = [];
517
+ const boxes = [];
428
518
  for (const collider of this._colliders){
429
519
  if (collider.node) {
430
520
  updateColliderFromNode(collider);
@@ -473,6 +563,18 @@ const DEFAULT_COLLIDER_SMOOTHING_TIME = 1 / 30;
473
563
  });
474
564
  break;
475
565
  }
566
+ case 'box':
567
+ {
568
+ const source = collider;
569
+ boxes.push({
570
+ particleCollider: source,
571
+ collider: {
572
+ ...source,
573
+ ...this.getSmoothedBoxData(source, blend)
574
+ }
575
+ });
576
+ break;
577
+ }
476
578
  }
477
579
  }
478
580
  // Check each particle against all colliders
@@ -481,13 +583,32 @@ const DEFAULT_COLLIDER_SMOOTHING_TIME = 1 / 30;
481
583
  continue; // Skip fixed particles
482
584
  }
483
585
  for (const collider of spheres){
484
- resolveSphereCollision(particle.position, collider.collider);
586
+ if (this._motionModel === 'kawaii') {
587
+ resolveInelasticCollision(particle, collider.collider, resolveSphereCollision, this.getInitialCollisionPenetration(particle, collider.particleCollider, collider.collider, resolveSphereCollision));
588
+ } else {
589
+ resolveSphereCollision(particle.position, collider.collider, particle.collisionRadius);
590
+ }
485
591
  }
486
592
  for (const collider of capsules){
487
- resolveCapsuleCollision(particle.position, collider.collider);
593
+ if (this._motionModel === 'kawaii') {
594
+ resolveInelasticCollision(particle, collider.collider, resolveCapsuleCollision, this.getInitialCollisionPenetration(particle, collider.particleCollider, collider.collider, resolveCapsuleCollision));
595
+ } else {
596
+ resolveCapsuleCollision(particle.position, collider.collider, particle.collisionRadius);
597
+ }
488
598
  }
489
599
  for (const collider of planes){
490
- resolvePlaneCollision(particle.position, collider.collider);
600
+ if (this._motionModel === 'kawaii') {
601
+ resolveInelasticCollision(particle, collider.collider, resolvePlaneCollision, this.getInitialCollisionPenetration(particle, collider.particleCollider, collider.collider, resolvePlaneCollision));
602
+ } else {
603
+ resolvePlaneCollision(particle.position, collider.collider, particle.collisionRadius);
604
+ }
605
+ }
606
+ for (const collider of boxes){
607
+ if (this._motionModel === 'kawaii') {
608
+ resolveInelasticCollision(particle, collider.collider, resolveBoxCollision, this.getInitialCollisionPenetration(particle, collider.particleCollider, collider.collider, resolveBoxCollision));
609
+ } else {
610
+ resolveBoxCollision(particle.position, collider.collider, particle.collisionRadius);
611
+ }
491
612
  }
492
613
  }
493
614
  }
@@ -561,6 +682,9 @@ const DEFAULT_COLLIDER_SMOOTHING_TIME = 1 / 30;
561
682
  this._smoothedSphereCenters = new WeakMap();
562
683
  this._smoothedCapsuleEndpoints = new WeakMap();
563
684
  this._smoothedPlaneData = new WeakMap();
685
+ this._smoothedBoxData = new WeakMap();
686
+ this._initialCollisionPenetrationElapsed = 0;
687
+ this._initialCollisionPenetration = new WeakMap();
564
688
  }
565
689
  /**
566
690
  * Gets the spring chain
@@ -630,6 +754,57 @@ const DEFAULT_COLLIDER_SMOOTHING_TIME = 1 / 30;
630
754
  }
631
755
  }
632
756
  }
757
+ get motionModel() {
758
+ return this._motionModel;
759
+ }
760
+ set motionModel(value) {
761
+ if (value !== 'legacy' && value !== 'kawaii') {
762
+ return;
763
+ }
764
+ if (this._motionModel !== value) {
765
+ this._motionModel = value;
766
+ this.reset();
767
+ }
768
+ }
769
+ get angleLimitRoot() {
770
+ return this._angleLimitRoot;
771
+ }
772
+ set angleLimitRoot(value) {
773
+ this._angleLimitRoot = Math.max(0, Number(value) || 0);
774
+ }
775
+ get angleLimitTip() {
776
+ return this._angleLimitTip;
777
+ }
778
+ set angleLimitTip(value) {
779
+ this._angleLimitTip = Math.max(0, Number(value) || 0);
780
+ }
781
+ get constraintVelocityHistoryRetention() {
782
+ return this._constraintVelocityHistoryRetention;
783
+ }
784
+ set constraintVelocityHistoryRetention(value) {
785
+ this._constraintVelocityHistoryRetention = Math.max(0, Math.min(1, Number(value) || 0));
786
+ }
787
+ get preserveInitialCollisionPenetration() {
788
+ return this._preserveInitialCollisionPenetration;
789
+ }
790
+ set preserveInitialCollisionPenetration(value) {
791
+ if (this._preserveInitialCollisionPenetration !== value) {
792
+ this._preserveInitialCollisionPenetration = value;
793
+ this._initialCollisionPenetrationElapsed = 0;
794
+ this._initialCollisionPenetration = new WeakMap();
795
+ }
796
+ }
797
+ get initialCollisionPenetrationReleaseTime() {
798
+ return this._initialCollisionPenetrationReleaseTime;
799
+ }
800
+ set initialCollisionPenetrationReleaseTime(value) {
801
+ const duration = Math.max(0, Number(value) || 0);
802
+ if (this._initialCollisionPenetrationReleaseTime !== duration) {
803
+ this._initialCollisionPenetrationReleaseTime = duration;
804
+ this._initialCollisionPenetrationElapsed = 0;
805
+ this._initialCollisionPenetration = new WeakMap();
806
+ }
807
+ }
633
808
  /**
634
809
  * Gets pose preservation strength [0-1]
635
810
  */ get poseFollow() {
@@ -699,6 +874,9 @@ const DEFAULT_COLLIDER_SMOOTHING_TIME = 1 / 30;
699
874
  this._smoothedSphereCenters = new WeakMap();
700
875
  this._smoothedCapsuleEndpoints = new WeakMap();
701
876
  this._smoothedPlaneData = new WeakMap();
877
+ this._smoothedBoxData = new WeakMap();
878
+ this._initialCollisionPenetrationElapsed = 0;
879
+ this._initialCollisionPenetration = new WeakMap();
702
880
  }
703
881
  /**
704
882
  * Removes a collider from the system
@@ -709,6 +887,9 @@ const DEFAULT_COLLIDER_SMOOTHING_TIME = 1 / 30;
709
887
  this._smoothedSphereCenters = new WeakMap();
710
888
  this._smoothedCapsuleEndpoints = new WeakMap();
711
889
  this._smoothedPlaneData = new WeakMap();
890
+ this._smoothedBoxData = new WeakMap();
891
+ this._initialCollisionPenetrationElapsed = 0;
892
+ this._initialCollisionPenetration = new WeakMap();
712
893
  return true;
713
894
  }
714
895
  return false;
@@ -720,12 +901,37 @@ const DEFAULT_COLLIDER_SMOOTHING_TIME = 1 / 30;
720
901
  this._smoothedSphereCenters = new WeakMap();
721
902
  this._smoothedCapsuleEndpoints = new WeakMap();
722
903
  this._smoothedPlaneData = new WeakMap();
904
+ this._smoothedBoxData = new WeakMap();
905
+ this._initialCollisionPenetrationElapsed = 0;
906
+ this._initialCollisionPenetration = new WeakMap();
723
907
  }
724
908
  /**
725
909
  * Gets all colliders
726
910
  */ get colliders() {
727
911
  return this._colliders;
728
912
  }
913
+ getInitialCollisionPenetration(particle, sourceCollider, collider, resolveCollision) {
914
+ if (!this._preserveInitialCollisionPenetration) {
915
+ return 0;
916
+ }
917
+ let particlePenetrations = this._initialCollisionPenetration.get(particle);
918
+ if (!particlePenetrations) {
919
+ particlePenetrations = new WeakMap();
920
+ this._initialCollisionPenetration.set(particle, particlePenetrations);
921
+ }
922
+ let penetration = particlePenetrations.get(sourceCollider);
923
+ if (penetration === undefined) {
924
+ penetration = measureCollisionPenetration(particle.animPosition, collider, resolveCollision, particle.collisionRadius) + INITIAL_COLLISION_PENETRATION_SLOP;
925
+ particlePenetrations.set(sourceCollider, penetration);
926
+ }
927
+ return getReleasedCollisionPenetration(penetration, this._initialCollisionPenetrationElapsed, this._initialCollisionPenetrationReleaseTime);
928
+ }
929
+ advanceInitialCollisionPenetrationRelease(deltaTime) {
930
+ if (!this._preserveInitialCollisionPenetration) {
931
+ return;
932
+ }
933
+ this._initialCollisionPenetrationElapsed = Math.min(this._initialCollisionPenetrationReleaseTime, this._initialCollisionPenetrationElapsed + Math.max(0, deltaTime));
934
+ }
729
935
  getTemporalBlendFactor(deltaTime, smoothingTime) {
730
936
  const dt = Math.min(Math.max(Number(deltaTime) || 0, 0), MAX_ACCUMULATED_SIMULATION_TIME);
731
937
  if (smoothingTime <= 0) {
@@ -798,6 +1004,25 @@ const DEFAULT_COLLIDER_SMOOTHING_TIME = 1 / 30;
798
1004
  }
799
1005
  return cached;
800
1006
  }
1007
+ getSmoothedBoxData(collider, blend) {
1008
+ const current = {
1009
+ center: collider.center.clone(),
1010
+ halfExtents: collider.halfExtents.clone(),
1011
+ axes: collider.axes.map((axis)=>axis.clone())
1012
+ };
1013
+ const cached = this._smoothedBoxData.get(collider);
1014
+ if (!cached || blend >= 1) {
1015
+ this._smoothedBoxData.set(collider, current);
1016
+ return current;
1017
+ }
1018
+ Vector3.lerp(cached.center, current.center, blend, cached.center);
1019
+ Vector3.lerp(cached.halfExtents, current.halfExtents, blend, cached.halfExtents);
1020
+ for(let i = 0; i < 3; i++){
1021
+ Vector3.lerp(cached.axes[i], current.axes[i], blend, cached.axes[i]);
1022
+ cached.axes[i].inplaceNormalize();
1023
+ }
1024
+ return cached;
1025
+ }
801
1026
  }
802
1027
 
803
1028
  export { SpringSystem };