如何在React Three Fiber场景中导入带预加载动画的自定义模型?
导入带预加载动画的自定义模型到React Three Fiber场景
问题背景
已成功导出带基础动画的立方体,但已知GLTFExporter无法导出包含材质动画的内容,现需将带有预加载动画的自定义GLTF/GLB模型导入到现有React Three Fiber场景中。
解决方案步骤
1. 使用@react-three/drei的useGLTF加载模型
@react-three/drei提供了便捷的模型加载工具,能自动处理GLTF/GLB模型的材质、网格和动画数据。若未安装依赖,先执行:
npm install @react-three/drei
2. 加载并播放模型动画
替换原有的Model组件,改为加载自定义模型,并利用AnimationMixer播放预加载的动画:
import React, { useRef, useEffect, useState } from 'react'; import { Canvas, useFrame, useThree } from '@react-three/fiber'; import { OrbitControls, useGLTF } from '@react-three/drei'; import * as THREE from 'three'; import { GLTFExporter } from 'three/examples/jsm/exporters/GLTFExporter'; import './App.css'; function CustomModel() { const meshRef = useRef(); // 替换为你的GLTF/GLB模型路径 const { scene, animations } = useGLTF('/your-custom-model.glb'); const { scene: rootScene } = useThree(); const [mixer] = useState(() => new THREE.AnimationMixer()); const clock = new THREE.Clock(); const [exported, setExported] = useState(false); useEffect(() => { if (scene && animations.length > 0) { // 获取模型主网格(根据你的模型结构调整,若模型有层级需遍历找到目标网格) const modelMesh = scene.children[0]; meshRef.current = modelMesh; modelMesh.name = 'customAnimatedModel'; // 播放预加载的第一个动画剪辑 const action = mixer.clipAction(animations[0], modelMesh); action.play(); // 动画完成后触发导出(可选) setTimeout(() => { if (!exported) { handleExport(rootScene, animations[0]); setExported(true); } }, animations[0].duration * 1000); } }, [mixer, exported, rootScene, scene, animations]); useFrame(() => { const delta = clock.getDelta(); mixer.update(delta); }); const handleExport = (scene, clip) => { const gltfExporter = new GLTFExporter(); const options = { binary: true, animations: [clip], }; gltfExporter.parse(scene, function (result) { if (result instanceof ArrayBuffer) { saveArrayBuffer(result, 'exported-model.glb'); } else { const output = JSON.stringify(result, null, 2); console.log(output); saveString(output, 'exported-model.gltf'); } }, function (error){ console.log("导出出错"); console.log(error); }, options); const link = document.createElement('a'); link.style.display = 'none'; document.body.appendChild(link); function save(blob, filename) { link.href = URL.createObjectURL(blob); link.download = filename; link.click(); } function saveString(text, filename) { save(new Blob([text], { type: 'text/plain' }), filename); } function saveArrayBuffer(buffer, filename) { save(new Blob([buffer], { type: 'application/octet-stream' }), filename); } }; return <primitive object={scene} ref={meshRef} />; } // 预加载模型,优化加载体验 useGLTF.preload('/your-custom-model.glb'); export default function App() { return ( <> <Canvas camera={{ position: [-8, 5, 8] }}> <ambientLight intensity={0.5} /> <CustomModel /> <OrbitControls /> </Canvas> </> ); }
3. 关键注意事项
- 确保自定义模型为标准GLTF 2.0/GLB格式,预加载动画需符合GLTF规范(支持位置、旋转、缩放动画;材质动画目前GLTFExporter导出受限,但导入播放不受影响)。
- 模型路径需正确:本地文件放在
public目录下,远程资源直接填写完整URL。 - 若模型包含多个动画剪辑,可通过
animations数组索引切换播放目标,或添加交互逻辑实现动画切换。
内容的提问来源于stack exchange,提问作者Marc Newsom
相关产品推荐
相关产品推荐

