在 react-three-fiber/drei/Three.js 中两次使用相同的 GLTF 模型
Use the same GLTF model twice in react-three-fiber/drei/Three.js
在这个最小的反应三纤维应用程序中,我试图加载并包含相同的 GLTF 模型两次:
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>
);
}
看到这个codesandbox
但是只有第二个 <primitive>
是可见的。如果我删除第二个 <primitive>
,那么第一个是可见的。
我正在努力理解为什么会发生这种情况以及如何做得更好。
(是因为第二次调用 useGLTF
记得 "/eye/scene.gltf"
和 returns 是同一个对象吗?这是否以某种方式搞乱了 <primitive>
,也许是因为 materials/geometries 没有被重新创建第二次,只存在一次?)
特别是,这是我想要实现的目标:
- 在我的 canvas
上多次使用 gltf 模型
- 理想情况下,只加载一次 gltf
最重要的是,也许你也可以帮助我澄清这些问题,以便我更好地理解这里的实际情况:
- 因为我只想要一个 3D 模型,使用
gltf.scene
对象是否正确?
<primitive>
实际上是显示 3D 模型的正确方法吗?或者我应该以某种方式从场景中提取 geometries/textures 并渲染它们?
谢谢!
我不是 three.js
方面的专家,只是根据我的发现并尝试回答您的问题。
1.即使定义了 2 个基元也只显示一只眼睛
如果使用useGLTF()
导入同一个模型,它将引用同一个对象。因此,这 2 个基元指向相同的 gltf,并且仅应用 last/one 配置。
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。 <primitive>
实际上是显示 3D 模型的正确方法吗?
是的,是的。但是如果你想在屏幕上多次显示相同的 gltf,你需要创建网格并应用模型的几何形状和材料,这样你就可以拥有一个新的对象。
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]} />
财政年度:
您可以使用此库 https://github.com/pmndrs/gltfjsx 从模型生成 jsx。
您不能在 webgl/threejs 中重复使用网格或将同一对象两次放入场景中,它只会卸载并重新装载。
您可以:
- 分享几何:看这个例子https://codesandbox.io/s/re-using-gltfs-dix1y?file=/src/Shoe.js:48-55
- 或深度克隆基础对象
下面是如何深度克隆基础对象,使用 useMemo
:
interface ObjectProps {
url: string;
position: [x: number, y: number, z: number];
}
const Object = ({ url, position, ...props }: ObjectProps) => {
const { scene } = useLoader(GLTFLoader, url)
const copiedScene = useMemo(() => scene.clone(), [scene])
return (
<group>
<primitive object={copiedScene} position={position} />
</group>
);
};
参考:https://github.com/pmndrs/react-three-fiber/issues/245#issuecomment-745552102
在这个最小的反应三纤维应用程序中,我试图加载并包含相同的 GLTF 模型两次:
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>
);
}
看到这个codesandbox
但是只有第二个 <primitive>
是可见的。如果我删除第二个 <primitive>
,那么第一个是可见的。
我正在努力理解为什么会发生这种情况以及如何做得更好。
(是因为第二次调用 useGLTF
记得 "/eye/scene.gltf"
和 returns 是同一个对象吗?这是否以某种方式搞乱了 <primitive>
,也许是因为 materials/geometries 没有被重新创建第二次,只存在一次?)
特别是,这是我想要实现的目标:
- 在我的 canvas 上多次使用 gltf 模型
- 理想情况下,只加载一次 gltf
最重要的是,也许你也可以帮助我澄清这些问题,以便我更好地理解这里的实际情况:
- 因为我只想要一个 3D 模型,使用
gltf.scene
对象是否正确? <primitive>
实际上是显示 3D 模型的正确方法吗?或者我应该以某种方式从场景中提取 geometries/textures 并渲染它们?
谢谢!
我不是 three.js
方面的专家,只是根据我的发现并尝试回答您的问题。
1.即使定义了 2 个基元也只显示一只眼睛
如果使用useGLTF()
导入同一个模型,它将引用同一个对象。因此,这 2 个基元指向相同的 gltf,并且仅应用 last/one 配置。
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。 <primitive>
实际上是显示 3D 模型的正确方法吗?
是的,是的。但是如果你想在屏幕上多次显示相同的 gltf,你需要创建网格并应用模型的几何形状和材料,这样你就可以拥有一个新的对象。
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]} />
财政年度:
您可以使用此库 https://github.com/pmndrs/gltfjsx 从模型生成 jsx。
您不能在 webgl/threejs 中重复使用网格或将同一对象两次放入场景中,它只会卸载并重新装载。 您可以:
- 分享几何:看这个例子https://codesandbox.io/s/re-using-gltfs-dix1y?file=/src/Shoe.js:48-55
- 或深度克隆基础对象
下面是如何深度克隆基础对象,使用 useMemo
:
interface ObjectProps {
url: string;
position: [x: number, y: number, z: number];
}
const Object = ({ url, position, ...props }: ObjectProps) => {
const { scene } = useLoader(GLTFLoader, url)
const copiedScene = useMemo(() => scene.clone(), [scene])
return (
<group>
<primitive object={copiedScene} position={position} />
</group>
);
};
参考:https://github.com/pmndrs/react-three-fiber/issues/245#issuecomment-745552102