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

如何监听glTF动画驱动的网格模型的旋转和位置属性变化?

问题原因&解决方案

你遇到的属性不更新问题核心是两个常见的使用错误,按优先级排查修改即可:

核心问题1:你手动新建了Mesh,没有复用GLTF导出的原节点对象

你当前代码里是自行创建了一个新的<mesh>节点,仅复用了nodes.topR的几何和材质,而GLTF自带的关键帧动画是绑定在导入时生成的nodes.topR原对象上的,你新创建的这个Mesh根本不在动画系统的控制范围内,所以它的position、rotation属性自然不会随动画更新。
你看到的模型移动大概率是你代码中未写全的其他原模型节点在动,不是你绑定了topR ref的这个新建Mesh。

修复方案

直接用primitive渲染原nodes.topR对象,不要手动新建Mesh:

return (
  <group
    layers={2}
    scale={[8, 8, 8]}
    ref={plane}
    {...props}
    dispose={null}
  >
    {/* 直接渲染原节点,动画会自动作用在这个对象上 */}
    <primitive 
      object={nodes.topR} 
      ref={topR}
      layers={2}
    >
      <meshStandardMaterial
        {...materials}
        metalness={0}
        roughness={0.8}
        side={THREE.DoubleSide}
        shadowSide={THREE.DoubleSide}
      />
    </primitive>
    {/* 其余节点逻辑 */}
  </group>
);

核心问题2:读取的是本地变换,而非世界变换

如果动画实际作用在topR的父级节点(比如你外层的plane group),那么topR本身的本地position、rotation确实不会变化,发生变化的是父级的变换属性,直接读本地属性自然看不到更新。

修复方案

读取节点的世界坐标和世界旋转即可:

useFrame(() => {
  if (actions.fold.isRunning() && topR.current) {
    // 先更新世界矩阵确保数值是最新的
    topR.current.updateWorldMatrix(true, false)
    // 读取世界位置
    const worldPosition = new THREE.Vector3()
    topR.current.getWorldPosition(worldPosition)
    // 读取世界旋转
    const worldRotation = new THREE.Euler()
    topR.current.getWorldRotation(worldRotation)
    console.log('实时世界位置', worldPosition)
    console.log('实时世界旋转', worldRotation)
  }
// 第二个参数设为-1,让当前useFrame在动画混合器更新后执行,避免拿到上一帧的旧值
}, -1)

可选排查项

如果修改后仍然有问题,可以打印动画轨道确认目标节点是否匹配:

useEffect(() => {
  if(actions.fold) {
    // 打印所有动画轨道的目标路径,确认是否对应topR节点
    console.log(actions.fold.getClip().tracks.map(track => track.name))
  }
}, [actions.fold])

内容的提问来源于stack exchange,提问作者Fatjon Rrapaj

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 23:15:05