"use strict"; Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); const THREE = require("three"); const _q = /* @__PURE__ */ new THREE.Quaternion(); const _targetPos = /* @__PURE__ */ new THREE.Vector3(); const _targetVec = /* @__PURE__ */ new THREE.Vector3(); const _effectorPos = /* @__PURE__ */ new THREE.Vector3(); const _effectorVec = /* @__PURE__ */ new THREE.Vector3(); const _linkPos = /* @__PURE__ */ new THREE.Vector3(); const _invLinkQ = /* @__PURE__ */ new THREE.Quaternion(); const _linkScale = /* @__PURE__ */ new THREE.Vector3(); const _axis = /* @__PURE__ */ new THREE.Vector3(); const _vector = /* @__PURE__ */ new THREE.Vector3(); const _matrix = /* @__PURE__ */ new THREE.Matrix4(); class CCDIKSolver { /** * @param {THREE.SkinnedMesh} mesh * @param {Array} iks */ constructor(mesh, iks = []) { this.mesh = mesh; this.iks = iks; this._valid(); } /** * Update all IK bones. * * @return {CCDIKSolver} */ update() { const iks = this.iks; for (let i = 0, il = iks.length; i < il; i++) { this.updateOne(iks[i]); } return this; } /** * Update one IK bone * * @param {Object} ik parameter * @return {CCDIKSolver} */ updateOne(ik) { const bones = this.mesh.skeleton.bones; const math = Math; const effector = bones[ik.effector]; const target = bones[ik.target]; _targetPos.setFromMatrixPosition(target.matrixWorld); const links = ik.links; const iteration = ik.iteration !== void 0 ? ik.iteration : 1; for (let i = 0; i < iteration; i++) { let rotated = false; for (let j = 0, jl = links.length; j < jl; j++) { const link = bones[links[j].index]; if (links[j].enabled === false) break; const limitation = links[j].limitation; const rotationMin = links[j].rotationMin; const rotationMax = links[j].rotationMax; link.matrixWorld.decompose(_linkPos, _invLinkQ, _linkScale); _invLinkQ.invert(); _effectorPos.setFromMatrixPosition(effector.matrixWorld); _effectorVec.subVectors(_effectorPos, _linkPos); _effectorVec.applyQuaternion(_invLinkQ); _effectorVec.normalize(); _targetVec.subVectors(_targetPos, _linkPos); _targetVec.applyQuaternion(_invLinkQ); _targetVec.normalize(); let angle = _targetVec.dot(_effectorVec); if (angle > 1) { angle = 1; } else if (angle < -1) { angle = -1; } angle = math.acos(angle); if (angle < 1e-5) continue; if (ik.minAngle !== void 0 && angle < ik.minAngle) { angle = ik.minAngle; } if (ik.maxAngle !== void 0 && angle > ik.maxAngle) { angle = ik.maxAngle; } _axis.crossVectors(_effectorVec, _targetVec); _axis.normalize(); _q.setFromAxisAngle(_axis, angle); link.quaternion.multiply(_q); if (limitation !== void 0) { let c = link.quaternion.w; if (c > 1) c = 1; const c2 = math.sqrt(1 - c * c); link.quaternion.set(limitation.x * c2, limitation.y * c2, limitation.z * c2, c); } if (rotationMin !== void 0) { link.rotation.setFromVector3(_vector.setFromEuler(link.rotation).max(rotationMin)); } if (rotationMax !== void 0) { link.rotation.setFromVector3(_vector.setFromEuler(link.rotation).min(rotationMax)); } link.updateMatrixWorld(true); rotated = true; } if (!rotated) break; } return this; } /** * Creates Helper * * @return {CCDIKHelper} */ createHelper() { return new CCDIKHelper(this.mesh, this.iks); } // private methods _valid() { const iks = this.iks; const bones = this.mesh.skeleton.bones; for (let i = 0, il = iks.length; i < il; i++) { const ik = iks[i]; const effector = bones[ik.effector]; const links = ik.links; let link0, link1; link0 = effector; for (let j = 0, jl = links.length; j < jl; j++) { link1 = bones[links[j].index]; if (link0.parent !== link1) { console.warn("THREE.CCDIKSolver: bone " + link0.name + " is not the child of bone " + link1.name); } link0 = link1; } } } } function getPosition(bone, matrixWorldInv) { return _vector.setFromMatrixPosition(bone.matrixWorld).applyMatrix4(matrixWorldInv); } function setPositionOfBoneToAttributeArray(array, index, bone, matrixWorldInv) { const v = getPosition(bone, matrixWorldInv); array[index * 3 + 0] = v.x; array[index * 3 + 1] = v.y; array[index * 3 + 2] = v.z; } class CCDIKHelper extends THREE.Object3D { constructor(mesh, iks = [], sphereSize = 0.25) { super(); this.root = mesh; this.iks = iks; this.matrix.copy(mesh.matrixWorld); this.matrixAutoUpdate = false; this.sphereGeometry = new THREE.SphereGeometry(sphereSize, 16, 8); this.targetSphereMaterial = new THREE.MeshBasicMaterial({ color: new THREE.Color(16746632), depthTest: false, depthWrite: false, transparent: true }); this.effectorSphereMaterial = new THREE.MeshBasicMaterial({ color: new THREE.Color(8978312), depthTest: false, depthWrite: false, transparent: true }); this.linkSphereMaterial = new THREE.MeshBasicMaterial({ color: new THREE.Color(8947967), depthTest: false, depthWrite: false, transparent: true }); this.lineMaterial = new THREE.LineBasicMaterial({ color: new THREE.Color(16711680), depthTest: false, depthWrite: false, transparent: true }); this._init(); } /** * Updates IK bones visualization. */ updateMatrixWorld(force) { const mesh = this.root; if (this.visible) { let offset = 0; const iks = this.iks; const bones = mesh.skeleton.bones; _matrix.copy(mesh.matrixWorld).invert(); for (let i = 0, il = iks.length; i < il; i++) { const ik = iks[i]; const targetBone = bones[ik.target]; const effectorBone = bones[ik.effector]; const targetMesh = this.children[offset++]; const effectorMesh = this.children[offset++]; targetMesh.position.copy(getPosition(targetBone, _matrix)); effectorMesh.position.copy(getPosition(effectorBone, _matrix)); for (let j = 0, jl = ik.links.length; j < jl; j++) { const link = ik.links[j]; const linkBone = bones[link.index]; const linkMesh = this.children[offset++]; linkMesh.position.copy(getPosition(linkBone, _matrix)); } const line = this.children[offset++]; const array = line.geometry.attributes.position.array; setPositionOfBoneToAttributeArray(array, 0, targetBone, _matrix); setPositionOfBoneToAttributeArray(array, 1, effectorBone, _matrix); for (let j = 0, jl = ik.links.length; j < jl; j++) { const link = ik.links[j]; const linkBone = bones[link.index]; setPositionOfBoneToAttributeArray(array, j + 2, linkBone, _matrix); } line.geometry.attributes.position.needsUpdate = true; } } this.matrix.copy(mesh.matrixWorld); super.updateMatrixWorld(force); } /** * Frees the GPU-related resources allocated by this instance. Call this method whenever this instance is no longer used in your app. */ dispose() { this.sphereGeometry.dispose(); this.targetSphereMaterial.dispose(); this.effectorSphereMaterial.dispose(); this.linkSphereMaterial.dispose(); this.lineMaterial.dispose(); const children = this.children; for (let i = 0; i < children.length; i++) { const child = children[i]; if (child.isLine) child.geometry.dispose(); } } // private method _init() { const scope = this; const iks = this.iks; function createLineGeometry(ik) { const geometry = new THREE.BufferGeometry(); const vertices = new Float32Array((2 + ik.links.length) * 3); geometry.setAttribute("position", new THREE.BufferAttribute(vertices, 3)); return geometry; } function createTargetMesh() { return new THREE.Mesh(scope.sphereGeometry, scope.targetSphereMaterial); } function createEffectorMesh() { return new THREE.Mesh(scope.sphereGeometry, scope.effectorSphereMaterial); } function createLinkMesh() { return new THREE.Mesh(scope.sphereGeometry, scope.linkSphereMaterial); } function createLine(ik) { return new THREE.Line(createLineGeometry(ik), scope.lineMaterial); } for (let i = 0, il = iks.length; i < il; i++) { const ik = iks[i]; this.add(createTargetMesh()); this.add(createEffectorMesh()); for (let j = 0, jl = ik.links.length; j < jl; j++) { this.add(createLinkMesh()); } this.add(createLine(ik)); } } } exports.CCDIKHelper = CCDIKHelper; exports.CCDIKSolver = CCDIKSolver; //# sourceMappingURL=CCDIKSolver.cjs.map