react-three-fiber
モチベーション
three.jsを久しぶりに触る
react + three.jsを使いたい
react-three-fiberが流行っているので使いたい
3D空間上にいくつか3Dモデルを配置したい
十字キーで操作したい
導入
リポジトリのディレクトリ内で、
npx create-react-app .
yarn add three react-three-fiber @pixiv/three-vrm @types/three
emotionに関しては以下の手順で設定
簡単な3Dオブジェクトの表示
code:app.js
import { css } from '@emotion/react'
import { Canvas } from 'react-three-fiber'
import SampleBox from './components/SampleBox'
const App = () => {
return (
<div css={container}>
<Canvas>
<SampleBox />
</Canvas>
</div>
)
}
const container = css`
width: 100vw;
height: 100vh;
`
export default App
code:SampleBox.jsx
import { useRef } from 'react'
import { useFrame } from 'react-three-fiber'
const SampleBox = () => {
const ref = useRef({})
useFrame(() => (ref.current.rotation.z += 0.01))
return (
<mesh ref={ref}>
<boxBufferGeometry attach="geometry" />
<meshBasicMaterial attach="material" color="hotpink" opacity={0.5} transparent />
</mesh>
)
}
export default SampleBox
これだけで、3Dを回転させるものが作れる。カメラの位置関係上2Dに見える。
https://gyazo.com/43d0beb9fe6d2b61e82be7804136609d
カメラを動かすためのorbitControlsの設定
code:utils/Controls.jsx
import { useRef } from 'react'
import { extend, useThree, useFrame } from 'react-three-fiber'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
extend({ OrbitControls })
const Controls = (props) => {
const {
camera,
gl: { domElement }
} = useThree()
const controls = useRef({})
useFrame(() => controls.current.update())
}
export default Controls
Controlsの追加
code:app.js
import { css } from '@emotion/react'
import { Canvas } from 'react-three-fiber'
import SampleBox from './components/SampleBox'
+ import Controls from './utils/Controls'
const App = () => {
return (
<div css={container}>
<Canvas>
<SampleBox />
+ <Controls />
</Canvas>
</div>
)
}
const container = css`
width: 100vw;
height: 100vh;
`
export default App
↓カメラをちょっと動かして、3D表示ぽく
https://gyazo.com/dd48c2a295a3a89f6709afe1011e9667
3Dモデルの表示
↓のvrmファイルを利用
ダウンロードし、public/models/に配置する
vrmの読み込み
code:src/utils/VRMAsset.jsx
import React, { useState, useEffect } from 'react'
import { useLoader } from 'react-three-fiber'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
import { VRM, VRMUtils, VRMSchema } from '@pixiv/three-vrm'
const VRMAsset = ({ url }) => {
const gltf = useLoader(GLTFLoader, url)
useEffect(() => {
VRMUtils.removeUnnecessaryJoints(gltf.scene)
VRM.from(gltf).then((vrm) => {
setScene(vrm.scene)
const boneNode = vrm.humanoid.getBoneNode(VRMSchema.HumanoidBoneName.Hips)
boneNode.rotateY(Math.PI)
})
if (scene === null) {
return null
}
return <primitive object={scene} dispose={null} />
}
export default VRMAsset
model読み込み
code:src/components/SampleModel.jsx
import { Suspense } from 'react'
import VRMAsset from '../utils/VRMAsset'
const SampleModel = () => {
return (
<Suspense fallback={null}>
<VRMAsset url="./models/three-vrm-girl.vrm" />
</Suspense>
)
}
export default SampleModel
code:App.js
import { css } from '@emotion/react'
import { Canvas } from 'react-three-fiber'
import { Vector3 } from 'three'
+ import SampleModel from './components/SampleModel'
import Controls from './utils/Controls'
const App = () => {
return (
<div css={container}>
<Canvas>
+ <SampleModel />
+ <Controls defaultCameraPosition={0, 1.25, 1} target={new Vector3(0, 1, 0)} /> + <directionalLight position={1, 1, 1} /> <gridHelper />
</Canvas>
</div>
)
}
const container = css`
width: 100vw;
height: 100vh;
`
export default App
https://gyazo.com/aa481b674a329535ed3b5a1ea3371a5c
参考
React (Typescript) + react-three-fiber + three-vrmでVRMモデルを表示してみる