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

Posted

技术标签:

【中文标题】如何在threejs或react-three-fiber中加载相同的gltf模型【英文标题】:How to load the same gltf model in threejs or react-three-fiber 【发布时间】:2021-12-08 01:04:06 【问题描述】:

我正在使用 react-three-fiber,我想建一所房子。所以我使用 GLTF 模型来显示门。

渲染一扇门很好,但是当我从同一个 GLTF 文件渲染两扇门时,只会渲染第二扇门。看起来第二扇门取代了第一扇门,而不是一扇新门。

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

我的代码:

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;

【问题讨论】:

【参考方案1】:

您似乎正在尝试克隆您的 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 而不是原始的

还有一个可以帮助您创建 Door 组件的工具是 gltfjsx,看看它: https://www.npmjs.com/package/gltfjsx

【讨论】:

【参考方案2】:

你不能在两个地方添加相同的模型,threejs 会从第一个地方自动卸载它。解决方案是gltfjsx。这就是允许您重用模型的原因。香草三中没有对应的,它们通常重新解析和/或克隆。使用 gltfjsx 模型只加载和解析一次,但由于它是不可变的,因此您可以轻松地重新使用它 ootb。

这里有一个例子:https://codesandbox.io/s/re-using-gltfs-dix1ygltfjsx 甚至可以生成实例,所以无论你渲染多少次,你都只有一个 drawcall。

【讨论】:

【参考方案3】:

你没有通过rotation第一道门的道具,

如果您不想将 rotation 属性传递给 First Door,请将旋转设置为像这样的可选属性。

interface DoorProps 
   rotation?: any;

【讨论】:

好的,谢谢。但是我试过了,我仍然只能看到第二扇门,第一扇没有旋转的门没有渲染。

以上是关于如何在threejs或react-three-fiber中加载相同的gltf模型的主要内容,如果未能解决你的问题,请参考以下文章

如何使用threejs实现第一人称视角的移动

ThreeJS - 如何找到枢轴点

ThreeJS初体验

如何在 Threejs 中绘制开口曲线形状

surfer如何导出三维gltf文件

ThreeJS之Scene(场景)