THREEJS前端3D开发之路(一:跃然“网”上,创建你的第一个3D人物)

605 阅读10分钟

引言: 作为一名传统vue操作员,我将和你一起进入前端3D开发以及React的世界,为个人发展提供可能性(共同学习⛽)此项目可能需要你有一点点前置知识(React)。

学习目标:🔘

  • ⭐了解3D开发的内部工作原理
  • ⭐掌握Three.js基础知识
  • ⭐为Web和移动应用程序创建优美的3D效果
  • ⭐使用React Three Fiber 和 React Three Drei 开发应用程序
  • ⭐使用GSAP探索动画
  • ⭐使用Blender进行3D建模

(Section One) 什么是Three.js❓

👋Three.js 是一个功能强大的开源库,用于在Web上创建令人惊叹的3D视觉效果,它为开发人员提供了一组易于使用的[webgl](WebGL 概念和基础入门WebGL 是什么 对于 WebGL 百度百科给出的解释是 WebGL 是一种 3D 绘图协 - 掘金封装(webgl在此暂不做赘述,想要了解的小伙伴可以点击大佬的链接,我在后续的特效文章也会讲到。)用于构建可以在任何现代web浏览器中呈现的交互式动画3D图形。

💼借助Three.js 我们可以创建各种3D对象和场景,包括复杂的几何图形、动态粒子系统以及逼真的照明和阴影效果。无论您是构建游戏、数据可视化还是交互式产品演示,Three.js 都能提供将想法变为现实所需的灵活性和功能。Three.js 的主要优势之一是它与不同的 Web 技术和框架(包括 HTML5、CSS 和 JavaScript)的广泛兼容性。这意味着您可以轻松地将Three.js集成到现有的 Web 项目中,或者使用熟悉的 Web 开发工具和技术从头开始新项目。

❗最重要的是Three.js拥有充满活力的社区(基本上好像每周更新一次😅),不断发展和改进,无论您是经验丰富的 3D 程序员还是新手,它都为构建🐄B的交互式 Web 体验提供了充满创意的可能。

基础🦾

📺Renderer(渲染器)

  • 渲染器负责将3D的场景绘制到Web页面上(实际上就是将Scene 场景 和 Camera相机 传递给Renderer渲染器,然后将相机视锥体内的3D场景部分进行投射成2D渲染到Canvas 画布上),在Three.js中,WebGlRenderer类用于创建渲染器。它使用WebGl(上文提过 一种基于OpenGL ES的图形API)与GPU交互并将场景绘制到网页上。

🌐Geometry(几何元素)

  • 几何图形定义Three.js中一个对象的形状和结构,它由顶点(3D空间中的点)和面(链接顶点的三角面)组成。Three.js提供了许多内置的几何体,例如BoxGeometry(立方体),SphereGeometry(球体)和PlaneGeometry(平面),以及创建自定义集合体的功能。

🔦Light(光)

  • 光是Three.js中能对你视觉造成冲击的大部分原因,有光线关系你才可以感知到物体的结构。它是用于模拟光线与场景中对象的交互方式。在 Three.js 中,灯光用于照亮场景并创建阴影。Three.js 提供了许多内置光源,例如 AmbientLight(环境光)、DirectionalLight(平行光) 和 PointLight(点光源),以及创建自定义光源的功能。

📸Camera(相机)

  • 摄像机确定查看器在场景中的视角和位置。PerspectiveCamera(透视相机) 和 OrthographicCamera(正交相机) 类用于创建相机。PerspectiveCamera 模拟透视视图,而 OrthographicCamera 模拟等轴测视图

🏆Material(材质)

  • 材质定义对象在场景中的显示方式,包括其颜色、纹理和阴影。这些材料被应用于几何体以定义其外观。它提供了许多内置材质,例如 MeshBasicMaterial(网格基础材质)、MeshLambertMaterial(网格Lambert材质- 受光照影响) 和 MeshPhongMaterial(网格Phone材质-受光照影响,可以实现镜面反射的效果,以及玻璃透明效果等),以及使用着色器创建,下图给大家简单列了一下不同材质的效果,想要自己试一下的可以点击此链接选一下不同材质和颜色玩一玩,还有一些不常用的材质在此不做赘述,后续用到再议。

         2024-10-30-16-12-05-image.png

🎬 Scene (场景)

  • 场景就是容纳上述所有元素(元素,相机,灯光)的容器

🧱Texture (纹理)

  • 纹理是应用于Three.js材质的图像。纹理可用于向对象的表面添加细节例如木纹图案或大理石纹理。在 Three.js 中,使用 TextureLoader 类加载纹理,并使用 texture 属性应用于材质。

🎞️Animation(动画)

  • 动画实在3D场景中随时间闯将运动或更改的过程在Three.js中动画是使用requestAnimationFrame方法来实现更新对象的位置,旋转和缩放的。

了解完上述内容,其实你已经知道了Three.js的所有内容了,也可以来创建我们第一个3D场景了

(Section Two) 寻找“二次元”的你

step1🎯 捏人

  • 此次Three.js之旅我们从寻找一个自己的模型开始,首先进入ReadyPlayerMe这个网站(可能有些人,比较慢这个只能去github上自己想一下办法了。。。😅,或者进入我的仓库,public文件夹下有准备好的素材🌟🌟🌟)

    点击创建一个你自己的角色(这里需要准备一张你迷人的自拍照)

2024-10-30-16-38-56-image.png

2024-10-30-16-42-00-image.png

  • 造型MakeUp一下,在我们的一阵骚操作下,哥们捏了个销售(bushi😅),然后我们就

    可以点击Next去生成我们的人物模型

2024-10-30-16-47-19-image.png

  • 点击copy我们复制链接就可以把我们的模型下载下来啦,可以看到我们得到了一个glb文件,这也是我们前端最常用的模型文件格式。(到现在我们已经向web3D开发迈出了一大步了)

     2024-10-30-16-50-53-image.png

2024-10-30-16-51-26-image.png

step2 🎯给模型附魔

  • 🛞 转换

首先我们需要把glb的模型文件转换成可以绑定动画的FBX文件,我们需要下载一个强大的开源免费的建模工具([Blender](blender.org - Home of the Blender project - Free and Open 3D Creation Software)),然后打开软件,删除调默认的方块模型,相机,还有灯光,选中模型按X键或者Delete键就可以删除掉了

2024-10-30-17-35-47-image.png

2024-10-30-17-37-44-image.png

导入我们下载好的文件glb文件

2024-10-30-17-38-48-image.png

导入以后先把这俩文件也删掉

然后我们就可以导出一个Fbx文件来绑定动画了!🎉🎉🎉

2024-10-30-17-39-55-image.png

  • 人物动画绑定

首先我们进入Mixamo这个网站,点击upload character 上传我们刚刚导出的FBX文件,然后选择一个左侧你喜欢的动作,我们把这个模型下载下来

2024-10-30-17-42-08-image.png

Step3 🎯创建React项目

  • 首先说一下我们为什么使用React 而不是Vue (俺其实很想用Vue),一个比较重要的原因是现阶段使用React-Three-fiber 以及React-Three-drei开发three.js很方便,并且社区已经非常完善了,对比vue 你差不多只可以使用three.js这个原生库去开发,虽然也有类似TroisJs Vue-GL 以及vue-Three这种库,但是和上面React的两个库相比还是小巫见大巫了,差的比较多,不过说到底,工具不重要,重要的是我们需要练习WEB3D开发的思维

    第一步,我们需要创建一个React项目(如果可以我希望你可以跟我保持一样的node版本,我的node版本是20.15.1)

npm create vite@latest react_threejs -- --template react
npm i 
npm run dev

下载依赖并启动项目,可以看到我们当前创建了一个React的前端模板框架

2024-10-30-18-01-48-image.png

2024-10-30-18-02-02-image.png

样式方面我们选择使用安装 - TailwindCSS中文文档 | TailwindCSS中文网,如果你不想使用tailwindcss可以跳过这部分,使用原生css,scss或less等,此系列tailwindcss不是课程的主要目的,本文也不会用到。

2024-10-30-18-06-39-image.png

然后我们需要安装一些库

npm i three @react-three/fiber @react-three/drei

我们先编写一些代码来看一看想要实现一个简单的3D页面有多么方便

/* eslint-disable react/no-unknown-property */
import { Canvas } from "@react-three/fiber";
import { OrbitControls } from "@react-three/drei";

function App() {
  return (
    <Canvas
      style={{
        height: "100vh",
        width: "100vw",
        display: "flex",
        justifyContent: "center",
        alignItems: "center",
      }}
    >
      <OrbitControls enableZoom enablePan enableRotate />
      <directionalLight/>
      <mesh>
        <boxGeometry />
        <meshStandardMaterial />
      </mesh>
    </Canvas>
  );
}

export default App;

2024-10-30-21-18-27-image.png

🎉🎉🎉我们获得了一个立方体,并且我们可以拖动视角进行旋转,缩放!!

现在我们来逐行解析一下这些代码都代表了什么意思

  • OrbitControls是一个来自 @react-three/drei 的控制器组件,用于控制相机视角
  • Canvas 是创建 3D 场景的容器,样式设置使其占满整个视口(100vh/100vw)并居中内容
<OrbitControls enableZoom enablePan enableRotate />
  • 添加轨道控制器,允许用户:
  • 缩放(zoom)
  • 平移(pan)
  • 旋转(rotate
<directionalLight position={[10, 10, 10]} intensity={1} />
  • 添加平行光源,位于坐标 [10,10,10],强度为 1
<mesh>
  <boxGeometry />
  <meshStandardMaterial />
</mesh>
  • 创建一个基础的立方体:
  • mesh 是 3D 对象的容器
  • boxGeometry 定义立方体的形状
  • meshStandardMaterial 定义材质

我要说明的是,react-three/fiberreact-three/drei这两个库基于的是threejs 如果你也用过three.js进行开发,你会发现这两个库简直太方便了,我们引入的Canvas组件承担了 threejs中 Scene 和Renderer的作用。Canvas 使用createRoot,创建一个WebGLRenderer,一个Perspective透视相机,Canvas的children属性可以接收 three.js jsx元素或者一些常规组件

相关代码

import * as THREE from 'three'
import { extend, createRoot, events } from '@react-three/fiber'

// 将THREE 命名空间注册为原生JSX元素
extend(THREE)

// 创建 react root
const root = createRoot(document.querySelector('canvas'))

// 配置 root、可选地注入事件、设置 camera 等
root.configure({ events, camera: { position: [0, 0, 50] } })

// 监听浏览器窗口大小变化,进行调整
window.addEventListener('resize', () => {
  root.configure({ size: { width: window.innerWidth, height: window.innerHeight } })
})

// 触发窗口尺寸变化事件
window.dispatchEvent(new Event('resize'))

// 在入口进行渲染
root.render(<App />)

Step3 🎯 动起来吧,二次元

  • 我们把下载好的模型放到public文件夹下
/* eslint-disable react/no-unknown-property */
import { Canvas } from "@react-three/fiber";
import { OrbitControls,useGLTF,useAnimations } from "@react-three/drei";
import { useEffect } from "react";

function Model(){
  const {scene,animations} = useGLTF('model/Person.glb')
  const {actions} = useAnimations(animations,scene)
  useEffect(() => {
    // 启动第一个动画(如果存在的话)
    const firstAnimation = Object.values(actions)[0];
    if (firstAnimation) {
      firstAnimation.play();
    }
  }, [actions]);
  return <primitive object={scene} />;
}

function App() {
  return (
    <Canvas
      style={{
        height: "100vh",
        width: "100vw",
        display: "flex",
        justifyContent: "center",
        alignItems: "center",
      }}
    >
      <OrbitControls />
      <ambientLight intensity={0.5} />
      <directionalLight position={[5, 5, 5]} intensity={1} />
      <Model />
    </Canvas>
  );
}

export default App;

PixPin_2024-10-31_11-51-11.gif

如果你也出现了这个画面,恭喜你,成功点亮了threejs的"Hello World!"

我们来解释一下这些代码💼

  • useGLTF: 用于加载 GLB/GLTF 格式的 3D 模型
  • scene: 包含模型的场景对象
  • animations: 模型包含的动画数据
  • useEffect 在组件挂载后自动播放第一个动画
  •  将 Three.js 对象直接渲染到场景中
  • 光源设置:
  • ambientLight: 环境光,提供整体照明
  • directionalLight: 平行光,提供方向性的光照
  • Model: 渲染我们的 3D 模型

小结:

  • 本文简单介绍了ThreeJS的基础,(渲染器,相机,网格【Geometry,Material】灯光,相机等)
  • 带大家简单下载模型以及绑定动画
  • 介绍了RTF组件Canvas 以及模型的下载与导入,使用副作用函数对模型进行操作,在前端页面的显示等。

🧷🧷🧷最后附上本文的所有链接MixamoReady Player Me Studio

🧷🎉🎉🎉以及此项目的[github](GitHub - Benbende41/Travle-In-ThreeJS)链接,此项目应该会不断更新。这是我第一次发文,希望大家有所收获,欢迎讨论。