Animate multiple meshes with shape keys (morph targets) individually

I am able to re-use the mesh multiple times in the scene, however the animation is shared between all of them. For now I want the animation to play only on the mesh I clicked on. I have done something similar in the past with skinnedMeshes using SkeletonUtils but I could not find a simple way to do it when the animation consists of shape keys (morph targets).

export default function Letter2(props) {
    const group = useRef()
    const { nodes, materials, animations } = useGLTF('./Letter/letter3-open.glb')
    const { actions } = useAnimations(animations, group)
    const normalMaterial = new THREE.MeshNormalMaterial({ side: THREE.DoubleSide });
    const eventHandler = (event) => {
        const action = actions.KeyAction
        action.play()
    }
    return (
        <group ref={group} {...props} dispose={null}>
            <group name="Scene">
                <mesh
                    name="Plane001"
                    castShadow
                    receiveShadow
                    geometry={nodes.Plane001.geometry}
                    material={normalMaterial}
                    morphTargetDictionary={nodes.Plane001.morphTargetDictionary}
                    morphTargetInfluences={nodes.Plane001.morphTargetInfluences}
                    onClick={eventHandler}
                />
            </group>
        </group>
    )
}

useGLTF.preload('/letter3-open.glb')

Does this help?

This solution only works for me if I remove the animations:

 const group = useRef()
    const {scene} = useGLTF('./Letter/letter3-open.glb')

    //const {animations} = useAnimations(scene, group)

    const clone = useMemo(() => scene.clone(), [scene])
    const { nodes } = useGraph(clone)
    
    //const { actions } = useAnimations(animations, group)
    const normalMaterial = new THREE.MeshNormalMaterial({ side: THREE.DoubleSide });

    const eventHandler = (event) => {
        //console.log(event)
        //const action = actions.KeyAction
        //action.play()
    }

Otherwise I get this error but maybe I am doing something wrong:

Uncaught TypeError: clips.forEach is not a function
    api useAnimations.js:19
    mountMemo react-reconciler.development.js:8279
    useMemo react-reconciler.development.js:8739
    useMemo React
    useAnimations useAnimations.js:17
    Letter2 Letter2.js:12
    renderWithHooks react-reconciler.development.js:7363
    mountIndeterminateComponent react-reconciler.development.js:12327
    beginWork react-reconciler.development.js:13831
    beginWork$1 react-reconciler.development.js:19513
    performUnitOfWork react-reconciler.development.js:18686
    workLoopSync react-reconciler.development.js:18597
    renderRootSync react-reconciler.development.js:18565
    recoverFromConcurrentError react-reconciler.development.js:17948
    performConcurrentWorkOnRoot react-reconciler.development.js:17848
    workLoop scheduler.development.js:266
    flushWork scheduler.development.js:239
    performWorkUntilDeadline scheduler.development.js:533

I also tried to take the “animations” from “useGraph(clone)” with similar results

Can you provide it as a sandbox? I can check if i get it running then

https://codesandbox.io/p/sandbox/shape-keys-animation-qx6lzv?file=%2Fsrc%2FLetter2.js

I also saved the animations in a memorized variable, now it works:

https://codesandbox.io/p/sandbox/shape-keys-animation-forked-rvkqk7

Thank you! This will save me a lot of time with the animations.

1 Like