UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

105 lines (76 loc) 3.27 kB
import Quaternion from "../../../core/geom/Quaternion.js"; import { v3_compute_interior_angle } from "../../../core/geom/vec3/v3_compute_interior_angle.js"; import Vector3 from "../../../core/geom/Vector3.js"; import { clamp } from "../../../core/math/clamp.js"; const d = new Vector3(); const delta_ca = new Vector3(); const delta_ta = new Vector3(); const axis0 = new Vector3(); const axis1 = new Vector3(); const inv_a_gr = new Quaternion(); const inv_b_gr = new Quaternion(); const r0 = new Quaternion(); const r1 = new Quaternion(); const r2 = new Quaternion(); const axis0_la = new Vector3(); const axis0_lb = new Vector3(); const axis1_la = new Vector3(); // TODO: investigate https://github.com/guillaumeblanc/ozz-animation/blob/master/src/animation/runtime/ik_two_bone_job.cc /** * Based on http://theorangeduck.com/page/simple-two-joint * @param {Vector3} a Root bone position * @param {Vector3} b Second bone position * @param {Vector3} c Effector position * @param {Vector3} t Target position * @param {number} eps EPSILON value, small value for rounding error compensation * @param {Quaternion} a_gr Global rotation of root bone * @param {Quaternion} b_gr Global rotation of second bone * @param {Quaternion} a_lr local rotation for root bone, this will be updated as a result * @param {Quaternion} b_lr local rotation for second bone, this will be updated as a result */ export function two_joint_ik( a, b, c, t, eps, a_gr, b_gr, a_lr, b_lr ) { //Compute lengths of bones const lab = b.distanceTo(a); const lcb = b.distanceTo(c); const maximum_extension = lab + lcb - eps; //clamp length to the target to maximum extension of the joint const lat = clamp(t.distanceTo(a), eps, maximum_extension); //compute current interior angles const ac_ab_0 = v3_compute_interior_angle(c, a, b); const ba_bc_0 = v3_compute_interior_angle(a, b, c); const ac_at_0 = v3_compute_interior_angle(c, a, t); // Using the cosine rule to compute desired interior angles const length_at_sqr = lat * lat; const length_cb_sqr = lcb * lcb; const length_ab_sqr = lab * lab; const ac_ab_1 = Math.acos(clamp((length_cb_sqr - length_ab_sqr - length_at_sqr) / (-2 * lab * lat), -1, 1)); const ba_bc_1 = Math.acos(clamp((length_at_sqr - length_ab_sqr - length_cb_sqr) / (-2 * lab * lcb), -1, 1)); d.copy(Vector3.back); d.applyQuaternion(b_gr); delta_ca.subVectors(c, a); delta_ta.subVectors(t, a); axis0.crossVectors(delta_ca, d); axis0.normalize(); axis1.crossVectors(delta_ca, delta_ta); axis1.normalize(); inv_a_gr.copyInverse(a_gr); inv_b_gr.copyInverse(b_gr); axis0_la.copy(axis0); axis0_la.applyQuaternion(inv_a_gr); const angle0 = ac_ab_1 - ac_ab_0; r0.fromAxisAngle(axis0_la, angle0); const angle1 = ba_bc_1 - ba_bc_0; axis0_lb.copy(axis0); axis0_lb.applyQuaternion(inv_b_gr); r1.fromAxisAngle(axis0_lb, angle1); axis1_la.copy(axis1); axis1_la.applyQuaternion(inv_a_gr); r2.fromAxisAngle(axis1_la, ac_at_0); r0.multiply(r2); a_lr.multiply(r0); b_lr.multiply(r1); }