@zephyr3d/scene 0.8.0 → 0.8.2

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 (389) hide show
  1. package/dist/animation/animationset.js +220 -1
  2. package/dist/animation/animationset.js.map +1 -1
  3. package/dist/animation/ik/ccd_solver.js +3 -4
  4. package/dist/animation/ik/ccd_solver.js.map +1 -1
  5. package/dist/animation/ik/fabrik_solver.js +3 -4
  6. package/dist/animation/ik/fabrik_solver.js.map +1 -1
  7. package/dist/animation/ik/ik_pole_constraint.js +7 -2
  8. package/dist/animation/ik/ik_pole_constraint.js.map +1 -1
  9. package/dist/animation/ik/ik_utils.js +0 -79
  10. package/dist/animation/ik/ik_utils.js.map +1 -1
  11. package/dist/animation/ik/two_bone_ik_solver.js +3 -4
  12. package/dist/animation/ik/two_bone_ik_solver.js.map +1 -1
  13. package/dist/animation/skeleton.js +157 -125
  14. package/dist/animation/skeleton.js.map +1 -1
  15. package/dist/animation/spring/spring_bone.js +240 -0
  16. package/dist/animation/spring/spring_bone.js.map +1 -0
  17. package/dist/animation/spring/spring_bone_collider.js +198 -0
  18. package/dist/animation/spring/spring_bone_collider.js.map +1 -0
  19. package/dist/animation/spring/spring_bone_constraint.js +170 -0
  20. package/dist/animation/spring/spring_bone_constraint.js.map +1 -0
  21. package/dist/animation/spring/spring_bone_system.js +328 -0
  22. package/dist/animation/spring/spring_bone_system.js.map +1 -0
  23. package/dist/asset/model.js +2 -2
  24. package/dist/index.d.ts +17 -0
  25. package/dist/material/mixins/pbr/common.js +20 -17
  26. package/dist/material/mixins/pbr/common.js.map +1 -1
  27. package/dist/render/gpu_picking.js +100 -0
  28. package/dist/render/gpu_picking.js.map +1 -0
  29. package/dist/render/rendergraph/device_pool_allocator.js +41 -0
  30. package/dist/render/rendergraph/device_pool_allocator.js.map +1 -0
  31. package/dist/render/rendergraph/executor.js +146 -0
  32. package/dist/render/rendergraph/executor.js.map +1 -0
  33. package/dist/render/rendergraph/forward_plus_builder.js +414 -0
  34. package/dist/render/rendergraph/forward_plus_builder.js.map +1 -0
  35. package/dist/render/rendergraph/rendergraph.js +306 -0
  36. package/dist/render/rendergraph/rendergraph.js.map +1 -0
  37. package/dist/render/rendergraph/types.js +57 -0
  38. package/dist/render/rendergraph/types.js.map +1 -0
  39. package/dist/render/sky_motion_vector.js +85 -0
  40. package/dist/render/sky_motion_vector.js.map +1 -0
  41. package/dist/utility/serialization/scene/animation.js +3 -3
  42. package/dist/utility/serialization/scene/node.js +1 -1
  43. package/package.json +2 -2
  44. package/dist/animation/ik/ik_chain_builder.js +0 -68
  45. package/dist/animation/ik/ik_chain_builder.js.map +0 -1
  46. package/dist/node_modules/@zephyr3d/runtime/dist/runtime/runtimemgr.js +0 -38
  47. package/dist/node_modules/@zephyr3d/runtime/dist/runtime/runtimemgr.js.map +0 -1
  48. package/dist/node_modules/@zephyr3d/runtime/dist/runtime/runtimescript.js +0 -10
  49. package/dist/node_modules/@zephyr3d/runtime/dist/runtime/runtimescript.js.map +0 -1
  50. package/dist/node_modules/@zephyr3d/runtime/dist/runtime/scriptingsystem.js +0 -127
  51. package/dist/node_modules/@zephyr3d/runtime/dist/runtime/scriptingsystem.js.map +0 -1
  52. package/dist/node_modules/@zephyr3d/runtime/dist/runtime/scriptregistry.js +0 -263
  53. package/dist/node_modules/@zephyr3d/runtime/dist/runtime/scriptregistry.js.map +0 -1
  54. package/dist/src/animation/animation.js +0 -127
  55. package/dist/src/animation/animation.js.map +0 -1
  56. package/dist/src/animation/animationset.js +0 -255
  57. package/dist/src/animation/animationset.js.map +0 -1
  58. package/dist/src/animation/animationtrack.js +0 -34
  59. package/dist/src/animation/animationtrack.js.map +0 -1
  60. package/dist/src/animation/eulerrotationtrack.js +0 -52
  61. package/dist/src/animation/eulerrotationtrack.js.map +0 -1
  62. package/dist/src/animation/morphtarget.js +0 -93
  63. package/dist/src/animation/morphtarget.js.map +0 -1
  64. package/dist/src/animation/morphtrack.js +0 -70
  65. package/dist/src/animation/morphtrack.js.map +0 -1
  66. package/dist/src/animation/proptrack.js +0 -161
  67. package/dist/src/animation/proptrack.js.map +0 -1
  68. package/dist/src/animation/rotationtrack.js +0 -51
  69. package/dist/src/animation/rotationtrack.js.map +0 -1
  70. package/dist/src/animation/scaletrack.js +0 -50
  71. package/dist/src/animation/scaletrack.js.map +0 -1
  72. package/dist/src/animation/skeleton.js +0 -204
  73. package/dist/src/animation/skeleton.js.map +0 -1
  74. package/dist/src/animation/translationtrack.js +0 -50
  75. package/dist/src/animation/translationtrack.js.map +0 -1
  76. package/dist/src/app/app.js +0 -129
  77. package/dist/src/app/app.js.map +0 -1
  78. package/dist/src/app/inputmgr.js +0 -267
  79. package/dist/src/app/inputmgr.js.map +0 -1
  80. package/dist/src/asset/assetmanager.js +0 -404
  81. package/dist/src/asset/assetmanager.js.map +0 -1
  82. package/dist/src/asset/builtin.js +0 -337
  83. package/dist/src/asset/builtin.js.map +0 -1
  84. package/dist/src/asset/loaders/dds/dds.js +0 -470
  85. package/dist/src/asset/loaders/dds/dds.js.map +0 -1
  86. package/dist/src/asset/loaders/dds/dds_loader.js +0 -28
  87. package/dist/src/asset/loaders/dds/dds_loader.js.map +0 -1
  88. package/dist/src/asset/loaders/gltf/gltf_loader.js +0 -1265
  89. package/dist/src/asset/loaders/gltf/gltf_loader.js.map +0 -1
  90. package/dist/src/asset/loaders/gltf/helpers.js +0 -327
  91. package/dist/src/asset/loaders/gltf/helpers.js.map +0 -1
  92. package/dist/src/asset/loaders/hdr/hdr.js +0 -180
  93. package/dist/src/asset/loaders/hdr/hdr.js.map +0 -1
  94. package/dist/src/asset/loaders/image/tga_Loader.js +0 -116
  95. package/dist/src/asset/loaders/image/tga_Loader.js.map +0 -1
  96. package/dist/src/asset/loaders/image/webimage_loader.js +0 -63
  97. package/dist/src/asset/loaders/image/webimage_loader.js.map +0 -1
  98. package/dist/src/asset/loaders/loader.js +0 -45
  99. package/dist/src/asset/loaders/loader.js.map +0 -1
  100. package/dist/src/asset/model.js +0 -414
  101. package/dist/src/asset/model.js.map +0 -1
  102. package/dist/src/blitter/bilateralblur.js +0 -221
  103. package/dist/src/blitter/bilateralblur.js.map +0 -1
  104. package/dist/src/blitter/blitter.js +0 -390
  105. package/dist/src/blitter/blitter.js.map +0 -1
  106. package/dist/src/blitter/box.js +0 -118
  107. package/dist/src/blitter/box.js.map +0 -1
  108. package/dist/src/blitter/copy.js +0 -22
  109. package/dist/src/blitter/copy.js.map +0 -1
  110. package/dist/src/blitter/gaussianblur.js +0 -228
  111. package/dist/src/blitter/gaussianblur.js.map +0 -1
  112. package/dist/src/camera/base.js +0 -92
  113. package/dist/src/camera/base.js.map +0 -1
  114. package/dist/src/camera/camera.js +0 -1005
  115. package/dist/src/camera/camera.js.map +0 -1
  116. package/dist/src/camera/fps.js +0 -238
  117. package/dist/src/camera/fps.js.map +0 -1
  118. package/dist/src/camera/orbit.js +0 -245
  119. package/dist/src/camera/orbit.js.map +0 -1
  120. package/dist/src/camera/orthocamera.js +0 -167
  121. package/dist/src/camera/orthocamera.js.map +0 -1
  122. package/dist/src/camera/perspectivecamera.js +0 -141
  123. package/dist/src/camera/perspectivecamera.js.map +0 -1
  124. package/dist/src/index.js +0 -120
  125. package/dist/src/index.js.map +0 -1
  126. package/dist/src/material/blinn.js +0 -81
  127. package/dist/src/material/blinn.js.map +0 -1
  128. package/dist/src/material/grassmaterial.js +0 -113
  129. package/dist/src/material/grassmaterial.js.map +0 -1
  130. package/dist/src/material/lambert.js +0 -92
  131. package/dist/src/material/lambert.js.map +0 -1
  132. package/dist/src/material/material.js +0 -301
  133. package/dist/src/material/material.js.map +0 -1
  134. package/dist/src/material/meshmaterial.js +0 -704
  135. package/dist/src/material/meshmaterial.js.map +0 -1
  136. package/dist/src/material/mixins/albedocolor.js +0 -76
  137. package/dist/src/material/mixins/albedocolor.js.map +0 -1
  138. package/dist/src/material/mixins/foliage.js +0 -47
  139. package/dist/src/material/mixins/foliage.js.map +0 -1
  140. package/dist/src/material/mixins/lightmodel/blinnphong.js +0 -112
  141. package/dist/src/material/mixins/lightmodel/blinnphong.js.map +0 -1
  142. package/dist/src/material/mixins/lightmodel/lambert.js +0 -58
  143. package/dist/src/material/mixins/lightmodel/lambert.js.map +0 -1
  144. package/dist/src/material/mixins/lightmodel/pbrmetallicroughness.js +0 -178
  145. package/dist/src/material/mixins/lightmodel/pbrmetallicroughness.js.map +0 -1
  146. package/dist/src/material/mixins/lightmodel/pbrspecularglossness.js +0 -139
  147. package/dist/src/material/mixins/lightmodel/pbrspecularglossness.js.map +0 -1
  148. package/dist/src/material/mixins/lit.js +0 -476
  149. package/dist/src/material/mixins/lit.js.map +0 -1
  150. package/dist/src/material/mixins/pbr/common.js +0 -918
  151. package/dist/src/material/mixins/pbr/common.js.map +0 -1
  152. package/dist/src/material/mixins/texture.js +0 -172
  153. package/dist/src/material/mixins/texture.js.map +0 -1
  154. package/dist/src/material/mixins/vertexcolor.js +0 -56
  155. package/dist/src/material/mixins/vertexcolor.js.map +0 -1
  156. package/dist/src/material/particle.js +0 -178
  157. package/dist/src/material/particle.js.map +0 -1
  158. package/dist/src/material/pbrmr.js +0 -97
  159. package/dist/src/material/pbrmr.js.map +0 -1
  160. package/dist/src/material/pbrsg.js +0 -97
  161. package/dist/src/material/pbrsg.js.map +0 -1
  162. package/dist/src/material/shader/helper.js +0 -1209
  163. package/dist/src/material/shader/helper.js.map +0 -1
  164. package/dist/src/material/terrain-cm.js +0 -606
  165. package/dist/src/material/terrain-cm.js.map +0 -1
  166. package/dist/src/material/terrainmaterial.js +0 -375
  167. package/dist/src/material/terrainmaterial.js.map +0 -1
  168. package/dist/src/material/unlit.js +0 -41
  169. package/dist/src/material/unlit.js.map +0 -1
  170. package/dist/src/material/water.js +0 -417
  171. package/dist/src/material/water.js.map +0 -1
  172. package/dist/src/posteffect/bloom.js +0 -361
  173. package/dist/src/posteffect/bloom.js.map +0 -1
  174. package/dist/src/posteffect/compositor.js +0 -226
  175. package/dist/src/posteffect/compositor.js.map +0 -1
  176. package/dist/src/posteffect/fxaa.js +0 -273
  177. package/dist/src/posteffect/fxaa.js.map +0 -1
  178. package/dist/src/posteffect/grayscale.js +0 -69
  179. package/dist/src/posteffect/grayscale.js.map +0 -1
  180. package/dist/src/posteffect/motionblur.js +0 -96
  181. package/dist/src/posteffect/motionblur.js.map +0 -1
  182. package/dist/src/posteffect/posteffect.js +0 -126
  183. package/dist/src/posteffect/posteffect.js.map +0 -1
  184. package/dist/src/posteffect/sao.js +0 -324
  185. package/dist/src/posteffect/sao.js.map +0 -1
  186. package/dist/src/posteffect/ssr.js +0 -489
  187. package/dist/src/posteffect/ssr.js.map +0 -1
  188. package/dist/src/posteffect/taa.js +0 -172
  189. package/dist/src/posteffect/taa.js.map +0 -1
  190. package/dist/src/posteffect/tonemap.js +0 -94
  191. package/dist/src/posteffect/tonemap.js.map +0 -1
  192. package/dist/src/render/abuffer_oit.js +0 -361
  193. package/dist/src/render/abuffer_oit.js.map +0 -1
  194. package/dist/src/render/clipmap.js +0 -851
  195. package/dist/src/render/clipmap.js.map +0 -1
  196. package/dist/src/render/cluster_light.js +0 -333
  197. package/dist/src/render/cluster_light.js.map +0 -1
  198. package/dist/src/render/cull_visitor.js +0 -187
  199. package/dist/src/render/cull_visitor.js.map +0 -1
  200. package/dist/src/render/depthpass.js +0 -68
  201. package/dist/src/render/depthpass.js.map +0 -1
  202. package/dist/src/render/drawable_mixin.js +0 -227
  203. package/dist/src/render/drawable_mixin.js.map +0 -1
  204. package/dist/src/render/envlight.js +0 -463
  205. package/dist/src/render/envlight.js.map +0 -1
  206. package/dist/src/render/fbm_wavegenerator.js +0 -251
  207. package/dist/src/render/fbm_wavegenerator.js.map +0 -1
  208. package/dist/src/render/fft_wavegenerator.js +0 -1006
  209. package/dist/src/render/fft_wavegenerator.js.map +0 -1
  210. package/dist/src/render/fullscreenquad.js +0 -38
  211. package/dist/src/render/fullscreenquad.js.map +0 -1
  212. package/dist/src/render/gerstner_wavegenerator.js +0 -314
  213. package/dist/src/render/gerstner_wavegenerator.js.map +0 -1
  214. package/dist/src/render/globalbindgroup_allocator.js +0 -60
  215. package/dist/src/render/globalbindgroup_allocator.js.map +0 -1
  216. package/dist/src/render/hzb.js +0 -273
  217. package/dist/src/render/hzb.js.map +0 -1
  218. package/dist/src/render/lightpass.js +0 -172
  219. package/dist/src/render/lightpass.js.map +0 -1
  220. package/dist/src/render/objectcolorpass.js +0 -51
  221. package/dist/src/render/objectcolorpass.js.map +0 -1
  222. package/dist/src/render/primitive.js +0 -364
  223. package/dist/src/render/primitive.js.map +0 -1
  224. package/dist/src/render/render_queue.js +0 -467
  225. package/dist/src/render/render_queue.js.map +0 -1
  226. package/dist/src/render/renderbundle_wrapper.js +0 -152
  227. package/dist/src/render/renderbundle_wrapper.js.map +0 -1
  228. package/dist/src/render/renderer.js +0 -455
  229. package/dist/src/render/renderer.js.map +0 -1
  230. package/dist/src/render/renderpass.js +0 -200
  231. package/dist/src/render/renderpass.js.map +0 -1
  232. package/dist/src/render/shadowmap_pass.js +0 -56
  233. package/dist/src/render/shadowmap_pass.js.map +0 -1
  234. package/dist/src/render/sky.js +0 -1103
  235. package/dist/src/render/sky.js.map +0 -1
  236. package/dist/src/render/weightedblended_oit.js +0 -168
  237. package/dist/src/render/weightedblended_oit.js.map +0 -1
  238. package/dist/src/scene/batchgroup.js +0 -162
  239. package/dist/src/scene/batchgroup.js.map +0 -1
  240. package/dist/src/scene/environment.js +0 -209
  241. package/dist/src/scene/environment.js.map +0 -1
  242. package/dist/src/scene/graph_node.js +0 -72
  243. package/dist/src/scene/graph_node.js.map +0 -1
  244. package/dist/src/scene/light.js +0 -416
  245. package/dist/src/scene/light.js.map +0 -1
  246. package/dist/src/scene/mesh.js +0 -341
  247. package/dist/src/scene/mesh.js.map +0 -1
  248. package/dist/src/scene/octree.js +0 -649
  249. package/dist/src/scene/octree.js.map +0 -1
  250. package/dist/src/scene/particlesys.js +0 -738
  251. package/dist/src/scene/particlesys.js.map +0 -1
  252. package/dist/src/scene/raycast_visitor.js +0 -103
  253. package/dist/src/scene/raycast_visitor.js.map +0 -1
  254. package/dist/src/scene/scene.js +0 -284
  255. package/dist/src/scene/scene.js.map +0 -1
  256. package/dist/src/scene/scene_node.js +0 -732
  257. package/dist/src/scene/scene_node.js.map +0 -1
  258. package/dist/src/scene/terrain/grass.js +0 -278
  259. package/dist/src/scene/terrain/grass.js.map +0 -1
  260. package/dist/src/scene/terrain/heightfield.js +0 -475
  261. package/dist/src/scene/terrain/heightfield.js.map +0 -1
  262. package/dist/src/scene/terrain/patch.js +0 -530
  263. package/dist/src/scene/terrain/patch.js.map +0 -1
  264. package/dist/src/scene/terrain/quadtree.js +0 -461
  265. package/dist/src/scene/terrain/quadtree.js.map +0 -1
  266. package/dist/src/scene/terrain/terrain.js +0 -246
  267. package/dist/src/scene/terrain/terrain.js.map +0 -1
  268. package/dist/src/scene/terrain-cm/grass.js +0 -594
  269. package/dist/src/scene/terrain-cm/grass.js.map +0 -1
  270. package/dist/src/scene/terrain-cm/grassmaterial.js +0 -159
  271. package/dist/src/scene/terrain-cm/grassmaterial.js.map +0 -1
  272. package/dist/src/scene/terrain-cm/terrain-cm.js +0 -538
  273. package/dist/src/scene/terrain-cm/terrain-cm.js.map +0 -1
  274. package/dist/src/scene/water.js +0 -374
  275. package/dist/src/scene/water.js.map +0 -1
  276. package/dist/src/shaders/atmosphere.js +0 -957
  277. package/dist/src/shaders/atmosphere.js.map +0 -1
  278. package/dist/src/shaders/fog.js +0 -112
  279. package/dist/src/shaders/fog.js.map +0 -1
  280. package/dist/src/shaders/misc.js +0 -266
  281. package/dist/src/shaders/misc.js.map +0 -1
  282. package/dist/src/shaders/noise.js +0 -222
  283. package/dist/src/shaders/noise.js.map +0 -1
  284. package/dist/src/shaders/pbr.js +0 -51
  285. package/dist/src/shaders/pbr.js.map +0 -1
  286. package/dist/src/shaders/shadow.js +0 -636
  287. package/dist/src/shaders/shadow.js.map +0 -1
  288. package/dist/src/shaders/ssr.js +0 -490
  289. package/dist/src/shaders/ssr.js.map +0 -1
  290. package/dist/src/shaders/temporal.js +0 -215
  291. package/dist/src/shaders/temporal.js.map +0 -1
  292. package/dist/src/shaders/water.js +0 -756
  293. package/dist/src/shaders/water.js.map +0 -1
  294. package/dist/src/shadow/esm.js +0 -237
  295. package/dist/src/shadow/esm.js.map +0 -1
  296. package/dist/src/shadow/pcf_opt.js +0 -181
  297. package/dist/src/shadow/pcf_opt.js.map +0 -1
  298. package/dist/src/shadow/pcf_pd.js +0 -189
  299. package/dist/src/shadow/pcf_pd.js.map +0 -1
  300. package/dist/src/shadow/shader.js +0 -37
  301. package/dist/src/shadow/shader.js.map +0 -1
  302. package/dist/src/shadow/shadow_impl.js +0 -15
  303. package/dist/src/shadow/shadow_impl.js.map +0 -1
  304. package/dist/src/shadow/shadowmapper.js +0 -790
  305. package/dist/src/shadow/shadowmapper.js.map +0 -1
  306. package/dist/src/shadow/ssm.js +0 -159
  307. package/dist/src/shadow/ssm.js.map +0 -1
  308. package/dist/src/shadow/vsm.js +0 -297
  309. package/dist/src/shadow/vsm.js.map +0 -1
  310. package/dist/src/shapes/box.js +0 -386
  311. package/dist/src/shapes/box.js.map +0 -1
  312. package/dist/src/shapes/cylinder.js +0 -125
  313. package/dist/src/shapes/cylinder.js.map +0 -1
  314. package/dist/src/shapes/plane.js +0 -88
  315. package/dist/src/shapes/plane.js.map +0 -1
  316. package/dist/src/shapes/shape.js +0 -87
  317. package/dist/src/shapes/shape.js.map +0 -1
  318. package/dist/src/shapes/sphere.js +0 -114
  319. package/dist/src/shapes/sphere.js.map +0 -1
  320. package/dist/src/shapes/tetrahedron.js +0 -188
  321. package/dist/src/shapes/tetrahedron.js.map +0 -1
  322. package/dist/src/shapes/torus.js +0 -111
  323. package/dist/src/shapes/torus.js.map +0 -1
  324. package/dist/src/utility/aabbtree.js +0 -400
  325. package/dist/src/utility/aabbtree.js.map +0 -1
  326. package/dist/src/utility/bounding_volume.js +0 -29
  327. package/dist/src/utility/bounding_volume.js.map +0 -1
  328. package/dist/src/utility/debug.js +0 -28
  329. package/dist/src/utility/debug.js.map +0 -1
  330. package/dist/src/utility/draco/decoder.js +0 -116
  331. package/dist/src/utility/draco/decoder.js.map +0 -1
  332. package/dist/src/utility/misc.js +0 -105
  333. package/dist/src/utility/misc.js.map +0 -1
  334. package/dist/src/utility/panorama.js +0 -163
  335. package/dist/src/utility/panorama.js.map +0 -1
  336. package/dist/src/utility/pmrem.js +0 -354
  337. package/dist/src/utility/pmrem.js.map +0 -1
  338. package/dist/src/utility/rendermipmap.js +0 -115
  339. package/dist/src/utility/rendermipmap.js.map +0 -1
  340. package/dist/src/utility/serialization/json.js +0 -402
  341. package/dist/src/utility/serialization/json.js.map +0 -1
  342. package/dist/src/utility/serialization/manager.js +0 -623
  343. package/dist/src/utility/serialization/manager.js.map +0 -1
  344. package/dist/src/utility/serialization/scene/animation.js +0 -248
  345. package/dist/src/utility/serialization/scene/animation.js.map +0 -1
  346. package/dist/src/utility/serialization/scene/batch.js +0 -59
  347. package/dist/src/utility/serialization/scene/batch.js.map +0 -1
  348. package/dist/src/utility/serialization/scene/camera.js +0 -790
  349. package/dist/src/utility/serialization/scene/camera.js.map +0 -1
  350. package/dist/src/utility/serialization/scene/common.js +0 -222
  351. package/dist/src/utility/serialization/scene/common.js.map +0 -1
  352. package/dist/src/utility/serialization/scene/light.js +0 -575
  353. package/dist/src/utility/serialization/scene/light.js.map +0 -1
  354. package/dist/src/utility/serialization/scene/material.js +0 -1111
  355. package/dist/src/utility/serialization/scene/material.js.map +0 -1
  356. package/dist/src/utility/serialization/scene/mesh.js +0 -148
  357. package/dist/src/utility/serialization/scene/mesh.js.map +0 -1
  358. package/dist/src/utility/serialization/scene/misc.js +0 -39
  359. package/dist/src/utility/serialization/scene/misc.js.map +0 -1
  360. package/dist/src/utility/serialization/scene/node.js +0 -451
  361. package/dist/src/utility/serialization/scene/node.js.map +0 -1
  362. package/dist/src/utility/serialization/scene/particle.js +0 -425
  363. package/dist/src/utility/serialization/scene/particle.js.map +0 -1
  364. package/dist/src/utility/serialization/scene/primitive.js +0 -692
  365. package/dist/src/utility/serialization/scene/primitive.js.map +0 -1
  366. package/dist/src/utility/serialization/scene/scene.js +0 -704
  367. package/dist/src/utility/serialization/scene/scene.js.map +0 -1
  368. package/dist/src/utility/serialization/scene/terrain.js +0 -488
  369. package/dist/src/utility/serialization/scene/terrain.js.map +0 -1
  370. package/dist/src/utility/serialization/scene/water.js +0 -465
  371. package/dist/src/utility/serialization/scene/water.js.map +0 -1
  372. package/dist/src/utility/shprojector.js +0 -297
  373. package/dist/src/utility/shprojector.js.map +0 -1
  374. package/dist/src/utility/textures/ggxlut.js +0 -213
  375. package/dist/src/utility/textures/ggxlut.js.map +0 -1
  376. package/dist/src/utility/textures/gradientnoise.js +0 -62
  377. package/dist/src/utility/textures/gradientnoise.js.map +0 -1
  378. package/dist/src/utility/textures/randomnoise.js +0 -41
  379. package/dist/src/utility/textures/randomnoise.js.map +0 -1
  380. package/dist/src/values.js +0 -162
  381. package/dist/src/values.js.map +0 -1
  382. package/dist/utility/blueprint/material/common.js +0 -7
  383. package/dist/utility/blueprint/material/common.js.map +0 -1
  384. package/dist/utility/serialization/blueprint/constants.js +0 -255
  385. package/dist/utility/serialization/blueprint/constants.js.map +0 -1
  386. package/dist/utility/serialization/blueprint/material/constants.js +0 -203
  387. package/dist/utility/serialization/blueprint/material/constants.js.map +0 -1
  388. package/dist/utility/serialization/blueprint/material/texture.js +0 -165
  389. package/dist/utility/serialization/blueprint/material/texture.js.map +0 -1
@@ -1,5 +1,10 @@
1
- import { Disposable, weightedAverage } from '@zephyr3d/base';
1
+ import { Disposable, weightedAverage, Interpolator } from '@zephyr3d/base';
2
2
  import { AnimationClip } from './animation.js';
3
+ import { NodeRotationTrack } from './rotationtrack.js';
4
+ import { NodeEulerRotationTrack } from './eulerrotationtrack.js';
5
+ import { NodeTranslationTrack } from './translationtrack.js';
6
+ import { NodeScaleTrack } from './scaletrack.js';
7
+ import { Skeleton } from './skeleton.js';
3
8
 
4
9
  /**
5
10
  * Animation set
@@ -327,6 +332,220 @@ import { AnimationClip } from './animation.js';
327
332
  }
328
333
  }
329
334
  /**
335
+ * Copy an animation clip from another AnimationSet into this one.
336
+ *
337
+ * Prerequisites:
338
+ * - Both sets must reference skeletons with identical joint names and counts.
339
+ * - The source clip must exist in `sourceSet`.
340
+ *
341
+ * @param sourceSet - The AnimationSet to copy from.
342
+ * @param animationName - Name of the clip to copy.
343
+ * @param targetName - Name for the new clip in this set. Defaults to `animationName`.
344
+ * @param excludeJoint - Optional predicate; joints whose name returns true are excluded from
345
+ * skeleton structure matching.
346
+ * @returns The newly created AnimationClip, or null on failure.
347
+ */ copyAnimationFrom(sourceSet, animationName, targetName, excludeJoint) {
348
+ const destName = targetName ?? animationName;
349
+ const sourceClip = sourceSet.get(animationName);
350
+ if (!sourceClip) {
351
+ console.error(`copyAnimationFrom: animation '${animationName}' not found in source set`);
352
+ return null;
353
+ }
354
+ if (this._animations[destName]) {
355
+ console.error(`copyAnimationFrom: animation '${destName}' already exists in target set`);
356
+ return null;
357
+ }
358
+ if (sourceClip.skeletons.size !== 1) {
359
+ console.error(`copyAnimationFrom: source animation clip must be affected by exactly one skeleton`);
360
+ return null;
361
+ }
362
+ const srcSkeletonId = [
363
+ ...sourceClip.skeletons
364
+ ][0];
365
+ const srcSkeleton = Skeleton.findSkeletonById(srcSkeletonId);
366
+ if (!srcSkeleton) {
367
+ console.error(`copyAnimationFrom: source skeleton '${srcSkeletonId}' not found`);
368
+ return null;
369
+ }
370
+ const nodeMap = new Map();
371
+ const jointRemapBySrcNode = new Map();
372
+ const jointsFiltered = srcSkeleton.joints.filter((j)=>!excludeJoint?.(j.name));
373
+ const srcRootNode = findRootJoint(jointsFiltered);
374
+ if (!srcRootNode) {
375
+ console.error(`copyAnimationFrom: cannot determine the root joint for source skeleton`);
376
+ return null;
377
+ }
378
+ // Build filtered joint lists for matching (exclude joints rejected by filterJoint)
379
+ const srcJointsFiltered = sortJoints(srcRootNode, jointsFiltered);
380
+ if (!srcJointsFiltered) {
381
+ console.error(`copyAnimationFrom: invalid source skeleton structure`);
382
+ return null;
383
+ }
384
+ let dstJointsFiltered = [];
385
+ const dstSkeleton = this._skeletons.map((ref)=>ref.get()).find((sk)=>{
386
+ if (!sk) {
387
+ return false;
388
+ }
389
+ const jointsFiltered = sk.joints.filter((j)=>!excludeJoint?.(j.name));
390
+ if (jointsFiltered.length !== srcJointsFiltered.length) {
391
+ return false;
392
+ }
393
+ const rootNode = findRootJoint(jointsFiltered);
394
+ if (!rootNode) {
395
+ return false;
396
+ }
397
+ const sortedJointsFiltered = sortJoints(rootNode, jointsFiltered);
398
+ if (sortedJointsFiltered && srcJointsFiltered.every((j, i)=>j.name === sortedJointsFiltered[i].name)) {
399
+ dstJointsFiltered = sortedJointsFiltered;
400
+ return true;
401
+ }
402
+ return false;
403
+ });
404
+ if (!dstJointsFiltered || !dstSkeleton) {
405
+ console.error(`copyAnimationFrom: no matching skeleton in target set for '${srcSkeletonId}'`);
406
+ return null;
407
+ }
408
+ // Build remap only for joints that pass the filter
409
+ for(let fi = 0; fi < srcJointsFiltered.length; fi++){
410
+ const srcJoint = srcJointsFiltered[fi];
411
+ const dstJoint = dstJointsFiltered[fi];
412
+ const si = srcSkeleton.joints.indexOf(srcJoint);
413
+ const di = dstSkeleton.joints.indexOf(dstJoint);
414
+ const srcLen = srcSkeleton.bindPose[si].position.magnitude;
415
+ const dstLen = dstSkeleton.bindPose[di].position.magnitude;
416
+ const translationScale = srcLen > 1e-6 ? dstLen / srcLen : 1;
417
+ nodeMap.set(srcJoint, dstJoint);
418
+ jointRemapBySrcNode.set(srcJoint, {
419
+ dstNode: dstJoint,
420
+ srcBindRot: srcSkeleton.bindPose[si].rotation,
421
+ dstBindRot: dstSkeleton.bindPose[di].rotation,
422
+ translationScale
423
+ });
424
+ }
425
+ const dstClip = this.createAnimation(destName);
426
+ if (!dstClip) {
427
+ return null;
428
+ }
429
+ dstClip.timeDuration = sourceClip.timeDuration;
430
+ dstClip.weight = sourceClip.weight;
431
+ dstClip.autoPlay = sourceClip.autoPlay;
432
+ // Register destination skeleton
433
+ dstClip.addSkeleton(dstSkeleton.persistentId);
434
+ for (const srcNode of srcJointsFiltered){
435
+ const srcTracks = sourceClip.tracks.get(srcNode);
436
+ if (!srcTracks) {
437
+ console.error(`copyAnimationFrom: no track for joint: ${srcNode.name}`);
438
+ return null;
439
+ }
440
+ const dstNode = nodeMap.get(srcNode);
441
+ const remap = jointRemapBySrcNode.get(srcNode) ?? null;
442
+ for (const srcTrack of srcTracks){
443
+ let dstTrack;
444
+ if (srcTrack instanceof NodeRotationTrack) {
445
+ dstTrack = retargetRotationTrack(srcTrack);
446
+ } else if (srcTrack instanceof NodeEulerRotationTrack) {
447
+ dstTrack = retargetEulerToRotationTrack(srcTrack);
448
+ } else if (srcTrack instanceof NodeTranslationTrack) {
449
+ dstTrack = retargetTranslationTrack(srcTrack, remap);
450
+ } else if (srcTrack instanceof NodeScaleTrack) {
451
+ dstTrack = new NodeScaleTrack(cloneInterpolator(srcTrack.interpolator));
452
+ } else {
453
+ console.warn(`copyAnimationFrom: unsupported track type '${srcTrack.constructor.name}', skipping`);
454
+ continue;
455
+ }
456
+ dstTrack.name = srcTrack.name;
457
+ dstTrack.target = srcTrack.target;
458
+ dstTrack.jointIndex = srcTrack.jointIndex;
459
+ dstClip.addTrack(dstNode, dstTrack);
460
+ }
461
+ }
462
+ return dstClip;
463
+ function findRootJoint(joints) {
464
+ let root = null;
465
+ for (const joint of joints){
466
+ if (!root) {
467
+ root = joint;
468
+ }
469
+ while(!root.isParentOf(joint)){
470
+ root = root.parent;
471
+ }
472
+ if (!root) {
473
+ break;
474
+ }
475
+ }
476
+ if (!root || !joints.includes(root)) {
477
+ return null;
478
+ }
479
+ return root;
480
+ }
481
+ function sortJoints(root, joints) {
482
+ const ordered = [];
483
+ const visited = new Set();
484
+ function visit(joint) {
485
+ if (visited.has(joint)) {
486
+ return true;
487
+ }
488
+ if (!joints.includes(joint)) {
489
+ return false;
490
+ }
491
+ if (joint !== root) {
492
+ visit(joint.parent);
493
+ }
494
+ visited.add(joint);
495
+ ordered.push(joint);
496
+ return true;
497
+ }
498
+ for (const joint of joints){
499
+ if (!visit(joint)) {
500
+ return null;
501
+ }
502
+ }
503
+ return ordered;
504
+ }
505
+ function retargetTranslationTrack(src, remap) {
506
+ if (!remap || Math.abs(remap.translationScale - 1) < 1e-6) {
507
+ return new NodeTranslationTrack(cloneInterpolator(src.interpolator));
508
+ }
509
+ const scale = remap.translationScale;
510
+ const srcOutputs = src.interpolator.outputs;
511
+ const newOutputs = new Float32Array(srcOutputs.length);
512
+ for(let i = 0; i < newOutputs.length; i++){
513
+ newOutputs[i] = srcOutputs[i] * scale;
514
+ }
515
+ return new NodeTranslationTrack(new Interpolator(src.interpolator.mode, 'vec3', new Float32Array(src.interpolator.inputs), newOutputs));
516
+ }
517
+ function cloneInterpolator(src) {
518
+ return new Interpolator(src.mode, src.target, src.inputs instanceof Float32Array ? new Float32Array(src.inputs) : [
519
+ ...src.inputs
520
+ ], src.outputs instanceof Float32Array ? new Float32Array(src.outputs) : [
521
+ ...src.outputs
522
+ ]);
523
+ }
524
+ function retargetRotationTrack(src) {
525
+ const isCubic = src.interpolator.mode === 'cubicspline';
526
+ const frameStride = isCubic ? 12 : 4;
527
+ const numFrames = src.interpolator.inputs.length;
528
+ const srcOutputs = src.interpolator.outputs;
529
+ const newOutputs = new Float32Array(srcOutputs.length);
530
+ for(let f = 0; f < numFrames; f++){
531
+ const base = f * frameStride;
532
+ newOutputs.set(srcOutputs.subarray(base, base + (isCubic ? 12 : 4)), base);
533
+ }
534
+ return new NodeRotationTrack(new Interpolator(src.interpolator.mode, 'quat', new Float32Array(src.interpolator.inputs), newOutputs));
535
+ }
536
+ function retargetEulerToRotationTrack(src) {
537
+ const srcInputs = src.interpolator.inputs;
538
+ const srcOutputs = src.interpolator.outputs;
539
+ const numFrames = srcInputs.length;
540
+ const newOutputs = new Float32Array(numFrames * 3);
541
+ for(let f = 0; f < numFrames; f++){
542
+ const base = f * 3;
543
+ newOutputs.set(srcOutputs.subarray(base, base + 3), base);
544
+ }
545
+ return new NodeRotationTrack(new Interpolator('linear', 'quat', new Float32Array(srcInputs), newOutputs));
546
+ }
547
+ }
548
+ /**
330
549
  * Dispose the animation set and release owned resources.
331
550
  *
332
551
  * - Disposes the weak reference to the model.
@@ -1 +1 @@
1
- {"version":3,"file":"animationset.js","sources":["../../src/animation/animationset.ts"],"sourcesContent":["import { weightedAverage, Disposable } from '@zephyr3d/base';\r\nimport type { DRef, IDisposable } from '@zephyr3d/base';\r\nimport type { SceneNode } from '../scene';\r\nimport { AnimationClip } from './animation';\r\nimport type { AnimationTrack } from './animationtrack';\r\nimport type { Skeleton } from './skeleton';\r\n\r\n/**\r\n * Options for playing an animation.\r\n *\r\n * Controls looping, playback speed (including reverse), and fade-in blending.\r\n * @public\r\n **/\r\nexport type PlayAnimationOptions = {\r\n /**\r\n * Number of loops to play.\r\n *\r\n * - 0: infinite looping (default).\r\n * - n \\> 0: play exactly n loops (each loop is one full duration of the clip).\r\n */\r\n repeat?: number;\r\n /**\r\n * Playback speed multiplier.\r\n *\r\n * - 1: normal speed (default).\r\n * - \\>1: faster; \\<1: slower.\r\n * - Negative values play the clip in reverse. The initial `currentTime` will be set to the end.\r\n */\r\n speedRatio?: number;\r\n /**\r\n * Fade-in duration in seconds.\r\n *\r\n * Interpolates the animation weight from 0 to the clip's configured weight over this time.\r\n * Use together with `stopAnimation(..., { fadeOut })` for smooth cross-fading.\r\n * Default is 0 (no fade-in).\r\n */\r\n fadeIn?: number;\r\n /**\r\n * Weight of the animation clip.\r\n *\r\n * Used during blending when multiple animations affect the same property.\r\n * Default is the clip's configured weight.\r\n */\r\n weight?: number;\r\n};\r\n\r\n/**\r\n * Options for stopping an animation.\r\n *\r\n * Allows a graceful fade-out instead of abrupt stop.\r\n * @public\r\n */\r\nexport type StopAnimationOptions = {\r\n /**\r\n * Fade-out duration in seconds.\r\n *\r\n * Interpolates the current animation weight down to 0 over this time.\r\n * Default is 0 (immediate stop).\r\n */\r\n fadeOut?: number;\r\n};\r\n\r\n/**\r\n * Animation set\r\n *\r\n * Manages a collection of named animation clips for a model and orchestrates:\r\n * - Playback state (time, loops, speed, weights, fade-in/out).\r\n * - Blending across multiple tracks targeting the same property via weighted averages.\r\n * - Skeleton usage and application for clips that drive skeletal animation.\r\n * - Active track registration and cleanup as clips start/stop.\r\n *\r\n * Usage:\r\n * - Create or retrieve `AnimationClip`s by name.\r\n * - Start playback with `playAnimation(name, options)`.\r\n * - Advance animation with `update(deltaSeconds)`.\r\n * - Optionally adjust weight while playing with `setAnimationWeight(name, weight)`.\r\n *\r\n * Lifetime:\r\n * - Disposing the set releases references to the model, clips, and clears active state.\r\n *\r\n * @public\r\n */\r\nexport class AnimationSet extends Disposable implements IDisposable {\r\n /** @internal */\r\n private _model: SceneNode;\r\n /** @internal */\r\n private _animations: Partial<Record<string, AnimationClip>>;\r\n /** @internal */\r\n private _skeletons: DRef<Skeleton>[];\r\n /** @internal */\r\n private readonly _activeTracks: Map<object, Map<unknown, AnimationTrack[]>>;\r\n /** @internal */\r\n private readonly _activeSkeletons: Map<Skeleton, number>;\r\n /** @internal */\r\n private readonly _activeAnimations: Map<\r\n AnimationClip,\r\n {\r\n currentTime: number;\r\n repeat: number;\r\n repeatCounter: number;\r\n weight: number;\r\n speedRatio: number;\r\n firstFrame: boolean;\r\n fadeIn: number;\r\n fadeOut: number;\r\n fadeOutStart: number;\r\n animateTime: number;\r\n }\r\n >;\r\n /**\r\n * Create an AnimationSet controlling the provided model.\r\n *\r\n * @param model - The SceneNode (model root) controlled by this animation set.\r\n */\r\n constructor(model: SceneNode) {\r\n super();\r\n this._model = model;\r\n this._animations = {};\r\n this._activeTracks = new Map();\r\n this._activeSkeletons = new Map();\r\n this._activeAnimations = new Map();\r\n this._skeletons = [];\r\n }\r\n /**\r\n * The model (SceneNode) controlled by this animation set.\r\n */\r\n get model() {\r\n return this._model;\r\n }\r\n /**\r\n * Number of animation clips registered in this set.\r\n */\r\n get numAnimations() {\r\n return Object.getOwnPropertyNames(this._animations).length;\r\n }\r\n /**\r\n * The skeletons used by animations in this set.\r\n */\r\n get skeletons() {\r\n return this._skeletons;\r\n }\r\n /**\r\n * Retrieve an animation clip by name.\r\n *\r\n * @param name - Name of the animation.\r\n * @returns The clip if present; otherwise null.\r\n */\r\n get(name: string) {\r\n return this._animations[name] ?? null;\r\n }\r\n /**\r\n * Create and register a new animation clip.\r\n *\r\n * @param name - Unique name for the animation clip.\r\n * @param embedded - Whether the clip is embedded/owned (implementation-specific). Default false.\r\n * @returns The created clip, or null if the name is empty or not unique.\r\n */\r\n createAnimation(name: string, embedded = false) {\r\n if (!name || this._animations[name]) {\r\n console.error('Animation must have unique name');\r\n return null;\r\n } else {\r\n const animation = new AnimationClip(name, this, embedded);\r\n this._animations[name] = animation;\r\n this._model.scene?.queueUpdateNode(this._model);\r\n return animation;\r\n }\r\n }\r\n /**\r\n * Delete and dispose an animation clip by name.\r\n *\r\n * - If the animation is currently playing, it is first stopped (immediately).\r\n *\r\n * @param name - Name of the animation to remove.\r\n */\r\n deleteAnimation(name: string) {\r\n const animation = this._animations[name];\r\n if (animation) {\r\n this.stopAnimation(name);\r\n delete this._animations[name];\r\n animation.dispose();\r\n }\r\n }\r\n /**\r\n * Get the list of all registered animation names.\r\n *\r\n * @returns An array of clip names.\r\n */\r\n getAnimationNames() {\r\n return Object.keys(this._animations);\r\n }\r\n /**\r\n * Advance and apply active animations.\r\n *\r\n * Responsibilities per call:\r\n * - Update time cursor for each active clip (respecting speedRatio and looping).\r\n * - Enforce repeat limits and apply fade-out termination if configured.\r\n * - For each animated target, blend active tracks (weighted by clip weight × fade-in × fade-out)\r\n * and apply the resulting state to the target.\r\n * - Apply all active skeletons to update skinning transforms.\r\n *\r\n * @param deltaInSeconds - Time step in seconds since last update.\r\n */\r\n update(deltaInSeconds: number) {\r\n this._activeAnimations.forEach((v, k) => {\r\n if (v.fadeOut > 0 && v.fadeOutStart < 0) {\r\n v.fadeOutStart = v.animateTime;\r\n }\r\n // Update animation time\r\n if (v.firstFrame) {\r\n v.firstFrame = false;\r\n } else {\r\n const timeAdvance = deltaInSeconds * v.speedRatio;\r\n v.currentTime += timeAdvance;\r\n v.animateTime += timeAdvance;\r\n if (v.currentTime > k.timeDuration) {\r\n v.repeatCounter++;\r\n v.currentTime = 0;\r\n } else if (v.currentTime < 0) {\r\n v.repeatCounter++;\r\n v.currentTime = k.timeDuration;\r\n }\r\n if (v.repeat !== 0 && v.repeatCounter >= v.repeat) {\r\n this.stopAnimation(k.name);\r\n } else if (v.fadeOut > 0) {\r\n if (v.animateTime - v.fadeOutStart >= v.fadeOut) {\r\n this.stopAnimation(k.name);\r\n }\r\n }\r\n }\r\n });\r\n // Update tracks\r\n this._activeTracks.forEach((v, k) => {\r\n v.forEach((alltracks) => {\r\n // Only deal with tracks which have not been removed\r\n const tracks = alltracks.filter(\r\n (track) => track.animation && this.isPlayingAnimation(track.animation.name)\r\n );\r\n if (tracks.length > 0) {\r\n const weights = tracks.map((track) => {\r\n const info = this._activeAnimations.get(track.animation!)!;\r\n const weight = info.weight;\r\n const fadeIn = info.fadeIn === 0 ? 1 : Math.min(1, info.animateTime / info.fadeIn);\r\n let fadeOut = 1;\r\n if (info.fadeOut !== 0) {\r\n fadeOut = 1 - (info.animateTime - info.fadeOutStart) / info.fadeOut;\r\n }\r\n return weight * fadeIn * fadeOut;\r\n });\r\n const states = tracks.map((track) => {\r\n const info = this._activeAnimations.get(track.animation!)!;\r\n const t = (info.currentTime / track.animation!.timeDuration) * track.getDuration();\r\n return track.calculateState(k, t);\r\n });\r\n const state = weightedAverage(weights, states, (a, b, t) => {\r\n return tracks[0].mixState(a, b, t);\r\n });\r\n tracks[0].applyState(k, state);\r\n }\r\n });\r\n });\r\n // Update skeletons\r\n this._skeletons.forEach((v) => {\r\n v.get()?.apply(deltaInSeconds);\r\n });\r\n }\r\n /**\r\n * Check whether an animation is currently playing.\r\n *\r\n * @param name - Optional animation name. If omitted, returns true if any animation is playing.\r\n * @returns True if playing; otherwise false.\r\n */\r\n isPlayingAnimation(name?: string) {\r\n if (name) {\r\n const animation = this._animations[name];\r\n return !!animation && this._activeAnimations.has(animation);\r\n }\r\n return this._activeAnimations.size > 0;\r\n }\r\n /**\r\n * Get an animation clip by name.\r\n *\r\n * Alias of `get(name)` returning a nullable type.\r\n *\r\n * @param name - Name of the animation.\r\n * @returns The clip if present; otherwise null.\r\n */\r\n getAnimationClip(name: string) {\r\n return this._animations[name] ?? null;\r\n }\r\n /**\r\n * Set the runtime blend weight for a currently playing animation.\r\n *\r\n * Has no effect if the clip is not active.\r\n *\r\n * @param name - Name of the playing animation.\r\n * @param weight - New weight value used during blending.\r\n */\r\n setAnimationWeight(name: string, weight: number) {\r\n const ani = this._animations[name];\r\n if (!ani) {\r\n console.error(`Animation ${name} not exists`);\r\n return;\r\n }\r\n const info = this._activeAnimations.get(ani);\r\n if (info) {\r\n info.weight = weight;\r\n }\r\n }\r\n /**\r\n * Start (or update) playback of an animation clip.\r\n *\r\n * Behavior:\r\n * - If the clip is already playing, updates its fade-in (resets fade-out).\r\n * - Otherwise initializes playback state (repeat counter, speed, weight, initial time).\r\n * - Registers clip tracks and skeletons into the active sets for blending and application.\r\n *\r\n * @param name - Name of the animation to play.\r\n * @param options - Playback options (repeat, speedRatio, fadeIn).\r\n */\r\n playAnimation(name: string, options?: PlayAnimationOptions) {\r\n const ani = this._animations[name];\r\n if (!ani) {\r\n console.error(`Animation ${name} not exists`);\r\n return;\r\n }\r\n const fadeIn = Math.max(options?.fadeIn ?? 0, 0);\r\n const info = this._activeAnimations.get(ani);\r\n if (info) {\r\n info.fadeOut = 0;\r\n info.fadeIn = fadeIn;\r\n } else {\r\n const repeat = options?.repeat ?? 0;\r\n const speedRatio = options?.speedRatio ?? 1;\r\n const weight = options?.weight ?? ani.weight ?? 1;\r\n this._activeAnimations.set(ani, {\r\n repeat,\r\n weight,\r\n speedRatio,\r\n fadeIn,\r\n fadeOut: 0,\r\n repeatCounter: 0,\r\n currentTime: speedRatio < 0 ? ani.timeDuration : 0,\r\n animateTime: 0,\r\n fadeOutStart: 0,\r\n firstFrame: true\r\n });\r\n ani.tracks?.forEach((v, k) => {\r\n let nodeTracks = this._activeTracks.get(k);\r\n if (!nodeTracks) {\r\n nodeTracks = new Map();\r\n this._activeTracks.set(k, nodeTracks);\r\n }\r\n for (const track of v) {\r\n const blendId = track.getBlendId();\r\n let blendedTracks = nodeTracks.get(blendId);\r\n if (!blendedTracks) {\r\n blendedTracks = [];\r\n nodeTracks.set(blendId, blendedTracks);\r\n }\r\n blendedTracks.push(track);\r\n }\r\n });\r\n ani.skeletons?.forEach((v, k) => {\r\n const skeleton = this.model.findSkeletonById(k);\r\n if (skeleton) {\r\n const refcount = this._activeSkeletons.get(skeleton);\r\n if (refcount) {\r\n this._activeSkeletons.set(skeleton, refcount + 1);\r\n } else {\r\n this._activeSkeletons.set(skeleton, 1);\r\n }\r\n skeleton.playing = true;\r\n }\r\n });\r\n }\r\n }\r\n /**\r\n * Stop playback of an animation clip.\r\n *\r\n * Behavior:\r\n * - If `options.fadeOut > 0`, marks the clip for fade-out; actual removal occurs after fade completes.\r\n * - If `fadeOut` is 0 or omitted, immediately:\r\n * - Removes the clip from active animations.\r\n * - Unregisters its tracks from active track maps.\r\n * - Decrements skeleton reference counts; resets and removes skeletons when refcount reaches 0.\r\n *\r\n * @param name - Name of the animation to stop.\r\n * @param options - Optional fade-out configuration.\r\n */\r\n stopAnimation(name: string, options?: StopAnimationOptions) {\r\n const ani = this._animations[name];\r\n if (!ani) {\r\n console.error(`Animation ${name} not exists`);\r\n return;\r\n }\r\n const info = this._activeAnimations.get(ani);\r\n if (info) {\r\n const fadeOut = Math.max(options?.fadeOut ?? 0, 0);\r\n if (fadeOut !== 0) {\r\n info.fadeOut = fadeOut;\r\n info.fadeOutStart = -1;\r\n } else {\r\n this._activeAnimations.delete(ani);\r\n this._activeTracks.forEach((v) => {\r\n v.forEach((tracks, id) => {\r\n v.set(\r\n id,\r\n tracks.filter((track) => track.animation !== ani)\r\n );\r\n });\r\n });\r\n ani.skeletons?.forEach((v, k) => {\r\n const skeleton = this.model.findSkeletonById(k);\r\n if (skeleton) {\r\n const refcount = this._activeSkeletons.get(skeleton)!;\r\n if (refcount === 1) {\r\n skeleton.reset();\r\n this._activeSkeletons.delete(skeleton);\r\n } else {\r\n this._activeSkeletons.set(skeleton, refcount - 1);\r\n }\r\n }\r\n });\r\n }\r\n }\r\n }\r\n /**\r\n * Dispose the animation set and release owned resources.\r\n *\r\n * - Disposes the weak reference to the model.\r\n * - Disposes all registered animation clips.\r\n * - Clears active animations, tracks, and skeleton references.\r\n */\r\n protected onDispose() {\r\n super.onDispose();\r\n for (const k in this._animations) {\r\n this._animations[k]!.dispose();\r\n }\r\n this._animations = {};\r\n this._activeAnimations.clear();\r\n this._activeSkeletons.clear();\r\n this._activeTracks.clear();\r\n }\r\n}\r\n"],"names":["AnimationSet","Disposable","model","_model","_animations","_activeTracks","Map","_activeSkeletons","_activeAnimations","_skeletons","numAnimations","Object","getOwnPropertyNames","length","skeletons","get","name","createAnimation","embedded","console","error","animation","AnimationClip","scene","queueUpdateNode","deleteAnimation","stopAnimation","dispose","getAnimationNames","keys","update","deltaInSeconds","forEach","v","k","fadeOut","fadeOutStart","animateTime","firstFrame","timeAdvance","speedRatio","currentTime","timeDuration","repeatCounter","repeat","alltracks","tracks","filter","track","isPlayingAnimation","weights","map","info","weight","fadeIn","Math","min","states","t","getDuration","calculateState","state","weightedAverage","a","b","mixState","applyState","apply","has","size","getAnimationClip","setAnimationWeight","ani","playAnimation","options","max","set","nodeTracks","blendId","getBlendId","blendedTracks","push","skeleton","findSkeletonById","refcount","playing","delete","id","reset","onDispose","clear"],"mappings":"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"}
1
+ {"version":3,"file":"animationset.js","sources":["../../src/animation/animationset.ts"],"sourcesContent":["import { weightedAverage, Disposable, Interpolator } from '@zephyr3d/base';\r\nimport type { DRef, IDisposable, Nullable, Quaternion } from '@zephyr3d/base';\r\nimport type { SceneNode } from '../scene';\r\nimport { AnimationClip } from './animation';\r\nimport type { AnimationTrack } from './animationtrack';\r\nimport { NodeRotationTrack } from './rotationtrack';\r\nimport { NodeEulerRotationTrack } from './eulerrotationtrack';\r\nimport { NodeTranslationTrack } from './translationtrack';\r\nimport { NodeScaleTrack } from './scaletrack';\r\nimport { Skeleton } from './skeleton';\r\n\r\n/**\r\n * Options for playing an animation.\r\n *\r\n * Controls looping, playback speed (including reverse), and fade-in blending.\r\n * @public\r\n **/\r\nexport type PlayAnimationOptions = {\r\n /**\r\n * Number of loops to play.\r\n *\r\n * - 0: infinite looping (default).\r\n * - n \\> 0: play exactly n loops (each loop is one full duration of the clip).\r\n */\r\n repeat?: number;\r\n /**\r\n * Playback speed multiplier.\r\n *\r\n * - 1: normal speed (default).\r\n * - \\>1: faster; \\<1: slower.\r\n * - Negative values play the clip in reverse. The initial `currentTime` will be set to the end.\r\n */\r\n speedRatio?: number;\r\n /**\r\n * Fade-in duration in seconds.\r\n *\r\n * Interpolates the animation weight from 0 to the clip's configured weight over this time.\r\n * Use together with `stopAnimation(..., { fadeOut })` for smooth cross-fading.\r\n * Default is 0 (no fade-in).\r\n */\r\n fadeIn?: number;\r\n /**\r\n * Weight of the animation clip.\r\n *\r\n * Used during blending when multiple animations affect the same property.\r\n * Default is the clip's configured weight.\r\n */\r\n weight?: number;\r\n};\r\n\r\n/**\r\n * Options for stopping an animation.\r\n *\r\n * Allows a graceful fade-out instead of abrupt stop.\r\n * @public\r\n */\r\nexport type StopAnimationOptions = {\r\n /**\r\n * Fade-out duration in seconds.\r\n *\r\n * Interpolates the current animation weight down to 0 over this time.\r\n * Default is 0 (immediate stop).\r\n */\r\n fadeOut?: number;\r\n};\r\n\r\n/**\r\n * Animation set\r\n *\r\n * Manages a collection of named animation clips for a model and orchestrates:\r\n * - Playback state (time, loops, speed, weights, fade-in/out).\r\n * - Blending across multiple tracks targeting the same property via weighted averages.\r\n * - Skeleton usage and application for clips that drive skeletal animation.\r\n * - Active track registration and cleanup as clips start/stop.\r\n *\r\n * Usage:\r\n * - Create or retrieve `AnimationClip`s by name.\r\n * - Start playback with `playAnimation(name, options)`.\r\n * - Advance animation with `update(deltaSeconds)`.\r\n * - Optionally adjust weight while playing with `setAnimationWeight(name, weight)`.\r\n *\r\n * Lifetime:\r\n * - Disposing the set releases references to the model, clips, and clears active state.\r\n *\r\n * @public\r\n */\r\nexport class AnimationSet extends Disposable implements IDisposable {\r\n /** @internal */\r\n private _model: SceneNode;\r\n /** @internal */\r\n private _animations: Partial<Record<string, AnimationClip>>;\r\n /** @internal */\r\n private _skeletons: DRef<Skeleton>[];\r\n /** @internal */\r\n private readonly _activeTracks: Map<object, Map<unknown, AnimationTrack[]>>;\r\n /** @internal */\r\n private readonly _activeSkeletons: Map<Skeleton, number>;\r\n /** @internal */\r\n private readonly _activeAnimations: Map<\r\n AnimationClip,\r\n {\r\n currentTime: number;\r\n repeat: number;\r\n repeatCounter: number;\r\n weight: number;\r\n speedRatio: number;\r\n firstFrame: boolean;\r\n fadeIn: number;\r\n fadeOut: number;\r\n fadeOutStart: number;\r\n animateTime: number;\r\n }\r\n >;\r\n /**\r\n * Create an AnimationSet controlling the provided model.\r\n *\r\n * @param model - The SceneNode (model root) controlled by this animation set.\r\n */\r\n constructor(model: SceneNode) {\r\n super();\r\n this._model = model;\r\n this._animations = {};\r\n this._activeTracks = new Map();\r\n this._activeSkeletons = new Map();\r\n this._activeAnimations = new Map();\r\n this._skeletons = [];\r\n }\r\n /**\r\n * The model (SceneNode) controlled by this animation set.\r\n */\r\n get model() {\r\n return this._model;\r\n }\r\n /**\r\n * Number of animation clips registered in this set.\r\n */\r\n get numAnimations() {\r\n return Object.getOwnPropertyNames(this._animations).length;\r\n }\r\n /**\r\n * The skeletons used by animations in this set.\r\n */\r\n get skeletons() {\r\n return this._skeletons;\r\n }\r\n /**\r\n * Retrieve an animation clip by name.\r\n *\r\n * @param name - Name of the animation.\r\n * @returns The clip if present; otherwise null.\r\n */\r\n get(name: string) {\r\n return this._animations[name] ?? null;\r\n }\r\n /**\r\n * Create and register a new animation clip.\r\n *\r\n * @param name - Unique name for the animation clip.\r\n * @param embedded - Whether the clip is embedded/owned (implementation-specific). Default false.\r\n * @returns The created clip, or null if the name is empty or not unique.\r\n */\r\n createAnimation(name: string, embedded = false) {\r\n if (!name || this._animations[name]) {\r\n console.error('Animation must have unique name');\r\n return null;\r\n } else {\r\n const animation = new AnimationClip(name, this, embedded);\r\n this._animations[name] = animation;\r\n this._model.scene?.queueUpdateNode(this._model);\r\n return animation;\r\n }\r\n }\r\n /**\r\n * Delete and dispose an animation clip by name.\r\n *\r\n * - If the animation is currently playing, it is first stopped (immediately).\r\n *\r\n * @param name - Name of the animation to remove.\r\n */\r\n deleteAnimation(name: string) {\r\n const animation = this._animations[name];\r\n if (animation) {\r\n this.stopAnimation(name);\r\n delete this._animations[name];\r\n animation.dispose();\r\n }\r\n }\r\n /**\r\n * Get the list of all registered animation names.\r\n *\r\n * @returns An array of clip names.\r\n */\r\n getAnimationNames() {\r\n return Object.keys(this._animations);\r\n }\r\n /**\r\n * Advance and apply active animations.\r\n *\r\n * Responsibilities per call:\r\n * - Update time cursor for each active clip (respecting speedRatio and looping).\r\n * - Enforce repeat limits and apply fade-out termination if configured.\r\n * - For each animated target, blend active tracks (weighted by clip weight × fade-in × fade-out)\r\n * and apply the resulting state to the target.\r\n * - Apply all active skeletons to update skinning transforms.\r\n *\r\n * @param deltaInSeconds - Time step in seconds since last update.\r\n */\r\n update(deltaInSeconds: number) {\r\n this._activeAnimations.forEach((v, k) => {\r\n if (v.fadeOut > 0 && v.fadeOutStart < 0) {\r\n v.fadeOutStart = v.animateTime;\r\n }\r\n // Update animation time\r\n if (v.firstFrame) {\r\n v.firstFrame = false;\r\n } else {\r\n const timeAdvance = deltaInSeconds * v.speedRatio;\r\n v.currentTime += timeAdvance;\r\n v.animateTime += timeAdvance;\r\n if (v.currentTime > k.timeDuration) {\r\n v.repeatCounter++;\r\n v.currentTime = 0;\r\n } else if (v.currentTime < 0) {\r\n v.repeatCounter++;\r\n v.currentTime = k.timeDuration;\r\n }\r\n if (v.repeat !== 0 && v.repeatCounter >= v.repeat) {\r\n this.stopAnimation(k.name);\r\n } else if (v.fadeOut > 0) {\r\n if (v.animateTime - v.fadeOutStart >= v.fadeOut) {\r\n this.stopAnimation(k.name);\r\n }\r\n }\r\n }\r\n });\r\n // Update tracks\r\n this._activeTracks.forEach((v, k) => {\r\n v.forEach((alltracks) => {\r\n // Only deal with tracks which have not been removed\r\n const tracks = alltracks.filter(\r\n (track) => track.animation && this.isPlayingAnimation(track.animation.name)\r\n );\r\n if (tracks.length > 0) {\r\n const weights = tracks.map((track) => {\r\n const info = this._activeAnimations.get(track.animation!)!;\r\n const weight = info.weight;\r\n const fadeIn = info.fadeIn === 0 ? 1 : Math.min(1, info.animateTime / info.fadeIn);\r\n let fadeOut = 1;\r\n if (info.fadeOut !== 0) {\r\n fadeOut = 1 - (info.animateTime - info.fadeOutStart) / info.fadeOut;\r\n }\r\n return weight * fadeIn * fadeOut;\r\n });\r\n const states = tracks.map((track) => {\r\n const info = this._activeAnimations.get(track.animation!)!;\r\n const t = (info.currentTime / track.animation!.timeDuration) * track.getDuration();\r\n return track.calculateState(k, t);\r\n });\r\n const state = weightedAverage(weights, states, (a, b, t) => {\r\n return tracks[0].mixState(a, b, t);\r\n });\r\n tracks[0].applyState(k, state);\r\n }\r\n });\r\n });\r\n // Update skeletons\r\n this._skeletons.forEach((v) => {\r\n v.get()?.apply(deltaInSeconds);\r\n });\r\n }\r\n /**\r\n * Check whether an animation is currently playing.\r\n *\r\n * @param name - Optional animation name. If omitted, returns true if any animation is playing.\r\n * @returns True if playing; otherwise false.\r\n */\r\n isPlayingAnimation(name?: string) {\r\n if (name) {\r\n const animation = this._animations[name];\r\n return !!animation && this._activeAnimations.has(animation);\r\n }\r\n return this._activeAnimations.size > 0;\r\n }\r\n /**\r\n * Get an animation clip by name.\r\n *\r\n * Alias of `get(name)` returning a nullable type.\r\n *\r\n * @param name - Name of the animation.\r\n * @returns The clip if present; otherwise null.\r\n */\r\n getAnimationClip(name: string) {\r\n return this._animations[name] ?? null;\r\n }\r\n /**\r\n * Set the runtime blend weight for a currently playing animation.\r\n *\r\n * Has no effect if the clip is not active.\r\n *\r\n * @param name - Name of the playing animation.\r\n * @param weight - New weight value used during blending.\r\n */\r\n setAnimationWeight(name: string, weight: number) {\r\n const ani = this._animations[name];\r\n if (!ani) {\r\n console.error(`Animation ${name} not exists`);\r\n return;\r\n }\r\n const info = this._activeAnimations.get(ani);\r\n if (info) {\r\n info.weight = weight;\r\n }\r\n }\r\n /**\r\n * Start (or update) playback of an animation clip.\r\n *\r\n * Behavior:\r\n * - If the clip is already playing, updates its fade-in (resets fade-out).\r\n * - Otherwise initializes playback state (repeat counter, speed, weight, initial time).\r\n * - Registers clip tracks and skeletons into the active sets for blending and application.\r\n *\r\n * @param name - Name of the animation to play.\r\n * @param options - Playback options (repeat, speedRatio, fadeIn).\r\n */\r\n playAnimation(name: string, options?: PlayAnimationOptions) {\r\n const ani = this._animations[name];\r\n if (!ani) {\r\n console.error(`Animation ${name} not exists`);\r\n return;\r\n }\r\n const fadeIn = Math.max(options?.fadeIn ?? 0, 0);\r\n const info = this._activeAnimations.get(ani);\r\n if (info) {\r\n info.fadeOut = 0;\r\n info.fadeIn = fadeIn;\r\n } else {\r\n const repeat = options?.repeat ?? 0;\r\n const speedRatio = options?.speedRatio ?? 1;\r\n const weight = options?.weight ?? ani.weight ?? 1;\r\n this._activeAnimations.set(ani, {\r\n repeat,\r\n weight,\r\n speedRatio,\r\n fadeIn,\r\n fadeOut: 0,\r\n repeatCounter: 0,\r\n currentTime: speedRatio < 0 ? ani.timeDuration : 0,\r\n animateTime: 0,\r\n fadeOutStart: 0,\r\n firstFrame: true\r\n });\r\n ani.tracks?.forEach((v, k) => {\r\n let nodeTracks = this._activeTracks.get(k);\r\n if (!nodeTracks) {\r\n nodeTracks = new Map();\r\n this._activeTracks.set(k, nodeTracks);\r\n }\r\n for (const track of v) {\r\n const blendId = track.getBlendId();\r\n let blendedTracks = nodeTracks.get(blendId);\r\n if (!blendedTracks) {\r\n blendedTracks = [];\r\n nodeTracks.set(blendId, blendedTracks);\r\n }\r\n blendedTracks.push(track);\r\n }\r\n });\r\n ani.skeletons?.forEach((v, k) => {\r\n const skeleton = this.model.findSkeletonById(k);\r\n if (skeleton) {\r\n const refcount = this._activeSkeletons.get(skeleton);\r\n if (refcount) {\r\n this._activeSkeletons.set(skeleton, refcount + 1);\r\n } else {\r\n this._activeSkeletons.set(skeleton, 1);\r\n }\r\n skeleton.playing = true;\r\n }\r\n });\r\n }\r\n }\r\n /**\r\n * Stop playback of an animation clip.\r\n *\r\n * Behavior:\r\n * - If `options.fadeOut > 0`, marks the clip for fade-out; actual removal occurs after fade completes.\r\n * - If `fadeOut` is 0 or omitted, immediately:\r\n * - Removes the clip from active animations.\r\n * - Unregisters its tracks from active track maps.\r\n * - Decrements skeleton reference counts; resets and removes skeletons when refcount reaches 0.\r\n *\r\n * @param name - Name of the animation to stop.\r\n * @param options - Optional fade-out configuration.\r\n */\r\n stopAnimation(name: string, options?: StopAnimationOptions) {\r\n const ani = this._animations[name];\r\n if (!ani) {\r\n console.error(`Animation ${name} not exists`);\r\n return;\r\n }\r\n const info = this._activeAnimations.get(ani);\r\n if (info) {\r\n const fadeOut = Math.max(options?.fadeOut ?? 0, 0);\r\n if (fadeOut !== 0) {\r\n info.fadeOut = fadeOut;\r\n info.fadeOutStart = -1;\r\n } else {\r\n this._activeAnimations.delete(ani);\r\n this._activeTracks.forEach((v) => {\r\n v.forEach((tracks, id) => {\r\n v.set(\r\n id,\r\n tracks.filter((track) => track.animation !== ani)\r\n );\r\n });\r\n });\r\n ani.skeletons?.forEach((v, k) => {\r\n const skeleton = this.model.findSkeletonById(k);\r\n if (skeleton) {\r\n const refcount = this._activeSkeletons.get(skeleton)!;\r\n if (refcount === 1) {\r\n skeleton.reset();\r\n this._activeSkeletons.delete(skeleton);\r\n } else {\r\n this._activeSkeletons.set(skeleton, refcount - 1);\r\n }\r\n }\r\n });\r\n }\r\n }\r\n }\r\n /**\r\n * Copy an animation clip from another AnimationSet into this one.\r\n *\r\n * Prerequisites:\r\n * - Both sets must reference skeletons with identical joint names and counts.\r\n * - The source clip must exist in `sourceSet`.\r\n *\r\n * @param sourceSet - The AnimationSet to copy from.\r\n * @param animationName - Name of the clip to copy.\r\n * @param targetName - Name for the new clip in this set. Defaults to `animationName`.\r\n * @param excludeJoint - Optional predicate; joints whose name returns true are excluded from\r\n * skeleton structure matching.\r\n * @returns The newly created AnimationClip, or null on failure.\r\n */\r\n copyAnimationFrom(\r\n sourceSet: AnimationSet,\r\n animationName: string,\r\n targetName?: string,\r\n excludeJoint?: (jointName: string) => boolean\r\n ): AnimationClip | null {\r\n const destName = targetName ?? animationName;\r\n const sourceClip = sourceSet.get(animationName);\r\n if (!sourceClip) {\r\n console.error(`copyAnimationFrom: animation '${animationName}' not found in source set`);\r\n return null;\r\n }\r\n if (this._animations[destName]) {\r\n console.error(`copyAnimationFrom: animation '${destName}' already exists in target set`);\r\n return null;\r\n }\r\n\r\n // Per-joint retargeting info indexed by source joint node\r\n type JointRemap = {\r\n dstNode: SceneNode;\r\n srcBindRot: Quaternion;\r\n dstBindRot: Quaternion;\r\n translationScale: number;\r\n };\r\n if (sourceClip.skeletons.size !== 1) {\r\n console.error(`copyAnimationFrom: source animation clip must be affected by exactly one skeleton`);\r\n return null;\r\n }\r\n const srcSkeletonId = [...sourceClip.skeletons][0];\r\n const srcSkeleton = Skeleton.findSkeletonById(srcSkeletonId);\r\n if (!srcSkeleton) {\r\n console.error(`copyAnimationFrom: source skeleton '${srcSkeletonId}' not found`);\r\n return null;\r\n }\r\n const nodeMap = new Map<object, SceneNode>();\r\n const jointRemapBySrcNode = new Map<object, JointRemap>();\r\n\r\n const jointsFiltered = srcSkeleton.joints.filter((j) => !excludeJoint?.(j.name));\r\n const srcRootNode = findRootJoint(jointsFiltered);\r\n if (!srcRootNode) {\r\n console.error(`copyAnimationFrom: cannot determine the root joint for source skeleton`);\r\n return null;\r\n }\r\n // Build filtered joint lists for matching (exclude joints rejected by filterJoint)\r\n const srcJointsFiltered = sortJoints(srcRootNode, jointsFiltered);\r\n if (!srcJointsFiltered) {\r\n console.error(`copyAnimationFrom: invalid source skeleton structure`);\r\n return null;\r\n }\r\n let dstJointsFiltered: SceneNode[] = [];\r\n const dstSkeleton = this._skeletons\r\n .map((ref) => ref.get())\r\n .find((sk) => {\r\n if (!sk) {\r\n return false;\r\n }\r\n const jointsFiltered = sk.joints.filter((j) => !excludeJoint?.(j.name));\r\n if (jointsFiltered.length !== srcJointsFiltered.length) {\r\n return false;\r\n }\r\n const rootNode = findRootJoint(jointsFiltered);\r\n if (!rootNode) {\r\n return false;\r\n }\r\n const sortedJointsFiltered = sortJoints(rootNode, jointsFiltered);\r\n if (\r\n sortedJointsFiltered &&\r\n srcJointsFiltered.every((j, i) => j.name === sortedJointsFiltered[i].name)\r\n ) {\r\n dstJointsFiltered = sortedJointsFiltered;\r\n return true;\r\n }\r\n return false;\r\n });\r\n if (!dstJointsFiltered || !dstSkeleton) {\r\n console.error(`copyAnimationFrom: no matching skeleton in target set for '${srcSkeletonId}'`);\r\n return null;\r\n }\r\n // Build remap only for joints that pass the filter\r\n for (let fi = 0; fi < srcJointsFiltered.length; fi++) {\r\n const srcJoint = srcJointsFiltered[fi];\r\n const dstJoint = dstJointsFiltered[fi];\r\n const si = srcSkeleton.joints.indexOf(srcJoint);\r\n const di = dstSkeleton.joints.indexOf(dstJoint);\r\n const srcLen = srcSkeleton.bindPose[si].position.magnitude;\r\n const dstLen = dstSkeleton.bindPose[di].position.magnitude;\r\n const translationScale = srcLen > 1e-6 ? dstLen / srcLen : 1;\r\n nodeMap.set(srcJoint, dstJoint);\r\n jointRemapBySrcNode.set(srcJoint, {\r\n dstNode: dstJoint,\r\n srcBindRot: srcSkeleton.bindPose[si].rotation,\r\n dstBindRot: dstSkeleton.bindPose[di].rotation,\r\n translationScale\r\n });\r\n }\r\n\r\n const dstClip = this.createAnimation(destName);\r\n if (!dstClip) {\r\n return null;\r\n }\r\n dstClip.timeDuration = sourceClip.timeDuration;\r\n dstClip.weight = sourceClip.weight;\r\n dstClip.autoPlay = sourceClip.autoPlay;\r\n\r\n // Register destination skeleton\r\n dstClip.addSkeleton(dstSkeleton.persistentId);\r\n\r\n for (const srcNode of srcJointsFiltered) {\r\n const srcTracks = sourceClip.tracks.get(srcNode);\r\n if (!srcTracks) {\r\n console.error(`copyAnimationFrom: no track for joint: ${srcNode.name}`);\r\n return null;\r\n }\r\n const dstNode = nodeMap.get(srcNode)!;\r\n const remap = jointRemapBySrcNode.get(srcNode) ?? null;\r\n\r\n for (const srcTrack of srcTracks) {\r\n let dstTrack: AnimationTrack;\r\n if (srcTrack instanceof NodeRotationTrack) {\r\n dstTrack = retargetRotationTrack(srcTrack);\r\n } else if (srcTrack instanceof NodeEulerRotationTrack) {\r\n dstTrack = retargetEulerToRotationTrack(srcTrack);\r\n } else if (srcTrack instanceof NodeTranslationTrack) {\r\n dstTrack = retargetTranslationTrack(srcTrack, remap);\r\n } else if (srcTrack instanceof NodeScaleTrack) {\r\n dstTrack = new NodeScaleTrack(cloneInterpolator(srcTrack.interpolator));\r\n } else {\r\n console.warn(`copyAnimationFrom: unsupported track type '${srcTrack.constructor.name}', skipping`);\r\n continue;\r\n }\r\n\r\n dstTrack.name = srcTrack.name;\r\n dstTrack.target = srcTrack.target;\r\n dstTrack.jointIndex = srcTrack.jointIndex;\r\n dstClip.addTrack(dstNode, dstTrack);\r\n }\r\n }\r\n\r\n return dstClip;\r\n\r\n function findRootJoint(joints: SceneNode[]) {\r\n let root: Nullable<SceneNode> = null;\r\n for (const joint of joints) {\r\n if (!root) {\r\n root = joint;\r\n }\r\n while (!root!.isParentOf(joint)) {\r\n root = root!.parent;\r\n }\r\n if (!root) {\r\n break;\r\n }\r\n }\r\n if (!root || !joints.includes(root)) {\r\n return null;\r\n }\r\n return root;\r\n }\r\n\r\n function sortJoints(root: SceneNode, joints: SceneNode[]): Nullable<SceneNode[]> {\r\n const ordered: SceneNode[] = [];\r\n const visited = new Set<SceneNode>();\r\n function visit(joint: SceneNode) {\r\n if (visited.has(joint)) {\r\n return true;\r\n }\r\n if (!joints.includes(joint)) {\r\n return false;\r\n }\r\n if (joint !== root) {\r\n visit(joint.parent!);\r\n }\r\n visited.add(joint);\r\n ordered.push(joint);\r\n return true;\r\n }\r\n for (const joint of joints) {\r\n if (!visit(joint)) {\r\n return null;\r\n }\r\n }\r\n return ordered;\r\n }\r\n function retargetTranslationTrack(\r\n src: NodeTranslationTrack,\r\n remap: JointRemap | null\r\n ): NodeTranslationTrack {\r\n if (!remap || Math.abs(remap.translationScale - 1) < 1e-6) {\r\n return new NodeTranslationTrack(cloneInterpolator(src.interpolator));\r\n }\r\n const scale = remap.translationScale;\r\n const srcOutputs = src.interpolator.outputs as Float32Array;\r\n const newOutputs = new Float32Array(srcOutputs.length);\r\n for (let i = 0; i < newOutputs.length; i++) {\r\n newOutputs[i] = srcOutputs[i] * scale;\r\n }\r\n return new NodeTranslationTrack(\r\n new Interpolator(\r\n src.interpolator.mode,\r\n 'vec3',\r\n new Float32Array(src.interpolator.inputs as Float32Array),\r\n newOutputs\r\n )\r\n );\r\n }\r\n\r\n function cloneInterpolator(src: Interpolator): Interpolator {\r\n return new Interpolator(\r\n src.mode,\r\n src.target,\r\n src.inputs instanceof Float32Array ? new Float32Array(src.inputs) : [...src.inputs],\r\n src.outputs instanceof Float32Array ? new Float32Array(src.outputs) : [...src.outputs]\r\n );\r\n }\r\n\r\n function retargetRotationTrack(src: NodeRotationTrack): NodeRotationTrack {\r\n const isCubic = src.interpolator.mode === 'cubicspline';\r\n const frameStride = isCubic ? 12 : 4;\r\n const numFrames = (src.interpolator.inputs as Float32Array).length;\r\n const srcOutputs = src.interpolator.outputs as Float32Array;\r\n const newOutputs = new Float32Array(srcOutputs.length);\r\n for (let f = 0; f < numFrames; f++) {\r\n const base = f * frameStride;\r\n newOutputs.set(srcOutputs.subarray(base, base + (isCubic ? 12 : 4)), base);\r\n }\r\n return new NodeRotationTrack(\r\n new Interpolator(\r\n src.interpolator.mode,\r\n 'quat',\r\n new Float32Array(src.interpolator.inputs as Float32Array),\r\n newOutputs\r\n )\r\n );\r\n }\r\n\r\n function retargetEulerToRotationTrack(src: NodeEulerRotationTrack): NodeRotationTrack {\r\n const srcInputs = src.interpolator.inputs as Float32Array;\r\n const srcOutputs = src.interpolator.outputs as Float32Array;\r\n const numFrames = srcInputs.length;\r\n const newOutputs = new Float32Array(numFrames * 3);\r\n for (let f = 0; f < numFrames; f++) {\r\n const base = f * 3;\r\n newOutputs.set(srcOutputs.subarray(base, base + 3), base);\r\n }\r\n return new NodeRotationTrack(\r\n new Interpolator('linear', 'quat', new Float32Array(srcInputs), newOutputs)\r\n );\r\n }\r\n }\r\n\r\n /**\r\n * Dispose the animation set and release owned resources.\r\n *\r\n * - Disposes the weak reference to the model.\r\n * - Disposes all registered animation clips.\r\n * - Clears active animations, tracks, and skeleton references.\r\n */\r\n protected onDispose() {\r\n super.onDispose();\r\n for (const k in this._animations) {\r\n this._animations[k]!.dispose();\r\n }\r\n this._animations = {};\r\n this._activeAnimations.clear();\r\n this._activeSkeletons.clear();\r\n this._activeTracks.clear();\r\n }\r\n}\r\n"],"names":["AnimationSet","Disposable","model","_model","_animations","_activeTracks","Map","_activeSkeletons","_activeAnimations","_skeletons","numAnimations","Object","getOwnPropertyNames","length","skeletons","get","name","createAnimation","embedded","console","error","animation","AnimationClip","scene","queueUpdateNode","deleteAnimation","stopAnimation","dispose","getAnimationNames","keys","update","deltaInSeconds","forEach","v","k","fadeOut","fadeOutStart","animateTime","firstFrame","timeAdvance","speedRatio","currentTime","timeDuration","repeatCounter","repeat","alltracks","tracks","filter","track","isPlayingAnimation","weights","map","info","weight","fadeIn","Math","min","states","t","getDuration","calculateState","state","weightedAverage","a","b","mixState","applyState","apply","has","size","getAnimationClip","setAnimationWeight","ani","playAnimation","options","max","set","nodeTracks","blendId","getBlendId","blendedTracks","push","skeleton","findSkeletonById","refcount","playing","delete","id","reset","copyAnimationFrom","sourceSet","animationName","targetName","excludeJoint","destName","sourceClip","srcSkeletonId","srcSkeleton","Skeleton","nodeMap","jointRemapBySrcNode","jointsFiltered","joints","j","srcRootNode","findRootJoint","srcJointsFiltered","sortJoints","dstJointsFiltered","dstSkeleton","ref","find","sk","rootNode","sortedJointsFiltered","every","i","fi","srcJoint","dstJoint","si","indexOf","di","srcLen","bindPose","position","magnitude","dstLen","translationScale","dstNode","srcBindRot","rotation","dstBindRot","dstClip","autoPlay","addSkeleton","persistentId","srcNode","srcTracks","remap","srcTrack","dstTrack","NodeRotationTrack","retargetRotationTrack","NodeEulerRotationTrack","retargetEulerToRotationTrack","NodeTranslationTrack","retargetTranslationTrack","NodeScaleTrack","cloneInterpolator","interpolator","warn","target","jointIndex","addTrack","root","joint","isParentOf","parent","includes","ordered","visited","Set","visit","add","src","abs","scale","srcOutputs","outputs","newOutputs","Float32Array","Interpolator","mode","inputs","isCubic","frameStride","numFrames","f","base","subarray","srcInputs","onDispose","clear"],"mappings":"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"}
@@ -327,9 +327,9 @@ import { IKUtils } from './ik_utils.js';
327
327
  // Apply swing-twist constraint to prevent over-rotation
328
328
  const swing = new Quaternion();
329
329
  const twist = new Quaternion();
330
- IKUtils.decomposeSwingTwist(worldRotation, newDirNorm, swing, twist);
330
+ worldRotation.decomposeSwingTwist(newDirNorm, swing, twist);
331
331
  // Get twist angle
332
- let twistAngle = IKUtils.getTwistAngle(twist, newDirNorm);
332
+ let twistAngle = twist.getTwistAngle(newDirNorm);
333
333
  // Get twist constraint for this joint
334
334
  const constraint = this._twistConstraints.get(i);
335
335
  if (constraint) {
@@ -339,8 +339,7 @@ import { IKUtils } from './ik_utils.js';
339
339
  // Store for next frame
340
340
  joint.previousTwist = twistAngle;
341
341
  // Reconstruct rotation from clamped twist: Q = Twist * Swing
342
- const clampedTwist = new Quaternion();
343
- IKUtils.createTwist(twistAngle, newDirNorm, clampedTwist);
342
+ const clampedTwist = Quaternion.fromAxisAngle(newDirNorm, twistAngle);
344
343
  worldRotation = Quaternion.multiply(clampedTwist, swing, worldRotation);
345
344
  // Blend with original rotation based on weight
346
345
  if (weight < 1) {
@@ -1 +1 @@
1
- {"version":3,"file":"ccd_solver.js","sources":["../../../src/animation/ik/ccd_solver.ts"],"sourcesContent":["import { Vector3, Quaternion } from '@zephyr3d/base';\r\nimport { IKSolver } from './ik_solver';\r\nimport type { IKChain } from './ik_chain';\r\nimport { IKUtils } from './ik_utils';\r\nimport type { TwistConstraint } from './ik_constraint';\r\n\r\n/**\r\n * Pole vector configuration for a specific joint.\r\n */\r\ninterface PoleVectorConfig {\r\n /** Pole vector position in world space */\r\n position: Vector3;\r\n /** Weight of the pole vector constraint (0-1) */\r\n weight: number;\r\n}\r\n\r\n/**\r\n * CCD (Cyclic Coordinate Descent) IK solver.\r\n *\r\n * @remarks\r\n * CCD is an iterative IK algorithm that works by:\r\n * 1. Starting from the joint closest to the end effector\r\n * 2. Rotating each joint to point the end effector toward the target\r\n * 3. Moving backward through the chain to the root\r\n * 4. Repeating until convergence or max iterations\r\n *\r\n * CCD is generally faster than FABRIK and works well for chains of any length.\r\n * It's particularly good for tentacles, tails, and other flexible chains.\r\n *\r\n * Supports multiple pole vectors to control the bending direction of different joints.\r\n *\r\n * @public\r\n */\r\nexport class CCDSolver extends IKSolver {\r\n /** Map of joint index to pole vector configuration */\r\n private _poleVectors: Map<number, PoleVectorConfig>;\r\n /** Twist constraints for each joint (indexed by joint index) */\r\n private _twistConstraints: Map<number, TwistConstraint>;\r\n\r\n /**\r\n * Create a CCD solver.\r\n *\r\n * @param chain - The IK chain to solve\r\n * @param maxIterations - Maximum number of iterations (default: 10)\r\n * @param tolerance - Convergence tolerance in world units (default: 0.001)\r\n */\r\n constructor(chain: IKChain, maxIterations = 10, tolerance = 0.001) {\r\n super(chain, maxIterations, tolerance);\r\n this._poleVectors = new Map();\r\n this._twistConstraints = new Map();\r\n\r\n // Set default twist constraints for all joints\r\n for (let i = 0; i < chain.joints.length - 1; i++) {\r\n // Middle joints have more restrictive twist limits\r\n const isMiddleJoint = i > 0 && i < chain.joints.length - 2;\r\n this._twistConstraints.set(i, {\r\n minTwist: isMiddleJoint ? -Math.PI * 0.2 : -Math.PI * 0.3,\r\n maxTwist: isMiddleJoint ? Math.PI * 0.2 : Math.PI * 0.3,\r\n smoothFactor: 0.3\r\n });\r\n }\r\n }\r\n\r\n /**\r\n * Set twist constraint for a specific joint.\r\n *\r\n * @param jointIndex - Index of the joint\r\n * @param minTwist - Minimum twist angle in radians\r\n * @param maxTwist - Maximum twist angle in radians\r\n * @param smoothFactor - Smoothing factor [0-1] (default: 0.3)\r\n */\r\n setTwistConstraint(\r\n jointIndex: number,\r\n minTwist: number,\r\n maxTwist: number,\r\n smoothFactor: number = 0.3\r\n ): void {\r\n if (jointIndex < 0 || jointIndex >= this._chain.joints.length - 1) {\r\n throw new Error(`Invalid joint index: ${jointIndex}`);\r\n }\r\n\r\n this._twistConstraints.set(jointIndex, {\r\n minTwist,\r\n maxTwist,\r\n smoothFactor: Math.max(0, Math.min(1, smoothFactor))\r\n });\r\n }\r\n\r\n /**\r\n * Get twist constraint for a specific joint.\r\n *\r\n * @param jointIndex - Index of the joint\r\n * @returns Twist constraint or undefined if not set\r\n */\r\n getTwistConstraint(jointIndex: number): TwistConstraint | undefined {\r\n return this._twistConstraints.get(jointIndex);\r\n }\r\n\r\n /**\r\n * Remove twist constraint for a specific joint.\r\n *\r\n * @param jointIndex - Index of the joint\r\n * @returns True if a constraint was removed\r\n */\r\n removeTwistConstraint(jointIndex: number): boolean {\r\n return this._twistConstraints.delete(jointIndex);\r\n }\r\n\r\n /**\r\n * Clear all twist constraints.\r\n */\r\n clearTwistConstraints(): void {\r\n this._twistConstraints.clear();\r\n }\r\n\r\n /**\r\n * Set pole vector for a specific joint.\r\n *\r\n * @param jointIndex - Index of the joint to apply pole vector to\r\n * @param poleVector - Pole vector position in world space\r\n * @param weight - Weight of the pole vector constraint (0-1, default: 1)\r\n */\r\n setPoleVector(jointIndex: number, poleVector: Vector3, weight = 1): void {\r\n if (jointIndex < 0 || jointIndex >= this._chain.joints.length) {\r\n throw new Error(`Invalid joint index: ${jointIndex}`);\r\n }\r\n\r\n this._poleVectors.set(jointIndex, {\r\n position: poleVector.clone(),\r\n weight: Math.max(0, Math.min(1, weight))\r\n });\r\n }\r\n\r\n /**\r\n * Remove pole vector for a specific joint.\r\n *\r\n * @param jointIndex - Index of the joint to remove pole vector from\r\n * @returns True if a pole vector was removed, false if none existed\r\n */\r\n removePoleVector(jointIndex: number): boolean {\r\n return this._poleVectors.delete(jointIndex);\r\n }\r\n\r\n /**\r\n * Clear all pole vectors.\r\n */\r\n clearPoleVectors(): void {\r\n this._poleVectors.clear();\r\n }\r\n\r\n /**\r\n * Get pole vector configuration for a specific joint.\r\n *\r\n * @param jointIndex - Index of the joint\r\n * @returns Pole vector configuration or undefined if not set\r\n */\r\n getPoleVector(jointIndex: number): { position: Vector3; weight: number } | undefined {\r\n const config = this._poleVectors.get(jointIndex);\r\n if (config) {\r\n return {\r\n position: config.position.clone(),\r\n weight: config.weight\r\n };\r\n }\r\n return undefined;\r\n }\r\n\r\n /**\r\n * Check if a joint has a pole vector.\r\n *\r\n * @param jointIndex - Index of the joint\r\n * @returns True if the joint has a pole vector\r\n */\r\n hasPoleVector(jointIndex: number): boolean {\r\n return this._poleVectors.has(jointIndex);\r\n }\r\n\r\n /**\r\n * Solve the IK chain to reach the target position using CCD algorithm.\r\n *\r\n * @param target - Target position for the end effector\r\n * @returns True if converged within tolerance, false otherwise\r\n */\r\n solve(target: Vector3): boolean {\r\n const joints = this._chain.joints;\r\n\r\n // Update joint positions from scene nodes before solving\r\n this._chain.updateFromNodes();\r\n\r\n // Store original positions\r\n this._chain.storeOriginalPositions();\r\n\r\n let converged = false;\r\n\r\n for (let iteration = 0; iteration < this._maxIterations; iteration++) {\r\n // Check convergence\r\n const endEffector = joints[joints.length - 1];\r\n const distToTarget = Vector3.distance(endEffector.position, target);\r\n\r\n if (distToTarget < this._tolerance) {\r\n converged = true;\r\n break;\r\n }\r\n\r\n // Iterate backward through joints (from second-to-last to root)\r\n // We skip the end effector itself since it doesn't have a child to rotate toward\r\n for (let i = joints.length - 2; i >= 0; i--) {\r\n const joint = joints[i];\r\n\r\n // Vector from current joint to end effector\r\n const toEnd = Vector3.sub(endEffector.position, joint.position, new Vector3());\r\n const toEndDist = toEnd.magnitude;\r\n\r\n // Vector from current joint to target\r\n const toTarget = Vector3.sub(target, joint.position, new Vector3());\r\n const toTargetDist = toTarget.magnitude;\r\n\r\n // Skip if either vector is too small\r\n if (toEndDist < 0.000001 || toTargetDist < 0.000001) {\r\n continue;\r\n }\r\n\r\n // Normalize vectors\r\n const toEndDir = Vector3.scale(toEnd, 1 / toEndDist, new Vector3());\r\n const toTargetDir = Vector3.scale(toTarget, 1 / toTargetDist, new Vector3());\r\n\r\n // Calculate rotation needed to align end effector toward target\r\n let rotation = new Quaternion();\r\n IKUtils.fromToRotation(toEndDir, toTargetDir, rotation);\r\n\r\n // Apply rotation to all joints from current to end effector\r\n this._rotateJointsFromIndex(i, rotation, joint.position);\r\n\r\n // Apply constraints after rotating this joint\r\n this._applyConstraintsForJoint(i);\r\n }\r\n\r\n // Apply all pole vector constraints after each full iteration\r\n // This is more stable than applying them during the CCD loop\r\n this._applyAllPoleVectors();\r\n }\r\n\r\n return converged;\r\n }\r\n\r\n /**\r\n * Rotate all joints from the given index to the end effector around a pivot point.\r\n *\r\n * @param startIndex - Index of the joint to start rotating from\r\n * @param rotation - Rotation to apply\r\n * @param pivot - Pivot point for rotation (position of the joint being adjusted)\r\n */\r\n private _rotateJointsFromIndex(startIndex: number, rotation: Quaternion, pivot: Vector3): void {\r\n const joints = this._chain.joints;\r\n\r\n // Rotate all joints from startIndex+1 to end effector\r\n for (let i = startIndex + 1; i < joints.length; i++) {\r\n const joint = joints[i];\r\n\r\n // Translate to pivot\r\n const offset = Vector3.sub(joint.position, pivot, new Vector3());\r\n\r\n // Rotate around pivot\r\n const rotated = rotation.transform(offset, new Vector3());\r\n\r\n // Translate back\r\n joint.position.set(Vector3.add(pivot, rotated, new Vector3()));\r\n }\r\n }\r\n\r\n /**\r\n * Apply all pole vector constraints.\r\n *\r\n * @remarks\r\n * This method applies all configured pole vectors to their respective joints.\r\n * Pole vectors are applied in reverse order (from end to root) to minimize\r\n * interference between multiple pole vectors. This ensures that pole vectors\r\n * closer to the end effector are not affected by pole vectors closer to the root.\r\n */\r\n private _applyAllPoleVectors(): void {\r\n if (this._poleVectors.size === 0) {\r\n return;\r\n }\r\n\r\n // Apply pole vectors in reverse order (from end to root)\r\n // This prevents earlier pole vectors from affecting later ones\r\n const sortedIndices = Array.from(this._poleVectors.keys()).sort((a, b) => b - a);\r\n\r\n for (const jointIndex of sortedIndices) {\r\n const config = this._poleVectors.get(jointIndex);\r\n if (config && config.weight > 0.001) {\r\n this._applyPoleVectorTwist(jointIndex, config.position, config.weight);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Apply pole vector twist to a specific joint.\r\n *\r\n * @remarks\r\n * This method is called after the base CCD rotation has been applied.\r\n * It adds an additional twist rotation around the joint-to-end axis\r\n * to make the next joint (child) bend toward the pole vector.\r\n *\r\n * @param jointIndex - Index of the pole joint\r\n * @param poleVector - Pole vector position in world space\r\n * @param weight - Weight of the pole vector constraint (0-1)\r\n */\r\n private _applyPoleVectorTwist(jointIndex: number, poleVector: Vector3, weight: number): void {\r\n const joints = this._chain.joints;\r\n\r\n // We need at least 3 joints to apply pole vector (parent, pole joint, child)\r\n if (jointIndex < 1 || jointIndex >= joints.length - 1) {\r\n return;\r\n }\r\n\r\n const parentJoint = joints[jointIndex - 1];\r\n const currentJoint = joints[jointIndex];\r\n const childJoint = joints[jointIndex + 1];\r\n\r\n const parentPos = parentJoint.position;\r\n const currentPos = currentJoint.position;\r\n const childPos = childJoint.position;\r\n\r\n // Calculate the plane defined by parent, child, and pole vector\r\n // Vector from parent to child (the \"line\" we're bending around)\r\n const parentToChild = Vector3.sub(childPos, parentPos, new Vector3());\r\n const lineLength = parentToChild.magnitude;\r\n\r\n if (lineLength < 0.000001) {\r\n return; // Parent and child are at same position\r\n }\r\n\r\n const lineDir = Vector3.scale(parentToChild, 1 / lineLength, new Vector3());\r\n\r\n // Project current joint onto the parent-child line\r\n const parentToCurrent = Vector3.sub(currentPos, parentPos, new Vector3());\r\n const projectionLength = Vector3.dot(parentToCurrent, lineDir);\r\n const projectionPoint = Vector3.scale(lineDir, projectionLength, new Vector3());\r\n Vector3.add(parentPos, projectionPoint, projectionPoint);\r\n\r\n // Vector from projection point to current joint (perpendicular to line)\r\n const perpendicular = Vector3.sub(currentPos, projectionPoint, new Vector3());\r\n const perpLength = perpendicular.magnitude;\r\n\r\n if (perpLength < 0.000001) {\r\n return; // Current joint is on the line\r\n }\r\n\r\n // Calculate desired direction toward pole vector\r\n const parentToPole = Vector3.sub(poleVector, parentPos, new Vector3());\r\n const poleProjectionLength = Vector3.dot(parentToPole, lineDir);\r\n const poleProjectionPoint = Vector3.scale(lineDir, poleProjectionLength, new Vector3());\r\n Vector3.add(parentPos, poleProjectionPoint, poleProjectionPoint);\r\n\r\n // Direction from projection to pole (perpendicular to line)\r\n const poleDirection = Vector3.sub(poleVector, poleProjectionPoint, new Vector3());\r\n const poleDirLength = poleDirection.magnitude;\r\n\r\n if (poleDirLength < 0.000001) {\r\n return; // Pole is on the line\r\n }\r\n\r\n poleDirection.scaleBy(1 / poleDirLength);\r\n\r\n // Calculate new position for current joint\r\n // Keep the same distance from the line, but rotate toward pole direction\r\n const desiredPerpendicular = Vector3.scale(poleDirection, perpLength, new Vector3());\r\n const newPosition = Vector3.add(projectionPoint, desiredPerpendicular, new Vector3());\r\n\r\n // Apply weight (blend between original and constrained position)\r\n if (weight < 0.999) {\r\n const blended = new Vector3();\r\n blended.x = currentPos.x + (newPosition.x - currentPos.x) * weight;\r\n blended.y = currentPos.y + (newPosition.y - currentPos.y) * weight;\r\n blended.z = currentPos.z + (newPosition.z - currentPos.z) * weight;\r\n currentJoint.position.set(blended);\r\n } else {\r\n currentJoint.position.set(newPosition);\r\n }\r\n }\r\n\r\n /**\r\n * Apply constraints for a specific joint.\r\n *\r\n * @param jointIndex - Index of the joint to apply constraints to\r\n */\r\n private _applyConstraintsForJoint(jointIndex: number): void {\r\n const constraints = this._chain.constraints;\r\n for (const constraint of constraints) {\r\n if (constraint.jointIndex === jointIndex) {\r\n constraint.apply(this._chain.joints);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Apply the solved joint positions to scene nodes as rotations.\r\n *\r\n * @param weight - Blend weight (0 = original, 1 = full IK, default: 1)\r\n */\r\n applyToNodes(weight = 1): void {\r\n const joints = this._chain.joints;\r\n\r\n // Apply rotation for all joints except the end effector\r\n for (let i = 0; i < joints.length - 1; i++) {\r\n const joint = joints[i];\r\n const nextJoint = joints[i + 1];\r\n\r\n // Calculate direction from current joint to next joint in world space\r\n const originalDir = Vector3.sub(nextJoint.originalPosition, joint.originalPosition, new Vector3());\r\n const newDir = Vector3.sub(nextJoint.position, joint.position, new Vector3());\r\n\r\n const originalDirNorm = Vector3.normalize(originalDir, new Vector3());\r\n const newDirNorm = Vector3.normalize(newDir, new Vector3());\r\n\r\n // Calculate basic rotation\r\n const deltaRotation = new Quaternion();\r\n IKUtils.fromToRotation(originalDirNorm, newDirNorm, deltaRotation);\r\n\r\n // Calculate new world rotation\r\n let worldRotation = Quaternion.multiply(deltaRotation, joint.originalRotation, new Quaternion());\r\n\r\n // Apply swing-twist constraint to prevent over-rotation\r\n const swing = new Quaternion();\r\n const twist = new Quaternion();\r\n IKUtils.decomposeSwingTwist(worldRotation, newDirNorm, swing, twist);\r\n\r\n // Get twist angle\r\n let twistAngle = IKUtils.getTwistAngle(twist, newDirNorm);\r\n\r\n // Get twist constraint for this joint\r\n const constraint = this._twistConstraints.get(i);\r\n if (constraint) {\r\n // Clamp and smooth twist\r\n twistAngle = IKUtils.clampAndSmoothTwist(\r\n twistAngle,\r\n joint.previousTwist,\r\n constraint.minTwist,\r\n constraint.maxTwist,\r\n constraint.smoothFactor\r\n );\r\n }\r\n\r\n // Store for next frame\r\n joint.previousTwist = twistAngle;\r\n\r\n // Reconstruct rotation from clamped twist: Q = Twist * Swing\r\n const clampedTwist = new Quaternion();\r\n IKUtils.createTwist(twistAngle, newDirNorm, clampedTwist);\r\n worldRotation = Quaternion.multiply(clampedTwist, swing, worldRotation);\r\n\r\n // Blend with original rotation based on weight\r\n if (weight < 1) {\r\n Quaternion.slerp(joint.originalRotation, worldRotation, weight, worldRotation);\r\n }\r\n\r\n // Store this frame's world rotation for next frame's twist continuity\r\n if (!joint.previousIKRotation) {\r\n joint.previousIKRotation = worldRotation.clone();\r\n } else {\r\n joint.previousIKRotation.set(worldRotation);\r\n }\r\n\r\n // Convert world rotation to local rotation (relative to parent)\r\n if (joint.node.parent) {\r\n const parentWorldRotation = new Quaternion();\r\n joint.node.parent.worldMatrix.decompose(null, parentWorldRotation, null);\r\n\r\n // localRotation = conjugate(parentWorldRotation) * worldRotation\r\n const parentInvRotation = Quaternion.conjugate(parentWorldRotation, new Quaternion());\r\n const localRotation = Quaternion.multiply(parentInvRotation, worldRotation, new Quaternion());\r\n\r\n joint.node.rotation = localRotation;\r\n } else {\r\n // Root node has no parent, world rotation is local rotation\r\n joint.node.rotation = worldRotation;\r\n }\r\n }\r\n }\r\n}\r\n"],"names":["CCDSolver","IKSolver","chain","maxIterations","tolerance","_poleVectors","Map","_twistConstraints","i","joints","length","isMiddleJoint","set","minTwist","Math","PI","maxTwist","smoothFactor","setTwistConstraint","jointIndex","_chain","Error","max","min","getTwistConstraint","get","removeTwistConstraint","delete","clearTwistConstraints","clear","setPoleVector","poleVector","weight","position","clone","removePoleVector","clearPoleVectors","getPoleVector","config","undefined","hasPoleVector","has","solve","target","updateFromNodes","storeOriginalPositions","converged","iteration","_maxIterations","endEffector","distToTarget","Vector3","distance","_tolerance","joint","toEnd","sub","toEndDist","magnitude","toTarget","toTargetDist","toEndDir","scale","toTargetDir","rotation","Quaternion","IKUtils","fromToRotation","_rotateJointsFromIndex","_applyConstraintsForJoint","_applyAllPoleVectors","startIndex","pivot","offset","rotated","transform","add","size","sortedIndices","Array","from","keys","sort","a","b","_applyPoleVectorTwist","parentJoint","currentJoint","childJoint","parentPos","currentPos","childPos","parentToChild","lineLength","lineDir","parentToCurrent","projectionLength","dot","projectionPoint","perpendicular","perpLength","parentToPole","poleProjectionLength","poleProjectionPoint","poleDirection","poleDirLength","scaleBy","desiredPerpendicular","newPosition","blended","x","y","z","constraints","constraint","apply","applyToNodes","nextJoint","originalDir","originalPosition","newDir","originalDirNorm","normalize","newDirNorm","deltaRotation","worldRotation","multiply","originalRotation","swing","twist","decomposeSwingTwist","twistAngle","getTwistAngle","clampAndSmoothTwist","previousTwist","clampedTwist","createTwist","slerp","previousIKRotation","node","parent","parentWorldRotation","worldMatrix","decompose","parentInvRotation","conjugate","localRotation"],"mappings":"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"}
1
+ {"version":3,"file":"ccd_solver.js","sources":["../../../src/animation/ik/ccd_solver.ts"],"sourcesContent":["import { Vector3, Quaternion } from '@zephyr3d/base';\r\nimport { IKSolver } from './ik_solver';\r\nimport type { IKChain } from './ik_chain';\r\nimport { IKUtils } from './ik_utils';\r\nimport type { TwistConstraint } from './ik_constraint';\r\n\r\n/**\r\n * Pole vector configuration for a specific joint.\r\n */\r\ninterface PoleVectorConfig {\r\n /** Pole vector position in world space */\r\n position: Vector3;\r\n /** Weight of the pole vector constraint (0-1) */\r\n weight: number;\r\n}\r\n\r\n/**\r\n * CCD (Cyclic Coordinate Descent) IK solver.\r\n *\r\n * @remarks\r\n * CCD is an iterative IK algorithm that works by:\r\n * 1. Starting from the joint closest to the end effector\r\n * 2. Rotating each joint to point the end effector toward the target\r\n * 3. Moving backward through the chain to the root\r\n * 4. Repeating until convergence or max iterations\r\n *\r\n * CCD is generally faster than FABRIK and works well for chains of any length.\r\n * It's particularly good for tentacles, tails, and other flexible chains.\r\n *\r\n * Supports multiple pole vectors to control the bending direction of different joints.\r\n *\r\n * @public\r\n */\r\nexport class CCDSolver extends IKSolver {\r\n /** Map of joint index to pole vector configuration */\r\n private _poleVectors: Map<number, PoleVectorConfig>;\r\n /** Twist constraints for each joint (indexed by joint index) */\r\n private _twistConstraints: Map<number, TwistConstraint>;\r\n\r\n /**\r\n * Create a CCD solver.\r\n *\r\n * @param chain - The IK chain to solve\r\n * @param maxIterations - Maximum number of iterations (default: 10)\r\n * @param tolerance - Convergence tolerance in world units (default: 0.001)\r\n */\r\n constructor(chain: IKChain, maxIterations = 10, tolerance = 0.001) {\r\n super(chain, maxIterations, tolerance);\r\n this._poleVectors = new Map();\r\n this._twistConstraints = new Map();\r\n\r\n // Set default twist constraints for all joints\r\n for (let i = 0; i < chain.joints.length - 1; i++) {\r\n // Middle joints have more restrictive twist limits\r\n const isMiddleJoint = i > 0 && i < chain.joints.length - 2;\r\n this._twistConstraints.set(i, {\r\n minTwist: isMiddleJoint ? -Math.PI * 0.2 : -Math.PI * 0.3,\r\n maxTwist: isMiddleJoint ? Math.PI * 0.2 : Math.PI * 0.3,\r\n smoothFactor: 0.3\r\n });\r\n }\r\n }\r\n\r\n /**\r\n * Set twist constraint for a specific joint.\r\n *\r\n * @param jointIndex - Index of the joint\r\n * @param minTwist - Minimum twist angle in radians\r\n * @param maxTwist - Maximum twist angle in radians\r\n * @param smoothFactor - Smoothing factor [0-1] (default: 0.3)\r\n */\r\n setTwistConstraint(\r\n jointIndex: number,\r\n minTwist: number,\r\n maxTwist: number,\r\n smoothFactor: number = 0.3\r\n ): void {\r\n if (jointIndex < 0 || jointIndex >= this._chain.joints.length - 1) {\r\n throw new Error(`Invalid joint index: ${jointIndex}`);\r\n }\r\n\r\n this._twistConstraints.set(jointIndex, {\r\n minTwist,\r\n maxTwist,\r\n smoothFactor: Math.max(0, Math.min(1, smoothFactor))\r\n });\r\n }\r\n\r\n /**\r\n * Get twist constraint for a specific joint.\r\n *\r\n * @param jointIndex - Index of the joint\r\n * @returns Twist constraint or undefined if not set\r\n */\r\n getTwistConstraint(jointIndex: number): TwistConstraint | undefined {\r\n return this._twistConstraints.get(jointIndex);\r\n }\r\n\r\n /**\r\n * Remove twist constraint for a specific joint.\r\n *\r\n * @param jointIndex - Index of the joint\r\n * @returns True if a constraint was removed\r\n */\r\n removeTwistConstraint(jointIndex: number): boolean {\r\n return this._twistConstraints.delete(jointIndex);\r\n }\r\n\r\n /**\r\n * Clear all twist constraints.\r\n */\r\n clearTwistConstraints(): void {\r\n this._twistConstraints.clear();\r\n }\r\n\r\n /**\r\n * Set pole vector for a specific joint.\r\n *\r\n * @param jointIndex - Index of the joint to apply pole vector to\r\n * @param poleVector - Pole vector position in world space\r\n * @param weight - Weight of the pole vector constraint (0-1, default: 1)\r\n */\r\n setPoleVector(jointIndex: number, poleVector: Vector3, weight = 1): void {\r\n if (jointIndex < 0 || jointIndex >= this._chain.joints.length) {\r\n throw new Error(`Invalid joint index: ${jointIndex}`);\r\n }\r\n\r\n this._poleVectors.set(jointIndex, {\r\n position: poleVector.clone(),\r\n weight: Math.max(0, Math.min(1, weight))\r\n });\r\n }\r\n\r\n /**\r\n * Remove pole vector for a specific joint.\r\n *\r\n * @param jointIndex - Index of the joint to remove pole vector from\r\n * @returns True if a pole vector was removed, false if none existed\r\n */\r\n removePoleVector(jointIndex: number): boolean {\r\n return this._poleVectors.delete(jointIndex);\r\n }\r\n\r\n /**\r\n * Clear all pole vectors.\r\n */\r\n clearPoleVectors(): void {\r\n this._poleVectors.clear();\r\n }\r\n\r\n /**\r\n * Get pole vector configuration for a specific joint.\r\n *\r\n * @param jointIndex - Index of the joint\r\n * @returns Pole vector configuration or undefined if not set\r\n */\r\n getPoleVector(jointIndex: number): { position: Vector3; weight: number } | undefined {\r\n const config = this._poleVectors.get(jointIndex);\r\n if (config) {\r\n return {\r\n position: config.position.clone(),\r\n weight: config.weight\r\n };\r\n }\r\n return undefined;\r\n }\r\n\r\n /**\r\n * Check if a joint has a pole vector.\r\n *\r\n * @param jointIndex - Index of the joint\r\n * @returns True if the joint has a pole vector\r\n */\r\n hasPoleVector(jointIndex: number): boolean {\r\n return this._poleVectors.has(jointIndex);\r\n }\r\n\r\n /**\r\n * Solve the IK chain to reach the target position using CCD algorithm.\r\n *\r\n * @param target - Target position for the end effector\r\n * @returns True if converged within tolerance, false otherwise\r\n */\r\n solve(target: Vector3): boolean {\r\n const joints = this._chain.joints;\r\n\r\n // Update joint positions from scene nodes before solving\r\n this._chain.updateFromNodes();\r\n\r\n // Store original positions\r\n this._chain.storeOriginalPositions();\r\n\r\n let converged = false;\r\n\r\n for (let iteration = 0; iteration < this._maxIterations; iteration++) {\r\n // Check convergence\r\n const endEffector = joints[joints.length - 1];\r\n const distToTarget = Vector3.distance(endEffector.position, target);\r\n\r\n if (distToTarget < this._tolerance) {\r\n converged = true;\r\n break;\r\n }\r\n\r\n // Iterate backward through joints (from second-to-last to root)\r\n // We skip the end effector itself since it doesn't have a child to rotate toward\r\n for (let i = joints.length - 2; i >= 0; i--) {\r\n const joint = joints[i];\r\n\r\n // Vector from current joint to end effector\r\n const toEnd = Vector3.sub(endEffector.position, joint.position, new Vector3());\r\n const toEndDist = toEnd.magnitude;\r\n\r\n // Vector from current joint to target\r\n const toTarget = Vector3.sub(target, joint.position, new Vector3());\r\n const toTargetDist = toTarget.magnitude;\r\n\r\n // Skip if either vector is too small\r\n if (toEndDist < 0.000001 || toTargetDist < 0.000001) {\r\n continue;\r\n }\r\n\r\n // Normalize vectors\r\n const toEndDir = Vector3.scale(toEnd, 1 / toEndDist, new Vector3());\r\n const toTargetDir = Vector3.scale(toTarget, 1 / toTargetDist, new Vector3());\r\n\r\n // Calculate rotation needed to align end effector toward target\r\n let rotation = new Quaternion();\r\n IKUtils.fromToRotation(toEndDir, toTargetDir, rotation);\r\n\r\n // Apply rotation to all joints from current to end effector\r\n this._rotateJointsFromIndex(i, rotation, joint.position);\r\n\r\n // Apply constraints after rotating this joint\r\n this._applyConstraintsForJoint(i);\r\n }\r\n\r\n // Apply all pole vector constraints after each full iteration\r\n // This is more stable than applying them during the CCD loop\r\n this._applyAllPoleVectors();\r\n }\r\n\r\n return converged;\r\n }\r\n\r\n /**\r\n * Rotate all joints from the given index to the end effector around a pivot point.\r\n *\r\n * @param startIndex - Index of the joint to start rotating from\r\n * @param rotation - Rotation to apply\r\n * @param pivot - Pivot point for rotation (position of the joint being adjusted)\r\n */\r\n private _rotateJointsFromIndex(startIndex: number, rotation: Quaternion, pivot: Vector3): void {\r\n const joints = this._chain.joints;\r\n\r\n // Rotate all joints from startIndex+1 to end effector\r\n for (let i = startIndex + 1; i < joints.length; i++) {\r\n const joint = joints[i];\r\n\r\n // Translate to pivot\r\n const offset = Vector3.sub(joint.position, pivot, new Vector3());\r\n\r\n // Rotate around pivot\r\n const rotated = rotation.transform(offset, new Vector3());\r\n\r\n // Translate back\r\n joint.position.set(Vector3.add(pivot, rotated, new Vector3()));\r\n }\r\n }\r\n\r\n /**\r\n * Apply all pole vector constraints.\r\n *\r\n * @remarks\r\n * This method applies all configured pole vectors to their respective joints.\r\n * Pole vectors are applied in reverse order (from end to root) to minimize\r\n * interference between multiple pole vectors. This ensures that pole vectors\r\n * closer to the end effector are not affected by pole vectors closer to the root.\r\n */\r\n private _applyAllPoleVectors(): void {\r\n if (this._poleVectors.size === 0) {\r\n return;\r\n }\r\n\r\n // Apply pole vectors in reverse order (from end to root)\r\n // This prevents earlier pole vectors from affecting later ones\r\n const sortedIndices = Array.from(this._poleVectors.keys()).sort((a, b) => b - a);\r\n\r\n for (const jointIndex of sortedIndices) {\r\n const config = this._poleVectors.get(jointIndex);\r\n if (config && config.weight > 0.001) {\r\n this._applyPoleVectorTwist(jointIndex, config.position, config.weight);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Apply pole vector twist to a specific joint.\r\n *\r\n * @remarks\r\n * This method is called after the base CCD rotation has been applied.\r\n * It adds an additional twist rotation around the joint-to-end axis\r\n * to make the next joint (child) bend toward the pole vector.\r\n *\r\n * @param jointIndex - Index of the pole joint\r\n * @param poleVector - Pole vector position in world space\r\n * @param weight - Weight of the pole vector constraint (0-1)\r\n */\r\n private _applyPoleVectorTwist(jointIndex: number, poleVector: Vector3, weight: number): void {\r\n const joints = this._chain.joints;\r\n\r\n // We need at least 3 joints to apply pole vector (parent, pole joint, child)\r\n if (jointIndex < 1 || jointIndex >= joints.length - 1) {\r\n return;\r\n }\r\n\r\n const parentJoint = joints[jointIndex - 1];\r\n const currentJoint = joints[jointIndex];\r\n const childJoint = joints[jointIndex + 1];\r\n\r\n const parentPos = parentJoint.position;\r\n const currentPos = currentJoint.position;\r\n const childPos = childJoint.position;\r\n\r\n // Calculate the plane defined by parent, child, and pole vector\r\n // Vector from parent to child (the \"line\" we're bending around)\r\n const parentToChild = Vector3.sub(childPos, parentPos, new Vector3());\r\n const lineLength = parentToChild.magnitude;\r\n\r\n if (lineLength < 0.000001) {\r\n return; // Parent and child are at same position\r\n }\r\n\r\n const lineDir = Vector3.scale(parentToChild, 1 / lineLength, new Vector3());\r\n\r\n // Project current joint onto the parent-child line\r\n const parentToCurrent = Vector3.sub(currentPos, parentPos, new Vector3());\r\n const projectionLength = Vector3.dot(parentToCurrent, lineDir);\r\n const projectionPoint = Vector3.scale(lineDir, projectionLength, new Vector3());\r\n Vector3.add(parentPos, projectionPoint, projectionPoint);\r\n\r\n // Vector from projection point to current joint (perpendicular to line)\r\n const perpendicular = Vector3.sub(currentPos, projectionPoint, new Vector3());\r\n const perpLength = perpendicular.magnitude;\r\n\r\n if (perpLength < 0.000001) {\r\n return; // Current joint is on the line\r\n }\r\n\r\n // Calculate desired direction toward pole vector\r\n const parentToPole = Vector3.sub(poleVector, parentPos, new Vector3());\r\n const poleProjectionLength = Vector3.dot(parentToPole, lineDir);\r\n const poleProjectionPoint = Vector3.scale(lineDir, poleProjectionLength, new Vector3());\r\n Vector3.add(parentPos, poleProjectionPoint, poleProjectionPoint);\r\n\r\n // Direction from projection to pole (perpendicular to line)\r\n const poleDirection = Vector3.sub(poleVector, poleProjectionPoint, new Vector3());\r\n const poleDirLength = poleDirection.magnitude;\r\n\r\n if (poleDirLength < 0.000001) {\r\n return; // Pole is on the line\r\n }\r\n\r\n poleDirection.scaleBy(1 / poleDirLength);\r\n\r\n // Calculate new position for current joint\r\n // Keep the same distance from the line, but rotate toward pole direction\r\n const desiredPerpendicular = Vector3.scale(poleDirection, perpLength, new Vector3());\r\n const newPosition = Vector3.add(projectionPoint, desiredPerpendicular, new Vector3());\r\n\r\n // Apply weight (blend between original and constrained position)\r\n if (weight < 0.999) {\r\n const blended = new Vector3();\r\n blended.x = currentPos.x + (newPosition.x - currentPos.x) * weight;\r\n blended.y = currentPos.y + (newPosition.y - currentPos.y) * weight;\r\n blended.z = currentPos.z + (newPosition.z - currentPos.z) * weight;\r\n currentJoint.position.set(blended);\r\n } else {\r\n currentJoint.position.set(newPosition);\r\n }\r\n }\r\n\r\n /**\r\n * Apply constraints for a specific joint.\r\n *\r\n * @param jointIndex - Index of the joint to apply constraints to\r\n */\r\n private _applyConstraintsForJoint(jointIndex: number): void {\r\n const constraints = this._chain.constraints;\r\n for (const constraint of constraints) {\r\n if (constraint.jointIndex === jointIndex) {\r\n constraint.apply(this._chain.joints);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Apply the solved joint positions to scene nodes as rotations.\r\n *\r\n * @param weight - Blend weight (0 = original, 1 = full IK, default: 1)\r\n */\r\n applyToNodes(weight = 1): void {\r\n const joints = this._chain.joints;\r\n\r\n // Apply rotation for all joints except the end effector\r\n for (let i = 0; i < joints.length - 1; i++) {\r\n const joint = joints[i];\r\n const nextJoint = joints[i + 1];\r\n\r\n // Calculate direction from current joint to next joint in world space\r\n const originalDir = Vector3.sub(nextJoint.originalPosition, joint.originalPosition, new Vector3());\r\n const newDir = Vector3.sub(nextJoint.position, joint.position, new Vector3());\r\n\r\n const originalDirNorm = Vector3.normalize(originalDir, new Vector3());\r\n const newDirNorm = Vector3.normalize(newDir, new Vector3());\r\n\r\n // Calculate basic rotation\r\n const deltaRotation = new Quaternion();\r\n IKUtils.fromToRotation(originalDirNorm, newDirNorm, deltaRotation);\r\n\r\n // Calculate new world rotation\r\n let worldRotation = Quaternion.multiply(deltaRotation, joint.originalRotation, new Quaternion());\r\n\r\n // Apply swing-twist constraint to prevent over-rotation\r\n const swing = new Quaternion();\r\n const twist = new Quaternion();\r\n worldRotation.decomposeSwingTwist(newDirNorm, swing, twist);\r\n\r\n // Get twist angle\r\n let twistAngle = twist.getTwistAngle(newDirNorm);\r\n\r\n // Get twist constraint for this joint\r\n const constraint = this._twistConstraints.get(i);\r\n if (constraint) {\r\n // Clamp and smooth twist\r\n twistAngle = IKUtils.clampAndSmoothTwist(\r\n twistAngle,\r\n joint.previousTwist,\r\n constraint.minTwist,\r\n constraint.maxTwist,\r\n constraint.smoothFactor\r\n );\r\n }\r\n\r\n // Store for next frame\r\n joint.previousTwist = twistAngle;\r\n\r\n // Reconstruct rotation from clamped twist: Q = Twist * Swing\r\n const clampedTwist = Quaternion.fromAxisAngle(newDirNorm, twistAngle);\r\n worldRotation = Quaternion.multiply(clampedTwist, swing, worldRotation);\r\n\r\n // Blend with original rotation based on weight\r\n if (weight < 1) {\r\n Quaternion.slerp(joint.originalRotation, worldRotation, weight, worldRotation);\r\n }\r\n\r\n // Store this frame's world rotation for next frame's twist continuity\r\n if (!joint.previousIKRotation) {\r\n joint.previousIKRotation = worldRotation.clone();\r\n } else {\r\n joint.previousIKRotation.set(worldRotation);\r\n }\r\n\r\n // Convert world rotation to local rotation (relative to parent)\r\n if (joint.node.parent) {\r\n const parentWorldRotation = new Quaternion();\r\n joint.node.parent.worldMatrix.decompose(null, parentWorldRotation, null);\r\n\r\n // localRotation = conjugate(parentWorldRotation) * worldRotation\r\n const parentInvRotation = Quaternion.conjugate(parentWorldRotation, new Quaternion());\r\n const localRotation = Quaternion.multiply(parentInvRotation, worldRotation, new Quaternion());\r\n\r\n joint.node.rotation = localRotation;\r\n } else {\r\n // Root node has no parent, world rotation is local rotation\r\n joint.node.rotation = worldRotation;\r\n }\r\n }\r\n }\r\n}\r\n"],"names":["CCDSolver","IKSolver","chain","maxIterations","tolerance","_poleVectors","Map","_twistConstraints","i","joints","length","isMiddleJoint","set","minTwist","Math","PI","maxTwist","smoothFactor","setTwistConstraint","jointIndex","_chain","Error","max","min","getTwistConstraint","get","removeTwistConstraint","delete","clearTwistConstraints","clear","setPoleVector","poleVector","weight","position","clone","removePoleVector","clearPoleVectors","getPoleVector","config","undefined","hasPoleVector","has","solve","target","updateFromNodes","storeOriginalPositions","converged","iteration","_maxIterations","endEffector","distToTarget","Vector3","distance","_tolerance","joint","toEnd","sub","toEndDist","magnitude","toTarget","toTargetDist","toEndDir","scale","toTargetDir","rotation","Quaternion","IKUtils","fromToRotation","_rotateJointsFromIndex","_applyConstraintsForJoint","_applyAllPoleVectors","startIndex","pivot","offset","rotated","transform","add","size","sortedIndices","Array","from","keys","sort","a","b","_applyPoleVectorTwist","parentJoint","currentJoint","childJoint","parentPos","currentPos","childPos","parentToChild","lineLength","lineDir","parentToCurrent","projectionLength","dot","projectionPoint","perpendicular","perpLength","parentToPole","poleProjectionLength","poleProjectionPoint","poleDirection","poleDirLength","scaleBy","desiredPerpendicular","newPosition","blended","x","y","z","constraints","constraint","apply","applyToNodes","nextJoint","originalDir","originalPosition","newDir","originalDirNorm","normalize","newDirNorm","deltaRotation","worldRotation","multiply","originalRotation","swing","twist","decomposeSwingTwist","twistAngle","getTwistAngle","clampAndSmoothTwist","previousTwist","clampedTwist","fromAxisAngle","slerp","previousIKRotation","node","parent","parentWorldRotation","worldMatrix","decompose","parentInvRotation","conjugate","localRotation"],"mappings":"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"}
@@ -182,9 +182,9 @@ import { IKUtils } from './ik_utils.js';
182
182
  // Apply swing-twist constraint to prevent over-rotation
183
183
  const swing = new Quaternion();
184
184
  const twist = new Quaternion();
185
- IKUtils.decomposeSwingTwist(worldRotation, newDirNorm, swing, twist);
185
+ worldRotation.decomposeSwingTwist(newDirNorm, swing, twist);
186
186
  // Get twist angle
187
- let twistAngle = IKUtils.getTwistAngle(twist, newDirNorm);
187
+ let twistAngle = twist.getTwistAngle(newDirNorm);
188
188
  // Get twist constraint for this joint
189
189
  const constraint = this._twistConstraints.get(i);
190
190
  if (constraint) {
@@ -194,8 +194,7 @@ import { IKUtils } from './ik_utils.js';
194
194
  // Store for next frame
195
195
  joint.previousTwist = twistAngle;
196
196
  // Reconstruct rotation from clamped twist: Q = Twist * Swing
197
- const clampedTwist = new Quaternion();
198
- IKUtils.createTwist(twistAngle, newDirNorm, clampedTwist);
197
+ const clampedTwist = Quaternion.fromAxisAngle(newDirNorm, twistAngle);
199
198
  worldRotation = Quaternion.multiply(clampedTwist, swing, worldRotation);
200
199
  // Blend with original rotation based on weight
201
200
  if (weight < 1) {