From 883bf3d2ad319128797bb79a4699954421ed3914 Mon Sep 17 00:00:00 2001 From: Antoine BERNIER Date: Wed, 10 May 2023 13:43:48 +0200 Subject: [PATCH] feat: origin landmark prop --- .storybook/stories/Facemesh.stories.tsx | 7 ++++-- README.md | 4 +++- src/core/Facemesh.tsx | 29 ++++++++++++++++--------- 3 files changed, 27 insertions(+), 13 deletions(-) diff --git a/.storybook/stories/Facemesh.stories.tsx b/.storybook/stories/Facemesh.stories.tsx index da1b5b360..48cc42cb6 100644 --- a/.storybook/stories/Facemesh.stories.tsx +++ b/.storybook/stories/Facemesh.stories.tsx @@ -6,6 +6,7 @@ import { Vector3 } from 'three' import { Setup } from '../Setup' import { Facemesh } from '../../src' +import { center } from 'maath/dist/declarations/src/buffer' export default { title: 'Shapes/Facemesh', @@ -20,18 +21,19 @@ export default { ], } -export const FacemeshSt = ({ depth, wireframe, flat, skin, debug }) => ( +export const FacemeshSt = ({ depth, origin, wireframe, flat, skin, debug }) => ( <> - + ) FacemeshSt.args = { depth: undefined, + origin: undefined, wireframe: false, flat: true, skin: '#cbcbcb', @@ -40,6 +42,7 @@ FacemeshSt.args = { FacemeshSt.argTypes = { depth: { control: { type: 'range', min: 0, max: 6.5, step: 0.01 } }, + origin: { control: 'select', options: [undefined, 168, 9] }, wireframe: { control: { type: 'boolean' } }, flat: { control: { type: 'boolean' } }, skin: { control: { type: 'color' } }, diff --git a/README.md b/README.md index a2758bced..287042c05 100644 --- a/README.md +++ b/README.md @@ -969,7 +969,9 @@ type FacemeshProps = { depth?: number /** a landmarks tri supposed to be vertical, default: [159, 386, 200] (see: https://github.com/tensorflow/tfjs-models/tree/master/face-landmarks-detection#mediapipe-facemesh-keypoints) */ verticalTri?: [number, number, number] - /** Displays bounding-box and sight-direction, default false */ + /** a landmark index to be the origin of the mesh. default: undefined (ie. the bbox center) */ + origin?: number + /** debug mode, default: false */ debug?: boolean } ``` diff --git a/src/core/Facemesh.tsx b/src/core/Facemesh.tsx index 0abb6d538..327bcf1aa 100644 --- a/src/core/Facemesh.tsx +++ b/src/core/Facemesh.tsx @@ -2,7 +2,7 @@ import * as React from 'react' import * as THREE from 'three' import { useThree } from '@react-three/fiber' -import { Line } from '../../src/core' +import { Line } from '../core' export type MediaPipeFaceMesh = typeof FacemeshDatas.SAMPLE_FACE @@ -17,7 +17,9 @@ export type FacemeshProps = { depth?: number /** a landmarks tri supposed to be vertical, default: [159, 386, 200] (see: https://github.com/tensorflow/tfjs-models/tree/master/face-landmarks-detection#mediapipe-facemesh-keypoints) */ verticalTri?: [number, number, number] - /** debug mode, default false */ + /** a landmark index to be the origin of the mesh. default: undefined (ie. the bbox center) */ + origin?: number + /** debug mode, default: false */ debug?: boolean } & JSX.IntrinsicElements['group'] @@ -27,7 +29,6 @@ export type FacemeshApi = { } const defaultLookAt = new THREE.Vector3(0, 0, -1) -const origin = new THREE.Vector3(0, 0, 0) export const Facemesh = React.forwardRef( ( @@ -37,6 +38,7 @@ export const Facemesh = React.forwardRef( height, depth, verticalTri = [159, 386, 200], + origin, debug = false, children, ...props @@ -87,21 +89,27 @@ export const Facemesh = React.forwardRef( // B. geometry (straightened) // - // center (before rotate back) + // 1. center (before rotate back) geometry.computeBoundingBox() if (debug) invalidate() // invalidate to force re-render for box3Helper (after .computeBoundingBox()) geometry.center() - // rotate back + rotate outerRef + // 2. rotate back + rotate outerRef (once 1.) geometry.applyQuaternion(sightDirQuaternionInverse) outerRef.current?.setRotationFromQuaternion(sightDirQuaternion) - // re-scale + // 3. origin: substract the geometry to that landmark coords (once 1.) + if (origin) { + const position = geometry.getAttribute('position') as THREE.BufferAttribute + geometry.translate(-position.getX(origin), -position.getY(origin), -position.getZ(origin)) + } + + // 4. re-scale geometry.boundingBox?.getSize(bboxSize) let scale = 1 - if (width) scale = (width * 1) / bboxSize.x // fit in width - if (height) scale = (height * 1) / bboxSize.y // fit in height - if (depth) scale = (depth * 1) / bboxSize.z // fit in depth + if (width) scale = width / bboxSize.x // fit in width + if (height) scale = height / bboxSize.y // fit in height + if (depth) scale = depth / bboxSize.z // fit in depth if (scale !== 1) geometry.scale(scale, scale, scale) geometry.computeVertexNormals() @@ -112,6 +120,7 @@ export const Facemesh = React.forwardRef( height, depth, verticalTri, + origin, debug, invalidate, sightDir, @@ -148,7 +157,7 @@ export const Facemesh = React.forwardRef( {meshRef.current?.geometry?.boundingBox && ( )} - + ) : null}