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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 16:20:22