VRMファイルの中身を表示するWebサイトそ作る過程でReact 内で Three.js を扱ったので、使用した場合の知見などについて共有します。
※ ここでは react-three-renderer などのライブラリを使わず、素の React と Three.js を使う方法を紹介します。
また、今回、「VRMファイルの中身を表示するWebサイト」のソースコードはこちらに公開しています。
作成したデモページはこちらです。
作ったものについて
人型の3DModelファイルであるVRMファイルの中にあるMeta情報(Boneとかアニメーションとか)を抽出して表示するWebAPIを作成してみました。
VRMファイルの中身はJSONになっているのでその情報を抽出することができます。
参考
使用した技術
WebAPI
Demo Page
React
ReacttはUIのパーツ(構成部品)を作るためのライブラリです。
FacebookがOSSとして公開しています。
Typescriptで開発することもできます。(今回紹介しているものはTypescriptにて記述しています。)
Reactのセットアップや導入については React公式 ページにまとまっていますので今回は省略します。
Reactの中でthree.jsを使う
three.jsのインストール
まずはthree.jsをインストールします。
yarn add three
最新の three.js にはTypescriptで開発するために必要なものが入っているので @types/three
のインストールをする必要はありません。
three.jsで何か表示してみる
Reactにて three.js を使って最小限のソースコードで何かしら表示させる方法は以下のようになります
import React from 'react';
import { WebGLRenderer, Scene, PerspectiveCamera } from 'three';
class App extends React.Component {
onCanvasLoaded = (canvas: HTMLCanvasElement) => {
if (!canvas) {
return;
}
const renderer = new WebGLRenderer({ canvas: canvas, antialias: true });
const scene = new Scene();
// new THREE.PerspectiveCamera(視野角, アスペクト比, near, far)
const camera = new PerspectiveCamera(45, canvas.clientWidth / canvas.clientHeight, 1, 2000);
renderer.render(scene, camera);
};
render():
| React.ReactElement<any, string | React.JSXElementConstructor<any>>
| string
| number
| {}
| React.ReactNodeArray
| React.ReactPortal
| boolean
| null
| undefined {
return (
<div>
<canvas ref={this.onCanvasLoaded} />
</div>
);
}
}
export default App;
React のJSX内ではcanvas
を指定することができますので、React.Component
を継承したClass内で描画処理を行っている render
メソッドに canvas
タグを指定します。このとき canvas
タグの中の ref
プロパティはcanvas
が描画された直後に呼ばれるものです。この ref
プロパティの中で取得できる canvas
(Typescriptだと canvas: HTMLCanvasElement
)を three.js のWebGLRenderer
に指定してあげれば、指定した canvas
に描画されます。
あとは three.js の描画に必要な Scene
と カメラ
(今回は場合はPerspectiveCamera
) を指定することで表示されます。
three.jsで色々と動かせる状態にする
上記の表示した内容は静止画になります。
three.js で動画のようにいろいろ動かしてみたくなると思います。
その場合の実装方法は以下のようになります。
import React from 'react';
import { WebGLRenderer, Scene, PerspectiveCamera } from 'three';
class App extends React.Component {
private scene: Scene | null = null;
private camera: PerspectiveCamera | null = null;
private renderer: WebGLRenderer | null = null;
constructor(props: any) {
super(props);
this.animate = this.animate.bind(this);
}
onCanvasLoaded = (canvas: HTMLCanvasElement) => {
if (!canvas) {
return;
}
this.renderer = new WebGLRenderer({ canvas: canvas, antialias: true });
this.scene = new Scene();
// new THREE.PerspectiveCamera(視野角, アスペクト比, near, far)
this.camera = new PerspectiveCamera(45, canvas.clientWidth / canvas.clientHeight, 1, 2000);
this.animate()
};
animate() {
window.requestAnimationFrame(this.animate);
if (this.renderer && this.scene && this.camera) {
this.renderer.render(this.scene, this.camera);
}
}
render():
| React.ReactElement<any, string | React.JSXElementConstructor<any>>
| string
| number
| {}
| React.ReactNodeArray
| React.ReactPortal
| boolean
| null
| undefined {
return (
<div>
<canvas ref={this.onCanvasLoaded} />
</div>
);
}
}
export default App;
window.requestAnimationFrame(this.animate)
ここで自身の function
を指定することで、指定した function
が繰り返し実行されるようになります。
これにより three.js 内でアニメーションするようになります。
しかし、React にて描画に影響を与える場合は事前に bind
しないとエラーが発生します。そのため、constructor
にて this.animate = this.animate.bind(this);
と指定することで、連続しての描画を実現しています。
あとは色々と表示させるためにScene
に追加したり、DirectionalLight
で光を当てたり、position
や scale
を変更させたり、各種 three.js の処理を作成していくことで、React と three.js が共存した物を作ることができます。
まとめ
React 内で three.js を使う場合についての紹介と実際に作成したものについて紹介しました。
React への three.js の導入は割とすんなり導入できるのではないかと思います。
React は GatsbyJS など人気のプロジェクト(ツール)に使われていることも多くあるので、これらを使いつつ、three.js を導入する場合の参考となればと思います。