UNPKG

kalidokit

Version:

Blendshape and kinematics calculator for Mediapipe/Tensorflow.js Face, Eyes, Pose, and Finger tracking models.

85 lines (84 loc) 3.14 kB
import Vector from "../utils/vector"; import { clamp } from "../utils/helpers"; import { RIGHT, LEFT } from "./../constants"; import { PI } from "./../constants"; /** * Calculates arm rotation as euler angles * @param {Array} lm : array of 3D pose vectors from tfjs or mediapipe */ export const calcArms = (lm) => { //Pure Rotation Calculations const UpperArm = { r: Vector.findRotation(lm[11], lm[13]), l: Vector.findRotation(lm[12], lm[14]), }; UpperArm.r.y = Vector.angleBetween3DCoords(lm[12], lm[11], lm[13]); UpperArm.l.y = Vector.angleBetween3DCoords(lm[11], lm[12], lm[14]); const LowerArm = { r: Vector.findRotation(lm[13], lm[15]), l: Vector.findRotation(lm[14], lm[16]), }; LowerArm.r.y = Vector.angleBetween3DCoords(lm[11], lm[13], lm[15]); LowerArm.l.y = Vector.angleBetween3DCoords(lm[12], lm[14], lm[16]); LowerArm.r.z = clamp(LowerArm.r.z, -2.14, 0); LowerArm.l.z = clamp(LowerArm.l.z, -2.14, 0); const Hand = { r: Vector.findRotation(Vector.fromArray(lm[15]), Vector.lerp(Vector.fromArray(lm[17]), Vector.fromArray(lm[19]), 0.5)), l: Vector.findRotation(Vector.fromArray(lm[16]), Vector.lerp(Vector.fromArray(lm[18]), Vector.fromArray(lm[20]), 0.5)), }; //Modify Rotations slightly for more natural movement const rightArmRig = rigArm(UpperArm.r, LowerArm.r, Hand.r, RIGHT); const leftArmRig = rigArm(UpperArm.l, LowerArm.l, Hand.l, LEFT); return { //Scaled UpperArm: { r: rightArmRig.UpperArm, l: leftArmRig.UpperArm, }, LowerArm: { r: rightArmRig.LowerArm, l: leftArmRig.LowerArm, }, Hand: { r: rightArmRig.Hand, l: leftArmRig.Hand, }, //Unscaled Unscaled: { UpperArm: UpperArm, LowerArm: LowerArm, Hand: Hand, }, }; }; /** * Converts normalized rotation values into radians clamped by human limits * @param {Object} UpperArm : normalized rotation values * @param {Object} LowerArm : normalized rotation values * @param {Object} Hand : normalized rotation values * @param {Side} side : left or right */ export const rigArm = (UpperArm, LowerArm, Hand, side = RIGHT) => { // Invert modifier based on left vs right side const invert = side === RIGHT ? 1 : -1; UpperArm.z *= -2.3 * invert; //Modify UpperArm rotationY by LowerArm X and Z rotations UpperArm.y *= PI * invert; UpperArm.y -= Math.max(LowerArm.x); UpperArm.y -= -invert * Math.max(LowerArm.z, 0); UpperArm.x -= 0.3 * invert; LowerArm.z *= -2.14 * invert; LowerArm.y *= 2.14 * invert; LowerArm.x *= 2.14 * invert; //Clamp values to human limits UpperArm.x = clamp(UpperArm.x, -0.5, PI); LowerArm.x = clamp(LowerArm.x, -0.3, 0.3); Hand.y = clamp(Hand.z * 2, -0.6, 0.6); //side to side Hand.z = Hand.z * -2.3 * invert; //up down return { //Returns Values in Radians for direct 3D usage UpperArm: UpperArm, LowerArm: LowerArm, Hand: Hand, }; };