如何监听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
相关产品推荐
相关产品推荐

