如何使用 Three.js 和 React 渲染你自己的 3D 模型
本文将介绍如何在 React 项目中使用 react-three-fiber 渲染和配置在 Blender 或 Maya 等 3D 软件程序中创建的 3D 资源。读完本文后,您将能够在自己的网站上渲染 3D 模型 (gltf / glb)。
获取您自己的 3D 模型
为了获得定制的 3D 模型,我们将使用Ready Player Me,这是一款来自 Wolf3D 的免费 3D 头像创建工具,任何人都可以在几分钟内创建自己的数字形象,无需任何 3D 建模经验。您只需快速自拍一张,然后等待程序根据您的喜好自动生成定制的 3D 头像即可。
然后,您可以自由地使用各种发型、肤色、面部特征、服装选项和其他可自定义的属性来对角色进行调整。
登录Ready Player Me后,您需要按照以下步骤操作即可。
选择体型
上传你自己的照片
定制您的外观
下载你的模型
在 React 中渲染模型
为了在我们的 React 应用程序中渲染模型,我们将使用React-three-fiber,一个用于 Threejs 的React 渲染器。
设置项目
首先,让我们使用 Create React App创建一个新的React项目:
npx create-react-app my-3d-model
#or
yarn create react-app my-3d-model
然后,使用以下命令安装@react-three/fiber和@react-three/drei :
npm install three @react-three/fiber @react-three/drei
#or
yarn add three @react-three/fiber @react-three/drei
将模型转换为可重用的 React 组件
完成后,继续运行以下命令,使用gltfjsx创建一个 javascript 文件,该文件以 React 功能组件的格式绘制出所有资产内容。
npx gltfjsx model.glb
该文件的内容类似于以下代码:
import React, { useRef } from "react";
import { useGLTF } from "@react-three/drei";
export default function Model({ ...props }) {
const group = useRef();
const { nodes, materials } = useGLTF("/model.glb");
return (
<group ref={group} {...props} dispose={null}>
<primitive object={nodes.Hips} />
<skinnedMesh
geometry={nodes.Wolf3D_Body.geometry}
material={materials.Wolf3D_Body}
skeleton={nodes.Wolf3D_Body.skeleton}
/>
<skinnedMesh
geometry={nodes.Wolf3D_Glasses.geometry}
material={materials.Wolf3D_Glasses}
skeleton={nodes.Wolf3D_Glasses.skeleton}
/>
<skinnedMesh
geometry={nodes.Wolf3D_Hair.geometry}
material={materials.Wolf3D_Hair}
skeleton={nodes.Wolf3D_Hair.skeleton}
/>
<skinnedMesh
geometry={nodes.Wolf3D_Outfit_Bottom.geometry}
material={materials.Wolf3D_Outfit_Bottom}
skeleton={nodes.Wolf3D_Outfit_Bottom.skeleton}
/>
<skinnedMesh
geometry={nodes.Wolf3D_Outfit_Footwear.geometry}
material={materials.Wolf3D_Outfit_Footwear}
skeleton={nodes.Wolf3D_Outfit_Footwear.skeleton}
/>
<skinnedMesh
geometry={nodes.Wolf3D_Outfit_Top.geometry}
material={materials.Wolf3D_Outfit_Top}
skeleton={nodes.Wolf3D_Outfit_Top.skeleton}
/>
<skinnedMesh
name="EyeLeft"
geometry={nodes.EyeLeft.geometry}
material={nodes.EyeLeft.material}
skeleton={nodes.EyeLeft.skeleton}
morphTargetDictionary={nodes.EyeLeft.morphTargetDictionary}
morphTargetInfluences={nodes.EyeLeft.morphTargetInfluences}
/>
<skinnedMesh
name="EyeRight"
geometry={nodes.EyeRight.geometry}
material={nodes.EyeRight.material}
skeleton={nodes.EyeRight.skeleton}
morphTargetDictionary={nodes.EyeRight.morphTargetDictionary}
morphTargetInfluences={nodes.EyeRight.morphTargetInfluences}
/>
<skinnedMesh
name="Wolf3D_Head"
geometry={nodes.Wolf3D_Head.geometry}
material={materials.Wolf3D_Skin}
skeleton={nodes.Wolf3D_Head.skeleton}
morphTargetDictionary={nodes.Wolf3D_Head.morphTargetDictionary}
morphTargetInfluences={nodes.Wolf3D_Head.morphTargetInfluences}
/>
<skinnedMesh
name="Wolf3D_Teeth"
geometry={nodes.Wolf3D_Teeth.geometry}
material={materials.Wolf3D_Teeth}
skeleton={nodes.Wolf3D_Teeth.skeleton}
morphTargetDictionary={nodes.Wolf3D_Teeth.morphTargetDictionary}
morphTargetInfluences={nodes.Wolf3D_Teeth.morphTargetInfluences}
/>
</group>
);
}
useGLTF.preload("/model.glb");
创造场景
import React, { Suspense } from "react";
import { Canvas } from "@react-three/fiber";
import { OrbitControls } from "@react-three/drei";
export default function App() {
return (
<Canvas
camera={{ position: [2, 0, 12.25], fov: 15 }}
style={{
backgroundColor: "#111a21",
width: "100vw",
height: "100vh",
}}
>
<ambientLight intensity={1.25} />
<ambientLight intensity={0.1} />
<directionalLight intensity={0.4} />
<Suspense fallback={null}>// your model here</Suspense>
<OrbitControls />
</Canvas>
);
}
将模型添加到场景
首先将模型(glb文件)添加到公共文件夹,对于gltfjsx生成的javascript文件,您可以将其添加到src文件夹或components文件夹。
import React, { Suspense } from "react";
import { Canvas } from "@react-three/fiber";
import { OrbitControls } from "@react-three/drei";
import Model from "./Model"; /* highlight-line */
export default function App() {
return (
<Canvas
camera={{ position: [2, 0, 12.25], fov: 15 }}
style={{
backgroundColor: "#111a21",
width: "100vw",
height: "100vh",
}}
>
<ambientLight intensity={1.25} />
<ambientLight intensity={0.1} />
<directionalLight intensity={0.4} />
<Suspense fallback={null}>
<Model position={[0.025, -0.9, 0]} /> /* highlight-line */
</Suspense>
<OrbitControls />
</Canvas>
);
}
body {
margin: 0;
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
}
结果:
https://codesandbox.io/s/bold-wing-9w9n3i?file=/src/Model.js
为模型添加动画
为了能够向您的 3D 模型添加动画,您需要在您的机器上安装搅拌机。
将模型导入到搅拌机
Blender 是一款免费开源的 3D 创作套件。它支持完整的 3D 流程建模、绑定、动画、模拟、渲染、合成和运动追踪,甚至视频编辑和游戏创作。
了解更多
创建新的搅拌机项目
清除场景中的所有物体
将 glb 文件导入到 blender
选择您的型号并点击Import glTF 2.0
将模型转换为fbx格式
在向我们的模型添加任何动画之前,我们需要先将其转换为FBX格式。
选择型号
要在搅拌机中选择 3D 模型,您只需单击字母a或使用鼠标即可。
将模型导出为 FBX
确保设置Path Mode为Copy,并选中该Embed textures选项。
使用mixamo添加动画
Mixamo是一款免费的在线服务,用于自动绑定和制作 3D 角色动画。它由 Mixamo Incorporated 开发,该公司于 2015 年被 Adobe 收购。Mixamo 允许用户上传 FBX、OBJ 或 Zip 文件,然后该网站会在两分钟内自动完成角色绑定。绑定流程最适合人形角色。
将模型上传至 mixamo
选择动画并下载动画模型
将动画模型转换回 glb 格式
为了在我们的 React 应用程序中使用该模型,我们需要将其更改回glb格式。
将动画模型导入到搅拌机
将动画模型导出为 glb
在 React 中渲染动画模型
在公共文件夹model.glb中用动画模型替换文件,并将以下更改添加到src/Model.js文件中。
import React, { useRef, useEffect } from "react"; /* highlight-line */
import { useGLTF, useAnimations } from "@react-three/drei"; /* highlight-line */
export default function Model({ ...props }) {
const group = useRef();
const { nodes, materials, animations } = useGLTF("/model.glb");
const { actions } = useAnimations(animations, group); /* highlight-line */
// 'Armature|mixamo.com|Layer0' is the name of the animation we need to run.
// console.log(actions);
useEffect(() => {
/* highlight-line */
actions["Armature|mixamo.com|Layer0"].play(); /* highlight-line */
}); /* highlight-line */
return (
<group ref={group} {...props} dispose={null}>
<primitive object={nodes.Hips} />
<skinnedMesh
geometry={nodes.Wolf3D_Body.geometry}
material={materials.Wolf3D_Body}
skeleton={nodes.Wolf3D_Body.skeleton}
/>
<skinnedMesh
geometry={nodes.Wolf3D_Glasses.geometry}
material={materials.Wolf3D_Glasses}
skeleton={nodes.Wolf3D_Glasses.skeleton}
/>
<skinnedMesh
geometry={nodes.Wolf3D_Hair.geometry}
material={materials.Wolf3D_Hair}
skeleton={nodes.Wolf3D_Hair.skeleton}
/>
<skinnedMesh
geometry={nodes.Wolf3D_Outfit_Bottom.geometry}
material={materials.Wolf3D_Outfit_Bottom}
skeleton={nodes.Wolf3D_Outfit_Bottom.skeleton}
/>
<skinnedMesh
geometry={nodes.Wolf3D_Outfit_Footwear.geometry}
material={materials.Wolf3D_Outfit_Footwear}
skeleton={nodes.Wolf3D_Outfit_Footwear.skeleton}
/>
<skinnedMesh
geometry={nodes.Wolf3D_Outfit_Top.geometry}
material={materials.Wolf3D_Outfit_Top}
skeleton={nodes.Wolf3D_Outfit_Top.skeleton}
/>
<skinnedMesh
name="EyeLeft"
geometry={nodes.EyeLeft.geometry}
material={nodes.EyeLeft.material}
skeleton={nodes.EyeLeft.skeleton}
morphTargetDictionary={nodes.EyeLeft.morphTargetDictionary}
morphTargetInfluences={nodes.EyeLeft.morphTargetInfluences}
/>
<skinnedMesh
name="EyeRight"
geometry={nodes.EyeRight.geometry}
material={nodes.EyeRight.material}
skeleton={nodes.EyeRight.skeleton}
morphTargetDictionary={nodes.EyeRight.morphTargetDictionary}
morphTargetInfluences={nodes.EyeRight.morphTargetInfluences}
/>
<skinnedMesh
name="Wolf3D_Head"
geometry={nodes.Wolf3D_Head.geometry}
material={materials.Wolf3D_Skin}
skeleton={nodes.Wolf3D_Head.skeleton}
morphTargetDictionary={nodes.Wolf3D_Head.morphTargetDictionary}
morphTargetInfluences={nodes.Wolf3D_Head.morphTargetInfluences}
/>
<skinnedMesh
name="Wolf3D_Teeth"
geometry={nodes.Wolf3D_Teeth.geometry}
material={materials.Wolf3D_Teeth}
skeleton={nodes.Wolf3D_Teeth.skeleton}
morphTargetDictionary={nodes.Wolf3D_Teeth.morphTargetDictionary}
morphTargetInfluences={nodes.Wolf3D_Teeth.morphTargetInfluences}
/>
</group>
);
}
useGLTF.preload("/model.glb");
结果:
https://codesandbox.io/s/3d-model-animation-d41e9u?file=/src/Model.js:271-281
另请阅读:
React 最佳实践 - 2022 年编写更优质代码的方法
10 个 JavaScript 单行代码 - 提升生产力的方法
我的博客
我的网站
在 Upwork 上找到
我 在 twitter 上找到
我 在 linkedin 上找到我
在 github 上找到我
后端开发教程 - Java、Spring Boot 实战 - msg200.com

















