@zephyr3d/scene 0.7.1 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/dist/animation/animation.js +0 -18
  2. package/dist/animation/animation.js.map +1 -1
  3. package/dist/animation/animationset.js +2 -2
  4. package/dist/animation/animationset.js.map +1 -1
  5. package/dist/animation/ik/ccd_solver.js +372 -0
  6. package/dist/animation/ik/ccd_solver.js.map +1 -0
  7. package/dist/animation/ik/fabrik_solver.js +399 -0
  8. package/dist/animation/ik/fabrik_solver.js.map +1 -0
  9. package/dist/animation/ik/ik_angle_constraint.js +181 -0
  10. package/dist/animation/ik/ik_angle_constraint.js.map +1 -0
  11. package/dist/animation/ik/ik_chain.js +163 -0
  12. package/dist/animation/ik/ik_chain.js.map +1 -0
  13. package/dist/animation/ik/ik_chain_builder.js +68 -0
  14. package/dist/animation/ik/ik_chain_builder.js.map +1 -0
  15. package/dist/animation/ik/ik_constraint.js +25 -0
  16. package/dist/animation/ik/ik_constraint.js.map +1 -0
  17. package/dist/animation/ik/ik_pole_constraint.js +123 -0
  18. package/dist/animation/ik/ik_pole_constraint.js.map +1 -0
  19. package/dist/animation/ik/ik_solver.js +48 -0
  20. package/dist/animation/ik/ik_solver.js.map +1 -0
  21. package/dist/animation/ik/ik_track.js +96 -0
  22. package/dist/animation/ik/ik_track.js.map +1 -0
  23. package/dist/animation/ik/ik_utils.js +270 -0
  24. package/dist/animation/ik/ik_utils.js.map +1 -0
  25. package/dist/animation/ik/two_bone_ik_solver.js +332 -0
  26. package/dist/animation/ik/two_bone_ik_solver.js.map +1 -0
  27. package/dist/animation/ik_modifier.js +61 -0
  28. package/dist/animation/ik_modifier.js.map +1 -0
  29. package/dist/animation/ik_postprocessor.js +71 -0
  30. package/dist/animation/ik_postprocessor.js.map +1 -0
  31. package/dist/animation/manual_transform_processor.js +156 -0
  32. package/dist/animation/manual_transform_processor.js.map +1 -0
  33. package/dist/animation/skeleton.js +55 -51
  34. package/dist/animation/skeleton.js.map +1 -1
  35. package/dist/animation/skeleton_modifier.js +38 -0
  36. package/dist/animation/skeleton_modifier.js.map +1 -0
  37. package/dist/animation/skeleton_postprocessor.js +50 -0
  38. package/dist/animation/skeleton_postprocessor.js.map +1 -0
  39. package/dist/animation/spring/multi_chain_spring_system.js +503 -0
  40. package/dist/animation/spring/multi_chain_spring_system.js.map +1 -0
  41. package/dist/animation/spring/spring_chain.js +103 -0
  42. package/dist/animation/spring/spring_chain.js.map +1 -0
  43. package/dist/animation/spring/spring_collider.js +247 -0
  44. package/dist/animation/spring/spring_collider.js.map +1 -0
  45. package/dist/animation/spring/spring_constraint.js +21 -0
  46. package/dist/animation/spring/spring_constraint.js.map +1 -0
  47. package/dist/animation/spring/spring_particle.js +20 -0
  48. package/dist/animation/spring/spring_particle.js.map +1 -0
  49. package/dist/animation/spring/spring_system.js +526 -0
  50. package/dist/animation/spring/spring_system.js.map +1 -0
  51. package/dist/animation/spring_modifier.js +45 -0
  52. package/dist/animation/spring_modifier.js.map +1 -0
  53. package/dist/animation/spring_postprocessor.js +54 -0
  54. package/dist/animation/spring_postprocessor.js.map +1 -0
  55. package/dist/app/screen.js +1 -1
  56. package/dist/app/screen.js.map +1 -1
  57. package/dist/asset/model.js +8 -4
  58. package/dist/asset/model.js.map +1 -1
  59. package/dist/camera/perspectivecamera.js +3 -3
  60. package/dist/camera/perspectivecamera.js.map +1 -1
  61. package/dist/index.d.ts +1385 -4
  62. package/dist/index.js +16 -0
  63. package/dist/index.js.map +1 -1
  64. package/dist/material/mixins/lightmodel/blinnphong.js +66 -4
  65. package/dist/material/mixins/lightmodel/blinnphong.js.map +1 -1
  66. package/dist/material/shader/helper.js +5 -3
  67. package/dist/material/shader/helper.js.map +1 -1
  68. package/dist/scene/mesh.js +15 -23
  69. package/dist/scene/mesh.js.map +1 -1
  70. package/dist/utility/serialization/scene/animation.js +21 -20
  71. package/dist/utility/serialization/scene/animation.js.map +1 -1
  72. package/dist/utility/serialization/scene/material.js +62 -0
  73. package/dist/utility/serialization/scene/material.js.map +1 -1
  74. package/package.json +2 -2
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ccd_solver.js","sources":["../../../src/animation/ik/ccd_solver.ts"],"sourcesContent":["import { Vector3, Quaternion } from '@zephyr3d/base';\r\nimport { IKSolver } from './ik_solver';\r\nimport type { IKChain } from './ik_chain';\r\nimport { IKUtils } from './ik_utils';\r\nimport type { TwistConstraint } from './ik_constraint';\r\n\r\n/**\r\n * Pole vector configuration for a specific joint.\r\n */\r\ninterface PoleVectorConfig {\r\n /** Pole vector position in world space */\r\n position: Vector3;\r\n /** Weight of the pole vector constraint (0-1) */\r\n weight: number;\r\n}\r\n\r\n/**\r\n * CCD (Cyclic Coordinate Descent) IK solver.\r\n *\r\n * @remarks\r\n * CCD is an iterative IK algorithm that works by:\r\n * 1. Starting from the joint closest to the end effector\r\n * 2. Rotating each joint to point the end effector toward the target\r\n * 3. Moving backward through the chain to the root\r\n * 4. Repeating until convergence or max iterations\r\n *\r\n * CCD is generally faster than FABRIK and works well for chains of any length.\r\n * It's particularly good for tentacles, tails, and other flexible chains.\r\n *\r\n * Supports multiple pole vectors to control the bending direction of different joints.\r\n *\r\n * @public\r\n */\r\nexport class CCDSolver extends IKSolver {\r\n /** Map of joint index to pole vector configuration */\r\n private _poleVectors: Map<number, PoleVectorConfig>;\r\n /** Twist constraints for each joint (indexed by joint index) */\r\n private _twistConstraints: Map<number, TwistConstraint>;\r\n\r\n /**\r\n * Create a CCD solver.\r\n *\r\n * @param chain - The IK chain to solve\r\n * @param maxIterations - Maximum number of iterations (default: 10)\r\n * @param tolerance - Convergence tolerance in world units (default: 0.001)\r\n */\r\n constructor(chain: IKChain, maxIterations = 10, tolerance = 0.001) {\r\n super(chain, maxIterations, tolerance);\r\n this._poleVectors = new Map();\r\n this._twistConstraints = new Map();\r\n\r\n // Set default twist constraints for all joints\r\n for (let i = 0; i < chain.joints.length - 1; i++) {\r\n // Middle joints have more restrictive twist limits\r\n const isMiddleJoint = i > 0 && i < chain.joints.length - 2;\r\n this._twistConstraints.set(i, {\r\n minTwist: isMiddleJoint ? -Math.PI * 0.2 : -Math.PI * 0.3,\r\n maxTwist: isMiddleJoint ? Math.PI * 0.2 : Math.PI * 0.3,\r\n smoothFactor: 0.3\r\n });\r\n }\r\n }\r\n\r\n /**\r\n * Set twist constraint for a specific joint.\r\n *\r\n * @param jointIndex - Index of the joint\r\n * @param minTwist - Minimum twist angle in radians\r\n * @param maxTwist - Maximum twist angle in radians\r\n * @param smoothFactor - Smoothing factor [0-1] (default: 0.3)\r\n */\r\n setTwistConstraint(\r\n jointIndex: number,\r\n minTwist: number,\r\n maxTwist: number,\r\n smoothFactor: number = 0.3\r\n ): void {\r\n if (jointIndex < 0 || jointIndex >= this._chain.joints.length - 1) {\r\n throw new Error(`Invalid joint index: ${jointIndex}`);\r\n }\r\n\r\n this._twistConstraints.set(jointIndex, {\r\n minTwist,\r\n maxTwist,\r\n smoothFactor: Math.max(0, Math.min(1, smoothFactor))\r\n });\r\n }\r\n\r\n /**\r\n * Get twist constraint for a specific joint.\r\n *\r\n * @param jointIndex - Index of the joint\r\n * @returns Twist constraint or undefined if not set\r\n */\r\n getTwistConstraint(jointIndex: number): TwistConstraint | undefined {\r\n return this._twistConstraints.get(jointIndex);\r\n }\r\n\r\n /**\r\n * Remove twist constraint for a specific joint.\r\n *\r\n * @param jointIndex - Index of the joint\r\n * @returns True if a constraint was removed\r\n */\r\n removeTwistConstraint(jointIndex: number): boolean {\r\n return this._twistConstraints.delete(jointIndex);\r\n }\r\n\r\n /**\r\n * Clear all twist constraints.\r\n */\r\n clearTwistConstraints(): void {\r\n this._twistConstraints.clear();\r\n }\r\n\r\n /**\r\n * Set pole vector for a specific joint.\r\n *\r\n * @param jointIndex - Index of the joint to apply pole vector to\r\n * @param poleVector - Pole vector position in world space\r\n * @param weight - Weight of the pole vector constraint (0-1, default: 1)\r\n */\r\n setPoleVector(jointIndex: number, poleVector: Vector3, weight = 1): void {\r\n if (jointIndex < 0 || jointIndex >= this._chain.joints.length) {\r\n throw new Error(`Invalid joint index: ${jointIndex}`);\r\n }\r\n\r\n this._poleVectors.set(jointIndex, {\r\n position: poleVector.clone(),\r\n weight: Math.max(0, Math.min(1, weight))\r\n });\r\n }\r\n\r\n /**\r\n * Remove pole vector for a specific joint.\r\n *\r\n * @param jointIndex - Index of the joint to remove pole vector from\r\n * @returns True if a pole vector was removed, false if none existed\r\n */\r\n removePoleVector(jointIndex: number): boolean {\r\n return this._poleVectors.delete(jointIndex);\r\n }\r\n\r\n /**\r\n * Clear all pole vectors.\r\n */\r\n clearPoleVectors(): void {\r\n this._poleVectors.clear();\r\n }\r\n\r\n /**\r\n * Get pole vector configuration for a specific joint.\r\n *\r\n * @param jointIndex - Index of the joint\r\n * @returns Pole vector configuration or undefined if not set\r\n */\r\n getPoleVector(jointIndex: number): { position: Vector3; weight: number } | undefined {\r\n const config = this._poleVectors.get(jointIndex);\r\n if (config) {\r\n return {\r\n position: config.position.clone(),\r\n weight: config.weight\r\n };\r\n }\r\n return undefined;\r\n }\r\n\r\n /**\r\n * Check if a joint has a pole vector.\r\n *\r\n * @param jointIndex - Index of the joint\r\n * @returns True if the joint has a pole vector\r\n */\r\n hasPoleVector(jointIndex: number): boolean {\r\n return this._poleVectors.has(jointIndex);\r\n }\r\n\r\n /**\r\n * Solve the IK chain to reach the target position using CCD algorithm.\r\n *\r\n * @param target - Target position for the end effector\r\n * @returns True if converged within tolerance, false otherwise\r\n */\r\n solve(target: Vector3): boolean {\r\n const joints = this._chain.joints;\r\n\r\n // Update joint positions from scene nodes before solving\r\n this._chain.updateFromNodes();\r\n\r\n // Store original positions\r\n this._chain.storeOriginalPositions();\r\n\r\n let converged = false;\r\n\r\n for (let iteration = 0; iteration < this._maxIterations; iteration++) {\r\n // Check convergence\r\n const endEffector = joints[joints.length - 1];\r\n const distToTarget = Vector3.distance(endEffector.position, target);\r\n\r\n if (distToTarget < this._tolerance) {\r\n converged = true;\r\n break;\r\n }\r\n\r\n // Iterate backward through joints (from second-to-last to root)\r\n // We skip the end effector itself since it doesn't have a child to rotate toward\r\n for (let i = joints.length - 2; i >= 0; i--) {\r\n const joint = joints[i];\r\n\r\n // Vector from current joint to end effector\r\n const toEnd = Vector3.sub(endEffector.position, joint.position, new Vector3());\r\n const toEndDist = toEnd.magnitude;\r\n\r\n // Vector from current joint to target\r\n const toTarget = Vector3.sub(target, joint.position, new Vector3());\r\n const toTargetDist = toTarget.magnitude;\r\n\r\n // Skip if either vector is too small\r\n if (toEndDist < 0.000001 || toTargetDist < 0.000001) {\r\n continue;\r\n }\r\n\r\n // Normalize vectors\r\n const toEndDir = Vector3.scale(toEnd, 1 / toEndDist, new Vector3());\r\n const toTargetDir = Vector3.scale(toTarget, 1 / toTargetDist, new Vector3());\r\n\r\n // Calculate rotation needed to align end effector toward target\r\n let rotation = new Quaternion();\r\n IKUtils.fromToRotation(toEndDir, toTargetDir, rotation);\r\n\r\n // Apply rotation to all joints from current to end effector\r\n this._rotateJointsFromIndex(i, rotation, joint.position);\r\n\r\n // Apply constraints after rotating this joint\r\n this._applyConstraintsForJoint(i);\r\n }\r\n\r\n // Apply all pole vector constraints after each full iteration\r\n // This is more stable than applying them during the CCD loop\r\n this._applyAllPoleVectors();\r\n }\r\n\r\n return converged;\r\n }\r\n\r\n /**\r\n * Rotate all joints from the given index to the end effector around a pivot point.\r\n *\r\n * @param startIndex - Index of the joint to start rotating from\r\n * @param rotation - Rotation to apply\r\n * @param pivot - Pivot point for rotation (position of the joint being adjusted)\r\n */\r\n private _rotateJointsFromIndex(startIndex: number, rotation: Quaternion, pivot: Vector3): void {\r\n const joints = this._chain.joints;\r\n\r\n // Rotate all joints from startIndex+1 to end effector\r\n for (let i = startIndex + 1; i < joints.length; i++) {\r\n const joint = joints[i];\r\n\r\n // Translate to pivot\r\n const offset = Vector3.sub(joint.position, pivot, new Vector3());\r\n\r\n // Rotate around pivot\r\n const rotated = rotation.transform(offset, new Vector3());\r\n\r\n // Translate back\r\n joint.position.set(Vector3.add(pivot, rotated, new Vector3()));\r\n }\r\n }\r\n\r\n /**\r\n * Apply all pole vector constraints.\r\n *\r\n * @remarks\r\n * This method applies all configured pole vectors to their respective joints.\r\n * Pole vectors are applied in reverse order (from end to root) to minimize\r\n * interference between multiple pole vectors. This ensures that pole vectors\r\n * closer to the end effector are not affected by pole vectors closer to the root.\r\n */\r\n private _applyAllPoleVectors(): void {\r\n if (this._poleVectors.size === 0) {\r\n return;\r\n }\r\n\r\n // Apply pole vectors in reverse order (from end to root)\r\n // This prevents earlier pole vectors from affecting later ones\r\n const sortedIndices = Array.from(this._poleVectors.keys()).sort((a, b) => b - a);\r\n\r\n for (const jointIndex of sortedIndices) {\r\n const config = this._poleVectors.get(jointIndex);\r\n if (config && config.weight > 0.001) {\r\n this._applyPoleVectorTwist(jointIndex, config.position, config.weight);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Apply pole vector twist to a specific joint.\r\n *\r\n * @remarks\r\n * This method is called after the base CCD rotation has been applied.\r\n * It adds an additional twist rotation around the joint-to-end axis\r\n * to make the next joint (child) bend toward the pole vector.\r\n *\r\n * @param jointIndex - Index of the pole joint\r\n * @param poleVector - Pole vector position in world space\r\n * @param weight - Weight of the pole vector constraint (0-1)\r\n */\r\n private _applyPoleVectorTwist(jointIndex: number, poleVector: Vector3, weight: number): void {\r\n const joints = this._chain.joints;\r\n\r\n // We need at least 3 joints to apply pole vector (parent, pole joint, child)\r\n if (jointIndex < 1 || jointIndex >= joints.length - 1) {\r\n return;\r\n }\r\n\r\n const parentJoint = joints[jointIndex - 1];\r\n const currentJoint = joints[jointIndex];\r\n const childJoint = joints[jointIndex + 1];\r\n\r\n const parentPos = parentJoint.position;\r\n const currentPos = currentJoint.position;\r\n const childPos = childJoint.position;\r\n\r\n // Calculate the plane defined by parent, child, and pole vector\r\n // Vector from parent to child (the \"line\" we're bending around)\r\n const parentToChild = Vector3.sub(childPos, parentPos, new Vector3());\r\n const lineLength = parentToChild.magnitude;\r\n\r\n if (lineLength < 0.000001) {\r\n return; // Parent and child are at same position\r\n }\r\n\r\n const lineDir = Vector3.scale(parentToChild, 1 / lineLength, new Vector3());\r\n\r\n // Project current joint onto the parent-child line\r\n const parentToCurrent = Vector3.sub(currentPos, parentPos, new Vector3());\r\n const projectionLength = Vector3.dot(parentToCurrent, lineDir);\r\n const projectionPoint = Vector3.scale(lineDir, projectionLength, new Vector3());\r\n Vector3.add(parentPos, projectionPoint, projectionPoint);\r\n\r\n // Vector from projection point to current joint (perpendicular to line)\r\n const perpendicular = Vector3.sub(currentPos, projectionPoint, new Vector3());\r\n const perpLength = perpendicular.magnitude;\r\n\r\n if (perpLength < 0.000001) {\r\n return; // Current joint is on the line\r\n }\r\n\r\n // Calculate desired direction toward pole vector\r\n const parentToPole = Vector3.sub(poleVector, parentPos, new Vector3());\r\n const poleProjectionLength = Vector3.dot(parentToPole, lineDir);\r\n const poleProjectionPoint = Vector3.scale(lineDir, poleProjectionLength, new Vector3());\r\n Vector3.add(parentPos, poleProjectionPoint, poleProjectionPoint);\r\n\r\n // Direction from projection to pole (perpendicular to line)\r\n const poleDirection = Vector3.sub(poleVector, poleProjectionPoint, new Vector3());\r\n const poleDirLength = poleDirection.magnitude;\r\n\r\n if (poleDirLength < 0.000001) {\r\n return; // Pole is on the line\r\n }\r\n\r\n poleDirection.scaleBy(1 / poleDirLength);\r\n\r\n // Calculate new position for current joint\r\n // Keep the same distance from the line, but rotate toward pole direction\r\n const desiredPerpendicular = Vector3.scale(poleDirection, perpLength, new Vector3());\r\n const newPosition = Vector3.add(projectionPoint, desiredPerpendicular, new Vector3());\r\n\r\n // Apply weight (blend between original and constrained position)\r\n if (weight < 0.999) {\r\n const blended = new Vector3();\r\n blended.x = currentPos.x + (newPosition.x - currentPos.x) * weight;\r\n blended.y = currentPos.y + (newPosition.y - currentPos.y) * weight;\r\n blended.z = currentPos.z + (newPosition.z - currentPos.z) * weight;\r\n currentJoint.position.set(blended);\r\n } else {\r\n currentJoint.position.set(newPosition);\r\n }\r\n }\r\n\r\n /**\r\n * Apply constraints for a specific joint.\r\n *\r\n * @param jointIndex - Index of the joint to apply constraints to\r\n */\r\n private _applyConstraintsForJoint(jointIndex: number): void {\r\n const constraints = this._chain.constraints;\r\n for (const constraint of constraints) {\r\n if (constraint.jointIndex === jointIndex) {\r\n constraint.apply(this._chain.joints);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Apply the solved joint positions to scene nodes as rotations.\r\n *\r\n * @param weight - Blend weight (0 = original, 1 = full IK, default: 1)\r\n */\r\n applyToNodes(weight = 1): void {\r\n const joints = this._chain.joints;\r\n\r\n // Apply rotation for all joints except the end effector\r\n for (let i = 0; i < joints.length - 1; i++) {\r\n const joint = joints[i];\r\n const nextJoint = joints[i + 1];\r\n\r\n // Calculate direction from current joint to next joint in world space\r\n const originalDir = Vector3.sub(nextJoint.originalPosition, joint.originalPosition, new Vector3());\r\n const newDir = Vector3.sub(nextJoint.position, joint.position, new Vector3());\r\n\r\n const originalDirNorm = Vector3.normalize(originalDir, new Vector3());\r\n const newDirNorm = Vector3.normalize(newDir, new Vector3());\r\n\r\n // Calculate basic rotation\r\n const deltaRotation = new Quaternion();\r\n IKUtils.fromToRotation(originalDirNorm, newDirNorm, deltaRotation);\r\n\r\n // Calculate new world rotation\r\n let worldRotation = Quaternion.multiply(deltaRotation, joint.originalRotation, new Quaternion());\r\n\r\n // Apply swing-twist constraint to prevent over-rotation\r\n const swing = new Quaternion();\r\n const twist = new Quaternion();\r\n IKUtils.decomposeSwingTwist(worldRotation, newDirNorm, swing, twist);\r\n\r\n // Get twist angle\r\n let twistAngle = IKUtils.getTwistAngle(twist, newDirNorm);\r\n\r\n // Get twist constraint for this joint\r\n const constraint = this._twistConstraints.get(i);\r\n if (constraint) {\r\n // Clamp and smooth twist\r\n twistAngle = IKUtils.clampAndSmoothTwist(\r\n twistAngle,\r\n joint.previousTwist,\r\n constraint.minTwist,\r\n constraint.maxTwist,\r\n constraint.smoothFactor\r\n );\r\n }\r\n\r\n // Store for next frame\r\n joint.previousTwist = twistAngle;\r\n\r\n // Reconstruct rotation from clamped twist: Q = Twist * Swing\r\n const clampedTwist = new Quaternion();\r\n IKUtils.createTwist(twistAngle, newDirNorm, clampedTwist);\r\n worldRotation = Quaternion.multiply(clampedTwist, swing, worldRotation);\r\n\r\n // Blend with original rotation based on weight\r\n if (weight < 1) {\r\n Quaternion.slerp(joint.originalRotation, worldRotation, weight, worldRotation);\r\n }\r\n\r\n // Store this frame's world rotation for next frame's twist continuity\r\n if (!joint.previousIKRotation) {\r\n joint.previousIKRotation = worldRotation.clone();\r\n } else {\r\n joint.previousIKRotation.set(worldRotation);\r\n }\r\n\r\n // Convert world rotation to local rotation (relative to parent)\r\n if (joint.node.parent) {\r\n const parentWorldRotation = new Quaternion();\r\n joint.node.parent.worldMatrix.decompose(null, parentWorldRotation, null);\r\n\r\n // localRotation = conjugate(parentWorldRotation) * worldRotation\r\n const parentInvRotation = Quaternion.conjugate(parentWorldRotation, new Quaternion());\r\n const localRotation = Quaternion.multiply(parentInvRotation, worldRotation, new Quaternion());\r\n\r\n joint.node.rotation = localRotation;\r\n } else {\r\n // Root node has no parent, world rotation is local rotation\r\n joint.node.rotation = worldRotation;\r\n }\r\n }\r\n }\r\n}\r\n"],"names":["CCDSolver","IKSolver","chain","maxIterations","tolerance","_poleVectors","Map","_twistConstraints","i","joints","length","isMiddleJoint","set","minTwist","Math","PI","maxTwist","smoothFactor","setTwistConstraint","jointIndex","_chain","Error","max","min","getTwistConstraint","get","removeTwistConstraint","delete","clearTwistConstraints","clear","setPoleVector","poleVector","weight","position","clone","removePoleVector","clearPoleVectors","getPoleVector","config","undefined","hasPoleVector","has","solve","target","updateFromNodes","storeOriginalPositions","converged","iteration","_maxIterations","endEffector","distToTarget","Vector3","distance","_tolerance","joint","toEnd","sub","toEndDist","magnitude","toTarget","toTargetDist","toEndDir","scale","toTargetDir","rotation","Quaternion","IKUtils","fromToRotation","_rotateJointsFromIndex","_applyConstraintsForJoint","_applyAllPoleVectors","startIndex","pivot","offset","rotated","transform","add","size","sortedIndices","Array","from","keys","sort","a","b","_applyPoleVectorTwist","parentJoint","currentJoint","childJoint","parentPos","currentPos","childPos","parentToChild","lineLength","lineDir","parentToCurrent","projectionLength","dot","projectionPoint","perpendicular","perpLength","parentToPole","poleProjectionLength","poleProjectionPoint","poleDirection","poleDirLength","scaleBy","desiredPerpendicular","newPosition","blended","x","y","z","constraints","constraint","apply","applyToNodes","nextJoint","originalDir","originalPosition","newDir","originalDirNorm","normalize","newDirNorm","deltaRotation","worldRotation","multiply","originalRotation","swing","twist","decomposeSwingTwist","twistAngle","getTwistAngle","clampAndSmoothTwist","previousTwist","clampedTwist","createTwist","slerp","previousIKRotation","node","parent","parentWorldRotation","worldMatrix","decompose","parentInvRotation","conjugate","localRotation"],"mappings":"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"}
@@ -0,0 +1,399 @@
1
+ import { Vector3, Quaternion } from '@zephyr3d/base';
2
+ import { IKSolver } from './ik_solver.js';
3
+ import { IKUtils } from './ik_utils.js';
4
+
5
+ /**
6
+ * FABRIK (Forward And Backward Reaching Inverse Kinematics) solver.
7
+ *
8
+ * @remarks
9
+ * FABRIK is an iterative IK algorithm that alternates between:
10
+ * 1. Forward pass: Move from end effector to root, pulling joints toward target
11
+ * 2. Backward pass: Move from root to end effector, restoring root position
12
+ *
13
+ * Supports multiple pole vectors to control the bending direction of different joints.
14
+ *
15
+ * @public
16
+ */ class FABRIKSolver extends IKSolver {
17
+ /** Map of joint index to pole vector configuration */ _poleVectors;
18
+ /** Twist constraints for each joint (indexed by joint index) */ _twistConstraints;
19
+ /**
20
+ * Create a FABRIK solver.
21
+ *
22
+ * @param chain - The IK chain to solve
23
+ * @param maxIterations - Maximum number of iterations (default: 15)
24
+ * @param tolerance - Convergence tolerance in world units (default: 0.001)
25
+ */ constructor(chain, maxIterations = 15, tolerance = 0.001){
26
+ super(chain, maxIterations, tolerance);
27
+ this._poleVectors = new Map();
28
+ this._twistConstraints = new Map();
29
+ // Set default twist constraints for all joints
30
+ for(let i = 0; i < chain.joints.length - 1; i++){
31
+ // Middle joints have more restrictive twist limits
32
+ const isMiddleJoint = i > 0 && i < chain.joints.length - 2;
33
+ this._twistConstraints.set(i, {
34
+ minTwist: isMiddleJoint ? -Math.PI * 0.2 : -Math.PI * 0.3,
35
+ maxTwist: isMiddleJoint ? Math.PI * 0.2 : Math.PI * 0.3,
36
+ smoothFactor: 0.3
37
+ });
38
+ }
39
+ }
40
+ /**
41
+ * Set twist constraint for a specific joint.
42
+ *
43
+ * @param jointIndex - Index of the joint
44
+ * @param minTwist - Minimum twist angle in radians
45
+ * @param maxTwist - Maximum twist angle in radians
46
+ * @param smoothFactor - Smoothing factor [0-1] (default: 0.3)
47
+ */ setTwistConstraint(jointIndex, minTwist, maxTwist, smoothFactor = 0.3) {
48
+ if (jointIndex < 0 || jointIndex >= this._chain.joints.length - 1) {
49
+ throw new Error(`Invalid joint index: ${jointIndex}`);
50
+ }
51
+ this._twistConstraints.set(jointIndex, {
52
+ minTwist,
53
+ maxTwist,
54
+ smoothFactor: Math.max(0, Math.min(1, smoothFactor))
55
+ });
56
+ }
57
+ /**
58
+ * Get twist constraint for a specific joint.
59
+ *
60
+ * @param jointIndex - Index of the joint
61
+ * @returns Twist constraint or undefined if not set
62
+ */ getTwistConstraint(jointIndex) {
63
+ return this._twistConstraints.get(jointIndex);
64
+ }
65
+ /**
66
+ * Remove twist constraint for a specific joint.
67
+ *
68
+ * @param jointIndex - Index of the joint
69
+ * @returns True if a constraint was removed
70
+ */ removeTwistConstraint(jointIndex) {
71
+ return this._twistConstraints.delete(jointIndex);
72
+ }
73
+ /**
74
+ * Clear all twist constraints.
75
+ */ clearTwistConstraints() {
76
+ this._twistConstraints.clear();
77
+ }
78
+ /**
79
+ * Set pole vector for a specific joint.
80
+ *
81
+ * @param jointIndex - Index of the joint to apply pole vector to
82
+ * @param poleVector - Pole vector position in world space
83
+ * @param weight - Weight of the pole vector constraint (0-1, default: 1)
84
+ */ setPoleVector(jointIndex, poleVector, weight = 1) {
85
+ if (jointIndex < 0 || jointIndex >= this._chain.joints.length) {
86
+ throw new Error(`Invalid joint index: ${jointIndex}`);
87
+ }
88
+ this._poleVectors.set(jointIndex, {
89
+ position: poleVector.clone(),
90
+ weight: Math.max(0, Math.min(1, weight))
91
+ });
92
+ }
93
+ /**
94
+ * Remove pole vector for a specific joint.
95
+ *
96
+ * @param jointIndex - Index of the joint to remove pole vector from
97
+ * @returns True if a pole vector was removed, false if none existed
98
+ */ removePoleVector(jointIndex) {
99
+ return this._poleVectors.delete(jointIndex);
100
+ }
101
+ /**
102
+ * Clear all pole vectors.
103
+ */ clearPoleVectors() {
104
+ this._poleVectors.clear();
105
+ }
106
+ /**
107
+ * Get pole vector configuration for a specific joint.
108
+ *
109
+ * @param jointIndex - Index of the joint
110
+ * @returns Pole vector configuration or undefined if not set
111
+ */ getPoleVector(jointIndex) {
112
+ const config = this._poleVectors.get(jointIndex);
113
+ if (config) {
114
+ return {
115
+ position: config.position.clone(),
116
+ weight: config.weight
117
+ };
118
+ }
119
+ return undefined;
120
+ }
121
+ /**
122
+ * Check if a joint has a pole vector.
123
+ *
124
+ * @param jointIndex - Index of the joint
125
+ * @returns True if the joint has a pole vector
126
+ */ hasPoleVector(jointIndex) {
127
+ return this._poleVectors.has(jointIndex);
128
+ }
129
+ /**
130
+ * Solve the IK chain to reach the target position using FABRIK algorithm.
131
+ *
132
+ * @param target - Target position for the end effector
133
+ * @returns True if converged within tolerance, false otherwise
134
+ */ solve(target) {
135
+ const joints = this._chain.joints;
136
+ // Update joint positions from scene nodes before solving
137
+ this._chain.updateFromNodes();
138
+ // Store original positions
139
+ this._chain.storeOriginalPositions();
140
+ const rootPos = joints[0].originalPosition.clone();
141
+ // Check if target is reachable
142
+ const distToTarget = Vector3.distance(rootPos, target);
143
+ if (distToTarget > this._chain.totalLength) {
144
+ // Target unreachable - stretch chain toward target
145
+ this._stretchToward(target);
146
+ return false;
147
+ }
148
+ let converged = false;
149
+ for(let iteration = 0; iteration < this._maxIterations; iteration++){
150
+ // Check convergence
151
+ const distToEnd = Vector3.distance(joints[joints.length - 1].position, target);
152
+ if (distToEnd < this._tolerance) {
153
+ converged = true;
154
+ break;
155
+ }
156
+ // Forward pass: end effector to root
157
+ this._forwardPass(target);
158
+ // Backward pass: root to end effector (constraints are applied within the pass)
159
+ this._backwardPass(rootPos);
160
+ }
161
+ return converged;
162
+ }
163
+ /**
164
+ * Apply the solved joint positions to scene nodes as rotations.
165
+ *
166
+ * @param weight - Blend weight (0 = original, 1 = full IK, default: 1)
167
+ */ applyToNodes(weight = 1) {
168
+ const joints = this._chain.joints;
169
+ for(let i = 0; i < joints.length - 1; i++){
170
+ const joint = joints[i];
171
+ const nextJoint = joints[i + 1];
172
+ // Calculate direction from current joint to next joint in world space
173
+ const originalDir = Vector3.sub(nextJoint.originalPosition, joint.originalPosition, new Vector3());
174
+ const newDir = Vector3.sub(nextJoint.position, joint.position, new Vector3());
175
+ const originalDirNorm = Vector3.normalize(originalDir, new Vector3());
176
+ const newDirNorm = Vector3.normalize(newDir, new Vector3());
177
+ // Calculate basic rotation
178
+ const deltaRotation = new Quaternion();
179
+ IKUtils.fromToRotation(originalDirNorm, newDirNorm, deltaRotation);
180
+ // Calculate new world rotation
181
+ let worldRotation = Quaternion.multiply(deltaRotation, joint.originalRotation, new Quaternion());
182
+ // Apply swing-twist constraint to prevent over-rotation
183
+ const swing = new Quaternion();
184
+ const twist = new Quaternion();
185
+ IKUtils.decomposeSwingTwist(worldRotation, newDirNorm, swing, twist);
186
+ // Get twist angle
187
+ let twistAngle = IKUtils.getTwistAngle(twist, newDirNorm);
188
+ // Get twist constraint for this joint
189
+ const constraint = this._twistConstraints.get(i);
190
+ if (constraint) {
191
+ // Clamp and smooth twist
192
+ twistAngle = IKUtils.clampAndSmoothTwist(twistAngle, joint.previousTwist, constraint.minTwist, constraint.maxTwist, constraint.smoothFactor);
193
+ }
194
+ // Store for next frame
195
+ joint.previousTwist = twistAngle;
196
+ // Reconstruct rotation from clamped twist: Q = Twist * Swing
197
+ const clampedTwist = new Quaternion();
198
+ IKUtils.createTwist(twistAngle, newDirNorm, clampedTwist);
199
+ worldRotation = Quaternion.multiply(clampedTwist, swing, worldRotation);
200
+ // Blend with original rotation based on weight
201
+ if (weight < 1) {
202
+ Quaternion.slerp(joint.originalRotation, worldRotation, weight, worldRotation);
203
+ }
204
+ // Store this frame's world rotation
205
+ if (!joint.previousIKRotation) {
206
+ joint.previousIKRotation = worldRotation.clone();
207
+ } else {
208
+ joint.previousIKRotation.set(worldRotation);
209
+ }
210
+ // Convert world rotation to local rotation (relative to parent)
211
+ if (joint.node.parent) {
212
+ const parentWorldRotation = new Quaternion();
213
+ joint.node.parent.worldMatrix.decompose(null, parentWorldRotation, null);
214
+ // localRotation = conjugate(parentWorldRotation) * worldRotation
215
+ const parentInvRotation = Quaternion.conjugate(parentWorldRotation, new Quaternion());
216
+ const localRotation = Quaternion.multiply(parentInvRotation, worldRotation, new Quaternion());
217
+ joint.node.rotation = localRotation;
218
+ } else {
219
+ // Root node has no parent, world rotation is local rotation
220
+ joint.node.rotation = worldRotation;
221
+ }
222
+ }
223
+ }
224
+ /**
225
+ * Forward pass: move from end effector toward root.
226
+ * Each joint is pulled toward its child, maintaining bone length.
227
+ * Constraints are applied immediately after each joint adjustment.
228
+ *
229
+ * @param target - Target position for end effector
230
+ */ _forwardPass(target) {
231
+ const joints = this._chain.joints;
232
+ // Set end effector to target
233
+ joints[joints.length - 1].position.set(target);
234
+ // Move backward through chain
235
+ for(let i = joints.length - 2; i >= 0; i--){
236
+ const joint = joints[i];
237
+ const childJoint = joints[i + 1];
238
+ // Calculate direction from child to current joint
239
+ const direction = Vector3.sub(joint.position, childJoint.position, new Vector3());
240
+ const distance = direction.magnitude;
241
+ if (distance > 0.000001) {
242
+ direction.scaleBy(1 / distance);
243
+ // Place joint at correct distance from child
244
+ Vector3.scale(direction, joint.boneLength, direction);
245
+ Vector3.add(childJoint.position, direction, joint.position);
246
+ }
247
+ // Apply constraints immediately after adjusting this joint
248
+ // This ensures constraints are integrated into the FABRIK algorithm
249
+ if (i > 0) {
250
+ // Apply constraints for joint i (not for root joint)
251
+ this._applyConstraintsForJoint(i);
252
+ }
253
+ }
254
+ }
255
+ /**
256
+ * Backward pass: move from root toward end effector.
257
+ * Each joint is pulled toward its parent, maintaining bone length.
258
+ * Constraints are applied immediately after each joint adjustment.
259
+ *
260
+ * @param rootPos - Original root position to restore
261
+ */ _backwardPass(rootPos) {
262
+ const joints = this._chain.joints;
263
+ // Restore root position
264
+ joints[0].position.set(rootPos);
265
+ // Move forward through chain
266
+ for(let i = 0; i < joints.length - 1; i++){
267
+ const joint = joints[i];
268
+ const childJoint = joints[i + 1];
269
+ // Calculate direction from current joint to child
270
+ const direction = Vector3.sub(childJoint.position, joint.position, new Vector3());
271
+ const distance = direction.magnitude;
272
+ if (distance > 0.000001) {
273
+ direction.scaleBy(1 / distance);
274
+ // Place child at correct distance from current joint
275
+ Vector3.scale(direction, joint.boneLength, direction);
276
+ Vector3.add(joint.position, direction, childJoint.position);
277
+ }
278
+ // Apply constraints immediately after adjusting this joint
279
+ // This ensures constraints are integrated into the FABRIK algorithm
280
+ this._applyConstraintsForJoint(i + 1);
281
+ }
282
+ }
283
+ /**
284
+ * Apply constraints for a specific joint.
285
+ * This is called during the FABRIK passes to integrate constraints into the algorithm.
286
+ *
287
+ * @param jointIndex - Index of the joint to apply constraints to
288
+ */ _applyConstraintsForJoint(jointIndex) {
289
+ const constraints = this._chain.constraints;
290
+ // Apply non-pole-vector constraints
291
+ // IKPoleVectorConstraint is deprecated and ignored in favor of built-in pole vectors
292
+ for (const constraint of constraints){
293
+ if (constraint.jointIndex === jointIndex) {
294
+ // Skip IKPoleVectorConstraint - use built-in pole vectors instead
295
+ if (constraint.constructor.name === 'IKPoleVectorConstraint') {
296
+ continue;
297
+ }
298
+ constraint.apply(this._chain.joints);
299
+ }
300
+ }
301
+ // Apply built-in pole vector if configured for this joint
302
+ const poleConfig = this._poleVectors.get(jointIndex);
303
+ if (poleConfig && poleConfig.weight > 0.001) {
304
+ this._applyPoleVectorTwist(jointIndex, poleConfig.position, poleConfig.weight);
305
+ }
306
+ }
307
+ /**
308
+ * Apply pole vector twist to a specific joint.
309
+ *
310
+ * @remarks
311
+ * This method adjusts the joint position to align with the pole vector.
312
+ * It uses the same algorithm as IKPoleVectorConstraint but is integrated
313
+ * into the solver for better performance and control.
314
+ *
315
+ * @param jointIndex - Index of the pole joint
316
+ * @param poleVector - Pole vector position in world space
317
+ * @param weight - Weight of the pole vector constraint (0-1)
318
+ */ _applyPoleVectorTwist(jointIndex, poleVector, weight) {
319
+ const joints = this._chain.joints;
320
+ // We need at least 3 joints to apply pole vector (parent, pole joint, child)
321
+ if (jointIndex < 1 || jointIndex >= joints.length - 1) {
322
+ return;
323
+ }
324
+ const parentJoint = joints[jointIndex - 1];
325
+ const currentJoint = joints[jointIndex];
326
+ const childJoint = joints[jointIndex + 1];
327
+ const parentPos = parentJoint.position;
328
+ const currentPos = currentJoint.position;
329
+ const childPos = childJoint.position;
330
+ // Calculate the plane defined by parent, child, and pole vector
331
+ // Vector from parent to child (the "line" we're bending around)
332
+ const parentToChild = Vector3.sub(childPos, parentPos, new Vector3());
333
+ const lineLength = parentToChild.magnitude;
334
+ if (lineLength < 0.000001) {
335
+ return; // Parent and child are at same position
336
+ }
337
+ const lineDir = Vector3.scale(parentToChild, 1 / lineLength, new Vector3());
338
+ // Project current joint onto the parent-child line
339
+ const parentToCurrent = Vector3.sub(currentPos, parentPos, new Vector3());
340
+ const projectionLength = Vector3.dot(parentToCurrent, lineDir);
341
+ const projectionPoint = Vector3.scale(lineDir, projectionLength, new Vector3());
342
+ Vector3.add(parentPos, projectionPoint, projectionPoint);
343
+ // Vector from projection point to current joint (perpendicular to line)
344
+ const perpendicular = Vector3.sub(currentPos, projectionPoint, new Vector3());
345
+ const perpLength = perpendicular.magnitude;
346
+ if (perpLength < 0.000001) {
347
+ return; // Current joint is on the line
348
+ }
349
+ // Calculate desired direction toward pole vector
350
+ const parentToPole = Vector3.sub(poleVector, parentPos, new Vector3());
351
+ const poleProjectionLength = Vector3.dot(parentToPole, lineDir);
352
+ const poleProjectionPoint = Vector3.scale(lineDir, poleProjectionLength, new Vector3());
353
+ Vector3.add(parentPos, poleProjectionPoint, poleProjectionPoint);
354
+ // Direction from projection to pole (perpendicular to line)
355
+ const poleDirection = Vector3.sub(poleVector, poleProjectionPoint, new Vector3());
356
+ const poleDirLength = poleDirection.magnitude;
357
+ if (poleDirLength < 0.000001) {
358
+ return; // Pole is on the line
359
+ }
360
+ poleDirection.scaleBy(1 / poleDirLength);
361
+ // Calculate new position for current joint
362
+ // Keep the same distance from the line, but rotate toward pole direction
363
+ const desiredPerpendicular = Vector3.scale(poleDirection, perpLength, new Vector3());
364
+ const newPosition = Vector3.add(projectionPoint, desiredPerpendicular, new Vector3());
365
+ // Apply weight (blend between original and constrained position)
366
+ if (weight < 0.999) {
367
+ const blended = new Vector3();
368
+ blended.x = currentPos.x + (newPosition.x - currentPos.x) * weight;
369
+ blended.y = currentPos.y + (newPosition.y - currentPos.y) * weight;
370
+ blended.z = currentPos.z + (newPosition.z - currentPos.z) * weight;
371
+ currentJoint.position.set(blended);
372
+ } else {
373
+ currentJoint.position.set(newPosition);
374
+ }
375
+ }
376
+ /**
377
+ * Stretch the chain toward an unreachable target.
378
+ * All joints are aligned in a straight line toward the target.
379
+ *
380
+ * @param target - Unreachable target position
381
+ */ _stretchToward(target) {
382
+ const joints = this._chain.joints;
383
+ const rootPos = joints[0].originalPosition;
384
+ // Calculate direction from root to target
385
+ const direction = Vector3.sub(target, rootPos, new Vector3()).inplaceNormalize();
386
+ // Place each joint along the direction at its bone length
387
+ let currentPos = rootPos.clone();
388
+ for(let i = 0; i < joints.length; i++){
389
+ joints[i].position.set(currentPos);
390
+ if (i < joints.length - 1) {
391
+ const offset = Vector3.scale(direction, joints[i].boneLength, new Vector3());
392
+ currentPos.addBy(offset);
393
+ }
394
+ }
395
+ }
396
+ }
397
+
398
+ export { FABRIKSolver };
399
+ //# sourceMappingURL=fabrik_solver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fabrik_solver.js","sources":["../../../src/animation/ik/fabrik_solver.ts"],"sourcesContent":["import { Vector3, Quaternion } from '@zephyr3d/base';\r\nimport { IKSolver } from './ik_solver';\r\nimport type { IKChain } from './ik_chain';\r\nimport { IKUtils } from './ik_utils';\r\nimport type { TwistConstraint } from './ik_constraint';\r\n\r\n/**\r\n * Pole vector configuration for a specific joint.\r\n */\r\ninterface PoleVectorConfig {\r\n /** Pole vector position in world space */\r\n position: Vector3;\r\n /** Weight of the pole vector constraint (0-1) */\r\n weight: number;\r\n}\r\n\r\n/**\r\n * FABRIK (Forward And Backward Reaching Inverse Kinematics) solver.\r\n *\r\n * @remarks\r\n * FABRIK is an iterative IK algorithm that alternates between:\r\n * 1. Forward pass: Move from end effector to root, pulling joints toward target\r\n * 2. Backward pass: Move from root to end effector, restoring root position\r\n *\r\n * Supports multiple pole vectors to control the bending direction of different joints.\r\n *\r\n * @public\r\n */\r\nexport class FABRIKSolver extends IKSolver {\r\n /** Map of joint index to pole vector configuration */\r\n private _poleVectors: Map<number, PoleVectorConfig>;\r\n /** Twist constraints for each joint (indexed by joint index) */\r\n private _twistConstraints: Map<number, TwistConstraint>;\r\n\r\n /**\r\n * Create a FABRIK solver.\r\n *\r\n * @param chain - The IK chain to solve\r\n * @param maxIterations - Maximum number of iterations (default: 15)\r\n * @param tolerance - Convergence tolerance in world units (default: 0.001)\r\n */\r\n constructor(chain: IKChain, maxIterations = 15, tolerance = 0.001) {\r\n super(chain, maxIterations, tolerance);\r\n this._poleVectors = new Map();\r\n this._twistConstraints = new Map();\r\n\r\n // Set default twist constraints for all joints\r\n for (let i = 0; i < chain.joints.length - 1; i++) {\r\n // Middle joints have more restrictive twist limits\r\n const isMiddleJoint = i > 0 && i < chain.joints.length - 2;\r\n this._twistConstraints.set(i, {\r\n minTwist: isMiddleJoint ? -Math.PI * 0.2 : -Math.PI * 0.3,\r\n maxTwist: isMiddleJoint ? Math.PI * 0.2 : Math.PI * 0.3,\r\n smoothFactor: 0.3\r\n });\r\n }\r\n }\r\n\r\n /**\r\n * Set twist constraint for a specific joint.\r\n *\r\n * @param jointIndex - Index of the joint\r\n * @param minTwist - Minimum twist angle in radians\r\n * @param maxTwist - Maximum twist angle in radians\r\n * @param smoothFactor - Smoothing factor [0-1] (default: 0.3)\r\n */\r\n setTwistConstraint(\r\n jointIndex: number,\r\n minTwist: number,\r\n maxTwist: number,\r\n smoothFactor: number = 0.3\r\n ): void {\r\n if (jointIndex < 0 || jointIndex >= this._chain.joints.length - 1) {\r\n throw new Error(`Invalid joint index: ${jointIndex}`);\r\n }\r\n\r\n this._twistConstraints.set(jointIndex, {\r\n minTwist,\r\n maxTwist,\r\n smoothFactor: Math.max(0, Math.min(1, smoothFactor))\r\n });\r\n }\r\n\r\n /**\r\n * Get twist constraint for a specific joint.\r\n *\r\n * @param jointIndex - Index of the joint\r\n * @returns Twist constraint or undefined if not set\r\n */\r\n getTwistConstraint(jointIndex: number): TwistConstraint | undefined {\r\n return this._twistConstraints.get(jointIndex);\r\n }\r\n\r\n /**\r\n * Remove twist constraint for a specific joint.\r\n *\r\n * @param jointIndex - Index of the joint\r\n * @returns True if a constraint was removed\r\n */\r\n removeTwistConstraint(jointIndex: number): boolean {\r\n return this._twistConstraints.delete(jointIndex);\r\n }\r\n\r\n /**\r\n * Clear all twist constraints.\r\n */\r\n clearTwistConstraints(): void {\r\n this._twistConstraints.clear();\r\n }\r\n\r\n /**\r\n * Set pole vector for a specific joint.\r\n *\r\n * @param jointIndex - Index of the joint to apply pole vector to\r\n * @param poleVector - Pole vector position in world space\r\n * @param weight - Weight of the pole vector constraint (0-1, default: 1)\r\n */\r\n setPoleVector(jointIndex: number, poleVector: Vector3, weight = 1): void {\r\n if (jointIndex < 0 || jointIndex >= this._chain.joints.length) {\r\n throw new Error(`Invalid joint index: ${jointIndex}`);\r\n }\r\n\r\n this._poleVectors.set(jointIndex, {\r\n position: poleVector.clone(),\r\n weight: Math.max(0, Math.min(1, weight))\r\n });\r\n }\r\n\r\n /**\r\n * Remove pole vector for a specific joint.\r\n *\r\n * @param jointIndex - Index of the joint to remove pole vector from\r\n * @returns True if a pole vector was removed, false if none existed\r\n */\r\n removePoleVector(jointIndex: number): boolean {\r\n return this._poleVectors.delete(jointIndex);\r\n }\r\n\r\n /**\r\n * Clear all pole vectors.\r\n */\r\n clearPoleVectors(): void {\r\n this._poleVectors.clear();\r\n }\r\n\r\n /**\r\n * Get pole vector configuration for a specific joint.\r\n *\r\n * @param jointIndex - Index of the joint\r\n * @returns Pole vector configuration or undefined if not set\r\n */\r\n getPoleVector(jointIndex: number): { position: Vector3; weight: number } | undefined {\r\n const config = this._poleVectors.get(jointIndex);\r\n if (config) {\r\n return {\r\n position: config.position.clone(),\r\n weight: config.weight\r\n };\r\n }\r\n return undefined;\r\n }\r\n\r\n /**\r\n * Check if a joint has a pole vector.\r\n *\r\n * @param jointIndex - Index of the joint\r\n * @returns True if the joint has a pole vector\r\n */\r\n hasPoleVector(jointIndex: number): boolean {\r\n return this._poleVectors.has(jointIndex);\r\n }\r\n\r\n /**\r\n * Solve the IK chain to reach the target position using FABRIK algorithm.\r\n *\r\n * @param target - Target position for the end effector\r\n * @returns True if converged within tolerance, false otherwise\r\n */\r\n solve(target: Vector3): boolean {\r\n const joints = this._chain.joints;\r\n\r\n // Update joint positions from scene nodes before solving\r\n this._chain.updateFromNodes();\r\n\r\n // Store original positions\r\n this._chain.storeOriginalPositions();\r\n\r\n const rootPos = joints[0].originalPosition.clone();\r\n\r\n // Check if target is reachable\r\n const distToTarget = Vector3.distance(rootPos, target);\r\n if (distToTarget > this._chain.totalLength) {\r\n // Target unreachable - stretch chain toward target\r\n this._stretchToward(target);\r\n return false;\r\n }\r\n\r\n let converged = false;\r\n for (let iteration = 0; iteration < this._maxIterations; iteration++) {\r\n // Check convergence\r\n const distToEnd = Vector3.distance(joints[joints.length - 1].position, target);\r\n if (distToEnd < this._tolerance) {\r\n converged = true;\r\n break;\r\n }\r\n\r\n // Forward pass: end effector to root\r\n this._forwardPass(target);\r\n\r\n // Backward pass: root to end effector (constraints are applied within the pass)\r\n this._backwardPass(rootPos);\r\n }\r\n\r\n return converged;\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 for (let i = 0; i < joints.length - 1; i++) {\r\n const joint = joints[i];\r\n const nextJoint = joints[i + 1];\r\n\r\n // Calculate direction from current joint to next joint in world space\r\n const originalDir = Vector3.sub(nextJoint.originalPosition, joint.originalPosition, new Vector3());\r\n const newDir = Vector3.sub(nextJoint.position, joint.position, new Vector3());\r\n\r\n const originalDirNorm = Vector3.normalize(originalDir, new Vector3());\r\n const newDirNorm = Vector3.normalize(newDir, new Vector3());\r\n\r\n // Calculate basic rotation\r\n const deltaRotation = new Quaternion();\r\n IKUtils.fromToRotation(originalDirNorm, newDirNorm, deltaRotation);\r\n\r\n // Calculate new world rotation\r\n let worldRotation = Quaternion.multiply(deltaRotation, joint.originalRotation, new Quaternion());\r\n\r\n // Apply swing-twist constraint to prevent over-rotation\r\n const swing = new Quaternion();\r\n const twist = new Quaternion();\r\n IKUtils.decomposeSwingTwist(worldRotation, newDirNorm, swing, twist);\r\n\r\n // Get twist angle\r\n let twistAngle = IKUtils.getTwistAngle(twist, newDirNorm);\r\n\r\n // Get twist constraint for this joint\r\n const constraint = this._twistConstraints.get(i);\r\n if (constraint) {\r\n // Clamp and smooth twist\r\n twistAngle = IKUtils.clampAndSmoothTwist(\r\n twistAngle,\r\n joint.previousTwist,\r\n constraint.minTwist,\r\n constraint.maxTwist,\r\n constraint.smoothFactor\r\n );\r\n }\r\n\r\n // Store for next frame\r\n joint.previousTwist = twistAngle;\r\n\r\n // Reconstruct rotation from clamped twist: Q = Twist * Swing\r\n const clampedTwist = new Quaternion();\r\n IKUtils.createTwist(twistAngle, newDirNorm, clampedTwist);\r\n worldRotation = Quaternion.multiply(clampedTwist, swing, worldRotation);\r\n\r\n // Blend with original rotation based on weight\r\n if (weight < 1) {\r\n Quaternion.slerp(joint.originalRotation, worldRotation, weight, worldRotation);\r\n }\r\n\r\n // Store this frame's world rotation\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 * Forward pass: move from end effector toward root.\r\n * Each joint is pulled toward its child, maintaining bone length.\r\n * Constraints are applied immediately after each joint adjustment.\r\n *\r\n * @param target - Target position for end effector\r\n */\r\n private _forwardPass(target: Vector3): void {\r\n const joints = this._chain.joints;\r\n\r\n // Set end effector to target\r\n joints[joints.length - 1].position.set(target);\r\n\r\n // Move backward through chain\r\n for (let i = joints.length - 2; i >= 0; i--) {\r\n const joint = joints[i];\r\n const childJoint = joints[i + 1];\r\n\r\n // Calculate direction from child to current joint\r\n const direction = Vector3.sub(joint.position, childJoint.position, new Vector3());\r\n const distance = direction.magnitude;\r\n\r\n if (distance > 0.000001) {\r\n direction.scaleBy(1 / distance);\r\n // Place joint at correct distance from child\r\n Vector3.scale(direction, joint.boneLength, direction);\r\n Vector3.add(childJoint.position, direction, joint.position);\r\n }\r\n\r\n // Apply constraints immediately after adjusting this joint\r\n // This ensures constraints are integrated into the FABRIK algorithm\r\n if (i > 0) {\r\n // Apply constraints for joint i (not for root joint)\r\n this._applyConstraintsForJoint(i);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Backward pass: move from root toward end effector.\r\n * Each joint is pulled toward its parent, maintaining bone length.\r\n * Constraints are applied immediately after each joint adjustment.\r\n *\r\n * @param rootPos - Original root position to restore\r\n */\r\n private _backwardPass(rootPos: Vector3): void {\r\n const joints = this._chain.joints;\r\n\r\n // Restore root position\r\n joints[0].position.set(rootPos);\r\n\r\n // Move forward through chain\r\n for (let i = 0; i < joints.length - 1; i++) {\r\n const joint = joints[i];\r\n const childJoint = joints[i + 1];\r\n\r\n // Calculate direction from current joint to child\r\n const direction = Vector3.sub(childJoint.position, joint.position, new Vector3());\r\n const distance = direction.magnitude;\r\n\r\n if (distance > 0.000001) {\r\n direction.scaleBy(1 / distance);\r\n // Place child at correct distance from current joint\r\n Vector3.scale(direction, joint.boneLength, direction);\r\n Vector3.add(joint.position, direction, childJoint.position);\r\n }\r\n\r\n // Apply constraints immediately after adjusting this joint\r\n // This ensures constraints are integrated into the FABRIK algorithm\r\n this._applyConstraintsForJoint(i + 1);\r\n }\r\n }\r\n\r\n /**\r\n * Apply constraints for a specific joint.\r\n * This is called during the FABRIK passes to integrate constraints into the algorithm.\r\n *\r\n * @param jointIndex - Index of the joint to apply constraints to\r\n */\r\n private _applyConstraintsForJoint(jointIndex: number): void {\r\n const constraints = this._chain.constraints;\r\n\r\n // Apply non-pole-vector constraints\r\n // IKPoleVectorConstraint is deprecated and ignored in favor of built-in pole vectors\r\n for (const constraint of constraints) {\r\n if (constraint.jointIndex === jointIndex) {\r\n // Skip IKPoleVectorConstraint - use built-in pole vectors instead\r\n if (constraint.constructor.name === 'IKPoleVectorConstraint') {\r\n continue;\r\n }\r\n constraint.apply(this._chain.joints);\r\n }\r\n }\r\n\r\n // Apply built-in pole vector if configured for this joint\r\n const poleConfig = this._poleVectors.get(jointIndex);\r\n if (poleConfig && poleConfig.weight > 0.001) {\r\n this._applyPoleVectorTwist(jointIndex, poleConfig.position, poleConfig.weight);\r\n }\r\n }\r\n\r\n /**\r\n * Apply pole vector twist to a specific joint.\r\n *\r\n * @remarks\r\n * This method adjusts the joint position to align with the pole vector.\r\n * It uses the same algorithm as IKPoleVectorConstraint but is integrated\r\n * into the solver for better performance and control.\r\n *\r\n * @param jointIndex - Index of the pole joint\r\n * @param poleVector - Pole vector position in world space\r\n * @param weight - Weight of the pole vector constraint (0-1)\r\n */\r\n private _applyPoleVectorTwist(jointIndex: number, poleVector: Vector3, weight: number): void {\r\n const joints = this._chain.joints;\r\n\r\n // We need at least 3 joints to apply pole vector (parent, pole joint, child)\r\n if (jointIndex < 1 || jointIndex >= joints.length - 1) {\r\n return;\r\n }\r\n\r\n const parentJoint = joints[jointIndex - 1];\r\n const currentJoint = joints[jointIndex];\r\n const childJoint = joints[jointIndex + 1];\r\n\r\n const parentPos = parentJoint.position;\r\n const currentPos = currentJoint.position;\r\n const childPos = childJoint.position;\r\n\r\n // Calculate the plane defined by parent, child, and pole vector\r\n // Vector from parent to child (the \"line\" we're bending around)\r\n const parentToChild = Vector3.sub(childPos, parentPos, new Vector3());\r\n const lineLength = parentToChild.magnitude;\r\n\r\n if (lineLength < 0.000001) {\r\n return; // Parent and child are at same position\r\n }\r\n\r\n const lineDir = Vector3.scale(parentToChild, 1 / lineLength, new Vector3());\r\n\r\n // Project current joint onto the parent-child line\r\n const parentToCurrent = Vector3.sub(currentPos, parentPos, new Vector3());\r\n const projectionLength = Vector3.dot(parentToCurrent, lineDir);\r\n const projectionPoint = Vector3.scale(lineDir, projectionLength, new Vector3());\r\n Vector3.add(parentPos, projectionPoint, projectionPoint);\r\n\r\n // Vector from projection point to current joint (perpendicular to line)\r\n const perpendicular = Vector3.sub(currentPos, projectionPoint, new Vector3());\r\n const perpLength = perpendicular.magnitude;\r\n\r\n if (perpLength < 0.000001) {\r\n return; // Current joint is on the line\r\n }\r\n\r\n // Calculate desired direction toward pole vector\r\n const parentToPole = Vector3.sub(poleVector, parentPos, new Vector3());\r\n const poleProjectionLength = Vector3.dot(parentToPole, lineDir);\r\n const poleProjectionPoint = Vector3.scale(lineDir, poleProjectionLength, new Vector3());\r\n Vector3.add(parentPos, poleProjectionPoint, poleProjectionPoint);\r\n\r\n // Direction from projection to pole (perpendicular to line)\r\n const poleDirection = Vector3.sub(poleVector, poleProjectionPoint, new Vector3());\r\n const poleDirLength = poleDirection.magnitude;\r\n\r\n if (poleDirLength < 0.000001) {\r\n return; // Pole is on the line\r\n }\r\n\r\n poleDirection.scaleBy(1 / poleDirLength);\r\n\r\n // Calculate new position for current joint\r\n // Keep the same distance from the line, but rotate toward pole direction\r\n const desiredPerpendicular = Vector3.scale(poleDirection, perpLength, new Vector3());\r\n const newPosition = Vector3.add(projectionPoint, desiredPerpendicular, new Vector3());\r\n\r\n // Apply weight (blend between original and constrained position)\r\n if (weight < 0.999) {\r\n const blended = new Vector3();\r\n blended.x = currentPos.x + (newPosition.x - currentPos.x) * weight;\r\n blended.y = currentPos.y + (newPosition.y - currentPos.y) * weight;\r\n blended.z = currentPos.z + (newPosition.z - currentPos.z) * weight;\r\n currentJoint.position.set(blended);\r\n } else {\r\n currentJoint.position.set(newPosition);\r\n }\r\n }\r\n\r\n /**\r\n * Stretch the chain toward an unreachable target.\r\n * All joints are aligned in a straight line toward the target.\r\n *\r\n * @param target - Unreachable target position\r\n */\r\n private _stretchToward(target: Vector3): void {\r\n const joints = this._chain.joints;\r\n const rootPos = joints[0].originalPosition;\r\n\r\n // Calculate direction from root to target\r\n const direction = Vector3.sub(target, rootPos, new Vector3()).inplaceNormalize();\r\n\r\n // Place each joint along the direction at its bone length\r\n let currentPos = rootPos.clone();\r\n for (let i = 0; i < joints.length; i++) {\r\n joints[i].position.set(currentPos);\r\n if (i < joints.length - 1) {\r\n const offset = Vector3.scale(direction, joints[i].boneLength, new Vector3());\r\n currentPos.addBy(offset);\r\n }\r\n }\r\n }\r\n}\r\n"],"names":["FABRIKSolver","IKSolver","chain","maxIterations","tolerance","_poleVectors","Map","_twistConstraints","i","joints","length","isMiddleJoint","set","minTwist","Math","PI","maxTwist","smoothFactor","setTwistConstraint","jointIndex","_chain","Error","max","min","getTwistConstraint","get","removeTwistConstraint","delete","clearTwistConstraints","clear","setPoleVector","poleVector","weight","position","clone","removePoleVector","clearPoleVectors","getPoleVector","config","undefined","hasPoleVector","has","solve","target","updateFromNodes","storeOriginalPositions","rootPos","originalPosition","distToTarget","Vector3","distance","totalLength","_stretchToward","converged","iteration","_maxIterations","distToEnd","_tolerance","_forwardPass","_backwardPass","applyToNodes","joint","nextJoint","originalDir","sub","newDir","originalDirNorm","normalize","newDirNorm","deltaRotation","Quaternion","IKUtils","fromToRotation","worldRotation","multiply","originalRotation","swing","twist","decomposeSwingTwist","twistAngle","getTwistAngle","constraint","clampAndSmoothTwist","previousTwist","clampedTwist","createTwist","slerp","previousIKRotation","node","parent","parentWorldRotation","worldMatrix","decompose","parentInvRotation","conjugate","localRotation","rotation","childJoint","direction","magnitude","scaleBy","scale","boneLength","add","_applyConstraintsForJoint","constraints","name","apply","poleConfig","_applyPoleVectorTwist","parentJoint","currentJoint","parentPos","currentPos","childPos","parentToChild","lineLength","lineDir","parentToCurrent","projectionLength","dot","projectionPoint","perpendicular","perpLength","parentToPole","poleProjectionLength","poleProjectionPoint","poleDirection","poleDirLength","desiredPerpendicular","newPosition","blended","x","y","z","inplaceNormalize","offset","addBy"],"mappings":"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"}