React Three Fiber多网格渲染异常:仅最后一个组件GLTF模型正常显示
异常核心根因
Three.js 引擎本身的设计规则是:同一个 Object3D 实例在同一场景树中,只能挂载在一个父节点下,不存在“一个对象同时出现在多个位置”的能力。
你当前的实现里,所有 ITEM 组件调用 useGLTF(modelPath) 时,由于传入的模型路径完全相同,useGLTF 内部的资源缓存机制会直接返回同一份全局缓存的 gltf.scene 实例,不会为每个组件生成独立副本。当你把这个同一个 scene 实例依次通过 <primitive> 挂载到每个 ITEM 的场景节点下时,后一次的挂载操作会自动把该实例从之前的父节点中移除,最终只有最后一个完成挂载的 ITEM 能持有这个模型实例,其余组件的模型自然会丢失。
排查步骤
- 先通过变量验证根因:临时给两个相邻的 ITEM 传入不同的模型路径,比如第一个传
/model/a.gltf,第二个传/model/b.gltf,如果两个模型都能正常渲染,就可以确认是同一份资源被重复挂载导致的问题。 - 全局检索代码里直接复用 Three.js 对象引用的位置:不管是通过
useGLTF获取的缓存对象,还是手动实例化的 Three.js 对象,只要是同一个引用被多次传入<primitive>的object属性,都会触发同类问题。
解决方案
根据你的业务场景选择对应实现:
1. 需独立操作多份相同模型(适配你当前每个模型独立转动、独立交互的需求,最常用)
每次挂载模型时,对全局缓存的 gltf 实例做深克隆,生成完全独立的副本再使用。修改 Model 组件逻辑:
import { useMemo } from 'react' import { clone } from 'three' import { useGLTF } from 'drei' const Model = ({ modelPath }) => { const gltf = useGLTF(modelPath, true) // 对缓存的原始scene做深克隆,生成独立可挂载的实例 const clonedScene = useMemo(() => clone(gltf.scene), [gltf]) return <primitive object={clonedScene} dispose={null} /> }
- 注意必须用
useMemo缓存克隆结果,不要在组件每次重渲染时都重新克隆,避免不必要的性能开销。 - drei 内置了专门的克隆工具
useClone,可以直接调用简化代码。
2. 静态展示场景
如果不需要给每个模型做独立的动画、交互逻辑,可以直接在顶层 Suspense 内部挂载同一份模型实例,在不同的位置坐标下引用渲染,不需要在每个 ITEM 组件内部单独加载模型。这种方式由于共用同一个实例,无法给不同位置的模型绑定独立的状态控制。
3. 修正现有代码的其他潜在问题
- 原代码中直接把 GLTF 模型塞在空
<mesh>节点下的结构不合理:GLTF 的 scene 是独立的 Object3D 类型,不是 mesh 的子几何体,会加剧渲染异常。正确的结构应该用<group>作为每个 ITEM 的容器,把旋转控制的 ref 直接绑定在克隆后的模型实例上:const ITEM = ({ item, count }) => { const modelPath = '/model/scene.gltf' const modelRef = useRef(null) useFrame(() => { if (modelRef.current) { modelRef.current.rotation.y += 0.01 } }) // 用传入的count参数做位置偏移,避免所有模型重叠 return ( <group position={[count * 2, 0, 0]}> <Model modelPath={modelPath} ref={modelRef} /> </group> ) } - 原代码中所有 ITEM 的 position 都是固定的
[1,1,1],就算解决了模型挂载问题,所有模型也会完全重叠在同一个坐标点上,记得利用传入的count参数给不同模型设置横向/纵向偏移,避免显示重叠。
内容的提问来源于stack exchange,提问作者ErgoEuan
相关产品推荐
相关产品推荐

