+++ date = "2024-08-02" tags = ["react", "vrm"] title = "vrmの表示にreact-three-fiberを使う" +++ 今回は`react-three-fiber`と`three-vrm-animation`の話になります。 react-three-fiberはsceneなどを自動でやってくれて、コードもシンプルになります。 > anim(vrma)を動かす場合は注意が必要で動きますが動きがおかしくなります。これは`react-three-fiber`で書く場合に発生します。個人環境では`unity + vrm 1.0`でexportしたものを使うと正常に動きました。 ```sh $ npx create-react-app vrm-model --template typescript $ npm i $ npm run start ``` ```ts:src/pages/vrm-model.tsx import * as THREE from 'three' import React, { useState, useEffect, useRef } from 'react'; import { OrbitControls } from '@react-three/drei' import { useFrame, Canvas } from '@react-three/fiber'; import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'; import { VRM, VRMUtils, VRMLoaderPlugin } from '@pixiv/three-vrm'; import { VRMAnimationLoaderPlugin, VRMAnimation, createVRMAnimationClip } from "@pixiv/three-vrm-animation"; interface ModelProps { url: string url_anim: string } const VRMModel: React.FC = ({ url, url_anim }) => { const [vrm, setVrm] = useState(null); const mixerRef = useRef(null); useEffect(() => { const loader = new GLTFLoader(); loader.register((parser) => new VRMLoaderPlugin(parser)); loader.register((parser) => new VRMAnimationLoaderPlugin(parser)); loader.load(url, (gltf) => { const vrmModel = gltf.userData.vrm as VRM; VRMUtils.removeUnnecessaryJoints(vrmModel.scene); setVrm(vrmModel); const mixer = new THREE.AnimationMixer(vrmModel.scene); mixerRef.current = mixer; loader.load(url_anim, (animGltf) => { const vrmAnimations = animGltf.userData.vrmAnimations as VRMAnimation[]; if (vrmAnimations && vrmAnimations.length > 0) { const clip = createVRMAnimationClip(vrmAnimations[0], vrmModel); mixer.clipAction(clip).play(); } }); }); }, [url, url_anim]); useFrame((state, delta) => { if (mixerRef.current) mixerRef.current.update(delta); if (vrm) vrm.update(delta); }); return vrm ? : null; }; export const VRMModelCanvas = () => { return (
) } export default VRMModelCanvas; ``` ```ts:src/App.tsx import React from 'react' import VRMModelCanvas from './pages/vrm_model' const App = () => { return ( ) } export default App; ``` ```json:package.json { "name": "vrm-model", "version": "0.1.0", "private": true, "dependencies": { "@pixiv/three-vrm": "^3.0.0", "@pixiv/three-vrm-animation": "^3.0.0", "@react-three/drei": "^9.109.2", "@react-three/fiber": "^8.16.8", "@react-three/postprocessing": "^2.16.2", "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", "@types/jest": "^27.5.2", "@types/node": "^16.18.104", "@types/react": "^18.3.3", "@types/react-dom": "^18.3.0", "@types/three": "^0.167.1", "react": "^18.3.1", "react-dom": "^18.3.1", "react-scripts": "5.0.1", "three": "^0.167.1", "three-stdlib": "^2.30.5", "typescript": "^4.9.5", "web-vitals": "^2.1.4" }, "scripts": { "start": "react-scripts start", "build": "react-scripts build", "test": "react-scripts test", "eject": "react-scripts eject" }, "eslintConfig": { "extends": [ "react-app", "react-app/jest" ] }, "browserslist": { "production": [ ">0.2%", "not dead", "not op_mini all" ], "development": [ "last 1 chrome version", "last 1 firefox version", "last 1 safari version" ] } } ``` ```json:tsconfig.json { "compilerOptions": { "target": "es5", "lib": [ "dom", "dom.iterable", "esnext" ], "allowJs": true, "skipLibCheck": true, "esModuleInterop": true, "allowSyntheticDefaultImports": true, "strict": true, "forceConsistentCasingInFileNames": true, "noFallthroughCasesInSwitch": true, "module": "esnext", "moduleResolution": "node", "resolveJsonModule": true, "isolatedModules": true, "noEmit": true, "jsx": "react-jsx" }, "include": [ "src" ] } ``` ## [issue] blenderでvrmのtextureが剥がれる modelにつけるアクセサリをblenderで統合させ、three-vrmで表示していましたが、textureが剥がされていることに気づきました。 最初はthreeの`toneMapping`の問題だろうと思っていましたが、model(vrm)の問題です。 `unity + vrm 1.0`でアクセサリを付けて、exportしましょう。