You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js中react-three/drei的useFBX无法读取FBX动画文件求助

解决Next.js中useFBX加载Mixamo动画返回undefined的问题

问题核心

你错误解构了useFBX的返回值——useFBX直接返回加载后的FBX Object3D对象,而非包含animation属性的结构,这是typingAnimation为undefined的直接原因。

修复步骤

  1. 修正useFBX的使用逻辑
    useFBX加载完成后,动画数据存储在返回对象的animations数组中(Mixamo下载的FBX通常仅包含一个动画,取索引0即可)。修改代码如下:
// 错误写法
// const {animation:typingAnimation} = useFBX("/animations/TypingAgain.fbx")

// 正确写法
const fbxAsset = useFBX("/animations/TypingAgain.fbx");
const typingAnimation = fbxAsset.animations[0];
  1. 添加FBX资源预加载
    和useGLTF一样,useFBX需要预加载资源确保组件渲染时资源就绪,在组件外部添加预加载代码:
useFBX.preload("/animations/TypingAgain.fbx");
  1. 验证文件路径一致性
    检查/public/animations目录下是否存在TypingAgain.fbx文件,确保代码中使用的文件名与实际文件完全匹配(注意大小写、拼写)。

修改后的完整代码示例

import React, { useEffect, useRef } from "react";
import { useFBX, useGLTF } from "@react-three/drei";

export function Avatar(props) {
  const { nodes, materials } = useGLTF("/images/3d/avatar.glb");

  // 修正FBX加载逻辑
  const fbxAsset = useFBX("/animations/TypingAgain.fbx");
  const typingAnimation = fbxAsset.animations[0];

  useEffect(()=>{
    // 加载完成后再执行动画相关逻辑
    if(typingAnimation) {
      console.log(typingAnimation);
      // 后续可通过AnimationMixer绑定并播放动画
    }
  }, [typingAnimation])

  return (
    <group {...props} dispose={null}>
      <primitive object={nodes.Hips} />
      <skinnedMesh
        name="EyeLeft"
        geometry={nodes.EyeLeft.geometry}
        material={materials.Wolf3D_Eye}
        skeleton={nodes.EyeLeft.skeleton}
        morphTargetDictionary={nodes.EyeLeft.morphTargetDictionary}
        morphTargetInfluences={nodes.EyeLeft.morphTargetInfluences}
      />
      <skinnedMesh
        name="EyeRight"
        geometry={nodes.EyeRight.geometry}
        material={materials.Wolf3D_Eye}
        skeleton={nodes.EyeRight.skeleton}
        morphTargetDictionary={nodes.EyeRight.morphTargetDictionary}
        morphTargetInfluences={nodes.EyeRight.morphTargetInfluences}
      />
      <skinnedMesh
        name="Wolf3D_Head"
        geometry={nodes.Wolf3D_Head.geometry}
        material={materials.Wolf3D_Skin}
        skeleton={nodes.Wolf3D_Head.skeleton}
        morphTargetDictionary={nodes.Wolf3D_Head.morphTargetDictionary}
        morphTargetInfluences={nodes.Wolf3D_Head.morphTargetInfluences}
      />
      <skinnedMesh
        name="Wolf3D_Teeth"
        geometry={nodes.Wolf3D_Teeth.geometry}
        material={materials.Wolf3D_Teeth}
        skeleton={nodes.Wolf3D_Teeth.skeleton}
        morphTargetDictionary={nodes.Wolf3D_Teeth.morphTargetDictionary}
        morphTargetInfluences={nodes.Wolf3D_Teeth.morphTargetInfluences}
      />
      <skinnedMesh
        geometry={nodes.Wolf3D_Hair.geometry}
        material={materials.Wolf3D_Hair}
        skeleton={nodes.Wolf3D_Hair.skeleton}
      />
      <skinnedMesh
        geometry={nodes.Wolf3D_Glasses.geometry}
        material={materials.Wolf3D_Glasses}
        skeleton={nodes.Wolf3D_Glasses.skeleton}
      />
      <skinnedMesh
        name="Wolf3D_Outfit_Top"
        geometry={nodes.Wolf3D_Outfit_Top.geometry}
        material={materials.Wolf3D_Outfit_Top}
        skeleton={nodes.Wolf3D_Outfit_Top.skeleton}
        morphTargetDictionary={nodes.Wolf3D_Outfit_Top.morphTargetDictionary}
        morphTargetInfluences={nodes.Wolf3D_Outfit_Top.morphTargetInfluences}
      />
      <skinnedMesh
        name="Wolf3D_Outfit_Bottom"
        geometry={nodes.Wolf3D_Outfit_Bottom.geometry}
        material={materials.Wolf3D_Outfit_Bottom}
        skeleton={nodes.Wolf3D_Outfit_Bottom.skeleton}
        morphTargetDictionary={nodes.Wolf3D_Outfit_Bottom.morphTargetDictionary}
        morphTargetInfluences={nodes.Wolf3D_Outfit_Bottom.morphTargetInfluences}
      />
      <skinnedMesh
        name="Wolf3D_Outfit_Footwear"
        geometry={nodes.Wolf3D_Outfit_Footwear.geometry}
        material={materials.Wolf3D_Outfit_Footwear}
        skeleton={nodes.Wolf3D_Outfit_Footwear.skeleton}
        morphTargetDictionary={
          nodes.Wolf3D_Outfit_Footwear.morphTargetDictionary
        }
        morphTargetInfluences={
          nodes.Wolf3D_Outfit_Footwear.morphTargetInfluences
        }
      />
      <skinnedMesh
        name="Wolf3D_Body"
        geometry={nodes.Wolf3D_Body.geometry}
        material={materials.Wolf3D_Body}
        skeleton={nodes.Wolf3D_Body.skeleton}
        morphTargetDictionary={nodes.Wolf3D_Body.morphTargetDictionary}
        morphTargetInfluences={nodes.Wolf3D_Body.morphTargetInfluences}
      />
    </group>
  );
}

useGLTF.preload("/images/3d/avatar.glb");
useFBX.preload("/animations/TypingAgain.fbx"); // 添加FBX预加载

额外提示

  • 动画加载是异步过程,useEffect中需先判断typingAnimation是否存在再执行后续逻辑。
  • 后续播放动画需使用AnimationMixer,可通过useAnimations钩子或手动创建Mixer绑定到Avatar骨骼上。

内容的提问来源于stack exchange,提问作者Petrando Richard

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 12:44:52