Hi I am trying to build a demo, where I can load multiple clones of the same animated model into react three fiber on demand:
Only the last added Model is animated! Why?
import React, { useRef, useEffect } from 'react';
import { useFrame } from '@react-three/fiber';
import { Clone, useGLTF } from '@react-three/drei';
import { AnimationMixer } from 'three';
const DynamicModel = React.memo(({ url, position }) => {
const { scene, animations } = useGLTF(url);
const mixer = useRef(new AnimationMixer(scene)).current;
useEffect(() => {
if (animations.length > 0) {
const action = mixer.clipAction(animations[0]);
action.play();
}
return () => action?.stop();
}, [animations, mixer]);
useFrame((_, delta) => {
mixer.update(delta);
});
return <Clone object={scene} position={position} />;
});
export default DynamicModel;
Now a manager for the Modesl to add:
import React, { useState, useCallback, useEffect } from "react";
import { Canvas } from "@react-three/fiber";
import DynamicModel from "./DynamicModel";
//import { uuid } from "uuidv4";
function ModelAdder() {
const [models, setModels] = useState([]);
console.log("render ModelAdder");
const handleKeyDown = useCallback((event) => {
if (event.key === "Enter") {
setModels((models) => [
...models,
{
id: Math.random(),
url: "/models/AnimatedModel.glb",
position: [Math.random() * 5, 0, Math.random() * 5],
},
]);
}
}, []);
useEffect(() => {
window.addEventListener("keydown", handleKeyDown);
return () => window.removeEventListener("keydown", handleKeyDown);
}, [handleKeyDown]);
return (
<group>
{models.map((model) => (
<DynamicModel
key={model.id}
url={model.url}
position={model.position}
/>
))}
</group>
);
}
export default ModelAdder;
Then I use in my Canvas. Everytime I hit Enter it adds a new Model (cloned) - but the animation is not played! How can I force it to play the animation? And also is there a way that when I add more models (Enter key in this example) that not the whole models.map is rerendered?