UNPKG

kalidokit

Version:

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

97 lines (96 loc) 3.1 kB
import Vector from "../utils/vector"; import Euler from "../utils/euler"; import { clamp } from "../utils/helpers"; import { RIGHT, LEFT } from "./../constants"; import { PI } from "./../constants"; export const offsets = { upperLeg: { z: 0.1, }, }; /** * Calculates leg rotation angles * @param {Results} lm : array of 3D pose vectors from tfjs or mediapipe */ export const calcLegs = (lm) => { const rightUpperLegSphericalCoords = Vector.getSphericalCoords(lm[23], lm[25], { x: "y", y: "z", z: "x" }); const leftUpperLegSphericalCoords = Vector.getSphericalCoords(lm[24], lm[26], { x: "y", y: "z", z: "x" }); const rightLowerLegSphericalCoords = Vector.getRelativeSphericalCoords(lm[23], lm[25], lm[27], { x: "y", y: "z", z: "x", }); const leftLowerLegSphericalCoords = Vector.getRelativeSphericalCoords(lm[24], lm[26], lm[28], { x: "y", y: "z", z: "x", }); const hipRotation = Vector.findRotation(lm[23], lm[24]); const UpperLeg = { r: new Vector({ x: rightUpperLegSphericalCoords.theta, y: rightLowerLegSphericalCoords.phi, z: rightUpperLegSphericalCoords.phi - hipRotation.z, }), l: new Vector({ x: leftUpperLegSphericalCoords.theta, y: leftLowerLegSphericalCoords.phi, z: leftUpperLegSphericalCoords.phi - hipRotation.z, }), }; const LowerLeg = { r: new Vector({ x: -Math.abs(rightLowerLegSphericalCoords.theta), y: 0, z: 0, // not relevant }), l: new Vector({ x: -Math.abs(leftLowerLegSphericalCoords.theta), y: 0, z: 0, // not relevant }), }; //Modify Rotations slightly for more natural movement const rightLegRig = rigLeg(UpperLeg.r, LowerLeg.r, RIGHT); const leftLegRig = rigLeg(UpperLeg.l, LowerLeg.l, LEFT); return { //Scaled UpperLeg: { r: rightLegRig.UpperLeg, l: leftLegRig.UpperLeg, }, LowerLeg: { r: rightLegRig.LowerLeg, l: leftLegRig.LowerLeg, }, //Unscaled Unscaled: { UpperLeg, LowerLeg, }, }; }; /** * Converts normalized rotation values into radians clamped by human limits * @param {Object} UpperLeg : normalized rotation values * @param {Object} LowerLeg : normalized rotation values * @param {Side} side : left or right */ export const rigLeg = (UpperLeg, LowerLeg, side = RIGHT) => { const invert = side === RIGHT ? 1 : -1; const rigedUpperLeg = new Euler({ x: clamp(UpperLeg.x, 0, 0.5) * PI, y: clamp(UpperLeg.y, -0.25, 0.25) * PI, z: clamp(UpperLeg.z, -0.5, 0.5) * PI + invert * offsets.upperLeg.z, rotationOrder: "XYZ", }); const rigedLowerLeg = new Euler({ x: LowerLeg.x * PI, y: LowerLeg.y * PI, z: LowerLeg.z * PI, }); return { UpperLeg: rigedUpperLeg, LowerLeg: rigedLowerLeg, }; };