In this minimal react-three-fiber App I am trying to load and include the same GLTF model twice:
import React, { Suspense } from "react";
import { Canvas } from "@react-three/fiber";
import { useGLTF } from "@react-three/drei";
function MyContent() {
const firstGltf = useGLTF("/eye/scene.gltf");
const secondGltf = useGLTF("/eye/scene.gltf");
return (
<>
<primitive object={firstGltf.scene} position={[-200, 0, -400]} />
<primitive object={secondGltf.scene} position={[200, 0, -400]} />
</>
);
}
export default function App() {
return (
<Canvas>
<ambientLight color="white" intensity={0.5} />
<Suspense fallback={null}>
<MyContent />
</Suspense>
</Canvas>
);
}
See this codesandbox
However only the second <primitive>
is visible. If i remove the second <primitive>
, then the first one is visible.
I'm struggling to understand why this happens and how to do it better.
(Is it because the second call to useGLTF
remembers that "/eye/scene.gltf"
has already been loaded and returns the same object? And is this somehow messing up the usage with <primitive>
, maybe because materials/geometries haven't been re-created a second time and exist only once?)
In particular, this is what I want to achieve:
On top of that, maybe you can help me to clarify these questions as well so I get a better understanding what's actually going on here:
gltf.scene
object?<primitive>
actually the correct approach to show the 3D model? Or should I somehow extract the geometries/textures from the scene and render them?Thank you!
I am not an expert on three.js
, just based on what I find and try to answer your questions.
1. Only one eye is shown even there is 2 primitives defined
If you import the same model by using useGLTF()
, it will refer to the same object. Therefore, the 2 primitives are pointing to the same gltf and only last/one config is applied.
const firstGltf = useGLTF("/eye/scene.gltf");
const secondGltf = useGLTF("/eye/scene.gltf");
const glassesGltf = useGLTF("/glasses/scene.gltf");
// for demonstrating first eye is same as second eye
// Output: false, true
console.log(firstGltf === glassesGltf, firstGltf === secondGltf);
2. Is <primitive>
actually the correct approach to show the 3D model?
Yes, it is. but if you want to display the same gltf to the screen more than once, you need to create meshes and apply the model's geometries and materials so you can have a new object.
function Model(props) {
const { nodes, materials } = useGLTF("/eye/scene.gltf");
return (
<group
{...props}
dispose={null}
rotation={[Math.PI, 0, -Math.PI / 2]}
scale={[1, 1, 1]}
>
<mesh
geometry={nodes.Sphere001_Eye_0.geometry}
material={materials.material}
/>
</group>
);
}
...
<Model position={[-1, 0, 1]} />
<Model position={[1, 0, 1]} />
Here is the codesandbox for demo
FYR:
You can use this library https://github.com/pmndrs/gltfjsx to generate jsx from the model.