(function (global, factory) { if (typeof define === "function" && define.amd) { define(["exports", "three"], factory); } else if (typeof exports !== "undefined") { factory(exports, require("three")); } else { var mod = { exports: {} }; factory(mod.exports, global.three); global.CCDIKSolver = mod.exports; } })(typeof globalThis !== "undefined" ? globalThis : typeof self !== "undefined" ? self : this, function (_exports, _three) { "use strict"; Object.defineProperty(_exports, "__esModule", { value: true }); _exports.CCDIKSolver = void 0; function _get() { if (typeof Reflect !== "undefined" && Reflect.get) { _get = Reflect.get; } else { _get = function _get(target, property, receiver) { var base = _superPropBase(target, property); if (!base) return; var desc = Object.getOwnPropertyDescriptor(base, property); if (desc.get) { return desc.get.call(arguments.length < 3 ? target : receiver); } return desc.value; }; } return _get.apply(this, arguments); } function _superPropBase(object, property) { while (!Object.prototype.hasOwnProperty.call(object, property)) { object = _getPrototypeOf(object); if (object === null) break; } return object; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } Object.defineProperty(subClass, "prototype", { value: Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }), writable: false }); if (superClass) _setPrototypeOf(subClass, superClass); } function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; } function _possibleConstructorReturn(self, call) { if (call && (typeof call === "object" || typeof call === "function")) { return call; } else if (call !== void 0) { throw new TypeError("Derived constructors may only return object or undefined"); } return _assertThisInitialized(self); } function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } } function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; } var _q = new _three.Quaternion(); var _targetPos = new _three.Vector3(); var _targetVec = new _three.Vector3(); var _effectorPos = new _three.Vector3(); var _effectorVec = new _three.Vector3(); var _linkPos = new _three.Vector3(); var _invLinkQ = new _three.Quaternion(); var _linkScale = new _three.Vector3(); var _axis = new _three.Vector3(); var _vector = new _three.Vector3(); var _matrix = new _three.Matrix4(); /** * CCD Algorithm * - https://sites.google.com/site/auraliusproject/ccd-algorithm * * // ik parameter example * // * // target, effector, index in links are bone index in skeleton.bones. * // the bones relation should be * // <-- parent child --> * // links[ n ], links[ n - 1 ], ..., links[ 0 ], effector * iks = [ { * target: 1, * effector: 2, * links: [ { index: 5, limitation: new Vector3( 1, 0, 0 ) }, { index: 4, enabled: false }, { index : 3 } ], * iteration: 10, * minAngle: 0.0, * maxAngle: 1.0, * } ]; */ var CCDIKSolver = /*#__PURE__*/function () { /** * @param {THREE.SkinnedMesh} mesh * @param {Array} iks */ function CCDIKSolver(mesh) { var iks = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : []; _classCallCheck(this, CCDIKSolver); this.mesh = mesh; this.iks = iks; this._valid(); } /** * Update all IK bones. * * @return {CCDIKSolver} */ _createClass(CCDIKSolver, [{ key: "update", value: function update() { var iks = this.iks; for (var i = 0, il = iks.length; i < il; i++) { this.updateOne(iks[i]); } return this; } /** * Update one IK bone * * @param {Object} ik parameter * @return {CCDIKSolver} */ }, { key: "updateOne", value: function updateOne(ik) { var bones = this.mesh.skeleton.bones; // for reference overhead reduction in loop var math = Math; var effector = bones[ik.effector]; var target = bones[ik.target]; // don't use getWorldPosition() here for the performance // because it calls updateMatrixWorld( true ) inside. _targetPos.setFromMatrixPosition(target.matrixWorld); var links = ik.links; var iteration = ik.iteration !== undefined ? ik.iteration : 1; for (var i = 0; i < iteration; i++) { var rotated = false; for (var j = 0, jl = links.length; j < jl; j++) { var link = bones[links[j].index]; // skip this link and following links. // this skip is used for MMD performance optimization. if (links[j].enabled === false) break; var limitation = links[j].limitation; var rotationMin = links[j].rotationMin; var rotationMax = links[j].rotationMax; // don't use getWorldPosition/Quaternion() here for the performance // because they call updateMatrixWorld( true ) inside. link.matrixWorld.decompose(_linkPos, _invLinkQ, _linkScale); _invLinkQ.invert(); _effectorPos.setFromMatrixPosition(effector.matrixWorld); // work in link world _effectorVec.subVectors(_effectorPos, _linkPos); _effectorVec.applyQuaternion(_invLinkQ); _effectorVec.normalize(); _targetVec.subVectors(_targetPos, _linkPos); _targetVec.applyQuaternion(_invLinkQ); _targetVec.normalize(); var angle = _targetVec.dot(_effectorVec); if (angle > 1.0) { angle = 1.0; } else if (angle < -1.0) { angle = -1.0; } angle = math.acos(angle); // skip if changing angle is too small to prevent vibration of bone // Refer to http://www20.atpages.jp/katwat/three.js_r58/examples/mytest37/mmd.three.js if (angle < 1e-5) continue; if (ik.minAngle !== undefined && angle < ik.minAngle) { angle = ik.minAngle; } if (ik.maxAngle !== undefined && angle > ik.maxAngle) { angle = ik.maxAngle; } _axis.crossVectors(_effectorVec, _targetVec); _axis.normalize(); _q.setFromAxisAngle(_axis, angle); link.quaternion.multiply(_q); // TODO: re-consider the limitation specification if (limitation !== undefined) { var c = link.quaternion.w; if (c > 1.0) c = 1.0; var c2 = math.sqrt(1 - c * c); link.quaternion.set(limitation.x * c2, limitation.y * c2, limitation.z * c2, c); } if (rotationMin !== undefined) { link.rotation.setFromVector3(link.rotation.toVector3(_vector).max(rotationMin)); } if (rotationMax !== undefined) { link.rotation.setFromVector3(link.rotation.toVector3(_vector).min(rotationMax)); } link.updateMatrixWorld(true); rotated = true; } if (!rotated) break; } return this; } /** * Creates Helper * * @return {CCDIKHelper} */ }, { key: "createHelper", value: function createHelper() { return new CCDIKHelper(this.mesh, this.mesh.geometry.userData.MMD.iks); } // private methods }, { key: "_valid", value: function _valid() { var iks = this.iks; var bones = this.mesh.skeleton.bones; for (var i = 0, il = iks.length; i < il; i++) { var ik = iks[i]; var effector = bones[ik.effector]; var links = ik.links; var link0 = void 0, link1 = void 0; link0 = effector; for (var 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; } } } }]); return CCDIKSolver; }(); _exports.CCDIKSolver = CCDIKSolver; function getPosition(bone, matrixWorldInv) { return _vector.setFromMatrixPosition(bone.matrixWorld).applyMatrix4(matrixWorldInv); } function setPositionOfBoneToAttributeArray(array, index, bone, matrixWorldInv) { var v = getPosition(bone, matrixWorldInv); array[index * 3 + 0] = v.x; array[index * 3 + 1] = v.y; array[index * 3 + 2] = v.z; } /** * Visualize IK bones * * @param {SkinnedMesh} mesh * @param {Array} iks */ var CCDIKHelper = /*#__PURE__*/function (_Object3D) { _inherits(CCDIKHelper, _Object3D); var _super = _createSuper(CCDIKHelper); function CCDIKHelper(mesh) { var _this; var iks = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : []; _classCallCheck(this, CCDIKHelper); _this = _super.call(this); _this.root = mesh; _this.iks = iks; _this.matrix.copy(mesh.matrixWorld); _this.matrixAutoUpdate = false; _this.sphereGeometry = new _three.SphereGeometry(0.25, 16, 8); _this.targetSphereMaterial = new _three.MeshBasicMaterial({ color: new _three.Color(0xff8888), depthTest: false, depthWrite: false, transparent: true }); _this.effectorSphereMaterial = new _three.MeshBasicMaterial({ color: new _three.Color(0x88ff88), depthTest: false, depthWrite: false, transparent: true }); _this.linkSphereMaterial = new _three.MeshBasicMaterial({ color: new _three.Color(0x8888ff), depthTest: false, depthWrite: false, transparent: true }); _this.lineMaterial = new _three.LineBasicMaterial({ color: new _three.Color(0xff0000), depthTest: false, depthWrite: false, transparent: true }); _this._init(); return _this; } /** * Updates IK bones visualization. */ _createClass(CCDIKHelper, [{ key: "updateMatrixWorld", value: function updateMatrixWorld(force) { var mesh = this.root; if (this.visible) { var offset = 0; var iks = this.iks; var bones = mesh.skeleton.bones; _matrix.copy(mesh.matrixWorld).invert(); for (var i = 0, il = iks.length; i < il; i++) { var ik = iks[i]; var targetBone = bones[ik.target]; var effectorBone = bones[ik.effector]; var targetMesh = this.children[offset++]; var effectorMesh = this.children[offset++]; targetMesh.position.copy(getPosition(targetBone, _matrix)); effectorMesh.position.copy(getPosition(effectorBone, _matrix)); for (var j = 0, jl = ik.links.length; j < jl; j++) { var link = ik.links[j]; var linkBone = bones[link.index]; var linkMesh = this.children[offset++]; linkMesh.position.copy(getPosition(linkBone, _matrix)); } var line = this.children[offset++]; var array = line.geometry.attributes.position.array; setPositionOfBoneToAttributeArray(array, 0, targetBone, _matrix); setPositionOfBoneToAttributeArray(array, 1, effectorBone, _matrix); for (var _j = 0, _jl = ik.links.length; _j < _jl; _j++) { var _link = ik.links[_j]; var _linkBone = bones[_link.index]; setPositionOfBoneToAttributeArray(array, _j + 2, _linkBone, _matrix); } line.geometry.attributes.position.needsUpdate = true; } } this.matrix.copy(mesh.matrixWorld); _get(_getPrototypeOf(CCDIKHelper.prototype), "updateMatrixWorld", this).call(this, force); } // private method }, { key: "_init", value: function _init() { var scope = this; var iks = this.iks; function createLineGeometry(ik) { var geometry = new _three.BufferGeometry(); var 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 (var i = 0, il = iks.length; i < il; i++) { var ik = iks[i]; this.add(createTargetMesh()); this.add(createEffectorMesh()); for (var j = 0, jl = ik.links.length; j < jl; j++) { this.add(createLinkMesh()); } this.add(createLine(ik)); } } }]); return CCDIKHelper; }(_three.Object3D); });