Reputation: 42
i'm using react-three-fiber and i want to make a house. So i use a GLTF model for displaying the door.
Render one door is fine but when i render 2 doors from the same GLTF file then only the 2nd door is rendered. Looks like the 2nd door has replaced the 1st instead of being a new door.
How can i achieve having multiple doors, i've searched but there seems to be no one asking this question???
My code:
Door.tsx
import React from 'react';
import { useLoader } from "@react-three/fiber";
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
interface DoorProps {
rotation: any;
}
function Door(props: DoorProps) {
const gltf = useLoader(GLTFLoader, '/simple_door.gltf');
return (
<>
<primitive
object={gltf.scene}
position={[25, 1, -17]}
scale={0.05}
rotation={props.rotation}
/>
</>
);
}
export default Door;
Room.tsx
function Room() {
return (
<Canvas
shadows
dpr={[1, 2]}
frameloop="demand"
style={{ height: 800 }}
camera={{ fov: 75, near: 0.1, far: 1000, position: [0, 10, 20] }}
>
<OrbitControls addEventListener={undefined} hasEventListener={undefined} removeEventListener={undefined} dispatchEvent={undefined} />
<ambientLight intensity={0.8} />
<color attach="background" args={['#d0d0d0']} />
<fog attach="fog" args={['#d0d0d0', 100, 600]} />
<Suspense fallback={null}>
<Environment preset="city" />
<Door />
<Plane
width={50}
height={10}
depth={1}
position={[0, 0, -20]}
/>
<Door
rotation={[0, 90*Math.PI/180, 0]}
/>
<Plane
width={50}
height={1}
depth={50}
position={[0, -4.5, 5]}
/>
</Suspense>
</Canvas>
);
};
export default Room;
Upvotes: 3
Views: 6187
Reputation: 1435
you can't add the same model in two places, threejs will unmount it automatically from the first place. the solution is gltfjsx. this is what allows you to re-use models. there is no counterpart for this in vanilla three, and they usually re-parse and/or clone. with gltfjsx the model is loaded and parsed only once, but since it is immutable you can readily re-use it ootb.
here's an example: https://codesandbox.io/s/re-using-gltfs-dix1y gltfjsx can even generate instances, so no matter how many times you render it, you'll have only one drawcall.
Upvotes: 1
Reputation: 694
Looks like you're trying to clone your 3D door model,
There are several ways to do so, what you're looking for is probably à simple use of the clone function :
import React from 'react';
import { useGraph } from '@react-three/fiber'
import { useGLTF } from '@react-three/drei'
import { SkeletonUtils } from "three/examples/jsm/utils/SkeletonUtils"
interface DoorProps {
rotation: any;
}
function Door(props: DoorProps) {
const { scene, materials, animations } = useGLTF('/simple_door.gltf');
const clone = useMemo(() => SkeletonUtils.clone(scene), [scene])
const { nodes } = useGraph(clone)
return (
<>
<primitive
object={nodes}
position={[25, 1, -17]}
scale={0.05}
rotation={props.rotation}
/>
</>
);
}
export default Door;
I used the drei package, because it helps to load other informations than the model if needed
here is another example : https://codesandbox.io/s/react-three-fiber-wildlife-nrbnq?file=/src/Model.js
you could maybe also want to display a lot of doors, in this case i recommend you to use instancedMesh instead of primitive
also a tool that would help you to create your Door component would be gltfjsx, have a look at it : https://www.npmjs.com/package/gltfjsx
Upvotes: 2
Reputation: 124
You did not pass rotation
prop for the first door,
If you don't want to pass rotation
prop to First Door make the rotation an optional prop like this.
interface DoorProps {
rotation?: any;
}
Upvotes: 0