Skip to content

Commit

Permalink
feat: added face mesh when animation is triggered and eye blink
Browse files Browse the repository at this point in the history
  • Loading branch information
andrepat0 committed Oct 4, 2024
1 parent a3b2adc commit 76c9374
Show file tree
Hide file tree
Showing 12 changed files with 645 additions and 368 deletions.
197 changes: 197 additions & 0 deletions src/components/Avatar/AvatarView/AvatarComponent/avatarComponent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
import React, { useState, useEffect, useCallback } from 'react';
import AnimationControlPanel from './components/controls';
import FullbodyAvatar from './components/fullbodyAvatar';
import HalfBodyAvatar from './components/halfbodyAvatar';


interface Props {
showControls: boolean;
animation?: string;
loading: boolean;
url: string;
sex: 'MALE' | 'FEMALE';
eyeBlink: boolean;
headMovement: boolean;
speaking: boolean;
isZoomed: boolean;
}

interface BaseAction {
weight: number;
action?: string;
}

const baseActions: Record<string, BaseAction> = {
Gioia1: { weight: 0 },
Gioia2: { weight: 0 },
Gioia3: { weight: 0 },
Idle1: { weight: 1 },
Idle2: { weight: 0 },
Idle3: { weight: 0 },
Idle4: { weight: 0 },
Idle5: { weight: 0 },
Loading: { weight: 0 },
Rabbia1: { weight: 0 },
Rabbia2: { weight: 0 },
Rabbia3: { weight: 0 },
Sorpresa1: { weight: 0 },
Sorpresa2: { weight: 0 },
Sorpresa3: { weight: 0 },
Timore1: { weight: 0 },
Timore2: { weight: 0 },
Timore3: { weight: 0 },
Tristezza1: { weight: 0 },
Tristezza2: { weight: 0 },
Tristezza3: { weight: 0 },
};




export const AvatarView: React.FC<Props & { halfBody: boolean }> = ({
showControls,
animation,
loading,
url,
sex,
eyeBlink,
headMovement,
speaking,
halfBody,
isZoomed,
}) => {
const [currentBaseAction, setCurrentBaseAction] = useState({
action: animation || 'Idle1',
weight: 1,
});

const [morphTargetInfluences, setMorphTargetInfluences] = useState<{
[key: string]: number;
}>({});
const [morphTargetDictionary, setMorphTargetDictionary] = useState<{
[key: string]: number;
}>({});

const [timeScale, setTimeScale] = useState(0.8);



const onBaseActionChange = useCallback((action: string) => {

// set the morph target influences for the given emotions
if(action === 'Gioia1' || action === 'Gioia2' || action === 'Gioia3'){
setMorphTargetInfluences({
'eyesClosed': 0.5,
'mouthSmile': 1,
})
}else if(action === 'Rabbia1' || action === 'Rabbia2' || action === 'Rabbia3'){
setMorphTargetInfluences({
'eyesClosed': 1,
'mouthSmile': -0.5,
})
}else if(action === 'Sorpresa1' || action === 'Sorpresa2' || action === 'Sorpresa3'){
setMorphTargetInfluences({
'mouthSmile': 0.5,
'eyesClosed': -0.5,
})
} else if(action === 'Tristezza1' || action === 'Tristezza2' || action === 'Tristezza3'){
setMorphTargetInfluences({
'mouthSmile': -0.6,
'eyesClosed': 0.5,
})
} else if(action === 'Timore1' || action === 'Timore2' || action === 'Timore3'){
setMorphTargetInfluences({
'mouthSmile': -0.5,
'eyesClosed': 1,
})
} else {
setMorphTargetInfluences({
'mouthSmile': 0,
'eyesClosed': 0,
})
}
setCurrentBaseAction({
action,
weight: 1,
});
}, []);

const onMorphTargetInfluencesChange = useCallback(
(influences: { [key: string]: number }) => {
setMorphTargetInfluences(prevInfluences => ({
...prevInfluences,
...influences,
}));
},
[]
);

const onMorphTargetDictionaryChange = useCallback(
(dictionary: { [key: string]: number }) => {
setMorphTargetDictionary(dictionary);
},
[]
);

const modifyTimeScale = useCallback((value: number) => {
setTimeScale(value);
}, []);

useEffect(() => {
if(loading){
setMorphTargetInfluences({
'mouthSmile': 0,
'eyesClosed': 0,
})
setCurrentBaseAction({
action: 'Loading',
weight: 1,
})
}
}, [loading]);





return (
<>
{showControls && (
<AnimationControlPanel
timeScale={timeScale}
morphTargetDictionary={morphTargetDictionary}
onBaseActionChange={onBaseActionChange}
onMorphTargetInfluencesChange={onMorphTargetInfluencesChange}
onMorphTargetDictionaryChange={onMorphTargetDictionaryChange}
baseActions={baseActions}
currentBaseAction={currentBaseAction}
modifyTimeScale={modifyTimeScale}
/>
)}
{
halfBody ? (
<HalfBodyAvatar
url={url}
setMorphTargetInfluences={setMorphTargetInfluences}
headMovement={headMovement}
speaking={speaking}
/>
) : (
<FullbodyAvatar
url={url}
sex={sex}
eyeBlink={eyeBlink}
speaking={speaking}
currentBaseAction={currentBaseAction}
timeScale={timeScale}
setMorphTargetInfluences={setMorphTargetInfluences}
setMorphTargetDictionary={setMorphTargetDictionary}
morphTargetInfluences={morphTargetInfluences}
morphTargetDictionary={morphTargetDictionary}
isZoomed={isZoomed}
/>
)
}
</>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,25 @@ interface AdditiveAction {

export interface AnimationControlPanelProps {
baseActions: Record<string, BaseAction>;
additiveActions: Record<string, AdditiveAction>;
onBaseActionChange: (action: string) => void;
onAdditiveActionChange?: (action: string, weight: number) => void;
currentBaseAction: {
action: string;
weight: number;
};
onMorphTargetInfluencesChange: (influences: { [key: string]: number }) => void;
onMorphTargetDictionaryChange: (dictionary: { [key: string]: number }) => void;
morphTargetDictionary: { [key: string]: number };
modifyTimeScale: (value: number) => void;
timeScale: number;
}

const AnimationControlPanel: React.FC<AnimationControlPanelProps> = ({
onBaseActionChange,
onAdditiveActionChange,
baseActions,
additiveActions,
modifyTimeScale,
onMorphTargetInfluencesChange,
onMorphTargetDictionaryChange,
morphTargetDictionary,
timeScale,
}) => {
const guiRef = useRef<GUI | null>(null);
Expand Down Expand Up @@ -59,14 +61,13 @@ const AnimationControlPanel: React.FC<AnimationControlPanelProps> = ({
crossFadeControlsRef.current.push(control);
});

Object.entries(additiveActions).forEach(([name, settings]) => {
panelSettingsRef.current[name] = settings.weight;
Object.entries(morphTargetDictionary).forEach(([name, settings]) => {
panelSettingsRef.current[name] = settings/100;
folder2
.add(panelSettingsRef.current, name, 0.0, 1.0, 0.01)
.add(panelSettingsRef.current, name, -1.0, 1.0, 0.01)
.listen()
.onChange((weight: number) => {
settings.weight = weight;
onAdditiveActionChange?.(name, weight);
onMorphTargetInfluencesChange({ [name]: weight });
});
});

Expand All @@ -85,7 +86,12 @@ const AnimationControlPanel: React.FC<AnimationControlPanelProps> = ({
};
}, [
onBaseActionChange,
onAdditiveActionChange /*onTimeScaleChange, setWeight, prepareCrossFade, modifyTimeScale */,
onMorphTargetInfluencesChange,
onMorphTargetDictionaryChange,
modifyTimeScale,
baseActions,
morphTargetDictionary,
timeScale,
]);

return null; // This component doesn't render anything itself
Expand Down
Loading

0 comments on commit 76c9374

Please sign in to comment.