Three Fiber 渲染器在 React 中渲染 3D 模型
Three.js是一个3D渲染/动画库,为了在画布上显示模型它结合了WebGL。如果你有兴趣深入了解Three.js为JavaScript环境提供的功能,可以参考我之前写的有关文章。不过,在本文中,我们将介绍一个能进一步简化Three.js在环境中所使用的库,即React Native。
今天我会提供一个速成演示,用于展示其通过React Native Three Fiber组件来渲染3D模型的简化功能。那现在就开始吧。
设置场景
在开始之前,我们首先需要安装以下核心依赖项。
npm i react react-dom react-three-fiber three drei
在网络环境中渲染3D模型的前提是必须要有一个专门为模型渲染而设置的场景。让我们从创建一个基本的反应组件开始,它将随着我们的操作进展来存储我们的工作。
rt React, { useRef } from "react";
import { Canvas, useLoader, useFrame } from "react-three-fiber";
export default function App() {
return (
<div style={{
height: innerHeight
}}>
</div>
);
};
export default App;
但如何创建场景呢?网站上的3D模型实际上是从画布上投影出来的,所以我们应该从这里入手,即通过调用由React NativeThree Fiber库提供的组件来实现。 现在,如果想看一下我们的app,我们会看到一个白色的窗口。
由于白色背景的原因,这导致我们网页上的场景看起来就好像没有被渲染过一样。
渲染一个3D形状
现在我们已经在网页上成功渲染了场景,接下来,我们需要再添加一个基本形状。为了渲染这个形状,我们首先要创建一个新的函数,用来保存形状的属性。
function Mesh() {
return (
<mesh rotation={[0, 0, 0]}>
<sphereGeometry attach="geometry" args={[1, 16, 16]} />
<meshStandardMaterial
attach="material"
color="blue"
/>
</mesh>
);
}
在上面的代码中,我们正在返回创建基本形状所需的HTML。ThreeJS中的形状被称为网格,它在Geometries的计算数据中持有所有3D对象的属性。所以,我们现在就可以通过在canvas场景内声明我们刚刚制作的< Mesh />函数来渲染我们的3D模型。
export default function App() {
return (
<div style={{
height: innerHeight
}}>
<Canvas>
<OrbitControls/>
<directionalLight intensity={0.5} />
<ambientLight intensity={0.5} />
<spotLight position={[10, 15, 10]} angle={0.9} />
<Mesh />
</Canvas>
</div>
);
};
现在我们的网页看起来如下图:
这不是我们真正想要的结果,但这并不意味着我们的形状没有被正常渲染,我们只是没有添加任何照明,所以形状被完全包裹在黑暗中了。我们可以们通过为HTML添加照明和聚光灯来改变这种情况:
让我们来分析一下以上代码片断:
在以上代码中,我们正在声明 ambientLight ,以在周围的场景中创建一个光源,并根据此方向性光源,使环境光照在一个特定的方向。最后一个组件是 spotLight ,它将在环境中渲染一个聚光灯,它将在特定的位置/角度照耀物体。最后,我们添加了OrbitControls,允许光标在3D环境中移动/旋转。
现在来看看我们渲染的对象:
看起来好多了,渲染对象现在已经被我们制作的光照亮了。现在,如果我们想,我们可以将网格的形状改为Three.js文档中提供的众多网格之一,以及物体的材料。
导入预制网格
现在,我们完成了场景实例的创建,并在该场景中用适当的灯光渲染了一个3D模型。然而,如果我们想要进一步操作,即从网上导入一个模型到我们的本地环境中,会怎么样呢?为了达到这个目的,我们需要向组件导入新的依赖项,不用担心,这不需要安装任何新的包。
接下来看看如果我们想把这个表导入场景中:
为了将这个表导入环境中,我们必须先创建一个新的函数。在这个新函数的范围内,应该包含叠加的已导入的3D对象的纹理,作为变量,同时还有一个组来持久化3D对象。此外,你还会注意到对GLTFLoader的调用,这是一个与Three.js链接的导入包,它允许从GLTF文件中检索数据。
function Table() {
// textures from the imported image
const texture = useLoader(THREE.TextureLoader, img)
const texture1 = useLoader(THREE.TextureLoader, img1)
const texture2 = useLoader(THREE.TextureLoader, img2)
const group = useRef();
// loading the table.gtlf file being imported into the component.
const { nodes } = useLoader(GLTFLoader, table);
// useFrame will run outside of react in animation frames to optimize updates.
useFrame(() => {
group.current.rotation.x = 5.09;
});
return (
// Add a ref to the group. This gives us a hook to manipulate the properties of this geometry in the useFrame callback.
<group ref={group} position={[-12, -20, -10]} >
<mesh visible geometry={nodes.mesh_1.geometry}>
<meshPhongMaterial attach="material" color="gold" map={texture} map={texture1} map={texture2}/>
</mesh>
<mesh visible geometry={nodes.mesh_0.geometry}>
<meshPhongMaterial attach="material" color="#795C34" map={texture} map={texture1} map={texture2}/>
</mesh>
</group>
);
}
在以上代码片断中,Mesh组件还接收了一个新的选项,geometry。这个选项将渲染导入范围内的任何模型的几何图形。此外,Mesh材质标签还包含一个纹理选项,它将把任何纹理图像应用到特定的网格表面。
function Loading() {
return (
<mesh rotation={[0, 0, 0]}>
<sphereGeometry attach="geometry" args={[1, 16, 16]} />
<meshStandardMaterial
attach="material"
color="white"
transparent
opacity={0.6}
roughness={1}
metalness={0}
/>
</mesh>
);
}
export default function App() {
return (
<div style={{
height: innerHeight
}}>
<Canvas>
<OrbitControls/>
<directionalLight intensity={0.5} />
<ambientLight intensity={0.5} />
<spotLight position={[10, 15, 10]} angle={0.9} />
<Suspense fallback={<Loading />}>
<Table />
</Suspense>
</Canvas>
</div>
);
}
最后,如果要进行网格异步渲染的话,我们希望有一个备份模型来代替我们试图导入的3D对象。这可以通过创建一个新的网格函数作为占位符来实现,并在导入的网格周围加一个悬念法。如果组件范围内的Mesh在调用时没有执行,suspense方法将调用备份的Mesh(即fallback选项中的Mesh)。
结论
通过本文,我们介绍了什么是Three.js库,以及Three Fiber如何在React Native环境中渲染3D模型,同时还介绍了如何从外部来源导入3D模型到自己的场景中。希望这篇博客能对你有所帮助,并可供未来的、对将3D模型/动画纳入他们的网站感到兴趣的开发者使用。
原文作者 Ben Yoss
原文链接 https://levelup.gitconnected.com/rendering-3d-objects-and-animation-in-react-using-three-fiber-bf0255e642be