一、react-three-fiber简介
使用可重用、自包含的组件以声明方式构建您的场景,这些组件对状态做出反应、易于交互并且可以利用 React 的生态系统。 没有任何限制,一切工作在three.js
这里将无一例外地工作。 生态完善。
需要安装的依赖
npm install three @react-three/fiber @react-three/drei @react-spring/three @react-three/postprocessing three
二、寻找免费角色和动画
首先让我们找到一个角色和一组要使用的动画。 为此,我们可以使用 Mixamo,这是一个由 Adobe 提供的免费角色模型和动画库。 如果没有帐户,则需要先创建一个。
第 1 步登录 Mixamo(或创建一个免费帐户)
第 2 步查找要下载的角色。 如果想使用与教程相同的角色,请使用 Michelle 角色。
我下载的是这个模型
然后导出模型转换为gltf格式
三、生成 React Component Wrapper
当我们在 React 中使用导出的 gltf 文件时,我们需要访问导出场景的某些部分,例如我们需要提取几何体、骨架和动画。
你可以通过不手动操作来节省大量时间,而是使用由 react-three-fiber 团队创建的名为 GLFTJSX 的有用工具。 这是一个命令行工具,你可以将 gltf 或 glb 文件作为输入运行,它将创建一个结构良好的 React 组件包装器作为输出。 GLFTJSX 不需要安装 只是使用命令 npx gltf scene.gltf(你下载的gltf文件),npx在执行的时候跟要gltf文件同目录
npx gltfjsx scene.gltf
四、 上代码!!!
index.tsx文件
import { PageContainer } from '@ant-design/pro-components';
import { Canvas } from '@react-three/fiber';
import { Card } from 'antd';
import {Html, OrbitControls,useProgress,} from '@react-three/drei';
import { Suspense } from 'react';
import { Model } from './person.jsx';
function Loader() {
const { progress } = useProgress();
return <Html center>{progress} % loaded</Html>;
}
const Page: React.FC = () => {
return (
<PageContainer ghost>
<Card>
<Canvas
style={{ height: '700px' }}
shadows
camera={{ position: [0, 0, 5], fov: 40 }}
>
<Suspense fallback={<Loader />}>
<ambientLight intensity={2}></ambientLight>
<directionalLight intensity={2} />
<Model scale={1} />
<OrbitControls />
{/* <OrbitControls makeDefault autoRotate /> */}
</Suspense>
</Canvas>
</Card>
</PageContainer>
);
};
export default Page;
person.jsx文件
/*
Auto-generated by: https://github.com/pmndrs/gltfjsx
Command: npx gltfjsx@6.2.13 scene.gltf
*/
import React, { useRef, useEffect } from 'react'
import { useGLTF, useAnimations } from '@react-three/drei'
export function Model(props) {
const group = useRef()
const { nodes, materials, animations } = useGLTF('/person.gltf')
const { actions } = useAnimations(animations, group)
// actions.Armada.play(); 如果动画较多的情况下 是会出现.play()方法不存在
useEffect(() => {
if (animations && animations.length > 0) {
animations.forEach((animation) => {
actions[animation.name].play()
})
//actions.animation.play()
}
}, [actions, animations])
return (
<group ref={group} {...props} dispose={null}>
<group name="Scene">
<group name="Armature" rotation={[Math.PI / 2, 0, 0]} scale={0.01}>
<primitive object={nodes.mixamorigHips} />
<skinnedMesh name="Ch03" geometry={nodes.Ch03.geometry} material={materials.Ch03_Body} skeleton={nodes.Ch03.skeleton} />
</group>
</group>
</group>
)
}
useGLTF.preload('/scene.gltf')