@zephyr3d/scene 0.9.0 → 0.9.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 (149) hide show
  1. package/dist/animation/animationset.js +135 -133
  2. package/dist/animation/animationset.js.map +1 -1
  3. package/dist/animation/cloth/gpu_cloth_system.js +9 -1
  4. package/dist/animation/cloth/gpu_cloth_system.js.map +1 -1
  5. package/dist/animation/fixed_geometry_cache_track.js +5 -1
  6. package/dist/animation/fixed_geometry_cache_track.js.map +1 -1
  7. package/dist/animation/geometry_cache_utils.js +20 -4
  8. package/dist/animation/geometry_cache_utils.js.map +1 -1
  9. package/dist/animation/ik/ik_angle_constraint.js +2 -6
  10. package/dist/animation/ik/ik_angle_constraint.js.map +1 -1
  11. package/dist/animation/ik/two_bone_ik_solver.js +2 -6
  12. package/dist/animation/ik/two_bone_ik_solver.js.map +1 -1
  13. package/dist/animation/joint_dynamics/collision.js +60 -12
  14. package/dist/animation/joint_dynamics/collision.js.map +1 -1
  15. package/dist/animation/joint_dynamics/constraints.js +20 -4
  16. package/dist/animation/joint_dynamics/constraints.js.map +1 -1
  17. package/dist/animation/joint_dynamics/controller.js +151 -103
  18. package/dist/animation/joint_dynamics/controller.js.map +1 -1
  19. package/dist/animation/joint_dynamics/solver.js +21 -11
  20. package/dist/animation/joint_dynamics/solver.js.map +1 -1
  21. package/dist/animation/joint_dynamics/types.js +15 -3
  22. package/dist/animation/joint_dynamics/types.js.map +1 -1
  23. package/dist/animation/pca_geometry_cache_track.js +5 -1
  24. package/dist/animation/pca_geometry_cache_track.js.map +1 -1
  25. package/dist/animation/skeleton.js +2 -2
  26. package/dist/animation/skeleton.js.map +1 -1
  27. package/dist/animation/skeleton_modifier.js +2 -6
  28. package/dist/animation/skeleton_modifier.js.map +1 -1
  29. package/dist/animation/spring/spring_system.js +87 -114
  30. package/dist/animation/spring/spring_system.js.map +1 -1
  31. package/dist/app/app.js.map +1 -1
  32. package/dist/app/engine.js +1 -1
  33. package/dist/app/engine.js.map +1 -1
  34. package/dist/app/screen.js +4 -4
  35. package/dist/app/screen.js.map +1 -1
  36. package/dist/app/scriptingsystem.js +24 -1
  37. package/dist/app/scriptingsystem.js.map +1 -1
  38. package/dist/app/scriptregistry.js +165 -144
  39. package/dist/app/scriptregistry.js.map +1 -1
  40. package/dist/asset/assetmanager.js +2 -2
  41. package/dist/asset/assetmanager.js.map +1 -1
  42. package/dist/asset/model.js +3 -3
  43. package/dist/asset/model.js.map +1 -1
  44. package/dist/camera/camera.js +185 -185
  45. package/dist/camera/camera.js.map +1 -1
  46. package/dist/camera/orbit.js.map +1 -1
  47. package/dist/index.d.ts +794 -261
  48. package/dist/index.js +2 -1
  49. package/dist/index.js.map +1 -1
  50. package/dist/material/material.js +290 -288
  51. package/dist/material/material.js.map +1 -1
  52. package/dist/material/mixins/lightmodel/pbrmetallicroughness.js +13 -26
  53. package/dist/material/mixins/lightmodel/pbrmetallicroughness.js.map +1 -1
  54. package/dist/material/pbrmr.js +1 -11
  55. package/dist/material/pbrmr.js.map +1 -1
  56. package/dist/material/sprite.js +6 -6
  57. package/dist/material/sprite.js.map +1 -1
  58. package/dist/material/terrain-cm.js +2 -2
  59. package/dist/material/terrain-cm.js.map +1 -1
  60. package/dist/posteffect/taa.js +31 -39
  61. package/dist/posteffect/taa.js.map +1 -1
  62. package/dist/render/drawable.js +5 -1
  63. package/dist/render/drawable.js.map +1 -1
  64. package/dist/render/rendergraph/device_pool_allocator.js +29 -3
  65. package/dist/render/rendergraph/device_pool_allocator.js.map +1 -1
  66. package/dist/render/rendergraph/executor.js +283 -33
  67. package/dist/render/rendergraph/executor.js.map +1 -1
  68. package/dist/render/rendergraph/forward_plus_builder.js +338 -108
  69. package/dist/render/rendergraph/forward_plus_builder.js.map +1 -1
  70. package/dist/render/rendergraph/history_resource_manager.js +236 -156
  71. package/dist/render/rendergraph/history_resource_manager.js.map +1 -1
  72. package/dist/render/rendergraph/history_resources.js +10 -0
  73. package/dist/render/rendergraph/history_resources.js.map +1 -0
  74. package/dist/render/rendergraph/rendergraph.js +162 -35
  75. package/dist/render/rendergraph/rendergraph.js.map +1 -1
  76. package/dist/render/rendergraph/types.js +36 -16
  77. package/dist/render/rendergraph/types.js.map +1 -1
  78. package/dist/render/rendertarget.js +5 -1
  79. package/dist/render/rendertarget.js.map +1 -1
  80. package/dist/render/screenrendertarget.js +5 -1
  81. package/dist/render/screenrendertarget.js.map +1 -1
  82. package/dist/render/sky.js +4 -4
  83. package/dist/render/sky.js.map +1 -1
  84. package/dist/scene/basesprite.js +2 -2
  85. package/dist/scene/basesprite.js.map +1 -1
  86. package/dist/scene/graph_node.js +1 -1
  87. package/dist/scene/graph_node.js.map +1 -1
  88. package/dist/scene/mesh.js +4 -20
  89. package/dist/scene/mesh.js.map +1 -1
  90. package/dist/scene/particlesys.js +1 -1
  91. package/dist/scene/particlesys.js.map +1 -1
  92. package/dist/scene/scene_node.js +2 -2
  93. package/dist/scene/scene_node.js.map +1 -1
  94. package/dist/scene/script_attachment.js +15 -3
  95. package/dist/scene/script_attachment.js.map +1 -1
  96. package/dist/scene/terrain-cm/terrain-cm.js +3 -3
  97. package/dist/scene/terrain-cm/terrain-cm.js.map +1 -1
  98. package/dist/shadow/shadowmapper.js.map +1 -1
  99. package/dist/shapes/box.js +1 -1
  100. package/dist/shapes/box.js.map +1 -1
  101. package/dist/shapes/capsule.js +0 -3
  102. package/dist/shapes/capsule.js.map +1 -1
  103. package/dist/shapes/cylinder.js +0 -3
  104. package/dist/shapes/cylinder.js.map +1 -1
  105. package/dist/shapes/plane.js +0 -3
  106. package/dist/shapes/plane.js.map +1 -1
  107. package/dist/shapes/tetrahedron.js +3 -9
  108. package/dist/shapes/tetrahedron.js.map +1 -1
  109. package/dist/shapes/torus.js +4 -7
  110. package/dist/shapes/torus.js.map +1 -1
  111. package/dist/utility/blueprint/material/inputs.js +3 -3
  112. package/dist/utility/blueprint/material/inputs.js.map +1 -1
  113. package/dist/utility/blueprint/material/ir.js +493 -493
  114. package/dist/utility/blueprint/material/ir.js.map +1 -1
  115. package/dist/utility/serialization/manager.js +34 -3
  116. package/dist/utility/serialization/manager.js.map +1 -1
  117. package/dist/utility/serialization/scene/animation.js +45 -0
  118. package/dist/utility/serialization/scene/animation.js.map +1 -1
  119. package/dist/utility/serialization/scene/camera.js +53 -0
  120. package/dist/utility/serialization/scene/camera.js.map +1 -1
  121. package/dist/utility/serialization/scene/common.js +10 -0
  122. package/dist/utility/serialization/scene/common.js.map +1 -1
  123. package/dist/utility/serialization/scene/light.js +30 -0
  124. package/dist/utility/serialization/scene/light.js.map +1 -1
  125. package/dist/utility/serialization/scene/material.js +63 -0
  126. package/dist/utility/serialization/scene/material.js.map +1 -1
  127. package/dist/utility/serialization/scene/mesh.js +11 -0
  128. package/dist/utility/serialization/scene/mesh.js.map +1 -1
  129. package/dist/utility/serialization/scene/misc.js +2 -0
  130. package/dist/utility/serialization/scene/misc.js.map +1 -1
  131. package/dist/utility/serialization/scene/node.js +19 -0
  132. package/dist/utility/serialization/scene/node.js.map +1 -1
  133. package/dist/utility/serialization/scene/particle.js +22 -0
  134. package/dist/utility/serialization/scene/particle.js.map +1 -1
  135. package/dist/utility/serialization/scene/primitive.js +33 -0
  136. package/dist/utility/serialization/scene/primitive.js.map +1 -1
  137. package/dist/utility/serialization/scene/scene.js +39 -0
  138. package/dist/utility/serialization/scene/scene.js.map +1 -1
  139. package/dist/utility/serialization/scene/script.js +2 -0
  140. package/dist/utility/serialization/scene/script.js.map +1 -1
  141. package/dist/utility/serialization/scene/sprite.js +6 -0
  142. package/dist/utility/serialization/scene/sprite.js.map +1 -1
  143. package/dist/utility/serialization/scene/terrain.js +9 -0
  144. package/dist/utility/serialization/scene/terrain.js.map +1 -1
  145. package/dist/utility/serialization/scene/water.js +21 -0
  146. package/dist/utility/serialization/scene/water.js.map +1 -1
  147. package/dist/utility/serialization/types.js +5 -1
  148. package/dist/utility/serialization/types.js.map +1 -1
  149. package/package.json +2 -2
@@ -1,7 +1,11 @@
1
1
  import { AnimationTrack } from './animationtrack.js';
2
2
  import { createGeometryCacheState, mixGeometryCacheBoundingBox, ensureGeometryCacheMeshBinding } from './geometry_cache_utils.js';
3
3
 
4
- class FixedGeometryCacheTrack extends AnimationTrack {
4
+ /**
5
+ * Geometry cache track backed by explicit per-frame vertex data.
6
+ *
7
+ * @public
8
+ */ class FixedGeometryCacheTrack extends AnimationTrack {
5
9
  _times;
6
10
  _frames;
7
11
  _state;
@@ -1 +1 @@
1
- {"version":3,"file":"fixed_geometry_cache_track.js","sources":["../../src/animation/fixed_geometry_cache_track.ts"],"sourcesContent":["import { AnimationTrack } from './animationtrack';\r\nimport type { Mesh } from '../scene';\r\nimport type { Nullable } from '@zephyr3d/base';\r\nimport {\r\n createGeometryCacheState,\r\n ensureGeometryCacheMeshBinding,\r\n mixGeometryCacheBoundingBox,\r\n type GeometryCacheFrame,\r\n type GeometryCacheMeshBinding,\r\n type GeometryCacheState\r\n} from './geometry_cache_utils';\r\n\r\nexport type FixedGeometryCacheFrame = GeometryCacheFrame;\r\nexport type FixedGeometryCacheState = GeometryCacheState;\r\n\r\nexport class FixedGeometryCacheTrack extends AnimationTrack<FixedGeometryCacheState> {\r\n private _times: Float32Array;\r\n private _frames: FixedGeometryCacheFrame[];\r\n private _state: Nullable<FixedGeometryCacheState>;\r\n private readonly _meshBindings: WeakMap<Mesh, GeometryCacheMeshBinding>;\r\n\r\n constructor(times?: Float32Array, frames?: FixedGeometryCacheFrame[], embedded?: boolean) {\r\n super(embedded);\r\n this._times = times ?? new Float32Array();\r\n this._frames = frames ?? [];\r\n this._state = this._frames.length > 0 ? createGeometryCacheState(this._frames[0]) : null;\r\n this._meshBindings = new WeakMap();\r\n }\r\n\r\n get times() {\r\n return this._times;\r\n }\r\n\r\n set times(value: Float32Array) {\r\n this._times = value ?? new Float32Array();\r\n }\r\n\r\n get frames() {\r\n return this._frames;\r\n }\r\n\r\n set frames(value: FixedGeometryCacheFrame[]) {\r\n this._frames = value ?? [];\r\n this._state = this._frames.length > 0 ? createGeometryCacheState(this._frames[0]) : null;\r\n }\r\n\r\n calculateState(_target: object, currentTime: number) {\r\n if (this._frames.length === 0) {\r\n throw new Error('FixedGeometryCacheTrack.calculateState(): no frames available');\r\n }\r\n if (this._frames.length === 1 || this._times.length <= 1) {\r\n return this.copyFrameToState(this._frames[0]);\r\n }\r\n if (currentTime <= this._times[0]) {\r\n return this.copyFrameToState(this._frames[0]);\r\n }\r\n const lastIndex = this._times.length - 1;\r\n if (currentTime >= this._times[lastIndex]) {\r\n return this.copyFrameToState(this._frames[lastIndex]);\r\n }\r\n let right = 1;\r\n while (right < this._times.length && this._times[right] < currentTime) {\r\n right++;\r\n }\r\n const left = Math.max(0, right - 1);\r\n const start = this._times[left];\r\n const end = this._times[right];\r\n const t = end > start ? (currentTime - start) / (end - start) : 0;\r\n return this.interpolateFrames(this._frames[left], this._frames[right], t);\r\n }\r\n\r\n applyState(target: object, state: FixedGeometryCacheState) {\r\n const mesh = target as Mesh;\r\n const binding = this.ensureMeshBinding(mesh, state);\r\n binding.positionBuffer.bufferSubData(0, state.positions as unknown as Float32Array<ArrayBuffer>);\r\n if (binding.normalBuffer && state.normals) {\r\n binding.normalBuffer.bufferSubData(0, state.normals as unknown as Float32Array<ArrayBuffer>);\r\n }\r\n mesh.setAnimatedBoundingBox(state.boundingBox);\r\n }\r\n\r\n mixState(a: FixedGeometryCacheState, b: FixedGeometryCacheState, t: number) {\r\n if (!this._state) {\r\n throw new Error('FixedGeometryCacheTrack.mixState(): invalid state');\r\n }\r\n const positions = new Float32Array(a.positions.length);\r\n for (let i = 0; i < positions.length; i++) {\r\n positions[i] = a.positions[i] + (b.positions[i] - a.positions[i]) * t;\r\n }\r\n let normals: Nullable<Float32Array> = null;\r\n if (a.normals && b.normals && a.normals.length === b.normals.length) {\r\n normals = new Float32Array(a.normals.length);\r\n for (let i = 0; i < normals.length; i++) {\r\n normals[i] = a.normals[i] + (b.normals[i] - a.normals[i]) * t;\r\n }\r\n }\r\n return {\r\n positions,\r\n normals,\r\n boundingBox: mixGeometryCacheBoundingBox(a.boundingBox, b.boundingBox, t)\r\n };\r\n }\r\n\r\n getBlendId() {\r\n return 'fixed-geometry-cache';\r\n }\r\n\r\n getDuration() {\r\n return this._times.length > 0 ? this._times[this._times.length - 1] : 0;\r\n }\r\n\r\n reset(target: object) {\r\n if (this._frames.length > 0) {\r\n this.applyState(target, this.copyFrameToState(this._frames[0]));\r\n }\r\n }\r\n\r\n private copyFrameToState(frame: FixedGeometryCacheFrame) {\r\n if (!this._state) {\r\n this._state = createGeometryCacheState(frame);\r\n }\r\n this._state.positions.set(frame.positions);\r\n if (frame.normals) {\r\n if (!this._state.normals || this._state.normals.length !== frame.normals.length) {\r\n this._state.normals = new Float32Array(frame.normals.length);\r\n }\r\n this._state.normals.set(frame.normals);\r\n } else {\r\n this._state.normals = null;\r\n }\r\n this._state.boundingBox.minPoint.set(frame.boundingBox.minPoint);\r\n this._state.boundingBox.maxPoint.set(frame.boundingBox.maxPoint);\r\n return this._state;\r\n }\r\n\r\n private interpolateFrames(a: FixedGeometryCacheFrame, b: FixedGeometryCacheFrame, t: number) {\r\n if (!this._state) {\r\n this._state = createGeometryCacheState(a);\r\n }\r\n for (let i = 0; i < this._state.positions.length; i++) {\r\n this._state.positions[i] = a.positions[i] + (b.positions[i] - a.positions[i]) * t;\r\n }\r\n if (a.normals && b.normals && a.normals.length === b.normals.length) {\r\n if (!this._state.normals || this._state.normals.length !== a.normals.length) {\r\n this._state.normals = new Float32Array(a.normals.length);\r\n }\r\n for (let i = 0; i < this._state.normals.length; i++) {\r\n this._state.normals[i] = a.normals[i] + (b.normals[i] - a.normals[i]) * t;\r\n }\r\n } else {\r\n this._state.normals = null;\r\n }\r\n this._state.boundingBox.minPoint.setXYZ(\r\n a.boundingBox.minPoint.x + (b.boundingBox.minPoint.x - a.boundingBox.minPoint.x) * t,\r\n a.boundingBox.minPoint.y + (b.boundingBox.minPoint.y - a.boundingBox.minPoint.y) * t,\r\n a.boundingBox.minPoint.z + (b.boundingBox.minPoint.z - a.boundingBox.minPoint.z) * t\r\n );\r\n this._state.boundingBox.maxPoint.setXYZ(\r\n a.boundingBox.maxPoint.x + (b.boundingBox.maxPoint.x - a.boundingBox.maxPoint.x) * t,\r\n a.boundingBox.maxPoint.y + (b.boundingBox.maxPoint.y - a.boundingBox.maxPoint.y) * t,\r\n a.boundingBox.maxPoint.z + (b.boundingBox.maxPoint.z - a.boundingBox.maxPoint.z) * t\r\n );\r\n return this._state;\r\n }\r\n\r\n private ensureMeshBinding(mesh: Mesh, state: FixedGeometryCacheState) {\r\n return ensureGeometryCacheMeshBinding(\r\n this._meshBindings,\r\n mesh,\r\n state,\r\n 'FixedGeometryCacheTrack.applyState()'\r\n );\r\n }\r\n}\r\n"],"names":["FixedGeometryCacheTrack","AnimationTrack","_times","_frames","_state","_meshBindings","times","frames","embedded","Float32Array","length","createGeometryCacheState","WeakMap","value","calculateState","_target","currentTime","Error","copyFrameToState","lastIndex","right","left","Math","max","start","end","t","interpolateFrames","applyState","target","state","mesh","binding","ensureMeshBinding","positionBuffer","bufferSubData","positions","normalBuffer","normals","setAnimatedBoundingBox","boundingBox","mixState","a","b","i","mixGeometryCacheBoundingBox","getBlendId","getDuration","reset","frame","set","minPoint","maxPoint","setXYZ","x","y","z","ensureGeometryCacheMeshBinding"],"mappings":"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"}
1
+ {"version":3,"file":"fixed_geometry_cache_track.js","sources":["../../src/animation/fixed_geometry_cache_track.ts"],"sourcesContent":["import { AnimationTrack } from './animationtrack';\r\nimport type { Mesh } from '../scene';\r\nimport type { Nullable } from '@zephyr3d/base';\r\nimport {\r\n createGeometryCacheState,\r\n ensureGeometryCacheMeshBinding,\r\n mixGeometryCacheBoundingBox,\r\n type GeometryCacheFrame,\r\n type GeometryCacheMeshBinding,\r\n type GeometryCacheState\r\n} from './geometry_cache_utils';\r\n\r\n/** @public */\r\nexport type FixedGeometryCacheFrame = GeometryCacheFrame;\r\n/** @public */\r\nexport type FixedGeometryCacheState = GeometryCacheState;\r\n\r\n/**\r\n * Geometry cache track backed by explicit per-frame vertex data.\r\n *\r\n * @public\r\n */\r\nexport class FixedGeometryCacheTrack extends AnimationTrack<FixedGeometryCacheState> {\r\n private _times: Float32Array;\r\n private _frames: FixedGeometryCacheFrame[];\r\n private _state: Nullable<FixedGeometryCacheState>;\r\n private readonly _meshBindings: WeakMap<Mesh, GeometryCacheMeshBinding>;\r\n\r\n constructor(times?: Float32Array, frames?: FixedGeometryCacheFrame[], embedded?: boolean) {\r\n super(embedded);\r\n this._times = times ?? new Float32Array();\r\n this._frames = frames ?? [];\r\n this._state = this._frames.length > 0 ? createGeometryCacheState(this._frames[0]) : null;\r\n this._meshBindings = new WeakMap();\r\n }\r\n\r\n get times() {\r\n return this._times;\r\n }\r\n\r\n set times(value: Float32Array) {\r\n this._times = value ?? new Float32Array();\r\n }\r\n\r\n get frames() {\r\n return this._frames;\r\n }\r\n\r\n set frames(value: FixedGeometryCacheFrame[]) {\r\n this._frames = value ?? [];\r\n this._state = this._frames.length > 0 ? createGeometryCacheState(this._frames[0]) : null;\r\n }\r\n\r\n calculateState(_target: object, currentTime: number) {\r\n if (this._frames.length === 0) {\r\n throw new Error('FixedGeometryCacheTrack.calculateState(): no frames available');\r\n }\r\n if (this._frames.length === 1 || this._times.length <= 1) {\r\n return this.copyFrameToState(this._frames[0]);\r\n }\r\n if (currentTime <= this._times[0]) {\r\n return this.copyFrameToState(this._frames[0]);\r\n }\r\n const lastIndex = this._times.length - 1;\r\n if (currentTime >= this._times[lastIndex]) {\r\n return this.copyFrameToState(this._frames[lastIndex]);\r\n }\r\n let right = 1;\r\n while (right < this._times.length && this._times[right] < currentTime) {\r\n right++;\r\n }\r\n const left = Math.max(0, right - 1);\r\n const start = this._times[left];\r\n const end = this._times[right];\r\n const t = end > start ? (currentTime - start) / (end - start) : 0;\r\n return this.interpolateFrames(this._frames[left], this._frames[right], t);\r\n }\r\n\r\n applyState(target: object, state: FixedGeometryCacheState) {\r\n const mesh = target as Mesh;\r\n const binding = this.ensureMeshBinding(mesh, state);\r\n binding.positionBuffer.bufferSubData(0, state.positions as unknown as Float32Array<ArrayBuffer>);\r\n if (binding.normalBuffer && state.normals) {\r\n binding.normalBuffer.bufferSubData(0, state.normals as unknown as Float32Array<ArrayBuffer>);\r\n }\r\n mesh.setAnimatedBoundingBox(state.boundingBox);\r\n }\r\n\r\n mixState(a: FixedGeometryCacheState, b: FixedGeometryCacheState, t: number) {\r\n if (!this._state) {\r\n throw new Error('FixedGeometryCacheTrack.mixState(): invalid state');\r\n }\r\n const positions = new Float32Array(a.positions.length);\r\n for (let i = 0; i < positions.length; i++) {\r\n positions[i] = a.positions[i] + (b.positions[i] - a.positions[i]) * t;\r\n }\r\n let normals: Nullable<Float32Array> = null;\r\n if (a.normals && b.normals && a.normals.length === b.normals.length) {\r\n normals = new Float32Array(a.normals.length);\r\n for (let i = 0; i < normals.length; i++) {\r\n normals[i] = a.normals[i] + (b.normals[i] - a.normals[i]) * t;\r\n }\r\n }\r\n return {\r\n positions,\r\n normals,\r\n boundingBox: mixGeometryCacheBoundingBox(a.boundingBox, b.boundingBox, t)\r\n };\r\n }\r\n\r\n getBlendId() {\r\n return 'fixed-geometry-cache';\r\n }\r\n\r\n getDuration() {\r\n return this._times.length > 0 ? this._times[this._times.length - 1] : 0;\r\n }\r\n\r\n reset(target: object) {\r\n if (this._frames.length > 0) {\r\n this.applyState(target, this.copyFrameToState(this._frames[0]));\r\n }\r\n }\r\n\r\n private copyFrameToState(frame: FixedGeometryCacheFrame) {\r\n if (!this._state) {\r\n this._state = createGeometryCacheState(frame);\r\n }\r\n this._state.positions.set(frame.positions);\r\n if (frame.normals) {\r\n if (!this._state.normals || this._state.normals.length !== frame.normals.length) {\r\n this._state.normals = new Float32Array(frame.normals.length);\r\n }\r\n this._state.normals.set(frame.normals);\r\n } else {\r\n this._state.normals = null;\r\n }\r\n this._state.boundingBox.minPoint.set(frame.boundingBox.minPoint);\r\n this._state.boundingBox.maxPoint.set(frame.boundingBox.maxPoint);\r\n return this._state;\r\n }\r\n\r\n private interpolateFrames(a: FixedGeometryCacheFrame, b: FixedGeometryCacheFrame, t: number) {\r\n if (!this._state) {\r\n this._state = createGeometryCacheState(a);\r\n }\r\n for (let i = 0; i < this._state.positions.length; i++) {\r\n this._state.positions[i] = a.positions[i] + (b.positions[i] - a.positions[i]) * t;\r\n }\r\n if (a.normals && b.normals && a.normals.length === b.normals.length) {\r\n if (!this._state.normals || this._state.normals.length !== a.normals.length) {\r\n this._state.normals = new Float32Array(a.normals.length);\r\n }\r\n for (let i = 0; i < this._state.normals.length; i++) {\r\n this._state.normals[i] = a.normals[i] + (b.normals[i] - a.normals[i]) * t;\r\n }\r\n } else {\r\n this._state.normals = null;\r\n }\r\n this._state.boundingBox.minPoint.setXYZ(\r\n a.boundingBox.minPoint.x + (b.boundingBox.minPoint.x - a.boundingBox.minPoint.x) * t,\r\n a.boundingBox.minPoint.y + (b.boundingBox.minPoint.y - a.boundingBox.minPoint.y) * t,\r\n a.boundingBox.minPoint.z + (b.boundingBox.minPoint.z - a.boundingBox.minPoint.z) * t\r\n );\r\n this._state.boundingBox.maxPoint.setXYZ(\r\n a.boundingBox.maxPoint.x + (b.boundingBox.maxPoint.x - a.boundingBox.maxPoint.x) * t,\r\n a.boundingBox.maxPoint.y + (b.boundingBox.maxPoint.y - a.boundingBox.maxPoint.y) * t,\r\n a.boundingBox.maxPoint.z + (b.boundingBox.maxPoint.z - a.boundingBox.maxPoint.z) * t\r\n );\r\n return this._state;\r\n }\r\n\r\n private ensureMeshBinding(mesh: Mesh, state: FixedGeometryCacheState) {\r\n return ensureGeometryCacheMeshBinding(\r\n this._meshBindings,\r\n mesh,\r\n state,\r\n 'FixedGeometryCacheTrack.applyState()'\r\n );\r\n }\r\n}\r\n"],"names":["FixedGeometryCacheTrack","AnimationTrack","_times","_frames","_state","_meshBindings","times","frames","embedded","Float32Array","length","createGeometryCacheState","WeakMap","value","calculateState","_target","currentTime","Error","copyFrameToState","lastIndex","right","left","Math","max","start","end","t","interpolateFrames","applyState","target","state","mesh","binding","ensureMeshBinding","positionBuffer","bufferSubData","positions","normalBuffer","normals","setAnimatedBoundingBox","boundingBox","mixState","a","b","i","mixGeometryCacheBoundingBox","getBlendId","getDuration","reset","frame","set","minPoint","maxPoint","setXYZ","x","y","z","ensureGeometryCacheMeshBinding"],"mappings":"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"}
@@ -3,17 +3,29 @@ import { BoundingBox } from '../utility/bounding_volume.js';
3
3
  import { Vector3 } from '@zephyr3d/base';
4
4
 
5
5
  const geometryCacheMeshStates = new WeakMap();
6
- function createGeometryCacheState(frame) {
6
+ /**
7
+ * Creates a reusable geometry cache state buffer for a frame layout.
8
+ *
9
+ * @public
10
+ */ function createGeometryCacheState(frame) {
7
11
  return {
8
12
  positions: new Float32Array(frame.positions.length),
9
13
  normals: frame.normals ? new Float32Array(frame.normals.length) : null,
10
14
  boundingBox: new BoundingBox()
11
15
  };
12
16
  }
13
- function mixGeometryCacheBoundingBox(a, b, t) {
17
+ /**
18
+ * Linearly interpolates two geometry-cache bounding boxes.
19
+ *
20
+ * @public
21
+ */ function mixGeometryCacheBoundingBox(a, b, t) {
14
22
  return new BoundingBox(new Vector3(a.minPoint.x + (b.minPoint.x - a.minPoint.x) * t, a.minPoint.y + (b.minPoint.y - a.minPoint.y) * t, a.minPoint.z + (b.minPoint.z - a.minPoint.z) * t), new Vector3(a.maxPoint.x + (b.maxPoint.x - a.maxPoint.x) * t, a.maxPoint.y + (b.maxPoint.y - a.maxPoint.y) * t, a.maxPoint.z + (b.maxPoint.z - a.maxPoint.z) * t));
15
23
  }
16
- function ensureGeometryCacheMeshBinding(meshBindings, mesh, state, errorPrefix) {
24
+ /**
25
+ * Ensures the target mesh has GPU buffers compatible with the geometry cache state.
26
+ *
27
+ * @public
28
+ */ function ensureGeometryCacheMeshBinding(meshBindings, mesh, state, errorPrefix) {
17
29
  let binding = meshBindings.get(mesh);
18
30
  if (!binding) {
19
31
  const primitive = mesh.primitive;
@@ -38,7 +50,11 @@ function ensureGeometryCacheMeshBinding(meshBindings, mesh, state, errorPrefix)
38
50
  }
39
51
  return binding;
40
52
  }
41
- async function restoreGeometryCacheMeshBinding(mesh) {
53
+ /**
54
+ * Restores a mesh primitive after geometry cache playback.
55
+ *
56
+ * @public
57
+ */ async function restoreGeometryCacheMeshBinding(mesh) {
42
58
  const meshState = geometryCacheMeshStates.get(mesh);
43
59
  if (!meshState) {
44
60
  return false;
@@ -1 +1 @@
1
- {"version":3,"file":"geometry_cache_utils.js","sources":["../../src/animation/geometry_cache_utils.ts"],"sourcesContent":["import { getDevice, getEngine } from '../app/api';\r\nimport type { Mesh } from '../scene';\r\nimport type { Primitive } from '../render/primitive';\r\nimport { BoundingBox } from '../utility/bounding_volume';\r\nimport type { Nullable } from '@zephyr3d/base';\r\nimport { Vector3 } from '@zephyr3d/base';\r\nimport type { StructuredBuffer } from '@zephyr3d/device';\r\n\r\nexport type GeometryCacheFrame = {\r\n positions: Float32Array;\r\n normals?: Nullable<Float32Array>;\r\n boundingBox: BoundingBox;\r\n};\r\n\r\nexport type GeometryCacheState = {\r\n positions: Float32Array;\r\n normals?: Nullable<Float32Array>;\r\n boundingBox: BoundingBox;\r\n};\r\n\r\nexport type GeometryCacheMeshBinding = {\r\n originalPrimitive: Primitive;\r\n primitive: Primitive;\r\n positionBuffer: StructuredBuffer;\r\n normalBuffer: Nullable<StructuredBuffer>;\r\n};\r\n\r\ntype GeometryCacheMeshState = {\r\n originalPrimitive: Primitive;\r\n originalPrimitiveAssetId: string;\r\n cachePrimitive: Primitive;\r\n positionBuffer: StructuredBuffer;\r\n normalBuffer: Nullable<StructuredBuffer>;\r\n};\r\n\r\nconst geometryCacheMeshStates = new WeakMap<Mesh, GeometryCacheMeshState>();\r\n\r\nexport function createGeometryCacheState(\r\n frame: Pick<GeometryCacheFrame, 'positions' | 'normals'>\r\n): GeometryCacheState {\r\n return {\r\n positions: new Float32Array(frame.positions.length),\r\n normals: frame.normals ? new Float32Array(frame.normals.length) : null,\r\n boundingBox: new BoundingBox()\r\n };\r\n}\r\n\r\nexport function mixGeometryCacheBoundingBox(a: BoundingBox, b: BoundingBox, t: number) {\r\n return new BoundingBox(\r\n new Vector3(\r\n a.minPoint.x + (b.minPoint.x - a.minPoint.x) * t,\r\n a.minPoint.y + (b.minPoint.y - a.minPoint.y) * t,\r\n a.minPoint.z + (b.minPoint.z - a.minPoint.z) * t\r\n ),\r\n new Vector3(\r\n a.maxPoint.x + (b.maxPoint.x - a.maxPoint.x) * t,\r\n a.maxPoint.y + (b.maxPoint.y - a.maxPoint.y) * t,\r\n a.maxPoint.z + (b.maxPoint.z - a.maxPoint.z) * t\r\n )\r\n );\r\n}\r\n\r\nexport function ensureGeometryCacheMeshBinding(\r\n meshBindings: WeakMap<Mesh, GeometryCacheMeshBinding>,\r\n mesh: Mesh,\r\n state: GeometryCacheState,\r\n errorPrefix: string\r\n) {\r\n let binding = meshBindings.get(mesh);\r\n if (!binding) {\r\n const primitive = mesh.primitive;\r\n const meshState = geometryCacheMeshStates.get(mesh);\r\n const originalPrimitive = meshState?.originalPrimitive ?? primitive;\r\n if (!originalPrimitive) {\r\n throw new Error(`${errorPrefix}: target mesh has no primitive`);\r\n }\r\n validateGeometryCacheState(originalPrimitive, state, errorPrefix);\r\n const ensuredState = meshState\r\n ? ensureGeometryCacheNormalBuffer(meshState, originalPrimitive, state, errorPrefix)\r\n : createGeometryCacheMeshState(originalPrimitive, state);\r\n geometryCacheMeshStates.set(mesh, ensuredState);\r\n if (mesh.primitive !== ensuredState.cachePrimitive) {\r\n mesh.primitive = ensuredState.cachePrimitive;\r\n }\r\n binding = {\r\n originalPrimitive,\r\n primitive: ensuredState.cachePrimitive,\r\n positionBuffer: ensuredState.positionBuffer,\r\n normalBuffer: ensuredState.normalBuffer\r\n };\r\n meshBindings.set(mesh, binding);\r\n }\r\n return binding;\r\n}\r\n\r\nexport async function restoreGeometryCacheMeshBinding(mesh: Mesh) {\r\n const meshState = geometryCacheMeshStates.get(mesh);\r\n if (!meshState) {\r\n return false;\r\n }\r\n const primitiveToRestore = await resolveOriginalPrimitive(meshState);\r\n if (mesh.primitive === meshState.cachePrimitive) {\r\n mesh.primitive = primitiveToRestore;\r\n }\r\n mesh.setAnimatedBoundingBox(null);\r\n mesh.scene?.queueUpdateNode(mesh);\r\n geometryCacheMeshStates.delete(mesh);\r\n return true;\r\n}\r\n\r\nfunction validateGeometryCacheState(primitive: Primitive, state: GeometryCacheState, errorPrefix: string) {\r\n const expectedPositionLength = primitive.getNumVertices() * 3;\r\n if (state.positions.length !== expectedPositionLength) {\r\n throw new Error(\r\n `${errorPrefix}: position count mismatch, expected ${expectedPositionLength}, got ${state.positions.length}`\r\n );\r\n }\r\n if (state.normals) {\r\n const expectedNormalLength = primitive.getNumVertices() * 3;\r\n if (state.normals.length !== expectedNormalLength) {\r\n throw new Error(\r\n `${errorPrefix}: normal count mismatch, expected ${expectedNormalLength}, got ${state.normals.length}`\r\n );\r\n }\r\n }\r\n}\r\n\r\nfunction createGeometryCacheMeshState(\r\n originalPrimitive: Primitive,\r\n state: GeometryCacheState\r\n): GeometryCacheMeshState {\r\n const cachePrimitive = originalPrimitive.clone();\r\n cachePrimitive.setBoundingVolume(originalPrimitive.getBoundingVolume()!);\r\n const primitiveAssetId = getEngine().resourceManager.getAssetId(originalPrimitive);\r\n if (primitiveAssetId) {\r\n getEngine().resourceManager.setAssetId(cachePrimitive, primitiveAssetId);\r\n }\r\n cachePrimitive.removeVertexBuffer('position');\r\n const positionBuffer = getDevice().createVertexBuffer(\r\n 'position_f32x3',\r\n state.positions as unknown as Float32Array<ArrayBuffer>,\r\n {\r\n dynamic: true\r\n }\r\n )!;\r\n cachePrimitive.setVertexBuffer(positionBuffer);\r\n let normalBuffer: Nullable<StructuredBuffer> = null;\r\n if (state.normals) {\r\n cachePrimitive.removeVertexBuffer('normal');\r\n normalBuffer = getDevice().createVertexBuffer(\r\n 'normal_f32x3',\r\n state.normals as unknown as Float32Array<ArrayBuffer>,\r\n {\r\n dynamic: true\r\n }\r\n )!;\r\n cachePrimitive.setVertexBuffer(normalBuffer);\r\n }\r\n return {\r\n originalPrimitive,\r\n originalPrimitiveAssetId: primitiveAssetId ?? '',\r\n cachePrimitive,\r\n positionBuffer,\r\n normalBuffer\r\n };\r\n}\r\n\r\nfunction ensureGeometryCacheNormalBuffer(\r\n meshState: GeometryCacheMeshState,\r\n originalPrimitive: Primitive,\r\n state: GeometryCacheState,\r\n errorPrefix: string\r\n) {\r\n if (state.normals && !meshState.normalBuffer) {\r\n const expectedNormalLength = originalPrimitive.getNumVertices() * 3;\r\n if (state.normals.length !== expectedNormalLength) {\r\n throw new Error(\r\n `${errorPrefix}: normal count mismatch, expected ${expectedNormalLength}, got ${state.normals.length}`\r\n );\r\n }\r\n meshState.cachePrimitive.removeVertexBuffer('normal');\r\n meshState.normalBuffer = getDevice().createVertexBuffer(\r\n 'normal_f32x3',\r\n state.normals as unknown as Float32Array<ArrayBuffer>,\r\n {\r\n dynamic: true\r\n }\r\n )!;\r\n meshState.cachePrimitive.setVertexBuffer(meshState.normalBuffer);\r\n }\r\n return meshState;\r\n}\r\n\r\nasync function resolveOriginalPrimitive(meshState: GeometryCacheMeshState) {\r\n if (meshState.originalPrimitiveAssetId) {\r\n const restoredPrimitive = await getEngine().resourceManager.fetchPrimitive(\r\n meshState.originalPrimitiveAssetId\r\n );\r\n if (restoredPrimitive) {\r\n return restoredPrimitive;\r\n }\r\n }\r\n return meshState.originalPrimitive;\r\n}\r\n"],"names":["geometryCacheMeshStates","WeakMap","createGeometryCacheState","frame","positions","Float32Array","length","normals","boundingBox","BoundingBox","mixGeometryCacheBoundingBox","a","b","t","Vector3","minPoint","x","y","z","maxPoint","ensureGeometryCacheMeshBinding","meshBindings","mesh","state","errorPrefix","binding","get","primitive","meshState","originalPrimitive","Error","validateGeometryCacheState","ensuredState","ensureGeometryCacheNormalBuffer","createGeometryCacheMeshState","set","cachePrimitive","positionBuffer","normalBuffer","restoreGeometryCacheMeshBinding","primitiveToRestore","resolveOriginalPrimitive","setAnimatedBoundingBox","scene","queueUpdateNode","delete","expectedPositionLength","getNumVertices","expectedNormalLength","clone","setBoundingVolume","getBoundingVolume","primitiveAssetId","getEngine","resourceManager","getAssetId","setAssetId","removeVertexBuffer","getDevice","createVertexBuffer","dynamic","setVertexBuffer","originalPrimitiveAssetId","restoredPrimitive","fetchPrimitive"],"mappings":"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"}
1
+ {"version":3,"file":"geometry_cache_utils.js","sources":["../../src/animation/geometry_cache_utils.ts"],"sourcesContent":["import { getDevice, getEngine } from '../app/api';\r\nimport type { Mesh } from '../scene';\r\nimport type { Primitive } from '../render/primitive';\r\nimport { BoundingBox } from '../utility/bounding_volume';\r\nimport type { Nullable } from '@zephyr3d/base';\r\nimport { Vector3 } from '@zephyr3d/base';\r\nimport type { StructuredBuffer } from '@zephyr3d/device';\r\n\r\n/**\r\n * Geometry cache frame data for a single sampled time.\r\n *\r\n * @public\r\n */\r\nexport type GeometryCacheFrame = {\r\n positions: Float32Array;\r\n normals?: Nullable<Float32Array>;\r\n boundingBox: BoundingBox;\r\n};\r\n\r\n/**\r\n * Mutable working state used while evaluating geometry cache tracks.\r\n *\r\n * @public\r\n */\r\nexport type GeometryCacheState = {\r\n positions: Float32Array;\r\n normals?: Nullable<Float32Array>;\r\n boundingBox: BoundingBox;\r\n};\r\n\r\n/**\r\n * GPU resources bound to a mesh while a geometry cache track is active.\r\n *\r\n * @public\r\n */\r\nexport type GeometryCacheMeshBinding = {\r\n originalPrimitive: Primitive;\r\n primitive: Primitive;\r\n positionBuffer: StructuredBuffer;\r\n normalBuffer: Nullable<StructuredBuffer>;\r\n};\r\n\r\ntype GeometryCacheMeshState = {\r\n originalPrimitive: Primitive;\r\n originalPrimitiveAssetId: string;\r\n cachePrimitive: Primitive;\r\n positionBuffer: StructuredBuffer;\r\n normalBuffer: Nullable<StructuredBuffer>;\r\n};\r\n\r\nconst geometryCacheMeshStates = new WeakMap<Mesh, GeometryCacheMeshState>();\r\n\r\n/**\r\n * Creates a reusable geometry cache state buffer for a frame layout.\r\n *\r\n * @public\r\n */\r\nexport function createGeometryCacheState(\r\n frame: Pick<GeometryCacheFrame, 'positions' | 'normals'>\r\n): GeometryCacheState {\r\n return {\r\n positions: new Float32Array(frame.positions.length),\r\n normals: frame.normals ? new Float32Array(frame.normals.length) : null,\r\n boundingBox: new BoundingBox()\r\n };\r\n}\r\n\r\n/**\r\n * Linearly interpolates two geometry-cache bounding boxes.\r\n *\r\n * @public\r\n */\r\nexport function mixGeometryCacheBoundingBox(a: BoundingBox, b: BoundingBox, t: number) {\r\n return new BoundingBox(\r\n new Vector3(\r\n a.minPoint.x + (b.minPoint.x - a.minPoint.x) * t,\r\n a.minPoint.y + (b.minPoint.y - a.minPoint.y) * t,\r\n a.minPoint.z + (b.minPoint.z - a.minPoint.z) * t\r\n ),\r\n new Vector3(\r\n a.maxPoint.x + (b.maxPoint.x - a.maxPoint.x) * t,\r\n a.maxPoint.y + (b.maxPoint.y - a.maxPoint.y) * t,\r\n a.maxPoint.z + (b.maxPoint.z - a.maxPoint.z) * t\r\n )\r\n );\r\n}\r\n\r\n/**\r\n * Ensures the target mesh has GPU buffers compatible with the geometry cache state.\r\n *\r\n * @public\r\n */\r\nexport function ensureGeometryCacheMeshBinding(\r\n meshBindings: WeakMap<Mesh, GeometryCacheMeshBinding>,\r\n mesh: Mesh,\r\n state: GeometryCacheState,\r\n errorPrefix: string\r\n) {\r\n let binding = meshBindings.get(mesh);\r\n if (!binding) {\r\n const primitive = mesh.primitive;\r\n const meshState = geometryCacheMeshStates.get(mesh);\r\n const originalPrimitive = meshState?.originalPrimitive ?? primitive;\r\n if (!originalPrimitive) {\r\n throw new Error(`${errorPrefix}: target mesh has no primitive`);\r\n }\r\n validateGeometryCacheState(originalPrimitive, state, errorPrefix);\r\n const ensuredState = meshState\r\n ? ensureGeometryCacheNormalBuffer(meshState, originalPrimitive, state, errorPrefix)\r\n : createGeometryCacheMeshState(originalPrimitive, state);\r\n geometryCacheMeshStates.set(mesh, ensuredState);\r\n if (mesh.primitive !== ensuredState.cachePrimitive) {\r\n mesh.primitive = ensuredState.cachePrimitive;\r\n }\r\n binding = {\r\n originalPrimitive,\r\n primitive: ensuredState.cachePrimitive,\r\n positionBuffer: ensuredState.positionBuffer,\r\n normalBuffer: ensuredState.normalBuffer\r\n };\r\n meshBindings.set(mesh, binding);\r\n }\r\n return binding;\r\n}\r\n\r\n/**\r\n * Restores a mesh primitive after geometry cache playback.\r\n *\r\n * @public\r\n */\r\nexport async function restoreGeometryCacheMeshBinding(mesh: Mesh) {\r\n const meshState = geometryCacheMeshStates.get(mesh);\r\n if (!meshState) {\r\n return false;\r\n }\r\n const primitiveToRestore = await resolveOriginalPrimitive(meshState);\r\n if (mesh.primitive === meshState.cachePrimitive) {\r\n mesh.primitive = primitiveToRestore;\r\n }\r\n mesh.setAnimatedBoundingBox(null);\r\n mesh.scene?.queueUpdateNode(mesh);\r\n geometryCacheMeshStates.delete(mesh);\r\n return true;\r\n}\r\n\r\nfunction validateGeometryCacheState(primitive: Primitive, state: GeometryCacheState, errorPrefix: string) {\r\n const expectedPositionLength = primitive.getNumVertices() * 3;\r\n if (state.positions.length !== expectedPositionLength) {\r\n throw new Error(\r\n `${errorPrefix}: position count mismatch, expected ${expectedPositionLength}, got ${state.positions.length}`\r\n );\r\n }\r\n if (state.normals) {\r\n const expectedNormalLength = primitive.getNumVertices() * 3;\r\n if (state.normals.length !== expectedNormalLength) {\r\n throw new Error(\r\n `${errorPrefix}: normal count mismatch, expected ${expectedNormalLength}, got ${state.normals.length}`\r\n );\r\n }\r\n }\r\n}\r\n\r\nfunction createGeometryCacheMeshState(\r\n originalPrimitive: Primitive,\r\n state: GeometryCacheState\r\n): GeometryCacheMeshState {\r\n const cachePrimitive = originalPrimitive.clone();\r\n cachePrimitive.setBoundingVolume(originalPrimitive.getBoundingVolume()!);\r\n const primitiveAssetId = getEngine().resourceManager.getAssetId(originalPrimitive);\r\n if (primitiveAssetId) {\r\n getEngine().resourceManager.setAssetId(cachePrimitive, primitiveAssetId);\r\n }\r\n cachePrimitive.removeVertexBuffer('position');\r\n const positionBuffer = getDevice().createVertexBuffer(\r\n 'position_f32x3',\r\n state.positions as unknown as Float32Array<ArrayBuffer>,\r\n {\r\n dynamic: true\r\n }\r\n )!;\r\n cachePrimitive.setVertexBuffer(positionBuffer);\r\n let normalBuffer: Nullable<StructuredBuffer> = null;\r\n if (state.normals) {\r\n cachePrimitive.removeVertexBuffer('normal');\r\n normalBuffer = getDevice().createVertexBuffer(\r\n 'normal_f32x3',\r\n state.normals as unknown as Float32Array<ArrayBuffer>,\r\n {\r\n dynamic: true\r\n }\r\n )!;\r\n cachePrimitive.setVertexBuffer(normalBuffer);\r\n }\r\n return {\r\n originalPrimitive,\r\n originalPrimitiveAssetId: primitiveAssetId ?? '',\r\n cachePrimitive,\r\n positionBuffer,\r\n normalBuffer\r\n };\r\n}\r\n\r\nfunction ensureGeometryCacheNormalBuffer(\r\n meshState: GeometryCacheMeshState,\r\n originalPrimitive: Primitive,\r\n state: GeometryCacheState,\r\n errorPrefix: string\r\n) {\r\n if (state.normals && !meshState.normalBuffer) {\r\n const expectedNormalLength = originalPrimitive.getNumVertices() * 3;\r\n if (state.normals.length !== expectedNormalLength) {\r\n throw new Error(\r\n `${errorPrefix}: normal count mismatch, expected ${expectedNormalLength}, got ${state.normals.length}`\r\n );\r\n }\r\n meshState.cachePrimitive.removeVertexBuffer('normal');\r\n meshState.normalBuffer = getDevice().createVertexBuffer(\r\n 'normal_f32x3',\r\n state.normals as unknown as Float32Array<ArrayBuffer>,\r\n {\r\n dynamic: true\r\n }\r\n )!;\r\n meshState.cachePrimitive.setVertexBuffer(meshState.normalBuffer);\r\n }\r\n return meshState;\r\n}\r\n\r\nasync function resolveOriginalPrimitive(meshState: GeometryCacheMeshState) {\r\n if (meshState.originalPrimitiveAssetId) {\r\n const restoredPrimitive = await getEngine().resourceManager.fetchPrimitive(\r\n meshState.originalPrimitiveAssetId\r\n );\r\n if (restoredPrimitive) {\r\n return restoredPrimitive;\r\n }\r\n }\r\n return meshState.originalPrimitive;\r\n}\r\n"],"names":["geometryCacheMeshStates","WeakMap","createGeometryCacheState","frame","positions","Float32Array","length","normals","boundingBox","BoundingBox","mixGeometryCacheBoundingBox","a","b","t","Vector3","minPoint","x","y","z","maxPoint","ensureGeometryCacheMeshBinding","meshBindings","mesh","state","errorPrefix","binding","get","primitive","meshState","originalPrimitive","Error","validateGeometryCacheState","ensuredState","ensureGeometryCacheNormalBuffer","createGeometryCacheMeshState","set","cachePrimitive","positionBuffer","normalBuffer","restoreGeometryCacheMeshBinding","primitiveToRestore","resolveOriginalPrimitive","setAnimatedBoundingBox","scene","queueUpdateNode","delete","expectedPositionLength","getNumVertices","expectedNormalLength","clone","setBoundingVolume","getBoundingVolume","primitiveAssetId","getEngine","resourceManager","getAssetId","setAssetId","removeVertexBuffer","getDevice","createVertexBuffer","dynamic","setVertexBuffer","originalPrimitiveAssetId","restoredPrimitive","fetchPrimitive"],"mappings":"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"}
@@ -34,9 +34,7 @@ import { IKConstraint } from './ik_constraint.js';
34
34
  */ get minAngle() {
35
35
  return this._minAngle;
36
36
  }
37
- /**
38
- * Set the minimum angle in degrees.
39
- */ set minAngle(value) {
37
+ set minAngle(value) {
40
38
  this._minAngle = Math.max(0, Math.min(value, this._maxAngle));
41
39
  }
42
40
  /**
@@ -44,9 +42,7 @@ import { IKConstraint } from './ik_constraint.js';
44
42
  */ get maxAngle() {
45
43
  return this._maxAngle;
46
44
  }
47
- /**
48
- * Set the maximum angle in degrees.
49
- */ set maxAngle(value) {
45
+ set maxAngle(value) {
50
46
  this._maxAngle = Math.min(180, Math.max(value, this._minAngle));
51
47
  }
52
48
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"ik_angle_constraint.js","sources":["../../../src/animation/ik/ik_angle_constraint.ts"],"sourcesContent":["import { Vector3 } from '@zephyr3d/base';\r\nimport { IKConstraint } from './ik_constraint';\r\nimport type { IKJoint } from './ik_joint';\r\n\r\n/**\r\n * Angle constraint for IK joints.\r\n *\r\n * Limits the angle between the bone from parent to this joint\r\n * and the bone from this joint to child.\r\n *\r\n * @remarks\r\n * This is useful for joints like elbows and knees that have\r\n * limited range of motion.\r\n *\r\n * @public\r\n */\r\nexport class IKAngleConstraint extends IKConstraint {\r\n /** Minimum angle in degrees */\r\n private _minAngle: number;\r\n /** Maximum angle in degrees */\r\n private _maxAngle: number;\r\n\r\n /**\r\n * Create an angle constraint.\r\n *\r\n * @param jointIndex - Index of the joint in the chain\r\n * @param minAngle - Minimum angle in degrees (0 = straight)\r\n * @param maxAngle - Maximum angle in degrees (180 = fully bent)\r\n */\r\n constructor(jointIndex: number, minAngle: number, maxAngle: number) {\r\n super(jointIndex);\r\n this._minAngle = Math.max(0, minAngle);\r\n this._maxAngle = Math.min(180, maxAngle);\r\n\r\n if (this._minAngle > this._maxAngle) {\r\n throw new Error('IKAngleConstraint: minAngle must be <= maxAngle');\r\n }\r\n }\r\n\r\n /**\r\n * Get the minimum angle in degrees.\r\n */\r\n get minAngle(): number {\r\n return this._minAngle;\r\n }\r\n\r\n /**\r\n * Set the minimum angle in degrees.\r\n */\r\n set minAngle(value: number) {\r\n this._minAngle = Math.max(0, Math.min(value, this._maxAngle));\r\n }\r\n\r\n /**\r\n * Get the maximum angle in degrees.\r\n */\r\n get maxAngle(): number {\r\n return this._maxAngle;\r\n }\r\n\r\n /**\r\n * Set the maximum angle in degrees.\r\n */\r\n set maxAngle(value: number) {\r\n this._maxAngle = Math.min(180, Math.max(value, this._minAngle));\r\n }\r\n\r\n /**\r\n * Apply the angle constraint to limit joint bending.\r\n */\r\n apply(joints: IKJoint[]): void {\r\n const index = this._jointIndex;\r\n\r\n // For end effector (last joint), we constrain the angle between the last two bones\r\n // For other joints, we constrain the angle at the joint itself\r\n if (index === joints.length - 1) {\r\n // End effector: constrain angle between (parent-1 -> parent) and (parent -> this)\r\n if (index < 2) {\r\n return; // Need at least 3 joints total\r\n }\r\n this._applyEndEffectorConstraint(joints, index);\r\n } else {\r\n // Regular joint: constrain angle between (parent -> this) and (this -> child)\r\n if (index < 1) {\r\n return; // Root joint cannot be constrained this way\r\n }\r\n this._applyRegularConstraint(joints, index);\r\n }\r\n }\r\n\r\n /**\r\n * Apply constraint to end effector joint.\r\n */\r\n private _applyEndEffectorConstraint(joints: IKJoint[], index: number): void {\r\n const grandParentJoint = joints[index - 2];\r\n const parentJoint = joints[index - 1];\r\n const currentJoint = joints[index];\r\n\r\n // Calculate bone vectors\r\n const incomingBone = Vector3.sub(parentJoint.position, grandParentJoint.position, new Vector3());\r\n const outgoingBone = Vector3.sub(currentJoint.position, parentJoint.position, new Vector3());\r\n\r\n const incomingLen = incomingBone.magnitude;\r\n const outgoingLen = outgoingBone.magnitude;\r\n\r\n if (incomingLen < 0.000001 || outgoingLen < 0.000001) {\r\n return;\r\n }\r\n\r\n // Normalize\r\n const incomingNorm = Vector3.scale(incomingBone, 1 / incomingLen, new Vector3());\r\n const outgoingNorm = Vector3.scale(outgoingBone, 1 / outgoingLen, new Vector3());\r\n\r\n // Calculate current angle\r\n const dot = Vector3.dot(incomingNorm, outgoingNorm);\r\n const currentAngleDeg = Math.acos(Math.max(-1, Math.min(1, dot))) * (180 / Math.PI);\r\n\r\n // Check if constraint is violated\r\n let targetAngleDeg = currentAngleDeg;\r\n if (currentAngleDeg < this._minAngle) {\r\n targetAngleDeg = this._minAngle;\r\n } else if (currentAngleDeg > this._maxAngle) {\r\n targetAngleDeg = this._maxAngle;\r\n } else {\r\n return;\r\n }\r\n\r\n // Apply the same constraint logic as regular joints\r\n this._adjustJointAngle(\r\n incomingNorm,\r\n outgoingNorm,\r\n currentAngleDeg,\r\n targetAngleDeg,\r\n parentJoint,\r\n currentJoint\r\n );\r\n }\r\n\r\n /**\r\n * Apply constraint to regular joint.\r\n */\r\n private _applyRegularConstraint(joints: IKJoint[], index: number): void {\r\n const parentJoint = joints[index - 1];\r\n const currentJoint = joints[index];\r\n const childJoint = joints[index + 1];\r\n\r\n // Calculate bone vectors: incoming bone (parent->current) and outgoing bone (current->child)\r\n const incomingBone = Vector3.sub(currentJoint.position, parentJoint.position, new Vector3());\r\n const outgoingBone = Vector3.sub(childJoint.position, currentJoint.position, new Vector3());\r\n\r\n const incomingLen = incomingBone.magnitude;\r\n const outgoingLen = outgoingBone.magnitude;\r\n\r\n if (incomingLen < 0.000001 || outgoingLen < 0.000001) {\r\n return;\r\n }\r\n\r\n // Normalize\r\n const incomingNorm = Vector3.scale(incomingBone, 1 / incomingLen, new Vector3());\r\n const outgoingNorm = Vector3.scale(outgoingBone, 1 / outgoingLen, new Vector3());\r\n\r\n // Calculate current angle between incoming and outgoing bones (interior angle)\r\n const dot = Vector3.dot(incomingNorm, outgoingNorm);\r\n const currentAngleDeg = Math.acos(Math.max(-1, Math.min(1, dot))) * (180 / Math.PI);\r\n\r\n // Check if constraint is violated\r\n let targetAngleDeg = currentAngleDeg;\r\n if (currentAngleDeg < this._minAngle) {\r\n targetAngleDeg = this._minAngle;\r\n } else if (currentAngleDeg > this._maxAngle) {\r\n targetAngleDeg = this._maxAngle;\r\n } else {\r\n return;\r\n }\r\n\r\n // Apply the constraint\r\n this._adjustJointAngle(\r\n incomingNorm,\r\n outgoingNorm,\r\n currentAngleDeg,\r\n targetAngleDeg,\r\n currentJoint,\r\n childJoint\r\n );\r\n }\r\n\r\n /**\r\n * Adjust joint angle by rotating the outgoing bone.\r\n */\r\n private _adjustJointAngle(\r\n incomingNorm: Vector3,\r\n outgoingNorm: Vector3,\r\n currentAngleDeg: number,\r\n targetAngleDeg: number,\r\n pivotJoint: IKJoint,\r\n targetJoint: IKJoint\r\n ): void {\r\n // Add a dead zone to prevent oscillation\r\n const angleDifference = Math.abs(targetAngleDeg - currentAngleDeg);\r\n const isHardConstraint = Math.abs(this._maxAngle - this._minAngle) < 0.01;\r\n const deadZone = isHardConstraint ? 0.2 : 0.1;\r\n\r\n if (angleDifference < deadZone) {\r\n return; // Too close to target, avoid over-correction\r\n }\r\n\r\n // Calculate rotation axis (perpendicular to both bone vectors)\r\n const axis = Vector3.cross(incomingNorm, outgoingNorm, new Vector3());\r\n const axisLen = axis.magnitude;\r\n\r\n // Use a smaller threshold to allow constraint to work at small angles\r\n if (axisLen < 0.0001) {\r\n return; // Vectors are too close to parallel or anti-parallel\r\n }\r\n\r\n axis.scaleBy(1 / axisLen);\r\n\r\n // Calculate the angle we need to rotate\r\n const targetAngleRad = targetAngleDeg * (Math.PI / 180);\r\n const currentAngleRad = currentAngleDeg * (Math.PI / 180);\r\n let deltaAngle = targetAngleRad - currentAngleRad;\r\n\r\n // Apply full correction without damping to ensure constraints are enforced\r\n // This is necessary because FABRIK will try to undo the constraint in the next iteration\r\n // So we need strong constraint enforcement\r\n\r\n // Rotate the outgoing bone vector around the axis by deltaAngle\r\n const cos = Math.cos(deltaAngle);\r\n const sin = Math.sin(deltaAngle);\r\n const oneMinusCos = 1 - cos;\r\n\r\n // Rodrigues' rotation formula\r\n const rotated = new Vector3();\r\n rotated.x =\r\n outgoingNorm.x * (cos + axis.x * axis.x * oneMinusCos) +\r\n outgoingNorm.y * (axis.x * axis.y * oneMinusCos - axis.z * sin) +\r\n outgoingNorm.z * (axis.x * axis.z * oneMinusCos + axis.y * sin);\r\n\r\n rotated.y =\r\n outgoingNorm.x * (axis.y * axis.x * oneMinusCos + axis.z * sin) +\r\n outgoingNorm.y * (cos + axis.y * axis.y * oneMinusCos) +\r\n outgoingNorm.z * (axis.y * axis.z * oneMinusCos - axis.x * sin);\r\n\r\n rotated.z =\r\n outgoingNorm.x * (axis.z * axis.x * oneMinusCos - axis.y * sin) +\r\n outgoingNorm.y * (axis.z * axis.y * oneMinusCos + axis.x * sin) +\r\n outgoingNorm.z * (cos + axis.z * axis.z * oneMinusCos);\r\n\r\n // Update target joint position using the rotated bone vector\r\n const boneLength = pivotJoint.boneLength;\r\n rotated.scaleBy(boneLength);\r\n Vector3.add(pivotJoint.position, rotated, targetJoint.position);\r\n\r\n // Note: We do NOT recursively update subsequent joints here.\r\n // Instead, we let FABRIK algorithm handle the propagation in subsequent iterations.\r\n // This ensures that each joint's constraint is properly applied.\r\n }\r\n}\r\n"],"names":["IKAngleConstraint","IKConstraint","jointIndex","minAngle","maxAngle","_minAngle","Math","max","_maxAngle","min","Error","value","apply","joints","index","_jointIndex","length","_applyEndEffectorConstraint","_applyRegularConstraint","grandParentJoint","parentJoint","currentJoint","incomingBone","Vector3","sub","position","outgoingBone","incomingLen","magnitude","outgoingLen","incomingNorm","scale","outgoingNorm","dot","currentAngleDeg","acos","PI","targetAngleDeg","_adjustJointAngle","childJoint","pivotJoint","targetJoint","angleDifference","abs","isHardConstraint","deadZone","axis","cross","axisLen","scaleBy","targetAngleRad","currentAngleRad","deltaAngle","cos","sin","oneMinusCos","rotated","x","y","z","boneLength","add"],"mappings":"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"}
1
+ {"version":3,"file":"ik_angle_constraint.js","sources":["../../../src/animation/ik/ik_angle_constraint.ts"],"sourcesContent":["import { Vector3 } from '@zephyr3d/base';\r\nimport { IKConstraint } from './ik_constraint';\r\nimport type { IKJoint } from './ik_joint';\r\n\r\n/**\r\n * Angle constraint for IK joints.\r\n *\r\n * Limits the angle between the bone from parent to this joint\r\n * and the bone from this joint to child.\r\n *\r\n * @remarks\r\n * This is useful for joints like elbows and knees that have\r\n * limited range of motion.\r\n *\r\n * @public\r\n */\r\nexport class IKAngleConstraint extends IKConstraint {\r\n /** Minimum angle in degrees */\r\n private _minAngle: number;\r\n /** Maximum angle in degrees */\r\n private _maxAngle: number;\r\n\r\n /**\r\n * Create an angle constraint.\r\n *\r\n * @param jointIndex - Index of the joint in the chain\r\n * @param minAngle - Minimum angle in degrees (0 = straight)\r\n * @param maxAngle - Maximum angle in degrees (180 = fully bent)\r\n */\r\n constructor(jointIndex: number, minAngle: number, maxAngle: number) {\r\n super(jointIndex);\r\n this._minAngle = Math.max(0, minAngle);\r\n this._maxAngle = Math.min(180, maxAngle);\r\n\r\n if (this._minAngle > this._maxAngle) {\r\n throw new Error('IKAngleConstraint: minAngle must be <= maxAngle');\r\n }\r\n }\r\n\r\n /**\r\n * Get the minimum angle in degrees.\r\n */\r\n get minAngle(): number {\r\n return this._minAngle;\r\n }\r\n\r\n set minAngle(value: number) {\r\n this._minAngle = Math.max(0, Math.min(value, this._maxAngle));\r\n }\r\n\r\n /**\r\n * Get the maximum angle in degrees.\r\n */\r\n get maxAngle(): number {\r\n return this._maxAngle;\r\n }\r\n\r\n set maxAngle(value: number) {\r\n this._maxAngle = Math.min(180, Math.max(value, this._minAngle));\r\n }\r\n\r\n /**\r\n * Apply the angle constraint to limit joint bending.\r\n */\r\n apply(joints: IKJoint[]): void {\r\n const index = this._jointIndex;\r\n\r\n // For end effector (last joint), we constrain the angle between the last two bones\r\n // For other joints, we constrain the angle at the joint itself\r\n if (index === joints.length - 1) {\r\n // End effector: constrain angle between (parent-1 -> parent) and (parent -> this)\r\n if (index < 2) {\r\n return; // Need at least 3 joints total\r\n }\r\n this._applyEndEffectorConstraint(joints, index);\r\n } else {\r\n // Regular joint: constrain angle between (parent -> this) and (this -> child)\r\n if (index < 1) {\r\n return; // Root joint cannot be constrained this way\r\n }\r\n this._applyRegularConstraint(joints, index);\r\n }\r\n }\r\n\r\n /**\r\n * Apply constraint to end effector joint.\r\n */\r\n private _applyEndEffectorConstraint(joints: IKJoint[], index: number): void {\r\n const grandParentJoint = joints[index - 2];\r\n const parentJoint = joints[index - 1];\r\n const currentJoint = joints[index];\r\n\r\n // Calculate bone vectors\r\n const incomingBone = Vector3.sub(parentJoint.position, grandParentJoint.position, new Vector3());\r\n const outgoingBone = Vector3.sub(currentJoint.position, parentJoint.position, new Vector3());\r\n\r\n const incomingLen = incomingBone.magnitude;\r\n const outgoingLen = outgoingBone.magnitude;\r\n\r\n if (incomingLen < 0.000001 || outgoingLen < 0.000001) {\r\n return;\r\n }\r\n\r\n // Normalize\r\n const incomingNorm = Vector3.scale(incomingBone, 1 / incomingLen, new Vector3());\r\n const outgoingNorm = Vector3.scale(outgoingBone, 1 / outgoingLen, new Vector3());\r\n\r\n // Calculate current angle\r\n const dot = Vector3.dot(incomingNorm, outgoingNorm);\r\n const currentAngleDeg = Math.acos(Math.max(-1, Math.min(1, dot))) * (180 / Math.PI);\r\n\r\n // Check if constraint is violated\r\n let targetAngleDeg = currentAngleDeg;\r\n if (currentAngleDeg < this._minAngle) {\r\n targetAngleDeg = this._minAngle;\r\n } else if (currentAngleDeg > this._maxAngle) {\r\n targetAngleDeg = this._maxAngle;\r\n } else {\r\n return;\r\n }\r\n\r\n // Apply the same constraint logic as regular joints\r\n this._adjustJointAngle(\r\n incomingNorm,\r\n outgoingNorm,\r\n currentAngleDeg,\r\n targetAngleDeg,\r\n parentJoint,\r\n currentJoint\r\n );\r\n }\r\n\r\n /**\r\n * Apply constraint to regular joint.\r\n */\r\n private _applyRegularConstraint(joints: IKJoint[], index: number): void {\r\n const parentJoint = joints[index - 1];\r\n const currentJoint = joints[index];\r\n const childJoint = joints[index + 1];\r\n\r\n // Calculate bone vectors: incoming bone (parent->current) and outgoing bone (current->child)\r\n const incomingBone = Vector3.sub(currentJoint.position, parentJoint.position, new Vector3());\r\n const outgoingBone = Vector3.sub(childJoint.position, currentJoint.position, new Vector3());\r\n\r\n const incomingLen = incomingBone.magnitude;\r\n const outgoingLen = outgoingBone.magnitude;\r\n\r\n if (incomingLen < 0.000001 || outgoingLen < 0.000001) {\r\n return;\r\n }\r\n\r\n // Normalize\r\n const incomingNorm = Vector3.scale(incomingBone, 1 / incomingLen, new Vector3());\r\n const outgoingNorm = Vector3.scale(outgoingBone, 1 / outgoingLen, new Vector3());\r\n\r\n // Calculate current angle between incoming and outgoing bones (interior angle)\r\n const dot = Vector3.dot(incomingNorm, outgoingNorm);\r\n const currentAngleDeg = Math.acos(Math.max(-1, Math.min(1, dot))) * (180 / Math.PI);\r\n\r\n // Check if constraint is violated\r\n let targetAngleDeg = currentAngleDeg;\r\n if (currentAngleDeg < this._minAngle) {\r\n targetAngleDeg = this._minAngle;\r\n } else if (currentAngleDeg > this._maxAngle) {\r\n targetAngleDeg = this._maxAngle;\r\n } else {\r\n return;\r\n }\r\n\r\n // Apply the constraint\r\n this._adjustJointAngle(\r\n incomingNorm,\r\n outgoingNorm,\r\n currentAngleDeg,\r\n targetAngleDeg,\r\n currentJoint,\r\n childJoint\r\n );\r\n }\r\n\r\n /**\r\n * Adjust joint angle by rotating the outgoing bone.\r\n */\r\n private _adjustJointAngle(\r\n incomingNorm: Vector3,\r\n outgoingNorm: Vector3,\r\n currentAngleDeg: number,\r\n targetAngleDeg: number,\r\n pivotJoint: IKJoint,\r\n targetJoint: IKJoint\r\n ): void {\r\n // Add a dead zone to prevent oscillation\r\n const angleDifference = Math.abs(targetAngleDeg - currentAngleDeg);\r\n const isHardConstraint = Math.abs(this._maxAngle - this._minAngle) < 0.01;\r\n const deadZone = isHardConstraint ? 0.2 : 0.1;\r\n\r\n if (angleDifference < deadZone) {\r\n return; // Too close to target, avoid over-correction\r\n }\r\n\r\n // Calculate rotation axis (perpendicular to both bone vectors)\r\n const axis = Vector3.cross(incomingNorm, outgoingNorm, new Vector3());\r\n const axisLen = axis.magnitude;\r\n\r\n // Use a smaller threshold to allow constraint to work at small angles\r\n if (axisLen < 0.0001) {\r\n return; // Vectors are too close to parallel or anti-parallel\r\n }\r\n\r\n axis.scaleBy(1 / axisLen);\r\n\r\n // Calculate the angle we need to rotate\r\n const targetAngleRad = targetAngleDeg * (Math.PI / 180);\r\n const currentAngleRad = currentAngleDeg * (Math.PI / 180);\r\n let deltaAngle = targetAngleRad - currentAngleRad;\r\n\r\n // Apply full correction without damping to ensure constraints are enforced\r\n // This is necessary because FABRIK will try to undo the constraint in the next iteration\r\n // So we need strong constraint enforcement\r\n\r\n // Rotate the outgoing bone vector around the axis by deltaAngle\r\n const cos = Math.cos(deltaAngle);\r\n const sin = Math.sin(deltaAngle);\r\n const oneMinusCos = 1 - cos;\r\n\r\n // Rodrigues' rotation formula\r\n const rotated = new Vector3();\r\n rotated.x =\r\n outgoingNorm.x * (cos + axis.x * axis.x * oneMinusCos) +\r\n outgoingNorm.y * (axis.x * axis.y * oneMinusCos - axis.z * sin) +\r\n outgoingNorm.z * (axis.x * axis.z * oneMinusCos + axis.y * sin);\r\n\r\n rotated.y =\r\n outgoingNorm.x * (axis.y * axis.x * oneMinusCos + axis.z * sin) +\r\n outgoingNorm.y * (cos + axis.y * axis.y * oneMinusCos) +\r\n outgoingNorm.z * (axis.y * axis.z * oneMinusCos - axis.x * sin);\r\n\r\n rotated.z =\r\n outgoingNorm.x * (axis.z * axis.x * oneMinusCos - axis.y * sin) +\r\n outgoingNorm.y * (axis.z * axis.y * oneMinusCos + axis.x * sin) +\r\n outgoingNorm.z * (cos + axis.z * axis.z * oneMinusCos);\r\n\r\n // Update target joint position using the rotated bone vector\r\n const boneLength = pivotJoint.boneLength;\r\n rotated.scaleBy(boneLength);\r\n Vector3.add(pivotJoint.position, rotated, targetJoint.position);\r\n\r\n // Note: We do NOT recursively update subsequent joints here.\r\n // Instead, we let FABRIK algorithm handle the propagation in subsequent iterations.\r\n // This ensures that each joint's constraint is properly applied.\r\n }\r\n}\r\n"],"names":["IKAngleConstraint","IKConstraint","jointIndex","minAngle","maxAngle","_minAngle","Math","max","_maxAngle","min","Error","value","apply","joints","index","_jointIndex","length","_applyEndEffectorConstraint","_applyRegularConstraint","grandParentJoint","parentJoint","currentJoint","incomingBone","Vector3","sub","position","outgoingBone","incomingLen","magnitude","outgoingLen","incomingNorm","scale","outgoingNorm","dot","currentAngleDeg","acos","PI","targetAngleDeg","_adjustJointAngle","childJoint","pivotJoint","targetJoint","angleDifference","abs","isHardConstraint","deadZone","axis","cross","axisLen","scaleBy","targetAngleRad","currentAngleRad","deltaAngle","cos","sin","oneMinusCos","rotated","x","y","z","boneLength","add"],"mappings":"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"}
@@ -89,9 +89,7 @@ import { IKUtils } from './ik_utils.js';
89
89
  */ get poleVector() {
90
90
  return this._poleVector;
91
91
  }
92
- /**
93
- * Set the pole vector position.
94
- */ set poleVector(value) {
92
+ set poleVector(value) {
95
93
  if (value) {
96
94
  if (!this._poleVector) {
97
95
  this._poleVector = value.clone();
@@ -107,9 +105,7 @@ import { IKUtils } from './ik_utils.js';
107
105
  */ get poleWeight() {
108
106
  return this._poleWeight;
109
107
  }
110
- /**
111
- * Set the pole vector weight (0-1).
112
- */ set poleWeight(value) {
108
+ set poleWeight(value) {
113
109
  this._poleWeight = Math.max(0, Math.min(1, value));
114
110
  }
115
111
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"two_bone_ik_solver.js","sources":["../../../src/animation/ik/two_bone_ik_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 * Two Bone IK solver for chains with exactly 3 joints (2 bones).\r\n *\r\n * @remarks\r\n * This solver uses an analytical solution specifically optimized for\r\n * two-bone chains like arms (shoulder-elbow-wrist) or legs (hip-knee-ankle).\r\n * It's faster and more stable than iterative methods like FABRIK for this case.\r\n *\r\n * The solver supports an optional pole vector to control the bending direction\r\n * of the middle joint (elbow/knee).\r\n *\r\n * @public\r\n */\r\nexport class TwoBoneIKSolver extends IKSolver {\r\n /** Optional pole vector position in world space */\r\n private _poleVector: Vector3 | null;\r\n /** Weight of the pole vector constraint (0-1) */\r\n private _poleWeight: number;\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 Two Bone IK solver.\r\n *\r\n * @param chain - The IK chain to solve (must have exactly 3 joints)\r\n * @param poleVector - Optional pole vector position in world space\r\n * @param poleWeight - Weight of the pole vector constraint (0-1, default: 1)\r\n */\r\n constructor(chain: IKChain, poleVector: Vector3 | null = null, poleWeight = 1) {\r\n super(chain, 1, 0.001); // Two bone IK doesn't need iterations\r\n\r\n if (chain.joints.length !== 3) {\r\n throw new Error('Two Bone IK requires exactly 3 joints (2 bones)');\r\n }\r\n\r\n this._poleVector = poleVector ? poleVector.clone() : null;\r\n this._poleWeight = Math.max(0, Math.min(1, poleWeight));\r\n this._twistConstraints = new Map();\r\n\r\n // Set default twist constraints\r\n // Root joint (shoulder/hip) - moderate twist\r\n this._twistConstraints.set(0, {\r\n minTwist: -Math.PI * 0.25, // -45 degrees\r\n maxTwist: Math.PI * 0.25, // +45 degrees\r\n smoothFactor: 0.3\r\n });\r\n\r\n // Middle joint (elbow/knee) - very limited twist\r\n this._twistConstraints.set(1, {\r\n minTwist: -Math.PI * 0.15, // -27 degrees\r\n maxTwist: Math.PI * 0.15, // +27 degrees\r\n smoothFactor: 0.3\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 (0 = root, 1 = middle)\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 * Get the pole vector position.\r\n */\r\n get poleVector(): Vector3 | null {\r\n return this._poleVector;\r\n }\r\n\r\n /**\r\n * Set the pole vector position.\r\n */\r\n set poleVector(value: Vector3 | null) {\r\n if (value) {\r\n if (!this._poleVector) {\r\n this._poleVector = value.clone();\r\n } else {\r\n this._poleVector.set(value);\r\n }\r\n } else {\r\n this._poleVector = null;\r\n }\r\n }\r\n\r\n /**\r\n * Get the pole vector weight.\r\n */\r\n get poleWeight(): number {\r\n return this._poleWeight;\r\n }\r\n\r\n /**\r\n * Set the pole vector weight (0-1).\r\n */\r\n set poleWeight(value: number) {\r\n this._poleWeight = Math.max(0, Math.min(1, value));\r\n }\r\n\r\n /**\r\n * Solve the IK chain to reach the target position using Two Bone IK algorithm.\r\n *\r\n * @param target - Target position for the end effector\r\n * @returns True if the target is reachable, false if stretched to maximum\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 const root = joints[0];\r\n const middle = joints[1];\r\n const end = joints[2];\r\n\r\n const rootPos = root.position;\r\n const upperLength = root.boneLength; // Length from root to middle\r\n const lowerLength = middle.boneLength; // Length from middle to end\r\n const totalLength = upperLength + lowerLength;\r\n\r\n // Calculate direction and distance from root to target\r\n const rootToTarget = Vector3.sub(target, rootPos, new Vector3());\r\n const targetDistance = rootToTarget.magnitude;\r\n\r\n // Check if target is reachable\r\n if (targetDistance < 0.000001) {\r\n // Target is at root position, keep original pose\r\n return true;\r\n }\r\n\r\n let reachable = true;\r\n\r\n // If target is unreachable, clamp to maximum distance\r\n let effectiveTarget = target;\r\n if (targetDistance >= totalLength - 0.0001) {\r\n // Stretch to maximum length\r\n const direction = Vector3.scale(rootToTarget, 1 / targetDistance, new Vector3());\r\n effectiveTarget = Vector3.add(\r\n rootPos,\r\n Vector3.scale(direction, totalLength - 0.0001, new Vector3()),\r\n new Vector3()\r\n );\r\n reachable = false;\r\n }\r\n\r\n // Calculate the distance from root to effective target\r\n const rootToEffectiveTarget = Vector3.sub(effectiveTarget, rootPos, new Vector3());\r\n const distance = rootToEffectiveTarget.magnitude;\r\n\r\n // Use law of cosines to find the angle at the root joint\r\n // cos(rootAngle) = (a² + c² - b²) / (2ac)\r\n const cosRootAngle =\r\n (upperLength * upperLength + distance * distance - lowerLength * lowerLength) /\r\n (2 * upperLength * distance);\r\n const clampedCosRootAngle = Math.max(-1, Math.min(1, cosRootAngle));\r\n const rootAngle = Math.acos(clampedCosRootAngle);\r\n\r\n // Determine the plane of bending\r\n let bendNormal: Vector3;\r\n\r\n if (this._poleVector && this._poleWeight > 0.001) {\r\n // Use pole vector to determine bend direction\r\n const rootToTargetDir = Vector3.normalize(rootToEffectiveTarget, new Vector3());\r\n const rootToPole = Vector3.sub(this._poleVector, rootPos, new Vector3());\r\n\r\n // Project pole vector onto plane perpendicular to root-target direction\r\n const projectionLength = Vector3.dot(rootToPole, rootToTargetDir);\r\n const projection = Vector3.scale(rootToTargetDir, projectionLength, new Vector3());\r\n const perpendicular = Vector3.sub(rootToPole, projection, new Vector3());\r\n\r\n const perpLength = perpendicular.magnitude;\r\n if (perpLength > 0.000001) {\r\n // Bend normal is perpendicular to both root-target and pole direction\r\n bendNormal = Vector3.cross(rootToTargetDir, perpendicular, new Vector3()).inplaceNormalize();\r\n } else {\r\n // Pole is on the line, use default bend direction\r\n bendNormal = this._getDefaultBendNormal(rootToEffectiveTarget);\r\n }\r\n\r\n // Apply pole weight\r\n if (this._poleWeight < 0.999) {\r\n const defaultNormal = this._getDefaultBendNormal(rootToEffectiveTarget);\r\n // Slerp between default and pole-based normal\r\n const angle = Math.acos(Math.max(-1, Math.min(1, Vector3.dot(defaultNormal, bendNormal))));\r\n if (angle > 0.001) {\r\n const axis = Vector3.cross(defaultNormal, bendNormal, new Vector3()).inplaceNormalize();\r\n const rotation = new Quaternion().fromAxisAngle(axis, angle * this._poleWeight);\r\n bendNormal = rotation.transform(defaultNormal, new Vector3());\r\n }\r\n }\r\n } else {\r\n // No pole vector, use default bend direction\r\n bendNormal = this._getDefaultBendNormal(rootToEffectiveTarget);\r\n }\r\n\r\n // Calculate middle joint position\r\n const rootToTargetDir = Vector3.normalize(rootToEffectiveTarget, new Vector3());\r\n\r\n // Rotate root-to-target direction by rootAngle around bendNormal\r\n const rotationToMiddle = new Quaternion().fromAxisAngle(bendNormal, rootAngle);\r\n const rootToMiddleDir = rotationToMiddle.transform(rootToTargetDir, new Vector3());\r\n\r\n // Place middle joint\r\n middle.position.set(\r\n Vector3.add(rootPos, Vector3.scale(rootToMiddleDir, upperLength, new Vector3()), new Vector3())\r\n );\r\n\r\n // Place end joint at target\r\n end.position.set(effectiveTarget);\r\n\r\n // Apply constraints after solving\r\n // Note: Constraints may modify joint positions, which could affect bone lengths\r\n // For Two Bone IK, we apply constraints and then restore bone lengths\r\n this._applyConstraints();\r\n\r\n return reachable;\r\n }\r\n\r\n /**\r\n * Apply all constraints to the joint chain.\r\n * After applying constraints, we need to restore bone lengths.\r\n */\r\n private _applyConstraints(): void {\r\n const constraints = this._chain.constraints;\r\n if (constraints.length === 0) {\r\n return;\r\n }\r\n\r\n const joints = this._chain.joints;\r\n\r\n // Apply each constraint\r\n for (const constraint of constraints) {\r\n constraint.apply(joints);\r\n }\r\n\r\n // After constraints are applied, we need to restore bone lengths\r\n // because constraints may have moved joints in ways that change bone lengths\r\n // For Two Bone IK, we fix this by adjusting positions while maintaining the constraint\r\n this._restoreBoneLengths();\r\n }\r\n\r\n /**\r\n * Restore bone lengths after constraints have been applied.\r\n * This ensures that the chain maintains correct bone lengths.\r\n */\r\n private _restoreBoneLengths(): void {\r\n const joints = this._chain.joints;\r\n const root = joints[0];\r\n const middle = joints[1];\r\n const end = joints[2];\r\n\r\n const upperLength = root.boneLength;\r\n const lowerLength = middle.boneLength;\r\n\r\n // Fix middle joint position to maintain upper bone length\r\n const rootToMiddle = Vector3.sub(middle.position, root.position, new Vector3());\r\n const rootToMiddleDist = rootToMiddle.magnitude;\r\n\r\n if (rootToMiddleDist > 0.000001 && Math.abs(rootToMiddleDist - upperLength) > 0.0001) {\r\n const rootToMiddleDir = Vector3.scale(rootToMiddle, 1 / rootToMiddleDist, new Vector3());\r\n middle.position.set(\r\n Vector3.add(root.position, Vector3.scale(rootToMiddleDir, upperLength, new Vector3()), new Vector3())\r\n );\r\n }\r\n\r\n // Fix end joint position to maintain lower bone length\r\n const middleToEnd = Vector3.sub(end.position, middle.position, new Vector3());\r\n const middleToEndDist = middleToEnd.magnitude;\r\n\r\n if (middleToEndDist > 0.000001 && Math.abs(middleToEndDist - lowerLength) > 0.0001) {\r\n const middleToEndDir = Vector3.scale(middleToEnd, 1 / middleToEndDist, new Vector3());\r\n end.position.set(\r\n Vector3.add(middle.position, Vector3.scale(middleToEndDir, lowerLength, new Vector3()), new Vector3())\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 root and middle joints (end joint doesn't need rotation)\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 // Decompose rotation around bone axis\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 /**\r\n * Get a default bend normal when no pole vector is specified.\r\n * This tries to find a reasonable perpendicular direction.\r\n *\r\n * @param rootToTarget - Direction from root to target\r\n * @returns A normalized perpendicular vector\r\n */\r\n private _getDefaultBendNormal(rootToTarget: Vector3): Vector3 {\r\n const rootToTargetDir = Vector3.normalize(rootToTarget, new Vector3());\r\n\r\n // Try to use world up (Y axis) as reference\r\n let bendNormal = Vector3.cross(rootToTargetDir, Vector3.axisPY(), new Vector3());\r\n const lenSq = bendNormal.x * bendNormal.x + bendNormal.y * bendNormal.y + bendNormal.z * bendNormal.z;\r\n\r\n // If root-to-target is parallel to Y axis, use X axis instead\r\n if (lenSq < 0.000001) {\r\n bendNormal = Vector3.cross(rootToTargetDir, Vector3.axisPX(), new Vector3());\r\n }\r\n\r\n return bendNormal.inplaceNormalize();\r\n }\r\n}\r\n"],"names":["TwoBoneIKSolver","IKSolver","chain","poleVector","poleWeight","joints","length","Error","_poleVector","clone","_poleWeight","Math","max","min","_twistConstraints","Map","set","minTwist","PI","maxTwist","smoothFactor","setTwistConstraint","jointIndex","_chain","getTwistConstraint","get","removeTwistConstraint","delete","clearTwistConstraints","clear","value","solve","target","updateFromNodes","storeOriginalPositions","root","middle","end","rootPos","position","upperLength","boneLength","lowerLength","totalLength","rootToTarget","Vector3","sub","targetDistance","magnitude","reachable","effectiveTarget","direction","scale","add","rootToEffectiveTarget","distance","cosRootAngle","clampedCosRootAngle","rootAngle","acos","bendNormal","rootToTargetDir","normalize","rootToPole","projectionLength","dot","projection","perpendicular","perpLength","cross","inplaceNormalize","_getDefaultBendNormal","defaultNormal","angle","axis","rotation","Quaternion","fromAxisAngle","transform","rotationToMiddle","rootToMiddleDir","_applyConstraints","constraints","constraint","apply","_restoreBoneLengths","rootToMiddle","rootToMiddleDist","abs","middleToEnd","middleToEndDist","middleToEndDir","applyToNodes","weight","i","joint","nextJoint","originalDir","originalPosition","newDir","originalDirNorm","newDirNorm","deltaRotation","IKUtils","fromToRotation","worldRotation","multiply","originalRotation","swing","twist","decomposeSwingTwist","twistAngle","getTwistAngle","clampAndSmoothTwist","previousTwist","clampedTwist","slerp","previousIKRotation","node","parent","parentWorldRotation","worldMatrix","decompose","parentInvRotation","conjugate","localRotation","axisPY","lenSq","x","y","z","axisPX"],"mappings":"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"}
1
+ {"version":3,"file":"two_bone_ik_solver.js","sources":["../../../src/animation/ik/two_bone_ik_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 * Two Bone IK solver for chains with exactly 3 joints (2 bones).\r\n *\r\n * @remarks\r\n * This solver uses an analytical solution specifically optimized for\r\n * two-bone chains like arms (shoulder-elbow-wrist) or legs (hip-knee-ankle).\r\n * It's faster and more stable than iterative methods like FABRIK for this case.\r\n *\r\n * The solver supports an optional pole vector to control the bending direction\r\n * of the middle joint (elbow/knee).\r\n *\r\n * @public\r\n */\r\nexport class TwoBoneIKSolver extends IKSolver {\r\n /** Optional pole vector position in world space */\r\n private _poleVector: Vector3 | null;\r\n /** Weight of the pole vector constraint (0-1) */\r\n private _poleWeight: number;\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 Two Bone IK solver.\r\n *\r\n * @param chain - The IK chain to solve (must have exactly 3 joints)\r\n * @param poleVector - Optional pole vector position in world space\r\n * @param poleWeight - Weight of the pole vector constraint (0-1, default: 1)\r\n */\r\n constructor(chain: IKChain, poleVector: Vector3 | null = null, poleWeight = 1) {\r\n super(chain, 1, 0.001); // Two bone IK doesn't need iterations\r\n\r\n if (chain.joints.length !== 3) {\r\n throw new Error('Two Bone IK requires exactly 3 joints (2 bones)');\r\n }\r\n\r\n this._poleVector = poleVector ? poleVector.clone() : null;\r\n this._poleWeight = Math.max(0, Math.min(1, poleWeight));\r\n this._twistConstraints = new Map();\r\n\r\n // Set default twist constraints\r\n // Root joint (shoulder/hip) - moderate twist\r\n this._twistConstraints.set(0, {\r\n minTwist: -Math.PI * 0.25, // -45 degrees\r\n maxTwist: Math.PI * 0.25, // +45 degrees\r\n smoothFactor: 0.3\r\n });\r\n\r\n // Middle joint (elbow/knee) - very limited twist\r\n this._twistConstraints.set(1, {\r\n minTwist: -Math.PI * 0.15, // -27 degrees\r\n maxTwist: Math.PI * 0.15, // +27 degrees\r\n smoothFactor: 0.3\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 (0 = root, 1 = middle)\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 * Get the pole vector position.\r\n */\r\n get poleVector(): Vector3 | null {\r\n return this._poleVector;\r\n }\r\n\r\n set poleVector(value: Vector3 | null) {\r\n if (value) {\r\n if (!this._poleVector) {\r\n this._poleVector = value.clone();\r\n } else {\r\n this._poleVector.set(value);\r\n }\r\n } else {\r\n this._poleVector = null;\r\n }\r\n }\r\n\r\n /**\r\n * Get the pole vector weight.\r\n */\r\n get poleWeight(): number {\r\n return this._poleWeight;\r\n }\r\n\r\n set poleWeight(value: number) {\r\n this._poleWeight = Math.max(0, Math.min(1, value));\r\n }\r\n\r\n /**\r\n * Solve the IK chain to reach the target position using Two Bone IK algorithm.\r\n *\r\n * @param target - Target position for the end effector\r\n * @returns True if the target is reachable, false if stretched to maximum\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 const root = joints[0];\r\n const middle = joints[1];\r\n const end = joints[2];\r\n\r\n const rootPos = root.position;\r\n const upperLength = root.boneLength; // Length from root to middle\r\n const lowerLength = middle.boneLength; // Length from middle to end\r\n const totalLength = upperLength + lowerLength;\r\n\r\n // Calculate direction and distance from root to target\r\n const rootToTarget = Vector3.sub(target, rootPos, new Vector3());\r\n const targetDistance = rootToTarget.magnitude;\r\n\r\n // Check if target is reachable\r\n if (targetDistance < 0.000001) {\r\n // Target is at root position, keep original pose\r\n return true;\r\n }\r\n\r\n let reachable = true;\r\n\r\n // If target is unreachable, clamp to maximum distance\r\n let effectiveTarget = target;\r\n if (targetDistance >= totalLength - 0.0001) {\r\n // Stretch to maximum length\r\n const direction = Vector3.scale(rootToTarget, 1 / targetDistance, new Vector3());\r\n effectiveTarget = Vector3.add(\r\n rootPos,\r\n Vector3.scale(direction, totalLength - 0.0001, new Vector3()),\r\n new Vector3()\r\n );\r\n reachable = false;\r\n }\r\n\r\n // Calculate the distance from root to effective target\r\n const rootToEffectiveTarget = Vector3.sub(effectiveTarget, rootPos, new Vector3());\r\n const distance = rootToEffectiveTarget.magnitude;\r\n\r\n // Use law of cosines to find the angle at the root joint\r\n // cos(rootAngle) = (a² + c² - b²) / (2ac)\r\n const cosRootAngle =\r\n (upperLength * upperLength + distance * distance - lowerLength * lowerLength) /\r\n (2 * upperLength * distance);\r\n const clampedCosRootAngle = Math.max(-1, Math.min(1, cosRootAngle));\r\n const rootAngle = Math.acos(clampedCosRootAngle);\r\n\r\n // Determine the plane of bending\r\n let bendNormal: Vector3;\r\n\r\n if (this._poleVector && this._poleWeight > 0.001) {\r\n // Use pole vector to determine bend direction\r\n const rootToTargetDir = Vector3.normalize(rootToEffectiveTarget, new Vector3());\r\n const rootToPole = Vector3.sub(this._poleVector, rootPos, new Vector3());\r\n\r\n // Project pole vector onto plane perpendicular to root-target direction\r\n const projectionLength = Vector3.dot(rootToPole, rootToTargetDir);\r\n const projection = Vector3.scale(rootToTargetDir, projectionLength, new Vector3());\r\n const perpendicular = Vector3.sub(rootToPole, projection, new Vector3());\r\n\r\n const perpLength = perpendicular.magnitude;\r\n if (perpLength > 0.000001) {\r\n // Bend normal is perpendicular to both root-target and pole direction\r\n bendNormal = Vector3.cross(rootToTargetDir, perpendicular, new Vector3()).inplaceNormalize();\r\n } else {\r\n // Pole is on the line, use default bend direction\r\n bendNormal = this._getDefaultBendNormal(rootToEffectiveTarget);\r\n }\r\n\r\n // Apply pole weight\r\n if (this._poleWeight < 0.999) {\r\n const defaultNormal = this._getDefaultBendNormal(rootToEffectiveTarget);\r\n // Slerp between default and pole-based normal\r\n const angle = Math.acos(Math.max(-1, Math.min(1, Vector3.dot(defaultNormal, bendNormal))));\r\n if (angle > 0.001) {\r\n const axis = Vector3.cross(defaultNormal, bendNormal, new Vector3()).inplaceNormalize();\r\n const rotation = new Quaternion().fromAxisAngle(axis, angle * this._poleWeight);\r\n bendNormal = rotation.transform(defaultNormal, new Vector3());\r\n }\r\n }\r\n } else {\r\n // No pole vector, use default bend direction\r\n bendNormal = this._getDefaultBendNormal(rootToEffectiveTarget);\r\n }\r\n\r\n // Calculate middle joint position\r\n const rootToTargetDir = Vector3.normalize(rootToEffectiveTarget, new Vector3());\r\n\r\n // Rotate root-to-target direction by rootAngle around bendNormal\r\n const rotationToMiddle = new Quaternion().fromAxisAngle(bendNormal, rootAngle);\r\n const rootToMiddleDir = rotationToMiddle.transform(rootToTargetDir, new Vector3());\r\n\r\n // Place middle joint\r\n middle.position.set(\r\n Vector3.add(rootPos, Vector3.scale(rootToMiddleDir, upperLength, new Vector3()), new Vector3())\r\n );\r\n\r\n // Place end joint at target\r\n end.position.set(effectiveTarget);\r\n\r\n // Apply constraints after solving\r\n // Note: Constraints may modify joint positions, which could affect bone lengths\r\n // For Two Bone IK, we apply constraints and then restore bone lengths\r\n this._applyConstraints();\r\n\r\n return reachable;\r\n }\r\n\r\n /**\r\n * Apply all constraints to the joint chain.\r\n * After applying constraints, we need to restore bone lengths.\r\n */\r\n private _applyConstraints(): void {\r\n const constraints = this._chain.constraints;\r\n if (constraints.length === 0) {\r\n return;\r\n }\r\n\r\n const joints = this._chain.joints;\r\n\r\n // Apply each constraint\r\n for (const constraint of constraints) {\r\n constraint.apply(joints);\r\n }\r\n\r\n // After constraints are applied, we need to restore bone lengths\r\n // because constraints may have moved joints in ways that change bone lengths\r\n // For Two Bone IK, we fix this by adjusting positions while maintaining the constraint\r\n this._restoreBoneLengths();\r\n }\r\n\r\n /**\r\n * Restore bone lengths after constraints have been applied.\r\n * This ensures that the chain maintains correct bone lengths.\r\n */\r\n private _restoreBoneLengths(): void {\r\n const joints = this._chain.joints;\r\n const root = joints[0];\r\n const middle = joints[1];\r\n const end = joints[2];\r\n\r\n const upperLength = root.boneLength;\r\n const lowerLength = middle.boneLength;\r\n\r\n // Fix middle joint position to maintain upper bone length\r\n const rootToMiddle = Vector3.sub(middle.position, root.position, new Vector3());\r\n const rootToMiddleDist = rootToMiddle.magnitude;\r\n\r\n if (rootToMiddleDist > 0.000001 && Math.abs(rootToMiddleDist - upperLength) > 0.0001) {\r\n const rootToMiddleDir = Vector3.scale(rootToMiddle, 1 / rootToMiddleDist, new Vector3());\r\n middle.position.set(\r\n Vector3.add(root.position, Vector3.scale(rootToMiddleDir, upperLength, new Vector3()), new Vector3())\r\n );\r\n }\r\n\r\n // Fix end joint position to maintain lower bone length\r\n const middleToEnd = Vector3.sub(end.position, middle.position, new Vector3());\r\n const middleToEndDist = middleToEnd.magnitude;\r\n\r\n if (middleToEndDist > 0.000001 && Math.abs(middleToEndDist - lowerLength) > 0.0001) {\r\n const middleToEndDir = Vector3.scale(middleToEnd, 1 / middleToEndDist, new Vector3());\r\n end.position.set(\r\n Vector3.add(middle.position, Vector3.scale(middleToEndDir, lowerLength, new Vector3()), new Vector3())\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 root and middle joints (end joint doesn't need rotation)\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 // Decompose rotation around bone axis\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 /**\r\n * Get a default bend normal when no pole vector is specified.\r\n * This tries to find a reasonable perpendicular direction.\r\n *\r\n * @param rootToTarget - Direction from root to target\r\n * @returns A normalized perpendicular vector\r\n */\r\n private _getDefaultBendNormal(rootToTarget: Vector3): Vector3 {\r\n const rootToTargetDir = Vector3.normalize(rootToTarget, new Vector3());\r\n\r\n // Try to use world up (Y axis) as reference\r\n let bendNormal = Vector3.cross(rootToTargetDir, Vector3.axisPY(), new Vector3());\r\n const lenSq = bendNormal.x * bendNormal.x + bendNormal.y * bendNormal.y + bendNormal.z * bendNormal.z;\r\n\r\n // If root-to-target is parallel to Y axis, use X axis instead\r\n if (lenSq < 0.000001) {\r\n bendNormal = Vector3.cross(rootToTargetDir, Vector3.axisPX(), new Vector3());\r\n }\r\n\r\n return bendNormal.inplaceNormalize();\r\n }\r\n}\r\n"],"names":["TwoBoneIKSolver","IKSolver","chain","poleVector","poleWeight","joints","length","Error","_poleVector","clone","_poleWeight","Math","max","min","_twistConstraints","Map","set","minTwist","PI","maxTwist","smoothFactor","setTwistConstraint","jointIndex","_chain","getTwistConstraint","get","removeTwistConstraint","delete","clearTwistConstraints","clear","value","solve","target","updateFromNodes","storeOriginalPositions","root","middle","end","rootPos","position","upperLength","boneLength","lowerLength","totalLength","rootToTarget","Vector3","sub","targetDistance","magnitude","reachable","effectiveTarget","direction","scale","add","rootToEffectiveTarget","distance","cosRootAngle","clampedCosRootAngle","rootAngle","acos","bendNormal","rootToTargetDir","normalize","rootToPole","projectionLength","dot","projection","perpendicular","perpLength","cross","inplaceNormalize","_getDefaultBendNormal","defaultNormal","angle","axis","rotation","Quaternion","fromAxisAngle","transform","rotationToMiddle","rootToMiddleDir","_applyConstraints","constraints","constraint","apply","_restoreBoneLengths","rootToMiddle","rootToMiddleDist","abs","middleToEnd","middleToEndDist","middleToEndDir","applyToNodes","weight","i","joint","nextJoint","originalDir","originalPosition","newDir","originalDirNorm","newDirNorm","deltaRotation","IKUtils","fromToRotation","worldRotation","multiply","originalRotation","swing","twist","decomposeSwingTwist","twistAngle","getTwistAngle","clampAndSmoothTwist","previousTwist","clampedTwist","slerp","previousIKRotation","node","parent","parentWorldRotation","worldMatrix","decompose","parentInvRotation","conjugate","localRotation","axisPY","lenSq","x","y","z","axisPX"],"mappings":"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"}