React Three Fiber动画入门

Posted 新缸中之脑

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了React Three Fiber动画入门相关的知识,希望对你有一定的参考价值。

使用静态对象和形状构建 3D 场景非常酷,但是当你可以使用动画使场景栩栩如生时,它会更酷。

在 3D 世界中,有一个称为角色装配的过程,它允许你创建称为骨架的特殊对象,其作用类似于骨骼和关节系统。 这些骨架连接到一块 3D 几何体上,例如人、动物或其他任何物体,并允许你弯曲和移动关节以使连接的几何体变形。 你可以使用此过程通过在骨架的不同姿势之间创建关键帧来创建动画。

推荐:用 NSDT场景设计器 快速搭建3D场景。

本教程不会教你如何创建这些装配角色之一,但会教你如何使用已在 React Three Fiber 中创建的角色。

本教程由三个主要部分组成。 从 Mixamo 服务获取一个预装配的 3D 模型和一组动画,准备该模型以用于 Blender 中的 WebGL,然后在 React Three Fiber 中使用该模型。 为什么我们要费心去学习 React 教程的前两部分? 好吧,如果你想重复这个过程来准备一些其他的绑定动画,你就可以做到。 让我们开始吧。

1、寻找免费角色和动画

首先让我们找到一个角色和一组要使用的动画。 为此,我们可以使用 Mixamo,这是一个由 Adobe 提供的免费角色模型和动画库。 如果没有帐户,则需要先创建一个。

第 1 步登录 Mixamo(或创建一个免费帐户)

第 2 步查找要下载的角色。 如果想使用与教程相同的角色,请使用 Michelle 角色。

第 3 步 下载 Capoeira 动画包。 如果需要,你可以选择另一个动画包,但使用相同的动画包可以更轻松地学习本教程。 这是因为动画的名称会有所不同,并可能导致与教程出现一些重大差异。

第 4 步将压缩的资源文件下载为 FBX。 下载时你可以使用所有默认选项。

第 5 步将下载的 .zip 文件的内容解压缩到您稍后可以找到的某个文件夹中。

2、安装Blender

你需要 Blender 将 Mixamo Rig 转换为适合 WebGL 的 GLTF 文件。 可以在此处下载最新版本。

3、在 Blender 中导入角色模型

在启动并运行 Blender 之后,就可以导入模型了。

第 1 步从 Blender 欢迎菜单打开一个新项目。 你可以只选择“常规”项目模板。

第 2 步从默认的 Blender 场景中删除所有内容,通过删除所有对象使其完全为空。 完成后,右上角的场景树中应该看不到任何东西。

第 3 步在 Blender 的文件菜单下找到导入菜单,然后选择 FBX (.fbx)。

第 4 步导航到从 Mixamo 中提取的 zip 文件的内容。 它看起来像这样。

Step 5 找到文件大小最大的fbx文件,这个文件包含人物几何体和默认的T-POSE。 如果你使用 Michelle 角色,则此文件的名称应为 Ch03_nonPBR.fbx。其他文件将包含 Mixamo 包中的所有不同动画。 我们稍后会回来导入这些。

第 6 步确保你在导入对话框中选择了“自动骨骼定向”选项。 你可以在屏幕截图中看到它的位置。 你现在应该可以在 Blender 中看到角色,但具有默认的 T-Pose 动画。

4、在 Blender 中导入动画数据

动画可以用与模型文件完全相同的方式导入,重复上一步的过程,但这次选择名为 armada.fbx 的 FBX 文件。该文件仅包含一个特定动作的动画数据。 由于此动画的名称是 armada,从现在开始我们将经常使用该名称来命名。

5、将动画附加到角色

现在动画已导入并存在于你的 Blender 场景中,但仍需要将其链接到模型。 在继续之前,请确保 3D 场景的内容看起来像这样。 它应该有两个骨骼。 一个带有 T 型姿势的模型称为 Armature,另一个带有动画但没有附加模型称为 Armature.001。 请注意,我将 Armature.001 下的动画名称从默认名称重命名为 Armada,这只是为了方便以后查找。 默认名称将是一些大而长的随机名称,我建议也更改它。

第 1 步在视口中选择第一个骨架(带有模型的骨架)后,通过选择视口顶部的动画选项卡切换到 Blender 中的动画布局。 你的视图应该更改为如下面的屏幕截图所示。

第 2 步切换到摄影表面板(底部)中的动作编辑器视图。

第 3 步将活动动作更改为导入的第二个动作,我们将其重命名为 Armada。

如果这有效,你应该会看到角色立即将其姿势更改为踢球动画的开始。 要尝试它,请点击摄影表上的播放按钮以查看动画播放。 如果由于某种原因它不起作用,你可能需要使用新的 Blender 重新开始并重新导入你的 .fbx 文件。 确保选中了“自动骨骼定向”选项。

第 3 步按下 Dope Sheet Action Editor 中的 Stash 按钮以确保动画保持与模型的关联。 点击存储后,动画将与工作对象的附件一起存储,以便稍后可以找到它,现在可以导入另一个模型并重复到此为止的步骤以附加另一个动画动作。

第 4 步 最后删除第二个骨架,即只有动画的那个。 不是上面有模型的那个。 这只是为了在导出前清理场景,因此导出文件中没有多余的对象。 拥有这些有时会使 GLFTJSX 感到困惑,所以这是一件好事。

6、将模型导出为 GLTF 文件

现在是时候从 Blender 导出到我们可以在 react-three-fiber 中使用的 .gltf 文件了。 GLTF 是你要导出到 WebGl 的任何 3d 数据的标准文件格式。

步骤 1 导出为 .gltf 文件。 .gltf 格式在导出后将保持人类可读性。 如果你想查看导出文件的结构,这有时会很有帮助。 你也可以导出为 .glb,它代表 GLTF 二进制文件。 它是一种用于表示 GLTF 的更节省空间的文件格式,但一旦导出,你就无法再轻松打开和检查文件的内容。

将文件命名为什么并不重要,但我将在我们要导出的动画名称之后将其命名为 armada.gltf。 你将在本教程的其余部分看到引用此名称。

7、生成 React Component Wrapper

当我们在 React 中使用导出的 gltf 文件时,我们需要访问导出场景的某些部分,例如我们需要提取几何体、骨架和动画。

你可以通过不手动操作来节省大量时间,而是使用由 react-three-fiber 团队创建的名为 GLFTJSX 的有用工具。 这是一个命令行工具,你可以将 gltf 或 glb 文件作为输入运行,它将创建一个结构良好的 React 组件包装器作为输出。

第 1 步 使用 npm 全局安装 GLTFJSX,以便您可以在命令行上使用它。

npm i -g gltfjsx

第 2 步以 armada.gltf 文件作为输入运行 GLTFJSX。 确保在与 .gltf 文件相同的目录中运行该命令。

gltfjsx armada.gltf

运行后你应该看到一个名为 Armada.js 的新文件,记住你保存这个文件的位置,以便我们稍后可以将它添加到我们的 React 项目中。

这就是为我们的 armada.gltf 文件生成的组件的样子。

/*
Auto-generated by: https://github.com/pmndrs/gltfjsx
*/

import * as THREE from "three";
import React,  useRef, useState  from "react";
import  useGLTF  from "@react-three/drei";

import  useAnimations  from "@react-three/drei";

export default function Model(props) 
  const group = useRef();
  const  nodes, materials, animations  = useGLTF("/armada.gltf");
  const  actions  = useAnimations(animations, group);

  return (
    <group ref=group ...props dispose=null>
      <group rotation=[Math.PI / 2, 0, 0] scale=[0.01, 0.01, 0.01]>
        <primitive object=nodes.mixamorigHips />
        <skinnedMesh
          material=materials.Ch03_Body
          geometry=nodes.Ch03.geometry
          skeleton=nodes.Ch03.skeleton
        />
      </group>
    </group>
  );


useGLTF.preload("/armada.gltf");

8、创建React-three-fiber场景

我们已经创建了使用动画角色所需的资产。 现在让我们进入 React。

步骤 1 创建一个新的 React 应用程序

npx create-react-app armada

步骤2 添加Three.js、React Three Fiber、drei依赖

yarn add three react-three-fiber @react-three/drei

第 3 步将 .gltf 文件和 Armada.js 组件包装器复制到 React 项目中。 Armada.js组件放在src目录下,armada.gltf文件放在public目录下。

第 4 步将 index.css 替换为以下内容,使 React Three Fiber 画布填充整个视口。

/*index.css*/
* 
  box-sizing: border-box;


html,
body,
#root 
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;


body 
  background: #000000;
  font-family: -apple-system, BlinkMacSystemFont, avenir next, avenir, helvetica
      neue, helvetica, ubuntu, roboto, noto, segoe ui, arial, sans-serif;

第 5 步创建一个空的 React Three Fiber 场景。 用以下代码替换 App.js 文件的内容。 这将创建一个带有 OrbitControls 和一些简单照明的空场景。

import React from "react";
import  Canvas  from "react-three-fiber";

import  OrbitControls  from "@react-three/drei";
import "./index.css";

export default function App() 
  return (
    <Canvas>
      <OrbitControls />
      <ambientLight intensity=0.6 />
      <directionalLight intensity=0.5 />
    </Canvas>
  );

9、将导入的角色添加到 React Three Fiber场景

现在是时候使用我们用 GLTFJSX 创建的 Armada.js 文件了。

步骤 1 将 Armada.js 文件导入到 App.js 文件中。

第 2 步从“react”中导入 Suspense,并从我们之前创建的 Armada 组件中导入 Armada。

步骤 3 在 Canvas 组件内添加一个 Suspense 组件。

步骤 4 在 Suspense 组件中添加 Armada 组件。

import React,  Suspense  from "react"; //highlight-line
import  Canvas  from "react-three-fiber";
import Armada from "./Armada.js";

import  OrbitControls  from "@react-three/drei";
import "./index.css";

export default function App() 
  return (
    <Canvas>
      <OrbitControls />
      <ambientLight intensity=0.6 />
      <directionalLight intensity=0.5 />
      // highlight-start
      <Suspense fallback=null>
        <Armada />
      </Suspense>
      // highlight-end
    </Canvas>
  );

你现在应该会在 Armada 动画的开头看到该角色,但它还没有移动。 我们将在下一步也是最后一步中解决这个问题。

10、警告

如果你看到有关无法从 drei 导入的错误,可能是因为导入路径在最新版本中发生了变化。 看起来像这样的导入将不再有效:

import  useAnimations  from "@react-three/drei/useAnimations";

相反,确保直接从 drei导入的, 像这样:

import  useAnimations  from "@react-three/drei";

11、播放动画

播放动画很容易! 你需要做的就是对 Armada.js 文件进行小的更改。 是的,从 GLTFJSX 自动生成。 动画将作为组件提供的 javascript 对象提供给您。

第 1 步打开自动生成的 Armada.js 组件(来自 gltfjsx)

第 2 步 在 useEffect 挂钩中调用要播放的动画的 play 方法。 动画的名称将来自 Blender 中动作的名称! 这就是为什么在导出之前重命名它如此重要。 如果你不记得要播放的动画的名称,总是可以先在挂钩中控制台记录操作对象。

// Armada.js
/*
Auto-generated by: https://github.com/pmndrs/gltfjsx
*/

import React,  useRef, useEffect  from "react";
import  useGLTF  from "@react-three/drei";
//highlight-start
import  useAnimations  from "@react-three/drei";
//highlight-end
export default function Model(props) 
  const group = useRef();
  const  nodes, materials, animations  = useGLTF("/armada.gltf");

  const  actions  = useAnimations(animations, group);
  //highlight-start
  useEffect(() => 
    actions.Armada.play();
  );
  //highlight-end
  return (
    <group ref=group ...props dispose=null>
      <group rotation=[Math.PI / 2, 0, 0] scale=[0.01, 0.01, 0.01]>
        <primitive object=nodes.mixamorigHips />
        <skinnedMesh
          material=materials.Ch03_Body
          geometry=nodes.Ch03.geometry
          skeleton=nodes.Ch03.skeleton
        />
      </group>
    </group>
  );


useGLTF.preload("/armada.gltf");

如果一切正常,你应该会看到你的角色开始执行踢球动画!


原文链接:React Three Fiber动画 — BimAnt

react-three-fiber如何提取和播放动画

【中文标题】react-three-fiber如何提取和播放动画【英文标题】:How to extract and play animation in react-three-fiber 【发布时间】:2021-01-04 05:49:30 【问题描述】:

我有 .gltf 动画模型。我成功加载了模型,但无法播放嵌入的动画。我想知道是否可以通过任何方式解决它。顺便说一句,我正在对此做出反应。提前谢谢你。

在这里你可以找到模型 https://drive.google.com/file/d/1ZVyklaQuqKbSliu33hFxdyNpg4EQtcBH/view?usp=sharing

这是我尝试过的代码。

import * as THREE from 'three'
import  OrbitControls  from "three/examples/jsm/controls/OrbitControls"
import React,  Suspense,useRef, useEffect, useState  from 'react'
import  Canvas ,extend, useThree, useFrame from 'react-three-fiber'
import  GLTFLoader  from 'three/examples/jsm/loaders/GLTFLoader'
import './style.module.css'

extend( OrbitControls )

function Hardware() 
  const [scene, set] = useState()
  useEffect(() => 
  new GLTFLoader().load("tern_construct_animation.gltf", gltf => 
    set(gltf.scene)
    const mixer = new THREE.AnimationMixer(gltf.scene)
    gltf.animations.forEach(clip => mixer.clipAction(clip).play())
  )
, [])

return scene ? <primitive object=scene /> : null



const Controls = () => 
  const orbitRef = useRef()
  const  camera, gl  = useThree()

  useFrame(() => 
    orbitRef.current.update()
  )

  return (
    <orbitControls
      autoRotate
      maxPolarAngle=Math.PI / 3
      minPolarAngle=Math.PI / 3
      args=[camera, gl.domElement]
      ref=orbitRef
    />
  )

const animated_element = () => 
  return (
    <Canvas camera= position: [0, 0, 5] >
      <ambientLight intensity=2 />
      <pointLight position=[40, 40, 40] />
      <Controls/>
      <Suspense fallback=null>
        <Hardware/>
      </Suspense>
    </Canvas>
  )


export default animated_element;

【问题讨论】:

如果你做console.log(gltf.animations),你会看到什么?里面有东西吗? 是的,我确实得到了一个包含许多 AnimationClip 项目的数组。看看这里我已经发布了image of the console@Marquizzo 【参考方案1】:

我也遇到了同样的问题。

这是对我有用的代码。

显然这个组件在树中被Suspense 包裹得更高。

import  useLoader, useFrame  from 'react-three-fiber';
import  
    GLTFLoader 
 from 'three/examples/jsm/loaders/GLTFLoader';
import * as THREE from 'three'

const Model = props => 
    const model = useLoader(
        GLTFLoader,
        props.path
    )

    // Here's the animation part
    // ************************* 
    let mixer
    if (model.animations.length) 
        mixer = new THREE.AnimationMixer(model.scene);
        model.animations.forEach(clip => 
            const action = mixer.clipAction(clip)
            action.play();
        );
    

    useFrame((state, delta) => 
        mixer?.update(delta)
    )
    // *************************

    model.scene.traverse(child => 
        if (child.isMesh) 
            child.castShadow = true
            child.receiveShadow = true
            child.material.side = THREE.FrontSide
        
    )

    return (
        <primitive 
            object=model.scene
            scale=props.scale
        />
    )


export default Model;

【讨论】:

谢谢,useFrame((state, delta) =&gt; mixer?.update(delta) ) 为我工作。我以前尝试使用useFrame(( clock ) =&gt; mixer?.update(clock.getDelta()));

以上是关于React Three Fiber动画入门的主要内容,如果未能解决你的问题,请参考以下文章

我想做一个用react-three-fiber放大的地球仪

bufferGeometry setFromPoints 与 react-three-fiber

threejs + vanilla js 和 react-three-fiber + create-react-app 的颜色差异

通过 react-three-fiber 中的道具传递纹理的 URL

React-Three-Fiber (R3F):GLTF 加载程序加载问题。为啥我看不到我的模型?

如何在threejs或react-three-fiber中加载相同的gltf模型