React Three Fiber中primitive标签复用同一模型为何仅第二个生效?
问题原因与解决方案
你遇到的问题不是primitive标签只能用一次,而是Three.js中同一个Object3D对象(比如你的model.scene)无法同时挂载到多个父节点下。当你第二次用primitive添加同一个scene对象时,它会被自动从第一个primitive的父节点中移除,导致第一个primitive没有可显示的内容。
另外你虽然调用了两次useGLTF,但useGLTF默认会缓存加载结果,所以model和model2其实指向的是同一个模型实例,并不是两个独立的副本。
解决方法
1. 克隆模型实例(推荐)
只加载一次模型,然后通过clone()方法创建独立的副本,这样就能同时渲染多个相同模型,还能避免重复请求资源:
import { useGLTF, OrbitControls, useHelper, useScroll, Html } from '@react-three/drei' import * as THREE from 'three' import { useFrame } from '@react-three/fiber' import { useRef, forwardRef, useMemo } from 'react' export default function App() { // 仅加载一次模型 const model = useGLTF('/iphone_14_pro_max.glb'); // 深克隆模型场景,确保材质、几何体都是独立引用 const modelSceneClone = useMemo(() => model.scene.clone(true), [model]) const scroll = useScroll() const iphone = useRef() const first = useRef() useFrame((state, delta) => { const r1 = scroll.range(0 / 4, 1 / 4) const r2 = scroll.range(1 / 4, 1 / 4) const r3 = scroll.range(1 / 4, 1 / 4) iphone.current.rotation.y = (Math.PI * 0.67) + r1 + r2 + r3 * 3 }) return( <> <directionalLight position={ [ 1, 2, 3 ] } intensity={ 1.5 } /> <ambientLight intensity={ 0.5 } /> <primitive ref={iphone} object={model.scene} scale={20} position={ [ 0, -1.5, 0] }> <Tagline ref={first} left="PRO" right="BEYOND"></Tagline> </primitive> {/* 使用克隆后的独立场景实例 */} <primitive object={modelSceneClone} scale={15} position={ [ 1, 1, 1] } rotation-y={-45}/> </> ) } const Tagline = forwardRef(({ left, right, ...props }, ref) => { return ( <Html occlude ref={ref} className="homepage" center {...props}> <h1>{left}</h1> <h1>{right}</h1> </Html> ) })
2. 禁用useGLTF缓存(不推荐)
如果一定要多次调用useGLTF,可以通过第二个参数禁用缓存,强制加载多个独立实例,但这样会重复请求模型文件,浪费带宽和性能:
const model = useGLTF('/iphone_14_pro_max.glb', { cache: false }); const model2 = useGLTF('/iphone_14_pro_max.glb', { cache: false });
关键说明
.clone(true)是深克隆,会复制模型的所有子对象、材质和几何体,确保每个副本都是独立的,不会互相影响状态。- 优先使用克隆方式,既保证功能又能优化性能。
内容的提问来源于stack exchange,提问作者Yustina Yasin
相关产品推荐
相关产品推荐

