如何在threejs或react-three-fiber中加载相同的gltf模型

3

我正在使用react-three-fiber制作一个房子。所以我使用GLTF模型来显示门。

渲染一个门没有问题,但是当我从同一个GLTF文件中渲染2个门时,只有第二个门被渲染。看起来第二个门替换了第一扇门,而不是成为新门。

我该如何实现多个门呢?我已经搜索过了,似乎没有人问这个问题???

我的代码:

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;
3个回答

2

看起来你正在尝试克隆你的3D门模型,

有几种方法可以做到这一点,你可能正在寻找的是使用克隆函数的简单方法:

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;

我使用了drei包,因为它可以帮助加载除了模型以外的其他信息。
以下是另一个例子: https://codesandbox.io/s/react-three-fiber-wildlife-nrbnq?file=/src/Model.js 如果你想要展示很多门,我推荐你使用instancedMesh而不是primitive。
此外,一个能够帮助你创建Door组件的工具是gltfjsx,请看这里: https://www.npmjs.com/package/gltfjsx

1
你不能在两个地方添加相同的模型,threejs会自动从第一个位置卸载它。解决方案是使用gltfjsx。这就是允许您重复使用模型的方法。在vanilla three中没有类似的对应物,通常会重新解析和/或克隆。使用gltfjsx后,模型只会被加载和解析一次,但由于它是不可变的,因此您可以轻松地在其它地方重复使用它。
以下是一个例子:https://codesandbox.io/s/re-using-gltfs-dix1y gltfjsx甚至可以生成实例,因此无论渲染多少次,您都只有一个绘制调用。

0

你没有为第一扇门传递 rotation 属性,

如果你不想将 rotation 属性传递给第一扇门,可以将其设置为可选属性,像这样:

interface DoorProps {
   rotation?: any;
}

是的,谢谢。但是我已经尝试过这个方法,仍然只能看到第二扇门,没有旋转的第一扇门没有被渲染出来。 - Tom Vu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接