如何使用 Three.js 和 React 渲染你自己的 3D 模型

2025-05-27

如何使用 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
Enter fullscreen mode Exit fullscreen mode

然后,使用以下命令安装@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
Enter fullscreen mode Exit fullscreen mode

将模型转换为可重用的 React 组件

完成后,继续运行以下命令,使用gltfjsx创建一个 javascript 文件,该文件以 React 功能组件的格式绘制出所有资产内容。

npx gltfjsx model.glb
Enter fullscreen mode Exit fullscreen mode

该文件的内容类似于以下代码:

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");
Enter fullscreen mode Exit fullscreen mode

创造场景

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>
  );
}
Enter fullscreen mode Exit fullscreen mode

将模型添加到场景

首先将模型(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>
  );
}
Enter fullscreen mode Exit fullscreen mode
body {
   margin: 0;
   display: flex;
   align-items: center;
   justify-content: center;
   height: 100vh;
}
Enter fullscreen mode Exit fullscreen mode

结果:

https://codesandbox.io/s/bold-wing-9w9n3i?file=/src/Model.js

为模型添加动画

为了能够向您的 3D 模型添加动画,您需要在您的机器上安装搅拌机。

将模型导入到搅拌机

Blender 是一款免费开源的 3D 创作套件。它支持完整的 3D 流程建模、绑定、动画、模拟、渲染、合成和运动追踪,甚至视频编辑和游戏创作。
了解更多

创建新的搅拌机项目

新的搅拌机项目

清除场景中的所有物体

空白搅拌机项目

将 glb 文件导入到 blender

blender导入glb文件

blender导入glb文件

选择您的型号并点击Import glTF 2.0

blender导入glb文件

将模型转换为fbx格式

在向我们的模型添加任何动画之前,我们需要先将其转换为FBX格式。

选择型号

要在搅拌机中选择 3D 模型,您只需单击字母a或使用鼠标即可。

搅拌机型号选择

将模型导出为 FBX

搅拌机模型导出

Blender 模型导出配置

确保设置Path ModeCopy,并选中该Embed textures选项。

使用mixamo添加动画

Mixamo是一款免费的在线服务,用于自动绑定和制作 3D 角色动画。它由 Mixamo Incorporated 开发,该公司于 2015 年被 Adob​​e 收购。Mixamo 允许用户上传 FBX、OBJ 或 Zip 文件,然后该网站会在两分钟内自动完成角色绑定。绑定流程最适合人形角色。

将模型上传至 mixamo

mixamo 模型上传

mixamo 模型上传

选择动画并下载动画模型

mixamo 模型动画

mixamo 模型下载

将动画模型转换回 glb 格式

为了在我们的 React 应用程序中使用该模型,我们需要将其更改回glb格式。

将动画模型导入到搅拌机

将动画模型导入到搅拌机

将动画模型导出为 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");
Enter fullscreen mode Exit fullscreen mode

结果:

https://codesandbox.io/s/3d-model-animation-d41e9u?file=/src/Model.js:271-281


另请阅读:
React 最佳实践 - 2022 年编写更优质代码的方法
10 个 JavaScript 单行代码 - 提升生产力的方法


我的博客
我的网站
在 Upwork 上找到
我 在 twitter 上找到
我 在 linkedin 上找到我
在 github 上找到我

文章来源:https://dev.to/nourdinelabib/how-to-use-thirdjs-and-react-to-render-a-3d-model-of-your-self-4kkf
PREV
构建聊天 - 使用 React、Websockets 和 Web-Push 实现浏览器通知 🤯
NEXT
如何在本地安装 DeepSeek Janus Pro 7B?