react-three-fiber中复制同一模型:添加双Primitive无效,求可行方法
解决React Three Fiber中复制模型的问题
你当前代码里两个<primitive>复用同一个gltf.scene实例是无效的——Three.js规定同一个3D对象不能同时挂载到场景的多个位置,第二个primitive会被忽略。下面是几种可行的解决方式:
方法一:克隆模型对象
直接克隆加载好的scene对象,生成独立的实例:
import { Stats, OrbitControls, Circle } from '@react-three/drei' import { Canvas, useLoader } from '@react-three/fiber' import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader' export default function App() { const gltf = useLoader(GLTFLoader, './models/monkey.glb') // 克隆出独立的模型实例,true表示递归克隆所有子对象和材质 const clonedMonkey = gltf.scene.clone(true) return ( <Canvas camera={{ position: [-0.5,1,2] }} shadows> <directionalLight position={[3.3,1.0,4.4]} castShadow /> {/* 原模型放在左侧 */} <primitive object={gltf.scene} position={[-1, 1, 0]} /> {/* 克隆模型放在右侧 */} <primitive object={clonedMonkey} position={[1, 1, 0]} /> <Circle args={[10]} rotation-x={-Math.PI / 2} receiveShadow> <meshStandardMaterial /> </Circle> <OrbitControls target={[0,0,0]} /> <axesHelper args={[5]} /> <Stats /> </Canvas> ) }
方法二:封装成可复用组件
更符合React组件化思路,把模型封装成独立组件,每次调用都会生成新实例:
import { Stats, OrbitControls, Circle } from '@react-three/drei' import { Canvas, useLoader } from '@react-three/fiber' import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader' // 封装模型组件,每次调用都会克隆新实例 function MonkeyModel({ position }) { const gltf = useLoader(GLTFLoader, './models/monkey.glb') return <primitive object={gltf.scene.clone(true)} position={position} /> } export default function App() { return ( <Canvas camera={{ position: [-0.5,1,2] }} shadows> <directionalLight position={[3.3,1.0,4.4]} castShadow /> {/* 两次调用组件,生成两个独立实例 */} <MonkeyModel position={[-1, 1, 0]} /> <MonkeyModel position={[1, 1, 0]} /> <Circle args={[10]} rotation-x={-Math.PI / 2} receiveShadow> <meshStandardMaterial /> </Circle> <OrbitControls target={[0,0,0]} /> <axesHelper args={[5]} /> <Stats /> </Canvas> ) }
方法三:用InstancedMesh(适合大量复制)
如果需要复制几十个甚至上百个相同模型,用InstancedMesh能大幅提升性能,两个模型的场景也适用:
import { Stats, OrbitControls, Circle } from '@react-three/drei' import { Canvas, useLoader } from '@react-three/fiber' import { GLTFLoader, Object3D } from 'three' export default function App() { const gltf = useLoader(GLTFLoader, './models/monkey.glb') // 假设模型根节点下的第一个子对象是要复用的mesh,根据实际模型结构调整 const targetMesh = gltf.scene.children[0] return ( <Canvas camera={{ position: [-0.5,1,2] }} shadows> <directionalLight position={[3.3,1.0,4.4]} castShadow /> {/* 创建实例化网格,参数:几何体、材质、实例数量 */} <instancedMesh args={[targetMesh.geometry, targetMesh.material, 2]}> {/* 设置第一个实例的位置 */} <setMatrixAt index={0} matrix={new Object3D().setPosition(-1,1,0).matrix} /> {/* 设置第二个实例的位置 */} <setMatrixAt index={1} matrix={new Object3D().setPosition(1,1,0).matrix} /> </instancedMesh> <Circle args={[10]} rotation-x={-Math.PI / 2} receiveShadow> <meshStandardMaterial /> </Circle> <OrbitControls target={[0,0,0]} /> <axesHelper args={[5]} /> <Stats /> </Canvas> ) }
内容的提问来源于stack exchange,提问作者ihat
相关产品推荐
相关产品推荐

